mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge branch 'main' of github.com:github/codeql into SharedDataflow_SequenceFlow
This commit is contained in:
24
change-notes/1.26/analysis-cpp.md
Normal file
24
change-notes/1.26/analysis-cpp.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Improvements to C/C++ analysis
|
||||
|
||||
The following changes in version 1.26 affect C/C++ analysis in all applications.
|
||||
|
||||
## General improvements
|
||||
|
||||
## New queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|-----------------------------|-----------|--------------------------------------------------------------------|
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|----------------------------|------------------------|------------------------------------------------------------------|
|
||||
| Inconsistent direction of for loop (`cpp/inconsistent-loop-direction`) | Fewer false positive results | The query now accounts for intentional wrapping of an unsigned loop counter. |
|
||||
| Overflow in uncontrolled allocation size (`cpp/uncontrolled-allocation-size`) | | The precision of this query has been decreased from "high" to "medium". As a result, the query is still run but results are no longer displayed on LGTM by default. |
|
||||
| Comparison result is always the same (`cpp/constant-comparison`) | More correct results | Bounds on expressions involving multiplication can now be determined in more cases. |
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
* The models library now models more taint flows through `std::string`.
|
||||
* The `SimpleRangeAnalysis` library now supports multiplications of the form
|
||||
`e1 * e2` when `e1` and `e2` are unsigned.
|
||||
29
change-notes/1.26/analysis-csharp.md
Normal file
29
change-notes/1.26/analysis-csharp.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Improvements to C# analysis
|
||||
|
||||
The following changes in version 1.26 affect C# analysis in all applications.
|
||||
|
||||
## New queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|-----------------------------|-----------|--------------------------------------------------------------------|
|
||||
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|------------------------------|------------------------|-----------------------------------|
|
||||
|
||||
|
||||
## Removal of old queries
|
||||
|
||||
## Changes to code extraction
|
||||
|
||||
* Partial method bodies are extracted. Previously, partial method bodies were skipped completely.
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
## Changes to autobuilder
|
||||
|
||||
## Changes to tooling support
|
||||
|
||||
* The Abstract Syntax Tree of C# files can be printed in Visual Studio Code.
|
||||
30
change-notes/1.26/analysis-javascript.md
Normal file
30
change-notes/1.26/analysis-javascript.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# Improvements to JavaScript analysis
|
||||
|
||||
## General improvements
|
||||
|
||||
* Support for the following frameworks and libraries has been improved:
|
||||
- [fast-json-stable-stringify](https://www.npmjs.com/package/fast-json-stable-stringify)
|
||||
- [fast-safe-stringify](https://www.npmjs.com/package/fast-safe-stringify)
|
||||
- [javascript-stringify](https://www.npmjs.com/package/javascript-stringify)
|
||||
- [js-stringify](https://www.npmjs.com/package/js-stringify)
|
||||
- [json-stable-stringify](https://www.npmjs.com/package/json-stable-stringify)
|
||||
- [json-stringify-safe](https://www.npmjs.com/package/json-stringify-safe)
|
||||
- [json3](https://www.npmjs.com/package/json3)
|
||||
- [object-inspect](https://www.npmjs.com/package/object-inspect)
|
||||
- [pretty-format](https://www.npmjs.com/package/pretty-format)
|
||||
- [stringify-object](https://www.npmjs.com/package/stringify-object)
|
||||
|
||||
## New queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|---------------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|--------------------------------|------------------------------|---------------------------------------------------------------------------|
|
||||
| Incomplete URL substring sanitization (`js/incomplete-url-substring-sanitization`) | More results | This query now recognizes additional URLs when the substring check is an inclusion check. |
|
||||
|
||||
|
||||
## Changes to libraries
|
||||
@@ -50,7 +50,12 @@ predicate illDefinedDecrForStmt(
|
||||
DataFlow::localFlowStep(DataFlow::exprNode(initialCondition), DataFlow::exprNode(lesserOperand)) and
|
||||
// `initialCondition` < `terminalCondition`
|
||||
(
|
||||
upperBound(initialCondition) < lowerBound(terminalCondition)
|
||||
upperBound(initialCondition) < lowerBound(terminalCondition) and
|
||||
(
|
||||
// exclude cases where the loop counter is `unsigned` (where wrapping behaviour can be used deliberately)
|
||||
v.getUnspecifiedType().(IntegralType).isSigned() or
|
||||
initialCondition.getValue().toInt() = 0
|
||||
)
|
||||
or
|
||||
(forstmt.conditionAlwaysFalse() or forstmt.conditionAlwaysTrue())
|
||||
)
|
||||
|
||||
@@ -18,6 +18,9 @@ Expr getTest() {
|
||||
or
|
||||
// boost tests; http://www.boost.org/
|
||||
result.(FunctionCall).getTarget().hasQualifiedName("boost::unit_test", "make_test_case")
|
||||
or
|
||||
// googletest tests; https://github.com/google/googletest/
|
||||
result.(FunctionCall).getTarget().hasQualifiedName("testing::internal", "MakeAndRegisterTestInfo")
|
||||
}
|
||||
|
||||
from File f, int n
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
/**
|
||||
* Provides classes for identifying and reasoning about Microsoft source code
|
||||
* annotation language (SAL) macros.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* A SAL macro defined in `sal.h` or a similar header file.
|
||||
*/
|
||||
class SALMacro extends Macro {
|
||||
SALMacro() {
|
||||
exists(string filename | filename = this.getFile().getBaseName() |
|
||||
@@ -20,27 +28,34 @@ class SALMacro extends Macro {
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
predicate isTopLevelMacroAccess(MacroAccess ma) { not exists(ma.getParentInvocation()) }
|
||||
private predicate isTopLevelMacroAccess(MacroAccess ma) { not exists(ma.getParentInvocation()) }
|
||||
|
||||
/**
|
||||
* An invocation of a SAL macro (excluding invocations inside other macros).
|
||||
*/
|
||||
class SALAnnotation extends MacroInvocation {
|
||||
SALAnnotation() {
|
||||
this.getMacro() instanceof SALMacro and
|
||||
isTopLevelMacroAccess(this)
|
||||
}
|
||||
|
||||
/** Returns the `Declaration` annotated by `this`. */
|
||||
/** Gets the `Declaration` annotated by `this`. */
|
||||
Declaration getDeclaration() {
|
||||
annotatesAt(this, result.getADeclarationEntry(), _, _) and
|
||||
not result instanceof Type // exclude typedefs
|
||||
}
|
||||
|
||||
/** Returns the `DeclarationEntry` annotated by `this`. */
|
||||
/** Gets the `DeclarationEntry` annotated by `this`. */
|
||||
DeclarationEntry getDeclarationEntry() {
|
||||
annotatesAt(this, result, _, _) and
|
||||
not result instanceof TypeDeclarationEntry // exclude typedefs
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A SAL macro indicating that the return value of a function should always be
|
||||
* checked.
|
||||
*/
|
||||
class SALCheckReturn extends SALAnnotation {
|
||||
SALCheckReturn() {
|
||||
exists(SALMacro m | m = this.getMacro() |
|
||||
@@ -50,6 +65,10 @@ class SALCheckReturn extends SALAnnotation {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A SAL macro indicating that a pointer variable or return value should not be
|
||||
* `NULL`.
|
||||
*/
|
||||
class SALNotNull extends SALAnnotation {
|
||||
SALNotNull() {
|
||||
exists(SALMacro m | m = this.getMacro() |
|
||||
@@ -69,6 +88,9 @@ class SALNotNull extends SALAnnotation {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A SAL macro indicating that a value may be `NULL`.
|
||||
*/
|
||||
class SALMaybeNull extends SALAnnotation {
|
||||
SALMaybeNull() {
|
||||
exists(SALMacro m | m = this.getMacro() |
|
||||
@@ -79,13 +101,29 @@ class SALMaybeNull extends SALAnnotation {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A parameter annotated by one or more SAL annotations.
|
||||
*/
|
||||
class SALParameter extends Parameter {
|
||||
/** One of this parameter's annotations. */
|
||||
SALAnnotation a;
|
||||
|
||||
SALParameter() { annotatesAt(a, this.getADeclarationEntry(), _, _) }
|
||||
|
||||
predicate isIn() { a.getMacroName().toLowerCase().matches("%\\_in%") }
|
||||
|
||||
predicate isOut() { a.getMacroName().toLowerCase().matches("%\\_out%") }
|
||||
|
||||
predicate isInOut() { a.getMacroName().toLowerCase().matches("%\\_inout%") }
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation details
|
||||
/**
|
||||
* Holds if `a` annotates the declaration entry `d` and
|
||||
* its start position is the `idx`th position in `file` that holds a SAL element.
|
||||
*/
|
||||
predicate annotatesAt(SALAnnotation a, DeclarationEntry d, File file, int idx) {
|
||||
private predicate annotatesAt(SALAnnotation a, DeclarationEntry d, File file, int idx) {
|
||||
annotatesAtPosition(a.(SALElement).getStartPosition(), d, file, idx)
|
||||
}
|
||||
|
||||
@@ -109,22 +147,6 @@ private predicate annotatesAtPosition(SALPosition pos, DeclarationEntry d, File
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A parameter annotated by one or more SAL annotations.
|
||||
*/
|
||||
class SALParameter extends Parameter {
|
||||
/** One of this parameter's annotations. */
|
||||
SALAnnotation a;
|
||||
|
||||
SALParameter() { annotatesAt(a, this.getADeclarationEntry(), _, _) }
|
||||
|
||||
predicate isIn() { a.getMacroName().toLowerCase().matches("%\\_in%") }
|
||||
|
||||
predicate isOut() { a.getMacroName().toLowerCase().matches("%\\_out%") }
|
||||
|
||||
predicate isInOut() { a.getMacroName().toLowerCase().matches("%\\_inout%") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A SAL element, that is, a SAL annotation or a declaration entry
|
||||
* that may have SAL annotations.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* user can result in integer overflow.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @precision medium
|
||||
* @id cpp/uncontrolled-allocation-size
|
||||
* @tags reliability
|
||||
* security
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
///// Library routines /////
|
||||
|
||||
int scanf(const char *format, ...);
|
||||
int sscanf(const char *str, const char *format, ...);
|
||||
int fscanf(const char *str, const char *format, ...);
|
||||
|
||||
///// EXAMPLES /////
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
// BAD, do not use scanf without specifying a length first
|
||||
char buf1[10];
|
||||
scanf("%s", buf1);
|
||||
|
||||
// GOOD, length is specified. The length should be one less than the size of the buffer, since the last character is the NULL terminator.
|
||||
char buf2[10];
|
||||
sscanf(buf2, "%9s");
|
||||
|
||||
// BAD, do not use scanf without specifying a length first
|
||||
char file[10];
|
||||
fscanf(file, "%s", buf2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>It is bad practice to use any of the <code>scanf</code> functions without including a specified length within the format parameter, as it will be vulnerable to buffer overflows.</p>
|
||||
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
|
||||
<p>Specify a length within the format string parameter, and make this length one less than the size of the buffer, since the last character should be reserved for the NULL terminator.</p>
|
||||
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>The following example demonstrates safe and unsafe uses of <code>scanf</code> type functions.</p>
|
||||
<sample src="MemoryUnsafeFunctionScan.cpp" />
|
||||
|
||||
</example>
|
||||
|
||||
<references>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @name Scanf function without a specified length
|
||||
* @description Use of one of the scanf functions without a specified length.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @id cpp/memory-unsafe-function-scan
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-120
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.commons.Scanf
|
||||
|
||||
from FunctionCall call, ScanfFunction sff
|
||||
where
|
||||
call.getTarget() = sff and
|
||||
call.getArgument(sff.getFormatParameterIndex()).getValue().regexpMatch(".*%l?s.*")
|
||||
select call, "Dangerous use of one of the scanf functions"
|
||||
@@ -0,0 +1,32 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>Private data that is stored in a file or buffer unencrypted is accessible to an attacker who gains access to the
|
||||
storage.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Ensure that private data is always encrypted before being stored.
|
||||
It may be wise to encrypt information before it is put into a buffer that may be readable in memory.</p>
|
||||
|
||||
<p>In general, decrypt private data only at the point where it is necessary for it to be used in
|
||||
cleartext.</p>
|
||||
|
||||
</recommendation>
|
||||
|
||||
<references>
|
||||
|
||||
<li><a href="https://owasp.org/www-project-top-ten/OWASP_Top_Ten_2017/Top_10-2017_A3-Sensitive_Data_Exposure">OWASP Sensitive_Data_Exposure</a></li>
|
||||
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
|
||||
<li>M. Howard and D. LeBlanc, <i>Writing Secure Code</i>, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.</li>
|
||||
|
||||
|
||||
|
||||
<!-- LocalWords: CWE
|
||||
-->
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @name Exposure of private information
|
||||
* @description If private information is written to an external location, it may be accessible by
|
||||
* unauthorized persons.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @id cpp/private-cleartext-write
|
||||
* @tags security
|
||||
* external/cwe/cwe-359
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import experimental.semmle.code.cpp.security.PrivateCleartextWrite
|
||||
import experimental.semmle.code.cpp.security.PrivateCleartextWrite::PrivateCleartextWrite
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from WriteConfig b, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where b.hasFlowPath(source, sink)
|
||||
select sink.getNode(),
|
||||
"This write into the external location '" + sink + "' may contain unencrypted data from $@",
|
||||
source, "this source."
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* EXPERIMENTAL: The API of this module may change without notice.
|
||||
*
|
||||
* Provides a class for modeling `Expr`s with a restricted range.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL: The API of this class may change without notice.
|
||||
*
|
||||
* An expression for which a range can be deduced. Extend this class to add
|
||||
* functionality to the range analysis library.
|
||||
*/
|
||||
abstract class SimpleRangeAnalysisExpr extends Expr {
|
||||
/**
|
||||
* Gets the lower bound of the expression.
|
||||
*
|
||||
* Implementations of this predicate should use
|
||||
* `getFullyConvertedLowerBounds` and `getFullyConvertedUpperBounds` for
|
||||
* recursive calls to get the bounds of their children.
|
||||
*/
|
||||
abstract float getLowerBounds();
|
||||
|
||||
/**
|
||||
* Gets the upper bound of the expression.
|
||||
*
|
||||
* Implementations of this predicate should use
|
||||
* `getFullyConvertedLowerBounds` and `getFullyConvertedUpperBounds` for
|
||||
* recursive calls to get the bounds of their children.
|
||||
*/
|
||||
abstract float getUpperBounds();
|
||||
|
||||
/**
|
||||
* Holds if the range this expression depends on the definition `srcDef` for
|
||||
* StackVariable `srcVar`.
|
||||
*
|
||||
* Because this predicate cannot be recursive, most implementations should
|
||||
* override `dependsOnChild` instead.
|
||||
*/
|
||||
predicate dependsOnDef(RangeSsaDefinition srcDef, StackVariable srcVar) { none() }
|
||||
|
||||
/**
|
||||
* Holds if this expression depends on the range of its unconverted
|
||||
* subexpression `child`. This information is used to inform the range
|
||||
* analysis about cyclic dependencies. Without this information, range
|
||||
* analysis might work for simple cases but will go into infinite loops on
|
||||
* complex code.
|
||||
*
|
||||
* For example, when modeling a function call whose return value depends on
|
||||
* all of its arguments, implement this predicate as
|
||||
* `child = this.getAnArgument()`.
|
||||
*/
|
||||
abstract predicate dependsOnChild(Expr child);
|
||||
}
|
||||
|
||||
import SimpleRangeAnalysisInternal
|
||||
|
||||
/**
|
||||
* This class exists to prevent the QL front end from emitting compile errors
|
||||
* inside `SimpleRangeAnalysis.qll` about certain conjuncts being empty
|
||||
* because the overrides of `SimpleRangeAnalysisExpr` that happen to be in
|
||||
* scope do not make use of every feature it offers.
|
||||
*/
|
||||
private class Empty extends SimpleRangeAnalysisExpr {
|
||||
Empty() {
|
||||
// This predicate is complicated enough that the QL type checker doesn't
|
||||
// see it as empty but simple enough that the optimizer should.
|
||||
this = this and none()
|
||||
}
|
||||
|
||||
override float getLowerBounds() { none() }
|
||||
|
||||
override float getUpperBounds() { none() }
|
||||
|
||||
override predicate dependsOnChild(Expr child) { none() }
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Provides a taint-tracking configuration for reasoning about private information flowing unencrypted to an external location.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.TaintTracking
|
||||
import experimental.semmle.code.cpp.security.PrivateData
|
||||
import semmle.code.cpp.security.FileWrite
|
||||
import semmle.code.cpp.security.BufferWrite
|
||||
import semmle.code.cpp.dataflow.TaintTracking
|
||||
|
||||
module PrivateCleartextWrite {
|
||||
/**
|
||||
* A data flow source for private information flowing unencrypted to an external location.
|
||||
*/
|
||||
abstract class Source extends DataFlow::ExprNode { }
|
||||
|
||||
/**
|
||||
* A data flow sink for private information flowing unencrypted to an external location.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::ExprNode { }
|
||||
|
||||
/**
|
||||
* A sanitizer for private information flowing unencrypted to an external location.
|
||||
*/
|
||||
abstract class Sanitizer extends DataFlow::ExprNode { }
|
||||
|
||||
/** A call to any method whose name suggests that it encodes or encrypts the parameter. */
|
||||
class ProtectSanitizer extends Sanitizer {
|
||||
ProtectSanitizer() {
|
||||
exists(Function m, string s |
|
||||
this.getExpr().(FunctionCall).getTarget() = m and
|
||||
m.getName().regexpMatch("(?i).*" + s + ".*")
|
||||
|
|
||||
s = "protect" or s = "encode" or s = "encrypt"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class WriteConfig extends TaintTracking::Configuration {
|
||||
WriteConfig() { this = "Write configuration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
class PrivateDataSource extends Source {
|
||||
PrivateDataSource() { this.getExpr() instanceof PrivateDataExpr }
|
||||
}
|
||||
|
||||
class WriteSink extends Sink {
|
||||
WriteSink() {
|
||||
exists(FileWrite f, BufferWrite b |
|
||||
this.asExpr() = f.getASource()
|
||||
or
|
||||
this.asExpr() = b.getAChild()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Provides classes and predicates for identifying private data and functions for security.
|
||||
*
|
||||
* 'Private' data in general is anything that would compromise user privacy if exposed. This
|
||||
* library tries to guess where private data may either be stored in a variable or produced by a
|
||||
* function.
|
||||
*
|
||||
* This library is not concerned with credentials. See `SensitiveActions` for expressions related
|
||||
* to credentials.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/** A string for `match` that identifies strings that look like they represent private data. */
|
||||
private string privateNames() {
|
||||
// Inspired by the list on https://cwe.mitre.org/data/definitions/359.html
|
||||
// Government identifiers, such as Social Security Numbers
|
||||
result = "%social%security%number%" or
|
||||
// Contact information, such as home addresses and telephone numbers
|
||||
result = "%postcode%" or
|
||||
result = "%zipcode%" or
|
||||
// result = "%telephone%" or
|
||||
// Geographic location - where the user is (or was)
|
||||
result = "%latitude%" or
|
||||
result = "%longitude%" or
|
||||
// Financial data - such as credit card numbers, salary, bank accounts, and debts
|
||||
result = "%creditcard%" or
|
||||
result = "%salary%" or
|
||||
result = "%bankaccount%" or
|
||||
// Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc.
|
||||
// result = "%email%" or
|
||||
// result = "%mobile%" or
|
||||
result = "%employer%" or
|
||||
// Health - medical conditions, insurance status, prescription records
|
||||
result = "%medical%"
|
||||
}
|
||||
|
||||
/** An expression that might contain private data. */
|
||||
abstract class PrivateDataExpr extends Expr { }
|
||||
|
||||
/** A functiond call that might produce private data. */
|
||||
class PrivateFunctionCall extends PrivateDataExpr, FunctionCall {
|
||||
PrivateFunctionCall() {
|
||||
exists(string s | this.getTarget().getName().toLowerCase() = s | s.matches(privateNames()))
|
||||
}
|
||||
}
|
||||
|
||||
/** An access to a variable that might contain private data. */
|
||||
class PrivateVariableAccess extends PrivateDataExpr, VariableAccess {
|
||||
PrivateVariableAccess() {
|
||||
exists(string s | this.getTarget().getName().toLowerCase() = s | s.matches(privateNames()))
|
||||
}
|
||||
}
|
||||
@@ -214,6 +214,9 @@ abstract class ImplicitConversionFunction extends MemberFunction {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: as of C++11 this class does not correspond perfectly with the
|
||||
* language definition of a converting constructor.
|
||||
*
|
||||
* A C++ constructor that also defines an implicit conversion. For example the
|
||||
* function `MyClass` in the following code is a `ConversionConstructor`:
|
||||
* ```
|
||||
@@ -225,15 +228,16 @@ abstract class ImplicitConversionFunction extends MemberFunction {
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
class ConversionConstructor extends Constructor, ImplicitConversionFunction {
|
||||
deprecated class ConversionConstructor extends Constructor, ImplicitConversionFunction {
|
||||
ConversionConstructor() {
|
||||
strictcount(Parameter p | p = getAParameter() and not p.hasInitializer()) = 1 and
|
||||
not hasSpecifier("explicit") and
|
||||
not this instanceof CopyConstructor
|
||||
not hasSpecifier("explicit")
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
not this instanceof MoveConstructor and result = "ConversionConstructor"
|
||||
not this instanceof CopyConstructor and
|
||||
not this instanceof MoveConstructor and
|
||||
result = "ConversionConstructor"
|
||||
}
|
||||
|
||||
/** Gets the type this `ConversionConstructor` takes as input. */
|
||||
|
||||
@@ -1066,7 +1066,7 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(Node node, Configuration config) {
|
||||
predicate localFlowEntry(Node node, Configuration config) {
|
||||
nodeCand2(node, config) and
|
||||
(
|
||||
config.isSource(node) or
|
||||
@@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption {
|
||||
* Holds if `node` is reachable with access path `ap` from a source in
|
||||
* the configuration `config`.
|
||||
*
|
||||
* The Boolean `fromArg` records whether the node is reached through an
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `argAp` records the access path of that
|
||||
* argument.
|
||||
*/
|
||||
private predicate flowFwd(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwd0(node, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd0(node, cc, argAp, apf, ap, config) and
|
||||
flowCand(node, _, _, apf, config)
|
||||
}
|
||||
|
||||
private predicate flowFwd0(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowCand(node, _, _, _, config) and
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, argAp, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, _)
|
||||
exists(Node mid, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, localCC)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, argAp, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, _) and
|
||||
exists(Node mid, AccessPathNil nil, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, localCC) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
flowFwd(mid, _, _, apf, ap, config) and
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, _, _, _, nil, config) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
@@ -1704,40 +1704,51 @@ private predicate flowFwd0(
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config))
|
||||
or
|
||||
// read
|
||||
exists(TypedContent tc |
|
||||
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
|
||||
flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and
|
||||
flowFwdConsCand(tc, apf, ap, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
flowFwdIn(_, node, _, _, apf, ap, config) and
|
||||
fromArg = true and
|
||||
flowFwdIn(_, node, _, cc, _, apf, ap, config) and
|
||||
if flowCand(node, true, _, apf, config)
|
||||
then argAp = TAccessPathSome(ap)
|
||||
else argAp = TAccessPathNone()
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call |
|
||||
flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and
|
||||
fromArg = false
|
||||
exists(DataFlowCallable c |
|
||||
flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and
|
||||
if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext()
|
||||
)
|
||||
or
|
||||
exists(AccessPath argAp0 |
|
||||
flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and
|
||||
flowFwdIsEntered(call, fromArg, argAp, argAp0, config)
|
||||
flowFwdIsEntered(call, cc, argAp, argAp0, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdLocalEntry(
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
LocalCallContext localCC, Configuration config
|
||||
) {
|
||||
flowFwd(node, cc, argAp, apf, ap, config) and
|
||||
localFlowEntry(node, config) and
|
||||
localCC = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdStore(
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, AccessPathFront apf0 |
|
||||
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(mid, cc, argAp, apf0, ap0, config) and
|
||||
flowFwdStore0(mid, tc, node, apf0, apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1764,20 +1775,20 @@ private predicate flowFwdStore0(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead0(
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
|
||||
boolean fromArg, AccessPathOption argAp, Configuration config
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(node1, cc, argAp, apf0, ap0, config) and
|
||||
readCandFwd(node1, tc, apf0, node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead(
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and
|
||||
flowCand(node, _, _, apf, unbind(config)) and
|
||||
flowCandConsCand(tc, apf, unbind(config))
|
||||
)
|
||||
@@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIn(
|
||||
DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
flowFwd(arg, fromArg, argAp, apf, ap, config) and
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c |
|
||||
flowFwd(arg, outercc, argAp, apf, ap, config) and
|
||||
flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and
|
||||
flowCand(p, _, _, _, unbind(config))
|
||||
c = p.getEnclosingCallable() and
|
||||
c = resolveCall(call, outercc) and
|
||||
flowCand(p, _, _, _, unbind(config)) and
|
||||
if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall()
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1809,13 +1823,19 @@ private predicate flowFwdIn(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdOut(
|
||||
DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow |
|
||||
flowFwd(ret, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd(ret, innercc, argAp, apf, ap, config) and
|
||||
flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and
|
||||
flowCand(node, _, _, _, unbind(config))
|
||||
innerc = ret.getEnclosingCallable() and
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
resolveReturn(innercc, innerc, call)
|
||||
or
|
||||
innercc.(CallContextCall).matchesCall(call)
|
||||
)
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg(
|
||||
DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config)
|
||||
flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIsEntered(
|
||||
DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, AccessPathFront apf |
|
||||
flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and
|
||||
flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and
|
||||
flowCand(p, true, TAccessPathFrontSome(_), apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1920,7 +1940,7 @@ private predicate flow0(
|
||||
// flow out of a callable
|
||||
flowOut(_, node, _, _, ap, config) and
|
||||
toReturn = true and
|
||||
if flowFwd(node, true, TAccessPathSome(_), _, ap, config)
|
||||
if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config)
|
||||
then returnAp = TAccessPathSome(ap)
|
||||
else returnAp = TAccessPathNone()
|
||||
}
|
||||
@@ -2006,9 +2026,10 @@ private predicate flowIsReturned(
|
||||
DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
exists(ReturnNodeExt ret, CallContextCall ccc |
|
||||
flowOut(call, ret, toReturn, returnAp, ap, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(_), _, ap, config)
|
||||
flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and
|
||||
ccc.matchesCall(call)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2031,7 +2052,7 @@ private newtype TSummaryCtx =
|
||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 |
|
||||
parameterFlow(p, ap, ret.getEnclosingCallable(), config) and
|
||||
flow(ret, true, TAccessPathSome(_), ap0, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config)
|
||||
flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0(
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
@@ -2867,7 +2888,7 @@ private module FlowExploration {
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
@@ -1066,7 +1066,7 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(Node node, Configuration config) {
|
||||
predicate localFlowEntry(Node node, Configuration config) {
|
||||
nodeCand2(node, config) and
|
||||
(
|
||||
config.isSource(node) or
|
||||
@@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption {
|
||||
* Holds if `node` is reachable with access path `ap` from a source in
|
||||
* the configuration `config`.
|
||||
*
|
||||
* The Boolean `fromArg` records whether the node is reached through an
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `argAp` records the access path of that
|
||||
* argument.
|
||||
*/
|
||||
private predicate flowFwd(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwd0(node, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd0(node, cc, argAp, apf, ap, config) and
|
||||
flowCand(node, _, _, apf, config)
|
||||
}
|
||||
|
||||
private predicate flowFwd0(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowCand(node, _, _, _, config) and
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, argAp, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, _)
|
||||
exists(Node mid, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, localCC)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, argAp, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, _) and
|
||||
exists(Node mid, AccessPathNil nil, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, localCC) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
flowFwd(mid, _, _, apf, ap, config) and
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, _, _, _, nil, config) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
@@ -1704,40 +1704,51 @@ private predicate flowFwd0(
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config))
|
||||
or
|
||||
// read
|
||||
exists(TypedContent tc |
|
||||
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
|
||||
flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and
|
||||
flowFwdConsCand(tc, apf, ap, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
flowFwdIn(_, node, _, _, apf, ap, config) and
|
||||
fromArg = true and
|
||||
flowFwdIn(_, node, _, cc, _, apf, ap, config) and
|
||||
if flowCand(node, true, _, apf, config)
|
||||
then argAp = TAccessPathSome(ap)
|
||||
else argAp = TAccessPathNone()
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call |
|
||||
flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and
|
||||
fromArg = false
|
||||
exists(DataFlowCallable c |
|
||||
flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and
|
||||
if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext()
|
||||
)
|
||||
or
|
||||
exists(AccessPath argAp0 |
|
||||
flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and
|
||||
flowFwdIsEntered(call, fromArg, argAp, argAp0, config)
|
||||
flowFwdIsEntered(call, cc, argAp, argAp0, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdLocalEntry(
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
LocalCallContext localCC, Configuration config
|
||||
) {
|
||||
flowFwd(node, cc, argAp, apf, ap, config) and
|
||||
localFlowEntry(node, config) and
|
||||
localCC = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdStore(
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, AccessPathFront apf0 |
|
||||
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(mid, cc, argAp, apf0, ap0, config) and
|
||||
flowFwdStore0(mid, tc, node, apf0, apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1764,20 +1775,20 @@ private predicate flowFwdStore0(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead0(
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
|
||||
boolean fromArg, AccessPathOption argAp, Configuration config
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(node1, cc, argAp, apf0, ap0, config) and
|
||||
readCandFwd(node1, tc, apf0, node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead(
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and
|
||||
flowCand(node, _, _, apf, unbind(config)) and
|
||||
flowCandConsCand(tc, apf, unbind(config))
|
||||
)
|
||||
@@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIn(
|
||||
DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
flowFwd(arg, fromArg, argAp, apf, ap, config) and
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c |
|
||||
flowFwd(arg, outercc, argAp, apf, ap, config) and
|
||||
flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and
|
||||
flowCand(p, _, _, _, unbind(config))
|
||||
c = p.getEnclosingCallable() and
|
||||
c = resolveCall(call, outercc) and
|
||||
flowCand(p, _, _, _, unbind(config)) and
|
||||
if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall()
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1809,13 +1823,19 @@ private predicate flowFwdIn(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdOut(
|
||||
DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow |
|
||||
flowFwd(ret, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd(ret, innercc, argAp, apf, ap, config) and
|
||||
flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and
|
||||
flowCand(node, _, _, _, unbind(config))
|
||||
innerc = ret.getEnclosingCallable() and
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
resolveReturn(innercc, innerc, call)
|
||||
or
|
||||
innercc.(CallContextCall).matchesCall(call)
|
||||
)
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg(
|
||||
DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config)
|
||||
flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIsEntered(
|
||||
DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, AccessPathFront apf |
|
||||
flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and
|
||||
flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and
|
||||
flowCand(p, true, TAccessPathFrontSome(_), apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1920,7 +1940,7 @@ private predicate flow0(
|
||||
// flow out of a callable
|
||||
flowOut(_, node, _, _, ap, config) and
|
||||
toReturn = true and
|
||||
if flowFwd(node, true, TAccessPathSome(_), _, ap, config)
|
||||
if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config)
|
||||
then returnAp = TAccessPathSome(ap)
|
||||
else returnAp = TAccessPathNone()
|
||||
}
|
||||
@@ -2006,9 +2026,10 @@ private predicate flowIsReturned(
|
||||
DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
exists(ReturnNodeExt ret, CallContextCall ccc |
|
||||
flowOut(call, ret, toReturn, returnAp, ap, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(_), _, ap, config)
|
||||
flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and
|
||||
ccc.matchesCall(call)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2031,7 +2052,7 @@ private newtype TSummaryCtx =
|
||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 |
|
||||
parameterFlow(p, ap, ret.getEnclosingCallable(), config) and
|
||||
flow(ret, true, TAccessPathSome(_), ap0, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config)
|
||||
flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0(
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
@@ -2867,7 +2888,7 @@ private module FlowExploration {
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
@@ -1066,7 +1066,7 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(Node node, Configuration config) {
|
||||
predicate localFlowEntry(Node node, Configuration config) {
|
||||
nodeCand2(node, config) and
|
||||
(
|
||||
config.isSource(node) or
|
||||
@@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption {
|
||||
* Holds if `node` is reachable with access path `ap` from a source in
|
||||
* the configuration `config`.
|
||||
*
|
||||
* The Boolean `fromArg` records whether the node is reached through an
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `argAp` records the access path of that
|
||||
* argument.
|
||||
*/
|
||||
private predicate flowFwd(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwd0(node, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd0(node, cc, argAp, apf, ap, config) and
|
||||
flowCand(node, _, _, apf, config)
|
||||
}
|
||||
|
||||
private predicate flowFwd0(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowCand(node, _, _, _, config) and
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, argAp, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, _)
|
||||
exists(Node mid, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, localCC)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, argAp, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, _) and
|
||||
exists(Node mid, AccessPathNil nil, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, localCC) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
flowFwd(mid, _, _, apf, ap, config) and
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, _, _, _, nil, config) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
@@ -1704,40 +1704,51 @@ private predicate flowFwd0(
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config))
|
||||
or
|
||||
// read
|
||||
exists(TypedContent tc |
|
||||
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
|
||||
flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and
|
||||
flowFwdConsCand(tc, apf, ap, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
flowFwdIn(_, node, _, _, apf, ap, config) and
|
||||
fromArg = true and
|
||||
flowFwdIn(_, node, _, cc, _, apf, ap, config) and
|
||||
if flowCand(node, true, _, apf, config)
|
||||
then argAp = TAccessPathSome(ap)
|
||||
else argAp = TAccessPathNone()
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call |
|
||||
flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and
|
||||
fromArg = false
|
||||
exists(DataFlowCallable c |
|
||||
flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and
|
||||
if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext()
|
||||
)
|
||||
or
|
||||
exists(AccessPath argAp0 |
|
||||
flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and
|
||||
flowFwdIsEntered(call, fromArg, argAp, argAp0, config)
|
||||
flowFwdIsEntered(call, cc, argAp, argAp0, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdLocalEntry(
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
LocalCallContext localCC, Configuration config
|
||||
) {
|
||||
flowFwd(node, cc, argAp, apf, ap, config) and
|
||||
localFlowEntry(node, config) and
|
||||
localCC = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdStore(
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, AccessPathFront apf0 |
|
||||
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(mid, cc, argAp, apf0, ap0, config) and
|
||||
flowFwdStore0(mid, tc, node, apf0, apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1764,20 +1775,20 @@ private predicate flowFwdStore0(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead0(
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
|
||||
boolean fromArg, AccessPathOption argAp, Configuration config
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(node1, cc, argAp, apf0, ap0, config) and
|
||||
readCandFwd(node1, tc, apf0, node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead(
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and
|
||||
flowCand(node, _, _, apf, unbind(config)) and
|
||||
flowCandConsCand(tc, apf, unbind(config))
|
||||
)
|
||||
@@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIn(
|
||||
DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
flowFwd(arg, fromArg, argAp, apf, ap, config) and
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c |
|
||||
flowFwd(arg, outercc, argAp, apf, ap, config) and
|
||||
flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and
|
||||
flowCand(p, _, _, _, unbind(config))
|
||||
c = p.getEnclosingCallable() and
|
||||
c = resolveCall(call, outercc) and
|
||||
flowCand(p, _, _, _, unbind(config)) and
|
||||
if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall()
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1809,13 +1823,19 @@ private predicate flowFwdIn(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdOut(
|
||||
DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow |
|
||||
flowFwd(ret, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd(ret, innercc, argAp, apf, ap, config) and
|
||||
flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and
|
||||
flowCand(node, _, _, _, unbind(config))
|
||||
innerc = ret.getEnclosingCallable() and
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
resolveReturn(innercc, innerc, call)
|
||||
or
|
||||
innercc.(CallContextCall).matchesCall(call)
|
||||
)
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg(
|
||||
DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config)
|
||||
flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIsEntered(
|
||||
DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, AccessPathFront apf |
|
||||
flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and
|
||||
flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and
|
||||
flowCand(p, true, TAccessPathFrontSome(_), apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1920,7 +1940,7 @@ private predicate flow0(
|
||||
// flow out of a callable
|
||||
flowOut(_, node, _, _, ap, config) and
|
||||
toReturn = true and
|
||||
if flowFwd(node, true, TAccessPathSome(_), _, ap, config)
|
||||
if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config)
|
||||
then returnAp = TAccessPathSome(ap)
|
||||
else returnAp = TAccessPathNone()
|
||||
}
|
||||
@@ -2006,9 +2026,10 @@ private predicate flowIsReturned(
|
||||
DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
exists(ReturnNodeExt ret, CallContextCall ccc |
|
||||
flowOut(call, ret, toReturn, returnAp, ap, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(_), _, ap, config)
|
||||
flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and
|
||||
ccc.matchesCall(call)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2031,7 +2052,7 @@ private newtype TSummaryCtx =
|
||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 |
|
||||
parameterFlow(p, ap, ret.getEnclosingCallable(), config) and
|
||||
flow(ret, true, TAccessPathSome(_), ap0, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config)
|
||||
flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0(
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
@@ -2867,7 +2888,7 @@ private module FlowExploration {
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
@@ -1066,7 +1066,7 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(Node node, Configuration config) {
|
||||
predicate localFlowEntry(Node node, Configuration config) {
|
||||
nodeCand2(node, config) and
|
||||
(
|
||||
config.isSource(node) or
|
||||
@@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption {
|
||||
* Holds if `node` is reachable with access path `ap` from a source in
|
||||
* the configuration `config`.
|
||||
*
|
||||
* The Boolean `fromArg` records whether the node is reached through an
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `argAp` records the access path of that
|
||||
* argument.
|
||||
*/
|
||||
private predicate flowFwd(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwd0(node, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd0(node, cc, argAp, apf, ap, config) and
|
||||
flowCand(node, _, _, apf, config)
|
||||
}
|
||||
|
||||
private predicate flowFwd0(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowCand(node, _, _, _, config) and
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, argAp, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, _)
|
||||
exists(Node mid, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, localCC)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, argAp, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, _) and
|
||||
exists(Node mid, AccessPathNil nil, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, localCC) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
flowFwd(mid, _, _, apf, ap, config) and
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, _, _, _, nil, config) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
@@ -1704,40 +1704,51 @@ private predicate flowFwd0(
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config))
|
||||
or
|
||||
// read
|
||||
exists(TypedContent tc |
|
||||
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
|
||||
flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and
|
||||
flowFwdConsCand(tc, apf, ap, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
flowFwdIn(_, node, _, _, apf, ap, config) and
|
||||
fromArg = true and
|
||||
flowFwdIn(_, node, _, cc, _, apf, ap, config) and
|
||||
if flowCand(node, true, _, apf, config)
|
||||
then argAp = TAccessPathSome(ap)
|
||||
else argAp = TAccessPathNone()
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call |
|
||||
flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and
|
||||
fromArg = false
|
||||
exists(DataFlowCallable c |
|
||||
flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and
|
||||
if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext()
|
||||
)
|
||||
or
|
||||
exists(AccessPath argAp0 |
|
||||
flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and
|
||||
flowFwdIsEntered(call, fromArg, argAp, argAp0, config)
|
||||
flowFwdIsEntered(call, cc, argAp, argAp0, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdLocalEntry(
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
LocalCallContext localCC, Configuration config
|
||||
) {
|
||||
flowFwd(node, cc, argAp, apf, ap, config) and
|
||||
localFlowEntry(node, config) and
|
||||
localCC = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdStore(
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, AccessPathFront apf0 |
|
||||
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(mid, cc, argAp, apf0, ap0, config) and
|
||||
flowFwdStore0(mid, tc, node, apf0, apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1764,20 +1775,20 @@ private predicate flowFwdStore0(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead0(
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
|
||||
boolean fromArg, AccessPathOption argAp, Configuration config
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(node1, cc, argAp, apf0, ap0, config) and
|
||||
readCandFwd(node1, tc, apf0, node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead(
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and
|
||||
flowCand(node, _, _, apf, unbind(config)) and
|
||||
flowCandConsCand(tc, apf, unbind(config))
|
||||
)
|
||||
@@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIn(
|
||||
DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
flowFwd(arg, fromArg, argAp, apf, ap, config) and
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c |
|
||||
flowFwd(arg, outercc, argAp, apf, ap, config) and
|
||||
flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and
|
||||
flowCand(p, _, _, _, unbind(config))
|
||||
c = p.getEnclosingCallable() and
|
||||
c = resolveCall(call, outercc) and
|
||||
flowCand(p, _, _, _, unbind(config)) and
|
||||
if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall()
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1809,13 +1823,19 @@ private predicate flowFwdIn(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdOut(
|
||||
DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow |
|
||||
flowFwd(ret, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd(ret, innercc, argAp, apf, ap, config) and
|
||||
flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and
|
||||
flowCand(node, _, _, _, unbind(config))
|
||||
innerc = ret.getEnclosingCallable() and
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
resolveReturn(innercc, innerc, call)
|
||||
or
|
||||
innercc.(CallContextCall).matchesCall(call)
|
||||
)
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg(
|
||||
DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config)
|
||||
flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIsEntered(
|
||||
DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, AccessPathFront apf |
|
||||
flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and
|
||||
flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and
|
||||
flowCand(p, true, TAccessPathFrontSome(_), apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1920,7 +1940,7 @@ private predicate flow0(
|
||||
// flow out of a callable
|
||||
flowOut(_, node, _, _, ap, config) and
|
||||
toReturn = true and
|
||||
if flowFwd(node, true, TAccessPathSome(_), _, ap, config)
|
||||
if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config)
|
||||
then returnAp = TAccessPathSome(ap)
|
||||
else returnAp = TAccessPathNone()
|
||||
}
|
||||
@@ -2006,9 +2026,10 @@ private predicate flowIsReturned(
|
||||
DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
exists(ReturnNodeExt ret, CallContextCall ccc |
|
||||
flowOut(call, ret, toReturn, returnAp, ap, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(_), _, ap, config)
|
||||
flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and
|
||||
ccc.matchesCall(call)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2031,7 +2052,7 @@ private newtype TSummaryCtx =
|
||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 |
|
||||
parameterFlow(p, ap, ret.getEnclosingCallable(), config) and
|
||||
flow(ret, true, TAccessPathSome(_), ap0, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config)
|
||||
flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0(
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
@@ -2867,7 +2888,7 @@ private module FlowExploration {
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
@@ -512,13 +512,19 @@ abstract class CallContext extends TCallContext {
|
||||
abstract predicate relevantFor(DataFlowCallable callable);
|
||||
}
|
||||
|
||||
class CallContextAny extends CallContext, TAnyCallContext {
|
||||
abstract class CallContextNoCall extends CallContext { }
|
||||
|
||||
class CallContextAny extends CallContextNoCall, TAnyCallContext {
|
||||
override string toString() { result = "CcAny" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) { any() }
|
||||
}
|
||||
|
||||
abstract class CallContextCall extends CallContext { }
|
||||
abstract class CallContextCall extends CallContext {
|
||||
/** Holds if this call context may be `call`. */
|
||||
bindingset[call]
|
||||
abstract predicate matchesCall(DataFlowCall call);
|
||||
}
|
||||
|
||||
class CallContextSpecificCall extends CallContextCall, TSpecificCall {
|
||||
override string toString() {
|
||||
@@ -529,6 +535,8 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall {
|
||||
recordDataFlowCallSite(getCall(), callable)
|
||||
}
|
||||
|
||||
override predicate matchesCall(DataFlowCall call) { call = this.getCall() }
|
||||
|
||||
DataFlowCall getCall() { this = TSpecificCall(result) }
|
||||
}
|
||||
|
||||
@@ -538,9 +546,11 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(ParameterNode p | p.getEnclosingCallable() = callable)
|
||||
}
|
||||
|
||||
override predicate matchesCall(DataFlowCall call) { any() }
|
||||
}
|
||||
|
||||
class CallContextReturn extends CallContext, TReturn {
|
||||
class CallContextReturn extends CallContextNoCall, TReturn {
|
||||
override string toString() {
|
||||
exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")")
|
||||
}
|
||||
|
||||
@@ -1066,7 +1066,7 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(Node node, Configuration config) {
|
||||
predicate localFlowEntry(Node node, Configuration config) {
|
||||
nodeCand2(node, config) and
|
||||
(
|
||||
config.isSource(node) or
|
||||
@@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption {
|
||||
* Holds if `node` is reachable with access path `ap` from a source in
|
||||
* the configuration `config`.
|
||||
*
|
||||
* The Boolean `fromArg` records whether the node is reached through an
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `argAp` records the access path of that
|
||||
* argument.
|
||||
*/
|
||||
private predicate flowFwd(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwd0(node, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd0(node, cc, argAp, apf, ap, config) and
|
||||
flowCand(node, _, _, apf, config)
|
||||
}
|
||||
|
||||
private predicate flowFwd0(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowCand(node, _, _, _, config) and
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, argAp, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, _)
|
||||
exists(Node mid, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, localCC)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, argAp, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, _) and
|
||||
exists(Node mid, AccessPathNil nil, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, localCC) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
flowFwd(mid, _, _, apf, ap, config) and
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, _, _, _, nil, config) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
@@ -1704,40 +1704,51 @@ private predicate flowFwd0(
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config))
|
||||
or
|
||||
// read
|
||||
exists(TypedContent tc |
|
||||
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
|
||||
flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and
|
||||
flowFwdConsCand(tc, apf, ap, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
flowFwdIn(_, node, _, _, apf, ap, config) and
|
||||
fromArg = true and
|
||||
flowFwdIn(_, node, _, cc, _, apf, ap, config) and
|
||||
if flowCand(node, true, _, apf, config)
|
||||
then argAp = TAccessPathSome(ap)
|
||||
else argAp = TAccessPathNone()
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call |
|
||||
flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and
|
||||
fromArg = false
|
||||
exists(DataFlowCallable c |
|
||||
flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and
|
||||
if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext()
|
||||
)
|
||||
or
|
||||
exists(AccessPath argAp0 |
|
||||
flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and
|
||||
flowFwdIsEntered(call, fromArg, argAp, argAp0, config)
|
||||
flowFwdIsEntered(call, cc, argAp, argAp0, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdLocalEntry(
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
LocalCallContext localCC, Configuration config
|
||||
) {
|
||||
flowFwd(node, cc, argAp, apf, ap, config) and
|
||||
localFlowEntry(node, config) and
|
||||
localCC = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdStore(
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, AccessPathFront apf0 |
|
||||
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(mid, cc, argAp, apf0, ap0, config) and
|
||||
flowFwdStore0(mid, tc, node, apf0, apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1764,20 +1775,20 @@ private predicate flowFwdStore0(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead0(
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
|
||||
boolean fromArg, AccessPathOption argAp, Configuration config
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(node1, cc, argAp, apf0, ap0, config) and
|
||||
readCandFwd(node1, tc, apf0, node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead(
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and
|
||||
flowCand(node, _, _, apf, unbind(config)) and
|
||||
flowCandConsCand(tc, apf, unbind(config))
|
||||
)
|
||||
@@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIn(
|
||||
DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
flowFwd(arg, fromArg, argAp, apf, ap, config) and
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c |
|
||||
flowFwd(arg, outercc, argAp, apf, ap, config) and
|
||||
flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and
|
||||
flowCand(p, _, _, _, unbind(config))
|
||||
c = p.getEnclosingCallable() and
|
||||
c = resolveCall(call, outercc) and
|
||||
flowCand(p, _, _, _, unbind(config)) and
|
||||
if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall()
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1809,13 +1823,19 @@ private predicate flowFwdIn(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdOut(
|
||||
DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow |
|
||||
flowFwd(ret, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd(ret, innercc, argAp, apf, ap, config) and
|
||||
flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and
|
||||
flowCand(node, _, _, _, unbind(config))
|
||||
innerc = ret.getEnclosingCallable() and
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
resolveReturn(innercc, innerc, call)
|
||||
or
|
||||
innercc.(CallContextCall).matchesCall(call)
|
||||
)
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg(
|
||||
DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config)
|
||||
flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIsEntered(
|
||||
DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, AccessPathFront apf |
|
||||
flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and
|
||||
flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and
|
||||
flowCand(p, true, TAccessPathFrontSome(_), apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1920,7 +1940,7 @@ private predicate flow0(
|
||||
// flow out of a callable
|
||||
flowOut(_, node, _, _, ap, config) and
|
||||
toReturn = true and
|
||||
if flowFwd(node, true, TAccessPathSome(_), _, ap, config)
|
||||
if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config)
|
||||
then returnAp = TAccessPathSome(ap)
|
||||
else returnAp = TAccessPathNone()
|
||||
}
|
||||
@@ -2006,9 +2026,10 @@ private predicate flowIsReturned(
|
||||
DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
exists(ReturnNodeExt ret, CallContextCall ccc |
|
||||
flowOut(call, ret, toReturn, returnAp, ap, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(_), _, ap, config)
|
||||
flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and
|
||||
ccc.matchesCall(call)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2031,7 +2052,7 @@ private newtype TSummaryCtx =
|
||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 |
|
||||
parameterFlow(p, ap, ret.getEnclosingCallable(), config) and
|
||||
flow(ret, true, TAccessPathSome(_), ap0, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config)
|
||||
flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0(
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
@@ -2867,7 +2888,7 @@ private module FlowExploration {
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
@@ -65,6 +65,15 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT
|
||||
// tracking. The flow from expression `x` into `x++` etc. is handled in the
|
||||
// case above.
|
||||
exprTo = DataFlow::getAnAccessToAssignedVariable(exprFrom.(PostfixCrementOperation))
|
||||
or
|
||||
// In `for (char c : s) { ... c ... }`, this rule propagates taint from `s`
|
||||
// to `c`.
|
||||
exists(RangeBasedForStmt rbf |
|
||||
exprFrom = rbf.getRange() and
|
||||
// It's guaranteed up to at least C++20 that the range-based for loop
|
||||
// desugars to a variable with an initializer.
|
||||
exprTo = rbf.getVariable().getInitializer().getExpr()
|
||||
)
|
||||
)
|
||||
or
|
||||
// Taint can flow through modeled functions
|
||||
|
||||
@@ -1066,7 +1066,7 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(Node node, Configuration config) {
|
||||
predicate localFlowEntry(Node node, Configuration config) {
|
||||
nodeCand2(node, config) and
|
||||
(
|
||||
config.isSource(node) or
|
||||
@@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption {
|
||||
* Holds if `node` is reachable with access path `ap` from a source in
|
||||
* the configuration `config`.
|
||||
*
|
||||
* The Boolean `fromArg` records whether the node is reached through an
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `argAp` records the access path of that
|
||||
* argument.
|
||||
*/
|
||||
private predicate flowFwd(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwd0(node, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd0(node, cc, argAp, apf, ap, config) and
|
||||
flowCand(node, _, _, apf, config)
|
||||
}
|
||||
|
||||
private predicate flowFwd0(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowCand(node, _, _, _, config) and
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, argAp, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, _)
|
||||
exists(Node mid, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, localCC)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, argAp, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, _) and
|
||||
exists(Node mid, AccessPathNil nil, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, localCC) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
flowFwd(mid, _, _, apf, ap, config) and
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, _, _, _, nil, config) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
@@ -1704,40 +1704,51 @@ private predicate flowFwd0(
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config))
|
||||
or
|
||||
// read
|
||||
exists(TypedContent tc |
|
||||
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
|
||||
flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and
|
||||
flowFwdConsCand(tc, apf, ap, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
flowFwdIn(_, node, _, _, apf, ap, config) and
|
||||
fromArg = true and
|
||||
flowFwdIn(_, node, _, cc, _, apf, ap, config) and
|
||||
if flowCand(node, true, _, apf, config)
|
||||
then argAp = TAccessPathSome(ap)
|
||||
else argAp = TAccessPathNone()
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call |
|
||||
flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and
|
||||
fromArg = false
|
||||
exists(DataFlowCallable c |
|
||||
flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and
|
||||
if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext()
|
||||
)
|
||||
or
|
||||
exists(AccessPath argAp0 |
|
||||
flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and
|
||||
flowFwdIsEntered(call, fromArg, argAp, argAp0, config)
|
||||
flowFwdIsEntered(call, cc, argAp, argAp0, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdLocalEntry(
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
LocalCallContext localCC, Configuration config
|
||||
) {
|
||||
flowFwd(node, cc, argAp, apf, ap, config) and
|
||||
localFlowEntry(node, config) and
|
||||
localCC = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdStore(
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, AccessPathFront apf0 |
|
||||
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(mid, cc, argAp, apf0, ap0, config) and
|
||||
flowFwdStore0(mid, tc, node, apf0, apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1764,20 +1775,20 @@ private predicate flowFwdStore0(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead0(
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
|
||||
boolean fromArg, AccessPathOption argAp, Configuration config
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(node1, cc, argAp, apf0, ap0, config) and
|
||||
readCandFwd(node1, tc, apf0, node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead(
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and
|
||||
flowCand(node, _, _, apf, unbind(config)) and
|
||||
flowCandConsCand(tc, apf, unbind(config))
|
||||
)
|
||||
@@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIn(
|
||||
DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
flowFwd(arg, fromArg, argAp, apf, ap, config) and
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c |
|
||||
flowFwd(arg, outercc, argAp, apf, ap, config) and
|
||||
flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and
|
||||
flowCand(p, _, _, _, unbind(config))
|
||||
c = p.getEnclosingCallable() and
|
||||
c = resolveCall(call, outercc) and
|
||||
flowCand(p, _, _, _, unbind(config)) and
|
||||
if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall()
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1809,13 +1823,19 @@ private predicate flowFwdIn(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdOut(
|
||||
DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow |
|
||||
flowFwd(ret, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd(ret, innercc, argAp, apf, ap, config) and
|
||||
flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and
|
||||
flowCand(node, _, _, _, unbind(config))
|
||||
innerc = ret.getEnclosingCallable() and
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
resolveReturn(innercc, innerc, call)
|
||||
or
|
||||
innercc.(CallContextCall).matchesCall(call)
|
||||
)
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg(
|
||||
DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config)
|
||||
flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIsEntered(
|
||||
DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, AccessPathFront apf |
|
||||
flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and
|
||||
flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and
|
||||
flowCand(p, true, TAccessPathFrontSome(_), apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1920,7 +1940,7 @@ private predicate flow0(
|
||||
// flow out of a callable
|
||||
flowOut(_, node, _, _, ap, config) and
|
||||
toReturn = true and
|
||||
if flowFwd(node, true, TAccessPathSome(_), _, ap, config)
|
||||
if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config)
|
||||
then returnAp = TAccessPathSome(ap)
|
||||
else returnAp = TAccessPathNone()
|
||||
}
|
||||
@@ -2006,9 +2026,10 @@ private predicate flowIsReturned(
|
||||
DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
exists(ReturnNodeExt ret, CallContextCall ccc |
|
||||
flowOut(call, ret, toReturn, returnAp, ap, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(_), _, ap, config)
|
||||
flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and
|
||||
ccc.matchesCall(call)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2031,7 +2052,7 @@ private newtype TSummaryCtx =
|
||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 |
|
||||
parameterFlow(p, ap, ret.getEnclosingCallable(), config) and
|
||||
flow(ret, true, TAccessPathSome(_), ap0, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config)
|
||||
flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0(
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
@@ -2867,7 +2888,7 @@ private module FlowExploration {
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
@@ -1066,7 +1066,7 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(Node node, Configuration config) {
|
||||
predicate localFlowEntry(Node node, Configuration config) {
|
||||
nodeCand2(node, config) and
|
||||
(
|
||||
config.isSource(node) or
|
||||
@@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption {
|
||||
* Holds if `node` is reachable with access path `ap` from a source in
|
||||
* the configuration `config`.
|
||||
*
|
||||
* The Boolean `fromArg` records whether the node is reached through an
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `argAp` records the access path of that
|
||||
* argument.
|
||||
*/
|
||||
private predicate flowFwd(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwd0(node, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd0(node, cc, argAp, apf, ap, config) and
|
||||
flowCand(node, _, _, apf, config)
|
||||
}
|
||||
|
||||
private predicate flowFwd0(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowCand(node, _, _, _, config) and
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, argAp, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, _)
|
||||
exists(Node mid, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, localCC)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, argAp, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, _) and
|
||||
exists(Node mid, AccessPathNil nil, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, localCC) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
flowFwd(mid, _, _, apf, ap, config) and
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, _, _, _, nil, config) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
@@ -1704,40 +1704,51 @@ private predicate flowFwd0(
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config))
|
||||
or
|
||||
// read
|
||||
exists(TypedContent tc |
|
||||
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
|
||||
flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and
|
||||
flowFwdConsCand(tc, apf, ap, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
flowFwdIn(_, node, _, _, apf, ap, config) and
|
||||
fromArg = true and
|
||||
flowFwdIn(_, node, _, cc, _, apf, ap, config) and
|
||||
if flowCand(node, true, _, apf, config)
|
||||
then argAp = TAccessPathSome(ap)
|
||||
else argAp = TAccessPathNone()
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call |
|
||||
flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and
|
||||
fromArg = false
|
||||
exists(DataFlowCallable c |
|
||||
flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and
|
||||
if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext()
|
||||
)
|
||||
or
|
||||
exists(AccessPath argAp0 |
|
||||
flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and
|
||||
flowFwdIsEntered(call, fromArg, argAp, argAp0, config)
|
||||
flowFwdIsEntered(call, cc, argAp, argAp0, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdLocalEntry(
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
LocalCallContext localCC, Configuration config
|
||||
) {
|
||||
flowFwd(node, cc, argAp, apf, ap, config) and
|
||||
localFlowEntry(node, config) and
|
||||
localCC = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdStore(
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, AccessPathFront apf0 |
|
||||
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(mid, cc, argAp, apf0, ap0, config) and
|
||||
flowFwdStore0(mid, tc, node, apf0, apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1764,20 +1775,20 @@ private predicate flowFwdStore0(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead0(
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
|
||||
boolean fromArg, AccessPathOption argAp, Configuration config
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(node1, cc, argAp, apf0, ap0, config) and
|
||||
readCandFwd(node1, tc, apf0, node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead(
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and
|
||||
flowCand(node, _, _, apf, unbind(config)) and
|
||||
flowCandConsCand(tc, apf, unbind(config))
|
||||
)
|
||||
@@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIn(
|
||||
DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
flowFwd(arg, fromArg, argAp, apf, ap, config) and
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c |
|
||||
flowFwd(arg, outercc, argAp, apf, ap, config) and
|
||||
flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and
|
||||
flowCand(p, _, _, _, unbind(config))
|
||||
c = p.getEnclosingCallable() and
|
||||
c = resolveCall(call, outercc) and
|
||||
flowCand(p, _, _, _, unbind(config)) and
|
||||
if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall()
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1809,13 +1823,19 @@ private predicate flowFwdIn(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdOut(
|
||||
DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow |
|
||||
flowFwd(ret, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd(ret, innercc, argAp, apf, ap, config) and
|
||||
flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and
|
||||
flowCand(node, _, _, _, unbind(config))
|
||||
innerc = ret.getEnclosingCallable() and
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
resolveReturn(innercc, innerc, call)
|
||||
or
|
||||
innercc.(CallContextCall).matchesCall(call)
|
||||
)
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg(
|
||||
DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config)
|
||||
flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIsEntered(
|
||||
DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, AccessPathFront apf |
|
||||
flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and
|
||||
flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and
|
||||
flowCand(p, true, TAccessPathFrontSome(_), apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1920,7 +1940,7 @@ private predicate flow0(
|
||||
// flow out of a callable
|
||||
flowOut(_, node, _, _, ap, config) and
|
||||
toReturn = true and
|
||||
if flowFwd(node, true, TAccessPathSome(_), _, ap, config)
|
||||
if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config)
|
||||
then returnAp = TAccessPathSome(ap)
|
||||
else returnAp = TAccessPathNone()
|
||||
}
|
||||
@@ -2006,9 +2026,10 @@ private predicate flowIsReturned(
|
||||
DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
exists(ReturnNodeExt ret, CallContextCall ccc |
|
||||
flowOut(call, ret, toReturn, returnAp, ap, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(_), _, ap, config)
|
||||
flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and
|
||||
ccc.matchesCall(call)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2031,7 +2052,7 @@ private newtype TSummaryCtx =
|
||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 |
|
||||
parameterFlow(p, ap, ret.getEnclosingCallable(), config) and
|
||||
flow(ret, true, TAccessPathSome(_), ap0, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config)
|
||||
flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0(
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
@@ -2867,7 +2888,7 @@ private module FlowExploration {
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
@@ -1066,7 +1066,7 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(Node node, Configuration config) {
|
||||
predicate localFlowEntry(Node node, Configuration config) {
|
||||
nodeCand2(node, config) and
|
||||
(
|
||||
config.isSource(node) or
|
||||
@@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption {
|
||||
* Holds if `node` is reachable with access path `ap` from a source in
|
||||
* the configuration `config`.
|
||||
*
|
||||
* The Boolean `fromArg` records whether the node is reached through an
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `argAp` records the access path of that
|
||||
* argument.
|
||||
*/
|
||||
private predicate flowFwd(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwd0(node, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd0(node, cc, argAp, apf, ap, config) and
|
||||
flowCand(node, _, _, apf, config)
|
||||
}
|
||||
|
||||
private predicate flowFwd0(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowCand(node, _, _, _, config) and
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, argAp, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, _)
|
||||
exists(Node mid, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, localCC)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, argAp, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, _) and
|
||||
exists(Node mid, AccessPathNil nil, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, localCC) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
flowFwd(mid, _, _, apf, ap, config) and
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, _, _, _, nil, config) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
@@ -1704,40 +1704,51 @@ private predicate flowFwd0(
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config))
|
||||
or
|
||||
// read
|
||||
exists(TypedContent tc |
|
||||
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
|
||||
flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and
|
||||
flowFwdConsCand(tc, apf, ap, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
flowFwdIn(_, node, _, _, apf, ap, config) and
|
||||
fromArg = true and
|
||||
flowFwdIn(_, node, _, cc, _, apf, ap, config) and
|
||||
if flowCand(node, true, _, apf, config)
|
||||
then argAp = TAccessPathSome(ap)
|
||||
else argAp = TAccessPathNone()
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call |
|
||||
flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and
|
||||
fromArg = false
|
||||
exists(DataFlowCallable c |
|
||||
flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and
|
||||
if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext()
|
||||
)
|
||||
or
|
||||
exists(AccessPath argAp0 |
|
||||
flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and
|
||||
flowFwdIsEntered(call, fromArg, argAp, argAp0, config)
|
||||
flowFwdIsEntered(call, cc, argAp, argAp0, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdLocalEntry(
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
LocalCallContext localCC, Configuration config
|
||||
) {
|
||||
flowFwd(node, cc, argAp, apf, ap, config) and
|
||||
localFlowEntry(node, config) and
|
||||
localCC = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdStore(
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, AccessPathFront apf0 |
|
||||
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(mid, cc, argAp, apf0, ap0, config) and
|
||||
flowFwdStore0(mid, tc, node, apf0, apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1764,20 +1775,20 @@ private predicate flowFwdStore0(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead0(
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
|
||||
boolean fromArg, AccessPathOption argAp, Configuration config
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(node1, cc, argAp, apf0, ap0, config) and
|
||||
readCandFwd(node1, tc, apf0, node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead(
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and
|
||||
flowCand(node, _, _, apf, unbind(config)) and
|
||||
flowCandConsCand(tc, apf, unbind(config))
|
||||
)
|
||||
@@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIn(
|
||||
DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
flowFwd(arg, fromArg, argAp, apf, ap, config) and
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c |
|
||||
flowFwd(arg, outercc, argAp, apf, ap, config) and
|
||||
flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and
|
||||
flowCand(p, _, _, _, unbind(config))
|
||||
c = p.getEnclosingCallable() and
|
||||
c = resolveCall(call, outercc) and
|
||||
flowCand(p, _, _, _, unbind(config)) and
|
||||
if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall()
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1809,13 +1823,19 @@ private predicate flowFwdIn(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdOut(
|
||||
DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow |
|
||||
flowFwd(ret, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd(ret, innercc, argAp, apf, ap, config) and
|
||||
flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and
|
||||
flowCand(node, _, _, _, unbind(config))
|
||||
innerc = ret.getEnclosingCallable() and
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
resolveReturn(innercc, innerc, call)
|
||||
or
|
||||
innercc.(CallContextCall).matchesCall(call)
|
||||
)
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg(
|
||||
DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config)
|
||||
flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIsEntered(
|
||||
DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, AccessPathFront apf |
|
||||
flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and
|
||||
flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and
|
||||
flowCand(p, true, TAccessPathFrontSome(_), apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1920,7 +1940,7 @@ private predicate flow0(
|
||||
// flow out of a callable
|
||||
flowOut(_, node, _, _, ap, config) and
|
||||
toReturn = true and
|
||||
if flowFwd(node, true, TAccessPathSome(_), _, ap, config)
|
||||
if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config)
|
||||
then returnAp = TAccessPathSome(ap)
|
||||
else returnAp = TAccessPathNone()
|
||||
}
|
||||
@@ -2006,9 +2026,10 @@ private predicate flowIsReturned(
|
||||
DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
exists(ReturnNodeExt ret, CallContextCall ccc |
|
||||
flowOut(call, ret, toReturn, returnAp, ap, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(_), _, ap, config)
|
||||
flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and
|
||||
ccc.matchesCall(call)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2031,7 +2052,7 @@ private newtype TSummaryCtx =
|
||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 |
|
||||
parameterFlow(p, ap, ret.getEnclosingCallable(), config) and
|
||||
flow(ret, true, TAccessPathSome(_), ap0, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config)
|
||||
flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0(
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
@@ -2867,7 +2888,7 @@ private module FlowExploration {
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
@@ -1066,7 +1066,7 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(Node node, Configuration config) {
|
||||
predicate localFlowEntry(Node node, Configuration config) {
|
||||
nodeCand2(node, config) and
|
||||
(
|
||||
config.isSource(node) or
|
||||
@@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption {
|
||||
* Holds if `node` is reachable with access path `ap` from a source in
|
||||
* the configuration `config`.
|
||||
*
|
||||
* The Boolean `fromArg` records whether the node is reached through an
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `argAp` records the access path of that
|
||||
* argument.
|
||||
*/
|
||||
private predicate flowFwd(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwd0(node, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd0(node, cc, argAp, apf, ap, config) and
|
||||
flowCand(node, _, _, apf, config)
|
||||
}
|
||||
|
||||
private predicate flowFwd0(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowCand(node, _, _, _, config) and
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, argAp, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, _)
|
||||
exists(Node mid, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, localCC)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, argAp, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, _) and
|
||||
exists(Node mid, AccessPathNil nil, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, localCC) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
flowFwd(mid, _, _, apf, ap, config) and
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, _, _, _, nil, config) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
@@ -1704,40 +1704,51 @@ private predicate flowFwd0(
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config))
|
||||
or
|
||||
// read
|
||||
exists(TypedContent tc |
|
||||
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
|
||||
flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and
|
||||
flowFwdConsCand(tc, apf, ap, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
flowFwdIn(_, node, _, _, apf, ap, config) and
|
||||
fromArg = true and
|
||||
flowFwdIn(_, node, _, cc, _, apf, ap, config) and
|
||||
if flowCand(node, true, _, apf, config)
|
||||
then argAp = TAccessPathSome(ap)
|
||||
else argAp = TAccessPathNone()
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call |
|
||||
flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and
|
||||
fromArg = false
|
||||
exists(DataFlowCallable c |
|
||||
flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and
|
||||
if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext()
|
||||
)
|
||||
or
|
||||
exists(AccessPath argAp0 |
|
||||
flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and
|
||||
flowFwdIsEntered(call, fromArg, argAp, argAp0, config)
|
||||
flowFwdIsEntered(call, cc, argAp, argAp0, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdLocalEntry(
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
LocalCallContext localCC, Configuration config
|
||||
) {
|
||||
flowFwd(node, cc, argAp, apf, ap, config) and
|
||||
localFlowEntry(node, config) and
|
||||
localCC = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdStore(
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, AccessPathFront apf0 |
|
||||
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(mid, cc, argAp, apf0, ap0, config) and
|
||||
flowFwdStore0(mid, tc, node, apf0, apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1764,20 +1775,20 @@ private predicate flowFwdStore0(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead0(
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
|
||||
boolean fromArg, AccessPathOption argAp, Configuration config
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(node1, cc, argAp, apf0, ap0, config) and
|
||||
readCandFwd(node1, tc, apf0, node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead(
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and
|
||||
flowCand(node, _, _, apf, unbind(config)) and
|
||||
flowCandConsCand(tc, apf, unbind(config))
|
||||
)
|
||||
@@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIn(
|
||||
DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
flowFwd(arg, fromArg, argAp, apf, ap, config) and
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c |
|
||||
flowFwd(arg, outercc, argAp, apf, ap, config) and
|
||||
flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and
|
||||
flowCand(p, _, _, _, unbind(config))
|
||||
c = p.getEnclosingCallable() and
|
||||
c = resolveCall(call, outercc) and
|
||||
flowCand(p, _, _, _, unbind(config)) and
|
||||
if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall()
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1809,13 +1823,19 @@ private predicate flowFwdIn(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdOut(
|
||||
DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow |
|
||||
flowFwd(ret, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd(ret, innercc, argAp, apf, ap, config) and
|
||||
flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and
|
||||
flowCand(node, _, _, _, unbind(config))
|
||||
innerc = ret.getEnclosingCallable() and
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
resolveReturn(innercc, innerc, call)
|
||||
or
|
||||
innercc.(CallContextCall).matchesCall(call)
|
||||
)
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg(
|
||||
DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config)
|
||||
flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIsEntered(
|
||||
DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, AccessPathFront apf |
|
||||
flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and
|
||||
flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and
|
||||
flowCand(p, true, TAccessPathFrontSome(_), apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1920,7 +1940,7 @@ private predicate flow0(
|
||||
// flow out of a callable
|
||||
flowOut(_, node, _, _, ap, config) and
|
||||
toReturn = true and
|
||||
if flowFwd(node, true, TAccessPathSome(_), _, ap, config)
|
||||
if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config)
|
||||
then returnAp = TAccessPathSome(ap)
|
||||
else returnAp = TAccessPathNone()
|
||||
}
|
||||
@@ -2006,9 +2026,10 @@ private predicate flowIsReturned(
|
||||
DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
exists(ReturnNodeExt ret, CallContextCall ccc |
|
||||
flowOut(call, ret, toReturn, returnAp, ap, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(_), _, ap, config)
|
||||
flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and
|
||||
ccc.matchesCall(call)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2031,7 +2052,7 @@ private newtype TSummaryCtx =
|
||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 |
|
||||
parameterFlow(p, ap, ret.getEnclosingCallable(), config) and
|
||||
flow(ret, true, TAccessPathSome(_), ap0, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config)
|
||||
flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0(
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
@@ -2867,7 +2888,7 @@ private module FlowExploration {
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
@@ -512,13 +512,19 @@ abstract class CallContext extends TCallContext {
|
||||
abstract predicate relevantFor(DataFlowCallable callable);
|
||||
}
|
||||
|
||||
class CallContextAny extends CallContext, TAnyCallContext {
|
||||
abstract class CallContextNoCall extends CallContext { }
|
||||
|
||||
class CallContextAny extends CallContextNoCall, TAnyCallContext {
|
||||
override string toString() { result = "CcAny" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) { any() }
|
||||
}
|
||||
|
||||
abstract class CallContextCall extends CallContext { }
|
||||
abstract class CallContextCall extends CallContext {
|
||||
/** Holds if this call context may be `call`. */
|
||||
bindingset[call]
|
||||
abstract predicate matchesCall(DataFlowCall call);
|
||||
}
|
||||
|
||||
class CallContextSpecificCall extends CallContextCall, TSpecificCall {
|
||||
override string toString() {
|
||||
@@ -529,6 +535,8 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall {
|
||||
recordDataFlowCallSite(getCall(), callable)
|
||||
}
|
||||
|
||||
override predicate matchesCall(DataFlowCall call) { call = this.getCall() }
|
||||
|
||||
DataFlowCall getCall() { this = TSpecificCall(result) }
|
||||
}
|
||||
|
||||
@@ -538,9 +546,11 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(ParameterNode p | p.getEnclosingCallable() = callable)
|
||||
}
|
||||
|
||||
override predicate matchesCall(DataFlowCall call) { any() }
|
||||
}
|
||||
|
||||
class CallContextReturn extends CallContext, TReturn {
|
||||
class CallContextReturn extends CallContextNoCall, TReturn {
|
||||
override string toString() {
|
||||
exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")")
|
||||
}
|
||||
|
||||
@@ -7,9 +7,17 @@ import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
|
||||
/**
|
||||
* Model for C++ conversion constructors.
|
||||
* Model for C++ conversion constructors. As of C++11 this does not correspond
|
||||
* perfectly with the language definition of a converting constructor, however,
|
||||
* it does correspond with the constructors we are confident taint should flow
|
||||
* through.
|
||||
*/
|
||||
class ConversionConstructorModel extends ConversionConstructor, TaintFunction {
|
||||
class ConversionConstructorModel extends Constructor, TaintFunction {
|
||||
ConversionConstructorModel() {
|
||||
strictcount(Parameter p | p = getAParameter() and not p.hasInitializer()) = 1 and
|
||||
not hasSpecifier("explicit")
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// taint flow from the first constructor argument to the returned object
|
||||
input.isParameter(0) and
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
|
||||
/**
|
||||
* The `std::basic_string` template class.
|
||||
*/
|
||||
class StdBasicString extends TemplateClass {
|
||||
StdBasicString() { this.hasQualifiedName("std", "basic_string") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard function `std::string.c_str`.
|
||||
*/
|
||||
@@ -12,3 +19,51 @@ class StdStringCStr extends TaintFunction {
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::string` function `operator+`.
|
||||
*/
|
||||
class StdStringPlus extends TaintFunction {
|
||||
StdStringPlus() {
|
||||
this.hasQualifiedName("std", "operator+") and
|
||||
this.getUnspecifiedType() = any(StdBasicString s).getAnInstantiation()
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from parameters to return value
|
||||
(
|
||||
input.isParameterDeref(0) or
|
||||
input.isParameterDeref(1)
|
||||
) and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::string` functions `operator+=` and `append`.
|
||||
*/
|
||||
class StdStringAppend extends TaintFunction {
|
||||
StdStringAppend() {
|
||||
this.hasQualifiedName("std", "basic_string", "operator+=") or
|
||||
this.hasQualifiedName("std", "basic_string", "append")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is a string (or
|
||||
* character).
|
||||
*/
|
||||
int getAStringParameter() {
|
||||
getParameter(result).getType() instanceof PointerType or
|
||||
getParameter(result).getType() instanceof ReferenceType or
|
||||
getParameter(result).getType() = getDeclaringType().getTemplateArgument(0) // i.e. `std::basic_string::CharT`
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from parameter to string itself (qualifier) and return value
|
||||
input.isParameterDeref(getAStringParameter()) and
|
||||
(
|
||||
output.isQualifierObject() or
|
||||
output.isReturnValueDeref()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
|
||||
import cpp
|
||||
private import RangeAnalysisUtils
|
||||
private import experimental.semmle.code.cpp.models.interfaces.SimpleRangeAnalysisExpr
|
||||
import RangeSSA
|
||||
import SimpleRangeAnalysisCached
|
||||
private import NanAnalysis
|
||||
@@ -156,6 +157,10 @@ float safeFloor(float v) {
|
||||
result = v
|
||||
}
|
||||
|
||||
private class UnsignedMulExpr extends MulExpr {
|
||||
UnsignedMulExpr() { this.getType().(IntegralType).isUnsigned() }
|
||||
}
|
||||
|
||||
/** Set of expressions which we know how to analyze. */
|
||||
private predicate analyzableExpr(Expr e) {
|
||||
// The type of the expression must be arithmetic. We reuse the logic in
|
||||
@@ -178,6 +183,8 @@ private predicate analyzableExpr(Expr e) {
|
||||
or
|
||||
e instanceof SubExpr
|
||||
or
|
||||
e instanceof UnsignedMulExpr
|
||||
or
|
||||
e instanceof AssignExpr
|
||||
or
|
||||
e instanceof AssignAddExpr
|
||||
@@ -207,6 +214,9 @@ private predicate analyzableExpr(Expr e) {
|
||||
or
|
||||
// `>>` by a constant
|
||||
exists(e.(RShiftExpr).getRightOperand().getValue())
|
||||
or
|
||||
// A modeled expression for range analysis
|
||||
e instanceof SimpleRangeAnalysisExpr
|
||||
)
|
||||
}
|
||||
|
||||
@@ -278,6 +288,10 @@ private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVaria
|
||||
or
|
||||
exists(SubExpr subExpr | e = subExpr | exprDependsOnDef(subExpr.getAnOperand(), srcDef, srcVar))
|
||||
or
|
||||
exists(UnsignedMulExpr mulExpr | e = mulExpr |
|
||||
exprDependsOnDef(mulExpr.getAnOperand(), srcDef, srcVar)
|
||||
)
|
||||
or
|
||||
exists(AssignExpr addExpr | e = addExpr | exprDependsOnDef(addExpr.getRValue(), srcDef, srcVar))
|
||||
or
|
||||
exists(AssignAddExpr addExpr | e = addExpr |
|
||||
@@ -318,6 +332,16 @@ private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVaria
|
||||
)
|
||||
or
|
||||
e = srcDef.getAUse(srcVar)
|
||||
or
|
||||
// A modeled expression for range analysis
|
||||
exists(SimpleRangeAnalysisExpr rae | rae = e |
|
||||
rae.dependsOnDef(srcDef, srcVar)
|
||||
or
|
||||
exists(Expr child |
|
||||
rae.dependsOnChild(child) and
|
||||
exprDependsOnDef(child, srcDef, srcVar)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -381,9 +405,17 @@ private predicate assignmentDef(RangeSsaDefinition def, StackVariable v, Expr ex
|
||||
)
|
||||
}
|
||||
|
||||
/** See comment above sourceDef. */
|
||||
/** See comment above assignmentDef. */
|
||||
private predicate analyzableDef(RangeSsaDefinition def, StackVariable v) {
|
||||
assignmentDef(def, v, _) or defDependsOnDef(def, v, _, _)
|
||||
assignmentDef(def, v, _)
|
||||
or
|
||||
analyzableExpr(def.(AssignOperation)) and
|
||||
v = def.getAVariable()
|
||||
or
|
||||
analyzableExpr(def.(CrementOperation)) and
|
||||
v = def.getAVariable()
|
||||
or
|
||||
phiDependsOnDef(def, v, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -435,13 +467,6 @@ private float addRoundingDownSmall(float x, float small) {
|
||||
if (x + small) - x > small then result = (x + small).nextDown() else result = (x + small)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the truncated lower bounds of the fully converted expression.
|
||||
*/
|
||||
private float getFullyConvertedLowerBounds(Expr expr) {
|
||||
result = getTruncatedLowerBounds(expr.getFullyConverted())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lower bounds of the expression.
|
||||
*
|
||||
@@ -488,13 +513,6 @@ private float getTruncatedLowerBounds(Expr expr) {
|
||||
result = exprMinVal(expr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the truncated upper bounds of the fully converted expression.
|
||||
*/
|
||||
private float getFullyConvertedUpperBounds(Expr expr) {
|
||||
result = getTruncatedUpperBounds(expr.getFullyConverted())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the upper bounds of the expression.
|
||||
*
|
||||
@@ -625,6 +643,13 @@ private float getLowerBoundsImpl(Expr expr) {
|
||||
result = addRoundingDown(xLow, -yHigh)
|
||||
)
|
||||
or
|
||||
exists(UnsignedMulExpr mulExpr, float xLow, float yLow |
|
||||
expr = mulExpr and
|
||||
xLow = getFullyConvertedLowerBounds(mulExpr.getLeftOperand()) and
|
||||
yLow = getFullyConvertedLowerBounds(mulExpr.getRightOperand()) and
|
||||
result = xLow * yLow
|
||||
)
|
||||
or
|
||||
exists(AssignExpr assign |
|
||||
expr = assign and
|
||||
result = getFullyConvertedLowerBounds(assign.getRValue())
|
||||
@@ -711,7 +736,9 @@ private float getLowerBoundsImpl(Expr expr) {
|
||||
or
|
||||
// Use SSA to get the lower bounds for a variable use.
|
||||
exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) |
|
||||
result = getDefLowerBounds(def, v)
|
||||
result = getDefLowerBounds(def, v) and
|
||||
// Not explicitly modeled by a SimpleRangeAnalysisExpr
|
||||
not expr instanceof SimpleRangeAnalysisExpr
|
||||
)
|
||||
or
|
||||
// unsigned `&` (tighter bounds may exist)
|
||||
@@ -727,6 +754,12 @@ private float getLowerBoundsImpl(Expr expr) {
|
||||
right = rsExpr.getRightOperand().getFullyConverted().getValue().toInt() and
|
||||
result = safeFloor(left / 2.pow(right))
|
||||
)
|
||||
or
|
||||
// A modeled expression for range analysis
|
||||
exists(SimpleRangeAnalysisExpr rangeAnalysisExpr |
|
||||
rangeAnalysisExpr = expr and
|
||||
result = rangeAnalysisExpr.getLowerBounds()
|
||||
)
|
||||
}
|
||||
|
||||
/** Only to be called by `getTruncatedUpperBounds`. */
|
||||
@@ -794,6 +827,13 @@ private float getUpperBoundsImpl(Expr expr) {
|
||||
result = addRoundingUp(xHigh, -yLow)
|
||||
)
|
||||
or
|
||||
exists(UnsignedMulExpr mulExpr, float xHigh, float yHigh |
|
||||
expr = mulExpr and
|
||||
xHigh = getFullyConvertedUpperBounds(mulExpr.getLeftOperand()) and
|
||||
yHigh = getFullyConvertedUpperBounds(mulExpr.getRightOperand()) and
|
||||
result = xHigh * yHigh
|
||||
)
|
||||
or
|
||||
exists(AssignExpr assign |
|
||||
expr = assign and
|
||||
result = getFullyConvertedUpperBounds(assign.getRValue())
|
||||
@@ -878,7 +918,9 @@ private float getUpperBoundsImpl(Expr expr) {
|
||||
or
|
||||
// Use SSA to get the upper bounds for a variable use.
|
||||
exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) |
|
||||
result = getDefUpperBounds(def, v)
|
||||
result = getDefUpperBounds(def, v) and
|
||||
// Not explicitly modeled by a SimpleRangeAnalysisExpr
|
||||
not expr instanceof SimpleRangeAnalysisExpr
|
||||
)
|
||||
or
|
||||
// unsigned `&` (tighter bounds may exist)
|
||||
@@ -896,6 +938,12 @@ private float getUpperBoundsImpl(Expr expr) {
|
||||
right = rsExpr.getRightOperand().getFullyConverted().getValue().toInt() and
|
||||
result = safeFloor(left / 2.pow(right))
|
||||
)
|
||||
or
|
||||
// A modeled expression for range analysis
|
||||
exists(SimpleRangeAnalysisExpr rangeAnalysisExpr |
|
||||
rangeAnalysisExpr = expr and
|
||||
result = rangeAnalysisExpr.getUpperBounds()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1480,3 +1528,25 @@ private module SimpleRangeAnalysisCached {
|
||||
convertedExprMightOverflowPositively(expr)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: do not use. This module contains utilities for use in the
|
||||
* experimental `SimpleRangeAnalysisExpr` module.
|
||||
*/
|
||||
module SimpleRangeAnalysisInternal {
|
||||
/**
|
||||
* Gets the truncated lower bounds of the fully converted expression.
|
||||
*/
|
||||
float getFullyConvertedLowerBounds(Expr expr) {
|
||||
result = getTruncatedLowerBounds(expr.getFullyConverted())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the truncated upper bounds of the fully converted expression.
|
||||
*/
|
||||
float getFullyConvertedUpperBounds(Expr expr) {
|
||||
result = getTruncatedUpperBounds(expr.getFullyConverted())
|
||||
}
|
||||
}
|
||||
|
||||
private import SimpleRangeAnalysisInternal
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/// Adds its arguments (has custom modeling in QL)
|
||||
int custom_add_function(int a, int b);
|
||||
|
||||
int test_extensibility_add(int x) {
|
||||
if (x >= -10 && x <= 10) {
|
||||
int result = custom_add_function(x, 100);
|
||||
return result; // 90 .. 110
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
| extensibility.c:5:7:5:7 | x | -2.147483648E9 | 2.147483647E9 |
|
||||
| extensibility.c:5:19:5:19 | x | -10.0 | 2.147483647E9 |
|
||||
| extensibility.c:6:38:6:38 | x | -10.0 | 10.0 |
|
||||
| extensibility.c:7:12:7:17 | result | 90.0 | 110.0 |
|
||||
@@ -0,0 +1,32 @@
|
||||
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||
import experimental.semmle.code.cpp.models.interfaces.SimpleRangeAnalysisExpr
|
||||
|
||||
class CustomAddFunctionCall extends SimpleRangeAnalysisExpr, FunctionCall {
|
||||
CustomAddFunctionCall() { this.getTarget().hasGlobalName("custom_add_function") }
|
||||
|
||||
override float getLowerBounds() {
|
||||
exists(float lower0, float lower1 |
|
||||
lower0 = getFullyConvertedLowerBounds(this.getArgument(0)) and
|
||||
lower1 = getFullyConvertedLowerBounds(this.getArgument(1)) and
|
||||
// Note: this rounds toward 0, not -Inf as it should
|
||||
result = lower0 + lower1
|
||||
)
|
||||
}
|
||||
|
||||
override float getUpperBounds() {
|
||||
exists(float upper0, float upper1 |
|
||||
upper0 = getFullyConvertedUpperBounds(this.getArgument(0)) and
|
||||
upper1 = getFullyConvertedUpperBounds(this.getArgument(1)) and
|
||||
// Note: this rounds toward 0, not Inf as it should
|
||||
result = upper0 + upper1
|
||||
)
|
||||
}
|
||||
|
||||
override predicate dependsOnChild(Expr child) { child = this.getAnArgument() }
|
||||
}
|
||||
|
||||
from VariableAccess expr, float lower, float upper
|
||||
where
|
||||
lower = lowerBound(expr) and
|
||||
upper = upperBound(expr)
|
||||
select expr, lower, upper
|
||||
@@ -0,0 +1,21 @@
|
||||
edges
|
||||
| test.cpp:77:16:77:22 | medical | test.cpp:78:24:78:27 | temp |
|
||||
| test.cpp:81:17:81:20 | call to func | test.cpp:82:24:82:28 | buff5 |
|
||||
| test.cpp:81:22:81:28 | medical | test.cpp:81:17:81:20 | call to func |
|
||||
nodes
|
||||
| test.cpp:57:9:57:18 | theZipcode | semmle.label | theZipcode |
|
||||
| test.cpp:74:24:74:30 | medical | semmle.label | medical |
|
||||
| test.cpp:77:16:77:22 | medical | semmle.label | medical |
|
||||
| test.cpp:78:24:78:27 | temp | semmle.label | temp |
|
||||
| test.cpp:81:17:81:20 | call to func | semmle.label | call to func |
|
||||
| test.cpp:81:22:81:28 | medical | semmle.label | medical |
|
||||
| test.cpp:82:24:82:28 | buff5 | semmle.label | buff5 |
|
||||
| test.cpp:96:37:96:46 | theZipcode | semmle.label | theZipcode |
|
||||
| test.cpp:99:42:99:51 | theZipcode | semmle.label | theZipcode |
|
||||
#select
|
||||
| test.cpp:57:9:57:18 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@ | test.cpp:57:9:57:18 | theZipcode | this source. |
|
||||
| test.cpp:74:24:74:30 | medical | This write into the external location 'medical' may contain unencrypted data from $@ | test.cpp:74:24:74:30 | medical | this source. |
|
||||
| test.cpp:78:24:78:27 | temp | This write into the external location 'temp' may contain unencrypted data from $@ | test.cpp:77:16:77:22 | medical | this source. |
|
||||
| test.cpp:82:24:82:28 | buff5 | This write into the external location 'buff5' may contain unencrypted data from $@ | test.cpp:81:22:81:28 | medical | this source. |
|
||||
| test.cpp:96:37:96:46 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@ | test.cpp:96:37:96:46 | theZipcode | this source. |
|
||||
| test.cpp:99:42:99:51 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@ | test.cpp:99:42:99:51 | theZipcode | this source. |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE/CWE-359/PrivateCleartextWrite.ql
|
||||
@@ -0,0 +1,105 @@
|
||||
#define FILE int
|
||||
#define wchar char
|
||||
#define size_t int
|
||||
typedef int streamsize;
|
||||
|
||||
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
|
||||
int fputs(const char *s, FILE *stream);
|
||||
int fputc(int c, FILE *stream);
|
||||
int fprintf(FILE *stream, const char *format, ...);
|
||||
int sprintf(char *s, const char *format, ...);
|
||||
size_t strlen(const char *s);
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <class charT>
|
||||
struct char_traits;
|
||||
|
||||
template <class charT, class traits = char_traits<charT>>
|
||||
class basic_ostream /*: virtual public basic_ios<charT,traits> - not needed for this test */
|
||||
{
|
||||
public:
|
||||
typedef charT char_type;
|
||||
basic_ostream<charT, traits> &write(const char_type *s, streamsize n);
|
||||
};
|
||||
|
||||
template <class charT, class traits = char_traits<charT>>
|
||||
class basic_ofstream : public basic_ostream<charT, traits>
|
||||
{
|
||||
public:
|
||||
};
|
||||
|
||||
template <class charT, class traits>
|
||||
basic_ostream<charT, traits> &operator<<(basic_ostream<charT, traits> &, const charT *);
|
||||
|
||||
typedef basic_ostream<char> ostream;
|
||||
typedef basic_ofstream<char> ofstream;
|
||||
}; // namespace std
|
||||
|
||||
using namespace std;
|
||||
|
||||
char *encrypt(char *buffer)
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
char *func(char *buffer)
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// test for CleartextFileWrite
|
||||
void file()
|
||||
{
|
||||
char *theZipcode = "cleartext zipcode!";
|
||||
FILE *file;
|
||||
|
||||
// BAD: write zipcode to file in cleartext
|
||||
fputs(theZipcode, file);
|
||||
|
||||
// GOOD: encrypt first
|
||||
char *encrypted = encrypt(theZipcode);
|
||||
fwrite(encrypted, sizeof(encrypted), 1, file);
|
||||
}
|
||||
|
||||
// test for CleartextBufferWrite
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *medical = "medical";
|
||||
char *buff1;
|
||||
char *buff2;
|
||||
char *buff3;
|
||||
char *buff4;
|
||||
|
||||
// BAD: write medical to buffer in cleartext
|
||||
sprintf(buff1, "%s", medical);
|
||||
|
||||
// BAD: write medical to buffer in cleartext
|
||||
char *temp = medical;
|
||||
sprintf(buff2, "%s", temp);
|
||||
|
||||
// BAD: write medical to buffer in cleartext
|
||||
char *buff5 = func(medical);
|
||||
sprintf(buff3, "%s", buff5);
|
||||
|
||||
char *buff6 = encrypt(medical);
|
||||
// GOOD: encrypt first
|
||||
sprintf(buff4, "%s", buff6);
|
||||
}
|
||||
|
||||
// test for CleartextFileWrite
|
||||
void stream()
|
||||
{
|
||||
char *theZipcode = "cleartext zipcode!";
|
||||
ofstream mystream;
|
||||
|
||||
// BAD: write zipcode to file in cleartext
|
||||
mystream << "the zipcode is: " << theZipcode;
|
||||
|
||||
// BAD: write zipcode to file in cleartext
|
||||
(mystream << "the zipcode is: ").write(theZipcode, strlen(theZipcode));
|
||||
|
||||
// GOOD: encrypt first
|
||||
char *encrypted = encrypt(theZipcode);
|
||||
mystream << "the zipcode is: " << encrypted;
|
||||
(mystream << "the zipcode is: ").write(encrypted, strlen(encrypted));
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
///// Library routines /////
|
||||
|
||||
int scanf(const char *format, ...);
|
||||
int sscanf(const char *str, const char *format, ...);
|
||||
int fscanf(const char *str, const char *format, ...);
|
||||
|
||||
///// Test code /////
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
// BAD, do not use scanf without specifying a length first
|
||||
char buf1[10];
|
||||
scanf("%s", buf1);
|
||||
|
||||
// GOOD, length is specified
|
||||
char buf2[10];
|
||||
sscanf(buf2, "%9s");
|
||||
|
||||
// BAD, do not use scanf without specifying a length first
|
||||
char file[10];
|
||||
fscanf(file, "%s", buf2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
| MemoryUnsafeFunctionScan.cpp:14:5:14:9 | call to scanf | Dangerous use of one of the scanf functions |
|
||||
| MemoryUnsafeFunctionScan.cpp:22:5:22:10 | call to fscanf | Dangerous use of one of the scanf functions |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE/CWE-120/MemoryUnsafeFunctionScan.ql
|
||||
@@ -308,99 +308,230 @@
|
||||
| movableclass.cpp:65:13:65:18 | call to source | movableclass.cpp:65:13:65:20 | call to MyMovableClass | TAINT |
|
||||
| movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:8:65:9 | ref arg s3 | TAINT |
|
||||
| movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:11:65:11 | call to operator= | TAINT |
|
||||
| stl.cpp:67:12:67:17 | call to source | stl.cpp:71:7:71:7 | a | |
|
||||
| stl.cpp:68:16:68:20 | 123 | stl.cpp:68:16:68:21 | call to basic_string | TAINT |
|
||||
| stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:72:7:72:7 | b | |
|
||||
| stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:74:7:74:7 | b | |
|
||||
| stl.cpp:69:16:69:21 | call to source | stl.cpp:69:16:69:24 | call to basic_string | TAINT |
|
||||
| stl.cpp:69:16:69:24 | call to basic_string | stl.cpp:73:7:73:7 | c | |
|
||||
| stl.cpp:69:16:69:24 | call to basic_string | stl.cpp:75:7:75:7 | c | |
|
||||
| stl.cpp:74:7:74:7 | b | stl.cpp:74:9:74:13 | call to c_str | TAINT |
|
||||
| stl.cpp:75:7:75:7 | c | stl.cpp:75:9:75:13 | call to c_str | TAINT |
|
||||
| stl.cpp:80:20:80:22 | call to basic_stringstream | stl.cpp:83:2:83:4 | ss1 | |
|
||||
| stl.cpp:80:20:80:22 | call to basic_stringstream | stl.cpp:89:7:89:9 | ss1 | |
|
||||
| stl.cpp:80:20:80:22 | call to basic_stringstream | stl.cpp:94:7:94:9 | ss1 | |
|
||||
| stl.cpp:80:25:80:27 | call to basic_stringstream | stl.cpp:84:2:84:4 | ss2 | |
|
||||
| stl.cpp:80:25:80:27 | call to basic_stringstream | stl.cpp:90:7:90:9 | ss2 | |
|
||||
| stl.cpp:80:25:80:27 | call to basic_stringstream | stl.cpp:95:7:95:9 | ss2 | |
|
||||
| stl.cpp:80:30:80:32 | call to basic_stringstream | stl.cpp:85:2:85:4 | ss3 | |
|
||||
| stl.cpp:80:30:80:32 | call to basic_stringstream | stl.cpp:91:7:91:9 | ss3 | |
|
||||
| stl.cpp:80:30:80:32 | call to basic_stringstream | stl.cpp:96:7:96:9 | ss3 | |
|
||||
| stl.cpp:80:35:80:37 | call to basic_stringstream | stl.cpp:86:2:86:4 | ss4 | |
|
||||
| stl.cpp:80:35:80:37 | call to basic_stringstream | stl.cpp:92:7:92:9 | ss4 | |
|
||||
| stl.cpp:80:35:80:37 | call to basic_stringstream | stl.cpp:97:7:97:9 | ss4 | |
|
||||
| stl.cpp:80:40:80:42 | call to basic_stringstream | stl.cpp:87:2:87:4 | ss5 | |
|
||||
| stl.cpp:80:40:80:42 | call to basic_stringstream | stl.cpp:93:7:93:9 | ss5 | |
|
||||
| stl.cpp:80:40:80:42 | call to basic_stringstream | stl.cpp:98:7:98:9 | ss5 | |
|
||||
| stl.cpp:81:16:81:21 | call to source | stl.cpp:81:16:81:24 | call to basic_string | TAINT |
|
||||
| stl.cpp:81:16:81:24 | call to basic_string | stl.cpp:87:9:87:9 | t | |
|
||||
| stl.cpp:83:2:83:4 | ref arg ss1 | stl.cpp:89:7:89:9 | ss1 | |
|
||||
| stl.cpp:83:2:83:4 | ref arg ss1 | stl.cpp:94:7:94:9 | ss1 | |
|
||||
| stl.cpp:84:2:84:4 | ref arg ss2 | stl.cpp:90:7:90:9 | ss2 | |
|
||||
| stl.cpp:84:2:84:4 | ref arg ss2 | stl.cpp:95:7:95:9 | ss2 | |
|
||||
| stl.cpp:85:2:85:4 | ref arg ss3 | stl.cpp:91:7:91:9 | ss3 | |
|
||||
| stl.cpp:85:2:85:4 | ref arg ss3 | stl.cpp:96:7:96:9 | ss3 | |
|
||||
| stl.cpp:86:2:86:4 | ref arg ss4 | stl.cpp:92:7:92:9 | ss4 | |
|
||||
| stl.cpp:86:2:86:4 | ref arg ss4 | stl.cpp:97:7:97:9 | ss4 | |
|
||||
| stl.cpp:87:2:87:4 | ref arg ss5 | stl.cpp:93:7:93:9 | ss5 | |
|
||||
| stl.cpp:87:2:87:4 | ref arg ss5 | stl.cpp:98:7:98:9 | ss5 | |
|
||||
| stl.cpp:101:32:101:37 | source | stl.cpp:106:9:106:14 | source | |
|
||||
| stl.cpp:103:20:103:22 | call to basic_stringstream | stl.cpp:105:2:105:4 | ss1 | |
|
||||
| stl.cpp:103:20:103:22 | call to basic_stringstream | stl.cpp:108:7:108:9 | ss1 | |
|
||||
| stl.cpp:103:20:103:22 | call to basic_stringstream | stl.cpp:110:7:110:9 | ss1 | |
|
||||
| stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:106:2:106:4 | ss2 | |
|
||||
| stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:109:7:109:9 | ss2 | |
|
||||
| stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:111:7:111:9 | ss2 | |
|
||||
| stl.cpp:105:2:105:4 | ref arg ss1 | stl.cpp:108:7:108:9 | ss1 | |
|
||||
| stl.cpp:105:2:105:4 | ref arg ss1 | stl.cpp:110:7:110:9 | ss1 | |
|
||||
| stl.cpp:106:2:106:4 | ref arg ss2 | stl.cpp:109:7:109:9 | ss2 | |
|
||||
| stl.cpp:106:2:106:4 | ref arg ss2 | stl.cpp:111:7:111:9 | ss2 | |
|
||||
| stl.cpp:124:16:124:28 | call to basic_string | stl.cpp:125:7:125:11 | path1 | |
|
||||
| stl.cpp:124:17:124:26 | call to user_input | stl.cpp:124:16:124:28 | call to basic_string | TAINT |
|
||||
| stl.cpp:125:7:125:11 | path1 | stl.cpp:125:13:125:17 | call to c_str | TAINT |
|
||||
| stl.cpp:128:10:128:19 | call to user_input | stl.cpp:128:10:128:21 | call to basic_string | TAINT |
|
||||
| stl.cpp:128:10:128:21 | call to basic_string | stl.cpp:128:2:128:21 | ... = ... | |
|
||||
| stl.cpp:128:10:128:21 | call to basic_string | stl.cpp:129:7:129:11 | path2 | |
|
||||
| stl.cpp:129:7:129:11 | path2 | stl.cpp:129:13:129:17 | call to c_str | TAINT |
|
||||
| stl.cpp:131:15:131:24 | call to user_input | stl.cpp:131:15:131:27 | call to basic_string | TAINT |
|
||||
| stl.cpp:131:15:131:27 | call to basic_string | stl.cpp:132:7:132:11 | path3 | |
|
||||
| stl.cpp:132:7:132:11 | path3 | stl.cpp:132:13:132:17 | call to c_str | TAINT |
|
||||
| stl.cpp:137:19:137:24 | call to source | stl.cpp:140:17:140:18 | cs | |
|
||||
| stl.cpp:137:19:137:24 | call to source | stl.cpp:142:7:142:8 | cs | |
|
||||
| stl.cpp:140:17:140:18 | cs | stl.cpp:140:17:140:19 | call to basic_string | TAINT |
|
||||
| stl.cpp:140:17:140:19 | call to basic_string | stl.cpp:143:7:143:8 | ss | |
|
||||
| stl.cpp:148:19:148:24 | call to source | stl.cpp:151:17:151:18 | cs | |
|
||||
| stl.cpp:151:17:151:18 | cs | stl.cpp:151:17:151:19 | call to basic_string | TAINT |
|
||||
| stl.cpp:151:17:151:19 | call to basic_string | stl.cpp:154:7:154:8 | ss | |
|
||||
| stl.cpp:151:17:151:19 | call to basic_string | stl.cpp:157:7:157:8 | ss | |
|
||||
| stl.cpp:154:7:154:8 | ss | stl.cpp:154:10:154:14 | call to c_str | TAINT |
|
||||
| stl.cpp:154:10:154:14 | call to c_str | stl.cpp:154:2:154:16 | ... = ... | |
|
||||
| stl.cpp:154:10:154:14 | call to c_str | stl.cpp:156:7:156:8 | cs | |
|
||||
| stl.cpp:163:18:163:24 | hello | stl.cpp:163:18:163:25 | call to basic_string | TAINT |
|
||||
| stl.cpp:163:18:163:25 | call to basic_string | stl.cpp:168:8:168:9 | s1 | |
|
||||
| stl.cpp:164:19:164:26 | call to basic_string | stl.cpp:169:8:169:9 | s2 | |
|
||||
| stl.cpp:164:20:164:26 | hello | stl.cpp:164:19:164:26 | call to basic_string | TAINT |
|
||||
| stl.cpp:166:8:166:14 | call to basic_string | stl.cpp:166:3:166:14 | ... = ... | |
|
||||
| stl.cpp:166:8:166:14 | call to basic_string | stl.cpp:170:8:170:9 | s3 | |
|
||||
| stl.cpp:166:8:166:14 | hello | stl.cpp:166:8:166:14 | call to basic_string | TAINT |
|
||||
| stl.cpp:174:18:174:23 | call to source | stl.cpp:174:18:174:26 | call to basic_string | TAINT |
|
||||
| stl.cpp:174:18:174:26 | call to basic_string | stl.cpp:179:8:179:9 | s1 | |
|
||||
| stl.cpp:175:19:175:27 | call to basic_string | stl.cpp:180:8:180:9 | s2 | |
|
||||
| stl.cpp:175:20:175:25 | call to source | stl.cpp:175:19:175:27 | call to basic_string | TAINT |
|
||||
| stl.cpp:177:8:177:13 | call to source | stl.cpp:177:8:177:15 | call to basic_string | TAINT |
|
||||
| stl.cpp:177:8:177:15 | call to basic_string | stl.cpp:177:3:177:15 | ... = ... | |
|
||||
| stl.cpp:177:8:177:15 | call to basic_string | stl.cpp:181:8:181:9 | s3 | |
|
||||
| stl.cpp:185:15:185:16 | call to basic_string | stl.cpp:186:20:186:21 | s1 | |
|
||||
| stl.cpp:185:15:185:16 | call to basic_string | stl.cpp:188:8:188:9 | s1 | |
|
||||
| stl.cpp:185:15:185:16 | call to basic_string | stl.cpp:190:8:190:9 | s1 | |
|
||||
| stl.cpp:186:20:186:21 | s1 | stl.cpp:191:8:191:9 | s2 | |
|
||||
| stl.cpp:188:8:188:9 | s1 | stl.cpp:188:3:188:9 | ... = ... | |
|
||||
| stl.cpp:188:8:188:9 | s1 | stl.cpp:192:8:192:9 | s3 | |
|
||||
| stl.cpp:196:19:196:40 | call to basic_string | stl.cpp:200:8:200:9 | s1 | |
|
||||
| stl.cpp:196:32:196:37 | call to source | stl.cpp:196:19:196:40 | call to basic_string | TAINT |
|
||||
| stl.cpp:198:8:198:28 | call to basic_string | stl.cpp:198:3:198:28 | ... = ... | |
|
||||
| stl.cpp:198:8:198:28 | call to basic_string | stl.cpp:201:8:201:9 | s2 | |
|
||||
| stl.cpp:198:20:198:25 | call to source | stl.cpp:198:8:198:28 | call to basic_string | TAINT |
|
||||
| string.cpp:24:12:24:17 | call to source | string.cpp:28:7:28:7 | a | |
|
||||
| string.cpp:25:16:25:20 | 123 | string.cpp:25:16:25:21 | call to basic_string | TAINT |
|
||||
| string.cpp:25:16:25:21 | call to basic_string | string.cpp:29:7:29:7 | b | |
|
||||
| string.cpp:25:16:25:21 | call to basic_string | string.cpp:31:7:31:7 | b | |
|
||||
| string.cpp:26:16:26:21 | call to source | string.cpp:26:16:26:24 | call to basic_string | TAINT |
|
||||
| string.cpp:26:16:26:24 | call to basic_string | string.cpp:30:7:30:7 | c | |
|
||||
| string.cpp:26:16:26:24 | call to basic_string | string.cpp:32:7:32:7 | c | |
|
||||
| string.cpp:31:7:31:7 | b | string.cpp:31:9:31:13 | call to c_str | TAINT |
|
||||
| string.cpp:32:7:32:7 | c | string.cpp:32:9:32:13 | call to c_str | TAINT |
|
||||
| string.cpp:37:16:37:28 | call to basic_string | string.cpp:38:7:38:11 | path1 | |
|
||||
| string.cpp:37:17:37:26 | call to user_input | string.cpp:37:16:37:28 | call to basic_string | TAINT |
|
||||
| string.cpp:38:7:38:11 | path1 | string.cpp:38:13:38:17 | call to c_str | TAINT |
|
||||
| string.cpp:41:10:41:19 | call to user_input | string.cpp:41:10:41:21 | call to basic_string | TAINT |
|
||||
| string.cpp:41:10:41:21 | call to basic_string | string.cpp:41:2:41:21 | ... = ... | |
|
||||
| string.cpp:41:10:41:21 | call to basic_string | string.cpp:42:7:42:11 | path2 | |
|
||||
| string.cpp:42:7:42:11 | path2 | string.cpp:42:13:42:17 | call to c_str | TAINT |
|
||||
| string.cpp:44:15:44:24 | call to user_input | string.cpp:44:15:44:27 | call to basic_string | TAINT |
|
||||
| string.cpp:44:15:44:27 | call to basic_string | string.cpp:45:7:45:11 | path3 | |
|
||||
| string.cpp:45:7:45:11 | path3 | string.cpp:45:13:45:17 | call to c_str | TAINT |
|
||||
| string.cpp:50:19:50:24 | call to source | string.cpp:53:17:53:18 | cs | |
|
||||
| string.cpp:50:19:50:24 | call to source | string.cpp:55:7:55:8 | cs | |
|
||||
| string.cpp:53:17:53:18 | cs | string.cpp:53:17:53:19 | call to basic_string | TAINT |
|
||||
| string.cpp:53:17:53:19 | call to basic_string | string.cpp:56:7:56:8 | ss | |
|
||||
| string.cpp:61:19:61:24 | call to source | string.cpp:64:17:64:18 | cs | |
|
||||
| string.cpp:64:17:64:18 | cs | string.cpp:64:17:64:19 | call to basic_string | TAINT |
|
||||
| string.cpp:64:17:64:19 | call to basic_string | string.cpp:67:7:67:8 | ss | |
|
||||
| string.cpp:64:17:64:19 | call to basic_string | string.cpp:70:7:70:8 | ss | |
|
||||
| string.cpp:67:7:67:8 | ss | string.cpp:67:10:67:14 | call to c_str | TAINT |
|
||||
| string.cpp:67:10:67:14 | call to c_str | string.cpp:67:2:67:16 | ... = ... | |
|
||||
| string.cpp:67:10:67:14 | call to c_str | string.cpp:69:7:69:8 | cs | |
|
||||
| string.cpp:76:18:76:24 | hello | string.cpp:76:18:76:25 | call to basic_string | TAINT |
|
||||
| string.cpp:76:18:76:25 | call to basic_string | string.cpp:81:8:81:9 | s1 | |
|
||||
| string.cpp:77:19:77:26 | call to basic_string | string.cpp:82:8:82:9 | s2 | |
|
||||
| string.cpp:77:20:77:26 | hello | string.cpp:77:19:77:26 | call to basic_string | TAINT |
|
||||
| string.cpp:79:8:79:14 | call to basic_string | string.cpp:79:3:79:14 | ... = ... | |
|
||||
| string.cpp:79:8:79:14 | call to basic_string | string.cpp:83:8:83:9 | s3 | |
|
||||
| string.cpp:79:8:79:14 | hello | string.cpp:79:8:79:14 | call to basic_string | TAINT |
|
||||
| string.cpp:87:18:87:23 | call to source | string.cpp:87:18:87:26 | call to basic_string | TAINT |
|
||||
| string.cpp:87:18:87:26 | call to basic_string | string.cpp:92:8:92:9 | s1 | |
|
||||
| string.cpp:88:19:88:27 | call to basic_string | string.cpp:93:8:93:9 | s2 | |
|
||||
| string.cpp:88:20:88:25 | call to source | string.cpp:88:19:88:27 | call to basic_string | TAINT |
|
||||
| string.cpp:90:8:90:13 | call to source | string.cpp:90:8:90:15 | call to basic_string | TAINT |
|
||||
| string.cpp:90:8:90:15 | call to basic_string | string.cpp:90:3:90:15 | ... = ... | |
|
||||
| string.cpp:90:8:90:15 | call to basic_string | string.cpp:94:8:94:9 | s3 | |
|
||||
| string.cpp:98:15:98:16 | call to basic_string | string.cpp:99:20:99:21 | s1 | |
|
||||
| string.cpp:98:15:98:16 | call to basic_string | string.cpp:101:8:101:9 | s1 | |
|
||||
| string.cpp:98:15:98:16 | call to basic_string | string.cpp:103:8:103:9 | s1 | |
|
||||
| string.cpp:99:20:99:21 | s1 | string.cpp:104:8:104:9 | s2 | |
|
||||
| string.cpp:101:8:101:9 | s1 | string.cpp:101:3:101:9 | ... = ... | |
|
||||
| string.cpp:101:8:101:9 | s1 | string.cpp:105:8:105:9 | s3 | |
|
||||
| string.cpp:109:19:109:40 | call to basic_string | string.cpp:113:8:113:9 | s1 | |
|
||||
| string.cpp:109:32:109:37 | call to source | string.cpp:109:19:109:40 | call to basic_string | TAINT |
|
||||
| string.cpp:111:8:111:28 | call to basic_string | string.cpp:111:3:111:28 | ... = ... | |
|
||||
| string.cpp:111:8:111:28 | call to basic_string | string.cpp:114:8:114:9 | s2 | |
|
||||
| string.cpp:111:20:111:25 | call to source | string.cpp:111:8:111:28 | call to basic_string | TAINT |
|
||||
| string.cpp:119:16:119:21 | call to source | string.cpp:119:16:119:24 | call to basic_string | TAINT |
|
||||
| string.cpp:119:16:119:24 | call to basic_string | string.cpp:120:15:120:15 | s | |
|
||||
| string.cpp:119:16:119:24 | call to basic_string | string.cpp:124:33:124:33 | s | |
|
||||
| string.cpp:119:16:119:24 | call to basic_string | string.cpp:124:50:124:50 | s | |
|
||||
| string.cpp:119:16:119:24 | call to basic_string | string.cpp:128:16:128:16 | s | |
|
||||
| string.cpp:120:15:120:15 | call to begin | string.cpp:120:15:120:15 | (__begin) | |
|
||||
| string.cpp:120:15:120:15 | call to begin | string.cpp:120:15:120:15 | (__begin) | |
|
||||
| string.cpp:120:15:120:15 | call to begin | string.cpp:120:15:120:15 | (__begin) | |
|
||||
| string.cpp:120:15:120:15 | call to end | string.cpp:120:15:120:15 | (__end) | |
|
||||
| string.cpp:120:15:120:15 | call to operator* | string.cpp:121:8:121:8 | c | |
|
||||
| string.cpp:120:15:120:15 | ref arg (__begin) | string.cpp:120:15:120:15 | (__begin) | |
|
||||
| string.cpp:120:15:120:15 | ref arg (__begin) | string.cpp:120:15:120:15 | (__begin) | |
|
||||
| string.cpp:120:15:120:15 | ref arg (__begin) | string.cpp:120:15:120:15 | (__begin) | |
|
||||
| string.cpp:120:15:120:15 | ref arg (__range) | string.cpp:120:15:120:15 | (__range) | |
|
||||
| string.cpp:120:15:120:15 | s | string.cpp:120:15:120:15 | (__range) | |
|
||||
| string.cpp:120:15:120:15 | s | string.cpp:120:15:120:15 | (__range) | |
|
||||
| string.cpp:120:15:120:15 | s | string.cpp:120:15:120:15 | call to operator* | TAINT |
|
||||
| string.cpp:124:33:124:33 | ref arg s | string.cpp:124:50:124:50 | s | |
|
||||
| string.cpp:124:33:124:33 | ref arg s | string.cpp:128:16:128:16 | s | |
|
||||
| string.cpp:124:35:124:39 | call to begin | string.cpp:124:44:124:45 | it | |
|
||||
| string.cpp:124:35:124:39 | call to begin | string.cpp:124:61:124:62 | it | |
|
||||
| string.cpp:124:35:124:39 | call to begin | string.cpp:125:9:125:10 | it | |
|
||||
| string.cpp:124:50:124:50 | ref arg s | string.cpp:124:50:124:50 | s | |
|
||||
| string.cpp:124:50:124:50 | ref arg s | string.cpp:128:16:128:16 | s | |
|
||||
| string.cpp:124:61:124:62 | ref arg it | string.cpp:124:44:124:45 | it | |
|
||||
| string.cpp:124:61:124:62 | ref arg it | string.cpp:124:61:124:62 | it | |
|
||||
| string.cpp:124:61:124:62 | ref arg it | string.cpp:125:9:125:10 | it | |
|
||||
| string.cpp:128:16:128:16 | call to begin | string.cpp:128:16:128:16 | (__begin) | |
|
||||
| string.cpp:128:16:128:16 | call to begin | string.cpp:128:16:128:16 | (__begin) | |
|
||||
| string.cpp:128:16:128:16 | call to begin | string.cpp:128:16:128:16 | (__begin) | |
|
||||
| string.cpp:128:16:128:16 | call to end | string.cpp:128:16:128:16 | (__end) | |
|
||||
| string.cpp:128:16:128:16 | call to operator* | string.cpp:129:8:129:8 | c | |
|
||||
| string.cpp:128:16:128:16 | ref arg (__begin) | string.cpp:128:16:128:16 | (__begin) | |
|
||||
| string.cpp:128:16:128:16 | ref arg (__begin) | string.cpp:128:16:128:16 | (__begin) | |
|
||||
| string.cpp:128:16:128:16 | ref arg (__begin) | string.cpp:128:16:128:16 | (__begin) | |
|
||||
| string.cpp:128:16:128:16 | ref arg (__range) | string.cpp:128:16:128:16 | (__range) | |
|
||||
| string.cpp:128:16:128:16 | s | string.cpp:128:16:128:16 | (__range) | |
|
||||
| string.cpp:128:16:128:16 | s | string.cpp:128:16:128:16 | (__range) | |
|
||||
| string.cpp:128:16:128:16 | s | string.cpp:128:16:128:16 | call to operator* | TAINT |
|
||||
| string.cpp:132:28:132:33 | call to source | string.cpp:132:28:132:36 | call to basic_string | TAINT |
|
||||
| string.cpp:132:28:132:36 | call to basic_string | string.cpp:133:22:133:28 | const_s | |
|
||||
| string.cpp:133:22:133:22 | call to begin | string.cpp:133:22:133:22 | (__begin) | |
|
||||
| string.cpp:133:22:133:22 | call to begin | string.cpp:133:22:133:22 | (__begin) | |
|
||||
| string.cpp:133:22:133:22 | call to begin | string.cpp:133:22:133:22 | (__begin) | |
|
||||
| string.cpp:133:22:133:22 | call to end | string.cpp:133:22:133:22 | (__end) | |
|
||||
| string.cpp:133:22:133:22 | call to operator* | string.cpp:134:8:134:8 | c | |
|
||||
| string.cpp:133:22:133:22 | ref arg (__begin) | string.cpp:133:22:133:22 | (__begin) | |
|
||||
| string.cpp:133:22:133:22 | ref arg (__begin) | string.cpp:133:22:133:22 | (__begin) | |
|
||||
| string.cpp:133:22:133:22 | ref arg (__begin) | string.cpp:133:22:133:22 | (__begin) | |
|
||||
| string.cpp:133:22:133:28 | const_s | string.cpp:133:22:133:22 | (__range) | |
|
||||
| string.cpp:133:22:133:28 | const_s | string.cpp:133:22:133:22 | (__range) | |
|
||||
| string.cpp:133:22:133:28 | const_s | string.cpp:133:22:133:22 | call to operator* | TAINT |
|
||||
| string.cpp:140:18:140:24 | hello | string.cpp:140:18:140:25 | call to basic_string | TAINT |
|
||||
| string.cpp:140:18:140:25 | call to basic_string | string.cpp:143:8:143:9 | s1 | |
|
||||
| string.cpp:140:18:140:25 | call to basic_string | string.cpp:143:13:143:14 | s1 | |
|
||||
| string.cpp:140:18:140:25 | call to basic_string | string.cpp:144:8:144:9 | s1 | |
|
||||
| string.cpp:140:18:140:25 | call to basic_string | string.cpp:145:13:145:14 | s1 | |
|
||||
| string.cpp:140:18:140:25 | call to basic_string | string.cpp:148:8:148:9 | s1 | |
|
||||
| string.cpp:140:18:140:25 | call to basic_string | string.cpp:149:8:149:9 | s1 | |
|
||||
| string.cpp:141:18:141:23 | call to source | string.cpp:141:18:141:26 | call to basic_string | TAINT |
|
||||
| string.cpp:141:18:141:26 | call to basic_string | string.cpp:144:13:144:14 | s2 | |
|
||||
| string.cpp:141:18:141:26 | call to basic_string | string.cpp:145:8:145:9 | s2 | |
|
||||
| string.cpp:141:18:141:26 | call to basic_string | string.cpp:146:8:146:9 | s2 | |
|
||||
| string.cpp:141:18:141:26 | call to basic_string | string.cpp:146:13:146:14 | s2 | |
|
||||
| string.cpp:143:8:143:9 | s1 | string.cpp:143:11:143:11 | call to operator+ | TAINT |
|
||||
| string.cpp:143:13:143:14 | s1 | string.cpp:143:11:143:11 | call to operator+ | TAINT |
|
||||
| string.cpp:144:8:144:9 | s1 | string.cpp:144:11:144:11 | call to operator+ | TAINT |
|
||||
| string.cpp:144:13:144:14 | s2 | string.cpp:144:11:144:11 | call to operator+ | TAINT |
|
||||
| string.cpp:145:8:145:9 | s2 | string.cpp:145:11:145:11 | call to operator+ | TAINT |
|
||||
| string.cpp:145:13:145:14 | s1 | string.cpp:145:11:145:11 | call to operator+ | TAINT |
|
||||
| string.cpp:146:8:146:9 | s2 | string.cpp:146:11:146:11 | call to operator+ | TAINT |
|
||||
| string.cpp:146:13:146:14 | s2 | string.cpp:146:11:146:11 | call to operator+ | TAINT |
|
||||
| string.cpp:148:8:148:9 | s1 | string.cpp:148:11:148:11 | call to operator+ | TAINT |
|
||||
| string.cpp:148:13:148:20 | world | string.cpp:148:11:148:11 | call to operator+ | TAINT |
|
||||
| string.cpp:149:8:149:9 | s1 | string.cpp:149:11:149:11 | call to operator+ | TAINT |
|
||||
| string.cpp:149:13:149:18 | call to source | string.cpp:149:11:149:11 | call to operator+ | TAINT |
|
||||
| string.cpp:153:18:153:22 | abc | string.cpp:153:18:153:23 | call to basic_string | TAINT |
|
||||
| string.cpp:153:18:153:23 | call to basic_string | string.cpp:157:8:157:9 | s3 | |
|
||||
| string.cpp:153:18:153:23 | call to basic_string | string.cpp:160:8:160:9 | s3 | |
|
||||
| string.cpp:153:18:153:23 | call to basic_string | string.cpp:164:8:164:9 | s3 | |
|
||||
| string.cpp:153:18:153:23 | call to basic_string | string.cpp:169:8:169:9 | s3 | |
|
||||
| string.cpp:153:18:153:23 | call to basic_string | string.cpp:173:8:173:9 | s3 | |
|
||||
| string.cpp:154:18:154:23 | call to source | string.cpp:154:18:154:26 | call to basic_string | TAINT |
|
||||
| string.cpp:154:18:154:26 | call to basic_string | string.cpp:157:13:157:14 | s4 | |
|
||||
| string.cpp:154:18:154:26 | call to basic_string | string.cpp:161:9:161:10 | s4 | |
|
||||
| string.cpp:154:18:154:26 | call to basic_string | string.cpp:170:13:170:14 | s4 | |
|
||||
| string.cpp:157:8:157:9 | s3 | string.cpp:157:11:157:11 | call to operator+ | TAINT |
|
||||
| string.cpp:157:11:157:11 | call to operator+ | string.cpp:157:3:157:14 | ... = ... | |
|
||||
| string.cpp:157:11:157:11 | call to operator+ | string.cpp:158:8:158:9 | s5 | |
|
||||
| string.cpp:157:13:157:14 | s4 | string.cpp:157:11:157:11 | call to operator+ | TAINT |
|
||||
| string.cpp:160:8:160:9 | s3 | string.cpp:160:3:160:9 | ... = ... | |
|
||||
| string.cpp:160:8:160:9 | s3 | string.cpp:161:3:161:4 | s6 | |
|
||||
| string.cpp:160:8:160:9 | s3 | string.cpp:162:8:162:9 | s6 | |
|
||||
| string.cpp:161:3:161:4 | ref arg s6 | string.cpp:162:8:162:9 | s6 | |
|
||||
| string.cpp:161:9:161:10 | s4 | string.cpp:161:3:161:4 | ref arg s6 | TAINT |
|
||||
| string.cpp:161:9:161:10 | s4 | string.cpp:161:6:161:6 | call to operator+= | TAINT |
|
||||
| string.cpp:164:8:164:9 | s3 | string.cpp:164:3:164:9 | ... = ... | |
|
||||
| string.cpp:164:8:164:9 | s3 | string.cpp:165:3:165:4 | s7 | |
|
||||
| string.cpp:164:8:164:9 | s3 | string.cpp:166:3:166:4 | s7 | |
|
||||
| string.cpp:164:8:164:9 | s3 | string.cpp:167:8:167:9 | s7 | |
|
||||
| string.cpp:165:3:165:4 | ref arg s7 | string.cpp:166:3:166:4 | s7 | |
|
||||
| string.cpp:165:3:165:4 | ref arg s7 | string.cpp:167:8:167:9 | s7 | |
|
||||
| string.cpp:165:9:165:14 | call to source | string.cpp:165:3:165:4 | ref arg s7 | TAINT |
|
||||
| string.cpp:165:9:165:14 | call to source | string.cpp:165:6:165:6 | call to operator+= | TAINT |
|
||||
| string.cpp:166:3:166:4 | ref arg s7 | string.cpp:167:8:167:9 | s7 | |
|
||||
| string.cpp:166:9:166:11 | | string.cpp:166:3:166:4 | ref arg s7 | TAINT |
|
||||
| string.cpp:166:9:166:11 | | string.cpp:166:6:166:6 | call to operator+= | TAINT |
|
||||
| string.cpp:169:8:169:9 | s3 | string.cpp:169:3:169:9 | ... = ... | |
|
||||
| string.cpp:169:8:169:9 | s3 | string.cpp:170:3:170:4 | s8 | |
|
||||
| string.cpp:169:8:169:9 | s3 | string.cpp:171:8:171:9 | s8 | |
|
||||
| string.cpp:170:3:170:4 | ref arg s8 | string.cpp:171:8:171:9 | s8 | |
|
||||
| string.cpp:170:13:170:14 | s4 | string.cpp:170:3:170:4 | ref arg s8 | TAINT |
|
||||
| string.cpp:170:13:170:14 | s4 | string.cpp:170:6:170:11 | call to append | TAINT |
|
||||
| string.cpp:173:8:173:9 | s3 | string.cpp:173:3:173:9 | ... = ... | |
|
||||
| string.cpp:173:8:173:9 | s3 | string.cpp:174:3:174:4 | s9 | |
|
||||
| string.cpp:173:8:173:9 | s3 | string.cpp:175:3:175:4 | s9 | |
|
||||
| string.cpp:173:8:173:9 | s3 | string.cpp:176:8:176:9 | s9 | |
|
||||
| string.cpp:174:3:174:4 | ref arg s9 | string.cpp:175:3:175:4 | s9 | |
|
||||
| string.cpp:174:3:174:4 | ref arg s9 | string.cpp:176:8:176:9 | s9 | |
|
||||
| string.cpp:174:13:174:18 | call to source | string.cpp:174:3:174:4 | ref arg s9 | TAINT |
|
||||
| string.cpp:174:13:174:18 | call to source | string.cpp:174:6:174:11 | call to append | TAINT |
|
||||
| string.cpp:175:3:175:4 | ref arg s9 | string.cpp:176:8:176:9 | s9 | |
|
||||
| string.cpp:175:13:175:15 | | string.cpp:175:3:175:4 | ref arg s9 | TAINT |
|
||||
| string.cpp:175:13:175:15 | | string.cpp:175:6:175:11 | call to append | TAINT |
|
||||
| string.cpp:180:19:180:23 | abc | string.cpp:180:19:180:24 | call to basic_string | TAINT |
|
||||
| string.cpp:180:19:180:24 | call to basic_string | string.cpp:183:3:183:5 | s10 | |
|
||||
| string.cpp:180:19:180:24 | call to basic_string | string.cpp:184:8:184:10 | s10 | |
|
||||
| string.cpp:181:12:181:26 | call to source | string.cpp:183:17:183:17 | c | |
|
||||
| string.cpp:183:3:183:5 | ref arg s10 | string.cpp:184:8:184:10 | s10 | |
|
||||
| string.cpp:183:17:183:17 | c | string.cpp:183:3:183:5 | ref arg s10 | TAINT |
|
||||
| string.cpp:183:17:183:17 | c | string.cpp:183:7:183:12 | call to append | TAINT |
|
||||
| stringstream.cpp:13:20:13:22 | call to basic_stringstream | stringstream.cpp:16:2:16:4 | ss1 | |
|
||||
| stringstream.cpp:13:20:13:22 | call to basic_stringstream | stringstream.cpp:22:7:22:9 | ss1 | |
|
||||
| stringstream.cpp:13:20:13:22 | call to basic_stringstream | stringstream.cpp:27:7:27:9 | ss1 | |
|
||||
| stringstream.cpp:13:25:13:27 | call to basic_stringstream | stringstream.cpp:17:2:17:4 | ss2 | |
|
||||
| stringstream.cpp:13:25:13:27 | call to basic_stringstream | stringstream.cpp:23:7:23:9 | ss2 | |
|
||||
| stringstream.cpp:13:25:13:27 | call to basic_stringstream | stringstream.cpp:28:7:28:9 | ss2 | |
|
||||
| stringstream.cpp:13:30:13:32 | call to basic_stringstream | stringstream.cpp:18:2:18:4 | ss3 | |
|
||||
| stringstream.cpp:13:30:13:32 | call to basic_stringstream | stringstream.cpp:24:7:24:9 | ss3 | |
|
||||
| stringstream.cpp:13:30:13:32 | call to basic_stringstream | stringstream.cpp:29:7:29:9 | ss3 | |
|
||||
| stringstream.cpp:13:35:13:37 | call to basic_stringstream | stringstream.cpp:19:2:19:4 | ss4 | |
|
||||
| stringstream.cpp:13:35:13:37 | call to basic_stringstream | stringstream.cpp:25:7:25:9 | ss4 | |
|
||||
| stringstream.cpp:13:35:13:37 | call to basic_stringstream | stringstream.cpp:30:7:30:9 | ss4 | |
|
||||
| stringstream.cpp:13:40:13:42 | call to basic_stringstream | stringstream.cpp:20:2:20:4 | ss5 | |
|
||||
| stringstream.cpp:13:40:13:42 | call to basic_stringstream | stringstream.cpp:26:7:26:9 | ss5 | |
|
||||
| stringstream.cpp:13:40:13:42 | call to basic_stringstream | stringstream.cpp:31:7:31:9 | ss5 | |
|
||||
| stringstream.cpp:14:16:14:21 | call to source | stringstream.cpp:14:16:14:24 | call to basic_string | TAINT |
|
||||
| stringstream.cpp:14:16:14:24 | call to basic_string | stringstream.cpp:20:9:20:9 | t | |
|
||||
| stringstream.cpp:16:2:16:4 | ref arg ss1 | stringstream.cpp:22:7:22:9 | ss1 | |
|
||||
| stringstream.cpp:16:2:16:4 | ref arg ss1 | stringstream.cpp:27:7:27:9 | ss1 | |
|
||||
| stringstream.cpp:17:2:17:4 | ref arg ss2 | stringstream.cpp:23:7:23:9 | ss2 | |
|
||||
| stringstream.cpp:17:2:17:4 | ref arg ss2 | stringstream.cpp:28:7:28:9 | ss2 | |
|
||||
| stringstream.cpp:18:2:18:4 | ref arg ss3 | stringstream.cpp:24:7:24:9 | ss3 | |
|
||||
| stringstream.cpp:18:2:18:4 | ref arg ss3 | stringstream.cpp:29:7:29:9 | ss3 | |
|
||||
| stringstream.cpp:19:2:19:4 | ref arg ss4 | stringstream.cpp:25:7:25:9 | ss4 | |
|
||||
| stringstream.cpp:19:2:19:4 | ref arg ss4 | stringstream.cpp:30:7:30:9 | ss4 | |
|
||||
| stringstream.cpp:20:2:20:4 | ref arg ss5 | stringstream.cpp:26:7:26:9 | ss5 | |
|
||||
| stringstream.cpp:20:2:20:4 | ref arg ss5 | stringstream.cpp:31:7:31:9 | ss5 | |
|
||||
| stringstream.cpp:34:32:34:37 | source | stringstream.cpp:39:9:39:14 | source | |
|
||||
| stringstream.cpp:36:20:36:22 | call to basic_stringstream | stringstream.cpp:38:2:38:4 | ss1 | |
|
||||
| stringstream.cpp:36:20:36:22 | call to basic_stringstream | stringstream.cpp:41:7:41:9 | ss1 | |
|
||||
| stringstream.cpp:36:20:36:22 | call to basic_stringstream | stringstream.cpp:43:7:43:9 | ss1 | |
|
||||
| stringstream.cpp:36:25:36:27 | call to basic_stringstream | stringstream.cpp:39:2:39:4 | ss2 | |
|
||||
| stringstream.cpp:36:25:36:27 | call to basic_stringstream | stringstream.cpp:42:7:42:9 | ss2 | |
|
||||
| stringstream.cpp:36:25:36:27 | call to basic_stringstream | stringstream.cpp:44:7:44:9 | ss2 | |
|
||||
| stringstream.cpp:38:2:38:4 | ref arg ss1 | stringstream.cpp:41:7:41:9 | ss1 | |
|
||||
| stringstream.cpp:38:2:38:4 | ref arg ss1 | stringstream.cpp:43:7:43:9 | ss1 | |
|
||||
| stringstream.cpp:39:2:39:4 | ref arg ss2 | stringstream.cpp:42:7:42:9 | ss2 | |
|
||||
| stringstream.cpp:39:2:39:4 | ref arg ss2 | stringstream.cpp:44:7:44:9 | ss2 | |
|
||||
| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
|
||||
| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
|
||||
| structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | |
|
||||
@@ -1199,3 +1330,57 @@
|
||||
| taint.cpp:483:18:483:19 | ref arg & ... | taint.cpp:483:19:483:19 | n [inner post update] | |
|
||||
| taint.cpp:483:19:483:19 | n | taint.cpp:483:18:483:19 | & ... | |
|
||||
| taint.cpp:483:28:483:34 | source1 | taint.cpp:483:11:483:15 | ref arg & ... | TAINT |
|
||||
| vector.cpp:8:43:8:49 | source1 | vector.cpp:12:21:12:27 | source1 | |
|
||||
| vector.cpp:8:43:8:49 | source1 | vector.cpp:26:33:26:39 | source1 | |
|
||||
| vector.cpp:12:21:12:27 | source1 | vector.cpp:12:21:12:28 | call to vector | TAINT |
|
||||
| vector.cpp:12:21:12:28 | call to vector | vector.cpp:14:14:14:14 | v | |
|
||||
| vector.cpp:12:21:12:28 | call to vector | vector.cpp:18:38:18:38 | v | |
|
||||
| vector.cpp:12:21:12:28 | call to vector | vector.cpp:18:55:18:55 | v | |
|
||||
| vector.cpp:12:21:12:28 | call to vector | vector.cpp:22:15:22:15 | v | |
|
||||
| vector.cpp:14:14:14:14 | call to begin | vector.cpp:14:14:14:14 | (__begin) | |
|
||||
| vector.cpp:14:14:14:14 | call to begin | vector.cpp:14:14:14:14 | (__begin) | |
|
||||
| vector.cpp:14:14:14:14 | call to begin | vector.cpp:14:14:14:14 | (__begin) | |
|
||||
| vector.cpp:14:14:14:14 | call to end | vector.cpp:14:14:14:14 | (__end) | |
|
||||
| vector.cpp:14:14:14:14 | call to operator* | vector.cpp:15:8:15:8 | x | |
|
||||
| vector.cpp:14:14:14:14 | ref arg (__begin) | vector.cpp:14:14:14:14 | (__begin) | |
|
||||
| vector.cpp:14:14:14:14 | ref arg (__begin) | vector.cpp:14:14:14:14 | (__begin) | |
|
||||
| vector.cpp:14:14:14:14 | ref arg (__begin) | vector.cpp:14:14:14:14 | (__begin) | |
|
||||
| vector.cpp:14:14:14:14 | ref arg (__range) | vector.cpp:14:14:14:14 | (__range) | |
|
||||
| vector.cpp:14:14:14:14 | v | vector.cpp:14:14:14:14 | (__range) | |
|
||||
| vector.cpp:14:14:14:14 | v | vector.cpp:14:14:14:14 | (__range) | |
|
||||
| vector.cpp:14:14:14:14 | v | vector.cpp:14:14:14:14 | call to operator* | TAINT |
|
||||
| vector.cpp:18:38:18:38 | ref arg v | vector.cpp:18:55:18:55 | v | |
|
||||
| vector.cpp:18:38:18:38 | ref arg v | vector.cpp:22:15:22:15 | v | |
|
||||
| vector.cpp:18:40:18:44 | call to begin | vector.cpp:18:49:18:50 | it | |
|
||||
| vector.cpp:18:40:18:44 | call to begin | vector.cpp:18:66:18:67 | it | |
|
||||
| vector.cpp:18:40:18:44 | call to begin | vector.cpp:19:9:19:10 | it | |
|
||||
| vector.cpp:18:55:18:55 | ref arg v | vector.cpp:18:55:18:55 | v | |
|
||||
| vector.cpp:18:55:18:55 | ref arg v | vector.cpp:22:15:22:15 | v | |
|
||||
| vector.cpp:18:66:18:67 | ref arg it | vector.cpp:18:49:18:50 | it | |
|
||||
| vector.cpp:18:66:18:67 | ref arg it | vector.cpp:18:66:18:67 | it | |
|
||||
| vector.cpp:18:66:18:67 | ref arg it | vector.cpp:19:9:19:10 | it | |
|
||||
| vector.cpp:22:15:22:15 | call to begin | vector.cpp:22:15:22:15 | (__begin) | |
|
||||
| vector.cpp:22:15:22:15 | call to begin | vector.cpp:22:15:22:15 | (__begin) | |
|
||||
| vector.cpp:22:15:22:15 | call to begin | vector.cpp:22:15:22:15 | (__begin) | |
|
||||
| vector.cpp:22:15:22:15 | call to end | vector.cpp:22:15:22:15 | (__end) | |
|
||||
| vector.cpp:22:15:22:15 | call to operator* | vector.cpp:23:8:23:8 | x | |
|
||||
| vector.cpp:22:15:22:15 | ref arg (__begin) | vector.cpp:22:15:22:15 | (__begin) | |
|
||||
| vector.cpp:22:15:22:15 | ref arg (__begin) | vector.cpp:22:15:22:15 | (__begin) | |
|
||||
| vector.cpp:22:15:22:15 | ref arg (__begin) | vector.cpp:22:15:22:15 | (__begin) | |
|
||||
| vector.cpp:22:15:22:15 | ref arg (__range) | vector.cpp:22:15:22:15 | (__range) | |
|
||||
| vector.cpp:22:15:22:15 | v | vector.cpp:22:15:22:15 | (__range) | |
|
||||
| vector.cpp:22:15:22:15 | v | vector.cpp:22:15:22:15 | (__range) | |
|
||||
| vector.cpp:22:15:22:15 | v | vector.cpp:22:15:22:15 | call to operator* | TAINT |
|
||||
| vector.cpp:26:33:26:39 | source1 | vector.cpp:26:33:26:40 | call to vector | TAINT |
|
||||
| vector.cpp:26:33:26:40 | call to vector | vector.cpp:27:21:27:27 | const_v | |
|
||||
| vector.cpp:27:21:27:21 | call to begin | vector.cpp:27:21:27:21 | (__begin) | |
|
||||
| vector.cpp:27:21:27:21 | call to begin | vector.cpp:27:21:27:21 | (__begin) | |
|
||||
| vector.cpp:27:21:27:21 | call to begin | vector.cpp:27:21:27:21 | (__begin) | |
|
||||
| vector.cpp:27:21:27:21 | call to end | vector.cpp:27:21:27:21 | (__end) | |
|
||||
| vector.cpp:27:21:27:21 | call to operator* | vector.cpp:28:8:28:8 | x | |
|
||||
| vector.cpp:27:21:27:21 | ref arg (__begin) | vector.cpp:27:21:27:21 | (__begin) | |
|
||||
| vector.cpp:27:21:27:21 | ref arg (__begin) | vector.cpp:27:21:27:21 | (__begin) | |
|
||||
| vector.cpp:27:21:27:21 | ref arg (__begin) | vector.cpp:27:21:27:21 | (__begin) | |
|
||||
| vector.cpp:27:21:27:27 | const_v | vector.cpp:27:21:27:21 | (__range) | |
|
||||
| vector.cpp:27:21:27:27 | const_v | vector.cpp:27:21:27:21 | (__range) | |
|
||||
| vector.cpp:27:21:27:27 | const_v | vector.cpp:27:21:27:21 | call to operator* | TAINT |
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
|
||||
typedef unsigned long size_t;
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<class charT> struct char_traits;
|
||||
|
||||
typedef size_t streamsize;
|
||||
|
||||
template <class T> class allocator {
|
||||
public:
|
||||
allocator() throw();
|
||||
};
|
||||
|
||||
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
|
||||
class basic_string {
|
||||
public:
|
||||
explicit basic_string(const Allocator& a = Allocator());
|
||||
basic_string(const charT* s, const Allocator& a = Allocator());
|
||||
|
||||
const charT* c_str() const;
|
||||
};
|
||||
|
||||
typedef basic_string<char> string;
|
||||
|
||||
template <class charT, class traits = char_traits<charT> >
|
||||
class basic_istream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
|
||||
public:
|
||||
basic_istream<charT,traits>& operator>>(int& n);
|
||||
};
|
||||
|
||||
template <class charT, class traits = char_traits<charT> >
|
||||
class basic_ostream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
|
||||
public:
|
||||
typedef charT char_type;
|
||||
basic_ostream<charT,traits>& write(const char_type* s, streamsize n);
|
||||
|
||||
basic_ostream<charT, traits>& operator<<(int n);
|
||||
};
|
||||
|
||||
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
|
||||
template<class charT, class traits, class Allocator> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const basic_string<charT, traits, Allocator>& str);
|
||||
|
||||
template<class charT, class traits = char_traits<charT>>
|
||||
class basic_iostream : public basic_istream<charT, traits>, public basic_ostream<charT, traits> {
|
||||
public:
|
||||
};
|
||||
|
||||
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>>
|
||||
class basic_stringstream : public basic_iostream<charT, traits> {
|
||||
public:
|
||||
explicit basic_stringstream(/*ios_base::openmode which = ios_base::out|ios_base::in - not needed for this test*/);
|
||||
|
||||
basic_string<charT, traits, Allocator> str() const;
|
||||
};
|
||||
|
||||
using stringstream = basic_stringstream<char>;
|
||||
}
|
||||
|
||||
char *source();
|
||||
void sink(const char *s) {};
|
||||
void sink(const std::string &s) {};
|
||||
void sink(const std::stringstream &s) {};
|
||||
|
||||
void test_string()
|
||||
{
|
||||
char *a = source();
|
||||
std::string b("123");
|
||||
std::string c(source());
|
||||
|
||||
sink(a); // tainted
|
||||
sink(b);
|
||||
sink(c); // tainted
|
||||
sink(b.c_str());
|
||||
sink(c.c_str()); // tainted
|
||||
}
|
||||
|
||||
void test_stringstream()
|
||||
{
|
||||
std::stringstream ss1, ss2, ss3, ss4, ss5;
|
||||
std::string t(source());
|
||||
|
||||
ss1 << "1234";
|
||||
ss2 << source();
|
||||
ss3 << "123" << source();
|
||||
ss4 << source() << "456";
|
||||
ss5 << t;
|
||||
|
||||
sink(ss1);
|
||||
sink(ss2); // tainted [NOT DETECTED]
|
||||
sink(ss3); // tainted [NOT DETECTED]
|
||||
sink(ss4); // tainted [NOT DETECTED]
|
||||
sink(ss5); // tainted [NOT DETECTED]
|
||||
sink(ss1.str());
|
||||
sink(ss2.str()); // tainted [NOT DETECTED]
|
||||
sink(ss3.str()); // tainted [NOT DETECTED]
|
||||
sink(ss4.str()); // tainted [NOT DETECTED]
|
||||
sink(ss5.str()); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test_stringstream_int(int source)
|
||||
{
|
||||
std::stringstream ss1, ss2;
|
||||
|
||||
ss1 << 1234;
|
||||
ss2 << source;
|
||||
|
||||
sink(ss1);
|
||||
sink(ss2); // tainted [NOT DETECTED]
|
||||
sink(ss1.str());
|
||||
sink(ss2.str()); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
char *user_input() {
|
||||
return source();
|
||||
}
|
||||
|
||||
void sink(const char *filename, const char *mode);
|
||||
|
||||
void test_strings2()
|
||||
{
|
||||
string path1 = user_input();
|
||||
sink(path1.c_str(), "r"); // tainted
|
||||
|
||||
string path2;
|
||||
path2 = user_input();
|
||||
sink(path2.c_str(), "r"); // tainted
|
||||
|
||||
string path3(user_input());
|
||||
sink(path3.c_str(), "r"); // tainted
|
||||
}
|
||||
|
||||
void test_string3()
|
||||
{
|
||||
const char *cs = source();
|
||||
|
||||
// convert char * -> std::string
|
||||
std::string ss(cs);
|
||||
|
||||
sink(cs); // tainted
|
||||
sink(ss); // tainted
|
||||
}
|
||||
|
||||
void test_string4()
|
||||
{
|
||||
const char *cs = source();
|
||||
|
||||
// convert char * -> std::string
|
||||
std::string ss(cs);
|
||||
|
||||
// convert back std::string -> char *
|
||||
cs = ss.c_str();
|
||||
|
||||
sink(cs); // tainted
|
||||
sink(ss); // tainted
|
||||
}
|
||||
|
||||
void test_string_constructors_assignments()
|
||||
{
|
||||
{
|
||||
std::string s1("hello");
|
||||
std::string s2 = "hello";
|
||||
std::string s3;
|
||||
s3 = "hello";
|
||||
|
||||
sink(s1);
|
||||
sink(s2);
|
||||
sink(s3);
|
||||
}
|
||||
|
||||
{
|
||||
std::string s1(source());
|
||||
std::string s2 = source();
|
||||
std::string s3;
|
||||
s3 = source();
|
||||
|
||||
sink(s1); // tainted
|
||||
sink(s2); // tainted
|
||||
sink(s3); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::string s1;
|
||||
std::string s2 = s1;
|
||||
std::string s3;
|
||||
s3 = s1;
|
||||
|
||||
sink(s1);
|
||||
sink(s2);
|
||||
sink(s3);
|
||||
}
|
||||
|
||||
{
|
||||
std::string s1 = std::string(source());
|
||||
std::string s2;
|
||||
s2 = std::string(source());
|
||||
|
||||
sink(s1); // tainted
|
||||
sink(s2); // tainted
|
||||
}
|
||||
}
|
||||
|
||||
126
cpp/ql/test/library-tests/dataflow/taint-tests/stl.h
Normal file
126
cpp/ql/test/library-tests/dataflow/taint-tests/stl.h
Normal file
@@ -0,0 +1,126 @@
|
||||
|
||||
typedef unsigned long size_t;
|
||||
|
||||
// --- string ---
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<class charT> struct char_traits;
|
||||
|
||||
typedef size_t streamsize;
|
||||
|
||||
struct ptrdiff_t;
|
||||
|
||||
template <class iterator_category,
|
||||
class value_type,
|
||||
class difference_type = ptrdiff_t,
|
||||
class pointer_type = value_type*,
|
||||
class reference_type = value_type&>
|
||||
struct iterator {
|
||||
iterator &operator++();
|
||||
iterator operator++(int);
|
||||
bool operator==(iterator other) const;
|
||||
bool operator!=(iterator other) const;
|
||||
reference_type operator*() const;
|
||||
};
|
||||
|
||||
struct input_iterator_tag {};
|
||||
struct forward_iterator_tag : public input_iterator_tag {};
|
||||
struct bidirectional_iterator_tag : public forward_iterator_tag {};
|
||||
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
|
||||
|
||||
template <class T> class allocator {
|
||||
public:
|
||||
allocator() throw();
|
||||
typedef size_t size_type;
|
||||
};
|
||||
|
||||
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
|
||||
class basic_string {
|
||||
public:
|
||||
typedef typename Allocator::size_type size_type;
|
||||
|
||||
explicit basic_string(const Allocator& a = Allocator());
|
||||
basic_string(const charT* s, const Allocator& a = Allocator());
|
||||
|
||||
const charT* c_str() const;
|
||||
|
||||
typedef std::iterator<random_access_iterator_tag, charT> iterator;
|
||||
typedef std::iterator<random_access_iterator_tag, const charT> const_iterator;
|
||||
|
||||
iterator begin();
|
||||
iterator end();
|
||||
const_iterator begin() const;
|
||||
const_iterator end() const;
|
||||
const_iterator cbegin() const;
|
||||
const_iterator cend() const;
|
||||
|
||||
template<class T> basic_string& operator+=(const T& t);
|
||||
basic_string& operator+=(const charT* s);
|
||||
basic_string& append(const basic_string& str);
|
||||
basic_string& append(const charT* s);
|
||||
basic_string& append(size_type n, charT c);
|
||||
};
|
||||
|
||||
template<class charT, class traits, class Allocator> basic_string<charT, traits, Allocator> operator+(const basic_string<charT, traits, Allocator>& lhs, const basic_string<charT, traits, Allocator>& rhs);
|
||||
template<class charT, class traits, class Allocator> basic_string<charT, traits, Allocator> operator+(const basic_string<charT, traits, Allocator>& lhs, const charT* rhs);
|
||||
|
||||
typedef basic_string<char> string;
|
||||
|
||||
template <class charT, class traits = char_traits<charT> >
|
||||
class basic_istream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
|
||||
public:
|
||||
basic_istream<charT,traits>& operator>>(int& n);
|
||||
};
|
||||
|
||||
template <class charT, class traits = char_traits<charT> >
|
||||
class basic_ostream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
|
||||
public:
|
||||
typedef charT char_type;
|
||||
basic_ostream<charT,traits>& write(const char_type* s, streamsize n);
|
||||
|
||||
basic_ostream<charT, traits>& operator<<(int n);
|
||||
};
|
||||
|
||||
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
|
||||
template<class charT, class traits, class Allocator> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const basic_string<charT, traits, Allocator>& str);
|
||||
|
||||
template<class charT, class traits = char_traits<charT>>
|
||||
class basic_iostream : public basic_istream<charT, traits>, public basic_ostream<charT, traits> {
|
||||
public:
|
||||
};
|
||||
|
||||
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>>
|
||||
class basic_stringstream : public basic_iostream<charT, traits> {
|
||||
public:
|
||||
explicit basic_stringstream(/*ios_base::openmode which = ios_base::out|ios_base::in - not needed for this test*/);
|
||||
|
||||
basic_string<charT, traits, Allocator> str() const;
|
||||
};
|
||||
|
||||
using stringstream = basic_stringstream<char>;
|
||||
}
|
||||
|
||||
// --- vector ---
|
||||
|
||||
namespace std {
|
||||
template <class T>
|
||||
class vector {
|
||||
private:
|
||||
void *data_;
|
||||
public:
|
||||
vector(int size);
|
||||
|
||||
T& operator[](int idx);
|
||||
const T& operator[](int idx) const;
|
||||
|
||||
typedef std::iterator<random_access_iterator_tag, T> iterator;
|
||||
typedef std::iterator<random_access_iterator_tag, const T> const_iterator;
|
||||
|
||||
iterator begin() noexcept;
|
||||
iterator end() noexcept;
|
||||
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
};
|
||||
}
|
||||
186
cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp
Normal file
186
cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
|
||||
#include "stl.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
char *source();
|
||||
|
||||
namespace ns_char
|
||||
{
|
||||
char source();
|
||||
}
|
||||
|
||||
char *user_input() {
|
||||
return source();
|
||||
}
|
||||
|
||||
void sink(const char *s) {};
|
||||
void sink(const std::string &s) {};
|
||||
void sink(const char *filename, const char *mode);
|
||||
void sink(char) {}
|
||||
|
||||
void test_string()
|
||||
{
|
||||
char *a = source();
|
||||
std::string b("123");
|
||||
std::string c(source());
|
||||
|
||||
sink(a); // tainted
|
||||
sink(b);
|
||||
sink(c); // tainted
|
||||
sink(b.c_str());
|
||||
sink(c.c_str()); // tainted
|
||||
}
|
||||
|
||||
void test_strings2()
|
||||
{
|
||||
string path1 = user_input();
|
||||
sink(path1.c_str(), "r"); // tainted
|
||||
|
||||
string path2;
|
||||
path2 = user_input();
|
||||
sink(path2.c_str(), "r"); // tainted
|
||||
|
||||
string path3(user_input());
|
||||
sink(path3.c_str(), "r"); // tainted
|
||||
}
|
||||
|
||||
void test_string3()
|
||||
{
|
||||
const char *cs = source();
|
||||
|
||||
// convert char * -> std::string
|
||||
std::string ss(cs);
|
||||
|
||||
sink(cs); // tainted
|
||||
sink(ss); // tainted
|
||||
}
|
||||
|
||||
void test_string4()
|
||||
{
|
||||
const char *cs = source();
|
||||
|
||||
// convert char * -> std::string
|
||||
std::string ss(cs);
|
||||
|
||||
// convert back std::string -> char *
|
||||
cs = ss.c_str();
|
||||
|
||||
sink(cs); // tainted
|
||||
sink(ss); // tainted
|
||||
}
|
||||
|
||||
void test_string_constructors_assignments()
|
||||
{
|
||||
{
|
||||
std::string s1("hello");
|
||||
std::string s2 = "hello";
|
||||
std::string s3;
|
||||
s3 = "hello";
|
||||
|
||||
sink(s1);
|
||||
sink(s2);
|
||||
sink(s3);
|
||||
}
|
||||
|
||||
{
|
||||
std::string s1(source());
|
||||
std::string s2 = source();
|
||||
std::string s3;
|
||||
s3 = source();
|
||||
|
||||
sink(s1); // tainted
|
||||
sink(s2); // tainted
|
||||
sink(s3); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::string s1;
|
||||
std::string s2 = s1;
|
||||
std::string s3;
|
||||
s3 = s1;
|
||||
|
||||
sink(s1);
|
||||
sink(s2);
|
||||
sink(s3);
|
||||
}
|
||||
|
||||
{
|
||||
std::string s1 = std::string(source());
|
||||
std::string s2;
|
||||
s2 = std::string(source());
|
||||
|
||||
sink(s1); // tainted
|
||||
sink(s2); // tainted
|
||||
}
|
||||
}
|
||||
|
||||
void test_range_based_for_loop_string() {
|
||||
std::string s(source());
|
||||
for(char c : s) {
|
||||
sink(c); // tainted [NOT DETECTED by IR]
|
||||
}
|
||||
|
||||
for(std::string::iterator it = s.begin(); it != s.end(); ++it) {
|
||||
sink(*it); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
for(char& c : s) {
|
||||
sink(c); // tainted [NOT DETECTED by IR]
|
||||
}
|
||||
|
||||
const std::string const_s(source());
|
||||
for(const char& c : const_s) {
|
||||
sink(c); // tainted [NOT DETECTED by IR]
|
||||
}
|
||||
}
|
||||
|
||||
void test_string_append() {
|
||||
{
|
||||
std::string s1("hello");
|
||||
std::string s2(source());
|
||||
|
||||
sink(s1 + s1);
|
||||
sink(s1 + s2); // tainted
|
||||
sink(s2 + s1); // tainted
|
||||
sink(s2 + s2); // tainted
|
||||
|
||||
sink(s1 + " world");
|
||||
sink(s1 + source()); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::string s3("abc");
|
||||
std::string s4(source());
|
||||
std::string s5, s6, s7, s8, s9;
|
||||
|
||||
s5 = s3 + s4;
|
||||
sink(s5); // tainted
|
||||
|
||||
s6 = s3;
|
||||
s6 += s4;
|
||||
sink(s6); // tainted
|
||||
|
||||
s7 = s3;
|
||||
s7 += source();
|
||||
s7 += " ";
|
||||
sink(s7); // tainted
|
||||
|
||||
s8 = s3;
|
||||
s8.append(s4);
|
||||
sink(s8); // tainted
|
||||
|
||||
s9 = s3;
|
||||
s9.append(source());
|
||||
s9.append(" ");
|
||||
sink(s9); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::string s10("abc");
|
||||
char c = ns_char::source();
|
||||
|
||||
s10.append(1, c);
|
||||
sink(s10); // tainted
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
#include "stl.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
char *source();
|
||||
|
||||
void sink(const std::string &s) {};
|
||||
void sink(const std::stringstream &s) {};
|
||||
|
||||
void test_stringstream()
|
||||
{
|
||||
std::stringstream ss1, ss2, ss3, ss4, ss5;
|
||||
std::string t(source());
|
||||
|
||||
ss1 << "1234";
|
||||
ss2 << source();
|
||||
ss3 << "123" << source();
|
||||
ss4 << source() << "456";
|
||||
ss5 << t;
|
||||
|
||||
sink(ss1);
|
||||
sink(ss2); // tainted [NOT DETECTED]
|
||||
sink(ss3); // tainted [NOT DETECTED]
|
||||
sink(ss4); // tainted [NOT DETECTED]
|
||||
sink(ss5); // tainted [NOT DETECTED]
|
||||
sink(ss1.str());
|
||||
sink(ss2.str()); // tainted [NOT DETECTED]
|
||||
sink(ss3.str()); // tainted [NOT DETECTED]
|
||||
sink(ss4.str()); // tainted [NOT DETECTED]
|
||||
sink(ss5.str()); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test_stringstream_int(int source)
|
||||
{
|
||||
std::stringstream ss1, ss2;
|
||||
|
||||
ss1 << 1234;
|
||||
ss2 << source;
|
||||
|
||||
sink(ss1);
|
||||
sink(ss2); // tainted [NOT DETECTED]
|
||||
sink(ss1.str());
|
||||
sink(ss2.str()); // tainted [NOT DETECTED]
|
||||
}
|
||||
@@ -32,21 +32,34 @@
|
||||
| movableclass.cpp:55:8:55:9 | s2 | movableclass.cpp:52:23:52:28 | call to source |
|
||||
| movableclass.cpp:64:8:64:9 | s2 | movableclass.cpp:23:55:23:60 | call to source |
|
||||
| movableclass.cpp:65:11:65:11 | call to operator= | movableclass.cpp:65:13:65:18 | call to source |
|
||||
| stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source |
|
||||
| stl.cpp:73:7:73:7 | c | stl.cpp:69:16:69:21 | call to source |
|
||||
| stl.cpp:75:9:75:13 | call to c_str | stl.cpp:69:16:69:21 | call to source |
|
||||
| stl.cpp:125:13:125:17 | call to c_str | stl.cpp:117:10:117:15 | call to source |
|
||||
| stl.cpp:129:13:129:17 | call to c_str | stl.cpp:117:10:117:15 | call to source |
|
||||
| stl.cpp:132:13:132:17 | call to c_str | stl.cpp:117:10:117:15 | call to source |
|
||||
| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:24 | call to source |
|
||||
| stl.cpp:143:7:143:8 | ss | stl.cpp:137:19:137:24 | call to source |
|
||||
| stl.cpp:156:7:156:8 | cs | stl.cpp:148:19:148:24 | call to source |
|
||||
| stl.cpp:157:7:157:8 | ss | stl.cpp:148:19:148:24 | call to source |
|
||||
| stl.cpp:179:8:179:9 | s1 | stl.cpp:174:18:174:23 | call to source |
|
||||
| stl.cpp:180:8:180:9 | s2 | stl.cpp:175:20:175:25 | call to source |
|
||||
| stl.cpp:181:8:181:9 | s3 | stl.cpp:177:8:177:13 | call to source |
|
||||
| stl.cpp:200:8:200:9 | s1 | stl.cpp:196:32:196:37 | call to source |
|
||||
| stl.cpp:201:8:201:9 | s2 | stl.cpp:198:20:198:25 | call to source |
|
||||
| string.cpp:28:7:28:7 | a | string.cpp:24:12:24:17 | call to source |
|
||||
| string.cpp:30:7:30:7 | c | string.cpp:26:16:26:21 | call to source |
|
||||
| string.cpp:32:9:32:13 | call to c_str | string.cpp:26:16:26:21 | call to source |
|
||||
| string.cpp:38:13:38:17 | call to c_str | string.cpp:14:10:14:15 | call to source |
|
||||
| string.cpp:42:13:42:17 | call to c_str | string.cpp:14:10:14:15 | call to source |
|
||||
| string.cpp:45:13:45:17 | call to c_str | string.cpp:14:10:14:15 | call to source |
|
||||
| string.cpp:55:7:55:8 | cs | string.cpp:50:19:50:24 | call to source |
|
||||
| string.cpp:56:7:56:8 | ss | string.cpp:50:19:50:24 | call to source |
|
||||
| string.cpp:69:7:69:8 | cs | string.cpp:61:19:61:24 | call to source |
|
||||
| string.cpp:70:7:70:8 | ss | string.cpp:61:19:61:24 | call to source |
|
||||
| string.cpp:92:8:92:9 | s1 | string.cpp:87:18:87:23 | call to source |
|
||||
| string.cpp:93:8:93:9 | s2 | string.cpp:88:20:88:25 | call to source |
|
||||
| string.cpp:94:8:94:9 | s3 | string.cpp:90:8:90:13 | call to source |
|
||||
| string.cpp:113:8:113:9 | s1 | string.cpp:109:32:109:37 | call to source |
|
||||
| string.cpp:114:8:114:9 | s2 | string.cpp:111:20:111:25 | call to source |
|
||||
| string.cpp:121:8:121:8 | c | string.cpp:119:16:119:21 | call to source |
|
||||
| string.cpp:129:8:129:8 | c | string.cpp:119:16:119:21 | call to source |
|
||||
| string.cpp:134:8:134:8 | c | string.cpp:132:28:132:33 | call to source |
|
||||
| string.cpp:144:11:144:11 | call to operator+ | string.cpp:141:18:141:23 | call to source |
|
||||
| string.cpp:145:11:145:11 | call to operator+ | string.cpp:141:18:141:23 | call to source |
|
||||
| string.cpp:146:11:146:11 | call to operator+ | string.cpp:141:18:141:23 | call to source |
|
||||
| string.cpp:149:11:149:11 | call to operator+ | string.cpp:149:13:149:18 | call to source |
|
||||
| string.cpp:158:8:158:9 | s5 | string.cpp:154:18:154:23 | call to source |
|
||||
| string.cpp:162:8:162:9 | s6 | string.cpp:154:18:154:23 | call to source |
|
||||
| string.cpp:167:8:167:9 | s7 | string.cpp:165:9:165:14 | call to source |
|
||||
| string.cpp:171:8:171:9 | s8 | string.cpp:154:18:154:23 | call to source |
|
||||
| string.cpp:176:8:176:9 | s9 | string.cpp:174:13:174:18 | call to source |
|
||||
| string.cpp:184:8:184:10 | s10 | string.cpp:181:12:181:26 | call to source |
|
||||
| structlikeclass.cpp:35:8:35:9 | s1 | structlikeclass.cpp:29:22:29:27 | call to source |
|
||||
| structlikeclass.cpp:36:8:36:9 | s2 | structlikeclass.cpp:30:24:30:29 | call to source |
|
||||
| structlikeclass.cpp:37:8:37:9 | s3 | structlikeclass.cpp:29:22:29:27 | call to source |
|
||||
@@ -153,3 +166,6 @@
|
||||
| taint.cpp:470:7:470:7 | x | taint.cpp:462:6:462:11 | call to source |
|
||||
| taint.cpp:471:7:471:7 | y | taint.cpp:462:6:462:11 | call to source |
|
||||
| taint.cpp:485:7:485:10 | line | taint.cpp:480:26:480:32 | source1 |
|
||||
| vector.cpp:15:8:15:8 | x | vector.cpp:8:43:8:49 | source1 |
|
||||
| vector.cpp:23:8:23:8 | x | vector.cpp:8:43:8:49 | source1 |
|
||||
| vector.cpp:28:8:28:8 | x | vector.cpp:8:43:8:49 | source1 |
|
||||
|
||||
@@ -30,20 +30,33 @@
|
||||
| movableclass.cpp:55:8:55:9 | movableclass.cpp:52:23:52:28 | AST only |
|
||||
| movableclass.cpp:64:8:64:9 | movableclass.cpp:23:55:23:60 | AST only |
|
||||
| movableclass.cpp:65:11:65:11 | movableclass.cpp:65:13:65:18 | AST only |
|
||||
| stl.cpp:73:7:73:7 | stl.cpp:69:16:69:21 | AST only |
|
||||
| stl.cpp:75:9:75:13 | stl.cpp:69:16:69:21 | AST only |
|
||||
| stl.cpp:125:13:125:17 | stl.cpp:117:10:117:15 | AST only |
|
||||
| stl.cpp:129:13:129:17 | stl.cpp:117:10:117:15 | AST only |
|
||||
| stl.cpp:132:13:132:17 | stl.cpp:117:10:117:15 | AST only |
|
||||
| stl.cpp:142:7:142:8 | stl.cpp:137:19:137:26 | IR only |
|
||||
| stl.cpp:143:7:143:8 | stl.cpp:137:19:137:24 | AST only |
|
||||
| stl.cpp:156:7:156:8 | stl.cpp:148:19:148:24 | AST only |
|
||||
| stl.cpp:157:7:157:8 | stl.cpp:148:19:148:24 | AST only |
|
||||
| stl.cpp:179:8:179:9 | stl.cpp:174:18:174:23 | AST only |
|
||||
| stl.cpp:180:8:180:9 | stl.cpp:175:20:175:25 | AST only |
|
||||
| stl.cpp:181:8:181:9 | stl.cpp:177:8:177:13 | AST only |
|
||||
| stl.cpp:200:8:200:9 | stl.cpp:196:32:196:37 | AST only |
|
||||
| stl.cpp:201:8:201:9 | stl.cpp:198:20:198:25 | AST only |
|
||||
| string.cpp:30:7:30:7 | string.cpp:26:16:26:21 | AST only |
|
||||
| string.cpp:32:9:32:13 | string.cpp:26:16:26:21 | AST only |
|
||||
| string.cpp:38:13:38:17 | string.cpp:14:10:14:15 | AST only |
|
||||
| string.cpp:42:13:42:17 | string.cpp:14:10:14:15 | AST only |
|
||||
| string.cpp:45:13:45:17 | string.cpp:14:10:14:15 | AST only |
|
||||
| string.cpp:55:7:55:8 | string.cpp:50:19:50:26 | IR only |
|
||||
| string.cpp:56:7:56:8 | string.cpp:50:19:50:24 | AST only |
|
||||
| string.cpp:69:7:69:8 | string.cpp:61:19:61:24 | AST only |
|
||||
| string.cpp:70:7:70:8 | string.cpp:61:19:61:24 | AST only |
|
||||
| string.cpp:92:8:92:9 | string.cpp:87:18:87:23 | AST only |
|
||||
| string.cpp:93:8:93:9 | string.cpp:88:20:88:25 | AST only |
|
||||
| string.cpp:94:8:94:9 | string.cpp:90:8:90:13 | AST only |
|
||||
| string.cpp:113:8:113:9 | string.cpp:109:32:109:37 | AST only |
|
||||
| string.cpp:114:8:114:9 | string.cpp:111:20:111:25 | AST only |
|
||||
| string.cpp:121:8:121:8 | string.cpp:119:16:119:21 | AST only |
|
||||
| string.cpp:129:8:129:8 | string.cpp:119:16:119:21 | AST only |
|
||||
| string.cpp:134:8:134:8 | string.cpp:132:28:132:33 | AST only |
|
||||
| string.cpp:144:11:144:11 | string.cpp:141:18:141:23 | AST only |
|
||||
| string.cpp:145:11:145:11 | string.cpp:141:18:141:23 | AST only |
|
||||
| string.cpp:146:11:146:11 | string.cpp:141:18:141:23 | AST only |
|
||||
| string.cpp:149:11:149:11 | string.cpp:149:13:149:18 | AST only |
|
||||
| string.cpp:158:8:158:9 | string.cpp:154:18:154:23 | AST only |
|
||||
| string.cpp:162:8:162:9 | string.cpp:154:18:154:23 | AST only |
|
||||
| string.cpp:167:8:167:9 | string.cpp:165:9:165:14 | AST only |
|
||||
| string.cpp:171:8:171:9 | string.cpp:154:18:154:23 | AST only |
|
||||
| string.cpp:176:8:176:9 | string.cpp:174:13:174:18 | AST only |
|
||||
| string.cpp:184:8:184:10 | string.cpp:181:12:181:26 | AST only |
|
||||
| structlikeclass.cpp:35:8:35:9 | structlikeclass.cpp:29:22:29:27 | AST only |
|
||||
| structlikeclass.cpp:36:8:36:9 | structlikeclass.cpp:30:24:30:29 | AST only |
|
||||
| structlikeclass.cpp:37:8:37:9 | structlikeclass.cpp:29:22:29:27 | AST only |
|
||||
@@ -88,3 +101,6 @@
|
||||
| taint.cpp:446:7:446:7 | taint.cpp:445:14:445:28 | AST only |
|
||||
| taint.cpp:447:9:447:17 | taint.cpp:445:14:445:28 | AST only |
|
||||
| taint.cpp:471:7:471:7 | taint.cpp:462:6:462:11 | AST only |
|
||||
| vector.cpp:15:8:15:8 | vector.cpp:8:43:8:49 | AST only |
|
||||
| vector.cpp:23:8:23:8 | vector.cpp:8:43:8:49 | AST only |
|
||||
| vector.cpp:28:8:28:8 | vector.cpp:8:43:8:49 | AST only |
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
| format.cpp:157:7:157:22 | (int)... | format.cpp:147:12:147:25 | call to source |
|
||||
| format.cpp:157:7:157:22 | access to array | format.cpp:147:12:147:25 | call to source |
|
||||
| format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source |
|
||||
| stl.cpp:71:7:71:7 | (const char *)... | stl.cpp:67:12:67:17 | call to source |
|
||||
| stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source |
|
||||
| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:24 | call to source |
|
||||
| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:26 | (const char *)... |
|
||||
| string.cpp:28:7:28:7 | (const char *)... | string.cpp:24:12:24:17 | call to source |
|
||||
| string.cpp:28:7:28:7 | a | string.cpp:24:12:24:17 | call to source |
|
||||
| string.cpp:55:7:55:8 | cs | string.cpp:50:19:50:24 | call to source |
|
||||
| string.cpp:55:7:55:8 | cs | string.cpp:50:19:50:26 | (const char *)... |
|
||||
| structlikeclass.cpp:38:8:38:9 | s4 | structlikeclass.cpp:33:8:33:13 | call to source |
|
||||
| structlikeclass.cpp:61:8:61:9 | s2 | structlikeclass.cpp:58:24:58:29 | call to source |
|
||||
| structlikeclass.cpp:62:8:62:20 | ... = ... | structlikeclass.cpp:62:13:62:18 | call to source |
|
||||
|
||||
30
cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp
Normal file
30
cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
#include "stl.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void sink(int);
|
||||
|
||||
void test_range_based_for_loop_vector(int source1) {
|
||||
// Tainting the vector by allocating a tainted length. This doesn't represent
|
||||
// how a vector would typically get tainted, but it allows this test to avoid
|
||||
// being concerned with std::vector modeling.
|
||||
std::vector<int> v(source1);
|
||||
|
||||
for(int x : v) {
|
||||
sink(x); // tainted [NOT DETECTED by IR]
|
||||
}
|
||||
|
||||
for(std::vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
|
||||
sink(*it); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
for(int& x : v) {
|
||||
sink(x); // tainted [NOT DETECTED by IR]
|
||||
}
|
||||
|
||||
const std::vector<int> const_v(source1);
|
||||
for(const int& x : const_v) {
|
||||
sink(x); // tainted [NOT DETECTED by IR]
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
| functions.cpp:23:7:23:11 | Table | Class | functions.cpp:30:8:30:13 | insert | |
|
||||
| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:33:7:33:7 | operator= | |
|
||||
| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:36:2:36:8 | MyClass | Constructor, NoArgConstructor, getAConstructor() |
|
||||
| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:37:2:37:8 | MyClass | Constructor, ConversionConstructor, getAConstructor() |
|
||||
| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:37:2:37:8 | MyClass | Constructor, getAConstructor() |
|
||||
| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:38:2:38:8 | MyClass | Constructor, CopyConstructor, getAConstructor() |
|
||||
| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:39:2:39:8 | MyClass | Constructor, ConversionConstructor, MoveConstructor, getAConstructor() |
|
||||
| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:39:2:39:8 | MyClass | Constructor, MoveConstructor, getAConstructor() |
|
||||
| functions.cpp:33:7:33:13 | MyClass | Class | functions.cpp:40:2:40:13 | operator int | ConversionOperator |
|
||||
|
||||
@@ -19,9 +19,6 @@ string describe(Class c, MemberFunction f) {
|
||||
f instanceof Destructor and
|
||||
result = "Destructor"
|
||||
or
|
||||
f instanceof ConversionConstructor and
|
||||
result = "ConversionConstructor"
|
||||
or
|
||||
f instanceof CopyConstructor and
|
||||
result = "CopyConstructor"
|
||||
or
|
||||
|
||||
@@ -291,7 +291,7 @@ struct A {
|
||||
Point *NewAliasing(int x) {
|
||||
Point* p = new Point;
|
||||
Point* q = new Point;
|
||||
int j = new A(new A(x))->i;
|
||||
int j = (new A(new A(x)))->i;
|
||||
A* a = new A;
|
||||
return p;
|
||||
}
|
||||
@@ -310,4 +310,4 @@ class ThisAliasTest {
|
||||
void setX(int arg) {
|
||||
this->x = arg;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||
|
||||
from VariableAccess expr
|
||||
select expr, lowerBound(expr)
|
||||
select expr, lowerBound(expr).toString()
|
||||
|
||||
@@ -422,7 +422,7 @@ void test17() {
|
||||
out(i); // 50
|
||||
|
||||
i = 20 + (j -= 10);
|
||||
out(i); // 60 [BUG: the analysis thinks it's 2^-31 .. 2^31-1]
|
||||
out(i); // 60
|
||||
}
|
||||
|
||||
// Tests for unsigned multiplication.
|
||||
@@ -463,3 +463,30 @@ int test_unsigned_mult02(unsigned b) {
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
unsigned long mult_rounding() {
|
||||
unsigned long x, y, xy;
|
||||
x = y = 1000000003UL; // 1e9 + 3
|
||||
xy = x * y;
|
||||
return xy; // BUG: upper bound should be >= 1000000006000000009UL
|
||||
}
|
||||
|
||||
unsigned long mult_overflow() {
|
||||
unsigned long x, y, xy;
|
||||
x = 274177UL;
|
||||
y = 67280421310721UL;
|
||||
xy = x * y;
|
||||
return xy; // BUG: lower bound should be <= 18446744073709551617UL
|
||||
}
|
||||
|
||||
unsigned long mult_lower_bound(unsigned int ui, unsigned long ul) {
|
||||
if (ui >= 10) {
|
||||
unsigned long result = (unsigned long)ui * ui;
|
||||
return result; // BUG: upper bound should be >= 18446744065119617025 (possibly a pretty-printing bug)
|
||||
}
|
||||
if (ul >= 10) {
|
||||
unsigned long result = ul * ul;
|
||||
return result; // lower bound is correctly 0 (overflow is possible)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||
|
||||
from VariableAccess expr
|
||||
select expr, upperBound(expr)
|
||||
select expr, upperBound(expr).toString()
|
||||
|
||||
@@ -385,10 +385,39 @@ void bitwise_ands()
|
||||
|
||||
void unsigned_mult(unsigned int x, unsigned int y) {
|
||||
if(x < 13 && y < 35) {
|
||||
if(x * y > 1024) {} // always false [NOT DETECTED]
|
||||
if(x * y > 1024) {} // always false
|
||||
if(x * y < 204) {}
|
||||
if(x >= 3 && y >= 2) {
|
||||
if(x * y < 5) {} // always false [NOT DETECTED]
|
||||
if(x * y < 5) {} // always false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mult_rounding() {
|
||||
unsigned long x, y, xy;
|
||||
x = y = 1000000003UL; // 1e9 + 3
|
||||
xy = 1000000006000000009UL; // x * y, precisely
|
||||
// Even though the range analysis wrongly considers x*y to be xy - 9, there
|
||||
// are no PointlessComparison false positives in these tests because alerts
|
||||
// are suppressed when ulp() < 1, which roughly means that the number is
|
||||
// larger than 2^53.
|
||||
if (x * y < xy) {} // always false [NOT DETECTED]
|
||||
if (x * y > xy) {} // always false [NOT DETECTED]
|
||||
}
|
||||
|
||||
void mult_overflow() {
|
||||
unsigned long x, y;
|
||||
// The following two numbers multiply to 2^64 + 1, which is 1 when truncated
|
||||
// to 64-bit unsigned.
|
||||
x = 274177UL;
|
||||
y = 67280421310721UL;
|
||||
if (x * y == 1) {} // always true [BUG: reported as always false]
|
||||
|
||||
// This bug appears to be caused by
|
||||
// `RangeAnalysisUtils::typeUpperBound(unsigned long)` having a result of
|
||||
// 2**64 + 384, making the range analysis think that the multiplication can't
|
||||
// overflow. The correct `typeUpperBound` would be 2**64 - 1, but we can't
|
||||
// represent that with a QL float or int. We could make `typeUpperBound`
|
||||
// exclusive instead of inclusive, but there is no exclusive upper bound for
|
||||
// floats.
|
||||
}
|
||||
|
||||
@@ -41,6 +41,9 @@
|
||||
| PointlessComparison.c:372:6:372:16 | ... >= ... | Comparison is always true because ... >> ... >= 1. |
|
||||
| PointlessComparison.c:373:6:373:16 | ... >= ... | Comparison is always false because ... >> ... <= 1. |
|
||||
| PointlessComparison.c:383:6:383:17 | ... >= ... | Comparison is always false because ... & ... <= 2. |
|
||||
| PointlessComparison.c:388:10:388:21 | ... > ... | Comparison is always false because ... * ... <= 408. |
|
||||
| PointlessComparison.c:391:12:391:20 | ... < ... | Comparison is always false because ... * ... >= 6. |
|
||||
| PointlessComparison.c:414:7:414:16 | ... == ... | Comparison is always false because ... * ... >= 18446744073709552000. |
|
||||
| PointlessComparison.cpp:36:6:36:33 | ... >= ... | Comparison is always false because ... >> ... <= 9223372036854776000. |
|
||||
| PointlessComparison.cpp:41:6:41:29 | ... >= ... | Comparison is always false because ... >> ... <= 140737488355327.5. |
|
||||
| PointlessComparison.cpp:42:6:42:29 | ... >= ... | Comparison is always false because ... >> ... <= 140737488355327.5. |
|
||||
|
||||
@@ -177,4 +177,43 @@ void FalseNegativeTestCases()
|
||||
for (int i = 100; i > 0; i += 2) {}
|
||||
// For comparison
|
||||
for (int i = 100; i > 0; i ++ ) {} // BUG
|
||||
}
|
||||
}
|
||||
|
||||
void IntendedOverflow(unsigned char p)
|
||||
{
|
||||
const unsigned char m = 10;
|
||||
unsigned char i;
|
||||
signed char s;
|
||||
|
||||
for (i = 63; i < 64; i--) {} // GOOD (legitimate way to count down with an unsigned)
|
||||
for (i = 63; i < 128; i--) {} // DUBIOUS (could still be a typo?)
|
||||
for (i = 63; i < 255; i--) {} // GOOD
|
||||
|
||||
for (i = m - 1; i < m; i--) {} // GOOD
|
||||
for (i = m - 2; i < m; i--) {} // DUBIOUS
|
||||
for (i = m; i < m + 1; i--) {} // GOOD
|
||||
|
||||
for (s = 63; s < 64; s--) {} // BAD (signed numbers don't wrap at 0 / at all)
|
||||
for (s = m + 1; s < m; s--) {} // BAD (never runs)
|
||||
|
||||
for (i = p - 1; i < p; i--) {} // GOOD
|
||||
for (s = p - 1; s < p; s--) {} // BAD [NOT DETECTED]
|
||||
|
||||
{
|
||||
int n;
|
||||
|
||||
n = 64;
|
||||
for (i = n - 1; i < n; i--) {} // GOOD
|
||||
n = 64;
|
||||
for (i = n - 1; i < 64; i--) {} // GOOD
|
||||
n = 64;
|
||||
for (i = 63; i < n; i--) {} // GOOD
|
||||
|
||||
n = 64;
|
||||
for (s = n - 1; s < n; s--) {} // BAD [NOT DETECTED]
|
||||
n = 64;
|
||||
for (s = n - 1; s < 64; s--) {} // BAD
|
||||
n = 64;
|
||||
for (s = 63; s < n; s--) {} // BAD [NOT DETECTED]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,3 +20,6 @@
|
||||
| inconsistentLoopDirection.cpp:140:5:142:5 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts upward from a value (200), but the terminal condition is lower (0). |
|
||||
| inconsistentLoopDirection.cpp:175:5:175:36 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts downward from a value (0), but the terminal condition is higher (10). |
|
||||
| inconsistentLoopDirection.cpp:179:5:179:38 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts upward from a value (100), but the terminal condition is lower (0). |
|
||||
| inconsistentLoopDirection.cpp:196:5:196:32 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "s" counts downward from a value (63), but the terminal condition is higher (64). |
|
||||
| inconsistentLoopDirection.cpp:197:5:197:34 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "s" counts downward from a value (... + ...), but the terminal condition is always false. |
|
||||
| inconsistentLoopDirection.cpp:215:3:215:33 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "s" counts downward from a value (... - ...), but the terminal condition is higher (64). |
|
||||
|
||||
9
csharp/.vscode/extensions.json
vendored
Normal file
9
csharp/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"github.vscode-codeql",
|
||||
"ms-dotnettools.csharp",
|
||||
"formulahendry.dotnet-test-explorer",
|
||||
"hbenl.vscode-test-explorer"
|
||||
],
|
||||
"unwantedRecommendations": []
|
||||
}
|
||||
7
csharp/.vscode/settings.json
vendored
Normal file
7
csharp/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"dotnet-test-explorer.enableTelemetry": false,
|
||||
"dotnet-test-explorer.testProjectPath": "**/*Tests.@(csproj|vbproj|fsproj)",
|
||||
"dotnet-test-explorer.testArguments": "/property:GenerateTargetFrameworkAttribute=false",
|
||||
"csharp.supressBuildAssetsNotification": true,
|
||||
"csharp.suppressDotnetRestoreNotification": true
|
||||
}
|
||||
53
csharp/.vscode/tasks.json
vendored
Normal file
53
csharp/.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "dotnet build",
|
||||
"command": "dotnet",
|
||||
"type": "shell",
|
||||
"args": [
|
||||
"build",
|
||||
// Ask dotnet build to generate full paths for file names.
|
||||
"/property:GenerateFullPaths=true",
|
||||
// Do not generate summary otherwise it leads to duplicate errors in Problems panel
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"reveal": "always"
|
||||
},
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "dotnet rebuild",
|
||||
"command": "dotnet",
|
||||
"type": "shell",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-incremental",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"reveal": "always"
|
||||
},
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "dotnet test",
|
||||
"command": "dotnet",
|
||||
"type": "shell",
|
||||
"args": [
|
||||
"test",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"group": "test",
|
||||
"presentation": {
|
||||
"reveal": "always"
|
||||
},
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
||||
18
csharp/codeql-extractor.yml
Normal file
18
csharp/codeql-extractor.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
name: "csharp"
|
||||
display_name: "C#"
|
||||
version: 1.22.1
|
||||
column_kind: "utf16"
|
||||
extra_env_vars:
|
||||
DOTNET_GENERATE_ASPNET_CERTIFICATE: "false"
|
||||
COR_ENABLE_PROFILING: "1"
|
||||
COR_PROFILER: "{A3C70A64-7D41-4A94-A3F6-FD47D9259997}"
|
||||
COR_PROFILER_PATH_64: "${env.CODEQL_EXTRACTOR_CSHARP_ROOT}/tools/${env.CODEQL_PLATFORM}/clrtracer64${env.CODEQL_PLATFORM_DLL_EXTENSION}"
|
||||
CORECLR_ENABLE_PROFILING: "1"
|
||||
CORECLR_PROFILER: "{A3C70A64-7D41-4A94-A3F6-FD47D9259997}"
|
||||
CORECLR_PROFILER_PATH_64: "${env.CODEQL_EXTRACTOR_CSHARP_ROOT}/tools/${env.CODEQL_PLATFORM}/clrtracer64${env.CODEQL_PLATFORM_DLL_EXTENSION}"
|
||||
file_types:
|
||||
- name: cs
|
||||
display_name: C# sources
|
||||
extensions:
|
||||
- .cs
|
||||
legacy_qltest_extraction: true
|
||||
@@ -17,7 +17,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
|
||||
protected abstract ArrayTypeSyntax TypeSyntax { get; }
|
||||
|
||||
public abstract InitializerExpressionSyntax Initializer { get; }
|
||||
public abstract InitializerExpressionSyntax Initializer { get; }
|
||||
|
||||
protected override void PopulateExpression(TextWriter trapFile)
|
||||
{
|
||||
@@ -48,7 +48,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
ExprKind.INT_LITERAL,
|
||||
this,
|
||||
child,
|
||||
false,
|
||||
true,
|
||||
size.ToString());
|
||||
|
||||
new Expression(info);
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>The <code>DataSet</code> and <code>DataTable</code> types are legacy .NET components that you can use to represent data sets as managed objects.</p>
|
||||
|
||||
<p>While <code>DataSet</code> and <code>DataTable</code> do impose default limitations on the types that are allowed to be present while deserializing XML payloads, <code>DataSet</code> and <code>DataTable</code> are in general not safe when populated with untrusted input.</p>
|
||||
|
||||
<p>Please visit <a href="https://go.microsoft.com/fwlink/?linkid=2132227">DataSet and DataTable security guidance</a> for more details.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Please review the <a href="https://go.microsoft.com/fwlink/?linkid=2132227">DataSet and DataTable security guidance</a> before making use of these types for serialization.</p>
|
||||
|
||||
</recommendation>
|
||||
<references>
|
||||
|
||||
<li>Microsoft Docs<a href="https://go.microsoft.com/fwlink/?linkid=2132227">DataSet and DataTable security guidance</a>.</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Provides classes for `DataSet` or `DataTable` deserialization queries.
|
||||
*
|
||||
* Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details.
|
||||
*/
|
||||
|
||||
import csharp
|
||||
|
||||
/**
|
||||
* Abstract class that depends or inherits from `DataSet` or `DataTable` types.
|
||||
*/
|
||||
abstract class DataSetOrTableRelatedClass extends Class { }
|
||||
|
||||
/**
|
||||
* `DataSet`, `DataTable` types, or any types derived from them.
|
||||
*/
|
||||
class DataSetOrTable extends DataSetOrTableRelatedClass {
|
||||
DataSetOrTable() {
|
||||
this.getABaseType*().getQualifiedName() = "System.Data.DataTable" or
|
||||
this.getABaseType*().getQualifiedName() = "System.Data.DataSet"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Class that include a property or generic collection of type `DataSet` and `DataTable`
|
||||
*/
|
||||
class ClassWithDataSetOrTableMember extends DataSetOrTableRelatedClass {
|
||||
ClassWithDataSetOrTableMember() {
|
||||
this.getAMember().(AssignableMember).getType() instanceof DataSetOrTable
|
||||
or
|
||||
exists(Property p | p = this.getAProperty() |
|
||||
p.getType() instanceof DataSetOrTable or
|
||||
p.getType().(ConstructedGeneric).getATypeArgument() instanceof DataSetOrTable
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializable types
|
||||
*/
|
||||
class SerializableClass extends Class {
|
||||
SerializableClass() {
|
||||
(
|
||||
this.getABaseType*().getQualifiedName() = "System.Xml.Serialization.XmlSerializer" or
|
||||
this.getABaseType*().getQualifiedName() = "System.Runtime.Serialization.ISerializable" or
|
||||
this.getABaseType*().getQualifiedName() = "System.Runtime.Serialization.XmlObjectSerializer" or
|
||||
this.getABaseType*().getQualifiedName() =
|
||||
"System.Runtime.Serialization.ISerializationSurrogateProvider" or
|
||||
this.getABaseType*().getQualifiedName() =
|
||||
"System.Runtime.Serialization.XmlSerializableServices" or
|
||||
this.getABaseType*().getQualifiedName() = "System.Xml.Serialization.IXmlSerializable"
|
||||
)
|
||||
or
|
||||
exists(Attribute a | a = this.getAnAttribute() |
|
||||
a.getType().getQualifiedName() = "System.SerializableAttribute"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the serializable class `c` has a property or field `m` that is of `DataSet` or `DataTable` related type
|
||||
*/
|
||||
predicate isClassUnsafeXmlSerializerImplementation(SerializableClass c, AssignableMember am) {
|
||||
am = c.getAMember() and
|
||||
am.getType() instanceof DataSetOrTableRelatedClass
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializable class that has a property or field that is of `DataSet` or `DataTable` related type
|
||||
*/
|
||||
class UnsafeXmlSerializerImplementation extends SerializableClass {
|
||||
UnsafeXmlSerializerImplementation() { isClassUnsafeXmlSerializerImplementation(this, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that may be unsafe when used to deserialize DataSet and DataTable related types
|
||||
*/
|
||||
class UnsafeXmlReadMethod extends Method {
|
||||
UnsafeXmlReadMethod() {
|
||||
this.getQualifiedName() = "System.Data.DataTable.ReadXml"
|
||||
or
|
||||
this.getQualifiedName() = "System.Data.DataTable.ReadXmlSchema"
|
||||
or
|
||||
this.getQualifiedName() = "System.Data.DataSet.ReadXml"
|
||||
or
|
||||
this.getQualifiedName() = "System.Data.DataSet.ReadXmlSchema"
|
||||
or
|
||||
this.getName().matches("ReadXml%") and
|
||||
exists(Class c | c.getAMethod() = this |
|
||||
c.getABaseType*() instanceof DataSetOrTableRelatedClass
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MethodCall that may be unsafe when used to deserialize DataSet and DataTable related types
|
||||
*/
|
||||
class UnsafeXmlReadMethodCall extends MethodCall {
|
||||
UnsafeXmlReadMethodCall() { exists(UnsafeXmlReadMethod uxrm | uxrm.getACall() = this) }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="DataSetSerialization.qhelp" /></qhelp>
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types
|
||||
* @description Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types may lead to the usage of dangerous functionality. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @id cs/dataset-serialization/defining-dataset-related-type
|
||||
* @tags security
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import DataSetSerialization
|
||||
|
||||
from DataSetOrTableRelatedClass dstc
|
||||
where dstc.fromSource()
|
||||
select dstc,
|
||||
"Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details."
|
||||
@@ -0,0 +1,5 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="DataSetSerialization.qhelp" /></qhelp>
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @name Defining a potentially unsafe XML serializer
|
||||
* @description Defining an XML serializable class that includes members that derive from DataSet or DataTable type may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details.
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @precision medium
|
||||
* @id cs/dataset-serialization/defining-potentially-unsafe-xml-serializer
|
||||
* @tags security
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import DataSetSerialization
|
||||
|
||||
from UnsafeXmlSerializerImplementation c, Member m
|
||||
where
|
||||
c.fromSource() and
|
||||
isClassUnsafeXmlSerializerImplementation(c, m)
|
||||
select m,
|
||||
"Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details.",
|
||||
c, c.toString(), m, m.toString()
|
||||
@@ -0,0 +1,5 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="DataSetSerialization.qhelp" /></qhelp>
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @name Unsafe type is used in data contract serializer
|
||||
* @description Unsafe type is used in data contract serializer. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details."
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @precision medium
|
||||
* @id cs/dataset-serialization/unsafe-type-used-data-contract-serializer
|
||||
* @tags security
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import DataSetSerialization
|
||||
|
||||
predicate xmlSerializerConstructorArgument(Expr e) {
|
||||
exists(ObjectCreation oc, Constructor c | e = oc.getArgument(0) |
|
||||
c = oc.getTarget() and
|
||||
c.getDeclaringType().getABaseType*().hasQualifiedName("System.Xml.Serialization.XmlSerializer")
|
||||
)
|
||||
}
|
||||
|
||||
predicate unsafeDataContractTypeCreation(Expr e) {
|
||||
exists(MethodCall gt |
|
||||
gt.getTarget().getName() = "GetType" and
|
||||
e = gt and
|
||||
gt.getQualifier().getType() instanceof DataSetOrTableRelatedClass
|
||||
)
|
||||
or
|
||||
e.(TypeofExpr).getTypeAccess().getTarget() instanceof DataSetOrTableRelatedClass
|
||||
}
|
||||
|
||||
class Conf extends DataFlow::Configuration {
|
||||
Conf() { this = "FlowToDataSerializerConstructor" }
|
||||
|
||||
override predicate isSource(DataFlow::Node node) { unsafeDataContractTypeCreation(node.asExpr()) }
|
||||
|
||||
override predicate isSink(DataFlow::Node node) { xmlSerializerConstructorArgument(node.asExpr()) }
|
||||
}
|
||||
|
||||
from Conf conf, DataFlow::Node source, DataFlow::Node sink
|
||||
where conf.hasFlow(source, sink)
|
||||
select sink,
|
||||
"Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source.",
|
||||
source, source.toString()
|
||||
@@ -0,0 +1,5 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="DataSetSerialization.qhelp" /></qhelp>
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name XML deserialization with a type type derived from DataSet or DataTable
|
||||
* @description Making an XML deserialization call with a type derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details."
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @precision medium
|
||||
* @id cs/dataset-serialization/xml-deserialization-with-dataset
|
||||
* @tags security
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import DataSetSerialization
|
||||
|
||||
from UnsafeXmlReadMethodCall mc
|
||||
select mc,
|
||||
"Making an XML deserialization call with a type derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details."
|
||||
@@ -1066,7 +1066,7 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(Node node, Configuration config) {
|
||||
predicate localFlowEntry(Node node, Configuration config) {
|
||||
nodeCand2(node, config) and
|
||||
(
|
||||
config.isSource(node) or
|
||||
@@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption {
|
||||
* Holds if `node` is reachable with access path `ap` from a source in
|
||||
* the configuration `config`.
|
||||
*
|
||||
* The Boolean `fromArg` records whether the node is reached through an
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `argAp` records the access path of that
|
||||
* argument.
|
||||
*/
|
||||
private predicate flowFwd(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwd0(node, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd0(node, cc, argAp, apf, ap, config) and
|
||||
flowCand(node, _, _, apf, config)
|
||||
}
|
||||
|
||||
private predicate flowFwd0(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowCand(node, _, _, _, config) and
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, argAp, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, _)
|
||||
exists(Node mid, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, localCC)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, argAp, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, _) and
|
||||
exists(Node mid, AccessPathNil nil, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, localCC) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
flowFwd(mid, _, _, apf, ap, config) and
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, _, _, _, nil, config) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
@@ -1704,40 +1704,51 @@ private predicate flowFwd0(
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config))
|
||||
or
|
||||
// read
|
||||
exists(TypedContent tc |
|
||||
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
|
||||
flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and
|
||||
flowFwdConsCand(tc, apf, ap, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
flowFwdIn(_, node, _, _, apf, ap, config) and
|
||||
fromArg = true and
|
||||
flowFwdIn(_, node, _, cc, _, apf, ap, config) and
|
||||
if flowCand(node, true, _, apf, config)
|
||||
then argAp = TAccessPathSome(ap)
|
||||
else argAp = TAccessPathNone()
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call |
|
||||
flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and
|
||||
fromArg = false
|
||||
exists(DataFlowCallable c |
|
||||
flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and
|
||||
if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext()
|
||||
)
|
||||
or
|
||||
exists(AccessPath argAp0 |
|
||||
flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and
|
||||
flowFwdIsEntered(call, fromArg, argAp, argAp0, config)
|
||||
flowFwdIsEntered(call, cc, argAp, argAp0, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdLocalEntry(
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
LocalCallContext localCC, Configuration config
|
||||
) {
|
||||
flowFwd(node, cc, argAp, apf, ap, config) and
|
||||
localFlowEntry(node, config) and
|
||||
localCC = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdStore(
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, AccessPathFront apf0 |
|
||||
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(mid, cc, argAp, apf0, ap0, config) and
|
||||
flowFwdStore0(mid, tc, node, apf0, apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1764,20 +1775,20 @@ private predicate flowFwdStore0(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead0(
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
|
||||
boolean fromArg, AccessPathOption argAp, Configuration config
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(node1, cc, argAp, apf0, ap0, config) and
|
||||
readCandFwd(node1, tc, apf0, node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead(
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and
|
||||
flowCand(node, _, _, apf, unbind(config)) and
|
||||
flowCandConsCand(tc, apf, unbind(config))
|
||||
)
|
||||
@@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIn(
|
||||
DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
flowFwd(arg, fromArg, argAp, apf, ap, config) and
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c |
|
||||
flowFwd(arg, outercc, argAp, apf, ap, config) and
|
||||
flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and
|
||||
flowCand(p, _, _, _, unbind(config))
|
||||
c = p.getEnclosingCallable() and
|
||||
c = resolveCall(call, outercc) and
|
||||
flowCand(p, _, _, _, unbind(config)) and
|
||||
if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall()
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1809,13 +1823,19 @@ private predicate flowFwdIn(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdOut(
|
||||
DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow |
|
||||
flowFwd(ret, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd(ret, innercc, argAp, apf, ap, config) and
|
||||
flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and
|
||||
flowCand(node, _, _, _, unbind(config))
|
||||
innerc = ret.getEnclosingCallable() and
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
resolveReturn(innercc, innerc, call)
|
||||
or
|
||||
innercc.(CallContextCall).matchesCall(call)
|
||||
)
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg(
|
||||
DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config)
|
||||
flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIsEntered(
|
||||
DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, AccessPathFront apf |
|
||||
flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and
|
||||
flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and
|
||||
flowCand(p, true, TAccessPathFrontSome(_), apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1920,7 +1940,7 @@ private predicate flow0(
|
||||
// flow out of a callable
|
||||
flowOut(_, node, _, _, ap, config) and
|
||||
toReturn = true and
|
||||
if flowFwd(node, true, TAccessPathSome(_), _, ap, config)
|
||||
if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config)
|
||||
then returnAp = TAccessPathSome(ap)
|
||||
else returnAp = TAccessPathNone()
|
||||
}
|
||||
@@ -2006,9 +2026,10 @@ private predicate flowIsReturned(
|
||||
DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
exists(ReturnNodeExt ret, CallContextCall ccc |
|
||||
flowOut(call, ret, toReturn, returnAp, ap, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(_), _, ap, config)
|
||||
flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and
|
||||
ccc.matchesCall(call)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2031,7 +2052,7 @@ private newtype TSummaryCtx =
|
||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 |
|
||||
parameterFlow(p, ap, ret.getEnclosingCallable(), config) and
|
||||
flow(ret, true, TAccessPathSome(_), ap0, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config)
|
||||
flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0(
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
@@ -2867,7 +2888,7 @@ private module FlowExploration {
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
@@ -1066,7 +1066,7 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(Node node, Configuration config) {
|
||||
predicate localFlowEntry(Node node, Configuration config) {
|
||||
nodeCand2(node, config) and
|
||||
(
|
||||
config.isSource(node) or
|
||||
@@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption {
|
||||
* Holds if `node` is reachable with access path `ap` from a source in
|
||||
* the configuration `config`.
|
||||
*
|
||||
* The Boolean `fromArg` records whether the node is reached through an
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `argAp` records the access path of that
|
||||
* argument.
|
||||
*/
|
||||
private predicate flowFwd(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwd0(node, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd0(node, cc, argAp, apf, ap, config) and
|
||||
flowCand(node, _, _, apf, config)
|
||||
}
|
||||
|
||||
private predicate flowFwd0(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowCand(node, _, _, _, config) and
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, argAp, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, _)
|
||||
exists(Node mid, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, localCC)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, argAp, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, _) and
|
||||
exists(Node mid, AccessPathNil nil, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, localCC) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
flowFwd(mid, _, _, apf, ap, config) and
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, _, _, _, nil, config) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
@@ -1704,40 +1704,51 @@ private predicate flowFwd0(
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config))
|
||||
or
|
||||
// read
|
||||
exists(TypedContent tc |
|
||||
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
|
||||
flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and
|
||||
flowFwdConsCand(tc, apf, ap, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
flowFwdIn(_, node, _, _, apf, ap, config) and
|
||||
fromArg = true and
|
||||
flowFwdIn(_, node, _, cc, _, apf, ap, config) and
|
||||
if flowCand(node, true, _, apf, config)
|
||||
then argAp = TAccessPathSome(ap)
|
||||
else argAp = TAccessPathNone()
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call |
|
||||
flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and
|
||||
fromArg = false
|
||||
exists(DataFlowCallable c |
|
||||
flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and
|
||||
if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext()
|
||||
)
|
||||
or
|
||||
exists(AccessPath argAp0 |
|
||||
flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and
|
||||
flowFwdIsEntered(call, fromArg, argAp, argAp0, config)
|
||||
flowFwdIsEntered(call, cc, argAp, argAp0, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdLocalEntry(
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
LocalCallContext localCC, Configuration config
|
||||
) {
|
||||
flowFwd(node, cc, argAp, apf, ap, config) and
|
||||
localFlowEntry(node, config) and
|
||||
localCC = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdStore(
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, AccessPathFront apf0 |
|
||||
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(mid, cc, argAp, apf0, ap0, config) and
|
||||
flowFwdStore0(mid, tc, node, apf0, apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1764,20 +1775,20 @@ private predicate flowFwdStore0(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead0(
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
|
||||
boolean fromArg, AccessPathOption argAp, Configuration config
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(node1, cc, argAp, apf0, ap0, config) and
|
||||
readCandFwd(node1, tc, apf0, node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead(
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and
|
||||
flowCand(node, _, _, apf, unbind(config)) and
|
||||
flowCandConsCand(tc, apf, unbind(config))
|
||||
)
|
||||
@@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIn(
|
||||
DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
flowFwd(arg, fromArg, argAp, apf, ap, config) and
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c |
|
||||
flowFwd(arg, outercc, argAp, apf, ap, config) and
|
||||
flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and
|
||||
flowCand(p, _, _, _, unbind(config))
|
||||
c = p.getEnclosingCallable() and
|
||||
c = resolveCall(call, outercc) and
|
||||
flowCand(p, _, _, _, unbind(config)) and
|
||||
if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall()
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1809,13 +1823,19 @@ private predicate flowFwdIn(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdOut(
|
||||
DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow |
|
||||
flowFwd(ret, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd(ret, innercc, argAp, apf, ap, config) and
|
||||
flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and
|
||||
flowCand(node, _, _, _, unbind(config))
|
||||
innerc = ret.getEnclosingCallable() and
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
resolveReturn(innercc, innerc, call)
|
||||
or
|
||||
innercc.(CallContextCall).matchesCall(call)
|
||||
)
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg(
|
||||
DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config)
|
||||
flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIsEntered(
|
||||
DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, AccessPathFront apf |
|
||||
flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and
|
||||
flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and
|
||||
flowCand(p, true, TAccessPathFrontSome(_), apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1920,7 +1940,7 @@ private predicate flow0(
|
||||
// flow out of a callable
|
||||
flowOut(_, node, _, _, ap, config) and
|
||||
toReturn = true and
|
||||
if flowFwd(node, true, TAccessPathSome(_), _, ap, config)
|
||||
if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config)
|
||||
then returnAp = TAccessPathSome(ap)
|
||||
else returnAp = TAccessPathNone()
|
||||
}
|
||||
@@ -2006,9 +2026,10 @@ private predicate flowIsReturned(
|
||||
DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
exists(ReturnNodeExt ret, CallContextCall ccc |
|
||||
flowOut(call, ret, toReturn, returnAp, ap, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(_), _, ap, config)
|
||||
flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and
|
||||
ccc.matchesCall(call)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2031,7 +2052,7 @@ private newtype TSummaryCtx =
|
||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 |
|
||||
parameterFlow(p, ap, ret.getEnclosingCallable(), config) and
|
||||
flow(ret, true, TAccessPathSome(_), ap0, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config)
|
||||
flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0(
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
@@ -2867,7 +2888,7 @@ private module FlowExploration {
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
@@ -1066,7 +1066,7 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(Node node, Configuration config) {
|
||||
predicate localFlowEntry(Node node, Configuration config) {
|
||||
nodeCand2(node, config) and
|
||||
(
|
||||
config.isSource(node) or
|
||||
@@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption {
|
||||
* Holds if `node` is reachable with access path `ap` from a source in
|
||||
* the configuration `config`.
|
||||
*
|
||||
* The Boolean `fromArg` records whether the node is reached through an
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `argAp` records the access path of that
|
||||
* argument.
|
||||
*/
|
||||
private predicate flowFwd(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwd0(node, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd0(node, cc, argAp, apf, ap, config) and
|
||||
flowCand(node, _, _, apf, config)
|
||||
}
|
||||
|
||||
private predicate flowFwd0(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowCand(node, _, _, _, config) and
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, argAp, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, _)
|
||||
exists(Node mid, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, localCC)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, argAp, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, _) and
|
||||
exists(Node mid, AccessPathNil nil, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, localCC) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
flowFwd(mid, _, _, apf, ap, config) and
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, _, _, _, nil, config) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
@@ -1704,40 +1704,51 @@ private predicate flowFwd0(
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config))
|
||||
or
|
||||
// read
|
||||
exists(TypedContent tc |
|
||||
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
|
||||
flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and
|
||||
flowFwdConsCand(tc, apf, ap, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
flowFwdIn(_, node, _, _, apf, ap, config) and
|
||||
fromArg = true and
|
||||
flowFwdIn(_, node, _, cc, _, apf, ap, config) and
|
||||
if flowCand(node, true, _, apf, config)
|
||||
then argAp = TAccessPathSome(ap)
|
||||
else argAp = TAccessPathNone()
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call |
|
||||
flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and
|
||||
fromArg = false
|
||||
exists(DataFlowCallable c |
|
||||
flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and
|
||||
if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext()
|
||||
)
|
||||
or
|
||||
exists(AccessPath argAp0 |
|
||||
flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and
|
||||
flowFwdIsEntered(call, fromArg, argAp, argAp0, config)
|
||||
flowFwdIsEntered(call, cc, argAp, argAp0, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdLocalEntry(
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
LocalCallContext localCC, Configuration config
|
||||
) {
|
||||
flowFwd(node, cc, argAp, apf, ap, config) and
|
||||
localFlowEntry(node, config) and
|
||||
localCC = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdStore(
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, AccessPathFront apf0 |
|
||||
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(mid, cc, argAp, apf0, ap0, config) and
|
||||
flowFwdStore0(mid, tc, node, apf0, apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1764,20 +1775,20 @@ private predicate flowFwdStore0(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead0(
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
|
||||
boolean fromArg, AccessPathOption argAp, Configuration config
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(node1, cc, argAp, apf0, ap0, config) and
|
||||
readCandFwd(node1, tc, apf0, node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead(
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and
|
||||
flowCand(node, _, _, apf, unbind(config)) and
|
||||
flowCandConsCand(tc, apf, unbind(config))
|
||||
)
|
||||
@@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIn(
|
||||
DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
flowFwd(arg, fromArg, argAp, apf, ap, config) and
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c |
|
||||
flowFwd(arg, outercc, argAp, apf, ap, config) and
|
||||
flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and
|
||||
flowCand(p, _, _, _, unbind(config))
|
||||
c = p.getEnclosingCallable() and
|
||||
c = resolveCall(call, outercc) and
|
||||
flowCand(p, _, _, _, unbind(config)) and
|
||||
if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall()
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1809,13 +1823,19 @@ private predicate flowFwdIn(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdOut(
|
||||
DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow |
|
||||
flowFwd(ret, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd(ret, innercc, argAp, apf, ap, config) and
|
||||
flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and
|
||||
flowCand(node, _, _, _, unbind(config))
|
||||
innerc = ret.getEnclosingCallable() and
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
resolveReturn(innercc, innerc, call)
|
||||
or
|
||||
innercc.(CallContextCall).matchesCall(call)
|
||||
)
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg(
|
||||
DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config)
|
||||
flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIsEntered(
|
||||
DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, AccessPathFront apf |
|
||||
flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and
|
||||
flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and
|
||||
flowCand(p, true, TAccessPathFrontSome(_), apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1920,7 +1940,7 @@ private predicate flow0(
|
||||
// flow out of a callable
|
||||
flowOut(_, node, _, _, ap, config) and
|
||||
toReturn = true and
|
||||
if flowFwd(node, true, TAccessPathSome(_), _, ap, config)
|
||||
if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config)
|
||||
then returnAp = TAccessPathSome(ap)
|
||||
else returnAp = TAccessPathNone()
|
||||
}
|
||||
@@ -2006,9 +2026,10 @@ private predicate flowIsReturned(
|
||||
DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
exists(ReturnNodeExt ret, CallContextCall ccc |
|
||||
flowOut(call, ret, toReturn, returnAp, ap, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(_), _, ap, config)
|
||||
flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and
|
||||
ccc.matchesCall(call)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2031,7 +2052,7 @@ private newtype TSummaryCtx =
|
||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 |
|
||||
parameterFlow(p, ap, ret.getEnclosingCallable(), config) and
|
||||
flow(ret, true, TAccessPathSome(_), ap0, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config)
|
||||
flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0(
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
@@ -2867,7 +2888,7 @@ private module FlowExploration {
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
@@ -1066,7 +1066,7 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(Node node, Configuration config) {
|
||||
predicate localFlowEntry(Node node, Configuration config) {
|
||||
nodeCand2(node, config) and
|
||||
(
|
||||
config.isSource(node) or
|
||||
@@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption {
|
||||
* Holds if `node` is reachable with access path `ap` from a source in
|
||||
* the configuration `config`.
|
||||
*
|
||||
* The Boolean `fromArg` records whether the node is reached through an
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `argAp` records the access path of that
|
||||
* argument.
|
||||
*/
|
||||
private predicate flowFwd(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwd0(node, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd0(node, cc, argAp, apf, ap, config) and
|
||||
flowCand(node, _, _, apf, config)
|
||||
}
|
||||
|
||||
private predicate flowFwd0(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowCand(node, _, _, _, config) and
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, argAp, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, _)
|
||||
exists(Node mid, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, localCC)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, argAp, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, _) and
|
||||
exists(Node mid, AccessPathNil nil, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, localCC) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
flowFwd(mid, _, _, apf, ap, config) and
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, _, _, _, nil, config) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
@@ -1704,40 +1704,51 @@ private predicate flowFwd0(
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config))
|
||||
or
|
||||
// read
|
||||
exists(TypedContent tc |
|
||||
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
|
||||
flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and
|
||||
flowFwdConsCand(tc, apf, ap, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
flowFwdIn(_, node, _, _, apf, ap, config) and
|
||||
fromArg = true and
|
||||
flowFwdIn(_, node, _, cc, _, apf, ap, config) and
|
||||
if flowCand(node, true, _, apf, config)
|
||||
then argAp = TAccessPathSome(ap)
|
||||
else argAp = TAccessPathNone()
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call |
|
||||
flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and
|
||||
fromArg = false
|
||||
exists(DataFlowCallable c |
|
||||
flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and
|
||||
if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext()
|
||||
)
|
||||
or
|
||||
exists(AccessPath argAp0 |
|
||||
flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and
|
||||
flowFwdIsEntered(call, fromArg, argAp, argAp0, config)
|
||||
flowFwdIsEntered(call, cc, argAp, argAp0, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdLocalEntry(
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
LocalCallContext localCC, Configuration config
|
||||
) {
|
||||
flowFwd(node, cc, argAp, apf, ap, config) and
|
||||
localFlowEntry(node, config) and
|
||||
localCC = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdStore(
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, AccessPathFront apf0 |
|
||||
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(mid, cc, argAp, apf0, ap0, config) and
|
||||
flowFwdStore0(mid, tc, node, apf0, apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1764,20 +1775,20 @@ private predicate flowFwdStore0(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead0(
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
|
||||
boolean fromArg, AccessPathOption argAp, Configuration config
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(node1, cc, argAp, apf0, ap0, config) and
|
||||
readCandFwd(node1, tc, apf0, node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead(
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and
|
||||
flowCand(node, _, _, apf, unbind(config)) and
|
||||
flowCandConsCand(tc, apf, unbind(config))
|
||||
)
|
||||
@@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIn(
|
||||
DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
flowFwd(arg, fromArg, argAp, apf, ap, config) and
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c |
|
||||
flowFwd(arg, outercc, argAp, apf, ap, config) and
|
||||
flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and
|
||||
flowCand(p, _, _, _, unbind(config))
|
||||
c = p.getEnclosingCallable() and
|
||||
c = resolveCall(call, outercc) and
|
||||
flowCand(p, _, _, _, unbind(config)) and
|
||||
if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall()
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1809,13 +1823,19 @@ private predicate flowFwdIn(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdOut(
|
||||
DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow |
|
||||
flowFwd(ret, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd(ret, innercc, argAp, apf, ap, config) and
|
||||
flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and
|
||||
flowCand(node, _, _, _, unbind(config))
|
||||
innerc = ret.getEnclosingCallable() and
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
resolveReturn(innercc, innerc, call)
|
||||
or
|
||||
innercc.(CallContextCall).matchesCall(call)
|
||||
)
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg(
|
||||
DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config)
|
||||
flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIsEntered(
|
||||
DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, AccessPathFront apf |
|
||||
flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and
|
||||
flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and
|
||||
flowCand(p, true, TAccessPathFrontSome(_), apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1920,7 +1940,7 @@ private predicate flow0(
|
||||
// flow out of a callable
|
||||
flowOut(_, node, _, _, ap, config) and
|
||||
toReturn = true and
|
||||
if flowFwd(node, true, TAccessPathSome(_), _, ap, config)
|
||||
if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config)
|
||||
then returnAp = TAccessPathSome(ap)
|
||||
else returnAp = TAccessPathNone()
|
||||
}
|
||||
@@ -2006,9 +2026,10 @@ private predicate flowIsReturned(
|
||||
DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
exists(ReturnNodeExt ret, CallContextCall ccc |
|
||||
flowOut(call, ret, toReturn, returnAp, ap, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(_), _, ap, config)
|
||||
flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and
|
||||
ccc.matchesCall(call)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2031,7 +2052,7 @@ private newtype TSummaryCtx =
|
||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 |
|
||||
parameterFlow(p, ap, ret.getEnclosingCallable(), config) and
|
||||
flow(ret, true, TAccessPathSome(_), ap0, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config)
|
||||
flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0(
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
@@ -2867,7 +2888,7 @@ private module FlowExploration {
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
@@ -1066,7 +1066,7 @@ private module LocalFlowBigStep {
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
*/
|
||||
private predicate localFlowEntry(Node node, Configuration config) {
|
||||
predicate localFlowEntry(Node node, Configuration config) {
|
||||
nodeCand2(node, config) and
|
||||
(
|
||||
config.isSource(node) or
|
||||
@@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption {
|
||||
* Holds if `node` is reachable with access path `ap` from a source in
|
||||
* the configuration `config`.
|
||||
*
|
||||
* The Boolean `fromArg` records whether the node is reached through an
|
||||
* The call context `cc` records whether the node is reached through an
|
||||
* argument in a call, and if so, `argAp` records the access path of that
|
||||
* argument.
|
||||
*/
|
||||
private predicate flowFwd(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwd0(node, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd0(node, cc, argAp, apf, ap, config) and
|
||||
flowCand(node, _, _, apf, config)
|
||||
}
|
||||
|
||||
private predicate flowFwd0(
|
||||
Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowCand(node, _, _, _, config) and
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, argAp, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, _)
|
||||
exists(Node mid, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and
|
||||
localFlowBigStep(mid, node, true, _, config, localCC)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, argAp, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, _) and
|
||||
exists(Node mid, AccessPathNil nil, LocalCallContext localCC |
|
||||
flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and
|
||||
localFlowBigStep(mid, node, false, apf, config, localCC) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
flowFwd(mid, _, _, apf, ap, config) and
|
||||
jumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, _, _, _, nil, config) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
cc instanceof CallContextAny and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
@@ -1704,40 +1704,51 @@ private predicate flowFwd0(
|
||||
)
|
||||
or
|
||||
// store
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config))
|
||||
exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config))
|
||||
or
|
||||
// read
|
||||
exists(TypedContent tc |
|
||||
flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and
|
||||
flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and
|
||||
flowFwdConsCand(tc, apf, ap, config)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
flowFwdIn(_, node, _, _, apf, ap, config) and
|
||||
fromArg = true and
|
||||
flowFwdIn(_, node, _, cc, _, apf, ap, config) and
|
||||
if flowCand(node, true, _, apf, config)
|
||||
then argAp = TAccessPathSome(ap)
|
||||
else argAp = TAccessPathNone()
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(DataFlowCall call |
|
||||
flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and
|
||||
fromArg = false
|
||||
exists(DataFlowCallable c |
|
||||
flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and
|
||||
if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext()
|
||||
)
|
||||
or
|
||||
exists(AccessPath argAp0 |
|
||||
flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and
|
||||
flowFwdIsEntered(call, fromArg, argAp, argAp0, config)
|
||||
flowFwdIsEntered(call, cc, argAp, argAp0, config)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdLocalEntry(
|
||||
Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap,
|
||||
LocalCallContext localCC, Configuration config
|
||||
) {
|
||||
flowFwd(node, cc, argAp, apf, ap, config) and
|
||||
localFlowEntry(node, config) and
|
||||
localCC = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdStore(
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, AccessPathFront apf0 |
|
||||
flowFwd(mid, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(mid, cc, argAp, apf0, ap0, config) and
|
||||
flowFwdStore0(mid, tc, node, apf0, apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1764,20 +1775,20 @@ private predicate flowFwdStore0(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead0(
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2,
|
||||
boolean fromArg, AccessPathOption argAp, Configuration config
|
||||
Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
flowFwd(node1, fromArg, argAp, apf0, ap0, config) and
|
||||
flowFwd(node1, cc, argAp, apf0, ap0, config) and
|
||||
readCandFwd(node1, tc, apf0, node2, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdRead(
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg,
|
||||
Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc,
|
||||
AccessPathOption argAp, Configuration config
|
||||
) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and
|
||||
flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and
|
||||
flowCand(node, _, _, apf, unbind(config)) and
|
||||
flowCandConsCand(tc, apf, unbind(config))
|
||||
)
|
||||
@@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIn(
|
||||
DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
flowFwd(arg, fromArg, argAp, apf, ap, config) and
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c |
|
||||
flowFwd(arg, outercc, argAp, apf, ap, config) and
|
||||
flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and
|
||||
flowCand(p, _, _, _, unbind(config))
|
||||
c = p.getEnclosingCallable() and
|
||||
c = resolveCall(call, outercc) and
|
||||
flowCand(p, _, _, _, unbind(config)) and
|
||||
if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall()
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1809,13 +1823,19 @@ private predicate flowFwdIn(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdOut(
|
||||
DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf,
|
||||
AccessPath ap, Configuration config
|
||||
DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc,
|
||||
AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow |
|
||||
flowFwd(ret, fromArg, argAp, apf, ap, config) and
|
||||
flowFwd(ret, innercc, argAp, apf, ap, config) and
|
||||
flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and
|
||||
flowCand(node, _, _, _, unbind(config))
|
||||
innerc = ret.getEnclosingCallable() and
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
(
|
||||
resolveReturn(innercc, innerc, call)
|
||||
or
|
||||
innercc.(CallContextCall).matchesCall(call)
|
||||
)
|
||||
|
|
||||
ap instanceof AccessPathNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg(
|
||||
DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config)
|
||||
flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowFwdIsEntered(
|
||||
DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, AccessPathFront apf |
|
||||
flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and
|
||||
flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and
|
||||
flowCand(p, true, TAccessPathFrontSome(_), apf, config)
|
||||
)
|
||||
}
|
||||
@@ -1920,7 +1940,7 @@ private predicate flow0(
|
||||
// flow out of a callable
|
||||
flowOut(_, node, _, _, ap, config) and
|
||||
toReturn = true and
|
||||
if flowFwd(node, true, TAccessPathSome(_), _, ap, config)
|
||||
if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config)
|
||||
then returnAp = TAccessPathSome(ap)
|
||||
else returnAp = TAccessPathNone()
|
||||
}
|
||||
@@ -2006,9 +2026,10 @@ private predicate flowIsReturned(
|
||||
DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
exists(ReturnNodeExt ret, CallContextCall ccc |
|
||||
flowOut(call, ret, toReturn, returnAp, ap, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(_), _, ap, config)
|
||||
flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and
|
||||
ccc.matchesCall(call)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2031,7 +2052,7 @@ private newtype TSummaryCtx =
|
||||
exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 |
|
||||
parameterFlow(p, ap, ret.getEnclosingCallable(), config) and
|
||||
flow(ret, true, TAccessPathSome(_), ap0, config) and
|
||||
flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config)
|
||||
flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0(
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
@@ -2867,7 +2888,7 @@ private module FlowExploration {
|
||||
) {
|
||||
pos = getReturnPosition(mid.getNode()) and
|
||||
innercc = mid.getCallContext() and
|
||||
not innercc instanceof CallContextCall and
|
||||
innercc instanceof CallContextNoCall and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
}
|
||||
|
||||
@@ -512,13 +512,19 @@ abstract class CallContext extends TCallContext {
|
||||
abstract predicate relevantFor(DataFlowCallable callable);
|
||||
}
|
||||
|
||||
class CallContextAny extends CallContext, TAnyCallContext {
|
||||
abstract class CallContextNoCall extends CallContext { }
|
||||
|
||||
class CallContextAny extends CallContextNoCall, TAnyCallContext {
|
||||
override string toString() { result = "CcAny" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) { any() }
|
||||
}
|
||||
|
||||
abstract class CallContextCall extends CallContext { }
|
||||
abstract class CallContextCall extends CallContext {
|
||||
/** Holds if this call context may be `call`. */
|
||||
bindingset[call]
|
||||
abstract predicate matchesCall(DataFlowCall call);
|
||||
}
|
||||
|
||||
class CallContextSpecificCall extends CallContextCall, TSpecificCall {
|
||||
override string toString() {
|
||||
@@ -529,6 +535,8 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall {
|
||||
recordDataFlowCallSite(getCall(), callable)
|
||||
}
|
||||
|
||||
override predicate matchesCall(DataFlowCall call) { call = this.getCall() }
|
||||
|
||||
DataFlowCall getCall() { this = TSpecificCall(result) }
|
||||
}
|
||||
|
||||
@@ -538,9 +546,11 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(ParameterNode p | p.getEnclosingCallable() = callable)
|
||||
}
|
||||
|
||||
override predicate matchesCall(DataFlowCall call) { any() }
|
||||
}
|
||||
|
||||
class CallContextReturn extends CallContext, TReturn {
|
||||
class CallContextReturn extends CallContextNoCall, TReturn {
|
||||
override string toString() {
|
||||
exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")")
|
||||
}
|
||||
|
||||
@@ -395,7 +395,7 @@ private predicate fieldOrPropertyStore(Expr e, Content c, Expr src, Expr q, bool
|
||||
f.isFieldLike() and
|
||||
f instanceof InstanceFieldOrProperty
|
||||
or
|
||||
exists(AccessPath ap |
|
||||
exists(LibraryFlow::AdjustedAccessPath ap |
|
||||
LibraryFlow::libraryFlowSummary(_, _, ap, _, _, _) and
|
||||
ap.contains(f.getContent())
|
||||
)
|
||||
@@ -440,7 +440,7 @@ private predicate fieldOrPropertyRead(Expr e1, Content c, FieldOrPropertyRead e2
|
||||
ret.isFieldLike() and
|
||||
ret = e2.getTarget()
|
||||
or
|
||||
exists(AccessPath ap, Property target |
|
||||
exists(LibraryFlow::AdjustedAccessPath ap, Property target |
|
||||
LibraryFlow::libraryFlowSummary(_, _, _, _, ap, _) and
|
||||
ap.contains(ret.getContent()) and
|
||||
target.getGetter() = e2.(PropertyCall).getARuntimeTarget() and
|
||||
@@ -569,8 +569,9 @@ private module Cached {
|
||||
)
|
||||
} or
|
||||
TLibraryCodeNode(
|
||||
ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp,
|
||||
CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue, LibraryCodeNodeState state
|
||||
ControlFlow::Node callCfn, CallableFlowSource source, AdjustedAccessPath sourceAp,
|
||||
CallableFlowSink sink, AdjustedAccessPath sinkAp, boolean preservesValue,
|
||||
LibraryCodeNodeState state
|
||||
) {
|
||||
libraryFlowSummary(callCfn.getElement(), source, sourceAp, sink, sinkAp, preservesValue) and
|
||||
(
|
||||
@@ -1451,11 +1452,12 @@ import OutNodes
|
||||
module LibraryFlow {
|
||||
pragma[nomagic]
|
||||
private ValueOrRefType getPreciseSourceProperty0(
|
||||
Call call, CallableFlowSource source, AccessPath sourceAp, Property p
|
||||
Call call, CallableFlowSource source, AccessPath sourceAp, Property p, AccessPath sourceApTail
|
||||
) {
|
||||
exists(LibraryTypeDataFlow ltdf, Property p0 |
|
||||
ltdf.callableFlow(source, sourceAp, _, _, call.getTarget().getSourceDeclaration(), _) and
|
||||
sourceAp = AccessPath::property(p0) and
|
||||
sourceAp.getHead().(PropertyContent).getProperty() = p0 and
|
||||
sourceAp.getTail() = sourceApTail and
|
||||
overridesOrImplementsSourceDecl(p, p0) and
|
||||
result = source.getSourceType(call)
|
||||
)
|
||||
@@ -1476,18 +1478,19 @@ module LibraryFlow {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private Property getPreciseSourceProperty(
|
||||
Call call, CallableFlowSource source, AccessPath sourceAp
|
||||
Call call, CallableFlowSource source, AccessPath sourceAp, AccessPath sourceApTail
|
||||
) {
|
||||
getPreciseSourceProperty0(call, source, sourceAp, result).hasMember(result)
|
||||
getPreciseSourceProperty0(call, source, sourceAp, result, sourceApTail).hasMember(result)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private ValueOrRefType getPreciseSinkProperty0(
|
||||
Call call, CallableFlowSink sink, AccessPath sinkAp, Property p
|
||||
Call call, CallableFlowSink sink, AccessPath sinkAp, Property p, AccessPath sinkApTail
|
||||
) {
|
||||
exists(LibraryTypeDataFlow ltdf, Property p0 |
|
||||
ltdf.callableFlow(_, _, sink, sinkAp, call.getTarget().getSourceDeclaration(), _) and
|
||||
sinkAp = AccessPath::property(p0) and
|
||||
sinkAp.getHead().(PropertyContent).getProperty() = p0 and
|
||||
sinkAp.getTail() = sinkApTail and
|
||||
overridesOrImplementsSourceDecl(p, p0) and
|
||||
result = sink.getSinkType(call)
|
||||
)
|
||||
@@ -1510,8 +1513,132 @@ module LibraryFlow {
|
||||
* from `IEnumerator<T>`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private Property getPreciseSinkProperty(Call call, CallableFlowSink sink, AccessPath sinkAp) {
|
||||
getPreciseSinkProperty0(call, sink, sinkAp, result).hasMember(result)
|
||||
private Property getPreciseSinkProperty(
|
||||
Call call, CallableFlowSink sink, AccessPath sinkAp, AccessPath sinkApTail
|
||||
) {
|
||||
getPreciseSinkProperty0(call, sink, sinkAp, result, sinkApTail).hasMember(result)
|
||||
}
|
||||
|
||||
predicate adjustSourceHead(
|
||||
Call call, CallableFlowSource source, AccessPath sourceAp0, AccessPath sourceApTail,
|
||||
PropertyContent p
|
||||
) {
|
||||
overridesOrImplementsSourceDecl(p.getProperty(),
|
||||
getPreciseSourceProperty(call, source, sourceAp0, sourceApTail).getSourceDeclaration())
|
||||
}
|
||||
|
||||
predicate adjustSinkHead(
|
||||
Call call, CallableFlowSink sink, AccessPath sinkAp0, AccessPath sinkApTail, PropertyContent p
|
||||
) {
|
||||
p.getProperty() = getPreciseSinkProperty(call, sink, sinkAp0, sinkApTail).getSourceDeclaration()
|
||||
}
|
||||
|
||||
private newtype TAdjustedAccessPath =
|
||||
TOriginalAccessPath(AccessPath ap) or
|
||||
THeadAdjustedAccessPath(PropertyContent head, AccessPath tail) {
|
||||
adjustSourceHead(_, _, _, tail, head)
|
||||
or
|
||||
adjustSinkHead(_, _, _, tail, head)
|
||||
}
|
||||
|
||||
/**
|
||||
* An access path used in a library-code flow-summary, where the head of the path
|
||||
* may have been adjusted. For example, in
|
||||
*
|
||||
* ```csharp
|
||||
* var list = new List<string>();
|
||||
* list.Add("taint");
|
||||
* var enumerator = list.getEnumerator();
|
||||
* ```
|
||||
*
|
||||
* the step from `list` to `list.getEnumerator()`, which may be modeled as a
|
||||
* read of a collection element followed by a store into the `Current`
|
||||
* property, can be strengthened to be a store into the `Current` property
|
||||
* from `List<T>.Enumerator`, rather than the generic `Current` property
|
||||
* from `IEnumerator<T>`.
|
||||
*/
|
||||
abstract class AdjustedAccessPath extends TAdjustedAccessPath {
|
||||
/** Gets the head of this access path, if any. */
|
||||
abstract Content getHead();
|
||||
|
||||
/** Gets the tail of this access path, if any. */
|
||||
abstract AdjustedAccessPath getTail();
|
||||
|
||||
/** Gets the length of this access path. */
|
||||
abstract int length();
|
||||
|
||||
/** Gets the access path obtained by dropping the first `i` elements, if any. */
|
||||
abstract AdjustedAccessPath drop(int i);
|
||||
|
||||
/** Holds if this access path contains content `c`. */
|
||||
predicate contains(Content c) { c = this.drop(_).getHead() }
|
||||
|
||||
/** Gets a textual representation of this access path. */
|
||||
string toString() {
|
||||
exists(Content head, AdjustedAccessPath tail |
|
||||
head = this.getHead() and
|
||||
tail = this.getTail() and
|
||||
if tail.length() = 0 then result = head.toString() else result = head + ", " + tail
|
||||
)
|
||||
or
|
||||
this.length() = 0 and
|
||||
result = "<empty>"
|
||||
}
|
||||
}
|
||||
|
||||
private class OriginalAccessPath extends AdjustedAccessPath, TOriginalAccessPath {
|
||||
private AccessPath ap;
|
||||
|
||||
OriginalAccessPath() { this = TOriginalAccessPath(ap) }
|
||||
|
||||
override Content getHead() { result = ap.getHead() }
|
||||
|
||||
override AdjustedAccessPath getTail() { result = TOriginalAccessPath(ap.getTail()) }
|
||||
|
||||
override int length() { result = ap.length() }
|
||||
|
||||
override AdjustedAccessPath drop(int i) { result = TOriginalAccessPath(ap.drop(i)) }
|
||||
}
|
||||
|
||||
private class HeadAdjustedAccessPath extends AdjustedAccessPath, THeadAdjustedAccessPath {
|
||||
private PropertyContent head;
|
||||
private AccessPath tail;
|
||||
|
||||
HeadAdjustedAccessPath() { this = THeadAdjustedAccessPath(head, tail) }
|
||||
|
||||
override Content getHead() { result = head }
|
||||
|
||||
override AdjustedAccessPath getTail() { result = TOriginalAccessPath(tail) }
|
||||
|
||||
override int length() { result = 1 + tail.length() }
|
||||
|
||||
override AdjustedAccessPath drop(int i) {
|
||||
i = 0 and result = this
|
||||
or
|
||||
result = TOriginalAccessPath(tail.drop(i - 1))
|
||||
}
|
||||
}
|
||||
|
||||
module AdjustedAccessPath {
|
||||
AdjustedAccessPath empty() { result.length() = 0 }
|
||||
|
||||
AdjustedAccessPath singleton(Content c) { result.getHead() = c and result.length() = 1 }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate callableFlow(
|
||||
CallableFlowSource source, AccessPath sourceAp, boolean adjustSourceAp, CallableFlowSink sink,
|
||||
AccessPath sinkAp, boolean adjustSinkAp, SourceDeclarationCallable c, boolean preservesValue
|
||||
) {
|
||||
any(LibraryTypeDataFlow ltdf).callableFlow(source, sourceAp, sink, sinkAp, c, preservesValue) and
|
||||
(
|
||||
if sourceAp.getHead() instanceof PropertyContent
|
||||
then adjustSourceAp = true
|
||||
else adjustSourceAp = false
|
||||
) and
|
||||
if sinkAp.getHead() instanceof PropertyContent
|
||||
then adjustSinkAp = true
|
||||
else adjustSinkAp = false
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1524,33 +1651,38 @@ module LibraryFlow {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate libraryFlowSummary(
|
||||
Call call, CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink,
|
||||
AccessPath sinkAp, boolean preservesValue
|
||||
Call call, CallableFlowSource source, AdjustedAccessPath sourceAp, CallableFlowSink sink,
|
||||
AdjustedAccessPath sinkAp, boolean preservesValue
|
||||
) {
|
||||
exists(LibraryTypeDataFlow ltdf, SourceDeclarationCallable c |
|
||||
c = call.getTarget().getSourceDeclaration()
|
||||
|
|
||||
ltdf.callableFlow(source, sink, c, preservesValue) and
|
||||
sourceAp = AccessPath::empty() and
|
||||
sinkAp = AccessPath::empty()
|
||||
exists(SourceDeclarationCallable c | c = call.getTarget().getSourceDeclaration() |
|
||||
any(LibraryTypeDataFlow ltdf).callableFlow(source, sink, c, preservesValue) and
|
||||
sourceAp = TOriginalAccessPath(AccessPath::empty()) and
|
||||
sinkAp = TOriginalAccessPath(AccessPath::empty())
|
||||
or
|
||||
exists(AccessPath sourceAp0, AccessPath sinkAp0 |
|
||||
ltdf.callableFlow(source, sourceAp0, sink, sinkAp0, c, preservesValue) and
|
||||
exists(
|
||||
AccessPath sourceAp0, boolean adjustSourceAp, AccessPath sinkAp0, boolean adjustSinkAp
|
||||
|
|
||||
callableFlow(source, sourceAp0, adjustSourceAp, sink, sinkAp0, adjustSinkAp, c,
|
||||
preservesValue) and
|
||||
(
|
||||
not sourceAp0 = AccessPath::property(_) and
|
||||
sourceAp = sourceAp0
|
||||
adjustSourceAp = false and
|
||||
sourceAp = TOriginalAccessPath(sourceAp0)
|
||||
or
|
||||
exists(Property p |
|
||||
overridesOrImplementsSourceDecl(p,
|
||||
getPreciseSourceProperty(call, source, sourceAp0).getSourceDeclaration()) and
|
||||
sourceAp = AccessPath::property(p)
|
||||
adjustSourceAp = true and
|
||||
exists(PropertyContent p, AccessPath sourceApTail |
|
||||
adjustSourceHead(call, source, sourceAp0, sourceApTail, p) and
|
||||
sourceAp = THeadAdjustedAccessPath(p, sourceApTail)
|
||||
)
|
||||
) and
|
||||
(
|
||||
not sinkAp0 = AccessPath::property(_) and
|
||||
sinkAp = sinkAp0
|
||||
adjustSinkAp = false and
|
||||
sinkAp = TOriginalAccessPath(sinkAp0)
|
||||
or
|
||||
sinkAp = AccessPath::property(getPreciseSinkProperty(call, sink, sinkAp0))
|
||||
adjustSinkAp = true and
|
||||
exists(PropertyContent p, AccessPath sinkApTail |
|
||||
adjustSinkHead(call, sink, sinkAp0, sinkApTail, p) and
|
||||
sinkAp = THeadAdjustedAccessPath(p, sinkApTail)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -1606,8 +1738,8 @@ module LibraryFlow {
|
||||
}
|
||||
|
||||
newtype TLibraryCodeNodeState =
|
||||
TLibraryCodeNodeAfterReadState(AccessPath ap) { ap.length() > 0 } or
|
||||
TLibraryCodeNodeBeforeStoreState(AccessPath ap) { ap.length() > 0 }
|
||||
TLibraryCodeNodeAfterReadState(AdjustedAccessPath ap) { ap.length() > 0 } or
|
||||
TLibraryCodeNodeBeforeStoreState(AdjustedAccessPath ap) { ap.length() > 0 }
|
||||
|
||||
/**
|
||||
* A state used to break up (complex) flow summaries for library code into atomic
|
||||
@@ -1626,12 +1758,12 @@ module LibraryFlow {
|
||||
*/
|
||||
class LibraryCodeNodeState extends TLibraryCodeNodeState {
|
||||
string toString() {
|
||||
exists(AccessPath ap |
|
||||
exists(AdjustedAccessPath ap |
|
||||
this = TLibraryCodeNodeAfterReadState(ap) and
|
||||
result = "after read: " + ap
|
||||
)
|
||||
or
|
||||
exists(AccessPath ap |
|
||||
exists(AdjustedAccessPath ap |
|
||||
this = TLibraryCodeNodeBeforeStoreState(ap) and
|
||||
result = "before store: " + ap
|
||||
)
|
||||
@@ -1639,12 +1771,12 @@ module LibraryFlow {
|
||||
|
||||
/** Holds if this state represents the state after the last read. */
|
||||
predicate isLastReadState() {
|
||||
this = TLibraryCodeNodeAfterReadState(any(AccessPath ap | ap.length() = 1))
|
||||
this = TLibraryCodeNodeAfterReadState(AdjustedAccessPath::singleton(_))
|
||||
}
|
||||
|
||||
/** Holds if this state represents the state before the first store. */
|
||||
predicate isFirstStoreState() {
|
||||
this = TLibraryCodeNodeBeforeStoreState(any(AccessPath ap | ap.length() = 1))
|
||||
this = TLibraryCodeNodeBeforeStoreState(AdjustedAccessPath::singleton(_))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1726,21 +1858,21 @@ module LibraryFlow {
|
||||
*/
|
||||
predicate localStepLibrary(Node pred, Node succ, boolean preservesValue) {
|
||||
exists(
|
||||
ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp,
|
||||
CallableFlowSink sink, AccessPath sinkAp
|
||||
ControlFlow::Node callCfn, CallableFlowSource source, AdjustedAccessPath sourceAp,
|
||||
CallableFlowSink sink, AdjustedAccessPath sinkAp
|
||||
|
|
||||
libraryFlowSummary(callCfn.getElement(), source, sourceAp, sink, sinkAp, preservesValue)
|
||||
|
|
||||
// Simple flow summary without reads or stores
|
||||
sourceAp = AccessPath::empty() and
|
||||
sinkAp = AccessPath::empty() and
|
||||
sourceAp = AdjustedAccessPath::empty() and
|
||||
sinkAp = AdjustedAccessPath::empty() and
|
||||
entry(pred, callCfn, source) and
|
||||
exit(succ, callCfn, sink)
|
||||
or
|
||||
// Entry step for a complex summary with no reads and (1) multiple stores, or
|
||||
// (2) at least one store and non-value-preservation
|
||||
exists(LibraryCodeNodeState succState |
|
||||
sourceAp.length() = 0 and
|
||||
sourceAp = AdjustedAccessPath::empty() and
|
||||
entry(pred, callCfn, source) and
|
||||
succState.isFirstStoreState() and
|
||||
succ = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, succState)
|
||||
@@ -1749,7 +1881,7 @@ module LibraryFlow {
|
||||
// Exit step for a complex summary with no stores and (1) multiple reads, or
|
||||
// (2) at least one read and non-value-preservation
|
||||
exists(LibraryCodeNodeState predState |
|
||||
sinkAp.length() = 0 and
|
||||
sinkAp = AdjustedAccessPath::empty() and
|
||||
predState.isLastReadState() and
|
||||
pred = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, predState) and
|
||||
exit(succ, callCfn, sink)
|
||||
@@ -1758,8 +1890,8 @@ module LibraryFlow {
|
||||
or
|
||||
// Internal step for complex flow summaries with both reads and writes
|
||||
exists(
|
||||
ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp,
|
||||
CallableFlowSink sink, AccessPath sinkAp, LibraryCodeNodeState predState,
|
||||
ControlFlow::Node callCfn, CallableFlowSource source, AdjustedAccessPath sourceAp,
|
||||
CallableFlowSink sink, AdjustedAccessPath sinkAp, LibraryCodeNodeState predState,
|
||||
LibraryCodeNodeState succState
|
||||
|
|
||||
predState.isLastReadState() and
|
||||
@@ -1775,8 +1907,8 @@ module LibraryFlow {
|
||||
*/
|
||||
predicate setterLibrary(Node pred, Content c, Node succ, boolean preservesValue) {
|
||||
exists(ControlFlow::Node callCfn, CallableFlowSource source, CallableFlowSink sink |
|
||||
libraryFlowSummary(callCfn.getElement(), source, AccessPath::empty(), sink,
|
||||
AccessPath::singleton(c), preservesValue)
|
||||
libraryFlowSummary(callCfn.getElement(), source, AdjustedAccessPath::empty(), sink,
|
||||
AdjustedAccessPath::singleton(c), preservesValue)
|
||||
|
|
||||
entry(pred, callCfn, source) and
|
||||
exit(succ, callCfn, sink)
|
||||
@@ -1790,9 +1922,9 @@ module LibraryFlow {
|
||||
predicate storeStepLibrary(Node pred, Content c, Node succ) {
|
||||
// Complex flow summary
|
||||
exists(
|
||||
ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp,
|
||||
CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue,
|
||||
LibraryCodeNodeState predState, AccessPath ap
|
||||
ControlFlow::Node callCfn, CallableFlowSource source, AdjustedAccessPath sourceAp,
|
||||
CallableFlowSink sink, AdjustedAccessPath sinkAp, boolean preservesValue,
|
||||
LibraryCodeNodeState predState, AdjustedAccessPath ap
|
||||
|
|
||||
predState = TLibraryCodeNodeBeforeStoreState(ap) and
|
||||
pred = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, predState) and
|
||||
@@ -1800,7 +1932,8 @@ module LibraryFlow {
|
||||
|
|
||||
// More stores needed
|
||||
exists(LibraryCodeNodeState succState |
|
||||
succState = TLibraryCodeNodeBeforeStoreState(any(AccessPath succAp | succAp.getTail() = ap)) and
|
||||
succState =
|
||||
TLibraryCodeNodeBeforeStoreState(any(AdjustedAccessPath succAp | succAp.getTail() = ap)) and
|
||||
succ = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, succState)
|
||||
)
|
||||
or
|
||||
@@ -1819,8 +1952,8 @@ module LibraryFlow {
|
||||
*/
|
||||
predicate getterLibrary(Node pred, Content c, Node succ, boolean preservesValue) {
|
||||
exists(ControlFlow::Node callCfn, CallableFlowSource source, CallableFlowSink sink |
|
||||
libraryFlowSummary(callCfn.getElement(), source, AccessPath::singleton(c), sink,
|
||||
AccessPath::empty(), preservesValue) and
|
||||
libraryFlowSummary(callCfn.getElement(), source, AdjustedAccessPath::singleton(c), sink,
|
||||
AdjustedAccessPath::empty(), preservesValue) and
|
||||
entry(pred, callCfn, source) and
|
||||
exit(succ, callCfn, sink)
|
||||
)
|
||||
@@ -1833,9 +1966,9 @@ module LibraryFlow {
|
||||
predicate readStepLibrary(Node pred, Content c, Node succ) {
|
||||
// Complex flow summary
|
||||
exists(
|
||||
ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp,
|
||||
CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue,
|
||||
LibraryCodeNodeState succState, AccessPath ap
|
||||
ControlFlow::Node callCfn, CallableFlowSource source, AdjustedAccessPath sourceAp,
|
||||
CallableFlowSink sink, AdjustedAccessPath sinkAp, boolean preservesValue,
|
||||
LibraryCodeNodeState succState, AdjustedAccessPath ap
|
||||
|
|
||||
succState = TLibraryCodeNodeAfterReadState(ap) and
|
||||
succ = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, succState) and
|
||||
@@ -1846,7 +1979,7 @@ module LibraryFlow {
|
||||
entry(pred, callCfn, source)
|
||||
or
|
||||
// Subsequent reads
|
||||
exists(LibraryCodeNodeState predState, AccessPath predAp |
|
||||
exists(LibraryCodeNodeState predState, AdjustedAccessPath predAp |
|
||||
predState = TLibraryCodeNodeAfterReadState(predAp) and
|
||||
predAp.getTail() = ap and
|
||||
pred = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, predState)
|
||||
@@ -1886,9 +2019,9 @@ private DataFlowType getContentType(Content c) {
|
||||
class LibraryCodeNode extends NodeImpl, TLibraryCodeNode {
|
||||
private ControlFlow::Node callCfn;
|
||||
private CallableFlowSource source;
|
||||
private AccessPath sourceAp;
|
||||
private LibraryFlow::AdjustedAccessPath sourceAp;
|
||||
private CallableFlowSink sink;
|
||||
private AccessPath sinkAp;
|
||||
private LibraryFlow::AdjustedAccessPath sinkAp;
|
||||
private boolean preservesValue;
|
||||
private LibraryFlow::LibraryCodeNodeState state;
|
||||
|
||||
@@ -1899,7 +2032,7 @@ class LibraryCodeNode extends NodeImpl, TLibraryCodeNode {
|
||||
override Callable getEnclosingCallableImpl() { result = callCfn.getEnclosingCallable() }
|
||||
|
||||
override DataFlowType getDataFlowType() {
|
||||
exists(AccessPath ap |
|
||||
exists(LibraryFlow::AdjustedAccessPath ap |
|
||||
state = LibraryFlow::TLibraryCodeNodeAfterReadState(ap) and
|
||||
if sinkAp.length() = 0 and state.isLastReadState() and preservesValue = true
|
||||
then result = Gvn::getGlobalValueNumber(sink.getSinkType(callCfn.getElement()))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.dataflow.DataFlow2
|
||||
private import semmle.code.csharp.dataflow.DataFlow3
|
||||
|
||||
/** The `System.Xml` namespace. */
|
||||
class SystemXmlNamespace extends Namespace {
|
||||
@@ -163,7 +163,7 @@ class XmlReaderSettingsCreation extends ObjectCreation {
|
||||
}
|
||||
}
|
||||
|
||||
private class SettingsDataFlowConfig extends DataFlow2::Configuration {
|
||||
private class SettingsDataFlowConfig extends DataFlow3::Configuration {
|
||||
SettingsDataFlowConfig() { this = "SettingsDataFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
| test0.cs:13:18:13:43 | DerivesFromDeprecatedType1 | Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. |
|
||||
| test0.cs:59:18:59:38 | AttributeSerializer01 | Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security Features/Serialization/DefiningDatasetRelatedType.ql
|
||||
@@ -0,0 +1,2 @@
|
||||
| test0.cs:15:24:15:32 | MyDataSet | Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | test0.cs:13:18:13:43 | DerivesFromDeprecatedType1 | DerivesFromDeprecatedType1 | test0.cs:15:24:15:32 | MyDataSet | MyDataSet |
|
||||
| test0.cs:61:25:61:33 | MyDataSet | Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. | test0.cs:59:18:59:38 | AttributeSerializer01 | AttributeSerializer01 | test0.cs:61:25:61:33 | MyDataSet | MyDataSet |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security Features/Serialization/DefiningPotentiallyUnsafeXmlSerializer.ql
|
||||
@@ -0,0 +1,2 @@
|
||||
| test0.cs:95:49:95:63 | typeof(...) | Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source. | test0.cs:95:49:95:63 | typeof(...) | typeof(...) |
|
||||
| test0.cs:96:49:96:77 | typeof(...) | Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source. | test0.cs:96:49:96:77 | typeof(...) | typeof(...) |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security Features/Serialization/UnsafeTypeUsedDataContractSerializer.ql
|
||||
@@ -0,0 +1 @@
|
||||
| test0.cs:88:17:88:46 | call to method ReadXmlSchema | Making an XML deserialization call with a type derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details. |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security Features/Serialization/XmlDeserializationWithDataSet.ql
|
||||
@@ -0,0 +1,101 @@
|
||||
// semmle-extractor-options: /r:System.Data.Common.dll /r:System.Runtime.WindowsRuntime.dll /r:System.Xml.XmlSerializer.dll /r:System.Runtime.Serialization.Xml.dll /r:System.Runtime.Serialization.Xml.dll /r:System.Collections.dll /r:System.Private.Xml.dll /r:System.Private.DataContractSerialization.dll /r:System.Runtime.Extensions.dll /r:System.ComponentModel.TypeConverter.dll /r:System.Xml.ReaderWriter.dll /r:System.IO.FileSystem.dll
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Xml.Serialization;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Xml;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DataSetSerializationTest
|
||||
{
|
||||
public class DerivesFromDeprecatedType1 : XmlSerializer // warning:DefiningDatasetRelatedType.ql
|
||||
{
|
||||
public DataSet MyDataSet { get; set; } // bug:DefiningPotentiallyUnsafeXmlSerializer.ql
|
||||
|
||||
public DerivesFromDeprecatedType1()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: I cannot use DataContract on a QL unit test
|
||||
*
|
||||
[DataContract(Name = "Customer", Namespace = "http://www.contoso.com")]
|
||||
public class PatternDataContractSerializer : XmlObjectSerializer
|
||||
{
|
||||
[DataMember()]
|
||||
public DataSet MyDataSet { get; set; }
|
||||
[DataMember()]
|
||||
public DataTable MyDataTable { get; set; }
|
||||
|
||||
PatternDataContractSerializer() { }
|
||||
private ExtensionDataObject extensionData_Value;
|
||||
public ExtensionDataObject ExtensionData
|
||||
{
|
||||
get
|
||||
{
|
||||
return extensionData_Value;
|
||||
}
|
||||
set
|
||||
{
|
||||
extensionData_Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteObject(System.IO.Stream stream, object graph) { }
|
||||
public override void WriteObjectContent(System.Xml.XmlDictionaryWriter writer, object graph) { }
|
||||
public override bool IsStartObject(System.Xml.XmlDictionaryReader reader) { return false; }
|
||||
public override void WriteStartObject(System.Xml.XmlDictionaryWriter writer, object graph) { }
|
||||
public override void WriteEndObject(System.Xml.XmlWriter writer) { }
|
||||
public override void WriteEndObject(XmlDictionaryWriter writer) { }
|
||||
public override object ReadObject(System.IO.Stream stream) { return null; }
|
||||
public override object ReadObject(XmlDictionaryReader reader, bool b) { return null; }
|
||||
}
|
||||
*/
|
||||
|
||||
[Serializable()]
|
||||
public class AttributeSerializer01 // warning:DefiningDatasetRelatedType.ql
|
||||
{
|
||||
private DataSet MyDataSet; // bug:DefiningPotentiallyUnsafeXmlSerializer.ql
|
||||
|
||||
AttributeSerializer01()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class Program
|
||||
{
|
||||
static string GetSerializedDataSet(DataSet dataSet)
|
||||
{
|
||||
DataTable dataTable = new DataTable("MyTable");
|
||||
dataTable.Columns.Add("FirstName", typeof(string));
|
||||
dataTable.Columns.Add("LastName", typeof(string));
|
||||
dataTable.Columns.Add("Age", typeof(int));
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
dataSet.WriteXml(writer, XmlWriteMode.DiffGram);
|
||||
return writer.ToString();
|
||||
}
|
||||
|
||||
static void datatable_readxmlschema_01(string fileName)
|
||||
{
|
||||
using (FileStream fs = File.OpenRead(fileName))
|
||||
{
|
||||
DataTable newTable = new DataTable();
|
||||
System.Xml.XmlTextReader reader = new System.Xml.XmlTextReader(fs);
|
||||
newTable.ReadXmlSchema(reader); //bug:XmlDeserializationWithDataSet.ql
|
||||
}
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
|
||||
XmlSerializer x = new XmlSerializer(typeof(DataSet)); // bug:UnsafeTypeUsedDataContractSerializer.ql
|
||||
XmlSerializer y = new XmlSerializer(typeof(AttributeSerializer01)); //bug:UnsafeTypeUsedDataContractSerializer.ql
|
||||
|
||||
Console.WriteLine("Hello World!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
| expressions.cs:168:27:168:44 | array creation of type Object[] | expressions.cs:168:27:168:44 | 1 | true |
|
||||
| expressions.cs:409:23:409:65 | array creation of type Int32[,] | expressions.cs:409:23:409:65 | 3 | true |
|
||||
| expressions.cs:409:23:409:65 | array creation of type Int32[,] | expressions.cs:409:23:409:65 | 3 | true |
|
||||
13
csharp/ql/test/library-tests/expressions/ArrayCreation11.ql
Normal file
13
csharp/ql/test/library-tests/expressions/ArrayCreation11.ql
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @name Test for array creations
|
||||
*/
|
||||
|
||||
import csharp
|
||||
|
||||
private boolean isImplicit(Expr expr) {
|
||||
if expr.isImplicit() then result = true else result = false
|
||||
}
|
||||
|
||||
from ArrayCreation ac, Expr expr
|
||||
where ac.isImplicitlySized() and not ac.isImplicitlyTyped() and expr = ac.getALengthArgument()
|
||||
select ac, expr, isImplicit(expr)
|
||||
9
csharp/tools/autobuild.cmd
Normal file
9
csharp/tools/autobuild.cmd
Normal file
@@ -0,0 +1,9 @@
|
||||
@echo off
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
|
||||
rem The autobuilder is already being traced
|
||||
set CODEQL_AUTOBUILDER_CSHARP_NO_INDEXING=true
|
||||
|
||||
type NUL && "%CODEQL_EXTRACTOR_CSHARP_ROOT%/tools/%CODEQL_PLATFORM%/Semmle.Autobuild.CSharp.exe" || exit /b %ERRORLEVEL%
|
||||
|
||||
ENDLOCAL
|
||||
14
csharp/tools/autobuild.sh
Executable file
14
csharp/tools/autobuild.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
if [ "$CODEQL_PLATFORM" != "linux64" ] && [ "$CODEQL_PLATFORM" != "osx64" ] ; then
|
||||
echo "Automatic build detection for $CODEQL_PLATFORM is not implemented."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# The autobuilder is already being traced
|
||||
CODEQL_AUTOBUILDER_CSHARP_NO_INDEXING="true"
|
||||
export CODEQL_AUTOBUILDER_CSHARP_NO_INDEXING
|
||||
|
||||
"$CODEQL_EXTRACTOR_CSHARP_ROOT/tools/$CODEQL_PLATFORM/Semmle.Autobuild.CSharp" || exit $?
|
||||
9
csharp/tools/linux64/compiler-tracing.spec
Normal file
9
csharp/tools/linux64/compiler-tracing.spec
Normal file
@@ -0,0 +1,9 @@
|
||||
**/mcs.exe:
|
||||
**/csc.exe:
|
||||
invoke ${config_dir}/Semmle.Extraction.CSharp.Driver
|
||||
prepend --compiler
|
||||
prepend "${compiler}"
|
||||
prepend --cil
|
||||
**/mono*:
|
||||
**/dotnet:
|
||||
invoke ${config_dir}/extract-csharp.sh
|
||||
16
csharp/tools/linux64/extract-csharp.sh
Executable file
16
csharp/tools/linux64/extract-csharp.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
echo extract-csharp.sh: Called with arguments: "$@"
|
||||
|
||||
extractor="$CODEQL_EXTRACTOR_CSHARP_ROOT/tools/$CODEQL_PLATFORM/Semmle.Extraction.CSharp.Driver"
|
||||
|
||||
for i in "$@"
|
||||
do
|
||||
shift
|
||||
if [[ `basename -- "$i"` =~ csc.exe|mcs.exe|csc.dll ]]
|
||||
then
|
||||
echo extract-csharp.sh: exec $extractor --cil $@
|
||||
exec "$extractor" --compiler $i --cil $@
|
||||
fi
|
||||
done
|
||||
|
||||
echo extract-csharp.sh: Not a compiler invocation
|
||||
14
csharp/tools/osx64/compiler-tracing.spec
Normal file
14
csharp/tools/osx64/compiler-tracing.spec
Normal file
@@ -0,0 +1,14 @@
|
||||
**/mcs.exe:
|
||||
**/csc.exe:
|
||||
invoke ${config_dir}/Semmle.Extraction.CSharp.Driver
|
||||
prepend --compiler
|
||||
prepend "${compiler}"
|
||||
prepend --cil
|
||||
**/mono*:
|
||||
**/dotnet:
|
||||
invoke ${config_dir}/extract-csharp.sh
|
||||
/usr/bin/codesign:
|
||||
replace yes
|
||||
invoke /usr/bin/env
|
||||
prepend /usr/bin/codesign
|
||||
trace no
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user