Merge branch 'main' into lgtm-updates

This commit is contained in:
James Fletcher
2022-09-29 17:37:54 +01:00
committed by GitHub
803 changed files with 75691 additions and 50818 deletions

View File

@@ -43,7 +43,7 @@ jobs:
env QHELP_OUT_DIR=qhelp-out make qhelp-to-markdown
- name: Upload qhelp markdown
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: qhelp-markdown
path: go/qhelp-out/**/*.md

View File

@@ -1,3 +1,18 @@
## 0.4.0
### Deprecated APIs
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.
### New Features
* Added subclasses of `BuiltInOperations` for `__is_same`, `__is_function`, `__is_layout_compatible`, `__is_pointer_interconvertible_base_of`, `__is_array`, `__array_rank`, `__array_extent`, `__is_arithmetic`, `__is_complete_type`, `__is_compound`, `__is_const`, `__is_floating_point`, `__is_fundamental`, `__is_integral`, `__is_lvalue_reference`, `__is_member_function_pointer`, `__is_member_object_pointer`, `__is_member_pointer`, `__is_object`, `__is_pointer`, `__is_reference`, `__is_rvalue_reference`, `__is_scalar`, `__is_signed`, `__is_unsigned`, `__is_void`, and `__is_volatile`.
### Bug Fixes
* Fixed an issue in the taint tracking analysis where implicit reads were not allowed by default in sinks or additional taint steps that used flow states.
## 0.3.5
## 0.3.4

View File

@@ -1,4 +0,0 @@
---
category: fix
---
* Fixed an issue in the taint tracking analysis where implicit reads were not allowed by default in sinks or additional taint steps that used flow states.

View File

@@ -1,5 +0,0 @@
---
category: deprecated
---
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.

View File

@@ -1,4 +1,14 @@
---
category: feature
---
## 0.4.0
### Deprecated APIs
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.
### New Features
* Added subclasses of `BuiltInOperations` for `__is_same`, `__is_function`, `__is_layout_compatible`, `__is_pointer_interconvertible_base_of`, `__is_array`, `__array_rank`, `__array_extent`, `__is_arithmetic`, `__is_complete_type`, `__is_compound`, `__is_const`, `__is_floating_point`, `__is_fundamental`, `__is_integral`, `__is_lvalue_reference`, `__is_member_function_pointer`, `__is_member_object_pointer`, `__is_member_pointer`, `__is_object`, `__is_pointer`, `__is_reference`, `__is_rvalue_reference`, `__is_scalar`, `__is_signed`, `__is_unsigned`, `__is_void`, and `__is_volatile`.
### Bug Fixes
* Fixed an issue in the taint tracking analysis where implicit reads were not allowed by default in sinks or additional taint steps that used flow states.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.3.5
lastReleaseVersion: 0.4.0

View File

@@ -20,7 +20,8 @@ module ProductFlow {
* `source1` and `source2` must belong to the same callable.
*/
predicate isSourcePair(
DataFlow::Node source1, string state1, DataFlow::Node source2, string state2
DataFlow::Node source1, DataFlow::FlowState state1, DataFlow::Node source2,
DataFlow::FlowState state2
) {
state1 = "" and
state2 = "" and
@@ -49,6 +50,89 @@ module ProductFlow {
this.isSinkPair(sink1, sink2)
}
/**
* Holds if data flow through `node` is prohibited through the first projection of the product
* dataflow graph when the flow state is `state`.
*/
predicate isBarrier1(DataFlow::Node node, DataFlow::FlowState state) {
this.isBarrier1(node) and state = ""
}
/**
* Holds if data flow through `node` is prohibited through the second projection of the product
* dataflow graph when the flow state is `state`.
*/
predicate isBarrier2(DataFlow::Node node, DataFlow::FlowState state) {
this.isBarrier2(node) and state = ""
}
/**
* Holds if data flow through `node` is prohibited through the first projection of the product
* dataflow graph.
*/
predicate isBarrier1(DataFlow::Node node) { none() }
/**
* Holds if data flow through `node` is prohibited through the second projection of the product
* dataflow graph.
*/
predicate isBarrier2(DataFlow::Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited in the first projection of the product
* dataflow graph.
*/
predicate isBarrierOut1(DataFlow::Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited in the second projection of the product
* dataflow graph.
*/
predicate isBarrierOut2(DataFlow::Node node) { none() }
/*
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
* the first projection of the product dataflow graph.
*/
predicate isAdditionalFlowStep1(DataFlow::Node node1, DataFlow::Node node2) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
* the first projection of the product dataflow graph.
*
* This step is only applicable in `state1` and updates the flow state to `state2`.
*/
predicate isAdditionalFlowStep1(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
state1 instanceof DataFlow::FlowStateEmpty and
state2 instanceof DataFlow::FlowStateEmpty and
this.isAdditionalFlowStep1(node1, node2)
}
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
* the second projection of the product dataflow graph.
*/
predicate isAdditionalFlowStep2(DataFlow::Node node1, DataFlow::Node node2) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
* the second projection of the product dataflow graph.
*
* This step is only applicable in `state1` and updates the flow state to `state2`.
*/
predicate isAdditionalFlowStep2(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
state1 instanceof DataFlow::FlowStateEmpty and
state2 instanceof DataFlow::FlowStateEmpty and
this.isAdditionalFlowStep2(node1, node2)
}
predicate hasFlowPath(
DataFlow::PathNode source1, DataFlow2::PathNode source2, DataFlow::PathNode sink1,
DataFlow2::PathNode sink2
@@ -63,30 +147,61 @@ module ProductFlow {
class Conf1 extends DataFlow::Configuration {
Conf1() { this = "Conf1" }
override predicate isSource(DataFlow::Node source, string state) {
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
exists(Configuration conf | conf.isSourcePair(source, state, _, _))
}
override predicate isSink(DataFlow::Node sink, string state) {
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
exists(Configuration conf | conf.isSinkPair(sink, state, _, _))
}
override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
exists(Configuration conf | conf.isBarrier1(node, state))
}
override predicate isBarrierOut(DataFlow::Node node) {
exists(Configuration conf | conf.isBarrierOut1(node))
}
override predicate isAdditionalFlowStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
exists(Configuration conf | conf.isAdditionalFlowStep1(node1, state1, node2, state2))
}
}
class Conf2 extends DataFlow2::Configuration {
Conf2() { this = "Conf2" }
override predicate isSource(DataFlow::Node source, string state) {
exists(Configuration conf, DataFlow::Node source1 |
conf.isSourcePair(source1, _, source, state) and
any(Conf1 c).hasFlow(source1, _)
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
exists(Configuration conf, DataFlow::PathNode source1 |
conf.isSourcePair(source1.getNode(), source1.getState(), source, state) and
any(Conf1 c).hasFlowPath(source1, _)
)
}
override predicate isSink(DataFlow::Node sink, string state) {
exists(Configuration conf, DataFlow::Node sink1 |
conf.isSinkPair(sink1, _, sink, state) and any(Conf1 c).hasFlow(_, sink1)
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
exists(Configuration conf, DataFlow::PathNode sink1 |
conf.isSinkPair(sink1.getNode(), sink1.getState(), sink, state) and
any(Conf1 c).hasFlowPath(_, sink1)
)
}
override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
exists(Configuration conf | conf.isBarrier2(node, state))
}
override predicate isBarrierOut(DataFlow::Node node) {
exists(Configuration conf | conf.isBarrierOut2(node))
}
override predicate isAdditionalFlowStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
exists(Configuration conf | conf.isAdditionalFlowStep2(node1, state1, node2, state2))
}
}
}
@@ -94,7 +209,7 @@ module ProductFlow {
Configuration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2,
DataFlow::PathNode node1, DataFlow2::PathNode node2
) {
conf.isSourcePair(node1.getNode(), _, node2.getNode(), _) and
conf.isSourcePair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState()) and
node1 = source1 and
node2 = source2
or
@@ -157,7 +272,7 @@ module ProductFlow {
) {
exists(DataFlow::PathNode mid1, DataFlow2::PathNode mid2 |
reachableInterprocEntry(conf, source1, source2, mid1, mid2) and
conf.isSinkPair(sink1.getNode(), _, sink2.getNode(), _) and
conf.isSinkPair(sink1.getNode(), sink1.getState(), sink2.getNode(), sink2.getState()) and
localPathStep1*(mid1, sink1) and
localPathStep2*(mid2, sink2)
)

View File

@@ -558,13 +558,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
read(_, tc.getContent(), _, config) and
hasReadStep(tc.getContent(), config) and
stepFilter(node1, node2, config)
}
@@ -598,13 +601,9 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
class ApOption = Unit;
class Cc = boolean;
private class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -613,7 +612,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -753,7 +752,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,13 +558,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
read(_, tc.getContent(), _, config) and
hasReadStep(tc.getContent(), config) and
stepFilter(node1, node2, config)
}
@@ -598,13 +601,9 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
class ApOption = Unit;
class Cc = boolean;
private class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -613,7 +612,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -753,7 +752,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,13 +558,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
read(_, tc.getContent(), _, config) and
hasReadStep(tc.getContent(), config) and
stepFilter(node1, node2, config)
}
@@ -598,13 +601,9 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
class ApOption = Unit;
class Cc = boolean;
private class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -613,7 +612,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -753,7 +752,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,13 +558,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
read(_, tc.getContent(), _, config) and
hasReadStep(tc.getContent(), config) and
stepFilter(node1, node2, config)
}
@@ -598,13 +601,9 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
class ApOption = Unit;
class Cc = boolean;
private class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -613,7 +612,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -753,7 +752,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -709,7 +709,8 @@ private module Cached {
*/
pragma[nomagic]
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
result = viableImplInCallContext(call, ctx)
result = viableImplInCallContext(call, ctx) and
result = viableCallable(call)
or
result = viableCallableLambda(call, TDataFlowCallSome(ctx))
or

View File

@@ -32,6 +32,19 @@ module Consistency {
/** Holds if `n` should be excluded from the consistency test `reverseRead`. */
predicate reverseReadExclude(Node n) { none() }
/** Holds if `n` should be excluded from the consistency test `postHasUniquePre`. */
predicate postHasUniquePreExclude(PostUpdateNode n) { none() }
/** Holds if `n` should be excluded from the consistency test `uniquePostUpdate`. */
predicate uniquePostUpdateExclude(Node n) { none() }
/** Holds if `(call, ctx)` should be excluded from the consistency test `viableImplInCallContextTooLargeExclude`. */
predicate viableImplInCallContextTooLargeExclude(
DataFlowCall call, DataFlowCall ctx, DataFlowCallable callable
) {
none()
}
}
private class RelevantNode extends Node {
@@ -166,6 +179,7 @@ module Consistency {
}
query predicate postHasUniquePre(PostUpdateNode n, string msg) {
not any(ConsistencyConfiguration conf).postHasUniquePreExclude(n) and
exists(int c |
c = count(n.getPreUpdateNode()) and
c != 1 and
@@ -174,6 +188,7 @@ module Consistency {
}
query predicate uniquePostUpdate(Node n, string msg) {
not any(ConsistencyConfiguration conf).uniquePostUpdateExclude(n) and
1 < strictcount(PostUpdateNode post | post.getPreUpdateNode() = n) and
msg = "Node has multiple PostUpdateNodes."
}
@@ -209,4 +224,12 @@ module Consistency {
not any(ConsistencyConfiguration c).postWithInFlowExclude(n) and
msg = "PostUpdateNode should not be the target of local flow."
}
query predicate viableImplInCallContextTooLarge(
DataFlowCall call, DataFlowCall ctx, DataFlowCallable callable
) {
callable = viableImplInCallContext(call, ctx) and
not callable = viableCallable(call) and
not any(ConsistencyConfiguration c).viableImplInCallContextTooLargeExclude(call, ctx, callable)
}
}

View File

@@ -416,6 +416,21 @@ class SsaPhiNode extends Node, TSsaPhiNode {
final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() }
override string toStringImpl() { result = "Phi" }
/**
* Gets a node that is used as input to this phi node.
* `fromBackEdge` is true if data flows along a back-edge,
* and `false` otherwise.
*/
final Node getAnInput(boolean fromBackEdge) {
localFlowStep(result, this) and
if phi.getBasicBlock().dominates(getBasicBlock(result))
then fromBackEdge = true
else fromBackEdge = false
}
/** Gets a node that is used as input to this phi node. */
final Node getAnInput() { result = this.getAnInput(_) }
}
/**

View File

@@ -301,7 +301,12 @@ private predicate defToNode(Node nodeFrom, Def def) {
nodeHasInstruction(nodeFrom, def.getDefiningInstruction(), def.getIndirectionIndex())
}
private predicate nodeToDefOrUse(Node nodeFrom, SsaDefOrUse defOrUse) {
/**
* INTERNAL: Do not use.
*
* Holds if `nodeFrom` is the node that correspond to the definition or use `defOrUse`.
*/
predicate nodeToDefOrUse(Node nodeFrom, SsaDefOrUse defOrUse) {
// Node -> Def
defToNode(nodeFrom, defOrUse)
or

View File

@@ -7,6 +7,7 @@ private import semmle.code.cpp.ir.IR as IR
private import Semantic
private import experimental.semmle.code.cpp.rangeanalysis.Bound as IRBound
private import semmle.code.cpp.controlflow.IRGuards as IRGuards
private import semmle.code.cpp.ir.ValueNumbering
module SemanticExprConfig {
class Location = Cpp::Location;
@@ -120,7 +121,15 @@ module SemanticExprConfig {
newtype TSsaVariable =
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() }
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() } or
TSsaPointerArithmeticGuard(IR::PointerArithmeticInstruction instr) {
exists(Guard g, IR::Operand use | use = instr.getAUse() |
g.comparesLt(use, _, _, _, _) or
g.comparesLt(_, use, _, _, _) or
g.comparesEq(use, _, _, _, _) or
g.comparesEq(_, use, _, _, _)
)
}
class SsaVariable extends TSsaVariable {
string toString() { none() }
@@ -129,6 +138,8 @@ module SemanticExprConfig {
IR::Instruction asInstruction() { none() }
IR::PointerArithmeticInstruction asPointerArithGuard() { none() }
IR::Operand asOperand() { none() }
}
@@ -144,6 +155,18 @@ module SemanticExprConfig {
final override IR::Instruction asInstruction() { result = instr }
}
class SsaPointerArithmeticGuard extends SsaVariable, TSsaPointerArithmeticGuard {
IR::PointerArithmeticInstruction instr;
SsaPointerArithmeticGuard() { this = TSsaPointerArithmeticGuard(instr) }
final override string toString() { result = instr.toString() }
final override Location getLocation() { result = instr.getLocation() }
final override IR::PointerArithmeticInstruction asPointerArithGuard() { result = instr }
}
class SsaOperand extends SsaVariable, TSsaOperand {
IR::Operand op;
@@ -168,7 +191,11 @@ module SemanticExprConfig {
)
}
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v.asInstruction() }
Expr getAUse(SsaVariable v) {
result.(IR::LoadInstruction).getSourceValue() = v.asInstruction()
or
result = valueNumber(v.asPointerArithGuard()).getAnInstruction()
}
SemType getSsaVariableType(SsaVariable v) {
result = getSemanticType(v.asInstruction().getResultIRType())
@@ -208,7 +235,9 @@ module SemanticExprConfig {
final override predicate hasRead(SsaVariable v) {
exists(IR::Operand operand |
operand.getDef() = v.asInstruction() and
operand.getDef() = v.asInstruction() or
operand.getDef() = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
not operand instanceof IR::PhiInputOperand and
operand.getUse().getBlock() = block
)
@@ -227,7 +256,9 @@ module SemanticExprConfig {
final override predicate hasRead(SsaVariable v) {
exists(IR::PhiInputOperand operand |
operand.getDef() = v.asInstruction() and
operand.getDef() = v.asInstruction() or
operand.getDef() = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
operand.getPredecessorBlock() = pred and
operand.getUse().getBlock() = succ
)

View File

@@ -10,7 +10,7 @@ class SemSsaVariable instanceof Specific::SsaVariable {
final Specific::Location getLocation() { result = super.getLocation() }
final SemLoadExpr getAUse() { result = Specific::getAUse(this) }
final SemExpr getAUse() { result = Specific::getAUse(this) }
final SemType getType() { result = Specific::getSsaVariableType(this) }

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 0.3.6-dev
version: 0.4.1-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

@@ -6,7 +6,7 @@ import cpp
* A function that concatenates the string from its second argument
* to the string from its first argument, for example `strcat`.
*/
class StrcatFunction extends Function {
deprecated class StrcatFunction extends Function {
StrcatFunction() {
getName() =
[

View File

@@ -558,13 +558,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
read(_, tc.getContent(), _, config) and
hasReadStep(tc.getContent(), config) and
stepFilter(node1, node2, config)
}
@@ -598,13 +601,9 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
class ApOption = Unit;
class Cc = boolean;
private class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -613,7 +612,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -753,7 +752,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,13 +558,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
read(_, tc.getContent(), _, config) and
hasReadStep(tc.getContent(), config) and
stepFilter(node1, node2, config)
}
@@ -598,13 +601,9 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
class ApOption = Unit;
class Cc = boolean;
private class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -613,7 +612,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -753,7 +752,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,13 +558,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
read(_, tc.getContent(), _, config) and
hasReadStep(tc.getContent(), config) and
stepFilter(node1, node2, config)
}
@@ -598,13 +601,9 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
class ApOption = Unit;
class Cc = boolean;
private class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -613,7 +612,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -753,7 +752,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,13 +558,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
read(_, tc.getContent(), _, config) and
hasReadStep(tc.getContent(), config) and
stepFilter(node1, node2, config)
}
@@ -598,13 +601,9 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
class ApOption = Unit;
class Cc = boolean;
private class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -613,7 +612,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -753,7 +752,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -709,7 +709,8 @@ private module Cached {
*/
pragma[nomagic]
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
result = viableImplInCallContext(call, ctx)
result = viableImplInCallContext(call, ctx) and
result = viableCallable(call)
or
result = viableCallableLambda(call, TDataFlowCallSome(ctx))
or

View File

@@ -32,6 +32,19 @@ module Consistency {
/** Holds if `n` should be excluded from the consistency test `reverseRead`. */
predicate reverseReadExclude(Node n) { none() }
/** Holds if `n` should be excluded from the consistency test `postHasUniquePre`. */
predicate postHasUniquePreExclude(PostUpdateNode n) { none() }
/** Holds if `n` should be excluded from the consistency test `uniquePostUpdate`. */
predicate uniquePostUpdateExclude(Node n) { none() }
/** Holds if `(call, ctx)` should be excluded from the consistency test `viableImplInCallContextTooLargeExclude`. */
predicate viableImplInCallContextTooLargeExclude(
DataFlowCall call, DataFlowCall ctx, DataFlowCallable callable
) {
none()
}
}
private class RelevantNode extends Node {
@@ -166,6 +179,7 @@ module Consistency {
}
query predicate postHasUniquePre(PostUpdateNode n, string msg) {
not any(ConsistencyConfiguration conf).postHasUniquePreExclude(n) and
exists(int c |
c = count(n.getPreUpdateNode()) and
c != 1 and
@@ -174,6 +188,7 @@ module Consistency {
}
query predicate uniquePostUpdate(Node n, string msg) {
not any(ConsistencyConfiguration conf).uniquePostUpdateExclude(n) and
1 < strictcount(PostUpdateNode post | post.getPreUpdateNode() = n) and
msg = "Node has multiple PostUpdateNodes."
}
@@ -209,4 +224,12 @@ module Consistency {
not any(ConsistencyConfiguration c).postWithInFlowExclude(n) and
msg = "PostUpdateNode should not be the target of local flow."
}
query predicate viableImplInCallContextTooLarge(
DataFlowCall call, DataFlowCall ctx, DataFlowCallable callable
) {
callable = viableImplInCallContext(call, ctx) and
not callable = viableCallable(call) and
not any(ConsistencyConfiguration c).viableImplInCallContextTooLargeExclude(call, ctx, callable)
}
}

View File

@@ -558,13 +558,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
read(_, tc.getContent(), _, config) and
hasReadStep(tc.getContent(), config) and
stepFilter(node1, node2, config)
}
@@ -598,13 +601,9 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
class ApOption = Unit;
class Cc = boolean;
private class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -613,7 +612,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -753,7 +752,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,13 +558,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
read(_, tc.getContent(), _, config) and
hasReadStep(tc.getContent(), config) and
stepFilter(node1, node2, config)
}
@@ -598,13 +601,9 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
class ApOption = Unit;
class Cc = boolean;
private class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -613,7 +612,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -753,7 +752,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,13 +558,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
read(_, tc.getContent(), _, config) and
hasReadStep(tc.getContent(), config) and
stepFilter(node1, node2, config)
}
@@ -598,13 +601,9 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
class ApOption = Unit;
class Cc = boolean;
private class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -613,7 +612,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -753,7 +752,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,13 +558,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
read(_, tc.getContent(), _, config) and
hasReadStep(tc.getContent(), config) and
stepFilter(node1, node2, config)
}
@@ -598,13 +601,9 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
class ApOption = Unit;
class Cc = boolean;
private class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -613,7 +612,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -753,7 +752,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,13 +558,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
read(_, tc.getContent(), _, config) and
hasReadStep(tc.getContent(), config) and
stepFilter(node1, node2, config)
}
@@ -598,13 +601,9 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
class ApOption = Unit;
class Cc = boolean;
private class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -613,7 +612,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -753,7 +752,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -709,7 +709,8 @@ private module Cached {
*/
pragma[nomagic]
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
result = viableImplInCallContext(call, ctx)
result = viableImplInCallContext(call, ctx) and
result = viableCallable(call)
or
result = viableCallableLambda(call, TDataFlowCallSome(ctx))
or

View File

@@ -32,6 +32,19 @@ module Consistency {
/** Holds if `n` should be excluded from the consistency test `reverseRead`. */
predicate reverseReadExclude(Node n) { none() }
/** Holds if `n` should be excluded from the consistency test `postHasUniquePre`. */
predicate postHasUniquePreExclude(PostUpdateNode n) { none() }
/** Holds if `n` should be excluded from the consistency test `uniquePostUpdate`. */
predicate uniquePostUpdateExclude(Node n) { none() }
/** Holds if `(call, ctx)` should be excluded from the consistency test `viableImplInCallContextTooLargeExclude`. */
predicate viableImplInCallContextTooLargeExclude(
DataFlowCall call, DataFlowCall ctx, DataFlowCallable callable
) {
none()
}
}
private class RelevantNode extends Node {
@@ -166,6 +179,7 @@ module Consistency {
}
query predicate postHasUniquePre(PostUpdateNode n, string msg) {
not any(ConsistencyConfiguration conf).postHasUniquePreExclude(n) and
exists(int c |
c = count(n.getPreUpdateNode()) and
c != 1 and
@@ -174,6 +188,7 @@ module Consistency {
}
query predicate uniquePostUpdate(Node n, string msg) {
not any(ConsistencyConfiguration conf).uniquePostUpdateExclude(n) and
1 < strictcount(PostUpdateNode post | post.getPreUpdateNode() = n) and
msg = "Node has multiple PostUpdateNodes."
}
@@ -209,4 +224,12 @@ module Consistency {
not any(ConsistencyConfiguration c).postWithInFlowExclude(n) and
msg = "PostUpdateNode should not be the target of local flow."
}
query predicate viableImplInCallContextTooLarge(
DataFlowCall call, DataFlowCall ctx, DataFlowCallable callable
) {
callable = viableImplInCallContext(call, ctx) and
not callable = viableCallable(call) and
not any(ConsistencyConfiguration c).viableImplInCallContextTooLargeExclude(call, ctx, callable)
}
}

View File

@@ -267,9 +267,6 @@ Instruction getSourceAddressFromNode(Node node) {
result = getSourceAddress(node.asOperand().(SideEffectOperand).getUse())
}
/** Gets the source value of `instr` if it's an instruction that behaves like a `LoadInstruction`. */
Instruction getSourceValue(Instruction instr) { result = getSourceValueOperand(instr).getDef() }
/**
* Gets the operand that represents the source value of `instr` if it's an instruction
* that behaves like a `LoadInstruction`.

View File

@@ -143,16 +143,6 @@ private module Cached {
)
}
cached
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::RegisterOperand oldOperand |
oldInstruction = getOldInstruction(instruction) and
oldOperand = oldInstruction.getAnOperand() and
tag = oldOperand.getOperandTag() and
result = getNewInstruction(oldOperand.getAnyDef())
)
}
pragma[noopt]
private predicate hasMemoryOperandDefinition(
OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand, Overlap overlap,

View File

@@ -256,12 +256,6 @@ CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag)
.getInstructionMemoryOperandType(getInstructionTag(instruction), tag)
}
Instruction getPhiOperandDefinition(
PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap
) {
none()
}
Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() }
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {

View File

@@ -143,16 +143,6 @@ private module Cached {
)
}
cached
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::RegisterOperand oldOperand |
oldInstruction = getOldInstruction(instruction) and
oldOperand = oldInstruction.getAnOperand() and
tag = oldOperand.getOperandTag() and
result = getNewInstruction(oldOperand.getAnyDef())
)
}
pragma[noopt]
private predicate hasMemoryOperandDefinition(
OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand, Overlap overlap,

View File

@@ -15,4 +15,4 @@ where
c.fromSource() and
c.isTopLevel() and
c.getParentScope() instanceof GlobalNamespace
select c, "This class is not declared in any namespace"
select c, "This class is not declared in any namespace."

View File

@@ -16,4 +16,4 @@ where
t.fromSource() and
n = t.getMetrics().getEfferentSourceCoupling() and
n > 10
select t as class_, "This class has too many dependencies (" + n.toString() + ")"
select t as class_, "This class has too many dependencies (" + n.toString() + ")."

View File

@@ -17,4 +17,4 @@ where
n = f.getMetrics().getNumberOfCalls() and
n > 99 and
not f.isMultiplyDefined()
select f as function, "This function makes too many calls (" + n.toString() + ")"
select f as function, "This function makes too many calls (" + n.toString() + ")."

View File

@@ -18,4 +18,4 @@ where
f.getMetrics().getNumberOfParameters() > 15
select f,
"This function has too many parameters (" + f.getMetrics().getNumberOfParameters().toString() +
")"
")."

View File

@@ -21,5 +21,5 @@ where
rhsType.getAMember() = m and
not m.(VirtualFunction).isPure()
) // add additional checks for concrete members in in-between supertypes
select e, "This assignment expression slices from type $@ to $@", rhsType, rhsType.getName(),
select e, "This assignment expression slices from type $@ to $@.", rhsType, rhsType.getName(),
lhsType, lhsType.getName()

View File

@@ -72,18 +72,6 @@ predicate floatTrivial(Literal lit) {
predicate charLiteral(Literal lit) { lit instanceof CharLiteral }
Type literalType(Literal literal) { result = literal.getType() }
predicate stringType(DerivedType t) {
t.getBaseType() instanceof CharType
or
exists(SpecifiedType constCharType |
t.getBaseType() = constCharType and
constCharType.isConst() and
constCharType.getBaseType() instanceof CharType
)
}
predicate numberType(Type t) { t instanceof FloatingPointType or t instanceof IntegralType }
predicate stringLiteral(Literal literal) { literal instanceof StringLiteral }

View File

@@ -18,4 +18,4 @@ where
f.hasSpecifier("virtual") and
f.getFile().fromSource() and
not f instanceof Destructor
select f, "Avoid having public virtual methods (NVI idiom)"
select f, "Avoid having public virtual methods (NVI idiom)."

View File

@@ -23,4 +23,4 @@ where
fclass = f.getDeclaringType() and
hubIndex = fclass.getMetrics().getAfferentCoupling() * fclass.getMetrics().getEfferentCoupling() and
hubIndex > 100
select f, "Avoid having public virtual methods (NVI idiom)"
select f, "Avoid having public virtual methods (NVI idiom)."

View File

@@ -38,5 +38,5 @@ where
sc = switch.getASwitchCase() and
tooLong(sc) and
switchCaseLength(sc, lines)
select switch, "Switch has at least one case that is too long: $@", sc,
select switch, "Switch has at least one case that is too long: $@.", sc,
sc.getExpr().toString() + " (" + lines.toString() + " lines)"

View File

@@ -58,4 +58,4 @@ where
not exists(AsmStmt s | f = s.getEnclosingFunction()) and
not v.getAnAttribute().getName() = "unused" and
not any(ErrorExpr e).getEnclosingFunction() = f // unextracted expr may use `v`
select v, "Variable " + v.getName() + " is not used"
select v, "Variable " + v.getName() + " is not used."

View File

@@ -27,4 +27,4 @@ where
not declarationHasSideEffects(v) and
not v.getAnAttribute().hasName("used") and
not v.getAnAttribute().hasName("unused")
select v, "Static variable " + v.getName() + " is never read"
select v, "Static variable " + v.getName() + " is never read."

View File

@@ -1,3 +1,14 @@
## 0.4.0
### New Queries
* Added a new medium-precision query, `cpp/missing-check-scanf`, which detects `scanf` output variables that are used without a proper return-value check to see that they were actually written. A variation of this query was originally contributed as an [experimental query by @ihsinme](https://github.com/github/codeql/pull/8246).
### Minor Analysis Improvements
* Modernizations from "Cleartext storage of sensitive information in buffer" (`cpp/cleartext-storage-buffer`) have been ported to the "Cleartext storage of sensitive information in file" (`cpp/cleartext-storage-file`), "Cleartext transmission of sensitive information" (`cpp/cleartext-transmission`) and "Cleartext storage of sensitive information in an SQLite database" (`cpp/cleartext-storage-database`) queries. These changes may result in more correct results and fewer false positive results from these queries.
* The alert message of many queries have been changed to make the message consistent with other languages.
## 0.3.4
## 0.3.3

View File

@@ -64,5 +64,5 @@ where
) and
(if context = test then testresult = "succeed" else testresult = "fail")
select cond,
"Variable '" + v.getName() + "' is always " + context + " here, this check will always " +
testresult + "."
"Variable '" + v.getName() + "' is always " + context + ", this check will always " + testresult +
"."

View File

@@ -29,4 +29,4 @@ from Expr alloc
where
allocateDescriptorCall(alloc) and
not exists(ClosedExpr closed | closed.pointsTo() = alloc)
select alloc, "This file descriptor is never closed"
select alloc, "This file descriptor is never closed."

View File

@@ -164,4 +164,4 @@ where
fopenVariableReaches(v, def, ret) and
ret.getAChild*() = v.getAnAccess()
)
select def, "The file opened here may not be closed at $@.", ret, "this exit point"
select def, "This file may not be closed at $@.", ret, "this exit point"

View File

@@ -14,4 +14,4 @@ import FileClosed
from Expr alloc
where fopenCall(alloc) and not fopenCallMayBeClosed(alloc)
select alloc, "The file is never closed"
select alloc, "The file is never closed."

View File

@@ -27,4 +27,4 @@ where
definitionUsePair(v, other, unchecked)
)
select unchecked,
"This dereference is not guarded by a non-null check, whereas other dereferences are guarded"
"This dereference is not guarded by a non-null check, whereas other dereferences are guarded."

View File

@@ -49,4 +49,4 @@ where
select dangerous,
"Variable '" + v.getName() +
"' is used as an array-offset before it is tested for being negative (test on line " +
check.getLocation().getStartLine().toString() + "). "
check.getLocation().getStartLine().toString() + ")."

View File

@@ -190,4 +190,4 @@ where
allocatedVariableReaches(v, def, ret) and
ret.getAChild*() = v.getAnAccess()
)
select def, "The memory allocated here may not be released at $@.", ret, "this exit point"
select def, "This memory allocation may not be released at $@.", ret, "this exit point"

View File

@@ -16,4 +16,4 @@ from AllocationExpr alloc
where
alloc.requiresDealloc() and
not allocMayBeFreed(alloc)
select alloc, "This memory is never freed"
select alloc, "This memory is never freed."

View File

@@ -117,6 +117,6 @@ where
output.getCall() = call and
output.hasGuardedAccess(access, false)
select access,
"$@ is read here, but may not have been written. " +
"This variable is read, but may not have been written. " +
"It should be guarded by a check that the $@ returns at least " +
output.getMinimumGuardConstant() + ".", access, access.toString(), call, call.toString()
output.getMinimumGuardConstant() + ".", call, call.toString()

View File

@@ -14,4 +14,4 @@ from Expr alloc, Expr free, Expr freed
where
allocReaches(freed, alloc, "new[]") and
freeExprOrIndirect(free, freed, "delete")
select free, "This memory may have been allocated with '$@', not 'new'.", alloc, "new[]"
select free, "This memory may have been allocated with $@, not 'new'.", alloc, "new[]"

View File

@@ -14,4 +14,4 @@ from Expr alloc, Expr free, Expr freed
where
allocReaches(freed, alloc, "new") and
freeExprOrIndirect(free, freed, "delete[]")
select free, "This memory may have been allocated with '$@', not 'new[]'.", alloc, "new"
select free, "This memory may have been allocated with $@, not 'new[]'.", alloc, "new"

View File

@@ -30,4 +30,4 @@ where
not v.getType().getUnderlyingType() instanceof ReferenceType and
not exists(ScopeUtilityClass util | def = util.getAUse()) and
not def.isInMacroExpansion()
select def, "Variable '" + v.getName() + "' is assigned a value that is never used"
select def, "Variable '" + v.getName() + "' is assigned a value that is never used."

View File

@@ -62,5 +62,5 @@ class UseAfterFreeReachability extends StackVariableReachability {
from UseAfterFreeReachability r, StackVariable v, Expr free, Expr e
where r.reaches(free, v, e)
select e, "Memory pointed to by '" + v.getName().toString() + "' may have been previously freed $@",
free, "here"
select e, "Memory pointed to by '" + v.getName().toString() + "' may have $@.", free,
"been previously freed"

View File

@@ -12,4 +12,4 @@ from File f
where
not exists(ExtractionProblem e | e.getFile() = f) and
exists(f.getRelativePath())
select f, "File successfully extracted"
select f, "File successfully extracted."

View File

@@ -22,4 +22,4 @@ where
not overflowTest(cmp) and
not cmp.isFromTemplateInstantiation(_) and
not isFromMacroDefinition(cmp)
select cmp, "Self comparison."
select cmp, "This expression compares an $@ to itself.", cmp.getLeftOperand(), "expression"

View File

@@ -55,5 +55,5 @@ where
cfg.hasFlowPath(source, sink) and
source.getNode().asExpr().getFullyConverted().getUnspecifiedType() =
sink.getNode().asExpr().getFullyConverted().getUnspecifiedType()
select sink, source, sink,
"Pointer arithmetic here may be done with the wrong type because of the cast $@.", source, "here"
select sink, source, sink, "This pointer arithmetic may be done with the wrong type because of $@.",
source, "this cast"

View File

@@ -24,4 +24,4 @@ where
va.getExplicitlyConverted().getType().getSize() > fct.getSize() and
va.getTarget() = fi and
not fct.getUnspecifiedType() instanceof BoolType
select va, "Implicit downcast of bitfield $@", fi, fi.toString()
select va, "Implicit downcast of bitfield $@.", fi, fi.toString()

View File

@@ -49,5 +49,4 @@ where
c.hasImplicitConversion() and
not whiteListWrapped(c)
select c,
"Return value of type " + t1.toString() + " is implicitly converted to " + t2.toString() +
" here."
"Return value of type " + t1.toString() + " is implicitly converted to " + t2.toString() + "."

View File

@@ -173,4 +173,4 @@ where
not actual.getUnspecifiedType() instanceof ErroneousType
select arg,
"This argument should be of type '" + expected.getName() + "' but is of type '" +
actual.getUnspecifiedType().getName() + "'"
actual.getUnspecifiedType().getName() + "'."

View File

@@ -17,5 +17,5 @@ import LeapYear
from Expr source, Expr sink, PossibleYearArithmeticOperationCheckConfiguration config
where config.hasFlow(DataFlow::exprNode(source), DataFlow::exprNode(sink))
select sink,
"This arithmetic operation $@ uses a constant value of 365 ends up modifying the date/time located at $@, without considering leap year scenarios.",
source, source.toString(), sink, sink.toString()
"An arithmetic operation $@ that uses a constant value of 365 ends up modifying this date/time, without considering leap year scenarios.",
source, source.toString()

View File

@@ -13,4 +13,4 @@ import NtohlArrayNoBound
from NetworkToBufferSizeConfiguration bufConfig, DataFlow::Node source, DataFlow::Node sink
where bufConfig.hasFlow(source, sink)
select sink, "Unchecked use of data from network function $@", source, source.toString()
select sink, "Unchecked use of data from network function $@.", source, source.toString()

View File

@@ -81,4 +81,4 @@ from UninitialisedLocalReachability r, LocalVariable v, VariableAccess va
where
r.reaches(_, v, va) and
not va = commonException()
select va, "The variable $@ may not be initialized here.", v, v.getName()
select va, "The variable $@ may not be initialized at this access.", v, v.getName()

View File

@@ -399,5 +399,5 @@ where
) and
source.asStore() = store and
sink.asSink(_) = load
select sink, source, sink, "Stack variable $@ escapes $@ and is used after it has expired.", var,
var.toString(), store, "here"
select sink, source, sink, "Stack variable $@ escapes at $@ and is used after it has expired.", var,
var.toString(), store, "this store"

View File

@@ -83,4 +83,4 @@ where
c.getAMemberFunction().getAnOverriddenFunction() = call.getStaticCallTarget()
)
select call.getUnconvertedResultExpression(), source, sink,
"Call to pure virtual function during " + msg
"Call to pure virtual function during " + msg + "."

View File

@@ -92,5 +92,6 @@ where
isOptionSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1_2(), e) and
msg = "no_tlsv1_2 was set"
)
select cc, "Usage of $@ with protocol $@ is not configured correctly: The option $@.", cc,
"boost::asio::ssl::context::context", protocolSource, protocolSource.toString(), e, msg
select cc,
"This usage of 'boost::asio::ssl::context::context' with protocol $@ is not configured correctly: The option $@.",
protocolSource, protocolSource.toString(), e, msg

View File

@@ -67,5 +67,5 @@ where
// the pointer was null. To follow this idea to its full generality, we
// should also give an alert when `check` post-dominates `deref`.
deref.getBlock() = dominator
select checked, "This null check is redundant because the value is $@ in any case", deref,
"dereferenced here"
select checked, "This null check is redundant because $@ in any case.", deref,
"the value is dereferenced"

View File

@@ -60,5 +60,5 @@ where
taintedWithPath(taintSource, taintedArg, sourceNode, sinkNode) and
isUserInput(taintSource, taintCause)
select taintedArg, sourceNode, sinkNode,
"This argument to a file access function is derived from $@ and then passed to " + callChain,
"This argument to a file access function is derived from $@ and then passed to " + callChain + ".",
taintSource, "user input (" + taintCause + ")"

View File

@@ -158,5 +158,5 @@ where
concatResult = sinkNode.getState().(ExecState).getSndNode()
select sinkAsArgumentIndirection(sinkNode.getNode()), sourceNode, sinkNode,
"This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to "
+ callChain, sourceNode, "user input (" + taintCause + ")", concatResult,
+ callChain + ".", sourceNode, "user input (" + taintCause + ")", concatResult,
concatResult.toString()

View File

@@ -50,5 +50,5 @@ where
taintedWithPath(taintSource, taintedArg, sourceNode, sinkNode) and
isUserInput(taintSource, taintCause)
select taintedArg, sourceNode, sinkNode,
"This argument to a SQL query function is derived from $@ and then passed to " + callChain,
"This argument to a SQL query function is derived from $@ and then passed to " + callChain + ".",
taintSource, "user input (" + taintCause + ")"

View File

@@ -34,5 +34,5 @@ where
isProcessOperationExplanation(arg, processOperation) and
taintedWithPath(source, arg, sourceNode, sinkNode)
select arg, sourceNode, sinkNode,
"The value of this argument may come from $@ and is being passed to " + processOperation, source,
source.toString()
"The value of this argument may come from $@ and is being passed to " + processOperation + ".",
source, source.toString()

View File

@@ -116,6 +116,10 @@ class ImproperArrayIndexValidationConfig extends TaintTracking::Configuration {
}
}
/** Gets `str` where the first letter has been lowercased. */
bindingset[str]
string lowerFirst(string str) { result = str.prefix(1).toLowerCase() + str.suffix(1) }
from
ImproperArrayIndexValidationConfig conf, DataFlow::PathNode source, DataFlow::PathNode sink,
string sourceType
@@ -123,5 +127,5 @@ where
conf.hasFlowPath(source, sink) and
isFlowSource(source.getNode(), sourceType)
select sink.getNode(), source, sink,
"$@ flows to here and is used in an array indexing expression, potentially causing an invalid access.",
source.getNode(), sourceType
"An array indexing expression depends on $@ that might be outside the bounds of the array.",
source.getNode(), lowerFirst(sourceType)

View File

@@ -34,4 +34,4 @@ where
isUserInput(userValue, cause)
select arg, sourceNode, sinkNode,
"The value of this argument may come from $@ and is being used as a formatting argument to " +
printfFunction, userValue, cause
printfFunction + ".", userValue, cause

View File

@@ -37,4 +37,4 @@ where
isUserInput(userValue, cause)
select arg, sourceNode, sinkNode,
"The value of this argument may come from $@ and is being used as a formatting argument to " +
printfFunction, userValue, cause
printfFunction + ".", userValue, cause

View File

@@ -86,4 +86,5 @@ class TaintSource extends VariableAccess {
from TaintSource source, VariableAccess sink
where source.reaches(sink)
select sink, "$@ flows to here and may not be null terminated.", source, "User-provided value"
select sink, "String operation depends on a $@ that may not be null terminated.", source,
"user-provided value"

View File

@@ -50,5 +50,5 @@ where
op.getAnOperand() = e and
missingGuard(op, e, effect)
select e, sourceNode, sinkNode,
"$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".", origin,
"User-provided value"
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
origin, "User-provided value"

View File

@@ -135,5 +135,5 @@ where
sink.getNode().asExpr() = va and
missingGuard(va, effect)
select sink.getNode(), source, sink,
"$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".",
getExpr(source.getNode()), "Uncontrolled value"
"Arithmetic expression depends on an $@, potentially causing an " + effect + ".",
getExpr(source.getNode()), "uncontrolled value"

View File

@@ -75,5 +75,6 @@ where
missingGuardAgainstOverflow(op, va) and effect = "overflow"
) and
causeEffectCorrespond(cause, effect)
select va, "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".",
select va,
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
origin, "Extreme value"

View File

@@ -36,5 +36,4 @@ where
not inSystemMacroExpansion(use) and
// Avoid double-counting: don't include all the conversions of `use`.
not use instanceof Conversion
select use, "$@ flows to here and is used in an expression which might " + kind + ".", origin,
"User-provided value"
select use, "$@ flows an expression which might " + kind + ".", origin, "User-provided value"

View File

@@ -99,5 +99,5 @@ where
isFlowSource(source.getNode(), taintCause) and
conf.hasFlowPath(source, sink) and
allocSink(alloc, sink.getNode())
select alloc, source, sink, "This allocation size is derived from $@ and might overflow",
select alloc, source, sink, "This allocation size is derived from $@ and might overflow.",
source.getNode(), "user input (" + taintCause + ")"

View File

@@ -39,9 +39,13 @@ where
isHresultBooleanConverted(e1, e2) and
if e2.isImplicit()
then
msg = "Implicit conversion from " + e1.getType().toString() + " to " + e2.getType().toString()
msg =
"Implicit conversion from " + e1.getType().toString() + " to " + e2.getType().toString() +
"."
else
msg = "Explicit conversion from " + e1.getType().toString() + " to " + e2.getType().toString()
msg =
"Explicit conversion from " + e1.getType().toString() + " to " + e2.getType().toString() +
"."
)
or
exists(ControlStructure ctls |
@@ -49,7 +53,7 @@ where
e1.getType().(TypedefType).hasName("HRESULT") and
not isHresultBooleanConverted(e1) and
not ctls instanceof SwitchStmt and // not controlled by a boolean condition
msg = "Direct usage of a type " + e1.getType().toString() + " as a conditional expression"
msg = "Direct usage of a type " + e1.getType().toString() + " as a conditional expression."
)
or
(
@@ -57,14 +61,14 @@ where
e1.getType().(TypedefType).hasName("HRESULT") and
msg =
"Usage of a type " + e1.getType().toString() +
" as an argument of a binary logical operation"
" as an argument of a binary logical operation."
)
or
exists(UnaryLogicalOperation ulop | ulop.getAnOperand() = e1 |
e1.getType().(TypedefType).hasName("HRESULT") and
msg =
"Usage of a type " + e1.getType().toString() +
" as an argument of a unary logical operation"
" as an argument of a unary logical operation."
) and
not isHresultBooleanConverted(e1)
)

View File

@@ -44,5 +44,5 @@ where
w.getASource() = sinkNode.getNode().asExpr() and
dest = w.getDest()
select w, sourceNode, sinkNode,
"This write into buffer '" + dest.toString() + "' may contain unencrypted data from $@", source,
"This write into buffer '" + dest.toString() + "' may contain unencrypted data from $@.", source,
"user input (" + source.getSourceType() + ")"

View File

@@ -73,5 +73,5 @@ where
not isFileName(globalValueNumber(source)) and // file names are not passwords
not exists(string convChar | convChar = w.getSourceConvChar(mid) | not convChar = ["s", "S"]) // ignore things written with other conversion characters
select w, sourceNode, midNode,
"This write into file '" + dest.toString() + "' may contain unencrypted data from $@", source,
"This write into file '" + dest.toString() + "' may contain unencrypted data from $@.", source,
"this source."

View File

@@ -258,9 +258,9 @@ where
then
msg =
"This operation transmits '" + sink.toString() +
"', which may contain unencrypted sensitive data from $@"
"', which may contain unencrypted sensitive data from $@."
else
msg =
"This operation receives into '" + sink.toString() +
"', which may put unencrypted sensitive data into $@"
"', which may put unencrypted sensitive data into $@."
select networkSendRecv, source, sink, msg, source, source.getNode().toString()

View File

@@ -74,5 +74,6 @@ where
config.hasFlowPath(source, sink) and
source.getNode().asExpr() = sensitive and
sqliteCall.getASource() = sink.getNode().asExpr()
select sqliteCall, source, sink, "This SQLite call may store $@ in a non-encrypted SQLite database",
sensitive, "sensitive information"
select sqliteCall, source, sink,
"This SQLite call may store $@ in a non-encrypted SQLite database.", sensitive,
"sensitive information"

View File

@@ -97,4 +97,4 @@ from
where
config.hasFlowPath(source, sink) and
str = source.getNode().asExpr()
select str, source, sink, "A URL may be constructed with the HTTP protocol."
select str, source, sink, "This URL may be constructed with the HTTP protocol."

View File

@@ -10,12 +10,6 @@ private predicate reaches(ControlFlowNode a, ControlFlowNode b) = fastTC(success
private predicate successor(ControlFlowNode a, ControlFlowNode b) { b = a.getASuccessor() }
class WhitelistedCallsConfig extends string {
WhitelistedCallsConfig() { this = "config" }
abstract predicate isWhitelisted(Call c);
}
abstract class WhitelistedCall extends Call {
override Function getTarget() { none() }
}

View File

@@ -44,5 +44,5 @@ where
)
select dest,
"This pointer might have type $@ (size " + sourceBase.getSize() +
"), but the pointer arithmetic here is done with type " + destType + " (size " +
destBase.getSize() + ").", sourceLoc, sourceBase.toString()
"), but this pointer arithmetic is done with type " + destType + " (size " + destBase.getSize() +
").", sourceLoc, sourceBase.toString()

View File

@@ -51,5 +51,5 @@ where
destBase instanceof CharType
select dest,
"This pointer might have type $@ (size " + sourceBase.getSize() +
"), but the pointer arithmetic here is done with type " + destType + " (size " +
destBase.getSize() + ").", sourceLoc, sourceBase.toString()
"), but this pointer arithmetic is done with type " + destType + " (size " + destBase.getSize() +
").", sourceLoc, sourceBase.toString()

View File

@@ -26,4 +26,4 @@ where
destBase instanceof VoidType
select dest,
"This pointer might have type $@ (size " + sourceBase.getSize() +
"), but the pointer arithmetic here is done with type void", sourceLoc, sourceBase.toString()
"), but this pointer arithmetic is done with type void.", sourceLoc, sourceBase.toString()

View File

@@ -18,4 +18,4 @@ from FunctionCall call, Function target
where
call.getTarget() = target and
target.hasGlobalOrStdName("gets")
select call, "gets does not guard against buffer overflow"
select call, "'gets' does not guard against buffer overflow."

View File

@@ -16,7 +16,7 @@ import cpp
predicate potentiallyDangerousFunction(Function f, string message) {
exists(string name | f.hasGlobalName(name) |
name = ["gmtime", "localtime", "ctime", "asctime"] and
message = "Call to " + name + " is potentially dangerous"
message = "Call to '" + name + "' is potentially dangerous."
)
}

View File

@@ -16,4 +16,4 @@ import FilePermissions
from FileCreationWithOptionalModeExpr fc
where not fc.hasModeArgument()
select fc,
"A file is created here without providing a mode argument, which may leak bits from the stack."
"This creates a file without providing a mode argument, which may leak bits from the stack."

Some files were not shown because too many files have changed in this diff Show More