mirror of
https://github.com/github/codeql.git
synced 2026-06-03 04:40:14 +02:00
Merge pull request #9 from microsoft/jb1/zipslip-fix
Manual Merge: C# ZipSlip Conflict
This commit is contained in:
@@ -1 +1 @@
|
||||
5.0.0
|
||||
6.1.2
|
||||
|
||||
4
.github/workflows/go-tests-other-os.yml
vendored
4
.github/workflows/go-tests-other-os.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: Set up Go 1.20
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.20.0
|
||||
go-version: '1.20'
|
||||
id: go
|
||||
|
||||
- name: Check out code
|
||||
@@ -50,7 +50,7 @@ jobs:
|
||||
- name: Set up Go 1.20
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.20.0
|
||||
go-version: '1.20'
|
||||
id: go
|
||||
|
||||
- name: Check out code
|
||||
|
||||
2
.github/workflows/go-tests.yml
vendored
2
.github/workflows/go-tests.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
- name: Set up Go 1.20
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.20.0
|
||||
go-version: '1.20'
|
||||
id: go
|
||||
|
||||
- name: Check out code
|
||||
|
||||
29
.github/workflows/ruby-build.yml
vendored
29
.github/workflows/ruby-build.yml
vendored
@@ -58,10 +58,8 @@ jobs:
|
||||
id: cache-extractor
|
||||
with:
|
||||
path: |
|
||||
ruby/extractor/target/release/autobuilder
|
||||
ruby/extractor/target/release/autobuilder.exe
|
||||
ruby/extractor/target/release/extractor
|
||||
ruby/extractor/target/release/extractor.exe
|
||||
ruby/extractor/target/release/codeql-extractor-ruby
|
||||
ruby/extractor/target/release/codeql-extractor-ruby.exe
|
||||
ruby/extractor/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-extractor-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/Cargo.lock') }}--${{ hashFiles('ruby/extractor/**/*.rs') }}
|
||||
- uses: actions/cache@v3
|
||||
@@ -88,15 +86,13 @@ jobs:
|
||||
run: |
|
||||
cd extractor
|
||||
cross build --release
|
||||
mv target/x86_64-unknown-linux-gnu/release/extractor target/release/
|
||||
mv target/x86_64-unknown-linux-gnu/release/autobuilder target/release/
|
||||
mv target/x86_64-unknown-linux-gnu/release/generator target/release/
|
||||
mv target/x86_64-unknown-linux-gnu/release/codeql-extractor-ruby target/release/
|
||||
- name: Release build (windows and macos)
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true' && runner.os != 'Linux'
|
||||
run: cd extractor && cargo build --release
|
||||
- name: Generate dbscheme
|
||||
if: ${{ matrix.os == 'ubuntu-latest' && steps.cache-extractor.outputs.cache-hit != 'true'}}
|
||||
run: extractor/target/release/generator --dbscheme ql/lib/ruby.dbscheme --library ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
||||
run: extractor/target/release/codeql-extractor-ruby generate --dbscheme ql/lib/ruby.dbscheme --library ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
with:
|
||||
@@ -111,10 +107,8 @@ jobs:
|
||||
with:
|
||||
name: extractor-${{ matrix.os }}
|
||||
path: |
|
||||
ruby/extractor/target/release/autobuilder
|
||||
ruby/extractor/target/release/autobuilder.exe
|
||||
ruby/extractor/target/release/extractor
|
||||
ruby/extractor/target/release/extractor.exe
|
||||
ruby/extractor/target/release/codeql-extractor-ruby
|
||||
ruby/extractor/target/release/codeql-extractor-ruby.exe
|
||||
retention-days: 1
|
||||
compile-queries:
|
||||
runs-on: ubuntu-latest-xl
|
||||
@@ -172,13 +166,10 @@ jobs:
|
||||
mkdir -p ruby
|
||||
cp -r codeql-extractor.yml tools ql/lib/ruby.dbscheme.stats ruby/
|
||||
mkdir -p ruby/tools/{linux64,osx64,win64}
|
||||
cp linux64/autobuilder ruby/tools/linux64/autobuilder
|
||||
cp osx64/autobuilder ruby/tools/osx64/autobuilder
|
||||
cp win64/autobuilder.exe ruby/tools/win64/autobuilder.exe
|
||||
cp linux64/extractor ruby/tools/linux64/extractor
|
||||
cp osx64/extractor ruby/tools/osx64/extractor
|
||||
cp win64/extractor.exe ruby/tools/win64/extractor.exe
|
||||
chmod +x ruby/tools/{linux64,osx64}/{autobuilder,extractor}
|
||||
cp linux64/codeql-extractor-ruby ruby/tools/linux64/extractor
|
||||
cp osx64/codeql-extractor-ruby ruby/tools/osx64/extractor
|
||||
cp win64/codeql-extractor-ruby.exe ruby/tools/win64/extractor.exe
|
||||
chmod +x ruby/tools/{linux64,osx64}/extractor
|
||||
zip -rq codeql-ruby.zip ruby
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<queries language="cpp"/>
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.7.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.7.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
3
cpp/ql/lib/change-notes/released/0.7.1.md
Normal file
3
cpp/ql/lib/change-notes/released/0.7.1.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.7.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.7.0
|
||||
lastReleaseVersion: 0.7.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.7.0
|
||||
version: 0.7.1
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -361,3 +361,52 @@ module MergePathGraph<
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a `PathGraph` from three `PathGraph`s by disjoint union.
|
||||
*/
|
||||
module MergePathGraph3<
|
||||
PathNodeSig PathNode1, PathNodeSig PathNode2, PathNodeSig PathNode3,
|
||||
PathGraphSig<PathNode1> Graph1, PathGraphSig<PathNode2> Graph2, PathGraphSig<PathNode3> Graph3>
|
||||
{
|
||||
private module MergedInner = MergePathGraph<PathNode1, PathNode2, Graph1, Graph2>;
|
||||
|
||||
private module Merged =
|
||||
MergePathGraph<MergedInner::PathNode, PathNode3, MergedInner::PathGraph, Graph3>;
|
||||
|
||||
/** A node in a graph of path explanations that is formed by disjoint union of the three given graphs. */
|
||||
class PathNode instanceof Merged::PathNode {
|
||||
/** Gets this as a projection on the first given `PathGraph`. */
|
||||
PathNode1 asPathNode1() { result = super.asPathNode1().asPathNode1() }
|
||||
|
||||
/** Gets this as a projection on the second given `PathGraph`. */
|
||||
PathNode2 asPathNode2() { result = super.asPathNode1().asPathNode2() }
|
||||
|
||||
/** Gets this as a projection on the third given `PathGraph`. */
|
||||
PathNode3 asPathNode3() { result = super.asPathNode2() }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
Node getNode() { result = super.getNode() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
*/
|
||||
module PathGraph = Merged::PathGraph;
|
||||
}
|
||||
|
||||
@@ -3031,6 +3031,17 @@ module Impl<FullStateConfigSig Config> {
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppType() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
this.(PathNodeMid).getAp() instanceof AccessPathNil and result = ""
|
||||
or
|
||||
exists(DataFlowType t | t = this.(PathNodeMid).getAp().getHead().getContainerType() |
|
||||
// The `concat` becomes "" if `ppReprType` has no result.
|
||||
result = concat(" : " + ppReprType(t))
|
||||
)
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -3046,14 +3057,14 @@ module Impl<FullStateConfigSig Config> {
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppType() + this.ppAp() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
|
||||
result = this.getNodeEx().toString() + this.ppType() + this.ppAp() + this.ppCtx()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3998,14 +4009,14 @@ module Impl<FullStateConfigSig Config> {
|
||||
*/
|
||||
class PartialPathNode extends TPartialPathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppType() + this.ppAp() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
|
||||
result = this.getNodeEx().toString() + this.ppType() + this.ppAp() + this.ppCtx()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4046,6 +4057,19 @@ module Impl<FullStateConfigSig Config> {
|
||||
*/
|
||||
int getSinkDistance() { result = distSink(this.getNodeEx().getEnclosingCallable()) }
|
||||
|
||||
private string ppType() {
|
||||
this instanceof PartialPathNodeRev and result = ""
|
||||
or
|
||||
this.(PartialPathNodeFwd).getAp() instanceof PartialAccessPathNil and result = ""
|
||||
or
|
||||
exists(DataFlowType t |
|
||||
t = this.(PartialPathNodeFwd).getAp().(PartialAccessPathCons).getType()
|
||||
|
|
||||
// The `concat` becomes "" if `ppReprType` has no result.
|
||||
result = concat(" : " + ppReprType(t))
|
||||
)
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
exists(string s |
|
||||
s = this.(PartialPathNodeFwd).getAp().toString() or
|
||||
|
||||
@@ -361,3 +361,52 @@ module MergePathGraph<
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a `PathGraph` from three `PathGraph`s by disjoint union.
|
||||
*/
|
||||
module MergePathGraph3<
|
||||
PathNodeSig PathNode1, PathNodeSig PathNode2, PathNodeSig PathNode3,
|
||||
PathGraphSig<PathNode1> Graph1, PathGraphSig<PathNode2> Graph2, PathGraphSig<PathNode3> Graph3>
|
||||
{
|
||||
private module MergedInner = MergePathGraph<PathNode1, PathNode2, Graph1, Graph2>;
|
||||
|
||||
private module Merged =
|
||||
MergePathGraph<MergedInner::PathNode, PathNode3, MergedInner::PathGraph, Graph3>;
|
||||
|
||||
/** A node in a graph of path explanations that is formed by disjoint union of the three given graphs. */
|
||||
class PathNode instanceof Merged::PathNode {
|
||||
/** Gets this as a projection on the first given `PathGraph`. */
|
||||
PathNode1 asPathNode1() { result = super.asPathNode1().asPathNode1() }
|
||||
|
||||
/** Gets this as a projection on the second given `PathGraph`. */
|
||||
PathNode2 asPathNode2() { result = super.asPathNode1().asPathNode2() }
|
||||
|
||||
/** Gets this as a projection on the third given `PathGraph`. */
|
||||
PathNode3 asPathNode3() { result = super.asPathNode2() }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
Node getNode() { result = super.getNode() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
*/
|
||||
module PathGraph = Merged::PathGraph;
|
||||
}
|
||||
|
||||
@@ -3031,6 +3031,17 @@ module Impl<FullStateConfigSig Config> {
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppType() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
this.(PathNodeMid).getAp() instanceof AccessPathNil and result = ""
|
||||
or
|
||||
exists(DataFlowType t | t = this.(PathNodeMid).getAp().getHead().getContainerType() |
|
||||
// The `concat` becomes "" if `ppReprType` has no result.
|
||||
result = concat(" : " + ppReprType(t))
|
||||
)
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -3046,14 +3057,14 @@ module Impl<FullStateConfigSig Config> {
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppType() + this.ppAp() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
|
||||
result = this.getNodeEx().toString() + this.ppType() + this.ppAp() + this.ppCtx()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3998,14 +4009,14 @@ module Impl<FullStateConfigSig Config> {
|
||||
*/
|
||||
class PartialPathNode extends TPartialPathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppType() + this.ppAp() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
|
||||
result = this.getNodeEx().toString() + this.ppType() + this.ppAp() + this.ppCtx()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4046,6 +4057,19 @@ module Impl<FullStateConfigSig Config> {
|
||||
*/
|
||||
int getSinkDistance() { result = distSink(this.getNodeEx().getEnclosingCallable()) }
|
||||
|
||||
private string ppType() {
|
||||
this instanceof PartialPathNodeRev and result = ""
|
||||
or
|
||||
this.(PartialPathNodeFwd).getAp() instanceof PartialAccessPathNil and result = ""
|
||||
or
|
||||
exists(DataFlowType t |
|
||||
t = this.(PartialPathNodeFwd).getAp().(PartialAccessPathCons).getType()
|
||||
|
|
||||
// The `concat` becomes "" if `ppReprType` has no result.
|
||||
result = concat(" : " + ppReprType(t))
|
||||
)
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
exists(string s |
|
||||
s = this.(PartialPathNodeFwd).getAp().toString() or
|
||||
|
||||
@@ -897,23 +897,6 @@ private class MyConsistencyConfiguration extends Consistency::ConsistencyConfigu
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the basic block of `node`.
|
||||
*/
|
||||
IRBlock getBasicBlock(Node node) {
|
||||
node.asInstruction().getBlock() = result
|
||||
or
|
||||
node.asOperand().getUse().getBlock() = result
|
||||
or
|
||||
node.(SsaPhiNode).getPhiNode().getBasicBlock() = result
|
||||
or
|
||||
node.(RawIndirectOperand).getOperand().getUse().getBlock() = result
|
||||
or
|
||||
node.(RawIndirectInstruction).getInstruction().getBlock() = result
|
||||
or
|
||||
result = getBasicBlock(node.(PostUpdateNode).getPreUpdateNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* A local flow relation that includes both local steps, read steps and
|
||||
* argument-to-return flow through summarized functions.
|
||||
@@ -999,7 +982,8 @@ private int countNumberOfBranchesUsingParameter(SwitchInstruction switch, Parame
|
||||
// we pick the one with the highest edge count.
|
||||
result =
|
||||
max(SsaPhiNode phi |
|
||||
switch.getSuccessor(caseOrDefaultEdge()).getBlock().dominanceFrontier() = getBasicBlock(phi) and
|
||||
switch.getSuccessor(caseOrDefaultEdge()).getBlock().dominanceFrontier() =
|
||||
phi.getBasicBlock() and
|
||||
phi.getSourceVariable() = sv
|
||||
|
|
||||
strictcount(phi.getAnInput())
|
||||
|
||||
@@ -160,6 +160,28 @@ class Node extends TIRDataFlowNode {
|
||||
/** Gets the operands corresponding to this node, if any. */
|
||||
Operand asOperand() { result = this.(OperandNode).getOperand() }
|
||||
|
||||
/**
|
||||
* Holds if this node is at index `i` in basic block `block`.
|
||||
*
|
||||
* Note: Phi nodes are considered to be at index `-1`.
|
||||
*/
|
||||
final predicate hasIndexInBlock(IRBlock block, int i) {
|
||||
this.asInstruction() = block.getInstruction(i)
|
||||
or
|
||||
this.asOperand().getUse() = block.getInstruction(i)
|
||||
or
|
||||
this.(SsaPhiNode).getPhiNode().getBasicBlock() = block and i = -1
|
||||
or
|
||||
this.(RawIndirectOperand).getOperand().getUse() = block.getInstruction(i)
|
||||
or
|
||||
this.(RawIndirectInstruction).getInstruction() = block.getInstruction(i)
|
||||
or
|
||||
this.(PostUpdateNode).getPreUpdateNode().hasIndexInBlock(block, i)
|
||||
}
|
||||
|
||||
/** Gets the basic block of this node, if any. */
|
||||
final IRBlock getBasicBlock() { this.hasIndexInBlock(result, _) }
|
||||
|
||||
/**
|
||||
* Gets the non-conversion expression corresponding to this node, if any.
|
||||
* This predicate only has a result on nodes that represent the value of
|
||||
@@ -530,7 +552,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
||||
*/
|
||||
final Node getAnInput(boolean fromBackEdge) {
|
||||
localFlowStep(result, this) and
|
||||
if phi.getBasicBlock().dominates(getBasicBlock(result))
|
||||
if phi.getBasicBlock().dominates(result.getBasicBlock())
|
||||
then fromBackEdge = true
|
||||
else fromBackEdge = false
|
||||
}
|
||||
@@ -1887,7 +1909,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
e = value.getAnInstruction().getConvertedResultExpression() and
|
||||
result.getConvertedExpr() = e and
|
||||
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
|
||||
g.controls(getBasicBlock(result), edge)
|
||||
g.controls(result.getBasicBlock(), edge)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,12 +26,17 @@ predicate ignoreOperand(Operand operand) {
|
||||
predicate ignoreInstruction(Instruction instr) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
(
|
||||
instr instanceof CallSideEffectInstruction or
|
||||
instr instanceof CallReadSideEffectInstruction or
|
||||
instr instanceof ExitFunctionInstruction or
|
||||
instr instanceof EnterFunctionInstruction or
|
||||
instr instanceof WriteSideEffectInstruction or
|
||||
instr instanceof PhiInstruction or
|
||||
instr instanceof ReadSideEffectInstruction or
|
||||
instr instanceof ChiInstruction or
|
||||
instr instanceof InitializeIndirectionInstruction or
|
||||
instr instanceof AliasedDefinitionInstruction or
|
||||
instr instanceof AliasedUseInstruction or
|
||||
instr instanceof InitializeNonLocalInstruction or
|
||||
instr instanceof ReturnIndirectionInstruction
|
||||
)
|
||||
|
||||
@@ -6,7 +6,7 @@ private import IRFunctionBaseInternal
|
||||
|
||||
private newtype TIRFunction =
|
||||
TFunctionIRFunction(Language::Function func) { IRConstruction::Raw::functionHasIR(func) } or
|
||||
TVarInitIRFunction(Language::GlobalVariable var) { IRConstruction::Raw::varHasIRFunc(var) }
|
||||
TVarInitIRFunction(Language::Variable var) { IRConstruction::Raw::varHasIRFunc(var) }
|
||||
|
||||
/**
|
||||
* The IR for a function. This base class contains only the predicates that are the same between all
|
||||
|
||||
@@ -37,7 +37,13 @@ module Raw {
|
||||
predicate functionHasIR(Function func) { exists(getTranslatedFunction(func)) }
|
||||
|
||||
cached
|
||||
predicate varHasIRFunc(GlobalOrNamespaceVariable var) {
|
||||
predicate varHasIRFunc(Variable var) {
|
||||
(
|
||||
var instanceof GlobalOrNamespaceVariable
|
||||
or
|
||||
not var.isFromUninstantiatedTemplate(_) and
|
||||
var instanceof StaticInitializedStaticLocalVariable
|
||||
) and
|
||||
var.hasInitializer() and
|
||||
(
|
||||
not var.getType().isDeeplyConst()
|
||||
@@ -75,9 +81,10 @@ module Raw {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasDynamicInitializationFlag(Function func, StaticLocalVariable var, CppType type) {
|
||||
predicate hasDynamicInitializationFlag(
|
||||
Function func, RuntimeInitializedStaticLocalVariable var, CppType type
|
||||
) {
|
||||
var.getFunction() = func and
|
||||
var.hasDynamicInitialization() and
|
||||
type = getBoolType()
|
||||
}
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ abstract class TranslatedSideEffects extends TranslatedElement {
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
|
||||
final override Declaration getFunction() { result = getExpr().getEnclosingDeclaration() }
|
||||
final override Declaration getFunction() { result = getEnclosingDeclaration(getExpr()) }
|
||||
|
||||
final override TranslatedElement getChild(int i) {
|
||||
result =
|
||||
|
||||
@@ -28,7 +28,11 @@ abstract class TranslatedCondition extends TranslatedElement {
|
||||
|
||||
final Expr getExpr() { result = expr }
|
||||
|
||||
final override Function getFunction() { result = expr.getEnclosingFunction() }
|
||||
final override Declaration getFunction() {
|
||||
result = getEnclosingFunction(expr) or
|
||||
result = getEnclosingVariable(expr).(GlobalOrNamespaceVariable) or
|
||||
result = getEnclosingVariable(expr).(StaticInitializedStaticLocalVariable)
|
||||
}
|
||||
|
||||
final Type getResultType() { result = expr.getUnspecifiedType() }
|
||||
}
|
||||
|
||||
@@ -28,9 +28,14 @@ abstract class TranslatedDeclarationEntry extends TranslatedElement, TTranslated
|
||||
|
||||
TranslatedDeclarationEntry() { this = TTranslatedDeclarationEntry(entry) }
|
||||
|
||||
final override Function getFunction() {
|
||||
exists(DeclStmt stmt |
|
||||
stmt = entry.getStmt() and
|
||||
final override Declaration getFunction() {
|
||||
exists(DeclStmt stmt | stmt = entry.getStmt() |
|
||||
result = entry.getDeclaration().(StaticInitializedStaticLocalVariable)
|
||||
or
|
||||
result = entry.getDeclaration().(GlobalOrNamespaceVariable)
|
||||
or
|
||||
not entry.getDeclaration() instanceof StaticInitializedStaticLocalVariable and
|
||||
not entry.getDeclaration() instanceof GlobalOrNamespaceVariable and
|
||||
result = stmt.getEnclosingFunction()
|
||||
)
|
||||
}
|
||||
@@ -237,7 +242,7 @@ class TranslatedStaticLocalVariableInitialization extends TranslatedElement,
|
||||
|
||||
final override LocalVariable getVariable() { result = var }
|
||||
|
||||
final override Function getFunction() { result = var.getFunction() }
|
||||
final override Declaration getFunction() { result = var.getFunction() }
|
||||
}
|
||||
|
||||
TranslatedConditionDecl getTranslatedConditionDecl(ConditionDeclExpr expr) {
|
||||
@@ -264,7 +269,7 @@ class TranslatedConditionDecl extends TranslatedLocalVariableDeclaration, TTrans
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
|
||||
override Function getFunction() { result = conditionDeclExpr.getEnclosingFunction() }
|
||||
override Declaration getFunction() { result = getEnclosingFunction(conditionDeclExpr) }
|
||||
|
||||
override LocalVariable getVariable() { result = conditionDeclExpr.getVariable() }
|
||||
}
|
||||
|
||||
@@ -62,15 +62,6 @@ private predicate ignoreExprAndDescendants(Expr expr) {
|
||||
// constant value.
|
||||
isIRConstant(getRealParent(expr))
|
||||
or
|
||||
// Only translate the initializer of a static local if it uses run-time data.
|
||||
// Otherwise the initializer does not run in function scope.
|
||||
exists(Initializer init, StaticStorageDurationVariable var |
|
||||
init = var.getInitializer() and
|
||||
not var.hasDynamicInitialization() and
|
||||
expr = init.getExpr().getFullyConverted() and
|
||||
not var instanceof GlobalOrNamespaceVariable
|
||||
)
|
||||
or
|
||||
// Ignore descendants of `__assume` expressions, since we translated these to `NoOp`.
|
||||
getRealParent(expr) instanceof AssumeExpr
|
||||
or
|
||||
@@ -118,8 +109,8 @@ private predicate ignoreExprOnly(Expr expr) {
|
||||
// should not be translated.
|
||||
exists(NewOrNewArrayExpr new | expr = new.getAllocatorCall().getArgument(0))
|
||||
or
|
||||
not translateFunction(expr.getEnclosingFunction()) and
|
||||
not Raw::varHasIRFunc(expr.getEnclosingVariable())
|
||||
not translateFunction(getEnclosingFunction(expr)) and
|
||||
not Raw::varHasIRFunc(getEnclosingVariable(expr))
|
||||
or
|
||||
// We do not yet translate destructors properly, so for now we ignore the
|
||||
// destructor call. We do, however, translate the expression being
|
||||
@@ -438,6 +429,17 @@ predicate hasTranslatedSyntheticTemporaryObject(Expr expr) {
|
||||
not expr.hasLValueToRValueConversion()
|
||||
}
|
||||
|
||||
class StaticInitializedStaticLocalVariable extends StaticLocalVariable {
|
||||
StaticInitializedStaticLocalVariable() {
|
||||
this.hasInitializer() and
|
||||
not this.hasDynamicInitialization()
|
||||
}
|
||||
}
|
||||
|
||||
class RuntimeInitializedStaticLocalVariable extends StaticLocalVariable {
|
||||
RuntimeInitializedStaticLocalVariable() { this.hasDynamicInitialization() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the specified `DeclarationEntry` needs an IR translation. An IR translation is only
|
||||
* necessary for automatic local variables, or for static local variables with dynamic
|
||||
@@ -453,7 +455,7 @@ private predicate translateDeclarationEntry(IRDeclarationEntry entry) {
|
||||
not var.isStatic()
|
||||
or
|
||||
// Ignore static variables unless they have a dynamic initializer.
|
||||
var.(StaticLocalVariable).hasDynamicInitialization()
|
||||
var instanceof RuntimeInitializedStaticLocalVariable
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -755,7 +757,7 @@ newtype TTranslatedElement =
|
||||
} or
|
||||
// The side effect that initializes newly-allocated memory.
|
||||
TTranslatedAllocationSideEffect(AllocationExpr expr) { not ignoreSideEffects(expr) } or
|
||||
TTranslatedGlobalOrNamespaceVarInit(GlobalOrNamespaceVariable var) { Raw::varHasIRFunc(var) }
|
||||
TTranslatedStaticStorageDurationVarInit(Variable var) { Raw::varHasIRFunc(var) }
|
||||
|
||||
/**
|
||||
* Gets the index of the first explicitly initialized element in `initList`
|
||||
@@ -1043,6 +1045,6 @@ abstract class TranslatedRootElement extends TranslatedElement {
|
||||
TranslatedRootElement() {
|
||||
this instanceof TTranslatedFunction
|
||||
or
|
||||
this instanceof TTranslatedGlobalOrNamespaceVarInit
|
||||
this instanceof TTranslatedStaticStorageDurationVarInit
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ abstract class TranslatedExpr extends TranslatedElement {
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = this.getAst() }
|
||||
|
||||
final override Declaration getFunction() { result = expr.getEnclosingDeclaration() }
|
||||
final override Declaration getFunction() { result = getEnclosingDeclaration(expr) }
|
||||
|
||||
/**
|
||||
* Gets the expression from which this `TranslatedExpr` is generated.
|
||||
@@ -90,12 +90,57 @@ abstract class TranslatedExpr extends TranslatedElement {
|
||||
* Gets the `TranslatedFunction` containing this expression.
|
||||
*/
|
||||
final TranslatedRootElement getEnclosingFunction() {
|
||||
result = getTranslatedFunction(expr.getEnclosingFunction())
|
||||
result = getTranslatedFunction(getEnclosingFunction(expr))
|
||||
or
|
||||
result = getTranslatedVarInit(expr.getEnclosingVariable())
|
||||
result = getTranslatedVarInit(getEnclosingVariable(expr))
|
||||
}
|
||||
}
|
||||
|
||||
Function getEnclosingFunction(Expr e) {
|
||||
not exists(getEnclosingVariable(e)) and
|
||||
result = e.getEnclosingFunction()
|
||||
}
|
||||
|
||||
Declaration getEnclosingDeclaration0(Expr e) {
|
||||
result = getEnclosingDeclaration0(e.getParentWithConversions())
|
||||
or
|
||||
exists(Initializer i, Variable v |
|
||||
i.getExpr().getFullyConverted() = e and
|
||||
v = i.getDeclaration()
|
||||
|
|
||||
if v instanceof StaticInitializedStaticLocalVariable or v instanceof GlobalOrNamespaceVariable
|
||||
then result = v
|
||||
else result = e.getEnclosingDeclaration()
|
||||
)
|
||||
}
|
||||
|
||||
Declaration getEnclosingDeclaration(Expr e) {
|
||||
result = getEnclosingDeclaration0(e)
|
||||
or
|
||||
not exists(getEnclosingDeclaration0(e)) and
|
||||
result = e.getEnclosingDeclaration()
|
||||
}
|
||||
|
||||
Variable getEnclosingVariable0(Expr e) {
|
||||
result = getEnclosingVariable0(e.getParentWithConversions())
|
||||
or
|
||||
exists(Initializer i, Variable v |
|
||||
i.getExpr().getFullyConverted() = e and
|
||||
v = i.getDeclaration()
|
||||
|
|
||||
if v instanceof StaticInitializedStaticLocalVariable or v instanceof GlobalOrNamespaceVariable
|
||||
then result = v
|
||||
else result = e.getEnclosingVariable()
|
||||
)
|
||||
}
|
||||
|
||||
Variable getEnclosingVariable(Expr e) {
|
||||
result = getEnclosingVariable0(e)
|
||||
or
|
||||
not exists(getEnclosingVariable0(e)) and
|
||||
result = e.getEnclosingVariable()
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of the "core" part of an expression. This is the part of
|
||||
* the expression that produces the result value of the expression, before any
|
||||
@@ -843,10 +888,21 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess {
|
||||
|
||||
override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = getIRUserVariable(expr.getEnclosingDeclaration(), expr.getTarget())
|
||||
exists(Declaration d, Variable v |
|
||||
accessHasEnclosingDeclarationAndVariable(d, v, expr) and
|
||||
result = getIRUserVariable(d, v)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate accessHasEnclosingDeclarationAndVariable(
|
||||
Declaration d, Variable v, VariableAccess va
|
||||
) {
|
||||
d = getEnclosingDeclaration(va) and
|
||||
v = va.getTarget()
|
||||
}
|
||||
|
||||
class TranslatedFieldAccess extends TranslatedVariableAccess {
|
||||
override FieldAccess expr;
|
||||
|
||||
@@ -2000,7 +2056,7 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr, St
|
||||
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getTranslatedFunction(expr.getEnclosingFunction()).getInitializeThisInstruction()
|
||||
result = getTranslatedFunction(getEnclosingFunction(expr)).getInitializeThisInstruction()
|
||||
}
|
||||
|
||||
final override Field getInstructionField(InstructionTag tag) {
|
||||
|
||||
@@ -322,11 +322,13 @@ class TranslatedFunction extends TranslatedRootElement, TTranslatedFunction {
|
||||
(
|
||||
var instanceof GlobalOrNamespaceVariable
|
||||
or
|
||||
var instanceof StaticLocalVariable
|
||||
or
|
||||
var instanceof MemberVariable and not var instanceof Field
|
||||
) and
|
||||
exists(VariableAccess access |
|
||||
access.getTarget() = var and
|
||||
access.getEnclosingFunction() = func
|
||||
getEnclosingFunction(access) = func
|
||||
)
|
||||
or
|
||||
var.(LocalScopeVariable).getFunction() = func
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.TranslatedElement
|
||||
private import TranslatedExpr
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.implementation.IRType
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
@@ -8,16 +9,16 @@ private import TranslatedInitialization
|
||||
private import InstructionTag
|
||||
private import semmle.code.cpp.ir.internal.IRUtilities
|
||||
|
||||
class TranslatedGlobalOrNamespaceVarInit extends TranslatedRootElement,
|
||||
TTranslatedGlobalOrNamespaceVarInit, InitializationContext
|
||||
class TranslatedStaticStorageDurationVarInit extends TranslatedRootElement,
|
||||
TTranslatedStaticStorageDurationVarInit, InitializationContext
|
||||
{
|
||||
GlobalOrNamespaceVariable var;
|
||||
Variable var;
|
||||
|
||||
TranslatedGlobalOrNamespaceVarInit() { this = TTranslatedGlobalOrNamespaceVarInit(var) }
|
||||
TranslatedStaticStorageDurationVarInit() { this = TTranslatedStaticStorageDurationVarInit(var) }
|
||||
|
||||
override string toString() { result = var.toString() }
|
||||
|
||||
final override GlobalOrNamespaceVariable getAst() { result = var }
|
||||
final override Variable getAst() { result = var }
|
||||
|
||||
final override Declaration getFunction() { result = var }
|
||||
|
||||
@@ -111,11 +112,13 @@ class TranslatedGlobalOrNamespaceVarInit extends TranslatedRootElement,
|
||||
(
|
||||
varUsed instanceof GlobalOrNamespaceVariable
|
||||
or
|
||||
varUsed instanceof StaticLocalVariable
|
||||
or
|
||||
varUsed instanceof MemberVariable and not varUsed instanceof Field
|
||||
) and
|
||||
exists(VariableAccess access |
|
||||
access.getTarget() = varUsed and
|
||||
access.getEnclosingVariable() = var
|
||||
getEnclosingVariable(access) = var
|
||||
)
|
||||
or
|
||||
var = varUsed
|
||||
@@ -128,6 +131,4 @@ class TranslatedGlobalOrNamespaceVarInit extends TranslatedRootElement,
|
||||
}
|
||||
}
|
||||
|
||||
TranslatedGlobalOrNamespaceVarInit getTranslatedVarInit(GlobalOrNamespaceVariable var) {
|
||||
result.getAst() = var
|
||||
}
|
||||
TranslatedStaticStorageDurationVarInit getTranslatedVarInit(Variable var) { result.getAst() = var }
|
||||
|
||||
@@ -138,8 +138,9 @@ abstract class TranslatedInitialization extends TranslatedElement, TTranslatedIn
|
||||
final override string toString() { result = "init: " + expr.toString() }
|
||||
|
||||
final override Declaration getFunction() {
|
||||
result = expr.getEnclosingFunction() or
|
||||
result = expr.getEnclosingVariable().(GlobalOrNamespaceVariable)
|
||||
result = getEnclosingFunction(expr) or
|
||||
result = getEnclosingVariable(expr).(GlobalOrNamespaceVariable) or
|
||||
result = getEnclosingVariable(expr).(StaticInitializedStaticLocalVariable)
|
||||
}
|
||||
|
||||
final override Locatable getAst() { result = expr }
|
||||
@@ -159,7 +160,7 @@ abstract class TranslatedInitialization extends TranslatedElement, TTranslatedIn
|
||||
final InitializationContext getContext() { result = getParent() }
|
||||
|
||||
final TranslatedFunction getEnclosingFunction() {
|
||||
result = getTranslatedFunction(expr.getEnclosingFunction())
|
||||
result = getTranslatedFunction(this.getFunction())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,8 +494,9 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
|
||||
final override Declaration getFunction() {
|
||||
result = ast.getEnclosingFunction() or
|
||||
result = ast.getEnclosingVariable().(GlobalOrNamespaceVariable)
|
||||
result = getEnclosingFunction(ast) or
|
||||
result = getEnclosingVariable(ast).(GlobalOrNamespaceVariable) or
|
||||
result = getEnclosingVariable(ast).(StaticInitializedStaticLocalVariable)
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction() { result = getInstruction(getFieldAddressTag()) }
|
||||
@@ -651,9 +653,11 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
|
||||
deprecated override Locatable getAST() { result = getAst() }
|
||||
|
||||
final override Declaration getFunction() {
|
||||
result = initList.getEnclosingFunction()
|
||||
result = getEnclosingFunction(initList)
|
||||
or
|
||||
result = initList.getEnclosingVariable().(GlobalOrNamespaceVariable)
|
||||
result = getEnclosingVariable(initList).(GlobalOrNamespaceVariable)
|
||||
or
|
||||
result = getEnclosingVariable(initList).(StaticInitializedStaticLocalVariable)
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction() { result = getInstruction(getElementIndexTag()) }
|
||||
@@ -852,7 +856,7 @@ abstract class TranslatedStructorCallFromStructor extends TranslatedElement, Str
|
||||
result = getStructorCall()
|
||||
}
|
||||
|
||||
final override Function getFunction() { result = call.getEnclosingFunction() }
|
||||
final override Function getFunction() { result = getEnclosingFunction(call) }
|
||||
|
||||
final override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = getStructorCall() and
|
||||
@@ -989,7 +993,7 @@ class TranslatedConstructorBareInit extends TranslatedElement, TTranslatedConstr
|
||||
|
||||
override TranslatedElement getChild(int id) { none() }
|
||||
|
||||
override Function getFunction() { result = getParent().getFunction() }
|
||||
override Declaration getFunction() { result = this.getParent().getFunction() }
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ class Variable = Cpp::Variable;
|
||||
|
||||
class AutomaticVariable = Cpp::StackVariable;
|
||||
|
||||
class StaticVariable = Cpp::Variable;
|
||||
class StaticVariable = Cpp::StaticStorageDurationVariable;
|
||||
|
||||
class GlobalVariable = Cpp::GlobalOrNamespaceVariable;
|
||||
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.Print as Print
|
||||
|
||||
predicate getIdentityString = Print::getIdentityString/1;
|
||||
string getIdentityString(Declaration decl) {
|
||||
if decl instanceof StaticLocalVariable
|
||||
then
|
||||
exists(StaticLocalVariable v | v = decl | result = v.getType().toString() + " " + v.getName())
|
||||
else result = Print::getIdentityString(decl)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisImpl
|
||||
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||
|
||||
/**
|
||||
* Gets the lower bound of the expression.
|
||||
@@ -22,8 +24,10 @@ private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.Rang
|
||||
* `lowerBound(expr.getFullyConverted())`
|
||||
*/
|
||||
float lowerBound(Expr expr) {
|
||||
exists(Instruction i, SemBound b | i.getAst() = expr and b instanceof SemZeroBound |
|
||||
semBounded(getSemanticExpr(i), b, result, false, _)
|
||||
exists(Instruction i, ConstantBounds::SemBound b |
|
||||
i.getAst() = expr and b instanceof ConstantBounds::SemZeroBound
|
||||
|
|
||||
ConstantStage::semBounded(getSemanticExpr(i), b, result, false, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -40,8 +44,10 @@ float lowerBound(Expr expr) {
|
||||
* `upperBound(expr.getFullyConverted())`
|
||||
*/
|
||||
float upperBound(Expr expr) {
|
||||
exists(Instruction i, SemBound b | i.getAst() = expr and b instanceof SemZeroBound |
|
||||
semBounded(getSemanticExpr(i), b, result, true, _)
|
||||
exists(Instruction i, ConstantBounds::SemBound b |
|
||||
i.getAst() = expr and b instanceof ConstantBounds::SemZeroBound
|
||||
|
|
||||
ConstantStage::semBounded(getSemanticExpr(i), b, result, true, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -90,7 +96,15 @@ predicate defMightOverflow(RangeSsaDefinition def, StackVariable v) {
|
||||
* does not consider the possibility that the expression might overflow
|
||||
* due to a conversion.
|
||||
*/
|
||||
predicate exprMightOverflowNegatively(Expr expr) { none() }
|
||||
predicate exprMightOverflowNegatively(Expr expr) {
|
||||
lowerBound(expr) < exprMinVal(expr)
|
||||
or
|
||||
exists(SemanticExprConfig::Expr semExpr |
|
||||
semExpr.getUnconverted().getAst() = expr and
|
||||
ConstantStage::potentiallyOverflowingExpr(false, semExpr) and
|
||||
not ConstantStage::initialBounded(semExpr, _, _, false, _, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow negatively. Conversions
|
||||
@@ -108,7 +122,15 @@ predicate convertedExprMightOverflowNegatively(Expr expr) {
|
||||
* does not consider the possibility that the expression might overflow
|
||||
* due to a conversion.
|
||||
*/
|
||||
predicate exprMightOverflowPositively(Expr expr) { none() }
|
||||
predicate exprMightOverflowPositively(Expr expr) {
|
||||
upperBound(expr) > exprMaxVal(expr)
|
||||
or
|
||||
exists(SemanticExprConfig::Expr semExpr |
|
||||
semExpr.getUnconverted().getAst() = expr and
|
||||
ConstantStage::potentiallyOverflowingExpr(true, semExpr) and
|
||||
not ConstantStage::initialBounded(semExpr, _, _, true, _, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow positively. Conversions
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
private import RangeAnalysisStage
|
||||
private import RangeAnalysisImpl
|
||||
|
||||
module FloatDelta implements DeltaSig {
|
||||
class Delta = float;
|
||||
@@ -18,3 +19,36 @@ module FloatDelta implements DeltaSig {
|
||||
bindingset[f]
|
||||
Delta fromFloat(float f) { result = f }
|
||||
}
|
||||
|
||||
module FloatOverflow implements OverflowSig<FloatDelta> {
|
||||
predicate semExprDoesNotOverflow(boolean positively, SemExpr expr) {
|
||||
exists(float lb, float ub, float delta |
|
||||
typeBounds(expr.getSemType(), lb, ub) and
|
||||
ConstantStage::initialBounded(expr, any(ConstantBounds::SemZeroBound b), delta, positively, _,
|
||||
_, _)
|
||||
|
|
||||
positively = true and delta < ub
|
||||
or
|
||||
positively = false and delta > lb
|
||||
)
|
||||
}
|
||||
|
||||
additional predicate typeBounds(SemType t, float lb, float ub) {
|
||||
exists(SemIntegerType integralType, float limit |
|
||||
integralType = t and limit = 2.pow(8 * integralType.getByteSize())
|
||||
|
|
||||
if integralType instanceof SemBooleanType
|
||||
then lb = 0 and ub = 1
|
||||
else
|
||||
if integralType.isSigned()
|
||||
then (
|
||||
lb = -(limit / 2) and ub = (limit / 2) - 1
|
||||
) else (
|
||||
lb = 0 and ub = limit - 1
|
||||
)
|
||||
)
|
||||
or
|
||||
// This covers all floating point types. The range is (-Inf, +Inf).
|
||||
t instanceof SemFloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
import RangeAnalysisImpl
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound
|
||||
private import RangeAnalysisImpl as Impl
|
||||
import Impl::Public
|
||||
|
||||
@@ -6,7 +6,7 @@ private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
private import RangeAnalysisStage
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||
|
||||
module CppLangImpl implements LangSig<FloatDelta> {
|
||||
module CppLangImplConstant implements LangSig<FloatDelta> {
|
||||
/**
|
||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
@@ -1,5 +1,6 @@
|
||||
private import RangeAnalysisStage
|
||||
private import RangeAnalysisSpecific
|
||||
private import RangeAnalysisConstantSpecific
|
||||
private import RangeAnalysisRelativeSpecific
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||
private import RangeUtils
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound as SemanticBound
|
||||
@@ -28,7 +29,7 @@ module ConstantBounds implements BoundSig<FloatDelta> {
|
||||
}
|
||||
}
|
||||
|
||||
private module RelativeBounds implements BoundSig<FloatDelta> {
|
||||
module RelativeBounds implements BoundSig<FloatDelta> {
|
||||
class SemBound instanceof SemanticBound::SemBound {
|
||||
SemBound() { not this instanceof SemanticBound::SemZeroBound }
|
||||
|
||||
@@ -46,11 +47,13 @@ private module RelativeBounds implements BoundSig<FloatDelta> {
|
||||
}
|
||||
}
|
||||
|
||||
private module ConstantStage =
|
||||
RangeStage<FloatDelta, ConstantBounds, CppLangImpl, RangeUtil<FloatDelta, CppLangImpl>>;
|
||||
module ConstantStage =
|
||||
RangeStage<FloatDelta, ConstantBounds, FloatOverflow, CppLangImplConstant,
|
||||
RangeUtil<FloatDelta, CppLangImplConstant>>;
|
||||
|
||||
private module RelativeStage =
|
||||
RangeStage<FloatDelta, RelativeBounds, CppLangImpl, RangeUtil<FloatDelta, CppLangImpl>>;
|
||||
module RelativeStage =
|
||||
RangeStage<FloatDelta, RelativeBounds, FloatOverflow, CppLangImplRelative,
|
||||
RangeUtil<FloatDelta, CppLangImplRelative>>;
|
||||
|
||||
private newtype TSemReason =
|
||||
TSemNoReason() or
|
||||
@@ -60,48 +63,52 @@ private newtype TSemReason =
|
||||
guard = any(RelativeStage::SemCondReason reason).getCond()
|
||||
}
|
||||
|
||||
/**
|
||||
* A reason for an inferred bound. This can either be `CondReason` if the bound
|
||||
* is due to a specific condition, or `NoReason` if the bound is inferred
|
||||
* without going through a bounding condition.
|
||||
*/
|
||||
abstract class SemReason extends TSemReason {
|
||||
/** Gets a textual representation of this reason. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A reason for an inferred bound that indicates that the bound is inferred
|
||||
* without going through a bounding condition.
|
||||
*/
|
||||
class SemNoReason extends SemReason, TSemNoReason {
|
||||
override string toString() { result = "NoReason" }
|
||||
}
|
||||
|
||||
/** A reason for an inferred bound pointing to a condition. */
|
||||
class SemCondReason extends SemReason, TSemCondReason {
|
||||
/** Gets the condition that is the reason for the bound. */
|
||||
SemGuard getCond() { this = TSemCondReason(result) }
|
||||
|
||||
override string toString() { result = getCond().toString() }
|
||||
}
|
||||
|
||||
private ConstantStage::SemReason constantReason(SemReason reason) {
|
||||
ConstantStage::SemReason constantReason(SemReason reason) {
|
||||
result instanceof ConstantStage::SemNoReason and reason instanceof SemNoReason
|
||||
or
|
||||
result.(ConstantStage::SemCondReason).getCond() = reason.(SemCondReason).getCond()
|
||||
}
|
||||
|
||||
private RelativeStage::SemReason relativeReason(SemReason reason) {
|
||||
RelativeStage::SemReason relativeReason(SemReason reason) {
|
||||
result instanceof RelativeStage::SemNoReason and reason instanceof SemNoReason
|
||||
or
|
||||
result.(RelativeStage::SemCondReason).getCond() = reason.(SemCondReason).getCond()
|
||||
}
|
||||
|
||||
predicate semBounded(
|
||||
SemExpr e, SemanticBound::SemBound b, float delta, boolean upper, SemReason reason
|
||||
) {
|
||||
ConstantStage::semBounded(e, b, delta, upper, constantReason(reason))
|
||||
or
|
||||
RelativeStage::semBounded(e, b, delta, upper, relativeReason(reason))
|
||||
import Public
|
||||
|
||||
module Public {
|
||||
predicate semBounded(
|
||||
SemExpr e, SemanticBound::SemBound b, float delta, boolean upper, SemReason reason
|
||||
) {
|
||||
ConstantStage::semBounded(e, b, delta, upper, constantReason(reason))
|
||||
or
|
||||
RelativeStage::semBounded(e, b, delta, upper, relativeReason(reason))
|
||||
}
|
||||
|
||||
/**
|
||||
* A reason for an inferred bound. This can either be `CondReason` if the bound
|
||||
* is due to a specific condition, or `NoReason` if the bound is inferred
|
||||
* without going through a bounding condition.
|
||||
*/
|
||||
abstract class SemReason extends TSemReason {
|
||||
/** Gets a textual representation of this reason. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A reason for an inferred bound that indicates that the bound is inferred
|
||||
* without going through a bounding condition.
|
||||
*/
|
||||
class SemNoReason extends SemReason, TSemNoReason {
|
||||
override string toString() { result = "NoReason" }
|
||||
}
|
||||
|
||||
/** A reason for an inferred bound pointing to a condition. */
|
||||
class SemCondReason extends SemReason, TSemCondReason {
|
||||
/** Gets the condition that is the reason for the bound. */
|
||||
SemGuard getCond() { this = TSemCondReason(result) }
|
||||
|
||||
override string toString() { result = getCond().toString() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* C++-specific implementation of range analysis.
|
||||
*/
|
||||
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
private import RangeAnalysisStage
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.IntDelta
|
||||
private import RangeAnalysisImpl
|
||||
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||
|
||||
module CppLangImplRelative implements LangSig<FloatDelta> {
|
||||
/**
|
||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadCopy(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Ignore the bound on this expression.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreExprBound(SemExpr e) {
|
||||
exists(boolean upper, float delta, ConstantBounds::SemZeroBound b, float lb, float ub |
|
||||
ConstantStage::semBounded(e, b, delta, upper, _) and
|
||||
typeBounds(e.getSemType(), lb, ub) and
|
||||
(
|
||||
upper = false and
|
||||
delta < lb
|
||||
or
|
||||
upper = true and
|
||||
delta > ub
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate typeBounds(SemType t, float lb, float ub) {
|
||||
exists(SemIntegerType integralType, float limit |
|
||||
integralType = t and limit = 2.pow(8 * integralType.getByteSize())
|
||||
|
|
||||
if integralType instanceof SemBooleanType
|
||||
then lb = 0 and ub = 1
|
||||
else
|
||||
if integralType.isSigned()
|
||||
then (
|
||||
lb = -(limit / 2) and ub = (limit / 2) - 1
|
||||
) else (
|
||||
lb = 0 and ub = limit - 1
|
||||
)
|
||||
)
|
||||
or
|
||||
// This covers all floating point types. The range is (-Inf, +Inf).
|
||||
t instanceof SemFloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignore any inferred zero lower bound on this expression.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreZeroLowerBound(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadArithmeticExpr(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the specified variable should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadAssignment(SemSsaVariable v) { none() }
|
||||
|
||||
/**
|
||||
* Adds additional results to `ssaRead()` that are specific to Java.
|
||||
*
|
||||
* This predicate handles propagation of offsets for post-increment and post-decrement expressions
|
||||
* in exactly the same way as the old Java implementation. Once the new implementation matches the
|
||||
* old one, we should remove this predicate and propagate deltas for all similar patterns, whether
|
||||
* or not they come from a post-increment/decrement expression.
|
||||
*/
|
||||
SemExpr specificSsaRead(SemSsaVariable v, float delta) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
|
||||
*/
|
||||
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
|
||||
*/
|
||||
predicate hasBound(SemExpr e, SemExpr bound, float delta, boolean upper) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the value of `dest` is known to be `src + delta`.
|
||||
*/
|
||||
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, float delta) { none() }
|
||||
|
||||
/**
|
||||
* Gets the type that range analysis should use to track the result of the specified expression,
|
||||
* if a type other than the original type of the expression is to be used.
|
||||
*
|
||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
||||
* actually references but whose values can be tracked as the type contained in the box.
|
||||
*/
|
||||
SemType getAlternateType(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Gets the type that range analysis should use to track the result of the specified source
|
||||
* variable, if a type other than the original type of the expression is to be used.
|
||||
*
|
||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
||||
* actually references but whose values can be tracked as the type contained in the box.
|
||||
*/
|
||||
SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
|
||||
}
|
||||
@@ -73,6 +73,7 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticCFG
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticType
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticOpcode
|
||||
private import ConstantAnalysis
|
||||
private import Sign
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticLocation
|
||||
|
||||
/**
|
||||
@@ -240,11 +241,19 @@ signature module BoundSig<DeltaSig D> {
|
||||
}
|
||||
}
|
||||
|
||||
module RangeStage<DeltaSig D, BoundSig<D> Bounds, LangSig<D> LangParam, UtilSig<D> UtilParam> {
|
||||
signature module OverflowSig<DeltaSig D> {
|
||||
predicate semExprDoesNotOverflow(boolean positively, SemExpr expr);
|
||||
}
|
||||
|
||||
module RangeStage<
|
||||
DeltaSig D, BoundSig<D> Bounds, OverflowSig<D> OverflowParam, LangSig<D> LangParam,
|
||||
UtilSig<D> UtilParam>
|
||||
{
|
||||
private import Bounds
|
||||
private import LangParam
|
||||
private import UtilParam
|
||||
private import D
|
||||
private import OverflowParam
|
||||
|
||||
/**
|
||||
* An expression that does conversion, boxing, or unboxing
|
||||
@@ -920,6 +929,81 @@ module RangeStage<DeltaSig D, BoundSig<D> Bounds, LangSig<D> LangParam, UtilSig<
|
||||
bounded(cast.getOperand(), b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
}
|
||||
|
||||
predicate bounded(
|
||||
SemExpr e, SemBound b, D::Delta delta, boolean upper, boolean fromBackEdge, D::Delta origdelta,
|
||||
SemReason reason
|
||||
) {
|
||||
initialBounded(e, b, delta, upper, fromBackEdge, origdelta, reason) and
|
||||
(
|
||||
semExprDoesNotOverflow(upper.booleanNot(), e)
|
||||
or
|
||||
not potentiallyOverflowingExpr(upper.booleanNot(), e)
|
||||
or
|
||||
exists(D::Delta otherDelta |
|
||||
initialBounded(e, _, otherDelta, upper.booleanNot(), _, _, _) and
|
||||
(
|
||||
upper = true and D::toFloat(otherDelta) >= 0
|
||||
or
|
||||
upper = false and D::toFloat(otherDelta) <= 0
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
predicate potentiallyOverflowingExpr(boolean positively, SemExpr expr) {
|
||||
(
|
||||
expr.getOpcode() instanceof Opcode::Add or
|
||||
expr.getOpcode() instanceof Opcode::PointerAdd
|
||||
) and
|
||||
(
|
||||
positively = true and
|
||||
(
|
||||
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getLeftOperand())) = TPos() and
|
||||
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getRightOperand())) = TPos()
|
||||
)
|
||||
or
|
||||
positively = false and
|
||||
(
|
||||
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getLeftOperand())) = TNeg() and
|
||||
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getRightOperand())) = TNeg()
|
||||
)
|
||||
)
|
||||
or
|
||||
(
|
||||
expr.getOpcode() instanceof Opcode::Sub or
|
||||
expr.getOpcode() instanceof Opcode::PointerSub
|
||||
) and
|
||||
(
|
||||
positively = true and
|
||||
(
|
||||
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getLeftOperand())) = TPos() and
|
||||
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getRightOperand())) = TNeg()
|
||||
)
|
||||
or
|
||||
positively = false and
|
||||
(
|
||||
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getLeftOperand())) = TNeg() and
|
||||
pragma[only_bind_out](semExprSign(expr.(SemBinaryExpr).getRightOperand())) = TPos()
|
||||
)
|
||||
)
|
||||
or
|
||||
positively in [true, false] and
|
||||
(
|
||||
expr.getOpcode() instanceof Opcode::Mul or
|
||||
expr.getOpcode() instanceof Opcode::ShiftLeft
|
||||
)
|
||||
or
|
||||
positively = false and
|
||||
(
|
||||
expr.getOpcode() instanceof Opcode::Negate or
|
||||
expr.getOpcode() instanceof Opcode::SubOne or
|
||||
expr.(SemDivExpr).getSemType() instanceof SemFloatingPointType
|
||||
)
|
||||
or
|
||||
positively = true and
|
||||
expr.getOpcode() instanceof Opcode::AddOne
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a normal form of `x` where -0.0 has changed to +0.0. This can be
|
||||
* needed on the lesser side of a floating-point comparison or on both sides of
|
||||
@@ -934,7 +1018,7 @@ module RangeStage<DeltaSig D, BoundSig<D> Bounds, LangSig<D> LangParam, UtilSig<
|
||||
* - `upper = true` : `e <= b + delta`
|
||||
* - `upper = false` : `e >= b + delta`
|
||||
*/
|
||||
private predicate bounded(
|
||||
predicate initialBounded(
|
||||
SemExpr e, SemBound b, D::Delta delta, boolean upper, boolean fromBackEdge, D::Delta origdelta,
|
||||
SemReason reason
|
||||
) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
private import RangeAnalysisSpecific
|
||||
private import RangeAnalysisRelativeSpecific
|
||||
private import RangeAnalysisStage as Range
|
||||
private import ConstantAnalysis
|
||||
|
||||
|
||||
@@ -314,9 +314,8 @@ class FreadBA extends BufferAccess {
|
||||
* but not:
|
||||
* &buffer[ix]
|
||||
*/
|
||||
class ArrayExprBA extends BufferAccess {
|
||||
class ArrayExprBA extends BufferAccess, ArrayExpr {
|
||||
ArrayExprBA() {
|
||||
exists(this.(ArrayExpr).getArrayOffset().getValue().toInt()) and
|
||||
not exists(AddressOfExpr aoe | aoe.getAChild() = this) and
|
||||
// exclude accesses in macro implementation of `strcmp`,
|
||||
// which are carefully controlled but can look dangerous.
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
## 0.6.1
|
||||
|
||||
### New Queries
|
||||
|
||||
* A new query `cpp/double-free` has been added. The query finds possible cases of deallocating the same pointer twice. The precision of the query has been set to "medium".
|
||||
* The query `cpp/use-after-free` has been modernized and assigned the precision "medium". The query finds cases of where a pointer is dereferenced after its memory has been deallocated.
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### New Queries
|
||||
|
||||
10
cpp/ql/src/Critical/DoubleFree.cpp
Normal file
10
cpp/ql/src/Critical/DoubleFree.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
int* f() {
|
||||
int *buff = malloc(SIZE*sizeof(int));
|
||||
do_stuff(buff);
|
||||
free(buff);
|
||||
int *new_buffer = malloc(SIZE*sizeof(int));
|
||||
free(buff); // BAD: If new_buffer is assigned the same address as buff,
|
||||
// the memory allocator will free the new buffer memory region,
|
||||
// leading to use-after-free problems and memory corruption.
|
||||
return new_buffer;
|
||||
}
|
||||
33
cpp/ql/src/Critical/DoubleFree.qhelp
Normal file
33
cpp/ql/src/Critical/DoubleFree.qhelp
Normal file
@@ -0,0 +1,33 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Deallocating memory more than once can lead to a double-free vulnerability. This can be exploited to
|
||||
corrupt the allocator's internal data structures, which can lead to denial-of-service attacks by crashing
|
||||
the program, or security vulnerabilities, by allowing an attacker to overwrite arbitrary memory locations.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>
|
||||
Ensure that all execution paths deallocate the allocated memory at most once. If possible, reassign
|
||||
the pointer to a null value after deallocating it. This will prevent double-free vulnerabilities since
|
||||
most deallocation functions will perform a null-pointer check before attempting to deallocate the memory.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
<example><sample src="DoubleFree.cpp" />
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
OWASP:
|
||||
<a href="https://owasp.org/www-community/vulnerabilities/Doubly_freeing_memory">Doubly freeing memory</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
49
cpp/ql/src/Critical/DoubleFree.ql
Normal file
49
cpp/ql/src/Critical/DoubleFree.ql
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @name Potential double free
|
||||
* @description Freeing a resource more than once can lead to undefined behavior and cause memory corruption.
|
||||
* @kind path-problem
|
||||
* @precision medium
|
||||
* @id cpp/double-free
|
||||
* @problem.severity warning
|
||||
* @security-severity 9.3
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-415
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
import FlowAfterFree
|
||||
import DoubleFree::PathGraph
|
||||
|
||||
predicate isFree(DataFlow::Node n, Expr e) { isFree(n, e, _) }
|
||||
|
||||
/**
|
||||
* `dealloc1` is a deallocation expression and `e` is an expression such
|
||||
* that is deallocated by a deallocation expression, and the `(dealloc1, e)` pair
|
||||
* should be excluded by the `FlowFromFree` library.
|
||||
*
|
||||
* Note that `e` is not necessarily the expression deallocated by `dealloc1`. It will
|
||||
* be bound to the second deallocation as identified by the `FlowFromFree` library.
|
||||
*/
|
||||
bindingset[dealloc1, e]
|
||||
predicate isExcludeFreePair(DeallocationExpr dealloc1, Expr e) {
|
||||
exists(DeallocationExpr dealloc2 | isFree(_, e, dealloc2) |
|
||||
dealloc1.(FunctionCall).getTarget().hasGlobalName("MmFreePagesFromMdl") and
|
||||
// From https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-mmfreepagesfrommdl:
|
||||
// "After calling MmFreePagesFromMdl, the caller must also call ExFreePool
|
||||
// to release the memory that was allocated for the MDL structure."
|
||||
isExFreePoolCall(dealloc2, _)
|
||||
)
|
||||
}
|
||||
|
||||
module DoubleFree = FlowFromFree<isFree/2, isExcludeFreePair/2>;
|
||||
|
||||
from DoubleFree::PathNode source, DoubleFree::PathNode sink, DeallocationExpr dealloc, Expr e2
|
||||
where
|
||||
DoubleFree::flowPath(source, sink) and
|
||||
isFree(source.getNode(), _, dealloc) and
|
||||
isFree(sink.getNode(), e2)
|
||||
select sink.getNode(), source, sink,
|
||||
"Memory pointed to by '" + e2.toString() + "' may already have been freed by $@.", dealloc,
|
||||
dealloc.toString()
|
||||
129
cpp/ql/src/Critical/FlowAfterFree.qll
Normal file
129
cpp/ql/src/Critical/FlowAfterFree.qll
Normal file
@@ -0,0 +1,129 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
private import semmle.code.cpp.ir.IR
|
||||
|
||||
/**
|
||||
* Signature for a predicate that holds if `n.asExpr() = e` and `n` is a sink in
|
||||
* the `FlowFromFreeConfig` module.
|
||||
*/
|
||||
private signature predicate isSinkSig(DataFlow::Node n, Expr e);
|
||||
|
||||
/**
|
||||
* Holds if `dealloc` is a deallocation expression and `e` is an expression such
|
||||
* that `isFree(_, e)` holds for some `isFree` predicate satisfying `isSinkSig`,
|
||||
* and this source-sink pair should be excluded from the analysis.
|
||||
*/
|
||||
bindingset[dealloc, e]
|
||||
private signature predicate isExcludedSig(DeallocationExpr dealloc, Expr e);
|
||||
|
||||
/**
|
||||
* Holds if `(b1, i1)` strictly post-dominates `(b2, i2)`
|
||||
*/
|
||||
bindingset[i1, i2]
|
||||
predicate strictlyPostDominates(IRBlock b1, int i1, IRBlock b2, int i2) {
|
||||
b1 = b2 and
|
||||
i1 > i2
|
||||
or
|
||||
b1.strictlyPostDominates(b2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(b1, i1)` strictly dominates `(b2, i2)`
|
||||
*/
|
||||
bindingset[i1, i2]
|
||||
predicate strictlyDominates(IRBlock b1, int i1, IRBlock b2, int i2) {
|
||||
b1 = b2 and
|
||||
i1 < i2
|
||||
or
|
||||
b1.strictlyDominates(b2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a `FlowFromFreeConfig` module that can be used to find flow between
|
||||
* a pointer being freed by some deallocation function, and a user-specified sink.
|
||||
*
|
||||
* In order to reduce false positives, the set of sinks is restricted to only those
|
||||
* that satisfy at least one of the following two criteria:
|
||||
* 1. The source dominates the sink, or
|
||||
* 2. The sink post-dominates the source.
|
||||
*/
|
||||
module FlowFromFree<isSinkSig/2 isASink, isExcludedSig/2 isExcluded> {
|
||||
module FlowFromFreeConfig implements DataFlow::StateConfigSig {
|
||||
class FlowState instanceof Expr {
|
||||
FlowState() { isFree(_, this, _) }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
}
|
||||
|
||||
predicate isSource(DataFlow::Node node, FlowState state) { isFree(node, state, _) }
|
||||
|
||||
pragma[inline]
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
exists(
|
||||
Expr e, DataFlow::Node source, IRBlock b1, int i1, IRBlock b2, int i2,
|
||||
DeallocationExpr dealloc
|
||||
|
|
||||
isASink(sink, e) and
|
||||
isFree(source, state, dealloc) and
|
||||
e != state and
|
||||
source.hasIndexInBlock(b1, i1) and
|
||||
sink.hasIndexInBlock(b2, i2) and
|
||||
not isExcluded(dealloc, e)
|
||||
|
|
||||
strictlyDominates(b1, i1, b2, i2)
|
||||
or
|
||||
strictlyPostDominates(b2, i2, b1, i1)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node n) {
|
||||
n.asIndirectExpr() = any(AddressOfExpr aoe)
|
||||
or
|
||||
n.asIndirectExpr() = any(Call call).getAnArgument()
|
||||
or
|
||||
exists(Expr e |
|
||||
n.asIndirectExpr() = e.(PointerDereferenceExpr).getOperand() or
|
||||
n.asIndirectExpr() = e.(ArrayExpr).getArrayBase()
|
||||
|
|
||||
e = any(StoreInstruction store).getDestinationAddress().getUnconvertedResultExpression()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node n, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node n1, FlowState state1, DataFlow::Node n2, FlowState state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
import DataFlow::GlobalWithState<FlowFromFreeConfig>
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` is a dataflow node such that `n.asExpr() = e` and `e`
|
||||
* is being freed by a deallocation expression `dealloc`.
|
||||
*/
|
||||
predicate isFree(DataFlow::Node n, Expr e, DeallocationExpr dealloc) {
|
||||
e = dealloc.getFreedExpr() and
|
||||
e = n.asExpr() and
|
||||
// Ignore realloc functions
|
||||
not exists(dealloc.(FunctionCall).getTarget().(AllocationFunction).getReallocPtrArg())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `fc` is a function call that is the result of expanding
|
||||
* the `ExFreePool` macro.
|
||||
*/
|
||||
predicate isExFreePoolCall(FunctionCall fc, Expr e) {
|
||||
e = fc.getArgument(0) and
|
||||
(
|
||||
exists(MacroInvocation mi |
|
||||
mi.getMacroName() = "ExFreePool" and
|
||||
mi.getExpr() = fc
|
||||
)
|
||||
or
|
||||
fc.getTarget().hasGlobalName("ExFreePool")
|
||||
)
|
||||
}
|
||||
@@ -16,160 +16,133 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.commons.Scanf
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
import semmle.code.cpp.dataflow.new.DataFlow::DataFlow
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.ir.ValueNumbering
|
||||
|
||||
/**
|
||||
* Holds if `call` is a `scanf`-like function that may write to `output` at index `index`.
|
||||
*
|
||||
* Furthermore, `instr` is the instruction that defines the address of the `index`'th argument
|
||||
* of `call`, and `vn` is the value number of `instr.`
|
||||
*/
|
||||
predicate isSource(ScanfFunctionCall call, int index, Instruction instr, ValueNumber vn, Expr output) {
|
||||
output = call.getOutputArgument(index).getFullyConverted() and
|
||||
instr.getConvertedResultExpression() = output and
|
||||
vn.getAnInstruction() = instr
|
||||
/** Holds if `n` reaches an argument to a call to a `scanf`-like function. */
|
||||
pragma[nomagic]
|
||||
predicate revFlow0(Node n) {
|
||||
isSink(_, _, n, _)
|
||||
or
|
||||
exists(Node succ | revFlow0(succ) | localFlowStep(n, succ))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is control-flow reachable in 0 or more steps from
|
||||
* a call to a `scanf`-like function.
|
||||
* Holds if `n` represents an uninitialized stack-allocated variable, or a
|
||||
* newly (and presumed uninitialized) heap allocation.
|
||||
*/
|
||||
predicate isUninitialized(Node n) {
|
||||
exists(n.asUninitialized()) or
|
||||
n.asIndirectExpr(1) instanceof AllocationExpr
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow0(Instruction instr) {
|
||||
isSource(_, _, instr, _, _)
|
||||
or
|
||||
exists(Instruction prev |
|
||||
fwdFlow0(prev) and
|
||||
prev.getASuccessor() = instr
|
||||
predicate fwdFlow0(Node n) {
|
||||
revFlow0(n) and
|
||||
(
|
||||
isUninitialized(n)
|
||||
or
|
||||
exists(Node prev |
|
||||
fwdFlow0(prev) and
|
||||
localFlowStep(prev, n)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of the IR translation of `access` that
|
||||
* is not an expression being deallocated, and `instr` has value
|
||||
* number `vn`.
|
||||
*/
|
||||
predicate isSink(Instruction instr, Access access, ValueNumber vn) {
|
||||
instr.getAst() = access and
|
||||
not any(DeallocationExpr dealloc).getFreedExpr() = access and
|
||||
vn.getAnInstruction() = instr
|
||||
predicate isSink(ScanfFunctionCall call, int index, Node n, Expr input) {
|
||||
input = call.getOutputArgument(index) and
|
||||
n.asIndirectExpr() = input
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a path from a call to a `scanf`-like function
|
||||
* Holds if `call` is a `scanf`-like call and `output` is the `index`'th
|
||||
* argument that has not been previously initialized.
|
||||
*/
|
||||
predicate isRelevantScanfCall(ScanfFunctionCall call, int index, Expr output) {
|
||||
exists(Node n | fwdFlow0(n) and isSink(call, index, n, output))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `call` is a `scanf`-like function that may write to `output` at
|
||||
* index `index` and `n` is the dataflow node that represents the data after
|
||||
* it has been written to by `call`.
|
||||
*/
|
||||
predicate isSource(ScanfFunctionCall call, int index, Node n, Expr output) {
|
||||
isRelevantScanfCall(call, index, output) and
|
||||
output = call.getOutputArgument(index) and
|
||||
n.asDefiningArgument() = output
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` is reachable from an output argument of a relevant call to
|
||||
* a `scanf`-like function.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node n) {
|
||||
isSource(_, _, n, _)
|
||||
or
|
||||
exists(Node prev |
|
||||
fwdFlow(prev) and
|
||||
localFlowStep(prev, n) and
|
||||
not isSanitizerOut(prev)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `n` should not have outgoing flow. */
|
||||
predicate isSanitizerOut(Node n) {
|
||||
// We disable flow out of sinks to reduce result duplication
|
||||
isSink(n, _)
|
||||
or
|
||||
// If the node is being passed to a function it may be
|
||||
// modified, and thus it's safe to later read the value.
|
||||
exists(n.asIndirectArgument())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` is a node such that `n.asExpr() = e` and `e` is not an
|
||||
* argument of a deallocation expression.
|
||||
*/
|
||||
predicate isSink(Node n, Expr e) {
|
||||
n.asExpr() = e and
|
||||
not any(DeallocationExpr dealloc).getFreedExpr() = e
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` is part of a path from a call to a `scanf`-like function
|
||||
* to a use of the written variable.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow0(Instruction instr) {
|
||||
fwdFlow0(instr) and
|
||||
predicate revFlow(Node n) {
|
||||
fwdFlow(n) and
|
||||
(
|
||||
isSink(instr, _, _)
|
||||
isSink(n, _)
|
||||
or
|
||||
exists(Instruction succ | revFlow0(succ) | instr.getASuccessor() = succ)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a path from a call to a `scanf`-like function
|
||||
* that writes to a variable with value number `vn`, without passing through
|
||||
* redefinitions of the variable.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow(Instruction instr, ValueNumber vn) {
|
||||
revFlow0(instr) and
|
||||
(
|
||||
isSource(_, _, instr, vn, _)
|
||||
or
|
||||
exists(Instruction prev |
|
||||
fwdFlow(prev, vn) and
|
||||
prev.getASuccessor() = instr and
|
||||
not isBarrier(instr, vn)
|
||||
exists(Node succ |
|
||||
revFlow(succ) and
|
||||
localFlowStep(n, succ) and
|
||||
not isSanitizerOut(n)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a path from a call to a `scanf`-like function
|
||||
* that writes to a variable with value number `vn`, without passing through
|
||||
* redefinitions of the variable.
|
||||
*
|
||||
* Note: This predicate only holds for the `(intr, vn)` pairs that are also
|
||||
* control-flow reachable from an argument to a `scanf`-like function call.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(Instruction instr, ValueNumber vn) {
|
||||
fwdFlow(instr, pragma[only_bind_out](vn)) and
|
||||
(
|
||||
isSink(instr, _, vn)
|
||||
or
|
||||
exists(Instruction succ | revFlow(succ, vn) |
|
||||
instr.getASuccessor() = succ and
|
||||
not isBarrier(succ, vn)
|
||||
)
|
||||
)
|
||||
/** A local flow step, restricted to relevant dataflow nodes. */
|
||||
private predicate step(Node n1, Node n2) {
|
||||
revFlow(n1) and
|
||||
revFlow(n2) and
|
||||
localFlowStep(n1, n2)
|
||||
}
|
||||
|
||||
/**
|
||||
* A type that bundles together a reachable instruction with the appropriate
|
||||
* value number (i.e., the value number that's transferred from the source
|
||||
* to the sink).
|
||||
*/
|
||||
newtype TNode = MkNode(Instruction instr, ValueNumber vn) { revFlow(instr, vn) }
|
||||
|
||||
class Node extends MkNode {
|
||||
ValueNumber vn;
|
||||
Instruction instr;
|
||||
|
||||
Node() { this = MkNode(instr, vn) }
|
||||
|
||||
final string toString() { result = instr.toString() }
|
||||
|
||||
final Node getASuccessor() { result = MkNode(pragma[only_bind_out](instr.getASuccessor()), vn) }
|
||||
|
||||
final Location getLocation() { result = instr.getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is an instruction with value number `vn` that is
|
||||
* used in a store operation, or is overwritten by another call to
|
||||
* a `scanf`-like function.
|
||||
*/
|
||||
private predicate isBarrier(Instruction instr, ValueNumber vn) {
|
||||
// We only need to compute barriers for instructions that we
|
||||
// managed to hit during the initial flow stage.
|
||||
revFlow0(pragma[only_bind_into](instr)) and
|
||||
valueNumber(instr) = vn and
|
||||
exists(Expr e | instr.getAst() = e |
|
||||
instr = any(StoreInstruction s).getDestinationAddress()
|
||||
or
|
||||
isSource(_, _, _, _, [e, e.getParent().(AddressOfExpr)])
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `n1` steps to `n2` in a single step. */
|
||||
predicate isSuccessor(Node n1, Node n2) { n1.getASuccessor() = n2 }
|
||||
|
||||
predicate hasFlow(Node n1, Node n2) = fastTC(isSuccessor/2)(n1, n2)
|
||||
|
||||
Node getNode(Instruction instr, ValueNumber vn) { result = MkNode(instr, vn) }
|
||||
predicate hasFlow(Node n1, Node n2) = fastTC(step/2)(n1, n2)
|
||||
|
||||
/**
|
||||
* Holds if `source` is the `index`'th argument to the `scanf`-like call `call`, and `sink` is
|
||||
* an instruction that is part of the translation of `access` which is a transitive
|
||||
* control-flow successor of `call`.
|
||||
*
|
||||
* Furthermore, `source` and `sink` have identical global value numbers.
|
||||
* a dataflow node that represents the expression `e`.
|
||||
*/
|
||||
predicate hasFlow(
|
||||
Instruction source, ScanfFunctionCall call, int index, Instruction sink, Access access
|
||||
) {
|
||||
exists(ValueNumber vn |
|
||||
isSource(call, index, source, vn, _) and
|
||||
hasFlow(getNode(source, pragma[only_bind_into](vn)), getNode(sink, pragma[only_bind_into](vn))) and
|
||||
isSink(sink, access, vn)
|
||||
)
|
||||
predicate hasFlow(Node source, ScanfFunctionCall call, int index, Node sink, Expr e) {
|
||||
isSource(call, index, source, _) and
|
||||
hasFlow(source, sink) and
|
||||
isSink(sink, e)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,7 +150,7 @@ predicate hasFlow(
|
||||
* success in writing the output argument at index `index`.
|
||||
*/
|
||||
int getMinimumGuardConstant(ScanfFunctionCall call, int index) {
|
||||
isSource(call, index, _, _, _) and
|
||||
isSource(call, index, _, _) and
|
||||
result =
|
||||
index + 1 -
|
||||
count(ScanfFormatLiteral f, int n |
|
||||
@@ -191,7 +164,7 @@ int getMinimumGuardConstant(ScanfFunctionCall call, int index) {
|
||||
* Holds the access to `e` isn't guarded by a check that ensures that `call` returned
|
||||
* at least `minGuard`.
|
||||
*/
|
||||
predicate hasNonGuardedAccess(ScanfFunctionCall call, Access e, int minGuard) {
|
||||
predicate hasNonGuardedAccess(ScanfFunctionCall call, Expr e, int minGuard) {
|
||||
exists(int index |
|
||||
hasFlow(_, call, index, _, e) and
|
||||
minGuard = getMinimumGuardConstant(call, index)
|
||||
@@ -211,7 +184,7 @@ BasicBlock blockGuardedBy(int value, string op, ScanfFunctionCall call) {
|
||||
exists(GuardCondition g, Expr left, Expr right |
|
||||
right = g.getAChild() and
|
||||
value = left.getValue().toInt() and
|
||||
DataFlow::localExprFlow(call, right)
|
||||
localExprFlow(call, right)
|
||||
|
|
||||
g.ensuresEq(left, right, 0, result, true) and op = "=="
|
||||
or
|
||||
@@ -221,9 +194,9 @@ BasicBlock blockGuardedBy(int value, string op, ScanfFunctionCall call) {
|
||||
)
|
||||
}
|
||||
|
||||
from ScanfFunctionCall call, Access access, int minGuard
|
||||
where hasNonGuardedAccess(call, access, minGuard)
|
||||
select access,
|
||||
from ScanfFunctionCall call, Expr e, int minGuard
|
||||
where hasNonGuardedAccess(call, e, minGuard)
|
||||
select e,
|
||||
"This variable is read, but may not have been written. " +
|
||||
"It should be guarded by a check that the $@ returns at least " + minGuard + ".", call,
|
||||
call.toString()
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* @name Potential use after free
|
||||
* @description An allocated memory block is used after it has been freed. Behavior in such cases is undefined and can cause memory corruption.
|
||||
* @kind problem
|
||||
* @kind path-problem
|
||||
* @precision medium
|
||||
* @id cpp/use-after-free
|
||||
* @problem.severity warning
|
||||
* @security-severity 9.3
|
||||
@@ -11,56 +12,159 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
import semmle.code.cpp.ir.IR
|
||||
import FlowAfterFree
|
||||
import UseAfterFree::PathGraph
|
||||
|
||||
/** `e` is an expression that frees the memory pointed to by `v`. */
|
||||
predicate isFreeExpr(Expr e, StackVariable v) {
|
||||
exists(VariableAccess va | va.getTarget() = v |
|
||||
exists(FunctionCall fc | fc = e |
|
||||
fc.getTarget().hasGlobalOrStdName("free") and
|
||||
va = fc.getArgument(0)
|
||||
)
|
||||
or
|
||||
e.(DeleteExpr).getExpr() = va
|
||||
or
|
||||
e.(DeleteArrayExpr).getExpr() = va
|
||||
/**
|
||||
* Holds if `call` is a call to a function that obviously
|
||||
* doesn't dereference its `i`'th argument.
|
||||
*/
|
||||
private predicate externalCallNeverDereferences(FormattingFunctionCall call, int arg) {
|
||||
exists(int formatArg |
|
||||
pragma[only_bind_out](call.getFormatArgument(formatArg)) =
|
||||
pragma[only_bind_out](call.getArgument(arg)) and
|
||||
call.getFormat().(FormatLiteral).getConvSpec(formatArg) != "%s"
|
||||
)
|
||||
}
|
||||
|
||||
/** `e` is an expression that (may) dereference `v`. */
|
||||
predicate isDerefExpr(Expr e, StackVariable v) {
|
||||
v.getAnAccess() = e and dereferenced(e)
|
||||
or
|
||||
isDerefByCallExpr(_, _, e, v)
|
||||
predicate isUse0(DataFlow::Node n, Expr e) {
|
||||
e = n.asExpr() and
|
||||
not isFree(_, e, _) and
|
||||
(
|
||||
e = any(PointerDereferenceExpr pde).getOperand()
|
||||
or
|
||||
e = any(PointerFieldAccess pfa).getQualifier()
|
||||
or
|
||||
e = any(ArrayExpr ae).getArrayBase()
|
||||
or
|
||||
e = any(Call call).getQualifier()
|
||||
or
|
||||
// Assume any function without a body will dereference the pointer
|
||||
exists(int i, Call call, Function f |
|
||||
n.asExpr() = call.getArgument(i) and
|
||||
f = call.getTarget() and
|
||||
not f.hasEntryPoint() and
|
||||
// Exclude known functions we know won't dereference the pointer.
|
||||
// For example, a call such as `printf("%p", myPointer)`.
|
||||
not externalCallNeverDereferences(call, i)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* `va` is passed by value as (part of) the `i`th argument in
|
||||
* call `c`. The target function is either a library function
|
||||
* or a source code function that dereferences the relevant
|
||||
* parameter.
|
||||
*/
|
||||
predicate isDerefByCallExpr(Call c, int i, VariableAccess va, StackVariable v) {
|
||||
v.getAnAccess() = va and
|
||||
va = c.getAnArgumentSubExpr(i) and
|
||||
not c.passesByReference(i, va) and
|
||||
(c.getTarget().hasEntryPoint() implies isDerefExpr(_, c.getTarget().getParameter(i)))
|
||||
}
|
||||
module ParameterSinks {
|
||||
import semmle.code.cpp.ir.ValueNumbering
|
||||
|
||||
class UseAfterFreeReachability extends StackVariableReachability {
|
||||
UseAfterFreeReachability() { this = "UseAfterFree" }
|
||||
predicate flowsToUse(DataFlow::Node n) {
|
||||
isUse0(n, _)
|
||||
or
|
||||
exists(DataFlow::Node succ |
|
||||
flowsToUse(succ) and
|
||||
DataFlow::localFlowStep(n, succ)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSource(ControlFlowNode node, StackVariable v) { isFreeExpr(node, v) }
|
||||
private predicate flowsFromParam(DataFlow::Node n) {
|
||||
flowsToUse(n) and
|
||||
(
|
||||
n.asParameter().getUnspecifiedType() instanceof PointerType
|
||||
or
|
||||
exists(DataFlow::Node prev |
|
||||
flowsFromParam(prev) and
|
||||
DataFlow::localFlowStep(prev, n)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(ControlFlowNode node, StackVariable v) { isDerefExpr(node, v) }
|
||||
private predicate step(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
flowsFromParam(n1) and
|
||||
flowsFromParam(n2) and
|
||||
DataFlow::localFlowStep(n1, n2)
|
||||
}
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
|
||||
definitionBarrier(v, node) or
|
||||
isFreeExpr(node, v)
|
||||
private predicate paramToUse(DataFlow::Node n1, DataFlow::Node n2) = fastTC(step/2)(n1, n2)
|
||||
|
||||
private predicate hasFlow(
|
||||
DataFlow::Node source, InitializeParameterInstruction init, DataFlow::Node sink
|
||||
) {
|
||||
pragma[only_bind_out](source.asParameter()) = pragma[only_bind_out](init.getParameter()) and
|
||||
paramToUse(source, sink) and
|
||||
isUse0(sink, _)
|
||||
}
|
||||
|
||||
private InitializeParameterInstruction getAnAlwaysDereferencedParameter0() {
|
||||
exists(DataFlow::Node source, DataFlow::Node sink, IRBlock b1, int i1, IRBlock b2, int i2 |
|
||||
hasFlow(pragma[only_bind_into](source), result, pragma[only_bind_into](sink)) and
|
||||
source.hasIndexInBlock(b1, pragma[only_bind_into](i1)) and
|
||||
sink.hasIndexInBlock(b2, pragma[only_bind_into](i2)) and
|
||||
strictlyPostDominates(b2, i2, b1, i1)
|
||||
)
|
||||
}
|
||||
|
||||
private CallInstruction getAnAlwaysReachedCallInstruction(IRFunction f) {
|
||||
result.getBlock().postDominates(f.getEntryBlock())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate callHasTargetAndArgument(Function f, int i, CallInstruction call, Instruction argument) {
|
||||
call.getStaticCallTarget() = f and
|
||||
call.getArgument(i) = argument
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate initializeParameterInFunction(Function f, int i, InitializeParameterInstruction init) {
|
||||
pragma[only_bind_out](init.getEnclosingFunction()) = f and
|
||||
init.hasIndex(i)
|
||||
}
|
||||
|
||||
InitializeParameterInstruction getAnAlwaysDereferencedParameter() {
|
||||
result = getAnAlwaysDereferencedParameter0()
|
||||
or
|
||||
exists(
|
||||
CallInstruction call, int i, InitializeParameterInstruction p, Instruction argument,
|
||||
Function f
|
||||
|
|
||||
callHasTargetAndArgument(f, i, call, argument) and
|
||||
initializeParameterInFunction(f, i, p) and
|
||||
p = getAnAlwaysDereferencedParameter() and
|
||||
result =
|
||||
pragma[only_bind_out](pragma[only_bind_into](valueNumber(argument)).getAnInstruction()) and
|
||||
call = getAnAlwaysReachedCallInstruction(_)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
predicate isUse(DataFlow::Node n, Expr e) {
|
||||
isUse0(n, e)
|
||||
or
|
||||
exists(CallInstruction call, int i, InitializeParameterInstruction init |
|
||||
n.asOperand().getDef().getUnconvertedResultExpression() = e and
|
||||
init = ParameterSinks::getAnAlwaysDereferencedParameter() and
|
||||
call.getArgumentOperand(i) = n.asOperand() and
|
||||
init.hasIndex(i) and
|
||||
init.getEnclosingFunction() = call.getStaticCallTarget()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* `dealloc1` is a deallocation expression, `e` is an expression that dereferences a
|
||||
* pointer, and the `(dealloc1, e)` pair should be excluded by the `FlowFromFree` library.
|
||||
*/
|
||||
bindingset[dealloc1, e]
|
||||
predicate isExcludeFreeUsePair(DeallocationExpr dealloc1, Expr e) {
|
||||
// From https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-mmfreepagesfrommdl:
|
||||
// "After calling MmFreePagesFromMdl, the caller must also call ExFreePool
|
||||
// to release the memory that was allocated for the MDL structure."
|
||||
dealloc1.(FunctionCall).getTarget().hasGlobalName("MmFreePagesFromMdl") and
|
||||
isExFreePoolCall(_, e)
|
||||
}
|
||||
|
||||
module UseAfterFree = FlowFromFree<isUse/2, isExcludeFreeUsePair/2>;
|
||||
|
||||
from UseAfterFree::PathNode source, UseAfterFree::PathNode sink, DeallocationExpr dealloc
|
||||
where
|
||||
UseAfterFree::flowPath(source, sink) and
|
||||
isFree(source.getNode(), _, dealloc)
|
||||
select sink.getNode(), source, sink, "Memory may have been previously freed by $@.", dealloc,
|
||||
dealloc.toString()
|
||||
|
||||
6
cpp/ql/src/change-notes/released/0.6.1.md
Normal file
6
cpp/ql/src/change-notes/released/0.6.1.md
Normal file
@@ -0,0 +1,6 @@
|
||||
## 0.6.1
|
||||
|
||||
### New Queries
|
||||
|
||||
* A new query `cpp/double-free` has been added. The query finds possible cases of deallocating the same pointer twice. The precision of the query has been set to "medium".
|
||||
* The query `cpp/use-after-free` has been modernized and assigned the precision "medium". The query finds cases of where a pointer is dereferenced after its memory has been deallocated.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.0
|
||||
lastReleaseVersion: 0.6.1
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @name Errors When Double Free
|
||||
* @description Freeing a previously allocated resource twice can lead to various vulnerabilities in the program.
|
||||
* @kind problem
|
||||
* @id cpp/double-free
|
||||
* @id cpp/experimental-double-free
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @tags security
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.6.0
|
||||
version: 0.6.1
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<queries language="cpp"/>
|
||||
@@ -575,6 +575,129 @@ edges
|
||||
| test.cpp:213:6:213:6 | q | test.cpp:213:5:213:13 | Store: ... = ... |
|
||||
| test.cpp:213:6:213:6 | q | test.cpp:213:5:213:13 | Store: ... = ... |
|
||||
| test.cpp:221:17:221:22 | call to malloc | test.cpp:222:5:222:5 | p |
|
||||
| test.cpp:231:18:231:30 | new[] | test.cpp:232:3:232:9 | newname |
|
||||
| test.cpp:232:3:232:9 | newname | test.cpp:232:3:232:16 | access to array |
|
||||
| test.cpp:232:3:232:16 | access to array | test.cpp:232:3:232:20 | Store: ... = ... |
|
||||
| test.cpp:238:20:238:32 | new[] | test.cpp:239:5:239:11 | newname |
|
||||
| test.cpp:239:5:239:11 | newname | test.cpp:239:5:239:18 | access to array |
|
||||
| test.cpp:239:5:239:18 | access to array | test.cpp:239:5:239:22 | Store: ... = ... |
|
||||
| test.cpp:248:24:248:30 | call to realloc | test.cpp:249:9:249:9 | p |
|
||||
| test.cpp:248:24:248:30 | call to realloc | test.cpp:250:22:250:22 | p |
|
||||
| test.cpp:248:24:248:30 | call to realloc | test.cpp:254:9:254:9 | p |
|
||||
| test.cpp:254:9:254:9 | p | test.cpp:254:9:254:12 | access to array |
|
||||
| test.cpp:254:9:254:12 | access to array | test.cpp:254:9:254:16 | Store: ... = ... |
|
||||
| test.cpp:260:13:260:24 | new[] | test.cpp:261:14:261:15 | xs |
|
||||
| test.cpp:261:14:261:15 | xs | test.cpp:261:14:261:21 | ... + ... |
|
||||
| test.cpp:261:14:261:15 | xs | test.cpp:261:14:261:21 | ... + ... |
|
||||
| test.cpp:261:14:261:15 | xs | test.cpp:261:14:261:21 | ... + ... |
|
||||
| test.cpp:261:14:261:15 | xs | test.cpp:261:14:261:21 | ... + ... |
|
||||
| test.cpp:261:14:261:15 | xs | test.cpp:262:26:262:28 | end |
|
||||
| test.cpp:261:14:261:15 | xs | test.cpp:262:26:262:28 | end |
|
||||
| test.cpp:261:14:261:15 | xs | test.cpp:262:31:262:31 | x |
|
||||
| test.cpp:261:14:261:15 | xs | test.cpp:262:31:262:33 | ... ++ |
|
||||
| test.cpp:261:14:261:15 | xs | test.cpp:262:31:262:33 | ... ++ |
|
||||
| test.cpp:261:14:261:15 | xs | test.cpp:264:14:264:14 | x |
|
||||
| test.cpp:261:14:261:15 | xs | test.cpp:264:14:264:14 | x |
|
||||
| test.cpp:261:14:261:21 | ... + ... | test.cpp:261:14:261:21 | ... + ... |
|
||||
| test.cpp:261:14:261:21 | ... + ... | test.cpp:261:14:261:21 | ... + ... |
|
||||
| test.cpp:261:14:261:21 | ... + ... | test.cpp:262:26:262:28 | end |
|
||||
| test.cpp:261:14:261:21 | ... + ... | test.cpp:262:26:262:28 | end |
|
||||
| test.cpp:261:14:261:21 | ... + ... | test.cpp:262:26:262:28 | end |
|
||||
| test.cpp:261:14:261:21 | ... + ... | test.cpp:262:26:262:28 | end |
|
||||
| test.cpp:261:14:261:21 | ... + ... | test.cpp:264:13:264:14 | Load: * ... |
|
||||
| test.cpp:261:14:261:21 | ... + ... | test.cpp:264:13:264:14 | Load: * ... |
|
||||
| test.cpp:261:14:261:21 | ... + ... | test.cpp:264:13:264:14 | Load: * ... |
|
||||
| test.cpp:261:14:261:21 | ... + ... | test.cpp:264:13:264:14 | Load: * ... |
|
||||
| test.cpp:262:21:262:21 | x | test.cpp:264:13:264:14 | Load: * ... |
|
||||
| test.cpp:262:26:262:28 | end | test.cpp:262:26:262:28 | end |
|
||||
| test.cpp:262:26:262:28 | end | test.cpp:262:26:262:28 | end |
|
||||
| test.cpp:262:26:262:28 | end | test.cpp:264:13:264:14 | Load: * ... |
|
||||
| test.cpp:262:26:262:28 | end | test.cpp:264:13:264:14 | Load: * ... |
|
||||
| test.cpp:262:31:262:31 | x | test.cpp:264:13:264:14 | Load: * ... |
|
||||
| test.cpp:262:31:262:33 | ... ++ | test.cpp:262:21:262:21 | x |
|
||||
| test.cpp:262:31:262:33 | ... ++ | test.cpp:262:21:262:21 | x |
|
||||
| test.cpp:262:31:262:33 | ... ++ | test.cpp:262:31:262:31 | x |
|
||||
| test.cpp:262:31:262:33 | ... ++ | test.cpp:262:31:262:31 | x |
|
||||
| test.cpp:262:31:262:33 | ... ++ | test.cpp:264:14:264:14 | x |
|
||||
| test.cpp:262:31:262:33 | ... ++ | test.cpp:264:14:264:14 | x |
|
||||
| test.cpp:262:31:262:33 | ... ++ | test.cpp:264:14:264:14 | x |
|
||||
| test.cpp:262:31:262:33 | ... ++ | test.cpp:264:14:264:14 | x |
|
||||
| test.cpp:264:14:264:14 | x | test.cpp:262:31:262:31 | x |
|
||||
| test.cpp:264:14:264:14 | x | test.cpp:264:13:264:14 | Load: * ... |
|
||||
| test.cpp:264:14:264:14 | x | test.cpp:264:13:264:14 | Load: * ... |
|
||||
| test.cpp:270:13:270:24 | new[] | test.cpp:271:14:271:15 | xs |
|
||||
| test.cpp:270:13:270:24 | new[] | test.cpp:272:31:272:31 | x |
|
||||
| test.cpp:271:14:271:15 | xs | test.cpp:271:14:271:21 | ... + ... |
|
||||
| test.cpp:271:14:271:15 | xs | test.cpp:271:14:271:21 | ... + ... |
|
||||
| test.cpp:271:14:271:15 | xs | test.cpp:271:14:271:21 | ... + ... |
|
||||
| test.cpp:271:14:271:15 | xs | test.cpp:271:14:271:21 | ... + ... |
|
||||
| test.cpp:271:14:271:15 | xs | test.cpp:272:26:272:28 | end |
|
||||
| test.cpp:271:14:271:15 | xs | test.cpp:272:26:272:28 | end |
|
||||
| test.cpp:271:14:271:15 | xs | test.cpp:272:31:272:31 | x |
|
||||
| test.cpp:271:14:271:15 | xs | test.cpp:272:31:272:33 | ... ++ |
|
||||
| test.cpp:271:14:271:15 | xs | test.cpp:272:31:272:33 | ... ++ |
|
||||
| test.cpp:271:14:271:15 | xs | test.cpp:274:5:274:6 | * ... |
|
||||
| test.cpp:271:14:271:15 | xs | test.cpp:274:6:274:6 | x |
|
||||
| test.cpp:271:14:271:15 | xs | test.cpp:274:6:274:6 | x |
|
||||
| test.cpp:271:14:271:21 | ... + ... | test.cpp:271:14:271:21 | ... + ... |
|
||||
| test.cpp:271:14:271:21 | ... + ... | test.cpp:271:14:271:21 | ... + ... |
|
||||
| test.cpp:271:14:271:21 | ... + ... | test.cpp:272:26:272:28 | end |
|
||||
| test.cpp:271:14:271:21 | ... + ... | test.cpp:272:26:272:28 | end |
|
||||
| test.cpp:271:14:271:21 | ... + ... | test.cpp:272:26:272:28 | end |
|
||||
| test.cpp:271:14:271:21 | ... + ... | test.cpp:272:26:272:28 | end |
|
||||
| test.cpp:271:14:271:21 | ... + ... | test.cpp:274:5:274:10 | Store: ... = ... |
|
||||
| test.cpp:271:14:271:21 | ... + ... | test.cpp:274:5:274:10 | Store: ... = ... |
|
||||
| test.cpp:271:14:271:21 | ... + ... | test.cpp:274:5:274:10 | Store: ... = ... |
|
||||
| test.cpp:271:14:271:21 | ... + ... | test.cpp:274:5:274:10 | Store: ... = ... |
|
||||
| test.cpp:272:21:272:21 | x | test.cpp:274:5:274:10 | Store: ... = ... |
|
||||
| test.cpp:272:26:272:28 | end | test.cpp:272:26:272:28 | end |
|
||||
| test.cpp:272:26:272:28 | end | test.cpp:272:26:272:28 | end |
|
||||
| test.cpp:272:26:272:28 | end | test.cpp:274:5:274:10 | Store: ... = ... |
|
||||
| test.cpp:272:26:272:28 | end | test.cpp:274:5:274:10 | Store: ... = ... |
|
||||
| test.cpp:272:31:272:31 | x | test.cpp:274:5:274:10 | Store: ... = ... |
|
||||
| test.cpp:272:31:272:33 | ... ++ | test.cpp:272:21:272:21 | x |
|
||||
| test.cpp:272:31:272:33 | ... ++ | test.cpp:272:21:272:21 | x |
|
||||
| test.cpp:272:31:272:33 | ... ++ | test.cpp:272:31:272:31 | x |
|
||||
| test.cpp:272:31:272:33 | ... ++ | test.cpp:272:31:272:31 | x |
|
||||
| test.cpp:272:31:272:33 | ... ++ | test.cpp:274:5:274:6 | * ... |
|
||||
| test.cpp:272:31:272:33 | ... ++ | test.cpp:274:5:274:6 | * ... |
|
||||
| test.cpp:272:31:272:33 | ... ++ | test.cpp:274:6:274:6 | x |
|
||||
| test.cpp:272:31:272:33 | ... ++ | test.cpp:274:6:274:6 | x |
|
||||
| test.cpp:272:31:272:33 | ... ++ | test.cpp:274:6:274:6 | x |
|
||||
| test.cpp:272:31:272:33 | ... ++ | test.cpp:274:6:274:6 | x |
|
||||
| test.cpp:274:5:274:6 | * ... | test.cpp:274:5:274:10 | Store: ... = ... |
|
||||
| test.cpp:274:6:274:6 | x | test.cpp:272:31:272:31 | x |
|
||||
| test.cpp:274:6:274:6 | x | test.cpp:274:5:274:6 | * ... |
|
||||
| test.cpp:274:6:274:6 | x | test.cpp:274:5:274:10 | Store: ... = ... |
|
||||
| test.cpp:274:6:274:6 | x | test.cpp:274:5:274:10 | Store: ... = ... |
|
||||
| test.cpp:280:13:280:24 | new[] | test.cpp:281:14:281:15 | xs |
|
||||
| test.cpp:281:14:281:15 | xs | test.cpp:282:30:282:32 | ... ++ |
|
||||
| test.cpp:281:14:281:15 | xs | test.cpp:282:30:282:32 | ... ++ |
|
||||
| test.cpp:282:21:282:21 | x | test.cpp:284:13:284:14 | Load: * ... |
|
||||
| test.cpp:282:30:282:30 | x | test.cpp:284:13:284:14 | Load: * ... |
|
||||
| test.cpp:282:30:282:32 | ... ++ | test.cpp:282:21:282:21 | x |
|
||||
| test.cpp:282:30:282:32 | ... ++ | test.cpp:282:21:282:21 | x |
|
||||
| test.cpp:282:30:282:32 | ... ++ | test.cpp:282:30:282:30 | x |
|
||||
| test.cpp:282:30:282:32 | ... ++ | test.cpp:282:30:282:30 | x |
|
||||
| test.cpp:282:30:282:32 | ... ++ | test.cpp:284:14:284:14 | x |
|
||||
| test.cpp:282:30:282:32 | ... ++ | test.cpp:284:14:284:14 | x |
|
||||
| test.cpp:284:14:284:14 | x | test.cpp:284:13:284:14 | Load: * ... |
|
||||
| test.cpp:290:13:290:24 | new[] | test.cpp:291:14:291:15 | xs |
|
||||
| test.cpp:290:13:290:24 | new[] | test.cpp:292:30:292:30 | x |
|
||||
| test.cpp:291:14:291:15 | xs | test.cpp:292:30:292:32 | ... ++ |
|
||||
| test.cpp:291:14:291:15 | xs | test.cpp:292:30:292:32 | ... ++ |
|
||||
| test.cpp:292:21:292:21 | x | test.cpp:294:5:294:10 | Store: ... = ... |
|
||||
| test.cpp:292:30:292:30 | x | test.cpp:294:5:294:10 | Store: ... = ... |
|
||||
| test.cpp:292:30:292:32 | ... ++ | test.cpp:292:21:292:21 | x |
|
||||
| test.cpp:292:30:292:32 | ... ++ | test.cpp:292:21:292:21 | x |
|
||||
| test.cpp:292:30:292:32 | ... ++ | test.cpp:292:30:292:30 | x |
|
||||
| test.cpp:292:30:292:32 | ... ++ | test.cpp:292:30:292:30 | x |
|
||||
| test.cpp:292:30:292:32 | ... ++ | test.cpp:294:5:294:6 | * ... |
|
||||
| test.cpp:292:30:292:32 | ... ++ | test.cpp:294:5:294:6 | * ... |
|
||||
| test.cpp:292:30:292:32 | ... ++ | test.cpp:294:6:294:6 | x |
|
||||
| test.cpp:292:30:292:32 | ... ++ | test.cpp:294:6:294:6 | x |
|
||||
| test.cpp:294:5:294:6 | * ... | test.cpp:294:5:294:10 | Store: ... = ... |
|
||||
| test.cpp:294:6:294:6 | x | test.cpp:294:5:294:10 | Store: ... = ... |
|
||||
#select
|
||||
| test.cpp:6:14:6:15 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:6:14:6:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
|
||||
| test.cpp:8:14:8:21 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:8:14:8:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
|
||||
@@ -593,3 +716,12 @@ edges
|
||||
| test.cpp:171:9:171:14 | Store: ... = ... | test.cpp:143:18:143:23 | call to malloc | test.cpp:171:9:171:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:143:18:143:23 | call to malloc | call to malloc | test.cpp:144:29:144:32 | size | size |
|
||||
| test.cpp:201:5:201:19 | Store: ... = ... | test.cpp:194:23:194:28 | call to malloc | test.cpp:201:5:201:19 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:194:23:194:28 | call to malloc | call to malloc | test.cpp:195:21:195:23 | len | len |
|
||||
| test.cpp:213:5:213:13 | Store: ... = ... | test.cpp:205:23:205:28 | call to malloc | test.cpp:213:5:213:13 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:205:23:205:28 | call to malloc | call to malloc | test.cpp:206:21:206:23 | len | len |
|
||||
| test.cpp:232:3:232:20 | Store: ... = ... | test.cpp:231:18:231:30 | new[] | test.cpp:232:3:232:20 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:231:18:231:30 | new[] | new[] | test.cpp:232:11:232:15 | index | index |
|
||||
| test.cpp:239:5:239:22 | Store: ... = ... | test.cpp:238:20:238:32 | new[] | test.cpp:239:5:239:22 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:238:20:238:32 | new[] | new[] | test.cpp:239:13:239:17 | index | index |
|
||||
| test.cpp:254:9:254:16 | Store: ... = ... | test.cpp:248:24:248:30 | call to realloc | test.cpp:254:9:254:16 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:248:24:248:30 | call to realloc | call to realloc | test.cpp:254:11:254:11 | i | i |
|
||||
| test.cpp:264:13:264:14 | Load: * ... | test.cpp:260:13:260:24 | new[] | test.cpp:264:13:264:14 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:260:13:260:24 | new[] | new[] | test.cpp:261:19:261:21 | len | len |
|
||||
| test.cpp:264:13:264:14 | Load: * ... | test.cpp:260:13:260:24 | new[] | test.cpp:264:13:264:14 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:260:13:260:24 | new[] | new[] | test.cpp:261:19:261:21 | len | len |
|
||||
| test.cpp:274:5:274:10 | Store: ... = ... | test.cpp:270:13:270:24 | new[] | test.cpp:274:5:274:10 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:270:13:270:24 | new[] | new[] | test.cpp:271:19:271:21 | len | len |
|
||||
| test.cpp:274:5:274:10 | Store: ... = ... | test.cpp:270:13:270:24 | new[] | test.cpp:274:5:274:10 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:270:13:270:24 | new[] | new[] | test.cpp:271:19:271:21 | len | len |
|
||||
| test.cpp:284:13:284:14 | Load: * ... | test.cpp:280:13:280:24 | new[] | test.cpp:284:13:284:14 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:280:13:280:24 | new[] | new[] | test.cpp:281:19:281:21 | len | len |
|
||||
| test.cpp:294:5:294:10 | Store: ... = ... | test.cpp:290:13:290:24 | new[] | test.cpp:294:5:294:10 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:290:13:290:24 | new[] | new[] | test.cpp:291:19:291:21 | len | len |
|
||||
|
||||
@@ -222,3 +222,75 @@ void test14(unsigned long n, char *p) {
|
||||
p[n - 1] = 'a'; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test15(unsigned index) {
|
||||
unsigned size = index + 13;
|
||||
if(size < index) {
|
||||
return;
|
||||
}
|
||||
int* newname = new int[size];
|
||||
newname[index] = 0; // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
void test16(unsigned index) {
|
||||
unsigned size = index + 13;
|
||||
if(size >= index) {
|
||||
int* newname = new int[size];
|
||||
newname[index] = 0; // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
void *realloc(void *, unsigned);
|
||||
|
||||
void test17(unsigned *p, unsigned x, unsigned k) {
|
||||
if(k > 0 && p[1] <= p[0]){
|
||||
unsigned n = 3*p[0] + k;
|
||||
p = (unsigned*)realloc(p, n);
|
||||
p[0] = n;
|
||||
unsigned i = p[1];
|
||||
// The following access is okay because:
|
||||
// n = 3*p[0] + k >= p[0] + k >= p[1] + k > p[1] = i
|
||||
// (where p[0] denotes the original value for p[0])
|
||||
p[i] = x; // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
void test17(unsigned len)
|
||||
{
|
||||
int *xs = new int[len];
|
||||
int *end = xs + len;
|
||||
for (int *x = xs; x <= end; x++)
|
||||
{
|
||||
int i = *x; // BAD
|
||||
}
|
||||
}
|
||||
|
||||
void test18(unsigned len)
|
||||
{
|
||||
int *xs = new int[len];
|
||||
int *end = xs + len;
|
||||
for (int *x = xs; x <= end; x++)
|
||||
{
|
||||
*x = 0; // BAD
|
||||
}
|
||||
}
|
||||
|
||||
void test19(unsigned len)
|
||||
{
|
||||
int *xs = new int[len];
|
||||
int *end = xs + len;
|
||||
for (int *x = xs; x < end; x++)
|
||||
{
|
||||
int i = *x; // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
void test20(unsigned len)
|
||||
{
|
||||
int *xs = new int[len];
|
||||
int *end = xs + len;
|
||||
for (int *x = xs; x < end; x++)
|
||||
{
|
||||
*x = 0; // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
| file://:0:0:0:0 | short __attribute((__may_alias__)) | type_attributes.c:25:30:25:42 | may_alias |
|
||||
| type_attributes.c:5:36:5:51 | my_packed_struct | type_attributes.c:5:23:5:32 | packed |
|
||||
| type_attributes.c:10:54:10:54 | union <unnamed> | type_attributes.c:10:30:10:50 | transparent_union |
|
||||
| type_attributes.c:16:54:16:54 | union <unnamed> | type_attributes.c:16:30:16:50 | transparent_union |
|
||||
| type_attributes.c:10:54:10:54 | (unnamed class/struct/union) | type_attributes.c:10:30:10:50 | transparent_union |
|
||||
| type_attributes.c:16:54:16:54 | (unnamed class/struct/union) | type_attributes.c:16:30:16:50 | transparent_union |
|
||||
| type_attributes.c:21:37:21:45 | unusedInt | type_attributes.c:21:24:21:29 | unused |
|
||||
| type_attributes.c:23:13:23:18 | depInt | type_attributes.c:23:36:23:45 | deprecated |
|
||||
| type_attributes_ms.cpp:1:29:1:29 | X | type_attributes_ms.cpp:1:19:1:26 | novtable |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
| (unnamed class/struct/union) |
|
||||
| float[3] |
|
||||
| float[3][3] |
|
||||
| foo[1] |
|
||||
| struct <unnamed> |
|
||||
|
||||
@@ -14377,6 +14377,37 @@ ir.cpp:
|
||||
# 1885| Type = [ClassTemplateInstantiation,Struct] Bar2<int>
|
||||
# 1885| ValueCategory = lvalue
|
||||
# 1886| getStmt(2): [ReturnStmt] return ...
|
||||
# 1891| [TopLevelFunction] int test_global_template_int()
|
||||
# 1891| <params>:
|
||||
# 1891| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1892| getStmt(0): [DeclStmt] declaration
|
||||
# 1892| getDeclarationEntry(0): [VariableDeclarationEntry] definition of local_int
|
||||
# 1892| Type = [IntType] int
|
||||
# 1892| getVariable().getInitializer(): [Initializer] initializer for local_int
|
||||
# 1892| getExpr(): [VariableAccess] global_template
|
||||
# 1892| Type = [IntType] int
|
||||
# 1892| ValueCategory = prvalue(load)
|
||||
# 1893| getStmt(1): [DeclStmt] declaration
|
||||
# 1893| getDeclarationEntry(0): [VariableDeclarationEntry] definition of local_char
|
||||
# 1893| Type = [PlainCharType] char
|
||||
# 1893| getVariable().getInitializer(): [Initializer] initializer for local_char
|
||||
# 1893| getExpr(): [VariableAccess] global_template
|
||||
# 1893| Type = [PlainCharType] char
|
||||
# 1893| ValueCategory = prvalue(load)
|
||||
# 1894| getStmt(2): [ReturnStmt] return ...
|
||||
# 1894| getExpr(): [AddExpr] ... + ...
|
||||
# 1894| Type = [IntType] int
|
||||
# 1894| ValueCategory = prvalue
|
||||
# 1894| getLeftOperand(): [VariableAccess] local_int
|
||||
# 1894| Type = [IntType] int
|
||||
# 1894| ValueCategory = prvalue(load)
|
||||
# 1894| getRightOperand(): [VariableAccess] local_char
|
||||
# 1894| Type = [PlainCharType] char
|
||||
# 1894| ValueCategory = prvalue(load)
|
||||
# 1894| getRightOperand().getFullyConverted(): [CStyleCast] (int)...
|
||||
# 1894| Conversion = [IntegralConversion] integral conversion
|
||||
# 1894| Type = [IntType] int
|
||||
# 1894| ValueCategory = prvalue
|
||||
perf-regression.cpp:
|
||||
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
|
||||
# 4| <params>:
|
||||
|
||||
@@ -18,5 +18,7 @@ predicate shouldDumpFunction(Declaration decl) {
|
||||
decl instanceof Function
|
||||
or
|
||||
decl.(GlobalOrNamespaceVariable).hasInitializer()
|
||||
or
|
||||
decl.(StaticLocalVariable).hasInitializer()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1886,4 +1886,12 @@ namespace missing_declaration_entries {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> T global_template = 42;
|
||||
|
||||
int test_global_template_int() {
|
||||
int local_int = global_template<int>;
|
||||
char local_char = global_template<char>;
|
||||
return local_int + (int)local_char;
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++17 --clang
|
||||
|
||||
@@ -5754,6 +5754,16 @@
|
||||
| ir.cpp:1231:5:1231:19 | Load | m1237_15 |
|
||||
| ir.cpp:1231:5:1231:19 | SideEffect | ~m1237_2 |
|
||||
| ir.cpp:1231:25:1231:25 | Address | &:r1231_5 |
|
||||
| ir.cpp:1232:16:1232:16 | Address | &:r1232_3 |
|
||||
| ir.cpp:1232:16:1232:16 | SideEffect | ~m1232_6 |
|
||||
| ir.cpp:1232:20:1232:20 | ChiPartial | partial:m1232_5 |
|
||||
| ir.cpp:1232:20:1232:20 | ChiTotal | total:m1232_2 |
|
||||
| ir.cpp:1232:20:1232:20 | StoreValue | r1232_4 |
|
||||
| ir.cpp:1233:16:1233:16 | Address | &:r1233_3 |
|
||||
| ir.cpp:1233:16:1233:16 | SideEffect | ~m1233_6 |
|
||||
| ir.cpp:1233:20:1233:28 | ChiPartial | partial:m1233_5 |
|
||||
| ir.cpp:1233:20:1233:28 | ChiTotal | total:m1233_2 |
|
||||
| ir.cpp:1233:20:1233:28 | StoreValue | r1233_4 |
|
||||
| ir.cpp:1234:16:1234:16 | Address | &:r1234_1 |
|
||||
| ir.cpp:1234:16:1234:16 | Address | &:r1234_1 |
|
||||
| ir.cpp:1234:16:1234:16 | Address | &:r1234_4 |
|
||||
@@ -8741,6 +8751,38 @@
|
||||
| ir.cpp:1885:11:1885:50 | ChiPartial | partial:m1885_4 |
|
||||
| ir.cpp:1885:11:1885:50 | ChiTotal | total:m1883_4 |
|
||||
| ir.cpp:1885:11:1885:50 | SideEffect | ~m1883_4 |
|
||||
| ir.cpp:1889:24:1889:24 | Address | &:r1889_3 |
|
||||
| ir.cpp:1889:24:1889:24 | Address | &:r1889_3 |
|
||||
| ir.cpp:1889:24:1889:24 | SideEffect | ~m1889_6 |
|
||||
| ir.cpp:1889:24:1889:24 | SideEffect | ~m1889_6 |
|
||||
| ir.cpp:1889:42:1889:43 | ChiPartial | partial:m1889_5 |
|
||||
| ir.cpp:1889:42:1889:43 | ChiPartial | partial:m1889_5 |
|
||||
| ir.cpp:1889:42:1889:43 | ChiTotal | total:m1889_2 |
|
||||
| ir.cpp:1889:42:1889:43 | ChiTotal | total:m1889_2 |
|
||||
| ir.cpp:1889:42:1889:43 | StoreValue | r1889_4 |
|
||||
| ir.cpp:1889:42:1889:43 | StoreValue | r1889_4 |
|
||||
| ir.cpp:1891:5:1891:28 | Address | &:r1891_5 |
|
||||
| ir.cpp:1891:5:1891:28 | ChiPartial | partial:m1891_3 |
|
||||
| ir.cpp:1891:5:1891:28 | ChiTotal | total:m1891_2 |
|
||||
| ir.cpp:1891:5:1891:28 | Load | m1894_8 |
|
||||
| ir.cpp:1891:5:1891:28 | SideEffect | m1891_3 |
|
||||
| ir.cpp:1892:9:1892:17 | Address | &:r1892_1 |
|
||||
| ir.cpp:1892:21:1892:40 | Address | &:r1892_2 |
|
||||
| ir.cpp:1892:21:1892:40 | Load | ~m1891_3 |
|
||||
| ir.cpp:1892:21:1892:40 | StoreValue | r1892_3 |
|
||||
| ir.cpp:1893:10:1893:19 | Address | &:r1893_1 |
|
||||
| ir.cpp:1893:23:1893:43 | Address | &:r1893_2 |
|
||||
| ir.cpp:1893:23:1893:43 | Load | ~m1891_3 |
|
||||
| ir.cpp:1893:23:1893:43 | StoreValue | r1893_3 |
|
||||
| ir.cpp:1894:5:1894:39 | Address | &:r1894_1 |
|
||||
| ir.cpp:1894:12:1894:20 | Address | &:r1894_2 |
|
||||
| ir.cpp:1894:12:1894:20 | Left | r1894_3 |
|
||||
| ir.cpp:1894:12:1894:20 | Load | m1892_4 |
|
||||
| ir.cpp:1894:12:1894:38 | StoreValue | r1894_7 |
|
||||
| ir.cpp:1894:24:1894:38 | Right | r1894_6 |
|
||||
| ir.cpp:1894:29:1894:38 | Address | &:r1894_4 |
|
||||
| ir.cpp:1894:29:1894:38 | Load | m1893_4 |
|
||||
| ir.cpp:1894:29:1894:38 | Unary | r1894_5 |
|
||||
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
|
||||
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
|
||||
| perf-regression.cpp:6:3:6:5 | Address | &:r6_7 |
|
||||
@@ -9030,6 +9072,34 @@
|
||||
| struct_init.cpp:20:6:20:25 | ChiPartial | partial:m20_3 |
|
||||
| struct_init.cpp:20:6:20:25 | ChiTotal | total:m20_2 |
|
||||
| struct_init.cpp:20:6:20:25 | SideEffect | ~m25_9 |
|
||||
| struct_init.cpp:21:17:21:28 | Left | r21_3 |
|
||||
| struct_init.cpp:21:17:21:28 | Left | r21_3 |
|
||||
| struct_init.cpp:21:17:21:28 | SideEffect | ~m23_10 |
|
||||
| struct_init.cpp:21:34:24:5 | Right | r21_4 |
|
||||
| struct_init.cpp:21:34:24:5 | Right | r21_6 |
|
||||
| struct_init.cpp:21:34:24:5 | Unary | r21_5 |
|
||||
| struct_init.cpp:21:34:24:5 | Unary | r21_5 |
|
||||
| struct_init.cpp:21:34:24:5 | Unary | r21_7 |
|
||||
| struct_init.cpp:21:34:24:5 | Unary | r21_7 |
|
||||
| struct_init.cpp:22:9:22:25 | Address | &:r22_1 |
|
||||
| struct_init.cpp:22:9:22:25 | Address | &:r22_6 |
|
||||
| struct_init.cpp:22:11:22:13 | ChiPartial | partial:m22_4 |
|
||||
| struct_init.cpp:22:11:22:13 | ChiTotal | total:m21_2 |
|
||||
| struct_init.cpp:22:11:22:13 | StoreValue | r22_3 |
|
||||
| struct_init.cpp:22:11:22:13 | Unary | r22_2 |
|
||||
| struct_init.cpp:22:16:22:23 | ChiPartial | partial:m22_8 |
|
||||
| struct_init.cpp:22:16:22:23 | ChiTotal | total:m22_5 |
|
||||
| struct_init.cpp:22:16:22:23 | StoreValue | r22_7 |
|
||||
| struct_init.cpp:23:9:23:26 | Address | &:r23_1 |
|
||||
| struct_init.cpp:23:9:23:26 | Address | &:r23_6 |
|
||||
| struct_init.cpp:23:11:23:13 | ChiPartial | partial:m23_4 |
|
||||
| struct_init.cpp:23:11:23:13 | ChiTotal | total:m22_9 |
|
||||
| struct_init.cpp:23:11:23:13 | StoreValue | r23_3 |
|
||||
| struct_init.cpp:23:11:23:13 | Unary | r23_2 |
|
||||
| struct_init.cpp:23:16:23:24 | ChiPartial | partial:m23_9 |
|
||||
| struct_init.cpp:23:16:23:24 | ChiTotal | total:m23_5 |
|
||||
| struct_init.cpp:23:16:23:24 | StoreValue | r23_8 |
|
||||
| struct_init.cpp:23:17:23:24 | Unary | r23_7 |
|
||||
| struct_init.cpp:25:5:25:19 | CallTarget | func:r25_1 |
|
||||
| struct_init.cpp:25:5:25:19 | ChiPartial | partial:m25_5 |
|
||||
| struct_init.cpp:25:5:25:19 | ChiTotal | total:m20_4 |
|
||||
|
||||
@@ -6841,6 +6841,28 @@ ir.cpp:
|
||||
# 1231| v1231_8(void) = AliasedUse : ~m?
|
||||
# 1231| v1231_9(void) = ExitFunction :
|
||||
|
||||
# 1232| int a
|
||||
# 1232| Block 0
|
||||
# 1232| v1232_1(void) = EnterFunction :
|
||||
# 1232| mu1232_2(unknown) = AliasedDefinition :
|
||||
# 1232| r1232_3(glval<int>) = VariableAddress[a] :
|
||||
# 1232| r1232_4(int) = Constant[0] :
|
||||
# 1232| mu1232_5(int) = Store[a] : &:r1232_3, r1232_4
|
||||
# 1232| v1232_6(void) = ReturnVoid :
|
||||
# 1232| v1232_7(void) = AliasedUse : ~m?
|
||||
# 1232| v1232_8(void) = ExitFunction :
|
||||
|
||||
# 1233| int b
|
||||
# 1233| Block 0
|
||||
# 1233| v1233_1(void) = EnterFunction :
|
||||
# 1233| mu1233_2(unknown) = AliasedDefinition :
|
||||
# 1233| r1233_3(glval<int>) = VariableAddress[b] :
|
||||
# 1233| r1233_4(int) = Constant[4] :
|
||||
# 1233| mu1233_5(int) = Store[b] : &:r1233_3, r1233_4
|
||||
# 1233| v1233_6(void) = ReturnVoid :
|
||||
# 1233| v1233_7(void) = AliasedUse : ~m?
|
||||
# 1233| v1233_8(void) = ExitFunction :
|
||||
|
||||
# 1240| void staticLocalWithConstructor(char const*)
|
||||
# 1240| Block 0
|
||||
# 1240| v1240_1(void) = EnterFunction :
|
||||
@@ -10035,6 +10057,54 @@ ir.cpp:
|
||||
# 1883| v1883_5(void) = AliasedUse : ~m?
|
||||
# 1883| v1883_6(void) = ExitFunction :
|
||||
|
||||
# 1889| char global_template<char>
|
||||
# 1889| Block 0
|
||||
# 1889| v1889_1(void) = EnterFunction :
|
||||
# 1889| mu1889_2(unknown) = AliasedDefinition :
|
||||
# 1889| r1889_3(glval<char>) = VariableAddress[global_template] :
|
||||
# 1889| r1889_4(char) = Constant[42] :
|
||||
# 1889| mu1889_5(char) = Store[global_template] : &:r1889_3, r1889_4
|
||||
# 1889| v1889_6(void) = ReturnVoid :
|
||||
# 1889| v1889_7(void) = AliasedUse : ~m?
|
||||
# 1889| v1889_8(void) = ExitFunction :
|
||||
|
||||
# 1889| int global_template<int>
|
||||
# 1889| Block 0
|
||||
# 1889| v1889_1(void) = EnterFunction :
|
||||
# 1889| mu1889_2(unknown) = AliasedDefinition :
|
||||
# 1889| r1889_3(glval<int>) = VariableAddress[global_template] :
|
||||
# 1889| r1889_4(int) = Constant[42] :
|
||||
# 1889| mu1889_5(int) = Store[global_template] : &:r1889_3, r1889_4
|
||||
# 1889| v1889_6(void) = ReturnVoid :
|
||||
# 1889| v1889_7(void) = AliasedUse : ~m?
|
||||
# 1889| v1889_8(void) = ExitFunction :
|
||||
|
||||
# 1891| int test_global_template_int()
|
||||
# 1891| Block 0
|
||||
# 1891| v1891_1(void) = EnterFunction :
|
||||
# 1891| mu1891_2(unknown) = AliasedDefinition :
|
||||
# 1891| mu1891_3(unknown) = InitializeNonLocal :
|
||||
# 1892| r1892_1(glval<int>) = VariableAddress[local_int] :
|
||||
# 1892| r1892_2(glval<int>) = VariableAddress[global_template] :
|
||||
# 1892| r1892_3(int) = Load[global_template] : &:r1892_2, ~m?
|
||||
# 1892| mu1892_4(int) = Store[local_int] : &:r1892_1, r1892_3
|
||||
# 1893| r1893_1(glval<char>) = VariableAddress[local_char] :
|
||||
# 1893| r1893_2(glval<char>) = VariableAddress[global_template] :
|
||||
# 1893| r1893_3(char) = Load[global_template] : &:r1893_2, ~m?
|
||||
# 1893| mu1893_4(char) = Store[local_char] : &:r1893_1, r1893_3
|
||||
# 1894| r1894_1(glval<int>) = VariableAddress[#return] :
|
||||
# 1894| r1894_2(glval<int>) = VariableAddress[local_int] :
|
||||
# 1894| r1894_3(int) = Load[local_int] : &:r1894_2, ~m?
|
||||
# 1894| r1894_4(glval<char>) = VariableAddress[local_char] :
|
||||
# 1894| r1894_5(char) = Load[local_char] : &:r1894_4, ~m?
|
||||
# 1894| r1894_6(int) = Convert : r1894_5
|
||||
# 1894| r1894_7(int) = Add : r1894_3, r1894_6
|
||||
# 1894| mu1894_8(int) = Store[#return] : &:r1894_1, r1894_7
|
||||
# 1891| r1891_4(glval<int>) = VariableAddress[#return] :
|
||||
# 1891| v1891_5(void) = ReturnValue : &:r1891_4, ~m?
|
||||
# 1891| v1891_6(void) = AliasedUse : ~m?
|
||||
# 1891| v1891_7(void) = ExitFunction :
|
||||
|
||||
perf-regression.cpp:
|
||||
# 6| void Big::Big()
|
||||
# 6| Block 0
|
||||
@@ -10320,6 +10390,34 @@ struct_init.cpp:
|
||||
# 20| v20_5(void) = AliasedUse : ~m?
|
||||
# 20| v20_6(void) = ExitFunction :
|
||||
|
||||
# 21| Info[] static_infos
|
||||
# 21| Block 0
|
||||
# 21| v21_1(void) = EnterFunction :
|
||||
# 21| mu21_2(unknown) = AliasedDefinition :
|
||||
# 21| r21_3(glval<Info[]>) = VariableAddress[static_infos] :
|
||||
# 21| r21_4(int) = Constant[0] :
|
||||
# 21| r21_5(glval<Info>) = PointerAdd[16] : r21_3, r21_4
|
||||
# 22| r22_1(glval<char *>) = FieldAddress[name] : r21_5
|
||||
# 22| r22_2(glval<char[2]>) = StringConstant["1"] :
|
||||
# 22| r22_3(char *) = Convert : r22_2
|
||||
# 22| mu22_4(char *) = Store[?] : &:r22_1, r22_3
|
||||
# 22| r22_5(glval<..(*)(..)>) = FieldAddress[handler] : r21_5
|
||||
# 22| r22_6(..(*)(..)) = FunctionAddress[handler1] :
|
||||
# 22| mu22_7(..(*)(..)) = Store[?] : &:r22_5, r22_6
|
||||
# 21| r21_6(int) = Constant[1] :
|
||||
# 21| r21_7(glval<Info>) = PointerAdd[16] : r21_3, r21_6
|
||||
# 23| r23_1(glval<char *>) = FieldAddress[name] : r21_7
|
||||
# 23| r23_2(glval<char[2]>) = StringConstant["2"] :
|
||||
# 23| r23_3(char *) = Convert : r23_2
|
||||
# 23| mu23_4(char *) = Store[?] : &:r23_1, r23_3
|
||||
# 23| r23_5(glval<..(*)(..)>) = FieldAddress[handler] : r21_7
|
||||
# 23| r23_6(glval<..()(..)>) = FunctionAddress[handler2] :
|
||||
# 23| r23_7(..(*)(..)) = CopyValue : r23_6
|
||||
# 23| mu23_8(..(*)(..)) = Store[?] : &:r23_5, r23_7
|
||||
# 21| v21_8(void) = ReturnVoid :
|
||||
# 21| v21_9(void) = AliasedUse : ~m?
|
||||
# 21| v21_10(void) = ExitFunction :
|
||||
|
||||
# 28| void declare_local_infos()
|
||||
# 28| Block 0
|
||||
# 28| v28_1(void) = EnterFunction :
|
||||
|
||||
@@ -3,14 +3,14 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.ModulusAnaly
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisSpecific
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisImpl
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
module ModulusAnalysisInstantiated =
|
||||
ModulusAnalysis<FloatDelta, ConstantBounds, RangeUtil<FloatDelta, CppLangImpl>>;
|
||||
ModulusAnalysis<FloatDelta, ConstantBounds, RangeUtil<FloatDelta, CppLangImplRelative>>;
|
||||
|
||||
class ModulusAnalysisTest extends InlineExpectationsTest {
|
||||
ModulusAnalysisTest() { this = "ModulusAnalysisTest" }
|
||||
|
||||
23
cpp/ql/test/library-tests/ir/range-analysis/Overflow.ql
Normal file
23
cpp/ql/test/library-tests/ir/range-analysis/Overflow.ql
Normal file
@@ -0,0 +1,23 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.rangeanalysis.new.SimpleRangeAnalysis
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class RangeAnalysisTest extends InlineExpectationsTest {
|
||||
RangeAnalysisTest() { this = "RangeAnalysisTest" }
|
||||
|
||||
override string getARelevantTag() { result = "overflow" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(Expr e |
|
||||
tag = "overflow" and
|
||||
element = e.toString() and
|
||||
location = e.getLocation() and
|
||||
value =
|
||||
strictconcat(string s |
|
||||
s = "+" and exprMightOverflowPositively(e)
|
||||
or
|
||||
s = "-" and exprMightOverflowNegatively(e)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,9 @@ int test1(struct List* p) {
|
||||
int count = 0;
|
||||
for (; p; p = p->next) {
|
||||
count = count+1;
|
||||
range(count); // $ range===count:p+1 range=>=1
|
||||
range(count); // $ range===count:p+1
|
||||
}
|
||||
range(count); // $ range=>=0
|
||||
range(count);
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -40,13 +40,13 @@ int test4() {
|
||||
int total = 0;
|
||||
for (i = 0; i < 2; i = i+1) {
|
||||
range(i); // $ range=<=1 range=>=0
|
||||
range(total); // $ range=>=0
|
||||
range(total);
|
||||
total += i;
|
||||
range(total); // $ range=<=i+1 range=<=i+1 range=>=0 range=>=i+0
|
||||
range(total); // $ range=<=i+1 range=<=i+1 MISSING: range=>=0 range=>=i+0
|
||||
}
|
||||
range(total); // $ range=>=0
|
||||
range(total); // $ MISSING: range=>=0
|
||||
range(i); // $ range===2
|
||||
range(total + i); // $ range===i+2 range=>=2 range=>=i+0
|
||||
range(total + i); // $ range=<=i+2 MISSING: range===i+2 range=>=2 range=>=i+0
|
||||
return total + i;
|
||||
}
|
||||
|
||||
@@ -55,13 +55,13 @@ int test5() {
|
||||
int total = 0;
|
||||
for (i = 0; i < 2; i++) {
|
||||
range(i); // $ range=<=1 range=>=0
|
||||
range(total); // $ range=>=0
|
||||
range(total); // $ MISSING: range=>=0
|
||||
total += i;
|
||||
range(total); // $ range=<=i+1 range=>=0 range=>=i+0
|
||||
range(total); // $ range=<=i+1 MISSING: range=>=0 range=>=i+0
|
||||
}
|
||||
range(total); // $ range=>=0
|
||||
range(total); // $ MISSING: range=>=0
|
||||
range(i); // $ range===2
|
||||
range(total + i); // $ range===i+2 range=>=2 range=>=i+0
|
||||
range(total + i); // $ range=<=i+2 MISSING: range===i+2 range=>=2 range=>=i+0
|
||||
return total + i;
|
||||
}
|
||||
|
||||
@@ -70,9 +70,9 @@ int test6() {
|
||||
int total = 0;
|
||||
for (i = 0; i+2 < 4; i = i+1) {
|
||||
range(i); // $ range=<=1 range=>=0
|
||||
range(total); // $ range=>=0
|
||||
range(total); // $ MISSING: range=>=0
|
||||
total += i;
|
||||
range(total); // $ range=<=i+1 range=>=0 range=>=i+0
|
||||
range(total); // $ range=<=i+1 MISSING: range=>=0 range=>=i+0
|
||||
}
|
||||
return total + i;
|
||||
}
|
||||
@@ -168,19 +168,19 @@ typedef unsigned long long size_type;
|
||||
|
||||
size_type test12_helper() {
|
||||
static size_type n = 0;
|
||||
return n++;
|
||||
return n++; // $ overflow=+
|
||||
}
|
||||
|
||||
int test12() {
|
||||
size_type Start = 0;
|
||||
while (Start <= test12_helper()-1)
|
||||
{
|
||||
range(Start);
|
||||
range(Start); // $ MISSING:range=>=0
|
||||
const size_type Length = test12_helper();
|
||||
Start += Length + 1;
|
||||
range(Start);
|
||||
Start += Length + 1; // $ overflow=+
|
||||
range(Start); // $ MISSING:range=>=1 MISSING:range=>=Start+1 MISSING:range=">=call to test12_helper+1"
|
||||
}
|
||||
range(Start);
|
||||
range(Start); // $ MISSING:range=>=0
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -190,13 +190,13 @@ int test13(char c, int i) {
|
||||
unsigned char uc = c;
|
||||
range(uc);
|
||||
unsigned int x = 0;
|
||||
unsigned int y = x-1;
|
||||
range(y); // $ range===-1
|
||||
int z = i+1;
|
||||
unsigned int y = x-1; // $ overflow=-
|
||||
range(y); // $ range===-1 overflow=-
|
||||
int z = i+1; // $ overflow=+
|
||||
range(z); // $ range===i+1
|
||||
range(c + i + uc + x + y + z);
|
||||
range((double)(c + i + uc + x + y + z));
|
||||
return (double)(c + i + uc + x + y + z);
|
||||
range(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=- MISSING: range=>=1
|
||||
range((double)(c + i + uc + x + y + z)); // $ overflow=+ overflow=+- overflow=- MISSING: range=>=1
|
||||
return (double)(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=-
|
||||
}
|
||||
|
||||
// Regression test for ODASA-6013.
|
||||
@@ -213,8 +213,8 @@ int test14(int x) {
|
||||
range(c0);
|
||||
unsigned short s0 = x;
|
||||
range(s0);
|
||||
range(x0 + x1 + x2 + x3 + c0 + s0);
|
||||
return x0 + x1 + x2 + x3 + c0 + s0;
|
||||
range(x0 + x1 + x2 + x3 + c0 + s0); // $ overflow=+ overflow=+-
|
||||
return x0 + x1 + x2 + x3 + c0 + s0; // $ overflow=+ overflow=+-
|
||||
}
|
||||
|
||||
long long test15(long long x) {
|
||||
@@ -243,7 +243,7 @@ int test_unary(int a) {
|
||||
range(b); // $ range=<=11 range=>=0
|
||||
int c = -a;
|
||||
range(c); // $ range=<=0 range=>=-11
|
||||
range(b+c); // $ range=<=11 range=>=-11
|
||||
range(b+c); // $ range=<=11 range=>=-11 MISSING:range=">=- ...+0"
|
||||
total += b+c;
|
||||
range(total); // $ range=<=0+11 range=<=19 range=>=0-11 range=>=-19
|
||||
}
|
||||
@@ -273,7 +273,7 @@ int test_unary(int a) {
|
||||
range(b); // $ range=<=0 range=>=-7
|
||||
int c = -a;
|
||||
range(c); // $ range=<=7 range=>=0
|
||||
range(b+c); // $ range=>=-7 range=<=7
|
||||
range(b+c); // $ range=>=-7 range=<=7 MISSING:range="<=- ...+0"
|
||||
total += b+c;
|
||||
range(total); // $ range="<=- ...+7" range="<=- ...+15" range="<=- ...+33" range=">=- ...-7" range=">=- ...-15" range=">=- ...-33" range=<=0+44 range=<=52 range=>=0-44 range=>=-52
|
||||
}
|
||||
@@ -315,9 +315,9 @@ int test_mult01(int a, int b) {
|
||||
if (3 <= a && a <= 11 && -13 <= b && b <= 23) {
|
||||
range(a); // $ range=<=11 range=>=3
|
||||
range(b); // $ range=<=23 range=>=-13
|
||||
int r = a*b; // -143 .. 253
|
||||
int r = a*b; // $ overflow=+- -143 .. 253
|
||||
range(r);
|
||||
total += r;
|
||||
total += r; // $ overflow=+
|
||||
range(total); // $ MISSING: range=">=... * ...+0"
|
||||
}
|
||||
if (3 <= a && a <= 11 && -13 <= b && b <= 0) {
|
||||
@@ -326,7 +326,7 @@ int test_mult01(int a, int b) {
|
||||
int r = a*b; // -143 .. 0
|
||||
range(r); // $ range=<=0 range=>=-143
|
||||
total += r;
|
||||
range(total); // $ range=<=3+0 range=>=3-143
|
||||
range(total); // $ range=>=3-143
|
||||
}
|
||||
if (3 <= a && a <= 11 && -13 <= b && b <= -7) {
|
||||
range(a); // $ range=<=11 range=>=3
|
||||
@@ -334,9 +334,9 @@ int test_mult01(int a, int b) {
|
||||
int r = a*b; // -143 .. -21
|
||||
range(r); // $ range=<=-21 range=>=-143
|
||||
total += r;
|
||||
range(total); // $ range=<=3-21 range=>=3-143 range=>=3-286
|
||||
range(total); // $ range=>=3-143 range=>=3-286
|
||||
}
|
||||
range(total); // $ range=<=3+0 range=>=3-143 range=>=3-286
|
||||
range(total); // $ range=>=3-143 range=>=3-286
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -363,9 +363,9 @@ int test_mult02(int a, int b) {
|
||||
if (0 <= a && a <= 11 && -13 <= b && b <= 23) {
|
||||
range(a); // $ range=<=11 range=>=0
|
||||
range(b); // $ range=<=23 range=>=-13
|
||||
int r = a*b; // -143 .. 253
|
||||
int r = a*b; // $ overflow=+- -143 .. 253
|
||||
range(r);
|
||||
total += r;
|
||||
total += r; // $ overflow=+
|
||||
range(total); // $ MISSING: range=">=... * ...+0"
|
||||
}
|
||||
if (0 <= a && a <= 11 && -13 <= b && b <= 0) {
|
||||
@@ -374,7 +374,7 @@ int test_mult02(int a, int b) {
|
||||
int r = a*b; // -143 .. 0
|
||||
range(r); // $ range=<=0 range=>=-143
|
||||
total += r;
|
||||
range(total); // $ range=<=0+0 range=>=0-143
|
||||
range(total); // $ range=>=0-143
|
||||
}
|
||||
if (0 <= a && a <= 11 && -13 <= b && b <= -7) {
|
||||
range(a); // $ range=<=11 range=>=0
|
||||
@@ -382,9 +382,9 @@ int test_mult02(int a, int b) {
|
||||
int r = a*b; // -143 .. 0
|
||||
range(r); // $ range=<=0 range=>=-143
|
||||
total += r;
|
||||
range(total); // $ range=<=0+0 range=>=0-143 range=>=0-286
|
||||
range(total); // $ range=>=0-143 range=>=0-286
|
||||
}
|
||||
range(total); // $ range=<=0+0 range=>=0-143 range=>=0-286
|
||||
range(total); // $range=>=0-143 range=>=0-286
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -395,7 +395,7 @@ int test_mult03(int a, int b) {
|
||||
if (-17 <= a && a <= 11 && 5 <= b && b <= 23) {
|
||||
range(a); // $ range=<=11 range=>=-17
|
||||
range(b); // $ range=<=23 range=>=5
|
||||
int r = a*b; // -391 .. 253
|
||||
int r = a*b; // $ overflow=+- -391 .. 253
|
||||
range(r);
|
||||
total += r;
|
||||
range(total);
|
||||
@@ -403,33 +403,33 @@ int test_mult03(int a, int b) {
|
||||
if (-17 <= a && a <= 11 && 0 <= b && b <= 23) {
|
||||
range(a); // $ range=<=11 range=>=-17
|
||||
range(b); // $ range=<=23 range=>=0
|
||||
int r = a*b; // -391 .. 253
|
||||
int r = a*b; // $ overflow=+- -391 .. 253
|
||||
range(r);
|
||||
total += r;
|
||||
total += r; // $ overflow=+-
|
||||
range(total);
|
||||
}
|
||||
if (-17 <= a && a <= 11 && -13 <= b && b <= 23) {
|
||||
range(a); // $ range=<=11 range=>=-17
|
||||
range(b); // $ range=<=23 range=>=-13
|
||||
int r = a*b; // -391 .. 253
|
||||
int r = a*b; // $ overflow=+- -391 .. 25
|
||||
range(r);
|
||||
total += r;
|
||||
total += r; // $ overflow=+-
|
||||
range(total);
|
||||
}
|
||||
if (-17 <= a && a <= 11 && -13 <= b && b <= 0) {
|
||||
range(a); // $ range=<=11 range=>=-17
|
||||
range(b); // $ range=<=0 range=>=-13
|
||||
int r = a*b; // -143 .. 221
|
||||
int r = a*b; // $ overflow=+- -143 .. 221
|
||||
range(r);
|
||||
total += r;
|
||||
total += r; // $ overflow=+-
|
||||
range(total);
|
||||
}
|
||||
if (-17 <= a && a <= 11 && -13 <= b && b <= -7) {
|
||||
range(a); // $ range=<=11 range=>=-17
|
||||
range(b); // $ range=<=-7 range=>=-13
|
||||
int r = a*b; // -143 .. 221
|
||||
int r = a*b; // $ overflow=+- -143 .. 221
|
||||
range(r);
|
||||
total += r;
|
||||
total += r; // $ overflow=+-
|
||||
range(total);
|
||||
}
|
||||
range(total);
|
||||
@@ -458,9 +458,9 @@ int test_mult04(int a, int b) {
|
||||
if (-17 <= a && a <= 0 && -13 <= b && b <= 23) {
|
||||
range(a); // $ range=<=0 range=>=-17
|
||||
range(b); // $ range=<=23 range=>=-13
|
||||
int r = a*b; // -391 .. 221
|
||||
int r = a*b; // $ overflow=+- -391 .. 221
|
||||
range(r);
|
||||
total += r;
|
||||
total += r; // $ overflow=-
|
||||
range(total); // $ MISSING: range="<=... * ...+0"
|
||||
}
|
||||
if (-17 <= a && a <= 0 && -13 <= b && b <= 0) {
|
||||
@@ -469,7 +469,7 @@ int test_mult04(int a, int b) {
|
||||
int r = a*b; // 0 .. 221
|
||||
range(r); // $ range=<=221 range=>=0
|
||||
total += r;
|
||||
range(total); // $ range="<=- ...+221" range=">=- ...+0"
|
||||
range(total); // $ range="<=- ...+221"
|
||||
}
|
||||
if (-17 <= a && a <= 0 && -13 <= b && b <= -7) {
|
||||
range(a); // $ range=<=0 range=>=-17
|
||||
@@ -477,9 +477,9 @@ int test_mult04(int a, int b) {
|
||||
int r = a*b; // 0 .. 221
|
||||
range(r); // $ range=<=221 range=>=0
|
||||
total += r;
|
||||
range(total); // $ range=">=- ...+0" range="<=- ...+221" range="<=- ...+442"
|
||||
range(total); // $ range="<=- ...+221" range="<=- ...+442"
|
||||
}
|
||||
range(total); // $ range=">=- ...+0" range="<=- ...+221" range="<=- ...+442"
|
||||
range(total); // $ range="<=- ...+221" range="<=- ...+442"
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -506,9 +506,9 @@ int test_mult05(int a, int b) {
|
||||
if (-17 <= a && a <= -2 && -13 <= b && b <= 23) {
|
||||
range(a); // $ range=<=-2 range=>=-17
|
||||
range(b); // $ range=<=23 range=>=-13
|
||||
int r = a*b; // -391 .. 221
|
||||
int r = a*b; // $ overflow=+- -391 .. 221
|
||||
range(r);
|
||||
total += r;
|
||||
total += r; // $ overflow=-
|
||||
range(total); // $ MISSING: range="<=... * ...+0"
|
||||
}
|
||||
if (-17 <= a && a <= -2 && -13 <= b && b <= 0) {
|
||||
@@ -517,7 +517,7 @@ int test_mult05(int a, int b) {
|
||||
int r = a*b; // 0 .. 221
|
||||
range(r); // $ range=<=221 range=>=0
|
||||
total += r;
|
||||
range(total); // $ range="<=- ...+221" range=">=- ...+0"
|
||||
range(total); // $ range="<=- ...+221"
|
||||
}
|
||||
if (-17 <= a && a <= -2 && -13 <= b && b <= -7) {
|
||||
range(a); // $ range=<=-2 range=>=-17
|
||||
@@ -525,9 +525,9 @@ int test_mult05(int a, int b) {
|
||||
int r = a*b; // 14 .. 221
|
||||
range(r); // $ range=<=221 range=>=14
|
||||
total += r;
|
||||
range(total); // $ range="<=- ...+221" range="<=- ...+442" range=">=- ...+14"
|
||||
range(total); // $ range="<=- ...+221" range="<=- ...+442"
|
||||
}
|
||||
range(total); // $ range=">=- ...+0" range="<=- ...+221" range="<=- ...+442"
|
||||
range(total); // $ range="<=- ...+221" range="<=- ...+442"
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -541,7 +541,7 @@ int test16(int x) {
|
||||
while (i < 3) {
|
||||
range(i); // $ range=<=2 range=>=0
|
||||
i++;
|
||||
range(i); // $ range="==... = ...:i+1" range=<=3 range=>=1
|
||||
range(i); // $ range=<=3 range=>=1 range="==... = ...:i+1" SPURIOUS:range="==... = ...:i+1"
|
||||
}
|
||||
range(d);
|
||||
d = i;
|
||||
@@ -586,7 +586,7 @@ unsigned int test_ternary01(unsigned int x) {
|
||||
(range(x), 500);
|
||||
range(y4); // $ range=<=500
|
||||
y5 = (x+1) ?:
|
||||
(range(x), 500); // $ range===-1
|
||||
(range(x), 500); // $ overflow=- range===-1
|
||||
range(y5); // $ range=<=500
|
||||
y6 = ((unsigned char)(x+1)) ?:
|
||||
(range(x), 5); // $ range=<=299
|
||||
@@ -598,8 +598,8 @@ unsigned int test_ternary01(unsigned int x) {
|
||||
(range(x), 500); // $ range=<=299
|
||||
range(y8); // y8 <= 300
|
||||
}
|
||||
range(y1 + y2 + y3 + y4 + y5 + y6 + y7 + y8); // $ MISSING: range=">=... = ...:... ? ... : ...+0" range=">=call to range+0"
|
||||
return y1 + y2 + y3 + y4 + y5 + y6 + y7 + y8;
|
||||
range(y1 + y2 + y3 + y4 + y5 + y6 + y7 + y8); // $ overflow=+ MISSING: range=">=... = ...:... ? ... : ...+0" range=">=call to range+0"
|
||||
return y1 + y2 + y3 + y4 + y5 + y6 + y7 + y8; // $ overflow=+
|
||||
}
|
||||
|
||||
// Test ternary expression lower bounds.
|
||||
@@ -628,8 +628,8 @@ unsigned int test_ternary02(unsigned int x) {
|
||||
(range(x), 5); // $ range=>=300
|
||||
range(y5); // y6 >= 0
|
||||
}
|
||||
range(y1 + y2 + y3 + y4 + y5); // $ range=">=call to range+207" MISSING: range=">=... = ...:... ? ... : ...+0" range=">=call to range+0"
|
||||
return y1 + y2 + y3 + y4 + y5;
|
||||
range(y1 + y2 + y3 + y4 + y5); // $ overflow=+ MISSING: range=">=call to range+207" range=">=... = ...:... ? ... : ...+0" range=">=call to range+0"
|
||||
return y1 + y2 + y3 + y4 + y5; // $ overflow=+
|
||||
}
|
||||
|
||||
// Test the comma expression.
|
||||
@@ -691,9 +691,9 @@ int test_unsigned_mult01(unsigned int a, unsigned b) {
|
||||
range(a); // $ range=<=11 range=>=3
|
||||
range(b); // $ range=<=23 range=>=0
|
||||
int r = a*b; // 0 .. 253
|
||||
range(r); // $ range=>=0 range=<=253
|
||||
range(r);// $ range=>=0 range=<=253
|
||||
total += r;
|
||||
range(total); // $ range=>=0 range=<=506 range=">=(unsigned int)...+0" range="<=(unsigned int)...+253"
|
||||
range(total); // $ range=">=(unsigned int)...+0" range=>=0 range=<=506 range="<=(unsigned int)...+253"
|
||||
}
|
||||
if (3 <= a && a <= 11 && 13 <= b && b <= 23) {
|
||||
range(a); // $ range=<=11 range=>=3
|
||||
@@ -701,7 +701,7 @@ int test_unsigned_mult01(unsigned int a, unsigned b) {
|
||||
int r = a*b; // 39 .. 253
|
||||
range(r); // $ range=>=39 range=<=253
|
||||
total += r;
|
||||
range(total); // $ range=>=39 range=<=759 range=">=(unsigned int)...+39" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
|
||||
range(total); // $ range=>=39 range=<=759 range="<=(unsigned int)...+253" range="<=(unsigned int)...+506" range=">=(unsigned int)...+39"
|
||||
}
|
||||
range(total); // $ range=>=0 range=<=759 range=">=(unsigned int)...+0" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
|
||||
return total;
|
||||
@@ -722,14 +722,14 @@ int test_unsigned_mult02(unsigned b) {
|
||||
int r = 11*b; // 0 .. 253
|
||||
range(r); // $ range=>=0 range=<=253
|
||||
total += r;
|
||||
range(total); // $ range=>=0 range=<=506 range=">=(unsigned int)...+0" range="<=(unsigned int)...+253"
|
||||
range(total); // $ range=">=(unsigned int)...+0" range=>=0 range="<=(unsigned int)...+253" range=<=506
|
||||
}
|
||||
if (13 <= b && b <= 23) {
|
||||
range(b); // $ range=<=23 range=>=13
|
||||
int r = 11*b; // 143 .. 253
|
||||
range(r); // $ range=>=143 range=<=253
|
||||
total += r;
|
||||
range(total); // $ range=>=143 range=<=759 range=">=(unsigned int)...+143" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
|
||||
range(total); // $ range="<=(unsigned int)...+253" range="<=(unsigned int)...+506" range=">=(unsigned int)...+143" range=>=143 range=<=759
|
||||
}
|
||||
range(total); // $ range=>=0 range=<=759 range=">=(unsigned int)...+0" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
|
||||
return total;
|
||||
@@ -751,7 +751,7 @@ unsigned long mult_overflow() {
|
||||
range(x); // $ range===274177
|
||||
y = 67280421310721UL;
|
||||
range(y);
|
||||
xy = x * y;
|
||||
xy = x * y; // $ overflow=+-
|
||||
range(xy);
|
||||
return xy; // BUG: upper bound should be >= 18446744073709551617UL
|
||||
}
|
||||
@@ -760,14 +760,14 @@ unsigned long mult_lower_bound(unsigned int ui, unsigned long ul) {
|
||||
if (ui >= 10) {
|
||||
range(ui); // $ range=>=10
|
||||
range((unsigned long)ui); // $ range=>=10
|
||||
unsigned long result = (unsigned long)ui * ui;
|
||||
range(result); // $ range=>=100 range=>=100
|
||||
unsigned long result = (unsigned long)ui * ui; // $ overflow=+
|
||||
range(result); // $ MISSING: range=>=100
|
||||
return result; // BUG: upper bound should be >= 18446744065119617025
|
||||
}
|
||||
if (ul >= 10) {
|
||||
range(ul); // $ range=>=10
|
||||
unsigned long result = ul * ul;
|
||||
range(result); // $ range=>=100
|
||||
unsigned long result = ul * ul; // $ overflow=+
|
||||
range(result); // $ MISSING: range=>=100
|
||||
return result; // BUG: lower bound should be 0 (overflow is possible)
|
||||
}
|
||||
return 0;
|
||||
@@ -800,13 +800,13 @@ int mul_by_constant(int i, int j) {
|
||||
i = 5 * i;
|
||||
range(i); // $ range=<=10 range=>=-5
|
||||
|
||||
i = i * -3;
|
||||
i = i * -3; // $ overflow=+-
|
||||
range(i); // -30 .. 15
|
||||
|
||||
i *= 7;
|
||||
i *= 7; // $ overflow=+-
|
||||
range(i); // -210 .. 105
|
||||
|
||||
i *= -11;
|
||||
i *= -11; // $ overflow=+-
|
||||
range(i); // -1155 .. 2310
|
||||
}
|
||||
if (i == -1) {
|
||||
@@ -815,7 +815,7 @@ int mul_by_constant(int i, int j) {
|
||||
i = i * (int)0xffFFffFF; // fully converted literal is -1
|
||||
range(i); // $ range===1
|
||||
}
|
||||
i = i * -1;
|
||||
i = i * -1; // $ overflow=+-
|
||||
range( i); // -2^31 .. 2^31-1
|
||||
|
||||
signed char sc = 1;
|
||||
@@ -873,11 +873,11 @@ void notequal_refinement(short n) {
|
||||
}
|
||||
|
||||
while (n != 0) {
|
||||
range(n); // $ range=<=n+0
|
||||
range(n); // $ MISSING:range=<=n+0
|
||||
n--; // 1 ..
|
||||
}
|
||||
|
||||
range(n); // $ range=<=n+0 // 0 .. 0
|
||||
range(n); // $ MISSING:range=<=n+0 // 0 .. 0
|
||||
}
|
||||
|
||||
void notequal_variations(short n, float f) {
|
||||
@@ -888,7 +888,7 @@ void notequal_variations(short n, float f) {
|
||||
}
|
||||
|
||||
if (n >= 5) {
|
||||
if (2 * n - 10 == 0) { // Same as `n == 10/2` (modulo overflow)
|
||||
if (2 * n - 10 == 0) { // $ overflow=+
|
||||
range(n); // $ range=>=5 MISSING: range===5
|
||||
return;
|
||||
}
|
||||
@@ -921,7 +921,7 @@ void two_bounds_from_one_test(short ss, unsigned short us) {
|
||||
}
|
||||
|
||||
if (ss < 0x8001) { // Lower bound removed in `getDefLowerBounds`
|
||||
range(ss); // $ range=<=32768 MISSING: range=>=-32768
|
||||
range(ss); // $ overflow=+ range=<=32768 MISSING: range=>=-32768
|
||||
}
|
||||
|
||||
if ((short)us >= 0) {
|
||||
@@ -936,7 +936,7 @@ void two_bounds_from_one_test(short ss, unsigned short us) {
|
||||
range(ss); // -32768 .. 32767
|
||||
}
|
||||
|
||||
if (ss + 1 < sizeof(int)) {
|
||||
if (ss + 1 < sizeof(int)) { // $ overflow=+
|
||||
range(ss); // -1 .. 2
|
||||
}
|
||||
}
|
||||
@@ -1020,7 +1020,7 @@ void test_overflow() {
|
||||
|
||||
void test_negate_unsigned(unsigned u) {
|
||||
if(10 < u && u < 20) {
|
||||
range<unsigned>(-u); // underflows
|
||||
range<unsigned>(-u); // $ overflow=-
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
return x;
|
||||
}
|
||||
|
||||
if (y - 2 == x && y > 300) {
|
||||
if (y - 2 == x && y > 300) { // $ overflow=-
|
||||
range(x + y); // $ range=<=802 range=>=600
|
||||
return x + y;
|
||||
}
|
||||
|
||||
if (x != y + 1) {
|
||||
if (x != y + 1) { // $ overflow=+
|
||||
range(x); // $ range=<=400
|
||||
int sum = x + y;
|
||||
int sum = x + y; // $ overflow=+-
|
||||
} else {
|
||||
if (y > 300) {
|
||||
range(x); // $ range=>=302 range=<=400 range===y+1
|
||||
range(x); // $ range=>=302 range=<=400 range=<=y+1 MISSING: range===y+1
|
||||
range(y); // $ range=>=301 range=<=399 range===x-1
|
||||
int sum = x + y;
|
||||
}
|
||||
@@ -38,10 +38,10 @@
|
||||
return x;
|
||||
}
|
||||
|
||||
if (y == x - 1 && y > 300 && y + 2 == z && z == 350) {
|
||||
if (y == x - 1 && y > 300 && y + 2 == z && z == 350) { // $ overflow=+ overflow=-
|
||||
range(x); // $ range===349 range===y+1 range===z-1
|
||||
range(y); // $ range===348 range===x-1 range===z-2
|
||||
range(z); // $ range===350 range===x+1 range===y+2
|
||||
range(y); // $ range===348 range=>=x-1 range===z-2 MISSING: range===x-1
|
||||
range(z); // $ range===350 range=<=y+2 MISSING: range===x+1 range===y+2
|
||||
return x + y + z;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,13 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.SignAnalysis
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisSpecific
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
module SignAnalysisInstantiated = SignAnalysis<FloatDelta, RangeUtil<FloatDelta, CppLangImpl>>;
|
||||
module SignAnalysisInstantiated =
|
||||
SignAnalysis<FloatDelta, RangeUtil<FloatDelta, CppLangImplRelative>>;
|
||||
|
||||
class SignAnalysisTest extends InlineExpectationsTest {
|
||||
SignAnalysisTest() { this = "SignAnalysisTest" }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
| a1.c:6:16:6:16 | struct <unnamed> | 0 members | 2 locations | -1 | <none> |
|
||||
| a1.c:10:16:10:16 | struct <unnamed> | 1 members | 2 locations | 0 | x |
|
||||
| a1.c:17:16:17:16 | struct <unnamed> | 1 members | 2 locations | 0 | x |
|
||||
| a1.c:6:16:6:16 | (unnamed class/struct/union) | 0 members | 2 locations | -1 | <none> |
|
||||
| a1.c:10:16:10:16 | (unnamed class/struct/union) | 1 members | 2 locations | 0 | x |
|
||||
| a1.c:17:16:17:16 | (unnamed class/struct/union) | 1 members | 2 locations | 0 | x |
|
||||
| a1.c:24:8:24:10 | Foo | 3 members | 2 locations | 0 | empty |
|
||||
| a1.c:24:8:24:10 | Foo | 3 members | 2 locations | 1 | nonempty |
|
||||
| a1.c:24:8:24:10 | Foo | 3 members | 2 locations | 2 | i |
|
||||
@@ -9,9 +9,9 @@
|
||||
| a1.c:36:8:36:10 | Bar | 3 members | 2 locations | 0 | empty |
|
||||
| a1.c:36:8:36:10 | Bar | 3 members | 2 locations | 1 | nonempty |
|
||||
| a1.c:36:8:36:10 | Bar | 3 members | 2 locations | 2 | i |
|
||||
| a2.c:6:16:6:16 | struct <unnamed> | 0 members | 2 locations | -1 | <none> |
|
||||
| a2.c:10:16:10:16 | struct <unnamed> | 1 members | 2 locations | 0 | x |
|
||||
| a2.c:17:16:17:16 | struct <unnamed> | 1 members | 2 locations | 0 | x |
|
||||
| a2.c:6:16:6:16 | (unnamed class/struct/union) | 0 members | 2 locations | -1 | <none> |
|
||||
| a2.c:10:16:10:16 | (unnamed class/struct/union) | 1 members | 2 locations | 0 | x |
|
||||
| a2.c:17:16:17:16 | (unnamed class/struct/union) | 1 members | 2 locations | 0 | x |
|
||||
| a2.c:24:8:24:10 | Foo | 3 members | 2 locations | 0 | empty |
|
||||
| a2.c:24:8:24:10 | Foo | 3 members | 2 locations | 1 | nonempty |
|
||||
| a2.c:24:8:24:10 | Foo | 3 members | 2 locations | 2 | i |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
| a1.c:10:16:10:16 | struct <unnamed> | 0 | file://:0:0:0:0 | int | 1 types |
|
||||
| a1.c:17:16:17:16 | struct <unnamed> | 0 | file://:0:0:0:0 | int | 1 types |
|
||||
| a1.c:10:16:10:16 | (unnamed class/struct/union) | 0 | file://:0:0:0:0 | int | 1 types |
|
||||
| a1.c:17:16:17:16 | (unnamed class/struct/union) | 0 | file://:0:0:0:0 | int | 1 types |
|
||||
| a1.c:24:8:24:10 | Foo | 0 | file://:0:0:0:0 | anon_empty_t * | 1 types |
|
||||
| a1.c:24:8:24:10 | Foo | 1 | file://:0:0:0:0 | anon_nonempty_t * | 1 types |
|
||||
| a1.c:24:8:24:10 | Foo | 2 | file://:0:0:0:0 | int | 1 types |
|
||||
@@ -7,8 +7,8 @@
|
||||
| a1.c:36:8:36:10 | Bar | 0 | file://:0:0:0:0 | Empty * | 1 types |
|
||||
| a1.c:36:8:36:10 | Bar | 1 | file://:0:0:0:0 | NonEmpty * | 1 types |
|
||||
| a1.c:36:8:36:10 | Bar | 2 | file://:0:0:0:0 | int | 1 types |
|
||||
| a2.c:10:16:10:16 | struct <unnamed> | 0 | file://:0:0:0:0 | int | 1 types |
|
||||
| a2.c:17:16:17:16 | struct <unnamed> | 0 | file://:0:0:0:0 | int | 1 types |
|
||||
| a2.c:10:16:10:16 | (unnamed class/struct/union) | 0 | file://:0:0:0:0 | int | 1 types |
|
||||
| a2.c:17:16:17:16 | (unnamed class/struct/union) | 0 | file://:0:0:0:0 | int | 1 types |
|
||||
| a2.c:24:8:24:10 | Foo | 0 | file://:0:0:0:0 | anon_empty_t * | 1 types |
|
||||
| a2.c:24:8:24:10 | Foo | 1 | file://:0:0:0:0 | anon_nonempty_t * | 1 types |
|
||||
| a2.c:24:8:24:10 | Foo | 2 | file://:0:0:0:0 | int | 1 types |
|
||||
|
||||
@@ -233,3 +233,14 @@ void f_if_ternary_1(int b, int x, int y) {
|
||||
if (b ? x : y) {
|
||||
}
|
||||
}
|
||||
|
||||
struct _A
|
||||
{
|
||||
unsigned int x;
|
||||
const char *y;
|
||||
} as[];
|
||||
|
||||
void regression_test(void)
|
||||
{
|
||||
static const void *a[] = {0 ? 0 : as};
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<queries language="cpp"/>
|
||||
@@ -0,0 +1,96 @@
|
||||
edges
|
||||
| test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a |
|
||||
| test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a |
|
||||
| test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a |
|
||||
| test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a |
|
||||
| test_free.cpp:30:10:30:10 | a | test_free.cpp:31:27:31:27 | a |
|
||||
| test_free.cpp:35:10:35:10 | a | test_free.cpp:37:27:37:27 | a |
|
||||
| test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||
| test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||
| test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||
| test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||
| test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||
| test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||
| test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||
| test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||
| test_free.cpp:50:27:50:27 | a | test_free.cpp:51:10:51:10 | a |
|
||||
| test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a |
|
||||
| test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a |
|
||||
| test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a |
|
||||
| test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a |
|
||||
| test_free.cpp:101:10:101:10 | a | test_free.cpp:103:10:103:10 | a |
|
||||
| test_free.cpp:128:10:128:11 | * ... | test_free.cpp:129:10:129:11 | * ... |
|
||||
| test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a |
|
||||
| test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a |
|
||||
| test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a |
|
||||
| test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a |
|
||||
| test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a |
|
||||
| test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a |
|
||||
| test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a |
|
||||
| test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a |
|
||||
nodes
|
||||
| test_free.cpp:11:10:11:10 | a | semmle.label | a |
|
||||
| test_free.cpp:11:10:11:10 | a | semmle.label | a |
|
||||
| test_free.cpp:14:10:14:10 | a | semmle.label | a |
|
||||
| test_free.cpp:14:10:14:10 | a | semmle.label | a |
|
||||
| test_free.cpp:30:10:30:10 | a | semmle.label | a |
|
||||
| test_free.cpp:31:27:31:27 | a | semmle.label | a |
|
||||
| test_free.cpp:35:10:35:10 | a | semmle.label | a |
|
||||
| test_free.cpp:37:27:37:27 | a | semmle.label | a |
|
||||
| test_free.cpp:42:27:42:27 | a | semmle.label | a |
|
||||
| test_free.cpp:42:27:42:27 | a | semmle.label | a |
|
||||
| test_free.cpp:44:27:44:27 | a | semmle.label | a |
|
||||
| test_free.cpp:44:27:44:27 | a | semmle.label | a |
|
||||
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
|
||||
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
|
||||
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
|
||||
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
|
||||
| test_free.cpp:50:27:50:27 | a | semmle.label | a |
|
||||
| test_free.cpp:51:10:51:10 | a | semmle.label | a |
|
||||
| test_free.cpp:69:10:69:10 | a | semmle.label | a |
|
||||
| test_free.cpp:69:10:69:10 | a | semmle.label | a |
|
||||
| test_free.cpp:72:14:72:14 | a | semmle.label | a |
|
||||
| test_free.cpp:72:14:72:14 | a | semmle.label | a |
|
||||
| test_free.cpp:101:10:101:10 | a | semmle.label | a |
|
||||
| test_free.cpp:103:10:103:10 | a | semmle.label | a |
|
||||
| test_free.cpp:128:10:128:11 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:129:10:129:11 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:152:27:152:27 | a | semmle.label | a |
|
||||
| test_free.cpp:152:27:152:27 | a | semmle.label | a |
|
||||
| test_free.cpp:154:10:154:10 | a | semmle.label | a |
|
||||
| test_free.cpp:154:10:154:10 | a | semmle.label | a |
|
||||
| test_free.cpp:207:10:207:10 | a | semmle.label | a |
|
||||
| test_free.cpp:207:10:207:10 | a | semmle.label | a |
|
||||
| test_free.cpp:209:10:209:10 | a | semmle.label | a |
|
||||
| test_free.cpp:209:10:209:10 | a | semmle.label | a |
|
||||
subpaths
|
||||
#select
|
||||
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
| test_free.cpp:31:27:31:27 | a | test_free.cpp:30:10:30:10 | a | test_free.cpp:31:27:31:27 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:30:5:30:8 | call to free | call to free |
|
||||
| test_free.cpp:37:27:37:27 | a | test_free.cpp:35:10:35:10 | a | test_free.cpp:37:27:37:27 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:35:5:35:8 | call to free | call to free |
|
||||
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
|
||||
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
|
||||
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
|
||||
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
|
||||
| test_free.cpp:51:10:51:10 | a | test_free.cpp:50:27:50:27 | a | test_free.cpp:51:10:51:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:50:22:50:25 | call to free | call to free |
|
||||
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
|
||||
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
|
||||
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
|
||||
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
|
||||
| test_free.cpp:103:10:103:10 | a | test_free.cpp:101:10:101:10 | a | test_free.cpp:103:10:103:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:101:5:101:8 | call to free | call to free |
|
||||
| test_free.cpp:129:10:129:11 | * ... | test_free.cpp:128:10:128:11 | * ... | test_free.cpp:129:10:129:11 | * ... | Memory pointed to by '* ...' may already have been freed by $@. | test_free.cpp:128:5:128:8 | call to free | call to free |
|
||||
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |
|
||||
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |
|
||||
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |
|
||||
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |
|
||||
@@ -0,0 +1 @@
|
||||
Critical/DoubleFree.ql
|
||||
@@ -26,6 +26,72 @@
|
||||
| test.cpp:128:15:128:16 | v4 |
|
||||
| test.cpp:185:10:185:12 | cpy |
|
||||
| test.cpp:199:10:199:12 | cpy |
|
||||
| test_free.cpp:11:10:11:10 | a |
|
||||
| test_free.cpp:14:10:14:10 | a |
|
||||
| test_free.cpp:16:10:16:10 | a |
|
||||
| test_free.cpp:18:18:18:18 | a |
|
||||
| test_free.cpp:23:10:23:10 | a |
|
||||
| test_free.cpp:25:10:25:10 | a |
|
||||
| test_free.cpp:26:10:26:10 | b |
|
||||
| test_free.cpp:30:10:30:10 | a |
|
||||
| test_free.cpp:31:27:31:27 | a |
|
||||
| test_free.cpp:35:10:35:10 | a |
|
||||
| test_free.cpp:37:27:37:27 | a |
|
||||
| test_free.cpp:42:27:42:27 | a |
|
||||
| test_free.cpp:44:27:44:27 | a |
|
||||
| test_free.cpp:46:10:46:10 | a |
|
||||
| test_free.cpp:50:27:50:27 | a |
|
||||
| test_free.cpp:51:10:51:10 | a |
|
||||
| test_free.cpp:55:27:55:27 | a |
|
||||
| test_free.cpp:57:10:57:10 | a |
|
||||
| test_free.cpp:61:10:61:10 | a |
|
||||
| test_free.cpp:63:10:63:10 | b |
|
||||
| test_free.cpp:69:10:69:10 | a |
|
||||
| test_free.cpp:72:14:72:14 | a |
|
||||
| test_free.cpp:83:12:83:12 | a |
|
||||
| test_free.cpp:85:12:85:12 | a |
|
||||
| test_free.cpp:90:10:90:10 | a |
|
||||
| test_free.cpp:95:10:95:10 | a |
|
||||
| test_free.cpp:101:10:101:10 | a |
|
||||
| test_free.cpp:102:23:102:23 | a |
|
||||
| test_free.cpp:103:10:103:10 | a |
|
||||
| test_free.cpp:104:10:104:10 | b |
|
||||
| test_free.cpp:107:23:107:23 | a |
|
||||
| test_free.cpp:112:14:112:14 | a |
|
||||
| test_free.cpp:114:10:114:10 | b |
|
||||
| test_free.cpp:118:23:118:23 | a |
|
||||
| test_free.cpp:119:17:119:17 | b |
|
||||
| test_free.cpp:121:14:121:14 | a |
|
||||
| test_free.cpp:126:10:126:11 | * ... |
|
||||
| test_free.cpp:128:10:128:11 | * ... |
|
||||
| test_free.cpp:129:10:129:11 | * ... |
|
||||
| test_free.cpp:131:10:131:13 | access to array |
|
||||
| test_free.cpp:132:10:132:13 | access to array |
|
||||
| test_free.cpp:143:27:143:30 | data |
|
||||
| test_free.cpp:145:14:145:22 | * ... |
|
||||
| test_free.cpp:148:10:148:17 | list_ptr |
|
||||
| test_free.cpp:152:27:152:27 | a |
|
||||
| test_free.cpp:154:10:154:10 | a |
|
||||
| test_free.cpp:159:14:159:15 | * ... |
|
||||
| test_free.cpp:162:10:162:10 | a |
|
||||
| test_free.cpp:167:23:167:23 | a |
|
||||
| test_free.cpp:173:10:173:10 | a |
|
||||
| test_free.cpp:181:10:181:10 | a |
|
||||
| test_free.cpp:183:10:183:10 | a |
|
||||
| test_free.cpp:185:10:185:10 | a |
|
||||
| test_free.cpp:188:10:188:10 | a |
|
||||
| test_free.cpp:193:20:193:20 | a |
|
||||
| test_free.cpp:199:20:199:20 | a |
|
||||
| test_free.cpp:205:10:205:10 | a |
|
||||
| test_free.cpp:207:10:207:10 | a |
|
||||
| test_free.cpp:209:10:209:10 | a |
|
||||
| test_free.cpp:213:10:213:10 | a |
|
||||
| test_free.cpp:216:10:216:10 | a |
|
||||
| test_free.cpp:220:10:220:10 | a |
|
||||
| test_free.cpp:227:24:227:45 | memory_descriptor_list |
|
||||
| test_free.cpp:233:14:233:15 | * ... |
|
||||
| test_free.cpp:239:14:239:15 | * ... |
|
||||
| test_free.cpp:245:10:245:11 | * ... |
|
||||
| virtual.cpp:18:10:18:10 | a |
|
||||
| virtual.cpp:19:10:19:10 | c |
|
||||
| virtual.cpp:38:10:38:10 | b |
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
| test_free.cpp:36:22:36:35 | ... = ... | This memory allocation may not be released at $@. | test_free.cpp:38:1:38:1 | return ... | this exit point |
|
||||
|
||||
@@ -11,3 +11,4 @@
|
||||
| test.cpp:156:3:156:26 | new | This memory is never freed. |
|
||||
| test.cpp:157:3:157:26 | new[] | This memory is never freed. |
|
||||
| test.cpp:169:14:169:19 | call to strdup | This memory is never freed. |
|
||||
| test_free.cpp:167:15:167:21 | call to realloc | This memory is never freed. |
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
edges
|
||||
| test_free.cpp:11:10:11:10 | a | test_free.cpp:12:5:12:5 | a |
|
||||
| test_free.cpp:11:10:11:10 | a | test_free.cpp:12:5:12:5 | a |
|
||||
| test_free.cpp:11:10:11:10 | a | test_free.cpp:13:6:13:6 | a |
|
||||
| test_free.cpp:11:10:11:10 | a | test_free.cpp:13:6:13:6 | a |
|
||||
| test_free.cpp:42:27:42:27 | a | test_free.cpp:45:5:45:5 | a |
|
||||
| test_free.cpp:42:27:42:27 | a | test_free.cpp:45:5:45:5 | a |
|
||||
| test_free.cpp:44:27:44:27 | a | test_free.cpp:45:5:45:5 | a |
|
||||
| test_free.cpp:44:27:44:27 | a | test_free.cpp:45:5:45:5 | a |
|
||||
| test_free.cpp:69:10:69:10 | a | test_free.cpp:71:9:71:9 | a |
|
||||
| test_free.cpp:69:10:69:10 | a | test_free.cpp:71:9:71:9 | a |
|
||||
| test_free.cpp:90:10:90:10 | a | test_free.cpp:91:5:91:5 | a |
|
||||
| test_free.cpp:90:10:90:10 | a | test_free.cpp:91:5:91:5 | a |
|
||||
| test_free.cpp:95:10:95:10 | a | test_free.cpp:96:9:96:9 | a |
|
||||
| test_free.cpp:101:10:101:10 | a | test_free.cpp:102:23:102:23 | a |
|
||||
| test_free.cpp:152:27:152:27 | a | test_free.cpp:153:5:153:5 | a |
|
||||
| test_free.cpp:152:27:152:27 | a | test_free.cpp:153:5:153:5 | a |
|
||||
| test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... |
|
||||
| test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... |
|
||||
| test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... |
|
||||
| test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... |
|
||||
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
|
||||
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
|
||||
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
|
||||
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... |
|
||||
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b |
|
||||
| test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b |
|
||||
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
|
||||
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
|
||||
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
|
||||
| test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... |
|
||||
nodes
|
||||
| test_free.cpp:11:10:11:10 | a | semmle.label | a |
|
||||
| test_free.cpp:11:10:11:10 | a | semmle.label | a |
|
||||
| test_free.cpp:12:5:12:5 | a | semmle.label | a |
|
||||
| test_free.cpp:13:6:13:6 | a | semmle.label | a |
|
||||
| test_free.cpp:42:27:42:27 | a | semmle.label | a |
|
||||
| test_free.cpp:42:27:42:27 | a | semmle.label | a |
|
||||
| test_free.cpp:44:27:44:27 | a | semmle.label | a |
|
||||
| test_free.cpp:44:27:44:27 | a | semmle.label | a |
|
||||
| test_free.cpp:45:5:45:5 | a | semmle.label | a |
|
||||
| test_free.cpp:45:5:45:5 | a | semmle.label | a |
|
||||
| test_free.cpp:69:10:69:10 | a | semmle.label | a |
|
||||
| test_free.cpp:69:10:69:10 | a | semmle.label | a |
|
||||
| test_free.cpp:71:9:71:9 | a | semmle.label | a |
|
||||
| test_free.cpp:90:10:90:10 | a | semmle.label | a |
|
||||
| test_free.cpp:90:10:90:10 | a | semmle.label | a |
|
||||
| test_free.cpp:91:5:91:5 | a | semmle.label | a |
|
||||
| test_free.cpp:95:10:95:10 | a | semmle.label | a |
|
||||
| test_free.cpp:96:9:96:9 | a | semmle.label | a |
|
||||
| test_free.cpp:101:10:101:10 | a | semmle.label | a |
|
||||
| test_free.cpp:102:23:102:23 | a | semmle.label | a |
|
||||
| test_free.cpp:152:27:152:27 | a | semmle.label | a |
|
||||
| test_free.cpp:152:27:152:27 | a | semmle.label | a |
|
||||
| test_free.cpp:153:5:153:5 | a | semmle.label | a |
|
||||
| test_free.cpp:233:14:233:15 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:233:14:233:15 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:236:9:236:10 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:236:9:236:10 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:239:14:239:15 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:239:14:239:15 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:241:9:241:10 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:241:9:241:10 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:241:10:241:10 | b | semmle.label | b |
|
||||
| test_free.cpp:245:10:245:11 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:245:10:245:11 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:246:9:246:10 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:246:9:246:10 | * ... | semmle.label | * ... |
|
||||
subpaths
|
||||
#select
|
||||
| test_free.cpp:12:5:12:5 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:12:5:12:5 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
| test_free.cpp:12:5:12:5 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:12:5:12:5 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
| test_free.cpp:13:6:13:6 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:13:6:13:6 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
| test_free.cpp:13:6:13:6 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:13:6:13:6 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
| test_free.cpp:45:5:45:5 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||
| test_free.cpp:45:5:45:5 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||
| test_free.cpp:45:5:45:5 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
|
||||
| test_free.cpp:45:5:45:5 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
|
||||
| test_free.cpp:71:9:71:9 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:71:9:71:9 | a | Memory may have been previously freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
|
||||
| test_free.cpp:71:9:71:9 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:71:9:71:9 | a | Memory may have been previously freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
|
||||
| test_free.cpp:91:5:91:5 | a | test_free.cpp:90:10:90:10 | a | test_free.cpp:91:5:91:5 | a | Memory may have been previously freed by $@. | test_free.cpp:90:5:90:8 | call to free | call to free |
|
||||
| test_free.cpp:91:5:91:5 | a | test_free.cpp:90:10:90:10 | a | test_free.cpp:91:5:91:5 | a | Memory may have been previously freed by $@. | test_free.cpp:90:5:90:8 | call to free | call to free |
|
||||
| test_free.cpp:96:9:96:9 | a | test_free.cpp:95:10:95:10 | a | test_free.cpp:96:9:96:9 | a | Memory may have been previously freed by $@. | test_free.cpp:95:5:95:8 | call to free | call to free |
|
||||
| test_free.cpp:102:23:102:23 | a | test_free.cpp:101:10:101:10 | a | test_free.cpp:102:23:102:23 | a | Memory may have been previously freed by $@. | test_free.cpp:101:5:101:8 | call to free | call to free |
|
||||
| test_free.cpp:153:5:153:5 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:153:5:153:5 | a | Memory may have been previously freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||
| test_free.cpp:153:5:153:5 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:153:5:153:5 | a | Memory may have been previously freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||
| test_free.cpp:236:9:236:10 | * ... | test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:233:9:233:12 | call to free | call to free |
|
||||
| test_free.cpp:236:9:236:10 | * ... | test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:233:9:233:12 | call to free | call to free |
|
||||
| test_free.cpp:236:9:236:10 | * ... | test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:233:9:233:12 | call to free | call to free |
|
||||
| test_free.cpp:236:9:236:10 | * ... | test_free.cpp:233:14:233:15 | * ... | test_free.cpp:236:9:236:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:233:9:233:12 | call to free | call to free |
|
||||
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
||||
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
||||
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
||||
| test_free.cpp:241:9:241:10 | * ... | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:9:241:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
||||
| test_free.cpp:241:10:241:10 | b | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
||||
| test_free.cpp:241:10:241:10 | b | test_free.cpp:239:14:239:15 | * ... | test_free.cpp:241:10:241:10 | b | Memory may have been previously freed by $@. | test_free.cpp:239:9:239:12 | call to free | call to free |
|
||||
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
|
||||
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
|
||||
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
|
||||
| test_free.cpp:246:9:246:10 | * ... | test_free.cpp:245:10:245:11 | * ... | test_free.cpp:246:9:246:10 | * ... | Memory may have been previously freed by $@. | test_free.cpp:245:5:245:8 | call to free | call to free |
|
||||
@@ -0,0 +1 @@
|
||||
Critical/UseAfterFree.ql
|
||||
247
cpp/ql/test/query-tests/Critical/MemoryFreed/test_free.cpp
Normal file
247
cpp/ql/test/query-tests/Critical/MemoryFreed/test_free.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
void *malloc(int);
|
||||
void free(void *);
|
||||
bool condition();
|
||||
void use(void*);
|
||||
void *realloc(void*, unsigned long);
|
||||
int strlen(char*);
|
||||
int asprintf(char ** strp, const char * fmt, ...);
|
||||
|
||||
|
||||
void* test_double_free1(int *a) {
|
||||
free(a); // GOOD
|
||||
a[5] = 5; // BAD
|
||||
*a = 5; // BAD
|
||||
free(a); // BAD
|
||||
a = (int*) malloc(8);
|
||||
free(a); // GOOD
|
||||
a = (int*) malloc(8);
|
||||
if (!a) free(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
void test_double_free_aliasing(void *a, void* b) {
|
||||
free(a); // GOOD
|
||||
a = b;
|
||||
free(a); // GOOD
|
||||
free(b); // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test_dominance1(void *a) {
|
||||
free(a);
|
||||
if (condition()) free(a); // BAD
|
||||
}
|
||||
|
||||
void test_dominance2(void *a) {
|
||||
free(a);
|
||||
if (condition()) a = malloc(10);
|
||||
if (condition()) free(a); // BAD
|
||||
}
|
||||
|
||||
void test_post_dominance1(int *a)
|
||||
{
|
||||
if (condition()) free(a);
|
||||
if (condition()) a[2] = 5; // BAD [NOT DETECTED]
|
||||
if (condition()) free(a); // BAD [NOT DETECTED]
|
||||
a[2] = 5; // BAD
|
||||
free(a); // BAD
|
||||
}
|
||||
|
||||
void test_post_dominance2(void *a) {
|
||||
if (condition()) free(a);
|
||||
free(a); // BAD
|
||||
}
|
||||
|
||||
void test_post_dominance3(void *a) {
|
||||
if (condition()) free(a);
|
||||
a = malloc(10);
|
||||
free(a); // GOOD
|
||||
}
|
||||
|
||||
void test_use_after_free6(int *a, int *b) {
|
||||
free(a);
|
||||
a=b;
|
||||
free(b);
|
||||
if (condition()) a[0] = 5; // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test_use_after_free7(int *a) {
|
||||
a[0] = 42;
|
||||
free(a);
|
||||
|
||||
if (a[3]) { // BAD
|
||||
free(a); // BAD
|
||||
}
|
||||
}
|
||||
|
||||
class A {
|
||||
public:
|
||||
void f();
|
||||
};
|
||||
|
||||
void test_new1() {
|
||||
A *a = new A();
|
||||
delete(a);
|
||||
a->f(); // BAD [NOT DETECTED]
|
||||
delete(a); // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test_dereference1(A *a) {
|
||||
a->f(); // GOOD
|
||||
free(a);
|
||||
a->f(); // BAD
|
||||
}
|
||||
|
||||
void* use_after_free(void *a) {
|
||||
free(a);
|
||||
use(a); // BAD
|
||||
return a; // BAD
|
||||
}
|
||||
|
||||
void test_realloc1(void *a) {
|
||||
free(a);
|
||||
void *b = realloc(a, sizeof(a)*3); // BAD [NOT DETECTED by cpp/double-free]
|
||||
free(a); // BAD
|
||||
free(b); // GOOD
|
||||
}
|
||||
void* test_realloc2(char *a) {
|
||||
void *b = realloc(a, strlen(a)+3); // GOOD
|
||||
|
||||
// From the man page on return values from realloc and reallocarray:
|
||||
// "If these functions fail, the original block is left untouched; it is not freed or moved."
|
||||
if (!b) {
|
||||
free(a); // GOOD
|
||||
}
|
||||
free(b); // GOOD
|
||||
}
|
||||
|
||||
void test_realloc3(void *a) {
|
||||
void *b = realloc(a, 100);
|
||||
if (b) free(b); // GOOD
|
||||
if (!b) {
|
||||
free(a); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test_ptr_deref(void ** a) {
|
||||
free(*a);
|
||||
*a = malloc(10);
|
||||
free(*a); // GOOD
|
||||
free(*a); // BAD [NOT DETECTED]
|
||||
*a = malloc(10);
|
||||
free(a[0]); // GOOD
|
||||
free(a[1]); // GOOD
|
||||
}
|
||||
|
||||
struct list {
|
||||
struct list *next;
|
||||
void* data;
|
||||
};
|
||||
|
||||
void test_loop1(struct list ** list_ptr) {
|
||||
struct list *next;
|
||||
while (*list_ptr) { // GOOD
|
||||
free((*list_ptr)->data); // GOOD
|
||||
next = (*list_ptr)->next; // GOOD
|
||||
free(*list_ptr); // GOOD
|
||||
*list_ptr = next; // GOOD
|
||||
}
|
||||
free(list_ptr); // GOOD
|
||||
}
|
||||
|
||||
void test_use_after_free8(struct list * a) {
|
||||
if (condition()) free(a);
|
||||
a->data = malloc(10); // BAD
|
||||
free(a); // BAD
|
||||
}
|
||||
|
||||
void test_loop2(char ** a) {
|
||||
while (*a) { // GOOD
|
||||
free(*a); // GOOD
|
||||
a++;
|
||||
}
|
||||
free(a); // GOOD
|
||||
}
|
||||
|
||||
void* test_realloc4() {
|
||||
void *a = 0;
|
||||
void *b = realloc(a, 10); // BAD for cpp/memory-never-freed
|
||||
if (!b) { return a; }
|
||||
return b;
|
||||
}
|
||||
|
||||
void test_sizeof(int *a) {
|
||||
free(a);
|
||||
int x = sizeof(a[0]); // GOOD
|
||||
}
|
||||
|
||||
void call_by_reference(char * &a);
|
||||
int custom_alloc_func(char ** a);
|
||||
|
||||
void test_reassign(char *a) {
|
||||
free(a); // GOOD
|
||||
asprintf(&a, "Hello world"); // GOOD
|
||||
free(a); //GOOD
|
||||
call_by_reference(a); // GOOD
|
||||
free(a); // GOOD
|
||||
int v;
|
||||
if (v = custom_alloc_func(&a)) return;
|
||||
free(a); // GOOD
|
||||
}
|
||||
|
||||
char* test_return1(char *a) {
|
||||
int ret = condition();
|
||||
if (!ret) free(a);
|
||||
return (ret ? a : 0);
|
||||
}
|
||||
|
||||
char* test_return2(char *a) {
|
||||
int ret = condition();
|
||||
if (!ret) free(a);
|
||||
if (ret) return a;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
void test_condition1(char *a) {
|
||||
free(a);
|
||||
if (asprintf(&a, "Hello world") || condition());
|
||||
free(a); //GOOD
|
||||
if (condition() || asprintf(&a, "Hello world"));
|
||||
free(a); // BAD
|
||||
}
|
||||
|
||||
void test_condition2(char *a) {
|
||||
free(a);
|
||||
if (condition()) a = (char*) malloc(10);
|
||||
else custom_alloc_func(&a);
|
||||
free(a); // GOOD
|
||||
}
|
||||
|
||||
void* test_return1(void *a) {
|
||||
free(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
void MmFreePagesFromMdl(void*);
|
||||
void ExFreePool(void*);
|
||||
void test_ms_free(void * memory_descriptor_list) {
|
||||
MmFreePagesFromMdl(memory_descriptor_list); //GOOD
|
||||
ExFreePool(memory_descriptor_list); // GOOD
|
||||
}
|
||||
|
||||
void test_loop3(char ** a, char ** b) {
|
||||
if (*a) {
|
||||
free(*a);
|
||||
a++;
|
||||
}
|
||||
use(*a); // GOOD [FALSE POSITIVE]
|
||||
|
||||
for (;*b; b++) {
|
||||
free(*b);
|
||||
}
|
||||
use(*b); // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
void test_deref(char **a) {
|
||||
free(*a);
|
||||
use(*a); // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
| test.cpp:35:7:35:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:34:3:34:7 | call to scanf | call to scanf |
|
||||
| test.cpp:51:7:51:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:50:3:50:7 | call to scanf | call to scanf |
|
||||
| test.cpp:68:7:68:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:67:3:67:7 | call to scanf | call to scanf |
|
||||
| test.cpp:80:7:80:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:79:3:79:7 | call to scanf | call to scanf |
|
||||
| test.cpp:90:8:90:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:89:3:89:7 | call to scanf | call to scanf |
|
||||
| test.cpp:98:8:98:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:97:3:97:7 | call to scanf | call to scanf |
|
||||
| test.cpp:90:7:90:8 | * ... | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:89:3:89:7 | call to scanf | call to scanf |
|
||||
| test.cpp:98:7:98:8 | * ... | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:97:3:97:7 | call to scanf | call to scanf |
|
||||
| test.cpp:108:7:108:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:107:3:107:8 | call to fscanf | call to fscanf |
|
||||
| test.cpp:115:7:115:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:114:3:114:8 | call to sscanf | call to sscanf |
|
||||
| test.cpp:164:8:164:8 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:162:7:162:11 | call to scanf | call to scanf |
|
||||
@@ -12,13 +11,9 @@
|
||||
| test.cpp:224:8:224:8 | j | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:221:7:221:11 | call to scanf | call to scanf |
|
||||
| test.cpp:248:9:248:9 | d | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:246:25:246:29 | call to scanf | call to scanf |
|
||||
| test.cpp:252:9:252:9 | d | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 2. | test.cpp:250:14:250:18 | call to scanf | call to scanf |
|
||||
| test.cpp:264:7:264:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:263:3:263:7 | call to scanf | call to scanf |
|
||||
| test.cpp:272:7:272:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:271:3:271:7 | call to scanf | call to scanf |
|
||||
| test.cpp:280:7:280:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:279:3:279:7 | call to scanf | call to scanf |
|
||||
| test.cpp:292:7:292:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:291:3:291:7 | call to scanf | call to scanf |
|
||||
| test.cpp:302:8:302:12 | ptr_i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:301:3:301:7 | call to scanf | call to scanf |
|
||||
| test.cpp:310:7:310:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:309:3:309:7 | call to scanf | call to scanf |
|
||||
| test.cpp:404:25:404:25 | u | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:403:6:403:11 | call to sscanf | call to sscanf |
|
||||
| test.cpp:416:7:416:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:413:7:413:11 | call to scanf | call to scanf |
|
||||
| test.cpp:423:7:423:7 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:420:7:420:11 | call to scanf | call to scanf |
|
||||
| test.cpp:430:6:430:6 | i | This variable is read, but may not have been written. It should be guarded by a check that the $@ returns at least 1. | test.cpp:429:2:429:6 | call to scanf | call to scanf |
|
||||
|
||||
@@ -48,7 +48,7 @@ int main()
|
||||
int i = 0;
|
||||
|
||||
scanf("%d", &i);
|
||||
use(i); // BAD. Design choice: already initialized variables shouldn't make a difference.
|
||||
use(i); // GOOD. Design choice: already initialized variables are fine.
|
||||
}
|
||||
|
||||
{
|
||||
@@ -261,7 +261,7 @@ int main()
|
||||
i = 0;
|
||||
|
||||
scanf("%d", &i);
|
||||
use(i); // BAD
|
||||
use(i); // GOOD
|
||||
}
|
||||
|
||||
{
|
||||
@@ -269,7 +269,7 @@ int main()
|
||||
|
||||
set_by_ref(i);
|
||||
scanf("%d", &i);
|
||||
use(i); // BAD
|
||||
use(i); // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
{
|
||||
@@ -277,7 +277,7 @@ int main()
|
||||
|
||||
set_by_ptr(&i);
|
||||
scanf("%d", &i);
|
||||
use(i); // BAD
|
||||
use(i); // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
{
|
||||
@@ -299,7 +299,7 @@ int main()
|
||||
int *ptr_i = &i;
|
||||
|
||||
scanf("%d", &i);
|
||||
use(*ptr_i); // BAD: may not have written `i`
|
||||
use(*ptr_i); // BAD [NOT DETECTED]: may not have written `i`
|
||||
}
|
||||
|
||||
{
|
||||
@@ -307,7 +307,7 @@ int main()
|
||||
int *ptr_i = &i;
|
||||
|
||||
scanf("%d", ptr_i);
|
||||
use(i); // BAD: may not have written `*ptr_i`
|
||||
use(i); // BAD [NOT DETECTED]: may not have written `*ptr_i`
|
||||
}
|
||||
|
||||
{
|
||||
@@ -427,5 +427,5 @@ void scan_and_write() {
|
||||
void scan_and_static_variable() {
|
||||
static int i;
|
||||
scanf("%d", &i);
|
||||
use(i); // GOOD [FALSE POSITIVE]: static variables are always 0-initialized
|
||||
use(i); // GOOD: static variables are always 0-initialized
|
||||
}
|
||||
|
||||
@@ -1,9 +1,74 @@
|
||||
| test.cpp:36:6:36:9 | data | Memory pointed to by 'data' may have $@. | test.cpp:35:2:35:5 | call to free | been previously freed |
|
||||
| test.cpp:70:7:70:10 | data | Memory pointed to by 'data' may have $@. | test.cpp:67:2:67:5 | call to free | been previously freed |
|
||||
| test.cpp:107:6:107:9 | data | Memory pointed to by 'data' may have $@. | test.cpp:105:2:105:5 | call to free | been previously freed |
|
||||
| test.cpp:117:6:117:9 | data | Memory pointed to by 'data' may have $@. | test.cpp:115:2:115:5 | call to free | been previously freed |
|
||||
| test.cpp:150:2:150:2 | c | Memory pointed to by 'c' may have $@. | test.cpp:149:2:149:10 | delete | been previously freed |
|
||||
| test.cpp:151:4:151:4 | c | Memory pointed to by 'c' may have $@. | test.cpp:149:2:149:10 | delete | been previously freed |
|
||||
| test.cpp:170:6:170:9 | data | Memory pointed to by 'data' may have $@. | test.cpp:165:2:165:5 | call to free | been previously freed |
|
||||
| test.cpp:193:6:193:9 | data | Memory pointed to by 'data' may have $@. | test.cpp:191:3:191:6 | call to free | been previously freed |
|
||||
| test.cpp:201:6:201:6 | x | Memory pointed to by 'x' may have $@. | test.cpp:200:2:200:9 | delete | been previously freed |
|
||||
edges
|
||||
| test.cpp:39:7:39:10 | data | test.cpp:41:6:41:9 | data |
|
||||
| test.cpp:39:7:39:10 | data | test.cpp:41:6:41:9 | data |
|
||||
| test.cpp:75:7:75:10 | data | test.cpp:79:7:79:10 | data |
|
||||
| test.cpp:75:7:75:10 | data | test.cpp:79:7:79:10 | data |
|
||||
| test.cpp:106:7:106:10 | data | test.cpp:108:6:108:9 | data |
|
||||
| test.cpp:106:7:106:10 | data | test.cpp:108:6:108:9 | data |
|
||||
| test.cpp:116:7:116:10 | data | test.cpp:119:6:119:9 | data |
|
||||
| test.cpp:116:7:116:10 | data | test.cpp:119:6:119:9 | data |
|
||||
| test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data |
|
||||
| test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data |
|
||||
| test.cpp:138:7:138:10 | data | test.cpp:141:6:141:9 | data |
|
||||
| test.cpp:138:7:138:10 | data | test.cpp:141:6:141:9 | data |
|
||||
| test.cpp:181:7:181:10 | data | test.cpp:186:6:186:9 | data |
|
||||
| test.cpp:181:7:181:10 | data | test.cpp:186:6:186:9 | data |
|
||||
| test.cpp:192:7:192:10 | data | test.cpp:197:6:197:9 | data |
|
||||
| test.cpp:192:7:192:10 | data | test.cpp:197:6:197:9 | data |
|
||||
| test.cpp:203:7:203:10 | data | test.cpp:209:6:209:9 | data |
|
||||
| test.cpp:203:7:203:10 | data | test.cpp:209:6:209:9 | data |
|
||||
| test.cpp:207:8:207:11 | data | test.cpp:209:6:209:9 | data |
|
||||
| test.cpp:207:8:207:11 | data | test.cpp:209:6:209:9 | data |
|
||||
nodes
|
||||
| test.cpp:39:7:39:10 | data | semmle.label | data |
|
||||
| test.cpp:39:7:39:10 | data | semmle.label | data |
|
||||
| test.cpp:41:6:41:9 | data | semmle.label | data |
|
||||
| test.cpp:75:7:75:10 | data | semmle.label | data |
|
||||
| test.cpp:75:7:75:10 | data | semmle.label | data |
|
||||
| test.cpp:79:7:79:10 | data | semmle.label | data |
|
||||
| test.cpp:106:7:106:10 | data | semmle.label | data |
|
||||
| test.cpp:106:7:106:10 | data | semmle.label | data |
|
||||
| test.cpp:108:6:108:9 | data | semmle.label | data |
|
||||
| test.cpp:116:7:116:10 | data | semmle.label | data |
|
||||
| test.cpp:116:7:116:10 | data | semmle.label | data |
|
||||
| test.cpp:119:6:119:9 | data | semmle.label | data |
|
||||
| test.cpp:127:7:127:10 | data | semmle.label | data |
|
||||
| test.cpp:127:7:127:10 | data | semmle.label | data |
|
||||
| test.cpp:130:6:130:9 | data | semmle.label | data |
|
||||
| test.cpp:138:7:138:10 | data | semmle.label | data |
|
||||
| test.cpp:138:7:138:10 | data | semmle.label | data |
|
||||
| test.cpp:141:6:141:9 | data | semmle.label | data |
|
||||
| test.cpp:181:7:181:10 | data | semmle.label | data |
|
||||
| test.cpp:181:7:181:10 | data | semmle.label | data |
|
||||
| test.cpp:186:6:186:9 | data | semmle.label | data |
|
||||
| test.cpp:192:7:192:10 | data | semmle.label | data |
|
||||
| test.cpp:192:7:192:10 | data | semmle.label | data |
|
||||
| test.cpp:197:6:197:9 | data | semmle.label | data |
|
||||
| test.cpp:203:7:203:10 | data | semmle.label | data |
|
||||
| test.cpp:203:7:203:10 | data | semmle.label | data |
|
||||
| test.cpp:207:8:207:11 | data | semmle.label | data |
|
||||
| test.cpp:207:8:207:11 | data | semmle.label | data |
|
||||
| test.cpp:209:6:209:9 | data | semmle.label | data |
|
||||
| test.cpp:209:6:209:9 | data | semmle.label | data |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:41:6:41:9 | data | test.cpp:39:7:39:10 | data | test.cpp:41:6:41:9 | data | Memory may have been previously freed by $@. | test.cpp:39:2:39:5 | call to free | call to free |
|
||||
| test.cpp:41:6:41:9 | data | test.cpp:39:7:39:10 | data | test.cpp:41:6:41:9 | data | Memory may have been previously freed by $@. | test.cpp:39:2:39:5 | call to free | call to free |
|
||||
| test.cpp:79:7:79:10 | data | test.cpp:75:7:75:10 | data | test.cpp:79:7:79:10 | data | Memory may have been previously freed by $@. | test.cpp:75:2:75:5 | call to free | call to free |
|
||||
| test.cpp:79:7:79:10 | data | test.cpp:75:7:75:10 | data | test.cpp:79:7:79:10 | data | Memory may have been previously freed by $@. | test.cpp:75:2:75:5 | call to free | call to free |
|
||||
| test.cpp:108:6:108:9 | data | test.cpp:106:7:106:10 | data | test.cpp:108:6:108:9 | data | Memory may have been previously freed by $@. | test.cpp:106:2:106:5 | call to free | call to free |
|
||||
| test.cpp:108:6:108:9 | data | test.cpp:106:7:106:10 | data | test.cpp:108:6:108:9 | data | Memory may have been previously freed by $@. | test.cpp:106:2:106:5 | call to free | call to free |
|
||||
| test.cpp:119:6:119:9 | data | test.cpp:116:7:116:10 | data | test.cpp:119:6:119:9 | data | Memory may have been previously freed by $@. | test.cpp:116:2:116:5 | call to free | call to free |
|
||||
| test.cpp:119:6:119:9 | data | test.cpp:116:7:116:10 | data | test.cpp:119:6:119:9 | data | Memory may have been previously freed by $@. | test.cpp:116:2:116:5 | call to free | call to free |
|
||||
| test.cpp:130:6:130:9 | data | test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data | Memory may have been previously freed by $@. | test.cpp:127:2:127:5 | call to free | call to free |
|
||||
| test.cpp:130:6:130:9 | data | test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data | Memory may have been previously freed by $@. | test.cpp:127:2:127:5 | call to free | call to free |
|
||||
| test.cpp:141:6:141:9 | data | test.cpp:138:7:138:10 | data | test.cpp:141:6:141:9 | data | Memory may have been previously freed by $@. | test.cpp:138:2:138:5 | call to free | call to free |
|
||||
| test.cpp:141:6:141:9 | data | test.cpp:138:7:138:10 | data | test.cpp:141:6:141:9 | data | Memory may have been previously freed by $@. | test.cpp:138:2:138:5 | call to free | call to free |
|
||||
| test.cpp:186:6:186:9 | data | test.cpp:181:7:181:10 | data | test.cpp:186:6:186:9 | data | Memory may have been previously freed by $@. | test.cpp:181:2:181:5 | call to free | call to free |
|
||||
| test.cpp:186:6:186:9 | data | test.cpp:181:7:181:10 | data | test.cpp:186:6:186:9 | data | Memory may have been previously freed by $@. | test.cpp:181:2:181:5 | call to free | call to free |
|
||||
| test.cpp:197:6:197:9 | data | test.cpp:192:7:192:10 | data | test.cpp:197:6:197:9 | data | Memory may have been previously freed by $@. | test.cpp:192:2:192:5 | call to free | call to free |
|
||||
| test.cpp:197:6:197:9 | data | test.cpp:192:7:192:10 | data | test.cpp:197:6:197:9 | data | Memory may have been previously freed by $@. | test.cpp:192:2:192:5 | call to free | call to free |
|
||||
| test.cpp:209:6:209:9 | data | test.cpp:203:7:203:10 | data | test.cpp:209:6:209:9 | data | Memory may have been previously freed by $@. | test.cpp:203:2:203:5 | call to free | call to free |
|
||||
| test.cpp:209:6:209:9 | data | test.cpp:203:7:203:10 | data | test.cpp:209:6:209:9 | data | Memory may have been previously freed by $@. | test.cpp:203:2:203:5 | call to free | call to free |
|
||||
| test.cpp:209:6:209:9 | data | test.cpp:207:8:207:11 | data | test.cpp:209:6:209:9 | data | Memory may have been previously freed by $@. | test.cpp:207:3:207:6 | call to free | call to free |
|
||||
| test.cpp:209:6:209:9 | data | test.cpp:207:8:207:11 | data | test.cpp:209:6:209:9 | data | Memory may have been previously freed by $@. | test.cpp:207:3:207:6 | call to free | call to free |
|
||||
|
||||
@@ -6,14 +6,18 @@ typedef unsigned long size_t;
|
||||
void *malloc(size_t size);
|
||||
void free(void *ptr);
|
||||
|
||||
void useExternal(char* data);
|
||||
void useExternal(...);
|
||||
|
||||
void use(char* data)
|
||||
void use_if_nonzero(char* data)
|
||||
{
|
||||
if (data)
|
||||
useExternal(data);
|
||||
}
|
||||
|
||||
void use(char* data) {
|
||||
useExternal(*data);
|
||||
}
|
||||
|
||||
[[noreturn]]
|
||||
void noReturn();
|
||||
|
||||
@@ -31,8 +35,9 @@ void test1()
|
||||
{
|
||||
char* data;
|
||||
data = (char *)malloc(100*sizeof(char));
|
||||
use(data); // GOOD
|
||||
use_if_nonzero(data); // GOOD
|
||||
free(data);
|
||||
use_if_nonzero(data); // BAD [NOT DETECTED]
|
||||
use(data); // BAD
|
||||
}
|
||||
|
||||
@@ -42,9 +47,11 @@ void test2()
|
||||
data = (char *)malloc(100*sizeof(char));
|
||||
free(data);
|
||||
myMalloc(&data);
|
||||
use_if_nonzero(data); // GOOD
|
||||
use(data); // GOOD
|
||||
free(data);
|
||||
myMalloc2(data);
|
||||
use_if_nonzero(data); // GOOD
|
||||
use(data); // GOOD
|
||||
}
|
||||
|
||||
@@ -56,6 +63,7 @@ void test3()
|
||||
data = NULL;
|
||||
if (data)
|
||||
{
|
||||
use_if_nonzero(data); // GOOD
|
||||
use(data); // GOOD
|
||||
}
|
||||
}
|
||||
@@ -67,6 +75,7 @@ void test4()
|
||||
free(data);
|
||||
if (data)
|
||||
{
|
||||
use_if_nonzero(data); // BAD [NOT DETECTED]
|
||||
use(data); // BAD
|
||||
}
|
||||
}
|
||||
@@ -85,7 +94,8 @@ char* returnsFreedData(int i)
|
||||
void test5()
|
||||
{
|
||||
char* data = returnsFreedData(1);
|
||||
use(data); // BAD (NOT REPORTED)
|
||||
use_if_nonzero(data); // BAD [NOT DETECTED]
|
||||
use(data); // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test6()
|
||||
@@ -94,7 +104,8 @@ void test6()
|
||||
data = (char *)malloc(100*sizeof(char));
|
||||
data2 = data;
|
||||
free(data);
|
||||
use(data2); // BAD (NOT REPORTED)
|
||||
use_if_nonzero(data2); // BAD [NOT DETECTED]
|
||||
use(data); // BAD
|
||||
}
|
||||
|
||||
void test7()
|
||||
@@ -104,6 +115,7 @@ void test7()
|
||||
data2 = data;
|
||||
free(data);
|
||||
data2 = NULL;
|
||||
use_if_nonzero(data); // BAD [NOT DETECTED]
|
||||
use(data); // BAD
|
||||
}
|
||||
|
||||
@@ -114,6 +126,7 @@ void test8()
|
||||
data = data2;
|
||||
free(data);
|
||||
data2 = NULL;
|
||||
use_if_nonzero(data); // BAD [NOT DETECTED]
|
||||
use(data); // BAD
|
||||
}
|
||||
|
||||
@@ -124,13 +137,15 @@ void test9()
|
||||
char *data, *data2;
|
||||
free(data);
|
||||
noReturnWrapper();
|
||||
use(data); // GOOD
|
||||
use_if_nonzero(data); // GOOD
|
||||
use(data); // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
void test10()
|
||||
{
|
||||
for (char *data; true; data = NULL)
|
||||
{
|
||||
use_if_nonzero(data); // GOOD
|
||||
use(data); // GOOD
|
||||
free(data);
|
||||
}
|
||||
@@ -140,7 +155,7 @@ class myClass
|
||||
{
|
||||
public:
|
||||
myClass() { }
|
||||
|
||||
|
||||
void myMethod() { }
|
||||
};
|
||||
|
||||
@@ -156,7 +171,8 @@ template<class T> T test()
|
||||
T* x;
|
||||
use(x); // GOOD
|
||||
delete x;
|
||||
use(x); // BAD
|
||||
use_if_nonzero(x); // BAD [NOT DETECTED]
|
||||
use(x); // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test12(int count)
|
||||
@@ -178,7 +194,7 @@ void test13()
|
||||
{
|
||||
data = NULL;
|
||||
}
|
||||
use(data); // GOOD
|
||||
use(data); // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
void test14()
|
||||
@@ -198,7 +214,7 @@ template<class T> T test15()
|
||||
T* x;
|
||||
use(x); // GOOD
|
||||
delete x;
|
||||
use(x); // BAD
|
||||
use(x); // BAD [NOT DETECTED]
|
||||
}
|
||||
void test15runner(void)
|
||||
{
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
package,sink,source,summary,sink:code,sink:encryption-decryptor,sink:encryption-encryptor,sink:encryption-keyprop,sink:encryption-symmetrickey,sink:html,sink:remote,sink:sql,sink:xss,source:file,source:local,source:remote,summary:taint,summary:value
|
||||
Dapper,55,,,,,,,,,,55,,,,,,
|
||||
JsonToItemsTaskFactory,,,7,,,,,,,,,,,,,7,
|
||||
Microsoft.ApplicationBlocks.Data,28,,,,,,,,,,28,,,,,,
|
||||
Microsoft.CSharp,,,24,,,,,,,,,,,,,24,
|
||||
Microsoft.EntityFrameworkCore,6,,,,,,,,,,6,,,,,,
|
||||
Microsoft.Extensions.Caching.Distributed,,,15,,,,,,,,,,,,,15,
|
||||
Microsoft.Extensions.Caching.Memory,,,46,,,,,,,,,,,,,45,1
|
||||
Microsoft.Extensions.Configuration,,,83,,,,,,,,,,,,,80,3
|
||||
Microsoft.Extensions.DependencyInjection,,,62,,,,,,,,,,,,,62,
|
||||
Microsoft.Extensions.DependencyModel,,,12,,,,,,,,,,,,,12,
|
||||
Microsoft.Extensions.FileProviders,,,16,,,,,,,,,,,,,16,
|
||||
Microsoft.Extensions.FileSystemGlobbing,,,15,,,,,,,,,,,,,13,2
|
||||
Microsoft.Extensions.Hosting,,,17,,,,,,,,,,,,,16,1
|
||||
Microsoft.Extensions.Http,,,10,,,,,,,,,,,,,10,
|
||||
Microsoft.Extensions.Logging,,,37,,,,,,,,,,,,,37,
|
||||
Microsoft.Extensions.Options,,,8,,,,,,,,,,,,,8,
|
||||
Microsoft.Extensions.Primitives,,,63,,,,,,,,,,,,,63,
|
||||
Microsoft.Interop,,,27,,,,,,,,,,,,,27,
|
||||
Microsoft.NET.Build.Tasks,,,1,,,,,,,,,,,,,1,
|
||||
Microsoft.NETCore.Platforms.BuildTasks,,,4,,,,,,,,,,,,,4,
|
||||
Microsoft.VisualBasic,,,10,,,,,,,,,,,,,5,5
|
||||
Microsoft.Win32,,,8,,,,,,,,,,,,,8,
|
||||
MySql.Data.MySqlClient,48,,,,,,,,,,48,,,,,,
|
||||
Newtonsoft.Json,,,91,,,,,,,,,,,,,73,18
|
||||
ServiceStack,194,,7,27,,,,,,75,92,,,,,7,
|
||||
System,65,8,12154,,8,8,9,,4,,33,3,1,3,4,10163,1991
|
||||
Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,,,
|
||||
package,sink,source,summary,sink:code,sink:encryption-decryptor,sink:encryption-encryptor,sink:encryption-keyprop,sink:encryption-symmetrickey,sink:html,sink:remote,sink:sql,sink:xss,source:file,source:file-write,source:local,source:remote,summary:taint,summary:value
|
||||
Dapper,55,,,,,,,,,,55,,,,,,,
|
||||
JsonToItemsTaskFactory,,,7,,,,,,,,,,,,,,7,
|
||||
Microsoft.ApplicationBlocks.Data,28,,,,,,,,,,28,,,,,,,
|
||||
Microsoft.CSharp,,,24,,,,,,,,,,,,,,24,
|
||||
Microsoft.EntityFrameworkCore,6,,,,,,,,,,6,,,,,,,
|
||||
Microsoft.Extensions.Caching.Distributed,,,15,,,,,,,,,,,,,,15,
|
||||
Microsoft.Extensions.Caching.Memory,,,46,,,,,,,,,,,,,,45,1
|
||||
Microsoft.Extensions.Configuration,,,83,,,,,,,,,,,,,,80,3
|
||||
Microsoft.Extensions.DependencyInjection,,,62,,,,,,,,,,,,,,62,
|
||||
Microsoft.Extensions.DependencyModel,,,12,,,,,,,,,,,,,,12,
|
||||
Microsoft.Extensions.FileProviders,,,16,,,,,,,,,,,,,,16,
|
||||
Microsoft.Extensions.FileSystemGlobbing,,,15,,,,,,,,,,,,,,13,2
|
||||
Microsoft.Extensions.Hosting,,,17,,,,,,,,,,,,,,16,1
|
||||
Microsoft.Extensions.Http,,,10,,,,,,,,,,,,,,10,
|
||||
Microsoft.Extensions.Logging,,,37,,,,,,,,,,,,,,37,
|
||||
Microsoft.Extensions.Options,,,8,,,,,,,,,,,,,,8,
|
||||
Microsoft.Extensions.Primitives,,,63,,,,,,,,,,,,,,63,
|
||||
Microsoft.Interop,,,27,,,,,,,,,,,,,,27,
|
||||
Microsoft.NET.Build.Tasks,,,1,,,,,,,,,,,,,,1,
|
||||
Microsoft.NETCore.Platforms.BuildTasks,,,4,,,,,,,,,,,,,,4,
|
||||
Microsoft.VisualBasic,,,10,,,,,,,,,,,,,,5,5
|
||||
Microsoft.Win32,,,8,,,,,,,,,,,,,,8,
|
||||
MySql.Data.MySqlClient,48,,,,,,,,,,48,,,,,,,
|
||||
Newtonsoft.Json,,,91,,,,,,,,,,,,,,73,18
|
||||
ServiceStack,194,,7,27,,,,,,75,92,,,,,,7,
|
||||
System,65,25,12154,,8,8,9,,4,,33,3,1,17,3,4,10163,1991
|
||||
Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,,,,
|
||||
|
||||
|
@@ -8,7 +8,7 @@ C# framework & library support
|
||||
|
||||
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
|
||||
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
|
||||
System,"``System.*``, ``System``",8,12154,65,7
|
||||
System,"``System.*``, ``System``",25,12154,65,7
|
||||
Others,"``Dapper``, ``JsonToItemsTaskFactory``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NETCore.Platforms.BuildTasks``, ``Microsoft.VisualBasic``, ``Microsoft.Win32``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``Windows.Security.Cryptography.Core``",,556,138,
|
||||
Totals,,8,12717,397,7
|
||||
Totals,,25,12717,397,7
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.5.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.5.0
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.5.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.5.0
|
||||
lastReleaseVersion: 1.5.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.5.0
|
||||
version: 1.5.1
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.5.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.5.0
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.5.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.5.0
|
||||
lastReleaseVersion: 1.5.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.5.0
|
||||
version: 1.5.1
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<queries language="csharp"/>
|
||||
@@ -1,7 +1,4 @@
|
||||
{
|
||||
"attributes": {},
|
||||
"helpLinks": [],
|
||||
"internal": false,
|
||||
"markdownMessage": "CodeQL found some projects which cannot be built with .NET Core:\n\n- `test.csproj`",
|
||||
"severity": "warning",
|
||||
"source": {
|
||||
@@ -16,9 +13,6 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"attributes": {},
|
||||
"helpLinks": [],
|
||||
"internal": false,
|
||||
"markdownMessage": "CodeQL was unable to build the following projects using MSBuild:\n\n- `test.csproj`\n\nSet up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
{
|
||||
"attributes": {},
|
||||
"helpLinks": [],
|
||||
"internal": false,
|
||||
"markdownMessage": "CodeQL was unable to build the following projects using MSBuild:\n\n- `test.sln`\n\nSet up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
@@ -16,9 +13,6 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"attributes": {},
|
||||
"helpLinks": [],
|
||||
"internal": false,
|
||||
"markdownMessage": "Some project files were not found when CodeQL built your project:\n\n- `Example.csproj`\n- `Example.Test.csproj`\n\nThis may lead to subsequent failures. You can check for common causes for missing project files:\n\n- Ensure that the project is built using the [intended operating system](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idruns-on) and that filenames on case-sensitive platforms are correctly specified.\n- If your repository uses Git submodules, ensure that those are [checked out](https://github.com/actions/checkout#usage) before the CodeQL Action is run.\n- If you auto-generate some project files as part of your build process, ensure that these are generated before the CodeQL Action is run.",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
{
|
||||
"attributes": {},
|
||||
"helpLinks": [],
|
||||
"internal": false,
|
||||
"markdownMessage": "CodeQL was unable to build the following projects using .NET Core:\n\n- `test.csproj`\n\nSet up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
@@ -16,9 +13,6 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"attributes": {},
|
||||
"helpLinks": [],
|
||||
"internal": false,
|
||||
"markdownMessage": "CodeQL was unable to build the following projects using MSBuild:\n\n- `test.csproj`\n\nSet up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
@@ -33,9 +27,6 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"attributes": {},
|
||||
"helpLinks": [],
|
||||
"internal": false,
|
||||
"markdownMessage": "[Configure your workflow](https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-xamarin-applications) for this SDK before running CodeQL.",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import os
|
||||
from create_database_utils import *
|
||||
from diagnostics_test_utils import *
|
||||
|
||||
@@ -22,35 +21,35 @@ check_diagnostics()
|
||||
# no arguments, but `--`
|
||||
s = run_codeql_database_create_stdout(['dotnet clean', 'rm -rf test-db', 'dotnet run --'], "test2-db")
|
||||
check_build_out("Default reply", s)
|
||||
check_diagnostics(diagnostics_dir="test2-db/diagnostic")
|
||||
check_diagnostics(test_db="test2-db")
|
||||
|
||||
# one argument, no `--`
|
||||
s = run_codeql_database_create_stdout(['dotnet clean', 'rm -rf test2-db', 'dotnet run hello'], "test3-db")
|
||||
check_build_out("Default reply", s)
|
||||
check_diagnostics(diagnostics_dir="test3-db/diagnostic")
|
||||
check_diagnostics(test_db="test3-db")
|
||||
|
||||
# one argument, but `--`
|
||||
s = run_codeql_database_create_stdout(['dotnet clean', 'rm -rf test3-db', 'dotnet run -- hello'], "test4-db")
|
||||
check_build_out("Default reply", s)
|
||||
check_diagnostics(diagnostics_dir="test4-db/diagnostic")
|
||||
check_diagnostics(test_db="test4-db")
|
||||
|
||||
# two arguments, no `--`
|
||||
s = run_codeql_database_create_stdout(['dotnet clean', 'rm -rf test4-db', 'dotnet run hello world'], "test5-db")
|
||||
check_build_out("hello, world", s)
|
||||
check_diagnostics(diagnostics_dir="test5-db/diagnostic")
|
||||
check_diagnostics(test_db="test5-db")
|
||||
|
||||
# two arguments, and `--`
|
||||
s = run_codeql_database_create_stdout(['dotnet clean', 'rm -rf test5-db', 'dotnet run -- hello world'], "test6-db")
|
||||
check_build_out("hello, world", s)
|
||||
check_diagnostics(diagnostics_dir="test6-db/diagnostic")
|
||||
check_diagnostics(test_db="test6-db")
|
||||
|
||||
# shared compilation enabled; tracer should override by changing the command
|
||||
# to `dotnet run -p:UseSharedCompilation=true -p:UseSharedCompilation=false -- hello world`
|
||||
s = run_codeql_database_create_stdout(['dotnet clean', 'rm -rf test6-db', 'dotnet run -p:UseSharedCompilation=true -- hello world'], "test7-db")
|
||||
check_build_out("hello, world", s)
|
||||
check_diagnostics(diagnostics_dir="test7-db/diagnostic")
|
||||
check_diagnostics(test_db="test7-db")
|
||||
|
||||
# option passed into `dotnet run`
|
||||
s = run_codeql_database_create_stdout(['dotnet clean', 'rm -rf test7-db', 'dotnet build', 'dotnet run --no-build hello world'], "test8-db")
|
||||
check_build_out("hello, world", s)
|
||||
check_diagnostics(diagnostics_dir="test8-db/diagnostic")
|
||||
check_diagnostics(test_db="test8-db")
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
{
|
||||
"attributes": {},
|
||||
"helpLinks": [],
|
||||
"internal": false,
|
||||
"markdownMessage": "CodeQL attempted to build your project using a script located at `build.sh`, which failed.\n\nSet up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
@@ -16,9 +13,6 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"attributes": {},
|
||||
"helpLinks": [],
|
||||
"internal": false,
|
||||
"markdownMessage": "CodeQL could not find any project or solution files in your repository.\n\nSet up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
{
|
||||
"attributes": {},
|
||||
"helpLinks": [],
|
||||
"internal": false,
|
||||
"markdownMessage": "CodeQL could not find any project or solution files in your repository.\n\nSet up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
@@ -16,9 +13,6 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"attributes": {},
|
||||
"helpLinks": [],
|
||||
"internal": false,
|
||||
"markdownMessage": "CodeQL found multiple potential build scripts for your project and attempted to run `build.sh`, which failed. This may not be the right build script for your project.\n\nSet up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
{
|
||||
"attributes": {},
|
||||
"helpLinks": [],
|
||||
"internal": false,
|
||||
"markdownMessage": "CodeQL attempted to build your project using a script located at `build.bat`, which failed.\n\nSet up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
@@ -16,9 +13,6 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"attributes": {},
|
||||
"helpLinks": [],
|
||||
"internal": false,
|
||||
"markdownMessage": "CodeQL could not find any project or solution files in your repository.\n\nSet up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
{
|
||||
"attributes": {},
|
||||
"helpLinks": [],
|
||||
"internal": false,
|
||||
"markdownMessage": "CodeQL could not find any project or solution files in your repository.\n\nSet up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
@@ -16,9 +13,6 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"attributes": {},
|
||||
"helpLinks": [],
|
||||
"internal": false,
|
||||
"markdownMessage": "CodeQL found multiple potential build scripts for your project and attempted to run `build.bat`, which failed. This may not be the right build script for your project.\n\nSet up a [manual build command](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages).",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.6.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user