mirror of
https://github.com/github/codeql.git
synced 2026-05-16 04:09:27 +02:00
Compare commits
238 Commits
codeql-cli
...
mbg/go/imp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12bc9f84bd | ||
|
|
f64e617da2 | ||
|
|
97b95337b6 | ||
|
|
a8d87ea4ea | ||
|
|
dfa23197c7 | ||
|
|
8a9fd8c619 | ||
|
|
42ee9afc69 | ||
|
|
c6809c46f5 | ||
|
|
0174a16d5a | ||
|
|
69bf334a33 | ||
|
|
01597ec23b | ||
|
|
c9d1aa6354 | ||
|
|
4666ed9957 | ||
|
|
4e701a12db | ||
|
|
628064118f | ||
|
|
648b28c1d2 | ||
|
|
7b89c6c7f7 | ||
|
|
9bc04e7591 | ||
|
|
c5403f4249 | ||
|
|
871fd9aba3 | ||
|
|
880d56c576 | ||
|
|
9c8945f626 | ||
|
|
6575927630 | ||
|
|
2dcb55cc42 | ||
|
|
0338ffd125 | ||
|
|
61580da14d | ||
|
|
8b91914826 | ||
|
|
aab43afd81 | ||
|
|
99940a6084 | ||
|
|
c11fac81fd | ||
|
|
85e71c30dc | ||
|
|
8e95395382 | ||
|
|
61fb89721a | ||
|
|
8198b1a6ef | ||
|
|
ab3d21ce7e | ||
|
|
9f27eb3eda | ||
|
|
4eea214cb4 | ||
|
|
b8f62ae4d5 | ||
|
|
5fe3ab7890 | ||
|
|
53c2d2f1e7 | ||
|
|
07d51a55fd | ||
|
|
41b95a1938 | ||
|
|
cfb0a862c1 | ||
|
|
9b23635d0a | ||
|
|
5c74bebe6c | ||
|
|
757cf8d43a | ||
|
|
b53fa0f7f3 | ||
|
|
d85f81d699 | ||
|
|
7c7bdb2242 | ||
|
|
92b3eda12d | ||
|
|
a8549d2e23 | ||
|
|
54c9aea251 | ||
|
|
73df4fa920 | ||
|
|
95ddd6ec74 | ||
|
|
51e7f3be1a | ||
|
|
5b184c179a | ||
|
|
cba4ba042c | ||
|
|
a33393d452 | ||
|
|
7cb8a6c52f | ||
|
|
6815bcaa80 | ||
|
|
105984f7de | ||
|
|
6233da3e40 | ||
|
|
5d5e31378b | ||
|
|
5cde3fa697 | ||
|
|
39a8b49222 | ||
|
|
b209fc67cb | ||
|
|
77128de105 | ||
|
|
7a1b85aa56 | ||
|
|
eb0621ab7a | ||
|
|
c0cf1c7c8c | ||
|
|
17990da205 | ||
|
|
d5475c4a89 | ||
|
|
471303bd7c | ||
|
|
2132c7bf96 | ||
|
|
7ca54a6f94 | ||
|
|
e8cb8b4f81 | ||
|
|
ba64cf3016 | ||
|
|
3c91333d0b | ||
|
|
d9e8e0e00a | ||
|
|
ff85db36e2 | ||
|
|
8f0b88497a | ||
|
|
31c427e64c | ||
|
|
e64a2d6c9c | ||
|
|
807e6795a7 | ||
|
|
880262d462 | ||
|
|
95ff5bae65 | ||
|
|
6cbe16e0c2 | ||
|
|
75615f2817 | ||
|
|
c07bf65eb6 | ||
|
|
8def1c2c13 | ||
|
|
1b90f22e84 | ||
|
|
ecdf62376d | ||
|
|
f5431abb10 | ||
|
|
73cc211779 | ||
|
|
08e08a2b3a | ||
|
|
657402b42f | ||
|
|
ecbf7aef18 | ||
|
|
669fc925e0 | ||
|
|
8a04840f93 | ||
|
|
f4e4e238ba | ||
|
|
8f682ef4e4 | ||
|
|
96d69ca49c | ||
|
|
8a261b7e7a | ||
|
|
daea674095 | ||
|
|
315f439135 | ||
|
|
06d8892e03 | ||
|
|
e22159ab5d | ||
|
|
355c7d9b41 | ||
|
|
00baccbc15 | ||
|
|
81dea9f89a | ||
|
|
76067cb12d | ||
|
|
e4cf7df38f | ||
|
|
b8b3689251 | ||
|
|
0693bf9e75 | ||
|
|
1aafc377ad | ||
|
|
abcd9165b4 | ||
|
|
0bc6934bfc | ||
|
|
4ae82ac215 | ||
|
|
ccad70897d | ||
|
|
318d954536 | ||
|
|
3239af9973 | ||
|
|
f7113e0105 | ||
|
|
ca2d94b297 | ||
|
|
2cff081f2b | ||
|
|
9055d9567a | ||
|
|
f99cb3f649 | ||
|
|
dfdd79d8cf | ||
|
|
8ec4f0b5bd | ||
|
|
b912918d8b | ||
|
|
ef88f3ed09 | ||
|
|
f5d4b2e6cd | ||
|
|
d909f2bc4f | ||
|
|
520a2c96ff | ||
|
|
12b9b805e2 | ||
|
|
9bfb189fa7 | ||
|
|
322fa36359 | ||
|
|
4a47e11a16 | ||
|
|
83249cd9c2 | ||
|
|
c6185b30ba | ||
|
|
9ce08c586c | ||
|
|
a8d3226e99 | ||
|
|
94212d103e | ||
|
|
608791fd7f | ||
|
|
7d92ec5ddf | ||
|
|
9157dee0db | ||
|
|
677520aa8e | ||
|
|
16dcc0969b | ||
|
|
09e59ccf44 | ||
|
|
a8f2cbc2b1 | ||
|
|
c00d0d302d | ||
|
|
5a7a1dc92e | ||
|
|
c480431ec0 | ||
|
|
f7fc2e0b00 | ||
|
|
397e641f2f | ||
|
|
00cbfaf40e | ||
|
|
dc4604f5a5 | ||
|
|
40b6e1624f | ||
|
|
22e843abc6 | ||
|
|
3c70a2d7df | ||
|
|
541effb8cb | ||
|
|
248ffa15a2 | ||
|
|
5843326b5c | ||
|
|
3a2b0a2feb | ||
|
|
07dd6d5c8d | ||
|
|
708d12624f | ||
|
|
3eddd3114f | ||
|
|
61ce7252e6 | ||
|
|
b86aeb68ae | ||
|
|
cf025e1924 | ||
|
|
a200ced2d6 | ||
|
|
c04e59611b | ||
|
|
c5a87c95d8 | ||
|
|
797f675285 | ||
|
|
c32c810ae7 | ||
|
|
32fe084630 | ||
|
|
0715c4ac5a | ||
|
|
99928b82ed | ||
|
|
377c6b4cc8 | ||
|
|
2939c89f7a | ||
|
|
bb6cc92728 | ||
|
|
d736426529 | ||
|
|
806d42852c | ||
|
|
2590d8a27f | ||
|
|
676bcf39a5 | ||
|
|
94364f724e | ||
|
|
cb85a756a0 | ||
|
|
e7886d0e57 | ||
|
|
0fa5a1f274 | ||
|
|
15bb846a5f | ||
|
|
5c454bdd8c | ||
|
|
f194c70e8a | ||
|
|
179270ffc1 | ||
|
|
1f78882cdc | ||
|
|
f0f6c229f6 | ||
|
|
2f6dd2ab81 | ||
|
|
6ec223c515 | ||
|
|
401717d739 | ||
|
|
527409d05f | ||
|
|
d3d2e2188d | ||
|
|
141af7cc87 | ||
|
|
6e3dddede0 | ||
|
|
683fe26034 | ||
|
|
ea1b8a3999 | ||
|
|
5f0efc19fa | ||
|
|
0dfd336729 | ||
|
|
b0758fd109 | ||
|
|
50775d0c53 | ||
|
|
9874d40d29 | ||
|
|
044ee9b08a | ||
|
|
d66494dcb0 | ||
|
|
86d6b8ef21 | ||
|
|
0f387eeac2 | ||
|
|
3195f0c828 | ||
|
|
d98ccdfa06 | ||
|
|
c8b02241af | ||
|
|
146d84bbf8 | ||
|
|
f95b33049e | ||
|
|
bfa189e2ac | ||
|
|
19b2e56d02 | ||
|
|
b754706e44 | ||
|
|
9db32f4d26 | ||
|
|
acb2bbb2a3 | ||
|
|
06f987ad58 | ||
|
|
925a2cca7e | ||
|
|
3ad9c026a5 | ||
|
|
7d9a68bf17 | ||
|
|
d7c784ef2f | ||
|
|
4ca8faa9c9 | ||
|
|
393f6b7666 | ||
|
|
830b83f653 | ||
|
|
f77f91ef49 | ||
|
|
78ddb998a2 | ||
|
|
b12f4d97f8 | ||
|
|
ee3085e15e | ||
|
|
53e96e5adf | ||
|
|
6f60eb9e1a | ||
|
|
845f384df6 | ||
|
|
39c52c9ecf |
4
.bazelrc
4
.bazelrc
@@ -14,6 +14,10 @@ build:linux --cxxopt=-std=c++20
|
||||
build:macos --cxxopt=-std=c++20 --cpu=darwin_x86_64
|
||||
build:windows --cxxopt=/std:c++20 --cxxopt=/Zc:preprocessor
|
||||
|
||||
# this requires developer mode, but is required to have pack installer functioning
|
||||
startup --windows_enable_symlinks
|
||||
common --enable_runfiles
|
||||
|
||||
common --registry=file:///%workspace%/misc/bazel/registry
|
||||
common --registry=https://bcr.bazel.build
|
||||
|
||||
|
||||
2
.github/workflows/buildifier.yml
vendored
2
.github/workflows/buildifier.yml
vendored
@@ -24,5 +24,5 @@ jobs:
|
||||
extra_args: >
|
||||
buildifier --all-files 2>&1 ||
|
||||
(
|
||||
echo -e "In order to format all bazel files, please run:\n bazel run //:buildifier"; exit 1
|
||||
echo -e "In order to format all bazel files, please run:\n bazel run //misc/bazel:buildifier"; exit 1
|
||||
)
|
||||
|
||||
5
.lfsconfig
Normal file
5
.lfsconfig
Normal file
@@ -0,0 +1,5 @@
|
||||
[lfs]
|
||||
# codeql is publicly forked by many users, and we don't want any LFS file polluting their working
|
||||
# copies. We therefore exclude everything by default.
|
||||
# For files required by bazel builds, use rules in `misc/bazel/lfs.bzl` to download them on demand.
|
||||
fetchinclude = /nothing
|
||||
@@ -26,7 +26,14 @@ repos:
|
||||
name: Format bazel files
|
||||
files: \.(bazel|bzl)
|
||||
language: system
|
||||
entry: bazel run //:buildifier
|
||||
entry: bazel run //misc/bazel:buildifier
|
||||
pass_filenames: false
|
||||
|
||||
- id: go-gen
|
||||
name: Check checked in generated files in go
|
||||
files: ^go/.*
|
||||
language: system
|
||||
entry: bazel run //go:gen
|
||||
pass_filenames: false
|
||||
|
||||
- id: codeql-format
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
load("@buildifier_prebuilt//:rules.bzl", "buildifier")
|
||||
|
||||
buildifier(
|
||||
name = "buildifier",
|
||||
exclude_patterns = [
|
||||
"./.git/*",
|
||||
],
|
||||
lint_mode = "fix",
|
||||
)
|
||||
|
||||
@@ -13,7 +13,8 @@ local_path_override(
|
||||
|
||||
# see https://registry.bazel.build/ for a list of available packages
|
||||
|
||||
bazel_dep(name = "platforms", version = "0.0.8")
|
||||
bazel_dep(name = "platforms", version = "0.0.9")
|
||||
bazel_dep(name = "rules_go", version = "0.47.0")
|
||||
bazel_dep(name = "rules_pkg", version = "0.10.1")
|
||||
bazel_dep(name = "rules_nodejs", version = "6.0.3")
|
||||
bazel_dep(name = "rules_python", version = "0.31.0")
|
||||
@@ -21,6 +22,7 @@ bazel_dep(name = "bazel_skylib", version = "1.5.0")
|
||||
bazel_dep(name = "abseil-cpp", version = "20240116.0", repo_name = "absl")
|
||||
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
|
||||
bazel_dep(name = "fmt", version = "10.0.0")
|
||||
bazel_dep(name = "gazelle", version = "0.36.0")
|
||||
|
||||
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
|
||||
|
||||
@@ -52,6 +54,9 @@ node.toolchain(
|
||||
)
|
||||
use_repo(node, "nodejs", "nodejs_toolchains")
|
||||
|
||||
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
|
||||
go_sdk.download(version = "1.22.2")
|
||||
|
||||
register_toolchains(
|
||||
"@nodejs_toolchains//:all",
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.13.0
|
||||
version: 0.13.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -790,6 +790,27 @@ private predicate simple_comparison_eq(Instruction test, Operand op, int k, Abst
|
||||
exists(switch.getSuccessor(case)) and
|
||||
case.getValue().toInt() = k
|
||||
)
|
||||
or
|
||||
// There's no implicit CompareInstruction in files compiled as C since C
|
||||
// doesn't have implicit boolean conversions. So instead we check whether
|
||||
// there's a branch on a value of pointer or integer type.
|
||||
exists(ConditionalBranchInstruction branch, IRType type |
|
||||
not test instanceof CompareInstruction and
|
||||
type = test.getResultIRType() and
|
||||
(type instanceof IRAddressType or type instanceof IRIntegerType) and
|
||||
test = branch.getCondition() and
|
||||
op.getDef() = test
|
||||
|
|
||||
// We'd like to also include a case such as:
|
||||
// ```
|
||||
// k = 1 and
|
||||
// value.(BooleanValue).getValue() = true
|
||||
// ```
|
||||
// but all we know is that the value is non-zero in the true branch.
|
||||
// So we can only conclude something in the false branch.
|
||||
k = 0 and
|
||||
value.(BooleanValue).getValue() = false
|
||||
)
|
||||
}
|
||||
|
||||
private predicate complex_eq(
|
||||
|
||||
@@ -1665,3 +1665,311 @@ class DataFlowSecondLevelScope extends TDataFlowSecondLevelScope {
|
||||
|
||||
/** Gets the second-level scope containing the node `n`, if any. */
|
||||
DataFlowSecondLevelScope getSecondLevelScope(Node n) { result.getANode() = n }
|
||||
|
||||
/**
|
||||
* Module that defines flow through iterators.
|
||||
* For example,
|
||||
* ```cpp
|
||||
* auto it = v.begin();
|
||||
* *it = source();
|
||||
* ...
|
||||
* sink(v[0]);
|
||||
* ```
|
||||
*/
|
||||
module IteratorFlow {
|
||||
private import codeql.ssa.Ssa as SsaImpl
|
||||
private import semmle.code.cpp.models.interfaces.Iterator as Interface
|
||||
private import semmle.code.cpp.models.implementations.Iterator as Impl
|
||||
|
||||
/**
|
||||
* A variable of some type that can produce an iterator.
|
||||
*/
|
||||
class SourceVariable extends Ssa::SourceVariable {
|
||||
SourceVariable() {
|
||||
exists(Interface::GetIteratorFunction gets, Cpp::FunctionInput input, int i |
|
||||
input.isParameterDerefOrQualifierObject(i) and
|
||||
gets.getsIterator(input, _)
|
||||
|
|
||||
this.getType().stripType() = gets.getParameter(i).getType().stripType()
|
||||
or
|
||||
i = -1 and
|
||||
this.getType().stripType() = gets.getDeclaringType()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private module SsaInput implements SsaImpl::InputSig<Location> {
|
||||
import Ssa::InputSigCommon
|
||||
|
||||
class SourceVariable = IteratorFlow::SourceVariable;
|
||||
|
||||
/** A call to function that dereferences an iterator. */
|
||||
private class IteratorPointerDereferenceCall extends CallInstruction {
|
||||
IteratorPointerDereferenceCall() {
|
||||
this.getStaticCallTarget() instanceof Impl::IteratorPointerDereferenceOperator
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to a function that obtains an iterator. */
|
||||
private class GetsIteratorCall extends CallInstruction {
|
||||
GetsIteratorCall() { this.getStaticCallTarget() instanceof Impl::GetIteratorFunction }
|
||||
}
|
||||
|
||||
/** A call to `operator++` or `operator--` on an iterator. */
|
||||
private class IteratorCrementCall extends CallInstruction {
|
||||
IteratorCrementCall() { this.getStaticCallTarget() instanceof Impl::IteratorCrementOperator }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an ultimate definition of `def`.
|
||||
*
|
||||
* Note: Unlike `def.getAnUltimateDefinition()` this predicate also
|
||||
* traverses back through iterator increment and decrement operations.
|
||||
*/
|
||||
private Ssa::Def getAnUltimateDefinition(Ssa::Def def) {
|
||||
result = def.getAnUltimateDefinition()
|
||||
or
|
||||
exists(IRBlock bb, int i, IteratorCrementCall crementCall, Ssa::SourceVariable sv |
|
||||
crementCall = def.getValue().asInstruction().(StoreInstruction).getSourceValue() and
|
||||
sv = def.getSourceVariable() and
|
||||
bb.getInstruction(i) = crementCall and
|
||||
Ssa::ssaDefReachesRead(sv, result.asDef(), bb, i)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `write` is an instruction that writes to address `address`
|
||||
*/
|
||||
private predicate isIteratorWrite(Instruction write, Operand address) {
|
||||
exists(Ssa::DefImpl writeDef, IRBlock bb, int i |
|
||||
writeDef.hasIndexInBlock(bb, i, _) and
|
||||
bb.getInstruction(i) = write and
|
||||
address = writeDef.getAddressOperand()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `writeToDeref` is a write to an iterator that was obtained
|
||||
* by `beginCall`. That is, the following instruction sequence holds:
|
||||
* ```cpp
|
||||
* it = container.begin(); // or a similar iterator-obtaining function call
|
||||
* ...
|
||||
* *it = value;
|
||||
* ```
|
||||
*/
|
||||
private predicate isIteratorStoreInstruction(
|
||||
GetsIteratorCall beginCall, Instruction writeToDeref
|
||||
) {
|
||||
exists(
|
||||
StoreInstruction beginStore, IRBlock bbStar, int iStar, Ssa::Def def,
|
||||
IteratorPointerDereferenceCall starCall, Ssa::Def ultimate, Operand address
|
||||
|
|
||||
isIteratorWrite(writeToDeref, address) and
|
||||
operandForFullyConvertedCall(address, starCall) and
|
||||
bbStar.getInstruction(iStar) = starCall and
|
||||
Ssa::ssaDefReachesRead(_, def.asDef(), bbStar, iStar) and
|
||||
ultimate = getAnUltimateDefinition*(def) and
|
||||
beginStore = ultimate.getValue().asInstruction() and
|
||||
operandForFullyConvertedCall(beginStore.getSourceValueOperand(), beginCall)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(bb, i)` contains a write to an iterator that may have been obtained
|
||||
* by calling `begin` (or related functions) on the variable `v`.
|
||||
*/
|
||||
predicate variableWrite(IRBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
certain = false and
|
||||
exists(GetsIteratorCall beginCall, Instruction writeToDeref, IRBlock bbQual, int iQual |
|
||||
isIteratorStoreInstruction(beginCall, writeToDeref) and
|
||||
bb.getInstruction(i) = writeToDeref and
|
||||
bbQual.getInstruction(iQual) = beginCall and
|
||||
Ssa::variableRead(bbQual, iQual, v, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `(bb, i)` reads the container variable `v`. */
|
||||
predicate variableRead(IRBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
Ssa::variableRead(bb, i, v, certain)
|
||||
}
|
||||
}
|
||||
|
||||
private module IteratorSsa = SsaImpl::Make<Location, SsaInput>;
|
||||
|
||||
cached
|
||||
private newtype TSsaDef =
|
||||
TDef(IteratorSsa::DefinitionExt def) or
|
||||
TPhi(PhiNode phi)
|
||||
|
||||
abstract private class SsaDef extends TSsaDef {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/** Gets the underlying non-phi definition or use. */
|
||||
IteratorSsa::DefinitionExt asDef() { none() }
|
||||
|
||||
/** Gets the underlying phi node. */
|
||||
PhiNode asPhi() { none() }
|
||||
|
||||
/** Gets the location of this element. */
|
||||
abstract Location getLocation();
|
||||
}
|
||||
|
||||
private class Def extends TDef, SsaDef {
|
||||
IteratorSsa::DefinitionExt def;
|
||||
|
||||
Def() { this = TDef(def) }
|
||||
|
||||
final override IteratorSsa::DefinitionExt asDef() { result = def }
|
||||
|
||||
final override Location getLocation() { result = this.getImpl().getLocation() }
|
||||
|
||||
/** Gets the variable written to by this definition. */
|
||||
final SourceVariable getSourceVariable() { result = def.getSourceVariable() }
|
||||
|
||||
override string toString() { result = def.toString() }
|
||||
|
||||
/**
|
||||
* Holds if this definition (or use) has index `index` in block `block`,
|
||||
* and is a definition (or use) of the variable `sv`.
|
||||
*/
|
||||
predicate hasIndexInBlock(IRBlock block, int index, SourceVariable sv) {
|
||||
def.definesAt(sv, block, index, _)
|
||||
}
|
||||
|
||||
private Ssa::DefImpl getImpl() {
|
||||
exists(IRBlock bb, int i |
|
||||
this.hasIndexInBlock(bb, i, _) and
|
||||
result.hasIndexInBlock(bb, i)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the value written by this definition (i.e., the "right-hand side"). */
|
||||
Node0Impl getValue() { result = this.getImpl().getValue() }
|
||||
|
||||
/** Gets the indirection index of this definition. */
|
||||
int getIndirectionIndex() { result = this.getImpl().getIndirectionIndex() }
|
||||
}
|
||||
|
||||
private class Phi extends TPhi, SsaDef {
|
||||
PhiNode phi;
|
||||
|
||||
Phi() { this = TPhi(phi) }
|
||||
|
||||
final override PhiNode asPhi() { result = phi }
|
||||
|
||||
final override Location getLocation() { result = phi.getBasicBlock().getLocation() }
|
||||
|
||||
override string toString() { result = phi.toString() }
|
||||
|
||||
SsaIteratorNode getNode() { result.getIteratorFlowNode() = phi }
|
||||
}
|
||||
|
||||
private class PhiNode extends IteratorSsa::DefinitionExt {
|
||||
PhiNode() {
|
||||
this instanceof IteratorSsa::PhiNode or
|
||||
this instanceof IteratorSsa::PhiReadNode
|
||||
}
|
||||
|
||||
SsaIteratorNode getNode() { result.getIteratorFlowNode() = this }
|
||||
}
|
||||
|
||||
cached
|
||||
private module IteratorSsaCached {
|
||||
cached
|
||||
predicate adjacentDefRead(IRBlock bb1, int i1, SourceVariable sv, IRBlock bb2, int i2) {
|
||||
IteratorSsa::adjacentDefReadExt(_, sv, bb1, i1, bb2, i2)
|
||||
or
|
||||
exists(PhiNode phi |
|
||||
IteratorSsa::lastRefRedefExt(_, sv, bb1, i1, phi) and
|
||||
phi.definesAt(sv, bb2, i2, _)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Node getAPriorDefinition(IteratorSsa::DefinitionExt next) {
|
||||
exists(IRBlock bb, int i, SourceVariable sv, IteratorSsa::DefinitionExt def |
|
||||
IteratorSsa::lastRefRedefExt(pragma[only_bind_into](def), pragma[only_bind_into](sv),
|
||||
pragma[only_bind_into](bb), pragma[only_bind_into](i), next) and
|
||||
nodeToDefOrUse(result, sv, bb, i, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The set of nodes necessary for iterator flow. */
|
||||
class IteratorFlowNode instanceof PhiNode {
|
||||
/** Gets a textual representation of this node. */
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
/** Gets the type of this node. */
|
||||
DataFlowType getType() {
|
||||
exists(Ssa::SourceVariable sv |
|
||||
super.definesAt(sv, _, _, _) and
|
||||
result = sv.getType()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `Declaration` that contains this block. */
|
||||
Declaration getFunction() { result = super.getBasicBlock().getEnclosingFunction() }
|
||||
|
||||
/** Gets the locatino of this node. */
|
||||
Location getLocation() { result = super.getBasicBlock().getLocation() }
|
||||
}
|
||||
|
||||
private import IteratorSsaCached
|
||||
|
||||
private predicate defToNode(Node node, Def def, boolean uncertain) {
|
||||
(
|
||||
nodeHasOperand(node, def.getValue().asOperand(), def.getIndirectionIndex())
|
||||
or
|
||||
nodeHasInstruction(node, def.getValue().asInstruction(), def.getIndirectionIndex())
|
||||
) and
|
||||
uncertain = false
|
||||
}
|
||||
|
||||
private predicate nodeToDefOrUse(
|
||||
Node node, SourceVariable sv, IRBlock bb, int i, boolean uncertain
|
||||
) {
|
||||
exists(Def def |
|
||||
def.hasIndexInBlock(bb, i, sv) and
|
||||
defToNode(node, def, uncertain)
|
||||
)
|
||||
or
|
||||
useToNode(bb, i, sv, node) and
|
||||
uncertain = false
|
||||
}
|
||||
|
||||
private predicate useToNode(IRBlock bb, int i, SourceVariable sv, Node nodeTo) {
|
||||
exists(PhiNode phi |
|
||||
phi.definesAt(sv, bb, i, _) and
|
||||
nodeTo = phi.getNode()
|
||||
)
|
||||
or
|
||||
exists(Ssa::UseImpl use |
|
||||
use.hasIndexInBlock(bb, i, sv) and
|
||||
nodeTo = use.getNode()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `nodeFrom` flows to `nodeTo` in a single step.
|
||||
*/
|
||||
predicate localFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
exists(
|
||||
Node nFrom, SourceVariable sv, IRBlock bb1, int i1, IRBlock bb2, int i2, boolean uncertain
|
||||
|
|
||||
adjacentDefRead(bb1, i1, sv, bb2, i2) and
|
||||
nodeToDefOrUse(nFrom, sv, bb1, i1, uncertain) and
|
||||
useToNode(bb2, i2, sv, nodeTo)
|
||||
|
|
||||
if uncertain = true
|
||||
then
|
||||
nodeFrom =
|
||||
[
|
||||
nFrom,
|
||||
getAPriorDefinition(any(IteratorSsa::DefinitionExt next | next.definesAt(sv, bb1, i1, _)))
|
||||
]
|
||||
else nFrom = nodeFrom
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ private newtype TIRDataFlowNode =
|
||||
Ssa::isModifiableByCall(operand, indirectionIndex)
|
||||
} or
|
||||
TSsaPhiNode(Ssa::PhiNode phi) or
|
||||
TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or
|
||||
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
|
||||
Ssa::hasRawIndirectOperand(node.asOperand(), indirectionIndex)
|
||||
} or
|
||||
@@ -653,6 +654,30 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
||||
predicate isPhiRead() { phi.isPhiRead() }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: do not use.
|
||||
*
|
||||
* Dataflow nodes necessary for iterator flow
|
||||
*/
|
||||
class SsaIteratorNode extends Node, TSsaIteratorNode {
|
||||
IteratorFlow::IteratorFlowNode node;
|
||||
|
||||
SsaIteratorNode() { this = TSsaIteratorNode(node) }
|
||||
|
||||
/** Gets the phi node associated with this node. */
|
||||
IteratorFlow::IteratorFlowNode getIteratorFlowNode() { result = node }
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override Declaration getFunction() { result = node.getFunction() }
|
||||
|
||||
override DataFlowType getType() { result = node.getType() }
|
||||
|
||||
final override Location getLocationImpl() { result = node.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = node.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: do not use.
|
||||
*
|
||||
@@ -1190,11 +1215,11 @@ class UninitializedNode extends Node {
|
||||
LocalVariable v;
|
||||
|
||||
UninitializedNode() {
|
||||
exists(Ssa::Def def |
|
||||
exists(Ssa::Def def, Ssa::SourceVariable sv |
|
||||
def.getIndirectionIndex() = 0 and
|
||||
def.getValue().asInstruction() instanceof UninitializedInstruction and
|
||||
Ssa::nodeToDefOrUse(this, def, _) and
|
||||
v = def.getSourceVariable().getBaseVariable().(Ssa::BaseIRVariable).getIRVariable().getAst()
|
||||
Ssa::defToNode(this, def, sv, _, _, _) and
|
||||
v = sv.getBaseVariable().(Ssa::BaseIRVariable).getIRVariable().getAst()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2151,6 +2176,8 @@ private module Cached {
|
||||
// Def-use/Use-use flow
|
||||
Ssa::ssaFlow(nodeFrom, nodeTo)
|
||||
or
|
||||
IteratorFlow::localFlowStep(nodeFrom, nodeTo)
|
||||
or
|
||||
// Operand -> Instruction flow
|
||||
simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction())
|
||||
or
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -246,14 +246,6 @@ private module IteratorIndirections {
|
||||
baseType = super.getValueType()
|
||||
}
|
||||
|
||||
override predicate isAdditionalDereference(Instruction deref, Operand address) {
|
||||
exists(CallInstruction call |
|
||||
operandForFullyConvertedCall(getAUse(deref), call) and
|
||||
this = call.getStaticCallTarget().getClassAndName("operator*") and
|
||||
address = call.getThisArgumentOperand()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalWrite(Node0Impl value, Operand address, boolean certain) {
|
||||
exists(CallInstruction call | call.getArgumentOperand(0) = value.asOperand() |
|
||||
this = call.getStaticCallTarget().getClassAndName("operator=") and
|
||||
@@ -262,16 +254,6 @@ private module IteratorIndirections {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(Node node1, Node node2) {
|
||||
exists(CallInstruction call |
|
||||
// Taint through `operator+=` and `operator-=` on iterators.
|
||||
call.getStaticCallTarget() instanceof Iterator::IteratorAssignArithmeticOperator and
|
||||
node2.(IndirectArgumentOutNode).getPreUpdateNode() = node1 and
|
||||
node1.(IndirectOperand).hasOperandAndIndirectionIndex(call.getArgumentOperand(0), _) and
|
||||
node1.getType().getUnspecifiedType() = this
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalConversionFlow(Operand opFrom, Instruction instrTo) {
|
||||
// This is a bit annoying: Consider the following snippet:
|
||||
// ```
|
||||
@@ -589,230 +571,6 @@ private class BaseCallInstruction extends BaseSourceVariableInstruction, CallIns
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
private import semmle.code.cpp.models.interfaces.Iterator as Interfaces
|
||||
private import semmle.code.cpp.models.implementations.Iterator as Iterator
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as IO
|
||||
|
||||
/**
|
||||
* Holds if `next` is a instruction with a memory result that potentially
|
||||
* updates the memory produced by `prev`.
|
||||
*/
|
||||
private predicate memorySucc(Instruction prev, Instruction next) {
|
||||
prev = next.(ChiInstruction).getTotal()
|
||||
or
|
||||
// Phi inputs can be inexact.
|
||||
prev = next.(PhiInstruction).getAnInputOperand().getAnyDef()
|
||||
or
|
||||
prev = next.(CopyInstruction).getSourceValue()
|
||||
or
|
||||
exists(ReadSideEffectInstruction read |
|
||||
next = read.getPrimaryInstruction() and
|
||||
isAdditionalConversionFlow(_, next) and
|
||||
prev = read.getSideEffectOperand().getAnyDef()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `iteratorDerefAddress` is an address of an iterator dereference (i.e., `*it`)
|
||||
* that is used for a write operation that writes the value `value`. The `memory` instruction
|
||||
* represents the memory that the IR's SSA analysis determined was read by the call to `operator*`.
|
||||
*
|
||||
* The `numberOfLoads` integer represents the number of dereferences this write corresponds to
|
||||
* on the underlying container that produced the iterator.
|
||||
*/
|
||||
private predicate isChiAfterIteratorDef(
|
||||
Instruction memory, Operand iteratorDerefAddress, Node0Impl value, int numberOfLoads
|
||||
) {
|
||||
exists(
|
||||
BaseSourceVariableInstruction iteratorBase, ReadSideEffectInstruction read,
|
||||
Operand iteratorAddress
|
||||
|
|
||||
numberOfLoads >= 0 and
|
||||
isDef(_, value, iteratorDerefAddress, iteratorBase, numberOfLoads + 2, 0) and
|
||||
isUse(_, iteratorAddress, iteratorBase, numberOfLoads + 1, 0) and
|
||||
iteratorBase.getResultType() instanceof Interfaces::Iterator and
|
||||
isDereference(iteratorAddress.getDef(), read.getArgumentDef().getAUse(), _) and
|
||||
memory = read.getSideEffectOperand().getAnyDef()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isSource(Instruction instr, Operand iteratorAddress, int numberOfLoads) {
|
||||
getAUse(instr) = iteratorAddress and
|
||||
exists(BaseSourceVariableInstruction iteratorBase |
|
||||
iteratorBase.getResultType() instanceof Interfaces::Iterator and
|
||||
not iteratorBase.getResultType() instanceof Cpp::PointerType and
|
||||
isUse(_, iteratorAddress, iteratorBase, numberOfLoads - 1, 0)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isSink(Instruction instr, CallInstruction call) {
|
||||
getAUse(instr).(ArgumentOperand).getCall() = call and
|
||||
// Only include operations that may modify the object that the iterator points to.
|
||||
// The following is a non-exhaustive list of things that may modify the value of the
|
||||
// iterator, but never the value of what the iterator points to.
|
||||
// The more things we can exclude here, the faster the small dataflow-like analysis
|
||||
// done by `convertsIntoArgument` will converge.
|
||||
not exists(Function f | f = call.getStaticCallTarget() |
|
||||
f instanceof Iterator::IteratorCrementOperator or
|
||||
f instanceof Iterator::IteratorBinaryArithmeticOperator or
|
||||
f instanceof Iterator::IteratorAssignArithmeticOperator or
|
||||
f instanceof Iterator::IteratorCrementMemberOperator or
|
||||
f instanceof Iterator::IteratorBinaryArithmeticMemberOperator or
|
||||
f instanceof Iterator::IteratorAssignArithmeticMemberOperator or
|
||||
f instanceof Iterator::IteratorAssignmentMemberOperator
|
||||
)
|
||||
}
|
||||
|
||||
private predicate convertsIntoArgumentFwd(Instruction instr) {
|
||||
isSource(instr, _, _)
|
||||
or
|
||||
exists(Instruction prev | convertsIntoArgumentFwd(prev) |
|
||||
conversionFlow(unique( | | getAUse(prev)), instr, false, _)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate convertsIntoArgumentRev(Instruction instr) {
|
||||
convertsIntoArgumentFwd(instr) and
|
||||
(
|
||||
isSink(instr, _)
|
||||
or
|
||||
exists(Instruction next | convertsIntoArgumentRev(next) |
|
||||
conversionFlow(unique( | | getAUse(instr)), next, false, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate convertsIntoArgument(
|
||||
Operand iteratorAddress, CallInstruction call, int numberOfLoads
|
||||
) {
|
||||
exists(Instruction iteratorAddressDef |
|
||||
isSource(iteratorAddressDef, iteratorAddress, numberOfLoads) and
|
||||
isSink(iteratorAddressDef, call) and
|
||||
convertsIntoArgumentRev(pragma[only_bind_into](iteratorAddressDef))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isChiAfterIteratorArgument(
|
||||
Instruction memory, Operand iteratorAddress, int numberOfLoads
|
||||
) {
|
||||
// Ideally, `iteratorAddress` would be an `ArgumentOperand`, but there might be
|
||||
// various conversions applied to it before it becomes an argument.
|
||||
// So we do a small amount of flow to find the call that the iterator is passed to.
|
||||
exists(CallInstruction call | convertsIntoArgument(iteratorAddress, call, numberOfLoads) |
|
||||
exists(ReadSideEffectInstruction read |
|
||||
read.getPrimaryInstruction() = call and
|
||||
read.getSideEffectOperand().getAnyDef() = memory
|
||||
)
|
||||
or
|
||||
exists(LoadInstruction load |
|
||||
iteratorAddress.getDef() = load and
|
||||
memory = load.getSourceValueOperand().getAnyDef()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `iterator` is a `StoreInstruction` that stores the result of some function
|
||||
* returning an iterator into an address computed started at `containerBase`.
|
||||
*
|
||||
* For example, given a declaration like `std::vector<int>::iterator it = v.begin()`,
|
||||
* the `iterator` will be the `StoreInstruction` generated by the write to `it`, and
|
||||
* `containerBase` will be the address of `v`.
|
||||
*/
|
||||
private predicate isChiAfterBegin(
|
||||
BaseSourceVariableInstruction containerBase, StoreInstruction iterator
|
||||
) {
|
||||
exists(
|
||||
CallInstruction getIterator, Iterator::GetIteratorFunction getIteratorFunction,
|
||||
IO::FunctionInput input, int i
|
||||
|
|
||||
getIterator = iterator.getSourceValue() and
|
||||
getIteratorFunction = getIterator.getStaticCallTarget() and
|
||||
getIteratorFunction.getsIterator(input, _) and
|
||||
isDef(_, any(Node0Impl n | n.asInstruction() = iterator), _, _, 1, 0) and
|
||||
input.isParameterDerefOrQualifierObject(i) and
|
||||
isUse(_, getIterator.getArgumentOperand(i), containerBase, 0, 0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `iteratorAddress` is an address of an iterator that is used for
|
||||
* a read operation. The `memory` instruction represents the memory that
|
||||
* the IR's SSA analysis determined was read by the call to `operator*`.
|
||||
*
|
||||
* Finally, the `numberOfLoads` integer represents the number of dereferences
|
||||
* this read corresponds to on the underlying container that produced the iterator.
|
||||
*/
|
||||
private predicate isChiBeforeIteratorUse(
|
||||
Operand iteratorAddress, Instruction memory, int numberOfLoads
|
||||
) {
|
||||
exists(
|
||||
BaseSourceVariableInstruction iteratorBase, LoadInstruction load,
|
||||
ReadSideEffectInstruction read, Operand iteratorDerefAddress
|
||||
|
|
||||
numberOfLoads >= 0 and
|
||||
isUse(_, iteratorAddress, iteratorBase, numberOfLoads + 1, 0) and
|
||||
isUse(_, iteratorDerefAddress, iteratorBase, numberOfLoads + 2, 0) and
|
||||
iteratorBase.getResultType() instanceof Interfaces::Iterator and
|
||||
load.getSourceAddressOperand() = iteratorDerefAddress and
|
||||
read.getPrimaryInstruction() = load.getSourceAddress() and
|
||||
memory = read.getSideEffectOperand().getAnyDef()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `iteratorDerefAddress` is an address of an iterator dereference (i.e., `*it`)
|
||||
* that is used for a write operation that writes the value `value` to a container that
|
||||
* created the iterator. `container` represents the base of the address of the container
|
||||
* that was used to create the iterator.
|
||||
*/
|
||||
cached
|
||||
predicate isIteratorDef(
|
||||
BaseSourceVariableInstruction container, Operand iteratorDerefAddress, Node0Impl value,
|
||||
int numberOfLoads, int indirectionIndex
|
||||
) {
|
||||
exists(Instruction memory, Instruction begin, int upper, int ind |
|
||||
isChiAfterIteratorDef(memory, iteratorDerefAddress, value, numberOfLoads) and
|
||||
memorySucc*(begin, memory) and
|
||||
isChiAfterBegin(container, begin) and
|
||||
upper = countIndirectionsForCppType(getResultLanguageType(container)) and
|
||||
ind = numberOfLoads + [1 .. upper] and
|
||||
indirectionIndex = ind - (numberOfLoads + 1)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `iteratorAddress` is an address of an iterator that is used for a
|
||||
* read operation to read a value from a container that created the iterator.
|
||||
* `container` represents the base of the address of the container that was used
|
||||
* to create the iterator.
|
||||
*/
|
||||
cached
|
||||
predicate isIteratorUse(
|
||||
BaseSourceVariableInstruction container, Operand iteratorAddress, int numberOfLoads,
|
||||
int indirectionIndex
|
||||
) {
|
||||
// Direct use
|
||||
exists(Instruction begin, Instruction memory, int upper, int ind |
|
||||
isChiBeforeIteratorUse(iteratorAddress, memory, numberOfLoads) and
|
||||
memorySucc*(begin, memory) and
|
||||
isChiAfterBegin(container, begin) and
|
||||
upper = countIndirectionsForCppType(getResultLanguageType(container)) and
|
||||
ind = numberOfLoads + [1 .. upper] and
|
||||
indirectionIndex = ind - (numberOfLoads + 1)
|
||||
)
|
||||
or
|
||||
// Use through function output
|
||||
exists(Instruction memory, Instruction begin, int upper, int ind |
|
||||
isChiAfterIteratorArgument(memory, iteratorAddress, numberOfLoads) and
|
||||
memorySucc*(begin, memory) and
|
||||
isChiAfterBegin(container, begin) and
|
||||
upper = countIndirectionsForCppType(getResultLanguageType(container)) and
|
||||
ind = numberOfLoads + [1 .. upper] and
|
||||
indirectionIndex = ind - (numberOfLoads - 1)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `op` is the only use of its defining instruction, and that op is used in a conversation */
|
||||
private predicate isConversion(Operand op) {
|
||||
exists(Instruction def, Operand use |
|
||||
|
||||
@@ -17,18 +17,11 @@ private import Imports::IRType
|
||||
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
|
||||
* by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
class IRVariable extends TIRVariable {
|
||||
abstract private class AbstractIRVariable extends TIRVariable {
|
||||
Language::Declaration func;
|
||||
|
||||
IRVariable() {
|
||||
this = TIRUserVariable(_, _, func) or
|
||||
this = TIRTempVariable(func, _, _, _) or
|
||||
this = TIRStringLiteral(func, _, _, _) or
|
||||
this = TIRDynamicInitializationFlag(func, _, _)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Holds if this variable's value cannot be changed within a function. Currently used for string
|
||||
@@ -49,13 +42,13 @@ class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
Language::LanguageType getLanguageType() { none() }
|
||||
abstract Language::LanguageType getLanguageType();
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
Language::AST getAst() { none() }
|
||||
abstract Language::AST getAst();
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = this.getAst() }
|
||||
@@ -64,7 +57,7 @@ class IRVariable extends TIRVariable {
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
* within the function.
|
||||
*/
|
||||
string getUniqueId() { none() }
|
||||
abstract string getUniqueId();
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
@@ -74,7 +67,7 @@ class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final IRFunction getEnclosingIRFunction() { result.getFunction() = func }
|
||||
final IRFunction getEnclosingIRFunction() { result.getFunction() = this.getEnclosingFunction() }
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
@@ -82,10 +75,18 @@ class IRVariable extends TIRVariable {
|
||||
final Language::Declaration getEnclosingFunction() { result = func }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable referenced by the IR for a function.
|
||||
*
|
||||
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
|
||||
* by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
final class IRVariable = AbstractIRVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
class IRUserVariable extends AbstractIRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
Language::LanguageType type;
|
||||
|
||||
@@ -114,26 +115,29 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
|
||||
* parameters, non-static local variables, and temporary variables.
|
||||
*/
|
||||
class IRAutomaticVariable extends IRVariable {
|
||||
IRAutomaticVariable() {
|
||||
exists(Language::Variable var |
|
||||
this = TIRUserVariable(var, _, func) and
|
||||
Language::isVariableAutomatic(var)
|
||||
)
|
||||
or
|
||||
this = TIRTempVariable(func, _, _, _)
|
||||
}
|
||||
abstract private class AbstractIRAutomaticVariable extends AbstractIRVariable { }
|
||||
|
||||
/**
|
||||
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
|
||||
* parameters, non-static local variables, and temporary variables.
|
||||
*/
|
||||
final class IRAutomaticVariable = AbstractIRAutomaticVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable that is allocated on the stack. This includes all parameters and
|
||||
* non-static local variables.
|
||||
*/
|
||||
private class AbstractIRAutomaticUserVariable extends IRUserVariable, AbstractIRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-declared variable that is allocated on the stack. This includes all parameters and
|
||||
* non-static local variables.
|
||||
*/
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
final class IRAutomaticUserVariable = AbstractIRAutomaticUserVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable that is not allocated on the stack. This includes all global variables,
|
||||
@@ -151,16 +155,10 @@ class IRStaticUserVariable extends IRUserVariable {
|
||||
* A variable that is not user-declared. This includes temporary variables generated as part of IR
|
||||
* construction, as well as string literals.
|
||||
*/
|
||||
class IRGeneratedVariable extends IRVariable {
|
||||
abstract private class AbstractIRGeneratedVariable extends AbstractIRVariable {
|
||||
Language::AST ast;
|
||||
Language::LanguageType type;
|
||||
|
||||
IRGeneratedVariable() {
|
||||
this = TIRTempVariable(func, ast, _, type) or
|
||||
this = TIRStringLiteral(func, ast, type, _) or
|
||||
this = TIRDynamicInitializationFlag(func, ast, type)
|
||||
}
|
||||
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
final override Language::AST getAst() { result = ast }
|
||||
@@ -196,12 +194,20 @@ class IRGeneratedVariable extends IRVariable {
|
||||
string getBaseString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable that is not user-declared. This includes temporary variables generated as part of IR
|
||||
* construction, as well as string literals.
|
||||
*/
|
||||
final class IRGeneratedVariable = AbstractIRGeneratedVariable;
|
||||
|
||||
/**
|
||||
* A temporary variable introduced by IR construction. The most common examples are the variable
|
||||
* generated to hold the return value of a function, or the variable generated to hold the result of
|
||||
* a condition operator (`a ? b : c`).
|
||||
*/
|
||||
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
class IRTempVariable extends AbstractIRGeneratedVariable, AbstractIRAutomaticVariable,
|
||||
TIRTempVariable
|
||||
{
|
||||
TempVariableTag tag;
|
||||
|
||||
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
|
||||
@@ -241,7 +247,7 @@ class IRThrowVariable extends IRTempVariable {
|
||||
* A temporary variable generated to hold the contents of all arguments passed to the `...` of a
|
||||
* function that accepts a variable number of arguments.
|
||||
*/
|
||||
class IREllipsisVariable extends IRTempVariable, IRParameter {
|
||||
class IREllipsisVariable extends IRTempVariable, AbstractIRParameter {
|
||||
IREllipsisVariable() { tag = EllipsisTempVar() }
|
||||
|
||||
final override string toString() { result = "#ellipsis" }
|
||||
@@ -252,7 +258,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
|
||||
/**
|
||||
* A temporary variable generated to hold the `this` pointer.
|
||||
*/
|
||||
class IRThisVariable extends IRTempVariable, IRParameter {
|
||||
class IRThisVariable extends IRTempVariable, AbstractIRParameter {
|
||||
IRThisVariable() { tag = ThisTempVar() }
|
||||
|
||||
final override string toString() { result = "#this" }
|
||||
@@ -264,7 +270,7 @@ class IRThisVariable extends IRTempVariable, IRParameter {
|
||||
* A variable generated to represent the contents of a string literal. This variable acts much like
|
||||
* a read-only global variable.
|
||||
*/
|
||||
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
|
||||
class IRStringLiteral extends AbstractIRGeneratedVariable, TIRStringLiteral {
|
||||
Language::StringLiteral literal;
|
||||
|
||||
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
|
||||
@@ -288,7 +294,7 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
|
||||
* used to model the runtime initialization of static local variables in C++, as well as static
|
||||
* fields in C#.
|
||||
*/
|
||||
class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitializationFlag {
|
||||
class IRDynamicInitializationFlag extends AbstractIRGeneratedVariable, TIRDynamicInitializationFlag {
|
||||
Language::Variable var;
|
||||
|
||||
IRDynamicInitializationFlag() {
|
||||
@@ -314,24 +320,24 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial
|
||||
* An IR variable which acts like a function parameter, including positional parameters and the
|
||||
* temporary variables generated for `this` and ellipsis parameters.
|
||||
*/
|
||||
class IRParameter extends IRAutomaticVariable {
|
||||
IRParameter() {
|
||||
this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter
|
||||
or
|
||||
this = TIRTempVariable(_, _, ThisTempVar(), _)
|
||||
or
|
||||
this = TIRTempVariable(_, _, EllipsisTempVar(), _)
|
||||
}
|
||||
|
||||
abstract private class AbstractIRParameter extends AbstractIRAutomaticVariable {
|
||||
/**
|
||||
* Gets the zero-based index of this parameter. The `this` parameter has index -1.
|
||||
*/
|
||||
int getIndex() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR variable which acts like a function parameter, including positional parameters and the
|
||||
* temporary variables generated for `this` and ellipsis parameters.
|
||||
*/
|
||||
final class IRParameter = AbstractIRParameter;
|
||||
|
||||
/**
|
||||
* An IR variable representing a positional parameter.
|
||||
*/
|
||||
class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable {
|
||||
class IRPositionalParameter extends AbstractIRParameter, AbstractIRAutomaticUserVariable {
|
||||
IRPositionalParameter() { this.getVariable() instanceof Language::Parameter }
|
||||
|
||||
final override int getIndex() { result = this.getVariable().(Language::Parameter).getIndex() }
|
||||
}
|
||||
|
||||
@@ -17,18 +17,11 @@ private import Imports::IRType
|
||||
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
|
||||
* by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
class IRVariable extends TIRVariable {
|
||||
abstract private class AbstractIRVariable extends TIRVariable {
|
||||
Language::Declaration func;
|
||||
|
||||
IRVariable() {
|
||||
this = TIRUserVariable(_, _, func) or
|
||||
this = TIRTempVariable(func, _, _, _) or
|
||||
this = TIRStringLiteral(func, _, _, _) or
|
||||
this = TIRDynamicInitializationFlag(func, _, _)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Holds if this variable's value cannot be changed within a function. Currently used for string
|
||||
@@ -49,13 +42,13 @@ class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
Language::LanguageType getLanguageType() { none() }
|
||||
abstract Language::LanguageType getLanguageType();
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
Language::AST getAst() { none() }
|
||||
abstract Language::AST getAst();
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = this.getAst() }
|
||||
@@ -64,7 +57,7 @@ class IRVariable extends TIRVariable {
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
* within the function.
|
||||
*/
|
||||
string getUniqueId() { none() }
|
||||
abstract string getUniqueId();
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
@@ -74,7 +67,7 @@ class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final IRFunction getEnclosingIRFunction() { result.getFunction() = func }
|
||||
final IRFunction getEnclosingIRFunction() { result.getFunction() = this.getEnclosingFunction() }
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
@@ -82,10 +75,18 @@ class IRVariable extends TIRVariable {
|
||||
final Language::Declaration getEnclosingFunction() { result = func }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable referenced by the IR for a function.
|
||||
*
|
||||
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
|
||||
* by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
final class IRVariable = AbstractIRVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
class IRUserVariable extends AbstractIRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
Language::LanguageType type;
|
||||
|
||||
@@ -114,26 +115,29 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
|
||||
* parameters, non-static local variables, and temporary variables.
|
||||
*/
|
||||
class IRAutomaticVariable extends IRVariable {
|
||||
IRAutomaticVariable() {
|
||||
exists(Language::Variable var |
|
||||
this = TIRUserVariable(var, _, func) and
|
||||
Language::isVariableAutomatic(var)
|
||||
)
|
||||
or
|
||||
this = TIRTempVariable(func, _, _, _)
|
||||
}
|
||||
abstract private class AbstractIRAutomaticVariable extends AbstractIRVariable { }
|
||||
|
||||
/**
|
||||
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
|
||||
* parameters, non-static local variables, and temporary variables.
|
||||
*/
|
||||
final class IRAutomaticVariable = AbstractIRAutomaticVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable that is allocated on the stack. This includes all parameters and
|
||||
* non-static local variables.
|
||||
*/
|
||||
private class AbstractIRAutomaticUserVariable extends IRUserVariable, AbstractIRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-declared variable that is allocated on the stack. This includes all parameters and
|
||||
* non-static local variables.
|
||||
*/
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
final class IRAutomaticUserVariable = AbstractIRAutomaticUserVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable that is not allocated on the stack. This includes all global variables,
|
||||
@@ -151,16 +155,10 @@ class IRStaticUserVariable extends IRUserVariable {
|
||||
* A variable that is not user-declared. This includes temporary variables generated as part of IR
|
||||
* construction, as well as string literals.
|
||||
*/
|
||||
class IRGeneratedVariable extends IRVariable {
|
||||
abstract private class AbstractIRGeneratedVariable extends AbstractIRVariable {
|
||||
Language::AST ast;
|
||||
Language::LanguageType type;
|
||||
|
||||
IRGeneratedVariable() {
|
||||
this = TIRTempVariable(func, ast, _, type) or
|
||||
this = TIRStringLiteral(func, ast, type, _) or
|
||||
this = TIRDynamicInitializationFlag(func, ast, type)
|
||||
}
|
||||
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
final override Language::AST getAst() { result = ast }
|
||||
@@ -196,12 +194,20 @@ class IRGeneratedVariable extends IRVariable {
|
||||
string getBaseString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable that is not user-declared. This includes temporary variables generated as part of IR
|
||||
* construction, as well as string literals.
|
||||
*/
|
||||
final class IRGeneratedVariable = AbstractIRGeneratedVariable;
|
||||
|
||||
/**
|
||||
* A temporary variable introduced by IR construction. The most common examples are the variable
|
||||
* generated to hold the return value of a function, or the variable generated to hold the result of
|
||||
* a condition operator (`a ? b : c`).
|
||||
*/
|
||||
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
class IRTempVariable extends AbstractIRGeneratedVariable, AbstractIRAutomaticVariable,
|
||||
TIRTempVariable
|
||||
{
|
||||
TempVariableTag tag;
|
||||
|
||||
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
|
||||
@@ -241,7 +247,7 @@ class IRThrowVariable extends IRTempVariable {
|
||||
* A temporary variable generated to hold the contents of all arguments passed to the `...` of a
|
||||
* function that accepts a variable number of arguments.
|
||||
*/
|
||||
class IREllipsisVariable extends IRTempVariable, IRParameter {
|
||||
class IREllipsisVariable extends IRTempVariable, AbstractIRParameter {
|
||||
IREllipsisVariable() { tag = EllipsisTempVar() }
|
||||
|
||||
final override string toString() { result = "#ellipsis" }
|
||||
@@ -252,7 +258,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
|
||||
/**
|
||||
* A temporary variable generated to hold the `this` pointer.
|
||||
*/
|
||||
class IRThisVariable extends IRTempVariable, IRParameter {
|
||||
class IRThisVariable extends IRTempVariable, AbstractIRParameter {
|
||||
IRThisVariable() { tag = ThisTempVar() }
|
||||
|
||||
final override string toString() { result = "#this" }
|
||||
@@ -264,7 +270,7 @@ class IRThisVariable extends IRTempVariable, IRParameter {
|
||||
* A variable generated to represent the contents of a string literal. This variable acts much like
|
||||
* a read-only global variable.
|
||||
*/
|
||||
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
|
||||
class IRStringLiteral extends AbstractIRGeneratedVariable, TIRStringLiteral {
|
||||
Language::StringLiteral literal;
|
||||
|
||||
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
|
||||
@@ -288,7 +294,7 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
|
||||
* used to model the runtime initialization of static local variables in C++, as well as static
|
||||
* fields in C#.
|
||||
*/
|
||||
class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitializationFlag {
|
||||
class IRDynamicInitializationFlag extends AbstractIRGeneratedVariable, TIRDynamicInitializationFlag {
|
||||
Language::Variable var;
|
||||
|
||||
IRDynamicInitializationFlag() {
|
||||
@@ -314,24 +320,24 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial
|
||||
* An IR variable which acts like a function parameter, including positional parameters and the
|
||||
* temporary variables generated for `this` and ellipsis parameters.
|
||||
*/
|
||||
class IRParameter extends IRAutomaticVariable {
|
||||
IRParameter() {
|
||||
this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter
|
||||
or
|
||||
this = TIRTempVariable(_, _, ThisTempVar(), _)
|
||||
or
|
||||
this = TIRTempVariable(_, _, EllipsisTempVar(), _)
|
||||
}
|
||||
|
||||
abstract private class AbstractIRParameter extends AbstractIRAutomaticVariable {
|
||||
/**
|
||||
* Gets the zero-based index of this parameter. The `this` parameter has index -1.
|
||||
*/
|
||||
int getIndex() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR variable which acts like a function parameter, including positional parameters and the
|
||||
* temporary variables generated for `this` and ellipsis parameters.
|
||||
*/
|
||||
final class IRParameter = AbstractIRParameter;
|
||||
|
||||
/**
|
||||
* An IR variable representing a positional parameter.
|
||||
*/
|
||||
class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable {
|
||||
class IRPositionalParameter extends AbstractIRParameter, AbstractIRAutomaticUserVariable {
|
||||
IRPositionalParameter() { this.getVariable() instanceof Language::Parameter }
|
||||
|
||||
final override int getIndex() { result = this.getVariable().(Language::Parameter).getIndex() }
|
||||
}
|
||||
|
||||
@@ -1163,6 +1163,8 @@ class TranslatedForStmt extends TranslatedLoop {
|
||||
class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
|
||||
override RangeBasedForStmt stmt;
|
||||
|
||||
override predicate handlesDestructorsExplicitly() { any() }
|
||||
|
||||
override TranslatedElement getChildInternal(int id) {
|
||||
id = 0 and result = this.getInitialization()
|
||||
or
|
||||
@@ -1216,6 +1218,19 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
|
||||
or
|
||||
child = this.getUpdate() and
|
||||
result = this.getCondition().getFirstInstruction(kind)
|
||||
or
|
||||
exists(int destructorId |
|
||||
destructorId >= this.getFirstDestructorCallIndex() and
|
||||
child = this.getChild(destructorId) and
|
||||
result = this.getChild(destructorId + 1).getFirstInstruction(kind)
|
||||
)
|
||||
or
|
||||
exists(int lastDestructorIndex |
|
||||
lastDestructorIndex =
|
||||
max(int n | exists(this.getChild(n)) and n >= this.getFirstDestructorCallIndex()) and
|
||||
child = this.getChild(lastDestructorIndex) and
|
||||
result = this.getParent().getChildSuccessor(this, kind)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
@@ -1231,7 +1246,9 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
|
||||
|
||||
override Instruction getChildFalseSuccessor(TranslatedCondition child, EdgeKind kind) {
|
||||
child = this.getCondition() and
|
||||
result = this.getParent().getChildSuccessor(this, kind)
|
||||
if this.hasAnImplicitDestructorCall()
|
||||
then result = this.getChild(this.getFirstDestructorCallIndex()).getFirstInstruction(kind)
|
||||
else result = this.getParent().getChildSuccessor(this, kind)
|
||||
}
|
||||
|
||||
private TranslatedDeclStmt getRangeVariableDeclStmt() {
|
||||
@@ -1276,6 +1293,11 @@ class TranslatedJumpStmt extends TranslatedStmt {
|
||||
override JumpStmt stmt;
|
||||
|
||||
override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
// The first instruction is a destructor call, if any.
|
||||
result = this.getChildInternal(0).getFirstInstruction(kind)
|
||||
or
|
||||
// Otherwise, the first (and only) instruction is a `NoOp`
|
||||
not exists(this.getChildInternal(0)) and
|
||||
result = this.getInstruction(OnlyInstructionTag()) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
@@ -1284,7 +1306,20 @@ class TranslatedJumpStmt extends TranslatedStmt {
|
||||
result = this.getInstruction(OnlyInstructionTag())
|
||||
}
|
||||
|
||||
override TranslatedElement getChildInternal(int id) { none() }
|
||||
private TranslatedCall getTranslatedImplicitDestructorCall(int id) {
|
||||
result.getExpr() = stmt.getImplicitDestructorCall(id)
|
||||
}
|
||||
|
||||
override TranslatedElement getLastChild() {
|
||||
result =
|
||||
this.getTranslatedImplicitDestructorCall(max(int id |
|
||||
exists(stmt.getImplicitDestructorCall(id))
|
||||
))
|
||||
}
|
||||
|
||||
override TranslatedElement getChildInternal(int id) {
|
||||
result = this.getTranslatedImplicitDestructorCall(id)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
@@ -1297,7 +1332,19 @@ class TranslatedJumpStmt extends TranslatedStmt {
|
||||
result = getTranslatedStmt(stmt.getTarget()).getFirstInstruction(kind)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) { none() }
|
||||
final override predicate handlesDestructorsExplicitly() { any() }
|
||||
|
||||
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
|
||||
exists(int id | child = this.getChildInternal(id) |
|
||||
// Transition to the next destructor call, if any.
|
||||
result = this.getChildInternal(id + 1).getFirstInstruction(kind)
|
||||
or
|
||||
// And otherwise, exit this element by flowing to the target of the jump.
|
||||
not exists(this.getChildInternal(id + 1)) and
|
||||
kind instanceof GotoEdge and
|
||||
result = this.getInstruction(OnlyInstructionTag())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private EdgeKind getCaseEdge(SwitchCase switchCase) {
|
||||
|
||||
@@ -17,18 +17,11 @@ private import Imports::IRType
|
||||
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
|
||||
* by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
class IRVariable extends TIRVariable {
|
||||
abstract private class AbstractIRVariable extends TIRVariable {
|
||||
Language::Declaration func;
|
||||
|
||||
IRVariable() {
|
||||
this = TIRUserVariable(_, _, func) or
|
||||
this = TIRTempVariable(func, _, _, _) or
|
||||
this = TIRStringLiteral(func, _, _, _) or
|
||||
this = TIRDynamicInitializationFlag(func, _, _)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Holds if this variable's value cannot be changed within a function. Currently used for string
|
||||
@@ -49,13 +42,13 @@ class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
Language::LanguageType getLanguageType() { none() }
|
||||
abstract Language::LanguageType getLanguageType();
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
Language::AST getAst() { none() }
|
||||
abstract Language::AST getAst();
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = this.getAst() }
|
||||
@@ -64,7 +57,7 @@ class IRVariable extends TIRVariable {
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
* within the function.
|
||||
*/
|
||||
string getUniqueId() { none() }
|
||||
abstract string getUniqueId();
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
@@ -74,7 +67,7 @@ class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final IRFunction getEnclosingIRFunction() { result.getFunction() = func }
|
||||
final IRFunction getEnclosingIRFunction() { result.getFunction() = this.getEnclosingFunction() }
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
@@ -82,10 +75,18 @@ class IRVariable extends TIRVariable {
|
||||
final Language::Declaration getEnclosingFunction() { result = func }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable referenced by the IR for a function.
|
||||
*
|
||||
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
|
||||
* by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
final class IRVariable = AbstractIRVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
class IRUserVariable extends AbstractIRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
Language::LanguageType type;
|
||||
|
||||
@@ -114,26 +115,29 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
|
||||
* parameters, non-static local variables, and temporary variables.
|
||||
*/
|
||||
class IRAutomaticVariable extends IRVariable {
|
||||
IRAutomaticVariable() {
|
||||
exists(Language::Variable var |
|
||||
this = TIRUserVariable(var, _, func) and
|
||||
Language::isVariableAutomatic(var)
|
||||
)
|
||||
or
|
||||
this = TIRTempVariable(func, _, _, _)
|
||||
}
|
||||
abstract private class AbstractIRAutomaticVariable extends AbstractIRVariable { }
|
||||
|
||||
/**
|
||||
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
|
||||
* parameters, non-static local variables, and temporary variables.
|
||||
*/
|
||||
final class IRAutomaticVariable = AbstractIRAutomaticVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable that is allocated on the stack. This includes all parameters and
|
||||
* non-static local variables.
|
||||
*/
|
||||
private class AbstractIRAutomaticUserVariable extends IRUserVariable, AbstractIRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-declared variable that is allocated on the stack. This includes all parameters and
|
||||
* non-static local variables.
|
||||
*/
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
final class IRAutomaticUserVariable = AbstractIRAutomaticUserVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable that is not allocated on the stack. This includes all global variables,
|
||||
@@ -151,16 +155,10 @@ class IRStaticUserVariable extends IRUserVariable {
|
||||
* A variable that is not user-declared. This includes temporary variables generated as part of IR
|
||||
* construction, as well as string literals.
|
||||
*/
|
||||
class IRGeneratedVariable extends IRVariable {
|
||||
abstract private class AbstractIRGeneratedVariable extends AbstractIRVariable {
|
||||
Language::AST ast;
|
||||
Language::LanguageType type;
|
||||
|
||||
IRGeneratedVariable() {
|
||||
this = TIRTempVariable(func, ast, _, type) or
|
||||
this = TIRStringLiteral(func, ast, type, _) or
|
||||
this = TIRDynamicInitializationFlag(func, ast, type)
|
||||
}
|
||||
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
final override Language::AST getAst() { result = ast }
|
||||
@@ -196,12 +194,20 @@ class IRGeneratedVariable extends IRVariable {
|
||||
string getBaseString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable that is not user-declared. This includes temporary variables generated as part of IR
|
||||
* construction, as well as string literals.
|
||||
*/
|
||||
final class IRGeneratedVariable = AbstractIRGeneratedVariable;
|
||||
|
||||
/**
|
||||
* A temporary variable introduced by IR construction. The most common examples are the variable
|
||||
* generated to hold the return value of a function, or the variable generated to hold the result of
|
||||
* a condition operator (`a ? b : c`).
|
||||
*/
|
||||
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
class IRTempVariable extends AbstractIRGeneratedVariable, AbstractIRAutomaticVariable,
|
||||
TIRTempVariable
|
||||
{
|
||||
TempVariableTag tag;
|
||||
|
||||
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
|
||||
@@ -241,7 +247,7 @@ class IRThrowVariable extends IRTempVariable {
|
||||
* A temporary variable generated to hold the contents of all arguments passed to the `...` of a
|
||||
* function that accepts a variable number of arguments.
|
||||
*/
|
||||
class IREllipsisVariable extends IRTempVariable, IRParameter {
|
||||
class IREllipsisVariable extends IRTempVariable, AbstractIRParameter {
|
||||
IREllipsisVariable() { tag = EllipsisTempVar() }
|
||||
|
||||
final override string toString() { result = "#ellipsis" }
|
||||
@@ -252,7 +258,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
|
||||
/**
|
||||
* A temporary variable generated to hold the `this` pointer.
|
||||
*/
|
||||
class IRThisVariable extends IRTempVariable, IRParameter {
|
||||
class IRThisVariable extends IRTempVariable, AbstractIRParameter {
|
||||
IRThisVariable() { tag = ThisTempVar() }
|
||||
|
||||
final override string toString() { result = "#this" }
|
||||
@@ -264,7 +270,7 @@ class IRThisVariable extends IRTempVariable, IRParameter {
|
||||
* A variable generated to represent the contents of a string literal. This variable acts much like
|
||||
* a read-only global variable.
|
||||
*/
|
||||
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
|
||||
class IRStringLiteral extends AbstractIRGeneratedVariable, TIRStringLiteral {
|
||||
Language::StringLiteral literal;
|
||||
|
||||
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
|
||||
@@ -288,7 +294,7 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
|
||||
* used to model the runtime initialization of static local variables in C++, as well as static
|
||||
* fields in C#.
|
||||
*/
|
||||
class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitializationFlag {
|
||||
class IRDynamicInitializationFlag extends AbstractIRGeneratedVariable, TIRDynamicInitializationFlag {
|
||||
Language::Variable var;
|
||||
|
||||
IRDynamicInitializationFlag() {
|
||||
@@ -314,24 +320,24 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial
|
||||
* An IR variable which acts like a function parameter, including positional parameters and the
|
||||
* temporary variables generated for `this` and ellipsis parameters.
|
||||
*/
|
||||
class IRParameter extends IRAutomaticVariable {
|
||||
IRParameter() {
|
||||
this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter
|
||||
or
|
||||
this = TIRTempVariable(_, _, ThisTempVar(), _)
|
||||
or
|
||||
this = TIRTempVariable(_, _, EllipsisTempVar(), _)
|
||||
}
|
||||
|
||||
abstract private class AbstractIRParameter extends AbstractIRAutomaticVariable {
|
||||
/**
|
||||
* Gets the zero-based index of this parameter. The `this` parameter has index -1.
|
||||
*/
|
||||
int getIndex() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR variable which acts like a function parameter, including positional parameters and the
|
||||
* temporary variables generated for `this` and ellipsis parameters.
|
||||
*/
|
||||
final class IRParameter = AbstractIRParameter;
|
||||
|
||||
/**
|
||||
* An IR variable representing a positional parameter.
|
||||
*/
|
||||
class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable {
|
||||
class IRPositionalParameter extends AbstractIRParameter, AbstractIRAutomaticUserVariable {
|
||||
IRPositionalParameter() { this.getVariable() instanceof Language::Parameter }
|
||||
|
||||
final override int getIndex() { result = this.getVariable().(Language::Parameter).getIndex() }
|
||||
}
|
||||
|
||||
@@ -560,7 +560,7 @@ private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMe
|
||||
TaintFunction, SideEffectFunction, AliasFunction
|
||||
{
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameterDeref(0) and
|
||||
(input.isParameterDeref(0) or input.isParameter(0)) and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
|
||||
@@ -579,17 +579,34 @@ private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMe
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { index = -1 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `begin` member function, or a related function, that returns an iterator.
|
||||
*/
|
||||
class BeginFunction extends MemberFunction {
|
||||
BeginFunction() {
|
||||
this.hasName(["begin", "cbegin", "rbegin", "crbegin", "before_begin", "cbefore_begin"]) and
|
||||
this.getType().getUnspecifiedType() instanceof Iterator
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An `end` member function, or a related function, that returns an iterator.
|
||||
*/
|
||||
class EndFunction extends MemberFunction {
|
||||
EndFunction() {
|
||||
this.hasName(["end", "cend", "rend", "crend"]) and
|
||||
this.getType().getUnspecifiedType() instanceof Iterator
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `begin` or `end` member function, or a related member function, that
|
||||
* returns an iterator.
|
||||
*/
|
||||
class BeginOrEndFunction extends MemberFunction {
|
||||
BeginOrEndFunction() {
|
||||
this.hasName([
|
||||
"begin", "cbegin", "rbegin", "crbegin", "end", "cend", "rend", "crend", "before_begin",
|
||||
"cbefore_begin"
|
||||
]) and
|
||||
this.getType().getUnspecifiedType() instanceof Iterator
|
||||
this instanceof BeginFunction or
|
||||
this instanceof EndFunction
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,8 @@ function.
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>cplusplus.com: <a href="http://www.tutorialspoint.com/cplusplus/cpp_functions.htm">C++ Functions</a>.</li>
|
||||
<li>CERT C Coding Standard: <a href="https://wiki.sei.cmu.edu/confluence/display/c/FIO47-C.+Use+valid+format+strings">FIO47-C. Use valid format strings</a>.</li>
|
||||
<li>Microsoft C Runtime Library Reference: <a href="https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/printf-printf-l-wprintf-wprintf-l">printf, wprintf</a>.</li>
|
||||
|
||||
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
|
||||
@@ -19,8 +19,8 @@ contents.
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>Review the format and arguments expected by the highlighted function calls. Update either
|
||||
the format or the arguments so that the expected number of arguments are passed to the
|
||||
<p>Review the format and arguments expected by the highlighted function calls. Update either
|
||||
the format or the arguments so that the expected number of arguments are passed to the
|
||||
function.
|
||||
</p>
|
||||
|
||||
@@ -30,11 +30,8 @@ function.
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>CERT C Coding
|
||||
Standard: <a href="https://www.securecoding.cert.org/confluence/display/c/FIO30-C.+Exclude+user+input+from+format+strings">FIO30-C. Exclude user input from format strings</a>.</li>
|
||||
<li>cplusplus.com: <a href="http://www.tutorialspoint.com/cplusplus/cpp_functions.htm">C++ Functions</a>.</li>
|
||||
<li>CERT C Coding Standard: <a href="https://wiki.sei.cmu.edu/confluence/display/c/FIO47-C.+Use+valid+format+strings">FIO47-C. Use valid format strings</a>.</li>
|
||||
<li>Microsoft C Runtime Library Reference: <a href="https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/printf-printf-l-wprintf-wprintf-l">printf, wprintf</a>.</li>
|
||||
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
int main() {
|
||||
printf("%s\n", 42); //printf will treat 42 as a char*, will most likely segfault
|
||||
return 0;
|
||||
}
|
||||
@@ -4,29 +4,33 @@
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>Each call to the <code>printf</code> function or a related function should include
|
||||
the type and sequence of arguments defined by the format. If the function is passed arguments
|
||||
the type and sequence of arguments defined by the format. If the function is passed arguments
|
||||
of a different type or in a different sequence then the arguments are reinterpreted to fit the type and sequence expected, resulting in unpredictable behavior.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>Review the format and arguments expected by the highlighted function calls. Update either
|
||||
the format or the arguments so that the expected type and sequence of arguments are passed to
|
||||
<p>Review the format and arguments expected by the highlighted function calls. Update either
|
||||
the format or the arguments so that the expected type and sequence of arguments are passed to
|
||||
the function.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
<example><sample src="WrongTypeFormatArguments.cpp" />
|
||||
<example>
|
||||
|
||||
<p>In the following example, the wrong format specifier is given for an integer format argument:</p>
|
||||
|
||||
<sample src="WrongTypeFormatArgumentsBad.cpp" />
|
||||
|
||||
<p>The corrected version uses <code>%i</code> as the format specifier for the integer format argument:</p>
|
||||
|
||||
<sample src="WrongTypeFormatArgumentsGood.cpp" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>CERT C Coding
|
||||
Standard: <a href="https://www.securecoding.cert.org/confluence/display/c/FIO30-C.+Exclude+user+input+from+format+strings">FIO30-C. Exclude user input from format strings</a>.</li>
|
||||
<li>cplusplus.com: <a href="http://www.tutorialspoint.com/cplusplus/cpp_functions.htm">C++ Functions</a>.</li>
|
||||
<li>CRT Alphabetical Function Reference: <a href="https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/printf-printf-l-wprintf-wprintf-l">printf, _printf_l, wprintf, _wprintf_l</a>.</li>
|
||||
|
||||
|
||||
|
||||
<li>Microsoft Learn: <a href="https://learn.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions?view=msvc-170">Format specification syntax: printf and wprintf functions</a>.</li>
|
||||
<li>cplusplus.com:<a href="https://cplusplus.com/reference/cstdio/printf/"></a>printf</li>
|
||||
<li>CERT C Coding Standard: <a href="https://wiki.sei.cmu.edu/confluence/display/c/FIO47-C.+Use+valid+format+strings">FIO47-C. Use valid format strings</a>.</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
int main() {
|
||||
printf("%s\n", 42); // BAD: printf will treat 42 as a char*, will most likely segfault
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
int main() {
|
||||
printf("%i\n", 42); // GOOD: printf will treat 42 as an int
|
||||
return 0;
|
||||
}
|
||||
@@ -2,19 +2,18 @@
|
||||
|
||||
void f_warning(int i)
|
||||
{
|
||||
// The usage of the logical not operator in this case is unlikely to be correct
|
||||
// BAD: the usage of the logical not operator in this case is unlikely to be correct
|
||||
// as the output is being used as an operator for a bit-wise and operation
|
||||
if (i & !FLAGS)
|
||||
if (i & !FLAGS)
|
||||
{
|
||||
// code
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void f_fixed(int i)
|
||||
{
|
||||
if (i & ~FLAGS) // Changing the logical not operator for the bit-wise not operator would fix this logic
|
||||
if (i & ~FLAGS) // GOOD: Changing the logical not operator for the bit-wise not operator would fix this logic
|
||||
{
|
||||
// code
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,13 @@
|
||||
<p>Carefully inspect the flagged expressions. Consider the intent in the code logic, and decide whether it is necessary to change the not operator.</p>
|
||||
</recommendation>
|
||||
|
||||
<example><sample src="IncorrectNotOperatorUsage.cpp" /></example>
|
||||
<example>
|
||||
<p>Here is an example of this issue and how it can be fixed:</p>
|
||||
|
||||
<sample src="IncorrectNotOperatorUsage.cpp" />
|
||||
|
||||
<p>In other cases, particularly when the expressions have <code>bool</code> type, the fix may instead be of the form <code>a && !b</code>.</p>
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
strncpy(dest, src, sizeof(src)); //wrong: size of dest should be used
|
||||
strncpy(dest, src, strlen(src)); //wrong: size of dest should be used
|
||||
@@ -3,7 +3,7 @@
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>The standard library function <code>strncpy</code> copies a source string to a destination buffer. The third argument defines the maximum number of characters to copy and should be less than
|
||||
<p>The standard library function <code>strncpy</code> copies a source string to a destination buffer. The third argument defines the maximum number of characters to copy and should be less than
|
||||
or equal to the size of the destination buffer. Calls of the form <code>strncpy(dest, src, strlen(src))</code> or <code>strncpy(dest, src, sizeof(src))</code> incorrectly set the third argument to the size of the source buffer. Executing a call of this type may cause a buffer overflow. Buffer overflows can lead to anything from a segmentation fault to a security vulnerability.</p>
|
||||
|
||||
</overview>
|
||||
@@ -12,14 +12,20 @@ or equal to the size of the destination buffer. Calls of the form <code>strncpy(
|
||||
not the source buffer.</p>
|
||||
|
||||
</recommendation>
|
||||
<example><sample src="StrncpyFlippedArgs.cpp" />
|
||||
|
||||
<example>
|
||||
<p>In the following examples, the size of the source buffer is incorrectly used as a parameter to <code>strncpy</code>:</p>
|
||||
|
||||
<sample src="StrncpyFlippedArgsBad.cpp" />
|
||||
|
||||
<p>The corrected version uses the size of the destination buffer, or a variable containing the size of the destination buffer as the size parameter to <code>strncpy</code>:</p>
|
||||
|
||||
<sample src="StrncpyFlippedArgsGood.cpp" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
|
||||
<li>cplusplus.com: <a href="http://www.cplusplus.com/reference/clibrary/cstring/strncpy/">strncpy</a>.</li>
|
||||
<li>cplusplus.com: <a href="https://cplusplus.com/reference/cstring/strncpy/">strncpy</a>.</li>
|
||||
<li>
|
||||
I. Gerg. <em>An Overview and Example of the Buffer-Overflow Exploit</em>. IANewsletter vol 7 no 4. 2005.
|
||||
</li>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
char src[256];
|
||||
char dest1[128];
|
||||
|
||||
...
|
||||
|
||||
strncpy(dest1, src, sizeof(src)); // wrong: size of dest should be used
|
||||
|
||||
char *dest2 = (char *)malloc(sz1 + sz2 + sz3);
|
||||
strncpy(dest2, src, strlen(src)); // wrong: size of dest should be used
|
||||
@@ -0,0 +1,10 @@
|
||||
char src[256];
|
||||
char dest1[128];
|
||||
|
||||
...
|
||||
|
||||
strncpy(dest1, src, sizeof(dest1)); // correct
|
||||
|
||||
size_t destSize = sz1 + sz2 + sz3;
|
||||
char *dest2 = (char *)malloc(destSize);
|
||||
strncpy(dest2, src, destSize); // correct
|
||||
@@ -30,6 +30,12 @@ This is because the temporary container is not bound to a rvalue reference.
|
||||
</p>
|
||||
<sample src="IteratorToExpiredContainerExtendedLifetime.cpp" />
|
||||
|
||||
<p>
|
||||
To fix <code>lifetime_of_temp_not_extended</code>, consider rewriting the code so that the lifetime of the temporary object is extended.
|
||||
In <code>fixed_lifetime_of_temp_not_extended</code>, the lifetime of the temporary object has been extended by storing it in an rvalue reference.
|
||||
</p>
|
||||
<sample src="IteratorToExpiredContainerExtendedLifetime-fixed.cpp" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
* @name Iterator to expired container
|
||||
* @description Using an iterator owned by a container whose lifetime has expired may lead to unexpected behavior.
|
||||
* @kind problem
|
||||
* @precision high
|
||||
* @precision medium
|
||||
* @id cpp/iterator-to-expired-container
|
||||
* @problem.severity warning
|
||||
* @security-severity 8.8
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-416
|
||||
@@ -61,14 +62,38 @@ DataFlow::Node getADestroyedNode(DataFlow::Node n) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate destroyedToBeginSink(DataFlow::Node sink, FunctionCall fc) {
|
||||
predicate destroyedToBeginSink(DataFlow::Node sink) {
|
||||
exists(CallInstruction call |
|
||||
call = sink.asOperand().(ThisArgumentOperand).getCall() and
|
||||
fc = call.getUnconvertedResultExpression() and
|
||||
call.getStaticCallTarget() instanceof BeginOrEndFunction
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node1` is the node corresponding to a qualifier of a destructor
|
||||
* call and `node2` is a node that is destroyed as a result of `node1` being
|
||||
* destroyed.
|
||||
*/
|
||||
private predicate qualifierToDestroyed(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
tempToDestructorSink(node1, _) and
|
||||
node2 = getADestroyedNode(node1)
|
||||
}
|
||||
|
||||
/**
|
||||
* A configuration to track flow from a destroyed node to a qualifier of
|
||||
* a `begin` or `end` function call.
|
||||
*
|
||||
* This configuration exists to prevent a cartesian product between all sinks and
|
||||
* all states in `Config::isSink`.
|
||||
*/
|
||||
module Config0 implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { qualifierToDestroyed(_, source) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { destroyedToBeginSink(sink) }
|
||||
}
|
||||
|
||||
module Flow0 = DataFlow::Global<Config0>;
|
||||
|
||||
/**
|
||||
* A configuration to track flow from a temporary variable to the qualifier of
|
||||
* a destructor call, and subsequently to a qualifier of a call to `begin` or
|
||||
@@ -78,12 +103,15 @@ module Config implements DataFlow::StateConfigSig {
|
||||
newtype FlowState =
|
||||
additional TempToDestructor() or
|
||||
additional DestroyedToBegin(DataFlow::Node n) {
|
||||
exists(DataFlow::Node thisOperand |
|
||||
tempToDestructorSink(thisOperand, _) and
|
||||
n = getADestroyedNode(thisOperand)
|
||||
)
|
||||
any(Flow0::PathNode pn | pn.isSource()).getNode() = n
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a qualifier to a call to `begin`, and `mid` is an
|
||||
* object that is destroyed.
|
||||
*/
|
||||
private predicate relevant(DataFlow::Node mid, DataFlow::Node sink) { Flow0::flow(mid, sink) }
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
source.asInstruction().(VariableAddressInstruction).getIRVariable() instanceof IRTempVariable and
|
||||
state = TempToDestructor()
|
||||
@@ -92,16 +120,16 @@ module Config implements DataFlow::StateConfigSig {
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
tempToDestructorSink(node1, _) and
|
||||
state1 = TempToDestructor() and
|
||||
state2 = DestroyedToBegin(node2) and
|
||||
node2 = getADestroyedNode(node1)
|
||||
qualifierToDestroyed(node1, node2)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
// Note: This is a non-trivial cartesian product!
|
||||
// Hopefully, both of these sets are quite small in practice
|
||||
destroyedToBeginSink(sink, _) and state instanceof DestroyedToBegin
|
||||
exists(DataFlow::Node mid |
|
||||
relevant(mid, sink) and
|
||||
state = DestroyedToBegin(mid)
|
||||
)
|
||||
}
|
||||
|
||||
DataFlow::FlowFeature getAFeature() {
|
||||
@@ -121,9 +149,9 @@ module Config implements DataFlow::StateConfigSig {
|
||||
|
||||
module Flow = DataFlow::GlobalWithState<Config>;
|
||||
|
||||
from Flow::PathNode source, Flow::PathNode sink, FunctionCall beginOrEnd, DataFlow::Node mid
|
||||
from Flow::PathNode source, Flow::PathNode sink, DataFlow::Node mid
|
||||
where
|
||||
Flow::flowPath(source, sink) and
|
||||
destroyedToBeginSink(sink.getNode(), beginOrEnd) and
|
||||
destroyedToBeginSink(sink.getNode()) and
|
||||
sink.getState() = Config::DestroyedToBegin(mid)
|
||||
select mid, "This object is destroyed before $@ is called.", beginOrEnd, beginOrEnd.toString()
|
||||
select mid, "This object is destroyed at the end of the full-expression."
|
||||
@@ -0,0 +1,6 @@
|
||||
void fixed_lifetime_of_temp_not_extended() {
|
||||
auto&& v = get_vector();
|
||||
for(auto x : log_and_return_argument(v)) {
|
||||
use(x); // GOOD: The lifetime of the container returned by `get_vector()` has been extended to the lifetime of `v`.
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,12 @@
|
||||
When the <code>std::string</code> object is destroyed, the pointer returned by <code>c_str</code> is no
|
||||
longer valid. If the pointer is used after the <code>std::string</code> object is destroyed, then the behavior is undefined.
|
||||
</p>
|
||||
|
||||
<p>Typically, this problem occurs when a <code>std::string</code> is returned by a function call (or overloaded operator)
|
||||
by value, and the result is not immediately stored in a variable by value or reference in a way that extends the lifetime of
|
||||
the temporary object. The resulting temporary <code>std::string</code> object is destroyed at the end of the containing expression
|
||||
statement, along with any memory returned by a call to <code>c_str</code>.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
@@ -39,6 +45,8 @@ points to valid memory.
|
||||
<references>
|
||||
|
||||
<li><a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM50-CPP.+Do+not+access+freed+memory">MEM50-CPP. Do not access freed memory</a>.</li>
|
||||
<li>Microsoft Learn: <a href="https://learn.microsoft.com/en-us/cpp/cpp/temporary-objects?view=msvc-170">Temporary objects</a>.</li>
|
||||
<li>cppreference.com: <a href="https://en.cppreference.com/w/cpp/language/reference_initialization#Lifetime_of_a_temporary">Lifetime of a temporary</a>.</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
|
||||
@@ -23,4 +23,5 @@ where
|
||||
(c.getTarget() instanceof StdStringCStr or c.getTarget() instanceof StdStringData) and
|
||||
isTemporary(c.getQualifier().getFullyConverted())
|
||||
select c,
|
||||
"The underlying string object is destroyed after the call to '" + c.getTarget() + "' returns."
|
||||
"The underlying temporary string object is destroyed after the call to '" + c.getTarget() +
|
||||
"' returns."
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* Added a new query, `cpp/iterator-to-expired-container`, to detect the creation of iterators owned by a temporary objects that are about to be destroyed.
|
||||
11
cpp/ql/src/experimental/Best Practices/GuardedFree.cpp
Normal file
11
cpp/ql/src/experimental/Best Practices/GuardedFree.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
void test()
|
||||
{
|
||||
char *foo = malloc(100);
|
||||
|
||||
// BAD
|
||||
if (foo)
|
||||
free(foo);
|
||||
|
||||
// GOOD
|
||||
free(foo);
|
||||
}
|
||||
18
cpp/ql/src/experimental/Best Practices/GuardedFree.qhelp
Normal file
18
cpp/ql/src/experimental/Best Practices/GuardedFree.qhelp
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE qhelp SYSTEM "qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>The <code>free</code> function, which deallocates heap memory, may accept a NULL pointer and take no action. Therefore, it is unnecessary to check its argument for the value of NULL before a function call to <code>free</code>. As such, these guards may hinder performance and readability.</p>
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>A function call to <code>free</code> should not depend upon the value of its argument. Delete the <code>if</code> condition preceeding a function call to <code>free</code> when its only purpose is to check the value of the pointer to be freed.</p>
|
||||
</recommendation>
|
||||
<example>
|
||||
<sample src = "GuardedFree.cpp" />
|
||||
</example>
|
||||
<references>
|
||||
<li>
|
||||
The Open Group Base Specifications Issue 7, 2018 Edition:
|
||||
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html">free - free allocated memory</a>
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
26
cpp/ql/src/experimental/Best Practices/GuardedFree.ql
Normal file
26
cpp/ql/src/experimental/Best Practices/GuardedFree.ql
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @name Guarded Free
|
||||
* @description NULL-condition guards before function calls to the memory-deallocation
|
||||
* function free(3) are unnecessary, because passing NULL to free(3) is a no-op.
|
||||
* @kind problem
|
||||
* @problem.severity recommendation
|
||||
* @precision very-high
|
||||
* @id cpp/guarded-free
|
||||
* @tags maintainability
|
||||
* readability
|
||||
* experimental
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
class FreeCall extends FunctionCall {
|
||||
FreeCall() { this.getTarget().hasGlobalName("free") }
|
||||
}
|
||||
|
||||
from GuardCondition gc, FreeCall fc, Variable v, BasicBlock bb
|
||||
where
|
||||
gc.ensuresEq(v.getAnAccess(), 0, bb, false) and
|
||||
fc.getArgument(0) = v.getAnAccess() and
|
||||
bb = fc.getEnclosingStmt()
|
||||
select gc, "unnecessary NULL check before call to $@", fc, "free"
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.9.11
|
||||
version: 0.9.12-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:680:17:680:17 | call to begin | call to begin |
|
||||
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:680:17:680:17 | call to end | call to end |
|
||||
| test.cpp:683:31:683:32 | call to at | This object is destroyed before $@ is called. | test.cpp:683:17:683:17 | call to begin | call to begin |
|
||||
| test.cpp:683:31:683:32 | call to at | This object is destroyed before $@ is called. | test.cpp:683:17:683:17 | call to end | call to end |
|
||||
| test.cpp:689:46:689:58 | pointer to ~vector output argument | This object is destroyed before $@ is called. | test.cpp:689:60:689:62 | call to end | call to end |
|
||||
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:703:19:703:23 | call to begin | call to begin |
|
||||
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:703:36:703:38 | call to end | call to end |
|
||||
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:750:17:750:17 | call to begin | call to begin |
|
||||
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:750:17:750:17 | call to end | call to end |
|
||||
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:759:17:759:17 | call to begin | call to begin |
|
||||
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:759:17:759:17 | call to end | call to end |
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security/CWE/CWE-416/IteratorToExpiredContainer.ql
|
||||
@@ -148,6 +148,24 @@ astGuardsCompare
|
||||
| 109 | y < 0+0 when ... < ... is true |
|
||||
| 109 | y >= 0+0 when ... < ... is false |
|
||||
| 109 | y >= 0+0 when ... \|\| ... is false |
|
||||
| 126 | 1 != 0 when 1 is true |
|
||||
| 126 | 1 != 0 when ... && ... is true |
|
||||
| 126 | 1 == 0 when 1 is false |
|
||||
| 126 | call to test3_condition != 0 when ... && ... is true |
|
||||
| 126 | call to test3_condition != 0 when call to test3_condition is true |
|
||||
| 126 | call to test3_condition == 0 when call to test3_condition is false |
|
||||
| 131 | b != 0 when b is true |
|
||||
| 131 | b == 0 when b is false |
|
||||
| 137 | 0 != 0 when 0 is true |
|
||||
| 137 | 0 == 0 when 0 is false |
|
||||
| 146 | ! ... != 0 when ! ... is true |
|
||||
| 146 | ! ... == 0 when ! ... is false |
|
||||
| 152 | x != 0 when ... && ... is true |
|
||||
| 152 | x != 0 when x is true |
|
||||
| 152 | x == 0 when x is false |
|
||||
| 152 | y != 0 when ... && ... is true |
|
||||
| 152 | y != 0 when y is true |
|
||||
| 152 | y == 0 when y is false |
|
||||
| 156 | ... + ... != x+0 when ... == ... is false |
|
||||
| 156 | ... + ... == x+0 when ... == ... is true |
|
||||
| 156 | x != ... + ...+0 when ... == ... is false |
|
||||
@@ -186,6 +204,8 @@ astGuardsCompare
|
||||
| 175 | call to foo != 0+0 when ... == ... is false |
|
||||
| 175 | call to foo == 0 when ... == ... is true |
|
||||
| 175 | call to foo == 0+0 when ... == ... is true |
|
||||
| 181 | x != 0 when x is true |
|
||||
| 181 | x == 0 when x is false |
|
||||
astGuardsControl
|
||||
| test.c:7:9:7:13 | ... > ... | false | 10 | 11 |
|
||||
| test.c:7:9:7:13 | ... > ... | true | 7 | 9 |
|
||||
@@ -487,8 +507,27 @@ astGuardsEnsure_const
|
||||
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 109 | 109 |
|
||||
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
|
||||
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 126 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 131 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 132 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 134 | 123 |
|
||||
| test.c:126:7:126:28 | ... && ... | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
|
||||
| test.c:126:7:126:28 | ... && ... | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
|
||||
| test.c:126:12:126:26 | call to test3_condition | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
|
||||
| test.c:131:7:131:7 | b | test.c:131:7:131:7 | b | != | 0 | 131 | 132 |
|
||||
| test.c:137:7:137:7 | 0 | test.c:137:7:137:7 | 0 | == | 0 | 142 | 136 |
|
||||
| test.c:146:7:146:8 | ! ... | test.c:146:7:146:8 | ! ... | != | 0 | 146 | 147 |
|
||||
| test.c:152:10:152:10 | x | test.c:152:10:152:10 | x | != | 0 | 151 | 152 |
|
||||
| test.c:152:10:152:10 | x | test.c:152:10:152:10 | x | != | 0 | 152 | 152 |
|
||||
| test.c:152:10:152:15 | ... && ... | test.c:152:10:152:10 | x | != | 0 | 151 | 152 |
|
||||
| test.c:152:10:152:15 | ... && ... | test.c:152:15:152:15 | y | != | 0 | 151 | 152 |
|
||||
| test.c:152:15:152:15 | y | test.c:152:15:152:15 | y | != | 0 | 151 | 152 |
|
||||
| test.c:175:13:175:32 | ... == ... | test.c:175:13:175:15 | call to foo | != | 0 | 175 | 175 |
|
||||
| test.c:175:13:175:32 | ... == ... | test.c:175:13:175:15 | call to foo | == | 0 | 175 | 175 |
|
||||
| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | != | 0 | 181 | 182 |
|
||||
| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | != | 0 | 186 | 180 |
|
||||
| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | == | 0 | 183 | 184 |
|
||||
| test.cpp:18:8:18:10 | call to get | test.cpp:18:8:18:10 | call to get | != | 0 | 19 | 19 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
|
||||
@@ -640,6 +679,20 @@ irGuardsCompare
|
||||
| 109 | y < 0+0 when CompareLT: ... < ... is true |
|
||||
| 109 | y >= 0 when CompareLT: ... < ... is false |
|
||||
| 109 | y >= 0+0 when CompareLT: ... < ... is false |
|
||||
| 126 | 1 != 0 when Constant: 1 is true |
|
||||
| 126 | 1 == 0 when Constant: 1 is false |
|
||||
| 126 | call to test3_condition != 0 when Call: call to test3_condition is true |
|
||||
| 126 | call to test3_condition == 0 when Call: call to test3_condition is false |
|
||||
| 131 | b != 0 when Load: b is true |
|
||||
| 131 | b == 0 when Load: b is false |
|
||||
| 137 | 0 != 0 when Constant: 0 is true |
|
||||
| 137 | 0 == 0 when Constant: 0 is false |
|
||||
| 146 | ! ... != 0 when LogicalNot: ! ... is true |
|
||||
| 146 | ! ... == 0 when LogicalNot: ! ... is false |
|
||||
| 152 | x != 0 when Load: x is true |
|
||||
| 152 | x == 0 when Load: x is false |
|
||||
| 152 | y != 0 when Load: y is true |
|
||||
| 152 | y == 0 when Load: y is false |
|
||||
| 156 | ... + ... != x+0 when CompareEQ: ... == ... is false |
|
||||
| 156 | ... + ... == x+0 when CompareEQ: ... == ... is true |
|
||||
| 156 | x != ... + ...+0 when CompareEQ: ... == ... is false |
|
||||
@@ -678,6 +731,8 @@ irGuardsCompare
|
||||
| 175 | call to foo != 0+0 when CompareEQ: ... == ... is false |
|
||||
| 175 | call to foo == 0 when CompareEQ: ... == ... is true |
|
||||
| 175 | call to foo == 0+0 when CompareEQ: ... == ... is true |
|
||||
| 181 | x != 0 when Load: x is true |
|
||||
| 181 | x == 0 when Load: x is false |
|
||||
irGuardsControl
|
||||
| test.c:7:9:7:13 | CompareGT: ... > ... | false | 11 | 11 |
|
||||
| test.c:7:9:7:13 | CompareGT: ... > ... | true | 8 | 8 |
|
||||
@@ -999,8 +1054,21 @@ irGuardsEnsure_const
|
||||
| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:9 | Load: x | != | 0 | 109 | 109 |
|
||||
| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:9 | Load: x | != | 0 | 113 | 113 |
|
||||
| test.c:109:19:109:23 | CompareLT: ... < ... | test.c:109:19:109:19 | Load: y | >= | 0 | 113 | 113 |
|
||||
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 126 | 126 |
|
||||
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 127 | 127 |
|
||||
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 131 | 131 |
|
||||
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 132 | 132 |
|
||||
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 134 | 134 |
|
||||
| test.c:126:12:126:26 | Call: call to test3_condition | test.c:126:12:126:26 | Call: call to test3_condition | != | 0 | 127 | 127 |
|
||||
| test.c:131:7:131:7 | Load: b | test.c:131:7:131:7 | Load: b | != | 0 | 132 | 132 |
|
||||
| test.c:137:7:137:7 | Constant: 0 | test.c:137:7:137:7 | Constant: 0 | == | 0 | 142 | 142 |
|
||||
| test.c:146:7:146:8 | LogicalNot: ! ... | test.c:146:7:146:8 | LogicalNot: ! ... | != | 0 | 147 | 147 |
|
||||
| test.c:152:10:152:10 | Load: x | test.c:152:10:152:10 | Load: x | != | 0 | 152 | 152 |
|
||||
| test.c:152:15:152:15 | Load: y | test.c:152:15:152:15 | Load: y | != | 0 | 152 | 152 |
|
||||
| test.c:175:13:175:32 | CompareEQ: ... == ... | test.c:175:13:175:15 | Call: call to foo | != | 0 | 175 | 175 |
|
||||
| test.c:175:13:175:32 | CompareEQ: ... == ... | test.c:175:13:175:15 | Call: call to foo | == | 0 | 175 | 175 |
|
||||
| test.c:181:9:181:9 | Load: x | test.c:181:9:181:9 | Load: x | != | 0 | 182 | 182 |
|
||||
| test.c:181:9:181:9 | Load: x | test.c:181:9:181:9 | Load: x | == | 0 | 184 | 184 |
|
||||
| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:10 | Call: call to get | != | 0 | 19 | 19 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | != | -1 | 34 | 34 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 30 | 30 |
|
||||
|
||||
@@ -26,6 +26,12 @@
|
||||
| test.c:137:7:137:7 | 0 |
|
||||
| test.c:146:7:146:8 | ! ... |
|
||||
| test.c:146:8:146:8 | x |
|
||||
| test.c:152:8:152:8 | p |
|
||||
| test.c:158:8:158:9 | ! ... |
|
||||
| test.c:158:9:158:9 | p |
|
||||
| test.c:164:8:164:8 | s |
|
||||
| test.c:170:8:170:9 | ! ... |
|
||||
| test.c:170:9:170:9 | s |
|
||||
| test.cpp:18:8:18:10 | call to get |
|
||||
| test.cpp:31:7:31:13 | ... == ... |
|
||||
| test.cpp:42:13:42:20 | call to getABool |
|
||||
|
||||
@@ -149,3 +149,23 @@
|
||||
| 111 | 0.0 == i+0 when ... != ... is false |
|
||||
| 111 | i != 0.0+0 when ... != ... is true |
|
||||
| 111 | i == 0.0+0 when ... != ... is false |
|
||||
| 126 | 1 != 0 when 1 is true |
|
||||
| 126 | 1 != 0 when ... && ... is true |
|
||||
| 126 | 1 == 0 when 1 is false |
|
||||
| 126 | call to test3_condition != 0 when ... && ... is true |
|
||||
| 126 | call to test3_condition != 0 when call to test3_condition is true |
|
||||
| 126 | call to test3_condition == 0 when call to test3_condition is false |
|
||||
| 131 | b != 0 when b is true |
|
||||
| 131 | b == 0 when b is false |
|
||||
| 137 | 0 != 0 when 0 is true |
|
||||
| 137 | 0 == 0 when 0 is false |
|
||||
| 146 | ! ... != 0 when ! ... is true |
|
||||
| 146 | ! ... == 0 when ! ... is false |
|
||||
| 152 | p != 0 when p is true |
|
||||
| 152 | p == 0 when p is false |
|
||||
| 158 | ! ... != 0 when ! ... is true |
|
||||
| 158 | ! ... == 0 when ! ... is false |
|
||||
| 164 | s != 0 when s is true |
|
||||
| 164 | s == 0 when s is false |
|
||||
| 170 | ! ... != 0 when ! ... is true |
|
||||
| 170 | ! ... == 0 when ! ... is false |
|
||||
|
||||
@@ -79,6 +79,12 @@
|
||||
| test.c:137:7:137:7 | 0 | false | 142 | 136 |
|
||||
| test.c:146:7:146:8 | ! ... | true | 146 | 147 |
|
||||
| test.c:146:8:146:8 | x | false | 146 | 147 |
|
||||
| test.c:152:8:152:8 | p | true | 152 | 154 |
|
||||
| test.c:158:8:158:9 | ! ... | true | 158 | 160 |
|
||||
| test.c:158:9:158:9 | p | false | 158 | 160 |
|
||||
| test.c:164:8:164:8 | s | true | 164 | 166 |
|
||||
| test.c:170:8:170:9 | ! ... | true | 170 | 172 |
|
||||
| test.c:170:9:170:9 | s | false | 170 | 172 |
|
||||
| test.cpp:18:8:18:10 | call to get | true | 19 | 19 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | false | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | false | 34 | 34 |
|
||||
|
||||
@@ -234,6 +234,21 @@ unary
|
||||
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
|
||||
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:19:109:19 | y | >= | 0 | 113 | 113 |
|
||||
| test.c:109:19:109:23 | ... < ... | test.c:109:19:109:19 | y | >= | 0 | 113 | 113 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 126 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 131 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 132 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 134 | 123 |
|
||||
| test.c:126:7:126:28 | ... && ... | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
|
||||
| test.c:126:7:126:28 | ... && ... | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
|
||||
| test.c:126:12:126:26 | call to test3_condition | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
|
||||
| test.c:131:7:131:7 | b | test.c:131:7:131:7 | b | != | 0 | 131 | 132 |
|
||||
| test.c:137:7:137:7 | 0 | test.c:137:7:137:7 | 0 | == | 0 | 142 | 136 |
|
||||
| test.c:146:7:146:8 | ! ... | test.c:146:7:146:8 | ! ... | != | 0 | 146 | 147 |
|
||||
| test.c:152:8:152:8 | p | test.c:152:8:152:8 | p | != | 0 | 152 | 154 |
|
||||
| test.c:158:8:158:9 | ! ... | test.c:158:8:158:9 | ! ... | != | 0 | 158 | 160 |
|
||||
| test.c:164:8:164:8 | s | test.c:164:8:164:8 | s | != | 0 | 164 | 166 |
|
||||
| test.c:170:8:170:9 | ! ... | test.c:170:8:170:9 | ! ... | != | 0 | 170 | 172 |
|
||||
| test.cpp:18:8:18:10 | call to get | test.cpp:18:8:18:10 | call to get | != | 0 | 19 | 19 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
|
||||
|
||||
@@ -147,3 +147,27 @@ void test5(int x) {
|
||||
test3();
|
||||
}
|
||||
}
|
||||
|
||||
void test6(char* p) {
|
||||
if(p) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void test7(char* p) {
|
||||
if(!p) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void test8(short s) {
|
||||
if(s) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void test9(short s) {
|
||||
if(!s) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -228,7 +228,6 @@ irFlow
|
||||
| test.cpp:333:17:333:22 | call to source | test.cpp:337:10:337:18 | globalVar |
|
||||
| test.cpp:333:17:333:22 | call to source | test.cpp:339:10:339:18 | globalVar |
|
||||
| test.cpp:333:17:333:22 | call to source | test.cpp:343:10:343:18 | globalVar |
|
||||
| test.cpp:333:17:333:22 | call to source | test.cpp:349:10:349:18 | globalVar |
|
||||
| test.cpp:347:17:347:22 | call to source | test.cpp:337:10:337:18 | globalVar |
|
||||
| test.cpp:347:17:347:22 | call to source | test.cpp:339:10:339:18 | globalVar |
|
||||
| test.cpp:347:17:347:22 | call to source | test.cpp:343:10:343:18 | globalVar |
|
||||
@@ -260,7 +259,6 @@ irFlow
|
||||
| test.cpp:562:17:562:31 | *call to indirect_source | test.cpp:566:10:566:19 | * ... |
|
||||
| test.cpp:562:17:562:31 | *call to indirect_source | test.cpp:568:10:568:19 | * ... |
|
||||
| test.cpp:562:17:562:31 | *call to indirect_source | test.cpp:572:10:572:19 | * ... |
|
||||
| test.cpp:562:17:562:31 | *call to indirect_source | test.cpp:578:10:578:19 | * ... |
|
||||
| test.cpp:576:17:576:31 | *call to indirect_source | test.cpp:566:10:566:19 | * ... |
|
||||
| test.cpp:576:17:576:31 | *call to indirect_source | test.cpp:568:10:568:19 | * ... |
|
||||
| test.cpp:576:17:576:31 | *call to indirect_source | test.cpp:572:10:572:19 | * ... |
|
||||
|
||||
@@ -346,7 +346,7 @@ namespace FlowThroughGlobals {
|
||||
void taintAndCall() {
|
||||
globalVar = source();
|
||||
calledAfterTaint();
|
||||
sink(globalVar); // $ ast ir=333:17 ir=347:17
|
||||
sink(globalVar); // $ ast ir
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,7 +575,7 @@ namespace IndirectFlowThroughGlobals {
|
||||
void taintAndCall() {
|
||||
globalInt = indirect_source();
|
||||
calledAfterTaint();
|
||||
sink(*globalInt); // $ ir=562:17 ir=576:17 MISSING: ast=562:17 ast=576:17
|
||||
sink(*globalInt); // $ ir MISSING: ast=562:17 ast=576:17
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,8 +66,8 @@ public:
|
||||
insert_iterator_by_trait operator++(int);
|
||||
insert_iterator_by_trait &operator--();
|
||||
insert_iterator_by_trait operator--(int);
|
||||
insert_iterator_by_trait operator*();
|
||||
insert_iterator_by_trait operator=(int x);
|
||||
insert_iterator_by_trait& operator*();
|
||||
insert_iterator_by_trait& operator=(int x);
|
||||
};
|
||||
|
||||
template<>
|
||||
|
||||
@@ -389,7 +389,7 @@ void test_vector_output_iterator(int b) {
|
||||
*i9 = source();
|
||||
taint_vector_output_iterator(i9);
|
||||
|
||||
sink(v9); // $ ast=330:10 MISSING: ir SPURIOUS: ast=389:8
|
||||
sink(v9); // $ ast=330:10 ir SPURIOUS: ast=389:8
|
||||
|
||||
std::vector<int>::iterator i10 = v10.begin();
|
||||
vector_iterator_assign_wrapper(i10, 10);
|
||||
@@ -440,14 +440,14 @@ void test_vector_inserter(char *source_string) {
|
||||
std::vector<std::string> out;
|
||||
auto it = std::back_inserter(out);
|
||||
*++it = std::string(source_string);
|
||||
sink(out); // $ ast MISSING: ir
|
||||
sink(out); // $ ast,ir
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<int> out;
|
||||
auto it = std::back_inserter(out);
|
||||
*++it = source();
|
||||
sink(out); // $ ast MISSING: ir
|
||||
sink(out); // $ ast,ir
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,7 @@ invalidOverlap
|
||||
nonUniqueEnclosingIRFunction
|
||||
fieldAddressOnNonPointer
|
||||
thisArgumentIsNonPointer
|
||||
| ir.cpp:2546:34:2546:34 | Call: call to operator bool | Call instruction 'Call: call to operator bool' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:2545:6:2545:23 | void this_inconsistency(bool) | void this_inconsistency(bool) |
|
||||
nonUniqueIRVariable
|
||||
| coroutines.cpp:87:20:87:20 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:87:20:87:20 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
|
||||
@@ -27,6 +27,7 @@ invalidOverlap
|
||||
nonUniqueEnclosingIRFunction
|
||||
fieldAddressOnNonPointer
|
||||
thisArgumentIsNonPointer
|
||||
| ir.cpp:2546:34:2546:34 | Call: call to operator bool | Call instruction 'Call: call to operator bool' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:2545:6:2545:23 | void this_inconsistency(bool) | void this_inconsistency(bool) |
|
||||
nonUniqueIRVariable
|
||||
| coroutines.cpp:87:20:87:20 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:87:20:87:20 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
|
||||
@@ -2191,6 +2191,7 @@ public:
|
||||
|
||||
void set_x(char y) { *x = y; }
|
||||
char get_x() { return *x; }
|
||||
operator bool() const;
|
||||
};
|
||||
|
||||
constexpr bool initialization_with_destructor_bool = true;
|
||||
@@ -2498,4 +2499,57 @@ void destructor_without_block(bool b)
|
||||
ClassWithDestructor g;
|
||||
}
|
||||
|
||||
void destruction_in_switch_1(int c) {
|
||||
switch (c) {
|
||||
case 0: {
|
||||
ClassWithDestructor x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void destruction_in_switch_2(int c) {
|
||||
switch (ClassWithDestructor y; c) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void destruction_in_switch_3(int c) {
|
||||
switch (ClassWithDestructor y; c) {
|
||||
case 0: {
|
||||
ClassWithDestructor x;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void destructor_possibly_not_handled() {
|
||||
ClassWithDestructor x;
|
||||
try {
|
||||
throw 42;
|
||||
}
|
||||
catch(char) {
|
||||
}
|
||||
}
|
||||
|
||||
ClassWithDestructor getClassWithDestructor();
|
||||
|
||||
void this_inconsistency(bool b) {
|
||||
if (const ClassWithDestructor& a = getClassWithDestructor())
|
||||
;
|
||||
}
|
||||
|
||||
void constexpr_inconsistency(bool b) {
|
||||
if constexpr (const ClassWithDestructor& a = getClassWithDestructor(); initialization_with_destructor_bool)
|
||||
;
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++20 --clang
|
||||
|
||||
@@ -21,6 +21,7 @@ lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
| ir.cpp:1535:8:1535:8 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1535:8:1535:8 | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() |
|
||||
| ir.cpp:2551:48:2551:71 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:2550:6:2550:28 | void constexpr_inconsistency(bool) | void constexpr_inconsistency(bool) |
|
||||
| try_except.c:13:13:13:13 | Left | Operand 'Left' is not dominated by its definition in function '$@'. | try_except.c:6:6:6:6 | void f() | void f() |
|
||||
| try_except.c:13:13:13:13 | Left | Operand 'Left' is not dominated by its definition in function '$@'. | try_except.c:6:6:6:6 | void f() | void f() |
|
||||
| try_except.c:39:15:39:15 | Left | Operand 'Left' is not dominated by its definition in function '$@'. | try_except.c:32:6:32:6 | void h(int) | void h(int) |
|
||||
@@ -36,6 +37,7 @@ invalidOverlap
|
||||
nonUniqueEnclosingIRFunction
|
||||
fieldAddressOnNonPointer
|
||||
thisArgumentIsNonPointer
|
||||
| ir.cpp:2546:34:2546:34 | Call: call to operator bool | Call instruction 'Call: call to operator bool' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:2545:6:2545:23 | void this_inconsistency(bool) | void this_inconsistency(bool) |
|
||||
nonUniqueIRVariable
|
||||
| coroutines.cpp:87:20:87:20 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:87:20:87:20 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,7 @@ invalidOverlap
|
||||
nonUniqueEnclosingIRFunction
|
||||
fieldAddressOnNonPointer
|
||||
thisArgumentIsNonPointer
|
||||
| ir.cpp:2546:34:2546:34 | Call: call to operator bool | Call instruction 'Call: call to operator bool' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:2545:6:2545:23 | void this_inconsistency(bool) | void this_inconsistency(bool) |
|
||||
nonUniqueIRVariable
|
||||
| coroutines.cpp:87:20:87:20 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:87:20:87:20 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
|
||||
@@ -27,6 +27,7 @@ invalidOverlap
|
||||
nonUniqueEnclosingIRFunction
|
||||
fieldAddressOnNonPointer
|
||||
thisArgumentIsNonPointer
|
||||
| ir.cpp:2546:34:2546:34 | Call: call to operator bool | Call instruction 'Call: call to operator bool' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:2545:6:2545:23 | void this_inconsistency(bool) | void this_inconsistency(bool) |
|
||||
nonUniqueIRVariable
|
||||
| coroutines.cpp:87:20:87:20 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
| coroutines.cpp:87:20:87:20 | VariableAddress: (unnamed local variable) | Variable address instruction 'VariableAddress: (unnamed local variable)' has no associated variable, in function '$@'. | coroutines.cpp:87:20:87:33 | co_returnable_void co_return_void() | co_returnable_void co_return_void() |
|
||||
|
||||
@@ -4,12 +4,6 @@ uniqueType
|
||||
uniqueNodeLocation
|
||||
missingLocation
|
||||
uniqueNodeToString
|
||||
| builtin.c:5:5:5:11 | (no string representation) | Node should have one toString but has 0. |
|
||||
| misc.c:227:7:227:28 | (no string representation) | Node should have one toString but has 0. |
|
||||
| static_init_templates.cpp:80:18:80:23 | (no string representation) | Node should have one toString but has 0. |
|
||||
| static_init_templates.cpp:80:18:80:23 | (no string representation) | Node should have one toString but has 0. |
|
||||
| static_init_templates.cpp:89:18:89:23 | (no string representation) | Node should have one toString but has 0. |
|
||||
| static_init_templates.cpp:89:18:89:23 | (no string representation) | Node should have one toString but has 0. |
|
||||
parameterCallable
|
||||
localFlowIsLocal
|
||||
readStepIsLocal
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
| test.cpp:128:15:128:16 | v4 |
|
||||
| test.cpp:185:10:185:12 | cpy |
|
||||
| test.cpp:199:10:199:12 | cpy |
|
||||
| test.cpp:208:7:208:7 | a |
|
||||
| test.cpp:214:7:214:7 | a |
|
||||
| test_free.cpp:11:10:11:10 | a |
|
||||
| test_free.cpp:14:10:14:10 | a |
|
||||
| test_free.cpp:16:10:16:10 | a |
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
edges
|
||||
| test.cpp:208:7:208:7 | pointer to free output argument | test.cpp:209:2:209:2 | a | provenance | |
|
||||
| test.cpp:214:7:214:7 | pointer to free output argument | test.cpp:215:2:215:2 | a | provenance | |
|
||||
| test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:12:5:12:5 | a | provenance | |
|
||||
| test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:13:5:13:6 | * ... | provenance | |
|
||||
| test_free.cpp:42:27:42:27 | pointer to free output argument | test_free.cpp:45:5:45:5 | a | provenance | |
|
||||
@@ -31,6 +33,10 @@ edges
|
||||
| test_free.cpp:322:12:322:12 | pointer to operator delete output argument | test_free.cpp:324:5:324:6 | * ... | provenance | |
|
||||
| test_free.cpp:331:12:331:12 | pointer to operator delete output argument | test_free.cpp:332:5:332:6 | * ... | provenance | |
|
||||
nodes
|
||||
| test.cpp:208:7:208:7 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||
| test.cpp:209:2:209:2 | a | semmle.label | a |
|
||||
| test.cpp:214:7:214:7 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||
| test.cpp:215:2:215:2 | a | semmle.label | a |
|
||||
| test_free.cpp:11:10:11:10 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||
| test_free.cpp:12:5:12:5 | a | semmle.label | a |
|
||||
| test_free.cpp:13:5:13:6 | * ... | semmle.label | * ... |
|
||||
@@ -82,6 +88,8 @@ nodes
|
||||
| test_free.cpp:332:5:332:6 | * ... | semmle.label | * ... |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:209:2:209:2 | a | test.cpp:208:7:208:7 | pointer to free output argument | test.cpp:209:2:209:2 | a | Memory may have been previously freed by $@. | test.cpp:208:2:208:5 | call to free | call to free |
|
||||
| test.cpp:215:2:215:2 | a | test.cpp:214:7:214:7 | pointer to free output argument | test.cpp:215:2:215:2 | a | Memory may have been previously freed by $@. | test.cpp:214:2:214:5 | call to free | call to free |
|
||||
| test_free.cpp:12:5:12:5 | a | test_free.cpp:11:10:11:10 | pointer to free output argument | 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:5:13:6 | * ... | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:13:5:13:6 | * ... | 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 | pointer to free output argument | 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 |
|
||||
|
||||
@@ -114,7 +114,7 @@ int main()
|
||||
mc2->method2();
|
||||
delete mc2;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
void *v1 = malloc(100);
|
||||
int *i2 = (int *)malloc(100);
|
||||
@@ -198,3 +198,19 @@ void test_strndupa_dealloc() {
|
||||
char *cpy = strndupa(msg, 4);
|
||||
free(cpy); // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
void test_reassignment() {
|
||||
char *a = (char *)malloc(128);
|
||||
char *b = (char *)malloc(128);
|
||||
|
||||
free(a);
|
||||
a[0] = 0; // BAD
|
||||
|
||||
a = b;
|
||||
a[0] = 0; // GOOD
|
||||
|
||||
free(a);
|
||||
a[0] = 0; // BAD
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
void C6317_positive(int i)
|
||||
{
|
||||
if (i & !FLAGS) // BUG
|
||||
if (i & !FLAGS) // BUG
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -71,3 +71,22 @@ void macroUsage(unsigned int arg1, unsigned int arg2)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void bool_examples(bool a, bool b)
|
||||
{
|
||||
if (a & !b) // dubious (confusing intent, but shouldn't produce a wrong result)
|
||||
{
|
||||
}
|
||||
|
||||
if (a & ~b)
|
||||
{
|
||||
}
|
||||
|
||||
if (a && ~b)
|
||||
{
|
||||
}
|
||||
|
||||
if (a && !b)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,3 +14,4 @@
|
||||
| IncorrectNotOperatorUsage.cpp:48:9:48:18 | ... \| ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.cpp:49:9:49:20 | ... \| ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.cpp:70:10:70:34 | ... \| ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.cpp:77:9:77:14 | ... & ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed at the end of the full-expression. |
|
||||
| test.cpp:683:31:683:32 | call to at | This object is destroyed at the end of the full-expression. |
|
||||
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed at the end of the full-expression. |
|
||||
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed at the end of the full-expression. |
|
||||
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed at the end of the full-expression. |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-416/IteratorToExpiredContainer.ql
|
||||
@@ -686,7 +686,7 @@ void test() {
|
||||
for (auto x : returnRef()[0]) {} // GOOD
|
||||
for (auto x : returnRef().at(0)) {} // GOOD
|
||||
|
||||
for(auto it = returnValue().begin(); it != returnValue().end(); ++it) {} // BAD
|
||||
for(auto it = returnValue().begin(); it != returnValue().end(); ++it) {} // BAD [NOT DETECTED]
|
||||
|
||||
{
|
||||
auto v = returnValue();
|
||||
@@ -792,4 +792,13 @@ void test4() {
|
||||
// function we may end up in the destructor call `chunk.~A()`in `A.foo`. This destructor
|
||||
// call can flow to `begin` through the back-edge and cause a strange FP.
|
||||
auto zero = A().size();
|
||||
}
|
||||
|
||||
void test5(int i)
|
||||
{
|
||||
while(i < 10) {
|
||||
const auto& vvs = returnValue();
|
||||
for(const auto& vs : vvs) { }
|
||||
++i;
|
||||
} // GOOD
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
| test.cpp:165:34:165:38 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:166:39:166:43 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:167:44:167:48 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:169:29:169:33 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:178:37:178:41 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:181:39:181:43 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:183:37:183:41 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:187:34:187:37 | call to data | The underlying string object is destroyed after the call to 'data' returns. |
|
||||
| test.cpp:188:39:188:42 | call to data | The underlying string object is destroyed after the call to 'data' returns. |
|
||||
| test.cpp:189:44:189:47 | call to data | The underlying string object is destroyed after the call to 'data' returns. |
|
||||
| test.cpp:191:29:191:32 | call to data | The underlying string object is destroyed after the call to 'data' returns. |
|
||||
| test.cpp:193:47:193:51 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:195:31:195:35 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:165:34:165:38 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:166:39:166:43 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:167:44:167:48 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:169:29:169:33 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:178:37:178:41 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:181:39:181:43 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:183:37:183:41 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:187:34:187:37 | call to data | The underlying temporary string object is destroyed after the call to 'data' returns. |
|
||||
| test.cpp:188:39:188:42 | call to data | The underlying temporary string object is destroyed after the call to 'data' returns. |
|
||||
| test.cpp:189:44:189:47 | call to data | The underlying temporary string object is destroyed after the call to 'data' returns. |
|
||||
| test.cpp:191:29:191:32 | call to data | The underlying temporary string object is destroyed after the call to 'data' returns. |
|
||||
| test.cpp:193:47:193:51 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:195:31:195:35 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
|
||||
@@ -22,3 +22,4 @@
|
||||
| test.cpp:416:2:418:2 | for(...;...;...) ... | test.cpp:416:18:416:23 | ... < ... | 1 | i | { ... } | i | return ... |
|
||||
| test.cpp:424:2:425:2 | for(...;...;...) ... | test.cpp:424:18:424:23 | ... < ... | 1 | i | { ... } | i | return ... |
|
||||
| test.cpp:433:2:434:2 | for(...;...;...) ... | test.cpp:433:18:433:22 | 0 | 0 | | { ... } | 0 | return ... |
|
||||
| test.cpp:559:3:564:3 | while (...) ... | test.cpp:559:9:559:15 | call to getBool | | call to getBool | { ... } | call to getBool | ExprStmt |
|
||||
|
||||
@@ -13,6 +13,7 @@ nodes
|
||||
| test.cpp:458:6:458:6 | definition of x | semmle.label | definition of x |
|
||||
| test.cpp:464:6:464:6 | definition of x | semmle.label | definition of x |
|
||||
| test.cpp:471:6:471:6 | definition of x | semmle.label | definition of x |
|
||||
| test.cpp:557:15:557:15 | definition of r | semmle.label | definition of r |
|
||||
#select
|
||||
| test.cpp:12:6:12:8 | foo | test.cpp:11:6:11:8 | definition of foo | test.cpp:11:6:11:8 | definition of foo | The variable $@ may not be initialized at this access. | test.cpp:11:6:11:8 | foo | foo |
|
||||
| test.cpp:113:6:113:8 | foo | test.cpp:111:6:111:8 | definition of foo | test.cpp:111:6:111:8 | definition of foo | The variable $@ may not be initialized at this access. | test.cpp:111:6:111:8 | foo | foo |
|
||||
@@ -27,3 +28,4 @@ nodes
|
||||
| test.cpp:460:7:460:7 | x | test.cpp:458:6:458:6 | definition of x | test.cpp:458:6:458:6 | definition of x | The variable $@ may not be initialized at this access. | test.cpp:458:6:458:6 | x | x |
|
||||
| test.cpp:467:2:467:2 | x | test.cpp:464:6:464:6 | definition of x | test.cpp:464:6:464:6 | definition of x | The variable $@ may not be initialized at this access. | test.cpp:464:6:464:6 | x | x |
|
||||
| test.cpp:474:7:474:7 | x | test.cpp:471:6:471:6 | definition of x | test.cpp:471:6:471:6 | definition of x | The variable $@ may not be initialized at this access. | test.cpp:471:6:471:6 | x | x |
|
||||
| test.cpp:567:7:567:7 | r | test.cpp:557:15:557:15 | definition of r | test.cpp:557:15:557:15 | definition of r | The variable $@ may not be initialized at this access. | test.cpp:557:15:557:15 | r | r |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Semmle test cases for rule CWE-457.
|
||||
|
||||
void use(int data);
|
||||
void use(...);
|
||||
|
||||
void test1() {
|
||||
int foo = 1;
|
||||
@@ -544,4 +544,25 @@ class StaticMethodClass{
|
||||
int static_method_false_positive(){
|
||||
StaticMethodClass *t;
|
||||
int i = t->get(); // GOOD: the `get` method is static and this is equivalent to StaticMethodClass::get()
|
||||
}
|
||||
|
||||
struct LinkedList
|
||||
{
|
||||
LinkedList* next;
|
||||
};
|
||||
|
||||
bool getBool();
|
||||
|
||||
void test45() {
|
||||
LinkedList *r, *s, **rP = &r;
|
||||
|
||||
while(getBool())
|
||||
{
|
||||
s = new LinkedList;
|
||||
*rP = s;
|
||||
rP = &s->next;
|
||||
}
|
||||
|
||||
*rP = NULL;
|
||||
use(r); // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
@@ -41,99 +41,99 @@
|
||||
| BoxedInt::~BoxedInt | true | 481 | 483 | |
|
||||
| BoxedInt::~BoxedInt | true | 483 | 222 | |
|
||||
| BoxedInt::~BoxedInt | true | 485 | 474 | |
|
||||
| NonTrivial::NonTrivial | false | 543 | 543 | NonTrivial |
|
||||
| NonTrivial::operator= | false | 549 | 549 | operator= |
|
||||
| NonTrivial::~NonTrivial | false | 557 | 557 | ~NonTrivial |
|
||||
| NonTrivial::~NonTrivial | false | 563 | 563 | return ... |
|
||||
| NonTrivial::~NonTrivial | false | 565 | 565 | { ... } |
|
||||
| NonTrivial::~NonTrivial | true | 563 | 557 | |
|
||||
| NonTrivial::~NonTrivial | true | 565 | 563 | |
|
||||
| NonTrivial::NonTrivial | false | 544 | 544 | NonTrivial |
|
||||
| NonTrivial::operator= | false | 550 | 550 | operator= |
|
||||
| NonTrivial::~NonTrivial | false | 558 | 558 | ~NonTrivial |
|
||||
| NonTrivial::~NonTrivial | false | 564 | 564 | return ... |
|
||||
| NonTrivial::~NonTrivial | false | 566 | 566 | { ... } |
|
||||
| NonTrivial::~NonTrivial | true | 564 | 558 | |
|
||||
| NonTrivial::~NonTrivial | true | 566 | 564 | |
|
||||
| __va_list_tag::operator= | false | 66 | 66 | operator= |
|
||||
| __va_list_tag::operator= | false | 72 | 72 | operator= |
|
||||
| early_return | false | 799 | 799 | early_return |
|
||||
| early_return | false | 807 | 807 | declaration |
|
||||
| early_return | false | 812 | 812 | if (...) ... |
|
||||
| early_return | false | 814 | 814 | x |
|
||||
| early_return | false | 816 | 816 | (bool)... |
|
||||
| early_return | false | 820 | 820 | declaration |
|
||||
| early_return | false | 822 | 822 | return ... |
|
||||
| early_return | false | 824 | 824 | { ... } |
|
||||
| early_return | false | 826 | 826 | declaration |
|
||||
| early_return | false | 831 | 831 | return ... |
|
||||
| early_return | false | 833 | 833 | { ... } |
|
||||
| early_return | false | 835 | 835 | inner |
|
||||
| early_return | false | 837 | 837 | call to inner.~NonTrivial |
|
||||
| early_return | false | 838 | 838 | before |
|
||||
| early_return | false | 840 | 840 | call to before.~NonTrivial |
|
||||
| early_return | false | 841 | 841 | inner |
|
||||
| early_return | false | 842 | 842 | call to inner.~NonTrivial |
|
||||
| early_return | false | 843 | 843 | before |
|
||||
| early_return | false | 844 | 844 | call to before.~NonTrivial |
|
||||
| early_return | false | 845 | 845 | after |
|
||||
| early_return | false | 846 | 846 | call to after.~NonTrivial |
|
||||
| early_return | true | 807 | 812 | |
|
||||
| early_return | true | 812 | 814 | |
|
||||
| early_return | true | 814 | 824 | T |
|
||||
| early_return | true | 814 | 826 | F |
|
||||
| early_return | true | 820 | 822 | |
|
||||
| early_return | true | 822 | 841 | |
|
||||
| early_return | true | 824 | 820 | |
|
||||
| early_return | true | 826 | 831 | |
|
||||
| early_return | true | 831 | 845 | |
|
||||
| early_return | true | 833 | 807 | |
|
||||
| early_return | true | 835 | 837 | |
|
||||
| early_return | true | 837 | 826 | |
|
||||
| early_return | true | 838 | 840 | |
|
||||
| early_return | true | 840 | 799 | |
|
||||
| early_return | true | 841 | 842 | |
|
||||
| early_return | true | 842 | 838 | |
|
||||
| early_return | true | 843 | 844 | |
|
||||
| early_return | true | 844 | 799 | |
|
||||
| early_return | true | 845 | 846 | |
|
||||
| early_return | true | 846 | 843 | |
|
||||
| early_throw | false | 749 | 749 | early_throw |
|
||||
| early_throw | false | 757 | 757 | declaration |
|
||||
| early_throw | false | 762 | 762 | if (...) ... |
|
||||
| early_throw | false | 764 | 764 | x |
|
||||
| early_throw | false | 766 | 766 | (bool)... |
|
||||
| early_throw | false | 770 | 770 | declaration |
|
||||
| early_throw | false | 772 | 772 | ExprStmt |
|
||||
| early_throw | false | 774 | 774 | re-throw exception |
|
||||
| early_throw | false | 776 | 776 | { ... } |
|
||||
| early_throw | false | 778 | 778 | declaration |
|
||||
| early_throw | false | 783 | 783 | return ... |
|
||||
| early_throw | false | 785 | 785 | { ... } |
|
||||
| early_throw | false | 787 | 787 | inner |
|
||||
| early_throw | false | 789 | 789 | call to inner.~NonTrivial |
|
||||
| early_throw | false | 790 | 790 | before |
|
||||
| early_throw | false | 792 | 792 | call to before.~NonTrivial |
|
||||
| early_throw | false | 793 | 793 | inner |
|
||||
| early_throw | false | 794 | 794 | call to inner.~NonTrivial |
|
||||
| early_throw | false | 795 | 795 | before |
|
||||
| early_throw | false | 796 | 796 | call to before.~NonTrivial |
|
||||
| early_throw | false | 797 | 797 | after |
|
||||
| early_throw | false | 798 | 798 | call to after.~NonTrivial |
|
||||
| early_throw | true | 757 | 762 | |
|
||||
| early_throw | true | 762 | 764 | |
|
||||
| early_throw | true | 764 | 776 | T |
|
||||
| early_throw | true | 764 | 778 | F |
|
||||
| early_throw | true | 770 | 772 | |
|
||||
| early_throw | true | 772 | 774 | |
|
||||
| early_throw | true | 774 | 793 | |
|
||||
| early_throw | true | 776 | 770 | |
|
||||
| early_throw | true | 778 | 783 | |
|
||||
| early_throw | true | 783 | 797 | |
|
||||
| early_throw | true | 785 | 757 | |
|
||||
| early_throw | true | 787 | 789 | |
|
||||
| early_throw | true | 789 | 778 | |
|
||||
| early_throw | true | 790 | 792 | |
|
||||
| early_throw | true | 792 | 749 | |
|
||||
| early_throw | true | 793 | 794 | |
|
||||
| early_throw | true | 794 | 790 | |
|
||||
| early_throw | true | 795 | 796 | |
|
||||
| early_throw | true | 796 | 749 | |
|
||||
| early_throw | true | 797 | 798 | |
|
||||
| early_throw | true | 798 | 795 | |
|
||||
| early_return | false | 800 | 800 | early_return |
|
||||
| early_return | false | 808 | 808 | declaration |
|
||||
| early_return | false | 813 | 813 | if (...) ... |
|
||||
| early_return | false | 815 | 815 | x |
|
||||
| early_return | false | 817 | 817 | (bool)... |
|
||||
| early_return | false | 821 | 821 | declaration |
|
||||
| early_return | false | 823 | 823 | return ... |
|
||||
| early_return | false | 825 | 825 | { ... } |
|
||||
| early_return | false | 827 | 827 | declaration |
|
||||
| early_return | false | 832 | 832 | return ... |
|
||||
| early_return | false | 834 | 834 | { ... } |
|
||||
| early_return | false | 836 | 836 | before |
|
||||
| early_return | false | 838 | 838 | call to before.~NonTrivial |
|
||||
| early_return | false | 839 | 839 | inner |
|
||||
| early_return | false | 841 | 841 | call to inner.~NonTrivial |
|
||||
| early_return | false | 842 | 842 | inner |
|
||||
| early_return | false | 843 | 843 | call to inner.~NonTrivial |
|
||||
| early_return | false | 844 | 844 | before |
|
||||
| early_return | false | 845 | 845 | call to before.~NonTrivial |
|
||||
| early_return | false | 846 | 846 | after |
|
||||
| early_return | false | 847 | 847 | call to after.~NonTrivial |
|
||||
| early_return | true | 808 | 813 | |
|
||||
| early_return | true | 813 | 815 | |
|
||||
| early_return | true | 815 | 825 | T |
|
||||
| early_return | true | 815 | 827 | F |
|
||||
| early_return | true | 821 | 823 | |
|
||||
| early_return | true | 823 | 839 | |
|
||||
| early_return | true | 825 | 821 | |
|
||||
| early_return | true | 827 | 832 | |
|
||||
| early_return | true | 832 | 846 | |
|
||||
| early_return | true | 834 | 808 | |
|
||||
| early_return | true | 836 | 838 | |
|
||||
| early_return | true | 838 | 800 | |
|
||||
| early_return | true | 839 | 841 | |
|
||||
| early_return | true | 841 | 836 | |
|
||||
| early_return | true | 842 | 843 | |
|
||||
| early_return | true | 843 | 827 | |
|
||||
| early_return | true | 844 | 845 | |
|
||||
| early_return | true | 845 | 800 | |
|
||||
| early_return | true | 846 | 847 | |
|
||||
| early_return | true | 847 | 844 | |
|
||||
| early_throw | false | 750 | 750 | early_throw |
|
||||
| early_throw | false | 758 | 758 | declaration |
|
||||
| early_throw | false | 763 | 763 | if (...) ... |
|
||||
| early_throw | false | 765 | 765 | x |
|
||||
| early_throw | false | 767 | 767 | (bool)... |
|
||||
| early_throw | false | 771 | 771 | declaration |
|
||||
| early_throw | false | 773 | 773 | ExprStmt |
|
||||
| early_throw | false | 775 | 775 | re-throw exception |
|
||||
| early_throw | false | 777 | 777 | { ... } |
|
||||
| early_throw | false | 779 | 779 | declaration |
|
||||
| early_throw | false | 784 | 784 | return ... |
|
||||
| early_throw | false | 786 | 786 | { ... } |
|
||||
| early_throw | false | 788 | 788 | before |
|
||||
| early_throw | false | 790 | 790 | call to before.~NonTrivial |
|
||||
| early_throw | false | 791 | 791 | inner |
|
||||
| early_throw | false | 793 | 793 | call to inner.~NonTrivial |
|
||||
| early_throw | false | 794 | 794 | inner |
|
||||
| early_throw | false | 795 | 795 | call to inner.~NonTrivial |
|
||||
| early_throw | false | 796 | 796 | before |
|
||||
| early_throw | false | 797 | 797 | call to before.~NonTrivial |
|
||||
| early_throw | false | 798 | 798 | after |
|
||||
| early_throw | false | 799 | 799 | call to after.~NonTrivial |
|
||||
| early_throw | true | 758 | 763 | |
|
||||
| early_throw | true | 763 | 765 | |
|
||||
| early_throw | true | 765 | 777 | T |
|
||||
| early_throw | true | 765 | 779 | F |
|
||||
| early_throw | true | 771 | 773 | |
|
||||
| early_throw | true | 773 | 775 | |
|
||||
| early_throw | true | 775 | 791 | |
|
||||
| early_throw | true | 777 | 771 | |
|
||||
| early_throw | true | 779 | 784 | |
|
||||
| early_throw | true | 784 | 798 | |
|
||||
| early_throw | true | 786 | 758 | |
|
||||
| early_throw | true | 788 | 790 | |
|
||||
| early_throw | true | 790 | 750 | |
|
||||
| early_throw | true | 791 | 793 | |
|
||||
| early_throw | true | 793 | 788 | |
|
||||
| early_throw | true | 794 | 795 | |
|
||||
| early_throw | true | 795 | 779 | |
|
||||
| early_throw | true | 796 | 797 | |
|
||||
| early_throw | true | 797 | 750 | |
|
||||
| early_throw | true | 798 | 799 | |
|
||||
| early_throw | true | 799 | 796 | |
|
||||
| for_decl_bind | false | 153 | 153 | for_decl_bind |
|
||||
| for_decl_bind | false | 161 | 161 | for(...;...;...) ... |
|
||||
| for_decl_bind | false | 164 | 164 | call to BoxedInt |
|
||||
@@ -194,108 +194,108 @@
|
||||
| for_decl_bind | true | 225 | 219 | |
|
||||
| for_decl_bind | true | 226 | 227 | |
|
||||
| for_decl_bind | true | 227 | 182 | |
|
||||
| for_loop_scope | false | 698 | 698 | for_loop_scope |
|
||||
| for_loop_scope | false | 706 | 706 | declaration |
|
||||
| for_loop_scope | false | 711 | 711 | for(...;...;...) ... |
|
||||
| for_loop_scope | false | 716 | 716 | x |
|
||||
| for_loop_scope | false | 720 | 720 | 10 |
|
||||
| for_loop_scope | false | 721 | 721 | ... < ... |
|
||||
| for_loop_scope | false | 726 | 726 | declaration |
|
||||
| for_loop_scope | false | 728 | 728 | { ... } |
|
||||
| for_loop_scope | false | 730 | 730 | declaration |
|
||||
| for_loop_scope | false | 732 | 732 | x |
|
||||
| for_loop_scope | false | 734 | 734 | ++ ... |
|
||||
| for_loop_scope | false | 736 | 736 | return ... |
|
||||
| for_loop_scope | false | 738 | 738 | { ... } |
|
||||
| for_loop_scope | false | 740 | 740 | for_scope |
|
||||
| for_loop_scope | false | 742 | 742 | call to for_scope.~NonTrivial |
|
||||
| for_loop_scope | false | 743 | 743 | inner_scope |
|
||||
| for_loop_scope | false | 745 | 745 | call to inner_scope.~NonTrivial |
|
||||
| for_loop_scope | false | 746 | 746 | outer_scope |
|
||||
| for_loop_scope | false | 748 | 748 | call to outer_scope.~NonTrivial |
|
||||
| for_loop_scope | true | 706 | 711 | |
|
||||
| for_loop_scope | true | 711 | 730 | |
|
||||
| for_loop_scope | true | 716 | 720 | |
|
||||
| for_loop_scope | true | 720 | 721 | |
|
||||
| for_loop_scope | true | 721 | 728 | T |
|
||||
| for_loop_scope | true | 721 | 740 | F |
|
||||
| for_loop_scope | true | 726 | 743 | |
|
||||
| for_loop_scope | true | 728 | 726 | |
|
||||
| for_loop_scope | true | 730 | 716 | |
|
||||
| for_loop_scope | true | 732 | 734 | |
|
||||
| for_loop_scope | true | 734 | 716 | |
|
||||
| for_loop_scope | true | 736 | 746 | |
|
||||
| for_loop_scope | true | 738 | 706 | |
|
||||
| for_loop_scope | true | 740 | 742 | |
|
||||
| for_loop_scope | true | 742 | 736 | |
|
||||
| for_loop_scope | true | 743 | 745 | |
|
||||
| for_loop_scope | true | 745 | 732 | |
|
||||
| for_loop_scope | true | 746 | 748 | |
|
||||
| for_loop_scope | true | 748 | 698 | |
|
||||
| gotos | false | 608 | 608 | gotos |
|
||||
| gotos | false | 616 | 616 | declaration |
|
||||
| gotos | false | 621 | 621 | if (...) ... |
|
||||
| gotos | false | 623 | 623 | x |
|
||||
| gotos | false | 625 | 625 | (bool)... |
|
||||
| gotos | false | 626 | 626 | goto ... |
|
||||
| gotos | false | 628 | 628 | x |
|
||||
| gotos | false | 630 | 630 | ++ ... |
|
||||
| gotos | false | 632 | 632 | initializer for y |
|
||||
| gotos | false | 643 | 643 | declaration |
|
||||
| gotos | false | 645 | 645 | label ...: |
|
||||
| gotos | false | 647 | 647 | declaration |
|
||||
| gotos | false | 649 | 649 | if (...) ... |
|
||||
| gotos | false | 651 | 651 | y |
|
||||
| gotos | false | 653 | 653 | (bool)... |
|
||||
| gotos | false | 654 | 654 | goto ... |
|
||||
| gotos | false | 656 | 656 | declaration |
|
||||
| gotos | false | 658 | 658 | { ... } |
|
||||
| gotos | false | 660 | 660 | label ...: |
|
||||
| gotos | false | 662 | 662 | ExprStmt |
|
||||
| gotos | false | 664 | 664 | x |
|
||||
| gotos | false | 666 | 666 | -- ... |
|
||||
| gotos | false | 668 | 668 | return ... |
|
||||
| gotos | false | 670 | 670 | { ... } |
|
||||
| gotos | false | 672 | 672 | nt2 |
|
||||
| gotos | false | 674 | 674 | call to nt2.~NonTrivial |
|
||||
| gotos | false | 675 | 675 | nt3 |
|
||||
| gotos | false | 676 | 676 | call to nt3.~NonTrivial |
|
||||
| gotos | false | 677 | 677 | nt2 |
|
||||
| gotos | false | 678 | 678 | call to nt2.~NonTrivial |
|
||||
| gotos | false | 679 | 679 | nt1 |
|
||||
| gotos | false | 681 | 681 | call to nt1.~NonTrivial |
|
||||
| gotos | true | 616 | 621 | |
|
||||
| gotos | true | 621 | 623 | |
|
||||
| gotos | true | 623 | 626 | T |
|
||||
| gotos | true | 623 | 658 | F |
|
||||
| gotos | true | 626 | 645 | |
|
||||
| gotos | true | 628 | 630 | |
|
||||
| gotos | true | 630 | 645 | |
|
||||
| gotos | true | 632 | 628 | |
|
||||
| gotos | true | 643 | 632 | |
|
||||
| gotos | true | 643 | 645 | |
|
||||
| gotos | true | 645 | 647 | |
|
||||
| gotos | true | 647 | 649 | |
|
||||
| gotos | true | 649 | 651 | |
|
||||
| gotos | true | 651 | 654 | T |
|
||||
| gotos | true | 651 | 656 | F |
|
||||
| gotos | true | 654 | 677 | |
|
||||
| gotos | true | 656 | 675 | |
|
||||
| gotos | true | 658 | 643 | |
|
||||
| gotos | true | 660 | 662 | |
|
||||
| gotos | true | 662 | 664 | |
|
||||
| gotos | true | 664 | 666 | |
|
||||
| gotos | true | 666 | 668 | |
|
||||
| gotos | true | 668 | 679 | |
|
||||
| gotos | true | 670 | 616 | |
|
||||
| gotos | true | 672 | 674 | |
|
||||
| gotos | true | 674 | 660 | |
|
||||
| gotos | true | 675 | 676 | |
|
||||
| gotos | true | 676 | 672 | |
|
||||
| gotos | true | 677 | 678 | |
|
||||
| gotos | true | 678 | 660 | |
|
||||
| gotos | true | 679 | 681 | |
|
||||
| gotos | true | 681 | 608 | |
|
||||
| for_loop_scope | false | 699 | 699 | for_loop_scope |
|
||||
| for_loop_scope | false | 707 | 707 | declaration |
|
||||
| for_loop_scope | false | 712 | 712 | for(...;...;...) ... |
|
||||
| for_loop_scope | false | 717 | 717 | x |
|
||||
| for_loop_scope | false | 721 | 721 | 10 |
|
||||
| for_loop_scope | false | 722 | 722 | ... < ... |
|
||||
| for_loop_scope | false | 727 | 727 | declaration |
|
||||
| for_loop_scope | false | 729 | 729 | { ... } |
|
||||
| for_loop_scope | false | 731 | 731 | declaration |
|
||||
| for_loop_scope | false | 733 | 733 | x |
|
||||
| for_loop_scope | false | 735 | 735 | ++ ... |
|
||||
| for_loop_scope | false | 737 | 737 | return ... |
|
||||
| for_loop_scope | false | 739 | 739 | { ... } |
|
||||
| for_loop_scope | false | 741 | 741 | for_scope |
|
||||
| for_loop_scope | false | 743 | 743 | call to for_scope.~NonTrivial |
|
||||
| for_loop_scope | false | 744 | 744 | inner_scope |
|
||||
| for_loop_scope | false | 746 | 746 | call to inner_scope.~NonTrivial |
|
||||
| for_loop_scope | false | 747 | 747 | outer_scope |
|
||||
| for_loop_scope | false | 749 | 749 | call to outer_scope.~NonTrivial |
|
||||
| for_loop_scope | true | 707 | 712 | |
|
||||
| for_loop_scope | true | 712 | 731 | |
|
||||
| for_loop_scope | true | 717 | 721 | |
|
||||
| for_loop_scope | true | 721 | 722 | |
|
||||
| for_loop_scope | true | 722 | 729 | T |
|
||||
| for_loop_scope | true | 722 | 741 | F |
|
||||
| for_loop_scope | true | 727 | 744 | |
|
||||
| for_loop_scope | true | 729 | 727 | |
|
||||
| for_loop_scope | true | 731 | 717 | |
|
||||
| for_loop_scope | true | 733 | 735 | |
|
||||
| for_loop_scope | true | 735 | 717 | |
|
||||
| for_loop_scope | true | 737 | 747 | |
|
||||
| for_loop_scope | true | 739 | 707 | |
|
||||
| for_loop_scope | true | 741 | 743 | |
|
||||
| for_loop_scope | true | 743 | 737 | |
|
||||
| for_loop_scope | true | 744 | 746 | |
|
||||
| for_loop_scope | true | 746 | 733 | |
|
||||
| for_loop_scope | true | 747 | 749 | |
|
||||
| for_loop_scope | true | 749 | 699 | |
|
||||
| gotos | false | 609 | 609 | gotos |
|
||||
| gotos | false | 617 | 617 | declaration |
|
||||
| gotos | false | 622 | 622 | if (...) ... |
|
||||
| gotos | false | 624 | 624 | x |
|
||||
| gotos | false | 626 | 626 | (bool)... |
|
||||
| gotos | false | 627 | 627 | goto ... |
|
||||
| gotos | false | 629 | 629 | x |
|
||||
| gotos | false | 631 | 631 | ++ ... |
|
||||
| gotos | false | 633 | 633 | initializer for y |
|
||||
| gotos | false | 644 | 644 | declaration |
|
||||
| gotos | false | 646 | 646 | label ...: |
|
||||
| gotos | false | 648 | 648 | declaration |
|
||||
| gotos | false | 650 | 650 | if (...) ... |
|
||||
| gotos | false | 652 | 652 | y |
|
||||
| gotos | false | 654 | 654 | (bool)... |
|
||||
| gotos | false | 655 | 655 | goto ... |
|
||||
| gotos | false | 657 | 657 | declaration |
|
||||
| gotos | false | 659 | 659 | { ... } |
|
||||
| gotos | false | 661 | 661 | label ...: |
|
||||
| gotos | false | 663 | 663 | ExprStmt |
|
||||
| gotos | false | 665 | 665 | x |
|
||||
| gotos | false | 667 | 667 | -- ... |
|
||||
| gotos | false | 669 | 669 | return ... |
|
||||
| gotos | false | 671 | 671 | { ... } |
|
||||
| gotos | false | 673 | 673 | nt2 |
|
||||
| gotos | false | 675 | 675 | call to nt2.~NonTrivial |
|
||||
| gotos | false | 676 | 676 | nt2 |
|
||||
| gotos | false | 677 | 677 | call to nt2.~NonTrivial |
|
||||
| gotos | false | 678 | 678 | nt3 |
|
||||
| gotos | false | 679 | 679 | call to nt3.~NonTrivial |
|
||||
| gotos | false | 680 | 680 | nt1 |
|
||||
| gotos | false | 682 | 682 | call to nt1.~NonTrivial |
|
||||
| gotos | true | 617 | 622 | |
|
||||
| gotos | true | 622 | 624 | |
|
||||
| gotos | true | 624 | 627 | T |
|
||||
| gotos | true | 624 | 659 | F |
|
||||
| gotos | true | 627 | 646 | |
|
||||
| gotos | true | 629 | 631 | |
|
||||
| gotos | true | 631 | 646 | |
|
||||
| gotos | true | 633 | 629 | |
|
||||
| gotos | true | 644 | 633 | |
|
||||
| gotos | true | 644 | 646 | |
|
||||
| gotos | true | 646 | 648 | |
|
||||
| gotos | true | 648 | 650 | |
|
||||
| gotos | true | 650 | 652 | |
|
||||
| gotos | true | 652 | 655 | T |
|
||||
| gotos | true | 652 | 657 | F |
|
||||
| gotos | true | 655 | 673 | |
|
||||
| gotos | true | 657 | 678 | |
|
||||
| gotos | true | 659 | 644 | |
|
||||
| gotos | true | 661 | 663 | |
|
||||
| gotos | true | 663 | 665 | |
|
||||
| gotos | true | 665 | 667 | |
|
||||
| gotos | true | 667 | 669 | |
|
||||
| gotos | true | 669 | 680 | |
|
||||
| gotos | true | 671 | 617 | |
|
||||
| gotos | true | 673 | 675 | |
|
||||
| gotos | true | 675 | 661 | |
|
||||
| gotos | true | 676 | 677 | |
|
||||
| gotos | true | 677 | 661 | |
|
||||
| gotos | true | 678 | 679 | |
|
||||
| gotos | true | 679 | 676 | |
|
||||
| gotos | true | 680 | 682 | |
|
||||
| gotos | true | 682 | 609 | |
|
||||
| if_decl_bind | false | 375 | 375 | if_decl_bind |
|
||||
| if_decl_bind | false | 383 | 383 | if (...) ... |
|
||||
| if_decl_bind | false | 386 | 386 | call to operator int |
|
||||
@@ -350,45 +350,45 @@
|
||||
| if_decl_bind | true | 435 | 383 | |
|
||||
| if_decl_bind | true | 437 | 439 | |
|
||||
| if_decl_bind | true | 439 | 424 | |
|
||||
| never_destructs | false | 682 | 682 | never_destructs |
|
||||
| never_destructs | false | 687 | 687 | declaration |
|
||||
| never_destructs | false | 692 | 692 | label ...: |
|
||||
| never_destructs | false | 694 | 694 | goto ... |
|
||||
| never_destructs | false | 696 | 696 | { ... } |
|
||||
| never_destructs | true | 687 | 692 | |
|
||||
| never_destructs | true | 692 | 694 | |
|
||||
| never_destructs | true | 694 | 692 | |
|
||||
| never_destructs | true | 696 | 687 | |
|
||||
| never_destructs | false | 683 | 683 | never_destructs |
|
||||
| never_destructs | false | 688 | 688 | declaration |
|
||||
| never_destructs | false | 693 | 693 | label ...: |
|
||||
| never_destructs | false | 695 | 695 | goto ... |
|
||||
| never_destructs | false | 697 | 697 | { ... } |
|
||||
| never_destructs | true | 688 | 693 | |
|
||||
| never_destructs | true | 693 | 695 | |
|
||||
| never_destructs | true | 695 | 693 | |
|
||||
| never_destructs | true | 697 | 688 | |
|
||||
| operator delete | false | 476 | 476 | operator delete |
|
||||
| operator new | false | 499 | 499 | operator new |
|
||||
| simple | false | 871 | 871 | simple |
|
||||
| simple | false | 876 | 876 | declaration |
|
||||
| simple | false | 881 | 881 | return ... |
|
||||
| simple | false | 883 | 883 | { ... } |
|
||||
| simple | false | 885 | 885 | nt |
|
||||
| simple | false | 887 | 887 | call to nt.~NonTrivial |
|
||||
| simple | true | 876 | 881 | |
|
||||
| simple | true | 881 | 885 | |
|
||||
| simple | true | 883 | 876 | |
|
||||
| simple | true | 885 | 887 | |
|
||||
| simple | true | 887 | 871 | |
|
||||
| simple2 | false | 847 | 847 | simple2 |
|
||||
| simple2 | false | 852 | 852 | declaration |
|
||||
| simple2 | false | 857 | 857 | declaration |
|
||||
| simple2 | false | 862 | 862 | return ... |
|
||||
| simple2 | false | 864 | 864 | { ... } |
|
||||
| simple2 | false | 866 | 866 | one |
|
||||
| simple2 | false | 868 | 868 | call to one.~NonTrivial |
|
||||
| simple2 | false | 869 | 869 | two |
|
||||
| simple2 | false | 870 | 870 | call to two.~NonTrivial |
|
||||
| simple2 | true | 852 | 857 | |
|
||||
| simple2 | true | 857 | 862 | |
|
||||
| simple2 | true | 862 | 869 | |
|
||||
| simple2 | true | 864 | 852 | |
|
||||
| simple2 | true | 866 | 868 | |
|
||||
| simple2 | true | 868 | 847 | |
|
||||
| simple2 | true | 869 | 870 | |
|
||||
| simple2 | true | 870 | 866 | |
|
||||
| simple | false | 872 | 872 | simple |
|
||||
| simple | false | 877 | 877 | declaration |
|
||||
| simple | false | 882 | 882 | return ... |
|
||||
| simple | false | 884 | 884 | { ... } |
|
||||
| simple | false | 886 | 886 | nt |
|
||||
| simple | false | 888 | 888 | call to nt.~NonTrivial |
|
||||
| simple | true | 877 | 882 | |
|
||||
| simple | true | 882 | 886 | |
|
||||
| simple | true | 884 | 877 | |
|
||||
| simple | true | 886 | 888 | |
|
||||
| simple | true | 888 | 872 | |
|
||||
| simple2 | false | 848 | 848 | simple2 |
|
||||
| simple2 | false | 853 | 853 | declaration |
|
||||
| simple2 | false | 858 | 858 | declaration |
|
||||
| simple2 | false | 863 | 863 | return ... |
|
||||
| simple2 | false | 865 | 865 | { ... } |
|
||||
| simple2 | false | 867 | 867 | one |
|
||||
| simple2 | false | 869 | 869 | call to one.~NonTrivial |
|
||||
| simple2 | false | 870 | 870 | two |
|
||||
| simple2 | false | 871 | 871 | call to two.~NonTrivial |
|
||||
| simple2 | true | 853 | 858 | |
|
||||
| simple2 | true | 858 | 863 | |
|
||||
| simple2 | true | 863 | 870 | |
|
||||
| simple2 | true | 865 | 853 | |
|
||||
| simple2 | true | 867 | 869 | |
|
||||
| simple2 | true | 869 | 848 | |
|
||||
| simple2 | true | 870 | 871 | |
|
||||
| simple2 | true | 871 | 867 | |
|
||||
| switch_decl_bind | false | 276 | 276 | switch_decl_bind |
|
||||
| switch_decl_bind | false | 284 | 284 | switch (...) ... |
|
||||
| switch_decl_bind | false | 287 | 287 | call to operator int |
|
||||
@@ -444,21 +444,21 @@
|
||||
| switch_decl_bind | true | 310 | 313 | |
|
||||
| switch_decl_bind | true | 313 | 315 | |
|
||||
| switch_decl_bind | true | 315 | 317 | |
|
||||
| switch_decl_bind | true | 317 | 371 | |
|
||||
| switch_decl_bind | true | 317 | 368 | |
|
||||
| switch_decl_bind | true | 319 | 324 | |
|
||||
| switch_decl_bind | true | 324 | 326 | |
|
||||
| switch_decl_bind | true | 326 | 328 | |
|
||||
| switch_decl_bind | true | 328 | 330 | |
|
||||
| switch_decl_bind | true | 330 | 332 | |
|
||||
| switch_decl_bind | true | 332 | 334 | |
|
||||
| switch_decl_bind | true | 334 | 373 | |
|
||||
| switch_decl_bind | true | 334 | 371 | |
|
||||
| switch_decl_bind | true | 336 | 338 | |
|
||||
| switch_decl_bind | true | 338 | 340 | |
|
||||
| switch_decl_bind | true | 340 | 342 | |
|
||||
| switch_decl_bind | true | 342 | 344 | |
|
||||
| switch_decl_bind | true | 344 | 348 | |
|
||||
| switch_decl_bind | true | 348 | 349 | |
|
||||
| switch_decl_bind | true | 349 | 368 | |
|
||||
| switch_decl_bind | true | 349 | 373 | |
|
||||
| switch_decl_bind | true | 351 | 300 | |
|
||||
| switch_decl_bind | true | 351 | 319 | |
|
||||
| switch_decl_bind | true | 351 | 336 | |
|
||||
@@ -501,10 +501,11 @@
|
||||
| while_decl_bind | true | 241 | 251 | |
|
||||
| while_decl_bind | true | 243 | 241 | |
|
||||
| while_decl_bind | true | 251 | 259 | T |
|
||||
| while_decl_bind | true | 251 | 271 | F |
|
||||
| while_decl_bind | true | 251 | 274 | F |
|
||||
| while_decl_bind | true | 253 | 255 | |
|
||||
| while_decl_bind | true | 255 | 257 | |
|
||||
| while_decl_bind | true | 257 | 274 | |
|
||||
| while_decl_bind | true | 257 | 243 | |
|
||||
| while_decl_bind | true | 257 | 271 | |
|
||||
| while_decl_bind | true | 259 | 253 | |
|
||||
| while_decl_bind | true | 261 | 263 | |
|
||||
| while_decl_bind | true | 263 | 265 | |
|
||||
@@ -512,6 +513,5 @@
|
||||
| while_decl_bind | true | 267 | 228 | |
|
||||
| while_decl_bind | true | 269 | 236 | |
|
||||
| while_decl_bind | true | 271 | 273 | |
|
||||
| while_decl_bind | true | 273 | 261 | |
|
||||
| while_decl_bind | true | 274 | 275 | |
|
||||
| while_decl_bind | true | 275 | 243 | |
|
||||
| while_decl_bind | true | 275 | 261 | |
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
/// "json.net"
|
||||
/// }
|
||||
/// </summary>
|
||||
private void AddPackageDependencies(JObject json)
|
||||
private void AddPackageDependencies(JObject json, string jsonPath)
|
||||
{
|
||||
// If there is more than one framework we need to pick just one.
|
||||
// To ensure stability we pick one based on the lexicographic order of
|
||||
@@ -91,7 +91,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
if (references is null)
|
||||
{
|
||||
logger.LogDebug("No references found in the targets section in the assets file.");
|
||||
logger.LogDebug($"No references found in the targets section in '{jsonPath}'");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
/// "microsoft.netcore.app.ref"
|
||||
/// }
|
||||
/// </summary>
|
||||
private void AddFrameworkDependencies(JObject json)
|
||||
private void AddFrameworkDependencies(JObject json, string jsonPath)
|
||||
{
|
||||
|
||||
var frameworks = json
|
||||
@@ -163,7 +163,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
if (frameworks is null)
|
||||
{
|
||||
logger.LogDebug("No framework section in assets.json.");
|
||||
logger.LogDebug($"No framework section in '{jsonPath}'.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
if (references is null)
|
||||
{
|
||||
logger.LogDebug("No framework references in assets.json.");
|
||||
logger.LogDebug($"No framework references in '{jsonPath}'.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -196,8 +196,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
try
|
||||
{
|
||||
var obj = JObject.Parse(json);
|
||||
AddPackageDependencies(obj);
|
||||
AddFrameworkDependencies(obj);
|
||||
AddPackageDependencies(obj, json);
|
||||
AddFrameworkDependencies(obj, json);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -94,7 +94,10 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
public HashSet<AssemblyLookupLocation> Restore()
|
||||
{
|
||||
var assemblyLookupLocations = new HashSet<AssemblyLookupLocation>();
|
||||
var checkNugetFeedResponsiveness = EnvironmentVariables.GetBoolean(EnvironmentVariableNames.CheckNugetFeedResponsiveness);
|
||||
var checkNugetFeedResponsiveness = EnvironmentVariables.GetBooleanOptOut(EnvironmentVariableNames.CheckNugetFeedResponsiveness);
|
||||
logger.LogInfo($"Checking NuGet feed responsiveness: {checkNugetFeedResponsiveness}");
|
||||
compilationInfoContainer.CompilationInfos.Add(("NuGet feed responsiveness checked", checkNugetFeedResponsiveness ? "1" : "0"));
|
||||
|
||||
try
|
||||
{
|
||||
if (checkNugetFeedResponsiveness && !CheckFeeds())
|
||||
|
||||
@@ -20,17 +20,9 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
protected override bool IsEnabled()
|
||||
{
|
||||
var webViewExtractionOption = Environment.GetEnvironmentVariable(EnvironmentVariableNames.WebViewGeneration);
|
||||
if (webViewExtractionOption == null ||
|
||||
bool.TryParse(webViewExtractionOption, out var shouldExtractWebViews) &&
|
||||
shouldExtractWebViews)
|
||||
{
|
||||
compilationInfoContainer.CompilationInfos.Add(("WebView extraction enabled", "1"));
|
||||
return true;
|
||||
}
|
||||
|
||||
compilationInfoContainer.CompilationInfos.Add(("WebView extraction enabled", "0"));
|
||||
return false;
|
||||
var webViewExtractionOption = EnvironmentVariables.GetBooleanOptOut(EnvironmentVariableNames.WebViewGeneration);
|
||||
compilationInfoContainer.CompilationInfos.Add(("WebView extraction enabled", webViewExtractionOption ? "1" : "0"));
|
||||
return webViewExtractionOption;
|
||||
}
|
||||
|
||||
protected override ICollection<string> AdditionalFiles => fileProvider.RazorViews;
|
||||
|
||||
@@ -29,6 +29,19 @@ namespace Semmle.Util
|
||||
return threads;
|
||||
}
|
||||
|
||||
public static bool GetBooleanOptOut(string name)
|
||||
{
|
||||
var env = Environment.GetEnvironmentVariable(name);
|
||||
if (env == null ||
|
||||
bool.TryParse(env, out var value) &&
|
||||
value)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool GetBoolean(string name)
|
||||
{
|
||||
var env = Environment.GetEnvironmentVariable(name);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.7.15
|
||||
version: 1.7.16-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.7.15
|
||||
version: 1.7.16-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
| All Nuget feeds reachable | 1.0 |
|
||||
| Failed project restore with package source error | 0.0 |
|
||||
| Failed solution restore with package source error | 0.0 |
|
||||
| NuGet feed responsiveness checked | 1.0 |
|
||||
| Project files on filesystem | 1.0 |
|
||||
| Resource extraction enabled | 1.0 |
|
||||
| Restored .NET framework variants | 1.0 |
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
| All Nuget feeds reachable | 1.0 |
|
||||
| Failed project restore with package source error | 1.0 |
|
||||
| Failed solution restore with package source error | 0.0 |
|
||||
| Fallback nuget restore | 1.0 |
|
||||
| NuGet feed responsiveness checked | 1.0 |
|
||||
| Project files on filesystem | 1.0 |
|
||||
| Resolved assembly conflicts | 7.0 |
|
||||
| Resource extraction enabled | 0.0 |
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
| All Nuget feeds reachable | 0.0 |
|
||||
| Fallback nuget restore | 1.0 |
|
||||
| Inherited Nuget feed count | 1.0 |
|
||||
| NuGet feed responsiveness checked | 1.0 |
|
||||
| Project files on filesystem | 1.0 |
|
||||
| Resolved assembly conflicts | 7.0 |
|
||||
| Resource extraction enabled | 0.0 |
|
||||
|
||||
@@ -2,7 +2,7 @@ from create_database_utils import *
|
||||
from diagnostics_test_utils import *
|
||||
import os
|
||||
|
||||
os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK"] = "true" # Enable NuGet feed check
|
||||
# os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK"] = "true" # Nuget feed check is enabled by default
|
||||
os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_TIMEOUT"] = "1" # 1ms, the GET request should fail with such short timeout
|
||||
os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_LIMIT"] = "1" # Limit the count of checks to 1
|
||||
os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_EXCLUDED"] = "https://abc.de:8000/packages/" # Exclude this feed from check
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
extensions:
|
||||
# Make sure that the extensible model predicates have at least one definition
|
||||
# to avoid errors about undefined extensionals.
|
||||
- addsTo:
|
||||
pack: codeql/csharp-all
|
||||
extensible: sourceModel
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-all
|
||||
version: 0.10.0
|
||||
version: 0.10.1-dev
|
||||
groups: csharp
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
|
||||
@@ -51,8 +51,6 @@ class TopLevelExprParent extends Element, @top_level_expr_parent {
|
||||
final Expr getAChildExpr() { result = this.getChildExpr(_) }
|
||||
}
|
||||
|
||||
private predicate hasNoSourceLocation(Element e) { not e.getALocation() instanceof SourceLocation }
|
||||
|
||||
/** INTERNAL: Do not use. */
|
||||
Expr getExpressionBody(Callable c) {
|
||||
result = c.getAChildExpr() and
|
||||
@@ -67,17 +65,46 @@ private ControlFlowElement getBody(Callable c) {
|
||||
result = getStatementBody(c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private SourceLocation getASourceLocation(Element e) {
|
||||
result = e.getALocation().(SourceLocation) and
|
||||
not exists(e.getALocation().(SourceLocation).getMappedLocation())
|
||||
or
|
||||
result = e.getALocation().(SourceLocation).getMappedLocation()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasNoSourceLocation(Element e) { not exists(getASourceLocation(e)) }
|
||||
|
||||
pragma[nomagic]
|
||||
private Location getFirstSourceLocation(Element e) {
|
||||
result =
|
||||
min(Location l, string filepath, int startline, int startcolumn, int endline, int endcolumn |
|
||||
l = getASourceLocation(e) and
|
||||
l.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
|
|
||||
l order by filepath, startline, startcolumn, endline, endcolumn
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
Location bestLocation(Element e) {
|
||||
result = e.getALocation().(SourceLocation) and
|
||||
not exists(e.getALocation().(SourceLocation).getMappedLocation())
|
||||
or
|
||||
result = e.getALocation().(SourceLocation).getMappedLocation()
|
||||
(
|
||||
if e.(Modifiable).isPartial() or e instanceof Namespace
|
||||
then result = getASourceLocation(e)
|
||||
else result = getFirstSourceLocation(e)
|
||||
)
|
||||
or
|
||||
hasNoSourceLocation(e) and
|
||||
result = min(Location l | l = e.getALocation() | l order by l.getFile().toString())
|
||||
result =
|
||||
min(Location l, string filepath |
|
||||
l = e.getALocation() and
|
||||
l.hasLocationInfo(filepath, _, _, _, _)
|
||||
|
|
||||
l order by filepath
|
||||
)
|
||||
or
|
||||
not exists(e.getALocation()) and
|
||||
result instanceof EmptyLocation
|
||||
|
||||
@@ -63,7 +63,7 @@ class EmptyLocation extends Location {
|
||||
*/
|
||||
class SourceLocation extends Location, @location_default {
|
||||
/** Gets the location that takes into account `#line` directives, if any. */
|
||||
Location getMappedLocation() {
|
||||
SourceLocation getMappedLocation() {
|
||||
locations_mapped(this, result) and
|
||||
not exists(LineDirective l | l.getALocation() = this)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.security.dataflow.flowsinks.FlowSinks
|
||||
private import semmle.code.csharp.security.dataflow.flowsources.FlowSources
|
||||
private import semmle.code.csharp.frameworks.system.codedom.Compiler
|
||||
private import semmle.code.csharp.security.Sanitizers
|
||||
@@ -16,7 +17,7 @@ abstract class Source extends DataFlow::Node { }
|
||||
/**
|
||||
* A data flow sink for user input treated as code vulnerabilities.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::ExprNode { }
|
||||
abstract class Sink extends ApiSinkExprNode { }
|
||||
|
||||
/**
|
||||
* A sanitizer for user input treated as code vulnerabilities.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import csharp
|
||||
private import semmle.code.csharp.controlflow.Guards
|
||||
private import semmle.code.csharp.controlflow.BasicBlocks
|
||||
private import semmle.code.csharp.security.dataflow.flowsinks.FlowSinks
|
||||
private import semmle.code.csharp.security.dataflow.flowsources.FlowSources
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.frameworks.system.Net
|
||||
@@ -14,12 +15,12 @@ private import semmle.code.csharp.security.SensitiveActions
|
||||
/**
|
||||
* A data flow source for user-controlled bypass of sensitive method.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
abstract class Source extends ApiSourceNode { }
|
||||
|
||||
/**
|
||||
* A data flow sink for user-controlled bypass of sensitive method.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::ExprNode {
|
||||
abstract class Sink extends ApiSinkExprNode {
|
||||
/** Gets the 'MethodCall' which is considered sensitive. */
|
||||
abstract MethodCall getSensitiveMethodCall();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.security.dataflow.flowsinks.FlowSinks
|
||||
private import semmle.code.csharp.security.dataflow.flowsources.FlowSources
|
||||
private import semmle.code.csharp.security.dataflow.flowsinks.ExternalLocationSink
|
||||
private import semmle.code.csharp.security.PrivateData
|
||||
@@ -15,7 +16,7 @@ abstract class Source extends DataFlow::ExprNode { }
|
||||
/**
|
||||
* A data flow sink for private information flowing unencrypted to an external location.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::ExprNode { }
|
||||
abstract class Sink extends ApiSinkExprNode { }
|
||||
|
||||
/**
|
||||
* A sanitizer for private information flowing unencrypted to an external location.
|
||||
|
||||
@@ -9,6 +9,7 @@ private import semmle.code.csharp.frameworks.Moq
|
||||
private import semmle.code.csharp.frameworks.system.web.Security
|
||||
private import semmle.code.csharp.frameworks.system.security.cryptography.X509Certificates
|
||||
private import semmle.code.csharp.frameworks.Test
|
||||
private import semmle.code.csharp.security.dataflow.flowsinks.FlowSinks
|
||||
|
||||
/**
|
||||
* A data flow source for hard coded credentials.
|
||||
@@ -18,7 +19,7 @@ abstract class Source extends DataFlow::ExprNode { }
|
||||
/**
|
||||
* A data flow sink for hard coded credentials.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::ExprNode {
|
||||
abstract class Sink extends ApiSinkExprNode {
|
||||
/**
|
||||
* Gets a description of this sink, including a placeholder for the sink and a placeholder for
|
||||
* the supplementary element.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.security.dataflow.flowsinks.FlowSinks
|
||||
private import semmle.code.csharp.security.dataflow.flowsources.FlowSources
|
||||
private import semmle.code.csharp.frameworks.system.DirectoryServices
|
||||
private import semmle.code.csharp.frameworks.system.directoryservices.Protocols
|
||||
@@ -18,7 +19,7 @@ abstract class Source extends DataFlow::Node { }
|
||||
/**
|
||||
* A data flow sink for unvalidated user input that is used to construct LDAP queries.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::ExprNode { }
|
||||
abstract class Sink extends ApiSinkExprNode { }
|
||||
|
||||
/**
|
||||
* A sanitizer for unvalidated user input that is used to construct LDAP queries.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.security.dataflow.flowsinks.FlowSinks
|
||||
private import semmle.code.csharp.security.dataflow.flowsources.FlowSources
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.frameworks.system.text.RegularExpressions
|
||||
@@ -18,7 +19,7 @@ abstract class Source extends DataFlow::Node { }
|
||||
/**
|
||||
* A data flow sink for untrusted user input used in log entries.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::ExprNode { }
|
||||
abstract class Sink extends ApiSinkExprNode { }
|
||||
|
||||
/**
|
||||
* A sanitizer for untrusted user input used in log entries.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.security.dataflow.flowsinks.FlowSinks
|
||||
private import semmle.code.csharp.security.dataflow.flowsources.FlowSources
|
||||
private import semmle.code.csharp.frameworks.system.Xml
|
||||
private import semmle.code.csharp.security.Sanitizers
|
||||
@@ -18,7 +19,7 @@ abstract class Source extends DataFlow::Node { }
|
||||
* A data flow sink for untrusted user input processed as XML without validation against a known
|
||||
* schema.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::ExprNode {
|
||||
abstract class Sink extends ApiSinkExprNode {
|
||||
/** Gets a string describing the reason why this is a sink. */
|
||||
abstract string getReason();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.dataflow.DataFlow2
|
||||
private import semmle.code.csharp.security.dataflow.flowsinks.FlowSinks
|
||||
private import semmle.code.csharp.security.dataflow.flowsources.FlowSources
|
||||
private import semmle.code.csharp.frameworks.system.text.RegularExpressions
|
||||
private import semmle.code.csharp.security.Sanitizers
|
||||
@@ -17,7 +18,7 @@ abstract class Source extends DataFlow::Node { }
|
||||
/**
|
||||
* A data flow sink for untrusted user input used in dangerous regular expression operations.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::ExprNode { }
|
||||
abstract class Sink extends ApiSinkExprNode { }
|
||||
|
||||
/**
|
||||
* A sanitizer for untrusted user input used in dangerous regular expression operations.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.security.dataflow.flowsinks.FlowSinks
|
||||
private import semmle.code.csharp.security.dataflow.flowsources.FlowSources
|
||||
private import semmle.code.csharp.frameworks.system.text.RegularExpressions
|
||||
private import semmle.code.csharp.security.Sanitizers
|
||||
@@ -16,7 +17,7 @@ abstract class Source extends DataFlow::Node { }
|
||||
/**
|
||||
* A data flow sink for untrusted user input used to construct regular expressions.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::ExprNode { }
|
||||
abstract class Sink extends ApiSinkExprNode { }
|
||||
|
||||
/**
|
||||
* A sanitizer for untrusted user input used to construct regular expressions.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.security.dataflow.flowsinks.FlowSinks
|
||||
private import semmle.code.csharp.security.dataflow.flowsources.FlowSources
|
||||
private import semmle.code.csharp.frameworks.system.Data
|
||||
private import semmle.code.csharp.security.Sanitizers
|
||||
@@ -15,7 +16,7 @@ abstract class Source extends DataFlow::Node { }
|
||||
/**
|
||||
* A data flow sink for untrusted user input used in resource descriptors.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::ExprNode { }
|
||||
abstract class Sink extends ApiSinkExprNode { }
|
||||
|
||||
/**
|
||||
* A sanitizer for untrusted user input used in resource descriptors.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.security.dataflow.flowsinks.FlowSinks
|
||||
private import semmle.code.csharp.security.dataflow.flowsources.FlowSources
|
||||
private import semmle.code.csharp.frameworks.Sql
|
||||
private import semmle.code.csharp.security.Sanitizers
|
||||
@@ -16,7 +17,7 @@ abstract class Source extends DataFlow::Node { }
|
||||
/**
|
||||
* A sink for SQL injection vulnerabilities.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::ExprNode { }
|
||||
abstract class Sink extends ApiSinkExprNode { }
|
||||
|
||||
/**
|
||||
* A sanitizer for SQL injection vulnerabilities.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user