mirror of
https://github.com/github/codeql.git
synced 2026-04-25 00:35:20 +02:00
Merge branch 'main' into aegilops/js/insecure-helmet-middleware
This commit is contained in:
@@ -1 +1 @@
|
||||
7.1.2
|
||||
7.2.0
|
||||
|
||||
2
.github/workflows/ruby-build.yml
vendored
2
.github/workflows/ruby-build.yml
vendored
@@ -7,6 +7,7 @@ on:
|
||||
- .github/workflows/ruby-build.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
- "shared/tree-sitter-extractor/**"
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
@@ -16,6 +17,7 @@ on:
|
||||
- .github/workflows/ruby-build.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
- "shared/tree-sitter-extractor/**"
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
|
||||
35
MODULE.bazel
35
MODULE.bazel
@@ -13,22 +13,45 @@ local_path_override(
|
||||
|
||||
# see https://registry.bazel.build/ for a list of available packages
|
||||
|
||||
bazel_dep(name = "platforms", version = "0.0.9")
|
||||
bazel_dep(name = "rules_go", version = "0.47.0")
|
||||
bazel_dep(name = "platforms", version = "0.0.10")
|
||||
bazel_dep(name = "rules_go", version = "0.48.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")
|
||||
bazel_dep(name = "bazel_skylib", version = "1.5.0")
|
||||
bazel_dep(name = "rules_nodejs", version = "6.2.0")
|
||||
bazel_dep(name = "rules_python", version = "0.32.2")
|
||||
bazel_dep(name = "bazel_skylib", version = "1.6.1")
|
||||
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 = "rules_kotlin", version = "1.9.4-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.36.0")
|
||||
bazel_dep(name = "gazelle", version = "0.37.0")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.15.1")
|
||||
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
|
||||
bazel_dep(name = "rules_rust", version = "0.46.0")
|
||||
|
||||
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
|
||||
|
||||
crate = use_extension(
|
||||
"@rules_rust//crate_universe:extension.bzl",
|
||||
"crate",
|
||||
)
|
||||
crate.from_cargo(
|
||||
name = "py_deps",
|
||||
cargo_lockfile = "//python/extractor/tsg-python:Cargo.lock",
|
||||
manifests = [
|
||||
"//python/extractor/tsg-python:Cargo.toml",
|
||||
"//python/extractor/tsg-python/tsp:Cargo.toml",
|
||||
],
|
||||
)
|
||||
crate.from_cargo(
|
||||
name = "ruby_deps",
|
||||
cargo_lockfile = "//ruby/extractor:Cargo.lock",
|
||||
manifests = [
|
||||
"//ruby/extractor:Cargo.toml",
|
||||
"//ruby/extractor/codeql-extractor-fake-crate:Cargo.toml",
|
||||
],
|
||||
)
|
||||
use_repo(crate, "py_deps", "ruby_deps")
|
||||
|
||||
dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
|
||||
dotnet.toolchain(dotnet_version = "8.0.101")
|
||||
use_repo(dotnet, "dotnet_toolchains")
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
## 1.1.0
|
||||
|
||||
### New Features
|
||||
|
||||
* Data models can now be added with data extensions. In this way source, sink and summary models can be added in extension `.model.yml` files, rather than by writing classes in QL code. New models should be added in the `lib/ext` folder.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* A partial model for the `Boost.Asio` network library has been added. This includes sources, sinks and summaries for certain functions in `Boost.Asio`, such as `read_until` and `write`.
|
||||
|
||||
## 1.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
4
cpp/ql/lib/change-notes/2024-06-10-builtin-expect.md
Normal file
4
cpp/ql/lib/change-notes/2024-06-10-builtin-expect.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The "Guards" library (`semmle.code.cpp.controlflow.Guards`) now also infers guards from calls to the builtin operation `__builtin_expect`. As a result, some queries may produce fewer false positives.
|
||||
4
cpp/ql/lib/change-notes/2024-06-13-double-free.md
Normal file
4
cpp/ql/lib/change-notes/2024-06-13-double-free.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The queries "Potential double free" (`cpp/double-free`) and "Potential use after free" (`cpp/use-after-free`) now produce fewer false positives.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* A partial model for the `Boost.Asio` network library has been added. This includes sources, sinks and summaries for certain functions in `Boost.Asio`, such as `read_until` and `write`.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Data models can now be added with data extensions. In this way source, sink and summary models can be added in extension `.model.yml` files, rather than by writing classes in QL code. New models should be added in the `lib/ext` folder.
|
||||
9
cpp/ql/lib/change-notes/released/1.1.0.md
Normal file
9
cpp/ql/lib/change-notes/released/1.1.0.md
Normal file
@@ -0,0 +1,9 @@
|
||||
## 1.1.0
|
||||
|
||||
### New Features
|
||||
|
||||
* Data models can now be added with data extensions. In this way source, sink and summary models can be added in extension `.model.yml` files, rather than by writing classes in QL code. New models should be added in the `lib/ext` folder.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* A partial model for the `Boost.Asio` network library has been added. This includes sources, sinks and summaries for certain functions in `Boost.Asio`, such as `read_until` and `write`.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.0
|
||||
lastReleaseVersion: 1.1.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 1.0.1-dev
|
||||
version: 1.1.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -375,6 +375,33 @@ cached
|
||||
class IRGuardCondition extends Instruction {
|
||||
Instruction branch;
|
||||
|
||||
/*
|
||||
* An `IRGuardCondition` supports reasoning about four different kinds of
|
||||
* relations:
|
||||
* 1. A unary equality relation of the form `e == k`
|
||||
* 2. A binary equality relation of the form `e1 == e2 + k`
|
||||
* 3. A unary inequality relation of the form `e < k`
|
||||
* 4. A binary inequality relation of the form `e1 < e2 + k`
|
||||
*
|
||||
* where `k` is a constant.
|
||||
*
|
||||
* Furthermore, the unary relations (i.e., case 1 and case 3) are also
|
||||
* inferred from `switch` statement guards: equality relations are inferred
|
||||
* from the unique `case` statement, if any, and inequality relations are
|
||||
* inferred from the [case range](https://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html)
|
||||
* gcc extension.
|
||||
*
|
||||
* The implementation of all four follows the same structure: Each relation
|
||||
* has a cached user-facing predicate that. For example,
|
||||
* `GuardCondition::comparesEq` calls `compares_eq`. This predicate has
|
||||
* several cases that recursively decompose the relation to bring it to a
|
||||
* canonical form (i.e., a relation of the form `e1 == e2 + k`). The base
|
||||
* case for this relation (i.e., `simple_comparison_eq`) handles
|
||||
* `CompareEQInstruction`s and `CompareNEInstruction`, and recursive
|
||||
* predicates (e.g., `complex_eq`) rewrites larger expressions such as
|
||||
* `e1 + k1 == e2 + k2` into canonical the form `e1 == e2 + (k2 - k1)`.
|
||||
*/
|
||||
|
||||
cached
|
||||
IRGuardCondition() { branch = getBranchForCondition(this) }
|
||||
|
||||
@@ -735,6 +762,8 @@ private predicate compares_eq(
|
||||
exists(AbstractValue dual | value = dual.getDualValue() |
|
||||
compares_eq(test.(LogicalNotInstruction).getUnary(), left, right, k, areEqual, dual)
|
||||
)
|
||||
or
|
||||
compares_eq(test.(BuiltinExpectCallInstruction).getCondition(), left, right, k, areEqual, value)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -776,7 +805,9 @@ private predicate unary_compares_eq(
|
||||
Instruction test, Operand op, int k, boolean areEqual, boolean inNonZeroCase, AbstractValue value
|
||||
) {
|
||||
/* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */
|
||||
exists(AbstractValue v | unary_simple_comparison_eq(test, op, k, inNonZeroCase, v) |
|
||||
exists(AbstractValue v |
|
||||
unary_simple_comparison_eq(test, k, inNonZeroCase, v) and op.getDef() = test
|
||||
|
|
||||
areEqual = true and value = v
|
||||
or
|
||||
areEqual = false and value = v.getDualValue()
|
||||
@@ -802,6 +833,9 @@ private predicate unary_compares_eq(
|
||||
int_value(const) = k1 and
|
||||
k = k1 + k2
|
||||
)
|
||||
or
|
||||
unary_compares_eq(test.(BuiltinExpectCallInstruction).getCondition(), op, k, areEqual,
|
||||
inNonZeroCase, value)
|
||||
}
|
||||
|
||||
/** Rearrange various simple comparisons into `left == right + k` form. */
|
||||
@@ -821,45 +855,55 @@ private predicate simple_comparison_eq(
|
||||
value.(BooleanValue).getValue() = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `test` is an instruction that is part of test that eventually is
|
||||
* used in a conditional branch.
|
||||
*/
|
||||
private predicate relevantUnaryComparison(Instruction test) {
|
||||
not test instanceof CompareInstruction and
|
||||
exists(IRType type, ConditionalBranchInstruction branch |
|
||||
type instanceof IRAddressType or type instanceof IRIntegerType
|
||||
|
|
||||
type = test.getResultIRType() and
|
||||
branch.getCondition() = test
|
||||
)
|
||||
or
|
||||
exists(LogicalNotInstruction logicalNot |
|
||||
relevantUnaryComparison(logicalNot) and
|
||||
test = logicalNot.getUnary()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Rearrange various simple comparisons into `op == k` form.
|
||||
*/
|
||||
private predicate unary_simple_comparison_eq(
|
||||
Instruction test, Operand op, int k, boolean inNonZeroCase, AbstractValue value
|
||||
Instruction test, int k, boolean inNonZeroCase, AbstractValue value
|
||||
) {
|
||||
exists(SwitchInstruction switch, CaseEdge case |
|
||||
test = switch.getExpression() and
|
||||
op.getDef() = test and
|
||||
case = value.(MatchValue).getCase() and
|
||||
exists(switch.getSuccessor(case)) and
|
||||
case.getValue().toInt() = k and
|
||||
inNonZeroCase = false
|
||||
)
|
||||
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.
|
||||
relevantUnaryComparison(test) and
|
||||
op.getDef() = test and
|
||||
// Any instruction with an integral type could potentially be part of a
|
||||
// check for nullness when used in a guard. So we include all integral
|
||||
// typed instructions here. However, since some of these instructions are
|
||||
// already included as guards in other cases, we exclude those here.
|
||||
// These are instructions that compute a binary equality or inequality
|
||||
// relation. For example, the following:
|
||||
// ```cpp
|
||||
// if(a == b + 42) { ... }
|
||||
// ```
|
||||
// generates the following IR:
|
||||
// ```
|
||||
// r1(glval<int>) = VariableAddress[a] :
|
||||
// r2(int) = Load[a] : &:r1, m1
|
||||
// r3(glval<int>) = VariableAddress[b] :
|
||||
// r4(int) = Load[b] : &:r3, m2
|
||||
// r5(int) = Constant[42] :
|
||||
// r6(int) = Add : r4, r5
|
||||
// r7(bool) = CompareEQ : r2, r6
|
||||
// v1(void) = ConditionalBranch : r7
|
||||
// ```
|
||||
// and since `r7` is an integral typed instruction this predicate could
|
||||
// include a case for when `r7` evaluates to true (in which case we would
|
||||
// infer that `r6` was non-zero, and a case for when `r7` evaluates to false
|
||||
// (in which case we would infer that `r6` was zero).
|
||||
// However, since `a == b + 42` is already supported when reasoning about
|
||||
// binary equalities we exclude those cases here.
|
||||
not test.isGLValue() and
|
||||
not simple_comparison_eq(test, _, _, _, _) and
|
||||
not simple_comparison_lt(test, _, _, _) and
|
||||
not test = any(SwitchInstruction switch).getExpression() and
|
||||
(
|
||||
test.getResultIRType() instanceof IRAddressType or
|
||||
test.getResultIRType() instanceof IRIntegerType or
|
||||
test.getResultIRType() instanceof IRBooleanType
|
||||
) and
|
||||
(
|
||||
k = 1 and
|
||||
value.(BooleanValue).getValue() = true and
|
||||
@@ -871,12 +915,68 @@ private predicate unary_simple_comparison_eq(
|
||||
)
|
||||
}
|
||||
|
||||
/** A call to the builtin operation `__builtin_expect`. */
|
||||
private class BuiltinExpectCallInstruction extends CallInstruction {
|
||||
BuiltinExpectCallInstruction() { this.getStaticCallTarget().hasName("__builtin_expect") }
|
||||
|
||||
/** Gets the condition of this call. */
|
||||
Instruction getCondition() {
|
||||
// The first parameter of `__builtin_expect` has type `long`. So we skip
|
||||
// the conversion when inferring guards.
|
||||
result = this.getArgument(0).(ConvertInstruction).getUnary()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `left == right + k` is `areEqual` if `cmp` evaluates to `value`,
|
||||
* and `cmp` is an instruction that compares the value of
|
||||
* `__builtin_expect(left == right + k, _)` to `0`.
|
||||
*/
|
||||
private predicate builtin_expect_eq(
|
||||
CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual, AbstractValue value
|
||||
) {
|
||||
exists(BuiltinExpectCallInstruction call, Instruction const, AbstractValue innerValue |
|
||||
int_value(const) = 0 and
|
||||
cmp.hasOperands(call.getAUse(), const.getAUse()) and
|
||||
compares_eq(call.getCondition(), left, right, k, areEqual, innerValue)
|
||||
|
|
||||
cmp instanceof CompareNEInstruction and
|
||||
value = innerValue
|
||||
or
|
||||
cmp instanceof CompareEQInstruction and
|
||||
value.getDualValue() = innerValue
|
||||
)
|
||||
}
|
||||
|
||||
private predicate complex_eq(
|
||||
CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual, AbstractValue value
|
||||
) {
|
||||
sub_eq(cmp, left, right, k, areEqual, value)
|
||||
or
|
||||
add_eq(cmp, left, right, k, areEqual, value)
|
||||
or
|
||||
builtin_expect_eq(cmp, left, right, k, areEqual, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `op == k` is `areEqual` if `cmp` evaluates to `value`, and `cmp` is
|
||||
* an instruction that compares the value of `__builtin_expect(op == k, _)` to `0`.
|
||||
*/
|
||||
private predicate unary_builtin_expect_eq(
|
||||
CompareInstruction cmp, Operand op, int k, boolean areEqual, boolean inNonZeroCase,
|
||||
AbstractValue value
|
||||
) {
|
||||
exists(BuiltinExpectCallInstruction call, Instruction const, AbstractValue innerValue |
|
||||
int_value(const) = 0 and
|
||||
cmp.hasOperands(call.getAUse(), const.getAUse()) and
|
||||
unary_compares_eq(call.getCondition(), op, k, areEqual, inNonZeroCase, innerValue)
|
||||
|
|
||||
cmp instanceof CompareNEInstruction and
|
||||
value = innerValue
|
||||
or
|
||||
cmp instanceof CompareEQInstruction and
|
||||
value.getDualValue() = innerValue
|
||||
)
|
||||
}
|
||||
|
||||
private predicate unary_complex_eq(
|
||||
@@ -885,6 +985,8 @@ private predicate unary_complex_eq(
|
||||
unary_sub_eq(test, op, k, areEqual, inNonZeroCase, value)
|
||||
or
|
||||
unary_add_eq(test, op, k, areEqual, inNonZeroCase, value)
|
||||
or
|
||||
unary_builtin_expect_eq(test, op, k, areEqual, inNonZeroCase, value)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -913,7 +1015,8 @@ private predicate compares_lt(
|
||||
|
||||
/** Holds if `op < k` evaluates to `isLt` given that `test` evaluates to `value`. */
|
||||
private predicate compares_lt(Instruction test, Operand op, int k, boolean isLt, AbstractValue value) {
|
||||
simple_comparison_lt(test, op, k, isLt, value)
|
||||
unary_simple_comparison_lt(test, k, isLt, value) and
|
||||
op.getDef() = test
|
||||
or
|
||||
complex_lt(test, op, k, isLt, value)
|
||||
or
|
||||
@@ -960,12 +1063,11 @@ private predicate simple_comparison_lt(CompareInstruction cmp, Operand left, Ope
|
||||
}
|
||||
|
||||
/** Rearrange various simple comparisons into `op < k` form. */
|
||||
private predicate simple_comparison_lt(
|
||||
Instruction test, Operand op, int k, boolean isLt, AbstractValue value
|
||||
private predicate unary_simple_comparison_lt(
|
||||
Instruction test, int k, boolean isLt, AbstractValue value
|
||||
) {
|
||||
exists(SwitchInstruction switch, CaseEdge case |
|
||||
test = switch.getExpression() and
|
||||
op.getDef() = test and
|
||||
case = value.(MatchValue).getCase() and
|
||||
exists(switch.getSuccessor(case)) and
|
||||
case.getMaxValue() > case.getMinValue()
|
||||
|
||||
@@ -17,6 +17,7 @@ private import SsaInternals as Ssa
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
private import codeql.util.Unit
|
||||
private import Node0ToString
|
||||
import ExprNodes
|
||||
|
||||
/**
|
||||
* The IR dataflow graph consists of the following nodes:
|
||||
@@ -1296,466 +1297,6 @@ class UninitializedNode extends Node {
|
||||
LocalVariable getLocalVariable() { result = v }
|
||||
}
|
||||
|
||||
private module GetConvertedResultExpression {
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
|
||||
|
||||
private Operand getAnInitializeDynamicAllocationInstructionAddress() {
|
||||
result = any(InitializeDynamicAllocationInstruction init).getAllocationAddressOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression that should be returned as the result expression from `instr`.
|
||||
*
|
||||
* Note that this predicate may return multiple results in cases where a conversion belongs to a
|
||||
* different AST element than its operand.
|
||||
*/
|
||||
Expr getConvertedResultExpression(Instruction instr, int n) {
|
||||
// Only fully converted instructions have a result for `asConvertedExpr`
|
||||
not conversionFlow(unique(Operand op |
|
||||
// The address operand of a `InitializeDynamicAllocationInstruction` is
|
||||
// special: we need to handle it during dataflow (since it's
|
||||
// effectively a store to an indirection), but it doesn't appear in
|
||||
// source syntax, so dataflow node <-> expression conversion shouldn't
|
||||
// care about it.
|
||||
op = getAUse(instr) and not op = getAnInitializeDynamicAllocationInstructionAddress()
|
||||
|
|
||||
op
|
||||
), _, false, false) and
|
||||
result = getConvertedResultExpressionImpl(instr) and
|
||||
n = 0
|
||||
or
|
||||
// If the conversion also has a result then we return multiple results
|
||||
exists(Operand operand | conversionFlow(operand, instr, false, false) |
|
||||
n = 1 and
|
||||
result = getConvertedResultExpressionImpl(operand.getDef())
|
||||
or
|
||||
result = getConvertedResultExpression(operand.getDef(), n - 1)
|
||||
)
|
||||
}
|
||||
|
||||
private Expr getConvertedResultExpressionImpl0(Instruction instr) {
|
||||
// IR construction inserts an additional cast to a `size_t` on the extent
|
||||
// of a `new[]` expression. The resulting `ConvertInstruction` doesn't have
|
||||
// a result for `getConvertedResultExpression`. We remap this here so that
|
||||
// this `ConvertInstruction` maps to the result of the expression that
|
||||
// represents the extent.
|
||||
exists(TranslatedNonConstantAllocationSize tas |
|
||||
result = tas.getExtent().getExpr() and
|
||||
instr = tas.getInstruction(AllocationExtentConvertTag())
|
||||
)
|
||||
or
|
||||
// There's no instruction that returns `ParenthesisExpr`, but some queries
|
||||
// expect this
|
||||
exists(TranslatedTransparentConversion ttc |
|
||||
result = ttc.getExpr().(ParenthesisExpr) and
|
||||
instr = ttc.getResult()
|
||||
)
|
||||
or
|
||||
// Certain expressions generate `CopyValueInstruction`s only when they
|
||||
// are needed. Examples of this include crement operations and compound
|
||||
// assignment operations. For example:
|
||||
// ```cpp
|
||||
// int x = ...
|
||||
// int y = x++;
|
||||
// ```
|
||||
// this generate IR like:
|
||||
// ```
|
||||
// r1(glval<int>) = VariableAddress[x] :
|
||||
// r2(int) = Constant[0] :
|
||||
// m3(int) = Store[x] : &:r1, r2
|
||||
// r4(glval<int>) = VariableAddress[y] :
|
||||
// r5(glval<int>) = VariableAddress[x] :
|
||||
// r6(int) = Load[x] : &:r5, m3
|
||||
// r7(int) = Constant[1] :
|
||||
// r8(int) = Add : r6, r7
|
||||
// m9(int) = Store[x] : &:r5, r8
|
||||
// r11(int) = CopyValue : r6
|
||||
// m12(int) = Store[y] : &:r4, r11
|
||||
// ```
|
||||
// When the `CopyValueInstruction` is not generated there is no instruction
|
||||
// whose `getConvertedResultExpression` maps back to the expression. When
|
||||
// such an instruction doesn't exist it means that the old value is not
|
||||
// needed, and in that case the only value that will propagate forward in
|
||||
// the program is the value that's been updated. So in those cases we just
|
||||
// use the result of `node.asDefinition()` as the result of `node.asExpr()`.
|
||||
exists(TranslatedCoreExpr tco |
|
||||
tco.getInstruction(_) = instr and
|
||||
tco.producesExprResult() and
|
||||
result = asDefinitionImpl0(instr)
|
||||
)
|
||||
}
|
||||
|
||||
private Expr getConvertedResultExpressionImpl(Instruction instr) {
|
||||
result = getConvertedResultExpressionImpl0(instr)
|
||||
or
|
||||
not exists(getConvertedResultExpressionImpl0(instr)) and
|
||||
result = instr.getConvertedResultExpression()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result for `node.asDefinition()` (when `node` is the instruction
|
||||
* node that wraps `store`) in the cases where `store.getAst()` should not be
|
||||
* used to define the result of `node.asDefinition()`.
|
||||
*/
|
||||
private Expr asDefinitionImpl0(StoreInstruction store) {
|
||||
// For an expression such as `i += 2` we pretend that the generated
|
||||
// `StoreInstruction` contains the result of the expression even though
|
||||
// this isn't totally aligned with the C/C++ standard.
|
||||
exists(TranslatedAssignOperation tao |
|
||||
store = tao.getInstruction(AssignmentStoreTag()) and
|
||||
result = tao.getExpr()
|
||||
)
|
||||
or
|
||||
// Similarly for `i++` and `++i` we pretend that the generated
|
||||
// `StoreInstruction` is contains the result of the expression even though
|
||||
// this isn't totally aligned with the C/C++ standard.
|
||||
exists(TranslatedCrementOperation tco |
|
||||
store = tco.getInstruction(CrementStoreTag()) and
|
||||
result = tco.getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression returned by `store.getAst()` should not be
|
||||
* returned as the result of `node.asDefinition()` when `node` is the
|
||||
* instruction node that wraps `store`.
|
||||
*/
|
||||
private predicate excludeAsDefinitionResult(StoreInstruction store) {
|
||||
// Exclude the store to the temporary generated by a ternary expression.
|
||||
exists(TranslatedConditionalExpr tce |
|
||||
store = tce.getInstruction(ConditionValueFalseStoreTag())
|
||||
or
|
||||
store = tce.getInstruction(ConditionValueTrueStoreTag())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression that represents the result of `StoreInstruction` for
|
||||
* dataflow purposes.
|
||||
*
|
||||
* For example, consider the following example
|
||||
* ```cpp
|
||||
* int x = 42; // 1
|
||||
* x = 34; // 2
|
||||
* ++x; // 3
|
||||
* x++; // 4
|
||||
* x += 1; // 5
|
||||
* int y = x += 2; // 6
|
||||
* ```
|
||||
* For (1) the result is `42`.
|
||||
* For (2) the result is `x = 34`.
|
||||
* For (3) the result is `++x`.
|
||||
* For (4) the result is `x++`.
|
||||
* For (5) the result is `x += 1`.
|
||||
* For (6) there are two results:
|
||||
* - For the `StoreInstruction` generated by `x += 2` the result
|
||||
* is `x += 2`
|
||||
* - For the `StoreInstruction` generated by `int y = ...` the result
|
||||
* is also `x += 2`
|
||||
*/
|
||||
Expr asDefinitionImpl(StoreInstruction store) {
|
||||
not exists(asDefinitionImpl0(store)) and
|
||||
not excludeAsDefinitionResult(store) and
|
||||
result = store.getAst().(Expr).getUnconverted()
|
||||
or
|
||||
result = asDefinitionImpl0(store)
|
||||
}
|
||||
}
|
||||
|
||||
private import GetConvertedResultExpression
|
||||
|
||||
/** Holds if `node` is an `OperandNode` that should map `node.asExpr()` to `e`. */
|
||||
predicate exprNodeShouldBeOperand(OperandNode node, Expr e, int n) {
|
||||
not exprNodeShouldBeIndirectOperand(_, e, n) and
|
||||
exists(Instruction def |
|
||||
unique( | | getAUse(def)) = node.getOperand() and
|
||||
e = getConvertedResultExpression(def, n)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an `IndirectOperand` that maps `node.asIndirectExpr()` to `e`. */
|
||||
private predicate indirectExprNodeShouldBeIndirectOperand(
|
||||
IndirectOperand node, Expr e, int n, int indirectionIndex
|
||||
) {
|
||||
exists(Instruction def |
|
||||
node.hasOperandAndIndirectionIndex(unique( | | getAUse(def)), indirectionIndex) and
|
||||
e = getConvertedResultExpression(def, n)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an `IndirectOperand` that maps `node.asExpr()` to `e`. */
|
||||
private predicate exprNodeShouldBeIndirectOperand(IndirectOperand node, Expr e, int n) {
|
||||
exists(ArgumentOperand operand |
|
||||
// When an argument (qualifier or positional) is a prvalue and the
|
||||
// parameter (qualifier or positional) is a (const) reference, IR
|
||||
// construction introduces a temporary `IRVariable`. The `VariableAddress`
|
||||
// instruction has the argument as its `getConvertedResultExpression`
|
||||
// result. However, the instruction actually represents the _address_ of
|
||||
// the argument. So to fix this mismatch, we have the indirection of the
|
||||
// `VariableAddressInstruction` map to the expression.
|
||||
node.hasOperandAndIndirectionIndex(operand, 1) and
|
||||
e = getConvertedResultExpression(operand.getDef(), n) and
|
||||
operand.getDef().(VariableAddressInstruction).getIRVariable() instanceof IRTempVariable
|
||||
)
|
||||
}
|
||||
|
||||
private predicate exprNodeShouldBeIndirectOutNode(IndirectArgumentOutNode node, Expr e, int n) {
|
||||
exists(CallInstruction call |
|
||||
call.getStaticCallTarget() instanceof Constructor and
|
||||
e = getConvertedResultExpression(call, n) and
|
||||
call.getThisArgumentOperand() = node.getAddressOperand()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an instruction node that maps `node.asExpr()` to `e`. */
|
||||
predicate exprNodeShouldBeInstruction(Node node, Expr e, int n) {
|
||||
not exprNodeShouldBeOperand(_, e, n) and
|
||||
not exprNodeShouldBeIndirectOutNode(_, e, n) and
|
||||
not exprNodeShouldBeIndirectOperand(_, e, n) and
|
||||
e = getConvertedResultExpression(node.asInstruction(), n)
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an `IndirectInstruction` that maps `node.asIndirectExpr()` to `e`. */
|
||||
predicate indirectExprNodeShouldBeIndirectInstruction(
|
||||
IndirectInstruction node, Expr e, int n, int indirectionIndex
|
||||
) {
|
||||
not indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) and
|
||||
exists(Instruction instr |
|
||||
node.hasInstructionAndIndirectionIndex(instr, indirectionIndex) and
|
||||
e = getConvertedResultExpression(instr, n)
|
||||
)
|
||||
}
|
||||
|
||||
abstract private class ExprNodeBase extends Node {
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. The returned
|
||||
* expression may be a `Conversion`.
|
||||
*/
|
||||
abstract Expr getConvertedExpr(int n);
|
||||
|
||||
/** Gets the non-conversion expression corresponding to this node, if any. */
|
||||
final Expr getExpr(int n) { result = this.getConvertedExpr(n).getUnconverted() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there exists a dataflow node whose `asExpr(n)` should evaluate
|
||||
* to `e`.
|
||||
*/
|
||||
private predicate exprNodeShouldBe(Expr e, int n) {
|
||||
exprNodeShouldBeInstruction(_, e, n) or
|
||||
exprNodeShouldBeOperand(_, e, n) or
|
||||
exprNodeShouldBeIndirectOutNode(_, e, n) or
|
||||
exprNodeShouldBeIndirectOperand(_, e, n)
|
||||
}
|
||||
|
||||
private class InstructionExprNode extends ExprNodeBase, InstructionNode {
|
||||
InstructionExprNode() {
|
||||
exists(Expr e, int n |
|
||||
exprNodeShouldBeInstruction(this, e, n) and
|
||||
not exists(Expr conv |
|
||||
exprNodeShouldBe(conv, n + 1) and
|
||||
conv.getUnconverted() = e.getUnconverted()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
final override Expr getConvertedExpr(int n) { exprNodeShouldBeInstruction(this, result, n) }
|
||||
}
|
||||
|
||||
private class OperandExprNode extends ExprNodeBase, OperandNode {
|
||||
OperandExprNode() {
|
||||
exists(Expr e, int n |
|
||||
exprNodeShouldBeOperand(this, e, n) and
|
||||
not exists(Expr conv |
|
||||
exprNodeShouldBe(conv, n + 1) and
|
||||
conv.getUnconverted() = e.getUnconverted()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
final override Expr getConvertedExpr(int n) { exprNodeShouldBeOperand(this, result, n) }
|
||||
}
|
||||
|
||||
abstract private class IndirectExprNodeBase extends Node {
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. The returned
|
||||
* expression may be a `Conversion`.
|
||||
*/
|
||||
abstract Expr getConvertedExpr(int n, int indirectionIndex);
|
||||
|
||||
/** Gets the non-conversion expression corresponding to this node, if any. */
|
||||
final Expr getExpr(int n, int indirectionIndex) {
|
||||
result = this.getConvertedExpr(n, indirectionIndex).getUnconverted()
|
||||
}
|
||||
}
|
||||
|
||||
/** A signature for converting an indirect node to an expression. */
|
||||
private signature module IndirectNodeToIndirectExprSig {
|
||||
/** The indirect node class to be converted to an expression */
|
||||
class IndirectNode;
|
||||
|
||||
/**
|
||||
* Holds if the indirect expression at indirection index `indirectionIndex`
|
||||
* of `node` is `e`. The integer `n` specifies how many conversions has been
|
||||
* applied to `node`.
|
||||
*/
|
||||
predicate indirectNodeHasIndirectExpr(IndirectNode node, Expr e, int n, int indirectionIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* A module that implements the logic for deciding whether an indirect node
|
||||
* should be an `IndirectExprNode`.
|
||||
*/
|
||||
private module IndirectNodeToIndirectExpr<IndirectNodeToIndirectExprSig Sig> {
|
||||
import Sig
|
||||
|
||||
/**
|
||||
* This predicate shifts the indirection index by one when `conv` is a
|
||||
* `ReferenceDereferenceExpr`.
|
||||
*
|
||||
* This is necessary because `ReferenceDereferenceExpr` is a conversion
|
||||
* in the AST, but appears as a `LoadInstruction` in the IR.
|
||||
*/
|
||||
bindingset[e, indirectionIndex]
|
||||
private predicate adjustForReference(
|
||||
Expr e, int indirectionIndex, Expr conv, int adjustedIndirectionIndex
|
||||
) {
|
||||
conv.(ReferenceDereferenceExpr).getExpr() = e and
|
||||
adjustedIndirectionIndex = indirectionIndex - 1
|
||||
or
|
||||
not conv instanceof ReferenceDereferenceExpr and
|
||||
conv = e and
|
||||
adjustedIndirectionIndex = indirectionIndex
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an `IndirectExprNode`. */
|
||||
predicate charpred(IndirectNode node) {
|
||||
exists(Expr e, int n, int indirectionIndex |
|
||||
indirectNodeHasIndirectExpr(node, e, n, indirectionIndex) and
|
||||
not exists(Expr conv, int adjustedIndirectionIndex |
|
||||
adjustForReference(e, indirectionIndex, conv, adjustedIndirectionIndex) and
|
||||
indirectExprNodeShouldBe(conv, n + 1, adjustedIndirectionIndex)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate indirectExprNodeShouldBe(Expr e, int n, int indirectionIndex) {
|
||||
indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) or
|
||||
indirectExprNodeShouldBeIndirectInstruction(_, e, n, indirectionIndex)
|
||||
}
|
||||
|
||||
private module IndirectOperandIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
|
||||
class IndirectNode = IndirectOperand;
|
||||
|
||||
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectOperand/4;
|
||||
}
|
||||
|
||||
module IndirectOperandToIndirectExpr =
|
||||
IndirectNodeToIndirectExpr<IndirectOperandIndirectExprNodeImpl>;
|
||||
|
||||
private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand
|
||||
{
|
||||
IndirectOperandIndirectExprNode() { IndirectOperandToIndirectExpr::charpred(this) }
|
||||
|
||||
final override Expr getConvertedExpr(int n, int index) {
|
||||
IndirectOperandToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
|
||||
}
|
||||
}
|
||||
|
||||
private module IndirectInstructionIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
|
||||
class IndirectNode = IndirectInstruction;
|
||||
|
||||
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectInstruction/4;
|
||||
}
|
||||
|
||||
module IndirectInstructionToIndirectExpr =
|
||||
IndirectNodeToIndirectExpr<IndirectInstructionIndirectExprNodeImpl>;
|
||||
|
||||
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase instanceof IndirectInstruction
|
||||
{
|
||||
IndirectInstructionIndirectExprNode() { IndirectInstructionToIndirectExpr::charpred(this) }
|
||||
|
||||
final override Expr getConvertedExpr(int n, int index) {
|
||||
IndirectInstructionToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
|
||||
}
|
||||
}
|
||||
|
||||
private class IndirectArgumentOutExprNode extends ExprNodeBase, IndirectArgumentOutNode {
|
||||
IndirectArgumentOutExprNode() { exprNodeShouldBeIndirectOutNode(this, _, _) }
|
||||
|
||||
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOutNode(this, result, n) }
|
||||
}
|
||||
|
||||
private class IndirectOperandExprNode extends ExprNodeBase instanceof IndirectOperand {
|
||||
IndirectOperandExprNode() { exprNodeShouldBeIndirectOperand(this, _, _) }
|
||||
|
||||
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOperand(this, result, n) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression, viewed as a node in a data flow graph.
|
||||
*/
|
||||
class ExprNode extends Node instanceof ExprNodeBase {
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
Expr getExpr(int n) { result = super.getExpr(n) }
|
||||
|
||||
/**
|
||||
* Gets the non-conversion expression corresponding to this node, if any. If
|
||||
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
|
||||
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
|
||||
* expression.
|
||||
*/
|
||||
final Expr getExpr() { result = this.getExpr(_) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
Expr getConvertedExpr(int n) { result = super.getConvertedExpr(n) }
|
||||
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. The returned
|
||||
* expression may be a `Conversion`.
|
||||
*/
|
||||
final Expr getConvertedExpr() { result = this.getConvertedExpr(_) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An indirect expression, viewed as a node in a data flow graph.
|
||||
*/
|
||||
class IndirectExprNode extends Node instanceof IndirectExprNodeBase {
|
||||
/**
|
||||
* Gets the non-conversion expression corresponding to this node, if any. If
|
||||
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
|
||||
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
|
||||
* expression.
|
||||
*/
|
||||
final Expr getExpr(int indirectionIndex) { result = this.getExpr(_, indirectionIndex) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
Expr getExpr(int n, int indirectionIndex) { result = super.getExpr(n, indirectionIndex) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
Expr getConvertedExpr(int n, int indirectionIndex) {
|
||||
result = super.getConvertedExpr(n, indirectionIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. The returned
|
||||
* expression may be a `Conversion`.
|
||||
*/
|
||||
Expr getConvertedExpr(int indirectionIndex) {
|
||||
result = this.getConvertedExpr(_, indirectionIndex)
|
||||
}
|
||||
}
|
||||
|
||||
abstract private class AbstractParameterNode extends Node {
|
||||
/**
|
||||
* Holds if this node is the parameter of `f` at the specified position. The
|
||||
|
||||
479
cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ExprNodes.qll
Normal file
479
cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ExprNodes.qll
Normal file
@@ -0,0 +1,479 @@
|
||||
/**
|
||||
* Provides the classes `ExprNode` and `IndirectExprNode` for converting between `Expr` and `Node`.
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import DataFlowUtil
|
||||
private import DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
private Operand getAnInitializeDynamicAllocationInstructionAddress() {
|
||||
result = any(InitializeDynamicAllocationInstruction init).getAllocationAddressOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression that should be returned as the result expression from `instr`.
|
||||
*
|
||||
* Note that this predicate may return multiple results in cases where a conversion belongs to a
|
||||
* different AST element than its operand.
|
||||
*/
|
||||
private Expr getConvertedResultExpression(Instruction instr, int n) {
|
||||
// Only fully converted instructions have a result for `asConvertedExpr`
|
||||
not conversionFlow(unique(Operand op |
|
||||
// The address operand of a `InitializeDynamicAllocationInstruction` is
|
||||
// special: we need to handle it during dataflow (since it's
|
||||
// effectively a store to an indirection), but it doesn't appear in
|
||||
// source syntax, so dataflow node <-> expression conversion shouldn't
|
||||
// care about it.
|
||||
op = getAUse(instr) and not op = getAnInitializeDynamicAllocationInstructionAddress()
|
||||
|
|
||||
op
|
||||
), _, false, false) and
|
||||
result = getConvertedResultExpressionImpl(instr) and
|
||||
n = 0
|
||||
or
|
||||
// If the conversion also has a result then we return multiple results
|
||||
exists(Operand operand | conversionFlow(operand, instr, false, false) |
|
||||
n = 1 and
|
||||
result = getConvertedResultExpressionImpl(operand.getDef())
|
||||
or
|
||||
result = getConvertedResultExpression(operand.getDef(), n - 1)
|
||||
)
|
||||
}
|
||||
|
||||
private Expr getConvertedResultExpressionImpl0(Instruction instr) {
|
||||
// IR construction inserts an additional cast to a `size_t` on the extent
|
||||
// of a `new[]` expression. The resulting `ConvertInstruction` doesn't have
|
||||
// a result for `getConvertedResultExpression`. We remap this here so that
|
||||
// this `ConvertInstruction` maps to the result of the expression that
|
||||
// represents the extent.
|
||||
exists(TranslatedNonConstantAllocationSize tas |
|
||||
result = tas.getExtent().getExpr() and
|
||||
instr = tas.getInstruction(AllocationExtentConvertTag())
|
||||
)
|
||||
or
|
||||
// There's no instruction that returns `ParenthesisExpr`, but some queries
|
||||
// expect this
|
||||
exists(TranslatedTransparentConversion ttc |
|
||||
result = ttc.getExpr().(ParenthesisExpr) and
|
||||
instr = ttc.getResult()
|
||||
)
|
||||
or
|
||||
// Certain expressions generate `CopyValueInstruction`s only when they
|
||||
// are needed. Examples of this include crement operations and compound
|
||||
// assignment operations. For example:
|
||||
// ```cpp
|
||||
// int x = ...
|
||||
// int y = x++;
|
||||
// ```
|
||||
// this generate IR like:
|
||||
// ```
|
||||
// r1(glval<int>) = VariableAddress[x] :
|
||||
// r2(int) = Constant[0] :
|
||||
// m3(int) = Store[x] : &:r1, r2
|
||||
// r4(glval<int>) = VariableAddress[y] :
|
||||
// r5(glval<int>) = VariableAddress[x] :
|
||||
// r6(int) = Load[x] : &:r5, m3
|
||||
// r7(int) = Constant[1] :
|
||||
// r8(int) = Add : r6, r7
|
||||
// m9(int) = Store[x] : &:r5, r8
|
||||
// r11(int) = CopyValue : r6
|
||||
// m12(int) = Store[y] : &:r4, r11
|
||||
// ```
|
||||
// When the `CopyValueInstruction` is not generated there is no instruction
|
||||
// whose `getConvertedResultExpression` maps back to the expression. When
|
||||
// such an instruction doesn't exist it means that the old value is not
|
||||
// needed, and in that case the only value that will propagate forward in
|
||||
// the program is the value that's been updated. So in those cases we just
|
||||
// use the result of `node.asDefinition()` as the result of `node.asExpr()`.
|
||||
exists(TranslatedCoreExpr tco |
|
||||
tco.getInstruction(_) = instr and
|
||||
tco.producesExprResult() and
|
||||
result = asDefinitionImpl0(instr)
|
||||
)
|
||||
}
|
||||
|
||||
private Expr getConvertedResultExpressionImpl(Instruction instr) {
|
||||
result = getConvertedResultExpressionImpl0(instr)
|
||||
or
|
||||
not exists(getConvertedResultExpressionImpl0(instr)) and
|
||||
result = instr.getConvertedResultExpression()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result for `node.asDefinition()` (when `node` is the instruction
|
||||
* node that wraps `store`) in the cases where `store.getAst()` should not be
|
||||
* used to define the result of `node.asDefinition()`.
|
||||
*/
|
||||
private Expr asDefinitionImpl0(StoreInstruction store) {
|
||||
// For an expression such as `i += 2` we pretend that the generated
|
||||
// `StoreInstruction` contains the result of the expression even though
|
||||
// this isn't totally aligned with the C/C++ standard.
|
||||
exists(TranslatedAssignOperation tao |
|
||||
store = tao.getInstruction(AssignmentStoreTag()) and
|
||||
result = tao.getExpr()
|
||||
)
|
||||
or
|
||||
// Similarly for `i++` and `++i` we pretend that the generated
|
||||
// `StoreInstruction` is contains the result of the expression even though
|
||||
// this isn't totally aligned with the C/C++ standard.
|
||||
exists(TranslatedCrementOperation tco |
|
||||
store = tco.getInstruction(CrementStoreTag()) and
|
||||
result = tco.getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression returned by `store.getAst()` should not be
|
||||
* returned as the result of `node.asDefinition()` when `node` is the
|
||||
* instruction node that wraps `store`.
|
||||
*/
|
||||
private predicate excludeAsDefinitionResult(StoreInstruction store) {
|
||||
// Exclude the store to the temporary generated by a ternary expression.
|
||||
exists(TranslatedConditionalExpr tce |
|
||||
store = tce.getInstruction(ConditionValueFalseStoreTag())
|
||||
or
|
||||
store = tce.getInstruction(ConditionValueTrueStoreTag())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression that represents the result of `StoreInstruction` for
|
||||
* dataflow purposes.
|
||||
*
|
||||
* For example, consider the following example
|
||||
* ```cpp
|
||||
* int x = 42; // 1
|
||||
* x = 34; // 2
|
||||
* ++x; // 3
|
||||
* x++; // 4
|
||||
* x += 1; // 5
|
||||
* int y = x += 2; // 6
|
||||
* ```
|
||||
* For (1) the result is `42`.
|
||||
* For (2) the result is `x = 34`.
|
||||
* For (3) the result is `++x`.
|
||||
* For (4) the result is `x++`.
|
||||
* For (5) the result is `x += 1`.
|
||||
* For (6) there are two results:
|
||||
* - For the `StoreInstruction` generated by `x += 2` the result
|
||||
* is `x += 2`
|
||||
* - For the `StoreInstruction` generated by `int y = ...` the result
|
||||
* is also `x += 2`
|
||||
*/
|
||||
cached
|
||||
Expr asDefinitionImpl(StoreInstruction store) {
|
||||
not exists(asDefinitionImpl0(store)) and
|
||||
not excludeAsDefinitionResult(store) and
|
||||
result = store.getAst().(Expr).getUnconverted()
|
||||
or
|
||||
result = asDefinitionImpl0(store)
|
||||
}
|
||||
|
||||
/** Holds if `node` is an `OperandNode` that should map `node.asExpr()` to `e`. */
|
||||
private predicate exprNodeShouldBeOperand(OperandNode node, Expr e, int n) {
|
||||
not exprNodeShouldBeIndirectOperand(_, e, n) and
|
||||
exists(Instruction def |
|
||||
unique( | | getAUse(def)) = node.getOperand() and
|
||||
e = getConvertedResultExpression(def, n)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an `IndirectOperand` that maps `node.asIndirectExpr()` to `e`. */
|
||||
private predicate indirectExprNodeShouldBeIndirectOperand(
|
||||
IndirectOperand node, Expr e, int n, int indirectionIndex
|
||||
) {
|
||||
exists(Instruction def |
|
||||
node.hasOperandAndIndirectionIndex(unique( | | getAUse(def)), indirectionIndex) and
|
||||
e = getConvertedResultExpression(def, n)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an `IndirectOperand` that maps `node.asExpr()` to `e`. */
|
||||
private predicate exprNodeShouldBeIndirectOperand(IndirectOperand node, Expr e, int n) {
|
||||
exists(ArgumentOperand operand |
|
||||
// When an argument (qualifier or positional) is a prvalue and the
|
||||
// parameter (qualifier or positional) is a (const) reference, IR
|
||||
// construction introduces a temporary `IRVariable`. The `VariableAddress`
|
||||
// instruction has the argument as its `getConvertedResultExpression`
|
||||
// result. However, the instruction actually represents the _address_ of
|
||||
// the argument. So to fix this mismatch, we have the indirection of the
|
||||
// `VariableAddressInstruction` map to the expression.
|
||||
node.hasOperandAndIndirectionIndex(operand, 1) and
|
||||
e = getConvertedResultExpression(operand.getDef(), n) and
|
||||
operand.getDef().(VariableAddressInstruction).getIRVariable() instanceof IRTempVariable
|
||||
)
|
||||
}
|
||||
|
||||
private predicate exprNodeShouldBeIndirectOutNode(IndirectArgumentOutNode node, Expr e, int n) {
|
||||
exists(CallInstruction call |
|
||||
call.getStaticCallTarget() instanceof Constructor and
|
||||
e = getConvertedResultExpression(call, n) and
|
||||
call.getThisArgumentOperand() = node.getAddressOperand()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an instruction node that maps `node.asExpr()` to `e`. */
|
||||
private predicate exprNodeShouldBeInstruction(Node node, Expr e, int n) {
|
||||
not exprNodeShouldBeOperand(_, e, n) and
|
||||
not exprNodeShouldBeIndirectOutNode(_, e, n) and
|
||||
not exprNodeShouldBeIndirectOperand(_, e, n) and
|
||||
e = getConvertedResultExpression(node.asInstruction(), n)
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an `IndirectInstruction` that maps `node.asIndirectExpr()` to `e`. */
|
||||
private predicate indirectExprNodeShouldBeIndirectInstruction(
|
||||
IndirectInstruction node, Expr e, int n, int indirectionIndex
|
||||
) {
|
||||
not indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) and
|
||||
exists(Instruction instr |
|
||||
node.hasInstructionAndIndirectionIndex(instr, indirectionIndex) and
|
||||
e = getConvertedResultExpression(instr, n)
|
||||
)
|
||||
}
|
||||
|
||||
abstract private class ExprNodeBase extends Node {
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. The returned
|
||||
* expression may be a `Conversion`.
|
||||
*/
|
||||
abstract Expr getConvertedExpr(int n);
|
||||
|
||||
/** Gets the non-conversion expression corresponding to this node, if any. */
|
||||
final Expr getExpr(int n) { result = this.getConvertedExpr(n).getUnconverted() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there exists a dataflow node whose `asExpr(n)` should evaluate
|
||||
* to `e`.
|
||||
*/
|
||||
private predicate exprNodeShouldBe(Expr e, int n) {
|
||||
exprNodeShouldBeInstruction(_, e, n) or
|
||||
exprNodeShouldBeOperand(_, e, n) or
|
||||
exprNodeShouldBeIndirectOutNode(_, e, n) or
|
||||
exprNodeShouldBeIndirectOperand(_, e, n)
|
||||
}
|
||||
|
||||
private class InstructionExprNode extends ExprNodeBase, InstructionNode {
|
||||
InstructionExprNode() {
|
||||
exists(Expr e, int n |
|
||||
exprNodeShouldBeInstruction(this, e, n) and
|
||||
not exists(Expr conv |
|
||||
exprNodeShouldBe(conv, n + 1) and
|
||||
conv.getUnconverted() = e.getUnconverted()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
final override Expr getConvertedExpr(int n) { exprNodeShouldBeInstruction(this, result, n) }
|
||||
}
|
||||
|
||||
private class OperandExprNode extends ExprNodeBase, OperandNode {
|
||||
OperandExprNode() {
|
||||
exists(Expr e, int n |
|
||||
exprNodeShouldBeOperand(this, e, n) and
|
||||
not exists(Expr conv |
|
||||
exprNodeShouldBe(conv, n + 1) and
|
||||
conv.getUnconverted() = e.getUnconverted()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
final override Expr getConvertedExpr(int n) { exprNodeShouldBeOperand(this, result, n) }
|
||||
}
|
||||
|
||||
abstract private class IndirectExprNodeBase extends Node {
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. The returned
|
||||
* expression may be a `Conversion`.
|
||||
*/
|
||||
abstract Expr getConvertedExpr(int n, int indirectionIndex);
|
||||
|
||||
/** Gets the non-conversion expression corresponding to this node, if any. */
|
||||
final Expr getExpr(int n, int indirectionIndex) {
|
||||
result = this.getConvertedExpr(n, indirectionIndex).getUnconverted()
|
||||
}
|
||||
}
|
||||
|
||||
/** A signature for converting an indirect node to an expression. */
|
||||
private signature module IndirectNodeToIndirectExprSig {
|
||||
/** The indirect node class to be converted to an expression */
|
||||
class IndirectNode;
|
||||
|
||||
/**
|
||||
* Holds if the indirect expression at indirection index `indirectionIndex`
|
||||
* of `node` is `e`. The integer `n` specifies how many conversions has been
|
||||
* applied to `node`.
|
||||
*/
|
||||
predicate indirectNodeHasIndirectExpr(IndirectNode node, Expr e, int n, int indirectionIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* A module that implements the logic for deciding whether an indirect node
|
||||
* should be an `IndirectExprNode`.
|
||||
*/
|
||||
private module IndirectNodeToIndirectExpr<IndirectNodeToIndirectExprSig Sig> {
|
||||
import Sig
|
||||
|
||||
/**
|
||||
* This predicate shifts the indirection index by one when `conv` is a
|
||||
* `ReferenceDereferenceExpr`.
|
||||
*
|
||||
* This is necessary because `ReferenceDereferenceExpr` is a conversion
|
||||
* in the AST, but appears as a `LoadInstruction` in the IR.
|
||||
*/
|
||||
bindingset[e, indirectionIndex]
|
||||
private predicate adjustForReference(
|
||||
Expr e, int indirectionIndex, Expr conv, int adjustedIndirectionIndex
|
||||
) {
|
||||
conv.(ReferenceDereferenceExpr).getExpr() = e and
|
||||
adjustedIndirectionIndex = indirectionIndex - 1
|
||||
or
|
||||
not conv instanceof ReferenceDereferenceExpr and
|
||||
conv = e and
|
||||
adjustedIndirectionIndex = indirectionIndex
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an `IndirectExprNode`. */
|
||||
predicate charpred(IndirectNode node) {
|
||||
exists(Expr e, int n, int indirectionIndex |
|
||||
indirectNodeHasIndirectExpr(node, e, n, indirectionIndex) and
|
||||
not exists(Expr conv, int adjustedIndirectionIndex |
|
||||
adjustForReference(e, indirectionIndex, conv, adjustedIndirectionIndex) and
|
||||
indirectExprNodeShouldBe(conv, n + 1, adjustedIndirectionIndex)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate indirectExprNodeShouldBe(Expr e, int n, int indirectionIndex) {
|
||||
indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) or
|
||||
indirectExprNodeShouldBeIndirectInstruction(_, e, n, indirectionIndex)
|
||||
}
|
||||
|
||||
private module IndirectOperandIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
|
||||
class IndirectNode = IndirectOperand;
|
||||
|
||||
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectOperand/4;
|
||||
}
|
||||
|
||||
module IndirectOperandToIndirectExpr =
|
||||
IndirectNodeToIndirectExpr<IndirectOperandIndirectExprNodeImpl>;
|
||||
|
||||
private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand
|
||||
{
|
||||
IndirectOperandIndirectExprNode() { IndirectOperandToIndirectExpr::charpred(this) }
|
||||
|
||||
final override Expr getConvertedExpr(int n, int index) {
|
||||
IndirectOperandToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
|
||||
}
|
||||
}
|
||||
|
||||
private module IndirectInstructionIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
|
||||
class IndirectNode = IndirectInstruction;
|
||||
|
||||
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectInstruction/4;
|
||||
}
|
||||
|
||||
module IndirectInstructionToIndirectExpr =
|
||||
IndirectNodeToIndirectExpr<IndirectInstructionIndirectExprNodeImpl>;
|
||||
|
||||
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase instanceof IndirectInstruction
|
||||
{
|
||||
IndirectInstructionIndirectExprNode() { IndirectInstructionToIndirectExpr::charpred(this) }
|
||||
|
||||
final override Expr getConvertedExpr(int n, int index) {
|
||||
IndirectInstructionToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
|
||||
}
|
||||
}
|
||||
|
||||
private class IndirectArgumentOutExprNode extends ExprNodeBase, IndirectArgumentOutNode {
|
||||
IndirectArgumentOutExprNode() { exprNodeShouldBeIndirectOutNode(this, _, _) }
|
||||
|
||||
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOutNode(this, result, n) }
|
||||
}
|
||||
|
||||
private class IndirectOperandExprNode extends ExprNodeBase instanceof IndirectOperand {
|
||||
IndirectOperandExprNode() { exprNodeShouldBeIndirectOperand(this, _, _) }
|
||||
|
||||
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOperand(this, result, n) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression, viewed as a node in a data flow graph.
|
||||
*/
|
||||
cached
|
||||
class ExprNode extends Node instanceof ExprNodeBase {
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
cached
|
||||
Expr getExpr(int n) { result = super.getExpr(n) }
|
||||
|
||||
/**
|
||||
* Gets the non-conversion expression corresponding to this node, if any. If
|
||||
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
|
||||
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
|
||||
* expression.
|
||||
*/
|
||||
cached
|
||||
final Expr getExpr() { result = this.getExpr(_) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
cached
|
||||
Expr getConvertedExpr(int n) { result = super.getConvertedExpr(n) }
|
||||
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. The returned
|
||||
* expression may be a `Conversion`.
|
||||
*/
|
||||
cached
|
||||
final Expr getConvertedExpr() { result = this.getConvertedExpr(_) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An indirect expression, viewed as a node in a data flow graph.
|
||||
*/
|
||||
cached
|
||||
class IndirectExprNode extends Node instanceof IndirectExprNodeBase {
|
||||
/**
|
||||
* Gets the non-conversion expression corresponding to this node, if any. If
|
||||
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
|
||||
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
|
||||
* expression.
|
||||
*/
|
||||
cached
|
||||
final Expr getExpr(int indirectionIndex) { result = this.getExpr(_, indirectionIndex) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
cached
|
||||
Expr getExpr(int n, int indirectionIndex) { result = super.getExpr(n, indirectionIndex) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
cached
|
||||
Expr getConvertedExpr(int n, int indirectionIndex) {
|
||||
result = super.getConvertedExpr(n, indirectionIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. The returned
|
||||
* expression may be a `Conversion`.
|
||||
*/
|
||||
cached
|
||||
Expr getConvertedExpr(int indirectionIndex) {
|
||||
result = this.getConvertedExpr(_, indirectionIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
@@ -95,7 +95,7 @@ module FlowFromFree<FlowFromFreeParamSig P> {
|
||||
e = any(StoreInstruction store).getDestinationAddress().getUnconvertedResultExpression()
|
||||
)
|
||||
or
|
||||
n.asExpr() instanceof ArrayExpr
|
||||
[n.asExpr(), n.asIndirectExpr()] instanceof ArrayExpr
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
## 1.0.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/dangerous-function-overflow` no longer produces a false positive alert when the `gets` function does not have exactly one parameter.
|
||||
|
||||
## 1.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
## 1.0.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/dangerous-function-overflow` no longer produces a false positive alert when the `gets` function does not have exactly one parameter.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.0
|
||||
lastReleaseVersion: 1.0.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 1.0.1-dev
|
||||
version: 1.0.2-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
| declspec.cpp:4:23:4:43 | Use fatal() instead | declspec.cpp:4:59:4:62 | exit | declspec.cpp:4:12:4:21 | deprecated | Use fatal() instead |
|
||||
| routine_attributes2.cpp:5:6:5:11 | hidden | routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.cpp:5:6:5:11 | visibility | hidden |
|
||||
| routine_attributes2.cpp:5:6:5:11 | hidden | routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.cpp:5:6:5:11 | visibility | hidden |
|
||||
| routine_attributes2.h:3:6:3:11 | hidden | routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.h:3:6:3:11 | visibility | hidden |
|
||||
| routine_attributes2.h:3:6:3:11 | hidden | routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.h:3:6:3:11 | visibility | hidden |
|
||||
| routine_attributes.c:3:53:3:59 | dummy | routine_attributes.c:3:12:3:24 | named_weakref | routine_attributes.c:3:44:3:50 | weakref | dummy |
|
||||
| routine_attributes.c:4:62:4:68 | dummy | routine_attributes.c:4:12:4:26 | aliased_weakref | routine_attributes.c:4:55:4:59 | alias | dummy |
|
||||
| routine_attributes.c:6:49:6:55 | dummy | routine_attributes.c:6:12:6:22 | plain_alias | routine_attributes.c:6:42:6:46 | alias | dummy |
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
| header_export.cpp:14:16:14:26 | myFunction4 | header_export.cpp:14:1:14:9 | dllexport |
|
||||
| header_export.cpp:18:6:18:16 | myFunction5 | header.h:10:2:10:10 | dllexport |
|
||||
| header_export.cpp:18:6:18:16 | myFunction5 | header.h:10:2:10:10 | dllimport |
|
||||
| routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.cpp:5:6:5:11 | visibility |
|
||||
| routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.cpp:5:6:5:11 | visibility |
|
||||
| routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.h:3:6:3:11 | visibility |
|
||||
| routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.h:3:6:3:11 | visibility |
|
||||
| routine_attributes.c:3:12:3:24 | named_weakref | routine_attributes.c:3:44:3:50 | weakref |
|
||||
| routine_attributes.c:4:12:4:26 | aliased_weakref | routine_attributes.c:4:46:4:52 | weakref |
|
||||
| routine_attributes.c:4:12:4:26 | aliased_weakref | routine_attributes.c:4:55:4:59 | alias |
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#define HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
#include "routine_attributes2.h"
|
||||
|
||||
void HIDDEN a_routine() {
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void HIDDEN a_routine();
|
||||
@@ -0,0 +1,3 @@
|
||||
#define HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
#include "routine_attributes2.h"
|
||||
@@ -1,3 +1,6 @@
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.cpp:5:7:5:12 | visibility | type_attributes2.cpp:5:7:5:12 | hidden |
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.h:3:7:3:12 | visibility | type_attributes2.h:3:7:3:12 | hidden |
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.h:3:7:3:12 | visibility | type_attributes2.h:3:7:3:12 | hidden |
|
||||
| type_attributes_ms.cpp:4:67:4:75 | IDispatch | type_attributes_ms.cpp:4:19:4:22 | uuid | type_attributes_ms.cpp:4:24:4:63 | {00020400-0000-0000-c000-000000000046} |
|
||||
| type_attributes_ms.cpp:5:30:5:33 | Str1 | type_attributes_ms.cpp:5:12:5:16 | align | type_attributes_ms.cpp:5:18:5:19 | 32 |
|
||||
| type_attributes_ms.cpp:6:55:6:62 | IUnknown | type_attributes_ms.cpp:6:2:6:2 | uuid | type_attributes_ms.cpp:6:2:6:2 | 00000000-0000-0000-c000-000000000046 |
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
| file://:0:0:0:0 | short __attribute((__may_alias__)) | type_attributes.c:25:30:25:42 | may_alias |
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.cpp:5:7:5:12 | visibility |
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.h:3:7:3:12 | visibility |
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.h:3:7:3:12 | visibility |
|
||||
| type_attributes.c:5:36:5:51 | my_packed_struct | type_attributes.c:5:23:5:32 | packed |
|
||||
| type_attributes.c:10:54:10:54 | (unnamed class/struct/union) | type_attributes.c:10:30:10:50 | transparent_union |
|
||||
| type_attributes.c:16:54:16:54 | (unnamed class/struct/union) | type_attributes.c:16:30:16:50 | transparent_union |
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#define HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
#include "type_attributes2.h"
|
||||
|
||||
class HIDDEN a_class {
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
class HIDDEN a_class;
|
||||
@@ -0,0 +1,3 @@
|
||||
#define HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
#include "type_attributes2.h"
|
||||
@@ -6,6 +6,10 @@
|
||||
| ms_var_attributes.cpp:12:42:12:46 | field | ms_var_attributes.cpp:12:14:12:21 | property |
|
||||
| ms_var_attributes.cpp:20:34:20:37 | pBuf | ms_var_attributes.cpp:20:12:20:12 | SAL_volatile |
|
||||
| ms_var_attributes.h:5:22:5:27 | myInt3 | ms_var_attributes.h:5:1:5:9 | dllexport |
|
||||
| var_attributes2.cpp:5:12:5:21 | a_variable | var_attributes2.cpp:5:5:5:10 | visibility |
|
||||
| var_attributes2.cpp:5:12:5:21 | a_variable | var_attributes2.cpp:5:5:5:10 | visibility |
|
||||
| var_attributes2.cpp:5:12:5:21 | a_variable | var_attributes2.h:3:12:3:17 | visibility |
|
||||
| var_attributes2.cpp:5:12:5:21 | a_variable | var_attributes2.h:3:12:3:17 | visibility |
|
||||
| var_attributes.c:1:12:1:19 | weak_var | var_attributes.c:1:36:1:39 | weak |
|
||||
| var_attributes.c:2:12:2:22 | weakref_var | var_attributes.c:2:39:2:45 | weakref |
|
||||
| var_attributes.c:3:12:3:19 | used_var | var_attributes.c:3:36:3:39 | used |
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#define HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
#include "var_attributes2.h"
|
||||
|
||||
int HIDDEN a_variable;
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
extern int HIDDEN a_variable;
|
||||
@@ -0,0 +1,3 @@
|
||||
#define HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
#include "var_attributes2.h"
|
||||
@@ -74,6 +74,8 @@ astGuardsCompare
|
||||
| 34 | j >= 10+0 when ... < ... is false |
|
||||
| 42 | 10 < j+1 when ... < ... is false |
|
||||
| 42 | 10 >= j+1 when ... < ... is true |
|
||||
| 42 | call to getABool != 0 when call to getABool is true |
|
||||
| 42 | call to getABool == 0 when call to getABool is false |
|
||||
| 42 | j < 10+0 when ... < ... is true |
|
||||
| 42 | j >= 10+0 when ... < ... is false |
|
||||
| 44 | 0 < z+0 when ... > ... is true |
|
||||
@@ -537,6 +539,8 @@ astGuardsEnsure_const
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
|
||||
| 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 | 31 | 32 |
|
||||
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | != | 0 | 43 | 45 |
|
||||
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | == | 0 | 53 | 53 |
|
||||
irGuards
|
||||
| test.c:7:9:7:13 | CompareGT: ... > ... |
|
||||
| test.c:17:8:17:12 | CompareLT: ... < ... |
|
||||
@@ -613,6 +617,8 @@ irGuardsCompare
|
||||
| 34 | j >= 10+0 when CompareLT: ... < ... is false |
|
||||
| 42 | 10 < j+1 when CompareLT: ... < ... is false |
|
||||
| 42 | 10 >= j+1 when CompareLT: ... < ... is true |
|
||||
| 42 | call to getABool != 0 when Call: call to getABool is true |
|
||||
| 42 | call to getABool == 0 when Call: call to getABool is false |
|
||||
| 42 | j < 10 when CompareLT: ... < ... is true |
|
||||
| 42 | j < 10+0 when CompareLT: ... < ... is true |
|
||||
| 42 | j >= 10 when CompareLT: ... < ... is false |
|
||||
@@ -1081,3 +1087,5 @@ irGuardsEnsure_const
|
||||
| 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 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 32 | 32 |
|
||||
| test.cpp:42:13:42:20 | Call: call to getABool | test.cpp:42:13:42:20 | Call: call to getABool | != | 0 | 44 | 44 |
|
||||
| test.cpp:42:13:42:20 | Call: call to getABool | test.cpp:42:13:42:20 | Call: call to getABool | == | 0 | 53 | 53 |
|
||||
|
||||
@@ -42,3 +42,10 @@
|
||||
| test.cpp:99:6:99:6 | f |
|
||||
| test.cpp:105:6:105:14 | ... != ... |
|
||||
| test.cpp:111:6:111:14 | ... != ... |
|
||||
| test.cpp:122:9:122:9 | b |
|
||||
| test.cpp:125:13:125:20 | ! ... |
|
||||
| test.cpp:125:14:125:17 | call to safe |
|
||||
| test.cpp:131:6:131:21 | call to __builtin_expect |
|
||||
| test.cpp:135:6:135:21 | call to __builtin_expect |
|
||||
| test.cpp:141:6:141:21 | call to __builtin_expect |
|
||||
| test.cpp:145:6:145:21 | call to __builtin_expect |
|
||||
|
||||
@@ -44,6 +44,8 @@
|
||||
| 34 | j >= 10+0 when ... < ... is false |
|
||||
| 42 | 10 < j+1 when ... < ... is false |
|
||||
| 42 | 10 >= j+1 when ... < ... is true |
|
||||
| 42 | call to getABool != 0 when call to getABool is true |
|
||||
| 42 | call to getABool == 0 when call to getABool is false |
|
||||
| 42 | j < 10 when ... < ... is true |
|
||||
| 42 | j < 10+0 when ... < ... is true |
|
||||
| 42 | j >= 10 when ... < ... is false |
|
||||
@@ -149,16 +151,59 @@
|
||||
| 111 | 0.0 == i+0 when ... != ... is false |
|
||||
| 111 | i != 0.0+0 when ... != ... is true |
|
||||
| 111 | i == 0.0+0 when ... != ... is false |
|
||||
| 122 | b != 0 when b is true |
|
||||
| 122 | b == 0 when b is false |
|
||||
| 125 | ! ... != 0 when ! ... is true |
|
||||
| 125 | ! ... == 0 when ! ... is false |
|
||||
| 125 | call to safe != 0 when ! ... is false |
|
||||
| 125 | call to safe != 0 when call to safe is true |
|
||||
| 125 | call to safe == 0 when call to safe 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 | ... + ... != a+0 when call to __builtin_expect is false |
|
||||
| 131 | ... + ... == a+0 when call to __builtin_expect is true |
|
||||
| 131 | a != ... + ...+0 when call to __builtin_expect is false |
|
||||
| 131 | a != b+42 when call to __builtin_expect is false |
|
||||
| 131 | a == ... + ...+0 when call to __builtin_expect is true |
|
||||
| 131 | a == b+42 when call to __builtin_expect is true |
|
||||
| 131 | b != 0 when b is true |
|
||||
| 131 | b != a+-42 when call to __builtin_expect is false |
|
||||
| 131 | b == 0 when b is false |
|
||||
| 131 | b == a+-42 when call to __builtin_expect is true |
|
||||
| 131 | call to __builtin_expect != 0 when call to __builtin_expect is true |
|
||||
| 131 | call to __builtin_expect == 0 when call to __builtin_expect is false |
|
||||
| 135 | ... + ... != a+0 when call to __builtin_expect is true |
|
||||
| 135 | ... + ... == a+0 when call to __builtin_expect is false |
|
||||
| 135 | a != ... + ...+0 when call to __builtin_expect is true |
|
||||
| 135 | a != b+42 when call to __builtin_expect is true |
|
||||
| 135 | a == ... + ...+0 when call to __builtin_expect is false |
|
||||
| 135 | a == b+42 when call to __builtin_expect is false |
|
||||
| 135 | b != a+-42 when call to __builtin_expect is true |
|
||||
| 135 | b == a+-42 when call to __builtin_expect is false |
|
||||
| 135 | call to __builtin_expect != 0 when call to __builtin_expect is true |
|
||||
| 135 | call to __builtin_expect == 0 when call to __builtin_expect is false |
|
||||
| 137 | 0 != 0 when 0 is true |
|
||||
| 137 | 0 == 0 when 0 is false |
|
||||
| 141 | 42 != a+0 when call to __builtin_expect is false |
|
||||
| 141 | 42 == a+0 when call to __builtin_expect is true |
|
||||
| 141 | a != 42 when call to __builtin_expect is false |
|
||||
| 141 | a != 42+0 when call to __builtin_expect is false |
|
||||
| 141 | a == 42 when call to __builtin_expect is true |
|
||||
| 141 | a == 42+0 when call to __builtin_expect is true |
|
||||
| 141 | call to __builtin_expect != 0 when call to __builtin_expect is true |
|
||||
| 141 | call to __builtin_expect == 0 when call to __builtin_expect is false |
|
||||
| 145 | 42 != a+0 when call to __builtin_expect is true |
|
||||
| 145 | 42 == a+0 when call to __builtin_expect is false |
|
||||
| 145 | a != 42 when call to __builtin_expect is true |
|
||||
| 145 | a != 42+0 when call to __builtin_expect is true |
|
||||
| 145 | a == 42 when call to __builtin_expect is false |
|
||||
| 145 | a == 42+0 when call to __builtin_expect is false |
|
||||
| 145 | call to __builtin_expect != 0 when call to __builtin_expect is true |
|
||||
| 145 | call to __builtin_expect == 0 when call to __builtin_expect is false |
|
||||
| 146 | ! ... != 0 when ! ... is true |
|
||||
| 146 | ! ... == 0 when ! ... is false |
|
||||
| 146 | x != 0 when ! ... is false |
|
||||
|
||||
@@ -100,3 +100,11 @@
|
||||
| test.cpp:99:6:99:6 | f | true | 99 | 100 |
|
||||
| test.cpp:105:6:105:14 | ... != ... | true | 105 | 106 |
|
||||
| test.cpp:111:6:111:14 | ... != ... | true | 111 | 112 |
|
||||
| test.cpp:122:9:122:9 | b | true | 123 | 125 |
|
||||
| test.cpp:122:9:122:9 | b | true | 125 | 125 |
|
||||
| test.cpp:125:13:125:20 | ! ... | true | 125 | 125 |
|
||||
| test.cpp:125:14:125:17 | call to safe | false | 125 | 125 |
|
||||
| test.cpp:131:6:131:21 | call to __builtin_expect | true | 131 | 132 |
|
||||
| test.cpp:135:6:135:21 | call to __builtin_expect | true | 135 | 136 |
|
||||
| test.cpp:141:6:141:21 | call to __builtin_expect | true | 141 | 142 |
|
||||
| test.cpp:145:6:145:21 | call to __builtin_expect | true | 145 | 146 |
|
||||
|
||||
@@ -159,6 +159,18 @@ binary
|
||||
| test.cpp:105:6:105:14 | ... != ... | test.cpp:105:11:105:14 | 0.0 | != | test.cpp:105:6:105:6 | f | 0 | 105 | 106 |
|
||||
| test.cpp:111:6:111:14 | ... != ... | test.cpp:111:6:111:6 | i | != | test.cpp:111:11:111:14 | 0.0 | 0 | 111 | 112 |
|
||||
| test.cpp:111:6:111:14 | ... != ... | test.cpp:111:11:111:14 | 0.0 | != | test.cpp:111:6:111:6 | i | 0 | 111 | 112 |
|
||||
| test.cpp:131:6:131:21 | call to __builtin_expect | test.cpp:131:23:131:23 | a | == | test.cpp:131:28:131:28 | b | 42 | 131 | 132 |
|
||||
| test.cpp:131:6:131:21 | call to __builtin_expect | test.cpp:131:23:131:23 | a | == | test.cpp:131:28:131:33 | ... + ... | 0 | 131 | 132 |
|
||||
| test.cpp:131:6:131:21 | call to __builtin_expect | test.cpp:131:28:131:28 | b | == | test.cpp:131:23:131:23 | a | -42 | 131 | 132 |
|
||||
| test.cpp:131:6:131:21 | call to __builtin_expect | test.cpp:131:28:131:33 | ... + ... | == | test.cpp:131:23:131:23 | a | 0 | 131 | 132 |
|
||||
| test.cpp:135:6:135:21 | call to __builtin_expect | test.cpp:135:23:135:23 | a | != | test.cpp:135:28:135:28 | b | 42 | 135 | 136 |
|
||||
| test.cpp:135:6:135:21 | call to __builtin_expect | test.cpp:135:23:135:23 | a | != | test.cpp:135:28:135:33 | ... + ... | 0 | 135 | 136 |
|
||||
| test.cpp:135:6:135:21 | call to __builtin_expect | test.cpp:135:28:135:28 | b | != | test.cpp:135:23:135:23 | a | -42 | 135 | 136 |
|
||||
| test.cpp:135:6:135:21 | call to __builtin_expect | test.cpp:135:28:135:33 | ... + ... | != | test.cpp:135:23:135:23 | a | 0 | 135 | 136 |
|
||||
| test.cpp:141:6:141:21 | call to __builtin_expect | test.cpp:141:23:141:23 | a | == | test.cpp:141:28:141:29 | 42 | 0 | 141 | 142 |
|
||||
| test.cpp:141:6:141:21 | call to __builtin_expect | test.cpp:141:28:141:29 | 42 | == | test.cpp:141:23:141:23 | a | 0 | 141 | 142 |
|
||||
| test.cpp:145:6:145:21 | call to __builtin_expect | test.cpp:145:23:145:23 | a | != | test.cpp:145:28:145:29 | 42 | 0 | 145 | 146 |
|
||||
| test.cpp:145:6:145:21 | call to __builtin_expect | test.cpp:145:28:145:29 | 42 | != | test.cpp:145:23:145:23 | a | 0 | 145 | 146 |
|
||||
unary
|
||||
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | < | 1 | 10 | 11 |
|
||||
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | >= | 1 | 7 | 9 |
|
||||
@@ -257,6 +269,8 @@ unary
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
|
||||
| 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 | 31 | 32 |
|
||||
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | != | 0 | 43 | 45 |
|
||||
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | == | 0 | 53 | 53 |
|
||||
| test.cpp:61:10:61:10 | i | test.cpp:61:10:61:10 | i | == | 0 | 62 | 64 |
|
||||
| test.cpp:61:10:61:10 | i | test.cpp:61:10:61:10 | i | == | 1 | 65 | 66 |
|
||||
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | < | 11 | 75 | 77 |
|
||||
@@ -264,3 +278,13 @@ unary
|
||||
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | >= | 0 | 75 | 77 |
|
||||
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | >= | 11 | 78 | 79 |
|
||||
| test.cpp:93:6:93:6 | c | test.cpp:93:6:93:6 | c | != | 0 | 93 | 94 |
|
||||
| test.cpp:122:9:122:9 | b | test.cpp:122:9:122:9 | b | != | 0 | 123 | 125 |
|
||||
| test.cpp:122:9:122:9 | b | test.cpp:122:9:122:9 | b | != | 0 | 125 | 125 |
|
||||
| test.cpp:125:13:125:20 | ! ... | test.cpp:125:13:125:20 | ! ... | != | 0 | 125 | 125 |
|
||||
| test.cpp:125:14:125:17 | call to safe | test.cpp:125:14:125:17 | call to safe | == | 0 | 125 | 125 |
|
||||
| test.cpp:131:6:131:21 | call to __builtin_expect | test.cpp:131:6:131:21 | call to __builtin_expect | != | 0 | 131 | 132 |
|
||||
| test.cpp:135:6:135:21 | call to __builtin_expect | test.cpp:135:6:135:21 | call to __builtin_expect | != | 0 | 135 | 136 |
|
||||
| test.cpp:141:6:141:21 | call to __builtin_expect | test.cpp:141:6:141:21 | call to __builtin_expect | != | 0 | 141 | 142 |
|
||||
| test.cpp:141:6:141:21 | call to __builtin_expect | test.cpp:141:23:141:23 | a | == | 42 | 141 | 142 |
|
||||
| test.cpp:145:6:145:21 | call to __builtin_expect | test.cpp:145:6:145:21 | call to __builtin_expect | != | 0 | 145 | 146 |
|
||||
| test.cpp:145:6:145:21 | call to __builtin_expect | test.cpp:145:23:145:23 | a | != | 42 | 145 | 146 |
|
||||
|
||||
@@ -112,3 +112,37 @@ void int_float_comparison(int i) {
|
||||
use(i);
|
||||
}
|
||||
}
|
||||
|
||||
int source();
|
||||
bool safe(int);
|
||||
|
||||
void test(bool b)
|
||||
{
|
||||
int x;
|
||||
if (b)
|
||||
{
|
||||
x = source();
|
||||
if (!safe(x)) return;
|
||||
}
|
||||
use(x);
|
||||
}
|
||||
|
||||
void binary_test_builtin_expected(int a, int b) {
|
||||
if(__builtin_expect(a == b + 42, 0)) {
|
||||
use(a);
|
||||
}
|
||||
|
||||
if(__builtin_expect(a != b + 42, 0)) {
|
||||
use(a);
|
||||
}
|
||||
}
|
||||
|
||||
void unary_test_builtin_expected(int a) {
|
||||
if(__builtin_expect(a == 42, 0)) {
|
||||
use(a);
|
||||
}
|
||||
|
||||
if(__builtin_expect(a != 42, 0)) {
|
||||
use(a);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (additionalEdges.ql:31,6-14)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (additionalEdges.ql:31,31-39)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (additionalEdges.ql:32,7-15)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (additionalEdges.ql:31,6-14)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (additionalEdges.ql:31,31-39)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (additionalEdges.ql:32,7-15)
|
||||
| tryExcept.c:7:7:7:7 | x | tryExcept.c:14:10:14:10 | x |
|
||||
| tryExcept.c:7:13:7:14 | 0 | tryExcept.c:10:9:10:9 | y |
|
||||
| tryExcept.c:10:9:10:9 | y | tryExcept.c:10:5:10:9 | ... = ... |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (standardEdges.ql:4,6-14)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (standardEdges.ql:4,31-39)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (standardEdges.ql:5,7-15)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (standardEdges.ql:4,6-14)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (standardEdges.ql:4,31-39)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (standardEdges.ql:5,7-15)
|
||||
| tryExcept.c:7:13:7:14 | 0 | tryExcept.c:10:9:10:9 | y |
|
||||
| tryExcept.c:10:9:10:9 | y | tryExcept.c:10:5:10:9 | ... = ... |
|
||||
|
||||
@@ -83,7 +83,7 @@ void test_guard_and_reassign() {
|
||||
if(!guarded(x)) {
|
||||
x = 0;
|
||||
}
|
||||
sink(x); // $ SPURIOUS: ast,ir
|
||||
sink(x); // $ SPURIOUS: ast
|
||||
}
|
||||
|
||||
void test_phi_read_guard(bool b) {
|
||||
@@ -98,7 +98,7 @@ void test_phi_read_guard(bool b) {
|
||||
return;
|
||||
}
|
||||
|
||||
sink(x); // $ SPURIOUS: ast,ir
|
||||
sink(x); // $ SPURIOUS: ast
|
||||
}
|
||||
|
||||
bool unsafe(int);
|
||||
|
||||
@@ -7,14 +7,17 @@ module AstTest {
|
||||
* S in `if (guarded(x)) S`.
|
||||
*/
|
||||
// This is tested in `BarrierGuard.cpp`.
|
||||
predicate testBarrierGuard(GuardCondition g, Expr checked, boolean isTrue) {
|
||||
g.(FunctionCall).getTarget().getName() = "guarded" and
|
||||
checked = g.(FunctionCall).getArgument(0) and
|
||||
isTrue = true
|
||||
or
|
||||
g.(FunctionCall).getTarget().getName() = "unsafe" and
|
||||
checked = g.(FunctionCall).getArgument(0) and
|
||||
isTrue = false
|
||||
predicate testBarrierGuard(GuardCondition g, Expr checked, boolean branch) {
|
||||
exists(Call call, boolean b |
|
||||
checked = call.getArgument(0) and
|
||||
g.comparesEq(call, 0, b, any(BooleanValue bv | bv.getValue() = branch))
|
||||
|
|
||||
call.getTarget().hasName("guarded") and
|
||||
b = false
|
||||
or
|
||||
call.getTarget().hasName("unsafe") and
|
||||
b = true
|
||||
)
|
||||
}
|
||||
|
||||
/** Common data flow configuration to be used by tests. */
|
||||
@@ -106,16 +109,16 @@ module IRTest {
|
||||
* S in `if (guarded(x)) S`.
|
||||
*/
|
||||
// This is tested in `BarrierGuard.cpp`.
|
||||
predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean isTrue) {
|
||||
exists(Call call |
|
||||
call = g.getUnconvertedResultExpression() and
|
||||
checked = call.getArgument(0)
|
||||
predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean branch) {
|
||||
exists(CallInstruction call, boolean b |
|
||||
checked = call.getArgument(0).getUnconvertedResultExpression() and
|
||||
g.comparesEq(call.getAUse(), 0, b, any(BooleanValue bv | bv.getValue() = branch))
|
||||
|
|
||||
call.getTarget().hasName("guarded") and
|
||||
isTrue = true
|
||||
call.getStaticCallTarget().hasName("guarded") and
|
||||
b = false
|
||||
or
|
||||
call.getTarget().hasName("unsafe") and
|
||||
isTrue = false
|
||||
call.getStaticCallTarget().hasName("unsafe") and
|
||||
b = true
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (has-parameter-flow-out.ql:5,18-61)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (has-parameter-flow-out.ql:5,18-61)
|
||||
testFailures
|
||||
failures
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localFlow.ql:4,6-14)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localFlow.ql:4,31-39)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localFlow.ql:6,3-11)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (localFlow.ql:4,6-14)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (localFlow.ql:4,31-39)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (localFlow.ql:6,3-11)
|
||||
| example.c:15:37:15:37 | b | example.c:15:37:15:37 | b |
|
||||
| example.c:15:37:15:37 | b | example.c:19:6:19:6 | b |
|
||||
| example.c:15:44:15:46 | pos | example.c:24:24:24:26 | pos |
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test-number-of-outnodes.ql:5,18-61)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (test-number-of-outnodes.ql:5,18-61)
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test-source-sink.ql:3,25-42)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test-source-sink.ql:3,57-74)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (test-source-sink.ql:3,25-42)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (test-source-sink.ql:3,57-74)
|
||||
astFlow
|
||||
| BarrierGuard.cpp:5:19:5:24 | source | BarrierGuard.cpp:9:10:9:15 | source |
|
||||
| BarrierGuard.cpp:13:17:13:22 | source | BarrierGuard.cpp:15:10:15:15 | source |
|
||||
@@ -145,8 +145,6 @@ irFlow
|
||||
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:55:13:55:13 | x |
|
||||
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:64:14:64:14 | x |
|
||||
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:66:14:66:14 | x |
|
||||
| BarrierGuard.cpp:81:11:81:16 | call to source | BarrierGuard.cpp:86:8:86:8 | x |
|
||||
| BarrierGuard.cpp:90:11:90:16 | call to source | BarrierGuard.cpp:101:8:101:8 | x |
|
||||
| acrossLinkTargets.cpp:19:27:19:32 | call to source | acrossLinkTargets.cpp:12:8:12:8 | x |
|
||||
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:18:8:18:19 | sourceArray1 |
|
||||
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:23:17:23:29 | *& ... |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (partial-definition-diff.ql:7,8-51)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (partial-definition-diff.ql:7,8-51)
|
||||
| A.cpp:25:13:25:13 | c | AST only |
|
||||
| A.cpp:27:28:27:28 | c | AST only |
|
||||
| A.cpp:28:23:28:26 | this | IR only |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (partial-definition.ql:6,8-51)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (partial-definition.ql:6,8-51)
|
||||
| A.cpp:25:7:25:10 | this |
|
||||
| A.cpp:25:13:25:13 | c |
|
||||
| A.cpp:27:22:27:25 | this |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:6,48-56)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:7,24-32)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:11,22-30)
|
||||
WARNING: Module TaintTracking has been deprecated and may be removed in future (taint.ql:19,20-33)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:6,48-56)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:7,24-32)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:11,22-30)
|
||||
WARNING: module 'TaintTracking' has been deprecated and may be removed in future (taint.ql:19,20-33)
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localTaint.ql:4,6-14)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localTaint.ql:4,31-39)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localTaint.ql:7,6-14)
|
||||
WARNING: Module TaintTracking has been deprecated and may be removed in future (localTaint.ql:6,3-16)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (localTaint.ql:4,6-14)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (localTaint.ql:4,31-39)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (localTaint.ql:7,6-14)
|
||||
WARNING: module 'TaintTracking' has been deprecated and may be removed in future (localTaint.ql:6,3-16)
|
||||
| arrayassignment.cpp:9:9:9:10 | 0 | arrayassignment.cpp:10:14:10:14 | x | |
|
||||
| arrayassignment.cpp:9:9:9:10 | 0 | arrayassignment.cpp:11:15:11:15 | x | |
|
||||
| arrayassignment.cpp:9:9:9:10 | 0 | arrayassignment.cpp:12:13:12:13 | x | |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:46,45-53)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:47,24-32)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:61,22-30)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:68,25-33)
|
||||
WARNING: Module TaintTracking has been deprecated and may be removed in future (taint.ql:73,20-33)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:46,45-53)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:47,24-32)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:61,22-30)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:68,25-33)
|
||||
WARNING: module 'TaintTracking' has been deprecated and may be removed in future (taint.ql:73,20-33)
|
||||
testFailures
|
||||
failures
|
||||
|
||||
@@ -13,21 +13,6 @@ edges
|
||||
| test_free.cpp:207:10:207:10 | pointer to free output argument | test_free.cpp:209:10:209:10 | a | provenance | |
|
||||
| test_free.cpp:301:12:301:14 | pointer to g_free output argument | test_free.cpp:302:12:302:14 | buf | provenance | |
|
||||
| test_free.cpp:319:16:319:16 | pointer to operator delete output argument | test_free.cpp:322:12:322:12 | a | provenance | |
|
||||
| test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | test_free.cpp:344:12:344:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | test_free.cpp:345:12:345:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | test_free.cpp:346:12:346:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:343:26:343:28 | pointer to operator delete output argument | test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | provenance | |
|
||||
| test_free.cpp:344:12:344:24 | *access to array [post update] [ptr] | test_free.cpp:345:12:345:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:344:12:344:24 | *access to array [post update] [ptr] | test_free.cpp:346:12:346:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:344:12:344:24 | *access to array [ptr] | test_free.cpp:344:26:344:28 | ptr | provenance | |
|
||||
| test_free.cpp:344:26:344:28 | pointer to operator delete output argument | test_free.cpp:344:12:344:24 | *access to array [post update] [ptr] | provenance | |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [post update] [ptr] | test_free.cpp:346:12:346:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [ptr] | test_free.cpp:345:26:345:28 | ptr | provenance | |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [ptr] | test_free.cpp:345:26:345:28 | ptr | provenance | |
|
||||
| test_free.cpp:345:26:345:28 | pointer to operator delete output argument | test_free.cpp:345:12:345:24 | *access to array [post update] [ptr] | provenance | |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | test_free.cpp:346:26:346:28 | ptr | provenance | |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | test_free.cpp:346:26:346:28 | ptr | provenance | |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | test_free.cpp:346:26:346:28 | ptr | provenance | |
|
||||
nodes
|
||||
| test_free.cpp:11:10:11:10 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||
| test_free.cpp:14:10:14:10 | a | semmle.label | a |
|
||||
@@ -57,24 +42,6 @@ nodes
|
||||
| test_free.cpp:302:12:302:14 | buf | semmle.label | buf |
|
||||
| test_free.cpp:319:16:319:16 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
|
||||
| test_free.cpp:322:12:322:12 | a | semmle.label | a |
|
||||
| test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | semmle.label | *access to array [post update] [ptr] |
|
||||
| test_free.cpp:343:26:343:28 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
|
||||
| test_free.cpp:344:12:344:24 | *access to array [post update] [ptr] | semmle.label | *access to array [post update] [ptr] |
|
||||
| test_free.cpp:344:12:344:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:344:26:344:28 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
|
||||
| test_free.cpp:344:26:344:28 | ptr | semmle.label | ptr |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [post update] [ptr] | semmle.label | *access to array [post update] [ptr] |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:345:26:345:28 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
|
||||
| test_free.cpp:345:26:345:28 | ptr | semmle.label | ptr |
|
||||
| test_free.cpp:345:26:345:28 | ptr | semmle.label | ptr |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:346:26:346:28 | ptr | semmle.label | ptr |
|
||||
| test_free.cpp:346:26:346:28 | ptr | semmle.label | ptr |
|
||||
| test_free.cpp:346:26:346:28 | ptr | semmle.label | ptr |
|
||||
subpaths
|
||||
#select
|
||||
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:14:10:14:10 | a | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:14:10:14:10 | a | a | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
@@ -91,9 +58,3 @@ subpaths
|
||||
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | pointer to free output argument | test_free.cpp:209:10:209:10 | a | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:209:10:209:10 | a | a | test_free.cpp:207:5:207:8 | call to free | call to free |
|
||||
| test_free.cpp:302:12:302:14 | buf | test_free.cpp:301:12:301:14 | pointer to g_free output argument | test_free.cpp:302:12:302:14 | buf | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:302:12:302:14 | buf | buf | test_free.cpp:301:5:301:10 | call to g_free | call to g_free |
|
||||
| test_free.cpp:322:12:322:12 | a | test_free.cpp:319:16:319:16 | pointer to operator delete output argument | test_free.cpp:322:12:322:12 | a | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:322:12:322:12 | a | a | test_free.cpp:319:9:319:16 | delete | delete |
|
||||
| test_free.cpp:344:26:344:28 | ptr | test_free.cpp:343:26:343:28 | pointer to operator delete output argument | test_free.cpp:344:26:344:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:344:26:344:28 | ptr | ptr | test_free.cpp:343:5:343:28 | delete | delete |
|
||||
| test_free.cpp:345:26:345:28 | ptr | test_free.cpp:343:26:343:28 | pointer to operator delete output argument | test_free.cpp:345:26:345:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:345:26:345:28 | ptr | ptr | test_free.cpp:343:5:343:28 | delete | delete |
|
||||
| test_free.cpp:345:26:345:28 | ptr | test_free.cpp:344:26:344:28 | pointer to operator delete output argument | test_free.cpp:345:26:345:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:345:26:345:28 | ptr | ptr | test_free.cpp:344:5:344:28 | delete | delete |
|
||||
| test_free.cpp:346:26:346:28 | ptr | test_free.cpp:343:26:343:28 | pointer to operator delete output argument | test_free.cpp:346:26:346:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:346:26:346:28 | ptr | ptr | test_free.cpp:343:5:343:28 | delete | delete |
|
||||
| test_free.cpp:346:26:346:28 | ptr | test_free.cpp:344:26:344:28 | pointer to operator delete output argument | test_free.cpp:346:26:346:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:346:26:346:28 | ptr | ptr | test_free.cpp:344:5:344:28 | delete | delete |
|
||||
| test_free.cpp:346:26:346:28 | ptr | test_free.cpp:345:26:345:28 | pointer to operator delete output argument | test_free.cpp:346:26:346:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:346:26:346:28 | ptr | ptr | test_free.cpp:345:5:345:28 | delete | delete |
|
||||
|
||||
@@ -115,6 +115,8 @@
|
||||
| test_free.cpp:344:26:344:28 | ptr |
|
||||
| test_free.cpp:345:26:345:28 | ptr |
|
||||
| test_free.cpp:346:26:346:28 | ptr |
|
||||
| test_free.cpp:356:19:356:19 | a |
|
||||
| test_free.cpp:357:19:357:19 | a |
|
||||
| virtual.cpp:18:10:18:10 | a |
|
||||
| virtual.cpp:19:10:19:10 | c |
|
||||
| virtual.cpp:38:10:38:10 | b |
|
||||
|
||||
@@ -341,7 +341,18 @@ struct PtrContainer {
|
||||
|
||||
void test_array(PtrContainer *containers) {
|
||||
delete containers[0].ptr; // GOOD
|
||||
delete containers[1].ptr; // GOOD [FALSE POSITIVE]
|
||||
delete containers[2].ptr; // GOOD [FALSE POSITIVE]
|
||||
delete containers[2].ptr; // BAD (double free)
|
||||
delete containers[1].ptr; // GOOD
|
||||
delete containers[2].ptr; // GOOD
|
||||
delete containers[2].ptr; // BAD (double free) [NOT DETECTED]
|
||||
}
|
||||
|
||||
struct E {
|
||||
struct EC {
|
||||
int* a;
|
||||
} ec[2];
|
||||
};
|
||||
|
||||
void test(E* e) {
|
||||
free(e->ec[0].a);
|
||||
free(e->ec[1].a); // GOOD
|
||||
}
|
||||
@@ -7,10 +7,11 @@
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
|
||||
<Company>GitHub</Company>
|
||||
<Product>CodeQL</Product>
|
||||
<Copyright>Copyright © $([System.DateTime]::Now.Year) $(Company)</Copyright>
|
||||
<Version>1.0.0.0</Version>
|
||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
<FileVersion>$(Version)</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -7,7 +7,6 @@ codeql_xunit_test(
|
||||
name = "Semmle.Autobuild.CSharp.Tests",
|
||||
srcs = glob([
|
||||
"*.cs",
|
||||
"Properties/*.cs",
|
||||
]),
|
||||
deps = [
|
||||
"//csharp/autobuilder/Semmle.Autobuild.CSharp:bin/Semmle.Autobuild.CSharp",
|
||||
|
||||
@@ -7,7 +7,6 @@ codeql_csharp_binary(
|
||||
name = "Semmle.Autobuild.CSharp",
|
||||
srcs = glob([
|
||||
"*.cs",
|
||||
"Properties/*.cs",
|
||||
]),
|
||||
visibility = ["//csharp:__subpackages__"],
|
||||
deps = [
|
||||
|
||||
@@ -7,7 +7,6 @@ codeql_xunit_test(
|
||||
name = "Semmle.Autobuild.Cpp.Tests",
|
||||
srcs = glob([
|
||||
"*.cs",
|
||||
"Properties/*.cs",
|
||||
]),
|
||||
deps = [
|
||||
"//csharp/autobuilder/Semmle.Autobuild.Cpp:bin/Semmle.Autobuild.Cpp",
|
||||
|
||||
@@ -7,7 +7,6 @@ codeql_csharp_binary(
|
||||
name = "Semmle.Autobuild.Cpp",
|
||||
srcs = glob([
|
||||
"*.cs",
|
||||
"Properties/*.cs",
|
||||
]),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
|
||||
@@ -7,7 +7,6 @@ codeql_csharp_library(
|
||||
name = "Semmle.Autobuild.Shared",
|
||||
srcs = glob([
|
||||
"*.cs",
|
||||
"Properties/*.cs",
|
||||
]),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
|
||||
@@ -2,43 +2,44 @@ package,sink,source,summary,sink:code-injection,sink:encryption-decryptor,sink:e
|
||||
Amazon.Lambda.APIGatewayEvents,,6,,,,,,,,,,,,,,,,,,6,,,
|
||||
Amazon.Lambda.Core,10,,,,,,,,,,,10,,,,,,,,,,,
|
||||
Dapper,55,42,1,,,,,,,,,,55,,42,,,,,,,,1
|
||||
ILCompiler,,,81,,,,,,,,,,,,,,,,,,,81,
|
||||
ILLink.RoslynAnalyzer,,,63,,,,,,,,,,,,,,,,,,,63,
|
||||
ILLink.Shared,,,32,,,,,,,,,,,,,,,,,,,30,2
|
||||
ILLink.Tasks,,,3,,,,,,,,,,,,,,,,,,,3,
|
||||
ILCompiler,,,123,,,,,,,,,,,,,,,,,,,123,
|
||||
ILLink.RoslynAnalyzer,,,145,,,,,,,,,,,,,,,,,,,145,
|
||||
ILLink.Shared,,,34,,,,,,,,,,,,,,,,,,,32,2
|
||||
ILLink.Tasks,,,4,,,,,,,,,,,,,,,,,,,4,
|
||||
Internal.IL,,,46,,,,,,,,,,,,,,,,,,,44,2
|
||||
Internal.Pgo,,,9,,,,,,,,,,,,,,,,,,,8,1
|
||||
Internal.TypeSystem,,,291,,,,,,,,,,,,,,,,,,,275,16
|
||||
JsonToItemsTaskFactory,,,5,,,,,,,,,,,,,,,,,,,5,
|
||||
Microsoft.Android.Build,,,14,,,,,,,,,,,,,,,,,,,14,
|
||||
Microsoft.Apple.Build,,,5,,,,,,,,,,,,,,,,,,,5,
|
||||
Internal.TypeSystem,,,315,,,,,,,,,,,,,,,,,,,299,16
|
||||
JsonToItemsTaskFactory,,,10,,,,,,,,,,,,,,,,,,,10,
|
||||
Microsoft.Android.Build,,,16,,,,,,,,,,,,,,,,,,,16,
|
||||
Microsoft.Apple.Build,,,8,,,,,,,,,,,,,,,,,,,8,
|
||||
Microsoft.ApplicationBlocks.Data,28,,,,,,,,,,,,28,,,,,,,,,,
|
||||
Microsoft.CSharp,,,10,,,,,,,,,,,,,,,,,,,10,
|
||||
Microsoft.CSharp,,,13,,,,,,,,,,,,,,,,,,,13,
|
||||
Microsoft.Diagnostics.Tools.Pgo,,,12,,,,,,,,,,,,,,,,,,,12,
|
||||
Microsoft.DotNet.Build.Tasks,,,6,,,,,,,,,,,,,,,,,,,6,
|
||||
Microsoft.EntityFrameworkCore,6,,12,,,,,,,,,,6,,,,,,,,,,12
|
||||
Microsoft.Extensions.Caching.Distributed,,,9,,,,,,,,,,,,,,,,,,,9,
|
||||
Microsoft.Extensions.Caching.Memory,,,30,,,,,,,,,,,,,,,,,,,29,1
|
||||
Microsoft.Extensions.Configuration,,2,77,,,,,,,,,,,,,2,,,,,,76,1
|
||||
Microsoft.Extensions.DependencyInjection,,,96,,,,,,,,,,,,,,,,,,,95,1
|
||||
Microsoft.Extensions.DependencyModel,,,9,,,,,,,,,,,,,,,,,,,9,
|
||||
Microsoft.Extensions.Caching.Distributed,,,10,,,,,,,,,,,,,,,,,,,10,
|
||||
Microsoft.Extensions.Caching.Memory,,,39,,,,,,,,,,,,,,,,,,,38,1
|
||||
Microsoft.Extensions.Configuration,,2,90,,,,,,,,,,,,,2,,,,,,89,1
|
||||
Microsoft.Extensions.DependencyInjection,,,134,,,,,,,,,,,,,,,,,,,133,1
|
||||
Microsoft.Extensions.DependencyModel,,,18,,,,,,,,,,,,,,,,,,,18,
|
||||
Microsoft.Extensions.Diagnostics.Metrics,,,15,,,,,,,,,,,,,,,,,,,15,
|
||||
Microsoft.Extensions.FileProviders,,,15,,,,,,,,,,,,,,,,,,,15,
|
||||
Microsoft.Extensions.FileSystemGlobbing,,,16,,,,,,,,,,,,,,,,,,,14,2
|
||||
Microsoft.Extensions.Hosting,,,26,,,,,,,,,,,,,,,,,,,25,1
|
||||
Microsoft.Extensions.Http,,,8,,,,,,,,,,,,,,,,,,,8,
|
||||
Microsoft.Extensions.Logging,,,53,,,,,,,,,,,,,,,,,,,52,1
|
||||
Microsoft.Extensions.Options,,,8,,,,,,,,,,,,,,,,,,,8,
|
||||
Microsoft.Extensions.Primitives,,,64,,,,,,,,,,,,,,,,,,,64,
|
||||
Microsoft.Interop,,,73,,,,,,,,,,,,,,,,,,,73,
|
||||
Microsoft.NET.Build.Tasks,,,1,,,,,,,,,,,,,,,,,,,1,
|
||||
Microsoft.NET.WebAssembly.Webcil,,,7,,,,,,,,,,,,,,,,,,,7,
|
||||
Microsoft.Extensions.FileSystemGlobbing,,,18,,,,,,,,,,,,,,,,,,,16,2
|
||||
Microsoft.Extensions.Hosting,,,41,,,,,,,,,,,,,,,,,,,40,1
|
||||
Microsoft.Extensions.Http,,,9,,,,,,,,,,,,,,,,,,,9,
|
||||
Microsoft.Extensions.Logging,,,65,,,,,,,,,,,,,,,,,,,64,1
|
||||
Microsoft.Extensions.Options,,,13,,,,,,,,,,,,,,,,,,,13,
|
||||
Microsoft.Extensions.Primitives,,,72,,,,,,,,,,,,,,,,,,,72,
|
||||
Microsoft.Interop,,,121,,,,,,,,,,,,,,,,,,,121,
|
||||
Microsoft.NET.Build.Tasks,,,4,,,,,,,,,,,,,,,,,,,4,
|
||||
Microsoft.NET.WebAssembly.Webcil,,,8,,,,,,,,,,,,,,,,,,,8,
|
||||
Microsoft.VisualBasic,,,6,,,,,,,,,,,,,,,,,,,1,5
|
||||
Microsoft.WebAssembly.Build.Tasks,,,3,,,,,,,,,,,,,,,,,,,3,
|
||||
Microsoft.WebAssembly.Build.Tasks,,,4,,,,,,,,,,,,,,,,,,,4,
|
||||
Microsoft.Win32,,4,4,,,,,,,,,,,,,,,,,,4,4,
|
||||
Mono.Linker,,,158,,,,,,,,,,,,,,,,,,,158,
|
||||
Mono.Linker,,,285,,,,,,,,,,,,,,,,,,,285,
|
||||
MySql.Data.MySqlClient,48,,,,,,,,,,,,48,,,,,,,,,,
|
||||
Newtonsoft.Json,,,91,,,,,,,,,,,,,,,,,,,73,18
|
||||
ServiceStack,194,,7,27,,,,,75,,,,92,,,,,,,,,7,
|
||||
SourceGenerators,,,4,,,,,,,,,,,,,,,,,,,4,
|
||||
System,49,44,9873,,3,3,1,,,4,5,,33,2,,3,15,17,3,4,,7968,1905
|
||||
SourceGenerators,,,5,,,,,,,,,,,,,,,,,,,5,
|
||||
System,60,44,10614,,7,6,5,,,4,5,,33,2,,3,15,17,3,4,,8709,1905
|
||||
Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,,,,,,,,,
|
||||
|
||||
|
@@ -8,7 +8,7 @@ C# framework & library support
|
||||
|
||||
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
|
||||
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
|
||||
System,"``System.*``, ``System``",44,9873,49,9
|
||||
Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``JsonToItemsTaskFactory``, ``Microsoft.Android.Build``, ``Microsoft.Apple.Build``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.Diagnostics.Metrics``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NET.WebAssembly.Webcil``, ``Microsoft.VisualBasic``, ``Microsoft.WebAssembly.Build.Tasks``, ``Microsoft.Win32``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",54,1357,148,
|
||||
Totals,,98,11237,391,9
|
||||
System,"``System.*``, ``System``",44,10614,60,9
|
||||
Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``JsonToItemsTaskFactory``, ``Microsoft.Android.Build``, ``Microsoft.Apple.Build``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.DotNet.Build.Tasks``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.Diagnostics.Metrics``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NET.WebAssembly.Webcil``, ``Microsoft.VisualBasic``, ``Microsoft.WebAssembly.Build.Tasks``, ``Microsoft.Win32``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",54,1821,148,
|
||||
Totals,,98,12442,402,9
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ codeql_csharp_library(
|
||||
name = "Semmle.Extraction.CSharp.DependencyFetching",
|
||||
srcs = glob([
|
||||
"*.cs",
|
||||
"Properties/*.cs",
|
||||
"SourceGenerators/**/*.cs",
|
||||
]),
|
||||
allow_unsafe_blocks = True,
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Expose internals for testing purposes.
|
||||
[assembly: InternalsVisibleTo("Semmle.Extraction.Tests")]
|
||||
@@ -6,6 +6,8 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Extraction\Semmle.Extraction.csproj" />
|
||||
|
||||
<InternalsVisibleTo Include="Semmle.Extraction.Tests" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\..\.paket\Paket.Restore.targets" />
|
||||
</Project>
|
||||
|
||||
@@ -7,7 +7,6 @@ codeql_csharp_binary(
|
||||
name = "Semmle.Extraction.CSharp.DependencyStubGenerator",
|
||||
srcs = glob([
|
||||
"*.cs",
|
||||
"Properties/*.cs",
|
||||
]),
|
||||
visibility = ["//csharp:__pkg__"],
|
||||
deps = [
|
||||
|
||||
@@ -7,7 +7,6 @@ codeql_csharp_binary(
|
||||
name = "Semmle.Extraction.CSharp.Driver",
|
||||
srcs = glob([
|
||||
"*.cs",
|
||||
"Properties/*.cs",
|
||||
]),
|
||||
visibility = ["//csharp:__pkg__"],
|
||||
deps = [
|
||||
|
||||
@@ -7,7 +7,6 @@ codeql_csharp_binary(
|
||||
name = "Semmle.Extraction.CSharp.Standalone",
|
||||
srcs = glob([
|
||||
"*.cs",
|
||||
"Properties/*.cs",
|
||||
]),
|
||||
visibility = ["//csharp:__subpackages__"],
|
||||
deps = [
|
||||
|
||||
@@ -42,17 +42,17 @@ namespace Semmle.Extraction.CSharp.Standalone
|
||||
(compilation, options) => analyser.Initialize(output.FullName, extractionInput.CompilationInfos, compilation, options),
|
||||
() =>
|
||||
{
|
||||
foreach (var type in analyser.MissingNamespaces)
|
||||
foreach (var type in analyser.ExtractionContext!.MissingNamespaces)
|
||||
{
|
||||
progressMonitor.MissingNamespace(type);
|
||||
}
|
||||
|
||||
foreach (var type in analyser.MissingTypes)
|
||||
foreach (var type in analyser.ExtractionContext!.MissingTypes)
|
||||
{
|
||||
progressMonitor.MissingType(type);
|
||||
}
|
||||
|
||||
progressMonitor.MissingSummary(analyser.MissingTypes.Count(), analyser.MissingNamespaces.Count());
|
||||
progressMonitor.MissingSummary(analyser.ExtractionContext!.MissingTypes.Count(), analyser.ExtractionContext!.MissingNamespaces.Count());
|
||||
});
|
||||
}
|
||||
finally
|
||||
@@ -69,29 +69,6 @@ namespace Semmle.Extraction.CSharp.Standalone
|
||||
}
|
||||
}
|
||||
|
||||
private static void ExtractStandalone(
|
||||
ExtractionInput extractionInput,
|
||||
IProgressMonitor pm,
|
||||
ILogger logger,
|
||||
CommonOptions options)
|
||||
{
|
||||
var stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
|
||||
var canonicalPathCache = CanonicalPathCache.Create(logger, 1000);
|
||||
var pathTransformer = new PathTransformer(canonicalPathCache);
|
||||
|
||||
using var analyser = new StandaloneAnalyser(pm, logger, false, pathTransformer);
|
||||
try
|
||||
{
|
||||
AnalyseStandalone(analyser, extractionInput, options, pm, stopwatch);
|
||||
}
|
||||
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
analyser.Logger.Log(Severity.Error, " Unhandled exception: {0}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private class ExtractionProgress : IProgressMonitor
|
||||
{
|
||||
public ExtractionProgress(ILogger output)
|
||||
@@ -141,8 +118,8 @@ namespace Semmle.Extraction.CSharp.Standalone
|
||||
|
||||
public static ExitCode Run(Options options)
|
||||
{
|
||||
var stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
var overallStopwatch = new Stopwatch();
|
||||
overallStopwatch.Start();
|
||||
|
||||
using var logger = new ConsoleLogger(options.Verbosity, logThreadId: true);
|
||||
logger.Log(Severity.Info, "Extracting C# with build-mode set to 'none'");
|
||||
@@ -158,12 +135,26 @@ namespace Semmle.Extraction.CSharp.Standalone
|
||||
|
||||
logger.Log(Severity.Info, "");
|
||||
logger.Log(Severity.Info, "Extracting...");
|
||||
ExtractStandalone(
|
||||
new ExtractionInput(dependencyManager.AllSourceFiles, dependencyManager.ReferenceFiles, dependencyManager.CompilationInfos),
|
||||
new ExtractionProgress(logger),
|
||||
fileLogger,
|
||||
options);
|
||||
logger.Log(Severity.Info, $"Extraction completed in {stopwatch.Elapsed}");
|
||||
|
||||
var analyzerStopwatch = new Stopwatch();
|
||||
analyzerStopwatch.Start();
|
||||
|
||||
var canonicalPathCache = CanonicalPathCache.Create(fileLogger, 1000);
|
||||
var pathTransformer = new PathTransformer(canonicalPathCache);
|
||||
|
||||
var progressMonitor = new ExtractionProgress(logger);
|
||||
using var analyser = new StandaloneAnalyser(progressMonitor, fileLogger, pathTransformer, canonicalPathCache, false);
|
||||
try
|
||||
{
|
||||
var extractionInput = new ExtractionInput(dependencyManager.AllSourceFiles, dependencyManager.ReferenceFiles, dependencyManager.CompilationInfos);
|
||||
AnalyseStandalone(analyser, extractionInput, options, progressMonitor, analyzerStopwatch);
|
||||
}
|
||||
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
fileLogger.Log(Severity.Error, " Unhandled exception: {0}", ex);
|
||||
}
|
||||
|
||||
logger.Log(Severity.Info, $"Extraction completed in {overallStopwatch.Elapsed}");
|
||||
|
||||
return ExitCode.Ok;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ codeql_csharp_library(
|
||||
name = "Semmle.Extraction.CSharp.StubGenerator",
|
||||
srcs = glob([
|
||||
"*.cs",
|
||||
"Properties/*.cs",
|
||||
]),
|
||||
internals_visible_to = ["Semmle.Extraction.Tests"],
|
||||
visibility = ["//csharp:__subpackages__"],
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Expose internals for testing purposes.
|
||||
[assembly: InternalsVisibleTo("Semmle.Extraction.Tests")]
|
||||
@@ -4,6 +4,8 @@
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp.DependencyFetching\Semmle.Extraction.CSharp.DependencyFetching.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp.Util\Semmle.Extraction.CSharp.Util.csproj" />
|
||||
|
||||
<InternalsVisibleTo Include="Semmle.Extraction.Tests" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\..\.paket\Paket.Restore.targets" />
|
||||
</Project>
|
||||
|
||||
@@ -6,7 +6,6 @@ load(
|
||||
codeql_csharp_library(
|
||||
name = "Semmle.Extraction.CSharp.Util",
|
||||
srcs = glob([
|
||||
"Properties/*.cs",
|
||||
"*.cs",
|
||||
]),
|
||||
visibility = ["//csharp:__subpackages__"],
|
||||
|
||||
@@ -11,7 +11,6 @@ codeql_csharp_library(
|
||||
"Extractor/**/*.cs",
|
||||
"Kinds/**/*.cs",
|
||||
"Populators/**/*.cs",
|
||||
"Properties/**/*.cs",
|
||||
"*.cs",
|
||||
]),
|
||||
allow_unsafe_blocks = True,
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
isOutputAssembly = init is null;
|
||||
if (isOutputAssembly)
|
||||
{
|
||||
assemblyPath = cx.Extractor.OutputPath;
|
||||
assemblyPath = cx.ExtractionContext.OutputPath;
|
||||
assembly = cx.Compilation.Assembly;
|
||||
}
|
||||
else
|
||||
@@ -25,7 +25,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
assembly = init!.MetadataModule!.ContainingAssembly;
|
||||
var identity = assembly.Identity;
|
||||
var idString = identity.Name + " " + identity.Version;
|
||||
assemblyPath = cx.Extractor.GetAssemblyFile(idString);
|
||||
assemblyPath = cx.ExtractionContext.GetAssemblyFile(idString);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
if (assemblyPath is not null)
|
||||
{
|
||||
var isBuildlessOutputAssembly = isOutputAssembly && Context.Extractor.Mode.HasFlag(ExtractorMode.Standalone);
|
||||
var isBuildlessOutputAssembly = isOutputAssembly && Context.ExtractionContext.Mode.HasFlag(ExtractorMode.Standalone);
|
||||
var identifier = isBuildlessOutputAssembly
|
||||
? ""
|
||||
: assembly.ToString() ?? "";
|
||||
@@ -74,7 +74,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override void WriteId(EscapingTextWriter trapFile)
|
||||
{
|
||||
if (isOutputAssembly && Context.Extractor.Mode.HasFlag(ExtractorMode.Standalone))
|
||||
if (isOutputAssembly && Context.ExtractionContext.Mode.HasFlag(ExtractorMode.Standalone))
|
||||
{
|
||||
trapFile.Write("buildlessOutputAssembly");
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
#nullable disable warnings
|
||||
private Compilation(Context cx) : base(cx, null)
|
||||
{
|
||||
cwd = cx.Extractor.Cwd;
|
||||
args = cx.Extractor.Args;
|
||||
cwd = cx.ExtractionContext.Cwd;
|
||||
args = cx.ExtractionContext.Args;
|
||||
hashCode = cwd.GetHashCode();
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
if (messageCount == limit + 1)
|
||||
{
|
||||
Context.Extractor.Logger.LogWarning($"Stopped logging {key} compiler diagnostics for the current compilation after reaching {limit}");
|
||||
Context.ExtractionContext.Logger.LogWarning($"Stopped logging {key} compiler diagnostics for the current compilation after reaching {limit}");
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
.Where(method => method.Parameters.Length >= Syntax.ArgumentList.Arguments.Count)
|
||||
.Where(method => method.Parameters.Count(p => !p.HasExplicitDefaultValue) <= Syntax.ArgumentList.Arguments.Count);
|
||||
|
||||
return Context.Extractor.Mode.HasFlag(ExtractorMode.Standalone) ?
|
||||
return Context.ExtractionContext.Mode.HasFlag(ExtractorMode.Standalone) ?
|
||||
candidates.FirstOrDefault() :
|
||||
candidates.SingleOrDefault();
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
}
|
||||
|
||||
trapFile.file_extraction_mode(this, Context.Extractor.Mode);
|
||||
trapFile.file_extraction_mode(this, Context.ExtractionContext.Mode);
|
||||
}
|
||||
|
||||
private bool IsPossiblyTextFile()
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
var mapped = Symbol.GetMappedLineSpan();
|
||||
if (mapped.HasMappedPath && mapped.IsValid)
|
||||
{
|
||||
var path = TryAdjustRelativeMappedFilePath(mapped.Path, Position.Path, Context.Extractor.Logger);
|
||||
var path = Context.TryAdjustRelativeMappedFilePath(mapped.Path, Position.Path);
|
||||
var mappedLoc = Create(Context, Location.Create(path, default, mapped.Span));
|
||||
|
||||
trapFile.locations_mapped(this, mappedLoc);
|
||||
@@ -64,25 +64,5 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override NonGeneratedSourceLocation Create(Context cx, Location init) => new NonGeneratedSourceLocation(cx, init);
|
||||
}
|
||||
|
||||
public static string TryAdjustRelativeMappedFilePath(string mappedToPath, string mappedFromPath, ILogger logger)
|
||||
{
|
||||
if (!Path.IsPathRooted(mappedToPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
var fullPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(mappedFromPath)!, mappedToPath));
|
||||
logger.LogDebug($"Found relative path in line mapping: '{mappedToPath}', interpreting it as '{fullPath}'");
|
||||
|
||||
mappedToPath = fullPath;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogDebug($"Failed to compute absolute path for relative path in line mapping: '{mappedToPath}': {e}");
|
||||
}
|
||||
}
|
||||
|
||||
return mappedToPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
if (method.MethodKind == MethodKind.ReducedExtension)
|
||||
{
|
||||
cx.Extractor.Logger.Log(Semmle.Util.Logging.Severity.Warning, "Reduced extension method symbols should not be directly extracted.");
|
||||
cx.ExtractionContext.Logger.Log(Semmle.Util.Logging.Severity.Warning, "Reduced extension method symbols should not be directly extracted.");
|
||||
}
|
||||
|
||||
return OrdinaryMethodFactory.Instance.CreateEntityFromSymbol(cx, method);
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
var path = Symbol.File.ValueText;
|
||||
if (!string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
path = NonGeneratedSourceLocation.TryAdjustRelativeMappedFilePath(path, Symbol.SyntaxTree.FilePath, Context.Extractor.Logger);
|
||||
path = Context.TryAdjustRelativeMappedFilePath(path, Symbol.SyntaxTree.FilePath);
|
||||
var file = File.Create(Context, path);
|
||||
trapFile.directive_line_file(this, file);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
protected override void PopulatePreprocessor(TextWriter trapFile)
|
||||
{
|
||||
var path = NonGeneratedSourceLocation.TryAdjustRelativeMappedFilePath(Symbol.File.ValueText, Symbol.SyntaxTree.FilePath, Context.Extractor.Logger);
|
||||
var path = Context.TryAdjustRelativeMappedFilePath(Symbol.File.ValueText, Symbol.SyntaxTree.FilePath);
|
||||
var file = File.Create(Context, path);
|
||||
trapFile.pragma_checksums(this, file, Symbol.Guid.ToString(), Symbol.Bytes.ToString());
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
if (Symbol.TypeKind == TypeKind.Error)
|
||||
{
|
||||
UnknownType.Create(Context); // make sure this exists so we can use it in `TypeRef::getReferencedType`
|
||||
Context.Extractor.MissingType(Symbol.ToString()!, Context.FromSource);
|
||||
Context.ExtractionContext.MissingType(Symbol.ToString()!, Context.FromSource);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.Extractor.MissingNamespace(name.ToFullString(), Context.FromSource);
|
||||
Context.ExtractionContext.MissingNamespace(name.ToFullString(), Context.FromSource);
|
||||
Context.ModelError(node, "Namespace not found");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CSharp;
|
||||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
using Semmle.Extraction.CSharp.Populators;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
@@ -18,7 +19,7 @@ namespace Semmle.Extraction.CSharp
|
||||
/// </summary>
|
||||
public class Analyser : IDisposable
|
||||
{
|
||||
protected Extraction.Extractor? extractor;
|
||||
public ExtractionContext? ExtractionContext { get; protected set; }
|
||||
protected CSharpCompilation? compilation;
|
||||
protected CommonOptions? options;
|
||||
private protected Entities.Compilation? compilationEntity;
|
||||
@@ -38,14 +39,23 @@ namespace Semmle.Extraction.CSharp
|
||||
|
||||
public PathTransformer PathTransformer { get; }
|
||||
|
||||
protected Analyser(IProgressMonitor pm, ILogger logger, bool addAssemblyTrapPrefix, PathTransformer pathTransformer)
|
||||
public IPathCache PathCache { get; }
|
||||
|
||||
protected Analyser(
|
||||
IProgressMonitor pm,
|
||||
ILogger logger,
|
||||
PathTransformer pathTransformer,
|
||||
IPathCache pathCache,
|
||||
bool addAssemblyTrapPrefix)
|
||||
{
|
||||
Logger = logger;
|
||||
PathTransformer = pathTransformer;
|
||||
PathCache = pathCache;
|
||||
this.addAssemblyTrapPrefix = addAssemblyTrapPrefix;
|
||||
this.progressMonitor = pm;
|
||||
|
||||
Logger.Log(Severity.Info, "EXTRACTION STARTING at {0}", DateTime.Now);
|
||||
stopWatch.Start();
|
||||
progressMonitor = pm;
|
||||
PathTransformer = pathTransformer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -98,12 +108,12 @@ namespace Semmle.Extraction.CSharp
|
||||
var def = reader.GetAssemblyDefinition();
|
||||
assemblyIdentity = reader.GetString(def.Name) + " " + def.Version;
|
||||
}
|
||||
extractor.SetAssemblyFile(assemblyIdentity, refPath);
|
||||
ExtractionContext.SetAssemblyFile(assemblyIdentity, refPath);
|
||||
|
||||
}
|
||||
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
extractor.Message(new Message("Exception reading reference file", reference.FilePath, null, ex.StackTrace));
|
||||
ExtractionContext.Message(new Message("Exception reading reference file", reference.FilePath, null, ex.StackTrace));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,7 +158,7 @@ namespace Semmle.Extraction.CSharp
|
||||
|
||||
if (compilation.GetAssemblyOrModuleSymbol(r) is IAssemblySymbol assembly)
|
||||
{
|
||||
var cx = new Context(extractor, compilation, trapWriter, new AssemblyScope(assembly, assemblyPath), addAssemblyTrapPrefix);
|
||||
var cx = new Context(ExtractionContext, compilation, trapWriter, new AssemblyScope(assembly, assemblyPath), addAssemblyTrapPrefix);
|
||||
|
||||
foreach (var module in assembly.Modules)
|
||||
{
|
||||
@@ -191,7 +201,7 @@ namespace Semmle.Extraction.CSharp
|
||||
|
||||
if (!upToDate)
|
||||
{
|
||||
var cx = new Context(extractor, compilation, trapWriter, new SourceScope(tree), addAssemblyTrapPrefix);
|
||||
var cx = new Context(ExtractionContext, compilation, trapWriter, new SourceScope(tree), addAssemblyTrapPrefix);
|
||||
// Ensure that the file itself is populated in case the source file is totally empty
|
||||
var root = tree.GetRoot();
|
||||
Entities.File.Create(cx, root.SyntaxTree.FilePath);
|
||||
@@ -213,7 +223,7 @@ namespace Semmle.Extraction.CSharp
|
||||
}
|
||||
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
extractor.Message(new Message($"Unhandled exception processing syntax tree. {ex.Message}", tree.FilePath, null, ex.StackTrace));
|
||||
ExtractionContext.Message(new Message($"Unhandled exception processing syntax tree. {ex.Message}", tree.FilePath, null, ex.StackTrace));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +231,7 @@ namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
try
|
||||
{
|
||||
var assemblyPath = extractor.OutputPath;
|
||||
var assemblyPath = ExtractionContext.OutputPath;
|
||||
var stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
var currentTaskId = IncrementTaskCount();
|
||||
@@ -231,11 +241,11 @@ namespace Semmle.Extraction.CSharp
|
||||
var assembly = compilation.Assembly;
|
||||
var trapWriter = transformedAssemblyPath.CreateTrapWriter(Logger, options.TrapCompression, discardDuplicates: false);
|
||||
compilationTrapFile = trapWriter; // Dispose later
|
||||
var cx = new Context(extractor, compilation, trapWriter, new AssemblyScope(assembly, assemblyPath), addAssemblyTrapPrefix);
|
||||
var cx = new Context(ExtractionContext, compilation, trapWriter, new AssemblyScope(assembly, assemblyPath), addAssemblyTrapPrefix);
|
||||
|
||||
compilationEntity = Entities.Compilation.Create(cx);
|
||||
|
||||
extractor.CompilationInfos.ForEach(ci => trapWriter.Writer.compilation_info(compilationEntity, ci.key, ci.value));
|
||||
ExtractionContext.CompilationInfos.ForEach(ci => trapWriter.Writer.compilation_info(compilationEntity, ci.key, ci.value));
|
||||
|
||||
ReportProgressTaskDone(currentTaskId, assemblyPath, trapWriter.TrapFile, stopwatch.Elapsed, AnalysisAction.Extracted);
|
||||
}
|
||||
@@ -318,7 +328,7 @@ namespace Semmle.Extraction.CSharp
|
||||
/// <summary>
|
||||
/// Number of errors encountered during extraction.
|
||||
/// </summary>
|
||||
private int ExtractorErrors => extractor?.Errors ?? 0;
|
||||
private int ExtractorErrors => ExtractionContext?.Errors ?? 0;
|
||||
|
||||
/// <summary>
|
||||
/// Number of errors encountered by the compiler.
|
||||
@@ -333,11 +343,26 @@ namespace Semmle.Extraction.CSharp
|
||||
/// <summary>
|
||||
/// Logs information about the extractor.
|
||||
/// </summary>
|
||||
public void LogExtractorInfo(string extractorVersion)
|
||||
public void LogExtractorInfo()
|
||||
{
|
||||
Logger.Log(Severity.Info, " Extractor: {0}", Environment.GetCommandLineArgs().First());
|
||||
Logger.Log(Severity.Info, " Extractor version: {0}", extractorVersion);
|
||||
Logger.Log(Severity.Info, " Extractor version: {0}", Version);
|
||||
Logger.Log(Severity.Info, " Current working directory: {0}", Directory.GetCurrentDirectory());
|
||||
}
|
||||
|
||||
private static string Version
|
||||
{
|
||||
get
|
||||
{
|
||||
// the attribute for the git information are always attached to the entry assembly by our build system
|
||||
var assembly = Assembly.GetEntryAssembly();
|
||||
var versionString = assembly?.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
|
||||
if (versionString == null)
|
||||
{
|
||||
return "unknown (not built from internal bazel workspace)";
|
||||
}
|
||||
return versionString.InformationalVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Semmle.Extraction.Entities;
|
||||
|
||||
@@ -76,8 +77,8 @@ namespace Semmle.Extraction.CSharp
|
||||
|
||||
internal CommentProcessor CommentGenerator { get; } = new CommentProcessor();
|
||||
|
||||
public Context(Extraction.Extractor e, Compilation c, TrapWriter trapWriter, IExtractionScope scope, bool addAssemblyTrapPrefix)
|
||||
: base(e, trapWriter, addAssemblyTrapPrefix)
|
||||
public Context(ExtractionContext extractionContext, Compilation c, TrapWriter trapWriter, IExtractionScope scope, bool addAssemblyTrapPrefix)
|
||||
: base(extractionContext, trapWriter, addAssemblyTrapPrefix)
|
||||
{
|
||||
Compilation = c;
|
||||
this.scope = scope;
|
||||
@@ -178,5 +179,25 @@ namespace Semmle.Extraction.CSharp
|
||||
extractedGenerics.Add(entity.Label);
|
||||
return true;
|
||||
}
|
||||
|
||||
public string TryAdjustRelativeMappedFilePath(string mappedToPath, string mappedFromPath)
|
||||
{
|
||||
if (!Path.IsPathRooted(mappedToPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
var fullPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(mappedFromPath)!, mappedToPath));
|
||||
ExtractionContext.Logger.LogDebug($"Found relative path in line mapping: '{mappedToPath}', interpreting it as '{fullPath}'");
|
||||
|
||||
mappedToPath = fullPath;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExtractionContext.Logger.LogDebug($"Failed to compute absolute path for relative path in line mapping: '{mappedToPath}': {e}");
|
||||
}
|
||||
}
|
||||
|
||||
return mappedToPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,20 +93,13 @@ namespace Semmle.Extraction.CSharp
|
||||
/// <returns><see cref="ExitCode"/></returns>
|
||||
public static ExitCode Run(string[] args)
|
||||
{
|
||||
var stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
var analyzerStopwatch = new Stopwatch();
|
||||
analyzerStopwatch.Start();
|
||||
|
||||
var options = Options.CreateWithEnvironment(args);
|
||||
var workingDirectory = Directory.GetCurrentDirectory();
|
||||
var compilerArgs = options.CompilerArguments.ToArray();
|
||||
|
||||
using var logger = MakeLogger(options.Verbosity, options.Console);
|
||||
|
||||
var canonicalPathCache = CanonicalPathCache.Create(logger, 1000);
|
||||
var pathTransformer = new PathTransformer(canonicalPathCache);
|
||||
|
||||
using var analyser = new TracingAnalyser(new LogProgressMonitor(logger), logger, options.AssemblySensitiveTrap, pathTransformer);
|
||||
|
||||
try
|
||||
{
|
||||
if (options.ProjectsToLoad.Any())
|
||||
@@ -115,13 +108,20 @@ namespace Semmle.Extraction.CSharp
|
||||
}
|
||||
|
||||
var compilerVersion = new CompilerVersion(options);
|
||||
|
||||
if (compilerVersion.SkipExtraction)
|
||||
{
|
||||
logger.Log(Severity.Warning, " Unrecognized compiler '{0}' because {1}", compilerVersion.SpecifiedCompiler, compilerVersion.SkipReason);
|
||||
return ExitCode.Ok;
|
||||
}
|
||||
|
||||
var workingDirectory = Directory.GetCurrentDirectory();
|
||||
var compilerArgs = options.CompilerArguments.ToArray();
|
||||
|
||||
var canonicalPathCache = CanonicalPathCache.Create(logger, 1000);
|
||||
var pathTransformer = new PathTransformer(canonicalPathCache);
|
||||
|
||||
using var analyser = new TracingAnalyser(new LogProgressMonitor(logger), logger, pathTransformer, canonicalPathCache, options.AssemblySensitiveTrap);
|
||||
|
||||
var compilerArguments = CSharpCommandLineParser.Default.Parse(
|
||||
compilerVersion.ArgsWithResponse,
|
||||
workingDirectory,
|
||||
@@ -144,7 +144,7 @@ namespace Semmle.Extraction.CSharp
|
||||
return ExitCode.Ok;
|
||||
}
|
||||
|
||||
return AnalyseTracing(workingDirectory, compilerArgs, analyser, compilerArguments, options, canonicalPathCache, stopwatch);
|
||||
return AnalyseTracing(workingDirectory, compilerArgs, analyser, compilerArguments, options, analyzerStopwatch);
|
||||
}
|
||||
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
@@ -226,7 +226,7 @@ namespace Semmle.Extraction.CSharp
|
||||
/// The resolved references will be added (thread-safely) to the supplied
|
||||
/// list <paramref name="ret"/>.
|
||||
/// </summary>
|
||||
private static IEnumerable<Action> ResolveReferences(Microsoft.CodeAnalysis.CommandLineArguments args, Analyser analyser, CanonicalPathCache canonicalPathCache, BlockingCollection<MetadataReference> ret)
|
||||
private static IEnumerable<Action> ResolveReferences(Microsoft.CodeAnalysis.CommandLineArguments args, Analyser analyser, BlockingCollection<MetadataReference> ret)
|
||||
{
|
||||
var referencePaths = new Lazy<string[]>(() => FixedReferencePaths(args).ToArray());
|
||||
return args.MetadataReferences.Select<CommandLineReference, Action>(clref => () =>
|
||||
@@ -235,7 +235,7 @@ namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
if (File.Exists(clref.Reference))
|
||||
{
|
||||
var reference = MakeReference(clref, canonicalPathCache.GetCanonicalPath(clref.Reference));
|
||||
var reference = MakeReference(clref, analyser.PathCache.GetCanonicalPath(clref.Reference));
|
||||
ret.Add(reference);
|
||||
}
|
||||
else
|
||||
@@ -252,7 +252,7 @@ namespace Semmle.Extraction.CSharp
|
||||
var composed = referencePaths.Value
|
||||
.Select(path => Path.Combine(path, clref.Reference))
|
||||
.Where(path => File.Exists(path))
|
||||
.Select(path => canonicalPathCache.GetCanonicalPath(path))
|
||||
.Select(path => analyser.PathCache.GetCanonicalPath(path))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (composed is not null)
|
||||
@@ -382,11 +382,10 @@ namespace Semmle.Extraction.CSharp
|
||||
TracingAnalyser analyser,
|
||||
CSharpCommandLineArguments compilerArguments,
|
||||
Options options,
|
||||
CanonicalPathCache canonicalPathCache,
|
||||
Stopwatch stopwatch)
|
||||
{
|
||||
return Analyse(stopwatch, analyser, options,
|
||||
references => ResolveReferences(compilerArguments, analyser, canonicalPathCache, references),
|
||||
references => ResolveReferences(compilerArguments, analyser, references),
|
||||
(analyser, syntaxTrees) =>
|
||||
{
|
||||
var paths = compilerArguments.SourceFiles
|
||||
@@ -399,7 +398,7 @@ namespace Semmle.Extraction.CSharp
|
||||
}
|
||||
|
||||
return ReadSyntaxTrees(
|
||||
paths.Select(canonicalPathCache.GetCanonicalPath),
|
||||
paths.Select(analyser.PathCache.GetCanonicalPath).ToHashSet(),
|
||||
analyser,
|
||||
compilerArguments.ParseOptions,
|
||||
compilerArguments.Encoding,
|
||||
|
||||
@@ -1,33 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Semmle.Util;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
public class StandaloneAnalyser : Analyser
|
||||
{
|
||||
public StandaloneAnalyser(IProgressMonitor pm, ILogger logger, bool addAssemblyTrapPrefix, PathTransformer pathTransformer)
|
||||
: base(pm, logger, addAssemblyTrapPrefix, pathTransformer)
|
||||
public StandaloneAnalyser(IProgressMonitor pm, ILogger logger, PathTransformer pathTransformer, IPathCache pathCache, bool addAssemblyTrapPrefix)
|
||||
: base(pm, logger, pathTransformer, pathCache, addAssemblyTrapPrefix)
|
||||
{
|
||||
}
|
||||
|
||||
public void Initialize(string outputPath, IEnumerable<(string, string)> compilationInfos, CSharpCompilation compilationIn, CommonOptions options)
|
||||
{
|
||||
compilation = compilationIn;
|
||||
extractor = new StandaloneExtractor(Directory.GetCurrentDirectory(), outputPath, compilationInfos, Logger, PathTransformer, options);
|
||||
ExtractionContext = new ExtractionContext(Directory.GetCurrentDirectory(), [], outputPath, compilationInfos, Logger, PathTransformer, ExtractorMode.Standalone, options.QlTest);
|
||||
this.options = options;
|
||||
LogExtractorInfo(Extraction.Extractor.Version);
|
||||
LogExtractorInfo();
|
||||
SetReferencePaths();
|
||||
}
|
||||
|
||||
#nullable disable warnings
|
||||
|
||||
public IEnumerable<string> MissingTypes => extractor.MissingTypes;
|
||||
|
||||
public IEnumerable<string> MissingNamespaces => extractor.MissingNamespaces;
|
||||
|
||||
#nullable restore warnings
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
private bool init;
|
||||
|
||||
public TracingAnalyser(IProgressMonitor pm, ILogger logger, bool addAssemblyTrapPrefix, PathTransformer pathTransformer)
|
||||
: base(pm, logger, addAssemblyTrapPrefix, pathTransformer)
|
||||
public TracingAnalyser(IProgressMonitor pm, ILogger logger, PathTransformer pathTransformer, IPathCache pathCache, bool addAssemblyTrapPrefix)
|
||||
: base(pm, logger, pathTransformer, pathCache, addAssemblyTrapPrefix)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -25,7 +25,8 @@ namespace Semmle.Extraction.CSharp
|
||||
/// <returns>A Boolean indicating whether to proceed with extraction.</returns>
|
||||
public bool BeginInitialize(IEnumerable<string> roslynArgs)
|
||||
{
|
||||
return init = LogRoslynArgs(roslynArgs, Extraction.Extractor.Version);
|
||||
LogExtractorInfo();
|
||||
return init = LogRoslynArgs(roslynArgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -46,12 +47,12 @@ namespace Semmle.Extraction.CSharp
|
||||
throw new InternalError("EndInitialize called without BeginInitialize returning true");
|
||||
this.options = options;
|
||||
this.compilation = compilation;
|
||||
this.extractor = new TracingExtractor(cwd, args, GetOutputName(compilation, commandLineArguments), Logger, PathTransformer, options);
|
||||
LogDiagnostics();
|
||||
this.ExtractionContext = new ExtractionContext(cwd, args, GetOutputName(compilation, commandLineArguments), [], Logger, PathTransformer, ExtractorMode.None, options.QlTest);
|
||||
var errorCount = LogDiagnostics();
|
||||
|
||||
SetReferencePaths();
|
||||
|
||||
CompilationErrors += FilteredDiagnostics.Count();
|
||||
CompilationErrors += errorCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -59,9 +60,8 @@ namespace Semmle.Extraction.CSharp
|
||||
/// </summary>
|
||||
/// <param name="roslynArgs">The arguments passed to Roslyn.</param>
|
||||
/// <returns>A Boolean indicating whether the same arguments have been logged previously.</returns>
|
||||
private bool LogRoslynArgs(IEnumerable<string> roslynArgs, string extractorVersion)
|
||||
private bool LogRoslynArgs(IEnumerable<string> roslynArgs)
|
||||
{
|
||||
LogExtractorInfo(extractorVersion);
|
||||
Logger.Log(Severity.Info, $" Arguments to Roslyn: {string.Join(' ', roslynArgs)}");
|
||||
|
||||
var tempFile = Extractor.GetCSharpArgsLogPath(Path.GetRandomFileName());
|
||||
@@ -137,27 +137,27 @@ namespace Semmle.Extraction.CSharp
|
||||
return Path.Combine(commandLineArguments.OutputDirectory, commandLineArguments.OutputFileName);
|
||||
}
|
||||
|
||||
#nullable disable warnings
|
||||
|
||||
/// <summary>
|
||||
/// Logs detailed information about this invocation,
|
||||
/// in the event that errors were detected.
|
||||
/// </summary>
|
||||
/// <returns>A Boolean indicating whether to proceed with extraction.</returns>
|
||||
private void LogDiagnostics()
|
||||
private int LogDiagnostics()
|
||||
{
|
||||
foreach (var error in FilteredDiagnostics)
|
||||
var filteredDiagnostics = compilation!
|
||||
.GetDiagnostics()
|
||||
.Where(e => e.Severity >= DiagnosticSeverity.Error && !errorsToIgnore.Contains(e.Id))
|
||||
.ToList();
|
||||
|
||||
foreach (var error in filteredDiagnostics)
|
||||
{
|
||||
Logger.Log(Severity.Error, " Compilation error: {0}", error);
|
||||
}
|
||||
|
||||
if (FilteredDiagnostics.Any())
|
||||
if (filteredDiagnostics.Count != 0)
|
||||
{
|
||||
foreach (var reference in compilation.References)
|
||||
{
|
||||
Logger.Log(Severity.Info, " Resolved reference {0}", reference.Display);
|
||||
}
|
||||
}
|
||||
|
||||
return filteredDiagnostics.Count;
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> errorsToIgnore = new HashSet<string>
|
||||
@@ -166,17 +166,5 @@ namespace Semmle.Extraction.CSharp
|
||||
"CS1589", // XML referencing not supported
|
||||
"CS1569" // Error writing XML documentation
|
||||
};
|
||||
|
||||
private IEnumerable<Diagnostic> FilteredDiagnostics
|
||||
{
|
||||
get
|
||||
{
|
||||
return extractor is null || extractor.Mode.HasFlag(ExtractorMode.Standalone) || compilation is null ? Enumerable.Empty<Diagnostic>() :
|
||||
compilation.
|
||||
GetDiagnostics().
|
||||
Where(e => e.Severity >= DiagnosticSeverity.Error && !errorsToIgnore.Contains(e.Id));
|
||||
}
|
||||
}
|
||||
#nullable restore warnings
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ codeql_xunit_test(
|
||||
name = "Semmle.Extraction.Tests",
|
||||
srcs = glob([
|
||||
"*.cs",
|
||||
"Properties/*.cs",
|
||||
]),
|
||||
deps = [
|
||||
"//csharp/extractor/Semmle.Extraction",
|
||||
|
||||
@@ -15,7 +15,6 @@ codeql_csharp_library(
|
||||
srcs = glob([
|
||||
"Entities/**/*.cs",
|
||||
"Extractor/**/*.cs",
|
||||
"Properties/*.cs",
|
||||
"*.cs",
|
||||
]),
|
||||
# enable via -c dbg on the bazel command line/in .bazelrc.local
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Semmle.Extraction
|
||||
/// <summary>
|
||||
/// Access various extraction functions, e.g. logger, trap writer.
|
||||
/// </summary>
|
||||
public Extractor Extractor { get; }
|
||||
public ExtractionContext ExtractionContext { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Access to the trap file.
|
||||
@@ -51,7 +51,7 @@ namespace Semmle.Extraction
|
||||
try
|
||||
{
|
||||
writingLabel = true;
|
||||
entity.DefineLabel(TrapWriter.Writer, Extractor);
|
||||
entity.DefineLabel(TrapWriter.Writer);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -190,9 +190,9 @@ namespace Semmle.Extraction
|
||||
}
|
||||
}
|
||||
|
||||
protected Context(Extractor extractor, TrapWriter trapWriter, bool shouldAddAssemblyTrapPrefix = false)
|
||||
protected Context(ExtractionContext extractionContext, TrapWriter trapWriter, bool shouldAddAssemblyTrapPrefix = false)
|
||||
{
|
||||
Extractor = extractor;
|
||||
ExtractionContext = extractionContext;
|
||||
TrapWriter = trapWriter;
|
||||
ShouldAddAssemblyTrapPrefix = shouldAddAssemblyTrapPrefix;
|
||||
}
|
||||
@@ -274,7 +274,7 @@ namespace Semmle.Extraction
|
||||
|
||||
bool duplicationGuard, deferred;
|
||||
|
||||
if (Extractor.Mode is ExtractorMode.Standalone)
|
||||
if (ExtractionContext.Mode is ExtractorMode.Standalone)
|
||||
{
|
||||
duplicationGuard = false;
|
||||
deferred = false;
|
||||
@@ -398,7 +398,7 @@ namespace Semmle.Extraction
|
||||
private void ExtractionError(Message msg)
|
||||
{
|
||||
new ExtractionMessage(this, msg);
|
||||
Extractor.Message(msg);
|
||||
ExtractionContext.Message(msg);
|
||||
}
|
||||
|
||||
private void ExtractionError(InternalError error)
|
||||
@@ -408,7 +408,7 @@ namespace Semmle.Extraction
|
||||
|
||||
private void ReportError(InternalError error)
|
||||
{
|
||||
if (!Extractor.Mode.HasFlag(ExtractorMode.Standalone))
|
||||
if (!ExtractionContext.Mode.HasFlag(ExtractorMode.Standalone))
|
||||
throw error;
|
||||
|
||||
ExtractionError(error);
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Semmle.Extraction
|
||||
|
||||
public abstract TrapStackBehaviour TrapStackBehaviour { get; }
|
||||
|
||||
public void DefineLabel(TextWriter trapFile, Extractor extractor)
|
||||
public void DefineLabel(TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteLabel(this);
|
||||
trapFile.Write("=");
|
||||
@@ -40,7 +40,7 @@ namespace Semmle.Extraction
|
||||
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
trapFile.WriteLine("\"");
|
||||
extractor.Message(new Message($"Unhandled exception generating id: {ex.Message}", ToString() ?? "", null, ex.StackTrace));
|
||||
Context.ExtractionContext.Message(new Message($"Unhandled exception generating id: {ex.Message}", ToString() ?? "", null, ex.StackTrace));
|
||||
}
|
||||
trapFile.WriteLine();
|
||||
}
|
||||
|
||||
@@ -48,6 +48,6 @@ namespace Semmle.Extraction
|
||||
/// </summary>
|
||||
TrapStackBehaviour TrapStackBehaviour { get; }
|
||||
|
||||
void DefineLabel(TextWriter trapFile, Extractor extractor);
|
||||
void DefineLabel(TextWriter trapFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Semmle.Extraction.Entities
|
||||
{
|
||||
if (messageCount == limit + 1)
|
||||
{
|
||||
Context.Extractor.Logger.LogWarning($"Stopped logging extractor messages after reaching {limit}");
|
||||
Context.ExtractionContext.Logger.LogWarning($"Stopped logging extractor messages after reaching {limit}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Semmle.Extraction.Entities
|
||||
: base(cx, path)
|
||||
{
|
||||
originalPath = path;
|
||||
transformedPathLazy = new Lazy<PathTransformer.ITransformedPath>(() => Context.Extractor.PathTransformer.Transform(originalPath));
|
||||
transformedPathLazy = new Lazy<PathTransformer.ITransformedPath>(() => Context.ExtractionContext.PathTransformer.Transform(originalPath));
|
||||
}
|
||||
|
||||
protected readonly string originalPath;
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using Semmle.Util.Logging;
|
||||
using CompilationInfo = (string key, string value);
|
||||
|
||||
@@ -9,20 +7,18 @@ namespace Semmle.Extraction
|
||||
/// <summary>
|
||||
/// Implementation of the main extractor state.
|
||||
/// </summary>
|
||||
public abstract class Extractor
|
||||
public class ExtractionContext
|
||||
{
|
||||
public string Cwd { get; init; }
|
||||
public string[] Args { get; init; }
|
||||
public abstract ExtractorMode Mode { get; }
|
||||
public ExtractorMode Mode { get; }
|
||||
public string OutputPath { get; }
|
||||
public IEnumerable<CompilationInfo> CompilationInfos { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new extractor instance for one compilation unit.
|
||||
/// </summary>
|
||||
/// <param name="logger">The object used for logging.</param>
|
||||
/// <param name="pathTransformer">The object used for path transformations.</param>
|
||||
protected Extractor(string cwd, string[] args, string outputPath, IEnumerable<CompilationInfo> compilationInfos, ILogger logger, PathTransformer pathTransformer)
|
||||
public ExtractionContext(string cwd, string[] args, string outputPath, IEnumerable<CompilationInfo> compilationInfos, ILogger logger, PathTransformer pathTransformer, ExtractorMode mode, bool isQlTest)
|
||||
{
|
||||
OutputPath = outputPath;
|
||||
Logger = logger;
|
||||
@@ -30,6 +26,12 @@ namespace Semmle.Extraction
|
||||
CompilationInfos = compilationInfos;
|
||||
Cwd = cwd;
|
||||
Args = args;
|
||||
|
||||
Mode = mode;
|
||||
if (isQlTest)
|
||||
{
|
||||
Mode |= ExtractorMode.QlTest;
|
||||
}
|
||||
}
|
||||
|
||||
// Limit the number of error messages in the log file
|
||||
@@ -107,21 +109,6 @@ namespace Semmle.Extraction
|
||||
|
||||
public ILogger Logger { get; private set; }
|
||||
|
||||
public static string Version
|
||||
{
|
||||
get
|
||||
{
|
||||
// the attribute for the git information are always attached to the entry assembly by our build system
|
||||
var assembly = Assembly.GetEntryAssembly();
|
||||
var versionString = assembly?.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
|
||||
if (versionString == null)
|
||||
{
|
||||
return "unknown (not built from internal bazel workspace)";
|
||||
}
|
||||
return versionString.InformationalVersion;
|
||||
}
|
||||
}
|
||||
|
||||
public PathTransformer PathTransformer { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Semmle.Util.Logging;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
{
|
||||
public class StandaloneExtractor : Extractor
|
||||
{
|
||||
public override ExtractorMode Mode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new extractor instance for one compilation unit.
|
||||
/// </summary>
|
||||
/// <param name="logger">The object used for logging.</param>
|
||||
/// <param name="pathTransformer">The object used for path transformations.</param>
|
||||
public StandaloneExtractor(string cwd, string outputPath, IEnumerable<(string, string)> compilationInfos, ILogger logger, PathTransformer pathTransformer, CommonOptions options)
|
||||
: base(cwd, [], outputPath, compilationInfos, logger, pathTransformer)
|
||||
{
|
||||
Mode = ExtractorMode.Standalone;
|
||||
if (options.QlTest)
|
||||
{
|
||||
Mode |= ExtractorMode.QlTest;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user