惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cisco Talos Blog
Cisco Talos Blog
Cyberwarzone
Cyberwarzone
T
Tenable Blog
Security Latest
Security Latest
NISL@THU
NISL@THU
V
Vulnerabilities – Threatpost
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
W
WeLiveSecurity
罗磊的独立博客
Stack Overflow Blog
Stack Overflow Blog
云风的 BLOG
云风的 BLOG
Martin Fowler
Martin Fowler
Engineering at Meta
Engineering at Meta
T
Tor Project blog
H
Heimdal Security Blog
Microsoft Security Blog
Microsoft Security Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
雷峰网
雷峰网
L
LINUX DO - 热门话题
The GitHub Blog
The GitHub Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Recorded Future
Recorded Future
Hugging Face - Blog
Hugging Face - Blog
P
Privacy & Cybersecurity Law Blog
F
Full Disclosure
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
PCI Perspectives
PCI Perspectives
MyScale Blog
MyScale Blog
B
Blog RSS Feed
www.infosecurity-magazine.com
www.infosecurity-magazine.com
K
Kaspersky official blog
Attack and Defense Labs
Attack and Defense Labs
H
Hackread – Cybersecurity News, Data Breaches, AI and More
有赞技术团队
有赞技术团队
Know Your Adversary
Know Your Adversary
Hacker News - Newest:
Hacker News - Newest: "LLM"
Scott Helme
Scott Helme
The Last Watchdog
The Last Watchdog
博客园 - 【当耐特】
S
Security Affairs
The Cloudflare Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
人人都是产品经理
人人都是产品经理
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
N
News and Events Feed by Topic
AI
AI
H
Help Net Security
美团技术团队
T
Threatpost
Project Zero
Project Zero

SumSec's Blog

AI Agent 工程的必然演进:CLI、Skills、Harne… 从安全角度谈Java反射机制--前章 · SUMSEC 从安全角度谈Java反射机制--终章 · SUMSEC 逆向学习fastjson反序列化始 · SUMSEC 2020年研究回顾总结 · SUMSEC Abstract syntax tree classes for … Analyzing data flow in Java · SUM… Annotations in Java · SUMSEC Basic query for Java code · SUMSEC BypassSuper使用介绍说明 · SUMSEC CodeQL Create OpenJdk/Jdk8 Databa… CodeQL library for Java · SUMSEC Navigating the call graph · SUMSEC Overflow-prone comparisons in Jav… Types in Java · SUMSEC Working with source locations · S… Aliases · SUMSEC Expression · SUMSEC Formulas · SUMSEC Modules · SUMSEC Predicates · SUMSEC Queries · SUMSEC Type · SUMSEC Variables · SUMSEC 一道shiro反序列化题目引发的思考 · SUMSEC 修改ysoserial使其支持任意代码执行 · SUMSEC 自定义 ClassLoader 隔离运行不同版本jar包的方式 ·… 2020网鼎杯---Java文件上传wp · SUMSEC CNVD-2020-10487(CVE-2020-1938)tom… JDSRC安全课笔记 · SUMSEC Java反序列化链回显解决方案 · SUMSEC Skipped breakpoint because it hap… Windows Terminal 配置文件 · SUMSEC bypass 学习笔记之绕安全狗bypass safedog · … 一次意外的代码审计----JfinalCMS审计 · SUMSEC 一篇文章读懂Java代码审计之XXE · SUMSEC 从安全角度谈Java反射机制--序章 · SUMSEC 小楼昨夜又春风,你知ysoserial-Gadget-URLDNS… 春眠不觉晓,RCE知多少? · SUMSEC 漫谈Commons-Collections反序列化 · SUMSEC 漫谈Java反序列化 · SUMSEC 白头搔更短,SSTI惹人心! · SUMSEC 记一次面试题 · SUMSEC About Me 关于我 · SUMSEC Apache Flink任意Jar包上传导致远程代码执行 · SU… CVE-2019-1388 UAC提权复现 · SUMSEC CVE-2019-16097 || Harbor任意管理员注册漏洞… Python加密shellcode免杀 · SUMSEC Telegram机器人作为渗透测试框架 · SUMSEC VM虚拟机无法安装vmtools解决|本程序需要您将此虚拟机上安装… 谁能想到,电视遥控器竟成了 Vibe Coding 神器 · SU… 从手改 Skill 到自动进化:评测结果和执行轨迹如何让 Agen… 模型人人都能用,什么才是你能带走的?我的答案是一个可进化的SKIL… 模型人人都能用,什么才是你能带走的?我的答案是一个可进化的Skil… AI 时代 ShiroAttack2 5.x:修改了什么 · SU… 在 AGI 降临前,先给 AI 开一条”脑内弹幕”通道 · SUM… 一篇博文,三种时间:网页幻灯与 Remotion 动效的交付逻辑 … 🔍 别让大模型”想太多”:SKILL开发中的语义陷阱与抗幻觉设计 … 2022 年年度总结 · SUMSEC Java Swing To RCE 漏洞分析 · SUMSEC SpringBoot GatewayEL表达式漏洞分析 · SUM… Sensitive keys in codebases · SUM… 论如何优雅注入 Java 内存马 · SUMSEC SUMSEC 知识点 · SUMSEC VMWare Workspace ONE Access Auth … Spring Framework RCE CVE-2022-229… 相似度算法调研 · SUMSEC CVE-2022-33891 Apache Spark shell… 正则匹配配置不当 · SUMSEC Spring Data MongoDB SpEL CVE-2022… CodeQl Usage Tricks · SUMSEC Spring Boot RCE到内存马探索 · SUMSEC Shiro后渗透拓展面 · SUMSEC shiro反序列化漏洞攻击拓展面–修改key · SUMSEC GitHub Java CodeQL CTF · SUMSEC Hack-Tools 转化成Web · SUMSEC CodeQL与Shiro550碰撞 · SUMSEC CodeQL初见Shiro550 · SUMSEC CodeQL与AST之间联系 · SUMSEC Java加载动态链接库 · SUMSEC Log4j2 漏洞分析 · SUMSEC Interprocedural-Analysis 过程间分析 · … Data Analysis Foundation 数据分析基础 ·… Data Flow Analysis · SUMSEC Intermediate Representation 中间代表(… PII泄露–用CodeQL识别日志中的PII数据 · SUMSEC CodeQL workshop for Java: Unsafe … 前言 · SUMSEC 漏洞环境的搭建 · SUMSEC Fastjson回显 · SUMSEC Tomcat通用回显学习笔记 · SUMSEC 从Java反序列化漏洞题看CodeQL数据流 · SUMSEC 概述 · SUMSEC 记一次Log4j失败的Gadget挖掘记录 · SUMSEC Ysoserial改造记录 · SUMSEC JNDI注入 · SUMSEC shiro JRMP gadget · SUMSEC Fastjson MySQL gadget复现 · SUMSEC 2021年度总结 · SUMSEC
Javadoc · SUMSEC
2026-07-17 · via SumSec's Blog

Javadoc

Javadoc

You can use CodeQL to find errors in Javadoc comments in Java code.

您可以使用CodeQL来查找Java代码中Javadoc注释的错误。

About analyzing Javadoc

To access Javadoc associated with a program element, we use member predicate getDoc of class Element, which returns a Documentable. Class Documentable, in turn, offers a member predicate getJavadoc to retrieve the Javadoc attached to the element in question, if any.

要访问与程序元素相关联的 Javadoc,我们使用 Element 类的成员谓词 getDoc,它返回一个 Documentable。类Documentable则提供了一个成员谓词getJavadoc来检索与相关元素相关的Javadoc,如果有的话。

Javadoc comments are represented by class Javadoc, which provides a view of the comment as a tree of JavadocElement nodes. Each JavadocElement is either a JavadocTag, representing a tag, or a JavadocText, representing a piece of free-form text.

Javadoc注释由类Javadoc表示,它提供了一个注释的视图,即JavadocElement节点的树。每个 JavadocElement 要么是一个 JavadocTag,代表一个标签,要么是一个 JavadocText,代表一段自由格式的文本。

The most important member predicates of class Javadoc are:

Javadoc类最重要的成员谓词是:

  • getAChild - retrieves a top-level JavadocElement node in the tree representation.

    getAChild - 检索树型表示中的一个顶层JavadocElement节点。

  • getVersion - returns the value of the @version tag, if any.

    getVersion - 返回@version标签的值(如果有的话)。

  • getAuthor - returns the value of the @author tag, if any.

    getAuthor - 如果有的话,返回@author标签的值。

For example, the following query finds all classes that have both an @author tag and a @version tag, and returns this information:

例如,下面的查询可以找到所有同时拥有@author标签和@version标签的类,并返回这些信息:

import java

from Class c, Javadoc jdoc, string author, string version
where jdoc = c.getDoc().getJavadoc() and
    author = jdoc.getAuthor() and
    version = jdoc.getVersion()
select c, author, version

image-20210327132707004

image-20210327132717979

JavadocElement defines member predicates getAChild and getParent to navigate up and down the tree of elements. It also provides a predicate getTagName to return the tag’s name, and a predicate getText to access the text associated with the tag.

JavadocElement 定义了成员谓词 getAChild 和 getParent,用于在元素树中上下导航。它还提供了一个谓词 getTagName 来返回标记的名称,以及一个谓词 getText 来访问与标记相关的文本。

We could rewrite the above query to use this API instead of getAuthor and getVersion:

我们可以重写上面的查询,使用这个API代替getAuthor和getVersion:

import java

from Class c, Javadoc jdoc, JavadocTag authorTag, JavadocTag versionTag
where jdoc = c.getDoc().getJavadoc() and
    authorTag.getTagName() = "@author" and authorTag.getParent() = jdoc and
    versionTag.getTagName() = "@version" and versionTag.getParent() = jdoc
select c, authorTag.getText(), versionTag.getText()

image-20210327132707004

image-20210327132717979

The JavadocTag has several subclasses representing specific kinds of Javadoc tags:

从类c,Javadoc jdoc,JavadocTag authorTag,JavadocTag versionTag:

  • ParamTag represents @param tags; member predicate getParamName returns the name of the parameter being documented.

    ParamTag代表@param标签;成员谓词getParamName返回被记录的参数名称。

  • ThrowsTag represents @throws tags; member predicate getExceptionName returns the name of the exception being documented.

    ThrowsTag代表@throws标签;成员谓词getExceptionName返回被记录的异常名称。

  • AuthorTag represents @author tags; member predicate getAuthorName returns the name of the author.

    AuthorTag代表@author标签;成员谓词getAuthorName返回被记录的作者名称。

As an example of using the CodeQL Javadoc API, let’s write a query that finds @param tags that refer to a non-existent parameter.

作为使用CodeQL Javadoc API的一个例子,让我们写一个查询来查找引用一个不存在的参数的@param标签。

For example, consider this program:

例如,考虑这个程序:

class A {
    /**
    * @param lst a list of strings
    */
    public String get(List<String> list) {
        return list.get(0);
    }
}

Here, the @param tag on A.get misspells the name of parameter list as lst. Our query should be able to find such cases.

这里,A.get上的@param标签将参数列表的名称误写为lst。我们的查询应该能够找到这种情况。

To begin with, we write a query that finds all callables (that is, methods or constructors) and their @param tags:

首先,我们写一个查询,找到所有可调用的方法(即方法或构造函数)和它们的@param标签:

import java

from Callable c, ParamTag pt
where c.getDoc().getJavadoc() = pt.getParent()
select c, pt

image-20210327133510876

image-20210327133535667

image-20210327133548916

It’s now easy to add another conjunct to the where clause, restricting the query to @param tags that refer to a non-existent parameter: we simply need to require that no parameter of c has the name pt.getParamName().

现在很容易在where子句中添加另一个共轭,将查询限制在引用不存在的参数的@param标签上:我们只需要要求c的任何参数都没有pt.getParamName()这个名字。

import java

from Callable c, ParamTag pt
where c.getDoc().getJavadoc() = pt.getParent() and
    not c.getAParameter().hasName(pt.getParamName())
select pt, "Spurious @param tag."

image-20210327133629753

image-20210327133636435

image-20210327133649013

A related, but somewhat more involved, problem is finding @throws tags that refer to an exception that the method in question cannot actually throw.

一个相关的,但比较复杂的问题是找到@throws标签,它指的是一个异常,而该方法实际上不能抛出。

For example, consider this Java program:

例如,考虑这个Java程序:

import java.io.IOException;

class A {
    /**
    * @throws IOException thrown if some IO operation fails
    * @throws RuntimeException thrown if something else goes wrong
    */
    public void foo() {
        // ...
    }
}

Notice that the Javadoc comment of A.foo documents two thrown exceptions: IOException and RuntimeException. The former is clearly spurious: A.foo doesn’t have a throws IOException clause, and therefore can’t throw this kind of exception. On the other hand, RuntimeException is an unchecked exception, so it can be thrown even if there is no explicit throws clause listing it. So our query should flag the @throws tag for IOException, but not the one for RuntimeException.

请注意,A.foo的Javadoc注释中记录了两个抛出的异常:IOException和RuntimeException。IOException和RuntimeException。前者显然是虚假的:A.foo没有throws IOException子句,因此不能抛出这种异常。另一方面,RuntimeException是一个未被选中的异常,所以即使没有显式的throws子句列出它,它也可以被抛出。所以我们的查询应该标记IOException的@throws标签,而不是RuntimeException的标签。

Remember that the CodeQL library represents @throws tags using class ThrowsTag. This class doesn’t provide a member predicate for determining the exception type that is being documented, so we first need to implement our own version. A simple version might look like this:

记住,CodeQL库使用类ThrowsTag来表示@throws标签。这个类没有提供一个成员谓词来确定被记录的异常类型,所以我们首先需要实现我们自己的版本。一个简单的版本可能是这样的:

RefType getDocumentedException(ThrowsTag tt) {
    result.hasName(tt.getExceptionName())
}

Similarly, Callable doesn’t come with a member predicate for querying all exceptions that the method or constructor may possibly throw. We can, however, implement this ourselves by using getAnException to find all throws clauses of the callable, and then use getType to resolve the corresponding exception types:

同样,Callable也没有自带一个成员谓词来查询方法或构造函数可能抛出的所有异常。不过,我们可以自己实现这个功能,使用getAnException查找callable的所有抛出子句,然后使用getType解析相应的异常类型:

predicate mayThrow(Callable c, RefType exn) {
    exn.getASupertype*() = c.getAnException().getType()
}

Note the use of getASupertype* to find both exceptions declared in a throws clause and their subtypes. For instance, if a method has a throws IOException clause, it may throw MalformedURLException, which is a subtype of IOException.

注意使用getASupertype*来查找throws子句中声明的异常和它们的子类型。例如,如果一个方法有一个throws IOException子句,它可能会抛出MalformedURLException,这是IOException的一个子类型。

Now we can write a query for finding all callables c and @throws tags tt such that:

现在我们可以写一个查询,用于查找所有可调用的c和@throws标签tt,这样:

  • tt belongs to a Javadoc comment attached to c. tt属于附加在c上的Javadoc注释。
  • c can’t throw the exception documented by tt. c不能抛出tt所记录的异常。
import java

// Determine the kind of exception for the `ThrowsTag`
RefType getDocumentedException(ThrowsTag tt) {
    result.hasName(tt.getExceptionName())
}

// Find all `throws` clauses of the callable and get the exception type
predicate mayThrow(Callable c, RefType exn) {
    exn.getASupertype*() = c.getAnException().getType()
}

from Callable c, ThrowsTag tt, RefType exn
where c.getDoc().getJavadoc() = tt.getParent+() and
    exn = getDocumentedException(tt) and
    not mayThrow(c, exn)
select tt, "Spurious @throws tag."

See this in the query console on LGTM.com. This finds several results in the LGTM.com demo projects.

➤ 在LGTM.com的查询控制台中看到这个。这可以在 LGTM.com 演示项目中找到几个结果。

image-20210327134654810

image-20210327135253078

image-20210327135242786

Improvements

Currently, there are two problems with this query:

目前,这个查询有两个问题:

  1. getDocumentedException is too liberal: it will return any reference type with the right name, even if it’s in a different package and not actually visible in the current compilation unit.

    getDocumentedException过于自由:它将返回任何名称正确的引用类型,即使它在不同的包中,并且在当前的编译单元中实际上不可见。

  2. mayThrow is too restrictive: it doesn’t account for unchecked exceptions, which do not need to be declared.

    mayThrow的限制性太强:它没有考虑到未被选中的异常,而这些异常不需要声明。

To see why the former is a problem, consider this program:

要了解为什么前者是个问题,请考虑这个程序:

class IOException extends Exception {}

class B {
    /** @throws IOException an IO exception */
    void bar() throws IOException {}
}

This program defines its own class IOException, which is unrelated to the class java.io.IOException in the standard library: they are in different packages. Our getDocumentedException predicate doesn’t check packages, however, so it will consider the @throws clause to refer to both IOException classes, and thus flag the @param tag as spurious, since B.bar can’t actually throw java.io.IOException.

这个程序定义了自己的类IOException,它与标准库中的类java.io.IOException无关:它们在不同的包中。然而,我们的getDocumentedException谓词并不检查包,因此它会认为@throws子句同时引用两个IOException类,从而将@param标签标记为虚假的,因为B.bar实际上不能抛出java.io.IOException。

As an example of the second problem, method A.foo from our previous example was annotated with a @throws RuntimeException tag. Our current version of mayThrow, however, would think that A.foo can’t throw a RuntimeException, and thus flag the tag as spurious.

作为第二个问题的例子,我们上一个例子中的方法A.foo被注解了一个@throws RuntimeException标签。然而,我们当前版本的mayThrow会认为A.foo不能抛出RuntimeException,从而将这个标签标记为虚假的。

We can make mayThrow less restrictive by introducing a new class to represent unchecked exceptions, which are just the subtypes of java.lang.RuntimeException and java.lang.Error:

我们可以通过引入一个新的类来表示unchecked异常,这只是java.lang.RuntimeException和java.lang.Error的子类型,从而使mayThrow的限制性降低:

class UncheckedException extends RefType {
    UncheckedException() {
        this.getASupertype*().hasQualifiedName("java.lang", "RuntimeException") or
        this.getASupertype*().hasQualifiedName("java.lang", "Error")
    }
}

Now we incorporate this new class into our mayThrow predicate:

现在我们将这个新类加入到我们的 mayThrow 谓词中:

predicate mayThrow(Callable c, RefType exn) {
    exn instanceof UncheckedException or
    exn.getASupertype*() = c.getAnException().getType()
}

Fixing getDocumentedException is more complicated, but we can easily cover three common cases:

修复getDocumentedException比较复杂,但我们可以轻松覆盖三种常见情况:

  1. The @throws tag specifies the fully qualified name of the exception.

    @throws标签指定了异常的完全限定名称。

  2. The @throws tag refers to a type in the same package.

    @throws标签指的是同一个包中的一个类型。

  3. The @throws tag refers to a type that is imported by the current compilation unit.

    @throws标签指的是当前编译单元导入的类型。

The first case can be covered by changing getDocumentedException to use the qualified name of the @throws tag. To handle the second and the third case, we can introduce a new predicate visibleIn that checks whether a reference type is visible in a compilation unit, either by virtue of belonging to the same package or by being explicitly imported. We then rewrite getDocumentedException as:

第一种情况可以通过修改getDocumentedException来使用@throws标签的限定名来处理。为了处理第二种和第三种情况,我们可以引入一个新的谓词visibleIn,它可以检查一个引用类型在编译单元中是否可见,无论是属于同一个包还是被显式导入。然后我们将getDocumentedException重写成:

import java

// Determine whether a reference type is visible in a compilation unit
predicate visibleIn(CompilationUnit cu, RefType tp) {
    cu.getPackage() = tp.getPackage()
    or
    exists(ImportType it | it.getCompilationUnit() = cu | it.getImportedType() = tp)
}

// Determine the kind of exception for the `ThrowsTag`
RefType getDocumentedException(ThrowsTag tt) {
    result.getQualifiedName() = tt.getExceptionName()
    or
    (result.hasName(tt.getExceptionName()) and visibleIn(tt.getFile(), result))
}

// Define a class to represent unchecked exceptions
class UncheckedException extends RefType {
    UncheckedException() {
        this.getASupertype*().hasQualifiedName("java.lang", "RuntimeException") or
        this.getASupertype*().hasQualifiedName("java.lang", "Error")
    }
}

// Find all `throws` clauses of the callable and get the exception type
predicate mayThrow(Callable c, RefType exn) {
    exn instanceof UncheckedException or
    exn.getASupertype*() = c.getAnException().getType()
}

from Callable c, ThrowsTag tt, RefType exn
where c.getDoc().getJavadoc() = tt.getParent+() and
    exn = getDocumentedException(tt) and
    not mayThrow(c, exn)
select tt, "Spurious @throws tag."

See this in the query console on LGTM.com. This finds many fewer, more interesting results in the LGTM.com demo projects.

➤ 在LGTM.com的查询控制台中看到。这在LGTM.com的演示项目中发现了很多少而有趣的结果。

image-20210327135340417

image-20210327135354874

image-20210327135400636

Currently, visibleIn only considers single-type imports, but you could extend it with support for other kinds of imports.

目前,visibleIn只考虑单一类型的导入,但你可以扩展它,支持其他类型的导入。