8000 Merge pull request #12125 from jketema/unique-function · github/codeql@9c039c4 · GitHub
[go: up one dir, main page]

Skip to content

Commit 9c039c4

Browse files
authored
Merge pull request #12125 from jketema/unique-function
C++: Ensure that only one `Function` exists for every function
2 parents ecd2003 + 1cb0247 commit 9c039c4

File tree

6 files changed

+72
-4
lines changed

6 files changed

+72
-4
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 function declaration that is not also a definition could be associated with a `Function` that did not have the definition as a `FunctionDeclarationEntry`. This is now fixed when only one definition exists, and a unique `Function` will exist that has both the declaration and the definition as a `FunctionDeclarationEntry`.

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

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

1112
/**
1213
* Get the `Element` that represents this `@element`.
@@ -30,11 +31,14 @@ pragma[inline]
3031
@element unresolveElement(Element e) {
3132
not result instanceof @usertype and
3233
not result instanceof @variable and
34+
not result instanceof @function and
3335
result = e
3436
or
3537
e = resolveClass(result)
3638
or
3739
e = resolveGlobalVariable(result)
40+
or
41+
e = resolveFunction(result)
3842
}
3943

4044
/**

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import semmle.code.cpp.exprs.Call
99
import semmle.code.cpp.metrics.MetricFunction
1010
import semmle.code.cpp.Linkage
1111
private import semmle.code.cpp.internal.ResolveClass
12+
private import semmle.code.cpp.internal.ResolveFunction
1213

1314
/**
1415
* A C/C++ function [N4140 8.3.5]. Both member functions and non-member
@@ -25,6 +26,8 @@ private import semmle.code.cpp.internal.ResolveClass
2526
* in more detail in `Declaration.qll`.
2627
*/
2728
class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
29+
Function() { isFunction(underlyingElement(this)) }
30+
2831
override string getName() { functions(underlyingElement(this), result, _) }
2932

3033
/**

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ private predicate loopConditionAlwaysUponEntry(ControlFlowNode loop, Expr condit
110110
* should be in this relation.
111111
*/
112112
pragma[noinline]
113-
private predicate isFunction(Element el) {
114-
el instanceof Function
113+
private predicate isFunction(@element el) {
114+
el instanceof @function
115115
or
116116
el.(Expr).getParent() = el
117117
}
@@ -122,7 +122,7 @@ private predicate isFunction(Element el) {
122122
*/
123123
pragma[noopt]
124124
private predicate callHasNoTarget(@funbindexpr fc) {
125-
exists(Function f |
125+
exists(@function f |
126126
funbind(fc, f) and
127127
not isFunction(f)
128128
)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
private predicate hasDefinition(@function f) {
2+
exists(@fun_decl fd | fun_decls(fd, f, _, _, _) | fun_def(fd))
3+
}
4+
5+
private predicate onlyOneCompleteFunctionExistsWithMangledName(@mangledname name) {
6+
strictcount(@function f | hasDefinition(f) and mangled_name(f, name)) = 1
7+
}
8+
9+
/** Holds if `f` is a unique function with a definition named `name`. */
10+
private predicate isFunctionWithMangledNameAndWithDefinition(@mangledname name, @function f) {
11+
hasDefinition(f) and
12+
mangled_name(f, name) and
13+
onlyOneCompleteFunctionExistsWithMangledName(name)
14+
}
15+
16+
/** Holds if `f` is a function without a definition named `name`. */
17+
private predicate isFunctionWithMangledNameAndWithoutDefinition(@mangledname name, @function f) {
18+
not hasDefinition(f) and
19+
mangled_name(f, name)
20+
}
21+
22+
/**
23+
* Holds if `incomplete` is a function without a definition, and there exists
24+
* a unique function `complete` with the same name that does have a definition.
25+
*/
26+
private predicate hasTwinWithDefinition(@function incomplete, @function complete) {
27+
not function_instantiation(incomplete, complete) and
28+
(
29+
not compgenerated(incomplete) or
30+
not compgenerated(complete)
31+
) and
32+
exists(@mangledname name |
33+
isFunctionWithMangledNameAndWithoutDefinition(name, incomplete) and
34+
isFunctionWithMangledNameAndWithDefinition(name, complete)
35+
)
36+
}
37+
38+
import Cached
39+
40+
cached
41+
private module Cached {
42+
/**
43+
* If `f` is a function without a definition, and there exists a unique
44+
* function with the same name that does have a definition, then the
45+
* result is that unique function. Otherwise, the result is `f`.
46+
*/
47+
cached
48+
@function resolveFunction(@function f) {
49+
hasTwinWithDefinition(f, result)
50+
or
51+
not hasTwinWithDefinition(f, _) and
52+
result = f
53+
}
54+
55+
cached
56+
predicate isFunction(@function f) { f = resolveFunction(_) }
57+
}

cpp/ql/lib/semmle/code/cpp/internal/ResolveGlobalVariable.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ private predicate isGlobalWithMangledNameAndWithoutDefinition(@mangledname name,
2424
* a unique global variable `complete` with the same name that does have a definition.
2525
*/
2626
private predicate hasTwinWithDefinition(@globalvariable incomplete, @globalvariable complete) {
27+
not variable_instantiation(incomplete, complete) and
2728
exists(@mangledname name |
28-
not variable_instantiation(incomplete, complete) and
2929
isGlobalWithMangledNameAndWithoutDefinition(name, incomplete) and
3030
isGlobalWithMangledNameAndWithDefinition(name, complete)
3131
)

0 commit comments

Comments
 (0)
0