Merge pull request #9 from microsoft/jb1/zipslip-fix

Manual Merge: C# ZipSlip Conflict
This commit is contained in:
dilanbhalla
2023-05-24 11:19:13 -07:00
committed by GitHub
803 changed files with 47622 additions and 28389 deletions

View File

@@ -1 +1 @@
5.0.0
6.1.2

View File

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

View File

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

View File

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

View File

@@ -1 +0,0 @@
<queries language="cpp"/>

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 0.7.0
version: 0.7.1
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -47,7 +47,7 @@ class Variable = Cpp::Variable;
class AutomaticVariable = Cpp::StackVariable;
class StaticVariable = Cpp::Variable;
class StaticVariable = Cpp::StaticStorageDurationVariable;
class GlobalVariable = Cpp::GlobalOrNamespaceVariable;

View File

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

View File

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

View File

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

View File

@@ -1,2 +1,3 @@
import RangeAnalysisImpl
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound
private import RangeAnalysisImpl as Impl
import Impl::Public

View File

@@ -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()`.
*

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,10 @@
## 0.6.1
### New Queries
* A new query `cpp/double-free` has been added. The query finds possible cases of deallocating the same pointer twice. The precision of the query has been set to "medium".
* The query `cpp/use-after-free` has been modernized and assigned the precision "medium". The query finds cases of where a pointer is dereferenced after its memory has been deallocated.
## 0.6.0
### New Queries

View File

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

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

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

View 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")
)
}

View File

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

View File

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

View File

@@ -0,0 +1,6 @@
## 0.6.1
### New Queries
* A new query `cpp/double-free` has been added. The query finds possible cases of deallocating the same pointer twice. The precision of the query has been set to "medium".
* The query `cpp/use-after-free` has been modernized and assigned the precision "medium". The query finds cases of where a pointer is dereferenced after its memory has been deallocated.

View File

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

View File

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

View File

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

View File

@@ -1 +0,0 @@
<queries language="cpp"/>

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
| (unnamed class/struct/union) |
| float[3] |
| float[3][3] |
| foo[1] |
| struct <unnamed> |

View File

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

View File

@@ -18,5 +18,7 @@ predicate shouldDumpFunction(Declaration decl) {
decl instanceof Function
or
decl.(GlobalOrNamespaceVariable).hasInitializer()
or
decl.(StaticLocalVariable).hasInitializer()
)
}

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1 +0,0 @@
<queries language="cpp"/>

View File

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

View File

@@ -0,0 +1 @@
Critical/DoubleFree.ql

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1 @@
Critical/UseAfterFree.ql

View 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]
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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,,,,,,,,,,
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
2 Dapper 55 55
3 JsonToItemsTaskFactory 7 7
4 Microsoft.ApplicationBlocks.Data 28 28
5 Microsoft.CSharp 24 24
6 Microsoft.EntityFrameworkCore 6 6
7 Microsoft.Extensions.Caching.Distributed 15 15
8 Microsoft.Extensions.Caching.Memory 46 45 1
9 Microsoft.Extensions.Configuration 83 80 3
10 Microsoft.Extensions.DependencyInjection 62 62
11 Microsoft.Extensions.DependencyModel 12 12
12 Microsoft.Extensions.FileProviders 16 16
13 Microsoft.Extensions.FileSystemGlobbing 15 13 2
14 Microsoft.Extensions.Hosting 17 16 1
15 Microsoft.Extensions.Http 10 10
16 Microsoft.Extensions.Logging 37 37
17 Microsoft.Extensions.Options 8 8
18 Microsoft.Extensions.Primitives 63 63
19 Microsoft.Interop 27 27
20 Microsoft.NET.Build.Tasks 1 1
21 Microsoft.NETCore.Platforms.BuildTasks 4 4
22 Microsoft.VisualBasic 10 5 5
23 Microsoft.Win32 8 8
24 MySql.Data.MySqlClient 48 48
25 Newtonsoft.Json 91 73 18
26 ServiceStack 194 7 27 75 92 7
27 System 65 8 25 12154 8 8 9 4 33 3 1 17 3 4 10163 1991
28 Windows.Security.Cryptography.Core 1 1

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1 +0,0 @@
<queries language="csharp"/>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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