Skip to content

Commit 03b77db

Browse files
committed
C++: Make 'node.asExpr()' behave as 'node.asDefinition()' in void contexts.
1 parent 359b15b commit 03b77db

File tree

4 files changed

+42
-19
lines changed

4 files changed

+42
-19
lines changed

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

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,7 +1214,7 @@ private module GetConvertedResultExpression {
12141214
// represents the extent.
12151215
exists(TranslatedNonConstantAllocationSize tas |
12161216
result = tas.getExtent().getExpr() and
1217-
instr = tas.getInstruction(any(AllocationExtentConvertTag tag))
1217+
instr = tas.getInstruction(AllocationExtentConvertTag())
12181218
)
12191219
or
12201220
// There's no instruction that returns `ParenthesisExpr`, but some queries
@@ -1223,6 +1223,39 @@ private module GetConvertedResultExpression {
12231223
result = ttc.getExpr().(ParenthesisExpr) and
12241224
instr = ttc.getResult()
12251225
)
1226+
or
1227+
// Certain expressions generate `CopyValueInstruction`s only when they
1228+
// are needed. Examples of this include crement operations and compound
1229+
// assignment operations. For example:
1230+
// ```cpp
1231+
// int x = ...
1232+
// int y = x++;
1233+
// ```
1234+
// this generate IR like:
1235+
// ```
1236+
// r1(glval<int>) = VariableAddress[x] :
1237+
// r2(int) = Constant[0] :
1238+
// m3(int) = Store[x] : &:r1, r2
1239+
// r4(glval<int>) = VariableAddress[y] :
1240+
// r5(glval<int>) = VariableAddress[x] :
1241+
// r6(int) = Load[x] : &:r5, m3
1242+
// r7(int) = Constant[1] :
1243+
// r8(int) = Add : r6, r7
1244+
// m9(int) = Store[x] : &:r5, r8
1245+
// r11(int) = CopyValue : r6
1246+
// m12(int) = Store[y] : &:r4, r11
1247+
// ```
1248+
// When the `CopyValueInstruction` is not generated there is no instruction
1249+
// whose `getConvertedResultExpression` maps back to the expression. When
1250+
// such an instruction doesn't exist it means that the old value is not
1251+
// needed, and in that case the only value that will propagate forward in
1252+
// the program is the value that's been updated. So in those cases we just
1253+
// use the result of `node.asDefinition()` as the result of `node.asExpr()`.
1254+
exists(TranslatedCoreExpr tco |
1255+
tco.getInstruction(_) = instr and
1256+
tco.producesExprResult() and
1257+
result = asDefinitionImpl0(instr)
1258+
)
12261259
}
12271260

12281261
private Expr getConvertedResultExpressionImpl(Instruction instr) {
@@ -1242,15 +1275,15 @@ private module GetConvertedResultExpression {
12421275
// `StoreInstruction` contains the result of the expression even though
12431276
// this isn't totally aligned with the C/C++ standard.
12441277
exists(TranslatedAssignOperation tao |
1245-
store = tao.getInstruction(any(AssignmentStoreTag tag)) and
1278+
store = tao.getInstruction(AssignmentStoreTag()) and
12461279
result = tao.getExpr()
12471280
)
12481281
or
12491282
// Similarly for `i++` and `++i` we pretend that the generated
12501283
// `StoreInstruction` is contains the result of the expression even though
12511284
// this isn't totally aligned with the C/C++ standard.
12521285
exists(TranslatedCrementOperation tco |
1253-
store = tco.getInstruction(any(CrementStoreTag tag)) and
1286+
store = tco.getInstruction(CrementStoreTag()) and
12541287
result = tco.getExpr()
12551288
)
12561289
}
@@ -2065,12 +2098,7 @@ module ExprFlowCached {
20652098
isIndirectBaseOfArrayAccess(n, result)
20662099
or
20672100
not isIndirectBaseOfArrayAccess(n, _) and
2068-
(
2069-
result = n.asExpr()
2070-
or
2071-
result = n.asDefinition() and
2072-
(result instanceof CrementOperation or result instanceof AssignOperation)
2073-
)
2101+
result = n.asExpr()
20742102
}
20752103

20762104
/**

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ predicate cannotContainString(Type t, boolean isIndirect) {
6868

6969
predicate isNonConst(DataFlow::Node node, boolean isIndirect) {
7070
exists(Expr e |
71-
e = [node.asExpr(), node.asDefinition()] and isIndirect = false
71+
e = [node.asExpr()] and isIndirect = false
7272
or
73-
e = [node.asIndirectExpr(), node.asIndirectDefinition()] and isIndirect = true
73+
e = [node.asIndirectExpr()] and isIndirect = true
7474
|
7575
exists(FunctionCall fc | fc = e |
7676
not (

cpp/ql/src/Security/CWE/CWE-190/IntegerOverflowTainted.ql

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,8 @@ predicate isSink(DataFlow::Node sink, string kind) {
3737
exists(Expr use |
3838
not use.getUnspecifiedType() instanceof PointerType and
3939
outOfBoundsExpr(use, kind) and
40-
not inSystemMacroExpansion(use)
41-
|
42-
if
43-
sink.asDefinition() instanceof CrementOperation or
44-
sink.asDefinition() instanceof AssignOperation
45-
then use = sink.asDefinition()
46-
else use = sink.asExpr()
40+
not inSystemMacroExpansion(use) and
41+
use = sink.asExpr()
4742
)
4843
}
4944

cpp/ql/src/Security/CWE/CWE-190/TaintedAllocationSize.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ module TaintedAllocationSizeConfig implements DataFlow::ConfigSig {
6060
predicate isSink(DataFlow::Node sink) { allocSink(_, sink) }
6161

6262
predicate isBarrier(DataFlow::Node node) {
63-
exists(Expr e | e = [node.asExpr(), node.asDefinition()] |
63+
exists(Expr e | e = node.asExpr() |
6464
// There can be two separate reasons for `convertedExprMightOverflow` not holding:
6565
// 1. `e` really cannot overflow.
6666
// 2. `e` isn't analyzable.

0 commit comments

Comments
 (0)