Skip to content

Commit aaa230a

Browse files
authored
Merge branch 'main' into SQL_int_sanitizer
2 parents a63bb1b + 062024b commit aaa230a

File tree

290 files changed

+6281
-2661
lines changed

Some content is hidden

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

290 files changed

+6281
-2661
lines changed

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

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,18 @@ predicate callDereferences(FunctionCall fc, int i) {
2626
}
2727

2828
/**
29-
* Holds if evaluation of `op` dereferences `e`.
29+
* Holds if evaluation of `op` dereferences `e` directly.
30+
*
31+
* This predicate does not recurse through function calls or arithmetic operations. To find
32+
* such cases, use `dereferencedByOperation`.
3033
*/
31-
predicate dereferencedByOperation(Expr op, Expr e) {
34+
predicate directDereferencedByOperation(Expr op, Expr e) {
3235
exists(PointerDereferenceExpr deref |
3336
deref.getAChild() = e and
3437
deref = op and
3538
not deref.getParent*() instanceof SizeofOperator
3639
)
3740
or
38-
exists(CrementOperation crement | dereferencedByOperation(e, op) and crement.getOperand() = e)
39-
or
4041
exists(ArrayExpr ae |
4142
(
4243
not ae.getParent() instanceof AddressOfExpr and
@@ -50,6 +51,24 @@ predicate dereferencedByOperation(Expr op, Expr e) {
5051
)
5152
)
5253
or
54+
// ptr->Field
55+
e = op.(FieldAccess).getQualifier() and isClassPointerType(e.getType())
56+
or
57+
// ptr->method()
58+
e = op.(Call).getQualifier() and isClassPointerType(e.getType())
59+
}
60+
61+
/**
62+
* Holds if evaluation of `op` dereferences `e`.
63+
*
64+
* This includes the set of operations identified via `directDereferencedByOperation`, as well
65+
* as calls to function that are known to dereference an argument.
66+
*/
67+
predicate dereferencedByOperation(Expr op, Expr e) {
68+
directDereferencedByOperation(op, e)
69+
or
70+
exists(CrementOperation crement | dereferencedByOperation(e, op) and crement.getOperand() = e)
71+
or
5372
exists(AddressOfExpr addof, ArrayExpr ae |
5473
dereferencedByOperation(addof, op) and
5574
addof.getOperand() = ae and
@@ -74,12 +93,6 @@ predicate dereferencedByOperation(Expr op, Expr e) {
7493
e = fc.getArgument(i) and
7594
op = fc
7695
)
77-
or
78-
// ptr->Field
79-
e = op.(FieldAccess).getQualifier() and isClassPointerType(e.getType())
80-
or
81-
// ptr->method()
82-
e = op.(Call).getQualifier() and isClassPointerType(e.getType())
8396
}
8497

8598
private predicate isClassPointerType(Type t) {

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,13 @@ private module GetConvertedResultExpression {
11131113
result = tas.getExtent().getExpr() and
11141114
instr = tas.getInstruction(any(AllocationExtentConvertTag tag))
11151115
)
1116+
or
1117+
// There's no instruction that returns `ParenthesisExpr`, but some queries
1118+
// expect this
1119+
exists(TranslatedTransparentConversion ttc |
1120+
result = ttc.getExpr().(ParenthesisExpr) and
1121+
instr = ttc.getResult()
1122+
)
11161123
}
11171124

11181125
private Expr getConvertedResultExpressionImpl(Instruction instr) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,7 @@ predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) {
766766
or
767767
exists(PhiNode phiTo |
768768
phi != phiTo and
769-
lastRefRedefExt(phi, _, _, phiTo) and
769+
lastRefRedefExt(phi, bb1, i1, phiTo) and
770770
nodeTo.(SsaPhiNode).getPhiNode() = phiTo
771771
)
772772
)

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,9 @@ abstract class TranslatedElement extends TTranslatedElement {
824824
/** DEPRECATED: Alias for getAst */
825825
deprecated Locatable getAST() { result = this.getAst() }
826826

827+
/** Gets the location of this element. */
828+
Location getLocation() { result = this.getAst().getLocation() }
829+
827830
/**
828831
* Get the first instruction to be executed in the evaluation of this element.
829832
*/

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedGlobalVar.qll

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ class TranslatedStaticStorageDurationVarInit extends TranslatedRootElement,
2222

2323
final override Declaration getFunction() { result = var }
2424

25-
final Location getLocation() { result = var.getLocation() }
26-
2725
override Instruction getFirstInstruction() { result = this.getInstruction(EnterFunctionTag()) }
2826

2927
override TranslatedElement getChild(int n) {

cpp/ql/src/Critical/FlowAfterFree.qll

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,11 @@ module FlowFromFree<isSinkSig/2 isASink, isExcludedSig/2 isExcluded> {
9898
* is being freed by a deallocation expression `dealloc`.
9999
*/
100100
predicate isFree(DataFlow::Node n, Expr e, DeallocationExpr dealloc) {
101-
e = dealloc.getFreedExpr() and
102-
e = n.asExpr() and
101+
exists(Expr conv |
102+
e = conv.getUnconverted() and
103+
conv = dealloc.getFreedExpr().getFullyConverted() and
104+
conv = n.asConvertedExpr()
105+
) and
103106
// Ignore realloc functions
104107
not exists(dealloc.(FunctionCall).getTarget().(AllocationFunction).getReallocPtrArg())
105108
}

cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ deprecated class PossibleYearArithmeticOperationCheckConfiguration extends Taint
296296
}
297297

298298
override predicate isSource(DataFlow::Node source) {
299-
exists(Operation op | op = source.asConvertedExpr() |
299+
exists(Operation op | op = source.asExpr() |
300300
op.getAChild*().getValue().toInt() = 365 and
301301
(
302302
not op.getParent() instanceof Expr or
@@ -321,7 +321,7 @@ deprecated class PossibleYearArithmeticOperationCheckConfiguration extends Taint
321321

322322
override predicate isSink(DataFlow::Node sink) {
323323
exists(StructLikeClass dds, FieldAccess fa, AssignExpr aexpr |
324-
aexpr.getRValue() = sink.asConvertedExpr()
324+
aexpr.getRValue() = sink.asExpr()
325325
|
326326
(dds instanceof PackedTimeType or dds instanceof UnpackedTimeType) and
327327
fa.getQualifier().getUnderlyingType() = dds and
@@ -336,7 +336,7 @@ deprecated class PossibleYearArithmeticOperationCheckConfiguration extends Taint
336336
*/
337337
private module PossibleYearArithmeticOperationCheckConfig implements DataFlow::ConfigSig {
338338
predicate isSource(DataFlow::Node source) {
339-
exists(Operation op | op = source.asConvertedExpr() |
339+
exists(Operation op | op = source.asExpr() |
340340
op.getAChild*().getValue().toInt() = 365 and
341341
(
342342
not op.getParent() instanceof Expr or
@@ -361,7 +361,7 @@ private module PossibleYearArithmeticOperationCheckConfig implements DataFlow::C
361361

362362
predicate isSink(DataFlow::Node sink) {
363363
exists(StructLikeClass dds, FieldAccess fa, AssignExpr aexpr |
364-
aexpr.getRValue() = sink.asConvertedExpr()
364+
aexpr.getRValue() = sink.asExpr()
365365
|
366366
(dds instanceof PackedTimeType or dds instanceof UnpackedTimeType) and
367367
fa.getQualifier().getUnderlyingType() = dds and
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @name Count AST inconsistencies
3+
* @description Counts the various AST inconsistencies that may occur.
4+
* This query is for internal use only and may change without notice.
5+
* @kind table
6+
* @id cpp/count-ast-inconsistencies
7+
*/
8+
9+
import cpp
10+
11+
predicate hasDuplicateFunctionEntryPointLocation(Function func) {
12+
count(func.getEntryPoint().getLocation()) > 1
13+
}
14+
15+
predicate hasDuplicateFunctionEntryPoint(Function func) { count(func.getEntryPoint()) > 1 }
16+
17+
select count(Function f | hasDuplicateFunctionEntryPoint(f) | f) as duplicateFunctionEntryPoint,
18+
count(Function f | hasDuplicateFunctionEntryPointLocation(f) | f) as duplicateFunctionEntryPointLocation
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>
7+
Using an object after its lifetime has ended results in undefined behavior.
8+
When an object's lifetime has ended it relinquishes ownership of its resources and the memory it occupied may be reused for other purposes.
9+
If the object is accessed after its lifetime has ended, the program may crash or behave in unexpected ways.
10+
</p>
11+
12+
</overview>
13+
<recommendation>
14+
15+
<p>
16+
Ensure that no object is accessed after its lifetime has ended.
17+
Use RAII ("Resource Acquisition Is Initialization") to manage the lifetime of objects, and avoid manual memory management, if possible.
18+
</p>
19+
20+
</recommendation>
21+
<example>
22+
<p>
23+
The following two examples demonstrate common lifetime violations when working with the C++ standard library.
24+
</p>
25+
26+
<p>
27+
The <code>bad_call_c_api</code> function contains a use of an expired lifetime.
28+
First, a temporary object of type <code>std::string</code> is constructed, and a pointer to its internal buffer is stored in a local variable.
29+
Once the <code>c_str()</code> call returns, the temporary object is destroyed, and the memory pointed to by <code>p</code> is freed.
30+
Thus, any attempt to dereference <code>p</code> inside <code>c_api</code> will result in a use-after-free vulnerability.
31+
32+
The <code>good_call_c_api</code> function contains a fixed version of the first example.
33+
The variable <code>hello</code> is declared as a local variable, and the pointer to its internal buffer is stored in <code>p</code>.
34+
The lifetime of hello outlives the call to <code>c_api</code>, so the pointer stored in <code>p</code> remains valid throughout the call to <code>c_api</code>.
35+
</p>
36+
<sample src="UseAfterExpiredLifetime_c_api_call.cpp" />
37+
38+
<p>
39+
The <code>bad_remove_even_numbers</code> function demonstrates a potential issue with iterator invalidation.
40+
Each C++ standard library container comes with a specification of which operations invalidates iterators pointing into the container.
41+
For example, calling <code>erase</code> on an object of type <code>std::vector&lt;T&gt;</code> invalidates all its iterators, and thus any attempt to dereference the iterator can result in a use-after-free vulnerability.
42+
43+
The <code>good_remove_even_numbers</code> function contains a fixd version of the third example.
44+
The <code>erase</code> function returns an iterator to the element following the last element removed, and this return value is used to ensure that <code>it</code> remains valid after the call to <code>erase</code>.
45+
</p>
46+
<sample src="UseAfterExpiredLifetime_iterator_invalidation.cpp" />
47+
48+
</example>
49+
<references>
50+
51+
<li>CERT C Coding Standard:
52+
<a href="https://wiki.sei.cmu.edu/confluence/display/c/MEM30-C.+Do+not+access+freed+memory">MEM30-C. Do not access freed memory</a>.</li>
53+
<li>
54+
OWASP:
55+
<a href="https://owasp.org/www-community/vulnerabilities/Using_freed_memory">Using freed memory</a>.
56+
</li>
57+
<li>
58+
<a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/docs/Lifetime.pdf">Lifetime safety: Preventing common dangling</a>
59+
</li>
60+
<li>
61+
<a href="https://en.cppreference.com/w/cpp/container">Containers library</a>
62+
</li>
63+
<li>
64+
<a href="https://en.cppreference.com/w/cpp/language/raii">RAII</a>
65+
</li>
66+
67+
</references>
68+
</qhelp>

0 commit comments

Comments
 (0)