github / github/codeql

Call chain analysis exception

オープン
#19,637 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る
question
主要言語
CodeQL
スター
10.1k
フォーク
2.1k
平均マージ
2日 15時間
マージ済み PR(30日)
141

説明

Hello, I'm not familiar with `isAdditionalFlowStep`, so there might be some issues with the rule I wrote. Could you please help me take a look?
```java
public class HashMap extends AbstractMap
// 4、key
implements Map, Cloneable, Serializable {
static final int hash(Object key) {
int h;
// 5、key.hashCode()
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

//1、s
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
reinitialize();
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new InvalidObjectException("Illegal load factor: " +
loadFactor);
s.readInt();
int mappings = s.readInt();
if (mappings < 0)
throw new InvalidObjectException("Illegal mappings count: " +
mappings);
else if (mappings > 0) {
float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
float fc = (float)mappings / lf + 1.0f;
int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
DEFAULT_INITIAL_CAPACITY :
(fc >= MAXIMUM_CAPACITY) ?
MAXIMUM_CAPACITY :
tableSizeFor((int)fc));
float ft = (float)cap * lf;
threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
(int)ft : Integer.MAX_VALUE);
@SuppressWarnings({"rawtypes","unchecked"})
Node[] tab = (Node[])new Node[cap];
table = tab;

for (int i = 0; i < mappings; i++) {
@SuppressWarnings("unchecked")
// 2、keu
K key = (K) s.readObject();
@SuppressWarnings("unchecked")
V value = (V) s.readObject();
// 3、hash(key)
putVal(hash(key), key, value, false, false);
}
}
}
}

public final class URL implements java.io.Serializable {

transient URLStreamHandler handler;

// 6
public synchronized int hashCode() {
if (hashCode != -1)
return hashCode;

// 7、handler.hashCode(this)
hashCode = handler.hashCode(this);
return hashCode;
}
}

public abstract class URLStreamHandler {

// 8、u
protected int hashCode(URL u) {
int h = 0;

String protocol = u.getProtocol();
if (protocol != null)
h += protocol.hashCode();

// 9、getHostAddress(u);
InetAddress addr = getHostAddress(u);
if (addr != null) {
h += addr.hashCode();
} else {
String host = u.getHost();
if (host != null)
h += host.toLowerCase().hashCode();
}

String file = u.getFile();
if (file != null)
h += file.hashCode();

if (u.getPort() == -1)
h += getDefaultPort();
else
h += u.getPort();

String ref = u.getRef();
if (ref != null)
h += ref.hashCode();

return h;
}
}
```

The path query from `HashMap.readObject` to `HashMap.hash->h = key.hashCode()` has been successfully completed.

```java
class ReadObjectSource extends DataFlow::Node {
ReadObjectSource() {
exists(Method m |
m.getDeclaringType().getASupertype() instanceof TypeSerializable and
m.hasName("readObject") and
m.getDeclaringType().hasQualifiedName("java.util", "HashMap") and
this.asParameter() = m.getParameter(0)
)
}
}

class GetHostAddressSource extends DataFlow::Node {
GetHostAddressSource() {
exists(MethodCall call |
call.getMethod().hasName("hashCode") and
call.getMethod().getDeclaringType().hasQualifiedName("java.lang", "Object") and
this.asExpr() = call.getQualifier()
)
}
}

module LiteralToURLConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof ReadObjectSource
}

predicate isSink(DataFlow::Node sink) {
sink instanceof GetHostAddressSource
}
}
```

![](https://cdn.nlark.com/yuque/0/2025/png/22749699/1748744685262-9609339c-f58a-4de4-862c-fab5f745c361.png)

However, the path from `HashMap.readObject` to `HashMap.hash->h = key.hashCode()` cannot be found as shown below, and it directly jumps to the `hashCode` method in other classes.

```java
class ReadObjectSource extends DataFlow::Node {
ReadObjectSource() {
exists(Method m |
m.getDeclaringType().getASupertype() instanceof TypeSerializable and
m.hasName("readObject") and
m.getDeclaringType().hasQualifiedName("java.util", "HashMap") and
this.asParameter() = m.getParameter(0)
)
}
}

class GetHostAddressSource extends DataFlow::Node {
GetHostAddressSource() {
exists(MethodCall call |
call.getMethod().hasName("getHostAddress") and
this.asExpr() = call.getArgument(0)
)
}
}

module LiteralToURLConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof ReadObjectSource
}

predicate isSink(DataFlow::Node sink) {
sink instanceof GetHostAddressSource
}

predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node sink){
source instanceof ReadObjectSource and
exists(
MethodCall call,
RefType rt
|
source instanceof ReadObjectSource and
sink.asExpr() = call.getQualifier() and
rt = sink.getType().(RefType)
)
}
}
```

![](https://cdn.nlark.com/yuque/0/2025/png/22749699/1748744782136-4017260b-16ef-4be9-bef8-9f437bb6f79f.png)

コントリビューションガイド

コントリビューションガイドを開く

調査の方向性

Start with the two DataFlow::ConfigSig examples in the issue and compare the successful path to the failing isAdditionalFlowStep configuration. Trace how ReadObjectSource, GetHostAddressSource, MethodCall, and RefType are used, then verify the behavior against the shown HashMap and URL call chain. Done means the path behavior is explained and the configuration either finds the intended path or documents why it cannot.

索引モデルが issue の本文から書いたものです。

評価

技術スタック
java
領域
devtools, security
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
説明が足りない
初心者へのやさしさ
30/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。