Skip to content

Commit b4d762f

Browse files
authored
Merge branch 'main' into experimental-manually-check-request-verb
2 parents c2710fb + 0a35f97 commit b4d762f

File tree

16 files changed

+813
-406
lines changed

16 files changed

+813
-406
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: fix
3+
---
4+
* Under certain circumstances a variable declaration that is not also a definition could be associated with a `Variable` that did not have the definition as a `VariableDeclarationEntry`. This is now fixed, and a unique `Variable` will exist that has both the declaration and the definition as a `VariableDeclarationEntry`.

cpp/ql/lib/semmle/code/cpp/Element.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import semmle.code.cpp.Location
77
private import semmle.code.cpp.Enclosing
88
private import semmle.code.cpp.internal.ResolveClass
9+
private import semmle.code.cpp.internal.ResolveGlobalVariable
910

1011
/**
1112
* Get the `Element` that represents this `@element`.
@@ -28,9 +29,12 @@ Element mkElement(@element e) { unresolveElement(result) = e }
2829
pragma[inline]
2930
@element unresolveElement(Element e) {
3031
not result instanceof @usertype and
32+
not result instanceof @variable and
3133
result = e
3234
or
3335
e = resolveClass(result)
36+
or
37+
e = resolveGlobalVariable(result)
3438
}
3539

3640
/**

cpp/ql/lib/semmle/code/cpp/Variable.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import semmle.code.cpp.Element
66
import semmle.code.cpp.exprs.Access
77
import semmle.code.cpp.Initializer
88
private import semmle.code.cpp.internal.ResolveClass
9+
private import semmle.code.cpp.internal.ResolveGlobalVariable
910

1011
/**
1112
* A C/C++ variable. For example, in the following code there are four
@@ -32,6 +33,8 @@ private import semmle.code.cpp.internal.ResolveClass
3233
* can have multiple declarations.
3334
*/
3435
class Variable extends Declaration, @variable {
36+
Variable() { isVariable(underlyingElement(this)) }
37+
3538
override string getAPrimaryQlClass() { result = "Variable" }
3639

3740
/** Gets the initializer of this variable, if any. */
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
private predicate hasDefinition(@globalvariable g) {
2+
exists(@var_decl vd | var_decls(vd, g, _, _, _) | var_def(vd))
3+
}
4+
5+
pragma[noinline]
6+
private predicate onlyOneCompleteGlobalVariableExistsWithMangledName(@mangledname name) {
7+
strictcount(@globalvariable g | hasDefinition(g) and mangled_name(g, name)) = 1
8+
}
9+
10+
/** Holds if `g` is a unique global variable with a definition named `name`. */
11+
pragma[noinline]
12+
private predicate isGlobalWithMangledNameAndWithDefinition(@mangledname name, @globalvariable g) {
13+
hasDefinition(g) and
14+
mangled_name(g, name) and
15+
onlyOneCompleteGlobalVariableExistsWithMangledName(name)
16+
}
17+
18+
/** Holds if `g` is a global variable without a definition named `name`. */
19+
pragma[noinline]
20+
private predicate isGlobalWithMangledNameAndWithoutDefinition(@mangledname name, @globalvariable g) {
21+
not hasDefinition(g) and
22+
mangled_name(g, name)
23+
}
24+
25+
/**
26+
* Holds if `incomplete` is a global variable without a definition, and there exists
27+
* a unique global variable `complete` with the same name that does have a definition.
28+
*/
29+
private predicate hasTwinWithDefinition(@globalvariable incomplete, @globalvariable complete) {
30+
exists(@mangledname name |
31+
not variable_instantiation(incomplete, complete) and
32+
isGlobalWithMangledNameAndWithoutDefinition(name, incomplete) and
33+
isGlobalWithMangledNameAndWithDefinition(name, complete)
34+
)
35+
}
36+
37+
import Cached
38+
39+
cached
40+
private module Cached {
41+
/**
42+
* If `v` is a global variable without a definition, and there exists a unique
43+
* global variable with the same name that does have a definition, then the
44+
* result is that unique global variable. Otherwise, the result is `v`.
45+
*/
46+
cached
47+
@variable resolveGlobalVariable(@variable v) {
48+
hasTwinWithDefinition(v, result)
49+
or
50+
not hasTwinWithDefinition(v, _) and
51+
result = v
52+
}
53+
54+
cached
55+
predicate isVariable(@variable v) {
56+
not v instanceof @globalvariable
57+
or
58+
v = resolveGlobalVariable(_)
59+
}
60+
}

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,12 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
7474

7575
from
7676
MustFlowPathNode source, MustFlowPathNode sink, VariableAddressInstruction var,
77-
ReturnStackAllocatedMemoryConfig conf, Function f
77+
ReturnStackAllocatedMemoryConfig conf
7878
where
79-
conf.hasFlowPath(source, sink) and
79+
conf.hasFlowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and
8080
source.getNode().asInstruction() = var and
8181
// Only raise an alert if we're returning from the _same_ callable as the on that
8282
// declared the stack variable.
83-
var.getEnclosingFunction() = pragma[only_bind_into](f) and
84-
sink.getNode().getEnclosingCallable() = pragma[only_bind_into](f)
83+
var.getEnclosingFunction() = sink.getNode().getEnclosingCallable()
8584
select sink.getNode(), source, sink, "May return stack-allocated memory from $@.", var.getAst(),
8685
var.getAst().toString()

cpp/ql/test/library-tests/variables/global/variables.expected

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@
44
| c.c:6:5:6:6 | ls | array of 4 {int} | 1 |
55
| c.c:8:5:8:7 | iss | array of 4 {array of 2 {int}} | 1 |
66
| c.c:12:11:12:11 | i | typedef {int} as "int_alias" | 1 |
7-
| c.h:4:12:4:13 | ks | array of {int} | 1 |
8-
| c.h:8:12:8:14 | iss | array of {array of 2 {int}} | 1 |
9-
| c.h:10:12:10:12 | i | int | 1 |
107
| d.cpp:3:7:3:8 | xs | array of {int} | 1 |
11-
| d.h:3:14:3:15 | xs | array of 2 {int} | 1 |
128
| file://:0:0:0:0 | (unnamed parameter 0) | reference to {const {struct __va_list_tag}} | 1 |
139
| file://:0:0:0:0 | (unnamed parameter 0) | rvalue reference to {struct __va_list_tag} | 1 |
1410
| file://:0:0:0:0 | fp_offset | unsigned int | 1 |

0 commit comments

Comments
 (0)