Compare commits

..

4 Commits

Author SHA1 Message Date
Nicolas Will
157a1550e0 Fix Micronaut local threat model value flow test 2026-02-27 17:31:52 +01:00
Nicolas Will
3869abebea Fix Micronaut ql-for-ql alerts 2026-02-27 17:24:02 +01:00
Nicolas Will
ededc8c676 Create 2026-02-27-micronaut.md 2026-02-27 17:22:06 +01:00
Nicolas Will
cf31af77c9 Add Micronaut framework support for Java QL
Add CodeQL support for Micronaut: add MaD models for HTTP, HTTP client and multipart (sources, sinks and summary propagation), new framework QLL modules (Controller, WebSocket, Config, Data, Security). Add library tests and query tests exercising request inputs, file uploads, HttpClient sinks (SSRF), header sinks (response-splitting) and redirect sinks (open-redirect), plus expected results and extractor options. Include Micronaut 4.x stubs used by the tests.
2026-02-27 17:17:07 +01:00
1189 changed files with 61868 additions and 90461 deletions

View File

@@ -20,10 +20,10 @@ bazel_dep(name = "rules_go", version = "0.59.0")
bazel_dep(name = "rules_java", version = "9.0.3")
bazel_dep(name = "rules_pkg", version = "1.0.1")
bazel_dep(name = "rules_nodejs", version = "6.7.3")
bazel_dep(name = "rules_python", version = "1.9.0")
bazel_dep(name = "rules_python", version = "0.40.0")
bazel_dep(name = "rules_shell", version = "0.5.0")
bazel_dep(name = "bazel_skylib", version = "1.8.1")
bazel_dep(name = "abseil-cpp", version = "20260107.1", repo_name = "absl")
bazel_dep(name = "abseil-cpp", version = "20240116.1", repo_name = "absl")
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
bazel_dep(name = "fmt", version = "12.1.0-codeql.1")
bazel_dep(name = "rules_kotlin", version = "2.2.2-codeql.1")
@@ -31,7 +31,7 @@ bazel_dep(name = "gazelle", version = "0.47.0")
bazel_dep(name = "rules_dotnet", version = "0.21.5-codeql.1")
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
bazel_dep(name = "rules_rust", version = "0.68.1.codeql.1")
bazel_dep(name = "zstd", version = "1.5.7.bcr.1")
bazel_dep(name = "zstd", version = "1.5.5.bcr.1")
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)

View File

@@ -1,7 +1,3 @@
## 0.4.29
No user-facing changes.
## 0.4.28
No user-facing changes.

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.4.29
lastReleaseVersion: 0.4.28

View File

@@ -1,5 +1,5 @@
name: codeql/actions-all
version: 0.4.30-dev
version: 0.4.29-dev
library: true
warnOnImplicitThis: true
dependencies:

View File

@@ -1,7 +1,3 @@
## 0.6.21
No user-facing changes.
## 0.6.20
No user-facing changes.

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.6.21
lastReleaseVersion: 0.6.20

View File

@@ -1,5 +1,5 @@
name: codeql/actions-queries
version: 0.6.22-dev
version: 0.6.21-dev
library: false
warnOnImplicitThis: true
groups: [actions, queries]

View File

@@ -1,21 +0,0 @@
class Element extends @element {
string toString() { none() }
}
class Trap extends @trap {
string toString() { none() }
}
class Tag extends @tag {
string toString() { none() }
}
from Element e, Trap trap
where
in_trap_or_tag(e, trap)
or
exists(Tag tag |
in_trap_or_tag(e, tag) and
trap_uses_tag(trap, tag)
)
select e, trap

View File

@@ -1,13 +0,0 @@
class SourceFile extends @source_file {
string toString() { none() }
}
class Trap extends @trap {
string toString() { none() }
}
from SourceFile source_file, string name, Trap trap
where
source_file_uses_trap(source_file, trap) and
source_file_name(source_file, name)
select name, trap

View File

@@ -1,8 +0,0 @@
description: Add source_file_name
compatibility: backwards
source_file_uses_trap.rel: run source_file_uses_trap.ql
source_file_name.rel: delete
tag_name.rel: delete
trap_uses_tag.rel: delete
in_trap.rel: run in_trap.ql
in_trap_or_tag.rel: delete

View File

@@ -1,18 +1,3 @@
## 8.0.0
### Breaking Changes
* CodeQL version 2.24.2 accidentally introduced a syntactical breaking change to `BarrierGuard<...>::getAnIndirectBarrierNode` and `InstructionBarrierGuard<...>::getAnIndirectBarrierNode`. These breaking changes have now been reverted so that the original code compiles again.
* `MustFlow`, the inter-procedural must-flow data flow analysis library, has been re-worked to use parameterized modules. Like in the case of data flow and taint tracking, instead of extending the `MustFlowConfiguration` class, the user should now implement a module with the `MustFlow::ConfigSig` signature, and instantiate the `MustFlow::Global` parameterized module with the implemented module.
### Minor Analysis Improvements
* Refactored the "Year field changed using an arithmetic operation without checking for leap year" query (`cpp/leap-year/unchecked-after-arithmetic-year-modification`) to address large numbers of false positive results.
### Bug Fixes
* The `allowInterproceduralFlow` predicate of must-flow data flow configurations now correctly handles direct recursion.
## 7.1.1
### Minor Analysis Improvements

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Refactored the "Year field changed using an arithmetic operation without checking for leap year" query (`cpp/leap-year/unchecked-after-arithmetic-year-modification`) to address large numbers of false positive results.

View File

@@ -0,0 +1,4 @@
---
category: fix
---
* The `allowInterproceduralFlow` predicate of must-flow data flow configurations now correctly handles direct recursion.

View File

@@ -0,0 +1,4 @@
---
category: breaking
---
* `MustFlow`, the inter-procedural must-flow data flow analysis library, has been re-worked to use parameterized modules. Like in the case of data flow and taint tracking, instead of extending the `MustFlowConfiguration` class, the user should now implement a module with the `MustFlow::ConfigSig` signature, and instantiate the `MustFlow::Global` parameterized module with the implemented module.

View File

@@ -0,0 +1,4 @@
---
category: breaking
---
* CodeQL version 2.24.2 accidentially introduced a syntactical breaking change to `BarrierGuard<...>::getAnIndirectBarrierNode` and `InstructionBarrierGuard<...>::getAnIndirectBarrierNode`. These breaking changes have now been reverted so that the original code compiles again.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Inline expectations test comments, which are of the form `// $ tag` or `// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.

View File

@@ -1,14 +0,0 @@
## 8.0.0
### Breaking Changes
* CodeQL version 2.24.2 accidentally introduced a syntactical breaking change to `BarrierGuard<...>::getAnIndirectBarrierNode` and `InstructionBarrierGuard<...>::getAnIndirectBarrierNode`. These breaking changes have now been reverted so that the original code compiles again.
* `MustFlow`, the inter-procedural must-flow data flow analysis library, has been re-worked to use parameterized modules. Like in the case of data flow and taint tracking, instead of extending the `MustFlowConfiguration` class, the user should now implement a module with the `MustFlow::ConfigSig` signature, and instantiate the `MustFlow::Global` parameterized module with the implemented module.
### Minor Analysis Improvements
* Refactored the "Year field changed using an arithmetic operation without checking for leap year" query (`cpp/leap-year/unchecked-after-arithmetic-year-modification`) to address large numbers of false positive results.
### Bug Fixes
* The `allowInterproceduralFlow` predicate of must-flow data flow configurations now correctly handles direct recursion.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 8.0.0
lastReleaseVersion: 7.1.1

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 8.0.1-dev
version: 7.1.2-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

@@ -555,7 +555,6 @@ private Locatable getSupportedFunctionTemplateArgument(Function templateFunction
* Normalize the `n`'th parameter of `f` by replacing template names
* with `func:N` (where `N` is the index of the template).
*/
pragma[nomagic]
private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remaining) {
exists(Function templateFunction |
templateFunction = getFullyTemplatedFunction(f) and

View File

@@ -201,7 +201,7 @@ module SourceSinkInterpretationInput implements
string toString() {
result = this.asElement().toString()
or
result = this.asNode().toStringImpl()
result = this.asNode().toString()
or
result = this.asCall().toString()
}

View File

@@ -1,6 +1,5 @@
private import cpp as Cpp
private import DataFlowUtil
private import DataFlowNodes
private import semmle.code.cpp.ir.IR
private import DataFlowDispatch
private import semmle.code.cpp.ir.internal.IRCppLanguage
@@ -17,42 +16,28 @@ private import semmle.code.cpp.dataflow.ExternalFlow as External
cached
private module Cached {
cached
newtype TIRDataFlowNode0 =
TInstructionNode0(Instruction i) {
not Ssa::ignoreInstruction(i) and
not exists(Operand op |
not Ssa::ignoreOperand(op) and i = Ssa::getIRRepresentationOfOperand(op)
) and
// We exclude `void`-typed instructions because they cannot contain data.
// However, if the instruction is a glvalue, and their type is `void`, then the result
// type of the instruction is really `void*`, and thus we still want to have a dataflow
// node for it.
(not i.getResultType() instanceof VoidType or i.isGLValue())
} or
TMultipleUseOperandNode0(Operand op) {
not Ssa::ignoreOperand(op) and not exists(Ssa::getIRRepresentationOfOperand(op))
} or
TSingleUseOperandNode0(Operand op) {
not Ssa::ignoreOperand(op) and exists(Ssa::getIRRepresentationOfOperand(op))
}
cached
string toStringCached(Node n) {
result = toExprString(n)
or
not exists(toExprString(n)) and
result = n.toStringImpl()
module Nodes0 {
cached
newtype TIRDataFlowNode0 =
TInstructionNode0(Instruction i) {
not Ssa::ignoreInstruction(i) and
not exists(Operand op |
not Ssa::ignoreOperand(op) and i = Ssa::getIRRepresentationOfOperand(op)
) and
// We exclude `void`-typed instructions because they cannot contain data.
// However, if the instruction is a glvalue, and their type is `void`, then the result
// type of the instruction is really `void*`, and thus we still want to have a dataflow
// node for it.
(not i.getResultType() instanceof VoidType or i.isGLValue())
} or
TMultipleUseOperandNode0(Operand op) {
not Ssa::ignoreOperand(op) and not exists(Ssa::getIRRepresentationOfOperand(op))
} or
TSingleUseOperandNode0(Operand op) {
not Ssa::ignoreOperand(op) and exists(Ssa::getIRRepresentationOfOperand(op))
}
}
cached
Location getLocationCached(Node n) { result = n.getLocationImpl() }
cached
newtype TContentApprox =
TFieldApproxContent(string s) { fieldHasApproxName(_, s) } or
TUnionApproxContent(string s) { unionHasApproxName(_, s) } or
TElementApproxContent()
/**
* Gets an additional term that is added to the `join` and `branch` computations to reflect
* an additional forward or backwards branching factor that is not taken into account
@@ -74,174 +59,38 @@ private module Cached {
result = countNumberOfBranchesUsingParameter(switch, p)
)
}
cached
newtype TDataFlowCallable =
TSourceCallable(Cpp::Declaration decl) or
TSummarizedCallable(FlowSummaryImpl::Public::SummarizedCallable c)
cached
newtype TDataFlowCall =
TNormalCall(CallInstruction call) or
TSummaryCall(
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
) {
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
}
/**
* Holds if data can flow from `node1` to `node2` in a way that loses the
* calling context. For example, this would happen with flow through a
* global or static variable.
*/
cached
predicate jumpStep(Node n1, Node n2) {
exists(GlobalLikeVariable v |
exists(Ssa::GlobalUse globalUse |
v = globalUse.getVariable() and
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
v = n2.asVariable()
or
v = n2.asIndirectVariable(globalUse.getIndirection())
)
or
exists(Ssa::GlobalDef globalDef |
v = globalDef.getVariable() and
n2.(InitialGlobalValue).getGlobalDef() = globalDef
|
globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
v = n1.asVariable()
or
v = n1.asIndirectVariable(globalDef.getIndirection())
)
)
or
// models-as-data summarized flow
FlowSummaryImpl::Private::Steps::summaryJumpStep(n1.(FlowSummaryNode).getSummaryNode(),
n2.(FlowSummaryNode).getSummaryNode())
}
/**
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
* Thus, `node2` references an object with a field `f` that contains the
* value of `node1`.
*
* The boolean `certain` is true if the destination address does not involve
* any pointer arithmetic, and false otherwise.
*/
cached
predicate storeStepImpl(Node node1, Content c, Node node2, boolean certain) {
exists(
PostFieldUpdateNode postFieldUpdate, int indirectionIndex1, int numberOfLoads,
StoreInstruction store, FieldContent fc
|
postFieldUpdate = node2 and
fc = c and
nodeHasInstruction(node1, pragma[only_bind_into](store),
pragma[only_bind_into](indirectionIndex1)) and
postFieldUpdate.getIndirectionIndex() = 1 and
numberOfLoadsFromOperand(postFieldUpdate.getFieldAddress(),
store.getDestinationAddressOperand(), numberOfLoads, certain) and
fc.getAField() = postFieldUpdate.getUpdatedField() and
getIndirectionIndexLate(fc) = 1 + indirectionIndex1 + numberOfLoads
)
or
// models-as-data summarized flow
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
node2.(FlowSummaryNode).getSummaryNode()) and
certain = true
}
/**
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
* Thus, `node2` references an object with a field `f` that contains the
* value of `node1`.
*/
cached
predicate storeStep(Node node1, ContentSet c, Node node2) { storeStepImpl(node1, c, node2, _) }
/**
* Holds if data can flow from `node1` to `node2` via a read of `f`.
* Thus, `node1` references an object with a field `f` whose value ends up in
* `node2`.
*/
cached
predicate readStep(Node node1, ContentSet c, Node node2) {
exists(
FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2, FieldContent fc
|
fc = c and
nodeHasOperand(node2, operand, indirectionIndex2) and
// The `1` here matches the `node2.getIndirectionIndex() = 1` conjunct
// in `storeStep`.
nodeHasOperand(node1, fa1.getObjectAddressOperand(), 1) and
numberOfLoadsFromOperand(fa1, operand, numberOfLoads, _) and
fc.getAField() = fa1.getField() and
getIndirectionIndexLate(fc) = indirectionIndex2 + numberOfLoads
)
or
// models-as-data summarized flow
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c,
node2.(FlowSummaryNode).getSummaryNode())
}
/**
* Holds if values stored inside content `c` are cleared at node `n`.
*/
cached
predicate clearsContent(Node n, ContentSet c) {
n =
any(PostUpdateNode pun, Content d |
d.impliesClearOf(c) and storeStepImpl(_, d, pun, true)
|
pun
).getPreUpdateNode() and
(
not exists(Operand op, Cpp::Operation p |
n.(IndirectOperand).hasOperandAndIndirectionIndex(op, _) and
(
p instanceof Cpp::AssignPointerAddExpr or
p instanceof Cpp::AssignPointerSubExpr or
p instanceof Cpp::CrementOperation
)
|
p.getAnOperand() = op.getUse().getAst()
)
or
forex(PostUpdateNode pun, Content d |
pragma[only_bind_into](d).impliesClearOf(pragma[only_bind_into](c)) and
storeStepImpl(_, d, pun, true) and
pun.getPreUpdateNode() = n
|
c.(Content).getIndirectionIndex() = d.getIndirectionIndex()
)
)
}
}
import Cached
private int getNumberOfIndirections(Node n) {
result = n.(RawIndirectOperand).getIndirectionIndex()
or
result = n.(RawIndirectInstruction).getIndirectionIndex()
or
result = n.(VariableNode).getIndirectionIndex()
or
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
or
result = n.(FinalParameterNode).getIndirectionIndex()
or
result = n.(BodyLessParameterNodeImpl).getIndirectionIndex()
}
private import Nodes0
/**
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
* output for `n`.
* A module for calculating the number of stars (i.e., `*`s) needed for various
* dataflow node `toString` predicates.
*/
string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
module NodeStars {
private int getNumberOfIndirections(Node n) {
result = n.(RawIndirectOperand).getIndirectionIndex()
or
result = n.(RawIndirectInstruction).getIndirectionIndex()
or
result = n.(VariableNode).getIndirectionIndex()
or
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
or
result = n.(FinalParameterNode).getIndirectionIndex()
or
result = n.(BodyLessParameterNodeImpl).getIndirectionIndex()
}
/**
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
* output for `n`.
*/
string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
}
import NodeStars
/**
* A cut-down `DataFlow::Node` class that does not depend on the output of SSA.
@@ -979,10 +828,85 @@ private int getMinIndirectionForGlobalDef(Ssa::GlobalDef def) {
result = getMinIndirectionsForType(def.getUnspecifiedType())
}
/**
* Holds if data can flow from `node1` to `node2` in a way that loses the
* calling context. For example, this would happen with flow through a
* global or static variable.
*/
predicate jumpStep(Node n1, Node n2) {
exists(GlobalLikeVariable v |
exists(Ssa::GlobalUse globalUse |
v = globalUse.getVariable() and
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
v = n2.asVariable()
or
v = n2.asIndirectVariable(globalUse.getIndirection())
)
or
exists(Ssa::GlobalDef globalDef |
v = globalDef.getVariable() and
n2.(InitialGlobalValue).getGlobalDef() = globalDef
|
globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
v = n1.asVariable()
or
v = n1.asIndirectVariable(globalDef.getIndirection())
)
)
or
// models-as-data summarized flow
FlowSummaryImpl::Private::Steps::summaryJumpStep(n1.(FlowSummaryNode).getSummaryNode(),
n2.(FlowSummaryNode).getSummaryNode())
}
bindingset[c]
pragma[inline_late]
private int getIndirectionIndexLate(Content c) { result = c.getIndirectionIndex() }
/**
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
* Thus, `node2` references an object with a field `f` that contains the
* value of `node1`.
*
* The boolean `certain` is true if the destination address does not involve
* any pointer arithmetic, and false otherwise. This has to do with whether a
* store step can be used to clear a field (see `clearsContent`).
*/
predicate storeStepImpl(Node node1, Content c, Node node2, boolean certain) {
exists(
PostFieldUpdateNode postFieldUpdate, int indirectionIndex1, int numberOfLoads,
StoreInstruction store, FieldContent fc
|
postFieldUpdate = node2 and
fc = c and
nodeHasInstruction(node1, pragma[only_bind_into](store),
pragma[only_bind_into](indirectionIndex1)) and
postFieldUpdate.getIndirectionIndex() = 1 and
numberOfLoadsFromOperand(postFieldUpdate.getFieldAddress(),
store.getDestinationAddressOperand(), numberOfLoads, certain) and
fc.getAField() = postFieldUpdate.getUpdatedField() and
getIndirectionIndexLate(fc) = 1 + indirectionIndex1 + numberOfLoads
)
or
// models-as-data summarized flow
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
node2.(FlowSummaryNode).getSummaryNode()) and
certain = true
}
/**
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
* Thus, `node2` references an object with a field `f` that contains the
* value of `node1`.
*/
predicate storeStep(Node node1, ContentSet c, Node node2) { storeStepImpl(node1, c, node2, _) }
/**
* Holds if `operandFrom` flows to `operandTo` using a sequence of conversion-like
* operations and exactly `n` `LoadInstruction` operations.
*/
private predicate numberOfLoadsFromOperandRec(
Operand operandFrom, Operand operandTo, int ind, boolean certain
) {
@@ -1033,6 +957,63 @@ predicate nodeHasInstruction(Node node, Instruction instr, int indirectionIndex)
hasInstructionAndIndex(node, instr, indirectionIndex)
}
/**
* Holds if data can flow from `node1` to `node2` via a read of `f`.
* Thus, `node1` references an object with a field `f` whose value ends up in
* `node2`.
*/
predicate readStep(Node node1, ContentSet c, Node node2) {
exists(
FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2, FieldContent fc
|
fc = c and
nodeHasOperand(node2, operand, indirectionIndex2) and
// The `1` here matches the `node2.getIndirectionIndex() = 1` conjunct
// in `storeStep`.
nodeHasOperand(node1, fa1.getObjectAddressOperand(), 1) and
numberOfLoadsFromOperand(fa1, operand, numberOfLoads, _) and
fc.getAField() = fa1.getField() and
getIndirectionIndexLate(fc) = indirectionIndex2 + numberOfLoads
)
or
// models-as-data summarized flow
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c,
node2.(FlowSummaryNode).getSummaryNode())
}
/**
* Holds if values stored inside content `c` are cleared at node `n`.
*/
predicate clearsContent(Node n, ContentSet c) {
n =
any(PostUpdateNode pun, Content d | d.impliesClearOf(c) and storeStepImpl(_, d, pun, true) | pun)
.getPreUpdateNode() and
(
// The crement operations and pointer addition and subtraction self-assign. We do not
// want to clear the contents if it is indirectly pointed at by any of these operations,
// as part of the contents might still be accessible afterwards. If there is no such
// indirection clearing the contents is safe.
not exists(Operand op, Cpp::Operation p |
n.(IndirectOperand).hasOperandAndIndirectionIndex(op, _) and
(
p instanceof Cpp::AssignPointerAddExpr or
p instanceof Cpp::AssignPointerSubExpr or
p instanceof Cpp::CrementOperation
)
|
p.getAnOperand() = op.getUse().getAst()
)
or
forex(PostUpdateNode pun, Content d |
pragma[only_bind_into](d).impliesClearOf(pragma[only_bind_into](c)) and
storeStepImpl(_, d, pun, true) and
pun.getPreUpdateNode() = n
|
c.(Content).getIndirectionIndex() = d.getIndirectionIndex()
)
)
}
/**
* Holds if the value that is being tracked is expected to be stored inside content `c`
* at node `n`.
@@ -1065,6 +1046,11 @@ class CastNode extends Node {
CastNode() { none() } // stub implementation
}
cached
private newtype TDataFlowCallable =
TSourceCallable(Cpp::Declaration decl) or
TSummarizedCallable(FlowSummaryImpl::Public::SummarizedCallable c)
/**
* A callable, which may be:
* - a function (that may contain code)
@@ -1148,6 +1134,15 @@ class DataFlowType extends TypeFinal {
string toString() { result = "" }
}
cached
private newtype TDataFlowCall =
TNormalCall(CallInstruction call) or
TSummaryCall(
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
) {
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
}
private predicate summarizedCallableIsManual(SummarizedCallable sc) {
sc.asSummarizedCallable().hasManualModel()
}
@@ -1528,6 +1523,12 @@ private predicate fieldHasApproxName(Field f, string s) {
private predicate unionHasApproxName(Cpp::Union u, string s) { s = u.getName().charAt(0) }
cached
private newtype TContentApprox =
TFieldApproxContent(string s) { fieldHasApproxName(_, s) } or
TUnionApproxContent(string s) { unionHasApproxName(_, s) } or
TElementApproxContent()
/** An approximated `Content`. */
class ContentApprox extends TContentApprox {
string toString() { none() } // overridden in subclasses

View File

@@ -6,8 +6,8 @@ private import cpp
private import semmle.code.cpp.ir.IR
private import DataFlowUtil
private import DataFlowPrivate
private import DataFlowNodes
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
cached
private module Cached {
@@ -73,9 +73,17 @@ private module Cached {
// a result for `getConvertedResultExpression`. We remap this here so that
// this `ConvertInstruction` maps to the result of the expression that
// represents the extent.
result = IRConstruction::Raw::getAllocationExtentConvertExpr(instr)
exists(TranslatedNonConstantAllocationSize tas |
result = tas.getExtent().getExpr() and
instr = tas.getInstruction(AllocationExtentConvertTag())
)
or
result = IRConstruction::Raw::getTransparentConversionParenthesisExpr(instr)
// 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
@@ -104,10 +112,10 @@ private module Cached {
// 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(StoreInstruction store |
store = instr and
IRConstruction::Raw::instructionProducesExprResult(store) and
result = asDefinitionImpl0(store)
exists(TranslatedCoreExpr tco |
tco.getInstruction(_) = instr and
tco.producesExprResult() and
result = asDefinitionImpl0(instr)
)
or
// IR construction breaks an array aggregate literal `{1, 2, 3}` into a
@@ -137,9 +145,18 @@ private module Cached {
// 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.
result = IRConstruction::Raw::getAssignOperationStoreExpr(store)
exists(TranslatedAssignOperation tao |
store = tao.getInstruction(AssignmentStoreTag()) and
result = tao.getExpr()
)
or
result = IRConstruction::Raw::getCrementOperationStoreExpr(store)
// Similarly for `i++` and `++i` 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(TranslatedCrementOperation tco |
store = tco.getInstruction(CrementStoreTag()) and
result = tco.getExpr()
)
}
/**
@@ -149,7 +166,11 @@ private module Cached {
*/
private predicate excludeAsDefinitionResult(StoreInstruction store) {
// Exclude the store to the temporary generated by a ternary expression.
IRConstruction::Raw::isConditionalExprTempStore(store)
exists(TranslatedConditionalExpr tce |
store = tce.getInstruction(ConditionValueFalseStoreTag())
or
store = tce.getInstruction(ConditionValueTrueStoreTag())
)
}
/**

View File

@@ -6,7 +6,6 @@
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
private import DataFlowUtil
private import DataFlowNodes
private import DataFlowPrivate
private import SsaImpl as Ssa

View File

@@ -6,7 +6,6 @@ private import cpp
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
private import PrintIRUtilities
/** A property provider for local IR dataflow store steps. */

View File

@@ -2,7 +2,6 @@ private import cpp
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
private import SsaImpl as Ssa
private import PrintIRUtilities

View File

@@ -6,7 +6,6 @@ private import cpp
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
private Instruction getInstruction(Node n, string stars) {
result = [n.asInstruction(), n.(RawIndirectInstruction).getInstruction()] and

View File

@@ -10,9 +10,8 @@ private import semmle.code.cpp.models.interfaces.PartialFlow as PartialFlow
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as FIO
private import semmle.code.cpp.ir.internal.IRCppLanguage
private import semmle.code.cpp.ir.dataflow.internal.ModelUtil
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedInitialization
private import DataFlowPrivate
private import DataFlowNodes
import SsaImplCommon
private module SourceVariables {
@@ -439,7 +438,10 @@ private predicate sourceVariableHasBaseAndIndex(SourceVariable v, BaseSourceVari
* initialize `v`.
*/
private Instruction getInitializationTargetAddress(IRVariable v) {
result = IRConstruction::Raw::getInitializationTargetAddress(v)
exists(TranslatedVariableInitialization init |
init.getIRVariable() = v and
result = init.getTargetAddress()
)
}
/** An initial definition of an SSA variable address. */

View File

@@ -4,12 +4,47 @@ import semmle.code.cpp.ir.internal.IRCppLanguage
private import semmle.code.cpp.ir.implementation.raw.internal.SideEffects as SideEffects
private import DataFlowImplCommon as DataFlowImplCommon
private import DataFlowUtil
private import DataFlowNodes
private import semmle.code.cpp.models.interfaces.PointerWrapper
private import DataFlowPrivate
private import TypeFlow
private import semmle.code.cpp.ir.ValueNumbering
/**
* Holds if `operand` is an operand that is not used by the dataflow library.
* Ignored operands are not recognized as uses by SSA, and they don't have a
* corresponding `(Indirect)OperandNode`.
*/
predicate ignoreOperand(Operand operand) {
operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand() or
operand = any(Instruction instr | ignoreInstruction(instr)).getAUse() or
operand instanceof MemoryOperand
}
/**
* Holds if `instr` is an instruction that is not used by the dataflow library.
* Ignored instructions are not recognized as reads/writes by SSA, and they
* don't have a corresponding `(Indirect)InstructionNode`.
*/
predicate ignoreInstruction(Instruction instr) {
DataFlowImplCommon::forceCachingInSameStage() and
(
instr instanceof CallSideEffectInstruction or
instr instanceof CallReadSideEffectInstruction or
instr instanceof ExitFunctionInstruction or
instr instanceof EnterFunctionInstruction or
instr instanceof WriteSideEffectInstruction or
instr instanceof PhiInstruction or
instr instanceof ReadSideEffectInstruction or
instr instanceof ChiInstruction or
instr instanceof InitializeIndirectionInstruction or
instr instanceof AliasedDefinitionInstruction or
instr instanceof AliasedUseInstruction or
instr instanceof InitializeNonLocalInstruction or
instr instanceof ReturnIndirectionInstruction or
instr instanceof UninitializedGroupInstruction
)
}
/**
* Gets the C++ type of `this` in the member function `f`.
* The result is a glvalue if `isGLValue` is true, and
@@ -20,6 +55,26 @@ private CppType getThisType(Cpp::MemberFunction f, boolean isGLValue) {
result.hasType(f.getTypeOfThis(), isGLValue)
}
/**
* Gets the C++ type of the instruction `i`.
*
* This is equivalent to `i.getResultLanguageType()` with the exception
* of instructions that directly references a `this` IRVariable. In this
* case, `i.getResultLanguageType()` gives an unknown type, whereas the
* predicate gives the expected type (i.e., a potentially cv-qualified
* type `A*` where `A` is the declaring type of the member function that
* contains `i`).
*/
cached
CppType getResultLanguageType(Instruction i) {
if i.(VariableAddressInstruction).getIRVariable() instanceof IRThisVariable
then
if i.isGLValue()
then result = getThisType(i.getEnclosingFunction(), true)
else result = getThisType(i.getEnclosingFunction(), false)
else result = i.getResultLanguageType()
}
/**
* Gets the C++ type of the operand `operand`.
* This is equivalent to the type of the operand's defining instruction.
@@ -292,6 +347,10 @@ predicate isWrite(Node0Impl value, Operand address, boolean certain) {
)
}
predicate isAdditionalConversionFlow(Operand opFrom, Instruction instrTo) {
any(Indirection ind).isAdditionalConversionFlow(opFrom, instrTo)
}
newtype TBaseSourceVariable =
// Each IR variable gets its own source variable
TBaseIRVariable(IRVariable var) or
@@ -513,69 +572,6 @@ private class BaseCallInstruction extends BaseSourceVariableInstruction, CallIns
cached
private module Cached {
/**
* Holds if `operand` is an operand that is not used by the dataflow library.
* Ignored operands are not recognized as uses by SSA, and they don't have a
* corresponding `(Indirect)OperandNode`.
*/
cached
predicate ignoreOperand(Operand operand) {
operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand() or
operand = any(Instruction instr | ignoreInstruction(instr)).getAUse() or
operand instanceof MemoryOperand
}
/**
* Holds if `instr` is an instruction that is not used by the dataflow library.
* Ignored instructions are not recognized as reads/writes by SSA, and they
* don't have a corresponding `(Indirect)InstructionNode`.
*/
cached
predicate ignoreInstruction(Instruction instr) {
DataFlowImplCommon::forceCachingInSameStage() and
(
instr instanceof CallSideEffectInstruction or
instr instanceof CallReadSideEffectInstruction or
instr instanceof ExitFunctionInstruction or
instr instanceof EnterFunctionInstruction or
instr instanceof WriteSideEffectInstruction or
instr instanceof PhiInstruction or
instr instanceof ReadSideEffectInstruction or
instr instanceof ChiInstruction or
instr instanceof InitializeIndirectionInstruction or
instr instanceof AliasedDefinitionInstruction or
instr instanceof AliasedUseInstruction or
instr instanceof InitializeNonLocalInstruction or
instr instanceof ReturnIndirectionInstruction or
instr instanceof UninitializedGroupInstruction
)
}
cached
predicate isAdditionalConversionFlow(Operand opFrom, Instruction instrTo) {
any(Indirection ind).isAdditionalConversionFlow(opFrom, instrTo)
}
/**
* Gets the C++ type of the instruction `i`.
*
* This is equivalent to `i.getResultLanguageType()` with the exception
* of instructions that directly references a `this` IRVariable. In this
* case, `i.getResultLanguageType()` gives an unknown type, whereas the
* predicate gives the expected type (i.e., a potentially cv-qualified
* type `A*` where `A` is the declaring type of the member function that
* contains `i`).
*/
cached
CppType getResultLanguageType(Instruction i) {
if i.(VariableAddressInstruction).getIRVariable() instanceof IRThisVariable
then
if i.isGLValue()
then result = getThisType(i.getEnclosingFunction(), true)
else result = getThisType(i.getEnclosingFunction(), false)
else result = i.getResultLanguageType()
}
/** Holds if `op` is the only use of its defining instruction, and that op is used in a conversation */
private predicate isConversion(Operand op) {
exists(Instruction def, Operand use |

View File

@@ -5,81 +5,64 @@ private import semmle.code.cpp.models.interfaces.DataFlow
private import semmle.code.cpp.models.interfaces.SideEffect
private import DataFlowUtil
private import DataFlowPrivate
private import DataFlowNodes
private import SsaImpl as Ssa
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.cpp.ir.dataflow.FlowSteps
cached
private module Cached {
private import DataFlowImplCommon as DataFlowImplCommon
/**
* This predicate exists to collapse the `cached` predicates in this module with the
* `cached` predicates in other C/C++ dataflow files, which is then collapsed
* with the `cached` predicates in `DataFlowImplCommon.qll`.
*/
cached
predicate forceCachingInSameStage() { DataFlowImplCommon::forceCachingInSameStage() }
/**
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
* (intra-procedural) step. This relation is only used for local taint flow
* (for example `TaintTracking::localTaint(source, sink)`) so it may contain
* special cases that should only apply to local taint flow.
*/
cached
predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// dataflow step
DataFlow::localFlowStep(nodeFrom, nodeTo)
or
// taint flow step
localAdditionalTaintStep(nodeFrom, nodeTo, _)
or
// models-as-data summarized flow for local data flow (i.e. special case for flow
// through calls to modeled functions, without relying on global dataflow to join
// the dots).
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(nodeFrom, nodeTo, _)
}
/**
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
* different objects.
*/
cached
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, string model) {
operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction()) and
model = ""
or
modeledTaintStep(nodeFrom, nodeTo, model)
or
// Flow from (the indirection of) an operand of a pointer arithmetic instruction to the
// indirection of the pointer arithmetic instruction. This provides flow from `source`
// in `x[source]` to the result of the associated load instruction.
exists(PointerArithmeticInstruction pai, int indirectionIndex |
nodeHasOperand(nodeFrom, pai.getAnOperand(), pragma[only_bind_into](indirectionIndex)) and
hasInstructionAndIndex(nodeTo, pai, indirectionIndex + 1)
) and
model = ""
or
any(Ssa::Indirection ind).isAdditionalTaintStep(nodeFrom, nodeTo) and
model = ""
or
// models-as-data summarized flow
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode(), false, model)
or
// object->field conflation for content that is a `TaintInheritingContent`.
exists(DataFlow::ContentSet f |
readStep(nodeFrom, f, nodeTo) and
f.getAReadContent() instanceof TaintInheritingContent
) and
model = ""
}
/**
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
* (intra-procedural) step. This relation is only used for local taint flow
* (for example `TaintTracking::localTaint(source, sink)`) so it may contain
* special cases that should only apply to local taint flow.
*/
predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// dataflow step
DataFlow::localFlowStep(nodeFrom, nodeTo)
or
// taint flow step
localAdditionalTaintStep(nodeFrom, nodeTo, _)
or
// models-as-data summarized flow for local data flow (i.e. special case for flow
// through calls to modeled functions, without relying on global dataflow to join
// the dots).
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(nodeFrom, nodeTo, _)
}
import Cached
/**
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
* different objects.
*/
cached
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, string model) {
operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction()) and
model = ""
or
modeledTaintStep(nodeFrom, nodeTo, model)
or
// Flow from (the indirection of) an operand of a pointer arithmetic instruction to the
// indirection of the pointer arithmetic instruction. This provides flow from `source`
// in `x[source]` to the result of the associated load instruction.
exists(PointerArithmeticInstruction pai, int indirectionIndex |
nodeHasOperand(nodeFrom, pai.getAnOperand(), pragma[only_bind_into](indirectionIndex)) and
hasInstructionAndIndex(nodeTo, pai, indirectionIndex + 1)
) and
model = ""
or
any(Ssa::Indirection ind).isAdditionalTaintStep(nodeFrom, nodeTo) and
model = ""
or
// models-as-data summarized flow
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode(), false, model)
or
// object->field conflation for content that is a `TaintInheritingContent`.
exists(DataFlow::ContentSet f |
readStep(nodeFrom, f, nodeTo) and
f.getAReadContent() instanceof TaintInheritingContent
) and
model = ""
}
/**
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
@@ -213,7 +196,7 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut, string
// Taint flow from a pointer argument to an output, when the model specifies flow from the deref
// to that output, but the deref is not modeled in the IR for the caller.
exists(
CallInstruction call, SideEffectOperandNode indirectArgument, Function func,
CallInstruction call, DataFlow::SideEffectOperandNode indirectArgument, Function func,
FunctionInput modelIn, FunctionOutput modelOut
|
indirectArgument = callInput(call, modelIn) and

View File

@@ -15,7 +15,6 @@ private import TranslatedCall
private import TranslatedStmt
private import TranslatedFunction
private import TranslatedGlobalVar
private import TranslatedInitialization
TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
instruction = TRawInstruction(result, _)
@@ -195,89 +194,6 @@ module Raw {
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
result = getInstructionConvertedResultExpression(instruction).getUnconverted()
}
/**
* Gets the expression associated with the instruction `instr` that computes
* the `Convert` instruction on the extent expression of an allocation.
*/
cached
Expr getAllocationExtentConvertExpr(Instruction instr) {
exists(TranslatedNonConstantAllocationSize tas |
instr = tas.getInstruction(AllocationExtentConvertTag()) and
result = tas.getExtent().getExpr()
)
}
/**
* Gets the `ParenthesisExpr` associated with a transparent conversion
* instruction, if any.
*/
cached
ParenthesisExpr getTransparentConversionParenthesisExpr(Instruction instr) {
exists(TranslatedTransparentConversion ttc |
result = ttc.getExpr() and
instr = ttc.getResult()
)
}
/**
* Holds if `instr` belongs to a `TranslatedCoreExpr` that produces an
* expression result. This indicates that the instruction represents a
* definition whose result should be mapped back to the expression.
*/
cached
predicate instructionProducesExprResult(Instruction instr) {
exists(TranslatedCoreExpr tco |
tco.getInstruction(_) = instr and
tco.producesExprResult()
)
}
/**
* Gets the expression associated with a `StoreInstruction` generated
* by an `TranslatedAssignOperation`.
*/
cached
Expr getAssignOperationStoreExpr(StoreInstruction store) {
exists(TranslatedAssignOperation tao |
store = tao.getInstruction(AssignmentStoreTag()) and
result = tao.getExpr()
)
}
/**
* Gets the expression associated with a `StoreInstruction` generated
* by an `TranslatedCrementOperation`.
*/
cached
Expr getCrementOperationStoreExpr(StoreInstruction store) {
exists(TranslatedCrementOperation tco |
store = tco.getInstruction(CrementStoreTag()) and
result = tco.getExpr()
)
}
/**
* Holds if `store` is a `StoreInstruction` that defines the temporary
* `IRVariable` generated as part of the translation of a ternary expression.
*/
cached
predicate isConditionalExprTempStore(StoreInstruction store) {
exists(TranslatedConditionalExpr tce |
store = tce.getInstruction(ConditionValueFalseStoreTag())
or
store = tce.getInstruction(ConditionValueTrueStoreTag())
)
}
/** Gets the instruction that computes the address used to initialize `v`. */
cached
Instruction getInitializationTargetAddress(IRVariable v) {
exists(TranslatedVariableInitialization init |
init.getIRVariable() = v and
result = init.getTargetAddress()
)
}
}
class TStageInstruction = TRawInstruction or TRawUnreachedInstruction;

View File

@@ -245,25 +245,6 @@ trap_filename(
string filename: string ref
);
/**
* Gives the tag name for `tag`.
* For debugging only.
*/
tag_name(
int tag: @tag,
string name: string ref
);
@trap_or_tag = @tag | @trap;
/**
* Gives the name for the source file.
*/
source_file_name(
int sf: @source_file,
string name: string ref
);
/**
* In `build-mode: none` overlay mode, indicates that `source_file`
* (`/path/to/foo.c`) uses the TRAP file `trap_file`; i.e. it is the
@@ -271,25 +252,16 @@ source_file_name(
* includes, or a template instantiation it transitively uses.
*/
source_file_uses_trap(
int source_file: @source_file ref,
string source_file: string ref,
int trap_file: @trap ref
);
/**
* In `build-mode: none` overlay mode, indicates that the TRAP file
* `trap_file` uses tag `tag`.
* Holds if there is a definition of `element` in TRAP file `trap_file`.
*/
trap_uses_tag(
int trap_file: @trap ref,
int tag: @tag ref
);
/**
* Holds if there is a definition of `element` in TRAP file or tag `t`.
*/
in_trap_or_tag(
in_trap(
int element: @element ref,
int t: @trap_or_tag ref
int trap_file: @trap ref
);
pch_uses(

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +0,0 @@
class Element extends @element {
string toString() { none() }
}
class Trap extends @trap {
string toString() { none() }
}
from Element e, Trap trap
where in_trap(e, trap)
select e, trap

View File

@@ -1,22 +0,0 @@
newtype TSourceFile = MkSourceFile(string name) { source_file_uses_trap(name, _) }
module FreshSourceFile = QlBuiltins::NewEntity<TSourceFile>;
class SourceFile extends FreshSourceFile::EntityId {
string toString() { none() }
}
class Trap extends @trap {
string toString() { none() }
}
query predicate mk_source_file_name(SourceFile source_file, string name) {
source_file = FreshSourceFile::map(MkSourceFile(name))
}
query predicate mk_source_file_uses_trap(SourceFile source_file, Trap trap) {
exists(string name |
source_file_uses_trap(name, trap) and
mk_source_file_name(source_file, name)
)
}

View File

@@ -1,6 +0,0 @@
description: Add source_file_name
compatibility: backwards
source_file_uses_trap.rel: run source_files.ql mk_source_file_uses_trap
source_file_name.rel: run source_files.ql mk_source_file_name
in_trap.rel: delete
in_trap_or_tag.rel: run in_trap_or_tag.ql

View File

@@ -1,7 +1,3 @@
## 1.5.12
No user-facing changes.
## 1.5.11
No user-facing changes.

View File

@@ -15,7 +15,6 @@
import cpp
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
/** Gets a loop that contains `e`. */
Loop getAnEnclosingLoopOfExpr(Expr e) { result = getAnEnclosingLoopOfStmt(e.getEnclosingStmt()) }
@@ -46,9 +45,9 @@ private Expr getExpr(DataFlow::Node node) {
or
result = node.asOperand().getUse().getAst()
or
result = node.(RawIndirectInstruction).getInstruction().getAst()
result = node.(DataFlow::RawIndirectInstruction).getInstruction().getAst()
or
result = node.(RawIndirectOperand).getOperand().getUse().getAst()
result = node.(DataFlow::RawIndirectOperand).getOperand().getUse().getAst()
}
/**
@@ -209,7 +208,7 @@ class LoopWithAlloca extends Stmt {
this.conditionRequiresInequality(va, _, _) and
DataFlow::localFlow(result, DataFlow::exprNode(va)) and
// Phi nodes will be preceded by nodes that represent actual definitions
not result instanceof SsaSynthNode and
not result instanceof DataFlow::SsaSynthNode and
// A source is outside the loop if it's not inside the loop
not exists(Expr e | e = getExpr(result) | this = getAnEnclosingLoopOfExpr(e))
)

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.5.12
lastReleaseVersion: 1.5.11

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 1.5.13-dev
version: 1.5.12-dev
groups:
- cpp
- queries

View File

@@ -8,7 +8,6 @@ private import semmle.code.cpp.dataflow.ExternalFlow as ExternalFlow
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as DataFlowPrivate
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes as DataFlowNodes
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.cpp.ir.dataflow.internal.TaintTrackingImplSpecific
private import semmle.code.cpp.dataflow.new.TaintTracking as Tt
@@ -404,7 +403,7 @@ private module SinkModelGeneratorInput implements SinkModelGeneratorInputSig {
}
predicate apiSource(DataFlow::Node source) {
DataFlowPrivate::nodeHasOperand(source, any(DataFlowNodes::FieldAddress fa), 1)
DataFlowPrivate::nodeHasOperand(source, any(DataFlow::FieldAddress fa), 1)
or
source instanceof DataFlow::ParameterNode
}
@@ -417,7 +416,7 @@ private module SinkModelGeneratorInput implements SinkModelGeneratorInputSig {
result = "Argument[" + DataFlow::repeatStars(indirectionIndex) + argumentIndex + "]"
)
or
DataFlowPrivate::nodeHasOperand(source, any(DataFlowNodes::FieldAddress fa), 1) and
DataFlowPrivate::nodeHasOperand(source, any(DataFlow::FieldAddress fa), 1) and
result = qualifierString()
}

View File

@@ -46,7 +46,7 @@ public:
{
C *c = new C();
B *b = B::make(c);
sink(b->c); // $ ast,ir
sink(b->c); // $ast,ir
}
void f2()

View File

@@ -26,9 +26,9 @@ public:
void func()
{
sink(s1); // $ ast,ir
sink(s1); // $ast,ir
sink(s2); // $ MISSING: ast,ir
sink(s3); // $ ast,ir
sink(s3); // $ast,ir
sink(s4); // $ MISSING: ast,ir
}
};

View File

@@ -19,7 +19,7 @@ public:
};
static void sinkWrap(Box2* b2) {
sink(b2->getBox1()->getElem()); // $ ast,ir=28:15 ast,ir=35:15 ast,ir=42:15 ast,ir=49:15
sink(b2->getBox1()->getElem()); // $ast,ir=28:15 ast,ir=35:15 ast,ir=42:15 ast,ir=49:15
}
Box2* boxfield;

View File

@@ -48,25 +48,25 @@ struct S {
void test_setDirectly() {
S s;
s.setDirectly(user_input());
sink(s.getDirectly()); // $ ast ir
sink(s.getDirectly()); // $ast ir
}
void test_setIndirectly() {
S s;
s.setIndirectly(user_input());
sink(s.getIndirectly()); // $ ast ir
sink(s.getIndirectly()); // $ast ir
}
void test_setThroughNonMember() {
S s;
s.setThroughNonMember(user_input());
sink(s.getThroughNonMember()); // $ ast ir
sink(s.getThroughNonMember()); // $ast ir
}
void test_nonMemberSetA() {
S s;
nonMemberSetA(&s, user_input());
sink(nonMemberGetA(&s)); // $ ast,ir
sink(nonMemberGetA(&s)); // $ast,ir
}
////////////////////
@@ -112,7 +112,7 @@ void test_outer_with_ptr(Outer *pouter) {
sink(outer.a); // $ ast,ir
sink(pouter->inner_nested.a); // $ ast,ir
sink(pouter->inner_ptr->a); // $ ast,ir
sink(pouter->inner_ptr->a); // $ast,ir
sink(pouter->a); // $ ast,ir
}

View File

@@ -64,7 +64,7 @@ void single_field_test()
A a;
a.i = user_input();
A a2 = a;
sink(a2.i); // $ ast,ir
sink(a2.i); //$ ast,ir
}
struct C {
@@ -81,7 +81,7 @@ struct C2
void m() {
f2.f1 = user_input();
sink(getf2f1()); // $ ast,ir
sink(getf2f1()); //$ ast,ir
}
};
@@ -91,7 +91,7 @@ void single_field_test_typedef(A_typedef a)
{
a.i = user_input();
A_typedef a2 = a;
sink(a2.i); // $ ast,ir
sink(a2.i); //$ ast,ir
}
namespace TestAdditionalCallTargets {
@@ -168,4 +168,4 @@ void test_union_with_two_instantiations_of_different_sizes() {
sink(u_int.y); // $ MISSING: ir
}
} // namespace Simple
} // namespace Simple

View File

@@ -12,14 +12,14 @@ struct Outer {
};
void absink(struct AB *ab) {
sink(ab->a); // $ ast,ir=20:20 ast,ir=27:7 ast,ir=40:20
sink(ab->a); //$ ast,ir=20:20 ast,ir=27:7 ast,ir=40:20
sink(ab->b); // no flow
}
int struct_init(void) {
struct AB ab = { user_input(), 0 };
sink(ab.a); // $ ast,ir
sink(ab.a); //$ ast,ir
sink(ab.b); // no flow
absink(&ab);
@@ -28,9 +28,9 @@ int struct_init(void) {
&ab,
};
sink(outer.nestedAB.a); // $ ast,ir
sink(outer.nestedAB.a); //$ ast,ir
sink(outer.nestedAB.b); // no flow
sink(outer.pointerAB->a); // $ ast,ir
sink(outer.pointerAB->a); //$ ast,ir
sink(outer.pointerAB->b); // no flow
absink(&outer.nestedAB);

View File

@@ -1,7 +1,6 @@
import testModels
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
string describe(DataFlow::Node n) {
n instanceof ParameterNode and result = "ParameterNode"

View File

@@ -75,7 +75,7 @@ void test_sources() {
int e = localMadSource();
sink(e); // $ ir
sink(MyNamespace::namespaceLocalMadSource()); // $ ir
sink(MyNamespace::namespaceLocalMadSource()); // $: ir
sink(MyNamespace::namespaceLocalMadSourceVar); // $ ir
sink(MyNamespace::MyNamespace2::namespace2LocalMadSource()); // $ ir
sink(MyNamespace::localMadSource()); // $ (the MyNamespace version of this function is not a source)
@@ -475,4 +475,4 @@ void test_receive_array() {
int array[10] = {x};
int y = receive_array(array);
sink(y); // $ ir
}
}

View File

@@ -450,7 +450,7 @@ void test_qualifiers()
b.member = source();
sink(b); // $ ir MISSING: ast
sink(b.member); // $ ast,ir
sink(b.getMember()); // $ MISSING: ir ast
sink(b.getMember()); // $ MISSING: ir ast
c = new MyClass2(0);
@@ -865,4 +865,4 @@ void test_iconv(size_t size) {
size_t size_out;
iconv(0, &s, &size, &p, &size_out);
sink(*p); // $ ast,ir
}
}

View File

@@ -24,64 +24,64 @@ struct DerivedVI : virtual Base1 {
};
void Locals() {
Point pt = { // $ ussa=pt
1, // $ ussa=pt[0..4)<int>
2 // $ ussa=pt[4..8)<int>
Point pt = { //$ussa=pt
1, //$ussa=pt[0..4)<int>
2 //$ussa=pt[4..8)<int>
};
int i = pt.x; // $ ussa=pt[0..4)<int>
i = pt.y; // $ ussa=pt[4..8)<int>
int i = pt.x; //$ussa=pt[0..4)<int>
i = pt.y; //$ussa=pt[4..8)<int>
int* p = &pt.x;
i = *p; // $ ussa=pt[0..4)<int>
i = *p; //$ussa=pt[0..4)<int>
p = &pt.y;
i = *p; // $ ussa=pt[4..8)<int>
i = *p; //$ussa=pt[4..8)<int>
}
void PointsTo(
int a, // $ raw=a
Point& b, // $ raw=b ussa=*b
Point* c, // $ raw=c ussa=*c
int* d, // $ raw=d ussa=*d
DerivedSI* e, // $ raw=e ussa=*e
DerivedMI* f, // $ raw=f ussa=*f
DerivedVI* g // $ raw=g ussa=*g
int a, //$raw=a
Point& b, //$raw=b ussa=*b
Point* c, //$raw=c ussa=*c
int* d, //$raw=d ussa=*d
DerivedSI* e, //$raw=e ussa=*e
DerivedMI* f, //$raw=f ussa=*f
DerivedVI* g //$raw=g ussa=*g
) {
int i = a; // $ raw=a
i = *&a; // $ raw=a
i = *(&a + 0); // $ raw=a
i = b.x; // $ raw=b ussa=*b[0..4)<int>
i = b.y; // $ raw=b ussa=*b[4..8)<int>
i = c->x; // $ raw=c ussa=*c[0..4)<int>
i = c->y; // $ raw=c ussa=*c[4..8)<int>
i = *d; // $ raw=d ussa=*d[0..4)<int>
i = *(d + 0); // $ raw=d ussa=*d[0..4)<int>
i = d[5]; // $ raw=d ussa=*d[20..24)<int>
i = 5[d]; // $ raw=d ussa=*d[20..24)<int>
i = d[a]; // $ raw=d raw=a ussa=*d[?..?)<int>
i = a[d]; // $ raw=d raw=a ussa=*d[?..?)<int>
int i = a; //$raw=a
i = *&a; //$raw=a
i = *(&a + 0); //$raw=a
i = b.x; //$raw=b ussa=*b[0..4)<int>
i = b.y; //$raw=b ussa=*b[4..8)<int>
i = c->x; //$raw=c ussa=*c[0..4)<int>
i = c->y; //$raw=c ussa=*c[4..8)<int>
i = *d; //$raw=d ussa=*d[0..4)<int>
i = *(d + 0); //$raw=d ussa=*d[0..4)<int>
i = d[5]; //$raw=d ussa=*d[20..24)<int>
i = 5[d]; //$raw=d ussa=*d[20..24)<int>
i = d[a]; //$raw=d raw=a ussa=*d[?..?)<int>
i = a[d]; //$raw=d raw=a ussa=*d[?..?)<int>
int* p = &b.x; // $ raw=b
i = *p; // $ ussa=*b[0..4)<int>
p = &b.y; // $ raw=b
i = *p; // $ ussa=*b[4..8)<int>
p = &c->x; // $ raw=c
i = *p; // $ ussa=*c[0..4)<int>
p = &c->y; // $ raw=c
i = *p; // $ ussa=*c[4..8)<int>
p = &d[5]; // $ raw=d
i = *p; // $ ussa=*d[20..24)<int>
p = &d[a]; // $ raw=d raw=a
i = *p; // $ ussa=*d[?..?)<int>
int* p = &b.x; //$raw=b
i = *p; //$ussa=*b[0..4)<int>
p = &b.y; //$raw=b
i = *p; //$ussa=*b[4..8)<int>
p = &c->x; //$raw=c
i = *p; //$ussa=*c[0..4)<int>
p = &c->y; //$raw=c
i = *p; //$ussa=*c[4..8)<int>
p = &d[5]; //$raw=d
i = *p; //$ussa=*d[20..24)<int>
p = &d[a]; //$raw=d raw=a
i = *p; //$ussa=*d[?..?)<int>
Point* q = &c[a]; // $ raw=c raw=a
i = q->x; // $ ussa=*c[?..?)<int>
i = q->y; // $ ussa=*c[?..?)<int>
Point* q = &c[a]; //$raw=c raw=a
i = q->x; //$ussa=*c[?..?)<int>
i = q->y; //$ussa=*c[?..?)<int>
i = e->b1; // $ raw=e ussa=*e[0..4)<int>
i = e->dsi; // $ raw=e ussa=*e[4..8)<int>
i = f->b1; // $ raw=f ussa=*f[0..4)<int>
i = f->b2; // $ raw=f ussa=*f[4..8)<int>
i = f->dmi; // $ raw=f ussa=*f[8..12)<int>
i = g->b1; // $ raw=g ussa=*g[?..?)<int>
i = g->dvi; // $ raw=g ussa=*g[8..12)<int>
}
i = e->b1; //$raw=e ussa=*e[0..4)<int>
i = e->dsi; //$raw=e ussa=*e[4..8)<int>
i = f->b1; //$raw=f ussa=*f[0..4)<int>
i = f->b2; //$raw=f ussa=*f[4..8)<int>
i = f->dmi; //$raw=f ussa=*f[8..12)<int>
i = g->b1; //$raw=g ussa=*g[?..?)<int>
i = g->dvi; //$raw=g ussa=*g[8..12)<int>
}

View File

@@ -10,24 +10,24 @@ struct S {
void unique_ptr_init(S s) {
unique_ptr<S> p(new S); // MISSING: $ussa=dynamic{1}
int i = (*p).x; // $ MISSING: ussa=dynamic{1}[0..4)<int>
*p = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
int i = (*p).x; //$ MISSING: ussa=dynamic{1}[0..4)<int>
*p = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
unique_ptr<S> q = std::move(p);
*(q.get()) = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
*(q.get()) = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
shared_ptr<S> t(std::move(q));
t->x = 5; // $ MISSING: ussa=dynamic{1}[0..4)<int>
*t = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
*(t.get()) = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
t->x = 5; //$ MISSING: ussa=dynamic{1}[0..4)<int>
*t = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
*(t.get()) = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
}
void shared_ptr_init(S s) {
shared_ptr<S> p(new S); // $ MISSING: ussa=dynamic{1}
int i = (*p).x; // $ MISSING: ussa=dynamic{1}[0..4)<int>
*p = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
shared_ptr<S> p(new S); //$ MISSING: ussa=dynamic{1}
int i = (*p).x; //$ MISSING: ussa=dynamic{1}[0..4)<int>
*p = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
shared_ptr<S> q = std::move(p);
*(q.get()) = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
*(q.get()) = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
shared_ptr<S> t(q);
t->x = 5; // $ MISSING: ussa=dynamic{1}[0..4)<int>
*t = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
*(t.get()) = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
t->x = 5; //$ MISSING: ussa=dynamic{1}[0..4)<int>
*t = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
*(t.get()) = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
}

View File

@@ -46,7 +46,7 @@ int test4() {
}
range(total); // $ MISSING: range=>=0
range(i); // $ range===2
range(total + i); // $ range="<=Phi: i+2" MISSING: range===i+2 range=>=2 range=>=i+0
range(total + i); // $ range="<=Phi: i+2" MISSING: range===i+2 range=>=2 range=>=i+0
return total + i;
}
@@ -210,7 +210,7 @@ int test14(int x) {
int x3 = (int)(unsigned int)x;
range(x3);
char c0 = x;
range(c0);
range(c0);
unsigned short s0 = x;
range(s0);
range(x0 + x1 + x2 + x3 + c0 + s0); // $ overflow=+ overflow=+-
@@ -218,7 +218,7 @@ int test14(int x) {
}
long long test15(long long x) {
return (x > 0 && (range(x), x == (int)x)) ? // $ range=>=1
return (x > 0 && (range(x), x == (int)x)) ? // $ range=>=1
(range(x), x) : // $ range=>=1
(range(x), -1);
}
@@ -228,7 +228,7 @@ int test_unary(int a) {
int total = 0;
if (3 <= a && a <= 11) {
range(a); // $ range=<=11 range=>=3
range(a); // $ range=<=11 range=>=3
int b = +a;
range(b); // $ range=<=11 range=>=3
int c = -a;
@@ -384,7 +384,7 @@ int test_mult02(int a, int b) {
total += r;
range(total); // $ range=">=Phi: 0-143" range=">=Phi: 0-286"
}
range(total); // $ range=">=Phi: 0-143" range=">=Phi: 0-286"
range(total); // $range=">=Phi: 0-143" range=">=Phi: 0-286"
return total;
}
@@ -467,7 +467,7 @@ int test_mult04(int a, int b) {
range(a); // $ range=<=0 range=>=-17
range(b); // $ range=<=0 range=>=-13
int r = a*b; // 0 .. 221
range(r); // $ range=<=221 range=>=0
range(r); // $ range=<=221 range=>=0
total += r;
range(total); // $ range="<=Phi: - ...+221"
}
@@ -1030,7 +1030,7 @@ void test_negate_signed(int s) {
}
}
// By setting the guard after the use in another guard we
// By setting the guard after the use in another guard we
// don't get the useful information
void test_guard_after_use(int pos, int size, int offset) {
if (pos + offset >= size) { // $ overflow=+-
@@ -1040,12 +1040,12 @@ void test_guard_after_use(int pos, int size, int offset) {
return;
}
range(pos + 1); // $ overflow=+ range="==InitializeParameter: pos+1" MISSING: range="<=InitializeParameter: size-1"
}
}
int cond();
// This is basically what we get when we have a loop that calls
// This is basically what we get when we have a loop that calls
// realloc in some iterations
void alloc_in_loop(int origLen) {
if (origLen <= 10) {
@@ -1066,12 +1066,12 @@ void alloc_in_loop(int origLen) {
}
}
// This came from a case where it handled the leftovers before an unrolled loop
// This came from a case where it handled the leftovers before an unrolled loop
void mask_at_start(int len) {
if (len < 0) {
return;
}
int leftOver = len & 63;
int leftOver = len & 63;
for (int i = 0; i < leftOver; i++) {
range(i); // $ range=<=62 range=>=0 range="<=Store: ... & ... | Store: leftOver-1" range="<=InitializeParameter: len-1"
}

View File

@@ -1,14 +1,14 @@
void Complex(void) {
_Complex float cf; // $ irtype=cfloat8
_Complex double cd; // $ irtype=cfloat16
_Complex long double cld; // $ irtype=cfloat32
_Complex float cf; //$irtype=cfloat8
_Complex double cd; //$irtype=cfloat16
_Complex long double cld; //$irtype=cfloat32
// _Complex __float128 cf128;
}
void Imaginary(void) {
_Imaginary float jf; // $ irtype=ifloat4
_Imaginary double jd; // $ irtype=ifloat8
_Imaginary long double jld; // $ irtype=ifloat16
_Imaginary float jf; //$irtype=ifloat4
_Imaginary double jd; //$irtype=ifloat8
_Imaginary long double jld; //$irtype=ifloat16
// _Imaginary __float128 jf128;
}

View File

@@ -22,44 +22,44 @@ enum class ScopedE {
};
void IRTypes() {
char c; // $ irtype=int1
signed char sc; // $ irtype=int1
unsigned char uc; // $ irtype=uint1
short s; // $ irtype=int2
signed short ss; // $ irtype=int2
unsigned short us; // $ irtype=uint2
int i; // $ irtype=int4
signed int si; // $ irtype=int4
unsigned int ui; // $ irtype=uint4
long l; // $ irtype=int8
signed long sl; // $ irtype=int8
unsigned long ul; // $ irtype=uint8
long long ll; // $ irtype=int8
signed long long sll; // $ irtype=int8
unsigned long long ull; // $ irtype=uint8
bool b; // $ irtype=bool1
float f; // $ irtype=float4
double d; // $ irtype=float8
long double ld; // $ irtype=float16
__float128 f128; // $ irtype=float16
char c; //$irtype=int1
signed char sc; //$irtype=int1
unsigned char uc; //$irtype=uint1
short s; //$irtype=int2
signed short ss; //$irtype=int2
unsigned short us; //$irtype=uint2
int i; //$irtype=int4
signed int si; //$irtype=int4
unsigned int ui; //$irtype=uint4
long l; //$irtype=int8
signed long sl; //$irtype=int8
unsigned long ul; //$irtype=uint8
long long ll; //$irtype=int8
signed long long sll; //$irtype=int8
unsigned long long ull; //$irtype=uint8
bool b; //$irtype=bool1
float f; //$irtype=float4
double d; //$irtype=float8
long double ld; //$irtype=float16
__float128 f128; //$irtype=float16
wchar_t wc; // $ irtype=uint4
// char8_t c8; // $ irtype=uint1
char16_t c16; // $ irtype=uint2
char32_t c32; // $ irtype=uint4
wchar_t wc; //$irtype=uint4
// char8_t c8; //$irtype=uint1
char16_t c16; //$irtype=uint2
char32_t c32; //$irtype=uint4
int* pi; // $ irtype=addr8
int& ri = i; // $ irtype=addr8
void (*pfn)() = nullptr; // $ irtype=func8
void (&rfn)() = IRTypes; // $ irtype=func8
int* pi; //$irtype=addr8
int& ri = i; //$irtype=addr8
void (*pfn)() = nullptr; //$irtype=func8
void (&rfn)() = IRTypes; //$irtype=func8
A s_a; // $ irtype=opaque4{A}
B s_b; // $ irtype=opaque16{B}
A s_a; //$irtype=opaque4{A}
B s_b; //$irtype=opaque16{B}
E e; // $ irtype=uint4
ScopedE se; // $ irtype=uint4
E e; //$irtype=uint4
ScopedE se; //$irtype=uint4
B a_b[10]; // $ irtype=opaque160{B[10]}
B a_b[10]; //$irtype=opaque160{B[10]}
}
// semmle-extractor-options: -std=c++17 --clang

View File

@@ -1338,7 +1338,7 @@ void indirect_time_conversion_check(WORD year, WORD offset){
void set_time(WORD year, WORD month, WORD day){
SYSTEMTIME tmp;
tmp.wYear = year; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
tmp.wYear = year; //$ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
tmp.wMonth = month;
tmp.wDay = day;
}

View File

@@ -44,5 +44,5 @@ NHibernate,3,,,,,,,,,,,,3,,,,,,,,,,
Newtonsoft.Json,,,91,,,,,,,,,,,,,,,,,,,73,18
ServiceStack,194,,7,27,,,,,75,,,,92,,,,,,,,,7,
SourceGenerators,,,5,,,,,,,,,,,,,,,,,,,,5
System,59,48,12495,,6,5,12,,,4,1,,31,2,,6,15,17,5,3,,6382,6113
System,59,47,12495,,6,5,12,,,4,1,,31,2,,6,15,17,4,3,,6382,6113
Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,,,,,,,,,
1 package sink source summary sink:code-injection sink:encryption-decryptor sink:encryption-encryptor sink:encryption-keyprop sink:encryption-symmetrickey sink:file-content-store sink:html-injection sink:js-injection sink:log-injection sink:sql-injection source:commandargs source:database source:environment source:file source:file-write source:remote source:stdin source:windows-registry summary:taint summary:value
44 Newtonsoft.Json 91 73 18
45 ServiceStack 194 7 27 75 92 7
46 SourceGenerators 5 5
47 System 59 48 47 12495 6 5 12 4 1 31 2 6 15 17 5 4 3 6382 6113
48 Windows.Security.Cryptography.Core 1 1

View File

@@ -8,7 +8,7 @@ C# framework & library support
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
System,"``System.*``, ``System``",48,12495,59,5
System,"``System.*``, ``System``",47,12495,59,5
Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.AspNetCore.Components``, ``Microsoft.AspNetCore.Http``, ``Microsoft.AspNetCore.Mvc``, ``Microsoft.AspNetCore.WebUtilities``, ``Microsoft.CSharp``, ``Microsoft.Data.SqlClient``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.DotNet.Build.Tasks``, ``Microsoft.DotNet.PlatformAbstractions``, ``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.JSInterop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.VisualBasic``, ``Microsoft.Win32``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``NHibernate``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",60,2406,162,4
Totals,,108,14908,415,9
Totals,,107,14908,415,9

View File

@@ -1,2 +0,0 @@
description: Remove inclusion of @assign_expr in @bin_op
compatibility: full

View File

@@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
@@ -13,9 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities
internal class Constructor : Method
{
private readonly List<SyntaxNode> declaringReferenceSyntax;
private readonly Lazy<ConstructorDeclarationSyntax?> ordinaryConstructorSyntaxLazy;
private readonly Lazy<TypeDeclarationSyntax?> primaryConstructorSyntaxLazy;
private readonly Lazy<PrimaryConstructorBaseTypeSyntax?> primaryBaseLazy;
private Constructor(Context cx, IMethodSymbol init)
: base(cx, init)
{
@@ -23,28 +20,8 @@ namespace Semmle.Extraction.CSharp.Entities
Symbol.DeclaringSyntaxReferences
.Select(r => r.GetSyntax())
.ToList();
ordinaryConstructorSyntaxLazy = new Lazy<ConstructorDeclarationSyntax?>(() =>
declaringReferenceSyntax
.OfType<ConstructorDeclarationSyntax>()
.FirstOrDefault());
primaryConstructorSyntaxLazy = new Lazy<TypeDeclarationSyntax?>(() =>
declaringReferenceSyntax
.OfType<TypeDeclarationSyntax>()
.FirstOrDefault(t => t is ClassDeclarationSyntax or StructDeclarationSyntax or RecordDeclarationSyntax));
primaryBaseLazy = new Lazy<PrimaryConstructorBaseTypeSyntax?>(() =>
PrimaryConstructorSyntax?
.BaseList?
.Types
.OfType<PrimaryConstructorBaseTypeSyntax>()
.FirstOrDefault());
}
private ConstructorDeclarationSyntax? OrdinaryConstructorSyntax => ordinaryConstructorSyntaxLazy.Value;
private TypeDeclarationSyntax? PrimaryConstructorSyntax => primaryConstructorSyntaxLazy.Value;
private PrimaryConstructorBaseTypeSyntax? PrimaryBase => primaryBaseLazy.Value;
public override void Populate(TextWriter trapFile)
{
PopulateMethod(trapFile);
@@ -199,6 +176,23 @@ namespace Semmle.Extraction.CSharp.Entities
init.PopulateArguments(trapFile, arguments, 0);
}
private ConstructorDeclarationSyntax? OrdinaryConstructorSyntax =>
declaringReferenceSyntax
.OfType<ConstructorDeclarationSyntax>()
.FirstOrDefault();
private TypeDeclarationSyntax? PrimaryConstructorSyntax =>
declaringReferenceSyntax
.OfType<TypeDeclarationSyntax>()
.FirstOrDefault(t => t is ClassDeclarationSyntax or StructDeclarationSyntax or RecordDeclarationSyntax);
private PrimaryConstructorBaseTypeSyntax? PrimaryBase =>
PrimaryConstructorSyntax?
.BaseList?
.Types
.OfType<PrimaryConstructorBaseTypeSyntax>()
.FirstOrDefault();
private bool IsPrimary => PrimaryConstructorSyntax is not null;
// This is a default constructor in a class or struct declared in source.
@@ -229,7 +223,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
case MethodKind.StaticConstructor:
case MethodKind.Constructor:
return ConstructorFactory.Instance.CreateEntityFromSymbol(cx, constructor.GetBodyDeclaringSymbol());
return ConstructorFactory.Instance.CreateEntityFromSymbol(cx, constructor);
default:
throw new InternalError(constructor, "Attempt to create a Constructor from a symbol that isn't a constructor");
}

View File

@@ -1,7 +1,3 @@
## 1.7.60
No user-facing changes.
## 1.7.59
No user-facing changes.

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.7.60
lastReleaseVersion: 1.7.59

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
version: 1.7.61-dev
version: 1.7.60-dev
groups:
- csharp
- solorigate

View File

@@ -1,7 +1,3 @@
## 1.7.60
No user-facing changes.
## 1.7.59
No user-facing changes.

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.7.60
lastReleaseVersion: 1.7.59

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
version: 1.7.61-dev
version: 1.7.60-dev
groups:
- csharp
- solorigate

View File

@@ -1,14 +1,3 @@
## 5.4.8
### Minor Analysis Improvements
* C# 14: Added support for partial events.
* C# 14: Added support for the `field` keyword in properties.
### Bug Fixes
* Fixed an issue where the body of a partial member could be extracted twice. When both a *defining* and an *implementing* declaration exist, only the *implementing* declaration is now extracted.
## 5.4.7
### Minor Analysis Improvements

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* C# 14: Added support for the `field` keyword in properties.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* C# 14: Added support for partial events.

View File

@@ -1,10 +1,4 @@
## 5.4.8
### Minor Analysis Improvements
* C# 14: Added support for partial events.
* C# 14: Added support for the `field` keyword in properties.
### Bug Fixes
---
category: fix
---
* Fixed an issue where the body of a partial member could be extracted twice. When both a *defining* and an *implementing* declaration exist, only the *implementing* declaration is now extracted.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* C# 14: Added support for partial constructors.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added post-update nodes for struct-type arguments, allowing data flow out of method calls via those arguments.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added reverse taint flow from implicit conversion operator calls to their arguments.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added `System.Net.WebSockets::ReceiveAsync` as a remote flow source.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Inline expectations test comments, which are of the form `// $ tag` or `// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 5.4.8
lastReleaseVersion: 5.4.7

View File

@@ -1,6 +0,0 @@
extensions:
- addsTo:
pack: codeql/csharp-all
extensible: sourceModel
data:
- ["System.Net.WebSockets", "WebSocket", True, "ReceiveAsync", "", "", "Argument[0]", "remote", "manual"]

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-all
version: 5.4.9-dev
version: 5.4.8-dev
groups: csharp
dbscheme: semmlecode.csharp.dbscheme
extractor: csharp

View File

@@ -142,7 +142,6 @@ private module GuardsInput implements
}
}
pragma[nomagic]
predicate equalityTest(Expr eqtest, Expr left, Expr right, boolean polarity) {
exists(ComparisonTest ct |
ct.getExpr() = eqtest and
@@ -411,22 +410,6 @@ private predicate typePattern(PatternMatch pm, TypePatternExpr tpe, Type t) {
t = pm.getExpr().getType()
}
pragma[nomagic]
private predicate dereferenceableExpr(Expr e, boolean isNullableType) {
exists(Type t | t = e.getType() |
t instanceof NullableType and
isNullableType = true
or
t instanceof RefType and
isNullableType = false
)
or
exists(Expr parent |
dereferenceableExpr(parent, isNullableType) and
e = getNullEquivParent(parent)
)
}
/**
* An expression that evaluates to a value that can be dereferenced. That is,
* an expression that may evaluate to `null`.
@@ -435,12 +418,21 @@ class DereferenceableExpr extends Expr {
private boolean isNullableType;
DereferenceableExpr() {
// There is currently a bug in the extractor: the type of `x?.Length` is
// incorrectly `int`, while it should have been `int?`. We apply
// `getNullEquivParent()` as a workaround
dereferenceableExpr(this, isNullableType) and
not this instanceof SwitchCaseExpr and
not this instanceof PatternExpr
exists(Expr e, Type t |
// There is currently a bug in the extractor: the type of `x?.Length` is
// incorrectly `int`, while it should have been `int?`. We apply
// `getNullEquivParent()` as a workaround
this = getNullEquivParent*(e) and
t = e.getType() and
not this instanceof SwitchCaseExpr and
not this instanceof PatternExpr
|
t instanceof NullableType and
isNullableType = true
or
t instanceof RefType and
isNullableType = false
)
}
/** Holds if this expression has a nullable type `T?`. */

View File

@@ -94,19 +94,9 @@ private Element getAChild(Element p) {
result = p.(AssignOperation).getExpandedAssignment()
}
pragma[nomagic]
private predicate astNode(Element e) {
e = any(@top_level_exprorstmt_parent p | not p instanceof Attribute)
or
exists(Element parent |
astNode(parent) and
e = getAChild(parent)
)
}
/** An AST node. */
class AstNode extends Element, TAstNode {
AstNode() { astNode(this) }
AstNode() { this = getAChild*(any(@top_level_exprorstmt_parent p | not p instanceof Attribute)) }
int getId() { idOf(this, result) }
}

View File

@@ -15,47 +15,16 @@ private class ControlFlowScope extends ControlFlowElement {
predicate isNonExact() { exactScope = false }
}
private newtype TControlFlowElementOrBasicBlock =
TControlFlowElement(ControlFlowElement cfe) or
TBasicBlock(ControlFlow::BasicBlock bb)
class ControlFlowElementOrBasicBlock extends TControlFlowElementOrBasicBlock {
ControlFlowElement asControlFlowElement() { this = TControlFlowElement(result) }
ControlFlow::BasicBlock asBasicBlock() { this = TBasicBlock(result) }
string toString() {
result = this.asControlFlowElement().toString()
or
result = this.asBasicBlock().toString()
}
Location getLocation() {
result = this.asControlFlowElement().getLocation()
or
result = this.asBasicBlock().getLocation()
}
}
private predicate isBasicBlock(ControlFlowElementOrBasicBlock c) { c instanceof TBasicBlock }
private predicate isNonExactScope(ControlFlowElementOrBasicBlock c) {
c.asControlFlowElement().(ControlFlowScope).isNonExact()
}
private predicate step(ControlFlowElementOrBasicBlock pred, ControlFlowElementOrBasicBlock succ) {
pred.asBasicBlock().getANode().getAstNode() = succ.asControlFlowElement()
private ControlFlowElement getANonExactScopeChild(ControlFlowScope scope) {
scope.isNonExact() and
result = scope
or
pred.asControlFlowElement() = succ.asControlFlowElement().getAChild()
result = getANonExactScopeChild(scope).getAChild()
}
private predicate basicBlockInNonExactScope(
ControlFlowElementOrBasicBlock bb, ControlFlowElementOrBasicBlock scope
) = doublyBoundedFastTC(step/2, isBasicBlock/1, isNonExactScope/1)(bb, scope)
pragma[noinline]
private ControlFlow::BasicBlock getABasicBlockInScope(ControlFlowScope scope, boolean exactScope) {
basicBlockInNonExactScope(TBasicBlock(result), TControlFlowElement(scope)) and
result.getANode().getAstNode() = getANonExactScopeChild(scope) and
exactScope = false
or
scope.isExact() and

View File

@@ -6,9 +6,7 @@ private import ControlFlowReachability
private import FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.csharp.dataflow.FlowSummary as FlowSummary
private import semmle.code.csharp.dataflow.internal.ExternalFlow
private import semmle.code.csharp.commons.Collections
private import semmle.code.csharp.Conversion
private import semmle.code.csharp.exprs.internal.Expr
private import semmle.code.csharp.dataflow.internal.SsaImpl as SsaImpl
private import semmle.code.csharp.ExprOrStmtParent
private import semmle.code.csharp.Unification
@@ -18,6 +16,7 @@ private import semmle.code.csharp.frameworks.EntityFramework
private import semmle.code.csharp.frameworks.system.linq.Expressions
private import semmle.code.csharp.frameworks.NHibernate
private import semmle.code.csharp.frameworks.Razor
private import semmle.code.csharp.frameworks.system.Collections
private import semmle.code.csharp.frameworks.system.threading.Tasks
private import semmle.code.csharp.internal.Location
private import codeql.util.Unit
@@ -1088,7 +1087,7 @@ predicate exprMayHavePostUpdateNode(Expr e) {
or
t = any(TypeParameter tp | not tp.isValueType())
or
t instanceof Struct
t.isRefLikeType()
)
}
@@ -2378,16 +2377,6 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
storeStepDelegateCall(node1, c, node2)
}
pragma[nomagic]
private predicate isAssignExprLValueDescendant(Expr e) {
e = any(AssignExpr ae).getLValue()
or
exists(Expr parent |
isAssignExprLValueDescendant(parent) and
e = parent.getAChildExpr()
)
}
private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration {
ReadStepConfiguration() { this = "ReadStepConfiguration" }
@@ -2443,7 +2432,7 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration
scope =
any(AssignExpr ae |
ae = defTo.(AssignableDefinitions::TupleAssignmentDefinition).getAssignment() and
isAssignExprLValueDescendant(e.(TupleExpr)) and
e = ae.getLValue().getAChildExpr*().(TupleExpr) and
exactScope = false and
isSuccessor = true
)
@@ -2499,7 +2488,7 @@ private predicate readContentStep(Node node1, Content c, Node node2) {
)
or
// item = variable in node1 = (..., variable, ...) in a case/is var (..., ...)
isPatternExprDescendant(te) and
te = any(PatternExpr pe).getAChildExpr*() and
exists(AssignableDefinitions::LocalVariableDefinition lvd |
node2.(AssignableDefinitionNode).getDefinition() = lvd and
lvd.getDeclaration() = item and
@@ -2556,7 +2545,6 @@ private predicate clearsCont(Node n, Content c) {
a.getType() = s and
f = s.getAField() and
c.(FieldContent).getField() = f.getUnboundDeclaration() and
not f.getType() instanceof CollectionType and
not f.isRef()
)
or

View File

@@ -239,25 +239,12 @@ module ModelValidation {
)
}
string getIncorrectConstructorSummaryOutput() {
exists(string namespace, string type, string name, string output |
type = name or
type = name + "<" + any(string s)
|
summaryModel(namespace, type, _, name, _, _, _, output, _, _, _) and
output.matches("ReturnValue%") and
result =
"Constructor model for " + namespace + "." + type +
" should use `Argument[this]` in the output, not `ReturnValue`."
)
}
/** Holds if some row in a MaD flow model appears to contain typos. */
query predicate invalidModelRow(string msg) {
msg =
[
getInvalidModelSignature(), getInvalidModelInput(), getInvalidModelOutput(),
getIncorrectConstructorSummaryOutput(), KindVal::getInvalidModelKind()
KindVal::getInvalidModelKind()
]
}
}

View File

@@ -109,16 +109,6 @@ private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityCon
}
}
private ControlFlow::Nodes::ExprNode getALastEvalNode(ControlFlow::Nodes::ExprNode cfn) {
exists(OperatorCall oc | any(LocalTaintExprStepConfiguration x).hasExprPath(_, result, oc, cfn) |
oc.getTarget() instanceof ImplicitConversionOperator
)
}
private ControlFlow::Nodes::ExprNode getPostUpdateReverseStep(ControlFlow::Nodes::ExprNode e) {
result = getALastEvalNode(e)
}
private predicate localTaintStepCommon(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
hasNodePath(any(LocalTaintExprStepConfiguration x), nodeFrom, nodeTo)
}
@@ -187,16 +177,6 @@ private module Cached {
readStep(nodeFrom, any(DataFlow::ContentSet c | c.isElement()), nodeTo)
or
nodeTo = nodeFrom.(DataFlow::NonLocalJumpNode).getAJumpSuccessor(false)
or
// Allow reverse update flow for implicit conversion operator calls.
// This is needed to support flow out of method call arguments, where an implicit conversion is applied
// to a call argument.
nodeTo.(PostUpdateNode).getPreUpdateNode().(DataFlow::ExprNode).getControlFlowNode() =
getPostUpdateReverseStep(nodeFrom
.(PostUpdateNode)
.getPreUpdateNode()
.(DataFlow::ExprNode)
.getControlFlowNode())
) and
model = ""
or

View File

@@ -15,47 +15,16 @@ private class ControlFlowScope extends ControlFlowElement {
predicate isNonExact() { exactScope = false }
}
private newtype TControlFlowElementOrBasicBlock =
TControlFlowElement(ControlFlowElement cfe) or
TBasicBlock(ControlFlow::BasicBlock bb)
class ControlFlowElementOrBasicBlock extends TControlFlowElementOrBasicBlock {
ControlFlowElement asControlFlowElement() { this = TControlFlowElement(result) }
ControlFlow::BasicBlock asBasicBlock() { this = TBasicBlock(result) }
string toString() {
result = this.asControlFlowElement().toString()
or
result = this.asBasicBlock().toString()
}
Location getLocation() {
result = this.asControlFlowElement().getLocation()
or
result = this.asBasicBlock().getLocation()
}
}
private predicate isBasicBlock(ControlFlowElementOrBasicBlock c) { c instanceof TBasicBlock }
private predicate isNonExactScope(ControlFlowElementOrBasicBlock c) {
c.asControlFlowElement().(ControlFlowScope).isNonExact()
}
private predicate step(ControlFlowElementOrBasicBlock pred, ControlFlowElementOrBasicBlock succ) {
pred.asBasicBlock().getANode().getAstNode() = succ.asControlFlowElement()
private ControlFlowElement getANonExactScopeChild(ControlFlowScope scope) {
scope.isNonExact() and
result = scope
or
pred.asControlFlowElement() = succ.asControlFlowElement().getAChild()
result = getANonExactScopeChild(scope).getAChild()
}
private predicate basicBlockInNonExactScope(
ControlFlowElementOrBasicBlock bb, ControlFlowElementOrBasicBlock scope
) = doublyBoundedFastTC(step/2, isBasicBlock/1, isNonExactScope/1)(bb, scope)
pragma[noinline]
private ControlFlow::BasicBlock getABasicBlockInScope(ControlFlowScope scope, boolean exactScope) {
basicBlockInNonExactScope(TBasicBlock(result), TControlFlowElement(scope)) and
result.getANode().getAstNode() = getANonExactScopeChild(scope) and
exactScope = false
or
scope.isExact() and

View File

@@ -11,7 +11,7 @@ import Expr
* (`LocalVariableDeclAndInitExpr`), a simple assignment (`AssignExpr`), or
* an assignment operation (`AssignOperation`).
*/
class Assignment extends BinaryOperation, @assign_expr {
class Assignment extends Operation, @assign_expr {
Assignment() {
this instanceof LocalVariableDeclExpr
implies
@@ -20,10 +20,6 @@ class Assignment extends BinaryOperation, @assign_expr {
expr_parent(_, 0, this)
}
override Expr getLeftOperand() { result = this.getChild(1) }
override Expr getRightOperand() { result = this.getChild(0) }
/** Gets the left operand of this assignment. */
Expr getLValue() { result = this.getChild(1) }

View File

@@ -21,7 +21,6 @@ import semmle.code.csharp.Type
private import semmle.code.csharp.ExprOrStmtParent
private import semmle.code.csharp.frameworks.System
private import semmle.code.csharp.TypeRef
private import internal.Expr
/**
* An expression. Either an access (`Access`), a call (`Call`), an object or
@@ -65,24 +64,14 @@ class Expr extends ControlFlowElement, @expr {
/** Gets the enclosing callable of this expression, if any. */
override Callable getEnclosingCallable() { enclosingCallable(this, result) }
pragma[nomagic]
private predicate isExpandedAssignmentRValueDescendant() {
this =
any(AssignOperation op).getExpandedAssignment().getRValue().getChildExpr(0).getAChildExpr()
or
exists(Expr parent |
parent.isExpandedAssignmentRValueDescendant() and
this = parent.getAChildExpr()
)
}
/**
* Holds if this expression is generated by the compiler and does not appear
* explicitly in the source code.
*/
final predicate isImplicit() {
compiler_generated(this) or
this.isExpandedAssignmentRValueDescendant()
this =
any(AssignOperation op).getExpandedAssignment().getRValue().getChildExpr(0).getAChildExpr+()
}
/**
@@ -244,8 +233,7 @@ class UnaryOperation extends Operation, @un_op {
* A binary operation. Either a binary arithmetic operation
* (`BinaryArithmeticOperation`), a binary bitwise operation
* (`BinaryBitwiseOperation`), a comparison operation (`ComparisonOperation`),
* a binary logical operation (`BinaryLogicalOperation`), or an
* assignment (`Assignment`).
* or a binary logical operation (`BinaryLogicalOperation`).
*/
class BinaryOperation extends Operation, @bin_op {
/** Gets the left operand of this binary operation. */
@@ -1145,7 +1133,7 @@ class TupleExpr extends Expr, @tuple_expr {
/** Holds if this expression is a tuple construction. */
predicate isConstruction() {
not this = getAnAssignOrForeachChild() and
not isPatternExprDescendant(this)
not this = any(PatternExpr pe).getAChildExpr*()
}
override string getAPrimaryQlClass() { result = "TupleExpr" }

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