Address review comments.

This commit is contained in:
Max Schaefer
2020-02-17 09:13:49 +00:00
parent f60b5daf94
commit ec9ba8aa7f
18 changed files with 44 additions and 33 deletions

View File

@@ -1,19 +1,20 @@
digraph ast {
graph [dpi=300];
"x" [shape=rect];
"y" [shape=rect];
"z" [shape=rect];
"x + y" [shape=rect];
"(x + y)" [shape=rect];
"z" [shape=rect];
"(x + y) * z" [shape=rect];
invis1 [style=invis];
invis2 [style=invis];
invis3 [style=invis];
"(x + y) * z" -> "(x + y)" [label=0];
"(x + y) * z" -> "z" [label=1];
"(x + y)" -> "x + y" [label=0];
"x + y" -> "x" [label=0];
"x + y" -> "y" [label=1];
"(x + y) * z" -> "(x + y)" [label=" 0"];
"(x + y) * z" -> "z" [label=" 1"];
"(x + y)" -> "x + y" [label=" 0"];
"x + y" -> "x" [label=" 0"];
"x + y" -> "y" [label=" 1"];
"z" -> invis1 [style=invis];
invis1 -> invis2 [style=invis];

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -1,4 +1,5 @@
digraph cfg {
graph [dpi=300];
rankdir=LR;
"x := 0" -> "p != nil";
"p != nil" -> "x = p.f";

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -1,4 +1,5 @@
digraph cfg2 {
graph [dpi=300];
rankdir=LR;
"p != nil is true" [shape=box];

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

@@ -1,4 +1,5 @@
digraph dfg {
graph [dpi=300];
rankdir=LR;
"x" [shape=diamond];

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -35,6 +35,9 @@ about which function may be invoked by a given call (taking virtual dispatch thr
account), as well as control-flow information about the order in which different operations may be
executed at runtime.
As a rule of thumb, you normally want to use the AST only for superficial syntactic queries. Any
analysis involving deeper semantic properties of the program should be done on the DFG.
The rest of this tutorial briefly summarizes the most important classes and predicates provided by
this library, including references to the `detailed API documentation
<https://help.semmle.com/qldoc/go/>`__ where applicable. We start by giving an overview of the AST
@@ -114,7 +117,7 @@ Statements
- ``CompoundAssignStmt``: an assignment statement with a compound operator, such as ``lhs += rhs``
- ``IncStmt``, ``DecStmt``: an increment statement or a decrement statement, respectively; use
``getExpr()`` to access the expression being incremented or decremented
``getOperand()`` to access the expression being incremented or decremented
- ``BlockStmt``: a block of statements between curly braces; use ``getStmt(i)`` to access the
``i``\ th statement in a block
- ``IfStmt``: an ``if`` statement; use ``getInit()``, ``getCond()``, ``getThen()``, and
@@ -136,6 +139,8 @@ Statements
deferred
- ``SendStmt``: a send statement; use ``getChannel()`` and ``getValue()`` to access the channel and
the value being sent over the channel, respectively
- ``RecvStmt``: a receive statement in a ``select`` statement; use ``getExpr()`` to access the
receiver expression, and ``getLhs(i)`` to access the ``i``\ th left-hand side
- ``ReturnStmt``: a ``return`` statement; use ``getExpr(i)`` to access the ``i``\ th returned
expression; if there is only a single returned expression you can use ``getExpr()`` instead
- ``BranchStmt``: a statement that interrupts structured control flow; use ``getLabel()`` to get the
@@ -152,7 +157,7 @@ Statements
- ``SwitchStmt``: a ``switch`` statement; use ``getInit()`` to access the (optional) init statement,
and ``getCase(i)`` to access the ``i``\ th ``case`` or ``default`` clause
- ``ExprSwitchStmt``: a ``switch`` statement examining the value of an expression
- ``ExpressionSwitchStmt``: a ``switch`` statement examining the value of an expression
- ``TypeSwitchStmt``: a ``switch`` statement examining the type of an expression
- ``CaseClause``: a ``case`` or ``default`` clause in a ``switch`` statement; use ``getExpr(i)`` to
@@ -421,10 +426,10 @@ In CodeQL, data-flow nodes are represented by class ``DataFlow::Node``, and the
are captured by the predicate ``DataFlow::localFlowStep``. The predicate ``DataFlow::localFlow``
generalizes this from a single flow step to zero or more flow steps.
Most expressions have a corresponding data-flow node (exceptions include type expressions, statement
labels, and other expressions that do not have a value). To map from the AST node of an expression to
the corresponding DFG node, use ``DataFlow::exprNode``. Note that the AST node and the DFG node are
different entities and cannot be used interchangeably.
Most expressions have a corresponding data-flow node; exceptions include type expressions, statement
labels and other expressions that do not have a value, as well as short-circuiting operators. To map
from the AST node of an expression to the corresponding DFG node, use ``DataFlow::exprNode``. Note
that the AST node and the DFG node are different entities and cannot be used interchangeably.
There is also a predicate ``asExpr()`` on ``DataFlow::Node`` that allows you to recover the
expression underlying a DFG node. However, this predicate should be used with caution, since many
@@ -445,16 +450,17 @@ Important subclasses of ``DataFlow::Node`` include:
corresponding AST node
- ``DataFlow::BinaryOperationNode``: an operation involving a binary operator; each ``BinaryExpr``
has a corresponding ``BinaryOperationNode``, but there are also binary operations that are not
explicit at the AST level, such as those arising from compound assignments and increment/
decrement statements; at the AST level, ``x + 1``, ``x += 1``, and ``x++`` are represented by
different kinds of AST nodes, while at the DFG level they are all modeled as a binary
operation node with operands ``x`` and ``1``
explicit at the AST level, such as those arising from compound assignments and
increment/decrement statements; at the AST level, ``x + 1``, ``x += 1``, and ``x++`` are
represented by different kinds of AST nodes, while at the DFG level they are all modeled as a
binary operation node with operands ``x`` and ``1``
- ``DataFlow::UnaryOperationNode``: analogous, but for unary operators
- ``DataFlow::PointerDereferenceNode``: a pointer dereference, either explicit in an expression of
the form ``*p``, or implicit in a field or method reference through a pointer
- ``DataFlow::AddressOperationNode``: analogous, but for taking the address of an entity
- ``DataFlow::RelationalComparisonNode``, ``DataFlow::EqualityTestNode``: data-flow nodes
corresponding to ``RelationalComparisonExpr`` and ``EqualityTestExpr`` AST nodes
- ``DataFlow::PointerDereferenceNode``: a pointer dereference, either explicit in an expression
of the form ``*p``, or implicit in a field or method reference through a pointer
- ``DataFlow::AddressOperationNode``: analogous, but for taking the address of an entity
- ``DataFlow::RelationalComparisonNode``, ``DataFlow::EqualityTestNode``: data-flow nodes
corresponding to ``RelationalComparisonExpr`` and ``EqualityTestExpr`` AST nodes
Finally, classes ``Read`` and ``Write`` represent, respectively, a read or a write of a variable, a
field, or an element of an array, a slice or a map. Use their member predicates ``readsVariable``,

View File

@@ -1,4 +1,5 @@
digraph ssa {
graph [dpi=300];
rankdir=LR;
"x1" [shape=diamond,label=<x<sub>1</sub>>];

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 67 KiB

View File

@@ -16,7 +16,7 @@ from
ControlFlow::ConditionGuardNode cond, DataFlow::CallNode lenA
where
// `i` is incremented in `fs`
fs.getPost().(IncStmt).getExpr() = i.getAReference() and
fs.getPost().(IncStmt).getOperand() = i.getAReference() and
// `idx` reads `a[i]`
idx.reads(a.getANode(), i.getARead()) and
// `lenA` is `len(a)`

View File

@@ -36,7 +36,7 @@ predicate bounds(RelationalComparisonExpr test, Variable v, string direction) {
* downward.
*/
predicate updates(IncDecStmt upd, Variable v, string direction) {
upd.getExpr() = v.getAReference() and
upd.getOperand() = v.getAReference() and
(
upd instanceof IncStmt and direction = "upward"
or

View File

@@ -1253,7 +1253,7 @@ class ReferenceExpr extends Expr {
predicate isLvalue() {
this = any(Assignment assgn).getLhs(_)
or
this = any(IncDecStmt ids).getExpr()
this = any(IncDecStmt ids).getOperand()
or
exists(RangeStmt rs |
this = rs.getKey() or
@@ -1271,7 +1271,7 @@ class ReferenceExpr extends Expr {
or
this = any(CompoundAssignStmt cmp).getLhs(_)
or
this = any(IncDecStmt ids).getExpr()
this = any(IncDecStmt ids).getOperand()
}
}

View File

@@ -103,8 +103,8 @@ class SendStmt extends @sendstmt, Stmt {
* An increment or decrement statement.
*/
class IncDecStmt extends @incdecstmt, Stmt {
/** Gets the expression. */
Expr getExpr() { result = getChildExpr(0) }
/** Gets the expression being incremented or decremented. */
Expr getOperand() { result = getChildExpr(0) }
/** Gets the increment or decrement operator. */
string getOperator() { none() }

View File

@@ -309,7 +309,7 @@ newtype TWriteTarget =
)
)
or
exists(IncDecStmt ids | write = MkIncDecNode(ids) | lhs = ids.getExpr().stripParens())
exists(IncDecStmt ids | write = MkIncDecNode(ids) | lhs = ids.getOperand().stripParens())
or
exists(ParameterOrReceiver parm | write = MkParameterInit(parm) | lhs = parm.getDeclaration())
or
@@ -1385,7 +1385,7 @@ module CFG {
}
private class IncDecTree extends ControlFlowTree, IncDecStmt {
override predicate firstNode(ControlFlow::Node first) { firstNode(getExpr(), first) }
override predicate firstNode(ControlFlow::Node first) { firstNode(getOperand(), first) }
override predicate lastNode(ControlFlow::Node last, Completion cmpl) {
ControlFlowTree.super.lastNode(last, cmpl)
@@ -1395,7 +1395,7 @@ module CFG {
}
override predicate succ(ControlFlow::Node pred, ControlFlow::Node succ) {
lastNode(getExpr(), pred, normalCompletion()) and
lastNode(getOperand(), pred, normalCompletion()) and
succ = MkImplicitOne(this)
or
pred = MkImplicitOne(this) and

View File

@@ -843,7 +843,7 @@ module IR {
/** Gets the corresponding increment or decrement statement. */
IncDecStmt getStmt() { result = ids }
override Type getResultType() { result = ids.getExpr().getType() }
override Type getResultType() { result = ids.getOperand().getType() }
override ControlFlow::Root getRoot() { result.isRootOf(ids) }
@@ -867,7 +867,7 @@ module IR {
/** Gets the corresponding increment or decrement statement. */
IncDecStmt getStmt() { result = ids }
override Type getResultType() { result = ids.getExpr().getType() }
override Type getResultType() { result = ids.getOperand().getType() }
override ControlFlow::Root getRoot() { result.isRootOf(ids) }

View File

@@ -536,7 +536,7 @@ class BinaryOperationNode extends Node {
exists(IR::EvalIncDecRhsInstruction rhs, IncDecStmt ids |
rhs = asInstruction() and ids = rhs.getStmt()
|
left = exprNode(ids.getExpr()) and
left = exprNode(ids.getOperand()) and
right = instructionNode(any(IR::EvalImplicitOneInstruction one | one.getStmt() = ids)) and
op = ids.getOperator().charAt(0)
)