Skip to content

Commit f7da6f5

Browse files
committed
C++: Ensure that only one Function exists for every function
1 parent 6831775 commit f7da6f5

File tree

5 files changed

+68
-4
lines changed

5 files changed

+68
-4
lines changed

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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy