mirror of
https://github.com/github/codeql.git
synced 2026-04-25 00:35:20 +02:00
Merge branch 'main' into modernsec3
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"extensions": [
|
||||
"rust-lang.rust",
|
||||
"rust-lang.rust-analyzer",
|
||||
"bungcip.better-toml",
|
||||
"github.vscode-codeql",
|
||||
"hbenl.vscode-test-explorer",
|
||||
|
||||
44
.github/workflows/tree-sitter-extractor-test.yml
vendored
Normal file
44
.github/workflows/tree-sitter-extractor-test.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: Test tree-sitter-extractor
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "shared/tree-sitter-extractor/**"
|
||||
- .github/workflows/tree-sitter-extractor-test.yml
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
pull_request:
|
||||
paths:
|
||||
- "shared/tree-sitter-extractor/**"
|
||||
- .github/workflows/tree-sitter-extractor-test.yml
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: shared/tree-sitter-extractor
|
||||
|
||||
jobs:
|
||||
test:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Check formatting
|
||||
run: cargo fmt --all -- --check
|
||||
- name: Run tests
|
||||
run: cargo test --verbose
|
||||
- name: Run clippy
|
||||
fmt:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Check formatting
|
||||
run: cargo fmt --check
|
||||
clippy:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Run clippy
|
||||
run: cargo clippy -- --no-deps -D warnings
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.7.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.7.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* A new predicate `BarrierGuard::getAnIndirectBarrierNode` has been added to the new dataflow library (`semmle.code.cpp.dataflow.new.DataFlow`) to mark indirect expressions as barrier nodes using the `BarrierGuard` API.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The new dataflow (`semmle.code.cpp.dataflow.new.DataFlow`) and taint-tracking libraries (`semmle.code.cpp.dataflow.new.TaintTracking`) now support tracking flow through static local variables.
|
||||
4
cpp/ql/lib/change-notes/2023-05-02-ir-noreturn-calls.md
Normal file
4
cpp/ql/lib/change-notes/2023-05-02-ir-noreturn-calls.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: majorAnalysis
|
||||
---
|
||||
* In the intermediate representation, handling of control flow after non-returning calls has been improved. This should remove false positives in queries that use the intermedite representation or libraries based on it, including the new data flow library.
|
||||
3
cpp/ql/lib/change-notes/released/0.7.1.md
Normal file
3
cpp/ql/lib/change-notes/released/0.7.1.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.7.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.7.0
|
||||
lastReleaseVersion: 0.7.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.7.1-dev
|
||||
version: 0.7.2-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -961,8 +961,16 @@ predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
|
||||
/**
|
||||
* A `Node` at which a cast can occur such that the type should be checked.
|
||||
*/
|
||||
class CastingNode extends Node {
|
||||
class CastingNode instanceof Node {
|
||||
CastingNode() { castingNode(this) }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate readStepWithTypes(
|
||||
@@ -1110,9 +1118,17 @@ LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable)
|
||||
* The value of a parameter at function entry, viewed as a node in a data
|
||||
* flow graph.
|
||||
*/
|
||||
class ParamNode extends Node {
|
||||
class ParamNode instanceof Node {
|
||||
ParamNode() { parameterNode(this, _, _) }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this node is the parameter of callable `c` at the specified
|
||||
* position.
|
||||
@@ -1121,9 +1137,17 @@ class ParamNode extends Node {
|
||||
}
|
||||
|
||||
/** A data-flow node that represents a call argument. */
|
||||
class ArgNode extends Node {
|
||||
class ArgNode instanceof Node {
|
||||
ArgNode() { argumentNode(this, _, _) }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Holds if this argument occurs at the given position in the given call. */
|
||||
final predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
argumentNode(this, call, pos)
|
||||
@@ -1134,9 +1158,17 @@ class ArgNode extends Node {
|
||||
* A node from which flow can return to the caller. This is either a regular
|
||||
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
|
||||
*/
|
||||
class ReturnNodeExt extends Node {
|
||||
class ReturnNodeExt instanceof Node {
|
||||
ReturnNodeExt() { returnNodeExt(this, _) }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the kind of this returned value. */
|
||||
ReturnKindExt getKind() { returnNodeExt(this, result) }
|
||||
}
|
||||
@@ -1145,8 +1177,16 @@ class ReturnNodeExt extends Node {
|
||||
* A node to which data can flow from a call. Either an ordinary out node
|
||||
* or a post-update node associated with a call argument.
|
||||
*/
|
||||
class OutNodeExt extends Node {
|
||||
class OutNodeExt instanceof Node {
|
||||
OutNodeExt() { outNodeExt(this) }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -961,8 +961,16 @@ predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
|
||||
/**
|
||||
* A `Node` at which a cast can occur such that the type should be checked.
|
||||
*/
|
||||
class CastingNode extends Node {
|
||||
class CastingNode instanceof Node {
|
||||
CastingNode() { castingNode(this) }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate readStepWithTypes(
|
||||
@@ -1110,9 +1118,17 @@ LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable)
|
||||
* The value of a parameter at function entry, viewed as a node in a data
|
||||
* flow graph.
|
||||
*/
|
||||
class ParamNode extends Node {
|
||||
class ParamNode instanceof Node {
|
||||
ParamNode() { parameterNode(this, _, _) }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this node is the parameter of callable `c` at the specified
|
||||
* position.
|
||||
@@ -1121,9 +1137,17 @@ class ParamNode extends Node {
|
||||
}
|
||||
|
||||
/** A data-flow node that represents a call argument. */
|
||||
class ArgNode extends Node {
|
||||
class ArgNode instanceof Node {
|
||||
ArgNode() { argumentNode(this, _, _) }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Holds if this argument occurs at the given position in the given call. */
|
||||
final predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
argumentNode(this, call, pos)
|
||||
@@ -1134,9 +1158,17 @@ class ArgNode extends Node {
|
||||
* A node from which flow can return to the caller. This is either a regular
|
||||
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
|
||||
*/
|
||||
class ReturnNodeExt extends Node {
|
||||
class ReturnNodeExt instanceof Node {
|
||||
ReturnNodeExt() { returnNodeExt(this, _) }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the kind of this returned value. */
|
||||
ReturnKindExt getKind() { returnNodeExt(this, result) }
|
||||
}
|
||||
@@ -1145,8 +1177,16 @@ class ReturnNodeExt extends Node {
|
||||
* A node to which data can flow from a call. Either an ordinary out node
|
||||
* or a post-update node associated with a call argument.
|
||||
*/
|
||||
class OutNodeExt extends Node {
|
||||
class OutNodeExt instanceof Node {
|
||||
OutNodeExt() { outNodeExt(this) }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -607,13 +607,21 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
|
||||
result.getReturnKind() = kind
|
||||
}
|
||||
|
||||
/** A variable that behaves like a global variable. */
|
||||
class GlobalLikeVariable extends Variable {
|
||||
GlobalLikeVariable() {
|
||||
this instanceof Cpp::GlobalOrNamespaceVariable or
|
||||
this instanceof Cpp::StaticLocalVariable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` in a way that loses the
|
||||
* calling context. For example, this would happen with flow through a
|
||||
* global or static variable.
|
||||
*/
|
||||
predicate jumpStep(Node n1, Node n2) {
|
||||
exists(Cpp::GlobalOrNamespaceVariable v |
|
||||
exists(GlobalLikeVariable v |
|
||||
exists(Ssa::GlobalUse globalUse |
|
||||
v = globalUse.getVariable() and
|
||||
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
||||
|
||||
@@ -1903,7 +1903,38 @@ signature predicate guardChecksSig(IRGuardCondition g, Expr e, boolean branch);
|
||||
* in data flow and taint tracking.
|
||||
*/
|
||||
module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
/** Gets a node that is safely guarded by the given guard check. */
|
||||
/**
|
||||
* Gets an expression node that is safely guarded by the given guard check.
|
||||
*
|
||||
* For example, given the following code:
|
||||
* ```cpp
|
||||
* int x = source();
|
||||
* // ...
|
||||
* if(is_safe_int(x)) {
|
||||
* sink(x);
|
||||
* }
|
||||
* ```
|
||||
* and the following barrier guard predicate:
|
||||
* ```ql
|
||||
* predicate myGuardChecks(IRGuardCondition g, Expr e, boolean branch) {
|
||||
* exists(Call call |
|
||||
* g.getUnconvertedResultExpression() = call and
|
||||
* call.getTarget().hasName("is_safe_int") and
|
||||
* e = call.getAnArgument() and
|
||||
* branch = true
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
* implementing `isBarrier` as:
|
||||
* ```ql
|
||||
* predicate isBarrier(DataFlow::Node barrier) {
|
||||
* barrier = DataFlow::BarrierGuard<myGuardChecks/3>::getABarrierNode()
|
||||
* }
|
||||
* ```
|
||||
* will block flow from `x = source()` to `sink(x)`.
|
||||
*
|
||||
* NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead.
|
||||
*/
|
||||
ExprNode getABarrierNode() {
|
||||
exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
|
||||
e = value.getAnInstruction().getConvertedResultExpression() and
|
||||
@@ -1912,6 +1943,84 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
g.controls(result.getBasicBlock(), edge)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an indirect expression node that is safely guarded by the given guard check.
|
||||
*
|
||||
* For example, given the following code:
|
||||
* ```cpp
|
||||
* int* p;
|
||||
* // ...
|
||||
* *p = source();
|
||||
* if(is_safe_pointer(p)) {
|
||||
* sink(*p);
|
||||
* }
|
||||
* ```
|
||||
* and the following barrier guard check:
|
||||
* ```ql
|
||||
* predicate myGuardChecks(IRGuardCondition g, Expr e, boolean branch) {
|
||||
* exists(Call call |
|
||||
* g.getUnconvertedResultExpression() = call and
|
||||
* call.getTarget().hasName("is_safe_pointer") and
|
||||
* e = call.getAnArgument() and
|
||||
* branch = true
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
* implementing `isBarrier` as:
|
||||
* ```ql
|
||||
* predicate isBarrier(DataFlow::Node barrier) {
|
||||
* barrier = DataFlow::BarrierGuard<myGuardChecks/3>::getAnIndirectBarrierNode()
|
||||
* }
|
||||
* ```
|
||||
* will block flow from `x = source()` to `sink(x)`.
|
||||
*
|
||||
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
|
||||
*/
|
||||
IndirectExprNode getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
|
||||
|
||||
/**
|
||||
* Gets an indirect expression node with indirection index `indirectionIndex` that is
|
||||
* safely guarded by the given guard check.
|
||||
*
|
||||
* For example, given the following code:
|
||||
* ```cpp
|
||||
* int* p;
|
||||
* // ...
|
||||
* *p = source();
|
||||
* if(is_safe_pointer(p)) {
|
||||
* sink(*p);
|
||||
* }
|
||||
* ```
|
||||
* and the following barrier guard check:
|
||||
* ```ql
|
||||
* predicate myGuardChecks(IRGuardCondition g, Expr e, boolean branch) {
|
||||
* exists(Call call |
|
||||
* g.getUnconvertedResultExpression() = call and
|
||||
* call.getTarget().hasName("is_safe_pointer") and
|
||||
* e = call.getAnArgument() and
|
||||
* branch = true
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
* implementing `isBarrier` as:
|
||||
* ```ql
|
||||
* predicate isBarrier(DataFlow::Node barrier) {
|
||||
* barrier = DataFlow::BarrierGuard<myGuardChecks/3>::getAnIndirectBarrierNode(1)
|
||||
* }
|
||||
* ```
|
||||
* will block flow from `x = source()` to `sink(x)`.
|
||||
*
|
||||
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
|
||||
*/
|
||||
IndirectExprNode getAnIndirectBarrierNode(int indirectionIndex) {
|
||||
exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
|
||||
e = value.getAnInstruction().getConvertedResultExpression() and
|
||||
result.getConvertedExpr(indirectionIndex) = e and
|
||||
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
|
||||
g.controls(result.getBasicBlock(), edge)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -145,14 +145,14 @@ private newtype TDefOrUseImpl =
|
||||
or
|
||||
// Since the pruning stage doesn't know about global variables we can't use the above check to
|
||||
// rule out dead assignments to globals.
|
||||
base.(VariableAddressInstruction).getAstVariable() instanceof Cpp::GlobalOrNamespaceVariable
|
||||
base.(VariableAddressInstruction).getAstVariable() instanceof GlobalLikeVariable
|
||||
)
|
||||
} or
|
||||
TUseImpl(Operand operand, int indirectionIndex) {
|
||||
isUse(_, operand, _, _, indirectionIndex) and
|
||||
not isDef(_, _, operand, _, _, _)
|
||||
} or
|
||||
TGlobalUse(Cpp::GlobalOrNamespaceVariable v, IRFunction f, int indirectionIndex) {
|
||||
TGlobalUse(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
|
||||
// Represents a final "use" of a global variable to ensure that
|
||||
// the assignment to a global variable isn't ruled out as dead.
|
||||
exists(VariableAddressInstruction vai, int defIndex |
|
||||
@@ -162,7 +162,7 @@ private newtype TDefOrUseImpl =
|
||||
indirectionIndex = [0 .. defIndex] + 1
|
||||
)
|
||||
} or
|
||||
TGlobalDefImpl(Cpp::GlobalOrNamespaceVariable v, IRFunction f, int indirectionIndex) {
|
||||
TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
|
||||
// Represents the initial "definition" of a global variable when entering
|
||||
// a function body.
|
||||
exists(VariableAddressInstruction vai |
|
||||
@@ -458,7 +458,7 @@ class FinalParameterUse extends UseImpl, TFinalParameterUse {
|
||||
}
|
||||
|
||||
class GlobalUse extends UseImpl, TGlobalUse {
|
||||
Cpp::GlobalOrNamespaceVariable global;
|
||||
GlobalLikeVariable global;
|
||||
IRFunction f;
|
||||
|
||||
GlobalUse() { this = TGlobalUse(global, f, ind) }
|
||||
@@ -468,7 +468,7 @@ class GlobalUse extends UseImpl, TGlobalUse {
|
||||
override int getIndirection() { result = ind + 1 }
|
||||
|
||||
/** Gets the global variable associated with this use. */
|
||||
Cpp::GlobalOrNamespaceVariable getVariable() { result = global }
|
||||
GlobalLikeVariable getVariable() { result = global }
|
||||
|
||||
/** Gets the `IRFunction` whose body is exited from after this use. */
|
||||
IRFunction getIRFunction() { result = f }
|
||||
@@ -496,14 +496,14 @@ class GlobalUse extends UseImpl, TGlobalUse {
|
||||
}
|
||||
|
||||
class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
|
||||
Cpp::GlobalOrNamespaceVariable global;
|
||||
GlobalLikeVariable global;
|
||||
IRFunction f;
|
||||
int indirectionIndex;
|
||||
|
||||
GlobalDefImpl() { this = TGlobalDefImpl(global, f, indirectionIndex) }
|
||||
|
||||
/** Gets the global variable associated with this definition. */
|
||||
Cpp::GlobalOrNamespaceVariable getVariable() { result = global }
|
||||
GlobalLikeVariable getVariable() { result = global }
|
||||
|
||||
/** Gets the `IRFunction` whose body is evaluated after this definition. */
|
||||
IRFunction getIRFunction() { result = f }
|
||||
@@ -760,13 +760,14 @@ private predicate variableWriteCand(IRBlock bb, int i, SourceVariable v) {
|
||||
}
|
||||
|
||||
private predicate sourceVariableIsGlobal(
|
||||
SourceVariable sv, Cpp::GlobalOrNamespaceVariable global, IRFunction func, int indirectionIndex
|
||||
SourceVariable sv, GlobalLikeVariable global, IRFunction func, int indirectionIndex
|
||||
) {
|
||||
exists(IRVariable irVar, BaseIRVariable base |
|
||||
sourceVariableHasBaseAndIndex(sv, base, indirectionIndex) and
|
||||
irVar = base.getIRVariable() and
|
||||
irVar.getEnclosingIRFunction() = func and
|
||||
global = irVar.getAst()
|
||||
global = irVar.getAst() and
|
||||
not irVar instanceof IRDynamicInitializationFlag
|
||||
)
|
||||
}
|
||||
|
||||
@@ -919,7 +920,7 @@ class GlobalDef extends TGlobalDef, SsaDefOrUse {
|
||||
IRFunction getIRFunction() { result = global.getIRFunction() }
|
||||
|
||||
/** Gets the global variable associated with this definition. */
|
||||
Cpp::GlobalOrNamespaceVariable getVariable() { result = global.getVariable() }
|
||||
GlobalLikeVariable getVariable() { result = global.getVariable() }
|
||||
}
|
||||
|
||||
class Phi extends TPhi, SsaDefOrUse {
|
||||
|
||||
@@ -34,9 +34,13 @@ private module Cached {
|
||||
|
||||
cached
|
||||
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
exists(OldIR::Instruction oldInstruction |
|
||||
irFunc = oldInstruction.getEnclosingIRFunction() and
|
||||
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
||||
(
|
||||
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
||||
or
|
||||
oldInstruction.getOpcode() instanceof Opcode::Unreached
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -366,21 +370,19 @@ private module Cached {
|
||||
then
|
||||
result = getChi(getOldInstruction(instruction)) and
|
||||
kind instanceof GotoEdge
|
||||
else (
|
||||
else
|
||||
exists(OldInstruction oldInstruction |
|
||||
oldInstruction = getOldInstruction(instruction) and
|
||||
(
|
||||
oldInstruction = getOldInstruction(instruction)
|
||||
or
|
||||
instruction = getChi(oldInstruction)
|
||||
) and
|
||||
(
|
||||
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
|
||||
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
|
||||
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = getChi(oldInstruction) and
|
||||
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
|
||||
@@ -19,6 +19,9 @@ newtype TInstruction =
|
||||
) {
|
||||
IRConstruction::Raw::hasInstruction(tag1, tag2)
|
||||
} or
|
||||
TRawUnreachedInstruction(IRFunctionBase irFunc) {
|
||||
IRConstruction::hasUnreachedInstruction(irFunc)
|
||||
} or
|
||||
TUnaliasedSsaPhiInstruction(
|
||||
TRawInstruction blockStartInstr, UnaliasedSsa::Ssa::MemoryLocation memoryLocation
|
||||
) {
|
||||
|
||||
@@ -178,9 +178,9 @@ module Raw {
|
||||
}
|
||||
}
|
||||
|
||||
class TStageInstruction = TRawInstruction;
|
||||
class TStageInstruction = TRawInstruction or TRawUnreachedInstruction;
|
||||
|
||||
predicate hasInstruction(TRawInstruction instr) { any() }
|
||||
predicate hasInstruction(TStageInstruction instr) { any() }
|
||||
|
||||
predicate hasModeledMemoryResult(Instruction instruction) { none() }
|
||||
|
||||
@@ -368,6 +368,11 @@ private predicate isStrictlyForwardGoto(GotoStmt goto) {
|
||||
|
||||
Locatable getInstructionAst(TStageInstruction instr) {
|
||||
result = getInstructionTranslatedElement(instr).getAst()
|
||||
or
|
||||
exists(IRFunction irFunc |
|
||||
instr = TRawUnreachedInstruction(irFunc) and
|
||||
result = irFunc.getFunction()
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for getInstructionAst */
|
||||
@@ -377,14 +382,22 @@ deprecated Locatable getInstructionAST(TStageInstruction instr) {
|
||||
|
||||
CppType getInstructionResultType(TStageInstruction instr) {
|
||||
getInstructionTranslatedElement(instr).hasInstruction(_, getInstructionTag(instr), result)
|
||||
or
|
||||
instr instanceof TRawUnreachedInstruction and
|
||||
result = getVoidType()
|
||||
}
|
||||
|
||||
predicate getInstructionOpcode(Opcode opcode, TStageInstruction instr) {
|
||||
getInstructionTranslatedElement(instr).hasInstruction(opcode, getInstructionTag(instr), _)
|
||||
or
|
||||
instr instanceof TRawUnreachedInstruction and
|
||||
opcode instanceof Opcode::Unreached
|
||||
}
|
||||
|
||||
IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) {
|
||||
result.getFunction() = getInstructionTranslatedElement(instr).getFunction()
|
||||
or
|
||||
instr = TRawUnreachedInstruction(result)
|
||||
}
|
||||
|
||||
Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction) {
|
||||
@@ -393,6 +406,16 @@ Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction
|
||||
.getPrimaryInstructionForSideEffect(getInstructionTag(instruction))
|
||||
}
|
||||
|
||||
predicate hasUnreachedInstruction(IRFunction func) {
|
||||
exists(Call c |
|
||||
c.getEnclosingFunction() = func.getFunction() and
|
||||
any(Options opt).exits(c.getTarget())
|
||||
) and
|
||||
not exists(TranslatedUnreachableReturnStmt return |
|
||||
return.getEnclosingFunction().getFunction() = func.getFunction()
|
||||
)
|
||||
}
|
||||
|
||||
import CachedForDebugging
|
||||
|
||||
cached
|
||||
|
||||
@@ -34,6 +34,7 @@ newtype TInstructionTag =
|
||||
CallTargetTag() or
|
||||
CallTag() or
|
||||
CallSideEffectTag() or
|
||||
CallNoReturnTag() or
|
||||
AllocationSizeTag() or
|
||||
AllocationElementSizeTag() or
|
||||
AllocationExtentConvertTag() or
|
||||
|
||||
@@ -8,6 +8,7 @@ private import SideEffects
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
private import TranslatedFunction
|
||||
private import DefaultOptions as DefaultOptions
|
||||
|
||||
/**
|
||||
* Gets the `CallInstruction` from the `TranslatedCallExpr` for the specified expression.
|
||||
@@ -66,7 +67,13 @@ abstract class TranslatedCall extends TranslatedExpr {
|
||||
)
|
||||
or
|
||||
child = getSideEffects() and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
if this.isNoReturn()
|
||||
then
|
||||
result =
|
||||
any(UnreachedInstruction instr |
|
||||
this.getEnclosingFunction().getFunction() = instr.getEnclosingFunction()
|
||||
)
|
||||
else result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -161,6 +168,8 @@ abstract class TranslatedCall extends TranslatedExpr {
|
||||
*/
|
||||
abstract predicate hasArguments();
|
||||
|
||||
predicate isNoReturn() { none() }
|
||||
|
||||
final TranslatedSideEffects getSideEffects() { result.getExpr() = expr }
|
||||
}
|
||||
|
||||
@@ -266,6 +275,8 @@ abstract class TranslatedCallExpr extends TranslatedNonConstantExpr, TranslatedC
|
||||
}
|
||||
|
||||
final override int getNumberOfArguments() { result = expr.getNumberOfArguments() }
|
||||
|
||||
final override predicate isNoReturn() { any(Options opt).exits(expr.getTarget()) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -821,7 +821,7 @@ abstract class TranslatedElement extends TTranslatedElement {
|
||||
abstract Locatable getAst();
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Locatable getAST() { result = getAst() }
|
||||
deprecated Locatable getAST() { result = this.getAst() }
|
||||
|
||||
/**
|
||||
* Get the first instruction to be executed in the evaluation of this element.
|
||||
@@ -831,7 +831,7 @@ abstract class TranslatedElement extends TTranslatedElement {
|
||||
/**
|
||||
* Get the immediate child elements of this element.
|
||||
*/
|
||||
final TranslatedElement getAChild() { result = getChild(_) }
|
||||
final TranslatedElement getAChild() { result = this.getChild(_) }
|
||||
|
||||
/**
|
||||
* Gets the immediate child element of this element. The `id` is unique
|
||||
@@ -844,25 +844,29 @@ abstract class TranslatedElement extends TTranslatedElement {
|
||||
* Gets the an identifier string for the element. This id is unique within
|
||||
* the scope of the element's function.
|
||||
*/
|
||||
final int getId() { result = getUniqueId() }
|
||||
final int getId() { result = this.getUniqueId() }
|
||||
|
||||
private TranslatedElement getChildByRank(int rankIndex) {
|
||||
result =
|
||||
rank[rankIndex + 1](TranslatedElement child, int id | child = getChild(id) | child order by id)
|
||||
rank[rankIndex + 1](TranslatedElement child, int id |
|
||||
child = this.getChild(id)
|
||||
|
|
||||
child order by id
|
||||
)
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
private int getDescendantCount() {
|
||||
result =
|
||||
1 + sum(TranslatedElement child | child = getChildByRank(_) | child.getDescendantCount())
|
||||
1 + sum(TranslatedElement child | child = this.getChildByRank(_) | child.getDescendantCount())
|
||||
}
|
||||
|
||||
private int getUniqueId() {
|
||||
if not exists(getParent())
|
||||
if not exists(this.getParent())
|
||||
then result = 0
|
||||
else
|
||||
exists(TranslatedElement parent |
|
||||
parent = getParent() and
|
||||
parent = this.getParent() and
|
||||
if this = parent.getChildByRank(0)
|
||||
then result = 1 + parent.getUniqueId()
|
||||
else
|
||||
@@ -908,7 +912,7 @@ abstract class TranslatedElement extends TTranslatedElement {
|
||||
* there is no enclosing `try`.
|
||||
*/
|
||||
Instruction getExceptionSuccessorInstruction() {
|
||||
result = getParent().getExceptionSuccessorInstruction()
|
||||
result = this.getParent().getExceptionSuccessorInstruction()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1022,14 +1026,14 @@ abstract class TranslatedElement extends TTranslatedElement {
|
||||
exists(Locatable ast |
|
||||
result.getAst() = ast and
|
||||
result.getTag() = tag and
|
||||
hasTempVariableAndAst(tag, ast)
|
||||
this.hasTempVariableAndAst(tag, ast)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasTempVariableAndAst(TempVariableTag tag, Locatable ast) {
|
||||
hasTempVariable(tag, _) and
|
||||
ast = getAst()
|
||||
this.hasTempVariable(tag, _) and
|
||||
ast = this.getAst()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,64 +35,64 @@ abstract class InitializationContext extends TranslatedElement {
|
||||
* declarations, `return` statements, and `throw` expressions.
|
||||
*/
|
||||
abstract class TranslatedVariableInitialization extends TranslatedElement, InitializationContext {
|
||||
final override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() }
|
||||
final override TranslatedElement getChild(int id) { id = 0 and result = this.getInitialization() }
|
||||
|
||||
final override Instruction getFirstInstruction() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
result = this.getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = InitializerVariableAddressTag() and
|
||||
opcode instanceof Opcode::VariableAddress and
|
||||
resultType = getTypeForGLValue(getTargetType())
|
||||
resultType = getTypeForGLValue(this.getTargetType())
|
||||
or
|
||||
hasUninitializedInstruction() and
|
||||
this.hasUninitializedInstruction() and
|
||||
tag = InitializerStoreTag() and
|
||||
opcode instanceof Opcode::Uninitialized and
|
||||
resultType = getTypeForPRValue(getTargetType())
|
||||
resultType = getTypeForPRValue(this.getTargetType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
(
|
||||
tag = InitializerVariableAddressTag() and
|
||||
kind instanceof GotoEdge and
|
||||
if hasUninitializedInstruction()
|
||||
then result = getInstruction(InitializerStoreTag())
|
||||
else result = getInitialization().getFirstInstruction()
|
||||
if this.hasUninitializedInstruction()
|
||||
then result = this.getInstruction(InitializerStoreTag())
|
||||
else result = this.getInitialization().getFirstInstruction()
|
||||
)
|
||||
or
|
||||
hasUninitializedInstruction() and
|
||||
this.hasUninitializedInstruction() and
|
||||
kind instanceof GotoEdge and
|
||||
tag = InitializerStoreTag() and
|
||||
(
|
||||
result = getInitialization().getFirstInstruction()
|
||||
result = this.getInitialization().getFirstInstruction()
|
||||
or
|
||||
not exists(getInitialization()) and result = getInitializationSuccessor()
|
||||
not exists(this.getInitialization()) and result = this.getInitializationSuccessor()
|
||||
)
|
||||
}
|
||||
|
||||
final override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getInitialization() and result = getInitializationSuccessor()
|
||||
child = this.getInitialization() and result = this.getInitializationSuccessor()
|
||||
}
|
||||
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
hasUninitializedInstruction() and
|
||||
this.hasUninitializedInstruction() and
|
||||
tag = InitializerStoreTag() and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
result = this.getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
final override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
(
|
||||
tag = InitializerVariableAddressTag()
|
||||
or
|
||||
hasUninitializedInstruction() and tag = InitializerStoreTag()
|
||||
this.hasUninitializedInstruction() and tag = InitializerStoreTag()
|
||||
) and
|
||||
result = getIRVariable()
|
||||
result = this.getIRVariable()
|
||||
}
|
||||
|
||||
final override Instruction getTargetAddress() {
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
result = this.getInstruction(InitializerVariableAddressTag())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,13 +116,13 @@ abstract class TranslatedVariableInitialization extends TranslatedElement, Initi
|
||||
*/
|
||||
final predicate hasUninitializedInstruction() {
|
||||
(
|
||||
not exists(getInitialization()) or
|
||||
getInitialization() instanceof TranslatedListInitialization or
|
||||
getInitialization() instanceof TranslatedConstructorInitialization or
|
||||
getInitialization().(TranslatedStringLiteralInitialization).zeroInitRange(_, _)
|
||||
not exists(this.getInitialization()) or
|
||||
this.getInitialization() instanceof TranslatedListInitialization or
|
||||
this.getInitialization() instanceof TranslatedConstructorInitialization or
|
||||
this.getInitialization().(TranslatedStringLiteralInitialization).zeroInitRange(_, _)
|
||||
) and
|
||||
// Variables with static or thread-local storage duration are zero-initialized at program startup.
|
||||
getIRVariable() instanceof IRAutomaticVariable
|
||||
this.getIRVariable() instanceof IRAutomaticVariable
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ abstract class TranslatedInitialization extends TranslatedElement, TTranslatedIn
|
||||
final override Locatable getAst() { result = expr }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
deprecated override Locatable getAST() { result = this.getAst() }
|
||||
|
||||
/**
|
||||
* Gets the expression that is doing the initialization.
|
||||
@@ -157,7 +157,7 @@ abstract class TranslatedInitialization extends TranslatedElement, TTranslatedIn
|
||||
* Gets the initialization context that describes the location being
|
||||
* initialized.
|
||||
*/
|
||||
final InitializationContext getContext() { result = getParent() }
|
||||
final InitializationContext getContext() { result = this.getParent() }
|
||||
|
||||
final TranslatedFunction getEnclosingFunction() {
|
||||
result = getTranslatedFunction(this.getFunction())
|
||||
@@ -169,17 +169,17 @@ abstract class TranslatedInitialization extends TranslatedElement, TTranslatedIn
|
||||
*/
|
||||
abstract class TranslatedListInitialization extends TranslatedInitialization, InitializationContext {
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getChild(0).getFirstInstruction()
|
||||
result = this.getChild(0).getFirstInstruction()
|
||||
or
|
||||
not exists(getChild(0)) and result = getParent().getChildSuccessor(this)
|
||||
not exists(this.getChild(0)) and result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
exists(int index |
|
||||
child = getChild(index) and
|
||||
if exists(getChild(index + 1))
|
||||
then result = getChild(index + 1).getFirstInstruction()
|
||||
else result = getParent().getChildSuccessor(this)
|
||||
child = this.getChild(index) and
|
||||
if exists(this.getChild(index + 1))
|
||||
then result = this.getChild(index + 1).getFirstInstruction()
|
||||
else result = this.getParent().getChildSuccessor(this)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -189,9 +189,9 @@ abstract class TranslatedListInitialization extends TranslatedInitialization, In
|
||||
|
||||
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
override Instruction getTargetAddress() { result = getContext().getTargetAddress() }
|
||||
override Instruction getTargetAddress() { result = this.getContext().getTargetAddress() }
|
||||
|
||||
override Type getTargetType() { result = getContext().getTargetType() }
|
||||
override Type getTargetType() { result = this.getContext().getTargetType() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -237,9 +237,11 @@ class TranslatedArrayListInitialization extends TranslatedListInitialization {
|
||||
abstract class TranslatedDirectInitialization extends TranslatedInitialization {
|
||||
TranslatedDirectInitialization() { not expr instanceof AggregateLiteral }
|
||||
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = getInitializer() }
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = this.getInitializer() }
|
||||
|
||||
override Instruction getFirstInstruction() { result = getInitializer().getFirstInstruction() }
|
||||
override Instruction getFirstInstruction() {
|
||||
result = this.getInitializer().getFirstInstruction()
|
||||
}
|
||||
|
||||
final TranslatedExpr getInitializer() { result = getTranslatedExpr(expr) }
|
||||
}
|
||||
@@ -258,27 +260,27 @@ class TranslatedSimpleDirectInitialization extends TranslatedDirectInitializatio
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = InitializerStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getTypeForPRValue(getContext().getTargetType())
|
||||
resultType = getTypeForPRValue(this.getContext().getTargetType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = InitializerStoreTag() and
|
||||
result = getParent().getChildSuccessor(this) and
|
||||
result = this.getParent().getChildSuccessor(this) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getInitializer() and result = getInstruction(InitializerStoreTag())
|
||||
child = this.getInitializer() and result = this.getInstruction(InitializerStoreTag())
|
||||
}
|
||||
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = InitializerStoreTag() and
|
||||
(
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getContext().getTargetAddress()
|
||||
result = this.getContext().getTargetAddress()
|
||||
or
|
||||
operandTag instanceof StoreValueOperandTag and
|
||||
result = getInitializer().getResult()
|
||||
result = this.getInitializer().getResult()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -305,13 +307,13 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
|
||||
// If the initializer string isn't large enough to fill the target, then
|
||||
// we have to generate another instruction sequence to store a constant
|
||||
// zero into the remainder of the array.
|
||||
zeroInitRange(_, elementCount) and
|
||||
this.zeroInitRange(_, elementCount) and
|
||||
(
|
||||
// Create a constant zero whose size is the size of the remaining
|
||||
// space in the target array.
|
||||
tag = ZeroPadStringConstantTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = getUnknownOpaqueType(elementCount * getElementType().getSize())
|
||||
resultType = getUnknownOpaqueType(elementCount * this.getElementType().getSize())
|
||||
or
|
||||
// The index of the first element to be zero initialized.
|
||||
tag = ZeroPadStringElementIndexTag() and
|
||||
@@ -321,12 +323,12 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
|
||||
// Compute the address of the first element to be zero initialized.
|
||||
tag = ZeroPadStringElementAddressTag() and
|
||||
opcode instanceof Opcode::PointerAdd and
|
||||
resultType = getTypeForGLValue(getElementType())
|
||||
resultType = getTypeForGLValue(this.getElementType())
|
||||
or
|
||||
// Store the constant zero into the remainder of the string.
|
||||
tag = ZeroPadStringStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getUnknownOpaqueType(elementCount * getElementType().getSize())
|
||||
resultType = getUnknownOpaqueType(elementCount * this.getElementType().getSize())
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -335,78 +337,78 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
|
||||
kind instanceof GotoEdge and
|
||||
(
|
||||
tag = InitializerLoadStringTag() and
|
||||
result = getInstruction(InitializerStoreTag())
|
||||
result = this.getInstruction(InitializerStoreTag())
|
||||
or
|
||||
if zeroInitRange(_, _)
|
||||
if this.zeroInitRange(_, _)
|
||||
then (
|
||||
tag = InitializerStoreTag() and
|
||||
result = getInstruction(ZeroPadStringConstantTag())
|
||||
result = this.getInstruction(ZeroPadStringConstantTag())
|
||||
or
|
||||
tag = ZeroPadStringConstantTag() and
|
||||
result = getInstruction(ZeroPadStringElementIndexTag())
|
||||
result = this.getInstruction(ZeroPadStringElementIndexTag())
|
||||
or
|
||||
tag = ZeroPadStringElementIndexTag() and
|
||||
result = getInstruction(ZeroPadStringElementAddressTag())
|
||||
result = this.getInstruction(ZeroPadStringElementAddressTag())
|
||||
or
|
||||
tag = ZeroPadStringElementAddressTag() and
|
||||
result = getInstruction(ZeroPadStringStoreTag())
|
||||
result = this.getInstruction(ZeroPadStringStoreTag())
|
||||
or
|
||||
tag = ZeroPadStringStoreTag() and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
result = this.getParent().getChildSuccessor(this)
|
||||
) else (
|
||||
tag = InitializerStoreTag() and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
result = this.getParent().getChildSuccessor(this)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getInitializer() and result = getInstruction(InitializerLoadStringTag())
|
||||
child = this.getInitializer() and result = this.getInstruction(InitializerLoadStringTag())
|
||||
}
|
||||
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = InitializerLoadStringTag() and
|
||||
(
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInitializer().getResult()
|
||||
result = this.getInitializer().getResult()
|
||||
)
|
||||
or
|
||||
tag = InitializerStoreTag() and
|
||||
(
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getContext().getTargetAddress()
|
||||
result = this.getContext().getTargetAddress()
|
||||
or
|
||||
operandTag instanceof StoreValueOperandTag and
|
||||
result = getInstruction(InitializerLoadStringTag())
|
||||
result = this.getInstruction(InitializerLoadStringTag())
|
||||
)
|
||||
or
|
||||
tag = ZeroPadStringElementAddressTag() and
|
||||
(
|
||||
operandTag instanceof LeftOperandTag and
|
||||
result = getContext().getTargetAddress()
|
||||
result = this.getContext().getTargetAddress()
|
||||
or
|
||||
operandTag instanceof RightOperandTag and
|
||||
result = getInstruction(ZeroPadStringElementIndexTag())
|
||||
result = this.getInstruction(ZeroPadStringElementIndexTag())
|
||||
)
|
||||
or
|
||||
tag = ZeroPadStringStoreTag() and
|
||||
(
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(ZeroPadStringElementAddressTag())
|
||||
result = this.getInstruction(ZeroPadStringElementAddressTag())
|
||||
or
|
||||
operandTag instanceof StoreValueOperandTag and
|
||||
result = getInstruction(ZeroPadStringConstantTag())
|
||||
result = this.getInstruction(ZeroPadStringConstantTag())
|
||||
)
|
||||
}
|
||||
|
||||
override int getInstructionElementSize(InstructionTag tag) {
|
||||
tag = ZeroPadStringElementAddressTag() and
|
||||
result = max(getElementType().getSize())
|
||||
result = max(this.getElementType().getSize())
|
||||
}
|
||||
|
||||
override string getInstructionConstantValue(InstructionTag tag) {
|
||||
exists(int startIndex |
|
||||
zeroInitRange(startIndex, _) and
|
||||
this.zeroInitRange(startIndex, _) and
|
||||
(
|
||||
tag = ZeroPadStringConstantTag() and
|
||||
result = "0"
|
||||
@@ -419,13 +421,13 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
|
||||
|
||||
override predicate needsUnknownOpaqueType(int byteSize) {
|
||||
exists(int elementCount |
|
||||
zeroInitRange(_, elementCount) and
|
||||
byteSize = elementCount * getElementType().getSize()
|
||||
this.zeroInitRange(_, elementCount) and
|
||||
byteSize = elementCount * this.getElementType().getSize()
|
||||
)
|
||||
}
|
||||
|
||||
private Type getElementType() {
|
||||
result = getContext().getTargetType().getUnspecifiedType().(ArrayType).getBaseType()
|
||||
result = this.getContext().getTargetType().getUnspecifiedType().(ArrayType).getBaseType()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -435,7 +437,8 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
|
||||
predicate zeroInitRange(int startIndex, int elementCount) {
|
||||
exists(int targetCount |
|
||||
startIndex = expr.getUnspecifiedType().(ArrayType).getArraySize() and
|
||||
targetCount = getContext().getTargetType().getUnspecifiedType().(ArrayType).getArraySize() and
|
||||
targetCount =
|
||||
this.getContext().getTargetType().getUnspecifiedType().(ArrayType).getArraySize() and
|
||||
elementCount = targetCount - startIndex and
|
||||
elementCount > 0
|
||||
)
|
||||
@@ -454,14 +457,14 @@ class TranslatedConstructorInitialization extends TranslatedDirectInitialization
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getInitializer() and result = getParent().getChildSuccessor(this)
|
||||
child = this.getInitializer() and result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
none()
|
||||
}
|
||||
|
||||
override Instruction getReceiver() { result = getContext().getTargetAddress() }
|
||||
override Instruction getReceiver() { result = this.getContext().getTargetAddress() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -491,7 +494,7 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
|
||||
final override Locatable getAst() { result = ast }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
deprecated override Locatable getAST() { result = this.getAst() }
|
||||
|
||||
final override Declaration getFunction() {
|
||||
result = getEnclosingFunction(ast) or
|
||||
@@ -499,7 +502,9 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
|
||||
result = getEnclosingVariable(ast).(StaticInitializedStaticLocalVariable)
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction() { result = getInstruction(getFieldAddressTag()) }
|
||||
final override Instruction getFirstInstruction() {
|
||||
result = this.getInstruction(this.getFieldAddressTag())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the zero-based index describing the order in which this field is to be
|
||||
@@ -508,19 +513,19 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
|
||||
final int getOrder() { result = field.getInitializationOrder() }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = getFieldAddressTag() and
|
||||
tag = this.getFieldAddressTag() and
|
||||
opcode instanceof Opcode::FieldAddress and
|
||||
resultType = getTypeForGLValue(field.getType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = getFieldAddressTag() and
|
||||
tag = this.getFieldAddressTag() and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getParent().(InitializationContext).getTargetAddress()
|
||||
result = this.getParent().(InitializationContext).getTargetAddress()
|
||||
}
|
||||
|
||||
override Field getInstructionField(InstructionTag tag) {
|
||||
tag = getFieldAddressTag() and result = field
|
||||
tag = this.getFieldAddressTag() and result = field
|
||||
}
|
||||
|
||||
final InstructionTag getFieldAddressTag() { result = InitializerFieldAddressTag() }
|
||||
@@ -545,21 +550,23 @@ class TranslatedExplicitFieldInitialization extends TranslatedFieldInitializatio
|
||||
this = TTranslatedExplicitFieldInitialization(ast, field, expr, position)
|
||||
}
|
||||
|
||||
override Instruction getTargetAddress() { result = getInstruction(getFieldAddressTag()) }
|
||||
override Instruction getTargetAddress() {
|
||||
result = this.getInstruction(this.getFieldAddressTag())
|
||||
}
|
||||
|
||||
override Type getTargetType() { result = field.getUnspecifiedType() }
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = getFieldAddressTag() and
|
||||
result = getInitialization().getFirstInstruction() and
|
||||
tag = this.getFieldAddressTag() and
|
||||
result = this.getInitialization().getFirstInstruction() and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getInitialization() and result = getParent().getChildSuccessor(this)
|
||||
child = this.getInitialization() and result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() }
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = this.getInitialization() }
|
||||
|
||||
private TranslatedInitialization getInitialization() {
|
||||
result = getTranslatedInitialization(expr)
|
||||
@@ -584,11 +591,11 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
TranslatedFieldInitialization.super.hasInstruction(opcode, tag, resultType)
|
||||
or
|
||||
tag = getFieldDefaultValueTag() and
|
||||
tag = this.getFieldDefaultValueTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = getTypeForPRValue(field.getType())
|
||||
or
|
||||
tag = getFieldDefaultValueStoreTag() and
|
||||
tag = this.getFieldDefaultValueStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getTypeForPRValue(field.getUnspecifiedType())
|
||||
}
|
||||
@@ -596,32 +603,32 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
kind instanceof GotoEdge and
|
||||
(
|
||||
tag = getFieldAddressTag() and
|
||||
result = getInstruction(getFieldDefaultValueTag())
|
||||
tag = this.getFieldAddressTag() and
|
||||
result = this.getInstruction(this.getFieldDefaultValueTag())
|
||||
or
|
||||
tag = getFieldDefaultValueTag() and
|
||||
result = getInstruction(getFieldDefaultValueStoreTag())
|
||||
tag = this.getFieldDefaultValueTag() and
|
||||
result = this.getInstruction(this.getFieldDefaultValueStoreTag())
|
||||
or
|
||||
tag = getFieldDefaultValueStoreTag() and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
tag = this.getFieldDefaultValueStoreTag() and
|
||||
result = this.getParent().getChildSuccessor(this)
|
||||
)
|
||||
}
|
||||
|
||||
override string getInstructionConstantValue(InstructionTag tag) {
|
||||
tag = getFieldDefaultValueTag() and
|
||||
tag = this.getFieldDefaultValueTag() and
|
||||
result = getZeroValue(field.getUnspecifiedType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
result = TranslatedFieldInitialization.super.getInstructionRegisterOperand(tag, operandTag)
|
||||
or
|
||||
tag = getFieldDefaultValueStoreTag() and
|
||||
tag = this.getFieldDefaultValueStoreTag() and
|
||||
(
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(getFieldAddressTag())
|
||||
result = this.getInstruction(this.getFieldAddressTag())
|
||||
or
|
||||
operandTag instanceof StoreValueOperandTag and
|
||||
result = getInstruction(getFieldDefaultValueTag())
|
||||
result = this.getInstruction(this.getFieldDefaultValueTag())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -644,13 +651,13 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
|
||||
ArrayOrVectorAggregateLiteral initList;
|
||||
|
||||
final override string toString() {
|
||||
result = initList.toString() + "[" + getElementIndex().toString() + "]"
|
||||
result = initList.toString() + "[" + this.getElementIndex().toString() + "]"
|
||||
}
|
||||
|
||||
final override Locatable getAst() { result = initList }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
deprecated override Locatable getAST() { result = this.getAst() }
|
||||
|
||||
final override Declaration getFunction() {
|
||||
result = getEnclosingFunction(initList)
|
||||
@@ -660,43 +667,45 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
|
||||
result = getEnclosingVariable(initList).(StaticInitializedStaticLocalVariable)
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction() { result = getInstruction(getElementIndexTag()) }
|
||||
final override Instruction getFirstInstruction() {
|
||||
result = this.getInstruction(this.getElementIndexTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = getElementIndexTag() and
|
||||
tag = this.getElementIndexTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = getIntType()
|
||||
or
|
||||
tag = getElementAddressTag() and
|
||||
tag = this.getElementAddressTag() and
|
||||
opcode instanceof Opcode::PointerAdd and
|
||||
resultType = getTypeForGLValue(getElementType())
|
||||
resultType = getTypeForGLValue(this.getElementType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = getElementIndexTag() and
|
||||
result = getInstruction(getElementAddressTag()) and
|
||||
tag = this.getElementIndexTag() and
|
||||
result = this.getInstruction(this.getElementAddressTag()) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = getElementAddressTag() and
|
||||
tag = this.getElementAddressTag() and
|
||||
(
|
||||
operandTag instanceof LeftOperandTag and
|
||||
result = getParent().(InitializationContext).getTargetAddress()
|
||||
result = this.getParent().(InitializationContext).getTargetAddress()
|
||||
or
|
||||
operandTag instanceof RightOperandTag and
|
||||
result = getInstruction(getElementIndexTag())
|
||||
result = this.getInstruction(this.getElementIndexTag())
|
||||
)
|
||||
}
|
||||
|
||||
override int getInstructionElementSize(InstructionTag tag) {
|
||||
tag = getElementAddressTag() and
|
||||
result = max(getElementType().getSize())
|
||||
tag = this.getElementAddressTag() and
|
||||
result = max(this.getElementType().getSize())
|
||||
}
|
||||
|
||||
override string getInstructionConstantValue(InstructionTag tag) {
|
||||
tag = getElementIndexTag() and
|
||||
result = getElementIndex().toString()
|
||||
tag = this.getElementIndexTag() and
|
||||
result = this.getElementIndex().toString()
|
||||
}
|
||||
|
||||
abstract int getElementIndex();
|
||||
@@ -726,23 +735,25 @@ class TranslatedExplicitElementInitialization extends TranslatedElementInitializ
|
||||
this = TTranslatedExplicitElementInitialization(initList, elementIndex, position)
|
||||
}
|
||||
|
||||
override Instruction getTargetAddress() { result = getInstruction(getElementAddressTag()) }
|
||||
override Instruction getTargetAddress() {
|
||||
result = this.getInstruction(this.getElementAddressTag())
|
||||
}
|
||||
|
||||
override Type getTargetType() { result = getElementType() }
|
||||
override Type getTargetType() { result = this.getElementType() }
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
result = TranslatedElementInitialization.super.getInstructionSuccessor(tag, kind)
|
||||
or
|
||||
tag = getElementAddressTag() and
|
||||
result = getInitialization().getFirstInstruction() and
|
||||
tag = this.getElementAddressTag() and
|
||||
result = this.getInitialization().getFirstInstruction() and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getInitialization() and result = getParent().getChildSuccessor(this)
|
||||
child = this.getInitialization() and result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() }
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = this.getInitialization() }
|
||||
|
||||
override int getElementIndex() { result = elementIndex }
|
||||
|
||||
@@ -773,13 +784,13 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
TranslatedElementInitialization.super.hasInstruction(opcode, tag, resultType)
|
||||
or
|
||||
tag = getElementDefaultValueTag() and
|
||||
tag = this.getElementDefaultValueTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
resultType = getDefaultValueType()
|
||||
resultType = this.getDefaultValueType()
|
||||
or
|
||||
tag = getElementDefaultValueStoreTag() and
|
||||
tag = this.getElementDefaultValueStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
resultType = getDefaultValueType()
|
||||
resultType = this.getDefaultValueType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -787,34 +798,34 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
|
||||
or
|
||||
kind instanceof GotoEdge and
|
||||
(
|
||||
tag = getElementAddressTag() and
|
||||
result = getInstruction(getElementDefaultValueTag())
|
||||
tag = this.getElementAddressTag() and
|
||||
result = this.getInstruction(this.getElementDefaultValueTag())
|
||||
or
|
||||
tag = getElementDefaultValueTag() and
|
||||
result = getInstruction(getElementDefaultValueStoreTag())
|
||||
tag = this.getElementDefaultValueTag() and
|
||||
result = this.getInstruction(this.getElementDefaultValueStoreTag())
|
||||
or
|
||||
tag = getElementDefaultValueStoreTag() and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
tag = this.getElementDefaultValueStoreTag() and
|
||||
result = this.getParent().getChildSuccessor(this)
|
||||
)
|
||||
}
|
||||
|
||||
override string getInstructionConstantValue(InstructionTag tag) {
|
||||
result = TranslatedElementInitialization.super.getInstructionConstantValue(tag)
|
||||
or
|
||||
tag = getElementDefaultValueTag() and
|
||||
result = getZeroValue(getElementType())
|
||||
tag = this.getElementDefaultValueTag() and
|
||||
result = getZeroValue(this.getElementType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
result = TranslatedElementInitialization.super.getInstructionRegisterOperand(tag, operandTag)
|
||||
or
|
||||
tag = getElementDefaultValueStoreTag() and
|
||||
tag = this.getElementDefaultValueStoreTag() and
|
||||
(
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(getElementAddressTag())
|
||||
result = this.getInstruction(this.getElementAddressTag())
|
||||
or
|
||||
operandTag instanceof StoreValueOperandTag and
|
||||
result = getInstruction(getElementDefaultValueTag())
|
||||
result = this.getInstruction(this.getElementDefaultValueTag())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -825,7 +836,7 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
|
||||
override int getElementIndex() { result = elementIndex }
|
||||
|
||||
override predicate needsUnknownOpaqueType(int byteSize) {
|
||||
elementCount != 0 and byteSize = elementCount * getElementType().getSize()
|
||||
elementCount != 0 and byteSize = elementCount * this.getElementType().getSize()
|
||||
}
|
||||
|
||||
private InstructionTag getElementDefaultValueTag() {
|
||||
@@ -838,8 +849,8 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
|
||||
|
||||
private CppType getDefaultValueType() {
|
||||
if elementCount = 1
|
||||
then result = getTypeForPRValue(getElementType())
|
||||
else result = getUnknownOpaqueType(elementCount * getElementType().getSize())
|
||||
then result = getTypeForPRValue(this.getElementType())
|
||||
else result = getUnknownOpaqueType(elementCount * this.getElementType().getSize())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -849,18 +860,18 @@ abstract class TranslatedStructorCallFromStructor extends TranslatedElement, Str
|
||||
final override Locatable getAst() { result = call }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
deprecated override Locatable getAST() { result = this.getAst() }
|
||||
|
||||
final override TranslatedElement getChild(int id) {
|
||||
id = 0 and
|
||||
result = getStructorCall()
|
||||
result = this.getStructorCall()
|
||||
}
|
||||
|
||||
final override Function getFunction() { result = getEnclosingFunction(call) }
|
||||
|
||||
final override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getStructorCall() and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
child = this.getStructorCall() and
|
||||
result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
final TranslatedExpr getStructorCall() { result = getTranslatedExpr(call) }
|
||||
@@ -871,7 +882,9 @@ abstract class TranslatedStructorCallFromStructor extends TranslatedElement, Str
|
||||
* destructor from within a derived class constructor or destructor.
|
||||
*/
|
||||
abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStructor {
|
||||
final override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
|
||||
final override Instruction getFirstInstruction() {
|
||||
result = this.getInstruction(OnlyInstructionTag())
|
||||
}
|
||||
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
@@ -882,15 +895,15 @@ abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStru
|
||||
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = OnlyInstructionTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = getStructorCall().getFirstInstruction()
|
||||
result = this.getStructorCall().getFirstInstruction()
|
||||
}
|
||||
|
||||
final override Instruction getReceiver() { result = getInstruction(OnlyInstructionTag()) }
|
||||
final override Instruction getReceiver() { result = this.getInstruction(OnlyInstructionTag()) }
|
||||
|
||||
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getTranslatedFunction(getFunction()).getInitializeThisInstruction()
|
||||
result = getTranslatedFunction(this.getFunction()).getInitializeThisInstruction()
|
||||
}
|
||||
|
||||
final override predicate getInstructionInheritance(
|
||||
@@ -898,7 +911,7 @@ abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStru
|
||||
) {
|
||||
tag = OnlyInstructionTag() and
|
||||
baseClass = call.getTarget().getDeclaringType().getUnspecifiedType() and
|
||||
derivedClass = getFunction().getDeclaringType().getUnspecifiedType()
|
||||
derivedClass = this.getFunction().getDeclaringType().getUnspecifiedType()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -924,7 +937,7 @@ class TranslatedConstructorDelegationInit extends TranslatedConstructorCallFromC
|
||||
final override string toString() { result = "delegation construct: " + call.toString() }
|
||||
|
||||
final override Instruction getFirstInstruction() {
|
||||
result = getStructorCall().getFirstInstruction()
|
||||
result = this.getStructorCall().getFirstInstruction()
|
||||
}
|
||||
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
@@ -934,7 +947,7 @@ class TranslatedConstructorDelegationInit extends TranslatedConstructorCallFromC
|
||||
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
final override Instruction getReceiver() {
|
||||
result = getTranslatedFunction(getFunction()).getInitializeThisInstruction()
|
||||
result = getTranslatedFunction(this.getFunction()).getInitializeThisInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -981,11 +994,11 @@ class TranslatedConstructorBareInit extends TranslatedElement, TTranslatedConstr
|
||||
override Locatable getAst() { result = init }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
deprecated override Locatable getAST() { result = this.getAst() }
|
||||
|
||||
final override string toString() { result = "construct base (no constructor)" }
|
||||
|
||||
override Instruction getFirstInstruction() { result = getParent().getChildSuccessor(this) }
|
||||
override Instruction getFirstInstruction() { result = this.getParent().getChildSuccessor(this) }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
|
||||
@@ -240,7 +240,7 @@ abstract class TranslatedStmt extends TranslatedElement, TTranslatedStmt {
|
||||
final override Locatable getAst() { result = stmt }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
deprecated override Locatable getAST() { result = this.getAst() }
|
||||
|
||||
final override Function getFunction() { result = stmt.getEnclosingFunction() }
|
||||
}
|
||||
@@ -254,7 +254,7 @@ class TranslatedEmptyStmt extends TranslatedStmt {
|
||||
|
||||
override TranslatedElement getChild(int id) { none() }
|
||||
|
||||
override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
|
||||
override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
@@ -264,7 +264,7 @@ class TranslatedEmptyStmt extends TranslatedStmt {
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = getParent().getChildSuccessor(this) and
|
||||
result = this.getParent().getChildSuccessor(this) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
@@ -279,19 +279,19 @@ class TranslatedEmptyStmt extends TranslatedStmt {
|
||||
class TranslatedDeclStmt extends TranslatedStmt {
|
||||
override DeclStmt stmt;
|
||||
|
||||
override TranslatedElement getChild(int id) { result = getDeclarationEntry(id) }
|
||||
override TranslatedElement getChild(int id) { result = this.getDeclarationEntry(id) }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getDeclarationEntry(0).getFirstInstruction()
|
||||
result = this.getDeclarationEntry(0).getFirstInstruction()
|
||||
or
|
||||
not exists(getDeclarationEntry(0)) and result = getParent().getChildSuccessor(this)
|
||||
not exists(this.getDeclarationEntry(0)) and result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
private int getChildCount() { result = count(getDeclarationEntry(_)) }
|
||||
private int getChildCount() { result = count(this.getDeclarationEntry(_)) }
|
||||
|
||||
IRDeclarationEntry getIRDeclarationEntry(int index) {
|
||||
result.hasIndex(index) and
|
||||
@@ -319,10 +319,10 @@ class TranslatedDeclStmt extends TranslatedStmt {
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
exists(int index |
|
||||
child = getDeclarationEntry(index) and
|
||||
if index = (getChildCount() - 1)
|
||||
then result = getParent().getChildSuccessor(this)
|
||||
else result = getDeclarationEntry(index + 1).getFirstInstruction()
|
||||
child = this.getDeclarationEntry(index) and
|
||||
if index = (this.getChildCount() - 1)
|
||||
then result = this.getParent().getChildSuccessor(this)
|
||||
else result = this.getDeclarationEntry(index + 1).getFirstInstruction()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -332,19 +332,19 @@ class TranslatedExprStmt extends TranslatedStmt {
|
||||
|
||||
TranslatedExpr getExpr() { result = getTranslatedExpr(stmt.getExpr().getFullyConverted()) }
|
||||
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = getExpr() }
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = this.getExpr() }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() { result = getExpr().getFirstInstruction() }
|
||||
override Instruction getFirstInstruction() { result = this.getExpr().getFirstInstruction() }
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getExpr() and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
child = this.getExpr() and
|
||||
result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,16 +363,18 @@ class TranslatedReturnValueStmt extends TranslatedReturnStmt, TranslatedVariable
|
||||
TranslatedReturnValueStmt() { stmt.hasExpr() and hasReturnValue(stmt.getEnclosingFunction()) }
|
||||
|
||||
final override Instruction getInitializationSuccessor() {
|
||||
result = getEnclosingFunction().getReturnSuccessorInstruction()
|
||||
result = this.getEnclosingFunction().getReturnSuccessorInstruction()
|
||||
}
|
||||
|
||||
final override Type getTargetType() { result = getEnclosingFunction().getReturnType() }
|
||||
final override Type getTargetType() { result = this.getEnclosingFunction().getReturnType() }
|
||||
|
||||
final override TranslatedInitialization getInitialization() {
|
||||
result = getTranslatedInitialization(stmt.getExpr().getFullyConverted())
|
||||
}
|
||||
|
||||
final override IRVariable getIRVariable() { result = getEnclosingFunction().getReturnVariable() }
|
||||
final override IRVariable getIRVariable() {
|
||||
result = this.getEnclosingFunction().getReturnVariable()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -385,10 +387,10 @@ class TranslatedReturnVoidExpressionStmt extends TranslatedReturnStmt {
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
id = 0 and
|
||||
result = getExpr()
|
||||
result = this.getExpr()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() { result = getExpr().getFirstInstruction() }
|
||||
override Instruction getFirstInstruction() { result = this.getExpr().getFirstInstruction() }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
@@ -398,13 +400,13 @@ class TranslatedReturnVoidExpressionStmt extends TranslatedReturnStmt {
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = getEnclosingFunction().getReturnSuccessorInstruction() and
|
||||
result = this.getEnclosingFunction().getReturnSuccessorInstruction() and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getExpr() and
|
||||
result = getInstruction(OnlyInstructionTag())
|
||||
child = this.getExpr() and
|
||||
result = this.getInstruction(OnlyInstructionTag())
|
||||
}
|
||||
|
||||
private TranslatedExpr getExpr() { result = getTranslatedExpr(stmt.getExpr()) }
|
||||
@@ -421,7 +423,7 @@ class TranslatedReturnVoidStmt extends TranslatedReturnStmt {
|
||||
|
||||
override TranslatedElement getChild(int id) { none() }
|
||||
|
||||
override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
|
||||
override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
@@ -431,7 +433,7 @@ class TranslatedReturnVoidStmt extends TranslatedReturnStmt {
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = getEnclosingFunction().getReturnSuccessorInstruction() and
|
||||
result = this.getEnclosingFunction().getReturnSuccessorInstruction() and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
@@ -452,7 +454,7 @@ class TranslatedUnreachableReturnStmt extends TranslatedReturnStmt {
|
||||
|
||||
override TranslatedElement getChild(int id) { none() }
|
||||
|
||||
override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
|
||||
override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
@@ -511,9 +513,9 @@ class TranslatedTryStmt extends TranslatedStmt {
|
||||
override TryOrMicrosoftTryStmt stmt;
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getBody()
|
||||
id = 0 and result = this.getBody()
|
||||
or
|
||||
result = getHandler(id - 1)
|
||||
result = this.getHandler(id - 1)
|
||||
or
|
||||
id = stmt.getNumberOfCatchClauses() + 1 and
|
||||
result = this.getFinally()
|
||||
@@ -525,7 +527,7 @@ class TranslatedTryStmt extends TranslatedStmt {
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
override Instruction getFirstInstruction() { result = getBody().getFirstInstruction() }
|
||||
override Instruction getFirstInstruction() { result = this.getBody().getFirstInstruction() }
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
// All non-finally children go to the successor of the `try` if
|
||||
@@ -546,19 +548,19 @@ class TranslatedTryStmt extends TranslatedStmt {
|
||||
|
||||
final Instruction getNextHandler(TranslatedHandler handler) {
|
||||
exists(int index |
|
||||
handler = getHandler(index) and
|
||||
result = getHandler(index + 1).getFirstInstruction()
|
||||
handler = this.getHandler(index) and
|
||||
result = this.getHandler(index + 1).getFirstInstruction()
|
||||
)
|
||||
or
|
||||
// The last catch clause flows to the exception successor of the parent
|
||||
// of the `try`, because the exception successor of the `try` itself is
|
||||
// the first catch clause.
|
||||
handler = getHandler(stmt.getNumberOfCatchClauses() - 1) and
|
||||
result = getParent().getExceptionSuccessorInstruction()
|
||||
handler = this.getHandler(stmt.getNumberOfCatchClauses() - 1) and
|
||||
result = this.getParent().getExceptionSuccessorInstruction()
|
||||
}
|
||||
|
||||
final override Instruction getExceptionSuccessorInstruction() {
|
||||
result = getHandler(0).getFirstInstruction()
|
||||
result = this.getHandler(0).getFirstInstruction()
|
||||
}
|
||||
|
||||
private TranslatedElement getHandler(int index) { result = stmt.getTranslatedHandler(index) }
|
||||
@@ -571,19 +573,19 @@ class TranslatedTryStmt extends TranslatedStmt {
|
||||
class TranslatedBlock extends TranslatedStmt {
|
||||
override BlockStmt stmt;
|
||||
|
||||
override TranslatedElement getChild(int id) { result = getStmt(id) }
|
||||
override TranslatedElement getChild(int id) { result = this.getStmt(id) }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
isEmpty() and
|
||||
this.isEmpty() and
|
||||
opcode instanceof Opcode::NoOp and
|
||||
tag = OnlyInstructionTag() and
|
||||
resultType = getVoidType()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
if isEmpty()
|
||||
then result = getInstruction(OnlyInstructionTag())
|
||||
else result = getStmt(0).getFirstInstruction()
|
||||
if this.isEmpty()
|
||||
then result = this.getInstruction(OnlyInstructionTag())
|
||||
else result = this.getStmt(0).getFirstInstruction()
|
||||
}
|
||||
|
||||
private predicate isEmpty() { not exists(stmt.getStmt(0)) }
|
||||
@@ -594,16 +596,16 @@ class TranslatedBlock extends TranslatedStmt {
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = getParent().getChildSuccessor(this) and
|
||||
result = this.getParent().getChildSuccessor(this) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
exists(int index |
|
||||
child = getStmt(index) and
|
||||
if index = (getStmtCount() - 1)
|
||||
then result = getParent().getChildSuccessor(this)
|
||||
else result = getStmt(index + 1).getFirstInstruction()
|
||||
child = this.getStmt(index) and
|
||||
if index = (this.getStmtCount() - 1)
|
||||
then result = this.getParent().getChildSuccessor(this)
|
||||
else result = this.getStmt(index + 1).getFirstInstruction()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -614,18 +616,18 @@ class TranslatedBlock extends TranslatedStmt {
|
||||
abstract class TranslatedHandler extends TranslatedStmt {
|
||||
override Handler stmt;
|
||||
|
||||
override TranslatedElement getChild(int id) { id = 1 and result = getBlock() }
|
||||
override TranslatedElement getChild(int id) { id = 1 and result = this.getBlock() }
|
||||
|
||||
override Instruction getFirstInstruction() { result = getInstruction(CatchTag()) }
|
||||
override Instruction getFirstInstruction() { result = this.getInstruction(CatchTag()) }
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getBlock() and result = getParent().getChildSuccessor(this)
|
||||
child = this.getBlock() and result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override Instruction getExceptionSuccessorInstruction() {
|
||||
// A throw from within a `catch` block flows to the handler for the parent of
|
||||
// the `try`.
|
||||
result = getParent().getParent().getExceptionSuccessorInstruction()
|
||||
result = this.getParent().getParent().getExceptionSuccessorInstruction()
|
||||
}
|
||||
|
||||
TranslatedStmt getBlock() { result = getTranslatedStmt(stmt.getBlock()) }
|
||||
@@ -647,23 +649,23 @@ class TranslatedCatchByTypeHandler extends TranslatedHandler {
|
||||
override TranslatedElement getChild(int id) {
|
||||
result = super.getChild(id)
|
||||
or
|
||||
id = 0 and result = getParameter()
|
||||
id = 0 and result = this.getParameter()
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
result = super.getChildSuccessor(child)
|
||||
or
|
||||
child = getParameter() and result = getBlock().getFirstInstruction()
|
||||
child = this.getParameter() and result = this.getBlock().getFirstInstruction()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = CatchTag() and
|
||||
(
|
||||
kind instanceof GotoEdge and
|
||||
result = getParameter().getFirstInstruction()
|
||||
result = this.getParameter().getFirstInstruction()
|
||||
or
|
||||
kind instanceof ExceptionEdge and
|
||||
result = getParent().(TranslatedTryStmt).getNextHandler(this)
|
||||
result = this.getParent().(TranslatedTryStmt).getNextHandler(this)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -692,7 +694,7 @@ class TranslatedCatchAnyHandler extends TranslatedHandler {
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = CatchTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = getBlock().getFirstInstruction()
|
||||
result = this.getBlock().getFirstInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -700,19 +702,19 @@ class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
|
||||
override IfStmt stmt;
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
if hasInitialization()
|
||||
then result = getInitialization().getFirstInstruction()
|
||||
else result = getFirstConditionInstruction()
|
||||
if this.hasInitialization()
|
||||
then result = this.getInitialization().getFirstInstruction()
|
||||
else result = this.getFirstConditionInstruction()
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getInitialization()
|
||||
id = 0 and result = this.getInitialization()
|
||||
or
|
||||
id = 1 and result = getCondition()
|
||||
id = 1 and result = this.getCondition()
|
||||
or
|
||||
id = 2 and result = getThen()
|
||||
id = 2 and result = this.getThen()
|
||||
or
|
||||
id = 3 and result = getElse()
|
||||
id = 3 and result = this.getElse()
|
||||
}
|
||||
|
||||
private predicate hasInitialization() { exists(stmt.getInitialization()) }
|
||||
@@ -726,7 +728,7 @@ class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
|
||||
}
|
||||
|
||||
private Instruction getFirstConditionInstruction() {
|
||||
result = getCondition().getFirstInstruction()
|
||||
result = this.getCondition().getFirstInstruction()
|
||||
}
|
||||
|
||||
private TranslatedStmt getThen() { result = getTranslatedStmt(stmt.getThen()) }
|
||||
@@ -738,23 +740,23 @@ class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
child = getCondition() and
|
||||
result = getThen().getFirstInstruction()
|
||||
child = this.getCondition() and
|
||||
result = this.getThen().getFirstInstruction()
|
||||
}
|
||||
|
||||
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
child = getCondition() and
|
||||
if hasElse()
|
||||
then result = getElse().getFirstInstruction()
|
||||
else result = getParent().getChildSuccessor(this)
|
||||
child = this.getCondition() and
|
||||
if this.hasElse()
|
||||
then result = this.getElse().getFirstInstruction()
|
||||
else result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getInitialization() and
|
||||
result = getFirstConditionInstruction()
|
||||
child = this.getInitialization() and
|
||||
result = this.getFirstConditionInstruction()
|
||||
or
|
||||
(child = getThen() or child = getElse()) and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
(child = this.getThen() or child = this.getElse()) and
|
||||
result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
@@ -772,17 +774,17 @@ abstract class TranslatedLoop extends TranslatedStmt, ConditionContext {
|
||||
final TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getStmt()) }
|
||||
|
||||
final Instruction getFirstConditionInstruction() {
|
||||
if hasCondition()
|
||||
then result = getCondition().getFirstInstruction()
|
||||
else result = getBody().getFirstInstruction()
|
||||
if this.hasCondition()
|
||||
then result = this.getCondition().getFirstInstruction()
|
||||
else result = this.getBody().getFirstInstruction()
|
||||
}
|
||||
|
||||
final predicate hasCondition() { exists(stmt.getCondition()) }
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getCondition()
|
||||
id = 0 and result = this.getCondition()
|
||||
or
|
||||
id = 1 and result = getBody()
|
||||
id = 1 and result = this.getBody()
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
@@ -792,31 +794,31 @@ abstract class TranslatedLoop extends TranslatedStmt, ConditionContext {
|
||||
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
final override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
child = getCondition() and result = getBody().getFirstInstruction()
|
||||
child = this.getCondition() and result = this.getBody().getFirstInstruction()
|
||||
}
|
||||
|
||||
final override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
child = getCondition() and result = getParent().getChildSuccessor(this)
|
||||
child = this.getCondition() and result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedWhileStmt extends TranslatedLoop {
|
||||
TranslatedWhileStmt() { stmt instanceof WhileStmt }
|
||||
|
||||
override Instruction getFirstInstruction() { result = getFirstConditionInstruction() }
|
||||
override Instruction getFirstInstruction() { result = this.getFirstConditionInstruction() }
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getBody() and result = getFirstConditionInstruction()
|
||||
child = this.getBody() and result = this.getFirstConditionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedDoStmt extends TranslatedLoop {
|
||||
TranslatedDoStmt() { stmt instanceof DoStmt }
|
||||
|
||||
override Instruction getFirstInstruction() { result = getBody().getFirstInstruction() }
|
||||
override Instruction getFirstInstruction() { result = this.getBody().getFirstInstruction() }
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getBody() and result = getFirstConditionInstruction()
|
||||
child = this.getBody() and result = this.getFirstConditionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -824,13 +826,13 @@ class TranslatedForStmt extends TranslatedLoop {
|
||||
override ForStmt stmt;
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getInitialization()
|
||||
id = 0 and result = this.getInitialization()
|
||||
or
|
||||
id = 1 and result = getCondition()
|
||||
id = 1 and result = this.getCondition()
|
||||
or
|
||||
id = 2 and result = getUpdate()
|
||||
id = 2 and result = this.getUpdate()
|
||||
or
|
||||
id = 3 and result = getBody()
|
||||
id = 3 and result = this.getBody()
|
||||
}
|
||||
|
||||
private TranslatedStmt getInitialization() {
|
||||
@@ -844,23 +846,23 @@ class TranslatedForStmt extends TranslatedLoop {
|
||||
private predicate hasUpdate() { exists(stmt.getUpdate()) }
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
if hasInitialization()
|
||||
then result = getInitialization().getFirstInstruction()
|
||||
else result = getFirstConditionInstruction()
|
||||
if this.hasInitialization()
|
||||
then result = this.getInitialization().getFirstInstruction()
|
||||
else result = this.getFirstConditionInstruction()
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getInitialization() and
|
||||
result = getFirstConditionInstruction()
|
||||
child = this.getInitialization() and
|
||||
result = this.getFirstConditionInstruction()
|
||||
or
|
||||
(
|
||||
child = getBody() and
|
||||
if hasUpdate()
|
||||
then result = getUpdate().getFirstInstruction()
|
||||
else result = getFirstConditionInstruction()
|
||||
child = this.getBody() and
|
||||
if this.hasUpdate()
|
||||
then result = this.getUpdate().getFirstInstruction()
|
||||
else result = this.getFirstConditionInstruction()
|
||||
)
|
||||
or
|
||||
child = getUpdate() and result = getFirstConditionInstruction()
|
||||
child = this.getUpdate() and result = this.getFirstConditionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -875,39 +877,39 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
|
||||
override RangeBasedForStmt stmt;
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getRangeVariableDeclStmt()
|
||||
id = 0 and result = this.getRangeVariableDeclStmt()
|
||||
or
|
||||
// Note: `__begin` and `__end` are declared by the same `DeclStmt`
|
||||
id = 1 and result = getBeginEndVariableDeclStmt()
|
||||
id = 1 and result = this.getBeginEndVariableDeclStmt()
|
||||
or
|
||||
id = 2 and result = getCondition()
|
||||
id = 2 and result = this.getCondition()
|
||||
or
|
||||
id = 3 and result = getUpdate()
|
||||
id = 3 and result = this.getUpdate()
|
||||
or
|
||||
id = 4 and result = getVariableDeclStmt()
|
||||
id = 4 and result = this.getVariableDeclStmt()
|
||||
or
|
||||
id = 5 and result = getBody()
|
||||
id = 5 and result = this.getBody()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = getRangeVariableDeclStmt().getFirstInstruction()
|
||||
result = this.getRangeVariableDeclStmt().getFirstInstruction()
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getRangeVariableDeclStmt() and
|
||||
result = getBeginEndVariableDeclStmt().getFirstInstruction()
|
||||
child = this.getRangeVariableDeclStmt() and
|
||||
result = this.getBeginEndVariableDeclStmt().getFirstInstruction()
|
||||
or
|
||||
child = getBeginEndVariableDeclStmt() and
|
||||
result = getCondition().getFirstInstruction()
|
||||
child = this.getBeginEndVariableDeclStmt() and
|
||||
result = this.getCondition().getFirstInstruction()
|
||||
or
|
||||
child = getVariableDeclStmt() and
|
||||
result = getBody().getFirstInstruction()
|
||||
child = this.getVariableDeclStmt() and
|
||||
result = this.getBody().getFirstInstruction()
|
||||
or
|
||||
child = getBody() and
|
||||
result = getUpdate().getFirstInstruction()
|
||||
child = this.getBody() and
|
||||
result = this.getUpdate().getFirstInstruction()
|
||||
or
|
||||
child = getUpdate() and
|
||||
result = getCondition().getFirstInstruction()
|
||||
child = this.getUpdate() and
|
||||
result = this.getCondition().getFirstInstruction()
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
@@ -917,11 +919,11 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
child = getCondition() and result = getVariableDeclStmt().getFirstInstruction()
|
||||
child = this.getCondition() and result = this.getVariableDeclStmt().getFirstInstruction()
|
||||
}
|
||||
|
||||
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
child = getCondition() and result = getParent().getChildSuccessor(this)
|
||||
child = this.getCondition() and result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
private TranslatedDeclStmt getRangeVariableDeclStmt() {
|
||||
@@ -961,7 +963,7 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
|
||||
class TranslatedJumpStmt extends TranslatedStmt {
|
||||
override JumpStmt stmt;
|
||||
|
||||
override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
|
||||
override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) }
|
||||
|
||||
override TranslatedElement getChild(int id) { none() }
|
||||
|
||||
@@ -996,22 +998,22 @@ class TranslatedSwitchStmt extends TranslatedStmt {
|
||||
result = getTranslatedExpr(stmt.getExpr().getFullyConverted())
|
||||
}
|
||||
|
||||
private Instruction getFirstExprInstruction() { result = getExpr().getFirstInstruction() }
|
||||
private Instruction getFirstExprInstruction() { result = this.getExpr().getFirstInstruction() }
|
||||
|
||||
private TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getStmt()) }
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
if hasInitialization()
|
||||
then result = getInitialization().getFirstInstruction()
|
||||
else result = getFirstExprInstruction()
|
||||
if this.hasInitialization()
|
||||
then result = this.getInitialization().getFirstInstruction()
|
||||
else result = this.getFirstExprInstruction()
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
id = 0 and result = getInitialization()
|
||||
id = 0 and result = this.getInitialization()
|
||||
or
|
||||
id = 1 and result = getExpr()
|
||||
id = 1 and result = this.getExpr()
|
||||
or
|
||||
id = 2 and result = getBody()
|
||||
id = 2 and result = this.getBody()
|
||||
}
|
||||
|
||||
private predicate hasInitialization() { exists(stmt.getInitialization()) }
|
||||
@@ -1029,7 +1031,7 @@ class TranslatedSwitchStmt extends TranslatedStmt {
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = SwitchBranchTag() and
|
||||
operandTag instanceof ConditionOperandTag and
|
||||
result = getExpr().getResult()
|
||||
result = this.getExpr().getResult()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
@@ -1043,15 +1045,15 @@ class TranslatedSwitchStmt extends TranslatedStmt {
|
||||
not stmt.hasDefaultCase() and
|
||||
tag = SwitchBranchTag() and
|
||||
kind instanceof DefaultEdge and
|
||||
result = getParent().getChildSuccessor(this)
|
||||
result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getInitialization() and result = getFirstExprInstruction()
|
||||
child = this.getInitialization() and result = this.getFirstExprInstruction()
|
||||
or
|
||||
child = getExpr() and result = getInstruction(SwitchBranchTag())
|
||||
child = this.getExpr() and result = this.getInstruction(SwitchBranchTag())
|
||||
or
|
||||
child = getBody() and result = getParent().getChildSuccessor(this)
|
||||
child = this.getBody() and result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1063,9 +1065,9 @@ class TranslatedAsmStmt extends TranslatedStmt {
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
if exists(getChild(0))
|
||||
then result = getChild(0).getFirstInstruction()
|
||||
else result = getInstruction(AsmTag())
|
||||
if exists(this.getChild(0))
|
||||
then result = this.getChild(0).getFirstInstruction()
|
||||
else result = this.getInstruction(AsmTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
@@ -1078,7 +1080,7 @@ class TranslatedAsmStmt extends TranslatedStmt {
|
||||
exists(int index |
|
||||
tag = AsmTag() and
|
||||
operandTag = asmOperand(index) and
|
||||
result = getChild(index).getResult()
|
||||
result = this.getChild(index).getResult()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1092,16 +1094,16 @@ class TranslatedAsmStmt extends TranslatedStmt {
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = AsmTag() and
|
||||
result = getParent().getChildSuccessor(this) and
|
||||
result = this.getParent().getChildSuccessor(this) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
exists(int index |
|
||||
child = getChild(index) and
|
||||
if exists(getChild(index + 1))
|
||||
then result = getChild(index + 1).getFirstInstruction()
|
||||
else result = getInstruction(AsmTag())
|
||||
child = this.getChild(index) and
|
||||
if exists(this.getChild(index + 1))
|
||||
then result = this.getChild(index + 1).getFirstInstruction()
|
||||
else result = this.getInstruction(AsmTag())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@ predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) {
|
||||
conditionValue = getConstantValue(instr.(ConditionalBranchInstruction).getCondition()) and
|
||||
if conditionValue = 0 then kind instanceof TrueEdge else kind instanceof FalseEdge
|
||||
)
|
||||
or
|
||||
instr.getSuccessor(kind) instanceof UnreachedInstruction and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -41,7 +44,9 @@ class ReachableBlock extends IRBlockBase {
|
||||
* An instruction that is contained in a reachable block.
|
||||
*/
|
||||
class ReachableInstruction extends Instruction {
|
||||
ReachableInstruction() { this.getBlock() instanceof ReachableBlock }
|
||||
ReachableInstruction() {
|
||||
this.getBlock() instanceof ReachableBlock and not this instanceof UnreachedInstruction
|
||||
}
|
||||
}
|
||||
|
||||
module Graph {
|
||||
|
||||
@@ -34,9 +34,13 @@ private module Cached {
|
||||
|
||||
cached
|
||||
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
exists(OldIR::Instruction oldInstruction |
|
||||
irFunc = oldInstruction.getEnclosingIRFunction() and
|
||||
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
||||
(
|
||||
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
||||
or
|
||||
oldInstruction.getOpcode() instanceof Opcode::Unreached
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -366,21 +370,19 @@ private module Cached {
|
||||
then
|
||||
result = getChi(getOldInstruction(instruction)) and
|
||||
kind instanceof GotoEdge
|
||||
else (
|
||||
else
|
||||
exists(OldInstruction oldInstruction |
|
||||
oldInstruction = getOldInstruction(instruction) and
|
||||
(
|
||||
oldInstruction = getOldInstruction(instruction)
|
||||
or
|
||||
instruction = getChi(oldInstruction)
|
||||
) and
|
||||
(
|
||||
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
|
||||
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
|
||||
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = getChi(oldInstruction) and
|
||||
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
|
||||
@@ -7,6 +7,9 @@ predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) {
|
||||
conditionValue = getConstantValue(instr.(ConditionalBranchInstruction).getCondition()) and
|
||||
if conditionValue = 0 then kind instanceof TrueEdge else kind instanceof FalseEdge
|
||||
)
|
||||
or
|
||||
instr.getSuccessor(kind) instanceof UnreachedInstruction and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -41,7 +44,9 @@ class ReachableBlock extends IRBlockBase {
|
||||
* An instruction that is contained in a reachable block.
|
||||
*/
|
||||
class ReachableInstruction extends Instruction {
|
||||
ReachableInstruction() { this.getBlock() instanceof ReachableBlock }
|
||||
ReachableInstruction() {
|
||||
this.getBlock() instanceof ReachableBlock and not this instanceof UnreachedInstruction
|
||||
}
|
||||
}
|
||||
|
||||
module Graph {
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
## 0.6.1
|
||||
|
||||
### New Queries
|
||||
|
||||
* A new query `cpp/double-free` has been added. The query finds possible cases of deallocating the same pointer twice. The precision of the query has been set to "medium".
|
||||
* The query `cpp/use-after-free` has been modernized and assigned the precision "medium". The query finds cases of where a pointer is dereferenced after its memory has been deallocated.
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### New Queries
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* A new query `cpp/double-free` has been added. The query finds possible cases of deallocating the same pointer twice. The precision of the query has been set to "medium".
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* The query `cpp/use-after-free` has been modernized and assigned the precision "medium". The query finds cases of where a pointer is dereferenced after its memory has been deallocated.
|
||||
6
cpp/ql/src/change-notes/released/0.6.1.md
Normal file
6
cpp/ql/src/change-notes/released/0.6.1.md
Normal file
@@ -0,0 +1,6 @@
|
||||
## 0.6.1
|
||||
|
||||
### New Queries
|
||||
|
||||
* A new query `cpp/double-free` has been added. The query finds possible cases of deallocating the same pointer twice. The precision of the query has been set to "medium".
|
||||
* The query `cpp/use-after-free` has been modernized and assigned the precision "medium". The query finds cases of where a pointer is dereferenced after its memory has been deallocated.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.0
|
||||
lastReleaseVersion: 0.6.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.6.1-dev
|
||||
version: 0.6.2-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -209,6 +209,9 @@ edges
|
||||
| test.cpp:207:17:207:19 | str indirection [string] | test.cpp:207:22:207:27 | string |
|
||||
| test.cpp:207:17:207:19 | str indirection [string] | test.cpp:207:22:207:27 | string indirection |
|
||||
| test.cpp:207:22:207:27 | string indirection | test.cpp:207:22:207:27 | string |
|
||||
| test.cpp:214:24:214:24 | p | test.cpp:216:10:216:10 | p |
|
||||
| test.cpp:220:43:220:48 | call to malloc | test.cpp:222:15:222:20 | buffer |
|
||||
| test.cpp:222:15:222:20 | buffer | test.cpp:214:24:214:24 | p |
|
||||
nodes
|
||||
| test.cpp:16:11:16:21 | mk_string_t indirection [string] | semmle.label | mk_string_t indirection [string] |
|
||||
| test.cpp:18:5:18:30 | ... = ... | semmle.label | ... = ... |
|
||||
@@ -374,6 +377,10 @@ nodes
|
||||
| test.cpp:207:17:207:19 | str indirection [string] | semmle.label | str indirection [string] |
|
||||
| test.cpp:207:22:207:27 | string | semmle.label | string |
|
||||
| test.cpp:207:22:207:27 | string indirection | semmle.label | string indirection |
|
||||
| test.cpp:214:24:214:24 | p | semmle.label | p |
|
||||
| test.cpp:216:10:216:10 | p | semmle.label | p |
|
||||
| test.cpp:220:43:220:48 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:222:15:222:20 | buffer | semmle.label | buffer |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:42:5:42:11 | call to strncpy | test.cpp:18:19:18:24 | call to malloc | test.cpp:42:18:42:23 | string | This write may overflow $@ by 1 element. | test.cpp:42:18:42:23 | string | string |
|
||||
@@ -391,3 +398,4 @@ subpaths
|
||||
| test.cpp:199:9:199:15 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:199:22:199:27 | string | This write may overflow $@ by 2 elements. | test.cpp:199:22:199:27 | string | string |
|
||||
| test.cpp:203:9:203:15 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:203:22:203:27 | string | This write may overflow $@ by 2 elements. | test.cpp:203:22:203:27 | string | string |
|
||||
| test.cpp:207:9:207:15 | call to strncpy | test.cpp:147:19:147:24 | call to malloc | test.cpp:207:22:207:27 | string | This write may overflow $@ by 3 elements. | test.cpp:207:22:207:27 | string | string |
|
||||
| test.cpp:216:3:216:8 | call to memset | test.cpp:220:43:220:48 | call to malloc | test.cpp:216:10:216:10 | p | This write may overflow $@ by 5 elements. | test.cpp:216:10:216:10 | p | p |
|
||||
|
||||
@@ -208,3 +208,16 @@ void test5(unsigned size, char *buf, unsigned anotherSize) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void *memset(void *, int, unsigned);
|
||||
|
||||
void call_memset(void *p, unsigned size)
|
||||
{
|
||||
memset(p, 0, size); // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
void test_missing_call_context(unsigned char *unrelated_buffer, unsigned size) {
|
||||
unsigned char* buffer = (unsigned char*)malloc(size);
|
||||
call_memset(unrelated_buffer, size + 5);
|
||||
call_memset(buffer, size);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
int source();
|
||||
void sink(int);
|
||||
void sink(...);
|
||||
bool guarded(int);
|
||||
|
||||
void bg_basic(int source) {
|
||||
@@ -66,3 +66,13 @@ void bg_structptr(XY *p1, XY *p2) { // $ ast-def=p1 ast-def=p2
|
||||
sink(p1->x); // $ ast,ir
|
||||
}
|
||||
}
|
||||
|
||||
int* indirect_source();
|
||||
bool guarded(const int*);
|
||||
|
||||
void bg_indirect_expr() {
|
||||
int *buf = indirect_source();
|
||||
if (guarded(buf)) {
|
||||
sink(buf);
|
||||
}
|
||||
}
|
||||
@@ -115,6 +115,16 @@ postWithInFlow
|
||||
| test.cpp:602:3:602:7 | access to array [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:608:3:608:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:608:4:608:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:639:3:639:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:646:3:646:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:652:3:652:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:653:3:653:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:659:3:659:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:660:3:660:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:671:3:671:3 | s [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:681:3:681:3 | s [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:689:3:689:3 | s [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:690:3:690:3 | s [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
viableImplInCallContextTooLarge
|
||||
uniqueParameterNodeAtPosition
|
||||
uniqueParameterNodePosition
|
||||
|
||||
@@ -627,4 +627,66 @@ void test_def_via_phi_read(bool b)
|
||||
}
|
||||
intPointerSource(buffer);
|
||||
sink(buffer); // $ ast,ir
|
||||
}
|
||||
}
|
||||
|
||||
void test_static_local_1() {
|
||||
static int x = source();
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
void test_static_local_2() {
|
||||
static int x = source();
|
||||
x = 0;
|
||||
sink(x); // clean
|
||||
}
|
||||
|
||||
void test_static_local_3() {
|
||||
static int x = 0;
|
||||
sink(x); // $ ir MISSING: ast
|
||||
x = source();
|
||||
}
|
||||
|
||||
void test_static_local_4() {
|
||||
static int x = 0;
|
||||
sink(x); // clean
|
||||
x = source();
|
||||
x = 0;
|
||||
}
|
||||
|
||||
void test_static_local_5() {
|
||||
static int x = 0;
|
||||
sink(x); // $ ir MISSING: ast
|
||||
x = 0;
|
||||
x = source();
|
||||
}
|
||||
|
||||
void test_static_local_6() {
|
||||
static int s = source();
|
||||
static int* ptr_to_s = &s;
|
||||
sink(*ptr_to_s); // $ ir MISSING: ast
|
||||
}
|
||||
|
||||
void test_static_local_7() {
|
||||
static int s = source();
|
||||
s = 0;
|
||||
static int* ptr_to_s = &s;
|
||||
sink(*ptr_to_s); // clean
|
||||
}
|
||||
|
||||
void test_static_local_8() {
|
||||
static int s;
|
||||
static int* ptr_to_s = &s;
|
||||
sink(*ptr_to_s); // $ ir MISSING: ast
|
||||
|
||||
s = source();
|
||||
}
|
||||
|
||||
void test_static_local_9() {
|
||||
static int s;
|
||||
static int* ptr_to_s = &s;
|
||||
sink(*ptr_to_s); // clean
|
||||
|
||||
s = source();
|
||||
s = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ module AstTest {
|
||||
}
|
||||
|
||||
module IRTest {
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.controlflow.IRGuards
|
||||
@@ -56,10 +57,13 @@ module IRTest {
|
||||
* S in `if (guarded(x)) S`.
|
||||
*/
|
||||
// This is tested in `BarrierGuard.cpp`.
|
||||
predicate testBarrierGuard(IRGuardCondition g, Instruction checked, boolean isTrue) {
|
||||
g.(CallInstruction).getStaticCallTarget().getName() = "guarded" and
|
||||
checked = g.(CallInstruction).getPositionalArgument(0) and
|
||||
isTrue = true
|
||||
predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean isTrue) {
|
||||
exists(Call call |
|
||||
call = g.getUnconvertedResultExpression() and
|
||||
call.getTarget().hasName("guarded") and
|
||||
checked = call.getArgument(0) and
|
||||
isTrue = true
|
||||
)
|
||||
}
|
||||
|
||||
/** Common data flow configuration to be used by tests. */
|
||||
@@ -90,7 +94,9 @@ module IRTest {
|
||||
barrierExpr.(VariableAccess).getTarget().hasName("barrier")
|
||||
)
|
||||
or
|
||||
barrier = DataFlow::InstructionBarrierGuard<testBarrierGuard/3>::getABarrierNode()
|
||||
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getABarrierNode()
|
||||
or
|
||||
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getAnIndirectBarrierNode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14408,6 +14408,60 @@ ir.cpp:
|
||||
# 1894| Conversion = [IntegralConversion] integral conversion
|
||||
# 1894| Type = [IntType] int
|
||||
# 1894| ValueCategory = prvalue
|
||||
# 1897| [TopLevelFunction] void noreturnFunc()
|
||||
# 1897| <params>:
|
||||
# 1899| [TopLevelFunction] int noreturnTest(int)
|
||||
# 1899| <params>:
|
||||
# 1899| getParameter(0): [Parameter] x
|
||||
# 1899| Type = [IntType] int
|
||||
# 1899| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1900| getStmt(0): [IfStmt] if (...) ...
|
||||
# 1900| getCondition(): [LTExpr] ... < ...
|
||||
# 1900| Type = [BoolType] bool
|
||||
# 1900| ValueCategory = prvalue
|
||||
# 1900| getLesserOperand(): [VariableAccess] x
|
||||
# 1900| Type = [IntType] int
|
||||
# 1900| ValueCategory = prvalue(load)
|
||||
# 1900| getGreaterOperand(): [Literal] 10
|
||||
# 1900| Type = [IntType] int
|
||||
# 1900| Value = [Literal] 10
|
||||
# 1900| ValueCategory = prvalue
|
||||
# 1900| getThen(): [BlockStmt] { ... }
|
||||
# 1901| getStmt(0): [ReturnStmt] return ...
|
||||
# 1901| getExpr(): [VariableAccess] x
|
||||
# 1901| Type = [IntType] int
|
||||
# 1901| ValueCategory = prvalue(load)
|
||||
# 1902| getElse(): [BlockStmt] { ... }
|
||||
# 1903| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 1903| getExpr(): [FunctionCall] call to noreturnFunc
|
||||
# 1903| Type = [VoidType] void
|
||||
# 1903| ValueCategory = prvalue
|
||||
# 1905| getStmt(1): [ReturnStmt] return ...
|
||||
# 1907| [TopLevelFunction] int noreturnTest2(int)
|
||||
# 1907| <params>:
|
||||
# 1907| getParameter(0): [Parameter] x
|
||||
# 1907| Type = [IntType] int
|
||||
# 1907| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1908| getStmt(0): [IfStmt] if (...) ...
|
||||
# 1908| getCondition(): [LTExpr] ... < ...
|
||||
# 1908| Type = [BoolType] bool
|
||||
# 1908| ValueCategory = prvalue
|
||||
# 1908| getLesserOperand(): [VariableAccess] x
|
||||
# 1908| Type = [IntType] int
|
||||
# 1908| ValueCategory = prvalue(load)
|
||||
# 1908| getGreaterOperand(): [Literal] 10
|
||||
# 1908| Type = [IntType] int
|
||||
# 1908| Value = [Literal] 10
|
||||
# 1908| ValueCategory = prvalue
|
||||
# 1908| getThen(): [BlockStmt] { ... }
|
||||
# 1909| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 1909| getExpr(): [FunctionCall] call to noreturnFunc
|
||||
# 1909| Type = [VoidType] void
|
||||
# 1909| ValueCategory = prvalue
|
||||
# 1911| getStmt(1): [ReturnStmt] return ...
|
||||
# 1911| getExpr(): [VariableAccess] x
|
||||
# 1911| Type = [IntType] int
|
||||
# 1911| ValueCategory = prvalue(load)
|
||||
perf-regression.cpp:
|
||||
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
|
||||
# 4| <params>:
|
||||
|
||||
@@ -1894,4 +1894,21 @@ int test_global_template_int() {
|
||||
return local_int + (int)local_char;
|
||||
}
|
||||
|
||||
[[noreturn]] void noreturnFunc();
|
||||
|
||||
int noreturnTest(int x) {
|
||||
if (x < 10) {
|
||||
return x;
|
||||
} else {
|
||||
noreturnFunc();
|
||||
}
|
||||
}
|
||||
|
||||
int noreturnTest2(int x) {
|
||||
if (x < 10) {
|
||||
noreturnFunc();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++17 --clang
|
||||
|
||||
@@ -8783,6 +8783,44 @@
|
||||
| ir.cpp:1894:29:1894:38 | Address | &:r1894_4 |
|
||||
| ir.cpp:1894:29:1894:38 | Load | m1893_4 |
|
||||
| ir.cpp:1894:29:1894:38 | Unary | r1894_5 |
|
||||
| ir.cpp:1899:5:1899:16 | Address | &:r1899_7 |
|
||||
| ir.cpp:1899:5:1899:16 | ChiPartial | partial:m1899_3 |
|
||||
| ir.cpp:1899:5:1899:16 | ChiTotal | total:m1899_2 |
|
||||
| ir.cpp:1899:5:1899:16 | Load | m1901_4 |
|
||||
| ir.cpp:1899:5:1899:16 | SideEffect | m1899_3 |
|
||||
| ir.cpp:1899:22:1899:22 | Address | &:r1899_5 |
|
||||
| ir.cpp:1900:9:1900:9 | Address | &:r1900_1 |
|
||||
| ir.cpp:1900:9:1900:9 | Left | r1900_2 |
|
||||
| ir.cpp:1900:9:1900:9 | Load | m1899_6 |
|
||||
| ir.cpp:1900:9:1900:14 | Condition | r1900_4 |
|
||||
| ir.cpp:1900:13:1900:14 | Right | r1900_3 |
|
||||
| ir.cpp:1901:9:1901:17 | Address | &:r1901_1 |
|
||||
| ir.cpp:1901:16:1901:16 | Address | &:r1901_2 |
|
||||
| ir.cpp:1901:16:1901:16 | Load | m1899_6 |
|
||||
| ir.cpp:1901:16:1901:16 | StoreValue | r1901_3 |
|
||||
| ir.cpp:1903:9:1903:20 | CallTarget | func:r1903_1 |
|
||||
| ir.cpp:1903:9:1903:20 | ChiPartial | partial:m1903_3 |
|
||||
| ir.cpp:1903:9:1903:20 | ChiTotal | total:m1899_4 |
|
||||
| ir.cpp:1903:9:1903:20 | SideEffect | ~m1899_4 |
|
||||
| ir.cpp:1907:5:1907:17 | Address | &:r1907_8 |
|
||||
| ir.cpp:1907:5:1907:17 | ChiPartial | partial:m1907_3 |
|
||||
| ir.cpp:1907:5:1907:17 | ChiTotal | total:m1907_2 |
|
||||
| ir.cpp:1907:5:1907:17 | Load | m1911_4 |
|
||||
| ir.cpp:1907:5:1907:17 | SideEffect | m1907_3 |
|
||||
| ir.cpp:1907:23:1907:23 | Address | &:r1907_5 |
|
||||
| ir.cpp:1908:9:1908:9 | Address | &:r1908_1 |
|
||||
| ir.cpp:1908:9:1908:9 | Left | r1908_2 |
|
||||
| ir.cpp:1908:9:1908:9 | Load | m1907_6 |
|
||||
| ir.cpp:1908:9:1908:14 | Condition | r1908_4 |
|
||||
| ir.cpp:1908:13:1908:14 | Right | r1908_3 |
|
||||
| ir.cpp:1909:9:1909:20 | CallTarget | func:r1909_1 |
|
||||
| ir.cpp:1909:9:1909:20 | ChiPartial | partial:m1909_3 |
|
||||
| ir.cpp:1909:9:1909:20 | ChiTotal | total:m1907_4 |
|
||||
| ir.cpp:1909:9:1909:20 | SideEffect | ~m1907_4 |
|
||||
| ir.cpp:1911:5:1911:13 | Address | &:r1911_1 |
|
||||
| ir.cpp:1911:12:1911:12 | Address | &:r1911_2 |
|
||||
| ir.cpp:1911:12:1911:12 | Load | m1907_6 |
|
||||
| ir.cpp:1911:12:1911:12 | StoreValue | r1911_3 |
|
||||
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
|
||||
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
|
||||
| perf-regression.cpp:6:3:6:5 | Address | &:r6_7 |
|
||||
|
||||
@@ -10105,6 +10105,68 @@ ir.cpp:
|
||||
# 1891| v1891_6(void) = AliasedUse : ~m?
|
||||
# 1891| v1891_7(void) = ExitFunction :
|
||||
|
||||
# 1899| int noreturnTest(int)
|
||||
# 1899| Block 0
|
||||
# 1899| v1899_1(void) = EnterFunction :
|
||||
# 1899| mu1899_2(unknown) = AliasedDefinition :
|
||||
# 1899| mu1899_3(unknown) = InitializeNonLocal :
|
||||
# 1899| r1899_4(glval<int>) = VariableAddress[x] :
|
||||
# 1899| mu1899_5(int) = InitializeParameter[x] : &:r1899_4
|
||||
# 1900| r1900_1(glval<int>) = VariableAddress[x] :
|
||||
# 1900| r1900_2(int) = Load[x] : &:r1900_1, ~m?
|
||||
# 1900| r1900_3(int) = Constant[10] :
|
||||
# 1900| r1900_4(bool) = CompareLT : r1900_2, r1900_3
|
||||
# 1900| v1900_5(void) = ConditionalBranch : r1900_4
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 1901| Block 1
|
||||
# 1901| r1901_1(glval<int>) = VariableAddress[#return] :
|
||||
# 1901| r1901_2(glval<int>) = VariableAddress[x] :
|
||||
# 1901| r1901_3(int) = Load[x] : &:r1901_2, ~m?
|
||||
# 1901| mu1901_4(int) = Store[#return] : &:r1901_1, r1901_3
|
||||
# 1899| r1899_6(glval<int>) = VariableAddress[#return] :
|
||||
# 1899| v1899_7(void) = ReturnValue : &:r1899_6, ~m?
|
||||
# 1899| v1899_8(void) = AliasedUse : ~m?
|
||||
# 1899| v1899_9(void) = ExitFunction :
|
||||
|
||||
# 1903| Block 2
|
||||
# 1903| r1903_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
|
||||
# 1903| v1903_2(void) = Call[noreturnFunc] : func:r1903_1
|
||||
# 1903| mu1903_3(unknown) = ^CallSideEffect : ~m?
|
||||
# 1905| v1905_1(void) = Unreached :
|
||||
|
||||
# 1907| int noreturnTest2(int)
|
||||
# 1907| Block 0
|
||||
# 1907| v1907_1(void) = EnterFunction :
|
||||
# 1907| mu1907_2(unknown) = AliasedDefinition :
|
||||
# 1907| mu1907_3(unknown) = InitializeNonLocal :
|
||||
# 1907| r1907_4(glval<int>) = VariableAddress[x] :
|
||||
# 1907| mu1907_5(int) = InitializeParameter[x] : &:r1907_4
|
||||
# 1908| r1908_1(glval<int>) = VariableAddress[x] :
|
||||
# 1908| r1908_2(int) = Load[x] : &:r1908_1, ~m?
|
||||
# 1908| r1908_3(int) = Constant[10] :
|
||||
# 1908| r1908_4(bool) = CompareLT : r1908_2, r1908_3
|
||||
# 1908| v1908_5(void) = ConditionalBranch : r1908_4
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 1909| Block 1
|
||||
# 1909| r1909_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
|
||||
# 1909| v1909_2(void) = Call[noreturnFunc] : func:r1909_1
|
||||
# 1909| mu1909_3(unknown) = ^CallSideEffect : ~m?
|
||||
# 1907| v1907_6(void) = Unreached :
|
||||
|
||||
# 1911| Block 2
|
||||
# 1911| r1911_1(glval<int>) = VariableAddress[#return] :
|
||||
# 1911| r1911_2(glval<int>) = VariableAddress[x] :
|
||||
# 1911| r1911_3(int) = Load[x] : &:r1911_2, ~m?
|
||||
# 1911| mu1911_4(int) = Store[#return] : &:r1911_1, r1911_3
|
||||
# 1907| r1907_7(glval<int>) = VariableAddress[#return] :
|
||||
# 1907| v1907_8(void) = ReturnValue : &:r1907_7, ~m?
|
||||
# 1907| v1907_9(void) = AliasedUse : ~m?
|
||||
# 1907| v1907_10(void) = ExitFunction :
|
||||
|
||||
perf-regression.cpp:
|
||||
# 6| void Big::Big()
|
||||
# 6| Block 0
|
||||
|
||||
@@ -2091,3 +2091,69 @@ ssa.cpp:
|
||||
# 417| v417_5(void) = ReturnVoid :
|
||||
# 417| v417_6(void) = AliasedUse : m417_3
|
||||
# 417| v417_7(void) = ExitFunction :
|
||||
|
||||
# 423| int noreturnTest(int)
|
||||
# 423| Block 0
|
||||
# 423| v423_1(void) = EnterFunction :
|
||||
# 423| m423_2(unknown) = AliasedDefinition :
|
||||
# 423| m423_3(unknown) = InitializeNonLocal :
|
||||
# 423| m423_4(unknown) = Chi : total:m423_2, partial:m423_3
|
||||
# 423| r423_5(glval<int>) = VariableAddress[x] :
|
||||
# 423| m423_6(int) = InitializeParameter[x] : &:r423_5
|
||||
# 424| r424_1(glval<int>) = VariableAddress[x] :
|
||||
# 424| r424_2(int) = Load[x] : &:r424_1, m423_6
|
||||
# 424| r424_3(int) = Constant[10] :
|
||||
# 424| r424_4(bool) = CompareLT : r424_2, r424_3
|
||||
# 424| v424_5(void) = ConditionalBranch : r424_4
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 425| Block 1
|
||||
# 425| r425_1(glval<int>) = VariableAddress[#return] :
|
||||
# 425| r425_2(glval<int>) = VariableAddress[x] :
|
||||
# 425| r425_3(int) = Load[x] : &:r425_2, m423_6
|
||||
# 425| m425_4(int) = Store[#return] : &:r425_1, r425_3
|
||||
# 423| r423_7(glval<int>) = VariableAddress[#return] :
|
||||
# 423| v423_8(void) = ReturnValue : &:r423_7, m425_4
|
||||
# 423| v423_9(void) = AliasedUse : m423_3
|
||||
# 423| v423_10(void) = ExitFunction :
|
||||
|
||||
# 427| Block 2
|
||||
# 427| r427_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
|
||||
# 427| v427_2(void) = Call[noreturnFunc] : func:r427_1
|
||||
# 427| m427_3(unknown) = ^CallSideEffect : ~m423_4
|
||||
# 427| m427_4(unknown) = Chi : total:m423_4, partial:m427_3
|
||||
# 423| v423_11(void) = Unreached :
|
||||
|
||||
# 431| int noreturnTest2(int)
|
||||
# 431| Block 0
|
||||
# 431| v431_1(void) = EnterFunction :
|
||||
# 431| m431_2(unknown) = AliasedDefinition :
|
||||
# 431| m431_3(unknown) = InitializeNonLocal :
|
||||
# 431| m431_4(unknown) = Chi : total:m431_2, partial:m431_3
|
||||
# 431| r431_5(glval<int>) = VariableAddress[x] :
|
||||
# 431| m431_6(int) = InitializeParameter[x] : &:r431_5
|
||||
# 432| r432_1(glval<int>) = VariableAddress[x] :
|
||||
# 432| r432_2(int) = Load[x] : &:r432_1, m431_6
|
||||
# 432| r432_3(int) = Constant[10] :
|
||||
# 432| r432_4(bool) = CompareLT : r432_2, r432_3
|
||||
# 432| v432_5(void) = ConditionalBranch : r432_4
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 433| Block 1
|
||||
# 433| r433_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
|
||||
# 433| v433_2(void) = Call[noreturnFunc] : func:r433_1
|
||||
# 433| m433_3(unknown) = ^CallSideEffect : ~m431_4
|
||||
# 433| m433_4(unknown) = Chi : total:m431_4, partial:m433_3
|
||||
# 431| v431_7(void) = Unreached :
|
||||
|
||||
# 435| Block 2
|
||||
# 435| r435_1(glval<int>) = VariableAddress[#return] :
|
||||
# 435| r435_2(glval<int>) = VariableAddress[x] :
|
||||
# 435| r435_3(int) = Load[x] : &:r435_2, m431_6
|
||||
# 435| m435_4(int) = Store[#return] : &:r435_1, r435_3
|
||||
# 431| r431_8(glval<int>) = VariableAddress[#return] :
|
||||
# 431| v431_9(void) = ReturnValue : &:r431_8, m435_4
|
||||
# 431| v431_10(void) = AliasedUse : m431_3
|
||||
# 431| v431_11(void) = ExitFunction :
|
||||
|
||||
@@ -2080,3 +2080,69 @@ ssa.cpp:
|
||||
# 417| v417_5(void) = ReturnVoid :
|
||||
# 417| v417_6(void) = AliasedUse : m417_3
|
||||
# 417| v417_7(void) = ExitFunction :
|
||||
|
||||
# 423| int noreturnTest(int)
|
||||
# 423| Block 0
|
||||
# 423| v423_1(void) = EnterFunction :
|
||||
# 423| m423_2(unknown) = AliasedDefinition :
|
||||
# 423| m423_3(unknown) = InitializeNonLocal :
|
||||
# 423| m423_4(unknown) = Chi : total:m423_2, partial:m423_3
|
||||
# 423| r423_5(glval<int>) = VariableAddress[x] :
|
||||
# 423| m423_6(int) = InitializeParameter[x] : &:r423_5
|
||||
# 424| r424_1(glval<int>) = VariableAddress[x] :
|
||||
# 424| r424_2(int) = Load[x] : &:r424_1, m423_6
|
||||
# 424| r424_3(int) = Constant[10] :
|
||||
# 424| r424_4(bool) = CompareLT : r424_2, r424_3
|
||||
# 424| v424_5(void) = ConditionalBranch : r424_4
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 425| Block 1
|
||||
# 425| r425_1(glval<int>) = VariableAddress[#return] :
|
||||
# 425| r425_2(glval<int>) = VariableAddress[x] :
|
||||
# 425| r425_3(int) = Load[x] : &:r425_2, m423_6
|
||||
# 425| m425_4(int) = Store[#return] : &:r425_1, r425_3
|
||||
# 423| r423_7(glval<int>) = VariableAddress[#return] :
|
||||
# 423| v423_8(void) = ReturnValue : &:r423_7, m425_4
|
||||
# 423| v423_9(void) = AliasedUse : m423_3
|
||||
# 423| v423_10(void) = ExitFunction :
|
||||
|
||||
# 427| Block 2
|
||||
# 427| r427_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
|
||||
# 427| v427_2(void) = Call[noreturnFunc] : func:r427_1
|
||||
# 427| m427_3(unknown) = ^CallSideEffect : ~m423_4
|
||||
# 427| m427_4(unknown) = Chi : total:m423_4, partial:m427_3
|
||||
# 423| v423_11(void) = Unreached :
|
||||
|
||||
# 431| int noreturnTest2(int)
|
||||
# 431| Block 0
|
||||
# 431| v431_1(void) = EnterFunction :
|
||||
# 431| m431_2(unknown) = AliasedDefinition :
|
||||
# 431| m431_3(unknown) = InitializeNonLocal :
|
||||
# 431| m431_4(unknown) = Chi : total:m431_2, partial:m431_3
|
||||
# 431| r431_5(glval<int>) = VariableAddress[x] :
|
||||
# 431| m431_6(int) = InitializeParameter[x] : &:r431_5
|
||||
# 432| r432_1(glval<int>) = VariableAddress[x] :
|
||||
# 432| r432_2(int) = Load[x] : &:r432_1, m431_6
|
||||
# 432| r432_3(int) = Constant[10] :
|
||||
# 432| r432_4(bool) = CompareLT : r432_2, r432_3
|
||||
# 432| v432_5(void) = ConditionalBranch : r432_4
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 433| Block 1
|
||||
# 433| r433_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
|
||||
# 433| v433_2(void) = Call[noreturnFunc] : func:r433_1
|
||||
# 433| m433_3(unknown) = ^CallSideEffect : ~m431_4
|
||||
# 433| m433_4(unknown) = Chi : total:m431_4, partial:m433_3
|
||||
# 431| v431_7(void) = Unreached :
|
||||
|
||||
# 435| Block 2
|
||||
# 435| r435_1(glval<int>) = VariableAddress[#return] :
|
||||
# 435| r435_2(glval<int>) = VariableAddress[x] :
|
||||
# 435| r435_3(int) = Load[x] : &:r435_2, m431_6
|
||||
# 435| m435_4(int) = Store[#return] : &:r435_1, r435_3
|
||||
# 431| r431_8(glval<int>) = VariableAddress[#return] :
|
||||
# 431| v431_9(void) = ReturnValue : &:r431_8, m435_4
|
||||
# 431| v431_10(void) = AliasedUse : m431_3
|
||||
# 431| v431_11(void) = ExitFunction :
|
||||
|
||||
@@ -417,3 +417,20 @@ void vla(int n1, int n2, int n3, bool b1) {
|
||||
void nested_array_designators() {
|
||||
int x[1][2] = {[0][0] = 1234, [0][1] = 5678};
|
||||
}
|
||||
|
||||
[[noreturn]] void noreturnFunc();
|
||||
|
||||
int noreturnTest(int x) {
|
||||
if (x < 10) {
|
||||
return x;
|
||||
} else {
|
||||
noreturnFunc();
|
||||
}
|
||||
}
|
||||
|
||||
int noreturnTest2(int x) {
|
||||
if (x < 10) {
|
||||
noreturnFunc();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
@@ -1940,3 +1940,65 @@ ssa.cpp:
|
||||
# 417| v417_4(void) = ReturnVoid :
|
||||
# 417| v417_5(void) = AliasedUse : ~m?
|
||||
# 417| v417_6(void) = ExitFunction :
|
||||
|
||||
# 423| int noreturnTest(int)
|
||||
# 423| Block 0
|
||||
# 423| v423_1(void) = EnterFunction :
|
||||
# 423| mu423_2(unknown) = AliasedDefinition :
|
||||
# 423| mu423_3(unknown) = InitializeNonLocal :
|
||||
# 423| r423_4(glval<int>) = VariableAddress[x] :
|
||||
# 423| m423_5(int) = InitializeParameter[x] : &:r423_4
|
||||
# 424| r424_1(glval<int>) = VariableAddress[x] :
|
||||
# 424| r424_2(int) = Load[x] : &:r424_1, m423_5
|
||||
# 424| r424_3(int) = Constant[10] :
|
||||
# 424| r424_4(bool) = CompareLT : r424_2, r424_3
|
||||
# 424| v424_5(void) = ConditionalBranch : r424_4
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 425| Block 1
|
||||
# 425| r425_1(glval<int>) = VariableAddress[#return] :
|
||||
# 425| r425_2(glval<int>) = VariableAddress[x] :
|
||||
# 425| r425_3(int) = Load[x] : &:r425_2, m423_5
|
||||
# 425| m425_4(int) = Store[#return] : &:r425_1, r425_3
|
||||
# 423| r423_6(glval<int>) = VariableAddress[#return] :
|
||||
# 423| v423_7(void) = ReturnValue : &:r423_6, m425_4
|
||||
# 423| v423_8(void) = AliasedUse : ~m?
|
||||
# 423| v423_9(void) = ExitFunction :
|
||||
|
||||
# 427| Block 2
|
||||
# 427| r427_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
|
||||
# 427| v427_2(void) = Call[noreturnFunc] : func:r427_1
|
||||
# 427| mu427_3(unknown) = ^CallSideEffect : ~m?
|
||||
# 423| v423_10(void) = Unreached :
|
||||
|
||||
# 431| int noreturnTest2(int)
|
||||
# 431| Block 0
|
||||
# 431| v431_1(void) = EnterFunction :
|
||||
# 431| mu431_2(unknown) = AliasedDefinition :
|
||||
# 431| mu431_3(unknown) = InitializeNonLocal :
|
||||
# 431| r431_4(glval<int>) = VariableAddress[x] :
|
||||
# 431| m431_5(int) = InitializeParameter[x] : &:r431_4
|
||||
# 432| r432_1(glval<int>) = VariableAddress[x] :
|
||||
# 432| r432_2(int) = Load[x] : &:r432_1, m431_5
|
||||
# 432| r432_3(int) = Constant[10] :
|
||||
# 432| r432_4(bool) = CompareLT : r432_2, r432_3
|
||||
# 432| v432_5(void) = ConditionalBranch : r432_4
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 433| Block 1
|
||||
# 433| r433_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
|
||||
# 433| v433_2(void) = Call[noreturnFunc] : func:r433_1
|
||||
# 433| mu433_3(unknown) = ^CallSideEffect : ~m?
|
||||
# 431| v431_6(void) = Unreached :
|
||||
|
||||
# 435| Block 2
|
||||
# 435| r435_1(glval<int>) = VariableAddress[#return] :
|
||||
# 435| r435_2(glval<int>) = VariableAddress[x] :
|
||||
# 435| r435_3(int) = Load[x] : &:r435_2, m431_5
|
||||
# 435| m435_4(int) = Store[#return] : &:r435_1, r435_3
|
||||
# 431| r431_7(glval<int>) = VariableAddress[#return] :
|
||||
# 431| v431_8(void) = ReturnValue : &:r431_7, m435_4
|
||||
# 431| v431_9(void) = AliasedUse : ~m?
|
||||
# 431| v431_10(void) = ExitFunction :
|
||||
|
||||
@@ -1940,3 +1940,65 @@ ssa.cpp:
|
||||
# 417| v417_4(void) = ReturnVoid :
|
||||
# 417| v417_5(void) = AliasedUse : ~m?
|
||||
# 417| v417_6(void) = ExitFunction :
|
||||
|
||||
# 423| int noreturnTest(int)
|
||||
# 423| Block 0
|
||||
# 423| v423_1(void) = EnterFunction :
|
||||
# 423| mu423_2(unknown) = AliasedDefinition :
|
||||
# 423| mu423_3(unknown) = InitializeNonLocal :
|
||||
# 423| r423_4(glval<int>) = VariableAddress[x] :
|
||||
# 423| m423_5(int) = InitializeParameter[x] : &:r423_4
|
||||
# 424| r424_1(glval<int>) = VariableAddress[x] :
|
||||
# 424| r424_2(int) = Load[x] : &:r424_1, m423_5
|
||||
# 424| r424_3(int) = Constant[10] :
|
||||
# 424| r424_4(bool) = CompareLT : r424_2, r424_3
|
||||
# 424| v424_5(void) = ConditionalBranch : r424_4
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 425| Block 1
|
||||
# 425| r425_1(glval<int>) = VariableAddress[#return] :
|
||||
# 425| r425_2(glval<int>) = VariableAddress[x] :
|
||||
# 425| r425_3(int) = Load[x] : &:r425_2, m423_5
|
||||
# 425| m425_4(int) = Store[#return] : &:r425_1, r425_3
|
||||
# 423| r423_6(glval<int>) = VariableAddress[#return] :
|
||||
# 423| v423_7(void) = ReturnValue : &:r423_6, m425_4
|
||||
# 423| v423_8(void) = AliasedUse : ~m?
|
||||
# 423| v423_9(void) = ExitFunction :
|
||||
|
||||
# 427| Block 2
|
||||
# 427| r427_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
|
||||
# 427| v427_2(void) = Call[noreturnFunc] : func:r427_1
|
||||
# 427| mu427_3(unknown) = ^CallSideEffect : ~m?
|
||||
# 423| v423_10(void) = Unreached :
|
||||
|
||||
# 431| int noreturnTest2(int)
|
||||
# 431| Block 0
|
||||
# 431| v431_1(void) = EnterFunction :
|
||||
# 431| mu431_2(unknown) = AliasedDefinition :
|
||||
# 431| mu431_3(unknown) = InitializeNonLocal :
|
||||
# 431| r431_4(glval<int>) = VariableAddress[x] :
|
||||
# 431| m431_5(int) = InitializeParameter[x] : &:r431_4
|
||||
# 432| r432_1(glval<int>) = VariableAddress[x] :
|
||||
# 432| r432_2(int) = Load[x] : &:r432_1, m431_5
|
||||
# 432| r432_3(int) = Constant[10] :
|
||||
# 432| r432_4(bool) = CompareLT : r432_2, r432_3
|
||||
# 432| v432_5(void) = ConditionalBranch : r432_4
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 433| Block 1
|
||||
# 433| r433_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
|
||||
# 433| v433_2(void) = Call[noreturnFunc] : func:r433_1
|
||||
# 433| mu433_3(unknown) = ^CallSideEffect : ~m?
|
||||
# 431| v431_6(void) = Unreached :
|
||||
|
||||
# 435| Block 2
|
||||
# 435| r435_1(glval<int>) = VariableAddress[#return] :
|
||||
# 435| r435_2(glval<int>) = VariableAddress[x] :
|
||||
# 435| r435_3(int) = Load[x] : &:r435_2, m431_5
|
||||
# 435| m435_4(int) = Store[#return] : &:r435_1, r435_3
|
||||
# 431| r431_7(glval<int>) = VariableAddress[#return] :
|
||||
# 431| v431_8(void) = ReturnValue : &:r431_7, m435_4
|
||||
# 431| v431_9(void) = AliasedUse : ~m?
|
||||
# 431| v431_10(void) = ExitFunction :
|
||||
|
||||
@@ -4,7 +4,9 @@ uniqueType
|
||||
uniqueNodeLocation
|
||||
missingLocation
|
||||
uniqueNodeToString
|
||||
| cpp11.cpp:50:15:50:16 | (no string representation) | Node should have one toString but has 0. |
|
||||
missingToString
|
||||
| Nodes without toString: 1 |
|
||||
parameterCallable
|
||||
localFlowIsLocal
|
||||
readStepIsLocal
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
| nested.cpp:21:23:21:26 | fmt0 | The format string argument to snprintf should be constant to prevent security issues and other potential errors. |
|
||||
| nested.cpp:79:32:79:38 | call to get_fmt | The format string argument to diagnostic should be constant to prevent security issues and other potential errors. |
|
||||
| nested.cpp:87:18:87:20 | fmt | The format string argument to diagnostic should be constant to prevent security issues and other potential errors. |
|
||||
| test.cpp:51:10:51:21 | call to make_message | The format string argument to printf should be constant to prevent security issues and other potential errors. |
|
||||
| test.cpp:57:12:57:16 | hello | The format string argument to printf should be constant to prevent security issues and other potential errors. |
|
||||
| test.cpp:60:12:60:21 | call to const_wash | The format string argument to printf should be constant to prevent security issues and other potential errors. |
|
||||
| test.cpp:61:12:61:26 | ... + ... | The format string argument to printf should be constant to prevent security issues and other potential errors. |
|
||||
|
||||
@@ -48,7 +48,7 @@ int main(int argc, char **argv) {
|
||||
printf(choose_message(argc - 1), argc - 1); // GOOD
|
||||
printf(messages[1]); // GOOD
|
||||
printf(message); // GOOD
|
||||
printf(make_message(argc - 1)); // BAD [NOT DETECTED]
|
||||
printf(make_message(argc - 1)); // BAD
|
||||
printf("Hello, World\n"); // GOOD
|
||||
printf(_("Hello, World\n")); // GOOD
|
||||
{
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.5.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.5.0
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.5.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.5.0
|
||||
lastReleaseVersion: 1.5.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.5.1-dev
|
||||
version: 1.5.2-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.5.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.5.0
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.5.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.5.0
|
||||
lastReleaseVersion: 1.5.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.5.1-dev
|
||||
version: 1.5.2-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.6.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
3
csharp/ql/lib/change-notes/released/0.6.1.md
Normal file
3
csharp/ql/lib/change-notes/released/0.6.1.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.6.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.0
|
||||
lastReleaseVersion: 0.6.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-all
|
||||
version: 0.6.1-dev
|
||||
version: 0.6.2-dev
|
||||
groups: csharp
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
|
||||
@@ -12,9 +12,9 @@ class Attribute extends Element, @cil_attribute {
|
||||
Method getConstructor() { cil_attribute(this, _, result) }
|
||||
|
||||
/** Gets the type of this attribute. */
|
||||
Type getType() { result = getConstructor().getDeclaringType() }
|
||||
Type getType() { result = this.getConstructor().getDeclaringType() }
|
||||
|
||||
override string toString() { result = "[" + getType().getName() + "(...)]" }
|
||||
override string toString() { result = "[" + this.getType().getName() + "(...)]" }
|
||||
|
||||
/** Gets the value of the `i`th argument of this attribute. */
|
||||
string getArgument(int i) { cil_attribute_positional_argument(this, i, result) }
|
||||
@@ -23,9 +23,9 @@ class Attribute extends Element, @cil_attribute {
|
||||
string getNamedArgument(string name) { cil_attribute_named_argument(this, name, result) }
|
||||
|
||||
/** Gets an argument of this attribute, if any. */
|
||||
string getAnArgument() { result = getArgument(_) or result = getNamedArgument(_) }
|
||||
string getAnArgument() { result = this.getArgument(_) or result = this.getNamedArgument(_) }
|
||||
|
||||
override CS::Location getLocation() { result = getDeclaration().getLocation() }
|
||||
override CS::Location getLocation() { result = this.getDeclaration().getLocation() }
|
||||
}
|
||||
|
||||
/** A generic attribute to a declaration. */
|
||||
|
||||
@@ -961,8 +961,16 @@ predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
|
||||
/**
|
||||
* A `Node` at which a cast can occur such that the type should be checked.
|
||||
*/
|
||||
class CastingNode extends Node {
|
||||
class CastingNode instanceof Node {
|
||||
CastingNode() { castingNode(this) }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate readStepWithTypes(
|
||||
@@ -1110,9 +1118,17 @@ LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable)
|
||||
* The value of a parameter at function entry, viewed as a node in a data
|
||||
* flow graph.
|
||||
*/
|
||||
class ParamNode extends Node {
|
||||
class ParamNode instanceof Node {
|
||||
ParamNode() { parameterNode(this, _, _) }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this node is the parameter of callable `c` at the specified
|
||||
* position.
|
||||
@@ -1121,9 +1137,17 @@ class ParamNode extends Node {
|
||||
}
|
||||
|
||||
/** A data-flow node that represents a call argument. */
|
||||
class ArgNode extends Node {
|
||||
class ArgNode instanceof Node {
|
||||
ArgNode() { argumentNode(this, _, _) }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Holds if this argument occurs at the given position in the given call. */
|
||||
final predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
argumentNode(this, call, pos)
|
||||
@@ -1134,9 +1158,17 @@ class ArgNode extends Node {
|
||||
* A node from which flow can return to the caller. This is either a regular
|
||||
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
|
||||
*/
|
||||
class ReturnNodeExt extends Node {
|
||||
class ReturnNodeExt instanceof Node {
|
||||
ReturnNodeExt() { returnNodeExt(this, _) }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the kind of this returned value. */
|
||||
ReturnKindExt getKind() { returnNodeExt(this, result) }
|
||||
}
|
||||
@@ -1145,8 +1177,16 @@ class ReturnNodeExt extends Node {
|
||||
* A node to which data can flow from a call. Either an ordinary out node
|
||||
* or a post-update node associated with a call argument.
|
||||
*/
|
||||
class OutNodeExt extends Node {
|
||||
class OutNodeExt instanceof Node {
|
||||
OutNodeExt() { outNodeExt(this) }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,11 +23,15 @@ abstract class Sink extends DataFlow::Node { }
|
||||
*/
|
||||
abstract private class InstanceMethodSink extends Sink {
|
||||
InstanceMethodSink() {
|
||||
not exists(
|
||||
SafeConstructorTrackingConfig safeConstructorTracking, DataFlow::Node safeTypeUsage,
|
||||
MethodCall mc
|
||||
|
|
||||
safeConstructorTracking.hasFlow(_, safeTypeUsage) and
|
||||
not exists(DataFlow::Node safeTypeUsage, MethodCall mc |
|
||||
(
|
||||
DataContractJsonSafeConstructorTracking::flowTo(safeTypeUsage) or
|
||||
JavaScriptSerializerSafeConstructorTracking::flowTo(safeTypeUsage) or
|
||||
XmlObjectSerializerDerivedConstructorTracking::flowTo(safeTypeUsage) or
|
||||
XmlSerializerSafeConstructorTracking::flowTo(safeTypeUsage) or
|
||||
DataContractSerializerSafeConstructorTracking::flowTo(safeTypeUsage) or
|
||||
XmlMessageFormatterSafeConstructorTracking::flowTo(safeTypeUsage)
|
||||
) and
|
||||
mc.getQualifier() = safeTypeUsage.asExpr() and
|
||||
mc.getAnArgument() = this.asExpr()
|
||||
)
|
||||
@@ -47,9 +51,11 @@ abstract class Sanitizer extends DataFlow::Node { }
|
||||
private class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `TaintToObjectMethodTracking` instead.
|
||||
*
|
||||
* User input to object method call deserialization flow tracking.
|
||||
*/
|
||||
class TaintToObjectMethodTrackingConfig extends TaintTracking::Configuration {
|
||||
deprecated class TaintToObjectMethodTrackingConfig extends TaintTracking::Configuration {
|
||||
TaintToObjectMethodTrackingConfig() { this = "TaintToObjectMethodTrackingConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -60,9 +66,27 @@ class TaintToObjectMethodTrackingConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
|
||||
/**
|
||||
* User input to object method call deserialization flow tracking configuration.
|
||||
*/
|
||||
private module TaintToObjectMethodTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof InstanceMethodSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* User input to object method call deserialization flow tracking module.
|
||||
*/
|
||||
module TaintToObjectMethodTracking = TaintTracking::Global<TaintToObjectMethodTrackingConfig>;
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `JsonConvertTracking` instead.
|
||||
*
|
||||
* User input to `JsonConvert` call deserialization flow tracking.
|
||||
*/
|
||||
class JsonConvertTrackingConfig extends TaintTracking::Configuration {
|
||||
deprecated class JsonConvertTrackingConfig extends TaintTracking::Configuration {
|
||||
JsonConvertTrackingConfig() { this = "JsonConvertTrackingConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -74,6 +98,24 @@ class JsonConvertTrackingConfig extends TaintTracking::Configuration {
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* User input to `JsonConvert` call deserialization flow tracking configuration.
|
||||
*/
|
||||
private module JsonConvertTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof NewtonsoftJsonConvertDeserializeObjectMethodSink
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* User input to `JsonConvert` call deserialization flow tracking module.
|
||||
*/
|
||||
module JsonConvertTracking = TaintTracking::Global<JsonConvertTrackingConfig>;
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `TypeNameTracking` instead.
|
||||
*
|
||||
@@ -186,9 +228,12 @@ private module TypeNameTrackingConfig implements DataFlow::ConfigSig {
|
||||
module TypeNameTracking = DataFlow::Global<TypeNameTrackingConfig>;
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `TaintToConstructorOrStaticMethodTracking` instead.
|
||||
*
|
||||
* User input to static method or constructor call deserialization flow tracking.
|
||||
*/
|
||||
class TaintToConstructorOrStaticMethodTrackingConfig extends TaintTracking::Configuration {
|
||||
deprecated class TaintToConstructorOrStaticMethodTrackingConfig extends TaintTracking::Configuration
|
||||
{
|
||||
TaintToConstructorOrStaticMethodTrackingConfig() {
|
||||
this = "TaintToConstructorOrStaticMethodTrackingConfig"
|
||||
}
|
||||
@@ -201,9 +246,28 @@ class TaintToConstructorOrStaticMethodTrackingConfig extends TaintTracking::Conf
|
||||
}
|
||||
|
||||
/**
|
||||
* User input to static method or constructor call deserialization flow tracking configuration.
|
||||
*/
|
||||
private module TaintToConstructorOrStaticMethodTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof ConstructorOrStaticMethodSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* User input to static method or constructor call deserialization flow tracking module.
|
||||
*/
|
||||
module TaintToConstructorOrStaticMethodTracking =
|
||||
TaintTracking::Global<TaintToConstructorOrStaticMethodTrackingConfig>;
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `TaintToObjectTypeTracking` instead.
|
||||
*
|
||||
* User input to instance type flow tracking.
|
||||
*/
|
||||
class TaintToObjectTypeTrackingConfig extends TaintTracking2::Configuration {
|
||||
deprecated class TaintToObjectTypeTrackingConfig extends TaintTracking2::Configuration {
|
||||
TaintToObjectTypeTrackingConfig() { this = "TaintToObjectTypeTrackingConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -234,9 +298,47 @@ class TaintToObjectTypeTrackingConfig extends TaintTracking2::Configuration {
|
||||
}
|
||||
|
||||
/**
|
||||
* User input to instance type flow tracking config.
|
||||
*/
|
||||
private module TaintToObjectTypeTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodCall mc |
|
||||
mc.getTarget() instanceof UnsafeDeserializer and
|
||||
sink.asExpr() = mc.getQualifier()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
exists(MethodCall mc, Method m |
|
||||
m = mc.getTarget() and
|
||||
m.getDeclaringType().hasQualifiedName("System", "Type") and
|
||||
m.hasName("GetType") and
|
||||
m.isStatic() and
|
||||
n1.asExpr() = mc.getArgument(0) and
|
||||
n2.asExpr() = mc
|
||||
)
|
||||
or
|
||||
exists(ObjectCreation oc |
|
||||
n1.asExpr() = oc.getAnArgument() and
|
||||
n2.asExpr() = oc and
|
||||
oc.getObjectType() instanceof StrongTypeDeserializer
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* User input to instance type flow tracking module.
|
||||
*/
|
||||
module TaintToObjectTypeTracking = TaintTracking::Global<TaintToObjectTypeTrackingConfig>;
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `WeakTypeCreationToUsageTracking` instead.
|
||||
*
|
||||
* Unsafe deserializer creation to usage tracking config.
|
||||
*/
|
||||
class WeakTypeCreationToUsageTrackingConfig extends TaintTracking2::Configuration {
|
||||
deprecated class WeakTypeCreationToUsageTrackingConfig extends TaintTracking2::Configuration {
|
||||
WeakTypeCreationToUsageTrackingConfig() { this = "DeserializerCreationToUsageTrackingConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
@@ -255,13 +357,30 @@ class WeakTypeCreationToUsageTrackingConfig extends TaintTracking2::Configuratio
|
||||
}
|
||||
|
||||
/**
|
||||
* Safe deserializer creation to usage tracking config.
|
||||
* Unsafe deserializer creation to usage tracking config.
|
||||
*/
|
||||
abstract class SafeConstructorTrackingConfig extends TaintTracking2::Configuration {
|
||||
bindingset[this]
|
||||
SafeConstructorTrackingConfig() { any() }
|
||||
private module WeakTypeCreationToUsageTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(ObjectCreation oc |
|
||||
oc.getObjectType() instanceof WeakTypeDeserializer and
|
||||
source.asExpr() = oc
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodCall mc |
|
||||
mc.getTarget() instanceof UnsafeDeserializer and
|
||||
sink.asExpr() = mc.getQualifier()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsafe deserializer creation to usage tracking module.
|
||||
*/
|
||||
module WeakTypeCreationToUsageTracking =
|
||||
TaintTracking::Global<WeakTypeCreationToUsageTrackingConfig>;
|
||||
|
||||
/** BinaryFormatter */
|
||||
private predicate isBinaryFormatterCall(MethodCall mc, Method m) {
|
||||
m = mc.getTarget() and
|
||||
@@ -367,13 +486,8 @@ private class DataContractJsonSerializerDeserializeMethodSink extends DataContra
|
||||
}
|
||||
}
|
||||
|
||||
private class DataContractJsonSafeConstructorTrackingConfiguration extends SafeConstructorTrackingConfig
|
||||
{
|
||||
DataContractJsonSafeConstructorTrackingConfiguration() {
|
||||
this = "DataContractJsonSafeConstructorTrackingConfiguration"
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
private module DataContractJsonSafeConstructorTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(ObjectCreation oc |
|
||||
oc = source.asExpr() and
|
||||
exists(Constructor c |
|
||||
@@ -385,7 +499,7 @@ private class DataContractJsonSafeConstructorTrackingConfiguration extends SafeC
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodCall mc |
|
||||
isDataContractJsonSerializerCall(mc, _) and
|
||||
mc.getQualifier() = sink.asExpr()
|
||||
@@ -393,6 +507,9 @@ private class DataContractJsonSafeConstructorTrackingConfiguration extends SafeC
|
||||
}
|
||||
}
|
||||
|
||||
private module DataContractJsonSafeConstructorTracking =
|
||||
TaintTracking::Global<DataContractJsonSafeConstructorTrackingConfig>;
|
||||
|
||||
/** JavaScriptSerializer */
|
||||
private predicate isJavaScriptSerializerCall(MethodCall mc, Method m) {
|
||||
m = mc.getTarget() and
|
||||
@@ -417,13 +534,8 @@ private class JavaScriptSerializerDeserializeMethodSink extends JavaScriptSerial
|
||||
}
|
||||
}
|
||||
|
||||
private class JavaScriptSerializerSafeConstructorTrackingConfiguration extends SafeConstructorTrackingConfig
|
||||
{
|
||||
JavaScriptSerializerSafeConstructorTrackingConfiguration() {
|
||||
this = "JavaScriptSerializerSafeConstructorTrackingConfiguration"
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
private module JavaScriptSerializerSafeConstructorTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(ObjectCreation oc |
|
||||
oc = source.asExpr() and
|
||||
exists(Constructor c |
|
||||
@@ -434,7 +546,7 @@ private class JavaScriptSerializerSafeConstructorTrackingConfiguration extends S
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodCall mc |
|
||||
isJavaScriptSerializerCall(mc, _) and
|
||||
mc.getQualifier() = sink.asExpr()
|
||||
@@ -442,6 +554,9 @@ private class JavaScriptSerializerSafeConstructorTrackingConfiguration extends S
|
||||
}
|
||||
}
|
||||
|
||||
private module JavaScriptSerializerSafeConstructorTracking =
|
||||
TaintTracking::Global<JavaScriptSerializerSafeConstructorTrackingConfig>;
|
||||
|
||||
/** XmlObjectSerializer */
|
||||
private predicate isXmlObjectSerializerCall(MethodCall mc, Method m) {
|
||||
m = mc.getTarget() and
|
||||
@@ -461,13 +576,8 @@ private class XmlObjectSerializerDeserializeMethodSink extends XmlObjectSerializ
|
||||
}
|
||||
}
|
||||
|
||||
private class XmlObjectSerializerDerivedConstructorTrackingConfiguration extends SafeConstructorTrackingConfig
|
||||
{
|
||||
XmlObjectSerializerDerivedConstructorTrackingConfiguration() {
|
||||
this = "XmlObjectSerializerDerivedConstructorTrackingConfiguration"
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
private module XmlObjectSerializerDerivedConstructorTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(ObjectCreation oc |
|
||||
oc = source.asExpr() and
|
||||
exists(ValueOrRefType declaringType |
|
||||
@@ -481,7 +591,7 @@ private class XmlObjectSerializerDerivedConstructorTrackingConfiguration extends
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodCall mc |
|
||||
isXmlObjectSerializerCall(mc, _) and
|
||||
mc.getQualifier() = sink.asExpr()
|
||||
@@ -489,6 +599,9 @@ private class XmlObjectSerializerDerivedConstructorTrackingConfiguration extends
|
||||
}
|
||||
}
|
||||
|
||||
private module XmlObjectSerializerDerivedConstructorTracking =
|
||||
TaintTracking::Global<XmlObjectSerializerDerivedConstructorTrackingConfig>;
|
||||
|
||||
/** XmlSerializer */
|
||||
private predicate isXmlSerializerCall(MethodCall mc, Method m) {
|
||||
m = mc.getTarget() and
|
||||
@@ -507,13 +620,8 @@ private class XmlSerializerDeserializeMethodSink extends XmlSerializerSink {
|
||||
}
|
||||
}
|
||||
|
||||
private class XmlSerializerSafeConstructorTrackingConfiguration extends SafeConstructorTrackingConfig
|
||||
{
|
||||
XmlSerializerSafeConstructorTrackingConfiguration() {
|
||||
this = "XmlSerializerSafeConstructorTrackingConfiguration"
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
private module XmlSerializerSafeConstructorTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(ObjectCreation oc |
|
||||
oc = source.asExpr() and
|
||||
exists(Constructor c |
|
||||
@@ -525,7 +633,7 @@ private class XmlSerializerSafeConstructorTrackingConfiguration extends SafeCons
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodCall mc |
|
||||
isXmlSerializerCall(mc, _) and
|
||||
mc.getQualifier() = sink.asExpr()
|
||||
@@ -533,6 +641,9 @@ private class XmlSerializerSafeConstructorTrackingConfiguration extends SafeCons
|
||||
}
|
||||
}
|
||||
|
||||
private module XmlSerializerSafeConstructorTracking =
|
||||
TaintTracking::Global<XmlSerializerSafeConstructorTrackingConfig>;
|
||||
|
||||
/** DataContractSerializer */
|
||||
private predicate isDataContractSerializerCall(MethodCall mc, Method m) {
|
||||
m = mc.getTarget() and
|
||||
@@ -555,13 +666,8 @@ private class DataContractSerializerDeserializeMethodSink extends DataContractSe
|
||||
}
|
||||
}
|
||||
|
||||
private class DataContractSerializerSafeConstructorTrackingConfiguration extends SafeConstructorTrackingConfig
|
||||
{
|
||||
DataContractSerializerSafeConstructorTrackingConfiguration() {
|
||||
this = "DataContractSerializerSafeConstructorTrackingConfiguration"
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
private module DataContractSerializerSafeConstructorTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(ObjectCreation oc |
|
||||
oc = source.asExpr() and
|
||||
exists(Constructor c |
|
||||
@@ -573,7 +679,7 @@ private class DataContractSerializerSafeConstructorTrackingConfiguration extends
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodCall mc |
|
||||
isDataContractSerializerCall(mc, _) and
|
||||
mc.getQualifier() = sink.asExpr()
|
||||
@@ -581,6 +687,9 @@ private class DataContractSerializerSafeConstructorTrackingConfiguration extends
|
||||
}
|
||||
}
|
||||
|
||||
private module DataContractSerializerSafeConstructorTracking =
|
||||
TaintTracking::Global<DataContractSerializerSafeConstructorTrackingConfig>;
|
||||
|
||||
/** XmlMessageFormatter */
|
||||
private predicate isXmlMessageFormatterCall(MethodCall mc, Method m) {
|
||||
m = mc.getTarget() and
|
||||
@@ -599,13 +708,8 @@ private class XmlMessageFormatterDeserializeMethodSink extends XmlMessageFormatt
|
||||
}
|
||||
}
|
||||
|
||||
private class XmlMessageFormatterSafeConstructorTrackingConfiguration extends SafeConstructorTrackingConfig
|
||||
{
|
||||
XmlMessageFormatterSafeConstructorTrackingConfiguration() {
|
||||
this = "XmlMessageFormatterSafeConstructorTrackingConfiguration"
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
private module XmlMessageFormatterSafeConstructorTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(ObjectCreation oc |
|
||||
oc = source.asExpr() and
|
||||
exists(Constructor c |
|
||||
@@ -617,7 +721,7 @@ private class XmlMessageFormatterSafeConstructorTrackingConfiguration extends Sa
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodCall mc |
|
||||
isXmlMessageFormatterCall(mc, _) and
|
||||
mc.getQualifier() = sink.asExpr()
|
||||
@@ -625,6 +729,9 @@ private class XmlMessageFormatterSafeConstructorTrackingConfiguration extends Sa
|
||||
}
|
||||
}
|
||||
|
||||
private module XmlMessageFormatterSafeConstructorTracking =
|
||||
TaintTracking::Global<XmlMessageFormatterSafeConstructorTrackingConfig>;
|
||||
|
||||
/** LosFormatter */
|
||||
private predicate isLosFormatterCall(MethodCall mc, Method m) {
|
||||
m = mc.getTarget() and
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
## 0.6.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Additional sinks modelling writes to unencrypted local files have been added to `ExternalLocationSink`, used by the `cs/cleartext-storage` and `cs/exposure-of-sensitive-information` queries.
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -13,43 +13,40 @@
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.security.dataflow.UnsafeDeserializationQuery
|
||||
import DataFlow::PathGraph
|
||||
import Flow::PathGraph
|
||||
|
||||
from DataFlow::PathNode userInput, DataFlow::PathNode deserializeCallArg
|
||||
module Flow =
|
||||
DataFlow::MergePathGraph3<TaintToObjectMethodTracking::PathNode,
|
||||
TaintToConstructorOrStaticMethodTracking::PathNode, JsonConvertTracking::PathNode,
|
||||
TaintToObjectMethodTracking::PathGraph, TaintToConstructorOrStaticMethodTracking::PathGraph,
|
||||
JsonConvertTracking::PathGraph>;
|
||||
|
||||
from Flow::PathNode userInput, Flow::PathNode deserializeCallArg
|
||||
where
|
||||
exists(TaintToObjectMethodTrackingConfig taintTracking |
|
||||
// all flows from user input to deserialization with weak and strong type serializers
|
||||
taintTracking.hasFlowPath(userInput, deserializeCallArg)
|
||||
) and
|
||||
// all flows from user input to deserialization with weak and strong type serializers
|
||||
TaintToObjectMethodTracking::flowPath(userInput.asPathNode1(), deserializeCallArg.asPathNode1()) and
|
||||
// intersect with strong types, but user controlled or weak types deserialization usages
|
||||
(
|
||||
exists(
|
||||
DataFlow::Node weakTypeUsage,
|
||||
WeakTypeCreationToUsageTrackingConfig weakTypeDeserializerTracking, MethodCall mc
|
||||
|
|
||||
weakTypeDeserializerTracking.hasFlowTo(weakTypeUsage) and
|
||||
exists(DataFlow::Node weakTypeUsage, MethodCall mc |
|
||||
WeakTypeCreationToUsageTracking::flowTo(weakTypeUsage) and
|
||||
mc.getQualifier() = weakTypeUsage.asExpr() and
|
||||
mc.getAnArgument() = deserializeCallArg.getNode().asExpr()
|
||||
)
|
||||
or
|
||||
exists(
|
||||
TaintToObjectTypeTrackingConfig userControlledTypeTracking, DataFlow::Node taintedTypeUsage,
|
||||
MethodCall mc
|
||||
|
|
||||
userControlledTypeTracking.hasFlowTo(taintedTypeUsage) and
|
||||
exists(DataFlow::Node taintedTypeUsage, MethodCall mc |
|
||||
TaintToObjectTypeTracking::flowTo(taintedTypeUsage) and
|
||||
mc.getQualifier() = taintedTypeUsage.asExpr() and
|
||||
mc.getAnArgument() = deserializeCallArg.getNode().asExpr()
|
||||
)
|
||||
)
|
||||
or
|
||||
// no type check needed - straightforward taint -> sink
|
||||
exists(TaintToConstructorOrStaticMethodTrackingConfig taintTracking2 |
|
||||
taintTracking2.hasFlowPath(userInput, deserializeCallArg)
|
||||
)
|
||||
TaintToConstructorOrStaticMethodTracking::flowPath(userInput.asPathNode2(),
|
||||
deserializeCallArg.asPathNode2())
|
||||
or
|
||||
// JsonConvert static method call, but with additional unsafe typename tracking
|
||||
exists(JsonConvertTrackingConfig taintTrackingJsonConvert, DataFlow::Node settingsCallArg |
|
||||
taintTrackingJsonConvert.hasFlowPath(userInput, deserializeCallArg) and
|
||||
exists(DataFlow::Node settingsCallArg |
|
||||
JsonConvertTracking::flowPath(userInput.asPathNode3(), deserializeCallArg.asPathNode3()) and
|
||||
TypeNameTracking::flow(_, settingsCallArg) and
|
||||
deserializeCallArg.getNode().asExpr().getParent() = settingsCallArg.asExpr().getParent()
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Additional sinks modelling writes to unencrypted local files have been added to `ExternalLocationSink`, used by the `cs/cleartext-storage` and `cs/exposure-of-sensitive-information` queries.
|
||||
## 0.6.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Additional sinks modelling writes to unencrypted local files have been added to `ExternalLocationSink`, used by the `cs/cleartext-storage` and `cs/exposure-of-sensitive-information` queries.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.0
|
||||
lastReleaseVersion: 0.6.1
|
||||
|
||||
@@ -19,6 +19,9 @@ newtype TInstruction =
|
||||
) {
|
||||
IRConstruction::Raw::hasInstruction(tag1, tag2)
|
||||
} or
|
||||
TRawUnreachedInstruction(IRFunctionBase irFunc) {
|
||||
IRConstruction::hasUnreachedInstruction(irFunc)
|
||||
} or
|
||||
TUnaliasedSsaPhiInstruction(
|
||||
TRawInstruction blockStartInstr, UnaliasedSsa::Ssa::MemoryLocation memoryLocation
|
||||
) {
|
||||
|
||||
@@ -414,6 +414,8 @@ private module Cached {
|
||||
}
|
||||
}
|
||||
|
||||
predicate hasUnreachedInstruction(IRFunction func) { none() }
|
||||
|
||||
import CachedForDebugging
|
||||
|
||||
cached
|
||||
|
||||
@@ -34,9 +34,13 @@ private module Cached {
|
||||
|
||||
cached
|
||||
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
exists(OldIR::Instruction oldInstruction |
|
||||
irFunc = oldInstruction.getEnclosingIRFunction() and
|
||||
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
||||
(
|
||||
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
|
||||
or
|
||||
oldInstruction.getOpcode() instanceof Opcode::Unreached
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -366,21 +370,19 @@ private module Cached {
|
||||
then
|
||||
result = getChi(getOldInstruction(instruction)) and
|
||||
kind instanceof GotoEdge
|
||||
else (
|
||||
else
|
||||
exists(OldInstruction oldInstruction |
|
||||
oldInstruction = getOldInstruction(instruction) and
|
||||
(
|
||||
oldInstruction = getOldInstruction(instruction)
|
||||
or
|
||||
instruction = getChi(oldInstruction)
|
||||
) and
|
||||
(
|
||||
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
|
||||
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
|
||||
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(OldInstruction oldInstruction |
|
||||
instruction = getChi(oldInstruction) and
|
||||
result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-queries
|
||||
version: 0.6.1-dev
|
||||
version: 0.6.2-dev
|
||||
groups:
|
||||
- csharp
|
||||
- queries
|
||||
|
||||
@@ -178,7 +178,7 @@ string captureThroughFlow(DataFlowTargetApi api) {
|
||||
string output
|
||||
|
|
||||
ThroughFlow::flow(p, returnNodeExt) and
|
||||
returnNodeExt.getEnclosingCallable() = api and
|
||||
returnNodeExt.(DataFlow::Node).getEnclosingCallable() = api and
|
||||
input = parameterNodeAsInput(p) and
|
||||
output = returnNodeAsOutput(returnNodeExt) and
|
||||
input != output and
|
||||
|
||||
@@ -121,7 +121,7 @@ class InstanceParameterNode = DataFlowPrivate::InstanceParameterNode;
|
||||
|
||||
pragma[nomagic]
|
||||
private CS::Parameter getParameter(DataFlowImplCommon::ReturnNodeExt node, ParameterPosition pos) {
|
||||
result = node.getEnclosingCallable().getParameter(pos.getPosition())
|
||||
result = node.(DataFlow::Node).getEnclosingCallable().getParameter(pos.getPosition())
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
edges
|
||||
| ../../../../resources/stubs/Newtonsoft.Json/13.0.1/Newtonsoft.Json.cs:930:20:930:20 | 4 : Int32 | Test.cs:19:32:19:52 | access to constant Auto : Int32 |
|
||||
| Test.cs:9:46:9:49 | access to parameter data : TextBox | Test.cs:9:46:9:54 | access to property Text |
|
||||
| Test.cs:17:46:17:49 | access to parameter data : TextBox | Test.cs:17:46:17:54 | access to property Text |
|
||||
| Test.cs:19:32:19:52 | access to constant Auto : Int32 | Test.cs:17:57:20:9 | object creation of type JsonSerializerSettings |
|
||||
| Test.cs:19:32:19:52 | access to constant Auto : TypeNameHandling | Test.cs:17:57:20:9 | object creation of type JsonSerializerSettings |
|
||||
| Test.cs:25:46:25:49 | access to parameter data : TextBox | Test.cs:25:46:25:54 | access to property Text |
|
||||
nodes
|
||||
| ../../../../resources/stubs/Newtonsoft.Json/13.0.1/Newtonsoft.Json.cs:930:20:930:20 | 4 : Int32 | semmle.label | 4 : Int32 |
|
||||
| Test.cs:9:46:9:49 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
|
||||
| Test.cs:9:46:9:54 | access to property Text | semmle.label | access to property Text |
|
||||
| Test.cs:17:46:17:49 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
|
||||
| Test.cs:17:46:17:54 | access to property Text | semmle.label | access to property Text |
|
||||
| Test.cs:17:57:20:9 | object creation of type JsonSerializerSettings | semmle.label | object creation of type JsonSerializerSettings |
|
||||
| Test.cs:19:32:19:52 | access to constant Auto : Int32 | semmle.label | access to constant Auto : Int32 |
|
||||
| Test.cs:19:32:19:52 | access to constant Auto : TypeNameHandling | semmle.label | access to constant Auto : TypeNameHandling |
|
||||
| Test.cs:25:46:25:49 | access to parameter data : TextBox | semmle.label | access to parameter data : TextBox |
|
||||
| Test.cs:25:46:25:54 | access to property Text | semmle.label | access to property Text |
|
||||
subpaths
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
.. _codeql-cli-reference:
|
||||
|
||||
:orphan:
|
||||
|
||||
CodeQL CLI reference
|
||||
====================
|
||||
|
||||
|
||||
@@ -10,12 +10,9 @@ CodeQL CLI
|
||||
|
||||
- `CodeQL CLI reference <https://docs.github.com/en/code-security/codeql-cli/codeql-cli-reference>`__: Learn more about the files you can use when running CodeQL processes and the results format and exit codes that CodeQL generates.
|
||||
|
||||
- `CodeQL CLI manual <manual>`__: Detailed information about all the commands available with the CodeQL CLI.
|
||||
- `CodeQL CLI manual <https://docs.github.com/en/code-security/codeql-cli/codeql-cli-manual>`__: Detailed information about all the commands available with the CodeQL CLI.
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:hidden:
|
||||
|
||||
using-the-codeql-cli
|
||||
codeql-cli-reference
|
||||
CodeQL CLI manual <https://codeql.github.com/docs/codeql-cli/manual>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
.. _using-the-codeql-cli:
|
||||
|
||||
:orphan:
|
||||
|
||||
Using the CodeQL CLI
|
||||
====================
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ To use standard code navigation features in the source code, you can right-click
|
||||
|
||||
If you're using an older database, code navigation commands such as **Go to Definition** and **Go to References** may not work.
|
||||
To use code navigation, try unzipping the database and running ``codeql database cleanup <database>`` on the unzipped database using the CodeQL CLI. Then, re-add the database to Visual Studio Code.
|
||||
For more information, see the `database cleanup <../../codeql-cli/manual/database-cleanup>`__ reference documentation.
|
||||
For more information, see `database cleanup <https://docs.github.com/en/code-security/codeql-cli/codeql-cli-manual/database-cleanup>`__ in the documentation for CodeQL CLI.
|
||||
|
||||
Comparing query results
|
||||
------------------------
|
||||
|
||||
@@ -112,7 +112,7 @@ Configuring settings for testing queries locally
|
||||
|
||||
To increase the number of threads used for testing queries, you can update the **Running Tests > Number Of Threads** setting.
|
||||
|
||||
To pass additional arguments to the CodeQL CLI when running tests, you can update the **Running Tests > Additional Test Arguments** setting. For more information about the available arguments, see "`test run <https://codeql.github.com/docs/codeql-cli/manual/test-run/>`_" in the CodeQL CLI help.
|
||||
To pass additional arguments to the CodeQL CLI when running tests, you can update the **Running Tests > Additional Test Arguments** setting. For more information about the available arguments, see `test run <https://docs.github.com/en/code-security/codeql-cli/codeql-cli-manual/test-run/>`_ in the documentation for CodeQL CLI.
|
||||
|
||||
Configuring settings for telemetry and data collection
|
||||
--------------------------------------------------------
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
.. pull-quote:: Other query-running commands
|
||||
|
||||
Queries run with ``database analyze`` have strict `metadata requirements
|
||||
<https://docs.github.com/en/code-security/codeql-cli/using-the-codeql-cli/using-custom-queries-with-the-codeql-cli#including-query-metadata>`__. You can also execute queries using the following
|
||||
plumbing-level subcommands:
|
||||
|
||||
- `database run-queries <../manual/database-run-queries>`__, which
|
||||
outputs non-interpreted results in an intermediate binary format called
|
||||
:ref:`BQRS <bqrs-file>`.
|
||||
- `query run <../manual/query-run>`__, which will output BQRS files, or print
|
||||
results tables directly to the command line. Viewing results directly in
|
||||
the command line may be useful for iterative query development using the CLI.
|
||||
|
||||
Queries run with these commands don't have the same metadata requirements.
|
||||
However, to save human-readable data you have to process each BQRS results
|
||||
file using the `bqrs decode <../manual/bqrs-decode>`__ plumbing
|
||||
subcommand. Therefore, for most use cases it's easiest to use ``database
|
||||
analyze`` to directly generate interpreted results.
|
||||
@@ -3,7 +3,6 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -22,28 +21,37 @@ import (
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintf(os.Stderr,
|
||||
`%s is a wrapper script that installs dependencies and calls the extractor.
|
||||
`%s is a wrapper script that installs dependencies and calls the extractor
|
||||
|
||||
When LGTM_SRC is not set, the script installs dependencies as described below, and then invokes the
|
||||
extractor in the working directory.
|
||||
Options:
|
||||
--identify-environment
|
||||
Produce an environment file specifying which Go version should be installed in the environment
|
||||
so that autobuilding will be successful. The location of this file is controlled by the
|
||||
environment variable CODEQL_EXTRACTOR_ENVIRONMENT_JSON, or defaults to 'environment.json' if
|
||||
that is not set.
|
||||
|
||||
If LGTM_SRC is set, it checks for the presence of the files 'go.mod', 'Gopkg.toml', and
|
||||
'glide.yaml' to determine how to install dependencies: if a 'Gopkg.toml' file is present, it uses
|
||||
'dep ensure', if there is a 'glide.yaml' it uses 'glide install', and otherwise 'go get'.
|
||||
Additionally, unless a 'go.mod' file is detected, it sets up a temporary GOPATH and moves all
|
||||
source files into a folder corresponding to the package's import path before installing
|
||||
dependencies.
|
||||
Build behavior:
|
||||
|
||||
This behavior can be further customized using environment variables: setting LGTM_INDEX_NEED_GOPATH
|
||||
to 'false' disables the GOPATH set-up, CODEQL_EXTRACTOR_GO_BUILD_COMMAND (or alternatively
|
||||
LGTM_INDEX_BUILD_COMMAND), can be set to a newline-separated list of commands to run in order to
|
||||
install dependencies, and LGTM_INDEX_IMPORT_PATH can be used to override the package import path,
|
||||
which is otherwise inferred from the SEMMLE_REPO_URL or GITHUB_REPOSITORY environment variables.
|
||||
When LGTM_SRC is not set, the script installs dependencies as described below, and then invokes the
|
||||
extractor in the working directory.
|
||||
|
||||
In resource-constrained environments, the environment variable CODEQL_EXTRACTOR_GO_MAX_GOROUTINES
|
||||
(or its legacy alias SEMMLE_MAX_GOROUTINES) can be used to limit the number of parallel goroutines
|
||||
started by the extractor, which reduces CPU and memory requirements. The default value for this
|
||||
variable is 32.
|
||||
If LGTM_SRC is set, it checks for the presence of the files 'go.mod', 'Gopkg.toml', and
|
||||
'glide.yaml' to determine how to install dependencies: if a 'Gopkg.toml' file is present, it uses
|
||||
'dep ensure', if there is a 'glide.yaml' it uses 'glide install', and otherwise 'go get'.
|
||||
Additionally, unless a 'go.mod' file is detected, it sets up a temporary GOPATH and moves all
|
||||
source files into a folder corresponding to the package's import path before installing
|
||||
dependencies.
|
||||
|
||||
This behavior can be further customized using environment variables: setting LGTM_INDEX_NEED_GOPATH
|
||||
to 'false' disables the GOPATH set-up, CODEQL_EXTRACTOR_GO_BUILD_COMMAND (or alternatively
|
||||
LGTM_INDEX_BUILD_COMMAND), can be set to a newline-separated list of commands to run in order to
|
||||
install dependencies, and LGTM_INDEX_IMPORT_PATH can be used to override the package import path,
|
||||
which is otherwise inferred from the SEMMLE_REPO_URL or GITHUB_REPOSITORY environment variables.
|
||||
|
||||
In resource-constrained environments, the environment variable CODEQL_EXTRACTOR_GO_MAX_GOROUTINES
|
||||
(or its legacy alias SEMMLE_MAX_GOROUTINES) can be used to limit the number of parallel goroutines
|
||||
started by the extractor, which reduces CPU and memory requirements. The default value for this
|
||||
variable is 32.
|
||||
`,
|
||||
os.Args[0])
|
||||
fmt.Fprintf(os.Stderr, "Usage:\n\n %s\n", os.Args[0])
|
||||
@@ -84,14 +92,7 @@ func getEnvGoSemVer() string {
|
||||
return "v" + goVersion[2:]
|
||||
}
|
||||
|
||||
func tryBuild(buildFile, cmd string, args ...string) bool {
|
||||
if util.FileExists(buildFile) {
|
||||
log.Printf("%s found, running %s\n", buildFile, cmd)
|
||||
return util.RunCmd(exec.Command(cmd, args...))
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Returns the import path of the package being built, or "" if it cannot be determined.
|
||||
func getImportPath() (importpath string) {
|
||||
importpath = os.Getenv("LGTM_INDEX_IMPORT_PATH")
|
||||
if importpath == "" {
|
||||
@@ -116,9 +117,11 @@ func getImportPath() (importpath string) {
|
||||
return
|
||||
}
|
||||
|
||||
// Returns the import path of the package being built from `repourl`, or "" if it cannot be
|
||||
// determined.
|
||||
func getImportPathFromRepoURL(repourl string) string {
|
||||
// check for scp-like URL as in "git@github.com:github/codeql-go.git"
|
||||
shorturl := regexp.MustCompile("^([^@]+@)?([^:]+):([^/].*?)(\\.git)?$")
|
||||
shorturl := regexp.MustCompile(`^([^@]+@)?([^:]+):([^/].*?)(\.git)?$`)
|
||||
m := shorturl.FindStringSubmatch(repourl)
|
||||
if m != nil {
|
||||
return m[2] + "/" + m[3]
|
||||
@@ -142,7 +145,7 @@ func getImportPathFromRepoURL(repourl string) string {
|
||||
host := u.Hostname()
|
||||
path := u.Path
|
||||
// strip off leading slashes and trailing `.git` if present
|
||||
path = regexp.MustCompile("^/+|\\.git$").ReplaceAllString(path, "")
|
||||
path = regexp.MustCompile(`^/+|\.git$`).ReplaceAllString(path, "")
|
||||
return host + "/" + path
|
||||
}
|
||||
|
||||
@@ -182,6 +185,8 @@ const (
|
||||
ModVendor
|
||||
)
|
||||
|
||||
// argsForGoVersion returns the arguments to pass to the Go compiler for the given `ModMode` and
|
||||
// Go version
|
||||
func (m ModMode) argsForGoVersion(version string) []string {
|
||||
switch m {
|
||||
case ModUnset:
|
||||
@@ -221,6 +226,7 @@ func checkVendor() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Returns the directory containing the source code to be analyzed.
|
||||
func getSourceDir() string {
|
||||
srcdir := os.Getenv("LGTM_SRC")
|
||||
if srcdir != "" {
|
||||
@@ -236,6 +242,7 @@ func getSourceDir() string {
|
||||
return srcdir
|
||||
}
|
||||
|
||||
// Returns the appropriate DependencyInstallerMode for the current project
|
||||
func getDepMode() DependencyInstallerMode {
|
||||
if util.FileExists("go.mod") {
|
||||
log.Println("Found go.mod, enabling go modules")
|
||||
@@ -252,6 +259,33 @@ func getDepMode() DependencyInstallerMode {
|
||||
return GoGetNoModules
|
||||
}
|
||||
|
||||
// Tries to open `go.mod` and read a go directive, returning the version and whether it was found.
|
||||
func tryReadGoDirective(depMode DependencyInstallerMode) (string, bool) {
|
||||
version := ""
|
||||
found := false
|
||||
if depMode == GoGetWithModules {
|
||||
versionRe := regexp.MustCompile(`(?m)^go[ \t\r]+([0-9]+\.[0-9]+)$`)
|
||||
goMod, err := os.ReadFile("go.mod")
|
||||
if err != nil {
|
||||
log.Println("Failed to read go.mod to check for missing Go version")
|
||||
} else {
|
||||
matches := versionRe.FindSubmatch(goMod)
|
||||
if matches != nil {
|
||||
found = true
|
||||
if len(matches) > 1 {
|
||||
version := string(matches[1])
|
||||
semverVersion := "v" + version
|
||||
if semver.Compare(semverVersion, getEnvGoSemVer()) >= 0 {
|
||||
diagnostics.EmitNewerGoVersionNeeded()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return version, found
|
||||
}
|
||||
|
||||
// Returns the appropriate ModMode for the current project
|
||||
func getModMode(depMode DependencyInstallerMode) ModMode {
|
||||
if depMode == GoGetWithModules {
|
||||
// if a vendor/modules.txt file exists, we assume that there are vendored Go dependencies, and
|
||||
@@ -265,7 +299,8 @@ func getModMode(depMode DependencyInstallerMode) ModMode {
|
||||
return ModUnset
|
||||
}
|
||||
|
||||
func fixGoVendorIssues(modMode ModMode, depMode DependencyInstallerMode, goDirectiveFound bool) ModMode {
|
||||
// fixGoVendorIssues fixes issues with go vendor for go version >= 1.14
|
||||
func fixGoVendorIssues(modMode ModMode, depMode DependencyInstallerMode, goModVersionFound bool) ModMode {
|
||||
if modMode == ModVendor {
|
||||
// fix go vendor issues with go versions >= 1.14 when no go version is specified in the go.mod
|
||||
// if this is the case, and dependencies were vendored with an old go version (and therefore
|
||||
@@ -275,9 +310,9 @@ func fixGoVendorIssues(modMode ModMode, depMode DependencyInstallerMode, goDirec
|
||||
// we work around this by adding an explicit go version of 1.13, which is the last version
|
||||
// where this is not an issue
|
||||
if depMode == GoGetWithModules {
|
||||
if !goDirectiveFound {
|
||||
if !goModVersionFound {
|
||||
// if the go.mod does not contain a version line
|
||||
modulesTxt, err := ioutil.ReadFile("vendor/modules.txt")
|
||||
modulesTxt, err := os.ReadFile("vendor/modules.txt")
|
||||
if err != nil {
|
||||
log.Println("Failed to read vendor/modules.txt to check for mismatched Go version")
|
||||
} else if explicitRe := regexp.MustCompile("(?m)^## explicit$"); !explicitRe.Match(modulesTxt) {
|
||||
@@ -294,6 +329,7 @@ func fixGoVendorIssues(modMode ModMode, depMode DependencyInstallerMode, goDirec
|
||||
return modMode
|
||||
}
|
||||
|
||||
// Determines whether the project needs a GOPATH set up
|
||||
func getNeedGopath(depMode DependencyInstallerMode, importpath string) bool {
|
||||
needGopath := true
|
||||
if depMode == GoGetWithModules {
|
||||
@@ -316,6 +352,7 @@ func getNeedGopath(depMode DependencyInstallerMode, importpath string) bool {
|
||||
return needGopath
|
||||
}
|
||||
|
||||
// Try to update `go.mod` and `go.sum` if the go version is >= 1.16.
|
||||
func tryUpdateGoModAndGoSum(modMode ModMode, depMode DependencyInstallerMode) {
|
||||
// Go 1.16 and later won't automatically attempt to update go.mod / go.sum during package loading, so try to update them here:
|
||||
if modMode != ModVendor && depMode == GoGetWithModules && semver.Compare(getEnvGoSemVer(), "v1.16") >= 0 {
|
||||
@@ -361,10 +398,11 @@ type moveGopathInfo struct {
|
||||
files []string
|
||||
}
|
||||
|
||||
// Moves all files in `srcdir` to a temporary directory with the correct layout to be added to the GOPATH
|
||||
func moveToTemporaryGopath(srcdir string, importpath string) moveGopathInfo {
|
||||
// a temporary directory where everything is moved while the correct
|
||||
// directory structure is created.
|
||||
scratch, err := ioutil.TempDir(srcdir, "scratch")
|
||||
scratch, err := os.MkdirTemp(srcdir, "scratch")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create temporary directory %s in directory %s: %s\n",
|
||||
scratch, srcdir, err.Error())
|
||||
@@ -422,6 +460,8 @@ func moveToTemporaryGopath(srcdir string, importpath string) moveGopathInfo {
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a path transformer file in the new directory to ensure paths in the source archive and the snapshot
|
||||
// match the original source location, not the location we moved it to.
|
||||
func createPathTransformerFile(newdir string) *os.File {
|
||||
err := os.Chdir(newdir)
|
||||
if err != nil {
|
||||
@@ -430,13 +470,14 @@ func createPathTransformerFile(newdir string) *os.File {
|
||||
|
||||
// set up SEMMLE_PATH_TRANSFORMER to ensure paths in the source archive and the snapshot
|
||||
// match the original source location, not the location we moved it to
|
||||
pt, err := ioutil.TempFile("", "path-transformer")
|
||||
pt, err := os.CreateTemp("", "path-transformer")
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to create path transformer file: %s.", err.Error())
|
||||
}
|
||||
return pt
|
||||
}
|
||||
|
||||
// Writes the path transformer file
|
||||
func writePathTransformerFile(pt *os.File, realSrc, root, newdir string) {
|
||||
_, err := pt.WriteString("#" + realSrc + "\n" + newdir + "//\n")
|
||||
if err != nil {
|
||||
@@ -452,6 +493,7 @@ func writePathTransformerFile(pt *os.File, realSrc, root, newdir string) {
|
||||
}
|
||||
}
|
||||
|
||||
// Adds `root` to GOPATH.
|
||||
func setGopath(root string) {
|
||||
// set/extend GOPATH
|
||||
oldGopath := os.Getenv("GOPATH")
|
||||
@@ -471,6 +513,8 @@ func setGopath(root string) {
|
||||
log.Printf("GOPATH set to %s.\n", newGopath)
|
||||
}
|
||||
|
||||
// Try to build the project without custom commands. If that fails, return a boolean indicating
|
||||
// that we should install dependencies ourselves.
|
||||
func buildWithoutCustomCommands(modMode ModMode) bool {
|
||||
shouldInstallDependencies := false
|
||||
// try to build the project
|
||||
@@ -490,6 +534,7 @@ func buildWithoutCustomCommands(modMode ModMode) bool {
|
||||
return shouldInstallDependencies
|
||||
}
|
||||
|
||||
// Build the project with custom commands.
|
||||
func buildWithCustomCommands(inst string) {
|
||||
// write custom build commands into a script, then run it
|
||||
var (
|
||||
@@ -505,7 +550,7 @@ func buildWithCustomCommands(inst string) {
|
||||
ext = ".sh"
|
||||
header = "#! /bin/bash\nset -xe +u\n"
|
||||
}
|
||||
script, err := ioutil.TempFile("", "go-build-command-*"+ext)
|
||||
script, err := os.CreateTemp("", "go-build-command-*"+ext)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to create temporary script holding custom build commands: %s\n", err.Error())
|
||||
}
|
||||
@@ -523,6 +568,7 @@ func buildWithCustomCommands(inst string) {
|
||||
util.RunCmd(exec.Command(script.Name()))
|
||||
}
|
||||
|
||||
// Install dependencies using the given dependency installer mode.
|
||||
func installDependencies(depMode DependencyInstallerMode) {
|
||||
// automatically determine command to install dependencies
|
||||
var install *exec.Cmd
|
||||
@@ -574,6 +620,7 @@ func installDependencies(depMode DependencyInstallerMode) {
|
||||
util.RunCmd(install)
|
||||
}
|
||||
|
||||
// Run the extractor.
|
||||
func extract(depMode DependencyInstallerMode, modMode ModMode) {
|
||||
extractor, err := util.GetExtractorPath()
|
||||
if err != nil {
|
||||
@@ -601,12 +648,8 @@ func extract(depMode DependencyInstallerMode, modMode ModMode) {
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) > 1 {
|
||||
usage()
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
// Build the project and run the extractor.
|
||||
func installDependenciesAndBuild() {
|
||||
log.Printf("Autobuilder was built with %s, environment has %s\n", runtime.Version(), getEnvGoVersion())
|
||||
|
||||
srcdir := getSourceDir()
|
||||
@@ -617,31 +660,14 @@ func main() {
|
||||
// determine how to install dependencies and whether a GOPATH needs to be set up before
|
||||
// extraction
|
||||
depMode := getDepMode()
|
||||
goDirectiveFound := false
|
||||
if _, present := os.LookupEnv("GO111MODULE"); !present {
|
||||
os.Setenv("GO111MODULE", "auto")
|
||||
}
|
||||
if depMode == GoGetWithModules {
|
||||
versionRe := regexp.MustCompile(`(?m)^go[ \t\r]+([0-9]+\.[0-9]+)$`)
|
||||
goMod, err := ioutil.ReadFile("go.mod")
|
||||
if err != nil {
|
||||
log.Println("Failed to read go.mod to check for missing Go version")
|
||||
} else {
|
||||
matches := versionRe.FindSubmatch(goMod)
|
||||
if matches != nil {
|
||||
goDirectiveFound = true
|
||||
if len(matches) > 1 {
|
||||
goDirectiveVersion := "v" + string(matches[1])
|
||||
if semver.Compare(goDirectiveVersion, getEnvGoSemVer()) >= 0 {
|
||||
diagnostics.EmitNewerGoVersionNeeded()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, goModVersionFound := tryReadGoDirective(depMode)
|
||||
|
||||
modMode := getModMode(depMode)
|
||||
modMode = fixGoVendorIssues(modMode, depMode, goDirectiveFound)
|
||||
modMode = fixGoVendorIssues(modMode, depMode, goModVersionFound)
|
||||
|
||||
tryUpdateGoModAndGoSum(modMode, depMode)
|
||||
|
||||
@@ -692,3 +718,186 @@ func main() {
|
||||
|
||||
extract(depMode, modMode)
|
||||
}
|
||||
|
||||
const minGoVersion = "1.11"
|
||||
const maxGoVersion = "1.20"
|
||||
|
||||
// Check if `version` is lower than `minGoVersion` or higher than `maxGoVersion`. Note that for
|
||||
// this comparison we ignore the patch part of the version, so 1.20.1 and 1.20 are considered
|
||||
// equal.
|
||||
func outsideSupportedRange(version string) bool {
|
||||
short := semver.MajorMinor("v" + version)
|
||||
return semver.Compare(short, "v"+minGoVersion) < 0 || semver.Compare(short, "v"+maxGoVersion) > 0
|
||||
}
|
||||
|
||||
// Check if `v.goModVersion` or `v.goEnvVersion` are outside of the supported range. If so, emit
|
||||
// a diagnostic and return an empty version to indicate that we should not attempt to install a
|
||||
// different version of Go.
|
||||
func checkForUnsupportedVersions(v versionInfo) (msg, version string) {
|
||||
if v.goModVersionFound && outsideSupportedRange(v.goModVersion) {
|
||||
msg = "The version of Go found in the `go.mod` file (" + v.goModVersion +
|
||||
") is outside of the supported range (" + minGoVersion + "-" + maxGoVersion + ")."
|
||||
version = ""
|
||||
diagnostics.EmitUnsupportedVersionGoMod(msg)
|
||||
}
|
||||
|
||||
if v.goEnVersionFound && outsideSupportedRange(v.goEnvVersion) {
|
||||
msg = "The version of Go installed in the environment (" + v.goEnvVersion +
|
||||
") is outside of the supported range (" + minGoVersion + "-" + maxGoVersion + ")."
|
||||
version = ""
|
||||
diagnostics.EmitUnsupportedVersionEnvironment(msg)
|
||||
}
|
||||
|
||||
return msg, version
|
||||
}
|
||||
|
||||
// Check if either `v.goEnVersionFound` or `v.goModVersionFound` are false. If so, emit
|
||||
// a diagnostic and return the version to install, or the empty string if we should not attempt to
|
||||
// install a version of Go. We assume that `checkForUnsupportedVersions` has already been
|
||||
// called, so any versions that are found are within the supported range.
|
||||
func checkForVersionsNotFound(v versionInfo) (msg, version string) {
|
||||
if !v.goEnVersionFound && !v.goModVersionFound {
|
||||
msg = "No version of Go installed and no `go.mod` file found. Writing an environment " +
|
||||
"file specifying the maximum supported version of Go (" + maxGoVersion + ")."
|
||||
version = maxGoVersion
|
||||
diagnostics.EmitNoGoModAndNoGoEnv(msg)
|
||||
}
|
||||
|
||||
if !v.goEnVersionFound && v.goModVersionFound {
|
||||
msg = "No version of Go installed. Writing an environment file specifying the version " +
|
||||
"of Go found in the `go.mod` file (" + v.goModVersion + ")."
|
||||
version = v.goModVersion
|
||||
diagnostics.EmitNoGoEnv(msg)
|
||||
}
|
||||
|
||||
if v.goEnVersionFound && !v.goModVersionFound {
|
||||
msg = "No `go.mod` file found. Version " + v.goEnvVersion + " installed in the environment."
|
||||
version = ""
|
||||
diagnostics.EmitNoGoMod(msg)
|
||||
}
|
||||
|
||||
return msg, version
|
||||
}
|
||||
|
||||
// Compare `v.goModVersion` and `v.goEnvVersion`. emit a diagnostic and return the version to
|
||||
// install, or the empty string if we should not attempt to install a version of Go. We assume that
|
||||
// `checkForUnsupportedVersions` and `checkForVersionsNotFound` have already been called, so both
|
||||
// versions are found and are within the supported range.
|
||||
func compareVersions(v versionInfo) (msg, version string) {
|
||||
if semver.Compare("v"+v.goModVersion, "v"+v.goEnvVersion) > 0 {
|
||||
msg = "The version of Go installed in the environment (" + v.goEnvVersion +
|
||||
") is lower than the version found in the `go.mod` file (" + v.goModVersion +
|
||||
").\nWriting an environment file specifying the version of Go from the `go.mod` " +
|
||||
"file (" + v.goModVersion + ")."
|
||||
version = v.goModVersion
|
||||
diagnostics.EmitVersionGoModHigherVersionEnvironment(msg)
|
||||
} else {
|
||||
msg = "The version of Go installed in the environment (" + v.goEnvVersion +
|
||||
") is high enough for the version found in the `go.mod` file (" + v.goModVersion + ")."
|
||||
version = ""
|
||||
diagnostics.EmitVersionGoModNotHigherVersionEnvironment(msg)
|
||||
}
|
||||
|
||||
return msg, version
|
||||
}
|
||||
|
||||
// Check the versions of Go found in the environment and in the `go.mod` file, and return a
|
||||
// version to install. If the version is the empty string then no installation is required.
|
||||
func getVersionToInstall(v versionInfo) (msg, version string) {
|
||||
msg, version = checkForUnsupportedVersions(v)
|
||||
if msg != "" {
|
||||
return msg, version
|
||||
}
|
||||
|
||||
msg, version = checkForVersionsNotFound(v)
|
||||
if msg != "" {
|
||||
return msg, version
|
||||
}
|
||||
|
||||
msg, version = compareVersions(v)
|
||||
return msg, version
|
||||
}
|
||||
|
||||
// Write an environment file to the current directory. If `version` is the empty string then
|
||||
// write an empty environment file, otherwise write an environment file specifying the version
|
||||
// of Go to install. The path to the environment file is specified by the
|
||||
// CODEQL_EXTRACTOR_ENVIRONMENT_JSON environment variable, or defaults to `environment.json`.
|
||||
func writeEnvironmentFile(version string) {
|
||||
var content string
|
||||
if version == "" {
|
||||
content = `{ "include": [] }`
|
||||
} else {
|
||||
content = `{ "include": [ { "go": { "version": "` + version + `" } } ] }`
|
||||
}
|
||||
|
||||
filename, ok := os.LookupEnv("CODEQL_EXTRACTOR_ENVIRONMENT_JSON")
|
||||
if !ok {
|
||||
filename = "environment.json"
|
||||
}
|
||||
|
||||
targetFile, err := os.Create(filename)
|
||||
if err != nil {
|
||||
log.Println("Failed to create environment file " + filename + ": ")
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err := targetFile.Close(); err != nil {
|
||||
log.Println("Failed to close environment file " + filename + ":")
|
||||
log.Println(err)
|
||||
}
|
||||
}()
|
||||
|
||||
_, err = targetFile.WriteString(content)
|
||||
if err != nil {
|
||||
log.Println("Failed to write to environment file " + filename + ": ")
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
type versionInfo struct {
|
||||
goModVersion string // The version of Go found in the go directive in the `go.mod` file.
|
||||
goModVersionFound bool // Whether a `go` directive was found in the `go.mod` file.
|
||||
goEnvVersion string // The version of Go found in the environment.
|
||||
goEnVersionFound bool // Whether an installation of Go was found in the environment.
|
||||
}
|
||||
|
||||
func (v versionInfo) String() string {
|
||||
return fmt.Sprintf(
|
||||
"go.mod version: %s, go.mod directive found: %t, go env version: %s, go installation found: %t",
|
||||
v.goModVersion, v.goModVersionFound, v.goEnvVersion, v.goEnVersionFound)
|
||||
}
|
||||
|
||||
// Check if Go is installed in the environment.
|
||||
func isGoInstalled() bool {
|
||||
_, err := exec.LookPath("go")
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// Get the version of Go to install and write it to an environment file.
|
||||
func identifyEnvironment() {
|
||||
var v versionInfo
|
||||
depMode := getDepMode()
|
||||
v.goModVersion, v.goModVersionFound = tryReadGoDirective(depMode)
|
||||
|
||||
v.goEnVersionFound = isGoInstalled()
|
||||
if v.goEnVersionFound {
|
||||
v.goEnvVersion = getEnvGoVersion()[2:]
|
||||
}
|
||||
|
||||
msg, versionToInstall := getVersionToInstall(v)
|
||||
log.Println(msg)
|
||||
|
||||
writeEnvironmentFile(versionToInstall)
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) == 1 {
|
||||
installDependenciesAndBuild()
|
||||
} else if len(os.Args) == 2 && os.Args[1] == "--identify-environment" {
|
||||
identifyEnvironment()
|
||||
} else {
|
||||
usage()
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,3 +33,56 @@ func TestParseGoVersion(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetVersionToInstall(t *testing.T) {
|
||||
tests := map[versionInfo]string{
|
||||
// checkForUnsupportedVersions()
|
||||
|
||||
// go.mod version below minGoVersion
|
||||
{"0.0", true, "1.20.3", true}: "",
|
||||
{"0.0", true, "9999.0", true}: "",
|
||||
{"0.0", true, "1.2.2", true}: "",
|
||||
{"0.0", true, "", false}: "",
|
||||
// go.mod version above maxGoVersion
|
||||
{"9999.0", true, "1.20.3", true}: "",
|
||||
{"9999.0", true, "9999.0.1", true}: "",
|
||||
{"9999.0", true, "1.1", true}: "",
|
||||
{"9999.0", true, "", false}: "",
|
||||
// Go installation found with version below minGoVersion
|
||||
{"1.20", true, "1.2.2", true}: "",
|
||||
{"1.11", true, "1.2.2", true}: "",
|
||||
{"", false, "1.2.2", true}: "",
|
||||
// Go installation found with version above maxGoVersion
|
||||
{"1.20", true, "9999.0.1", true}: "",
|
||||
{"1.11", true, "9999.0.1", true}: "",
|
||||
{"", false, "9999.0.1", true}: "",
|
||||
|
||||
// checkForVersionsNotFound()
|
||||
|
||||
// Go installation not found, go.mod version in supported range
|
||||
{"1.20", true, "", false}: "1.20",
|
||||
{"1.11", true, "", false}: "1.11",
|
||||
// Go installation not found, go.mod not found
|
||||
{"", false, "", false}: maxGoVersion,
|
||||
// Go installation found with version in supported range, go.mod not found
|
||||
{"", false, "1.11.13", true}: "",
|
||||
{"", false, "1.20.3", true}: "",
|
||||
|
||||
// compareVersions()
|
||||
|
||||
// Go installation found with version in supported range, go.mod version in supported range and go.mod version > go installation version
|
||||
{"1.20", true, "1.11.13", true}: "1.20",
|
||||
{"1.20", true, "1.12", true}: "1.20",
|
||||
// Go installation found with version in supported range, go.mod version in supported range and go.mod version <= go installation version
|
||||
// (Note comparisons ignore the patch version)
|
||||
{"1.11", true, "1.20", true}: "",
|
||||
{"1.11", true, "1.20.3", true}: "",
|
||||
{"1.20", true, "1.20.3", true}: "",
|
||||
}
|
||||
for input, expected := range tests {
|
||||
_, actual := getVersionToInstall(input)
|
||||
if actual != expected {
|
||||
t.Errorf("Expected getVersionToInstall(\"%s\") to be \"%s\", but got \"%s\".", input, expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
@@ -22,7 +21,7 @@ func main() {
|
||||
buildSteps := os.Args[2]
|
||||
|
||||
haveRepo := false
|
||||
content, err := ioutil.ReadFile(vars)
|
||||
content, err := os.ReadFile(vars)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -34,7 +33,7 @@ func main() {
|
||||
additionalVars += "SEMMLE_REPO_URL=${repository}\n"
|
||||
}
|
||||
content = append(content, []byte(additionalVars)...)
|
||||
err = ioutil.WriteFile(vars, content, 0644)
|
||||
err = os.WriteFile(vars, content, 0644)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -47,7 +46,7 @@ func main() {
|
||||
<build export="%s">${semmle_dist}/language-packs/go/tools/platform/${semmle_platform}/bin/go-autobuilder</build>
|
||||
</autoupdate>
|
||||
`, export))
|
||||
err = ioutil.WriteFile(buildSteps, content, 0644)
|
||||
err = os.WriteFile(buildSteps, content, 0644)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"go/scanner"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
@@ -20,7 +19,7 @@ func main() {
|
||||
defer csv.Flush()
|
||||
|
||||
for _, fileName := range flag.Args() {
|
||||
src, err := ioutil.ReadFile(fileName)
|
||||
src, err := os.ReadFile(fileName)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to read file %s.", fileName)
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ type visibilityStruct struct {
|
||||
}
|
||||
|
||||
var fullVisibility *visibilityStruct = &visibilityStruct{true, true, true}
|
||||
var telemetryOnly *visibilityStruct = &visibilityStruct{false, false, true}
|
||||
|
||||
type locationStruct struct {
|
||||
File string `json:"file,omitempty"`
|
||||
@@ -192,3 +193,80 @@ func EmitRelativeImportPaths() {
|
||||
noLocation,
|
||||
)
|
||||
}
|
||||
|
||||
func EmitUnsupportedVersionGoMod(msg string) {
|
||||
emitDiagnostic(
|
||||
"go/autobuilder/env-unsupported-version-in-go-mod",
|
||||
"Unsupported Go version in `go.mod` file",
|
||||
msg,
|
||||
severityNote,
|
||||
telemetryOnly,
|
||||
noLocation,
|
||||
)
|
||||
}
|
||||
|
||||
func EmitUnsupportedVersionEnvironment(msg string) {
|
||||
emitDiagnostic(
|
||||
"go/autobuilder/env-unsupported-version-in-environment",
|
||||
"Unsupported Go version in environment",
|
||||
msg,
|
||||
severityNote,
|
||||
telemetryOnly,
|
||||
noLocation,
|
||||
)
|
||||
}
|
||||
|
||||
func EmitNoGoModAndNoGoEnv(msg string) {
|
||||
emitDiagnostic(
|
||||
"go/autobuilder/env-no-go-mod-and-no-go-env",
|
||||
"No `go.mod` file found and no Go version in environment",
|
||||
msg,
|
||||
severityNote,
|
||||
telemetryOnly,
|
||||
noLocation,
|
||||
)
|
||||
}
|
||||
|
||||
func EmitNoGoEnv(msg string) {
|
||||
emitDiagnostic(
|
||||
"go/autobuilder/env-no-go-env",
|
||||
"No Go version in environment",
|
||||
msg,
|
||||
severityNote,
|
||||
telemetryOnly,
|
||||
noLocation,
|
||||
)
|
||||
}
|
||||
|
||||
func EmitNoGoMod(msg string) {
|
||||
emitDiagnostic(
|
||||
"go/autobuilder/env-no-go-mod",
|
||||
"No `go.mod` file found",
|
||||
msg,
|
||||
severityNote,
|
||||
telemetryOnly,
|
||||
noLocation,
|
||||
)
|
||||
}
|
||||
|
||||
func EmitVersionGoModHigherVersionEnvironment(msg string) {
|
||||
emitDiagnostic(
|
||||
"go/autobuilder/env-version-go-mod-higher-than-go-env",
|
||||
"The Go version in `go.mod` file is higher than the Go version in environment",
|
||||
msg,
|
||||
severityNote,
|
||||
telemetryOnly,
|
||||
noLocation,
|
||||
)
|
||||
}
|
||||
|
||||
func EmitVersionGoModNotHigherVersionEnvironment(msg string) {
|
||||
emitDiagnostic(
|
||||
"go/autobuilder/env-version-go-mod-lower-than-or-equal-to-go-env",
|
||||
"The Go version in `go.mod` file is lower than or equal to the Go version in environment",
|
||||
msg,
|
||||
severityNote,
|
||||
telemetryOnly,
|
||||
noLocation,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"go/token"
|
||||
"go/types"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -1807,7 +1806,7 @@ func extractNumLines(tw *trap.Writer, fileName string, ast *ast.File) {
|
||||
|
||||
// count lines of code by tokenizing
|
||||
linesOfCode := 0
|
||||
src, err := ioutil.ReadFile(fileName)
|
||||
src, err := os.ReadFile(fileName)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to read file %s.", fileName)
|
||||
}
|
||||
|
||||
@@ -2,13 +2,14 @@ package extractor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/mod/modfile"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/mod/modfile"
|
||||
|
||||
"github.com/github/codeql-go/extractor/dbscheme"
|
||||
"github.com/github/codeql-go/extractor/srcarchive"
|
||||
"github.com/github/codeql-go/extractor/trap"
|
||||
@@ -45,7 +46,7 @@ func (extraction *Extraction) extractGoMod(path string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open go.mod file %s: %s", path, err.Error())
|
||||
}
|
||||
data, err := ioutil.ReadAll(file)
|
||||
data, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read go.mod file %s: %s", path, err.Error())
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package srcarchive
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func mkProjectLayout(projectLayoutSource string, t *testing.T) (*ProjectLayout, error) {
|
||||
pt, err := ioutil.TempFile("", "path-transformer")
|
||||
pt, err := os.CreateTemp("", "path-transformer")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create temporary file for project layout: %s", err.Error())
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/types"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"unicode/utf8"
|
||||
@@ -51,7 +50,7 @@ func NewWriter(path string, pkg *packages.Package) (*Writer, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tmpFile, err := ioutil.TempFile(trapFileDir, filepath.Base(trapFilePath))
|
||||
tmpFile, err := os.CreateTemp(trapFileDir, filepath.Base(trapFilePath))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
## 0.5.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Taking a slice is now considered a sanitizer for `SafeUrlFlow`.
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
## 0.5.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Taking a slice is now considered a sanitizer for `SafeUrlFlow`.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.5.0
|
||||
lastReleaseVersion: 0.5.1
|
||||
|
||||
@@ -20,7 +20,7 @@ external string selectedSourceFile();
|
||||
* A hook to customize the functions printed by this query.
|
||||
*/
|
||||
class Cfg extends PrintAstConfiguration {
|
||||
override predicate shouldPrintFunction(FuncDecl func) { shouldPrintFile(func.getFile()) }
|
||||
override predicate shouldPrintFunction(FuncDecl func) { this.shouldPrintFile(func.getFile()) }
|
||||
|
||||
override predicate shouldPrintFile(File file) {
|
||||
file = getFileBySourceArchiveName(selectedSourceFile())
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/go-all
|
||||
version: 0.5.1-dev
|
||||
version: 0.5.2-dev
|
||||
groups: go
|
||||
dbscheme: go.dbscheme
|
||||
extractor: go
|
||||
@@ -10,3 +10,4 @@ dependencies:
|
||||
codeql/util: ${workspace}
|
||||
dataExtensions:
|
||||
- ext/*.model.yml
|
||||
warnOnImplicitThis: true
|
||||
|
||||
@@ -19,7 +19,7 @@ class Error extends @error {
|
||||
int getIndex() { errors(this, _, _, _, _, _, _, _, result) }
|
||||
|
||||
/** Gets the file in which this error was reported, if it can be determined. */
|
||||
ExtractedOrExternalFile getFile() { hasLocationInfo(result.getAbsolutePath(), _, _, _, _) }
|
||||
ExtractedOrExternalFile getFile() { this.hasLocationInfo(result.getAbsolutePath(), _, _, _, _) }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
@@ -37,7 +37,7 @@ class Error extends @error {
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this error. */
|
||||
string toString() { result = getMessage() }
|
||||
string toString() { result = this.getMessage() }
|
||||
}
|
||||
|
||||
/** An error reported by an unknown part of the Go frontend. */
|
||||
|
||||
@@ -32,17 +32,19 @@ module HTML {
|
||||
/**
|
||||
* Holds if this is a toplevel element, that is, if it does not have a parent element.
|
||||
*/
|
||||
predicate isTopLevel() { not exists(getParent()) }
|
||||
predicate isTopLevel() { not exists(this.getParent()) }
|
||||
|
||||
/**
|
||||
* Gets the root HTML document element in which this element is contained.
|
||||
*/
|
||||
DocumentElement getDocument() { result = getRoot() }
|
||||
DocumentElement getDocument() { result = this.getRoot() }
|
||||
|
||||
/**
|
||||
* Gets the root element in which this element is contained.
|
||||
*/
|
||||
Element getRoot() { if isTopLevel() then result = this else result = getParent().getRoot() }
|
||||
Element getRoot() {
|
||||
if this.isTopLevel() then result = this else result = this.getParent().getRoot()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `i`th child element (0-based) of this element.
|
||||
@@ -52,7 +54,7 @@ module HTML {
|
||||
/**
|
||||
* Gets a child element of this element.
|
||||
*/
|
||||
Element getChild() { result = getChild(_) }
|
||||
Element getChild() { result = this.getChild(_) }
|
||||
|
||||
/**
|
||||
* Gets the `i`th attribute (0-based) of this element.
|
||||
@@ -62,13 +64,13 @@ module HTML {
|
||||
/**
|
||||
* Gets an attribute of this element.
|
||||
*/
|
||||
Attribute getAnAttribute() { result = getAttribute(_) }
|
||||
Attribute getAnAttribute() { result = this.getAttribute(_) }
|
||||
|
||||
/**
|
||||
* Gets an attribute of this element that has the given name.
|
||||
*/
|
||||
Attribute getAttributeByName(string name) {
|
||||
result = getAnAttribute() and
|
||||
result = this.getAnAttribute() and
|
||||
result.getName() = name
|
||||
}
|
||||
|
||||
@@ -77,7 +79,7 @@ module HTML {
|
||||
*/
|
||||
TextNode getTextNode() { result.getParent() = this }
|
||||
|
||||
override string toString() { result = "<" + getName() + ">...</>" }
|
||||
override string toString() { result = "<" + this.getName() + ">...</>" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,7 +108,7 @@ module HTML {
|
||||
* Gets the root element in which the element to which this attribute
|
||||
* belongs is contained.
|
||||
*/
|
||||
Element getRoot() { result = getElement().getRoot() }
|
||||
Element getRoot() { result = this.getElement().getRoot() }
|
||||
|
||||
/**
|
||||
* Gets the name of this attribute.
|
||||
@@ -121,7 +123,7 @@ module HTML {
|
||||
*/
|
||||
string getValue() { xmlAttrs(this, _, _, result, _, _) }
|
||||
|
||||
override string toString() { result = getName() + "=" + getValue() }
|
||||
override string toString() { result = this.getName() + "=" + this.getValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,7 +140,7 @@ module HTML {
|
||||
* ```
|
||||
*/
|
||||
class DocumentElement extends Element {
|
||||
DocumentElement() { getName() = "html" }
|
||||
DocumentElement() { this.getName() = "html" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,7 +157,7 @@ module HTML {
|
||||
class TextNode extends Locatable, @xmlcharacters {
|
||||
TextNode() { exists(HtmlFile f | xmlChars(this, _, _, _, _, f)) }
|
||||
|
||||
override string toString() { result = getText() }
|
||||
override string toString() { result = this.getText() }
|
||||
|
||||
/**
|
||||
* Gets the content of this text node.
|
||||
@@ -198,7 +200,7 @@ module HTML {
|
||||
Element getParent() { xmlComments(this, _, result, _) }
|
||||
|
||||
/** Gets the text of this comment, not including delimiters. */
|
||||
string getText() { result = toString().regexpCapture("(?s)<!--(.*)-->", 1) }
|
||||
string getText() { result = this.toString().regexpCapture("(?s)<!--(.*)-->", 1) }
|
||||
|
||||
override string toString() { xmlComments(this, result, _, _) }
|
||||
|
||||
|
||||
@@ -25,12 +25,12 @@ class Location extends @location {
|
||||
int getEndColumn() { locations_default(this, _, _, _, _, result) }
|
||||
|
||||
/** Gets the number of lines covered by this location. */
|
||||
int getNumLines() { result = getEndLine() - getStartLine() + 1 }
|
||||
int getNumLines() { result = this.getEndLine() - this.getStartLine() + 1 }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() {
|
||||
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
|
||||
hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
|
||||
this.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
|
||||
result = filepath + "@" + startline + ":" + startcolumn + ":" + endline + ":" + endcolumn
|
||||
)
|
||||
}
|
||||
@@ -55,13 +55,13 @@ class Location extends @location {
|
||||
/** A program element with a location. */
|
||||
class Locatable extends @locatable {
|
||||
/** Gets the file this program element comes from. */
|
||||
File getFile() { result = getLocation().getFile() }
|
||||
File getFile() { result = this.getLocation().getFile() }
|
||||
|
||||
/** Gets this element's location. */
|
||||
Location getLocation() { has_location(this, result) }
|
||||
|
||||
/** Gets the number of lines covered by this element. */
|
||||
int getNumLines() { result = getLocation().getNumLines() }
|
||||
int getNumLines() { result = this.getLocation().getNumLines() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
@@ -73,7 +73,7 @@ class Locatable extends @locatable {
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
|
||||
@@ -22,7 +22,7 @@ class Package extends @package {
|
||||
PackageScope getScope() { packages(this, _, _, result) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = "package " + getPath() }
|
||||
string toString() { result = "package " + this.getPath() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -85,12 +85,12 @@ class PrintAstNode extends TPrintAstNode {
|
||||
* within a function are printed, but the query can override
|
||||
* `PrintAstConfiguration.shouldPrintFunction` to filter the output.
|
||||
*/
|
||||
predicate shouldPrint() { exists(getLocation()) }
|
||||
predicate shouldPrint() { exists(this.getLocation()) }
|
||||
|
||||
/**
|
||||
* Gets a child of this node.
|
||||
*/
|
||||
PrintAstNode getAChild() { result = getChild(_) }
|
||||
PrintAstNode getAChild() { result = this.getChild(_) }
|
||||
|
||||
/**
|
||||
* Gets the location of this node in the source code.
|
||||
@@ -103,7 +103,7 @@ class PrintAstNode extends TPrintAstNode {
|
||||
*/
|
||||
string getProperty(string key) {
|
||||
key = "semmle.label" and
|
||||
result = toString()
|
||||
result = this.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +112,7 @@ class PrintAstNode extends TPrintAstNode {
|
||||
* this.
|
||||
*/
|
||||
string getChildEdgeLabel(int childIndex) {
|
||||
exists(getChild(childIndex)) and
|
||||
exists(this.getChild(childIndex)) and
|
||||
result = childIndex.toString()
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ class FileNode extends BaseAstNode {
|
||||
result = super.getProperty(key)
|
||||
or
|
||||
key = "semmle.order" and
|
||||
result = getSortOrder().toString()
|
||||
result = this.getSortOrder().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -220,7 +220,7 @@ class FileNode extends BaseAstNode {
|
||||
*/
|
||||
override BaseAstNode getChild(int childIndex) {
|
||||
if exists(ast.getPackageNameExpr())
|
||||
then result = getChildPackageFirst(childIndex, TAstNode(ast.getPackageNameExpr()), _)
|
||||
then result = this.getChildPackageFirst(childIndex, TAstNode(ast.getPackageNameExpr()), _)
|
||||
else result = super.getChild(childIndex)
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ class FileNode extends BaseAstNode {
|
||||
* of this method.
|
||||
*/
|
||||
override string getChildEdgeLabel(int childIndex) {
|
||||
if getChild(childIndex) = TAstNode(ast.getPackageNameExpr())
|
||||
if this.getChild(childIndex) = TAstNode(ast.getPackageNameExpr())
|
||||
then result = "package"
|
||||
else result = super.getChildEdgeLabel(childIndex)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user