Merge branch 'main' into modernsec3

This commit is contained in:
Geoffrey White
2023-05-04 12:50:27 +01:00
507 changed files with 5020 additions and 3095 deletions

View File

@@ -1,6 +1,6 @@
{
"extensions": [
"rust-lang.rust",
"rust-lang.rust-analyzer",
"bungcip.better-toml",
"github.vscode-codeql",
"hbenl.vscode-test-explorer",

View 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

View File

@@ -1,3 +1,7 @@
## 0.7.1
No user-facing changes.
## 0.7.0
### Breaking Changes

View File

@@ -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.

View File

@@ -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.

View 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.

View File

@@ -0,0 +1,3 @@
## 0.7.1
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.7.0
lastReleaseVersion: 0.7.1

View File

@@ -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

View File

@@ -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)
}
}
/**

View File

@@ -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)
}
}
/**

View File

@@ -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

View File

@@ -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)
)
}
}
/**

View File

@@ -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 {

View File

@@ -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

View File

@@ -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
) {

View File

@@ -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

View File

@@ -34,6 +34,7 @@ newtype TInstructionTag =
CallTargetTag() or
CallTag() or
CallSideEffectTag() or
CallNoReturnTag() or
AllocationSizeTag() or
AllocationElementSizeTag() or
AllocationExtentConvertTag() or

View File

@@ -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()) }
}
/**

View File

@@ -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()
}
/**

View File

@@ -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()

View File

@@ -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())
)
}
}

View File

@@ -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 {

View File

@@ -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

View File

@@ -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 {

View File

@@ -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

View File

@@ -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".

View File

@@ -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.

View 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.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.6.0
lastReleaseVersion: 0.6.1

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 0.6.1-dev
version: 0.6.2-dev
groups:
- cpp
- queries

View File

@@ -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 |

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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()
}
}
}

View File

@@ -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>:

View File

@@ -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

View File

@@ -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 |

View File

@@ -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

View File

@@ -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 :

View File

@@ -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 :

View File

@@ -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;
}

View File

@@ -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 :

View File

@@ -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 :

View File

@@ -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

View File

@@ -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. |

View File

@@ -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
{

View File

@@ -1,3 +1,7 @@
## 1.5.1
No user-facing changes.
## 1.5.0
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.5.1
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.5.0
lastReleaseVersion: 1.5.1

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
version: 1.5.1-dev
version: 1.5.2-dev
groups:
- csharp
- solorigate

View File

@@ -1,3 +1,7 @@
## 1.5.1
No user-facing changes.
## 1.5.0
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.5.1
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.5.0
lastReleaseVersion: 1.5.1

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
version: 1.5.1-dev
version: 1.5.2-dev
groups:
- csharp
- solorigate

View File

@@ -1,3 +1,7 @@
## 0.6.1
No user-facing changes.
## 0.6.0
### Deprecated APIs

View File

@@ -0,0 +1,3 @@
## 0.6.1
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.6.0
lastReleaseVersion: 0.6.1

View File

@@ -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

View File

@@ -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. */

View File

@@ -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)
}
}
/**

View File

@@ -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

View File

@@ -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

View File

@@ -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()
)

View File

@@ -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.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.6.0
lastReleaseVersion: 0.6.1

View File

@@ -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
) {

View File

@@ -414,6 +414,8 @@ private module Cached {
}
}
predicate hasUnreachedInstruction(IRFunction func) { none() }
import CachedForDebugging
cached

View File

@@ -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

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-queries
version: 0.6.1-dev
version: 0.6.2-dev
groups:
- csharp
- queries

View File

@@ -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

View File

@@ -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())
}
/**

View File

@@ -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

View File

@@ -1,5 +1,7 @@
.. _codeql-cli-reference:
:orphan:
CodeQL CLI reference
====================

View File

@@ -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>

View File

@@ -1,5 +1,7 @@
.. _using-the-codeql-cli:
:orphan:
Using the CodeQL CLI
====================

View File

@@ -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
------------------------

View File

@@ -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
--------------------------------------------------------

View File

@@ -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.

View File

@@ -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)
}
}

View File

@@ -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)
}
}
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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,
)
}

View File

@@ -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)
}

View File

@@ -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())
}

View File

@@ -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())
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -1,4 +1,5 @@
---
category: minorAnalysis
---
## 0.5.1
### Minor Analysis Improvements
* Taking a slice is now considered a sanitizer for `SafeUrlFlow`.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.5.0
lastReleaseVersion: 0.5.1

View File

@@ -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())

View File

@@ -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

View File

@@ -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. */

View File

@@ -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, _, _) }

View File

@@ -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. */

View File

@@ -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() }
}
/**

View File

@@ -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