Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e28a45b

Browse files
author
Robert Marsh
committed
Merge branch 'main' into rdmarsh2/cpp/output-iterators-1
Resolve test output conflicts from IR model improvements
2 parents 772a515 + 475519c commit e28a45b

181 files changed

Lines changed: 7323 additions & 1697 deletions

File tree

Some content is hidden

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

change-notes/1.26/analysis-cpp.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ The following changes in version 1.26 affect C/C++ analysis in all applications.
2323
* The QL class `Block`, denoting the `{ ... }` statement, is renamed to `BlockStmt`.
2424
* The models library now models many taint flows through `std::array`, `std::vector`, `std::deque`, `std::list` and `std::forward_list`.
2525
* The models library now models many more taint flows through `std::string`.
26-
* The models library now models some taint flows through `std::ostream`.
26+
* The models library now models many taint flows through `std::istream` and `std::ostream`.
2727
* The models library now models some taint flows through `std::shared_ptr`, `std::unique_ptr`, `std::make_shared` and `std::make_unique`.
2828
* The `SimpleRangeAnalysis` library now supports multiplications of the form
2929
`e1 * e2` and `x *= e2` when `e1` and `e2` are unsigned or constant.

change-notes/1.26/analysis-javascript.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
* Support for the following frameworks and libraries has been improved:
66
- [bluebird](https://www.npmjs.com/package/bluebird)
7+
- [express](https://www.npmjs.com/package/express)
78
- [fast-json-stable-stringify](https://www.npmjs.com/package/fast-json-stable-stringify)
89
- [fast-safe-stringify](https://www.npmjs.com/package/fast-safe-stringify)
10+
- [http](https://nodejs.org/api/http.html)
911
- [javascript-stringify](https://www.npmjs.com/package/javascript-stringify)
1012
- [js-stringify](https://www.npmjs.com/package/js-stringify)
1113
- [json-stable-stringify](https://www.npmjs.com/package/json-stable-stringify)
@@ -18,6 +20,7 @@
1820
- [underscore](https://www.npmjs.com/package/underscore)
1921

2022
* Analyzing files with the ".cjs" extension is now supported.
23+
* ES2021 features are now supported.
2124

2225
## New queries
2326

config/identical-files.json

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@
5050
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll",
5151
"python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll"
5252
],
53+
"SsaReadPosition Java/C#": [
54+
"java/ql/src/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
55+
"csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
56+
],
57+
"Sign Java/C#": [
58+
"java/ql/src/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll",
59+
"csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll"
60+
],
61+
"SignAnalysis Java/C#": [
62+
"java/ql/src/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll",
63+
"csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisCommon.qll"
64+
],
5365
"C++ SubBasicBlocks": [
5466
"cpp/ql/src/semmle/code/cpp/controlflow/SubBasicBlocks.qll",
5567
"cpp/ql/src/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll"
@@ -87,7 +99,7 @@
8799
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll",
88100
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll",
89101
"csharp/ql/src/experimental/ir/implementation/raw/Operand.qll",
90-
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll"
102+
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll"
91103
],
92104
"IR IRType": [
93105
"cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll",
@@ -109,11 +121,11 @@
109121
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll",
110122
"csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll"
111123
],
112-
"IR TInstruction":[
124+
"IR TInstruction": [
113125
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll",
114126
"csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll"
115127
],
116-
"IR TIRVariable":[
128+
"IR TIRVariable": [
117129
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll",
118130
"csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll"
119131
],
@@ -381,4 +393,4 @@
381393
"javascript/ql/src/Comments/CommentedOutCodeReferences.qhelp",
382394
"python/ql/src/Lexical/CommentedOutCodeReferences.qhelp"
383395
]
384-
}
396+
}

cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -279,20 +279,62 @@ private predicate reachableRecursive(ControlFlowNode n) {
279279
reachableRecursive(n.getAPredecessor())
280280
}
281281

282+
/** Holds if `e` is a compile time constant with integer value `val`. */
282283
private predicate compileTimeConstantInt(Expr e, int val) {
283-
val = e.getFullyConverted().getValue().toInt() and
284-
not e instanceof StringLiteral and
285-
not exists(Expr e1 | e1.getConversion() = e) // only values for fully converted expressions
284+
(
285+
// If we have an integer value then we are done.
286+
if exists(e.getValue().toInt())
287+
then val = e.getValue().toInt()
288+
else
289+
// Otherwise, if we are a conversion of another expression with an
290+
// integer value, and that value can be converted into our type,
291+
// then we have that value.
292+
exists(Expr x, int valx |
293+
x.getConversion() = e and
294+
compileTimeConstantInt(x, valx) and
295+
val = convertIntToType(valx, e.getType().getUnspecifiedType())
296+
)
297+
) and
298+
// If our unconverted expression is a string literal `"123"`, then we
299+
// do not have integer value `123`.
300+
not e.getUnconverted() instanceof StringLiteral
286301
}
287302

288-
library class CompileTimeConstantInt extends Expr {
289-
CompileTimeConstantInt() { compileTimeConstantInt(this, _) }
303+
/**
304+
* Get `val` represented as type `t`, if that is possible without
305+
* overflow or underflows.
306+
*/
307+
bindingset[val, t]
308+
private int convertIntToType(int val, IntegralType t) {
309+
if t instanceof BoolType
310+
then if val = 0 then result = 0 else result = 1
311+
else
312+
if t.isUnsigned()
313+
then if val >= 0 and val.bitShiftRight(t.getSize() * 8) = 0 then result = val else none()
314+
else
315+
if val >= 0 and val.bitShiftRight(t.getSize() * 8 - 1) = 0
316+
then result = val
317+
else
318+
if (-(val + 1)).bitShiftRight(t.getSize() * 8 - 1) = 0
319+
then result = val
320+
else none()
321+
}
322+
323+
/**
324+
* INTERNAL: Do not use.
325+
* An expression that has been found to have an integer value at compile
326+
* time.
327+
*/
328+
class CompileTimeConstantInt extends Expr {
329+
int val;
330+
331+
CompileTimeConstantInt() { compileTimeConstantInt(this.getFullyConverted(), val) }
290332

291-
int getIntValue() { compileTimeConstantInt(this, result) }
333+
int getIntValue() { result = val }
292334
}
293335

294336
library class CompileTimeVariableExpr extends Expr {
295-
CompileTimeVariableExpr() { not compileTimeConstantInt(this, _) }
337+
CompileTimeVariableExpr() { not this instanceof CompileTimeConstantInt }
296338
}
297339

298340
/** A helper class for evaluation of expressions. */

cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,9 +264,6 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
264264
t instanceof Union
265265
or
266266
t instanceof ArrayType
267-
or
268-
// Buffers of unknown size
269-
t instanceof UnknownType
270267
)
271268
or
272269
exists(BinaryInstruction bin |

cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

Lines changed: 157 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -197,28 +197,37 @@ private class CollectionContent extends Content, TCollectionContent {
197197
}
198198

199199
private class ArrayContent extends Content, TArrayContent {
200-
override string toString() { result = "array" }
200+
ArrayContent() { this = TArrayContent() }
201+
202+
override string toString() { result = "array content" }
201203
}
202204

203-
private predicate storeStepNoChi(Node node1, Content f, PostUpdateNode node2) {
205+
private predicate fieldStoreStepNoChi(Node node1, FieldContent f, PostUpdateNode node2) {
204206
exists(StoreInstruction store, Class c |
205207
store = node2.asInstruction() and
206208
store.getSourceValue() = node1.asInstruction() and
207209
getWrittenField(store, f.(FieldContent).getAField(), c) and
208-
f.(FieldContent).hasOffset(c, _, _)
210+
f.hasOffset(c, _, _)
209211
)
210212
}
211213

214+
private FieldAddressInstruction getFieldInstruction(Instruction instr) {
215+
result = instr or
216+
result = instr.(CopyValueInstruction).getUnary()
217+
}
218+
212219
pragma[noinline]
213-
private predicate getWrittenField(StoreInstruction store, Field f, Class c) {
220+
private predicate getWrittenField(Instruction instr, Field f, Class c) {
214221
exists(FieldAddressInstruction fa |
215-
fa = store.getDestinationAddress() and
222+
fa =
223+
getFieldInstruction([instr.(StoreInstruction).getDestinationAddress(),
224+
instr.(WriteSideEffectInstruction).getDestinationAddress()]) and
216225
f = fa.getField() and
217226
c = f.getDeclaringType()
218227
)
219228
}
220229

221-
private predicate storeStepChi(Node node1, Content f, PostUpdateNode node2) {
230+
private predicate fieldStoreStepChi(Node node1, FieldContent f, PostUpdateNode node2) {
222231
exists(StoreInstruction store, ChiInstruction chi |
223232
node1.asInstruction() = store and
224233
node2.asInstruction() = chi and
@@ -227,23 +236,59 @@ private predicate storeStepChi(Node node1, Content f, PostUpdateNode node2) {
227236
c = chi.getResultType() and
228237
exists(int startBit, int endBit |
229238
chi.getUpdatedInterval(startBit, endBit) and
230-
f.(FieldContent).hasOffset(c, startBit, endBit)
239+
f.hasOffset(c, startBit, endBit)
231240
)
232241
or
233-
getWrittenField(store, f.(FieldContent).getAField(), c) and
234-
f.(FieldContent).hasOffset(c, _, _)
242+
getWrittenField(store, f.getAField(), c) and
243+
f.hasOffset(c, _, _)
235244
)
236245
)
237246
}
238247

248+
private predicate arrayStoreStepChi(Node node1, ArrayContent a, PostUpdateNode node2) {
249+
a = TArrayContent() and
250+
exists(StoreInstruction store |
251+
node1.asInstruction() = store and
252+
(
253+
// `x[i] = taint()`
254+
// This matches the characteristic predicate in `ArrayStoreNode`.
255+
store.getDestinationAddress() instanceof PointerAddInstruction
256+
or
257+
// `*p = taint()`
258+
// This matches the characteristic predicate in `PointerStoreNode`.
259+
store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction
260+
) and
261+
// This `ChiInstruction` will always have a non-conflated result because both `ArrayStoreNode`
262+
// and `PointerStoreNode` require it in their characteristic predicates.
263+
node2.asInstruction().(ChiInstruction).getPartial() = store
264+
)
265+
}
266+
239267
/**
240268
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
241269
* Thus, `node2` references an object with a field `f` that contains the
242270
* value of `node1`.
243271
*/
244272
predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
245-
storeStepNoChi(node1, f, node2) or
246-
storeStepChi(node1, f, node2)
273+
fieldStoreStepNoChi(node1, f, node2) or
274+
fieldStoreStepChi(node1, f, node2) or
275+
arrayStoreStepChi(node1, f, node2) or
276+
fieldStoreStepAfterArraySuppression(node1, f, node2)
277+
}
278+
279+
// This predicate pushes the correct `FieldContent` onto the access path when the
280+
// `suppressArrayRead` predicate has popped off an `ArrayContent`.
281+
private predicate fieldStoreStepAfterArraySuppression(
282+
Node node1, FieldContent f, PostUpdateNode node2
283+
) {
284+
exists(BufferMayWriteSideEffectInstruction write, ChiInstruction chi, Class c |
285+
not chi.isResultConflated() and
286+
node1.asInstruction() = chi and
287+
node2.asInstruction() = chi and
288+
chi.getPartial() = write and
289+
getWrittenField(write, f.getAField(), c) and
290+
f.hasOffset(c, _, _)
291+
)
247292
}
248293

249294
bindingset[result, i]
@@ -263,23 +308,120 @@ private predicate getLoadedField(LoadInstruction load, Field f, Class c) {
263308
* Thus, `node1` references an object with a field `f` whose value ends up in
264309
* `node2`.
265310
*/
266-
predicate readStep(Node node1, Content f, Node node2) {
311+
private predicate fieldReadStep(Node node1, FieldContent f, Node node2) {
267312
exists(LoadInstruction load |
268313
node2.asInstruction() = load and
269314
node1.asInstruction() = load.getSourceValueOperand().getAnyDef() and
270315
exists(Class c |
271316
c = load.getSourceValueOperand().getAnyDef().getResultType() and
272317
exists(int startBit, int endBit |
273318
load.getSourceValueOperand().getUsedInterval(unbindInt(startBit), unbindInt(endBit)) and
274-
f.(FieldContent).hasOffset(c, startBit, endBit)
319+
f.hasOffset(c, startBit, endBit)
275320
)
276321
or
277-
getLoadedField(load, f.(FieldContent).getAField(), c) and
278-
f.(FieldContent).hasOffset(c, _, _)
322+
getLoadedField(load, f.getAField(), c) and
323+
f.hasOffset(c, _, _)
324+
)
325+
)
326+
}
327+
328+
/**
329+
* When a store step happens in a function that looks like an array write such as:
330+
* ```cpp
331+
* void f(int* pa) {
332+
* pa = source();
333+
* }
334+
* ```
335+
* it can be a write to an array, but it can also happen that `f` is called as `f(&a.x)`. If that is
336+
* the case, the `ArrayContent` that was written by the call to `f` should be popped off the access
337+
* path, and a `FieldContent` containing `x` should be pushed instead.
338+
* So this case pops `ArrayContent` off the access path, and the `fieldStoreStepAfterArraySuppression`
339+
* predicate in `storeStep` ensures that we push the right `FieldContent` onto the access path.
340+
*/
341+
predicate suppressArrayRead(Node node1, ArrayContent a, Node node2) {
342+
a = TArrayContent() and
343+
exists(BufferMayWriteSideEffectInstruction write, ChiInstruction chi |
344+
node1.asInstruction() = write and
345+
node2.asInstruction() = chi and
346+
chi.getPartial() = write and
347+
getWrittenField(write, _, _)
348+
)
349+
}
350+
351+
private class ArrayToPointerConvertInstruction extends ConvertInstruction {
352+
ArrayToPointerConvertInstruction() {
353+
this.getUnary().getResultType() instanceof ArrayType and
354+
this.getResultType() instanceof PointerType
355+
}
356+
}
357+
358+
private Instruction skipOneCopyValueInstruction(Instruction instr) {
359+
not instr instanceof CopyValueInstruction and result = instr
360+
or
361+
result = instr.(CopyValueInstruction).getUnary()
362+
}
363+
364+
private Instruction skipCopyValueInstructions(Instruction instr) {
365+
result = skipOneCopyValueInstruction*(instr) and not result instanceof CopyValueInstruction
366+
}
367+
368+
private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) {
369+
a = TArrayContent() and
370+
// Explicit dereferences such as `*p` or `p[i]` where `p` is a pointer or array.
371+
exists(LoadInstruction load, Instruction address |
372+
load.getSourceValueOperand().isDefinitionInexact() and
373+
node1.asInstruction() = load.getSourceValueOperand().getAnyDef() and
374+
load = node2.asInstruction() and
375+
address = skipCopyValueInstructions(load.getSourceAddress()) and
376+
(
377+
address instanceof LoadInstruction or
378+
address instanceof ArrayToPointerConvertInstruction or
379+
address instanceof PointerOffsetInstruction
279380
)
280381
)
281382
}
282383

384+
/**
385+
* In cases such as:
386+
* ```cpp
387+
* void f(int* pa) {
388+
* *pa = source();
389+
* }
390+
* ...
391+
* int x;
392+
* f(&x);
393+
* use(x);
394+
* ```
395+
* the load on `x` in `use(x)` will exactly overlap with its definition (in this case the definition
396+
* is a `BufferMayWriteSideEffect`). This predicate pops the `ArrayContent` (pushed by the store in `f`)
397+
* from the access path.
398+
*/
399+
private predicate exactReadStep(Node node1, ArrayContent a, Node node2) {
400+
a = TArrayContent() and
401+
exists(BufferMayWriteSideEffectInstruction write, ChiInstruction chi |
402+
not chi.isResultConflated() and
403+
chi.getPartial() = write and
404+
node1.asInstruction() = write and
405+
node2.asInstruction() = chi and
406+
// To distinquish this case from the `arrayReadStep` case we require that the entire variable was
407+
// overwritten by the `BufferMayWriteSideEffectInstruction` (i.e., there is a load that reads the
408+
// entire variable).
409+
exists(LoadInstruction load | load.getSourceValue() = chi)
410+
)
411+
}
412+
413+
/**
414+
* Holds if data can flow from `node1` to `node2` via a read of `f`.
415+
* Thus, `node1` references an object with a field `f` whose value ends up in
416+
* `node2`.
417+
*/
418+
predicate readStep(Node node1, Content f, Node node2) {
419+
fieldReadStep(node1, f, node2) or
420+
arrayReadStep(node1, f, node2) or
421+
exactReadStep(node1, f, node2) or
422+
suppressArrayRead(node1, f, node2)
423+
}
424+
283425
/**
284426
* Holds if values stored inside content `c` are cleared at node `n`.
285427
*/

0 commit comments

Comments
 (0)