mirror of
https://github.com/github/codeql.git
synced 2026-05-13 02:39:26 +02:00
C++: Field flow through ConstructorFieldInit
This allows a member initializer list to be seen as a sequence of field
assignments. For example, the constructor
C() : a(taint()) { }
now has data flow similar to
C() { this.a = taint(); }
This commit is contained in:
@@ -178,6 +178,12 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
|
||||
node2.getPreUpdateNode().asExpr() = fa.getQualifier() and
|
||||
f.(FieldContent).getField() = fa.getTarget()
|
||||
)
|
||||
or
|
||||
exists(ConstructorFieldInit cfi |
|
||||
node2.getPreUpdateNode().(PreConstructorInitThis).getConstructorFieldInit() = cfi and
|
||||
f.(FieldContent).getField() = cfi.getTarget() and
|
||||
node1.asExpr() = cfi.getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,6 +13,8 @@ private newtype TNode =
|
||||
TPreConstructorCallNode(ConstructorCall call) or
|
||||
TExplicitParameterNode(Parameter p) { exists(p.getFunction().getBlock()) } or
|
||||
TInstanceParameterNode(MemberFunction f) { exists(f.getBlock()) and not f.isStatic() } or
|
||||
TPreConstructorInitThis(ConstructorFieldInit cfi) or
|
||||
TPostConstructorInitThis(ConstructorFieldInit cfi) or
|
||||
TUninitializedNode(LocalVariable v) { not v.hasInitializer() }
|
||||
|
||||
/**
|
||||
@@ -288,6 +290,44 @@ class PreConstructorCallNode extends Node, TPreConstructorCallNode {
|
||||
override string toString() { result = getConstructorCall().toString() + " [pre constructor call]" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A synthetic data-flow node that plays the role of the post-update `this`
|
||||
* pointer in a `ConstructorFieldInit`. For example, the `x(1)` in
|
||||
* `C() : x(1) { }` is roughly equivalent to `this.x = 1`, and this node is
|
||||
* equivalent to the `this` _after_ the field has been assigned.
|
||||
*/
|
||||
private class PostConstructorInitThis extends PostUpdateNode, TPostConstructorInitThis {
|
||||
override PreConstructorInitThis getPreUpdateNode() {
|
||||
this = TPostConstructorInitThis(result.getConstructorFieldInit())
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = getPreUpdateNode().getConstructorFieldInit().toString() + " [post-this]"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: do not use.
|
||||
*
|
||||
* A synthetic data-flow node that plays the role of the pre-update `this`
|
||||
* pointer in a `ConstructorFieldInit`. For example, the `x(1)` in
|
||||
* `C() : x(1) { }` is roughly equivalent to `this.x = 1`, and this node is
|
||||
* equivalent to the `this` _before_ the field has been assigned.
|
||||
*/
|
||||
class PreConstructorInitThis extends Node, TPreConstructorInitThis {
|
||||
ConstructorFieldInit getConstructorFieldInit() { this = TPreConstructorInitThis(result) }
|
||||
|
||||
override Constructor getFunction() { result = getConstructorFieldInit().getEnclosingFunction() }
|
||||
|
||||
override PointerType getType() {
|
||||
result.getBaseType() = getConstructorFieldInit().getEnclosingFunction().getDeclaringType()
|
||||
}
|
||||
|
||||
override Location getLocation() { result = getConstructorFieldInit().getLocation() }
|
||||
|
||||
override string toString() { result = getConstructorFieldInit().toString() + " [pre-this]" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Node` corresponding to `e`.
|
||||
*/
|
||||
@@ -313,6 +353,12 @@ DefinitionByReferenceNode definitionByReferenceNodeFromArgument(Expr argument) {
|
||||
UninitializedNode uninitializedNode(LocalVariable v) { result.getLocalVariable() = v }
|
||||
|
||||
private module ThisFlow {
|
||||
/**
|
||||
* Gets the 0-based index of `thisNode` in `b`, where `thisNode` is an access
|
||||
* to `this` that may or may not have an associated `PostUpdateNode`. To make
|
||||
* room for synthetic nodes that access `this`, the index may not correspond
|
||||
* to an actual `ControlFlowNode`.
|
||||
*/
|
||||
private int basicBlockThisIndex(BasicBlock b, Node thisNode) {
|
||||
// The implicit `this` parameter node is given a very negative offset to
|
||||
// make space for any `ConstructorFieldInit`s there may be between it and
|
||||
@@ -320,6 +366,16 @@ private module ThisFlow {
|
||||
thisNode.(ImplicitParameterNode).getFunction().getBlock() = b and
|
||||
result = -1000
|
||||
or
|
||||
// Place the synthetic `this` node for a `ConstructorFieldInit` at a
|
||||
// negative offset in the first basic block, between the
|
||||
// `ImplicitParameterNode` and the first statement.
|
||||
exists(Constructor constructor, int i |
|
||||
thisNode.(PreConstructorInitThis).getConstructorFieldInit() =
|
||||
constructor.getInitializer(i) and
|
||||
result = -999 + i and
|
||||
b = thisNode.getFunction().getBlock()
|
||||
)
|
||||
or
|
||||
b.getNode(result) = thisNode.asExpr().(ThisExpr)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user