Skip to content

Commit 6fdba62

Browse files
authored
Merge pull request #1121 from jbj/return-stack-allocated-1.20-fixes
Approved by geoffw0
2 parents 13cd7d0 + 111a462 commit 6fdba62

File tree

3 files changed

+68
-2
lines changed

3 files changed

+68
-2
lines changed

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,24 @@ import semmle.code.cpp.dataflow.DataFlow
2222
*/
2323
predicate conservativeDataFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
2424
DataFlow::localFlowStep(n1, n2) and
25-
not n2.asExpr() instanceof FieldAccess
25+
not n2.asExpr() instanceof FieldAccess and
26+
not hasNontrivialConversion(n2.asExpr())
27+
}
28+
29+
/**
30+
* Holds if `e` has a conversion that changes it from lvalue to pointer or
31+
* back. As the data-flow library does not support conversions, we cannot track
32+
* data flow through such expressions.
33+
*/
34+
predicate hasNontrivialConversion(Expr e) {
35+
e instanceof Conversion and not
36+
(
37+
e instanceof Cast
38+
or
39+
e instanceof ParenthesisExpr
40+
)
41+
or
42+
hasNontrivialConversion(e.getConversion())
2643
}
2744

2845
from LocalScopeVariable var, VariableAccess va, ReturnStmt r
@@ -39,9 +56,10 @@ where
3956
or
4057
// The data flow library doesn't support conversions, so here we check that
4158
// the address escapes into some expression `pointerToLocal`, which flows
42-
// in a non-trivial way (one or more steps) to a returned expression.
59+
// in a one or more steps to a returned expression.
4360
exists(Expr pointerToLocal |
4461
variableAddressEscapesTree(va, pointerToLocal.getFullyConverted()) and
62+
not hasNontrivialConversion(pointerToLocal) and
4563
conservativeDataFlowStep+(
4664
DataFlow::exprNode(pointerToLocal),
4765
DataFlow::exprNode(r.getExpr())

cpp/ql/test/query-tests/Likely Bugs/Memory Management/ReturnStackAllocatedMemory/ReturnStackAllocatedMemory.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@
55
| test.cpp:92:2:92:12 | return ... | May return stack-allocated memory from $@. | test.cpp:89:10:89:11 | mc | mc |
66
| test.cpp:112:2:112:12 | return ... | May return stack-allocated memory from $@. | test.cpp:112:9:112:11 | arr | arr |
77
| test.cpp:119:2:119:19 | return ... | May return stack-allocated memory from $@. | test.cpp:119:11:119:13 | arr | arr |
8+
| test.cpp:149:3:149:22 | return ... | May return stack-allocated memory from $@. | test.cpp:149:11:149:21 | threadLocal | threadLocal |
9+
| test.cpp:171:3:171:24 | return ... | May return stack-allocated memory from $@. | test.cpp:170:35:170:41 | myLocal | myLocal |

cpp/ql/test/query-tests/Likely Bugs/Memory Management/ReturnStackAllocatedMemory/test.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,49 @@ char *testArray5()
143143

144144
return arr; // GOOD
145145
}
146+
147+
int *returnThreadLocal() {
148+
thread_local int threadLocal;
149+
return &threadLocal; // GOOD [FALSE POSITIVE]
150+
}
151+
152+
int returnDereferenced() {
153+
int localInt = 2;
154+
int &localRef = localInt;
155+
return localRef; // GOOD
156+
}
157+
158+
typedef unsigned long size_t;
159+
void *memcpy(void *s1, const void *s2, size_t n);
160+
161+
char *returnAfterCopy() {
162+
char localBuf[] = "Data";
163+
static char staticBuf[sizeof(localBuf)];
164+
memcpy(staticBuf, localBuf, sizeof(staticBuf));
165+
return staticBuf; // GOOD
166+
}
167+
168+
void *conversionBeforeDataFlow() {
169+
int myLocal;
170+
void *pointerToLocal = (void *)&myLocal; // has conversion
171+
return pointerToLocal; // BAD
172+
}
173+
174+
void *arrayConversionBeforeDataFlow() {
175+
int localArray[4];
176+
int *pointerToLocal = localArray; // has conversion
177+
return pointerToLocal; // BAD [NOT DETECTED]
178+
}
179+
180+
int &dataFlowThroughReference() {
181+
int myLocal;
182+
int &refToLocal = myLocal; // has conversion
183+
return refToLocal; // BAD [NOT DETECTED]
184+
}
185+
186+
int *&conversionInFlow() {
187+
int myLocal;
188+
int *p = &myLocal;
189+
int *&pRef = p; // has conversion in the middle of data flow
190+
return pRef; // BAD [NOT DETECTED]
191+
}

0 commit comments

Comments
 (0)