Skip to content

Commit e991aa3

Browse files
committed
Merge branch 'main' into cleartextstorage
2 parents 83ec1d0 + ed3a33f commit e991aa3

File tree

33 files changed

+4302
-3987
lines changed

33 files changed

+4302
-3987
lines changed

java/ql/lib/semmle/code/java/controlflow/BasicBlocks.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ private module Input implements BB::InputSig<Location> {
5757
* Holds if `node` represents an exit node to be used when calculating
5858
* post dominance.
5959
*/
60-
predicate nodeIsPostDominanceExit(Node node) { node instanceof ControlFlow::ExitNode }
60+
predicate nodeIsPostDominanceExit(Node node) { node instanceof ControlFlow::NormalExitNode }
6161
}
6262

6363
private module BbImpl = BB::Make<Location, Input>;

java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,16 @@ predicate expectsContent(Node n, ContentSet c) {
348348
FlowSummaryImpl::Private::Steps::summaryExpectsContent(n.(FlowSummaryNode).getSummaryNode(), c)
349349
}
350350

351+
pragma[nomagic]
352+
private predicate numericRepresentative(RefType t) {
353+
t.(BoxedType).getPrimitiveType().getName() = "double"
354+
}
355+
356+
pragma[nomagic]
357+
private predicate booleanRepresentative(RefType t) {
358+
t.(BoxedType).getPrimitiveType().getName() = "boolean"
359+
}
360+
351361
/**
352362
* Gets a representative (boxed) type for `t` for the purpose of pruning
353363
* possible flow. A single type is used for all numeric types to account for
@@ -356,10 +366,10 @@ predicate expectsContent(Node n, ContentSet c) {
356366
RefType getErasedRepr(Type t) {
357367
exists(Type e | e = t.getErasure() |
358368
if e instanceof NumericOrCharType
359-
then result.(BoxedType).getPrimitiveType().getName() = "double"
369+
then numericRepresentative(result)
360370
else
361371
if e instanceof BooleanType
362-
then result.(BoxedType).getPrimitiveType().getName() = "boolean"
372+
then booleanRepresentative(result)
363373
else result = e
364374
)
365375
or

java/ql/lib/semmle/code/java/dispatch/ObjFlow.qll

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -214,24 +214,35 @@ private predicate relevantNode(ObjNode n) {
214214
exists(ObjNode mid | relevantNode(mid) and objStep(mid, n) and relevantNodeBack(n))
215215
}
216216

217-
pragma[noinline]
218-
private predicate objStepPruned(ObjNode n1, ObjNode n2) {
219-
objStep(n1, n2) and relevantNode(n1) and relevantNode(n2)
217+
private newtype TObjFlowNode =
218+
TObjNode(ObjNode n) { relevantNode(n) } or
219+
TObjType(RefType t) { source(t, _) }
220+
221+
private predicate objStepPruned(TObjFlowNode node1, TObjFlowNode node2) {
222+
exists(ObjNode n1, ObjNode n2 |
223+
node1 = TObjNode(n1) and
224+
node2 = TObjNode(n2) and
225+
objStep(n1, n2)
226+
)
227+
or
228+
exists(RefType t, ObjNode n |
229+
node1 = TObjType(t) and
230+
node2 = TObjNode(n) and
231+
source(t, n)
232+
)
220233
}
221234

222-
private predicate stepPlus(Node n1, Node n2) = fastTC(objStepPruned/2)(n1, n2)
235+
private predicate flowSrc(TObjFlowNode src) { src instanceof TObjType }
236+
237+
private predicate flowSink(TObjFlowNode sink) { exists(ObjNode n | sink = TObjNode(n) and sink(n)) }
238+
239+
private predicate stepPlus(TObjFlowNode n1, TObjFlowNode n2) =
240+
doublyBoundedFastTC(objStepPruned/2, flowSrc/1, flowSink/1)(n1, n2)
223241

224242
/**
225243
* Holds if the qualifier `n` of an `Object.toString()` call might have type `t`.
226244
*/
227-
pragma[noopt]
228-
private predicate objType(ObjNode n, RefType t) {
229-
exists(ObjNode n2 |
230-
sink(n) and
231-
(stepPlus(n2, n) or n2 = n) and
232-
source(t, n2)
233-
)
234-
}
245+
private predicate objType(ObjNode n, RefType t) { stepPlus(TObjType(t), TObjNode(n)) }
235246

236247
private VirtualMethodCall objectToString(ObjNode n) {
237248
result.getQualifier() = n.asExpr() and sink(n)

java/ql/src/Likely Bugs/Resource Leaks/CloseType.qll

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -212,33 +212,35 @@ private LocalVariableDecl getCloseableVariable(CloseableInitExpr cie) {
212212
/**
213213
* A variable on which a "close" method is called, implicitly or explicitly, directly or indirectly.
214214
*/
215-
private predicate closeCalled(Variable v) {
215+
private predicate closeCalled(LocalScopeVariable v) {
216216
// `close()` is implicitly called on variables declared or referenced
217217
// in the resources clause of try-with-resource statements.
218218
exists(TryStmt try | try.getAResourceVariable() = v)
219219
or
220220
// Otherwise, there should be an explicit call to a method whose name contains "close".
221221
exists(MethodCall e |
222-
v = getCloseableVariable(_) or v instanceof Parameter or v instanceof LocalVariableDecl
223-
|
224222
e.getMethod().getName().toLowerCase().matches("%close%") and
225223
exists(VarAccess va | va = v.getAnAccess() |
226224
e.getQualifier() = va or
227225
e.getAnArgument() = va
228226
)
229-
or
230-
// The "close" call could happen indirectly inside a helper method of unknown name.
231-
exists(int i | e.getArgument(i) = v.getAnAccess() |
232-
exists(Parameter p, int j | p.getPosition() = j and p.getCallable() = e.getMethod() |
233-
closeCalled(p) and i = j
234-
or
235-
// The helper method could be iterating over a varargs parameter.
236-
exists(EnhancedForStmt for | for.getExpr() = p.getAnAccess() |
237-
closeCalled(for.getVariable().getVariable())
238-
) and
239-
p.isVarargs() and
240-
j <= i
241-
)
227+
)
228+
or
229+
// The "close" call could happen indirectly inside a helper method of unknown name.
230+
exists(Parameter p |
231+
closeCalled(p) and p.getAnArgument() = v.getAnAccess() and p.getCallable() instanceof Method
232+
)
233+
or
234+
exists(MethodCall e, int i | e.getArgument(i) = v.getAnAccess() |
235+
exists(Parameter p, int j |
236+
p.getPosition() = j and p.getCallable() = e.getMethod().getSourceDeclaration()
237+
|
238+
// The helper method could be iterating over a varargs parameter.
239+
exists(EnhancedForStmt for | for.getExpr() = p.getAnAccess() |
240+
closeCalled(for.getVariable().getVariable())
241+
) and
242+
p.isVarargs() and
243+
j <= i
242244
)
243245
)
244246
}

java/ql/test-kotlin1/library-tests/controlflow/basic/strictPostDominance.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,12 @@
208208
| Test.kt:101:5:103:5 | ... -> ... | Test.kt:101:5:103:5 | <Expr>; |
209209
| Test.kt:101:5:103:5 | <Expr>; | Test.kt:100:25:110:1 | { ... } |
210210
| Test.kt:102:9:102:25 | throw ... | Test.kt:101:33:103:5 | { ... } |
211+
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:100:25:110:1 | { ... } |
212+
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:101:5:103:5 | ... -> ... |
213+
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:101:5:103:5 | <Expr>; |
214+
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:100:25:110:1 | { ... } |
215+
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:101:5:103:5 | ... -> ... |
216+
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:101:5:103:5 | <Expr>; |
211217
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:105:5:109:5 | <Expr>; |
212218
| Test.kt:106:9:106:29 | <Expr>; | Test.kt:105:20:107:5 | { ... } |
213219
| Test.kt:108:9:108:29 | <Expr>; | Test.kt:107:27:109:5 | { ... } |

java/ql/test-kotlin2/library-tests/controlflow/basic/strictPostDominance.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,12 @@
208208
| Test.kt:101:9:103:5 | ... -> ... | Test.kt:100:25:110:1 | { ... } |
209209
| Test.kt:101:9:103:5 | ... -> ... | Test.kt:101:5:103:5 | <Expr>; |
210210
| Test.kt:102:9:102:25 | throw ... | Test.kt:101:33:103:5 | { ... } |
211+
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:100:25:110:1 | { ... } |
212+
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:101:5:103:5 | <Expr>; |
213+
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:101:9:103:5 | ... -> ... |
214+
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:100:25:110:1 | { ... } |
215+
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:101:5:103:5 | <Expr>; |
216+
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:101:9:103:5 | ... -> ... |
211217
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:105:5:109:5 | <Expr>; |
212218
| Test.kt:106:9:106:29 | <Expr>; | Test.kt:105:20:107:5 | { ... } |
213219
| Test.kt:108:9:108:29 | <Expr>; | Test.kt:107:27:109:5 | { ... } |

java/ql/test/query-tests/Nullness/B.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,4 +408,32 @@ public void bitwise(Object x, boolean b) {
408408
x.hashCode(); // NPE
409409
}
410410
}
411+
412+
public void corrCondLoop1(boolean a[]) {
413+
Object x = new Object();
414+
for (int i = 0; i < a.length; i++) {
415+
boolean b = a[i];
416+
if (b) {
417+
x = null;
418+
}
419+
if (!b) {
420+
x.hashCode(); // NPE - false negative
421+
}
422+
// flow can loop around from one iteration to the next
423+
}
424+
}
425+
426+
public void corrCondLoop2(boolean a[]) {
427+
for (int i = 0; i < a.length; i++) {
428+
// x is local to the loop iteration and thus cannot loop around and reach the sink
429+
Object x = new Object();
430+
boolean b = a[i];
431+
if (b) {
432+
x = null;
433+
}
434+
if (!b) {
435+
x.hashCode(); // OK
436+
}
437+
}
438+
}
411439
}

rust/ql/lib/codeql/rust/Frameworks.qll

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,4 @@
44

55
private import codeql.rust.frameworks.rustcrypto.RustCrypto
66
private import codeql.rust.frameworks.Poem
7-
private import codeql.rust.frameworks.Sqlx
87
private import codeql.rust.frameworks.stdlib.Stdlib

rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,8 @@ extensible predicate sourceModel(
6868
*
6969
* For example, `input = Argument[0]` means the first argument of the call.
7070
*
71-
* The following kinds are supported:
72-
*
73-
* - `sql-injection`: a flow sink for SQL injection.
71+
* The sink kinds supported by queries can be found by searching for uses of
72+
* the `sinkNode` predicate.
7473
*/
7574
extensible predicate sinkModel(
7675
string path, string input, string kind, string provenance, QlBuiltins::ExtensionId madId

rust/ql/lib/codeql/rust/elements/internal/TraitImpl.qll

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,36 @@ module Impl {
3636
not this.hasGenericParamList() and
3737
result = 0
3838
}
39+
40+
private int nrOfDirectTypeBounds() {
41+
result = this.getTypeBoundList().getNumberOfBounds()
42+
or
43+
not this.hasTypeBoundList() and
44+
result = 0
45+
}
46+
47+
/**
48+
* Gets the `index`th type bound of this trait, if any.
49+
*
50+
* This includes type bounds directly on the trait and bounds from any
51+
* `where` clauses for `Self`.
52+
*/
53+
TypeBound getTypeBound(int index) {
54+
result = this.getTypeBoundList().getBound(index)
55+
or
56+
exists(WherePred wp |
57+
wp = this.getWhereClause().getAPredicate() and
58+
wp.getTypeRepr().(PathTypeRepr).getPath().getText() = "Self" and
59+
result = wp.getTypeBoundList().getBound(index - this.nrOfDirectTypeBounds())
60+
)
61+
}
62+
63+
/**
64+
* Gets a type bound of this trait.
65+
*
66+
* This includes type bounds directly on the trait and bounds from any
67+
* `where` clauses for `Self`.
68+
*/
69+
TypeBound getATypeBound() { result = this.getTypeBound(_) }
3970
}
4071
}

0 commit comments

Comments
 (0)