mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
C++: Simplify models for side effects and alias info.
This commit is contained in:
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user