mirror of
https://github.com/github/codeql.git
synced 2026-05-01 11:45:14 +02:00
Merge branch 'main' into alternative-instruction-operand-flow
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
{ "provide": [ "*/ql/src/qlpack.yml",
|
||||
"*/ql/test/qlpack.yml",
|
||||
"*/ql/examples/qlpack.yml",
|
||||
"*/upgrades/qlpack.yml",
|
||||
"misc/legacy-support/*/qlpack.yml",
|
||||
"misc/suite-helpers/qlpack.yml" ] }
|
||||
|
||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"omnisharp.autoStart": false
|
||||
}
|
||||
@@ -28,27 +28,51 @@ The following changes in version 1.25 affect C# analysis in all applications.
|
||||
such as `A<int>.B`, no longer are considered unbound generics. (Such nested types do,
|
||||
however, still have relevant `.getSourceDeclaration()`s, for example `A<>.B`.)
|
||||
* The data-flow library has been improved, which affects most security queries by potentially
|
||||
adding more results. Flow through methods now takes nested field reads/writes into account.
|
||||
For example, the library is able to track flow from `"taint"` to `Sink()` via the method
|
||||
`GetF2F1()` in
|
||||
```csharp
|
||||
class C1
|
||||
{
|
||||
string F1;
|
||||
}
|
||||
adding more results:
|
||||
- Flow through methods now takes nested field reads/writes into account.
|
||||
For example, the library is able to track flow from `"taint"` to `Sink()` via the method
|
||||
`GetF2F1()` in
|
||||
```csharp
|
||||
class C1
|
||||
{
|
||||
string F1;
|
||||
}
|
||||
|
||||
class C2
|
||||
{
|
||||
C1 F2;
|
||||
|
||||
string GetF2F1() => F2.F1; // Nested field read
|
||||
class C2
|
||||
{
|
||||
C1 F2;
|
||||
|
||||
void M()
|
||||
{
|
||||
F2 = new C1() { F1 = "taint" };
|
||||
Sink(GetF2F1()); // NEW: "taint" reaches here
|
||||
}
|
||||
}
|
||||
```
|
||||
string GetF2F1() => F2.F1; // Nested field read
|
||||
|
||||
void M()
|
||||
{
|
||||
F2 = new C1() { F1 = "taint" };
|
||||
Sink(GetF2F1()); // NEW: "taint" reaches here
|
||||
}
|
||||
}
|
||||
```
|
||||
- Flow through collections is now modeled precisely. For example, instead of modeling an array
|
||||
store `a[i] = x` as a taint-step from `x` to `a`, we now model it as a data-flow step that
|
||||
stores `x` into `a`. To get the value back out, a matching read step must be taken.
|
||||
|
||||
For source-code based data-flow analysis, the following constructs are modeled as stores into
|
||||
collections:
|
||||
- Direct array assignments, `a[i] = x`.
|
||||
- Array initializers, `new [] { x }`.
|
||||
- C# 6-style array initializers, `new C() { Array = { [i] = x } }`.
|
||||
- Call arguments that match a `params` parameter, where the C# compiler creates an array under-the-hood.
|
||||
- `yield return` statements.
|
||||
|
||||
The following source-code constructs read from a collection:
|
||||
- Direct array reads, `a[i]`.
|
||||
- `foreach` statements.
|
||||
|
||||
For calls out to library code, existing flow summaries have been refined to precisely
|
||||
capture how they interact with collection contents. For example, a call to
|
||||
`System.Collections.Generic.List<T>.Add(T)` stores the value of the argument into the
|
||||
qualifier, and a call to `System.Collections.Generic.List<T>.get_Item(int)` (that is, an
|
||||
indexer call) reads contents out of the qualifier. Moreover, the effect of
|
||||
collection-clearing methods such as `System.Collections.Generic.List<T>.Clear()` is now
|
||||
also modeled.
|
||||
|
||||
## Changes to autobuilder
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
- [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
|
||||
- [bluebird](http://bluebirdjs.com/)
|
||||
- [express](https://www.npmjs.com/package/express)
|
||||
- [execa](https://www.npmjs.com/package/execa)
|
||||
- [fancy-log](https://www.npmjs.com/package/fancy-log)
|
||||
- [fastify](https://www.npmjs.com/package/fastify)
|
||||
- [foreground-child](https://www.npmjs.com/package/foreground-child)
|
||||
- [fstream](https://www.npmjs.com/package/fstream)
|
||||
- [jGrowl](https://github.com/stanlemon/jGrowl)
|
||||
- [jQuery](https://jquery.com/)
|
||||
@@ -17,6 +19,7 @@
|
||||
- [mssql](https://www.npmjs.com/package/mssql)
|
||||
- [mysql](https://www.npmjs.com/package/mysql)
|
||||
- [npmlog](https://www.npmjs.com/package/npmlog)
|
||||
- [opener](https://www.npmjs.com/package/opener)
|
||||
- [pg](https://www.npmjs.com/package/pg)
|
||||
- [sequelize](https://www.npmjs.com/package/sequelize)
|
||||
- [spanner](https://www.npmjs.com/package/spanner)
|
||||
|
||||
19
change-notes/1.26/analysis-cpp.md
Normal file
19
change-notes/1.26/analysis-cpp.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# 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. |
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
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** |
|
||||
|--------------------------------|------------------------------|---------------------------------------------------------------------------|
|
||||
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
3
cpp/ql/examples/qlpack.yml
Normal file
3
cpp/ql/examples/qlpack.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
name: codeql-cpp-examples
|
||||
version: 0.0.0
|
||||
libraryPathDependencies: codeql-cpp
|
||||
@@ -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())
|
||||
)
|
||||
|
||||
@@ -9,3 +9,10 @@
|
||||
tags contain:
|
||||
- ide-contextual-queries/local-definitions
|
||||
- ide-contextual-queries/local-references
|
||||
- query: Metrics/Dependencies/ExternalDependencies.ql
|
||||
- query: Metrics/Dependencies/ExternalDependenciesSourceLinks.ql
|
||||
- query: Metrics/Files/FLinesOfCode.ql
|
||||
- query: Metrics/Files/FLinesOfCommentedOutCode.ql
|
||||
- query: Metrics/Files/FLinesOfComments.ql
|
||||
- query: Metrics/Files/FLinesOfDuplicatedCode.ql
|
||||
- query: Metrics/Files/FNumberOfTests.ql
|
||||
|
||||
@@ -197,7 +197,8 @@ class Element extends ElementBase {
|
||||
initialisers(underlyingElement(this), unresolveElement(result), _, _) or
|
||||
exprconv(unresolveElement(result), underlyingElement(this)) or
|
||||
param_decl_bind(underlyingElement(this), _, unresolveElement(result)) or
|
||||
using_container(unresolveElement(result), underlyingElement(this))
|
||||
using_container(unresolveElement(result), underlyingElement(this)) or
|
||||
static_asserts(unresolveElement(this), _, _, _, underlyingElement(result))
|
||||
}
|
||||
|
||||
/** Gets the closest `Element` enclosing this one. */
|
||||
@@ -278,12 +279,12 @@ class StaticAssert extends Locatable, @static_assert {
|
||||
/**
|
||||
* Gets the expression which this static assertion ensures is true.
|
||||
*/
|
||||
Expr getCondition() { static_asserts(underlyingElement(this), unresolveElement(result), _, _) }
|
||||
Expr getCondition() { static_asserts(underlyingElement(this), unresolveElement(result), _, _, _) }
|
||||
|
||||
/**
|
||||
* Gets the message which will be reported by the compiler if this static assertion fails.
|
||||
*/
|
||||
string getMessage() { static_asserts(underlyingElement(this), _, result, _) }
|
||||
string getMessage() { static_asserts(underlyingElement(this), _, result, _, _) }
|
||||
|
||||
override Location getLocation() { static_asserts(underlyingElement(this), _, _, result) }
|
||||
override Location getLocation() { static_asserts(underlyingElement(this), _, _, result, _) }
|
||||
}
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -582,7 +582,7 @@ class TemplateVariable extends Variable {
|
||||
* float a;
|
||||
* }
|
||||
*
|
||||
* template<type T>
|
||||
* template<typename T>
|
||||
* void myTemplateFunction() {
|
||||
* T b;
|
||||
* }
|
||||
|
||||
@@ -49,6 +49,18 @@ predicate primitiveVariadicFormatter(TopLevelFunction f, int formatParamIndex) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A standard function such as `vsprintf` that has an output parameter
|
||||
* and a variable argument list of type `va_arg`.
|
||||
*/
|
||||
private predicate primitiveVariadicFormatterOutput(TopLevelFunction f, int outputParamIndex) {
|
||||
// note: this might look like the regular expression in `primitiveVariadicFormatter`, but
|
||||
// there is one important difference: the [fs] part is not optional, as these classify
|
||||
// the `printf` variants that write to a buffer.
|
||||
// Conveniently, these buffer parameters are all at index 0.
|
||||
f.getName().regexpMatch("_?_?va?[fs]n?w?printf(_s)?(_p)?(_l)?") and outputParamIndex = 0
|
||||
}
|
||||
|
||||
private predicate callsVariadicFormatter(Function f, int formatParamIndex) {
|
||||
exists(FunctionCall fc, int i |
|
||||
variadicFormatter(fc.getTarget(), i) and
|
||||
@@ -57,6 +69,26 @@ private predicate callsVariadicFormatter(Function f, int formatParamIndex) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate callsVariadicFormatterOutput(Function f, int outputParamIndex) {
|
||||
exists(FunctionCall fc, int i |
|
||||
fc.getEnclosingFunction() = f and
|
||||
variadicFormatterOutput(fc.getTarget(), i) and
|
||||
fc.getArgument(i) = f.getParameter(outputParamIndex).getAnAccess()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` is a function such as `vprintf` that takes variable argument list
|
||||
* of type `va_arg` and writes formatted output to a buffer given as a parameter at
|
||||
* index `outputParamIndex`, if any.
|
||||
*/
|
||||
private predicate variadicFormatterOutput(Function f, int outputParamIndex) {
|
||||
primitiveVariadicFormatterOutput(f, outputParamIndex)
|
||||
or
|
||||
not f.isVarargs() and
|
||||
callsVariadicFormatterOutput(f, outputParamIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` is a function such as `vprintf` that has a format parameter
|
||||
* (at `formatParamIndex`) and a variable argument list of type `va_arg`.
|
||||
@@ -78,6 +110,8 @@ class UserDefinedFormattingFunction extends FormattingFunction {
|
||||
UserDefinedFormattingFunction() { isVarargs() and callsVariadicFormatter(this, _) }
|
||||
|
||||
override int getFormatParameterIndex() { callsVariadicFormatter(this, result) }
|
||||
|
||||
override int getOutputParameterIndex() { callsVariadicFormatterOutput(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -697,13 +697,20 @@ predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)
|
||||
*/
|
||||
class BarrierGuard extends IRGuardCondition {
|
||||
/** Override this predicate to hold if this guard validates `instr` upon evaluating to `b`. */
|
||||
abstract predicate checks(Instruction instr, boolean b);
|
||||
predicate checksInstr(Instruction instr, boolean b) { none() }
|
||||
|
||||
/** Override this predicate to hold if this guard validates `expr` upon evaluating to `b`. */
|
||||
predicate checks(Expr e, boolean b) { none() }
|
||||
|
||||
/** Gets a node guarded by this guard. */
|
||||
final Node getAGuardedNode() {
|
||||
exists(ValueNumber value, boolean edge |
|
||||
(
|
||||
this.checksInstr(value.getAnInstruction(), edge)
|
||||
or
|
||||
this.checks(value.getAnInstruction().getConvertedResultExpression(), edge)
|
||||
) and
|
||||
result.asInstruction() = value.getAnInstruction() and
|
||||
this.checks(value.getAnInstruction(), edge) and
|
||||
this.controls(result.asInstruction().getBlock(), edge)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -508,7 +508,8 @@ static_asserts(
|
||||
unique int id: @static_assert,
|
||||
int condition : @expr ref,
|
||||
string message : string ref,
|
||||
int location: @location_default ref
|
||||
int location: @location_default ref,
|
||||
int enclosing : @element ref
|
||||
);
|
||||
|
||||
// each function has an ordered list of parameters
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@ import semmle.code.cpp.ir.IR
|
||||
class TestBarrierGuard extends DataFlow::BarrierGuard {
|
||||
TestBarrierGuard() { this.(CallInstruction).getStaticCallTarget().getName() = "guarded" }
|
||||
|
||||
override predicate checks(Instruction checked, boolean isTrue) {
|
||||
override predicate checksInstr(Instruction checked, boolean isTrue) {
|
||||
checked = this.(CallInstruction).getPositionalArgument(0) and
|
||||
isTrue = true
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ void test1()
|
||||
{
|
||||
char buffer[256] = {0};
|
||||
sink(mysprintf(buffer, 256, "%s", string::source()));
|
||||
sink(buffer); // tainted [NOT DETECTED - implement UserDefinedFormattingFunction.getOutputParameterIndex()]
|
||||
sink(buffer); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -206,6 +206,8 @@
|
||||
| format.cpp:113:21:113:24 | {...} | format.cpp:115:8:115:13 | buffer | |
|
||||
| format.cpp:113:23:113:23 | 0 | format.cpp:113:21:113:24 | {...} | TAINT |
|
||||
| format.cpp:114:18:114:23 | ref arg buffer | format.cpp:115:8:115:13 | buffer | |
|
||||
| format.cpp:114:31:114:34 | %s | format.cpp:114:18:114:23 | ref arg buffer | TAINT |
|
||||
| format.cpp:114:37:114:50 | call to source | format.cpp:114:18:114:23 | ref arg buffer | TAINT |
|
||||
| format.cpp:119:10:119:11 | 0 | format.cpp:120:29:120:29 | i | |
|
||||
| format.cpp:119:10:119:11 | 0 | format.cpp:121:8:121:8 | i | |
|
||||
| format.cpp:120:28:120:29 | ref arg & ... | format.cpp:120:29:120:29 | i [inner post update] | |
|
||||
@@ -306,99 +308,205 @@
|
||||
| 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 |
|
||||
| stl.cpp:97:12:97:17 | call to source | stl.cpp:101:7:101:7 | a | |
|
||||
| stl.cpp:98:16:98:20 | 123 | stl.cpp:98:16:98:21 | call to basic_string | TAINT |
|
||||
| stl.cpp:98:16:98:21 | call to basic_string | stl.cpp:102:7:102:7 | b | |
|
||||
| stl.cpp:98:16:98:21 | call to basic_string | stl.cpp:104:7:104:7 | b | |
|
||||
| stl.cpp:99:16:99:21 | call to source | stl.cpp:99:16:99:24 | call to basic_string | TAINT |
|
||||
| stl.cpp:99:16:99:24 | call to basic_string | stl.cpp:103:7:103:7 | c | |
|
||||
| stl.cpp:99:16:99:24 | call to basic_string | stl.cpp:105:7:105:7 | c | |
|
||||
| stl.cpp:104:7:104:7 | b | stl.cpp:104:9:104:13 | call to c_str | TAINT |
|
||||
| stl.cpp:105:7:105:7 | c | stl.cpp:105:9:105:13 | call to c_str | TAINT |
|
||||
| stl.cpp:110:20:110:22 | call to basic_stringstream | stl.cpp:113:2:113:4 | ss1 | |
|
||||
| stl.cpp:110:20:110:22 | call to basic_stringstream | stl.cpp:119:7:119:9 | ss1 | |
|
||||
| stl.cpp:110:20:110:22 | call to basic_stringstream | stl.cpp:124:7:124:9 | ss1 | |
|
||||
| stl.cpp:110:25:110:27 | call to basic_stringstream | stl.cpp:114:2:114:4 | ss2 | |
|
||||
| stl.cpp:110:25:110:27 | call to basic_stringstream | stl.cpp:120:7:120:9 | ss2 | |
|
||||
| stl.cpp:110:25:110:27 | call to basic_stringstream | stl.cpp:125:7:125:9 | ss2 | |
|
||||
| stl.cpp:110:30:110:32 | call to basic_stringstream | stl.cpp:115:2:115:4 | ss3 | |
|
||||
| stl.cpp:110:30:110:32 | call to basic_stringstream | stl.cpp:121:7:121:9 | ss3 | |
|
||||
| stl.cpp:110:30:110:32 | call to basic_stringstream | stl.cpp:126:7:126:9 | ss3 | |
|
||||
| stl.cpp:110:35:110:37 | call to basic_stringstream | stl.cpp:116:2:116:4 | ss4 | |
|
||||
| stl.cpp:110:35:110:37 | call to basic_stringstream | stl.cpp:122:7:122:9 | ss4 | |
|
||||
| stl.cpp:110:35:110:37 | call to basic_stringstream | stl.cpp:127:7:127:9 | ss4 | |
|
||||
| stl.cpp:110:40:110:42 | call to basic_stringstream | stl.cpp:117:2:117:4 | ss5 | |
|
||||
| stl.cpp:110:40:110:42 | call to basic_stringstream | stl.cpp:123:7:123:9 | ss5 | |
|
||||
| stl.cpp:110:40:110:42 | call to basic_stringstream | stl.cpp:128:7:128:9 | ss5 | |
|
||||
| stl.cpp:111:16:111:21 | call to source | stl.cpp:111:16:111:24 | call to basic_string | TAINT |
|
||||
| stl.cpp:111:16:111:24 | call to basic_string | stl.cpp:117:9:117:9 | t | |
|
||||
| stl.cpp:113:2:113:4 | ref arg ss1 | stl.cpp:119:7:119:9 | ss1 | |
|
||||
| stl.cpp:113:2:113:4 | ref arg ss1 | stl.cpp:124:7:124:9 | ss1 | |
|
||||
| stl.cpp:114:2:114:4 | ref arg ss2 | stl.cpp:120:7:120:9 | ss2 | |
|
||||
| stl.cpp:114:2:114:4 | ref arg ss2 | stl.cpp:125:7:125:9 | ss2 | |
|
||||
| stl.cpp:115:2:115:4 | ref arg ss3 | stl.cpp:121:7:121:9 | ss3 | |
|
||||
| stl.cpp:115:2:115:4 | ref arg ss3 | stl.cpp:126:7:126:9 | ss3 | |
|
||||
| stl.cpp:116:2:116:4 | ref arg ss4 | stl.cpp:122:7:122:9 | ss4 | |
|
||||
| stl.cpp:116:2:116:4 | ref arg ss4 | stl.cpp:127:7:127:9 | ss4 | |
|
||||
| stl.cpp:117:2:117:4 | ref arg ss5 | stl.cpp:123:7:123:9 | ss5 | |
|
||||
| stl.cpp:117:2:117:4 | ref arg ss5 | stl.cpp:128:7:128:9 | ss5 | |
|
||||
| stl.cpp:131:32:131:37 | source | stl.cpp:136:9:136:14 | source | |
|
||||
| stl.cpp:133:20:133:22 | call to basic_stringstream | stl.cpp:135:2:135:4 | ss1 | |
|
||||
| stl.cpp:133:20:133:22 | call to basic_stringstream | stl.cpp:138:7:138:9 | ss1 | |
|
||||
| stl.cpp:133:20:133:22 | call to basic_stringstream | stl.cpp:140:7:140:9 | ss1 | |
|
||||
| stl.cpp:133:25:133:27 | call to basic_stringstream | stl.cpp:136:2:136:4 | ss2 | |
|
||||
| stl.cpp:133:25:133:27 | call to basic_stringstream | stl.cpp:139:7:139:9 | ss2 | |
|
||||
| stl.cpp:133:25:133:27 | call to basic_stringstream | stl.cpp:141:7:141:9 | ss2 | |
|
||||
| stl.cpp:135:2:135:4 | ref arg ss1 | stl.cpp:138:7:138:9 | ss1 | |
|
||||
| stl.cpp:135:2:135:4 | ref arg ss1 | stl.cpp:140:7:140:9 | ss1 | |
|
||||
| stl.cpp:136:2:136:4 | ref arg ss2 | stl.cpp:139:7:139:9 | ss2 | |
|
||||
| stl.cpp:136:2:136:4 | ref arg ss2 | stl.cpp:141:7:141:9 | ss2 | |
|
||||
| stl.cpp:154:16:154:28 | call to basic_string | stl.cpp:155:7:155:11 | path1 | |
|
||||
| stl.cpp:154:17:154:26 | call to user_input | stl.cpp:154:16:154:28 | call to basic_string | TAINT |
|
||||
| stl.cpp:155:7:155:11 | path1 | stl.cpp:155:13:155:17 | call to c_str | TAINT |
|
||||
| stl.cpp:158:10:158:19 | call to user_input | stl.cpp:158:10:158:21 | call to basic_string | TAINT |
|
||||
| stl.cpp:158:10:158:21 | call to basic_string | stl.cpp:158:2:158:21 | ... = ... | |
|
||||
| stl.cpp:158:10:158:21 | call to basic_string | stl.cpp:159:7:159:11 | path2 | |
|
||||
| stl.cpp:159:7:159:11 | path2 | stl.cpp:159:13:159:17 | call to c_str | TAINT |
|
||||
| stl.cpp:161:15:161:24 | call to user_input | stl.cpp:161:15:161:27 | call to basic_string | TAINT |
|
||||
| stl.cpp:161:15:161:27 | call to basic_string | stl.cpp:162:7:162:11 | path3 | |
|
||||
| stl.cpp:162:7:162:11 | path3 | stl.cpp:162:13:162:17 | call to c_str | TAINT |
|
||||
| stl.cpp:167:19:167:24 | call to source | stl.cpp:170:17:170:18 | cs | |
|
||||
| stl.cpp:167:19:167:24 | call to source | stl.cpp:172:7:172:8 | cs | |
|
||||
| stl.cpp:170:17:170:18 | cs | stl.cpp:170:17:170:19 | call to basic_string | TAINT |
|
||||
| stl.cpp:170:17:170:19 | call to basic_string | stl.cpp:173:7:173:8 | ss | |
|
||||
| stl.cpp:178:19:178:24 | call to source | stl.cpp:181:17:181:18 | cs | |
|
||||
| stl.cpp:181:17:181:18 | cs | stl.cpp:181:17:181:19 | call to basic_string | TAINT |
|
||||
| stl.cpp:181:17:181:19 | call to basic_string | stl.cpp:184:7:184:8 | ss | |
|
||||
| stl.cpp:181:17:181:19 | call to basic_string | stl.cpp:187:7:187:8 | ss | |
|
||||
| stl.cpp:184:7:184:8 | ss | stl.cpp:184:10:184:14 | call to c_str | TAINT |
|
||||
| stl.cpp:184:10:184:14 | call to c_str | stl.cpp:184:2:184:16 | ... = ... | |
|
||||
| stl.cpp:184:10:184:14 | call to c_str | stl.cpp:186:7:186:8 | cs | |
|
||||
| stl.cpp:193:18:193:24 | hello | stl.cpp:193:18:193:25 | call to basic_string | TAINT |
|
||||
| stl.cpp:193:18:193:25 | call to basic_string | stl.cpp:198:8:198:9 | s1 | |
|
||||
| stl.cpp:194:19:194:26 | call to basic_string | stl.cpp:199:8:199:9 | s2 | |
|
||||
| stl.cpp:194:20:194:26 | hello | stl.cpp:194:19:194:26 | call to basic_string | TAINT |
|
||||
| stl.cpp:196:8:196:14 | call to basic_string | stl.cpp:196:3:196:14 | ... = ... | |
|
||||
| stl.cpp:196:8:196:14 | call to basic_string | stl.cpp:200:8:200:9 | s3 | |
|
||||
| stl.cpp:196:8:196:14 | hello | stl.cpp:196:8:196:14 | call to basic_string | TAINT |
|
||||
| stl.cpp:204:18:204:23 | call to source | stl.cpp:204:18:204:26 | call to basic_string | TAINT |
|
||||
| stl.cpp:204:18:204:26 | call to basic_string | stl.cpp:209:8:209:9 | s1 | |
|
||||
| stl.cpp:205:19:205:27 | call to basic_string | stl.cpp:210:8:210:9 | s2 | |
|
||||
| stl.cpp:205:20:205:25 | call to source | stl.cpp:205:19:205:27 | call to basic_string | TAINT |
|
||||
| stl.cpp:207:8:207:13 | call to source | stl.cpp:207:8:207:15 | call to basic_string | TAINT |
|
||||
| stl.cpp:207:8:207:15 | call to basic_string | stl.cpp:207:3:207:15 | ... = ... | |
|
||||
| stl.cpp:207:8:207:15 | call to basic_string | stl.cpp:211:8:211:9 | s3 | |
|
||||
| stl.cpp:215:15:215:16 | call to basic_string | stl.cpp:216:20:216:21 | s1 | |
|
||||
| stl.cpp:215:15:215:16 | call to basic_string | stl.cpp:218:8:218:9 | s1 | |
|
||||
| stl.cpp:215:15:215:16 | call to basic_string | stl.cpp:220:8:220:9 | s1 | |
|
||||
| stl.cpp:216:20:216:21 | s1 | stl.cpp:221:8:221:9 | s2 | |
|
||||
| stl.cpp:218:8:218:9 | s1 | stl.cpp:218:3:218:9 | ... = ... | |
|
||||
| stl.cpp:218:8:218:9 | s1 | stl.cpp:222:8:222:9 | s3 | |
|
||||
| stl.cpp:226:19:226:40 | call to basic_string | stl.cpp:230:8:230:9 | s1 | |
|
||||
| stl.cpp:226:32:226:37 | call to source | stl.cpp:226:19:226:40 | call to basic_string | TAINT |
|
||||
| stl.cpp:228:8:228:28 | call to basic_string | stl.cpp:228:3:228:28 | ... = ... | |
|
||||
| stl.cpp:228:8:228:28 | call to basic_string | stl.cpp:231:8:231:9 | s2 | |
|
||||
| stl.cpp:228:20:228:25 | call to source | stl.cpp:228:8:228:28 | call to basic_string | TAINT |
|
||||
| stl.cpp:238:16:238:21 | call to source | stl.cpp:238:16:238:24 | call to basic_string | TAINT |
|
||||
| stl.cpp:238:16:238:24 | call to basic_string | stl.cpp:239:15:239:15 | s | |
|
||||
| stl.cpp:238:16:238:24 | call to basic_string | stl.cpp:243:33:243:33 | s | |
|
||||
| stl.cpp:238:16:238:24 | call to basic_string | stl.cpp:243:50:243:50 | s | |
|
||||
| stl.cpp:238:16:238:24 | call to basic_string | stl.cpp:247:16:247:16 | s | |
|
||||
| stl.cpp:239:15:239:15 | call to begin | stl.cpp:239:15:239:15 | (__begin) | |
|
||||
| stl.cpp:239:15:239:15 | call to begin | stl.cpp:239:15:239:15 | (__begin) | |
|
||||
| stl.cpp:239:15:239:15 | call to begin | stl.cpp:239:15:239:15 | (__begin) | |
|
||||
| stl.cpp:239:15:239:15 | call to end | stl.cpp:239:15:239:15 | (__end) | |
|
||||
| stl.cpp:239:15:239:15 | call to operator* | stl.cpp:240:8:240:8 | c | |
|
||||
| stl.cpp:239:15:239:15 | ref arg (__begin) | stl.cpp:239:15:239:15 | (__begin) | |
|
||||
| stl.cpp:239:15:239:15 | ref arg (__begin) | stl.cpp:239:15:239:15 | (__begin) | |
|
||||
| stl.cpp:239:15:239:15 | ref arg (__begin) | stl.cpp:239:15:239:15 | (__begin) | |
|
||||
| stl.cpp:239:15:239:15 | ref arg (__range) | stl.cpp:239:15:239:15 | (__range) | |
|
||||
| stl.cpp:239:15:239:15 | s | stl.cpp:239:15:239:15 | (__range) | |
|
||||
| stl.cpp:239:15:239:15 | s | stl.cpp:239:15:239:15 | (__range) | |
|
||||
| stl.cpp:239:15:239:15 | s | stl.cpp:239:15:239:15 | call to operator* | TAINT |
|
||||
| stl.cpp:243:33:243:33 | ref arg s | stl.cpp:243:50:243:50 | s | |
|
||||
| stl.cpp:243:33:243:33 | ref arg s | stl.cpp:247:16:247:16 | s | |
|
||||
| stl.cpp:243:35:243:39 | call to begin | stl.cpp:243:44:243:45 | it | |
|
||||
| stl.cpp:243:35:243:39 | call to begin | stl.cpp:243:61:243:62 | it | |
|
||||
| stl.cpp:243:35:243:39 | call to begin | stl.cpp:244:9:244:10 | it | |
|
||||
| stl.cpp:243:50:243:50 | ref arg s | stl.cpp:243:50:243:50 | s | |
|
||||
| stl.cpp:243:50:243:50 | ref arg s | stl.cpp:247:16:247:16 | s | |
|
||||
| stl.cpp:243:61:243:62 | ref arg it | stl.cpp:243:44:243:45 | it | |
|
||||
| stl.cpp:243:61:243:62 | ref arg it | stl.cpp:243:61:243:62 | it | |
|
||||
| stl.cpp:243:61:243:62 | ref arg it | stl.cpp:244:9:244:10 | it | |
|
||||
| stl.cpp:247:16:247:16 | call to begin | stl.cpp:247:16:247:16 | (__begin) | |
|
||||
| stl.cpp:247:16:247:16 | call to begin | stl.cpp:247:16:247:16 | (__begin) | |
|
||||
| stl.cpp:247:16:247:16 | call to begin | stl.cpp:247:16:247:16 | (__begin) | |
|
||||
| stl.cpp:247:16:247:16 | call to end | stl.cpp:247:16:247:16 | (__end) | |
|
||||
| stl.cpp:247:16:247:16 | call to operator* | stl.cpp:248:8:248:8 | c | |
|
||||
| stl.cpp:247:16:247:16 | ref arg (__begin) | stl.cpp:247:16:247:16 | (__begin) | |
|
||||
| stl.cpp:247:16:247:16 | ref arg (__begin) | stl.cpp:247:16:247:16 | (__begin) | |
|
||||
| stl.cpp:247:16:247:16 | ref arg (__begin) | stl.cpp:247:16:247:16 | (__begin) | |
|
||||
| stl.cpp:247:16:247:16 | ref arg (__range) | stl.cpp:247:16:247:16 | (__range) | |
|
||||
| stl.cpp:247:16:247:16 | s | stl.cpp:247:16:247:16 | (__range) | |
|
||||
| stl.cpp:247:16:247:16 | s | stl.cpp:247:16:247:16 | (__range) | |
|
||||
| stl.cpp:247:16:247:16 | s | stl.cpp:247:16:247:16 | call to operator* | TAINT |
|
||||
| stl.cpp:251:28:251:33 | call to source | stl.cpp:251:28:251:36 | call to basic_string | TAINT |
|
||||
| stl.cpp:251:28:251:36 | call to basic_string | stl.cpp:252:22:252:28 | const_s | |
|
||||
| stl.cpp:252:22:252:22 | call to begin | stl.cpp:252:22:252:22 | (__begin) | |
|
||||
| stl.cpp:252:22:252:22 | call to begin | stl.cpp:252:22:252:22 | (__begin) | |
|
||||
| stl.cpp:252:22:252:22 | call to begin | stl.cpp:252:22:252:22 | (__begin) | |
|
||||
| stl.cpp:252:22:252:22 | call to end | stl.cpp:252:22:252:22 | (__end) | |
|
||||
| stl.cpp:252:22:252:22 | call to operator* | stl.cpp:253:8:253:8 | c | |
|
||||
| stl.cpp:252:22:252:22 | ref arg (__begin) | stl.cpp:252:22:252:22 | (__begin) | |
|
||||
| stl.cpp:252:22:252:22 | ref arg (__begin) | stl.cpp:252:22:252:22 | (__begin) | |
|
||||
| stl.cpp:252:22:252:22 | ref arg (__begin) | stl.cpp:252:22:252:22 | (__begin) | |
|
||||
| stl.cpp:252:22:252:28 | const_s | stl.cpp:252:22:252:22 | (__range) | |
|
||||
| stl.cpp:252:22:252:28 | const_s | stl.cpp:252:22:252:22 | (__range) | |
|
||||
| stl.cpp:252:22:252:28 | const_s | stl.cpp:252:22:252:22 | call to operator* | TAINT |
|
||||
| stl.cpp:288:43:288:49 | source1 | stl.cpp:292:21:292:27 | source1 | |
|
||||
| stl.cpp:288:43:288:49 | source1 | stl.cpp:306:33:306:39 | source1 | |
|
||||
| stl.cpp:292:21:292:27 | source1 | stl.cpp:292:21:292:28 | call to vector | TAINT |
|
||||
| stl.cpp:292:21:292:28 | call to vector | stl.cpp:294:14:294:14 | v | |
|
||||
| stl.cpp:292:21:292:28 | call to vector | stl.cpp:298:38:298:38 | v | |
|
||||
| stl.cpp:292:21:292:28 | call to vector | stl.cpp:298:55:298:55 | v | |
|
||||
| stl.cpp:292:21:292:28 | call to vector | stl.cpp:302:15:302:15 | v | |
|
||||
| stl.cpp:294:14:294:14 | call to begin | stl.cpp:294:14:294:14 | (__begin) | |
|
||||
| stl.cpp:294:14:294:14 | call to begin | stl.cpp:294:14:294:14 | (__begin) | |
|
||||
| stl.cpp:294:14:294:14 | call to begin | stl.cpp:294:14:294:14 | (__begin) | |
|
||||
| stl.cpp:294:14:294:14 | call to end | stl.cpp:294:14:294:14 | (__end) | |
|
||||
| stl.cpp:294:14:294:14 | call to operator* | stl.cpp:295:8:295:8 | x | |
|
||||
| stl.cpp:294:14:294:14 | ref arg (__begin) | stl.cpp:294:14:294:14 | (__begin) | |
|
||||
| stl.cpp:294:14:294:14 | ref arg (__begin) | stl.cpp:294:14:294:14 | (__begin) | |
|
||||
| stl.cpp:294:14:294:14 | ref arg (__begin) | stl.cpp:294:14:294:14 | (__begin) | |
|
||||
| stl.cpp:294:14:294:14 | ref arg (__range) | stl.cpp:294:14:294:14 | (__range) | |
|
||||
| stl.cpp:294:14:294:14 | v | stl.cpp:294:14:294:14 | (__range) | |
|
||||
| stl.cpp:294:14:294:14 | v | stl.cpp:294:14:294:14 | (__range) | |
|
||||
| stl.cpp:294:14:294:14 | v | stl.cpp:294:14:294:14 | call to operator* | TAINT |
|
||||
| stl.cpp:298:38:298:38 | ref arg v | stl.cpp:298:55:298:55 | v | |
|
||||
| stl.cpp:298:38:298:38 | ref arg v | stl.cpp:302:15:302:15 | v | |
|
||||
| stl.cpp:298:40:298:44 | call to begin | stl.cpp:298:49:298:50 | it | |
|
||||
| stl.cpp:298:40:298:44 | call to begin | stl.cpp:298:66:298:67 | it | |
|
||||
| stl.cpp:298:40:298:44 | call to begin | stl.cpp:299:9:299:10 | it | |
|
||||
| stl.cpp:298:55:298:55 | ref arg v | stl.cpp:298:55:298:55 | v | |
|
||||
| stl.cpp:298:55:298:55 | ref arg v | stl.cpp:302:15:302:15 | v | |
|
||||
| stl.cpp:298:66:298:67 | ref arg it | stl.cpp:298:49:298:50 | it | |
|
||||
| stl.cpp:298:66:298:67 | ref arg it | stl.cpp:298:66:298:67 | it | |
|
||||
| stl.cpp:298:66:298:67 | ref arg it | stl.cpp:299:9:299:10 | it | |
|
||||
| stl.cpp:302:15:302:15 | call to begin | stl.cpp:302:15:302:15 | (__begin) | |
|
||||
| stl.cpp:302:15:302:15 | call to begin | stl.cpp:302:15:302:15 | (__begin) | |
|
||||
| stl.cpp:302:15:302:15 | call to begin | stl.cpp:302:15:302:15 | (__begin) | |
|
||||
| stl.cpp:302:15:302:15 | call to end | stl.cpp:302:15:302:15 | (__end) | |
|
||||
| stl.cpp:302:15:302:15 | call to operator* | stl.cpp:303:8:303:8 | x | |
|
||||
| stl.cpp:302:15:302:15 | ref arg (__begin) | stl.cpp:302:15:302:15 | (__begin) | |
|
||||
| stl.cpp:302:15:302:15 | ref arg (__begin) | stl.cpp:302:15:302:15 | (__begin) | |
|
||||
| stl.cpp:302:15:302:15 | ref arg (__begin) | stl.cpp:302:15:302:15 | (__begin) | |
|
||||
| stl.cpp:302:15:302:15 | ref arg (__range) | stl.cpp:302:15:302:15 | (__range) | |
|
||||
| stl.cpp:302:15:302:15 | v | stl.cpp:302:15:302:15 | (__range) | |
|
||||
| stl.cpp:302:15:302:15 | v | stl.cpp:302:15:302:15 | (__range) | |
|
||||
| stl.cpp:302:15:302:15 | v | stl.cpp:302:15:302:15 | call to operator* | TAINT |
|
||||
| stl.cpp:306:33:306:39 | source1 | stl.cpp:306:33:306:40 | call to vector | TAINT |
|
||||
| stl.cpp:306:33:306:40 | call to vector | stl.cpp:307:21:307:27 | const_v | |
|
||||
| stl.cpp:307:21:307:21 | call to begin | stl.cpp:307:21:307:21 | (__begin) | |
|
||||
| stl.cpp:307:21:307:21 | call to begin | stl.cpp:307:21:307:21 | (__begin) | |
|
||||
| stl.cpp:307:21:307:21 | call to begin | stl.cpp:307:21:307:21 | (__begin) | |
|
||||
| stl.cpp:307:21:307:21 | call to end | stl.cpp:307:21:307:21 | (__end) | |
|
||||
| stl.cpp:307:21:307:21 | call to operator* | stl.cpp:308:8:308:8 | x | |
|
||||
| stl.cpp:307:21:307:21 | ref arg (__begin) | stl.cpp:307:21:307:21 | (__begin) | |
|
||||
| stl.cpp:307:21:307:21 | ref arg (__begin) | stl.cpp:307:21:307:21 | (__begin) | |
|
||||
| stl.cpp:307:21:307:21 | ref arg (__begin) | stl.cpp:307:21:307:21 | (__begin) | |
|
||||
| stl.cpp:307:21:307:27 | const_v | stl.cpp:307:21:307:21 | (__range) | |
|
||||
| stl.cpp:307:21:307:27 | const_v | stl.cpp:307:21:307:21 | (__range) | |
|
||||
| stl.cpp:307:21:307:27 | const_v | stl.cpp:307:21:307:21 | call to operator* | 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 | 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] | |
|
||||
|
||||
@@ -7,6 +7,26 @@ namespace std
|
||||
|
||||
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();
|
||||
@@ -19,6 +39,16 @@ namespace std
|
||||
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;
|
||||
};
|
||||
|
||||
typedef basic_string<char> string;
|
||||
@@ -202,3 +232,79 @@ void test_string_constructors_assignments()
|
||||
}
|
||||
}
|
||||
|
||||
void sink(char) {}
|
||||
|
||||
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]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
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]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
| format.cpp:100:8:100:13 | buffer | format.cpp:99:30:99:43 | call to source |
|
||||
| format.cpp:105:8:105:13 | buffer | format.cpp:104:31:104:45 | call to source |
|
||||
| format.cpp:110:8:110:14 | wbuffer | format.cpp:109:38:109:52 | call to source |
|
||||
| format.cpp:115:8:115:13 | buffer | format.cpp:114:37:114:50 | 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 |
|
||||
| movableclass.cpp:44:8:44:9 | s1 | movableclass.cpp:39:21:39:26 | call to source |
|
||||
@@ -31,21 +32,27 @@
|
||||
| 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 |
|
||||
| stl.cpp:101:7:101:7 | a | stl.cpp:97:12:97:17 | call to source |
|
||||
| stl.cpp:103:7:103:7 | c | stl.cpp:99:16:99:21 | call to source |
|
||||
| stl.cpp:105:9:105:13 | call to c_str | stl.cpp:99:16:99:21 | call to source |
|
||||
| stl.cpp:155:13:155:17 | call to c_str | stl.cpp:147:10:147:15 | call to source |
|
||||
| stl.cpp:159:13:159:17 | call to c_str | stl.cpp:147:10:147:15 | call to source |
|
||||
| stl.cpp:162:13:162:17 | call to c_str | stl.cpp:147:10:147:15 | call to source |
|
||||
| stl.cpp:172:7:172:8 | cs | stl.cpp:167:19:167:24 | call to source |
|
||||
| stl.cpp:173:7:173:8 | ss | stl.cpp:167:19:167:24 | call to source |
|
||||
| stl.cpp:186:7:186:8 | cs | stl.cpp:178:19:178:24 | call to source |
|
||||
| stl.cpp:187:7:187:8 | ss | stl.cpp:178:19:178:24 | call to source |
|
||||
| stl.cpp:209:8:209:9 | s1 | stl.cpp:204:18:204:23 | call to source |
|
||||
| stl.cpp:210:8:210:9 | s2 | stl.cpp:205:20:205:25 | call to source |
|
||||
| stl.cpp:211:8:211:9 | s3 | stl.cpp:207:8:207:13 | call to source |
|
||||
| stl.cpp:230:8:230:9 | s1 | stl.cpp:226:32:226:37 | call to source |
|
||||
| stl.cpp:231:8:231:9 | s2 | stl.cpp:228:20:228:25 | call to source |
|
||||
| stl.cpp:240:8:240:8 | c | stl.cpp:238:16:238:21 | call to source |
|
||||
| stl.cpp:248:8:248:8 | c | stl.cpp:238:16:238:21 | call to source |
|
||||
| stl.cpp:253:8:253:8 | c | stl.cpp:251:28:251:33 | call to source |
|
||||
| stl.cpp:295:8:295:8 | x | stl.cpp:288:43:288:49 | source1 |
|
||||
| stl.cpp:303:8:303:8 | x | stl.cpp:288:43:288:49 | source1 |
|
||||
| stl.cpp:308:8:308:8 | x | stl.cpp:288:43:288:49 | source1 |
|
||||
| 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 |
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
| format.cpp:100:8:100:13 | format.cpp:99:30:99:43 | AST only |
|
||||
| format.cpp:105:8:105:13 | format.cpp:104:31:104:45 | AST only |
|
||||
| format.cpp:110:8:110:14 | format.cpp:109:38:109:52 | AST only |
|
||||
| format.cpp:115:8:115:13 | format.cpp:114:37:114:50 | AST only |
|
||||
| movableclass.cpp:44:8:44:9 | movableclass.cpp:39:21:39:26 | AST only |
|
||||
| movableclass.cpp:45:8:45:9 | movableclass.cpp:40:23:40:28 | AST only |
|
||||
| movableclass.cpp:46:8:46:9 | movableclass.cpp:42:8:42:13 | AST only |
|
||||
@@ -29,20 +30,26 @@
|
||||
| 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 |
|
||||
| stl.cpp:103:7:103:7 | stl.cpp:99:16:99:21 | AST only |
|
||||
| stl.cpp:105:9:105:13 | stl.cpp:99:16:99:21 | AST only |
|
||||
| stl.cpp:155:13:155:17 | stl.cpp:147:10:147:15 | AST only |
|
||||
| stl.cpp:159:13:159:17 | stl.cpp:147:10:147:15 | AST only |
|
||||
| stl.cpp:162:13:162:17 | stl.cpp:147:10:147:15 | AST only |
|
||||
| stl.cpp:172:7:172:8 | stl.cpp:167:19:167:26 | IR only |
|
||||
| stl.cpp:173:7:173:8 | stl.cpp:167:19:167:24 | AST only |
|
||||
| stl.cpp:186:7:186:8 | stl.cpp:178:19:178:24 | AST only |
|
||||
| stl.cpp:187:7:187:8 | stl.cpp:178:19:178:24 | AST only |
|
||||
| stl.cpp:209:8:209:9 | stl.cpp:204:18:204:23 | AST only |
|
||||
| stl.cpp:210:8:210:9 | stl.cpp:205:20:205:25 | AST only |
|
||||
| stl.cpp:211:8:211:9 | stl.cpp:207:8:207:13 | AST only |
|
||||
| stl.cpp:230:8:230:9 | stl.cpp:226:32:226:37 | AST only |
|
||||
| stl.cpp:231:8:231:9 | stl.cpp:228:20:228:25 | AST only |
|
||||
| stl.cpp:240:8:240:8 | stl.cpp:238:16:238:21 | AST only |
|
||||
| stl.cpp:248:8:248:8 | stl.cpp:238:16:238:21 | AST only |
|
||||
| stl.cpp:253:8:253:8 | stl.cpp:251:28:251:33 | AST only |
|
||||
| stl.cpp:295:8:295:8 | stl.cpp:288:43:288:49 | AST only |
|
||||
| stl.cpp:303:8:303:8 | stl.cpp:288:43:288:49 | AST only |
|
||||
| stl.cpp:308:8:308:8 | stl.cpp:288:43:288:49 | 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 |
|
||||
|
||||
@@ -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 *)... |
|
||||
| stl.cpp:101:7:101:7 | (const char *)... | stl.cpp:97:12:97:17 | call to source |
|
||||
| stl.cpp:101:7:101:7 | a | stl.cpp:97:12:97:17 | call to source |
|
||||
| stl.cpp:172:7:172:8 | cs | stl.cpp:167:19:167:24 | call to source |
|
||||
| stl.cpp:172:7:172:8 | cs | stl.cpp:167:19:167: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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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). |
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
| tests.cpp:259:2:259:8 | call to sprintf | This 'call to sprintf' operation requires 17 bytes but the destination is only 10 bytes. |
|
||||
| tests.cpp:272:2:272:8 | call to sprintf | This 'call to sprintf' operation requires 9 bytes but the destination is only 8 bytes. |
|
||||
| tests.cpp:273:2:273:8 | call to sprintf | This 'call to sprintf' operation requires 9 bytes but the destination is only 8 bytes. |
|
||||
| tests.cpp:308:3:308:9 | call to sprintf | This 'call to sprintf' operation requires 9 bytes but the destination is only 8 bytes. |
|
||||
|
||||
@@ -289,3 +289,22 @@ void test5(va_list args, float f)
|
||||
vsprintf(buffer4, "123", args); // GOOD
|
||||
vsprintf(buffer4, "1234", args); // BAD: buffer overflow [NOT DETECTED]
|
||||
}
|
||||
|
||||
namespace custom_sprintf_impl {
|
||||
int sprintf(char *buf, const char *format, ...)
|
||||
{
|
||||
__builtin_va_list args;
|
||||
int i;
|
||||
|
||||
__builtin_va_start(args, format);
|
||||
i = vsprintf(buf, format, args);
|
||||
__builtin_va_end(args);
|
||||
return i;
|
||||
}
|
||||
|
||||
void regression_test1()
|
||||
{
|
||||
char buffer8[8];
|
||||
sprintf(buffer8, "12345678"); // BAD: potential buffer overflow
|
||||
}
|
||||
}
|
||||
2109
cpp/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/old.dbscheme
Normal file
2109
cpp/upgrades/025827d85c3f44a7fd52d4fad636e9a4141f12dd/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
||||
class StaticAssert extends @static_assert {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Expr extends @expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_default {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class NameSpace extends @namespace {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from StaticAssert sa, Expr condition, string message, Location loc, NameSpace ns
|
||||
where
|
||||
static_asserts(sa, condition, message, loc) and
|
||||
namespaces(ns, "")
|
||||
select sa, condition, message, loc, ns
|
||||
@@ -0,0 +1,4 @@
|
||||
description: Give static_assert's an enclosing element
|
||||
compatibility: partial
|
||||
static_asserts.rel: run static_asserts.qlo
|
||||
|
||||
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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -19,15 +19,15 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
/// <summary>
|
||||
/// List of strings passed to FileDelete.
|
||||
/// </summary>
|
||||
public IList<string> FileDeleteIn = new List<string>();
|
||||
public readonly IList<string> FileDeleteIn = new List<string>();
|
||||
|
||||
void IBuildActions.FileDelete(string file)
|
||||
{
|
||||
FileDeleteIn.Add(file);
|
||||
}
|
||||
|
||||
public IList<string> FileExistsIn = new List<string>();
|
||||
public IDictionary<string, bool> FileExists = new Dictionary<string, bool>();
|
||||
public readonly IList<string> FileExistsIn = new List<string>();
|
||||
public readonly IDictionary<string, bool> FileExists = new Dictionary<string, bool>();
|
||||
|
||||
bool IBuildActions.FileExists(string file)
|
||||
{
|
||||
@@ -39,10 +39,10 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
throw new ArgumentException("Missing FileExists " + file);
|
||||
}
|
||||
|
||||
public IList<string> RunProcessIn = new List<string>();
|
||||
public IDictionary<string, int> RunProcess = new Dictionary<string, int>();
|
||||
public IDictionary<string, string> RunProcessOut = new Dictionary<string, string>();
|
||||
public IDictionary<string, string> RunProcessWorkingDirectory = new Dictionary<string, string>();
|
||||
public readonly IList<string> RunProcessIn = new List<string>();
|
||||
public readonly IDictionary<string, int> RunProcess = new Dictionary<string, int>();
|
||||
public readonly IDictionary<string, string> RunProcessOut = new Dictionary<string, string>();
|
||||
public readonly IDictionary<string, string> RunProcessWorkingDirectory = new Dictionary<string, string>();
|
||||
|
||||
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env, out IList<string> stdOut)
|
||||
{
|
||||
@@ -72,14 +72,14 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
throw new ArgumentException("Missing RunProcess " + pattern);
|
||||
}
|
||||
|
||||
public IList<string> DirectoryDeleteIn = new List<string>();
|
||||
public readonly IList<string> DirectoryDeleteIn = new List<string>();
|
||||
|
||||
void IBuildActions.DirectoryDelete(string dir, bool recursive)
|
||||
{
|
||||
DirectoryDeleteIn.Add(dir);
|
||||
}
|
||||
|
||||
public IDictionary<string, bool> DirectoryExists = new Dictionary<string, bool>();
|
||||
public readonly IDictionary<string, bool> DirectoryExists = new Dictionary<string, bool>();
|
||||
|
||||
bool IBuildActions.DirectoryExists(string dir)
|
||||
{
|
||||
@@ -88,7 +88,7 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
throw new ArgumentException("Missing DirectoryExists " + dir);
|
||||
}
|
||||
|
||||
public IDictionary<string, string?> GetEnvironmentVariable = new Dictionary<string, string?>();
|
||||
public readonly IDictionary<string, string?> GetEnvironmentVariable = new Dictionary<string, string?>();
|
||||
|
||||
string? IBuildActions.GetEnvironmentVariable(string name)
|
||||
{
|
||||
@@ -104,7 +104,7 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
return GetCurrentDirectory;
|
||||
}
|
||||
|
||||
public IDictionary<string, string> EnumerateFiles = new Dictionary<string, string>();
|
||||
public readonly IDictionary<string, string> EnumerateFiles = new Dictionary<string, string>();
|
||||
|
||||
IEnumerable<string> IBuildActions.EnumerateFiles(string dir)
|
||||
{
|
||||
@@ -113,7 +113,7 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
throw new ArgumentException("Missing EnumerateFiles " + dir);
|
||||
}
|
||||
|
||||
public IDictionary<string, string> EnumerateDirectories = new Dictionary<string, string>();
|
||||
public readonly IDictionary<string, string> EnumerateDirectories = new Dictionary<string, string>();
|
||||
|
||||
IEnumerable<string> IBuildActions.EnumerateDirectories(string dir)
|
||||
{
|
||||
@@ -137,7 +137,8 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
{
|
||||
}
|
||||
|
||||
public IDictionary<string, XmlDocument> LoadXml = new Dictionary<string, XmlDocument>();
|
||||
public readonly IDictionary<string, XmlDocument> LoadXml = new Dictionary<string, XmlDocument>();
|
||||
|
||||
XmlDocument IBuildActions.LoadXml(string filename)
|
||||
{
|
||||
if (LoadXml.TryGetValue(filename, out var xml))
|
||||
@@ -178,10 +179,10 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
|
||||
public class BuildScriptTests
|
||||
{
|
||||
TestActions Actions = new TestActions();
|
||||
readonly TestActions Actions = new TestActions();
|
||||
|
||||
// Records the arguments passed to StartCallback.
|
||||
IList<string> StartCallbackIn = new List<string>();
|
||||
readonly IList<string> StartCallbackIn = new List<string>();
|
||||
|
||||
void StartCallback(string s, bool silent)
|
||||
{
|
||||
@@ -189,8 +190,8 @@ namespace Semmle.Autobuild.CSharp.Tests
|
||||
}
|
||||
|
||||
// Records the arguments passed to EndCallback
|
||||
IList<string> EndCallbackIn = new List<string>();
|
||||
IList<int> EndCallbackReturn = new List<int>();
|
||||
readonly IList<string> EndCallbackIn = new List<string>();
|
||||
readonly IList<int> EndCallbackReturn = new List<int>();
|
||||
|
||||
void EndCallback(int ret, string s, bool silent)
|
||||
{
|
||||
|
||||
@@ -19,6 +19,12 @@ namespace Semmle.Autobuild.Shared
|
||||
BuildScript Analyse(Autobuilder builder, bool auto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A delegate used to wrap a build script in an environment where an appropriate
|
||||
/// version of .NET Core is automatically installed.
|
||||
/// </summary>
|
||||
public delegate BuildScript WithDotNet(Autobuilder builder, Func<IDictionary<string, string>?, BuildScript> f);
|
||||
|
||||
/// <summary>
|
||||
/// Exception indicating that environment variables are missing or invalid.
|
||||
/// </summary>
|
||||
|
||||
@@ -11,9 +11,9 @@ namespace Semmle.Autobuild.Shared
|
||||
/// </summary>
|
||||
public class BuildCommandAutoRule : IBuildRule
|
||||
{
|
||||
private readonly Func<Autobuilder, Func<IDictionary<string, string>?, BuildScript>, BuildScript> withDotNet;
|
||||
private readonly WithDotNet withDotNet;
|
||||
|
||||
public BuildCommandAutoRule(Func<Autobuilder, Func<IDictionary<string, string>?, BuildScript>, BuildScript> withDotNet)
|
||||
public BuildCommandAutoRule(WithDotNet withDotNet)
|
||||
{
|
||||
this.withDotNet = withDotNet;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@ namespace Semmle.Autobuild.Shared
|
||||
/// </summary>
|
||||
public class BuildCommandRule : IBuildRule
|
||||
{
|
||||
private readonly Func<Autobuilder, Func<IDictionary<string, string>?, BuildScript>, BuildScript> withDotNet;
|
||||
private readonly WithDotNet withDotNet;
|
||||
|
||||
public BuildCommandRule(Func<Autobuilder, Func<IDictionary<string, string>?, BuildScript>, BuildScript> withDotNet)
|
||||
public BuildCommandRule(WithDotNet withDotNet)
|
||||
{
|
||||
this.withDotNet = withDotNet;
|
||||
}
|
||||
|
||||
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
|
||||
@@ -185,7 +185,7 @@ namespace Semmle.Extraction.Tests
|
||||
|
||||
class StringTrapEmitter : ITrapEmitter
|
||||
{
|
||||
string Content;
|
||||
readonly string Content;
|
||||
public StringTrapEmitter(string content)
|
||||
{
|
||||
Content = content;
|
||||
|
||||
@@ -191,7 +191,7 @@ namespace Semmle.Extraction.Tests
|
||||
[Fact]
|
||||
public void ArchiveArguments()
|
||||
{
|
||||
var sw = new StringWriter();
|
||||
using var sw = new StringWriter();
|
||||
var file = Path.GetTempFileName();
|
||||
|
||||
try
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Semmle.Extraction.Entities
|
||||
|
||||
class GeneratedLocationFactory : ICachedEntityFactory<string?, GeneratedLocation>
|
||||
{
|
||||
public static GeneratedLocationFactory Instance = new GeneratedLocationFactory();
|
||||
public static readonly GeneratedLocationFactory Instance = new GeneratedLocationFactory();
|
||||
|
||||
public GeneratedLocation Create(Context cx, string? init) => new GeneratedLocation(cx);
|
||||
}
|
||||
|
||||
@@ -21,15 +21,7 @@ namespace SemmleTests.Semmle.Util
|
||||
// Change directories to a directory that is in canonical form.
|
||||
Directory.SetCurrentDirectory(cache.GetCanonicalPath(Path.GetTempPath()));
|
||||
|
||||
if (Win32.IsWindows())
|
||||
{
|
||||
root = @"X:\";
|
||||
}
|
||||
else
|
||||
{
|
||||
root = "/";
|
||||
}
|
||||
|
||||
root = Win32.IsWindows() ? @"X:\" : "/";
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
@@ -143,10 +135,10 @@ namespace SemmleTests.Semmle.Util
|
||||
Assert.Equal(0, cache.CacheSize);
|
||||
|
||||
// The file "ABC" will fill the cache with parent directory info.
|
||||
string cp = cache.GetCanonicalPath("ABC");
|
||||
cache.GetCanonicalPath("ABC");
|
||||
Assert.True(cache.CacheSize == 2);
|
||||
|
||||
cp = cache.GetCanonicalPath("def");
|
||||
string cp = cache.GetCanonicalPath("def");
|
||||
Assert.Equal(2, cache.CacheSize);
|
||||
Assert.Equal(Path.GetFullPath("def"), cp);
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace SemmleTests.Semmle.Util
|
||||
Assert.Equal("def", File.ReadAllText(shortPath));
|
||||
}
|
||||
|
||||
byte[] buffer1 = new byte[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
readonly byte[] buffer1 = new byte[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
|
||||
[Fact]
|
||||
public void CreateShortStream()
|
||||
|
||||
3
csharp/ql/examples/qlpack.yml
Normal file
3
csharp/ql/examples/qlpack.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
name: codeql-csharp-examples
|
||||
version: 0.0.0
|
||||
libraryPathDependencies: codeql-csharp
|
||||
@@ -6,7 +6,7 @@
|
||||
* @problem.severity recommendation
|
||||
* @precision high
|
||||
* @id cs/inefficient-containskey
|
||||
* @tag maintainability efficiency
|
||||
* @tags maintainability efficiency
|
||||
*/
|
||||
|
||||
import csharp
|
||||
|
||||
@@ -7,3 +7,10 @@
|
||||
tags contain:
|
||||
- ide-contextual-queries/local-definitions
|
||||
- ide-contextual-queries/local-references
|
||||
- query: Metrics/Dependencies/ExternalDependencies.ql
|
||||
- query: Metrics/Dependencies/ExternalDependenciesSourceLinks.ql
|
||||
- query: Metrics/Files/FLinesOfCode.ql
|
||||
- query: Metrics/Files/FLinesOfCommentedCode.ql
|
||||
- query: Metrics/Files/FLinesOfComment.ql
|
||||
- query: Metrics/Files/FLinesOfDuplicatedCode.ql
|
||||
- query: Metrics/Files/FNumberOfTests.ql
|
||||
|
||||
@@ -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."
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Provides classes representing individual opcodes.
|
||||
*
|
||||
* See ECMA-335 (http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-335.pdf)
|
||||
* See ECMA-335 (https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf)
|
||||
* pages 32-101 for a detailed explanation of these instructions.
|
||||
*/
|
||||
|
||||
|
||||
@@ -876,6 +876,8 @@ module Internal {
|
||||
not e.(QualifiableExpr).isConditional()
|
||||
or
|
||||
e instanceof SuppressNullableWarningExpr
|
||||
or
|
||||
e.stripCasts().getType() = any(ValueType t | not t instanceof NullableType)
|
||||
}
|
||||
|
||||
/** Holds if expression `e2` is a non-`null` value whenever `e1` is. */
|
||||
|
||||
@@ -197,42 +197,44 @@ private predicate isNullDefaultArgument(Ssa::ExplicitDefinition def, AlwaysNullE
|
||||
|
||||
/** Holds if `def` is an SSA definition that may be `null`. */
|
||||
private predicate defMaybeNull(Ssa::Definition def, string msg, Element reason) {
|
||||
// A variable compared to `null` might be `null`
|
||||
exists(G::DereferenceableExpr de | de = def.getARead() |
|
||||
reason = de.getANullCheck(_, true) and
|
||||
msg = "as suggested by $@ null check" and
|
||||
not de = any(Ssa::PseudoDefinition pdef).getARead() and
|
||||
strictcount(Element e | e = any(Ssa::Definition def0 | de = def0.getARead()).getElement()) = 1 and
|
||||
not nonNullDef(def) and
|
||||
// Don't use a check as reason if there is a `null` assignment
|
||||
// or argument
|
||||
not def.(Ssa::ExplicitDefinition).getADefinition().getSource() instanceof MaybeNullExpr and
|
||||
not isMaybeNullArgument(def, _)
|
||||
)
|
||||
or
|
||||
// A parameter might be `null` if there is a `null` argument somewhere
|
||||
isMaybeNullArgument(def, reason) and
|
||||
not nonNullDef(def) and
|
||||
(
|
||||
if reason instanceof AlwaysNullExpr
|
||||
then msg = "because of $@ null argument"
|
||||
else msg = "because of $@ potential null argument"
|
||||
)
|
||||
or
|
||||
isNullDefaultArgument(def, reason) and msg = "because the parameter has a null default value"
|
||||
or
|
||||
// If the source of a variable is `null` then the variable may be `null`
|
||||
exists(AssignableDefinition adef | adef = def.(Ssa::ExplicitDefinition).getADefinition() |
|
||||
adef.getSource() instanceof MaybeNullExpr and
|
||||
reason = adef.getExpr() and
|
||||
msg = "because of $@ assignment"
|
||||
)
|
||||
or
|
||||
// A variable of nullable type may be null
|
||||
exists(Dereference d | dereferenceAt(_, _, def, d) |
|
||||
d.hasNullableType() and
|
||||
not def instanceof Ssa::PseudoDefinition and
|
||||
reason = def.getSourceVariable().getAssignable() and
|
||||
msg = "because it has a nullable type"
|
||||
// A variable compared to `null` might be `null`
|
||||
exists(G::DereferenceableExpr de | de = def.getARead() |
|
||||
reason = de.getANullCheck(_, true) and
|
||||
msg = "as suggested by $@ null check" and
|
||||
not de = any(Ssa::PseudoDefinition pdef).getARead() and
|
||||
strictcount(Element e | e = any(Ssa::Definition def0 | de = def0.getARead()).getElement()) = 1 and
|
||||
// Don't use a check as reason if there is a `null` assignment
|
||||
// or argument
|
||||
not def.(Ssa::ExplicitDefinition).getADefinition().getSource() instanceof MaybeNullExpr and
|
||||
not isMaybeNullArgument(def, _)
|
||||
)
|
||||
or
|
||||
// A parameter might be `null` if there is a `null` argument somewhere
|
||||
isMaybeNullArgument(def, reason) and
|
||||
(
|
||||
if reason instanceof AlwaysNullExpr
|
||||
then msg = "because of $@ null argument"
|
||||
else msg = "because of $@ potential null argument"
|
||||
)
|
||||
or
|
||||
isNullDefaultArgument(def, reason) and msg = "because the parameter has a null default value"
|
||||
or
|
||||
// If the source of a variable is `null` then the variable may be `null`
|
||||
exists(AssignableDefinition adef | adef = def.(Ssa::ExplicitDefinition).getADefinition() |
|
||||
adef.getSource() instanceof MaybeNullExpr and
|
||||
reason = adef.getExpr() and
|
||||
msg = "because of $@ assignment"
|
||||
)
|
||||
or
|
||||
// A variable of nullable type may be null
|
||||
exists(Dereference d | dereferenceAt(_, _, def, d) |
|
||||
d.hasNullableType() and
|
||||
not def instanceof Ssa::PseudoDefinition and
|
||||
reason = def.getSourceVariable().getAssignable() and
|
||||
msg = "because it has a nullable type"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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()))
|
||||
|
||||
@@ -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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,10 @@ alwaysNull
|
||||
| dataflow.cs:80:21:80:44 | access to property NullProperty |
|
||||
| dataflow.cs:89:31:89:44 | call to method NullFunction |
|
||||
alwaysNotNull
|
||||
| dataflow.cs:71:13:71:20 | access to local variable nonNull1 |
|
||||
| dataflow.cs:71:13:71:35 | Int32 nonNull1 = ... |
|
||||
| dataflow.cs:71:24:71:35 | default(...) |
|
||||
| dataflow.cs:71:32:71:34 | access to type Int32 |
|
||||
| dataflow.cs:72:27:72:30 | this access |
|
||||
| dataflow.cs:72:27:72:40 | call to method GetType |
|
||||
| dataflow.cs:73:30:73:33 | true |
|
||||
@@ -25,6 +28,7 @@ alwaysNotNull
|
||||
| dataflow.cs:85:24:85:30 | access to local variable nonNull |
|
||||
| dataflow.cs:85:24:85:55 | call to method ReturnsNonNullIndirect |
|
||||
| dataflow.cs:86:24:86:30 | access to local variable nonNull |
|
||||
| dataflow.cs:89:24:89:27 | access to field cond |
|
||||
| dataflow.cs:89:24:89:27 | this access |
|
||||
| dataflow.cs:89:31:89:44 | this access |
|
||||
| dataflow.cs:89:48:89:51 | this access |
|
||||
|
||||
@@ -385,6 +385,32 @@ public class E
|
||||
return true;
|
||||
return e1.Long == e2.Long; // GOOD (false positive)
|
||||
}
|
||||
|
||||
int Ex38(int? i)
|
||||
{
|
||||
i ??= 0;
|
||||
return i.Value; // GOOD
|
||||
}
|
||||
|
||||
System.Drawing.Color Ex39(System.Drawing.Color? color)
|
||||
{
|
||||
color ??= System.Drawing.Color.White;
|
||||
return color.Value; // GOOD
|
||||
}
|
||||
|
||||
int Ex40()
|
||||
{
|
||||
int? i = null;
|
||||
i ??= null;
|
||||
return i.Value; // BAD (always)
|
||||
}
|
||||
|
||||
int Ex41()
|
||||
{
|
||||
int? i = 1;
|
||||
i ??= null;
|
||||
return i.Value; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
public static class Extensions
|
||||
@@ -393,4 +419,4 @@ public static class Extensions
|
||||
public static int M2(this string s) => s.Length;
|
||||
}
|
||||
|
||||
// semmle-extractor-options: /r:System.Linq.dll
|
||||
// semmle-extractor-options: /r:System.Linq.dll /r:System.Drawing.Primitives.dll
|
||||
|
||||
@@ -1115,12 +1115,14 @@
|
||||
| E.cs:176:13:176:14 | access to local variable b2 | true | E.cs:175:19:175:42 | ... ? ... : ... | true |
|
||||
| E.cs:176:13:176:22 | ... == ... | false | E.cs:176:13:176:14 | (...) ... | non-null |
|
||||
| E.cs:176:13:176:22 | ... == ... | true | E.cs:176:13:176:14 | (...) ... | null |
|
||||
| E.cs:176:13:176:22 | ... == ... | true | E.cs:176:19:176:22 | null | non-null |
|
||||
| E.cs:180:13:180:23 | ... == ... | false | E.cs:180:13:180:15 | access to parameter obj | non-null |
|
||||
| E.cs:180:13:180:23 | ... == ... | true | E.cs:180:13:180:15 | access to parameter obj | null |
|
||||
| E.cs:184:13:184:14 | (...) ... | non-null | E.cs:184:13:184:14 | access to parameter b1 | non-null |
|
||||
| E.cs:184:13:184:14 | (...) ... | null | E.cs:184:13:184:14 | access to parameter b1 | null |
|
||||
| E.cs:184:13:184:22 | ... == ... | false | E.cs:184:13:184:14 | (...) ... | non-null |
|
||||
| E.cs:184:13:184:22 | ... == ... | true | E.cs:184:13:184:14 | (...) ... | null |
|
||||
| E.cs:184:13:184:22 | ... == ... | true | E.cs:184:19:184:22 | null | non-null |
|
||||
| E.cs:193:19:193:29 | call to method ToString | non-null | E.cs:193:17:193:17 | access to parameter o | non-null |
|
||||
| E.cs:198:17:198:29 | ... ? ... : ... | non-null | E.cs:198:17:198:17 | access to parameter b | false |
|
||||
| E.cs:198:17:198:29 | ... ? ... : ... | non-null | E.cs:198:28:198:29 | "" | non-null |
|
||||
@@ -1256,6 +1258,26 @@
|
||||
| E.cs:384:13:384:36 | ... && ... | true | E.cs:384:27:384:36 | ... == ... | true |
|
||||
| E.cs:384:27:384:36 | ... == ... | false | E.cs:384:27:384:28 | access to parameter e2 | non-null |
|
||||
| E.cs:384:27:384:36 | ... == ... | true | E.cs:384:27:384:28 | access to parameter e2 | null |
|
||||
| E.cs:404:9:404:9 | access to local variable i | non-null | E.cs:403:18:403:21 | null | non-null |
|
||||
| E.cs:404:9:404:9 | access to local variable i | null | E.cs:403:18:403:21 | null | null |
|
||||
| E.cs:404:9:404:18 | ... = ... | non-null | E.cs:404:9:404:9 | access to local variable i | non-null |
|
||||
| E.cs:404:9:404:18 | ... = ... | non-null | E.cs:404:9:404:18 | ... ?? ... | non-null |
|
||||
| E.cs:404:9:404:18 | ... = ... | null | E.cs:404:9:404:9 | access to local variable i | null |
|
||||
| E.cs:404:9:404:18 | ... = ... | null | E.cs:404:9:404:18 | ... ?? ... | null |
|
||||
| E.cs:404:9:404:18 | ... ?? ... | null | E.cs:404:9:404:9 | access to local variable i | null |
|
||||
| E.cs:404:9:404:18 | ... ?? ... | null | E.cs:404:15:404:18 | null | null |
|
||||
| E.cs:405:16:405:16 | access to local variable i | non-null | E.cs:404:9:404:18 | ... ?? ... | non-null |
|
||||
| E.cs:405:16:405:16 | access to local variable i | null | E.cs:404:9:404:18 | ... ?? ... | null |
|
||||
| E.cs:411:9:411:9 | access to local variable i | non-null | E.cs:410:18:410:18 | (...) ... | non-null |
|
||||
| E.cs:411:9:411:9 | access to local variable i | null | E.cs:410:18:410:18 | (...) ... | null |
|
||||
| E.cs:411:9:411:18 | ... = ... | non-null | E.cs:411:9:411:9 | access to local variable i | non-null |
|
||||
| E.cs:411:9:411:18 | ... = ... | non-null | E.cs:411:9:411:18 | ... ?? ... | non-null |
|
||||
| E.cs:411:9:411:18 | ... = ... | null | E.cs:411:9:411:9 | access to local variable i | null |
|
||||
| E.cs:411:9:411:18 | ... = ... | null | E.cs:411:9:411:18 | ... ?? ... | null |
|
||||
| E.cs:411:9:411:18 | ... ?? ... | null | E.cs:411:9:411:9 | access to local variable i | null |
|
||||
| E.cs:411:9:411:18 | ... ?? ... | null | E.cs:411:15:411:18 | null | null |
|
||||
| E.cs:412:16:412:16 | access to local variable i | non-null | E.cs:411:9:411:18 | ... ?? ... | non-null |
|
||||
| E.cs:412:16:412:16 | access to local variable i | null | E.cs:411:9:411:18 | ... ?? ... | null |
|
||||
| Forwarding.cs:9:13:9:30 | !... | false | Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | true |
|
||||
| Forwarding.cs:9:13:9:30 | !... | true | Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | false |
|
||||
| Forwarding.cs:9:14:9:14 | access to local variable s | empty | Forwarding.cs:7:20:7:23 | null | empty |
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
| E.cs:323:13:323:14 | access to parameter s1 | Variable $@ is always null here. | E.cs:319:29:319:30 | s1 | s1 |
|
||||
| E.cs:324:13:324:14 | access to parameter s2 | Variable $@ is always null here. | E.cs:319:40:319:41 | s2 | s2 |
|
||||
| E.cs:331:9:331:9 | access to local variable x | Variable $@ is always null here. | E.cs:330:13:330:13 | x | x |
|
||||
| E.cs:405:16:405:16 | access to local variable i | Variable $@ is always null here. | E.cs:403:14:403:14 | i | i |
|
||||
| Forwarding.cs:36:31:36:31 | access to local variable s | Variable $@ is always null here. | Forwarding.cs:7:16:7:16 | s | s |
|
||||
| Forwarding.cs:40:27:40:27 | access to local variable s | Variable $@ is always null here. | Forwarding.cs:7:16:7:16 | s | s |
|
||||
| NullAlwaysBad.cs:9:30:9:30 | access to parameter s | Variable $@ is always null here. | NullAlwaysBad.cs:7:29:7:29 | s | s |
|
||||
|
||||
@@ -219,10 +219,12 @@
|
||||
| E.cs:175:19:175:29 | ... == ... | E.cs:175:19:175:21 | access to parameter obj | true | true |
|
||||
| E.cs:176:13:176:22 | ... == ... | E.cs:176:13:176:14 | (...) ... | false | false |
|
||||
| E.cs:176:13:176:22 | ... == ... | E.cs:176:13:176:14 | (...) ... | true | true |
|
||||
| E.cs:176:13:176:22 | ... == ... | E.cs:176:19:176:22 | null | true | false |
|
||||
| E.cs:180:13:180:23 | ... == ... | E.cs:180:13:180:15 | access to parameter obj | false | false |
|
||||
| E.cs:180:13:180:23 | ... == ... | E.cs:180:13:180:15 | access to parameter obj | true | true |
|
||||
| E.cs:184:13:184:22 | ... == ... | E.cs:184:13:184:14 | (...) ... | false | false |
|
||||
| E.cs:184:13:184:22 | ... == ... | E.cs:184:13:184:14 | (...) ... | true | true |
|
||||
| E.cs:184:13:184:22 | ... == ... | E.cs:184:19:184:22 | null | true | false |
|
||||
| E.cs:193:17:193:17 | access to parameter o | E.cs:193:17:193:17 | access to parameter o | non-null | false |
|
||||
| E.cs:193:17:193:17 | access to parameter o | E.cs:193:17:193:17 | access to parameter o | null | true |
|
||||
| E.cs:208:13:208:23 | ... is ... | E.cs:208:13:208:13 | access to parameter s | false | true |
|
||||
@@ -276,6 +278,14 @@
|
||||
| E.cs:384:13:384:22 | ... == ... | E.cs:384:13:384:14 | access to parameter e1 | true | true |
|
||||
| E.cs:384:27:384:36 | ... == ... | E.cs:384:27:384:28 | access to parameter e2 | false | false |
|
||||
| E.cs:384:27:384:36 | ... == ... | E.cs:384:27:384:28 | access to parameter e2 | true | true |
|
||||
| E.cs:391:9:391:9 | access to parameter i | E.cs:391:9:391:9 | access to parameter i | non-null | false |
|
||||
| E.cs:391:9:391:9 | access to parameter i | E.cs:391:9:391:9 | access to parameter i | null | true |
|
||||
| E.cs:397:9:397:13 | access to parameter color | E.cs:397:9:397:13 | access to parameter color | non-null | false |
|
||||
| E.cs:397:9:397:13 | access to parameter color | E.cs:397:9:397:13 | access to parameter color | null | true |
|
||||
| E.cs:404:9:404:9 | access to local variable i | E.cs:404:9:404:9 | access to local variable i | non-null | false |
|
||||
| E.cs:404:9:404:9 | access to local variable i | E.cs:404:9:404:9 | access to local variable i | null | true |
|
||||
| E.cs:411:9:411:9 | access to local variable i | E.cs:411:9:411:9 | access to local variable i | non-null | false |
|
||||
| E.cs:411:9:411:9 | access to local variable i | E.cs:411:9:411:9 | access to local variable i | null | true |
|
||||
| Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | Forwarding.cs:9:14:9:14 | access to local variable s | false | false |
|
||||
| Forwarding.cs:14:13:14:32 | call to method IsNotNullOrEmpty | Forwarding.cs:14:13:14:13 | access to local variable s | true | false |
|
||||
| Forwarding.cs:19:14:19:23 | call to method IsNull | Forwarding.cs:19:14:19:14 | access to local variable s | false | false |
|
||||
|
||||
@@ -370,6 +370,9 @@ nodes
|
||||
| E.cs:384:27:384:28 | access to parameter e2 |
|
||||
| E.cs:386:16:386:17 | access to parameter e1 |
|
||||
| E.cs:386:27:386:28 | access to parameter e2 |
|
||||
| E.cs:404:9:404:18 | SSA def(i) |
|
||||
| E.cs:404:9:404:18 | SSA def(i) |
|
||||
| E.cs:405:16:405:16 | access to local variable i |
|
||||
| Forwarding.cs:7:16:7:23 | SSA def(s) |
|
||||
| Forwarding.cs:14:9:17:9 | if (...) ... |
|
||||
| Forwarding.cs:19:9:22:9 | if (...) ... |
|
||||
@@ -719,6 +722,8 @@ edges
|
||||
| E.cs:384:9:385:24 | if (...) ... | E.cs:384:27:384:28 | access to parameter e2 |
|
||||
| E.cs:384:9:385:24 | if (...) ... | E.cs:386:27:386:28 | access to parameter e2 |
|
||||
| E.cs:384:27:384:28 | access to parameter e2 | E.cs:386:16:386:17 | access to parameter e1 |
|
||||
| E.cs:404:9:404:18 | SSA def(i) | E.cs:405:16:405:16 | access to local variable i |
|
||||
| E.cs:404:9:404:18 | SSA def(i) | E.cs:405:16:405:16 | access to local variable i |
|
||||
| Forwarding.cs:7:16:7:23 | SSA def(s) | Forwarding.cs:14:9:17:9 | if (...) ... |
|
||||
| Forwarding.cs:14:9:17:9 | if (...) ... | Forwarding.cs:19:9:22:9 | if (...) ... |
|
||||
| Forwarding.cs:19:9:22:9 | if (...) ... | Forwarding.cs:24:9:27:9 | if (...) ... |
|
||||
|
||||
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
|
||||
16
csharp/tools/osx64/extract-csharp.sh
Executable file
16
csharp/tools/osx64/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/pre-finalize.cmd
Normal file
14
csharp/tools/pre-finalize.cmd
Normal file
@@ -0,0 +1,14 @@
|
||||
@echo off
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
|
||||
type NUL && "%CODEQL_DIST%\codeql" database index-files ^
|
||||
--include-extension=.config ^
|
||||
--include-extension=.csproj ^
|
||||
--include-extension=.props ^
|
||||
--include-extension=.xml ^
|
||||
--size-limit 10m ^
|
||||
--language xml ^
|
||||
-- ^
|
||||
"%CODEQL_EXTRACTOR_CSHARP_WIP_DATABASE%"
|
||||
|
||||
ENDLOCAL
|
||||
13
csharp/tools/pre-finalize.sh
Executable file
13
csharp/tools/pre-finalize.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
"$CODEQL_DIST/codeql" database index-files \
|
||||
--include-extension=.config \
|
||||
--include-extension=.csproj \
|
||||
--include-extension=.props \
|
||||
--include-extension=.xml \
|
||||
--size-limit 10m \
|
||||
--language xml \
|
||||
-- \
|
||||
"$CODEQL_EXTRACTOR_CSHARP_WIP_DATABASE"
|
||||
9
csharp/tools/win64/compiler-tracing.spec
Normal file
9
csharp/tools/win64/compiler-tracing.spec
Normal file
@@ -0,0 +1,9 @@
|
||||
**\fakes*.exe:
|
||||
**\moles*.exe:
|
||||
order compiler
|
||||
trace no
|
||||
**\csc*.exe:
|
||||
invoke ${config_dir}\Semmle.Extraction.CSharp.Driver.exe
|
||||
prepend --compiler
|
||||
prepend "${compiler}"
|
||||
prepend --cil
|
||||
BIN
docs/language/images/query-progress.png
Normal file
BIN
docs/language/images/query-progress.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
145
docs/language/learn-ql/cpp/basic-query-cpp.rst
Normal file
145
docs/language/learn-ql/cpp/basic-query-cpp.rst
Normal file
@@ -0,0 +1,145 @@
|
||||
Basic query for C and C++ code
|
||||
==============================
|
||||
|
||||
Learn to write and run a simple CodeQL query using LGTM.
|
||||
|
||||
About the query
|
||||
---------------
|
||||
|
||||
The query we're going to run performs a basic search of the code for ``if`` statements that are redundant, in the sense that they have an empty then branch. For example, code such as:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
if (error) { }
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
|
||||
#. Click the project in the search results.
|
||||
|
||||
#. Click **Query this project**.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **C/C++** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import cpp
|
||||
|
||||
from IfStmt ifstmt, Block block
|
||||
where ifstmt.getThen() = block and
|
||||
block.getNumStmt() = 0
|
||||
select ifstmt, "This 'if' statement is redundant."
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
|
||||
#. Click **Run**.
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
|
||||
.. image:: ../../images/query-progress.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to the expression ``ifstmt`` and is linked to the location in the source code of the project where ``ifstmt`` occurs. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/4242591143131494898/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click a link in the ``ifstmt`` column to view the ``if`` statement in the code viewer.
|
||||
|
||||
The matching ``if`` statement is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
After the initial ``import`` statement, this simple query comprises three parts that serve similar purposes to the FROM, WHERE, and SELECT parts of an SQL query.
|
||||
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
| Query part | Purpose | Details |
|
||||
+===============================================================+===================================================================================================================+========================================================================================================================+
|
||||
| ``import cpp`` | Imports the standard CodeQL libraries for C/C++. | Every query begins with one or more ``import`` statements. |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``from IfStmt ifstmt, Block block`` | Defines the variables for the query. | We use: |
|
||||
| | Declarations are of the form: | |
|
||||
| | ``<type> <variable name>`` | - an ``IfStmt`` variable for ``if`` statements |
|
||||
| | | - a ``Block`` variable for the statement block |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``where ifstmt.getThen() = block and block.getNumStmt() = 0`` | Defines a condition on the variables. | ``ifstmt.getThen() = block`` relates the two variables. The block must be the ``then`` branch of the ``if`` statement. |
|
||||
| | | |
|
||||
| | | ``block.getNumStmt() = 0`` states that the block must be empty (that is, it contains no statements). |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``select ifstmt, "This 'if' statement is redundant."`` | Defines what to report for each match. | Reports the resulting ``if`` statement with a string that explains the problem. |
|
||||
| | | |
|
||||
| | ``select`` statements for queries that are used to find instances of poor coding practice are always in the form: | |
|
||||
| | ``select <program element>, "<alert message>"`` | |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
Extend the query
|
||||
----------------
|
||||
|
||||
Query writing is an inherently iterative process. You write a simple query and then, when you run it, you discover examples that you had not previously considered, or opportunities for improvement.
|
||||
|
||||
Remove false positive results
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Browsing the results of our basic query shows that it could be improved. Among the results you are likely to find examples of ``if`` statements with an ``else`` branch, where an empty ``then`` branch does serve a purpose. For example:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
if (...) {
|
||||
...
|
||||
} else if (!strcmp(option, "-verbose") {
|
||||
// nothing to do - handled earlier
|
||||
} else {
|
||||
error("unrecognized option");
|
||||
}
|
||||
|
||||
In this case, identifying the ``if`` statement with the empty ``then`` branch as redundant is a false positive. One solution to this is to modify the query to ignore empty ``then`` branches if the ``if`` statement has an ``else`` branch.
|
||||
|
||||
To exclude ``if`` statements that have an ``else`` branch:
|
||||
|
||||
#. Extend the ``where`` clause to include the following extra condition:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
and not ifstmt.hasElse()
|
||||
|
||||
The ``where`` clause is now:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
where ifstmt.getThen() = block and
|
||||
block.getNumStmt() = 0 and
|
||||
not ifstmt.hasElse()
|
||||
|
||||
#. Click **Run**.
|
||||
|
||||
There are now fewer results because ``if`` statements with an ``else`` branch are no longer reported.
|
||||
|
||||
➤ `See this in the query console <https://lgtm.com/query/1899933116489579248/>`__
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../../reusables/cpp-further-reading.rst
|
||||
.. include:: ../../reusables/codeql-ref-tools-further-reading.rst
|
||||
@@ -6,6 +6,7 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
basic-query-cpp
|
||||
introduce-libraries-cpp
|
||||
function-classes
|
||||
expressions-types
|
||||
@@ -18,7 +19,7 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat
|
||||
value-numbering-hash-cons
|
||||
|
||||
|
||||
- `Basic C/C++ query <https://lgtm.com/help/lgtm/console/ql-cpp-basic-example>`__: Learn to write and run a simple CodeQL query using LGTM.
|
||||
- :doc:`Basic query for C and C++ code <basic-query-cpp>`: Learn to write and run a simple CodeQL query using LGTM.
|
||||
|
||||
- :doc:`CodeQL library for C and C++ <introduce-libraries-cpp>`: When analyzing C or C++ code, you can use the large collection of classes in the CodeQL library for C and C++.
|
||||
|
||||
|
||||
150
docs/language/learn-ql/csharp/basic-query-csharp.rst
Normal file
150
docs/language/learn-ql/csharp/basic-query-csharp.rst
Normal file
@@ -0,0 +1,150 @@
|
||||
Basic query for C# code
|
||||
=======================
|
||||
|
||||
Learn to write and run a simple CodeQL query using LGTM.
|
||||
|
||||
About the query
|
||||
---------------
|
||||
|
||||
The query we're going to run performs a basic search of the code for ``if`` statements that are redundant, in the sense that they have an empty then branch. For example, code such as:
|
||||
|
||||
.. code-block:: csharp
|
||||
|
||||
if (error) { }
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
|
||||
#. Click the project in the search results.
|
||||
|
||||
#. Click **Query this project**.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **C#** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import csharp
|
||||
|
||||
from IfStmt ifstmt, BlockStmt block
|
||||
where ifstmt.getThen() = block and
|
||||
block.isEmpty()
|
||||
select ifstmt, "This 'if' statement is redundant."
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
|
||||
#. Click **Run**.
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
|
||||
.. image:: ../../images/query-progress.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to the expression ``ifstmt`` and is linked to the location in the source code of the project where ``ifstmt`` occurs. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/1214010107827821393/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click a link in the ``ifstmt`` column to view the ``if`` statement in the code viewer.
|
||||
|
||||
The matching ``if`` statement is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
After the initial ``import`` statement, this simple query comprises three parts that serve similar purposes to the FROM, WHERE, and SELECT parts of an SQL query.
|
||||
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
| Query part | Purpose | Details |
|
||||
+===============================================================+===================================================================================================================+========================================================================================================================+
|
||||
| ``import csharp`` | Imports the standard CodeQL libraries for C#. | Every query begins with one or more ``import`` statements. |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``from IfStmt ifstmt, BlockStmt block`` | Defines the variables for the query. | We use: |
|
||||
| | Declarations are of the form: | |
|
||||
| | ``<type> <variable name>`` | - an ``IfStmt`` variable for ``if`` statements |
|
||||
| | | - a ``BlockStmt`` variable for the then block |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``where ifstmt.getThen() = block and block.isEmpty()`` | Defines a condition on the variables. | ``ifstmt.getThen() = block`` relates the two variables. The block must be the ``then`` branch of the ``if`` statement. |
|
||||
| | | |
|
||||
| | | ``block.isEmpty()`` states that the block must be empty (that is, it contains no statements). |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``select ifstmt, "This 'if' statement is redundant."`` | Defines what to report for each match. | Reports the resulting ``if`` statement with a string that explains the problem. |
|
||||
| | | |
|
||||
| | ``select`` statements for queries that are used to find instances of poor coding practice are always in the form: | |
|
||||
| | ``select <program element>, "<alert message>"`` | |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
Extend the query
|
||||
----------------
|
||||
|
||||
Query writing is an inherently iterative process. You write a simple query and then, when you run it, you discover examples that you had not previously considered, or opportunities for improvement.
|
||||
|
||||
Remove false positive results
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Browsing the results of our basic query shows that it could be improved. Among the results you are likely to find examples of ``if`` statements with an ``else`` branch, where an empty ``then`` branch does serve a purpose. For example:
|
||||
|
||||
.. code-block:: csharp
|
||||
|
||||
if (...)
|
||||
{
|
||||
...
|
||||
}
|
||||
else if (option == "-verbose")
|
||||
{
|
||||
// nothing to do - handled earlier
|
||||
}
|
||||
else
|
||||
{
|
||||
error("unrecognized option");
|
||||
}
|
||||
|
||||
In this case, identifying the ``if`` statement with the empty ``then`` branch as redundant is a false positive. One solution to this is to modify the query to ignore empty ``then`` branches if the ``if`` statement has an ``else`` branch.
|
||||
|
||||
To exclude ``if`` statements that have an ``else`` branch:
|
||||
|
||||
#. Add the following to the where clause:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
and not exists(ifstmt.getElse())
|
||||
|
||||
The ``where`` clause is now:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
where ifstmt.getThen() = block and
|
||||
block.isEmpty() and
|
||||
not exists(ifstmt.getElse())
|
||||
|
||||
#. Click **Run**.
|
||||
|
||||
There are now fewer results because ``if`` statements with an ``else`` branch are no longer included.
|
||||
|
||||
➤ `See this in the query console <https://lgtm.com/query/6233102733683510530/>`__
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../../reusables/csharp-further-reading.rst
|
||||
.. include:: ../../reusables/codeql-ref-tools-further-reading.rst
|
||||
@@ -6,10 +6,11 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
basic-query-csharp
|
||||
introduce-libraries-csharp
|
||||
dataflow
|
||||
|
||||
- `Basic C# query <https://lgtm.com/help/lgtm/console/ql-csharp-basic-example>`__: Learn to write and run a simple CodeQL query using LGTM.
|
||||
- :doc:`Basic query for C# code <basic-query-csharp>`: Learn to write and run a simple CodeQL query using LGTM.
|
||||
|
||||
- :doc:`CodeQL library for C# <introduce-libraries-csharp>`: When you're analyzing a C# program, you can make use of the large collection of classes in the CodeQL library for C#.
|
||||
|
||||
|
||||
151
docs/language/learn-ql/go/basic-query-go.rst
Normal file
151
docs/language/learn-ql/go/basic-query-go.rst
Normal file
@@ -0,0 +1,151 @@
|
||||
Basic query for Go code
|
||||
=======================
|
||||
|
||||
Learn to write and run a simple CodeQL query using LGTM.
|
||||
|
||||
About the query
|
||||
---------------
|
||||
|
||||
The query we're going to run searches the code for methods defined on value types that modify their receiver by writing a field:
|
||||
|
||||
.. code-block:: go
|
||||
|
||||
func (s MyStruct) valueMethod() { s.f = 1 } // method on value
|
||||
|
||||
This is problematic because the receiver argument is passed by value, not by reference. Consequently, valueMethod is called with a copy of the receiver object, so any changes it makes to the receiver will be invisible to the caller. To prevent this, the method should be defined on a pointer instead:
|
||||
|
||||
.. code-block:: go
|
||||
|
||||
func (s *MyStruct) pointerMethod() { s.f = 1 } // method on pointer
|
||||
|
||||
For further information on using methods on values or pointers in Go, see the `Go FAQ <https://golang.org/doc/faq#methods_on_values_or_pointers>`__.
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
|
||||
#. Click the project in the search results.
|
||||
|
||||
#. Click **Query this project**.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **Go** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import go
|
||||
|
||||
from Method m, Variable recv, Write w, Field f
|
||||
where
|
||||
recv = m.getReceiver() and
|
||||
w.writesField(recv.getARead(), f, _) and
|
||||
not recv.getType() instanceof PointerType
|
||||
select w, "This update to " + f + " has no effect, because " + recv + " is not a pointer."
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
|
||||
#. Click **Run**.
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
|
||||
.. image:: ../../images/query-progress.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to ``w``, which is the location in the source code where the receiver ``recv`` is modified. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/6221190009056970603/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click a link in the ``w`` column to view it in the code viewer.
|
||||
|
||||
The matching ``w`` is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
After the initial ``import`` statement, this simple query comprises three parts that serve similar purposes to the FROM, WHERE, and SELECT parts of an SQL query.
|
||||
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Query part | Purpose | Details |
|
||||
+===============================================================+===================================================================================================================+======================================================================================================================================+
|
||||
| ``import go`` | Imports the standard CodeQL libraries for Go. | Every query begins with one or more ``import`` statements. |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``from Method m, Variable recv, Write w, Field f`` | Defines the variables for the query. | We declare: |
|
||||
| | Declarations are of the form: | |
|
||||
| | ``<type> <variable name>`` | - ``m`` as a variable for all methods |
|
||||
| | | - a ``recv`` variable, which is the receiver of ``m`` |
|
||||
| | | - ``w`` as the location in the code where the receiver is modified |
|
||||
| | | - ``f`` as the field that is written when ``m`` is called |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``where recv = m.getReceiver() and | Defines a condition on the variables. | ``recv = m.getReceiver()`` states that ``recv`` must be the receiver variable of ``m``. |
|
||||
| w.writesField(recv.getARead(), f, _) and | | |
|
||||
| not recv.getType() instanceof PointerType`` | | ``w.writesField(recv.getARead(), f, _)`` states that ``w`` must be a location in the code where field ``f`` of ``recv`` is modified. |
|
||||
| | | We use a `'don't-care' expression <https://help.semmle.com/QL/ql-handbook/expressions.html#don-t-care-expressions>`__ _ for the |
|
||||
| | | value that is written to ``f``—the actual value doesn't matter in this query. |
|
||||
| | | |
|
||||
| | | ``not recv.getType() instanceof PointerType`` states that ``m`` is not a pointer method. |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``select w, "This update to " + f + | Defines what to report for each match. | Reports ``w`` with a message that explains the potential problem. |
|
||||
| " has no effect, because " + recv + " is not a pointer."`` | | |
|
||||
| | ``select`` statements for queries that are used to find instances of poor coding practice are always in the form: | |
|
||||
| | ``select <program element>, "<alert message>"`` | |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
Extend the query
|
||||
----------------
|
||||
|
||||
Query writing is an inherently iterative process. You write a simple query and then, when you run it, you discover examples that you had not previously considered, or opportunities for improvement.
|
||||
|
||||
Remove false positive results
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Among the results generated by the first iteration of this query, you can find cases where a value method is called but the receiver variable is returned. In such cases, the change to the receiver is not invisible to the caller, so a pointer method is not required. These are false positive results and you can improve the query by adding an extra condition to remove them.
|
||||
|
||||
To exclude these values:
|
||||
|
||||
#. Extend the where clause to include the following extra condition:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
not exists(ReturnStmt ret | ret.getExpr() = recv.getARead().asExpr())
|
||||
|
||||
The ``where`` clause is now:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
where e.isPure() and
|
||||
recv = m.getReceiver() and
|
||||
w.writesField(recv.getARead(), f, _) and
|
||||
not recv.getType() instanceof PointerType and
|
||||
not exists(ReturnStmt ret | ret.getExpr() = recv.getARead().asExpr())
|
||||
|
||||
#. Click **Run**.
|
||||
|
||||
There are now fewer results because value methods that return their receiver variable are no longer reported.
|
||||
|
||||
➤ `See this in the query console <https://lgtm.com/query/9110448975027954322/>`__
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../../reusables/go-further-reading.rst
|
||||
.. include:: ../../reusables/codeql-ref-tools-further-reading.rst
|
||||
@@ -554,7 +554,7 @@ fact that ``p != nil`` is ``true`` at this point:
|
||||
|
||||
|cfg2|
|
||||
|
||||
A typical use of this information would be in an analyis that looks for ``nil`` dereferences: such
|
||||
A typical use of this information would be in an analysis that looks for ``nil`` dereferences: such
|
||||
an analysis would be able to conclude that the field read ``p.f`` is safe because it is immediately
|
||||
preceded by a condition guard node guaranteeing that ``p`` is not ``nil``.
|
||||
|
||||
|
||||
122
docs/language/learn-ql/go/library-modeling-go.rst
Normal file
122
docs/language/learn-ql/go/library-modeling-go.rst
Normal file
@@ -0,0 +1,122 @@
|
||||
Modeling data flow in Go libraries
|
||||
==================================
|
||||
|
||||
When analyzing a Go program, CodeQL does not examine the source code for
|
||||
external packages. To track the flow of untrusted data through a library, you
|
||||
can create a model of the library.
|
||||
|
||||
You can find existing models in the ``ql/src/semmle/go/frameworks/`` folder of the
|
||||
`CodeQL for Go repository <https://github.com/github/codeql-go/tree/main/ql/src/semmle/go/frameworks>`__.
|
||||
To add a new model, you should make a new file in that folder, named after the library.
|
||||
|
||||
Sources
|
||||
-------
|
||||
|
||||
To mark a source of data that is controlled by an untrusted user, we
|
||||
create a class extending ``UntrustedFlowSource::Range``. Inheritance and
|
||||
the characteristic predicate of the class should be used to specify
|
||||
exactly the dataflow node that introduces the data. Here is a short
|
||||
example from ``Mux.qll``.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
class RequestVars extends DataFlow::UntrustedFlowSource::Range, DataFlow::CallNode {
|
||||
RequestVars() { this.getTarget().hasQualifiedName("github.com/gorilla/mux", "Vars") }
|
||||
}
|
||||
|
||||
This has the effect that all calls to `the function Vars from the
|
||||
package mux <http://www.gorillatoolkit.org/pkg/mux#Vars>`__ are
|
||||
treated as sources of untrusted data.
|
||||
|
||||
Flow propagation
|
||||
----------------
|
||||
|
||||
By default, we assume that all functions in libraries do not have
|
||||
any data flow. To indicate that a particular function does have data flow,
|
||||
create a class extending ``TaintTracking::FunctionModel`` (or
|
||||
``DataFlow::FunctionModel`` if the untrusted user data is passed on
|
||||
without being modified).
|
||||
|
||||
Inheritance and the characteristic predicate of the class should specify
|
||||
the function. The class should also have a member predicate with the signature
|
||||
``override predicate hasTaintFlow(FunctionInput inp, FunctionOutput outp)``
|
||||
(or
|
||||
``override predicate hasDataFlow(FunctionInput inp, FunctionOutput outp)``
|
||||
if extending ``DataFlow::FunctionModel``). The body should constrain
|
||||
``inp`` and ``outp``.
|
||||
|
||||
``FunctionInput`` is an abstract representation of the inputs to a
|
||||
function. The options are:
|
||||
|
||||
* the receiver (``inp.isReceiver()``)
|
||||
* one of the parameters (``inp.isParameter(i)``)
|
||||
* one of the results (``inp.isResult(i)``, or ``inp.isResult`` if there is only one result)
|
||||
|
||||
Note that it may seem strange that the result of a function could be
|
||||
considered as a function input, but it is needed in some cases. For
|
||||
instance, the function ``bufio.NewWriter`` returns a writer ``bw`` that
|
||||
buffers write operations to an underlying writer ``w``. If tainted data
|
||||
is written to ``bw``, then it makes sense to propagate that taint back
|
||||
to the underlying writer ``w``, which can be modeled by saying that
|
||||
``bufio.NewWriter`` propagates taint from its result to its first
|
||||
argument.
|
||||
|
||||
Similarly, ``FunctionOutput`` is an abstract representation of the
|
||||
outputs to a function. The options are:
|
||||
|
||||
* the receiver (``outp.isReceiver()``)
|
||||
* one of the parameters (``outp.isParameter(i)``)
|
||||
* one of the results (``outp.isResult(i)``, or ``outp.isResult`` if there is only one result)
|
||||
|
||||
Here is an example from ``Gin.qll``, which has been slightly simplified.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
private class ParamsGet extends TaintTracking::FunctionModel, Method {
|
||||
ParamsGet() { this.hasQualifiedName("github.com/gin-gonic/gin", "Params", "Get") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput inp, FunctionOutput outp) {
|
||||
inp.isReceiver() and outp.isResult(0)
|
||||
}
|
||||
}
|
||||
|
||||
This has the effect that calls to the ``Get`` method with receiver type
|
||||
``Params`` from the ``gin-gonic/gin`` package allow taint to flow from
|
||||
the receiver to the first result. In other words, if ``p`` has type
|
||||
``Params`` and taint can flow to it, then after the line
|
||||
``x := p.Get("foo")`` taint can also flow to ``x``.
|
||||
|
||||
Sanitizers
|
||||
----------
|
||||
|
||||
It is not necessary to indicate that library functions are sanitizers.
|
||||
Their bodies are not analyzed, so it is assumed that data does not
|
||||
flow through them.
|
||||
|
||||
Sinks
|
||||
-----
|
||||
|
||||
Data-flow sinks are specified by queries rather than by library models.
|
||||
However, you can use library models to indicate when functions belong to
|
||||
special categories. Queries can then use these categories when specifying
|
||||
sinks. Classes representing these special categories are contained in
|
||||
``ql/src/semmle/go/Concepts.qll`` in the `CodeQL for Go repository
|
||||
<https://github.com/github/codeql-go/blob/main/ql/src/semmle/go/Concepts.qll>`__.
|
||||
``Concepts.qll`` includes classes for logger mechanisms,
|
||||
HTTP response writers, HTTP redirects, and marshaling and unmarshaling
|
||||
functions.
|
||||
|
||||
Here is a short example from ``Stdlib.qll``, which has been slightly simplified.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
private class PrintfCall extends LoggerCall::Range, DataFlow::CallNode {
|
||||
PrintfCall() { this.getTarget().hasQualifiedName("fmt", ["Print", "Printf", "Println"]) }
|
||||
|
||||
override DataFlow::Node getAMessageComponent() { result = this.getAnArgument() }
|
||||
}
|
||||
|
||||
This has the effect that any call to ``Print``, ``Printf``, or
|
||||
``Println`` in the package ``fmt`` is recognized as a logger call.
|
||||
Any query that uses logger calls as a sink will then identify when tainted data
|
||||
has been passed as an argument to ``Print``, ``Printf``, or ``Println``.
|
||||
@@ -6,11 +6,16 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
basic-query-go
|
||||
introduce-libraries-go
|
||||
ast-class-reference
|
||||
library-modeling-go
|
||||
|
||||
- `Basic Go query <https://lgtm.com/help/lgtm/console/ql-go-basic-example>`__: Learn to write and run a simple CodeQL query using LGTM.
|
||||
- :doc:`Basic query for Go code <basic-query-go>`: Learn to write and run a simple CodeQL query using LGTM.
|
||||
|
||||
- :doc:`CodeQL library for Go <introduce-libraries-go>`: When you're analyzing a Go program, you can make use of the large collection of classes in the CodeQL library for Go.
|
||||
|
||||
- :doc:`Abstract syntax tree classes for working with Go programs <ast-class-reference>`: CodeQL has a large selection of classes for representing the abstract syntax tree of Go programs.
|
||||
|
||||
- :doc:`Modeling data flow in Go libraries <library-modeling-go>`: When analyzing a Go program, CodeQL does not examine the source code for external packages.
|
||||
To track the flow of untrusted data through a library, you can create a model of the library.
|
||||
|
||||
145
docs/language/learn-ql/java/basic-query-java.rst
Normal file
145
docs/language/learn-ql/java/basic-query-java.rst
Normal file
@@ -0,0 +1,145 @@
|
||||
Basic query for Java code
|
||||
=========================
|
||||
|
||||
Learn to write and run a simple CodeQL query using LGTM.
|
||||
|
||||
About the query
|
||||
---------------
|
||||
|
||||
The query we're going to run performs a basic search of the code for ``if`` statements that are redundant, in the sense that they have an empty then branch. For example, code such as:
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
if (error) { }
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
|
||||
#. Click the project in the search results.
|
||||
|
||||
#. Click **Query this project**.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **Java** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import java
|
||||
|
||||
from IfStmt ifstmt, Block block
|
||||
where ifstmt.getThen() = block and
|
||||
block.getNumStmt() = 0
|
||||
select ifstmt, "This 'if' statement is redundant."
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
|
||||
#. Click **Run**.
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
|
||||
.. image:: ../../images/query-progress.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to the expression ``ifstmt`` and is linked to the location in the source code of the project where ``ifstmt`` occurs. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/3235645104630320782/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click a link in the ``ifstmt`` column to view the ``if`` statement in the code viewer.
|
||||
|
||||
The matching ``if`` statement is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
After the initial ``import`` statement, this simple query comprises three parts that serve similar purposes to the FROM, WHERE, and SELECT parts of an SQL query.
|
||||
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
| Query part | Purpose | Details |
|
||||
+===============================================================+===================================================================================================================+========================================================================================================================+
|
||||
| ``import java`` | Imports the standard CodeQL libraries for Java. | Every query begins with one or more ``import`` statements. |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``from IfStmt ifstmt, Block block`` | Defines the variables for the query. | We use: |
|
||||
| | Declarations are of the form: | |
|
||||
| | ``<type> <variable name>`` | - an ``IfStmt`` variable for ``if`` statements |
|
||||
| | | - a ``Block`` variable for the then block |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``where ifstmt.getThen() = block and block.getNumStmt() = 0`` | Defines a condition on the variables. | ``ifstmt.getThen() = block`` relates the two variables. The block must be the ``then`` branch of the ``if`` statement. |
|
||||
| | | |
|
||||
| | | ``block.getNumStmt() = 0`` states that the block must be empty (that is, it contains no statements). |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``select ifstmt, "This 'if' statement is redundant."`` | Defines what to report for each match. | Reports the resulting ``if`` statement with a string that explains the problem. |
|
||||
| | | |
|
||||
| | ``select`` statements for queries that are used to find instances of poor coding practice are always in the form: | |
|
||||
| | ``select <program element>, "<alert message>"`` | |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
Extend the query
|
||||
----------------
|
||||
|
||||
Query writing is an inherently iterative process. You write a simple query and then, when you run it, you discover examples that you had not previously considered, or opportunities for improvement.
|
||||
|
||||
Remove false positive results
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Browsing the results of our basic query shows that it could be improved. Among the results you are likely to find examples of ``if`` statements with an ``else`` branch, where an empty ``then`` branch does serve a purpose. For example:
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
if (...) {
|
||||
...
|
||||
} else if ("-verbose".equals(option)) {
|
||||
// nothing to do - handled earlier
|
||||
} else {
|
||||
error("unrecognized option");
|
||||
}
|
||||
|
||||
In this case, identifying the ``if`` statement with the empty ``then`` branch as redundant is a false positive. One solution to this is to modify the query to ignore empty ``then`` branches if the ``if`` statement has an ``else`` branch.
|
||||
|
||||
To exclude ``if`` statements that have an ``else`` branch:
|
||||
|
||||
#. Extend the where clause to include the following extra condition:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
and not exists(ifstmt.getElse())
|
||||
|
||||
The ``where`` clause is now:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
where ifstmt.getThen() = block and
|
||||
block.getNumStmt() = 0 and
|
||||
not exists(ifstmt.getElse())
|
||||
|
||||
#. Click **Run**.
|
||||
|
||||
There are now fewer results because ``if`` statements with an ``else`` branch are no longer included.
|
||||
|
||||
➤ `See this in the query console <https://lgtm.com/query/6382189874776576029/>`__
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../../reusables/java-further-reading.rst
|
||||
.. include:: ../../reusables/codeql-ref-tools-further-reading.rst
|
||||
@@ -6,6 +6,7 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
basic-query-java
|
||||
introduce-libraries-java
|
||||
dataflow
|
||||
types-class-hierarchy
|
||||
@@ -16,7 +17,7 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat
|
||||
source-locations
|
||||
ast-class-reference
|
||||
|
||||
- `Basic Java query <https://lgtm.com/help/lgtm/console/ql-java-basic-example>`__: Learn to write and run a simple CodeQL query using LGTM.
|
||||
- :doc:`Basic query for Java code <basic-query-java>`: Learn to write and run a simple CodeQL query using LGTM.
|
||||
|
||||
- :doc:`CodeQL library for Java <introduce-libraries-java>`: When analyzing Java code, you can use the large collection of classes in the CodeQL library for Java.
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user