mirror of
https://github.com/github/codeql.git
synced 2026-07-20 10:48:17 +02:00
Merge branch 'master' into objectapi-to-valueapi-expectedmappingforformatstring
This commit is contained in:
@@ -2,5 +2,4 @@
|
||||
"*/ql/test/qlpack.yml",
|
||||
"*/upgrades/qlpack.yml",
|
||||
"misc/legacy-support/*/qlpack.yml",
|
||||
"misc/suite-helpers/qlpack.yml",
|
||||
"codeql/.codeqlmanifest.json" ] }
|
||||
"misc/suite-helpers/qlpack.yml" ] }
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
# editor and OS artifacts
|
||||
*~
|
||||
.DS_STORE
|
||||
*.swp
|
||||
|
||||
# query compilation caches
|
||||
.cache
|
||||
|
||||
@@ -27,10 +27,10 @@ The following changes in version 1.24 affect C/C++ analysis in all applications.
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
* The data-flow library has been improved when flow through functions needs to be
|
||||
combined with both taint tracking and flow through fields allowing more flow
|
||||
to be tracked. This affects and improves some security queries, which may
|
||||
report additional results.
|
||||
* The data-flow library has been improved, which affects and improves some security queries. The improvements are:
|
||||
- Track flow through functions that combine taint tracking with flow through fields.
|
||||
- Track flow through clone-like functions, that is, functions that read contents of a field from a
|
||||
parameter and stores the value in the field of a returned object.
|
||||
* Created the `semmle.code.cpp.models.interfaces.Allocation` library to model allocation such as `new` expressions and calls to `malloc`. This in intended to replace the functionality in `semmle.code.cpp.commons.Alloc` with a more consistent and useful interface.
|
||||
* Created the `semmle.code.cpp.models.interfaces.Deallocation` library to model deallocation such as `delete` expressions and calls to `free`. This in intended to replace the functionality in `semmle.code.cpp.commons.Alloc` with a more consistent and useful interface.
|
||||
* The new class `StackVariable` should be used in place of `LocalScopeVariable`
|
||||
|
||||
@@ -33,10 +33,10 @@ The following changes in version 1.24 affect C# analysis in all applications.
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
* The data-flow library has been improved when flow through methods needs to be
|
||||
combined with both taint tracking and flow through fields allowing more flow
|
||||
to be tracked. This affects and improves most security queries, which may
|
||||
report additional results.
|
||||
* The data-flow library has been improved, which affects and improves most security queries. The improvements are:
|
||||
- Track flow through methods that combine taint tracking with flow through fields.
|
||||
- Track flow through clone-like methods, that is, methods that read contents of a field from a
|
||||
parameter and stores the value in the field of a returned object.
|
||||
* The taint tracking library now tracks flow through (implicit or explicit) conversion operator calls.
|
||||
* [Code contracts](https://docs.microsoft.com/en-us/dotnet/framework/debug-trace-profile/code-contracts) are now recognized, and are treated like any other assertion methods.
|
||||
* Expression nullability flow state is given by the predicates `Expr.hasNotNullFlowState()` and `Expr.hasMaybeNullFlowState()`.
|
||||
|
||||
@@ -26,10 +26,10 @@ The following changes in version 1.24 affect Java analysis in all applications.
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
* The data-flow library has been improved when flow through methods needs to be
|
||||
combined with both taint tracking and flow through fields allowing more flow
|
||||
to be tracked. This affects and improves most security queries, which may
|
||||
report additional results.
|
||||
* The data-flow library has been improved, which affects and improves most security queries. The improvements are:
|
||||
- Track flow through methods that combine taint tracking with flow through fields.
|
||||
- Track flow through clone-like methods, that is, methods that read contents of a field from a
|
||||
parameter and stores the value in the field of a returned object.
|
||||
* Identification of test classes has been improved. Previously, one of the
|
||||
match conditions would classify any class with a name containing the string
|
||||
"Test" as a test class, but now this matching has been replaced with one that
|
||||
|
||||
@@ -9,22 +9,26 @@
|
||||
|
||||
* Imports that rely on path-mappings from a `tsconfig.json` file can now be resolved.
|
||||
|
||||
* Export declarations of the form `export * as ns from "x"` are now analyzed more precisely.
|
||||
|
||||
* The analysis of sanitizer guards has improved, leading to fewer false-positive results from the security queries.
|
||||
|
||||
* Support for the following frameworks and libraries has been improved:
|
||||
- [react](https://www.npmjs.com/package/react)
|
||||
- [typeahead.js](https://www.npmjs.com/package/typeahead.js)
|
||||
- [Handlebars](https://www.npmjs.com/package/handlebars)
|
||||
- [Electron](https://electronjs.org/)
|
||||
- [Handlebars](https://www.npmjs.com/package/handlebars)
|
||||
- [Koa](https://www.npmjs.com/package/koa)
|
||||
- [Node.js](https://nodejs.org/)
|
||||
- [Socket.IO](https://socket.io/)
|
||||
- [ws](https://github.com/websockets/ws)
|
||||
- [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API)
|
||||
- [Koa](https://www.npmjs.com/package/koa)
|
||||
- [lazy-cache](https://www.npmjs.com/package/lazy-cache)
|
||||
- [chrome-remote-interface](https://www.npmjs.com/package/chrome-remote-interface)
|
||||
- [for-in](https://www.npmjs.com/package/for-in)
|
||||
- [for-own](https://www.npmjs.com/package/for-own)
|
||||
- [http2](https://nodejs.org/api/http2.html)
|
||||
- [lazy-cache](https://www.npmjs.com/package/lazy-cache)
|
||||
- [react](https://www.npmjs.com/package/react)
|
||||
- [send](https://www.npmjs.com/package/send)
|
||||
- [typeahead.js](https://www.npmjs.com/package/typeahead.js)
|
||||
- [ws](https://github.com/websockets/ws)
|
||||
|
||||
## New queries
|
||||
|
||||
@@ -34,6 +38,7 @@
|
||||
| Regular expression always matches (`js/regex/always-matches`) | correctness, regular-expressions | Highlights regular expression checks that trivially succeed by matching an empty substring. Results are shown on LGTM by default. |
|
||||
| Missing await (`js/missing-await`) | correctness | Highlights expressions that operate directly on a promise object in a nonsensical way, instead of awaiting its result. Results are shown on LGTM by default. |
|
||||
| Prototype pollution in utility function (`js/prototype-pollution-utility`) | security, external/cwe/cwe-400, external/cwe/cwe-471 | Highlights recursive copying operations that are susceptible to prototype pollution. Results are shown on LGTM by default. |
|
||||
| Unsafe jQuery plugin (`js/unsafe-jquery-plugin`) | Highlights potential XSS vulnerabilities in unsafely designed jQuery plugins. Results are shown on LGTM by default. |
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
@@ -47,6 +52,7 @@
|
||||
| Use of call stack introspection in strict mode (`js/strict-mode-call-stack-introspection`) | Fewer false positive results | The query no longer flags expression statements. |
|
||||
| Missing CSRF middleware (`js/missing-token-validation`) | Fewer false positive results | The query reports fewer duplicates and only flags handlers that explicitly access cookie data. |
|
||||
| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional ways dangerous paths can be constructed. |
|
||||
| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional ways of constructing arguments to `cmd.exe` and `/bin/sh`. |
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
|
||||
37
change-notes/1.24/analysis-python.md
Normal file
37
change-notes/1.24/analysis-python.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Improvements to Python analysis
|
||||
|
||||
The following changes in version 1.24 affect Python analysis in all applications.
|
||||
|
||||
## General improvements
|
||||
|
||||
## New queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|-----------------------------|-----------|--------------------------------------------------------------------|
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|----------------------------|------------------------|------------------------------------------------------------------|
|
||||
|
||||
### Web framework support
|
||||
|
||||
The QL-library support for the web frameworks Bottle, CherryPy, Falcon, Pyramid, TurboGears, Tornado, and Twisted have
|
||||
been fixed so they provide a proper HttpRequestTaintSource, instead of a TaintSource. This will enable results for the following queries:
|
||||
|
||||
- py/path-injection
|
||||
- py/command-line-injection
|
||||
- py/reflective-xss
|
||||
- py/sql-injection
|
||||
- py/code-injection
|
||||
- py/unsafe-deserialization
|
||||
- py/url-redirection
|
||||
|
||||
The QL-library support for the web framework Twisted have been fixed so they provide a proper
|
||||
HttpResponseTaintSink, instead of a TaintSink. This will enable results for the following
|
||||
queries:
|
||||
|
||||
- py/reflective-xss
|
||||
- py/stack-trace-exposure
|
||||
|
||||
## Changes to libraries
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -301,3 +301,5 @@ class DataFlowCall extends Expr {
|
||||
}
|
||||
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
@@ -335,6 +335,12 @@ private Element adjustedSink(DataFlow::Node sink) {
|
||||
// For compatibility, send flow into a `NotExpr` even if it's part of a
|
||||
// short-circuiting condition and thus might get skipped.
|
||||
result.(NotExpr).getOperand() = sink.asExpr()
|
||||
or
|
||||
// Taint postfix and prefix crement operations when their operand is tainted.
|
||||
result.(CrementOperation).getAnOperand() = sink.asExpr()
|
||||
or
|
||||
// Taint `e1 += e2`, `e &= e2` and friends when `e1` or `e2` is tainted.
|
||||
result.(AssignOperation).getAnOperand() = sink.asExpr()
|
||||
}
|
||||
|
||||
predicate tainted(Expr source, Element tainted) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -210,3 +210,5 @@ class DataFlowCall extends CallInstruction {
|
||||
}
|
||||
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
// The `ValueNumbering` library has to be imported right after `cpp` to ensure
|
||||
// that the cached IR gets the same checksum here as it does in queries that use
|
||||
// `ValueNumbering` without `DataFlow`.
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.controlflow.IRGuards
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
private import semmle.code.cpp.models.interfaces.DataFlow
|
||||
|
||||
private newtype TIRDataFlowNode =
|
||||
@@ -300,10 +303,12 @@ ParameterNode parameterNode(Parameter p) { result.getParameter() = p }
|
||||
VariableNode variableNode(Variable v) { result.getVariable() = v }
|
||||
|
||||
/**
|
||||
* DEPRECATED: See UninitializedNode.
|
||||
*
|
||||
* Gets the `Node` corresponding to the value of an uninitialized local
|
||||
* variable `v`.
|
||||
*/
|
||||
UninitializedNode uninitializedNode(LocalVariable v) { result.getLocalVariable() = v }
|
||||
Node uninitializedNode(LocalVariable v) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local
|
||||
|
||||
@@ -11,13 +11,19 @@ cached
|
||||
private newtype TOperand =
|
||||
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
|
||||
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
|
||||
not Construction::isInCycle(useInstr)
|
||||
not Construction::isInCycle(useInstr) and
|
||||
strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
|
||||
} or
|
||||
TNonPhiMemoryOperand(
|
||||
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
|
||||
) {
|
||||
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
|
||||
not Construction::isInCycle(useInstr)
|
||||
not Construction::isInCycle(useInstr) and
|
||||
(
|
||||
strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
|
||||
or
|
||||
tag instanceof UnmodeledUseOperandTag
|
||||
)
|
||||
} or
|
||||
TPhiOperand(
|
||||
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
|
||||
@@ -2,10 +2,10 @@ private import ValueNumberingImports
|
||||
private import cpp
|
||||
|
||||
newtype TValueNumber =
|
||||
TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
variableAddressValueNumber(_, irFunc, var)
|
||||
TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) {
|
||||
variableAddressValueNumber(_, irFunc, ast)
|
||||
} or
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) {
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
@@ -19,19 +19,18 @@ newtype TValueNumber =
|
||||
fieldAddressValueNumber(_, irFunc, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
IRFunction irFunc, Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand
|
||||
) {
|
||||
binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand)
|
||||
binaryValueNumber(_, irFunc, opcode, leftOperand, rightOperand)
|
||||
} or
|
||||
TPointerArithmeticValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand,
|
||||
IRFunction irFunc, Opcode opcode, int elementSize, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
} or
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, type, operand)
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, TValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, TValueNumber operand
|
||||
@@ -99,28 +98,49 @@ private predicate numberableInstruction(Instruction instr) {
|
||||
instr instanceof LoadTotalOverlapInstruction
|
||||
}
|
||||
|
||||
private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
// count rather than strictcount to handle missing AST elements
|
||||
// separate instanceof and inline casts to avoid failed casts with a count of 0
|
||||
instr instanceof VariableAddressInstruction and
|
||||
count(instr.(VariableAddressInstruction).getIRVariable().getAST()) != 1
|
||||
or
|
||||
instr instanceof ConstantInstruction and
|
||||
count(instr.getResultIRType()) != 1
|
||||
or
|
||||
instr instanceof FieldAddressInstruction and
|
||||
count(instr.(FieldAddressInstruction).getField()) != 1
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
|
||||
VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
instr.getIRVariable().getAST() = ast and
|
||||
strictcount(instr.getIRVariable().getAST()) = 1
|
||||
}
|
||||
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
instr.getIRVariable().getAST() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
strictcount(instr.getResultIRType()) = 1 and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
@@ -139,42 +159,40 @@ private predicate fieldAddressValueNumber(
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getField() = field and
|
||||
strictcount(instr.getField()) = 1 and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
|
||||
private predicate binaryValueNumber(
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand,
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getLeft()) = leftOperand and
|
||||
tvalueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate pointerArithmeticValueNumber(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type,
|
||||
int elementSize, TValueNumber leftOperand, TValueNumber rightOperand
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
TValueNumber leftOperand, TValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getElementSize() = elementSize and
|
||||
tvalueNumber(instr.getLeft()) = leftOperand and
|
||||
tvalueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
@@ -194,9 +212,9 @@ private predicate loadTotalOverlapValueNumber(
|
||||
TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getAnOperand().(MemoryOperand).getAnyDef()) = memOperand and
|
||||
tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = operand
|
||||
tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = operand and
|
||||
instr.getResultIRType() = type
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,7 +224,11 @@ private predicate loadTotalOverlapValueNumber(
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
not numberableInstruction(instr)
|
||||
(
|
||||
not numberableInstruction(instr)
|
||||
or
|
||||
filteredNumberableInstruction(instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,12 +258,12 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(IRVariable var |
|
||||
variableAddressValueNumber(instr, irFunc, var) and
|
||||
result = TVariableAddressValueNumber(irFunc, var)
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(IRVariable var |
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
@@ -249,7 +271,7 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
@@ -264,14 +286,14 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand)
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, type, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, type, operand)
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
@@ -281,14 +303,10 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
|
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand,
|
||||
rightOperand) and
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
|
||||
@@ -96,7 +96,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getMemoryOperandDefinition(
|
||||
private Instruction getMemoryOperandDefinition0(
|
||||
Instruction instruction, MemoryOperandTag tag, Overlap overlap
|
||||
) {
|
||||
exists(OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand |
|
||||
@@ -142,6 +142,19 @@ private module Cached {
|
||||
overlap instanceof MustExactlyOverlap
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getMemoryOperandDefinition(
|
||||
Instruction instruction, MemoryOperandTag tag, Overlap overlap
|
||||
) {
|
||||
// getMemoryOperandDefinition0 currently has a bug where it can match with multiple overlaps.
|
||||
// This predicate ensures that the chosen overlap is the most conservative if there's any doubt.
|
||||
result = getMemoryOperandDefinition0(instruction, tag, overlap) and
|
||||
not (
|
||||
overlap instanceof MustExactlyOverlap and
|
||||
exists(MustTotallyOverlap o | exists(getMemoryOperandDefinition0(instruction, tag, o)))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
|
||||
* through a phi instruction and therefore should be impossible.
|
||||
|
||||
@@ -11,13 +11,19 @@ cached
|
||||
private newtype TOperand =
|
||||
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
|
||||
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
|
||||
not Construction::isInCycle(useInstr)
|
||||
not Construction::isInCycle(useInstr) and
|
||||
strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
|
||||
} or
|
||||
TNonPhiMemoryOperand(
|
||||
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
|
||||
) {
|
||||
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
|
||||
not Construction::isInCycle(useInstr)
|
||||
not Construction::isInCycle(useInstr) and
|
||||
(
|
||||
strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
|
||||
or
|
||||
tag instanceof UnmodeledUseOperandTag
|
||||
)
|
||||
} or
|
||||
TPhiOperand(
|
||||
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
|
||||
@@ -2,10 +2,10 @@ private import ValueNumberingImports
|
||||
private import cpp
|
||||
|
||||
newtype TValueNumber =
|
||||
TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
variableAddressValueNumber(_, irFunc, var)
|
||||
TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) {
|
||||
variableAddressValueNumber(_, irFunc, ast)
|
||||
} or
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) {
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
@@ -19,19 +19,18 @@ newtype TValueNumber =
|
||||
fieldAddressValueNumber(_, irFunc, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
IRFunction irFunc, Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand
|
||||
) {
|
||||
binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand)
|
||||
binaryValueNumber(_, irFunc, opcode, leftOperand, rightOperand)
|
||||
} or
|
||||
TPointerArithmeticValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand,
|
||||
IRFunction irFunc, Opcode opcode, int elementSize, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
} or
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, type, operand)
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, TValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, TValueNumber operand
|
||||
@@ -99,28 +98,49 @@ private predicate numberableInstruction(Instruction instr) {
|
||||
instr instanceof LoadTotalOverlapInstruction
|
||||
}
|
||||
|
||||
private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
// count rather than strictcount to handle missing AST elements
|
||||
// separate instanceof and inline casts to avoid failed casts with a count of 0
|
||||
instr instanceof VariableAddressInstruction and
|
||||
count(instr.(VariableAddressInstruction).getIRVariable().getAST()) != 1
|
||||
or
|
||||
instr instanceof ConstantInstruction and
|
||||
count(instr.getResultIRType()) != 1
|
||||
or
|
||||
instr instanceof FieldAddressInstruction and
|
||||
count(instr.(FieldAddressInstruction).getField()) != 1
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
|
||||
VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
instr.getIRVariable().getAST() = ast and
|
||||
strictcount(instr.getIRVariable().getAST()) = 1
|
||||
}
|
||||
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
instr.getIRVariable().getAST() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
strictcount(instr.getResultIRType()) = 1 and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
@@ -139,42 +159,40 @@ private predicate fieldAddressValueNumber(
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getField() = field and
|
||||
strictcount(instr.getField()) = 1 and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
|
||||
private predicate binaryValueNumber(
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand,
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getLeft()) = leftOperand and
|
||||
tvalueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate pointerArithmeticValueNumber(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type,
|
||||
int elementSize, TValueNumber leftOperand, TValueNumber rightOperand
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
TValueNumber leftOperand, TValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getElementSize() = elementSize and
|
||||
tvalueNumber(instr.getLeft()) = leftOperand and
|
||||
tvalueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
@@ -194,9 +212,9 @@ private predicate loadTotalOverlapValueNumber(
|
||||
TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getAnOperand().(MemoryOperand).getAnyDef()) = memOperand and
|
||||
tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = operand
|
||||
tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = operand and
|
||||
instr.getResultIRType() = type
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,7 +224,11 @@ private predicate loadTotalOverlapValueNumber(
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
not numberableInstruction(instr)
|
||||
(
|
||||
not numberableInstruction(instr)
|
||||
or
|
||||
filteredNumberableInstruction(instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,12 +258,12 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(IRVariable var |
|
||||
variableAddressValueNumber(instr, irFunc, var) and
|
||||
result = TVariableAddressValueNumber(irFunc, var)
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(IRVariable var |
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
@@ -249,7 +271,7 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
@@ -264,14 +286,14 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand)
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, type, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, type, operand)
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
@@ -281,14 +303,10 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
|
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand,
|
||||
rightOperand) and
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
|
||||
@@ -102,6 +102,19 @@ private module Cached {
|
||||
result = getMemoryOperandDefinition(instr, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a non-phi instruction that defines an operand of `instr` but only if
|
||||
* both `instr` and the result have neighbor on the other side of the edge
|
||||
* between them. This is a necessary condition for being in a cycle, and it
|
||||
* removes about two thirds of the tuples that would otherwise be in this
|
||||
* predicate.
|
||||
*/
|
||||
private Instruction getNonPhiOperandDefOfIntermediate(Instruction instr) {
|
||||
result = getNonPhiOperandDef(instr) and
|
||||
exists(getNonPhiOperandDef(result)) and
|
||||
instr = getNonPhiOperandDef(_)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
|
||||
* through a phi instruction and therefore should be impossible.
|
||||
@@ -115,7 +128,7 @@ private module Cached {
|
||||
cached
|
||||
predicate isInCycle(Instruction instr) {
|
||||
instr instanceof Instruction and
|
||||
getNonPhiOperandDef+(instr) = instr
|
||||
getNonPhiOperandDefOfIntermediate+(instr) = instr
|
||||
}
|
||||
|
||||
cached
|
||||
|
||||
@@ -11,13 +11,19 @@ cached
|
||||
private newtype TOperand =
|
||||
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
|
||||
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
|
||||
not Construction::isInCycle(useInstr)
|
||||
not Construction::isInCycle(useInstr) and
|
||||
strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
|
||||
} or
|
||||
TNonPhiMemoryOperand(
|
||||
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
|
||||
) {
|
||||
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
|
||||
not Construction::isInCycle(useInstr)
|
||||
not Construction::isInCycle(useInstr) and
|
||||
(
|
||||
strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
|
||||
or
|
||||
tag instanceof UnmodeledUseOperandTag
|
||||
)
|
||||
} or
|
||||
TPhiOperand(
|
||||
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
|
||||
@@ -2,10 +2,10 @@ private import ValueNumberingImports
|
||||
private import cpp
|
||||
|
||||
newtype TValueNumber =
|
||||
TVariableAddressValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
variableAddressValueNumber(_, irFunc, var)
|
||||
TVariableAddressValueNumber(IRFunction irFunc, Language::AST ast) {
|
||||
variableAddressValueNumber(_, irFunc, ast)
|
||||
} or
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, IRVariable var) {
|
||||
TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) {
|
||||
initializeParameterValueNumber(_, irFunc, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
|
||||
@@ -19,19 +19,18 @@ newtype TValueNumber =
|
||||
fieldAddressValueNumber(_, irFunc, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
IRFunction irFunc, Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand
|
||||
) {
|
||||
binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand)
|
||||
binaryValueNumber(_, irFunc, opcode, leftOperand, rightOperand)
|
||||
} or
|
||||
TPointerArithmeticValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand,
|
||||
IRFunction irFunc, Opcode opcode, int elementSize, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
pointerArithmeticValueNumber(_, irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
} or
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, type, operand)
|
||||
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, TValueNumber operand) {
|
||||
unaryValueNumber(_, irFunc, opcode, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(
|
||||
IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, TValueNumber operand
|
||||
@@ -99,28 +98,49 @@ private predicate numberableInstruction(Instruction instr) {
|
||||
instr instanceof LoadTotalOverlapInstruction
|
||||
}
|
||||
|
||||
private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
// count rather than strictcount to handle missing AST elements
|
||||
// separate instanceof and inline casts to avoid failed casts with a count of 0
|
||||
instr instanceof VariableAddressInstruction and
|
||||
count(instr.(VariableAddressInstruction).getIRVariable().getAST()) != 1
|
||||
or
|
||||
instr instanceof ConstantInstruction and
|
||||
count(instr.getResultIRType()) != 1
|
||||
or
|
||||
instr instanceof FieldAddressInstruction and
|
||||
count(instr.(FieldAddressInstruction).getField()) != 1
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
|
||||
VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
instr.getIRVariable().getAST() = ast and
|
||||
strictcount(instr.getIRVariable().getAST()) = 1
|
||||
}
|
||||
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getIRVariable() = var
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
instr.getIRVariable().getAST() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(
|
||||
predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
strictcount(instr.getResultIRType()) = 1 and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
@@ -139,42 +159,40 @@ private predicate fieldAddressValueNumber(
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getField() = field and
|
||||
strictcount(instr.getField()) = 1 and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
|
||||
private predicate binaryValueNumber(
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber leftOperand,
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getLeft()) = leftOperand and
|
||||
tvalueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate pointerArithmeticValueNumber(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type,
|
||||
int elementSize, TValueNumber leftOperand, TValueNumber rightOperand
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
TValueNumber leftOperand, TValueNumber rightOperand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getElementSize() = elementSize and
|
||||
tvalueNumber(instr.getLeft()) = leftOperand and
|
||||
tvalueNumber(instr.getRight()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, TValueNumber operand
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
|
||||
@@ -194,9 +212,9 @@ private predicate loadTotalOverlapValueNumber(
|
||||
TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
tvalueNumber(instr.getAnOperand().(MemoryOperand).getAnyDef()) = memOperand and
|
||||
tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = operand
|
||||
tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = operand and
|
||||
instr.getResultIRType() = type
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,7 +224,11 @@ private predicate loadTotalOverlapValueNumber(
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
not numberableInstruction(instr)
|
||||
(
|
||||
not numberableInstruction(instr)
|
||||
or
|
||||
filteredNumberableInstruction(instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,12 +258,12 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(IRVariable var |
|
||||
variableAddressValueNumber(instr, irFunc, var) and
|
||||
result = TVariableAddressValueNumber(irFunc, var)
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(IRVariable var |
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
@@ -249,7 +271,7 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
initializeThisValueNumber(instr, irFunc) and
|
||||
result = TInitializeThisValueNumber(irFunc)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
@@ -264,14 +286,14 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand)
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, IRType type, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, type, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, type, operand)
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
@@ -281,14 +303,10 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, IRType type, int elementSize, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
|
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand,
|
||||
rightOperand) and
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
|
||||
@@ -96,7 +96,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getMemoryOperandDefinition(
|
||||
private Instruction getMemoryOperandDefinition0(
|
||||
Instruction instruction, MemoryOperandTag tag, Overlap overlap
|
||||
) {
|
||||
exists(OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand |
|
||||
@@ -142,6 +142,19 @@ private module Cached {
|
||||
overlap instanceof MustExactlyOverlap
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getMemoryOperandDefinition(
|
||||
Instruction instruction, MemoryOperandTag tag, Overlap overlap
|
||||
) {
|
||||
// getMemoryOperandDefinition0 currently has a bug where it can match with multiple overlaps.
|
||||
// This predicate ensures that the chosen overlap is the most conservative if there's any doubt.
|
||||
result = getMemoryOperandDefinition0(instruction, tag, overlap) and
|
||||
not (
|
||||
overlap instanceof MustExactlyOverlap and
|
||||
exists(MustTotallyOverlap o | exists(getMemoryOperandDefinition0(instruction, tag, o)))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
|
||||
* through a phi instruction and therefore should be impossible.
|
||||
|
||||
@@ -97,6 +97,8 @@ class GVN extends TValueNumber {
|
||||
or
|
||||
this instanceof TInheritanceConversionValueNumber and result = "InheritanceConversion"
|
||||
or
|
||||
this instanceof TLoadTotalOverlapValueNumber and result = "LoadTotalOverlap"
|
||||
or
|
||||
this instanceof TUniqueValueNumber and result = "Unique"
|
||||
}
|
||||
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
* Support for tracking tainted data through the program.
|
||||
*/
|
||||
|
||||
import TaintTrackingImpl
|
||||
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking
|
||||
|
||||
@@ -1 +1 @@
|
||||
import GlobalValueNumberingImpl
|
||||
import semmle.code.cpp.ir.internal.ASTValueNumbering
|
||||
|
||||
@@ -15,39 +15,27 @@
|
||||
| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:23:38:28 | call to getenv | |
|
||||
| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:23:38:40 | (const char *)... | |
|
||||
| test.cpp:38:23:38:28 | call to getenv | test.cpp:40:14:40:19 | envStr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:8:24:8:25 | s1 | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:8:24:8:25 | s1 | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:45:13:45:24 | envStrGlobal | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:45:13:45:24 | envStrGlobal | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:14:49:19 | envStr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:28 | call to getenv | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:40 | (const char *)... | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:15:50:24 | envStr_ptr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:15:50:24 | envStr_ptr | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:28:50:40 | & ... | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:29:50:40 | envStrGlobal | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:2:52:12 | * ... | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:3:52:12 | envStr_ptr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:16:52:21 | envStr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:6:54:35 | ! ... | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:12 | call to strcmp | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:35 | (bool)... | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:14:54:25 | envStrGlobal | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:6:54:35 | ! ... | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:12 | call to strcmp | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:35 | (bool)... | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:14:54:25 | envStrGlobal | |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:10:27:10:27 | s | |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:18:60:25 | userName | |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:34 | call to getenv | |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:47 | (const char *)... | |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:25:64:32 | userName | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:11:20:11:21 | s1 | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:11:36:11:37 | s2 | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:67:7:67:13 | copying | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:17:68:24 | userName | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:28:68:33 | call to getenv | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:28:68:46 | (const char *)... | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:69:10:69:13 | copy | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:5:70:10 | call to strcpy | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:12:70:15 | copy | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:18:70:25 | userName | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:71:12:71:15 | copy | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:15:22:15:25 | nptr | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:15:75:18 | call to atoi | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:25 | call to getenv | |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import semmle.code.cpp.security.TaintTracking as AST
|
||||
import semmle.code.cpp.security.TaintTrackingImpl as AST
|
||||
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IR
|
||||
import cpp
|
||||
|
||||
|
||||
@@ -1,40 +1,42 @@
|
||||
| test.cpp:5:3:5:3 | x | 5:c3-c3 6:c3-c3 |
|
||||
| test.cpp:5:7:5:8 | p0 | 5:c7-c8 6:c7-c8 |
|
||||
| test.cpp:5:7:5:13 | ... + ... | 5:c7-c13 6:c7-c13 7:c7-c7 |
|
||||
| test.cpp:5:12:5:13 | p1 | 5:c12-c13 6:c12-c13 |
|
||||
| test.cpp:16:3:16:3 | x | 16:c3-c3 17:c3-c3 |
|
||||
| test.cpp:16:7:16:8 | p0 | 16:c7-c8 17:c7-c8 |
|
||||
| test.cpp:16:7:16:13 | ... + ... | 16:c7-c13 17:c7-c13 |
|
||||
| test.cpp:16:7:16:24 | ... + ... | 16:c7-c24 17:c7-c24 18:c7-c7 |
|
||||
| test.cpp:16:12:16:13 | p1 | 16:c12-c13 17:c12-c13 |
|
||||
| test.cpp:16:17:16:24 | global01 | 16:c17-c24 17:c17-c24 |
|
||||
| test.cpp:29:7:29:8 | p0 | 29:c7-c8 31:c7-c8 |
|
||||
| test.cpp:29:7:29:13 | ... + ... | 29:c7-c13 31:c7-c13 |
|
||||
| test.cpp:29:12:29:13 | p1 | 29:c12-c13 31:c12-c13 |
|
||||
| test.cpp:31:7:31:24 | ... + ... | 31:c7-c24 32:c7-c7 |
|
||||
| test.cpp:43:7:43:8 | p0 | 43:c7-c8 45:c7-c8 |
|
||||
| test.cpp:43:7:43:13 | ... + ... | 43:c7-c13 45:c7-c13 |
|
||||
| test.cpp:43:12:43:13 | p1 | 43:c12-c13 45:c12-c13 |
|
||||
| test.cpp:44:9:44:9 | 0 | 44:c9-c9 51:c25-c25 53:c18-c21 56:c39-c42 59:c17-c20 88:c12-c12 |
|
||||
| test.cpp:45:7:45:24 | ... + ... | 45:c7-c24 46:c7-c7 |
|
||||
| test.cpp:53:10:53:13 | (int)... | 53:c10-c13 56:c21-c24 |
|
||||
| test.cpp:53:10:53:13 | * ... | 53:c10-c13 56:c21-c24 |
|
||||
| test.cpp:53:11:53:13 | str | 53:c11-c13 56:c22-c24 |
|
||||
| test.cpp:53:18:53:21 | 0 | 53:c18-c21 56:c39-c42 59:c17-c20 |
|
||||
| test.cpp:56:13:56:16 | (int)... | 56:c13-c16 56:c31-c34 59:c9-c12 |
|
||||
| test.cpp:56:13:56:16 | * ... | 56:c13-c16 56:c31-c34 59:c9-c12 |
|
||||
| test.cpp:56:14:56:16 | ptr | 56:c14-c16 56:c32-c34 56:c47-c49 59:c10-c12 |
|
||||
| test.cpp:62:5:62:10 | result | 62:c5-c10 65:c10-c15 |
|
||||
| test.cpp:77:20:77:30 | (signed short)... | 77:c20-c30 79:c7-c7 |
|
||||
| test.cpp:79:11:79:14 | vals | 79:c11-c14 79:c24-c27 |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | 105:c11-c12 106:c14-c35 107:c11-c12 |
|
||||
| test.cpp:105:11:105:12 | pd | 105:c11-c12 106:c33-c34 |
|
||||
| test.cpp:105:15:105:15 | b | 105:c15-c15 107:c15-c15 109:c10-c10 |
|
||||
| test.cpp:125:11:125:12 | pa | 125:c11-c12 126:c11-c12 128:c3-c4 129:c11-c12 |
|
||||
| test.cpp:125:15:125:15 | x | 125:c15-c15 126:c15-c15 128:c7-c7 |
|
||||
| test.cpp:136:11:136:18 | global_a | 136:c11-c18 137:c11-c18 139:c3-c10 |
|
||||
| test.cpp:136:21:136:21 | x | 136:c21-c21 137:c21-c21 139:c13-c13 |
|
||||
| test.cpp:144:11:144:12 | pa | 144:c11-c12 145:c11-c12 147:c3-c4 149:c11-c12 |
|
||||
| test.cpp:145:15:145:15 | y | 145:c15-c15 147:c7-c7 |
|
||||
| test.cpp:153:11:153:18 | global_a | 153:c11-c18 154:c11-c18 156:c3-c10 |
|
||||
| test.cpp:153:21:153:21 | x | 153:c21-c21 154:c21-c21 |
|
||||
| test.cpp:5:3:5:3 | GVN | 5:c3-c3 6:c3-c3 |
|
||||
| test.cpp:5:7:5:8 | GVN | 5:c7-c8 6:c7-c8 |
|
||||
| test.cpp:5:7:5:13 | GVN | 5:c7-c13 6:c7-c13 7:c7-c7 |
|
||||
| test.cpp:5:12:5:13 | GVN | 5:c12-c13 6:c12-c13 |
|
||||
| test.cpp:16:3:16:3 | GVN | 16:c3-c3 17:c3-c3 |
|
||||
| test.cpp:16:7:16:8 | GVN | 16:c7-c8 17:c7-c8 |
|
||||
| test.cpp:16:7:16:13 | GVN | 16:c7-c13 17:c7-c13 |
|
||||
| test.cpp:16:7:16:24 | GVN | 16:c7-c24 17:c7-c24 18:c7-c7 |
|
||||
| test.cpp:16:12:16:13 | GVN | 16:c12-c13 17:c12-c13 |
|
||||
| test.cpp:16:17:16:24 | GVN | 16:c17-c24 17:c17-c24 |
|
||||
| test.cpp:29:3:29:3 | GVN | 29:c3-c3 31:c3-c3 |
|
||||
| test.cpp:29:7:29:8 | GVN | 29:c7-c8 31:c7-c8 |
|
||||
| test.cpp:29:7:29:13 | GVN | 29:c7-c13 31:c7-c13 |
|
||||
| test.cpp:29:12:29:13 | GVN | 29:c12-c13 31:c12-c13 |
|
||||
| test.cpp:31:7:31:24 | GVN | 31:c7-c24 32:c7-c7 |
|
||||
| test.cpp:43:3:43:3 | GVN | 43:c3-c3 45:c3-c3 |
|
||||
| test.cpp:43:7:43:8 | GVN | 43:c7-c8 45:c7-c8 |
|
||||
| test.cpp:43:7:43:13 | GVN | 43:c7-c13 45:c7-c13 |
|
||||
| test.cpp:43:7:43:24 | GVN | 43:c7-c24 45:c7-c24 46:c7-c7 |
|
||||
| test.cpp:43:12:43:13 | GVN | 43:c12-c13 45:c12-c13 |
|
||||
| test.cpp:43:17:43:24 | GVN | 43:c17-c24 45:c17-c24 |
|
||||
| test.cpp:44:3:44:5 | GVN | 44:c3-c5 44:c4-c5 |
|
||||
| test.cpp:53:10:53:13 | GVN | 53:c10-c13 56:c21-c24 |
|
||||
| test.cpp:53:10:53:13 | GVN | 53:c10-c13 56:c21-c24 |
|
||||
| test.cpp:53:11:53:13 | GVN | 53:c11-c13 56:c22-c24 |
|
||||
| test.cpp:53:18:53:21 | GVN | 53:c18-c21 56:c39-c42 59:c17-c20 |
|
||||
| test.cpp:56:14:56:16 | GVN | 56:c14-c16 56:c32-c34 56:c47-c49 59:c10-c12 |
|
||||
| test.cpp:62:5:62:10 | GVN | 62:c5-c10 65:c10-c15 |
|
||||
| test.cpp:77:20:77:28 | GVN | 77:c20-c28 79:c7-c7 |
|
||||
| test.cpp:79:11:79:14 | GVN | 79:c11-c14 79:c24-c27 |
|
||||
| test.cpp:92:11:92:16 | GVN | 92:c11-c16 92:c15-c16 93:c10-c10 |
|
||||
| test.cpp:105:11:105:12 | GVN | 105:c11-c12 106:c33-c34 |
|
||||
| test.cpp:105:11:105:12 | GVN | 105:c11-c12 106:c33-c34 107:c11-c12 |
|
||||
| test.cpp:105:15:105:15 | GVN | 105:c15-c15 107:c15-c15 109:c10-c10 |
|
||||
| test.cpp:113:3:113:5 | GVN | 113:c3-c5 115:c3-c5 |
|
||||
| test.cpp:125:11:125:12 | GVN | 125:c11-c12 126:c11-c12 128:c3-c4 129:c11-c12 |
|
||||
| test.cpp:125:15:125:15 | GVN | 125:c15-c15 126:c15-c15 |
|
||||
| test.cpp:128:11:128:11 | GVN | 128:c11-c11 129:c15-c15 |
|
||||
| test.cpp:136:11:136:18 | GVN | 136:c11-c18 137:c11-c18 139:c3-c10 |
|
||||
| test.cpp:144:11:144:12 | GVN | 144:c11-c12 145:c11-c12 147:c3-c4 149:c11-c12 |
|
||||
| test.cpp:144:15:144:15 | GVN | 144:c15-c15 149:c15-c15 |
|
||||
| test.cpp:153:11:153:18 | GVN | 153:c11-c18 154:c11-c18 156:c3-c10 |
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
| test.cpp:5:3:5:13 | ... = ... | |
|
||||
| test.cpp:6:3:6:13 | ... = ... | |
|
||||
| test.cpp:7:3:7:7 | ... = ... | |
|
||||
| test.cpp:10:16:10:16 | 1 | |
|
||||
| test.cpp:16:3:16:24 | ... = ... | |
|
||||
| test.cpp:17:3:17:24 | ... = ... | |
|
||||
| test.cpp:18:3:18:7 | ... = ... | |
|
||||
| test.cpp:21:16:21:16 | 2 | |
|
||||
| test.cpp:29:3:29:24 | ... = ... | |
|
||||
| test.cpp:30:3:30:17 | call to change_global02 | |
|
||||
| test.cpp:31:3:31:24 | ... = ... | |
|
||||
| test.cpp:32:3:32:7 | ... = ... | |
|
||||
| test.cpp:35:16:35:16 | 3 | |
|
||||
| test.cpp:43:3:43:24 | ... = ... | |
|
||||
| test.cpp:44:3:44:9 | ... = ... | |
|
||||
| test.cpp:45:3:45:24 | ... = ... | |
|
||||
| test.cpp:46:3:46:7 | ... = ... | |
|
||||
| test.cpp:51:25:51:25 | (unsigned int)... | |
|
||||
| test.cpp:53:10:53:13 | (int)... | |
|
||||
| test.cpp:53:10:53:13 | * ... | LoadTotalOverlap, Unary |
|
||||
| test.cpp:53:18:53:21 | (int)... | |
|
||||
| test.cpp:55:5:55:15 | ... = ... | |
|
||||
| test.cpp:56:12:56:25 | (...) | |
|
||||
| test.cpp:56:12:56:43 | ... && ... | |
|
||||
| test.cpp:56:13:56:16 | (int)... | |
|
||||
| test.cpp:56:13:56:16 | * ... | Unary, Unique |
|
||||
| test.cpp:56:21:56:24 | (int)... | |
|
||||
| test.cpp:56:21:56:24 | * ... | LoadTotalOverlap, Unary |
|
||||
| test.cpp:56:30:56:43 | (...) | |
|
||||
| test.cpp:56:31:56:34 | (int)... | |
|
||||
| test.cpp:56:31:56:34 | * ... | Unary, Unique |
|
||||
| test.cpp:56:39:56:42 | (int)... | |
|
||||
| test.cpp:56:47:56:51 | ... ++ | |
|
||||
| test.cpp:59:9:59:12 | (int)... | |
|
||||
| test.cpp:59:9:59:12 | * ... | Unary, Unique |
|
||||
| test.cpp:59:17:59:20 | (int)... | |
|
||||
| test.cpp:62:5:62:12 | ... ++ | |
|
||||
| test.cpp:77:20:77:28 | call to getAValue | Unary, Unique |
|
||||
| test.cpp:77:20:77:30 | (signed short)... | |
|
||||
| test.cpp:79:7:79:7 | (int)... | |
|
||||
| test.cpp:79:7:79:7 | v | Unary, Unary |
|
||||
| test.cpp:79:11:79:20 | (int)... | |
|
||||
| test.cpp:79:17:79:20 | val1 | LoadTotalOverlap, Unary |
|
||||
| test.cpp:79:24:79:33 | (int)... | |
|
||||
| test.cpp:79:30:79:33 | val2 | LoadTotalOverlap, Unary |
|
||||
| test.cpp:80:5:80:19 | ... = ... | |
|
||||
| test.cpp:80:9:80:17 | call to getAValue | Unary, Unique |
|
||||
| test.cpp:80:9:80:19 | (signed short)... | |
|
||||
| test.cpp:88:3:88:20 | ... = ... | |
|
||||
| test.cpp:88:12:88:12 | (void *)... | |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | |
|
||||
| test.cpp:105:11:105:12 | pd | InheritanceConversion, InitializeParameter |
|
||||
| test.cpp:106:14:106:35 | static_cast<Base *>... | |
|
||||
| test.cpp:106:33:106:34 | pd | InheritanceConversion, InitializeParameter |
|
||||
| test.cpp:128:3:128:11 | ... = ... | |
|
||||
| test.cpp:139:3:139:24 | ... = ... | |
|
||||
| test.cpp:147:3:147:18 | ... = ... | |
|
||||
| test.cpp:156:3:156:17 | ... = ... | |
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
| test.cpp:5:3:5:13 | ... = ... | test.cpp:5:3:5:13 | ... = ... | AST only |
|
||||
| test.cpp:6:3:6:13 | ... = ... | test.cpp:6:3:6:13 | ... = ... | AST only |
|
||||
| test.cpp:7:3:7:7 | ... = ... | test.cpp:7:3:7:7 | ... = ... | AST only |
|
||||
| test.cpp:10:16:10:16 | 1 | test.cpp:10:16:10:16 | 1 | AST only |
|
||||
| test.cpp:16:3:16:24 | ... = ... | test.cpp:16:3:16:24 | ... = ... | AST only |
|
||||
| test.cpp:17:3:17:24 | ... = ... | test.cpp:17:3:17:24 | ... = ... | AST only |
|
||||
| test.cpp:18:3:18:7 | ... = ... | test.cpp:18:3:18:7 | ... = ... | AST only |
|
||||
| test.cpp:21:16:21:16 | 2 | test.cpp:21:16:21:16 | 2 | AST only |
|
||||
| test.cpp:29:3:29:3 | x | test.cpp:31:3:31:3 | x | IR only |
|
||||
| test.cpp:29:3:29:24 | ... = ... | test.cpp:29:3:29:24 | ... = ... | AST only |
|
||||
| test.cpp:30:3:30:17 | call to change_global02 | test.cpp:30:3:30:17 | call to change_global02 | AST only |
|
||||
| test.cpp:31:3:31:3 | x | test.cpp:29:3:29:3 | x | IR only |
|
||||
| test.cpp:31:3:31:24 | ... = ... | test.cpp:31:3:31:24 | ... = ... | AST only |
|
||||
| test.cpp:32:3:32:7 | ... = ... | test.cpp:32:3:32:7 | ... = ... | AST only |
|
||||
| test.cpp:35:16:35:16 | 3 | test.cpp:35:16:35:16 | 3 | AST only |
|
||||
| test.cpp:43:3:43:3 | x | test.cpp:45:3:45:3 | x | IR only |
|
||||
| test.cpp:43:3:43:24 | ... = ... | test.cpp:43:3:43:24 | ... = ... | AST only |
|
||||
| test.cpp:43:7:43:24 | ... + ... | test.cpp:45:7:45:24 | ... + ... | IR only |
|
||||
| test.cpp:43:7:43:24 | ... + ... | test.cpp:46:7:46:7 | x | IR only |
|
||||
| test.cpp:43:17:43:24 | global03 | test.cpp:45:17:45:24 | global03 | IR only |
|
||||
| test.cpp:44:3:44:5 | * ... | test.cpp:44:4:44:5 | p2 | IR only |
|
||||
| test.cpp:44:3:44:9 | ... = ... | test.cpp:44:3:44:9 | ... = ... | AST only |
|
||||
| test.cpp:44:4:44:5 | p2 | test.cpp:44:3:44:5 | * ... | IR only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:45:3:45:3 | x | test.cpp:43:3:43:3 | x | IR only |
|
||||
| test.cpp:45:3:45:24 | ... = ... | test.cpp:45:3:45:24 | ... = ... | AST only |
|
||||
| test.cpp:45:7:45:24 | ... + ... | test.cpp:43:7:43:24 | ... + ... | IR only |
|
||||
| test.cpp:45:17:45:24 | global03 | test.cpp:43:17:43:24 | global03 | IR only |
|
||||
| test.cpp:46:3:46:7 | ... = ... | test.cpp:46:3:46:7 | ... = ... | AST only |
|
||||
| test.cpp:46:7:46:7 | x | test.cpp:43:7:43:24 | ... + ... | IR only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:51:25:51:25 | (unsigned int)... | test.cpp:51:25:51:25 | (unsigned int)... | AST only |
|
||||
| test.cpp:53:10:53:13 | (int)... | test.cpp:53:10:53:13 | (int)... | AST only |
|
||||
| test.cpp:53:10:53:13 | (int)... | test.cpp:56:21:56:24 | (int)... | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:55:5:55:15 | ... = ... | test.cpp:55:5:55:15 | ... = ... | AST only |
|
||||
| test.cpp:56:12:56:25 | (...) | test.cpp:56:12:56:25 | (...) | AST only |
|
||||
| test.cpp:56:12:56:43 | ... && ... | test.cpp:56:12:56:43 | ... && ... | AST only |
|
||||
| test.cpp:56:13:56:16 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
|
||||
| test.cpp:56:13:56:16 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
|
||||
| test.cpp:56:13:56:16 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
|
||||
| test.cpp:56:13:56:16 | * ... | test.cpp:56:31:56:34 | * ... | AST only |
|
||||
| test.cpp:56:13:56:16 | * ... | test.cpp:59:9:59:12 | * ... | AST only |
|
||||
| test.cpp:56:21:56:24 | (int)... | test.cpp:53:10:53:13 | (int)... | AST only |
|
||||
| test.cpp:56:21:56:24 | (int)... | test.cpp:56:21:56:24 | (int)... | AST only |
|
||||
| test.cpp:56:30:56:43 | (...) | test.cpp:56:30:56:43 | (...) | AST only |
|
||||
| test.cpp:56:31:56:34 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
|
||||
| test.cpp:56:31:56:34 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
|
||||
| test.cpp:56:31:56:34 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
|
||||
| test.cpp:56:31:56:34 | * ... | test.cpp:56:13:56:16 | * ... | AST only |
|
||||
| test.cpp:56:31:56:34 | * ... | test.cpp:59:9:59:12 | * ... | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:56:47:56:51 | ... ++ | test.cpp:56:47:56:51 | ... ++ | AST only |
|
||||
| test.cpp:59:9:59:12 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
|
||||
| test.cpp:59:9:59:12 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
|
||||
| test.cpp:59:9:59:12 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
|
||||
| test.cpp:59:9:59:12 | * ... | test.cpp:56:13:56:16 | * ... | AST only |
|
||||
| test.cpp:59:9:59:12 | * ... | test.cpp:56:31:56:34 | * ... | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:62:5:62:12 | ... ++ | test.cpp:62:5:62:12 | ... ++ | AST only |
|
||||
| test.cpp:77:20:77:28 | call to getAValue | test.cpp:79:7:79:7 | v | IR only |
|
||||
| test.cpp:77:20:77:30 | (signed short)... | test.cpp:77:20:77:30 | (signed short)... | AST only |
|
||||
| test.cpp:77:20:77:30 | (signed short)... | test.cpp:79:7:79:7 | v | AST only |
|
||||
| test.cpp:79:7:79:7 | (int)... | test.cpp:79:7:79:7 | (int)... | AST only |
|
||||
| test.cpp:79:7:79:7 | v | test.cpp:77:20:77:28 | call to getAValue | IR only |
|
||||
| test.cpp:79:7:79:7 | v | test.cpp:77:20:77:30 | (signed short)... | AST only |
|
||||
| test.cpp:79:11:79:20 | (int)... | test.cpp:79:11:79:20 | (int)... | AST only |
|
||||
| test.cpp:79:24:79:33 | (int)... | test.cpp:79:24:79:33 | (int)... | AST only |
|
||||
| test.cpp:80:5:80:19 | ... = ... | test.cpp:80:5:80:19 | ... = ... | AST only |
|
||||
| test.cpp:80:9:80:19 | (signed short)... | test.cpp:80:9:80:19 | (signed short)... | AST only |
|
||||
| test.cpp:88:3:88:20 | ... = ... | test.cpp:88:3:88:20 | ... = ... | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:88:12:88:12 | (void *)... | test.cpp:88:12:88:12 | (void *)... | AST only |
|
||||
| test.cpp:92:11:92:16 | ... = ... | test.cpp:92:15:92:16 | 10 | IR only |
|
||||
| test.cpp:92:11:92:16 | ... = ... | test.cpp:93:10:93:10 | x | IR only |
|
||||
| test.cpp:92:15:92:16 | 10 | test.cpp:92:11:92:16 | ... = ... | IR only |
|
||||
| test.cpp:92:15:92:16 | 10 | test.cpp:93:10:93:10 | x | IR only |
|
||||
| test.cpp:93:10:93:10 | x | test.cpp:92:11:92:16 | ... = ... | IR only |
|
||||
| test.cpp:93:10:93:10 | x | test.cpp:92:15:92:16 | 10 | IR only |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | test.cpp:105:11:105:12 | (Base *)... | AST only |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | test.cpp:106:14:106:35 | static_cast<Base *>... | AST only |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | test.cpp:107:11:107:12 | pb | AST only |
|
||||
| test.cpp:105:11:105:12 | pd | test.cpp:107:11:107:12 | pb | IR only |
|
||||
| test.cpp:106:14:106:35 | static_cast<Base *>... | test.cpp:105:11:105:12 | (Base *)... | AST only |
|
||||
| test.cpp:106:14:106:35 | static_cast<Base *>... | test.cpp:106:14:106:35 | static_cast<Base *>... | AST only |
|
||||
| test.cpp:106:14:106:35 | static_cast<Base *>... | test.cpp:107:11:107:12 | pb | AST only |
|
||||
| test.cpp:106:33:106:34 | pd | test.cpp:107:11:107:12 | pb | IR only |
|
||||
| test.cpp:107:11:107:12 | pb | test.cpp:105:11:105:12 | (Base *)... | AST only |
|
||||
| test.cpp:107:11:107:12 | pb | test.cpp:105:11:105:12 | pd | IR only |
|
||||
| test.cpp:107:11:107:12 | pb | test.cpp:106:14:106:35 | static_cast<Base *>... | AST only |
|
||||
| test.cpp:107:11:107:12 | pb | test.cpp:106:33:106:34 | pd | IR only |
|
||||
| test.cpp:113:3:113:5 | a | test.cpp:115:3:115:5 | a | IR only |
|
||||
| test.cpp:115:3:115:5 | a | test.cpp:113:3:113:5 | a | IR only |
|
||||
| test.cpp:125:15:125:15 | x | test.cpp:128:7:128:7 | x | AST only |
|
||||
| test.cpp:126:15:126:15 | x | test.cpp:128:7:128:7 | x | AST only |
|
||||
| test.cpp:128:3:128:11 | ... = ... | test.cpp:128:3:128:11 | ... = ... | AST only |
|
||||
| test.cpp:128:7:128:7 | x | test.cpp:125:15:125:15 | x | AST only |
|
||||
| test.cpp:128:7:128:7 | x | test.cpp:126:15:126:15 | x | AST only |
|
||||
| test.cpp:128:11:128:11 | n | test.cpp:129:15:129:15 | x | IR only |
|
||||
| test.cpp:129:15:129:15 | x | test.cpp:128:11:128:11 | n | IR only |
|
||||
| test.cpp:136:21:136:21 | x | test.cpp:137:21:137:21 | x | AST only |
|
||||
| test.cpp:136:21:136:21 | x | test.cpp:139:13:139:13 | x | AST only |
|
||||
| test.cpp:137:21:137:21 | x | test.cpp:136:21:136:21 | x | AST only |
|
||||
| test.cpp:137:21:137:21 | x | test.cpp:139:13:139:13 | x | AST only |
|
||||
| test.cpp:139:3:139:24 | ... = ... | test.cpp:139:3:139:24 | ... = ... | AST only |
|
||||
| test.cpp:139:13:139:13 | x | test.cpp:136:21:136:21 | x | AST only |
|
||||
| test.cpp:139:13:139:13 | x | test.cpp:137:21:137:21 | x | AST only |
|
||||
| test.cpp:144:15:144:15 | x | test.cpp:149:15:149:15 | x | IR only |
|
||||
| test.cpp:145:15:145:15 | y | test.cpp:147:7:147:7 | y | AST only |
|
||||
| test.cpp:147:3:147:18 | ... = ... | test.cpp:147:3:147:18 | ... = ... | AST only |
|
||||
| test.cpp:147:7:147:7 | y | test.cpp:145:15:145:15 | y | AST only |
|
||||
| test.cpp:149:15:149:15 | x | test.cpp:144:15:144:15 | x | IR only |
|
||||
| test.cpp:153:21:153:21 | x | test.cpp:154:21:154:21 | x | AST only |
|
||||
| test.cpp:154:21:154:21 | x | test.cpp:153:21:153:21 | x | AST only |
|
||||
| test.cpp:156:3:156:17 | ... = ... | test.cpp:156:3:156:17 | ... = ... | AST only |
|
||||
|
||||
@@ -12,6 +12,5 @@
|
||||
| test.cpp:46:2:46:9 | call to strcpy_s | Potentially unsafe call to strcpy_s; second argument should be size of destination. |
|
||||
| test.cpp:47:2:47:9 | call to strcpy_s | Potentially unsafe call to strcpy_s; second argument should be size of destination. |
|
||||
| test.cpp:60:3:60:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:63:3:63:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:68:2:68:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:79:3:79:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:82:3:82:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
| tests.c:28:3:28:9 | call to sprintf | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv |
|
||||
| tests.c:29:3:29:9 | call to sprintf | This 'call to sprintf' with input from $@ may overflow the destination. | tests.c:29:28:29:31 | argv | argv |
|
||||
| tests.c:31:15:31:23 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv |
|
||||
| tests.c:31:15:31:23 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:29:28:29:31 | argv | argv |
|
||||
| tests.c:31:15:31:23 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:31:15:31:23 | buffer100 | buffer100 |
|
||||
| tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:28:22:28:25 | argv | argv |
|
||||
| tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:29:28:29:31 | argv | argv |
|
||||
| tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:31:15:31:23 | buffer100 | buffer100 |
|
||||
| tests.c:33:21:33:29 | buffer100 | This 'scanf string argument' with input from $@ may overflow the destination. | tests.c:33:21:33:29 | buffer100 | buffer100 |
|
||||
| tests.c:34:25:34:33 | buffer100 | This 'sscanf string argument' with input from $@ may overflow the destination. | tests.c:34:10:34:13 | argv | argv |
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
| test1.c:18:16:18:16 | i | $@ flows to here and is used in an array indexing expression, potentially causing an invalid access. | test1.c:8:16:8:19 | argv | User-provided value |
|
||||
| test1.c:33:11:33:11 | i | $@ flows to here and is used in an array indexing expression, potentially causing an invalid access. | test1.c:8:16:8:19 | argv | User-provided value |
|
||||
| test1.c:37:11:37:11 | i | $@ flows to here and is used in an array indexing expression, potentially causing an invalid access. | test1.c:8:16:8:19 | argv | User-provided value |
|
||||
| test1.c:53:15:53:15 | j | $@ flows to here and is used in an array indexing expression, potentially causing an invalid access. | test1.c:8:16:8:19 | argv | User-provided value |
|
||||
|
||||
@@ -16,15 +16,7 @@
|
||||
| argvLocal.c:132:15:132:20 | ... + ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:126:10:126:13 | argv | argv |
|
||||
| argvLocal.c:135:9:135:12 | ... ++ | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:115:13:115:16 | argv | argv |
|
||||
| argvLocal.c:136:15:136:18 | -- ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:115:13:115:16 | argv | argv |
|
||||
| argvLocal.c:139:9:139:26 | ... ? ... : ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:126:10:126:13 | argv | argv |
|
||||
| argvLocal.c:140:15:140:32 | ... ? ... : ... | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:126:10:126:13 | argv | argv |
|
||||
| argvLocal.c:144:9:144:10 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:100:7:100:10 | argv | argv |
|
||||
| argvLocal.c:145:15:145:16 | i7 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:100:7:100:10 | argv | argv |
|
||||
| argvLocal.c:150:9:150:10 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:149:15:149:18 | argv | argv |
|
||||
| argvLocal.c:151:15:151:16 | i8 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:149:15:149:18 | argv | argv |
|
||||
| argvLocal.c:156:9:156:10 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:155:23:155:26 | argv | argv |
|
||||
| argvLocal.c:157:15:157:16 | i9 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:155:23:155:26 | argv | argv |
|
||||
| argvLocal.c:162:9:162:11 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:161:42:161:45 | argv | argv |
|
||||
| argvLocal.c:163:15:163:17 | i91 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:161:42:161:45 | argv | argv |
|
||||
| argvLocal.c:167:18:167:20 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | argvLocal.c:166:18:166:21 | argv | argv |
|
||||
| argvLocal.c:168:24:168:26 | i10 | The value of this argument may come from $@ and is being used as a formatting argument to printWrapper(correct), which calls printf(format) | argvLocal.c:166:18:166:21 | argv | argv |
|
||||
|
||||
@@ -3,6 +3,3 @@
|
||||
| funcsLocal.c:32:9:32:10 | i4 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:31:13:31:17 | call to fgets | fgets |
|
||||
| funcsLocal.c:37:9:37:10 | i5 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:36:7:36:8 | i5 | gets |
|
||||
| funcsLocal.c:42:9:42:10 | i6 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:41:13:41:16 | call to gets | gets |
|
||||
| funcsLocal.c:47:9:47:11 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:46:7:46:9 | * ... | gets |
|
||||
| funcsLocal.c:53:9:53:11 | * ... | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:52:8:52:11 | call to gets | gets |
|
||||
| funcsLocal.c:58:9:58:10 | e1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | funcsLocal.c:16:8:16:9 | i1 | fread |
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
| ifs.c:62:9:62:10 | c7 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:61:8:61:11 | argv | argv |
|
||||
| ifs.c:69:9:69:10 | c8 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:68:8:68:11 | argv | argv |
|
||||
| ifs.c:75:9:75:10 | i1 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:74:8:74:11 | argv | argv |
|
||||
| ifs.c:81:9:81:10 | i2 | The value of this argument may come from $@ and is being used as a formatting argument to printf(format) | ifs.c:80:8:80:11 | argv | argv |
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
| test.cpp:42:31:42:36 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:43:31:43:36 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:45:31:45:36 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:48:25:48:30 | call to malloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:49:17:49:30 | new[] | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:52:21:52:27 | call to realloc | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:52:35:52:60 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
| test.cpp:55:11:55:24 | new[] | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
| test.c:17:10:17:12 | min | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:8:9:8:15 | 2147483647 | Extreme value |
|
||||
| test.c:48:3:48:5 | sc2 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:47:9:47:16 | - ... | Extreme value |
|
||||
| test.c:50:3:50:5 | sc3 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:49:9:49:16 | 127 | Extreme value |
|
||||
| test.c:56:3:56:5 | sc5 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:54:9:54:16 | 127 | Extreme value |
|
||||
| test.c:59:3:59:5 | sc6 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:58:9:58:16 | 127 | Extreme value |
|
||||
| test.c:63:3:63:5 | sc8 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:62:9:62:16 | - ... | Extreme value |
|
||||
| test.c:75:3:75:5 | sc1 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:74:9:74:16 | 127 | Extreme value |
|
||||
|
||||
@@ -8,4 +8,3 @@
|
||||
| test.c:77:9:77:9 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:75:13:75:19 | ... ^ ... | Uncontrolled value |
|
||||
| test.c:100:5:100:5 | r | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:99:14:99:19 | call to rand | Uncontrolled value |
|
||||
| test.cpp:25:7:25:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:8:9:8:12 | call to rand | Uncontrolled value |
|
||||
| test.cpp:37:7:37:7 | r | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.cpp:18:9:18:12 | call to rand | Uncontrolled value |
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
| test.cpp:24:10:24:35 | ! ... | Reliance on untrusted input $@ to raise privilege at $@ | test.cpp:20:29:20:34 | call to getenv | call to getenv | test.cpp:25:9:25:27 | ... = ... | ... = ... |
|
||||
| test.cpp:41:10:41:38 | ! ... | Reliance on untrusted input $@ to raise privilege at $@ | test.cpp:20:29:20:34 | call to getenv | call to getenv | test.cpp:42:8:42:26 | ... = ... | ... = ... |
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
@@ -9,10 +10,12 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteSubId(Location);
|
||||
trapFile.Write('_');
|
||||
trapFile.Write(symbol.Name);
|
||||
trapFile.Write(";localvar");
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public override void WriteQuotedId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write('*');
|
||||
}
|
||||
|
||||
public override void Populate(TextWriter trapFile) { }
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Semmle.Extraction
|
||||
|
||||
public abstract void WriteId(System.IO.TextWriter trapFile);
|
||||
|
||||
public void WriteQuotedId(TextWriter trapFile)
|
||||
public virtual void WriteQuotedId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write("@\"");
|
||||
WriteId(trapFile);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
import semmle.code.csharp.serialization.Serialization
|
||||
import semmle.code.csharp.controlflow.Guards
|
||||
import semmle.code.csharp.dataflow.DataFlow
|
||||
|
||||
/**
|
||||
* The result is a write to the field `f`, assigning it the value
|
||||
@@ -29,7 +30,11 @@ GuardedExpr checkedWrite(Field f, Variable v, IfStmt check) {
|
||||
Expr uncheckedWrite(Callable callable, Field f) {
|
||||
result = f.getAnAssignedValue() and
|
||||
result.getEnclosingCallable() = callable and
|
||||
not callable.calls*(checkedWrite(f, _, _).getEnclosingCallable())
|
||||
not callable.calls*(checkedWrite(f, _, _).getEnclosingCallable()) and
|
||||
// Exclude object creations because they were not deserialized
|
||||
not exists(Expr src | DataFlow::localExprFlow(src, result) |
|
||||
src instanceof ObjectCreation or src.hasValue()
|
||||
)
|
||||
}
|
||||
|
||||
from BinarySerializableType t, Field f, IfStmt check, Expr write, Expr unsafeWrite
|
||||
|
||||
@@ -50,7 +50,7 @@ module Stages {
|
||||
cached
|
||||
module DataFlowStage {
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon::Public
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon
|
||||
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate
|
||||
|
||||
cached
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@ private import cil
|
||||
private import dotnet
|
||||
private import DataFlowPublic
|
||||
private import DataFlowDispatch
|
||||
private import DataFlowImplCommon::Public
|
||||
private import DataFlowImplCommon
|
||||
private import ControlFlowReachability
|
||||
private import DelegateDataFlow
|
||||
private import semmle.code.csharp.Caching
|
||||
@@ -380,7 +380,9 @@ private module Cached {
|
||||
a = cfn.getElement() and
|
||||
t = a.stripCasts().getType()
|
||||
|
|
||||
t instanceof RefType or
|
||||
t instanceof RefType and
|
||||
not t instanceof NullType
|
||||
or
|
||||
t = any(TypeParameter tp | not tp.isValueType())
|
||||
)
|
||||
or
|
||||
@@ -1495,3 +1497,5 @@ private predicate viableConstantBooleanParamArg(
|
||||
b = arg.getBooleanValue()
|
||||
)
|
||||
}
|
||||
|
||||
int accessPathLimit() { result = 3 }
|
||||
|
||||
@@ -11,13 +11,19 @@ cached
|
||||
private newtype TOperand =
|
||||
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
|
||||
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
|
||||
not Construction::isInCycle(useInstr)
|
||||
not Construction::isInCycle(useInstr) and
|
||||
strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
|
||||
} or
|
||||
TNonPhiMemoryOperand(
|
||||
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
|
||||
) {
|
||||
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
|
||||
not Construction::isInCycle(useInstr)
|
||||
not Construction::isInCycle(useInstr) and
|
||||
(
|
||||
strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
|
||||
or
|
||||
tag instanceof UnmodeledUseOperandTag
|
||||
)
|
||||
} or
|
||||
TPhiOperand(
|
||||
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
|
||||
@@ -11,13 +11,19 @@ cached
|
||||
private newtype TOperand =
|
||||
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
|
||||
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
|
||||
not Construction::isInCycle(useInstr)
|
||||
not Construction::isInCycle(useInstr) and
|
||||
strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
|
||||
} or
|
||||
TNonPhiMemoryOperand(
|
||||
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
|
||||
) {
|
||||
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
|
||||
not Construction::isInCycle(useInstr)
|
||||
not Construction::isInCycle(useInstr) and
|
||||
(
|
||||
strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
|
||||
or
|
||||
tag instanceof UnmodeledUseOperandTag
|
||||
)
|
||||
} or
|
||||
TPhiOperand(
|
||||
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
|
||||
@@ -96,7 +96,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getMemoryOperandDefinition(
|
||||
private Instruction getMemoryOperandDefinition0(
|
||||
Instruction instruction, MemoryOperandTag tag, Overlap overlap
|
||||
) {
|
||||
exists(OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand |
|
||||
@@ -142,6 +142,19 @@ private module Cached {
|
||||
overlap instanceof MustExactlyOverlap
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getMemoryOperandDefinition(
|
||||
Instruction instruction, MemoryOperandTag tag, Overlap overlap
|
||||
) {
|
||||
// getMemoryOperandDefinition0 currently has a bug where it can match with multiple overlaps.
|
||||
// This predicate ensures that the chosen overlap is the most conservative if there's any doubt.
|
||||
result = getMemoryOperandDefinition0(instruction, tag, overlap) and
|
||||
not (
|
||||
overlap instanceof MustExactlyOverlap and
|
||||
exists(MustTotallyOverlap o | exists(getMemoryOperandDefinition0(instruction, tag, o)))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
|
||||
* through a phi instruction and therefore should be impossible.
|
||||
|
||||
@@ -69,7 +69,6 @@ nodes
|
||||
| CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
|
||||
| CallSensitivityFlow.cs:189:40:189:40 | o : Object | semmle.label | o : Object |
|
||||
| CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | semmle.label | access to parameter o |
|
||||
| CallSensitivityFlow.cs:203:22:203:22 | access to parameter o | semmle.label | access to parameter o |
|
||||
#select
|
||||
| CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object : Object | CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object : Object | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | $@ | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | access to parameter o |
|
||||
| CallSensitivityFlow.cs:79:25:79:36 | object creation of type Object : Object | CallSensitivityFlow.cs:79:25:79:36 | object creation of type Object : Object | CallSensitivityFlow.cs:31:18:31:18 | access to parameter o | $@ | CallSensitivityFlow.cs:31:18:31:18 | access to parameter o | access to parameter o |
|
||||
|
||||
@@ -174,6 +174,37 @@ edges
|
||||
| G.cs:52:14:52:21 | access to field boxfield [Box1, Elem] | G.cs:52:14:52:26 | access to field Box1 [Elem] : Elem |
|
||||
| G.cs:52:14:52:21 | this access [boxfield, Box1, ... (3)] | G.cs:52:14:52:21 | access to field boxfield [Box1, Elem] |
|
||||
| G.cs:52:14:52:26 | access to field Box1 [Elem] : Elem | G.cs:52:14:52:31 | access to field Elem |
|
||||
| H.cs:23:9:23:9 | [post] access to local variable a [FieldA] : Object | H.cs:24:27:24:27 | access to local variable a [FieldA] : Object |
|
||||
| H.cs:23:20:23:31 | object creation of type Object : Object | H.cs:23:9:23:9 | [post] access to local variable a [FieldA] : Object |
|
||||
| H.cs:24:21:24:28 | call to method Clone [FieldA] : Object | H.cs:25:14:25:18 | access to local variable clone [FieldA] : Object |
|
||||
| H.cs:24:27:24:27 | access to local variable a [FieldA] : Object | H.cs:24:21:24:28 | call to method Clone [FieldA] : Object |
|
||||
| H.cs:25:14:25:18 | access to local variable clone [FieldA] : Object | H.cs:25:14:25:25 | access to field FieldA |
|
||||
| H.cs:43:9:43:9 | [post] access to local variable a [FieldA] : Object | H.cs:44:27:44:27 | access to local variable a [FieldA] : Object |
|
||||
| H.cs:43:20:43:31 | object creation of type Object : Object | H.cs:43:9:43:9 | [post] access to local variable a [FieldA] : Object |
|
||||
| H.cs:44:17:44:28 | call to method Transform [FieldB] : Object | H.cs:45:14:45:14 | access to local variable b [FieldB] : Object |
|
||||
| H.cs:44:27:44:27 | access to local variable a [FieldA] : Object | H.cs:44:17:44:28 | call to method Transform [FieldB] : Object |
|
||||
| H.cs:45:14:45:14 | access to local variable b [FieldB] : Object | H.cs:45:14:45:21 | access to field FieldB |
|
||||
| H.cs:63:9:63:9 | [post] access to local variable a [FieldA] : Object | H.cs:64:22:64:22 | access to local variable a [FieldA] : Object |
|
||||
| H.cs:63:20:63:31 | object creation of type Object : Object | H.cs:63:9:63:9 | [post] access to local variable a [FieldA] : Object |
|
||||
| H.cs:64:22:64:22 | access to local variable a [FieldA] : Object | H.cs:64:25:64:26 | [post] access to local variable b1 [FieldB] : Object |
|
||||
| H.cs:64:25:64:26 | [post] access to local variable b1 [FieldB] : Object | H.cs:65:14:65:15 | access to local variable b1 [FieldB] : Object |
|
||||
| H.cs:65:14:65:15 | access to local variable b1 [FieldB] : Object | H.cs:65:14:65:22 | access to field FieldB |
|
||||
| H.cs:88:17:88:17 | [post] access to local variable a [FieldA] : Object | H.cs:89:14:89:14 | access to local variable a [FieldA] : Object |
|
||||
| H.cs:88:20:88:31 | object creation of type Object : Object | H.cs:88:17:88:17 | [post] access to local variable a [FieldA] : Object |
|
||||
| H.cs:88:20:88:31 | object creation of type Object : Object | H.cs:88:34:88:35 | [post] access to local variable b1 [FieldB] : Object |
|
||||
| H.cs:88:34:88:35 | [post] access to local variable b1 [FieldB] : Object | H.cs:90:14:90:15 | access to local variable b1 [FieldB] : Object |
|
||||
| H.cs:89:14:89:14 | access to local variable a [FieldA] : Object | H.cs:89:14:89:21 | access to field FieldA |
|
||||
| H.cs:90:14:90:15 | access to local variable b1 [FieldB] : Object | H.cs:90:14:90:22 | access to field FieldB |
|
||||
| H.cs:112:9:112:9 | [post] access to local variable a [FieldA] : Object | H.cs:113:31:113:31 | access to local variable a [FieldA] : Object |
|
||||
| H.cs:112:20:112:31 | object creation of type Object : Object | H.cs:112:9:112:9 | [post] access to local variable a [FieldA] : Object |
|
||||
| H.cs:113:17:113:32 | call to method TransformWrap [FieldB] : Object | H.cs:114:14:114:14 | access to local variable b [FieldB] : Object |
|
||||
| H.cs:113:31:113:31 | access to local variable a [FieldA] : Object | H.cs:113:17:113:32 | call to method TransformWrap [FieldB] : Object |
|
||||
| H.cs:114:14:114:14 | access to local variable b [FieldB] : Object | H.cs:114:14:114:21 | access to field FieldB |
|
||||
| H.cs:130:9:130:9 | [post] access to local variable a [FieldA] : Object | H.cs:131:18:131:18 | access to local variable a [FieldA] : Object |
|
||||
| H.cs:130:20:130:31 | object creation of type Object : Object | H.cs:130:9:130:9 | [post] access to local variable a [FieldA] : Object |
|
||||
| H.cs:131:18:131:18 | access to local variable a [FieldA] : Object | H.cs:131:14:131:19 | call to method Get |
|
||||
| H.cs:147:17:147:32 | call to method Through : A | H.cs:148:14:148:14 | access to local variable a |
|
||||
| H.cs:147:25:147:31 | object creation of type A : A | H.cs:147:17:147:32 | call to method Through : A |
|
||||
nodes
|
||||
| A.cs:5:17:5:23 | object creation of type C : C | semmle.label | object creation of type C : C |
|
||||
| A.cs:6:17:6:25 | call to method Make [c] : C | semmle.label | call to method Make [c] : C |
|
||||
@@ -371,6 +402,44 @@ nodes
|
||||
| G.cs:52:14:52:21 | this access [boxfield, Box1, ... (3)] | semmle.label | this access [boxfield, Box1, ... (3)] |
|
||||
| G.cs:52:14:52:26 | access to field Box1 [Elem] : Elem | semmle.label | access to field Box1 [Elem] : Elem |
|
||||
| G.cs:52:14:52:31 | access to field Elem | semmle.label | access to field Elem |
|
||||
| H.cs:23:9:23:9 | [post] access to local variable a [FieldA] : Object | semmle.label | [post] access to local variable a [FieldA] : Object |
|
||||
| H.cs:23:20:23:31 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
|
||||
| H.cs:24:21:24:28 | call to method Clone [FieldA] : Object | semmle.label | call to method Clone [FieldA] : Object |
|
||||
| H.cs:24:27:24:27 | access to local variable a [FieldA] : Object | semmle.label | access to local variable a [FieldA] : Object |
|
||||
| H.cs:25:14:25:18 | access to local variable clone [FieldA] : Object | semmle.label | access to local variable clone [FieldA] : Object |
|
||||
| H.cs:25:14:25:25 | access to field FieldA | semmle.label | access to field FieldA |
|
||||
| H.cs:43:9:43:9 | [post] access to local variable a [FieldA] : Object | semmle.label | [post] access to local variable a [FieldA] : Object |
|
||||
| H.cs:43:20:43:31 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
|
||||
| H.cs:44:17:44:28 | call to method Transform [FieldB] : Object | semmle.label | call to method Transform [FieldB] : Object |
|
||||
| H.cs:44:27:44:27 | access to local variable a [FieldA] : Object | semmle.label | access to local variable a [FieldA] : Object |
|
||||
| H.cs:45:14:45:14 | access to local variable b [FieldB] : Object | semmle.label | access to local variable b [FieldB] : Object |
|
||||
| H.cs:45:14:45:21 | access to field FieldB | semmle.label | access to field FieldB |
|
||||
| H.cs:63:9:63:9 | [post] access to local variable a [FieldA] : Object | semmle.label | [post] access to local variable a [FieldA] : Object |
|
||||
| H.cs:63:20:63:31 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
|
||||
| H.cs:64:22:64:22 | access to local variable a [FieldA] : Object | semmle.label | access to local variable a [FieldA] : Object |
|
||||
| H.cs:64:25:64:26 | [post] access to local variable b1 [FieldB] : Object | semmle.label | [post] access to local variable b1 [FieldB] : Object |
|
||||
| H.cs:65:14:65:15 | access to local variable b1 [FieldB] : Object | semmle.label | access to local variable b1 [FieldB] : Object |
|
||||
| H.cs:65:14:65:22 | access to field FieldB | semmle.label | access to field FieldB |
|
||||
| H.cs:88:17:88:17 | [post] access to local variable a [FieldA] : Object | semmle.label | [post] access to local variable a [FieldA] : Object |
|
||||
| H.cs:88:20:88:31 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
|
||||
| H.cs:88:34:88:35 | [post] access to local variable b1 [FieldB] : Object | semmle.label | [post] access to local variable b1 [FieldB] : Object |
|
||||
| H.cs:89:14:89:14 | access to local variable a [FieldA] : Object | semmle.label | access to local variable a [FieldA] : Object |
|
||||
| H.cs:89:14:89:21 | access to field FieldA | semmle.label | access to field FieldA |
|
||||
| H.cs:90:14:90:15 | access to local variable b1 [FieldB] : Object | semmle.label | access to local variable b1 [FieldB] : Object |
|
||||
| H.cs:90:14:90:22 | access to field FieldB | semmle.label | access to field FieldB |
|
||||
| H.cs:112:9:112:9 | [post] access to local variable a [FieldA] : Object | semmle.label | [post] access to local variable a [FieldA] : Object |
|
||||
| H.cs:112:20:112:31 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
|
||||
| H.cs:113:17:113:32 | call to method TransformWrap [FieldB] : Object | semmle.label | call to method TransformWrap [FieldB] : Object |
|
||||
| H.cs:113:31:113:31 | access to local variable a [FieldA] : Object | semmle.label | access to local variable a [FieldA] : Object |
|
||||
| H.cs:114:14:114:14 | access to local variable b [FieldB] : Object | semmle.label | access to local variable b [FieldB] : Object |
|
||||
| H.cs:114:14:114:21 | access to field FieldB | semmle.label | access to field FieldB |
|
||||
| H.cs:130:9:130:9 | [post] access to local variable a [FieldA] : Object | semmle.label | [post] access to local variable a [FieldA] : Object |
|
||||
| H.cs:130:20:130:31 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
|
||||
| H.cs:131:14:131:19 | call to method Get | semmle.label | call to method Get |
|
||||
| H.cs:131:18:131:18 | access to local variable a [FieldA] : Object | semmle.label | access to local variable a [FieldA] : Object |
|
||||
| H.cs:147:17:147:32 | call to method Through : A | semmle.label | call to method Through : A |
|
||||
| H.cs:147:25:147:31 | object creation of type A : A | semmle.label | object creation of type A : A |
|
||||
| H.cs:148:14:148:14 | access to local variable a | semmle.label | access to local variable a |
|
||||
#select
|
||||
| A.cs:7:14:7:16 | access to field c | A.cs:5:17:5:23 | object creation of type C : C | A.cs:7:14:7:16 | access to field c | $@ | A.cs:5:17:5:23 | object creation of type C : C | object creation of type C : C |
|
||||
| A.cs:14:14:14:20 | call to method Get | A.cs:13:15:13:22 | object creation of type C1 : C1 | A.cs:14:14:14:20 | call to method Get | $@ | A.cs:13:15:13:22 | object creation of type C1 : C1 | object creation of type C1 : C1 |
|
||||
@@ -410,3 +479,11 @@ nodes
|
||||
| G.cs:39:14:39:35 | call to method GetElem | G.cs:23:18:23:27 | object creation of type Elem : Elem | G.cs:39:14:39:35 | call to method GetElem | $@ | G.cs:23:18:23:27 | object creation of type Elem : Elem | object creation of type Elem : Elem |
|
||||
| G.cs:39:14:39:35 | call to method GetElem | G.cs:31:18:31:27 | object creation of type Elem : Elem | G.cs:39:14:39:35 | call to method GetElem | $@ | G.cs:31:18:31:27 | object creation of type Elem : Elem | object creation of type Elem : Elem |
|
||||
| G.cs:52:14:52:31 | access to field Elem | G.cs:44:18:44:27 | object creation of type Elem : Elem | G.cs:52:14:52:31 | access to field Elem | $@ | G.cs:44:18:44:27 | object creation of type Elem : Elem | object creation of type Elem : Elem |
|
||||
| H.cs:25:14:25:25 | access to field FieldA | H.cs:23:20:23:31 | object creation of type Object : Object | H.cs:25:14:25:25 | access to field FieldA | $@ | H.cs:23:20:23:31 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| H.cs:45:14:45:21 | access to field FieldB | H.cs:43:20:43:31 | object creation of type Object : Object | H.cs:45:14:45:21 | access to field FieldB | $@ | H.cs:43:20:43:31 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| H.cs:65:14:65:22 | access to field FieldB | H.cs:63:20:63:31 | object creation of type Object : Object | H.cs:65:14:65:22 | access to field FieldB | $@ | H.cs:63:20:63:31 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| H.cs:89:14:89:21 | access to field FieldA | H.cs:88:20:88:31 | object creation of type Object : Object | H.cs:89:14:89:21 | access to field FieldA | $@ | H.cs:88:20:88:31 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| H.cs:90:14:90:22 | access to field FieldB | H.cs:88:20:88:31 | object creation of type Object : Object | H.cs:90:14:90:22 | access to field FieldB | $@ | H.cs:88:20:88:31 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| H.cs:114:14:114:21 | access to field FieldB | H.cs:112:20:112:31 | object creation of type Object : Object | H.cs:114:14:114:21 | access to field FieldB | $@ | H.cs:112:20:112:31 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| H.cs:131:14:131:19 | call to method Get | H.cs:130:20:130:31 | object creation of type Object : Object | H.cs:131:14:131:19 | call to method Get | $@ | H.cs:130:20:130:31 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| H.cs:148:14:148:14 | access to local variable a | H.cs:147:25:147:31 | object creation of type A : A | H.cs:148:14:148:14 | access to local variable a | $@ | H.cs:147:25:147:31 | object creation of type A : A | object creation of type A : A |
|
||||
|
||||
154
csharp/ql/test/library-tests/dataflow/fields/H.cs
Normal file
154
csharp/ql/test/library-tests/dataflow/fields/H.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
public class H
|
||||
{
|
||||
class A
|
||||
{
|
||||
public object FieldA;
|
||||
}
|
||||
|
||||
class B
|
||||
{
|
||||
public object FieldB;
|
||||
}
|
||||
|
||||
A Clone(A a)
|
||||
{
|
||||
var ret = new A();
|
||||
ret.FieldA = a.FieldA;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void M1(object o)
|
||||
{
|
||||
var a = new A();
|
||||
a.FieldA = new object();
|
||||
var clone = Clone(a);
|
||||
Sink(clone.FieldA); // flow
|
||||
|
||||
a = new A();
|
||||
a.FieldA = o;
|
||||
clone = Clone(a);
|
||||
Sink(clone.FieldA); // no flow
|
||||
}
|
||||
|
||||
B Transform(A a)
|
||||
{
|
||||
var b = new B();
|
||||
b.FieldB = a.FieldA;
|
||||
return b;
|
||||
}
|
||||
|
||||
void M2(object o)
|
||||
{
|
||||
var a = new A();
|
||||
a.FieldA = new object();
|
||||
var b = Transform(a);
|
||||
Sink(b.FieldB); // flow
|
||||
|
||||
a = new A();
|
||||
a.FieldA = o;
|
||||
b = Transform(a);
|
||||
Sink(b.FieldB); // no flow
|
||||
}
|
||||
|
||||
void TransformArg(A a, B b1, B b2)
|
||||
{
|
||||
b1.FieldB = a.FieldA;
|
||||
}
|
||||
|
||||
void M3(object o)
|
||||
{
|
||||
var a = new A();
|
||||
var b1 = new B();
|
||||
var b2 = new B();
|
||||
a.FieldA = new object();
|
||||
TransformArg(a, b1, b2);
|
||||
Sink(b1.FieldB); // flow
|
||||
Sink(b2.FieldB); // no flow
|
||||
|
||||
a = new A();
|
||||
b1 = new B();
|
||||
b2 = new B();
|
||||
a.FieldA = o;
|
||||
TransformArg(a, b1, b2);
|
||||
Sink(b1.FieldB); // no flow
|
||||
Sink(b2.FieldB); // no flow
|
||||
}
|
||||
|
||||
void SetArgs(A a, object o, B b1, B b2)
|
||||
{
|
||||
a.FieldA = o;
|
||||
TransformArg(a, b1, b2);
|
||||
}
|
||||
|
||||
void M4(object o)
|
||||
{
|
||||
var a = new A();
|
||||
var b1 = new B();
|
||||
var b2 = new B();
|
||||
SetArgs(a, new object(), b1, b2);
|
||||
Sink(a.FieldA); // flow
|
||||
Sink(b1.FieldB); // flow
|
||||
Sink(b2.FieldB); // no flow
|
||||
|
||||
a = new A();
|
||||
b1 = new B();
|
||||
b2 = new B();
|
||||
SetArgs(a, o, b1, b2);
|
||||
Sink(a.FieldA); // no flow
|
||||
Sink(b1.FieldB); // no flow
|
||||
Sink(b2.FieldB); // no flow
|
||||
}
|
||||
|
||||
B TransformWrap(A a)
|
||||
{
|
||||
var temp = new B();
|
||||
temp.FieldB = a;
|
||||
return Transform((A)temp.FieldB);
|
||||
}
|
||||
|
||||
void M5(object o)
|
||||
{
|
||||
var a = new A();
|
||||
a.FieldA = new object();
|
||||
var b = TransformWrap(a);
|
||||
Sink(b.FieldB); // flow
|
||||
|
||||
a = new A();
|
||||
a.FieldA = o;
|
||||
b = TransformWrap(a);
|
||||
Sink(b.FieldB); // no flow
|
||||
}
|
||||
|
||||
object Get(A a)
|
||||
{
|
||||
return Transform(a).FieldB;
|
||||
}
|
||||
|
||||
void M6(object o)
|
||||
{
|
||||
var a = new A();
|
||||
a.FieldA = new object();
|
||||
Sink(Get(a)); // flow
|
||||
|
||||
a = new A();
|
||||
a.FieldA = o;
|
||||
Sink(Get(a)); // no flow
|
||||
}
|
||||
|
||||
object Through(object o)
|
||||
{
|
||||
var a = new A();
|
||||
a.FieldA = o as A;
|
||||
return Transform(a).FieldB;
|
||||
}
|
||||
|
||||
void M7()
|
||||
{
|
||||
var a = Through(new A());
|
||||
Sink(a); // flow
|
||||
var b = Through(new B());
|
||||
Sink(b); // no flow
|
||||
}
|
||||
|
||||
public static void Sink(object o) { }
|
||||
}
|
||||
@@ -269,8 +269,6 @@ nodes
|
||||
| GlobalDataFlow.cs:56:37:56:37 | x : String | semmle.label | x : String |
|
||||
| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | semmle.label | access to parameter x : String |
|
||||
| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String |
|
||||
| GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | semmle.label | access to parameter nonSinkParam0 |
|
||||
| GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 | semmle.label | access to parameter nonSinkParam0 |
|
||||
| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String |
|
||||
| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | semmle.label | call to method Return : String |
|
||||
| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String |
|
||||
|
||||
@@ -1824,6 +1824,8 @@
|
||||
| GlobalDataFlow.cs:84:126:84:126 | x : Object | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String |
|
||||
| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x |
|
||||
| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x |
|
||||
| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x |
|
||||
| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String |
|
||||
| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String |
|
||||
| GlobalDataFlow.cs:84:126:84:126 | x : String | GlobalDataFlow.cs:84:135:84:135 | access to parameter x : String |
|
||||
| GlobalDataFlow.cs:84:126:84:126 | x : String[] | GlobalDataFlow.cs:84:126:84:126 | x |
|
||||
@@ -1904,6 +1906,8 @@
|
||||
| GlobalDataFlow.cs:86:129:86:129 | y : Object | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String |
|
||||
| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y |
|
||||
| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y |
|
||||
| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y |
|
||||
| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String |
|
||||
| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String |
|
||||
| GlobalDataFlow.cs:86:129:86:129 | y : String | GlobalDataFlow.cs:86:135:86:135 | access to parameter y : String |
|
||||
| GlobalDataFlow.cs:86:129:86:129 | y : String[] | GlobalDataFlow.cs:86:129:86:129 | y |
|
||||
@@ -2124,10 +2128,14 @@
|
||||
| GlobalDataFlow.cs:90:97:90:97 | s : Object | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String |
|
||||
| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... |
|
||||
| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... |
|
||||
| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... |
|
||||
| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String |
|
||||
| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String |
|
||||
| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String |
|
||||
| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s |
|
||||
| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s |
|
||||
| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s |
|
||||
| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String |
|
||||
| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String |
|
||||
| GlobalDataFlow.cs:90:97:90:97 | s : String | GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String |
|
||||
| GlobalDataFlow.cs:90:97:90:97 | s : String[] | GlobalDataFlow.cs:90:97:90:97 | s |
|
||||
@@ -2144,6 +2152,8 @@
|
||||
| GlobalDataFlow.cs:90:103:90:109 | ... + ... : String | GlobalDataFlow.cs:90:91:90:109 | [output] (...) => ... : String |
|
||||
| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... |
|
||||
| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... |
|
||||
| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... |
|
||||
| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String |
|
||||
| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String |
|
||||
| GlobalDataFlow.cs:90:109:90:109 | access to parameter s : String | GlobalDataFlow.cs:90:103:90:109 | ... + ... : String |
|
||||
| GlobalDataFlow.cs:90:112:90:112 | x : Object | GlobalDataFlow.cs:90:112:90:112 | x |
|
||||
@@ -2592,6 +2602,8 @@
|
||||
| GlobalDataFlow.cs:114:76:114:76 | x : Object | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String |
|
||||
| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x |
|
||||
| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x |
|
||||
| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x |
|
||||
| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String |
|
||||
| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String |
|
||||
| GlobalDataFlow.cs:114:76:114:76 | x : String | GlobalDataFlow.cs:114:81:114:81 | access to parameter x : String |
|
||||
| GlobalDataFlow.cs:114:76:114:76 | x : String[] | GlobalDataFlow.cs:114:76:114:76 | x |
|
||||
@@ -2658,6 +2670,8 @@
|
||||
| GlobalDataFlow.cs:116:127:116:127 | y : Object | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String |
|
||||
| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y |
|
||||
| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y |
|
||||
| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y |
|
||||
| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String |
|
||||
| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String |
|
||||
| GlobalDataFlow.cs:116:127:116:127 | y : String | GlobalDataFlow.cs:116:133:116:133 | access to parameter y : String |
|
||||
| GlobalDataFlow.cs:116:127:116:127 | y : String[] | GlobalDataFlow.cs:116:127:116:127 | y |
|
||||
@@ -2720,6 +2734,8 @@
|
||||
| GlobalDataFlow.cs:118:124:118:124 | x : Object | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String |
|
||||
| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x |
|
||||
| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x |
|
||||
| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x |
|
||||
| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String |
|
||||
| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String |
|
||||
| GlobalDataFlow.cs:118:124:118:124 | x : String | GlobalDataFlow.cs:118:133:118:133 | access to parameter x : String |
|
||||
| GlobalDataFlow.cs:118:124:118:124 | x : String[] | GlobalDataFlow.cs:118:124:118:124 | x |
|
||||
@@ -4252,14 +4268,20 @@
|
||||
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : String[] | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T |
|
||||
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 |
|
||||
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 |
|
||||
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 |
|
||||
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T |
|
||||
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T |
|
||||
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T |
|
||||
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 |
|
||||
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 |
|
||||
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 |
|
||||
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T |
|
||||
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T |
|
||||
| GlobalDataFlow.cs:292:31:292:40 | sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T |
|
||||
| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 |
|
||||
| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 |
|
||||
| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 |
|
||||
| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T |
|
||||
| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T |
|
||||
| GlobalDataFlow.cs:294:15:294:24 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T |
|
||||
| GlobalDataFlow.cs:295:16:295:25 | access to parameter sinkParam8 : T | GlobalDataFlow.cs:82:84:82:94 | [output] delegate creation of type Func<String,String> |
|
||||
@@ -4827,6 +4849,10 @@
|
||||
| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x |
|
||||
| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x |
|
||||
| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x |
|
||||
| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x |
|
||||
| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x |
|
||||
| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T |
|
||||
| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T |
|
||||
| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T |
|
||||
| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T |
|
||||
| GlobalDataFlow.cs:429:22:429:22 | SSA def(x) : T | GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T |
|
||||
@@ -4871,20 +4897,32 @@
|
||||
| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call |
|
||||
| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call |
|
||||
| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call |
|
||||
| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call |
|
||||
| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call |
|
||||
| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable<T> |
|
||||
| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable<T> |
|
||||
| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable<T> |
|
||||
| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable<T> |
|
||||
| GlobalDataFlow.cs:431:44:431:47 | delegate call : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : IEnumerable<T> |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x : T |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x : T |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:80:79:80:79 | x : T |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x : T |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x : T |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:112:84:112:84 | x : T |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : T |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : T |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : T |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : T |
|
||||
| GlobalDataFlow.cs:431:46:431:46 | access to local variable x : T | GlobalDataFlow.cs:431:44:431:47 | delegate call : T |
|
||||
|
||||
@@ -316,8 +316,6 @@ nodes
|
||||
| GlobalDataFlow.cs:56:37:56:37 | x : String | semmle.label | x : String |
|
||||
| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | semmle.label | access to parameter x : String |
|
||||
| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String |
|
||||
| GlobalDataFlow.cs:60:38:60:50 | access to parameter nonSinkParam0 | semmle.label | access to parameter nonSinkParam0 |
|
||||
| GlobalDataFlow.cs:61:61:61:73 | access to parameter nonSinkParam0 | semmle.label | access to parameter nonSinkParam0 |
|
||||
| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String |
|
||||
| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | semmle.label | call to method Return : String |
|
||||
| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String |
|
||||
|
||||
@@ -10,14 +10,14 @@ public class Test1
|
||||
{
|
||||
if (v == "valid")
|
||||
{
|
||||
f = v /* safe write */;
|
||||
f = v; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
[OnDeserializing]
|
||||
public void Deserialize()
|
||||
{
|
||||
f = "invalid" /* unsafe write */;
|
||||
f = $"invalid"; // BAD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,19 +30,19 @@ public class Test2
|
||||
{
|
||||
if (v == "valid")
|
||||
{
|
||||
f = v /* safe write */;
|
||||
f = v; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
[OnDeserializing]
|
||||
public void Deserialize()
|
||||
{
|
||||
var v = "invalid";
|
||||
f = v /* unsafe write -- false negative */;
|
||||
var v = $"invalid";
|
||||
f = v; // BAD: False negative
|
||||
|
||||
if (v == "valid")
|
||||
{
|
||||
f = v; /* safe write */
|
||||
f = v; // GOOD
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,25 +56,25 @@ public class Test3
|
||||
{
|
||||
if (v == "valid")
|
||||
{
|
||||
f = v /* safe write */;
|
||||
f = v; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
[OnDeserializing]
|
||||
public void Deserialize()
|
||||
{
|
||||
var v = "invalid";
|
||||
f = v /* unsafe write -- false negative */;
|
||||
var v = $"invalid";
|
||||
f = v; // GOOD: False negative
|
||||
Assign(v);
|
||||
}
|
||||
|
||||
private void Assign(string v)
|
||||
{
|
||||
f = v /* unsafe write -- false negative */;
|
||||
f = v; // GOOD: False negative
|
||||
|
||||
if (v == "valid")
|
||||
{
|
||||
f = v /* safe write */;
|
||||
f = v; // GOOD
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,21 +88,21 @@ public class Test4
|
||||
{
|
||||
if (v == "valid")
|
||||
{
|
||||
f = v /* safe write */;
|
||||
f = v; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
[OnDeserializing]
|
||||
public void Deserialize()
|
||||
{
|
||||
var v = "invalid";
|
||||
var v = $"invalid";
|
||||
if (v == "valid")
|
||||
Assign(v);
|
||||
}
|
||||
|
||||
private void Assign(string v)
|
||||
{
|
||||
f = v /* safe write */;
|
||||
f = v; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,13 +115,13 @@ public class Test5 : ISerializable
|
||||
{
|
||||
if (age < 0)
|
||||
throw new ArgumentException(nameof(age));
|
||||
Age = age /* safe write */;
|
||||
Age = age; // GOOD
|
||||
}
|
||||
|
||||
[OnDeserializing]
|
||||
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
Age = info.GetInt32("age"); /* unsafe write */;
|
||||
Age = info.GetInt32("age"); // BAD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ public class Test6 : ISerializable
|
||||
{
|
||||
if (age < 0)
|
||||
throw new ArgumentException(nameof(age));
|
||||
Age = age /* safe write */;
|
||||
Age = age; // GOOD
|
||||
}
|
||||
|
||||
[OnDeserializing]
|
||||
@@ -143,7 +143,7 @@ public class Test6 : ISerializable
|
||||
int age = info.GetInt32("age");
|
||||
if (age < 0)
|
||||
throw new SerializationException("age");
|
||||
Age = age; /* safe write */;
|
||||
Age = age; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ public class Test7 : ISerializable
|
||||
{
|
||||
if (age < 0)
|
||||
throw new ArgumentException(nameof(age));
|
||||
Age = age /* safe write */;
|
||||
Age = age; // GOOD
|
||||
}
|
||||
|
||||
[OnDeserializing]
|
||||
@@ -165,6 +165,27 @@ public class Test7 : ISerializable
|
||||
int age = info.GetInt32("age");
|
||||
if (false)
|
||||
throw new SerializationException("age");
|
||||
Age = age; /* unsafe write */;
|
||||
Age = age; // BAD
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Test8 : ISerializable
|
||||
{
|
||||
string Options;
|
||||
|
||||
public int Age;
|
||||
|
||||
public Test8(string options)
|
||||
{
|
||||
if (options == null)
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
Options = options; // GOOD
|
||||
}
|
||||
|
||||
[OnDeserializing]
|
||||
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
Options = new string(""); // GOOD: A created object
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
| RuntimeChecksBypass.cs:20:13:20:21 | "invalid" | This write to $@ may be circumventing a $@. | RuntimeChecksBypass.cs:7:19:7:19 | f | f | RuntimeChecksBypass.cs:11:9:14:9 | if (...) ... | check |
|
||||
| RuntimeChecksBypass.cs:20:13:20:22 | $"..." | This write to $@ may be circumventing a $@. | RuntimeChecksBypass.cs:7:19:7:19 | f | f | RuntimeChecksBypass.cs:11:9:14:9 | if (...) ... | check |
|
||||
| RuntimeChecksBypass.cs:124:15:124:34 | call to method GetInt32 | This write to $@ may be circumventing a $@. | RuntimeChecksBypass.cs:112:16:112:18 | Age | Age | RuntimeChecksBypass.cs:116:9:117:53 | if (...) ... | check |
|
||||
| RuntimeChecksBypass.cs:168:15:168:17 | access to local variable age | This write to $@ may be circumventing a $@. | RuntimeChecksBypass.cs:153:16:153:18 | Age | Age | RuntimeChecksBypass.cs:157:9:158:53 | if (...) ... | check |
|
||||
| RuntimeChecksBypassBad.cs:19:15:19:34 | call to method GetInt32 | This write to $@ may be circumventing a $@. | RuntimeChecksBypassBad.cs:7:16:7:18 | Age | Age | RuntimeChecksBypassBad.cs:11:9:12:53 | if (...) ... | check |
|
||||
|
||||
@@ -113,7 +113,7 @@ Then we can make the source more specific, for example an access to a public par
|
||||
where
|
||||
fileReader.getDeclaringType().hasQualifiedName("java.io", "FileReader") and
|
||||
call.getCallee() = fileReader and
|
||||
DataFlow::localFlow(DataFlow::parameterNode(p), DataFlow::exprNode(fc.getArgument(0)))
|
||||
DataFlow::localFlow(DataFlow::parameterNode(p), DataFlow::exprNode(call.getArgument(0)))
|
||||
select p
|
||||
|
||||
The following example finds calls to formatting functions where the format string is not hard-coded.
|
||||
|
||||
@@ -393,16 +393,73 @@ aggregation in a simpler form:
|
||||
Monotonic aggregates
|
||||
====================
|
||||
|
||||
In addition to the standard aggregates, QL also supports monotonic aggregates.
|
||||
These are a slightly different way of computing aggregates which have some advantages.
|
||||
For example, you can use monotonic aggregates :ref:`recursively <recursion>`.
|
||||
You can't do this with normal aggregates.
|
||||
In addition to standard aggregates, QL also supports monotonic aggregates.
|
||||
Monotonic aggregates differ from standard aggregates in the way that they deal with the
|
||||
values generated by the ``<expression>`` part of the formula:
|
||||
|
||||
For more information and examples, see `Monotonic aggregates in QL
|
||||
<https://help.semmle.com/QL/learn-ql/advanced/monotonic-aggregates.html>`_.
|
||||
- Standard aggregates take the ``<expression>`` values for each ``<formula>`` value and
|
||||
flatten them into a list. A single aggregation function is applied to all the values.
|
||||
- Monotonic aggregates take an ``<expression>`` for each value given by the ``<formula>``,
|
||||
and create combinations of all the possible values. The aggregation
|
||||
function is applied to each of the resulting combinations.
|
||||
|
||||
.. TODO: Eventually replace this link with just the relevant examples.
|
||||
(Some of the content is a duplicate of the above discussion on aggregates.)
|
||||
In general, if the ``<expression>`` is total and functional, then monotonic aggregates are
|
||||
equivalent to standard aggregates. Results differ when there is not precisely one ``<expression>``
|
||||
value for each value generated by the ``<formula>``:
|
||||
|
||||
- If there are missing ``<expression>`` values (that is, there is no
|
||||
``<expression>`` value for a value generated by the ``<formula>``), monotonic aggregates
|
||||
won't compute a result, as you cannot create combinations of values
|
||||
including exactly one ``<expression>`` value for each value generated by the ``<formula>``.
|
||||
|
||||
- If there is more than one ``<expression>`` per ``<formula>`` result, you can create multiple
|
||||
combinations of values including exactly one ``<expression>`` value for each
|
||||
value generated by the ``<formula>``. Here, the aggregation function is applied to each of the
|
||||
resulting combinations.
|
||||
|
||||
Recursive monotonic aggregates
|
||||
------------------------------
|
||||
|
||||
Monotonic aggregates may be used :ref:`recursively <recursion>`, but the recursive call may only appear in the
|
||||
expression, and not in the range. The recursive semantics for aggregates are the same as the
|
||||
recursive semantics for the rest of QL. For example, we might define a predicate to calculate
|
||||
the distance of a node in a graph from the leaves as follows:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
int depth(Node n) {
|
||||
if not exists(n.getAChild())
|
||||
then result = 0
|
||||
else result = 1 + max(Node child | child = n.getAChild() | depth(child))
|
||||
}
|
||||
|
||||
Here the recursive call is in the expression, which is legal. The recursive semantics for aggregates
|
||||
are the same as the recursive semantics for the rest of QL. If you understand how aggregates work in
|
||||
the non-recursive case then you should not find it difficult to use them recursively. However, it is
|
||||
worth seeing how the evaluation of a recursive aggregation proceeds.
|
||||
|
||||
Consider the depth example we just saw with the following graph as input (arrows point from children to parents):
|
||||
|
||||
.. |image0| image:: ../images/monotonic-aggregates-graph.png
|
||||
|
||||
|image0|
|
||||
|
||||
Then the evaluation of the ``depth`` predicate proceeds as follows:
|
||||
|
||||
+-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| **Stage** | **depth** | **Comments** |
|
||||
+===========+============================================+==========================================================================================================================================================================+
|
||||
| 0 | | We always begin with the empty set. |
|
||||
+-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| 1 | ``(0, b), (0, d), (0, e)`` | The nodes with no children have depth 0. The recursive step for **a** and **c** fails to produce a value, since some of their children do not have values for ``depth``. |
|
||||
+-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| 2 | ``(0, b), (0, d), (0, e), (1, c)`` | The recursive step for **c** succeeds, since ``depth`` now has a value for all its children (**d** and **e**). The recursive step for **a** still fails. |
|
||||
+-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| 3 | ``(0, b), (0, d), (0, e), (1, c), (2, a)`` | The recursive step for **a** succeeds, since ``depth`` now has a value for all its children (**b** and **c**). |
|
||||
+-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
Here, we can see that at the intermediate stages it is very important for the aggregate to
|
||||
fail if some of the children lack a value - this prevents erroneous values being added.
|
||||
|
||||
.. index:: any
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
private import java
|
||||
private import DataFlowUtil
|
||||
private import DataFlowImplCommon::Public
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowDispatch
|
||||
private import semmle.code.java.controlflow.Guards
|
||||
private import semmle.code.java.dataflow.SSA
|
||||
@@ -324,3 +324,5 @@ predicate isUnreachableInCall(Node n, DataFlowCall call) {
|
||||
guard.controls(n.asExpr().getBasicBlock(), arg.getBooleanValue().booleanNot())
|
||||
)
|
||||
}
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
@@ -380,10 +380,25 @@ private predicate argToMethodStep(Expr tracked, MethodAccess sink) {
|
||||
taintPreservingArgumentToMethod(m, i) and
|
||||
tracked = sink.(MethodAccess).getArgument(i)
|
||||
)
|
||||
or
|
||||
exists(MethodAccess ma |
|
||||
taintPreservingArgumentToMethod(ma.getMethod()) and
|
||||
tracked = ma.getAnArgument() and
|
||||
sink = ma
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `method` is a library method that return tainted data if its
|
||||
* Holds if `method` is a library method that returns tainted data if any
|
||||
* of its arguments are tainted.
|
||||
*/
|
||||
private predicate taintPreservingArgumentToMethod(Method method) {
|
||||
method.getDeclaringType() instanceof TypeString and
|
||||
(method.hasName("format") or method.hasName("join"))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `method` is a library method that returns tainted data if its
|
||||
* `arg`th argument is tainted.
|
||||
*/
|
||||
private predicate taintPreservingArgumentToMethod(Method method, int arg) {
|
||||
|
||||
@@ -32,7 +32,6 @@ nodes
|
||||
| A2.java:15:15:15:28 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A2.java:27:27:27:34 | o : Number | semmle.label | o : Number |
|
||||
| A2.java:29:9:29:9 | o | semmle.label | o |
|
||||
| A2.java:37:10:37:10 | o | semmle.label | o |
|
||||
| A.java:14:29:14:36 | o : Number | semmle.label | o : Number |
|
||||
| A.java:16:9:16:9 | o | semmle.label | o |
|
||||
| A.java:20:30:20:37 | o : Number | semmle.label | o : Number |
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
| Read | A.java:5:12:5:15 | this | A.java:5:12:5:19 | this.foo | A.java:2:7:2:9 | foo |
|
||||
| Read | A.java:21:13:21:13 | a | A.java:21:13:21:22 | getFoo(...) | A.java:2:7:2:9 | foo |
|
||||
| Read | A.java:23:9:23:9 | a | A.java:23:9:23:19 | aGetter(...) | A.java:2:7:2:9 | foo |
|
||||
| Read | A.java:24:9:24:10 | a2 | A.java:24:9:24:23 | notAGetter(...) | A.java:2:7:2:9 | foo |
|
||||
| Read | A.java:45:12:45:38 | maybeIdWrap(...) | A.java:45:12:45:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo |
|
||||
| Read | A.java:49:12:49:38 | maybeIdWrap(...) | A.java:49:12:49:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo |
|
||||
| Store | A.java:9:16:9:16 | x | A.java:9:5:9:8 | this [post update] | A.java:2:7:2:9 | foo |
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.internal.DataFlowImplCommon::Public
|
||||
import semmle.code.java.dataflow.internal.DataFlowImplCommon
|
||||
import semmle.code.java.dataflow.internal.DataFlowImplSpecific::Public
|
||||
import semmle.code.java.dataflow.internal.DataFlowImplSpecific::Private
|
||||
|
||||
private predicate read(Node n1, Content f, Node n2) {
|
||||
readDirect(n1, f, n2) or
|
||||
argumentValueFlowsThrough(_, n1, TContentSome(f), TContentNone(), n2)
|
||||
}
|
||||
|
||||
private predicate store(Node n1, Content f, Node n2) {
|
||||
storeDirect(n1, f, n2) or
|
||||
argumentValueFlowsThrough(_, n1, TContentNone(), TContentSome(f), n2)
|
||||
}
|
||||
|
||||
from Node n1, Content f, Node n2, string k
|
||||
where
|
||||
read(n1, f, n2) and k = "Read"
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
+ semmlecode-javascript-queries/Security/CWE-079/ReflectedXss.ql: /Security/CWE/CWE-079
|
||||
+ semmlecode-javascript-queries/Security/CWE-079/StoredXss.ql: /Security/CWE/CWE-079
|
||||
+ semmlecode-javascript-queries/Security/CWE-079/Xss.ql: /Security/CWE/CWE-079
|
||||
+ semmlecode-javascript-queries/Security/CWE-079/UnsafeJQueryPlugin.ql: /Security/CWE/CWE-079
|
||||
+ semmlecode-javascript-queries/Security/CWE-089/SqlInjection.ql: /Security/CWE/CWE-089
|
||||
+ semmlecode-javascript-queries/Security/CWE-094/CodeInjection.ql: /Security/CWE/CWE-094
|
||||
+ semmlecode-javascript-queries/Security/CWE-094/UnsafeDynamicMethodAccess.ql: /Security/CWE/CWE-094
|
||||
|
||||
101
javascript/ql/src/Security/CWE-079/UnsafeJQueryPlugin.qhelp
Normal file
101
javascript/ql/src/Security/CWE-079/UnsafeJQueryPlugin.qhelp
Normal file
@@ -0,0 +1,101 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
|
||||
Library plugins, such as those for the jQuery library, are often
|
||||
configurable through options provided by the clients of the
|
||||
plugin.
|
||||
|
||||
|
||||
Clients, however, do not know the implementation details
|
||||
of the plugin, so it is important to document the capabilities of each
|
||||
option. The documentation for the plugin options that the client is
|
||||
responsible for sanitizing is of particular importance.
|
||||
|
||||
Otherwise, the plugin may write user input (for example, a URL query
|
||||
parameter) to a web page without properly sanitizing it first,
|
||||
which allows for a cross-site scripting vulnerability in the client
|
||||
application through dynamic HTML construction.
|
||||
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
|
||||
Document all options that can lead to cross-site scripting
|
||||
attacks, and guard against unsafe inputs where dynamic HTML
|
||||
construction is not intended.
|
||||
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
|
||||
The following example shows a jQuery plugin that selects a
|
||||
DOM element, and copies its text content to another DOM element. The
|
||||
selection is performed by using the plugin option
|
||||
<code>sourceSelector</code> as a CSS selector.
|
||||
|
||||
</p>
|
||||
|
||||
<sample src="examples/UnsafeJQueryPlugin.js" />
|
||||
|
||||
<p>
|
||||
|
||||
This is, however, not a safe plugin, since the call to
|
||||
<code>jQuery</code> interprets <code>sourceSelector</code> as HTML if
|
||||
it is a string that starts with <code><</code>.
|
||||
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
Instead of documenting that the client is responsible for
|
||||
sanitizing <code>sourceSelector</code>, the plugin can use
|
||||
<code>jQuery.find</code> to always interpret
|
||||
<code>sourceSelector</code> as a CSS selector:
|
||||
|
||||
</p>
|
||||
|
||||
<sample src="examples/UnsafeJQueryPlugin_safe.js" />
|
||||
|
||||
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
OWASP:
|
||||
<a href="https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet">DOM based
|
||||
XSS Prevention Cheat Sheet</a>.
|
||||
</li>
|
||||
<li>
|
||||
OWASP:
|
||||
<a href="https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet">XSS
|
||||
(Cross Site Scripting) Prevention Cheat Sheet</a>.
|
||||
</li>
|
||||
<li>
|
||||
OWASP
|
||||
<a href="https://www.owasp.org/index.php/DOM_Based_XSS">DOM Based XSS</a>.
|
||||
</li>
|
||||
<li>
|
||||
OWASP
|
||||
<a href="https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting">Types of Cross-Site
|
||||
Scripting</a>.
|
||||
</li>
|
||||
<li>
|
||||
Wikipedia: <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">Cross-site scripting</a>.
|
||||
</li>
|
||||
<li>
|
||||
jQuery: <a href="https://learn.jquery.com/plugins/basic-plugin-creation/">Plugin creation</a>.
|
||||
</li>
|
||||
<li>
|
||||
Bootstrap: <a href="https://github.com/twbs/bootstrap/pull/27047">XSS vulnerable bootstrap plugins</a>.
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
25
javascript/ql/src/Security/CWE-079/UnsafeJQueryPlugin.ql
Normal file
25
javascript/ql/src/Security/CWE-079/UnsafeJQueryPlugin.ql
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @name Unsafe jQuery plugin
|
||||
* @description A jQuery plugin that unintentionally constructs HTML from some of its options may be unsafe to use for clients.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @precision high
|
||||
* @id js/unsafe-jquery-plugin
|
||||
* @tags security
|
||||
* external/cwe/cwe-079
|
||||
* external/cwe/cwe-116
|
||||
* frameworks/jquery
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import semmle.javascript.security.dataflow.UnsafeJQueryPlugin::UnsafeJQueryPlugin
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from
|
||||
Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, JQueryPluginMethod plugin
|
||||
where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
source.getNode().(Source).getPlugin() = plugin and
|
||||
not isLikelyIntentionalHtmlSink(plugin, sink.getNode())
|
||||
select sink.getNode(), source, sink, "Potential XSS vulnerability in the $@.", plugin,
|
||||
"'$.fn." + plugin.getPluginName() + "' plugin"
|
||||
@@ -0,0 +1,6 @@
|
||||
jQuery.fn.copyText = function(options) {
|
||||
// BAD may evaluate `options.sourceSelector` as HTML
|
||||
var source = jQuery(options.sourceSelector),
|
||||
text = source.text();
|
||||
jQuery(this).text(text);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
jQuery.fn.copyText = function(options) {
|
||||
// GOOD may not evaluate `options.sourceSelector` as HTML
|
||||
var source = jQuery.find(options.sourceSelector),
|
||||
text = source.text();
|
||||
jQuery(this).text(text);
|
||||
}
|
||||
@@ -78,7 +78,7 @@ predicate importLookup(ASTNode path, Module target, string kind) {
|
||||
or
|
||||
exists(ReExportDeclaration red |
|
||||
path = red.getImportedPath() and
|
||||
target = red.getImportedModule()
|
||||
target = red.getReExportedModule()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -273,12 +273,12 @@ class BulkReExportDeclaration extends ReExportDeclaration, @exportalldeclaration
|
||||
override ConstantString getImportedPath() { result = getChildExpr(0) }
|
||||
|
||||
override predicate exportsAs(LexicalName v, string name) {
|
||||
getImportedModule().exportsAs(v, name) and
|
||||
getReExportedES2015Module().exportsAs(v, name) and
|
||||
not isShadowedFromBulkExport(this, name)
|
||||
}
|
||||
|
||||
override DataFlow::Node getSourceNode(string name) {
|
||||
result = getImportedModule().getAnExport().getSourceNode(name)
|
||||
result = getReExportedES2015Module().getAnExport().getSourceNode(name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ class ExportNamedDeclaration extends ExportDeclaration, @exportnameddeclaration
|
||||
exists(ExportSpecifier spec | spec = getASpecifier() and name = spec.getExportedName() |
|
||||
v = spec.getLocal().(LexicalAccess).getALexicalName()
|
||||
or
|
||||
this.(ReExportDeclaration).getImportedModule().exportsAs(v, spec.getLocalName())
|
||||
this.(ReExportDeclaration).getReExportedES2015Module().exportsAs(v, spec.getLocalName())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -393,7 +393,7 @@ class ExportNamedDeclaration extends ExportDeclaration, @exportnameddeclaration
|
||||
not exists(getImportedPath()) and result = DataFlow::valueNode(spec.getLocal())
|
||||
or
|
||||
exists(ReExportDeclaration red | red = this |
|
||||
result = red.getImportedModule().getAnExport().getSourceNode(spec.getLocalName())
|
||||
result = red.getReExportedES2015Module().getAnExport().getSourceNode(spec.getLocalName())
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -545,14 +545,18 @@ class ReExportDefaultSpecifier extends ExportDefaultSpecifier {
|
||||
}
|
||||
|
||||
/**
|
||||
* A namespace export specifier.
|
||||
* A namespace export specifier, that is `*` or `* as x` occuring in an export declaration.
|
||||
*
|
||||
* Example:
|
||||
* Examples:
|
||||
*
|
||||
* ```
|
||||
* export
|
||||
* * // namespace export specifier
|
||||
* from 'a';
|
||||
*
|
||||
* export
|
||||
* * as x // namespace export specifier
|
||||
* from 'a';
|
||||
* ```
|
||||
*/
|
||||
class ExportNamespaceSpecifier extends ExportSpecifier, @exportnamespacespecifier { }
|
||||
@@ -564,6 +568,7 @@ class ExportNamespaceSpecifier extends ExportSpecifier, @exportnamespacespecifie
|
||||
*
|
||||
* ```
|
||||
* export * from 'a'; // bulk re-export declaration
|
||||
* export * as x from 'a'; // namespace re-export declaration
|
||||
* export { x } from 'a'; // named re-export declaration
|
||||
* export x from 'a'; // default re-export declaration
|
||||
* ```
|
||||
@@ -572,8 +577,23 @@ abstract class ReExportDeclaration extends ExportDeclaration {
|
||||
/** Gets the path of the module from which this declaration re-exports. */
|
||||
abstract ConstantString getImportedPath();
|
||||
|
||||
/** Gets the module from which this declaration re-exports. */
|
||||
/**
|
||||
* DEPRECATED. Use `getReExportedES2015Module()` instead.
|
||||
*
|
||||
* Gets the module from which this declaration re-exports.
|
||||
*/
|
||||
deprecated
|
||||
ES2015Module getImportedModule() {
|
||||
result = getReExportedModule()
|
||||
}
|
||||
|
||||
/** Gets the module from which this declaration re-exports, if it is an ES2015 module. */
|
||||
ES2015Module getReExportedES2015Module() {
|
||||
result = getReExportedModule()
|
||||
}
|
||||
|
||||
/** Gets the module from which this declaration re-exports. */
|
||||
Module getReExportedModule() {
|
||||
result.getFile() = getEnclosingModule().resolve(getImportedPath().(PathExpr))
|
||||
or
|
||||
result = resolveFromTypeRoot()
|
||||
@@ -641,4 +661,4 @@ class OriginalExportDeclaration extends ExportDeclaration {
|
||||
result = this.(ExportDefaultDeclaration).getSourceNode(name) or
|
||||
result = this.(ExportNamedDeclaration).getSourceNode(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,69 +271,84 @@ module TaintTracking {
|
||||
ArrayFunctionTaintStep() { this = call }
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
// `array.map(function (elt, i, ary) { ... })`: if `array` is tainted, then so are
|
||||
// `elt` and `ary`; similar for `forEach`
|
||||
exists(string name, Function f, int i |
|
||||
(name = "map" or name = "forEach") and
|
||||
(i = 0 or i = 2) and
|
||||
call.getArgument(0).analyze().getAValue().(AbstractFunction).getFunction() = f and
|
||||
call.(DataFlow::MethodCallNode).getMethodName() = name and
|
||||
pred = call.getReceiver() and
|
||||
succ = DataFlow::parameterNode(f.getParameter(i))
|
||||
)
|
||||
or
|
||||
// `array.map` with tainted return value in callback
|
||||
exists(DataFlow::FunctionNode f |
|
||||
call.(DataFlow::MethodCallNode).getMethodName() = "map" and
|
||||
call.getArgument(0) = f and // Require the argument to be a closure to avoid spurious call/return flow
|
||||
pred = f.getAReturn() and
|
||||
succ = call
|
||||
)
|
||||
or
|
||||
// `array.push(e)`, `array.unshift(e)`: if `e` is tainted, then so is `array`.
|
||||
exists(string name |
|
||||
name = "push" or
|
||||
name = "unshift"
|
||||
|
|
||||
pred = call.getAnArgument() and
|
||||
succ.(DataFlow::SourceNode).getAMethodCall(name) = call
|
||||
)
|
||||
or
|
||||
// `array.push(...e)`, `array.unshift(...e)`: if `e` is tainted, then so is `array`.
|
||||
exists(string name |
|
||||
name = "push" or
|
||||
name = "unshift"
|
||||
|
|
||||
pred = call.getASpreadArgument() and
|
||||
// Make sure we handle reflective calls
|
||||
succ = call.getReceiver().getALocalSource() and
|
||||
call.getCalleeName() = name
|
||||
)
|
||||
or
|
||||
// `array.splice(i, del, e)`: if `e` is tainted, then so is `array`.
|
||||
exists(string name | name = "splice" |
|
||||
pred = call.getArgument(2) and
|
||||
succ.(DataFlow::SourceNode).getAMethodCall(name) = call
|
||||
)
|
||||
or
|
||||
// `e = array.pop()`, `e = array.shift()`, or similar: if `array` is tainted, then so is `e`.
|
||||
exists(string name |
|
||||
name = "pop" or
|
||||
name = "shift" or
|
||||
name = "slice" or
|
||||
name = "splice"
|
||||
|
|
||||
call.(DataFlow::MethodCallNode).calls(pred, name) and
|
||||
succ = call
|
||||
)
|
||||
or
|
||||
// `e = Array.from(x)`: if `x` is tainted, then so is `e`.
|
||||
call = DataFlow::globalVarRef("Array").getAPropertyRead("from").getACall() and
|
||||
pred = call.getAnArgument() and
|
||||
succ = call
|
||||
arrayFunctionTaintStep(pred, succ, call)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint propagating data flow edge from `pred` to `succ` caused by a call `call` to a builtin array functions.
|
||||
*/
|
||||
predicate arrayFunctionTaintStep(DataFlow::Node pred, DataFlow::Node succ, DataFlow::CallNode call) {
|
||||
// `array.map(function (elt, i, ary) { ... })`: if `array` is tainted, then so are
|
||||
// `elt` and `ary`; similar for `forEach`
|
||||
exists(string name, Function f, int i |
|
||||
(name = "map" or name = "forEach") and
|
||||
(i = 0 or i = 2) and
|
||||
call.getArgument(0).analyze().getAValue().(AbstractFunction).getFunction() = f and
|
||||
call.(DataFlow::MethodCallNode).getMethodName() = name and
|
||||
pred = call.getReceiver() and
|
||||
succ = DataFlow::parameterNode(f.getParameter(i))
|
||||
)
|
||||
or
|
||||
// `array.map` with tainted return value in callback
|
||||
exists(DataFlow::FunctionNode f |
|
||||
call.(DataFlow::MethodCallNode).getMethodName() = "map" and
|
||||
call.getArgument(0) = f and // Require the argument to be a closure to avoid spurious call/return flow
|
||||
pred = f.getAReturn() and
|
||||
succ = call
|
||||
)
|
||||
or
|
||||
// `array.push(e)`, `array.unshift(e)`: if `e` is tainted, then so is `array`.
|
||||
exists(string name |
|
||||
name = "push" or
|
||||
name = "unshift"
|
||||
|
|
||||
pred = call.getAnArgument() and
|
||||
succ.(DataFlow::SourceNode).getAMethodCall(name) = call
|
||||
)
|
||||
or
|
||||
// `array.push(...e)`, `array.unshift(...e)`: if `e` is tainted, then so is `array`.
|
||||
exists(string name |
|
||||
name = "push" or
|
||||
name = "unshift"
|
||||
|
|
||||
pred = call.getASpreadArgument() and
|
||||
// Make sure we handle reflective calls
|
||||
succ = call.getReceiver().getALocalSource() and
|
||||
call.getCalleeName() = name
|
||||
)
|
||||
or
|
||||
// `array.splice(i, del, e)`: if `e` is tainted, then so is `array`.
|
||||
exists(string name | name = "splice" |
|
||||
pred = call.getArgument(2) and
|
||||
succ.(DataFlow::SourceNode).getAMethodCall(name) = call
|
||||
)
|
||||
or
|
||||
// `e = array.pop()`, `e = array.shift()`, or similar: if `array` is tainted, then so is `e`.
|
||||
exists(string name |
|
||||
name = "pop" or
|
||||
name = "shift" or
|
||||
name = "slice" or
|
||||
name = "splice"
|
||||
|
|
||||
call.(DataFlow::MethodCallNode).calls(pred, name) and
|
||||
succ = call
|
||||
)
|
||||
or
|
||||
// `e = Array.from(x)`: if `x` is tainted, then so is `e`.
|
||||
call = DataFlow::globalVarRef("Array").getAPropertyRead("from").getACall() and
|
||||
pred = call.getAnArgument() and
|
||||
succ = call
|
||||
or
|
||||
// `e = arr1.concat(arr2, arr3)`: if any of the `arr` is tainted, then so is `e`.
|
||||
call.(DataFlow::MethodCallNode).calls(pred, "concat") and
|
||||
succ = call
|
||||
or
|
||||
call.(DataFlow::MethodCallNode).getMethodName() = "concat" and
|
||||
succ = call and
|
||||
pred = call.getAnArgument()
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint propagating data flow edge for assignments of the form `o[k] = v`, where
|
||||
* `k` is not a constant and `o` refers to some object literal; in this case, we consider
|
||||
|
||||
@@ -65,7 +65,7 @@ private predicate mayDynamicallyComputeExports(Module m) {
|
||||
or
|
||||
// `m` re-exports all exports of some other module that dynamically computes its exports
|
||||
exists(BulkReExportDeclaration rexp | rexp = m.(ES2015Module).getAnExport() |
|
||||
mayDynamicallyComputeExports(rexp.getImportedModule())
|
||||
mayDynamicallyComputeExports(rexp.getReExportedModule())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ private predicate relevantExport(ES2015Module m, string x) {
|
||||
)
|
||||
or
|
||||
exists(ReExportDeclaration rexp, string y |
|
||||
rexp.getImportedModule() = m and
|
||||
rexp.getReExportedModule() = m and
|
||||
reExportsAs(rexp, x, y)
|
||||
)
|
||||
}
|
||||
@@ -110,9 +110,9 @@ private predicate incompleteExport(ES2015Module m, string y) {
|
||||
mayDependOnLookupPath(rexp.getImportedPath().getStringValue())
|
||||
or
|
||||
// unresolvable path
|
||||
not exists(rexp.getImportedModule())
|
||||
not exists(rexp.getReExportedModule())
|
||||
or
|
||||
exists(Module n | n = rexp.getImportedModule() |
|
||||
exists(Module n | n = rexp.getReExportedModule() |
|
||||
// re-export from CommonJS/AMD
|
||||
mayDynamicallyComputeExports(n)
|
||||
or
|
||||
@@ -399,3 +399,16 @@ private class AnalyzedClosureGlobalAccessPath extends AnalyzedNode, AnalyzedProp
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A namespace export declaration analyzed as a property write.
|
||||
*/
|
||||
private class AnalyzedExportNamespaceSpecifier extends AnalyzedPropertyWrite, DataFlow::ValueNode {
|
||||
override ExportNamespaceSpecifier astNode;
|
||||
|
||||
override predicate writesValue(AbstractValue baseVal, string propName, AbstractValue value) {
|
||||
baseVal = TAbstractExportsObject(getTopLevel()) and
|
||||
propName = astNode.getExportedName() and
|
||||
value = TAbstractExportsObject(astNode.getExportDeclaration().(ReExportDeclaration).getReExportedModule())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,4 +549,72 @@ module ClientRequest {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to an instance of `chrome-remote-interface`.
|
||||
*
|
||||
* An instantiation of `chrome-remote-interface` either accepts a callback or returns a promise.
|
||||
*
|
||||
* The `isPromise` parameter reflects whether the reference is a promise containing
|
||||
* an instance of `chrome-remote-interface`, or an instance of `chrome-remote-interface`.
|
||||
*/
|
||||
private DataFlow::SourceNode chromeRemoteInterface(DataFlow::TypeTracker t, boolean isPromise) {
|
||||
t.start() and
|
||||
exists(DataFlow::CallNode call |
|
||||
call = DataFlow::moduleImport("chrome-remote-interface").getAnInvocation()
|
||||
|
|
||||
result = call and isPromise = true
|
||||
or
|
||||
result = call.getCallback([0 .. 1]).getParameter(0) and isPromise = false
|
||||
)
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = chromeRemoteInterface(t2, isPromise).track(t2, t))
|
||||
or
|
||||
// Simple promise tracking.
|
||||
exists(DataFlow::TypeTracker t2, DataFlow::SourceNode pred |
|
||||
pred = chromeRemoteInterface(t2, true) and
|
||||
isPromise = false and
|
||||
(
|
||||
t2 = t and
|
||||
exists(AwaitExpr await | DataFlow::valueNode(await.getOperand()).getALocalSource() = pred |
|
||||
result.getEnclosingExpr() = await
|
||||
)
|
||||
or
|
||||
t2 = t and
|
||||
exists(DataFlow::MethodCallNode thenCall |
|
||||
thenCall.getMethodName() = "then" and pred = thenCall.getReceiver().getALocalSource()
|
||||
|
|
||||
result = thenCall.getCallback(0).getParameter(0)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to navigate a browser controlled by `chrome-remote-interface` to a specific URL.
|
||||
*/
|
||||
class ChromeRemoteInterfaceRequest extends ClientRequest::Range, DataFlow::CallNode {
|
||||
int optionsArg;
|
||||
|
||||
ChromeRemoteInterfaceRequest() {
|
||||
exists(DataFlow::SourceNode instance |
|
||||
instance = chromeRemoteInterface(DataFlow::TypeTracker::end(), false)
|
||||
|
|
||||
optionsArg = 0 and
|
||||
this = instance.getAPropertyRead("Page").getAMemberCall("navigate")
|
||||
or
|
||||
optionsArg = 1 and
|
||||
this = instance.getAMemberCall("send") and
|
||||
this.getArgument(0).mayHaveStringValue("Page.navigate")
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrl() {
|
||||
result = getArgument(optionsArg).getALocalSource().getAPropertyWrite("url").getRhs()
|
||||
}
|
||||
|
||||
override DataFlow::Node getHost() { none() }
|
||||
|
||||
override DataFlow::Node getADataNode() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,8 +119,11 @@ module HTTP {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `http` or `https` directly as appropriate.
|
||||
*
|
||||
* Gets the string `http` or `https`.
|
||||
*/
|
||||
deprecated
|
||||
string httpOrHttps() { result = "http" or result = "https" }
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,7 +42,18 @@ module NodeJSLib {
|
||||
* Holds if `call` is an invocation of `http.createServer` or `https.createServer`.
|
||||
*/
|
||||
predicate isCreateServer(CallExpr call) {
|
||||
call = DataFlow::moduleMember(HTTP::httpOrHttps(), "createServer").getAnInvocation().asExpr()
|
||||
exists(string pkg, string fn |
|
||||
pkg = "http" and fn = "createServer"
|
||||
or
|
||||
pkg = "https" and fn = "createServer"
|
||||
or
|
||||
// http2 compatibility API
|
||||
pkg = "http2" and fn = "createServer"
|
||||
or
|
||||
pkg = "http2" and fn = "createSecureServer"
|
||||
|
|
||||
call = DataFlow::moduleMember(pkg, fn).getAnInvocation().asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -356,10 +367,12 @@ module NodeJSLib {
|
||||
/** An expression that is passed as `http.request({ auth: <expr> }, ...)`. */
|
||||
class Credentials extends CredentialsExpr {
|
||||
Credentials() {
|
||||
this = DataFlow::moduleMember(HTTP::httpOrHttps(), "request")
|
||||
.getACall()
|
||||
.getOptionArgument(0, "auth")
|
||||
.asExpr()
|
||||
exists(string http | http = "http" or http = "https" |
|
||||
this = DataFlow::moduleMember(http, "request")
|
||||
.getACall()
|
||||
.getOptionArgument(0, "auth")
|
||||
.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
override string getCredentialsKind() { result = "credentials" }
|
||||
@@ -881,7 +894,6 @@ module NodeJSLib {
|
||||
override string getSourceType() { result = "NodeJSClientRequest error event" }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An NodeJS EventEmitter instance.
|
||||
* Events dispatched on this EventEmitter will be handled by event handlers registered on this EventEmitter.
|
||||
|
||||
@@ -30,9 +30,14 @@ private DataFlow::Node commandArgument(SystemCommandExecution sys, DataFlow::Typ
|
||||
t.start() and
|
||||
result = sys.getACommandArgument()
|
||||
or
|
||||
exists(DataFlow::TypeBackTracker t2 |
|
||||
t = t2.smallstep(result, commandArgument(sys, t2))
|
||||
)
|
||||
exists(DataFlow::TypeBackTracker t2 | t = t2.smallstep(result, commandArgument(sys, t2)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data-flow node whose value ends up being interpreted as the command argument in `sys`.
|
||||
*/
|
||||
private DataFlow::Node commandArgument(SystemCommandExecution sys) {
|
||||
result = commandArgument(sys, DataFlow::TypeBackTracker::end())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,11 +48,23 @@ private DataFlow::SourceNode argumentList(SystemCommandExecution sys, DataFlow::
|
||||
t.start() and
|
||||
result = sys.getArgumentList().getALocalSource()
|
||||
or
|
||||
exists(DataFlow::TypeBackTracker t2 |
|
||||
result = argumentList(sys, t2).backtrack(t2, t)
|
||||
exists(DataFlow::TypeBackTracker t2, DataFlow::SourceNode pred |
|
||||
pred = argumentList(sys, t2)
|
||||
|
|
||||
result = pred.backtrack(t2, t)
|
||||
or
|
||||
t = t2.continue() and
|
||||
TaintTracking::arrayFunctionTaintStep(result, pred, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data-flow node whose value ends up being interpreted as the argument list in `sys`.
|
||||
*/
|
||||
private DataFlow::SourceNode argumentList(SystemCommandExecution sys) {
|
||||
result = argumentList(sys, DataFlow::TypeBackTracker::end())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `source` contributes to the arguments of an indirect command execution `sys`.
|
||||
*
|
||||
@@ -61,15 +78,22 @@ private DataFlow::SourceNode argumentList(SystemCommandExecution sys, DataFlow::
|
||||
* let args = ["-c", cmd];
|
||||
* childProcess.spawn(sh, args, cb);
|
||||
* ```
|
||||
* or
|
||||
* ```
|
||||
* let cmd = getCommand();
|
||||
* childProcess.spawn("cmd.exe", ["/c"].concat(cmd), cb);
|
||||
* ```
|
||||
*/
|
||||
predicate isIndirectCommandArgument(DataFlow::Node source, SystemCommandExecution sys) {
|
||||
exists(
|
||||
DataFlow::ArrayCreationNode args, DataFlow::Node shell, string dashC
|
||||
|
|
||||
exists(DataFlow::ArrayCreationNode args, DataFlow::Node shell, string dashC |
|
||||
shellCmd(shell.asExpr(), dashC) and
|
||||
shell = commandArgument(sys, DataFlow::TypeBackTracker::end()) and
|
||||
args = argumentList(sys, DataFlow::TypeBackTracker::end()) and
|
||||
shell = commandArgument(sys) and
|
||||
args.getAPropertyWrite().getRhs().mayHaveStringValue(dashC) and
|
||||
source = args.getAPropertyWrite().getRhs()
|
||||
args = argumentList(sys) and
|
||||
(
|
||||
source = argumentList(sys)
|
||||
or
|
||||
source = argumentList(sys).getAPropertyWrite().getRhs()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Provides a taint-tracking configuration for reasoning about DOM-based
|
||||
* cross-site scripting vulnerabilities in unsafe jQuery plugins.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import semmle.javascript.security.dataflow.Xss
|
||||
|
||||
module UnsafeJQueryPlugin {
|
||||
import UnsafeJQueryPluginCustomizations::UnsafeJQueryPlugin
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about XSS in unsafe jQuery plugins.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "UnsafeJQueryPlugin" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
super.isSanitizer(node)
|
||||
or
|
||||
node instanceof DomBasedXss::Sanitizer
|
||||
or
|
||||
node instanceof Sanitizer
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
// jQuery plugins tend to be implemented as classes that store data in fields initialized by the constructor.
|
||||
DataFlow::localFieldStep(src, sink)
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
// prefixing prevents forced html/css confusion:
|
||||
|
||||
// prefixing through concatenation:
|
||||
StringConcatenation::taintStep(pred, succ, _, any(int i | i >= 1))
|
||||
or
|
||||
// prefixing through a poor-mans templating system:
|
||||
exists(DataFlow::MethodCallNode replace |
|
||||
replace = succ and
|
||||
pred = replace.getArgument(1) and
|
||||
replace.getMethodName() = "replace"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode node) {
|
||||
super.isSanitizerGuard(node) or
|
||||
node instanceof IsElementSanitizer or
|
||||
node instanceof PropertyPresenceSanitizer
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for reasoning about
|
||||
* unsafe jQuery plugins, as well as extension points for adding your
|
||||
* own.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
private import semmle.javascript.dataflow.InferredTypes
|
||||
import semmle.javascript.security.dataflow.Xss
|
||||
|
||||
module UnsafeJQueryPlugin {
|
||||
private import DataFlow::FlowLabel
|
||||
|
||||
/**
|
||||
* A data flow source for unsafe jQuery plugins.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node {
|
||||
/**
|
||||
* Gets the plugin that this source is used in.
|
||||
*/
|
||||
abstract JQueryPluginMethod getPlugin();
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow sink for unsafe jQuery plugins.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sanitizer for unsafe jQuery plugins.
|
||||
*/
|
||||
abstract class Sanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* An argument that may act as a HTML fragment rather than a CSS selector, as a sink for remote unsafe jQuery plugins.
|
||||
*/
|
||||
class AmbiguousHtmlOrSelectorArgument extends DataFlow::Node {
|
||||
AmbiguousHtmlOrSelectorArgument() {
|
||||
exists(JQuery::MethodCall call |
|
||||
call.interpretsArgumentAsSelector(this) and call.interpretsArgumentAsHtml(this)
|
||||
) and
|
||||
// the $-function in particular will not construct HTML for non-string values
|
||||
analyze().getAType() = TTString() and
|
||||
// any fixed prefix makes the call unambiguous
|
||||
not exists(DataFlow::Node prefix |
|
||||
DomBasedXss::isPrefixOfJQueryHtmlString(this, prefix) and
|
||||
prefix.mayHaveStringValue(_)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds for jQuery plugin definitions of the form `$.fn.<pluginName> = <plugin>`.
|
||||
*/
|
||||
private predicate jQueryPluginDefinition(string pluginName, DataFlow::Node plugin) {
|
||||
exists(DataFlow::PropRead fn, DataFlow::PropWrite write |
|
||||
fn = jquery().getAPropertyRead("fn") and
|
||||
(
|
||||
write = fn.getAPropertyWrite()
|
||||
or
|
||||
exists(ExtendCall extend, DataFlow::SourceNode source |
|
||||
fn.flowsTo(extend.getDestinationOperand()) and
|
||||
source = extend.getASourceOperand() and
|
||||
write = source.getAPropertyWrite()
|
||||
)
|
||||
) and
|
||||
plugin = write.getRhs() and
|
||||
(
|
||||
pluginName = write.getPropertyName() or
|
||||
write.getPropertyNameExpr().flow().mayHaveStringValue(pluginName)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a node that is registered as a jQuery plugin method at `def`.
|
||||
*/
|
||||
private DataFlow::SourceNode getAJQueryPluginMethod(
|
||||
DataFlow::TypeBackTracker t, DataFlow::Node def
|
||||
) {
|
||||
t.start() and
|
||||
jQueryPluginDefinition(_, def) and
|
||||
result.flowsTo(def)
|
||||
or
|
||||
exists(DataFlow::TypeBackTracker t2 | result = getAJQueryPluginMethod(t2, def).backtrack(t2, t))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a function that is registered as a jQuery plugin method at `def`.
|
||||
*/
|
||||
private DataFlow::FunctionNode getAJQueryPluginMethod(DataFlow::Node def) {
|
||||
result = getAJQueryPluginMethod(DataFlow::TypeBackTracker::end(), def)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an operand to `extend`.
|
||||
*/
|
||||
private DataFlow::SourceNode getAnExtendOperand(DataFlow::TypeBackTracker t, ExtendCall extend) {
|
||||
t.start() and
|
||||
result.flowsTo(extend.getAnOperand())
|
||||
or
|
||||
exists(DataFlow::TypeBackTracker t2 | result = getAnExtendOperand(t2, extend).backtrack(t2, t))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an operand to `extend`.
|
||||
*/
|
||||
private DataFlow::SourceNode getAnExtendOperand(ExtendCall extend) {
|
||||
result = getAnExtendOperand(DataFlow::TypeBackTracker::end(), extend)
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that is registered as a jQuery plugin method.
|
||||
*/
|
||||
class JQueryPluginMethod extends DataFlow::FunctionNode {
|
||||
string pluginName;
|
||||
|
||||
JQueryPluginMethod() {
|
||||
exists(DataFlow::Node def |
|
||||
jQueryPluginDefinition(pluginName, def) and
|
||||
this = getAJQueryPluginMethod(def)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this plugin.
|
||||
*/
|
||||
string getPluginName() { result = pluginName }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `plugin` has a default option defined at `def`.
|
||||
*/
|
||||
private predicate hasDefaultOption(JQueryPluginMethod plugin, DataFlow::PropWrite def) {
|
||||
exists(ExtendCall extend, JQueryPluginOptions options, DataFlow::SourceNode default |
|
||||
options.getPlugin() = plugin and
|
||||
options = getAnExtendOperand(extend) and
|
||||
default = getAnExtendOperand(extend) and
|
||||
default.getAPropertyWrite() = def
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* The client-provided options object for a jQuery plugin.
|
||||
*/
|
||||
class JQueryPluginOptions extends DataFlow::ParameterNode {
|
||||
JQueryPluginMethod method;
|
||||
|
||||
JQueryPluginOptions() {
|
||||
exists(string optionsPattern |
|
||||
optionsPattern = "(?i)(opt(ion)?s?)" and
|
||||
if method.getAParameter().getName().regexpMatch(optionsPattern)
|
||||
then (
|
||||
// use the last parameter named something like "options" if it exists ...
|
||||
getName().regexpMatch(optionsPattern) and
|
||||
this = method.getAParameter()
|
||||
) else (
|
||||
// ... otherwise, use the last parameter, unless it looks like a DOM node
|
||||
this = method.getLastParameter() and
|
||||
not getName().regexpMatch("(?i)(e(l(em(ent(s)?)?)?)?)")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the plugin method that these options are used in.
|
||||
*/
|
||||
JQueryPluginMethod getPlugin() { result = method }
|
||||
}
|
||||
|
||||
/**
|
||||
* Expression of form `isElement(x)`, which sanitizes `x`.
|
||||
*/
|
||||
class IsElementSanitizer extends TaintTracking::SanitizerGuardNode, DataFlow::CallNode {
|
||||
IsElementSanitizer() {
|
||||
// common ad hoc sanitizing calls
|
||||
exists(string name | getCalleeName() = name |
|
||||
name = "isElement" or name = "isDocument" or name = "isWindow"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sanitizes(boolean outcome, Expr e) {
|
||||
outcome = true and e = getArgument(0).asExpr()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expression like `typeof x.<?> !== "undefined"` or `x.<?>`, which sanitizes `x`, as it is unlikely to be a string afterwards.
|
||||
*/
|
||||
class PropertyPresenceSanitizer extends TaintTracking::SanitizerGuardNode, DataFlow::ValueNode {
|
||||
DataFlow::Node input;
|
||||
boolean polarity;
|
||||
|
||||
PropertyPresenceSanitizer() {
|
||||
exists(DataFlow::PropRead read, string name |
|
||||
not name = "length" and read.accesses(input, name)
|
||||
|
|
||||
exists(EqualityTest test |
|
||||
polarity = test.getPolarity().booleanNot() and
|
||||
this = test.flow()
|
||||
|
|
||||
exists(Expr undef | test.hasOperands(read.asExpr(), undef) |
|
||||
SyntacticConstants::isUndefined(undef)
|
||||
)
|
||||
or
|
||||
exists(Expr op1, Expr op2 | test.hasOperands(op1, op2) |
|
||||
read.asExpr() = op1.(TypeofExpr).getOperand() and
|
||||
op2.mayHaveStringValue(any(InferredType t | t = TTUndefined()).getTypeofTag())
|
||||
)
|
||||
)
|
||||
or
|
||||
polarity = true and
|
||||
this = read
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sanitizes(boolean outcome, Expr e) {
|
||||
outcome = polarity and
|
||||
e = input.asExpr()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The client-provided options object for a jQuery plugin, considered as a source for unsafe jQuery plugins.
|
||||
*/
|
||||
class JQueryPluginOptionsAsSource extends Source, JQueryPluginOptions {
|
||||
override JQueryPluginMethod getPlugin() { result = JQueryPluginOptions.super.getPlugin() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An argument that may act as a HTML fragment rather than a CSS selector, as a sink for remote unsafe jQuery plugins.
|
||||
*/
|
||||
class AmbiguousHtmlOrSelectorArgumentAsSink extends Sink {
|
||||
AmbiguousHtmlOrSelectorArgumentAsSink() { this instanceof AmbiguousHtmlOrSelectorArgument }
|
||||
}
|
||||
|
||||
/**
|
||||
* A hint that a value is expected to be treated as a HTML fragment later.
|
||||
*/
|
||||
class IntentionalHtmlFragmentHint extends Sanitizer {
|
||||
IntentionalHtmlFragmentHint() {
|
||||
this.(DataFlow::PropRead).getPropertyName().regexpMatch("(?i).*(html|template).*")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `plugin` likely expects `sink` to be treated as a HTML fragment.
|
||||
*/
|
||||
predicate isLikelyIntentionalHtmlSink(JQueryPluginMethod plugin, Sink sink) {
|
||||
exists(DataFlow::PropWrite defaultDef, string default, DataFlow::PropRead finalRead |
|
||||
hasDefaultOption(plugin, defaultDef) and
|
||||
defaultDef.getPropertyName() = finalRead.getPropertyName() and
|
||||
defaultDef.getRhs().mayHaveStringValue(default) and
|
||||
default.regexpMatch("\\s*<.*") and
|
||||
finalRead.flowsTo(sink)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ module DomBasedXss {
|
||||
* Holds if `prefix` is a prefix of `htmlString`, which may be intepreted as
|
||||
* HTML by a jQuery method.
|
||||
*/
|
||||
private predicate isPrefixOfJQueryHtmlString(DataFlow::Node htmlString, DataFlow::Node prefix) {
|
||||
predicate isPrefixOfJQueryHtmlString(DataFlow::Node htmlString, DataFlow::Node prefix) {
|
||||
any(JQuery::MethodCall call).interpretsArgumentAsHtml(htmlString) and
|
||||
prefix = htmlString
|
||||
or
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user