C++: Simplify models for side effects and alias info.

This commit is contained in:
Dave Bartolomeo
2018-12-06 12:35:33 -08:00
parent 2b80aee557
commit 84b39bf999
4 changed files with 63 additions and 133 deletions

View File

@@ -308,11 +308,11 @@ class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
}
override predicate hasReadSideEffect() {
SideEffectModel::functionReadsMemory(funcCall.getTarget())
not funcCall.getTarget().(SideEffectFunction).neverReadsMemory()
}
override predicate hasWriteSideEffect() {
SideEffectModel::functionWritesMemory(funcCall.getTarget())
not funcCall.getTarget().(SideEffectFunction).neverWritesMemory()
}
}

View File

@@ -6,8 +6,7 @@ import semmle.code.cpp.models.interfaces.SideEffect
/**
* The standard function templates `std::move` and `std::identity`
*/
class IdentityFunction extends DataFlowFunction, SideEffectModel::SideEffectFunction,
AliasModel::AliasFunction {
class IdentityFunction extends DataFlowFunction, SideEffectFunction, AliasFunction {
IdentityFunction() {
this.getNamespace().getParentNamespace() instanceof GlobalNamespace and
this.getNamespace().getName() = "std" and
@@ -17,23 +16,25 @@ class IdentityFunction extends DataFlowFunction, SideEffectModel::SideEffectFunc
)
}
override predicate readsMemory() {
override predicate neverReadsMemory() {
any()
}
override predicate neverWritesMemory() {
any()
}
override predicate parameterNeverEscapes(int index) {
none()
}
override predicate writesMemory() {
none()
}
override AliasModel::ParameterEscape getParameterEscapeBehavior(int index) {
exists(getParameter(index)) and
if index = 0 then
result instanceof AliasModel::EscapesOnlyViaReturn
else
result instanceof AliasModel::DoesNotEscape
override predicate parameterEscapesOnlyViaReturn(int index) {
// These functions simply return the argument value.
index = 0
}
override predicate parameterIsAlwaysReturned(int index) {
// These functions simply return the argument value.
index = 0
}

View File

@@ -10,92 +10,45 @@
import semmle.code.cpp.Function
import semmle.code.cpp.models.Models
module AliasModel {
private newtype TParameterEscape =
TDoesNotEscape() or
TEscapesOnlyViaReturn() or
TEscapes()
class ParameterEscape extends TParameterEscape {
string toString() {
result = "Unknown"
}
}
class DoesNotEscape extends ParameterEscape, TDoesNotEscape {
override string toString() {
result = "DoesNotEscape"
}
}
class EscapesOnlyViaReturn extends ParameterEscape, TEscapesOnlyViaReturn {
override string toString() {
result = "EscapesOnlyViaReturn"
}
}
class Escapes extends ParameterEscape, TEscapes {
override string toString() {
result = "Escapes"
}
}
/**
* Models the aliasing behavior of a library function.
*/
abstract class AliasFunction extends Function {
/**
* Models the aliasing behavior of a library function.
*/
abstract class AliasFunction extends Function {
/**
* Specifies whether the address passed to the parameter at the specified index is retained after
* the function returns. The result is given as a `ParameterEscape` object. See the comments for
* that class and its subclasses for a description of each possible result.
*
* Example:
* ```
* int* g;
* int* func(int* p, int* q, int* r, int* s, int n) {
* *s = 1; // `s` does not escape.
* g = p; // Stored in global. `p` escapes.
* if (rand()) {
* return q; // `q` escapes via the return value.
* }
* else {
* return r + n; // `r` escapes via the return value, even though an offset has been added.
* }
* }
* ```
*
* For the above function, the following terms hold:
* - `getParameterEscapeBehavior(0) instanceof Escapes`
* - `getParameterEscapeBehavior(1) instanceof EscapesOnlyViaReturn`
* - `getParameterEscapeBehavior(2) instanceof EscapesOnlyViaReturn`
* - `getParameterEscapeBehavior(3) instanceof DoesNotEscape`
*/
abstract ParameterEscape getParameterEscapeBehavior(int index);
/**
* Holds if the function always returns the value of the parameter at the specified index.
*/
abstract predicate parameterIsAlwaysReturned(int index);
}
/**
* Specifies whether the address passed to the parameter at the specified index is retained after
* the function returns. The result is given as a `ParameterEscape` object. See the comments for
* that class and its subclasses for a description of each possible result.
* Holds if the address passed to the parameter at the specified index is never retained after
* the function returns.
*
* Example:
* ```
* int* g;
* int* func(int* p, int* q, int* r, int* s, int n) {
* *s = 1; // `s` does not escape.
* g = p; // Stored in global. `p` escapes.
* if (rand()) {
* return q; // `q` escapes via the return value.
* }
* else {
* return r + n; // `r` escapes via the return value, even though an offset has been added.
* }
* }
* ```
*
* For the above function, the following terms hold:
* - `parameterEscapesOnlyViaReturn(1)`
* - `parameterEscapesOnlyViaReturn(2)`
* - `parameterNeverEscapes(3)`
*/
ParameterEscape getParameterEscapeBehavior(Function f, int index) {
result = f.(AliasFunction).getParameterEscapeBehavior(index) or
(
not f instanceof AliasFunction and
exists(f.getParameter(index)) and
result instanceof Escapes
)
}
abstract predicate parameterNeverEscapes(int index);
/**
* Holds if the address passed to the parameter at the specified index escapes via the return
* value of the function, but does not otherwise escape. See the comment for
* `parameterNeverEscapes` for an example.
*/
abstract predicate parameterEscapesOnlyViaReturn(int index);
/**
* Holds if the function always returns the value of the parameter at the specified index.
*/
predicate parameterIsAlwaysReturned(Function f, int index) {
f.(AliasFunction).parameterIsAlwaysReturned(index)
}
}
abstract predicate parameterIsAlwaysReturned(int index);
}

View File

@@ -10,45 +10,21 @@
import semmle.code.cpp.Function
import semmle.code.cpp.models.Models
module SideEffectModel {
/**
* Models the side effects of a library function.
*/
abstract class SideEffectFunction extends Function {
/**
* Models the side effects of a library function.
*/
abstract class SideEffectFunction extends Function {
/**
* Holds if the function may read from memory that was defined before entry to the function. This
* memory could be from global variables, or from other memory that was reachable from a pointer
* that was passed into the function.
*/
abstract predicate readsMemory();
/**
* Holds if the function may write to memory that remains allocated after the function returns.
* This memory could be from global variables, or from other memory that was reachable from a
* pointer that was passed into the function.
*/
abstract predicate writesMemory();
}
/**
* Holds if the function `f` may read from memory that was defined before entry to the function.
* Holds if the function never reads from memory that was defined before entry to the function.
* This memory could be from global variables, or from other memory that was reachable from a
* pointer that was passed into the function.
*/
predicate functionReadsMemory(Function f) {
not exists(SideEffectFunction sideEffect |
sideEffect = f and not sideEffect.readsMemory()
)
}
abstract predicate neverReadsMemory();
/**
* Holds if the function `f` may write to memory that remains allocated after the function returns.
* This memory could be from global variables, or from other memory that was reachable from a
* pointer that was passed into the function.
*/
predicate functionWritesMemory(Function f) {
not exists(SideEffectFunction sideEffect |
sideEffect = f and not sideEffect.writesMemory()
)
}
* Holds if the function never writes to memory that remains allocated after the function
* returns. This memory could be from global variables, or from other memory that was reachable
* from a pointer that was passed into the function.
*/
abstract predicate neverWritesMemory();
}