Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 65360b2

Browse files
C++: Change model API based on feedback
I've separated the model interface for memory side effects from the model for escaped addresses. It will be fairly common for a given model to extend both interfaces, but they are used for two different purposes. I've also put each model interface and the non-member predicates that query it into a named module, which seemed cleaner than having predicates named `functionModelReadsMemory()` and `getFunctionModelParameterAliasBehavior()`.
1 parent e11b4b6 commit 65360b2

6 files changed

Lines changed: 173 additions & 78 deletions

File tree

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import cpp
22
private import semmle.code.cpp.ir.implementation.Opcode
33
private import semmle.code.cpp.ir.internal.OperandTag
4-
private import semmle.code.cpp.models.interfaces.SideEffectFunction
4+
private import semmle.code.cpp.models.interfaces.SideEffect
55
private import InstructionTag
66
private import TranslatedElement
77
private import TranslatedExpr
@@ -308,11 +308,11 @@ class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
308308
}
309309

310310
override predicate hasReadSideEffect() {
311-
functionReadsMemory(funcCall.getTarget())
311+
SideEffectModel::functionReadsMemory(funcCall.getTarget())
312312
}
313313

314314
override predicate hasWriteSideEffect() {
315-
functionWritesMemory(funcCall.getTarget())
315+
SideEffectModel::functionWritesMemory(funcCall.getTarget())
316316
}
317317
}
318318

@@ -336,4 +336,3 @@ class TranslatedStructorCall extends TranslatedFunctionCall {
336336
any()
337337
}
338338
}
339-

cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import semmle.code.cpp.Function
2+
import semmle.code.cpp.models.interfaces.Alias
23
import semmle.code.cpp.models.interfaces.DataFlow
3-
import semmle.code.cpp.models.interfaces.SideEffectFunction
4+
import semmle.code.cpp.models.interfaces.SideEffect
45

56
/**
67
* The standard function templates `std::move` and `std::identity`
78
*/
8-
class IdentityFunction extends DataFlowFunction, SideEffectFunction {
9+
class IdentityFunction extends DataFlowFunction, SideEffectModel::SideEffectFunction,
10+
AliasModel::AliasFunction {
911
IdentityFunction() {
1012
this.getNamespace().getParentNamespace() instanceof GlobalNamespace and
1113
this.getNamespace().getName() = "std" and
@@ -23,9 +25,16 @@ class IdentityFunction extends DataFlowFunction, SideEffectFunction {
2325
none()
2426
}
2527

26-
override predicate parameterEscapes(int index) {
27-
// Note that returning the value of the parameter does not count as escaping.
28-
none()
28+
override AliasModel::ParameterEscape getParameterEscapeBehavior(int index) {
29+
exists(getParameter(index)) and
30+
if index = 0 then
31+
result instanceof AliasModel::EscapesOnlyViaReturn
32+
else
33+
result instanceof AliasModel::DoesNotEscape
34+
}
35+
36+
override predicate parameterIsAlwaysReturned(int index) {
37+
index = 0
2938
}
3039

3140
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/**
2+
* Provides an abstract class for accurate alias modeling of library
3+
* functions when source code is not available. To use this QL library,
4+
* create a QL class extending `AliasFunction` with a characteristic
5+
* predicate that selects the function or set of functions you are modeling.
6+
* Within that class, override the predicates provided by `AliasFunction`
7+
* to match the flow within that function.
8+
*/
9+
10+
import semmle.code.cpp.Function
11+
import semmle.code.cpp.models.Models
12+
13+
module AliasModel {
14+
private newtype TParameterEscape =
15+
TDoesNotEscape() or
16+
TEscapesOnlyViaReturn() or
17+
TEscapes()
18+
19+
class ParameterEscape extends TParameterEscape {
20+
string toString() {
21+
result = "Unknown"
22+
}
23+
}
24+
25+
class DoesNotEscape extends ParameterEscape, TDoesNotEscape {
26+
override string toString() {
27+
result = "DoesNotEscape"
28+
}
29+
}
30+
31+
class EscapesOnlyViaReturn extends ParameterEscape, TEscapesOnlyViaReturn {
32+
override string toString() {
33+
result = "EscapesOnlyViaReturn"
34+
}
35+
}
36+
37+
class Escapes extends ParameterEscape, TEscapes {
38+
override string toString() {
39+
result = "Escapes"
40+
}
41+
}
42+
43+
/**
44+
* Models the aliasing behavior of a library function.
45+
*/
46+
abstract class AliasFunction extends Function {
47+
/**
48+
* Specifies whether the address passed to the parameter at the specified index is retained after
49+
* the function returns. The result is given as a `ParameterEscape` object. See the comments for
50+
* that class and its subclasses for a description of each possible result.
51+
*
52+
* Example:
53+
* ```
54+
* int* g;
55+
* int* func(int* p, int* q, int* r, int* s, int n) {
56+
* *s = 1; // `s` does not escape.
57+
* g = p; // Stored in global. `p` escapes.
58+
* if (rand()) {
59+
* return q; // `q` escapes via the return value.
60+
* }
61+
* else {
62+
* return r + n; // `r` escapes via the return value, even though an offset has been added.
63+
* }
64+
* }
65+
* ```
66+
*
67+
* For the above function, the following terms hold:
68+
* - `getParameterEscapeBehavior(0) instanceof Escapes`
69+
* - `getParameterEscapeBehavior(1) instanceof EscapesOnlyViaReturn`
70+
* - `getParameterEscapeBehavior(2) instanceof EscapesOnlyViaReturn`
71+
* - `getParameterEscapeBehavior(3) instanceof DoesNotEscape`
72+
*/
73+
abstract ParameterEscape getParameterEscapeBehavior(int index);
74+
75+
/**
76+
* Holds if the function always returns the value of the parameter at the specified index.
77+
*/
78+
abstract predicate parameterIsAlwaysReturned(int index);
79+
}
80+
81+
/**
82+
* Specifies whether the address passed to the parameter at the specified index is retained after
83+
* the function returns. The result is given as a `ParameterEscape` object. See the comments for
84+
* that class and its subclasses for a description of each possible result.
85+
*/
86+
ParameterEscape getParameterEscapeBehavior(Function f, int index) {
87+
result = f.(AliasFunction).getParameterEscapeBehavior(index) or
88+
(
89+
not f instanceof AliasFunction and
90+
exists(f.getParameter(index)) and
91+
result instanceof Escapes
92+
)
93+
}
94+
95+
/**
96+
* Holds if the function always returns the value of the parameter at the specified index.
97+
*/
98+
predicate parameterIsAlwaysReturned(Function f, int index) {
99+
f.(AliasFunction).parameterIsAlwaysReturned(index)
100+
}
101+
}

cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Provides a set of QL clcasses for indicating dataflows through a particular
2+
* Provides a set of QL classes for indicating dataflows through a particular
33
* parameter, return value, or qualifier, as well as flows at one level of
44
* pointer indirection.
55
*/
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* Provides an abstract class for accurate dataflow modeling of library
3+
* functions when source code is not available. To use this QL library,
4+
* create a QL class extending `SideEffectFunction` with a characteristic
5+
* predicate that selects the function or set of functions you are modeling.
6+
* Within that class, override the predicates provided by `SideEffectFunction`
7+
* to match the flow within that function.
8+
*/
9+
10+
import semmle.code.cpp.Function
11+
import semmle.code.cpp.models.Models
12+
13+
module SideEffectModel {
14+
/**
15+
* Models the side effects of a library function.
16+
*/
17+
abstract class SideEffectFunction extends Function {
18+
/**
19+
* Holds if the function may read from memory that was defined before entry to the function. This
20+
* memory could be from global variables, or from other memory that was reachable from a pointer
21+
* that was passed into the function.
22+
*/
23+
abstract predicate readsMemory();
24+
25+
/**
26+
* Holds if the function may write to memory that remains allocated after the function returns.
27+
* This memory could be from global variables, or from other memory that was reachable from a
28+
* pointer that was passed into the function.
29+
*/
30+
abstract predicate writesMemory();
31+
}
32+
33+
/**
34+
* Holds if the function `f` may read from memory that was defined before entry to the function.
35+
* This memory could be from global variables, or from other memory that was reachable from a
36+
* pointer that was passed into the function.
37+
*/
38+
predicate functionReadsMemory(Function f) {
39+
not exists(SideEffectFunction sideEffect |
40+
sideEffect = f and not sideEffect.readsMemory()
41+
)
42+
}
43+
44+
/**
45+
* Holds if the function `f` may write to memory that remains allocated after the function returns.
46+
* This memory could be from global variables, or from other memory that was reachable from a
47+
* pointer that was passed into the function.
48+
*/
49+
predicate functionWritesMemory(Function f) {
50+
not exists(SideEffectFunction sideEffect |
51+
sideEffect = f and not sideEffect.writesMemory()
52+
)
53+
}
54+
}

cpp/ql/src/semmle/code/cpp/models/interfaces/SideEffectFunction.qll

Lines changed: 0 additions & 68 deletions
This file was deleted.

0 commit comments

Comments
 (0)