C++: Improved ConstructorCall field flow

This commit changes C++ `ConstructorCall` to behave like
`new`-expressions in Java: they are both `ExprNode`s and
`PostUpdateNodes`, and there's a "pre-update node" (here called
`PreConstructorCallNode`) to play the role of the qualifier argument
when calling a constructor.
This commit is contained in:
Jonas Jensen
2019-08-13 10:55:27 +02:00
parent 1f1824cb9b
commit 38ec693ead
6 changed files with 62 additions and 40 deletions

View File

@@ -6,9 +6,7 @@ private import DataFlowDispatch
private Node getInstanceArgument(Call call) {
result.asExpr() = call.getQualifier()
or
// For constructors, there is no qualifier, so we pretend the call itself
// is the instance argument.
result.asExpr() = call.(ConstructorCall)
result.(PreConstructorCallNode).getConstructorCall() = call
// This does not include the implicit `this` argument on auto-generated
// base class destructor calls as those do not have an AST element.
}

View File

@@ -10,7 +10,7 @@ cached
private newtype TNode =
TExprNode(Expr e) or
TPartialDefinitionNode(PartialDefinition pd) or
TPostConstructorCallNode(ConstructorCall call) or
TPreConstructorCallNode(ConstructorCall call) or
TExplicitParameterNode(Parameter p) { exists(p.getFunction().getBlock()) } or
TInstanceParameterNode(MemberFunction f) { exists(f.getBlock()) and not f.isStatic() } or
TUninitializedNode(LocalVariable v) { not v.hasInitializer() }
@@ -48,8 +48,8 @@ class Node extends TNode {
*
* Partial definitions are created for field stores (`x.y = taint();` is a partial
* definition of `x`), and for calls that may change the value of an object (so
* `x.set(taint())` is a partial definition of `x`, annd `transfer(&x, taint())` is
* a partial definition of `&x`).s
* `x.set(taint())` is a partial definition of `x`, and `transfer(&x, taint())` is
* a partial definition of `&x`).
*/
Expr asPartialDefinition() {
result = this.(PartialDefinitionNode).getPartialDefinition().getDefinedExpr()
@@ -226,8 +226,6 @@ abstract class PostUpdateNode extends Node {
override Type getType() { result = getPreUpdateNode().getType() }
override Location getLocation() { result = getPreUpdateNode().getLocation() }
override string toString() { result = getPreUpdateNode().toString() + " [post update]" }
}
class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNode {
@@ -240,14 +238,36 @@ class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNode {
override Location getLocation() { result = pd.getLocation() }
PartialDefinition getPartialDefinition() { result = pd }
override string toString() { result = getPreUpdateNode().toString() + " [post update]" }
}
class PostConstructorCallNode extends PostUpdateNode, TPostConstructorCallNode {
ConstructorCall call;
private class PostConstructorCallNode extends PostUpdateNode, TExprNode {
PostConstructorCallNode() { this = TExprNode(any(ConstructorCall c)) }
PostConstructorCallNode() { this = TPostConstructorCallNode(call) }
override PreConstructorCallNode getPreUpdateNode() {
TExprNode(result.getConstructorCall()) = this
}
}
override Node getPreUpdateNode() { result.asExpr() = call }
/**
* INTERNAL: do not use.
*
* A synthetic data-flow node that plays the role of the qualifier (or
* `this`-argument) to a constructor call.
*/
class PreConstructorCallNode extends Node, TPreConstructorCallNode {
PreConstructorCallNode() { this = TPreConstructorCallNode(_) }
ConstructorCall getConstructorCall() { this = TPreConstructorCallNode(result) }
override Function getFunction() { result = getConstructorCall().getEnclosingFunction() }
override Type getType() { result = getConstructorCall().getType() }
override Location getLocation() { result = getConstructorCall().getLocation() }
override string toString() { result = getConstructorCall().toString() + " [pre constructor call]" }
}
/**