Skip to content

Commit 2db1fbc

Browse files
Merge branch 'main' into python-flask-session-interface
2 parents 8ff0cb6 + 3f66b63 commit 2db1fbc

File tree

351 files changed

+40652
-39488
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

351 files changed

+40652
-39488
lines changed

.bazelversion

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
7.1.0
1+
7.1.2
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
description: Revert support for repeated initializers, which are allowed in C with designated initializers.
22
compatibility: full
3-
aggregate_field_init.rel: reorder aggregate_field_init.rel (int aggregate, int initializer, int field, int position) aggregate initializer field
4-
aggregate_array_init.rel: reorder aggregate_array_init.rel (int aggregate, int initializer, int element_index, int position) aggregate initializer element_index
3+
aggregate_field_init.rel: reorder aggregate_field_init.rel (@aggregateliteral aggregate, @expr initializer, @membervariable field, int position) aggregate initializer field
4+
aggregate_array_init.rel: reorder aggregate_array_init.rel (@aggregateliteral aggregate, @expr initializer, int element_index, int position) aggregate initializer element_index

cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll

Lines changed: 104 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,7 @@ class IRGuardCondition extends Instruction {
565565
/** Holds if (determined by this guard) `op == k` evaluates to `areEqual` if this expression evaluates to `value`. */
566566
cached
567567
predicate comparesEq(Operand op, int k, boolean areEqual, AbstractValue value) {
568-
compares_eq(this, op, k, areEqual, value)
568+
unary_compares_eq(this, op, k, areEqual, false, value)
569569
}
570570

571571
/**
@@ -586,7 +586,7 @@ class IRGuardCondition extends Instruction {
586586
cached
587587
predicate ensuresEq(Operand op, int k, IRBlock block, boolean areEqual) {
588588
exists(AbstractValue value |
589-
compares_eq(this, op, k, areEqual, value) and this.valueControls(block, value)
589+
unary_compares_eq(this, op, k, areEqual, false, value) and this.valueControls(block, value)
590590
)
591591
}
592592

@@ -611,7 +611,7 @@ class IRGuardCondition extends Instruction {
611611
cached
612612
predicate ensuresEqEdge(Operand op, int k, IRBlock pred, IRBlock succ, boolean areEqual) {
613613
exists(AbstractValue value |
614-
compares_eq(this, op, k, areEqual, value) and
614+
unary_compares_eq(this, op, k, areEqual, false, value) and
615615
this.valueControlsEdge(pred, succ, value)
616616
)
617617
}
@@ -737,26 +737,66 @@ private predicate compares_eq(
737737
)
738738
}
739739

740-
/** Holds if `op == k` is `areEqual` given that `test` is equal to `value`. */
741-
private predicate compares_eq(
742-
Instruction test, Operand op, int k, boolean areEqual, AbstractValue value
740+
/**
741+
* Holds if `op == k` is `areEqual` given that `test` is equal to `value`.
742+
*
743+
* Many internal predicates in this file have a `inNonZeroCase` column.
744+
* Ideally, the `k` column would be a type such as `Option<int>::Option`, to
745+
* represent whether we have a concrete value `k` such that `op == k`, or whether
746+
* we only know that `op != 0`.
747+
* However, cannot instantiate `Option` with an infinite type. Thus the boolean
748+
* `inNonZeroCase` is used to distinquish the `Some` (where we have a concrete
749+
* value `k`) and `None` cases (where we only know that `op != 0`).
750+
*
751+
* Thus, if `inNonZeroCase = true` then `op != 0` and the value of `k` is
752+
* meaningless.
753+
*
754+
* To see why `inNonZeroCase` is needed consider the following C program:
755+
* ```c
756+
* char* p = ...;
757+
* if(p) {
758+
* use(p);
759+
* }
760+
* ```
761+
* in C++ there would be an int-to-bool conversion on `p`. However, since C
762+
* does not have booleans there is no conversion. We want to be able to
763+
* conclude that `p` is non-zero in the true branch, so we need to give `k`
764+
* some value. However, simply setting `k = 1` would make the rest of the
765+
* analysis think that `k == 1` holds inside the branch. So we distinquish
766+
* between the above case and
767+
* ```c
768+
* if(p == 1) {
769+
* use(p)
770+
* }
771+
* ```
772+
* by setting `inNonZeroCase` to `true` in the former case, but not in the
773+
* latter.
774+
*/
775+
private predicate unary_compares_eq(
776+
Instruction test, Operand op, int k, boolean areEqual, boolean inNonZeroCase, AbstractValue value
743777
) {
744778
/* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */
745-
exists(AbstractValue v | simple_comparison_eq(test, op, k, v) |
779+
exists(AbstractValue v | unary_simple_comparison_eq(test, op, k, inNonZeroCase, v) |
746780
areEqual = true and value = v
747781
or
748782
areEqual = false and value = v.getDualValue()
749783
)
750784
or
751-
complex_eq(test, op, k, areEqual, value)
785+
unary_complex_eq(test, op, k, areEqual, inNonZeroCase, value)
752786
or
753787
/* (x is true => (op == k)) => (!x is false => (op == k)) */
754-
exists(AbstractValue dual | value = dual.getDualValue() |
755-
compares_eq(test.(LogicalNotInstruction).getUnary(), op, k, areEqual, dual)
788+
exists(AbstractValue dual, boolean inNonZeroCase0 |
789+
value = dual.getDualValue() and
790+
unary_compares_eq(test.(LogicalNotInstruction).getUnary(), op, k, inNonZeroCase0, areEqual, dual)
791+
|
792+
k = 0 and inNonZeroCase = inNonZeroCase0
793+
or
794+
k != 0 and inNonZeroCase = true
756795
)
757796
or
758797
// ((test is `areEqual` => op == const + k2) and const == `k1`) =>
759798
// test is `areEqual` => op == k1 + k2
799+
inNonZeroCase = false and
760800
exists(int k1, int k2, ConstantInstruction const |
761801
compares_eq(test, op, const.getAUse(), k2, areEqual, value) and
762802
int_value(const) = k1 and
@@ -781,35 +821,53 @@ private predicate simple_comparison_eq(
781821
value.(BooleanValue).getValue() = false
782822
}
783823

784-
/** Rearrange various simple comparisons into `op == k` form. */
785-
private predicate simple_comparison_eq(Instruction test, Operand op, int k, AbstractValue value) {
824+
/**
825+
* Holds if `test` is an instruction that is part of test that eventually is
826+
* used in a conditional branch.
827+
*/
828+
private predicate relevantUnaryComparison(Instruction test) {
829+
not test instanceof CompareInstruction and
830+
exists(IRType type, ConditionalBranchInstruction branch |
831+
type instanceof IRAddressType or type instanceof IRIntegerType
832+
|
833+
type = test.getResultIRType() and
834+
branch.getCondition() = test
835+
)
836+
or
837+
exists(LogicalNotInstruction logicalNot |
838+
relevantUnaryComparison(logicalNot) and
839+
test = logicalNot.getUnary()
840+
)
841+
}
842+
843+
/**
844+
* Rearrange various simple comparisons into `op == k` form.
845+
*/
846+
private predicate unary_simple_comparison_eq(
847+
Instruction test, Operand op, int k, boolean inNonZeroCase, AbstractValue value
848+
) {
786849
exists(SwitchInstruction switch, CaseEdge case |
787850
test = switch.getExpression() and
788851
op.getDef() = test and
789852
case = value.(MatchValue).getCase() and
790853
exists(switch.getSuccessor(case)) and
791-
case.getValue().toInt() = k
854+
case.getValue().toInt() = k and
855+
inNonZeroCase = false
792856
)
793857
or
794858
// There's no implicit CompareInstruction in files compiled as C since C
795859
// doesn't have implicit boolean conversions. So instead we check whether
796860
// there's a branch on a value of pointer or integer type.
797-
exists(ConditionalBranchInstruction branch, IRType type |
798-
not test instanceof CompareInstruction and
799-
type = test.getResultIRType() and
800-
(type instanceof IRAddressType or type instanceof IRIntegerType) and
801-
test = branch.getCondition() and
802-
op.getDef() = test
803-
|
804-
// We'd like to also include a case such as:
805-
// ```
806-
// k = 1 and
807-
// value.(BooleanValue).getValue() = true
808-
// ```
809-
// but all we know is that the value is non-zero in the true branch.
810-
// So we can only conclude something in the false branch.
861+
relevantUnaryComparison(test) and
862+
op.getDef() = test and
863+
(
864+
k = 1 and
865+
value.(BooleanValue).getValue() = true and
866+
inNonZeroCase = true
867+
or
811868
k = 0 and
812-
value.(BooleanValue).getValue() = false
869+
value.(BooleanValue).getValue() = false and
870+
inNonZeroCase = false
813871
)
814872
}
815873

@@ -821,12 +879,12 @@ private predicate complex_eq(
821879
add_eq(cmp, left, right, k, areEqual, value)
822880
}
823881

824-
private predicate complex_eq(
825-
Instruction test, Operand op, int k, boolean areEqual, AbstractValue value
882+
private predicate unary_complex_eq(
883+
Instruction test, Operand op, int k, boolean areEqual, boolean inNonZeroCase, AbstractValue value
826884
) {
827-
sub_eq(test, op, k, areEqual, value)
885+
unary_sub_eq(test, op, k, areEqual, inNonZeroCase, value)
828886
or
829-
add_eq(test, op, k, areEqual, value)
887+
unary_add_eq(test, op, k, areEqual, inNonZeroCase, value)
830888
}
831889

832890
/*
@@ -1090,16 +1148,20 @@ private predicate sub_eq(
10901148
}
10911149

10921150
// op - x == c => op == (c+x)
1093-
private predicate sub_eq(Instruction test, Operand op, int k, boolean areEqual, AbstractValue value) {
1151+
private predicate unary_sub_eq(
1152+
Instruction test, Operand op, int k, boolean areEqual, boolean inNonZeroCase, AbstractValue value
1153+
) {
1154+
inNonZeroCase = false and
10941155
exists(SubInstruction sub, int c, int x |
1095-
compares_eq(test, sub.getAUse(), c, areEqual, value) and
1156+
unary_compares_eq(test, sub.getAUse(), c, areEqual, inNonZeroCase, value) and
10961157
op = sub.getLeftOperand() and
10971158
x = int_value(sub.getRight()) and
10981159
k = c + x
10991160
)
11001161
or
1162+
inNonZeroCase = false and
11011163
exists(PointerSubInstruction sub, int c, int x |
1102-
compares_eq(test, sub.getAUse(), c, areEqual, value) and
1164+
unary_compares_eq(test, sub.getAUse(), c, areEqual, inNonZeroCase, value) and
11031165
op = sub.getLeftOperand() and
11041166
x = int_value(sub.getRight()) and
11051167
k = c + x
@@ -1153,11 +1215,13 @@ private predicate add_eq(
11531215
}
11541216

11551217
// left + x == right + c => left == right + (c-x)
1156-
private predicate add_eq(
1157-
Instruction test, Operand left, int k, boolean areEqual, AbstractValue value
1218+
private predicate unary_add_eq(
1219+
Instruction test, Operand left, int k, boolean areEqual, boolean inNonZeroCase,
1220+
AbstractValue value
11581221
) {
1222+
inNonZeroCase = false and
11591223
exists(AddInstruction lhs, int c, int x |
1160-
compares_eq(test, lhs.getAUse(), c, areEqual, value) and
1224+
unary_compares_eq(test, lhs.getAUse(), c, areEqual, inNonZeroCase, value) and
11611225
(
11621226
left = lhs.getLeftOperand() and x = int_value(lhs.getRight())
11631227
or
@@ -1166,8 +1230,9 @@ private predicate add_eq(
11661230
k = c - x
11671231
)
11681232
or
1233+
inNonZeroCase = false and
11691234
exists(PointerAddInstruction lhs, int c, int x |
1170-
compares_eq(test, lhs.getAUse(), c, areEqual, value) and
1235+
unary_compares_eq(test, lhs.getAUse(), c, areEqual, inNonZeroCase, value) and
11711236
(
11721237
left = lhs.getLeftOperand() and x = int_value(lhs.getRight())
11731238
or

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ProductFlow.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ module ProductFlow {
546546
Flow1::PathGraph::edges(pred1, succ1, _, _) and
547547
exists(ReturnKindExt returnKind |
548548
succ1.getNode() = returnKind.getAnOutNode(call) and
549-
pred1.getNode().(ReturnNodeExt).getKind() = returnKind
549+
paramReturnNode(_, pred1.asParameterReturnNode(), _, returnKind)
550550
)
551551
}
552552

@@ -574,7 +574,7 @@ module ProductFlow {
574574
Flow2::PathGraph::edges(pred2, succ2, _, _) and
575575
exists(ReturnKindExt returnKind |
576576
succ2.getNode() = returnKind.getAnOutNode(call) and
577-
pred2.getNode().(ReturnNodeExt).getKind() = returnKind
577+
paramReturnNode(_, pred2.asParameterReturnNode(), _, returnKind)
578578
)
579579
}
580580

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
description: Removed unused column from the `folders` and `files` relations
22
compatibility: full
3-
files.rel: reorder files.rel (int id, string name, string simple, string ext, int fromSource) id name
4-
folders.rel: reorder folders.rel (int id, string name, string simple) id name
3+
files.rel: reorder files.rel (@file id, string name, string simple, string ext, int fromSource) id name
4+
folders.rel: reorder folders.rel (@folder id, string name, string simple) id name

cpp/ql/src/Critical/NotInitialised.ql

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ predicate undefinedLocalUse(VariableAccess va) {
5454
// it is hard to tell when a struct or array has been initialized, so we
5555
// ignore them
5656
not isAggregateType(lv.getUnderlyingType()) and
57+
not lv.isStatic() and // static variables are initialized to zero or null by default
5758
not lv.getType().hasName("va_list") and
5859
va = lv.getAnAccess() and
5960
noDefPath(lv, va) and
@@ -70,7 +71,8 @@ predicate uninitialisedGlobal(GlobalVariable gv) {
7071
va = gv.getAnAccess() and
7172
va.isRValue() and
7273
not gv.hasInitializer() and
73-
not gv.hasSpecifier("extern")
74+
not gv.hasSpecifier("extern") and
75+
not gv.isStatic() // static variables are initialized to zero or null by default
7476
)
7577
}
7678

cpp/ql/src/Likely Bugs/Format/NonConstantFormat.qhelp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ in the previous example, one solution is to make the log message a trailing argu
4242
<p>An alternative solution is to allow <code>log_with_timestamp</code> to accept format arguments:</p>
4343
<sample src="NonConstantFormat-2-good.c" />
4444
<p>In this formulation, the non-constant format string to <code>printf</code> has been replaced with
45-
a non-constant format string to <code>vprintf</code>. Semmle will no longer consider the body of
45+
a non-constant format string to <code>vprintf</code>. The analysis will no longer consider the body of
4646
<code>log_with_timestamp</code> to be a problem, and will instead check that every call to
4747
<code>log_with_timestamp</code> passes a constant format string.</p>
4848

cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,19 @@ class AllocaCall extends FunctionCall {
3737
}
3838
}
3939

40+
/**
41+
* Gets an expression associated with a dataflow node.
42+
*/
43+
private Expr getExpr(DataFlow::Node node) {
44+
result = node.asInstruction().getAst()
45+
or
46+
result = node.asOperand().getUse().getAst()
47+
or
48+
result = node.(DataFlow::RawIndirectInstruction).getInstruction().getAst()
49+
or
50+
result = node.(DataFlow::RawIndirectOperand).getOperand().getUse().getAst()
51+
}
52+
4053
/**
4154
* A loop that contains an `alloca` call.
4255
*/
@@ -185,19 +198,6 @@ class LoopWithAlloca extends Stmt {
185198
not this.conditionReachesWithoutUpdate(var, this.(Loop).getCondition())
186199
}
187200

188-
/**
189-
* Gets an expression associated with a dataflow node.
190-
*/
191-
private Expr getExpr(DataFlow::Node node) {
192-
result = node.asInstruction().getAst()
193-
or
194-
result = node.asOperand().getUse().getAst()
195-
or
196-
result = node.(DataFlow::RawIndirectInstruction).getInstruction().getAst()
197-
or
198-
result = node.(DataFlow::RawIndirectOperand).getOperand().getUse().getAst()
199-
}
200-
201201
/**
202202
* Gets a definition that may be the most recent definition of the
203203
* controlling variable `var` before this loop.
@@ -210,7 +210,7 @@ class LoopWithAlloca extends Stmt {
210210
// Phi nodes will be preceded by nodes that represent actual definitions
211211
not result instanceof DataFlow::SsaPhiNode and
212212
// A source is outside the loop if it's not inside the loop
213-
not exists(Expr e | e = this.getExpr(result) | this = getAnEnclosingLoopOfExpr(e))
213+
not exists(Expr e | e = getExpr(result) | this = getAnEnclosingLoopOfExpr(e))
214214
)
215215
}
216216

@@ -221,9 +221,9 @@ class LoopWithAlloca extends Stmt {
221221
private int getAControllingVarInitialValue(Variable var, DataFlow::Node source) {
222222
source = this.getAPrecedingDef(var) and
223223
(
224-
result = this.getExpr(source).getValue().toInt()
224+
result = getExpr(source).getValue().toInt()
225225
or
226-
result = this.getExpr(source).(Assignment).getRValue().getValue().toInt()
226+
result = getExpr(source).(Assignment).getRValue().getValue().toInt()
227227
)
228228
}
229229

cpp/ql/src/Likely Bugs/Memory Management/NtohlArrayNoBound.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class SnprintfSizeExpr extends BufferAccess, FunctionCall {
107107
}
108108

109109
class MemcmpSizeExpr extends BufferAccess, FunctionCall {
110-
MemcmpSizeExpr() { this.getTarget().hasName("Memcmp") }
110+
MemcmpSizeExpr() { this.getTarget().hasName("memcmp") }
111111

112112
override Expr getPointer() {
113113
result = this.getArgument(0) or

cpp/ql/src/Security/CWE/CWE-416/UseOfUniquePointerAfterLifetimeEnds.ql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ where
3030
outlivesFullExpr(c) and
3131
not c.isFromUninstantiatedTemplate(_) and
3232
isUniquePointerDerefFunction(c.getTarget()) and
33+
// Exclude cases where the pointer is implicitly converted to a non-pointer type
34+
not c.getActualType() instanceof IntegralType and
3335
isTemporary(c.getQualifier().getFullyConverted())
3436
select c,
3537
"The underlying unique pointer object is destroyed after the call to '" + c.getTarget() +

0 commit comments

Comments
 (0)