Compare commits

..

1 Commits

Author SHA1 Message Date
github-actions[bot]
76dec1f262 use ATM model from training run classification_test 2022-10-11 14:02:13 +00:00
1019 changed files with 14156 additions and 14445 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@v3
uses: actions/upload-artifact@v2
with:
name: qhelp-markdown
path: go/qhelp-out/**/*.md

View File

@@ -27,7 +27,7 @@ on:
- main
- "rc/*"
paths:
- "**/*.qhelp"
- "ruby/**/*.qhelp"
jobs:
qhelp:

View File

@@ -4,7 +4,8 @@ This open source repository contains the standard CodeQL libraries and queries t
## How do I learn CodeQL and run queries?
There is [extensive documentation](https://codeql.github.com/docs/) on getting started with writing CodeQL using the [CodeQL extension for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/) and the [CodeQL CLI](https://codeql.github.com/docs/codeql-cli/).
There is [extensive documentation](https://codeql.github.com/docs/) on getting started with writing CodeQL.
You can use the [CodeQL for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/) extension or the [interactive query console](https://lgtm.com/help/lgtm/using-query-console) on LGTM.com (Semmle Legacy product) to try out your queries on any open source project that's currently being analyzed.
## Contributing

View File

@@ -1,18 +1,3 @@
## 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,14 +1,4 @@
## 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
---
category: feature
---
* 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

@@ -0,0 +1,4 @@
---
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,6 +1,5 @@
## 0.3.0
### Deprecated APIs
---
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.
The old name still exists as a deprecated alias.

View File

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

View File

@@ -20,8 +20,7 @@ module ProductFlow {
* `source1` and `source2` must belong to the same callable.
*/
predicate isSourcePair(
DataFlow::Node source1, DataFlow::FlowState state1, DataFlow::Node source2,
DataFlow::FlowState state2
DataFlow::Node source1, string state1, DataFlow::Node source2, string state2
) {
state1 = "" and
state2 = "" and
@@ -50,101 +49,6 @@ 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)
}
/**
* Holds if data flow into `node` is prohibited in the first projection of the product
* dataflow graph.
*/
predicate isBarrierIn1(DataFlow::Node node) { none() }
/**
* Holds if data flow into `node` is prohibited in the second projection of the product
* dataflow graph.
*/
predicate isBarrierIn2(DataFlow::Node node) { none() }
predicate hasFlowPath(
DataFlow::PathNode source1, DataFlow2::PathNode source2, DataFlow::PathNode sink1,
DataFlow2::PathNode sink2
@@ -159,78 +63,38 @@ module ProductFlow {
class Conf1 extends DataFlow::Configuration {
Conf1() { this = "Conf1" }
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
override predicate isSource(DataFlow::Node source, string state) {
exists(Configuration conf | conf.isSourcePair(source, state, _, _))
}
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
override predicate isSink(DataFlow::Node sink, string 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))
}
override predicate isBarrierIn(DataFlow::Node node) {
exists(Configuration conf | conf.isBarrierIn1(node))
}
}
class Conf2 extends DataFlow2::Configuration {
Conf2() { this = "Conf2" }
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 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 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 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 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))
}
override predicate isBarrierIn(DataFlow::Node node) {
exists(Configuration conf | conf.isBarrierIn2(node))
}
}
}
pragma[nomagic]
private predicate reachableInterprocEntry(
Configuration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2,
DataFlow::PathNode node1, DataFlow2::PathNode node2
) {
conf.isSourcePair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState()) and
conf.isSourcePair(node1.getNode(), _, node2.getNode(), _) and
node1 = source1 and
node2 = source2
or
@@ -293,7 +157,7 @@ module ProductFlow {
) {
exists(DataFlow::PathNode mid1, DataFlow2::PathNode mid2 |
reachableInterprocEntry(conf, source1, source2, mid1, mid2) and
conf.isSinkPair(sink1.getNode(), sink1.getState(), sink2.getNode(), sink2.getState()) and
conf.isSinkPair(sink1.getNode(), _, sink2.getNode(), _) and
localPathStep1*(mid1, sink1) and
localPathStep2*(mid2, sink2)
)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,7 +7,6 @@ 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;
@@ -121,15 +120,7 @@ module SemanticExprConfig {
newtype TSsaVariable =
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
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, _, _, _)
)
}
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() }
class SsaVariable extends TSsaVariable {
string toString() { none() }
@@ -138,8 +129,6 @@ module SemanticExprConfig {
IR::Instruction asInstruction() { none() }
IR::PointerArithmeticInstruction asPointerArithGuard() { none() }
IR::Operand asOperand() { none() }
}
@@ -155,18 +144,6 @@ 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;
@@ -191,11 +168,7 @@ module SemanticExprConfig {
)
}
Expr getAUse(SsaVariable v) {
result.(IR::LoadInstruction).getSourceValue() = v.asInstruction()
or
result = valueNumber(v.asPointerArithGuard()).getAnInstruction()
}
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v.asInstruction() }
SemType getSsaVariableType(SsaVariable v) {
result = getSemanticType(v.asInstruction().getResultIRType())
@@ -235,9 +208,7 @@ module SemanticExprConfig {
final override predicate hasRead(SsaVariable v) {
exists(IR::Operand operand |
operand.getDef() = v.asInstruction() or
operand.getDef() = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
operand.getDef() = v.asInstruction() and
not operand instanceof IR::PhiInputOperand and
operand.getUse().getBlock() = block
)
@@ -256,9 +227,7 @@ module SemanticExprConfig {
final override predicate hasRead(SsaVariable v) {
exists(IR::PhiInputOperand operand |
operand.getDef() = v.asInstruction() or
operand.getDef() = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
operand.getDef() = v.asInstruction() and
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 SemExpr getAUse() { result = Specific::getAUse(this) }
final SemLoadExpr getAUse() { result = Specific::getAUse(this) }
final SemType getType() { result = Specific::getSsaVariableType(this) }

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 0.4.1-dev
version: 0.4.0-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`.
*/
deprecated class StrcatFunction extends Function {
class StrcatFunction extends Function {
StrcatFunction() {
getName() =
[

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -267,6 +267,9 @@ 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,6 +143,16 @@ 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,6 +256,12 @@ 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,6 +143,16 @@ 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

@@ -205,149 +205,57 @@ private predicate deconstructSizeExpr(Expr sizeExpr, Expr lengthExpr, int sizeof
sizeof = 1
}
/** A `Function` that is a call target of an allocation. */
private signature class CallAllocationExprTarget extends Function;
/**
* This module abstracts over the type of allocation call-targets and provides a
* class `CallAllocationExprImpl` which contains the implementation of the various
* predicates required by the `Allocation` class.
*
* This module is then instantiated for two types of allocation call-targets:
* - `AllocationFunction`: Functions that we've explicitly modeled as functions that
* perform allocations (i.e., `malloc`).
* - `HeuristicAllocationFunction`: Functions that we deduce as behaving like an allocation
* function using various heuristics.
* An allocation expression that is a function call, such as call to `malloc`.
*/
private module CallAllocationExprBase<CallAllocationExprTarget Target> {
/** A module that contains the collection of member-predicates required on `Target`. */
signature module Param {
/**
* Gets the index of the input pointer argument to be reallocated, if
* this is a `realloc` function.
*/
int getReallocPtrArg(Target target);
private class CallAllocationExpr extends AllocationExpr, FunctionCall {
AllocationFunction target;
/**
* Gets the index of the argument for the allocation size, if any. The actual
* allocation size is the value of this argument multiplied by the result of
* `getSizeMult()`, in bytes.
*/
int getSizeArg(Target target);
/**
* Gets the index of an argument that multiplies the allocation size given
* by `getSizeArg`, if any.
*/
int getSizeMult(Target target);
/**
* Holds if this allocation requires a
* corresponding deallocation of some sort (most do, but `alloca` for example
* does not). If it is unclear, we default to no (for example a placement `new`
* allocation may or may not require a corresponding `delete`).
*/
predicate requiresDealloc(Target target);
CallAllocationExpr() {
target = this.getTarget() and
// realloc(ptr, 0) only frees the pointer
not (
exists(target.getReallocPtrArg()) and
this.getArgument(target.getSizeArg()).getValue().toInt() = 0
) and
// these are modeled directly (and more accurately), avoid duplication
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
}
/**
* A module that abstracts over a collection of predicates in
* the `Param` module). This should really be member-predicates
* on `CallAllocationExprTarget`, but we cannot yet write this in QL.
*/
module With<Param P> {
private import P
/**
* An allocation expression that is a function call, such as call to `malloc`.
*/
class CallAllocationExprImpl instanceof FunctionCall {
Target target;
CallAllocationExprImpl() {
target = this.getTarget() and
// realloc(ptr, 0) only frees the pointer
not (
exists(getReallocPtrArg(target)) and
this.getArgument(getSizeArg(target)).getValue().toInt() = 0
) and
// these are modeled directly (and more accurately), avoid duplication
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
}
string toString() { result = super.toString() }
Expr getSizeExprImpl() {
exists(Expr sizeExpr | sizeExpr = super.getArgument(getSizeArg(target)) |
if exists(getSizeMult(target))
then result = sizeExpr
else
exists(Expr lengthExpr |
deconstructSizeExpr(sizeExpr, lengthExpr, _) and
result = lengthExpr
)
override Expr getSizeExpr() {
exists(Expr sizeExpr | sizeExpr = this.getArgument(target.getSizeArg()) |
if exists(target.getSizeMult())
then result = sizeExpr
else
exists(Expr lengthExpr |
deconstructSizeExpr(sizeExpr, lengthExpr, _) and
result = lengthExpr
)
}
int getSizeMultImpl() {
// malloc with multiplier argument that is a constant
result = super.getArgument(getSizeMult(target)).getValue().toInt()
or
// malloc with no multiplier argument
not exists(getSizeMult(target)) and
deconstructSizeExpr(super.getArgument(getSizeArg(target)), _, result)
}
int getSizeBytesImpl() {
result = this.getSizeExprImpl().getValue().toInt() * this.getSizeMultImpl()
}
Expr getReallocPtrImpl() { result = super.getArgument(getReallocPtrArg(target)) }
Type getAllocatedElementTypeImpl() {
result =
super.getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and
not result instanceof VoidType
}
predicate requiresDeallocImpl() { requiresDealloc(target) }
}
}
}
private module CallAllocationExpr {
private module Param implements CallAllocationExprBase<AllocationFunction>::Param {
int getReallocPtrArg(AllocationFunction f) { result = f.getReallocPtrArg() }
int getSizeArg(AllocationFunction f) { result = f.getSizeArg() }
int getSizeMult(AllocationFunction f) { result = f.getSizeMult() }
predicate requiresDealloc(AllocationFunction f) { f.requiresDealloc() }
)
}
/**
* A class that provides the implementation of `AllocationExpr` for an allocation
* that calls an `AllocationFunction`.
*/
private class Base =
CallAllocationExprBase<AllocationFunction>::With<Param>::CallAllocationExprImpl;
class CallAllocationExpr extends AllocationExpr, Base {
override Expr getSizeExpr() { result = super.getSizeExprImpl() }
override int getSizeMult() { result = super.getSizeMultImpl() }
override Type getAllocatedElementType() { result = super.getAllocatedElementTypeImpl() }
override predicate requiresDealloc() { super.requiresDeallocImpl() }
override int getSizeBytes() { result = super.getSizeBytesImpl() }
override Expr getReallocPtr() { result = super.getReallocPtrImpl() }
override string toString() { result = AllocationExpr.super.toString() }
override int getSizeMult() {
// malloc with multiplier argument that is a constant
result = this.getArgument(target.getSizeMult()).getValue().toInt()
or
// malloc with no multiplier argument
not exists(target.getSizeMult()) and
deconstructSizeExpr(this.getArgument(target.getSizeArg()), _, result)
}
override int getSizeBytes() {
result = this.getSizeExpr().getValue().toInt() * this.getSizeMult()
}
override Expr getReallocPtr() { result = this.getArgument(target.getReallocPtrArg()) }
override Type getAllocatedElementType() {
result =
this.getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and
not result instanceof VoidType
}
override predicate requiresDealloc() { target.requiresDealloc() }
}
/**
@@ -386,99 +294,3 @@ private class NewArrayAllocationExpr extends AllocationExpr, NewArrayExpr {
override predicate requiresDealloc() { not exists(this.getPlacementPointer()) }
}
private module HeuristicAllocation {
/** A class that maps an `AllocationExpr` to an `HeuristicAllocationExpr`. */
private class HeuristicAllocationModeled extends HeuristicAllocationExpr instanceof AllocationExpr {
override Expr getSizeExpr() { result = AllocationExpr.super.getSizeExpr() }
override int getSizeMult() { result = AllocationExpr.super.getSizeMult() }
override int getSizeBytes() { result = AllocationExpr.super.getSizeBytes() }
override Expr getReallocPtr() { result = AllocationExpr.super.getReallocPtr() }
override Type getAllocatedElementType() {
result = AllocationExpr.super.getAllocatedElementType()
}
override predicate requiresDealloc() { AllocationExpr.super.requiresDealloc() }
}
/** A class that maps an `AllocationFunction` to an `HeuristicAllocationFunction`. */
private class HeuristicAllocationFunctionModeled extends HeuristicAllocationFunction instanceof AllocationFunction {
override int getSizeArg() { result = AllocationFunction.super.getSizeArg() }
override int getSizeMult() { result = AllocationFunction.super.getSizeMult() }
override int getReallocPtrArg() { result = AllocationFunction.super.getReallocPtrArg() }
override predicate requiresDealloc() { AllocationFunction.super.requiresDealloc() }
}
private int getAnUnsignedParameter(Function f) {
f.getParameter(result).getUnspecifiedType().(IntegralType).isUnsigned()
}
private int getAPointerParameter(Function f) {
f.getParameter(result).getUnspecifiedType() instanceof PointerType
}
/**
* A class that uses heuristics to find additional allocation functions. The required are as follows:
* 1. The word `alloc` must appear in the function name
* 2. The function must return a pointer type
* 3. There must be a unique parameter of unsigned integral type.
*/
private class HeuristicAllocationFunctionByName extends HeuristicAllocationFunction instanceof Function {
int sizeArg;
HeuristicAllocationFunctionByName() {
Function.super.getName().matches("%alloc%") and
Function.super.getUnspecifiedType() instanceof PointerType and
sizeArg = unique( | | getAnUnsignedParameter(this))
}
override int getSizeArg() { result = sizeArg }
override int getReallocPtrArg() {
Function.super.getName().matches("%realloc%") and
result = unique( | | getAPointerParameter(this))
}
override predicate requiresDealloc() { none() }
}
private module Param implements CallAllocationExprBase<HeuristicAllocationFunction>::Param {
int getReallocPtrArg(HeuristicAllocationFunction f) { result = f.getReallocPtrArg() }
int getSizeArg(HeuristicAllocationFunction f) { result = f.getSizeArg() }
int getSizeMult(HeuristicAllocationFunction f) { result = f.getSizeMult() }
predicate requiresDealloc(HeuristicAllocationFunction f) { f.requiresDealloc() }
}
/**
* A class that provides the implementation of `AllocationExpr` for an allocation
* that calls an `HeuristicAllocationFunction`.
*/
private class Base =
CallAllocationExprBase<HeuristicAllocationFunction>::With<Param>::CallAllocationExprImpl;
private class CallAllocationExpr extends HeuristicAllocationExpr, Base {
override Expr getSizeExpr() { result = super.getSizeExprImpl() }
override int getSizeMult() { result = super.getSizeMultImpl() }
override Type getAllocatedElementType() { result = super.getAllocatedElementTypeImpl() }
override predicate requiresDealloc() { super.requiresDeallocImpl() }
override int getSizeBytes() { result = super.getSizeBytesImpl() }
override Expr getReallocPtr() { result = super.getReallocPtrImpl() }
override string toString() { result = HeuristicAllocationExpr.super.toString() }
}
}

View File

@@ -113,84 +113,3 @@ class OperatorNewAllocationFunction extends AllocationFunction {
result = 1
}
}
/**
* An expression that _might_ allocate memory.
*
* Unlike `AllocationExpr`, this class uses heuristics (such as a call target's
* name and parameters) to include additional expressions.
*/
abstract class HeuristicAllocationExpr extends Expr {
/**
* Gets an expression for the allocation size, if any. The actual allocation
* size is the value of this expression multiplied by the result of
* `getSizeMult()`, in bytes.
*/
Expr getSizeExpr() { none() }
/**
* Gets a constant multiplier for the allocation size given by `getSizeExpr`,
* in bytes.
*/
int getSizeMult() { none() }
/**
* Gets the size of this allocation in bytes, if it is a fixed size and that
* size can be determined.
*/
int getSizeBytes() { none() }
/**
* Gets the expression for the input pointer argument to be reallocated, if
* this is a `realloc` function.
*/
Expr getReallocPtr() { none() }
/**
* Gets the type of the elements that are allocated, if it can be determined.
*/
Type getAllocatedElementType() { none() }
/**
* Whether or not this allocation requires a corresponding deallocation of
* some sort (most do, but `alloca` for example does not). If it is unclear,
* we default to no (for example a placement `new` allocation may or may not
* require a corresponding `delete`).
*/
predicate requiresDealloc() { any() }
}
/**
* An function that _might_ allocate memory.
*
* Unlike `AllocationFunction`, this class uses heuristics (such as the function's
* name and its parameters) to include additional functions.
*/
abstract class HeuristicAllocationFunction extends Function {
/**
* Gets the index of the argument for the allocation size, if any. The actual
* allocation size is the value of this argument multiplied by the result of
* `getSizeMult()`, in bytes.
*/
int getSizeArg() { none() }
/**
* Gets the index of an argument that multiplies the allocation size given by
* `getSizeArg`, if any.
*/
int getSizeMult() { none() }
/**
* Gets the index of the input pointer argument to be reallocated, if this
* is a `realloc` function.
*/
int getReallocPtrArg() { none() }
/**
* Whether or not this allocation requires a corresponding deallocation of
* some sort (most do, but `alloca` for example does not). If it is unclear,
* we default to no (for example a placement `new` allocation may or may not
* require a corresponding `delete`).
*/
predicate requiresDealloc() { any() }
}

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,6 +72,18 @@ 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,14 +1,3 @@
## 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 + ", this check will always " + testresult +
"."
"Variable '" + v.getName() + "' is always " + context + " here, 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, "This file may not be closed at $@.", ret, "this exit point"
select def, "The file opened here 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, "This memory allocation may not be released at $@.", ret, "this exit point"
select def, "The memory allocated here 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,
"This variable is read, but may not have been written. " +
"$@ is read here, but may not have been written. " +
"It should be guarded by a check that the $@ returns at least " +
output.getMinimumGuardConstant() + ".", call, call.toString()
output.getMinimumGuardConstant() + ".", access, access.toString(), 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 $@.", free,
"been previously freed"
select e, "Memory pointed to by '" + v.getName().toString() + "' may have been previously freed $@",
free, "here"

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, "This expression compares an $@ to itself.", cmp.getLeftOperand(), "expression"
select cmp, "Self comparison."

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, "This pointer arithmetic may be done with the wrong type because of $@.",
source, "this cast"
select sink, source, sink,
"Pointer arithmetic here may be done with the wrong type because of the cast $@.", source, "here"

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

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,
"An arithmetic operation $@ that uses a constant value of 365 ends up modifying this date/time, without considering leap year scenarios.",
source, source.toString()
"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()

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 at this access.", v, v.getName()
select va, "The variable $@ may not be initialized here.", 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 at $@ and is used after it has expired.", var,
var.toString(), store, "this store"
select sink, source, sink, "Stack variable $@ escapes $@ and is used after it has expired.", var,
var.toString(), store, "here"

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,6 +92,5 @@ where
isOptionSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1_2(), e) and
msg = "no_tlsv1_2 was set"
)
select cc,
"This usage of 'boost::asio::ssl::context::context' with protocol $@ is not configured correctly: The option $@.",
protocolSource, protocolSource.toString(), e, msg
select cc, "Usage of $@ with protocol $@ is not configured correctly: The option $@.", cc,
"boost::asio::ssl::context::context", 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 $@ in any case.", deref,
"the value is dereferenced"
select checked, "This null check is redundant because the value is $@ in any case", deref,
"dereferenced here"

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,10 +116,6 @@ 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
@@ -127,5 +123,5 @@ where
conf.hasFlowPath(source, sink) and
isFlowSource(source.getNode(), sourceType)
select sink.getNode(), source, sink,
"An array indexing expression depends on $@ that might be outside the bounds of the array.",
source.getNode(), lowerFirst(sourceType)
"$@ flows to here and is used in an array indexing expression, potentially causing an invalid access.",
source.getNode(), 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,5 +86,4 @@ class TaintSource extends VariableAccess {
from TaintSource source, VariableAccess sink
where source.reaches(sink)
select sink, "String operation depends on a $@ that may not be null terminated.", source,
"user-provided value"
select sink, "$@ flows to here and 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 an operand of an arithmetic expression, potentially causing an " + effect + ".",
origin, "User-provided value"
"$@ flows to here and is used in arithmetic, 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,
"Arithmetic expression depends on an $@, potentially causing an " + effect + ".",
getExpr(source.getNode()), "uncontrolled value"
"$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".",
getExpr(source.getNode()), "Uncontrolled value"

View File

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

View File

@@ -36,4 +36,5 @@ where
not inSystemMacroExpansion(use) and
// Avoid double-counting: don't include all the conversions of `use`.
not use instanceof Conversion
select use, "$@ flows an expression which might " + kind + ".", origin, "User-provided value"
select use, "$@ flows to here and is used in 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,13 +39,9 @@ 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 |
@@ -53,7 +49,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
(
@@ -61,14 +57,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,6 +74,5 @@ 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, "This URL may be constructed with the HTTP protocol."
select str, source, sink, "A URL may be constructed with the HTTP protocol."

View File

@@ -10,6 +10,12 @@ 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 this pointer arithmetic is done with type " + destType + " (size " + destBase.getSize() +
").", sourceLoc, sourceBase.toString()
"), but the pointer arithmetic here 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 this pointer arithmetic is done with type " + destType + " (size " + destBase.getSize() +
").", sourceLoc, sourceBase.toString()
"), but the pointer arithmetic here 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 this pointer arithmetic is done with type void.", sourceLoc, sourceBase.toString()
"), but the pointer arithmetic here 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,
"This creates a file without providing a mode argument, which may leak bits from the stack."
"A file is created here without providing a mode argument, which may leak bits from the stack."

View File

@@ -37,5 +37,5 @@ from Expr source, Expr condition, Expr raise, PathNode sourceNode, PathNode sink
where
taintedWithPath(source, condition, sourceNode, sinkNode) and
sensitiveCondition(condition, raise)
select condition, sourceNode, sinkNode, "Reliance on untrusted input $@ to raise privilege at $@.",
select condition, sourceNode, sinkNode, "Reliance on untrusted input $@ to raise privilege at $@",
source, source.toString(), raise, raise.toString()

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The alert message of many queries have been changed to make the message consistent with other languages.

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