mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge master into next.
JavaScript semantic conflicts fixed by referring to the `LegacyLanguage` enum. C++ conflicts fixed by accepting Qltest output.
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
path_classifiers:
|
||||
library:
|
||||
- javascript/externs
|
||||
- javascript/extractor/lib
|
||||
|
||||
test:
|
||||
- csharp/ql/src
|
||||
- csharp/ql/test
|
||||
- javascript/extractor/parser-tests
|
||||
- javascript/extractor/tests
|
||||
- javascript/ql/src
|
||||
- javascript/ql/test
|
||||
|
||||
|
||||
@@ -28,3 +28,4 @@
|
||||
|
||||
* Added a hash consing library for structural comparison of expressions.
|
||||
* `getBufferSize` now detects variable size structs more reliably.
|
||||
* Buffer.qll now treats arrays of zero size as a special case.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## General improvements
|
||||
|
||||
* Control flow graph improvements:
|
||||
* The control flow graph construction now takes simple Boolean conditions on local scope variables into account. For example, in `if (b) x = 0; if (b) x = 1;`, the control flow graph will reflect that taking the `true` (resp. `false`) branch in the first condition implies taking the same branch in the second condition. In effect, the first assignment to `x` will now be identified as being dead.
|
||||
* The control flow graph construction now takes simple Boolean conditions on local scope variables into account. For example, in `if (b) x = 0; if (b) x = 1;`, the control flow graph will reflect that taking the `true` (resp. `false`) branch in the first condition implies taking the same branch in the second condition. In effect, the first assignment to `x` will now be identified as being dead.
|
||||
* Code that is only reachable from a constant failing assertion, such as `Debug.Assert(false)`, is considered to be unreachable.
|
||||
|
||||
## New queries
|
||||
@@ -21,3 +21,5 @@
|
||||
|
||||
|
||||
## Changes to QL libraries
|
||||
|
||||
* `getArgument()` on `AccessorCall` has been improved so it now takes tuple assignments into account. For example, the argument for the implicit `value` parameter in the setter of property `P` is `0` in `(P, x) = (0, 1)`. Additionally, the argument for the `value` parameter in compound assignments is now only the expanded value, for example, in `P += 7` the argument is `P + 7` and not `7`.
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
* Support for popular libraries has been improved. Consequently, queries may produce more results on code bases that use the following features:
|
||||
- file system access, for example through [fs-extra](https://github.com/jprichardson/node-fs-extra) or [globby](https://www.npmjs.com/package/globby)
|
||||
- outbound network access, for example through the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
|
||||
- the [Google Cloud Spanner](https://cloud.google.com/spanner), [lodash](https://lodash.com) and [underscore](https://underscorejs.org/) libraries
|
||||
- the [lodash](https://lodash.com), [underscore](https://underscorejs.org/), [async](https://www.npmjs.com/package/async) and [async-es](https://www.npmjs.com/package/async-es) libraries
|
||||
|
||||
* The type inference now handles nested imports (that is, imports not appearing at the toplevel). This may yield fewer false-positive results on projects that use this non-standard language feature.
|
||||
* Type inference for function calls has been improved. This may give additional results for queries that rely on type inference.
|
||||
|
||||
## New queries
|
||||
|
||||
@@ -37,9 +37,10 @@
|
||||
| Server-side URL redirect | More results | This rule now recognizes redirection calls in more cases. |
|
||||
| Unused variable, import, function or class | Fewer false-positive results | This rule now flags fewer variables that may be used by `eval` calls. |
|
||||
| Unused variable, import, function or class | Fewer results | This rule now flags import statements with multiple unused imports once. |
|
||||
| User-controlled bypass of security check | Fewer results | This rule no longer flags conditions that guard early returns. The precision of this rule has been revised to "medium". Results are no longer shown on LGTM by default. |
|
||||
| Whitespace contradicts operator precedence | Fewer false-positive results | This rule no longer flags operators with asymmetric whitespace. |
|
||||
| Unused import | Fewer false-positive results | This rule no longer flags imports used by the `transform-react-jsx` Babel plugin. |
|
||||
| Self assignment | Fewer false-positive results | This rule now ignores self-assignments preceded by a JSDoc comment with a `@type` tag. |
|
||||
| Client side cross-site scripting | More results | This rule now also flags HTML injection in the body of an email. |
|
||||
|
||||
## Changes to QL libraries
|
||||
|
||||
@@ -48,3 +49,5 @@
|
||||
* The `DataFlow::ThisNode` class now corresponds to the implicit receiver parameter of a function, as opposed to an indivdual `this` expression. This means `getALocalSource` now maps all `this` expressions within a given function to the same source. The data-flow node associated with a `ThisExpr` can no longer be cast to `DataFlow::SourceNode` or `DataFlow::ThisNode` - it is recomended to use `getALocalSource` before casting or instead of casting.
|
||||
|
||||
* `ReactComponent::getAThisAccess` has been renamed to `getAThisNode`. The old name is still usable but is deprecated. It no longer gets individual `this` expressions, but the `ThisNode` mentioned above.
|
||||
|
||||
* A `DataFlow::ParameterNode` instance now exists for all function parameters. Previously, unused parameters did not have a corresponding dataflow node.
|
||||
|
||||
26
change-notes/1.19/extractor-javascript.md
Normal file
26
change-notes/1.19/extractor-javascript.md
Normal file
@@ -0,0 +1,26 @@
|
||||
[[ condition: enterprise-only ]]
|
||||
|
||||
# Improvements to JavaScript analysis
|
||||
|
||||
> NOTES
|
||||
>
|
||||
> Please describe your changes in terms that are suitable for
|
||||
> customers to read. These notes will have only minor tidying up
|
||||
> before they are published as part of the release notes.
|
||||
>
|
||||
> This file is written for lgtm users and should contain *only*
|
||||
> notes about changes that affect lgtm enterprise users. Add
|
||||
> any other customer-facing changes to the `studio-java.md`
|
||||
> file.
|
||||
>
|
||||
|
||||
## General improvements
|
||||
|
||||
> Changes that affect alerts in many files or from many queries
|
||||
> For example, changes to file classification
|
||||
|
||||
## Changes to code extraction
|
||||
|
||||
* The TypeScript compiler is now bundled with the distribution, and no longer needs to be installed manually.
|
||||
Should the compiler version need to be overridden, set the `SEMMLE_TYPESCRIPT_HOME` environment variable to
|
||||
point to an installation of the `typescript` NPM package.
|
||||
@@ -4,5 +4,5 @@ void fillRect(int x, int y, int w, int h,
|
||||
int r2, int g2, int b2, int a2,
|
||||
gradient_type grad, unsigned int flags, bool border)
|
||||
{
|
||||
// ...
|
||||
// ...
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
int find(int start, char *str, char goal)
|
||||
{
|
||||
int len = strlen(str);
|
||||
//Potential buffer overflow
|
||||
//Potential buffer overflow
|
||||
for (int i = start; str[i] != 0 && i < len; i++) {
|
||||
if (str[i] == goal)
|
||||
return i;
|
||||
@@ -12,7 +12,7 @@ int find(int start, char *str, char goal)
|
||||
int findRangeCheck(int start, char *str, char goal)
|
||||
{
|
||||
int len = strlen(str);
|
||||
//Range check protects against buffer overflow
|
||||
//Range check protects against buffer overflow
|
||||
for (int i = start; i < len && str[i] != 0 ; i++) {
|
||||
if (str[i] == goal)
|
||||
return i;
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
void sanitize(Fields[] record) {
|
||||
//The number of fields here can be put in a const
|
||||
for (fieldCtr = 0; field < 7; field++) {
|
||||
sanitize(fields[fieldCtr]);
|
||||
}
|
||||
for (fieldCtr = 0; field < 7; field++) {
|
||||
sanitize(fields[fieldCtr]);
|
||||
}
|
||||
}
|
||||
|
||||
#define NUM_FIELDS 7
|
||||
|
||||
void process(Fields[] record) {
|
||||
//This avoids using a magic constant by using the macro instead
|
||||
for (fieldCtr = 0; field < NUM_FIELDS; field++) {
|
||||
process(fields[fieldCtr]);
|
||||
}
|
||||
//This avoids using a magic constant by using the macro instead
|
||||
for (fieldCtr = 0; field < NUM_FIELDS; field++) {
|
||||
process(fields[fieldCtr]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
//start of file
|
||||
static void f() { //static function f() is unused in the file
|
||||
//...
|
||||
//...
|
||||
}
|
||||
static void g() {
|
||||
//...
|
||||
//...
|
||||
}
|
||||
void public_func() { //non-static function public_func is not called in file,
|
||||
//but could be visible in other files
|
||||
//...
|
||||
g(); //call to g()
|
||||
//...
|
||||
//...
|
||||
g(); //call to g()
|
||||
//...
|
||||
}
|
||||
//end of file
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
typedef struct Names {
|
||||
char first[100];
|
||||
char last[100];
|
||||
char first[100];
|
||||
char last[100];
|
||||
} Names;
|
||||
|
||||
int doFoo(Names n) { //wrong: n is passed by value (meaning the entire structure
|
||||
//is copied onto the stack, instead of just a pointer)
|
||||
...
|
||||
...
|
||||
}
|
||||
|
||||
int doBar(Names &n) { //better, only a reference is passed
|
||||
...
|
||||
...
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
Record records[SIZE] = ...;
|
||||
|
||||
int f() {
|
||||
int recordIdx = 0;
|
||||
recordIdx = readUserInput(); //recordIdx is returned from a function
|
||||
int recordIdx = 0;
|
||||
recordIdx = readUserInput(); //recordIdx is returned from a function
|
||||
// there is no check so it could be negative
|
||||
doFoo(&(records[recordIdx])); //but is not checked before use as an array offset
|
||||
doFoo(&(records[recordIdx])); //but is not checked before use as an array offset
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
* @tags reliability
|
||||
* correctness
|
||||
* security
|
||||
* external/cwe/190
|
||||
* external/cwe/192
|
||||
* external/cwe/cwe-190
|
||||
* external/cwe/cwe-192
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
if (!flags & SOME_BIT) { //wrong: '!' has higher precedence than '&', so this
|
||||
// is bracketed as '(!flags) & SOME_BIT', and does not
|
||||
// check whether a particular bit is set.
|
||||
// ...
|
||||
// is bracketed as '(!flags) & SOME_BIT', and does not
|
||||
// check whether a particular bit is set.
|
||||
// ...
|
||||
}
|
||||
|
||||
if ((p != NULL) & p->f()) { //wrong: The use of '&' rather than '&&' will still
|
||||
// de-reference the pointer even if it is NULL.
|
||||
// ...
|
||||
// de-reference the pointer even if it is NULL.
|
||||
// ...
|
||||
}
|
||||
|
||||
int bits = (s > 8) & 0xff; //wrong: Invalid attempt to get the 8 most significant
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#define FLAGS 0x4004
|
||||
|
||||
void f_warning(int i)
|
||||
{
|
||||
// The usage of the logical not operator in this case is unlikely to be correct
|
||||
// as the output is being used as an operator for a bit-wise and operation
|
||||
if (i & !FLAGS)
|
||||
{
|
||||
// code
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void f_fixed(int i)
|
||||
{
|
||||
if (i & ~FLAGS) // Changing the logical not operator for the bit-wise not operator would fix this logic
|
||||
{
|
||||
// code
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>This rule finds logical-not operator usage as an operator for in a bit-wise operation.</p>
|
||||
|
||||
<p>Due to the nature of logical operation result value, only the lowest bit could possibly be set, and it is unlikely to be intent in bitwise opeartions. Violations are often indicative of a typo, using a logical-not (<code>!</code>) opeartor instead of the bit-wise not (<code>~</code>) operator. </p>
|
||||
<p>This rule is restricted to analyze bit-wise and (<code>&</code>) and bit-wise or (<code>|</code>) operation in order to provide better precision.</p>
|
||||
<p>This rule ignores instances where a double negation (<code>!!</code>) is explicitly used as the opeartor of the bitwise operation, as this is a commonly used as a mechanism to normalize an integer value to either 1 or 0.</p>
|
||||
<p>NOTE: It is not recommended to use this rule in kernel code or older C code as it will likely find several false positive instances.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>Carefully inspect the flagged expressions. Consider the intent in the code logic, and decide whether it is necessary to change the not operator.</p>
|
||||
</recommendation>
|
||||
|
||||
<example><sample src="IncorrectNotOperatorUsage.cpp" /></example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
<a href="https://docs.microsoft.com/en-us/visualstudio/code-quality/c6317?view=vs-2017">warning C6317: incorrect operator: logical-not (!) is not interchangeable with ones-complement (~)</a>
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @name Incorrect Not Operator Usage
|
||||
* @description Usage of a logical-not (!) operator as an operand for a bit-wise operation.
|
||||
* This commonly indicates the usage of an incorrect operator instead of the bit-wise not (~) operator,
|
||||
* also known as ones' complement operator.
|
||||
* @kind problem
|
||||
* @id cpp/incorrect-not-operator-usage
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @tags security
|
||||
* external/cwe/cwe-480
|
||||
* external/microsoft/c6317
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* It's common in some projects to use "a double negation" to normalize the boolean
|
||||
* result to either 1 or 0.
|
||||
* This predciate is intended to filter explicit usage of a double negation as it typically
|
||||
* indicates the explicit purpose to normalize the result for bit-wise or arithmetic purposes.
|
||||
*/
|
||||
predicate doubleNegationNormalization( NotExpr notexpr ){
|
||||
notexpr.getAnOperand() instanceof NotExpr
|
||||
}
|
||||
|
||||
from BinaryBitwiseOperation binbitwop
|
||||
where exists( NotExpr notexpr |
|
||||
binbitwop.getAnOperand() = notexpr
|
||||
and not doubleNegationNormalization(notexpr)
|
||||
and ( binbitwop instanceof BitwiseAndExpr
|
||||
or binbitwop instanceof BitwiseOrExpr )
|
||||
)
|
||||
select binbitwop, "Usage of a logical not (!) expression as a bitwise operator."
|
||||
|
||||
@@ -14,53 +14,56 @@ import cpp
|
||||
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||
import semmle.code.cpp.dataflow.DataFlow
|
||||
|
||||
predicate illDefinedDecrForStmt( ForStmt forstmt, Variable v, Expr initialCondition, Expr terminalCondition ) {
|
||||
v.getAnAssignedValue() = initialCondition
|
||||
and
|
||||
exists(
|
||||
RelationalOperation rel |
|
||||
rel = forstmt.getCondition() |
|
||||
terminalCondition = rel.getGreaterOperand()
|
||||
and v.getAnAccess() = rel.getLesserOperand()
|
||||
and
|
||||
DataFlow::localFlowStep(DataFlow::exprNode(initialCondition), DataFlow::exprNode(rel.getLesserOperand()))
|
||||
/**
|
||||
* A `for` statement whose update is a crement operation on a variable.
|
||||
*/
|
||||
predicate candidateForStmt(ForStmt forStmt, Variable v, CrementOperation update, RelationalOperation rel) {
|
||||
update = forStmt.getUpdate() and
|
||||
update.getAnOperand() = v.getAnAccess() and
|
||||
rel = forStmt.getCondition()
|
||||
}
|
||||
|
||||
predicate illDefinedDecrForStmt( ForStmt forstmt, Variable v, Expr initialCondition, Expr terminalCondition ) {
|
||||
exists(DecrementOperation dec, RelationalOperation rel |
|
||||
// decrementing for loop
|
||||
candidateForStmt(forstmt, v, dec, rel) and
|
||||
|
||||
// condition is `v < terminalCondition`
|
||||
terminalCondition = rel.getGreaterOperand() and
|
||||
v.getAnAccess() = rel.getLesserOperand() and
|
||||
|
||||
// `initialCondition` is a value of `v` in the for loop
|
||||
v.getAnAssignedValue() = initialCondition and
|
||||
DataFlow::localFlowStep(DataFlow::exprNode(initialCondition), DataFlow::exprNode(rel.getLesserOperand())) and
|
||||
|
||||
// `initialCondition` < `terminalCondition`
|
||||
(
|
||||
( upperBound(initialCondition) < lowerBound(terminalCondition) )
|
||||
or
|
||||
( forstmt.conditionAlwaysFalse() or forstmt.conditionAlwaysTrue() )
|
||||
)
|
||||
and
|
||||
exists(
|
||||
DecrementOperation dec |
|
||||
dec = forstmt.getUpdate().(DecrementOperation)
|
||||
and dec.getAnOperand() = v.getAnAccess()
|
||||
)
|
||||
and
|
||||
(
|
||||
( upperBound(initialCondition) < lowerBound(terminalCondition) )
|
||||
or
|
||||
( forstmt.conditionAlwaysFalse() or forstmt.conditionAlwaysTrue() )
|
||||
)
|
||||
}
|
||||
|
||||
predicate illDefinedIncrForStmt( ForStmt forstmt, Variable v, Expr initialCondition, Expr terminalCondition ) {
|
||||
v.getAnAssignedValue() = initialCondition
|
||||
and
|
||||
exists(
|
||||
RelationalOperation rel |
|
||||
rel = forstmt.getCondition() |
|
||||
terminalCondition = rel.getLesserOperand()
|
||||
and v.getAnAccess() = rel.getGreaterOperand()
|
||||
and
|
||||
DataFlow::localFlowStep(DataFlow::exprNode(initialCondition), DataFlow::exprNode(rel.getGreaterOperand()))
|
||||
)
|
||||
and
|
||||
exists( IncrementOperation incr |
|
||||
incr = forstmt.getUpdate().(IncrementOperation)
|
||||
and
|
||||
incr.getAnOperand() = v.getAnAccess()
|
||||
)
|
||||
and
|
||||
(
|
||||
( upperBound(terminalCondition) < lowerBound(initialCondition))
|
||||
or
|
||||
( forstmt.conditionAlwaysFalse() or forstmt.conditionAlwaysTrue())
|
||||
predicate illDefinedIncrForStmt( ForStmt forstmt, Variable v, Expr initialCondition, Expr terminalCondition ) {
|
||||
exists(IncrementOperation inc, RelationalOperation rel |
|
||||
// incrementing for loop
|
||||
candidateForStmt(forstmt, v, inc, rel) and
|
||||
|
||||
// condition is `v > terminalCondition`
|
||||
terminalCondition = rel.getLesserOperand() and
|
||||
v.getAnAccess() = rel.getGreaterOperand() and
|
||||
|
||||
// `initialCondition` is a value of `v` in the for loop
|
||||
v.getAnAssignedValue() = initialCondition and
|
||||
DataFlow::localFlowStep(DataFlow::exprNode(initialCondition), DataFlow::exprNode(rel.getGreaterOperand())) and
|
||||
|
||||
// `terminalCondition` < `initialCondition`
|
||||
(
|
||||
( upperBound(terminalCondition) < lowerBound(initialCondition) )
|
||||
or
|
||||
( forstmt.conditionAlwaysFalse() or forstmt.conditionAlwaysTrue() )
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -104,9 +104,13 @@ where
|
||||
// Some of the functions operate on a larger char type, like `wchar_t`, so we
|
||||
// need to take this into account in the fixed size case.
|
||||
charSize = f.getParameter(argDest).getType().getUnspecifiedType().(PointerType).getBaseType().getSize() and
|
||||
if exists (fc.getArgument(argLimit).getValue().toInt()) then (
|
||||
if exists(fc.getArgument(argLimit).getValue().toInt()) then (
|
||||
// Fixed sized case
|
||||
arrayExprFixedSize(copyDest) < charSize * fc.getArgument(argLimit).getValue().toInt()
|
||||
exists(int size |
|
||||
size = arrayExprFixedSize(copyDest) and
|
||||
size < charSize * fc.getArgument(argLimit).getValue().toInt() and
|
||||
size != 0 // if the array has zero size, something special is going on
|
||||
)
|
||||
) else exists (Access takenSizeOf, BufferSizeExpr sizeExpr, int plus |
|
||||
// Variable sized case
|
||||
sizeExpr = fc.getArgument(argLimit).getAChild*() and
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
int x1 = 0;
|
||||
for (x1 = 0; x1 < 100; x1++) {
|
||||
int x2 = 0;
|
||||
for (x1 = 0; x1 < 300; x1++) {
|
||||
int x2 = 0;
|
||||
for (x1 = 0; x1 < 300; x1++) {
|
||||
// this is most likely a typo
|
||||
// the outer loop will exit immediately
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (x1 = 0; x1 < 100; x1++) {
|
||||
if(x1 == 10 && condition) {
|
||||
for (; x1 < 75; x1++) {
|
||||
for (; x1 < 75; x1++) {
|
||||
// this should be written as a while loop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
class Base {
|
||||
public:
|
||||
Resource *p;
|
||||
Base() {
|
||||
p = createResource();
|
||||
}
|
||||
//...
|
||||
~Base() {
|
||||
//wrong: this destructor is non-virtual, but Base has a derived class
|
||||
// with a non-virtual destructor
|
||||
freeResource(p);
|
||||
}
|
||||
Resource *p;
|
||||
Base() {
|
||||
p = createResource();
|
||||
}
|
||||
//...
|
||||
~Base() {
|
||||
//wrong: this destructor is non-virtual, but Base has a derived class
|
||||
//with a non-virtual destructor
|
||||
freeResource(p);
|
||||
}
|
||||
};
|
||||
|
||||
class Derived: public Base {
|
||||
public:
|
||||
Resource *dp;
|
||||
Derived() {
|
||||
dp = createResource2();
|
||||
}
|
||||
~Derived() {
|
||||
freeResource2(dp);
|
||||
}
|
||||
Resource *dp;
|
||||
Derived() {
|
||||
dp = createResource2();
|
||||
}
|
||||
~Derived() {
|
||||
freeResource2(dp);
|
||||
}
|
||||
};
|
||||
|
||||
int f() {
|
||||
Base *b = new Derived(); //creates resources for both Base::p and Derived::dp
|
||||
//...
|
||||
delete b; //will only call Base::~Base(), leaking the resource dp.
|
||||
Base *b = new Derived(); //creates resources for both Base::p and Derived::dp
|
||||
//...
|
||||
delete b; //will only call Base::~Base(), leaking the resource dp.
|
||||
// Change both destructors to virtual to ensure they are both called.
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
class Base {
|
||||
public:
|
||||
Resource *p;
|
||||
Base() {
|
||||
p = createResource();
|
||||
}
|
||||
virtual void f() { //has virtual function
|
||||
//...
|
||||
}
|
||||
//...
|
||||
~Base() { //wrong: is non-virtual
|
||||
freeResource(p);
|
||||
}
|
||||
};
|
||||
|
||||
class Derived: public Base {
|
||||
public:
|
||||
Resource *dp;
|
||||
Derived() {
|
||||
dp = createResource2();
|
||||
}
|
||||
~Derived() {
|
||||
freeResource2(dp);
|
||||
}
|
||||
};
|
||||
|
||||
int f() {
|
||||
Base *b = new Derived(); //creates resources for both Base::p and Derived::dp
|
||||
//...
|
||||
|
||||
//will only call Base::~Base(), leaking the resource dp.
|
||||
//Change both destructors to virtual to ensure they are both called.
|
||||
delete b;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
This rule finds classes with virtual functions but no virtual destructor. Deleting a class without a virtual destructor will
|
||||
only call the destructor of the type of the pointer being deleted. This can cause a defect if the pointer type is a base
|
||||
type while the object instance is a derived type.
|
||||
</p>
|
||||
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>
|
||||
Make sure that all classes with virtual functions also have a virtual destructor, especially if other classes derive from them.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
<example><sample src="NonVirtualDestructorInBaseClass.cpp" />
|
||||
|
||||
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
S. Meyers. <em>Effective C++ 3d ed.</em> pp 40-44. Addison-Wesley Professional, 2005.
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspx">When should your destructor be virtual?</a>
|
||||
</li>
|
||||
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
27
cpp/ql/src/Likely Bugs/OO/NonVirtualDestructorInBaseClass.ql
Normal file
27
cpp/ql/src/Likely Bugs/OO/NonVirtualDestructorInBaseClass.ql
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* @name Non-virtual destructor in base class
|
||||
* @description All base classes with a virtual function should define a virtual destructor. If an application attempts to delete a derived class object through a base class pointer, the result is undefined if the base class destructor is non-virtual.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision high
|
||||
* @id cpp/virtual-destructor
|
||||
* @tags reliability
|
||||
* readability
|
||||
* language-features
|
||||
*/
|
||||
import cpp
|
||||
|
||||
// find classes with virtual functions that have a destructor that is not virtual and for which there exists a derived class
|
||||
// when calling the destructor of a derived class the destructor in the base class may not be called
|
||||
|
||||
from Class c
|
||||
where exists(VirtualFunction f | f.getDeclaringType() = c)
|
||||
and exists(Destructor d | d.getDeclaringType() = c and
|
||||
// Ignore non-public destructors, which prevent an object of the declaring class from being deleted
|
||||
// directly (except from within the class itself). This is a common pattern in real-world code.
|
||||
d.hasSpecifier("public") and
|
||||
not d.isVirtual() and
|
||||
not d.isDeleted() and
|
||||
not d.isCompilerGenerated())
|
||||
and exists(ClassDerivation d | d.getBaseClass() = c)
|
||||
select c, "A base class with a virtual function should define a virtual destructor."
|
||||
@@ -1,35 +1,35 @@
|
||||
class Base {
|
||||
protected:
|
||||
Resource* resource;
|
||||
Resource* resource;
|
||||
public:
|
||||
virtual void init() {
|
||||
resource = createResource();
|
||||
}
|
||||
virtual void release() {
|
||||
freeResource(resource);
|
||||
}
|
||||
virtual void init() {
|
||||
resource = createResource();
|
||||
}
|
||||
virtual void release() {
|
||||
freeResource(resource);
|
||||
}
|
||||
};
|
||||
|
||||
class Derived: public Base {
|
||||
virtual void init() {
|
||||
resource = createResourceV2();
|
||||
}
|
||||
virtual void release() {
|
||||
freeResourceV2(resource);
|
||||
}
|
||||
virtual void init() {
|
||||
resource = createResourceV2();
|
||||
}
|
||||
virtual void release() {
|
||||
freeResourceV2(resource);
|
||||
}
|
||||
};
|
||||
|
||||
Base::Base() {
|
||||
this->init();
|
||||
this->init();
|
||||
}
|
||||
Base::~Base() {
|
||||
this->release();
|
||||
this->release();
|
||||
}
|
||||
|
||||
int f() {
|
||||
// this will call Base::Base() and then Derived::Derived(), but this->init()
|
||||
// inBase::Base() will resolve to Base::init(), not Derived::init()
|
||||
// The reason for this is that when Base::Base is called, the object being
|
||||
// created is still of type Base (including the vtable)
|
||||
Derived* d = new Derived();
|
||||
// this will call Base::Base() and then Derived::Derived(), but this->init()
|
||||
// inBase::Base() will resolve to Base::init(), not Derived::init()
|
||||
// The reason for this is that when Base::Base is called, the object being
|
||||
// created is still of type Base (including the vtable)
|
||||
Derived* d = new Derived();
|
||||
}
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
class Base {
|
||||
protected:
|
||||
Resource* resource;
|
||||
Resource* resource;
|
||||
public:
|
||||
virtual void init() {
|
||||
resource = createResource();
|
||||
}
|
||||
virtual void release() {
|
||||
freeResource(resource);
|
||||
}
|
||||
virtual void init() {
|
||||
resource = createResource();
|
||||
}
|
||||
virtual void release() {
|
||||
freeResource(resource);
|
||||
}
|
||||
};
|
||||
|
||||
class Derived: public Base {
|
||||
virtual void init() {
|
||||
resource = createResourceV2();
|
||||
}
|
||||
virtual void release() {
|
||||
freeResourceV2(resource);
|
||||
}
|
||||
virtual void init() {
|
||||
resource = createResourceV2();
|
||||
}
|
||||
virtual void release() {
|
||||
freeResourceV2(resource);
|
||||
}
|
||||
};
|
||||
|
||||
Base::Base() {
|
||||
this->init();
|
||||
this->init();
|
||||
}
|
||||
Base::~Base() {
|
||||
this->release();
|
||||
this->release();
|
||||
}
|
||||
|
||||
int f() {
|
||||
// this will call Base::Base() and then Derived::Derived(), but this->init()
|
||||
// inBase::Base() will resolve to Base::init(), not Derived::init()
|
||||
// The reason for this is that when Base::Base is called, the object being
|
||||
// created is still of type Base (including the vtable)
|
||||
Derived* d = new Derived();
|
||||
// this will call Base::Base() and then Derived::Derived(), but this->init()
|
||||
// inBase::Base() will resolve to Base::init(), not Derived::init()
|
||||
// The reason for this is that when Base::Base is called, the object being
|
||||
// created is still of type Base (including the vtable)
|
||||
Derived* d = new Derived();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
struct X {
|
||||
//This struct will have a compiler-generated copy constructor
|
||||
//This struct will have a compiler-generated copy constructor
|
||||
X(const X&, int);
|
||||
...
|
||||
};
|
||||
@@ -7,7 +7,7 @@ struct X {
|
||||
//However, if this is declared later, it will override the compiler-generated
|
||||
//constructor
|
||||
X::X(const X& x, int i =0) {
|
||||
this-> i = i; //uses the i parameter, instead of x.i
|
||||
this-> i = i; //uses the i parameter, instead of x.i
|
||||
}
|
||||
|
||||
C c(1);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision high
|
||||
* @id cpp/virtual-destructor
|
||||
* @id cpp/jsf/av-rule-78
|
||||
* @tags reliability
|
||||
* readability
|
||||
* language-features
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
// cannot close the file
|
||||
class ResourceLeak {
|
||||
private:
|
||||
int sockfd;
|
||||
FILE* file;
|
||||
int sockfd;
|
||||
FILE* file;
|
||||
public:
|
||||
C() {
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
}
|
||||
C() {
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
}
|
||||
|
||||
void f() {
|
||||
file = fopen("foo.txt", "r");
|
||||
...
|
||||
}
|
||||
void f() {
|
||||
file = fopen("foo.txt", "r");
|
||||
...
|
||||
}
|
||||
};
|
||||
|
||||
// This class relies on its client to release any stream it
|
||||
|
||||
@@ -83,6 +83,7 @@ predicate assignOperatorWithWrongType(Operator op, string msg) {
|
||||
predicate assignOperatorWithWrongResult(Operator op, string msg) {
|
||||
op.hasName("operator=")
|
||||
and not returnsDereferenceThis(op)
|
||||
and exists(op.getBlock())
|
||||
and not op.getType() instanceof VoidType
|
||||
and not assignOperatorWithWrongType(op, _)
|
||||
and msg = "Assignment operator in class " + op.getDeclaringType().getName() + " does not return a reference to *this."
|
||||
|
||||
@@ -6,13 +6,13 @@ class C : protected Superclass,
|
||||
public InterfaceA, public InterfaceB,
|
||||
private ImplementationA, private ImplementationB
|
||||
{
|
||||
//implementation
|
||||
//implementation
|
||||
};
|
||||
|
||||
//wrong: multiple protected bases
|
||||
class D : protected Superclass1, protected Superclass2,
|
||||
public Interface, private Implementation
|
||||
{
|
||||
//implementation
|
||||
//implementation
|
||||
};
|
||||
|
||||
|
||||
@@ -18,13 +18,17 @@ import cpp
|
||||
programmer, we can flag it anyway, since this is arguably a bug.) */
|
||||
|
||||
predicate functionsMissingReturnStmt(Function f, ControlFlowNode blame) {
|
||||
f.fromSource() and
|
||||
exists(Type returnType |
|
||||
returnType = f.getType().getUnderlyingType().getUnspecifiedType() and
|
||||
not returnType instanceof VoidType and
|
||||
not returnType instanceof TemplateParameter
|
||||
) and
|
||||
exists(ReturnStmt s | f.getAPredecessor() = s | blame = s.getAPredecessor())}
|
||||
f.fromSource() and
|
||||
exists(Type returnType |
|
||||
returnType = f.getType().getUnderlyingType().getUnspecifiedType() and
|
||||
not returnType instanceof VoidType and
|
||||
not returnType instanceof TemplateParameter
|
||||
) and
|
||||
exists(ReturnStmt s |
|
||||
f.getAPredecessor() = s and
|
||||
blame = s.getAPredecessor()
|
||||
)
|
||||
}
|
||||
|
||||
/* If a function has a value-carrying return statement, but the extractor hit a snag
|
||||
whilst parsing the value, then the control flow graph will not include the value.
|
||||
|
||||
@@ -542,5 +542,5 @@ query predicate edges(PrintASTNode source, PrintASTNode target, string key, stri
|
||||
}
|
||||
|
||||
query predicate graphProperties(string key, string value) {
|
||||
key = "semmle.graphKind" and value = "tree"
|
||||
key = "semmle.graphKind" and value = "tree"
|
||||
}
|
||||
|
||||
@@ -57,7 +57,9 @@ int getBufferSize(Expr bufferExpr, Element why) {
|
||||
// buffer is a fixed size array
|
||||
result = bufferVar.getType().getUnspecifiedType().(ArrayType).getSize() and
|
||||
why = bufferVar and
|
||||
not memberMayBeVarSize(_, bufferVar)
|
||||
not memberMayBeVarSize(_, bufferVar) and
|
||||
not result = 0 // zero sized arrays are likely to have special usage, for example
|
||||
// behaving a bit like a 'union' overlapping other fields.
|
||||
) or (
|
||||
// buffer is an initialized array
|
||||
// e.g. int buffer[] = {1, 2, 3};
|
||||
|
||||
@@ -240,13 +240,18 @@ class BasicBlock extends ControlFlowNodeBase {
|
||||
|
||||
/**
|
||||
* Holds if control flow may reach this basic block from a function entry
|
||||
* point or a `catch` clause of a reachable `try` statement.
|
||||
* point or any handler of a reachable `try` statement.
|
||||
*/
|
||||
predicate isReachable() {
|
||||
exists(Function f | f.getBlock() = this)
|
||||
or
|
||||
exists(TryStmt t, BasicBlock tryblock | this = t.getACatchClause() and tryblock.isReachable() and tryblock.contains(t))
|
||||
or
|
||||
exists(TryStmt t, BasicBlock tryblock |
|
||||
// a `Handler` preceeds the `CatchBlock`, and is always the beginning
|
||||
// of a new `BasicBlock` (see `primitive_basic_block_entry_node`).
|
||||
this.(Handler).getTryStmt() = t and
|
||||
tryblock.isReachable() and
|
||||
tryblock.contains(t)
|
||||
) or
|
||||
exists(BasicBlock pred | pred.getASuccessor() = this and pred.isReachable())
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ private cached module Cached {
|
||||
or
|
||||
reachable(n.getAPredecessor())
|
||||
or
|
||||
n instanceof CatchBlock
|
||||
n instanceof Handler
|
||||
}
|
||||
|
||||
/** Holds if `condition` always evaluates to a nonzero value. */
|
||||
|
||||
@@ -136,6 +136,28 @@ private predicate impossibleDefaultSwitchEdge(Block switchBlock, DefaultCase dc)
|
||||
val <= switchCaseRangeEnd(sc))))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the function `f` never returns due to not containing a return
|
||||
* statement (explicit or compiler generated). This can be thought of as
|
||||
* a lightweight `potentiallyReturningFunction`- reachability of return
|
||||
* statements is not checked.
|
||||
*/
|
||||
private predicate nonReturningFunction(Function f)
|
||||
{
|
||||
exists(f.getBlock()) and
|
||||
not exists(ReturnStmt ret | ret.getEnclosingFunction() = f) and
|
||||
not getOptions().exits(f)
|
||||
}
|
||||
|
||||
/**
|
||||
* An edge from a call to a function that never returns is impossible.
|
||||
*/
|
||||
private predicate impossibleFunctionReturn(FunctionCall fc, Node succ) {
|
||||
nonReturningFunction(fc.getTarget()) and
|
||||
not fc.isVirtual() and
|
||||
successors_extended(fc, succ)
|
||||
}
|
||||
|
||||
/**
|
||||
* If `pred` is a function call with (at least) one function target,
|
||||
* (at least) one such target must be potentially returning.
|
||||
@@ -158,6 +180,7 @@ cached predicate successors_adapted(Node pred, Node succ) {
|
||||
and not impossibleTrueEdge(pred, succ)
|
||||
and not impossibleSwitchEdge(pred, succ)
|
||||
and not impossibleDefaultSwitchEdge(pred, succ)
|
||||
and not impossibleFunctionReturn(pred, succ)
|
||||
and not getOptions().exprExits(pred)
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,14 @@ private cached module Cached {
|
||||
// that the node have at least one successor.
|
||||
or
|
||||
(not successors_extended(_, node) and successors_extended(node, _))
|
||||
|
||||
// An exception handler is always the start of a new basic block. We
|
||||
// don't generate edges for [possible] exceptions, but in practice control
|
||||
// flow could reach the handler from anywhere inside the try block that
|
||||
// could throw an exception of a corresponding type. A `Handler` usually
|
||||
// needs to be considered reachable (see also `BasicBlock.isReachable`).
|
||||
or
|
||||
node instanceof Handler
|
||||
}
|
||||
|
||||
/** Holds if `n2` follows `n1` in a `PrimitiveBasicBlock`. */
|
||||
|
||||
@@ -221,9 +221,7 @@ module FlowVar_internal {
|
||||
BlockVar() { this = TBlockVar(sbb, v) }
|
||||
|
||||
override VariableAccess getAnAccess() {
|
||||
result.getTarget() = v and
|
||||
result = getAReachedBlockVarSBB(this).getANode() and
|
||||
not overwrite(result, _)
|
||||
variableAccessInSBB(v, getAReachedBlockVarSBB(this), result)
|
||||
}
|
||||
|
||||
override predicate definedByInitialValue(LocalScopeVariable lsv) {
|
||||
@@ -373,6 +371,15 @@ module FlowVar_internal {
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `va` is a read access to `v` in `sbb`, where `v` is modeled by `BlockVar`. */
|
||||
pragma[noinline]
|
||||
private predicate variableAccessInSBB(Variable v, SubBasicBlock sbb, VariableAccess va) {
|
||||
exists(TBlockVar(_, v)) and
|
||||
va.getTarget() = v and
|
||||
va = sbb.getANode() and
|
||||
not overwrite(va, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* A local variable that is uninitialized immediately after its declaration.
|
||||
*/
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
| ODASA-5692.cpp:11:18:13:3 | { ... } |
|
||||
| ODASA-5692.cpp:14:15:16:3 | { ... } |
|
||||
| ODASA-5692.cpp:14:15:16:3 | { ... } |
|
||||
| exceptions.cpp:44:19:46:5 | { ... } |
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
| exceptions.cpp:28:20:28:20 | e | exceptions.cpp:28:23:30:9 | { ... } |
|
||||
| exceptions.cpp:32:16:32:16 | e | exceptions.cpp:32:19:34:5 | { ... } |
|
||||
| exceptions.cpp:35:16:35:16 | e | exceptions.cpp:35:19:37:5 | { ... } |
|
||||
| exceptions.cpp:42:18:42:18 | e | exceptions.cpp:42:21:44:5 | { ... } |
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
void f1(void) throw (int);
|
||||
void f2(void) throw ();
|
||||
void f3(void);
|
||||
void f4(void) {
|
||||
return;
|
||||
}
|
||||
void f5(void) {
|
||||
throw 3;
|
||||
}
|
||||
void f4(void) { return; }
|
||||
void f5(void) { throw 3; }
|
||||
void g(void);
|
||||
void h(void);
|
||||
void i(void);
|
||||
void j(void);
|
||||
void k(void);
|
||||
void l(void);
|
||||
void m(void);
|
||||
void n(void);
|
||||
|
||||
|
||||
void fun(void) {
|
||||
try {
|
||||
@@ -36,5 +36,15 @@ void fun(void) {
|
||||
j();
|
||||
}
|
||||
k();
|
||||
|
||||
try {
|
||||
throw 7;
|
||||
} catch (int e) {
|
||||
l();
|
||||
} catch (...) {
|
||||
m();
|
||||
}
|
||||
n();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,351 +1,384 @@
|
||||
| C::C | false | 435 | 435 | C |
|
||||
| C::C | false | 624 | 624 | C |
|
||||
| C::operator= | false | 617 | 617 | operator= |
|
||||
| C::~C | false | 556 | 556 | ~C |
|
||||
| Error::Error | false | 242 | 242 | Error |
|
||||
| Error::Error | false | 255 | 255 | Error |
|
||||
| Error::Error | false | 260 | 260 | return ... |
|
||||
| Error::Error | false | 262 | 262 | { ... } |
|
||||
| Error::Error | true | 260 | 255 | |
|
||||
| Error::Error | true | 262 | 260 | |
|
||||
| Error::operator= | false | 236 | 236 | operator= |
|
||||
| Error::~Error | false | 246 | 246 | ~Error |
|
||||
| Error::~Error | false | 251 | 251 | return ... |
|
||||
| Error::~Error | false | 253 | 253 | { ... } |
|
||||
| Error::~Error | true | 251 | 246 | |
|
||||
| Error::~Error | true | 253 | 251 | |
|
||||
| C::C | false | 493 | 493 | C |
|
||||
| C::C | false | 682 | 682 | C |
|
||||
| C::operator= | false | 675 | 675 | operator= |
|
||||
| C::~C | false | 614 | 614 | ~C |
|
||||
| Error::Error | false | 259 | 259 | Error |
|
||||
| Error::Error | false | 272 | 272 | Error |
|
||||
| Error::Error | false | 277 | 277 | return ... |
|
||||
| Error::Error | false | 279 | 279 | { ... } |
|
||||
| Error::Error | true | 277 | 272 | |
|
||||
| Error::Error | true | 279 | 277 | |
|
||||
| Error::operator= | false | 253 | 253 | operator= |
|
||||
| Error::~Error | false | 263 | 263 | ~Error |
|
||||
| Error::~Error | false | 268 | 268 | return ... |
|
||||
| Error::~Error | false | 270 | 270 | { ... } |
|
||||
| Error::~Error | true | 268 | 263 | |
|
||||
| Error::~Error | true | 270 | 268 | |
|
||||
| __va_list_tag::operator= | false | 140 | 140 | operator= |
|
||||
| __va_list_tag::operator= | false | 147 | 147 | operator= |
|
||||
| f | false | 419 | 419 | f |
|
||||
| f | false | 430 | 430 | declaration |
|
||||
| f | false | 433 | 433 | call to C |
|
||||
| f | false | 438 | 438 | 102 |
|
||||
| f | false | 439 | 439 | initializer for c102 |
|
||||
| f | false | 443 | 443 | call to C |
|
||||
| f | false | 447 | 447 | 103 |
|
||||
| f | false | 448 | 448 | initializer for c103 |
|
||||
| f | false | 451 | 451 | declaration |
|
||||
| f | false | 453 | 453 | b1 |
|
||||
| f | false | 455 | 455 | (bool)... |
|
||||
| f | false | 458 | 458 | 1 |
|
||||
| f | false | 459 | 459 | throw ... |
|
||||
| f | false | 461 | 461 | ExprStmt |
|
||||
| f | false | 463 | 463 | { ... } |
|
||||
| f | false | 465 | 465 | if (...) ... |
|
||||
| f | false | 467 | 467 | declaration |
|
||||
| f | false | 469 | 469 | { ... } |
|
||||
| f | false | 476 | 476 | 1 |
|
||||
| f | false | 478 | 478 | call to C |
|
||||
| f | false | 482 | 482 | 104 |
|
||||
| f | false | 483 | 483 | initializer for c104 |
|
||||
| f | false | 486 | 486 | declaration |
|
||||
| f | false | 488 | 488 | { ... } |
|
||||
| f | false | 490 | 490 | __try { ... } __except( ... ) { ... } |
|
||||
| f | false | 492 | 492 | declaration |
|
||||
| f | false | 495 | 495 | call to C |
|
||||
| f | false | 499 | 499 | 106 |
|
||||
| f | false | 500 | 500 | initializer for c106 |
|
||||
| f | false | 504 | 504 | call to C |
|
||||
| f | false | 508 | 508 | 107 |
|
||||
| f | false | 509 | 509 | initializer for c107 |
|
||||
| f | false | 512 | 512 | declaration |
|
||||
| f | false | 514 | 514 | b2 |
|
||||
| f | false | 516 | 516 | (bool)... |
|
||||
| f | false | 519 | 519 | 2 |
|
||||
| f | false | 520 | 520 | throw ... |
|
||||
| f | false | 522 | 522 | ExprStmt |
|
||||
| f | false | 524 | 524 | { ... } |
|
||||
| f | false | 526 | 526 | if (...) ... |
|
||||
| f | false | 528 | 528 | declaration |
|
||||
| f | false | 530 | 530 | { ... } |
|
||||
| f | false | 533 | 533 | call to C |
|
||||
| f | false | 537 | 537 | 108 |
|
||||
| f | false | 538 | 538 | initializer for c108 |
|
||||
| f | false | 541 | 541 | declaration |
|
||||
| f | false | 543 | 543 | { ... } |
|
||||
| f | false | 545 | 545 | __try { ... } __finally { ... } |
|
||||
| f | false | 547 | 547 | declaration |
|
||||
| f | false | 549 | 549 | return ... |
|
||||
| f | false | 551 | 551 | { ... } |
|
||||
| f | false | 553 | 553 | c101 |
|
||||
| f | false | 555 | 555 | call to c101.~C |
|
||||
| f | false | 557 | 557 | c105 |
|
||||
| f | false | 558 | 558 | call to c105.~C |
|
||||
| f | false | 559 | 559 | c109 |
|
||||
| f | false | 560 | 560 | call to c109.~C |
|
||||
| f | false | 561 | 561 | c101 |
|
||||
| f | false | 562 | 562 | call to c101.~C |
|
||||
| f | false | 563 | 563 | c105 |
|
||||
| f | false | 564 | 564 | call to c105.~C |
|
||||
| f | false | 565 | 565 | c108 |
|
||||
| f | false | 567 | 567 | call to c108.~C |
|
||||
| f | false | 568 | 568 | c106 |
|
||||
| f | false | 570 | 570 | call to c106.~C |
|
||||
| f | false | 571 | 571 | c107 |
|
||||
| f | false | 572 | 572 | call to c107.~C |
|
||||
| f | false | 573 | 573 | c106 |
|
||||
| f | false | 574 | 574 | call to c106.~C |
|
||||
| f | false | 575 | 575 | c104 |
|
||||
| f | false | 577 | 577 | call to c104.~C |
|
||||
| f | false | 578 | 578 | c102 |
|
||||
| f | false | 580 | 580 | call to c102.~C |
|
||||
| f | false | 581 | 581 | c103 |
|
||||
| f | false | 582 | 582 | call to c103.~C |
|
||||
| f | false | 583 | 583 | c102 |
|
||||
| f | false | 584 | 584 | call to c102.~C |
|
||||
| f | false | 586 | 586 | call to C |
|
||||
| f | false | 590 | 590 | 101 |
|
||||
| f | false | 591 | 591 | initializer for c101 |
|
||||
| f | false | 595 | 595 | call to C |
|
||||
| f | false | 599 | 599 | 105 |
|
||||
| f | false | 600 | 600 | initializer for c105 |
|
||||
| f | false | 604 | 604 | call to C |
|
||||
| f | false | 608 | 608 | 109 |
|
||||
| f | false | 609 | 609 | initializer for c109 |
|
||||
| f | true | 430 | 591 | |
|
||||
| f | true | 433 | 465 | |
|
||||
| f | true | 438 | 433 | |
|
||||
| f | true | 439 | 438 | |
|
||||
| f | true | 443 | 581 | |
|
||||
| f | true | 447 | 443 | |
|
||||
| f | true | 448 | 447 | |
|
||||
| f | true | 451 | 439 | |
|
||||
| f | true | 453 | 463 | T |
|
||||
| f | true | 453 | 467 | F |
|
||||
| f | true | 458 | 459 | |
|
||||
| f | true | 459 | 583 | |
|
||||
| f | true | 461 | 458 | |
|
||||
| f | true | 463 | 461 | |
|
||||
| f | true | 465 | 453 | |
|
||||
| f | true | 467 | 448 | |
|
||||
| f | true | 469 | 451 | |
|
||||
| f | true | 476 | 488 | T |
|
||||
| f | true | 478 | 575 | |
|
||||
| f | true | 482 | 478 | |
|
||||
| f | true | 483 | 482 | |
|
||||
| f | true | 486 | 483 | |
|
||||
| f | true | 488 | 486 | |
|
||||
| f | true | 490 | 469 | |
|
||||
| f | true | 492 | 600 | |
|
||||
| f | true | 495 | 526 | |
|
||||
| f | true | 499 | 495 | |
|
||||
| f | true | 500 | 499 | |
|
||||
| f | true | 504 | 571 | |
|
||||
| f | true | 508 | 504 | |
|
||||
| f | true | 509 | 508 | |
|
||||
| f | true | 512 | 500 | |
|
||||
| f | true | 514 | 524 | T |
|
||||
| f | true | 514 | 528 | F |
|
||||
| f | true | 519 | 520 | |
|
||||
| f | true | 520 | 573 | |
|
||||
| f | true | 522 | 519 | |
|
||||
| f | true | 524 | 522 | |
|
||||
| f | true | 526 | 514 | |
|
||||
| f | true | 528 | 509 | |
|
||||
| f | true | 530 | 512 | |
|
||||
| f | true | 533 | 565 | |
|
||||
| f | true | 537 | 533 | |
|
||||
| f | true | 538 | 537 | |
|
||||
| f | true | 541 | 538 | |
|
||||
| f | true | 543 | 541 | |
|
||||
| f | true | 545 | 530 | |
|
||||
| f | true | 547 | 609 | |
|
||||
| f | true | 549 | 559 | |
|
||||
| f | true | 551 | 430 | |
|
||||
| f | true | 553 | 555 | |
|
||||
| f | true | 555 | 419 | |
|
||||
| f | true | 557 | 558 | |
|
||||
| f | true | 558 | 553 | |
|
||||
| f | true | 559 | 560 | |
|
||||
| f | true | 560 | 557 | |
|
||||
| f | true | 561 | 562 | |
|
||||
| f | true | 562 | 419 | |
|
||||
| f | true | 563 | 564 | |
|
||||
| f | true | 564 | 561 | |
|
||||
| f | true | 565 | 567 | |
|
||||
| f | true | 567 | 547 | |
|
||||
| f | true | 567 | 563 | |
|
||||
| f | true | 568 | 570 | |
|
||||
| f | true | 570 | 543 | |
|
||||
| f | true | 571 | 572 | |
|
||||
| f | true | 572 | 568 | |
|
||||
| f | true | 573 | 574 | |
|
||||
| f | true | 574 | 543 | |
|
||||
| f | true | 575 | 577 | |
|
||||
| f | true | 577 | 492 | |
|
||||
| f | true | 578 | 580 | |
|
||||
| f | true | 580 | 492 | |
|
||||
| f | true | 581 | 582 | |
|
||||
| f | true | 582 | 578 | |
|
||||
| f | true | 583 | 584 | |
|
||||
| f | true | 584 | 476 | |
|
||||
| f | true | 586 | 490 | |
|
||||
| f | true | 590 | 586 | |
|
||||
| f | true | 591 | 590 | |
|
||||
| f | true | 595 | 545 | |
|
||||
| f | true | 599 | 595 | |
|
||||
| f | true | 600 | 599 | |
|
||||
| f | true | 604 | 549 | |
|
||||
| f | true | 608 | 604 | |
|
||||
| f | true | 609 | 608 | |
|
||||
| f1 | false | 275 | 275 | f1 |
|
||||
| f2 | false | 282 | 282 | f2 |
|
||||
| f3 | false | 287 | 287 | f3 |
|
||||
| f4 | false | 292 | 292 | f4 |
|
||||
| f4 | false | 381 | 381 | return ... |
|
||||
| f4 | false | 383 | 383 | { ... } |
|
||||
| f4 | true | 381 | 292 | |
|
||||
| f4 | true | 383 | 381 | |
|
||||
| f5 | false | 297 | 297 | f5 |
|
||||
| f5 | false | 370 | 370 | 3 |
|
||||
| f5 | false | 371 | 371 | throw ... |
|
||||
| f5 | false | 373 | 373 | ExprStmt |
|
||||
| f5 | false | 375 | 375 | { ... } |
|
||||
| f5 | true | 370 | 371 | |
|
||||
| f5 | true | 371 | 297 | |
|
||||
| f5 | true | 373 | 370 | |
|
||||
| f5 | true | 375 | 373 | |
|
||||
| fun | false | 270 | 270 | fun |
|
||||
| fun | false | 278 | 278 | call to f1 |
|
||||
| fun | false | 280 | 280 | ExprStmt |
|
||||
| fun | false | 283 | 283 | call to f2 |
|
||||
| fun | false | 285 | 285 | ExprStmt |
|
||||
| fun | false | 288 | 288 | call to f3 |
|
||||
| fun | false | 290 | 290 | ExprStmt |
|
||||
| fun | false | 293 | 293 | call to f4 |
|
||||
| fun | false | 295 | 295 | ExprStmt |
|
||||
| fun | false | 298 | 298 | call to f5 |
|
||||
| fun | false | 300 | 300 | ExprStmt |
|
||||
| fun | false | 304 | 304 | 5 |
|
||||
| fun | false | 305 | 305 | throw ... |
|
||||
| f | false | 477 | 477 | f |
|
||||
| f | false | 488 | 488 | declaration |
|
||||
| f | false | 491 | 491 | call to C |
|
||||
| f | false | 496 | 496 | 102 |
|
||||
| f | false | 497 | 497 | initializer for c102 |
|
||||
| f | false | 501 | 501 | call to C |
|
||||
| f | false | 505 | 505 | 103 |
|
||||
| f | false | 506 | 506 | initializer for c103 |
|
||||
| f | false | 509 | 509 | declaration |
|
||||
| f | false | 511 | 511 | b1 |
|
||||
| f | false | 513 | 513 | (bool)... |
|
||||
| f | false | 516 | 516 | 1 |
|
||||
| f | false | 517 | 517 | throw ... |
|
||||
| f | false | 519 | 519 | ExprStmt |
|
||||
| f | false | 521 | 521 | { ... } |
|
||||
| f | false | 523 | 523 | if (...) ... |
|
||||
| f | false | 525 | 525 | declaration |
|
||||
| f | false | 527 | 527 | { ... } |
|
||||
| f | false | 534 | 534 | 1 |
|
||||
| f | false | 536 | 536 | call to C |
|
||||
| f | false | 540 | 540 | 104 |
|
||||
| f | false | 541 | 541 | initializer for c104 |
|
||||
| f | false | 544 | 544 | declaration |
|
||||
| f | false | 546 | 546 | { ... } |
|
||||
| f | false | 548 | 548 | __try { ... } __except( ... ) { ... } |
|
||||
| f | false | 550 | 550 | declaration |
|
||||
| f | false | 553 | 553 | call to C |
|
||||
| f | false | 557 | 557 | 106 |
|
||||
| f | false | 558 | 558 | initializer for c106 |
|
||||
| f | false | 562 | 562 | call to C |
|
||||
| f | false | 566 | 566 | 107 |
|
||||
| f | false | 567 | 567 | initializer for c107 |
|
||||
| f | false | 570 | 570 | declaration |
|
||||
| f | false | 572 | 572 | b2 |
|
||||
| f | false | 574 | 574 | (bool)... |
|
||||
| f | false | 577 | 577 | 2 |
|
||||
| f | false | 578 | 578 | throw ... |
|
||||
| f | false | 580 | 580 | ExprStmt |
|
||||
| f | false | 582 | 582 | { ... } |
|
||||
| f | false | 584 | 584 | if (...) ... |
|
||||
| f | false | 586 | 586 | declaration |
|
||||
| f | false | 588 | 588 | { ... } |
|
||||
| f | false | 591 | 591 | call to C |
|
||||
| f | false | 595 | 595 | 108 |
|
||||
| f | false | 596 | 596 | initializer for c108 |
|
||||
| f | false | 599 | 599 | declaration |
|
||||
| f | false | 601 | 601 | { ... } |
|
||||
| f | false | 603 | 603 | __try { ... } __finally { ... } |
|
||||
| f | false | 605 | 605 | declaration |
|
||||
| f | false | 607 | 607 | return ... |
|
||||
| f | false | 609 | 609 | { ... } |
|
||||
| f | false | 611 | 611 | c101 |
|
||||
| f | false | 613 | 613 | call to c101.~C |
|
||||
| f | false | 615 | 615 | c105 |
|
||||
| f | false | 616 | 616 | call to c105.~C |
|
||||
| f | false | 617 | 617 | c109 |
|
||||
| f | false | 618 | 618 | call to c109.~C |
|
||||
| f | false | 619 | 619 | c101 |
|
||||
| f | false | 620 | 620 | call to c101.~C |
|
||||
| f | false | 621 | 621 | c105 |
|
||||
| f | false | 622 | 622 | call to c105.~C |
|
||||
| f | false | 623 | 623 | c108 |
|
||||
| f | false | 625 | 625 | call to c108.~C |
|
||||
| f | false | 626 | 626 | c106 |
|
||||
| f | false | 628 | 628 | call to c106.~C |
|
||||
| f | false | 629 | 629 | c107 |
|
||||
| f | false | 630 | 630 | call to c107.~C |
|
||||
| f | false | 631 | 631 | c106 |
|
||||
| f | false | 632 | 632 | call to c106.~C |
|
||||
| f | false | 633 | 633 | c104 |
|
||||
| f | false | 635 | 635 | call to c104.~C |
|
||||
| f | false | 636 | 636 | c102 |
|
||||
| f | false | 638 | 638 | call to c102.~C |
|
||||
| f | false | 639 | 639 | c103 |
|
||||
| f | false | 640 | 640 | call to c103.~C |
|
||||
| f | false | 641 | 641 | c102 |
|
||||
| f | false | 642 | 642 | call to c102.~C |
|
||||
| f | false | 644 | 644 | call to C |
|
||||
| f | false | 648 | 648 | 101 |
|
||||
| f | false | 649 | 649 | initializer for c101 |
|
||||
| f | false | 653 | 653 | call to C |
|
||||
| f | false | 657 | 657 | 105 |
|
||||
| f | false | 658 | 658 | initializer for c105 |
|
||||
| f | false | 662 | 662 | call to C |
|
||||
| f | false | 666 | 666 | 109 |
|
||||
| f | false | 667 | 667 | initializer for c109 |
|
||||
| f | true | 488 | 649 | |
|
||||
| f | true | 491 | 523 | |
|
||||
| f | true | 496 | 491 | |
|
||||
| f | true | 497 | 496 | |
|
||||
| f | true | 501 | 639 | |
|
||||
| f | true | 505 | 501 | |
|
||||
| f | true | 506 | 505 | |
|
||||
| f | true | 509 | 497 | |
|
||||
| f | true | 511 | 521 | T |
|
||||
| f | true | 511 | 525 | F |
|
||||
| f | true | 516 | 517 | |
|
||||
| f | true | 517 | 641 | |
|
||||
| f | true | 519 | 516 | |
|
||||
| f | true | 521 | 519 | |
|
||||
| f | true | 523 | 511 | |
|
||||
| f | true | 525 | 506 | |
|
||||
| f | true | 527 | 509 | |
|
||||
| f | true | 534 | 546 | T |
|
||||
| f | true | 536 | 633 | |
|
||||
| f | true | 540 | 536 | |
|
||||
| f | true | 541 | 540 | |
|
||||
| f | true | 544 | 541 | |
|
||||
| f | true | 546 | 544 | |
|
||||
| f | true | 548 | 527 | |
|
||||
| f | true | 550 | 658 | |
|
||||
| f | true | 553 | 584 | |
|
||||
| f | true | 557 | 553 | |
|
||||
| f | true | 558 | 557 | |
|
||||
| f | true | 562 | 629 | |
|
||||
| f | true | 566 | 562 | |
|
||||
| f | true | 567 | 566 | |
|
||||
| f | true | 570 | 558 | |
|
||||
| f | true | 572 | 582 | T |
|
||||
| f | true | 572 | 586 | F |
|
||||
| f | true | 577 | 578 | |
|
||||
| f | true | 578 | 631 | |
|
||||
| f | true | 580 | 577 | |
|
||||
| f | true | 582 | 580 | |
|
||||
| f | true | 584 | 572 | |
|
||||
| f | true | 586 | 567 | |
|
||||
| f | true | 588 | 570 | |
|
||||
| f | true | 591 | 623 | |
|
||||
| f | true | 595 | 591 | |
|
||||
| f | true | 596 | 595 | |
|
||||
| f | true | 599 | 596 | |
|
||||
| f | true | 601 | 599 | |
|
||||
| f | true | 603 | 588 | |
|
||||
| f | true | 605 | 667 | |
|
||||
| f | true | 607 | 617 | |
|
||||
| f | true | 609 | 488 | |
|
||||
| f | true | 611 | 613 | |
|
||||
| f | true | 613 | 477 | |
|
||||
| f | true | 615 | 616 | |
|
||||
| f | true | 616 | 611 | |
|
||||
| f | true | 617 | 618 | |
|
||||
| f | true | 618 | 615 | |
|
||||
| f | true | 619 | 620 | |
|
||||
| f | true | 620 | 477 | |
|
||||
| f | true | 621 | 622 | |
|
||||
| f | true | 622 | 619 | |
|
||||
| f | true | 623 | 625 | |
|
||||
| f | true | 625 | 605 | |
|
||||
| f | true | 625 | 621 | |
|
||||
| f | true | 626 | 628 | |
|
||||
| f | true | 628 | 601 | |
|
||||
| f | true | 629 | 630 | |
|
||||
| f | true | 630 | 626 | |
|
||||
| f | true | 631 | 632 | |
|
||||
| f | true | 632 | 601 | |
|
||||
| f | true | 633 | 635 | |
|
||||
| f | true | 635 | 550 | |
|
||||
| f | true | 636 | 638 | |
|
||||
| f | true | 638 | 550 | |
|
||||
| f | true | 639 | 640 | |
|
||||
| f | true | 640 | 636 | |
|
||||
| f | true | 641 | 642 | |
|
||||
| f | true | 642 | 534 | |
|
||||
| f | true | 644 | 548 | |
|
||||
| f | true | 648 | 644 | |
|
||||
| f | true | 649 | 648 | |
|
||||
| f | true | 653 | 603 | |
|
||||
| f | true | 657 | 653 | |
|
||||
| f | true | 658 | 657 | |
|
||||
| f | true | 662 | 607 | |
|
||||
| f | true | 666 | 662 | |
|
||||
| f | true | 667 | 666 | |
|
||||
| f1 | false | 292 | 292 | f1 |
|
||||
| f2 | false | 299 | 299 | f2 |
|
||||
| f3 | false | 304 | 304 | f3 |
|
||||
| f4 | false | 309 | 309 | f4 |
|
||||
| f4 | false | 433 | 433 | return ... |
|
||||
| f4 | false | 435 | 435 | { ... } |
|
||||
| f4 | true | 433 | 309 | |
|
||||
| f4 | true | 435 | 433 | |
|
||||
| f5 | false | 314 | 314 | f5 |
|
||||
| f5 | false | 422 | 422 | 3 |
|
||||
| f5 | false | 423 | 423 | throw ... |
|
||||
| f5 | false | 425 | 425 | ExprStmt |
|
||||
| f5 | false | 427 | 427 | { ... } |
|
||||
| f5 | true | 422 | 423 | |
|
||||
| f5 | true | 423 | 314 | |
|
||||
| f5 | true | 425 | 422 | |
|
||||
| f5 | true | 427 | 425 | |
|
||||
| fun | false | 287 | 287 | fun |
|
||||
| fun | false | 295 | 295 | call to f1 |
|
||||
| fun | false | 297 | 297 | ExprStmt |
|
||||
| fun | false | 300 | 300 | call to f2 |
|
||||
| fun | false | 302 | 302 | ExprStmt |
|
||||
| fun | false | 305 | 305 | call to f3 |
|
||||
| fun | false | 307 | 307 | ExprStmt |
|
||||
| fun | false | 310 | 310 | call to g |
|
||||
| fun | false | 310 | 310 | call to f4 |
|
||||
| fun | false | 312 | 312 | ExprStmt |
|
||||
| fun | false | 314 | 314 | { ... } |
|
||||
| fun | false | 320 | 320 | call to h |
|
||||
| fun | false | 322 | 322 | ExprStmt |
|
||||
| fun | false | 324 | 324 | { ... } |
|
||||
| fun | false | 326 | 326 | <handler> |
|
||||
| fun | false | 327 | 327 | try { ... } |
|
||||
| fun | false | 329 | 329 | { ... } |
|
||||
| fun | false | 335 | 335 | call to i |
|
||||
| fun | false | 337 | 337 | ExprStmt |
|
||||
| fun | false | 339 | 339 | { ... } |
|
||||
| fun | false | 345 | 345 | call to j |
|
||||
| fun | false | 347 | 347 | ExprStmt |
|
||||
| fun | false | 349 | 349 | { ... } |
|
||||
| fun | false | 351 | 351 | <handler> |
|
||||
| fun | false | 352 | 352 | <handler> |
|
||||
| fun | false | 353 | 353 | try { ... } |
|
||||
| fun | false | 356 | 356 | call to k |
|
||||
| fun | false | 358 | 358 | ExprStmt |
|
||||
| fun | false | 360 | 360 | return ... |
|
||||
| fun | false | 362 | 362 | { ... } |
|
||||
| fun | true | 278 | 285 | |
|
||||
| fun | true | 280 | 278 | |
|
||||
| fun | true | 283 | 290 | |
|
||||
| fun | true | 285 | 283 | |
|
||||
| fun | true | 288 | 295 | |
|
||||
| fun | true | 290 | 288 | |
|
||||
| fun | true | 293 | 300 | |
|
||||
| fun | true | 295 | 293 | |
|
||||
| fun | true | 298 | 307 | |
|
||||
| fun | true | 300 | 298 | |
|
||||
| fun | true | 304 | 305 | |
|
||||
| fun | true | 305 | 326 | |
|
||||
| fun | true | 307 | 304 | |
|
||||
| fun | true | 310 | 358 | |
|
||||
| fun | false | 315 | 315 | call to f5 |
|
||||
| fun | false | 317 | 317 | ExprStmt |
|
||||
| fun | false | 321 | 321 | 5 |
|
||||
| fun | false | 322 | 322 | throw ... |
|
||||
| fun | false | 324 | 324 | ExprStmt |
|
||||
| fun | false | 327 | 327 | call to g |
|
||||
| fun | false | 329 | 329 | ExprStmt |
|
||||
| fun | false | 331 | 331 | { ... } |
|
||||
| fun | false | 337 | 337 | call to h |
|
||||
| fun | false | 339 | 339 | ExprStmt |
|
||||
| fun | false | 341 | 341 | { ... } |
|
||||
| fun | false | 343 | 343 | <handler> |
|
||||
| fun | false | 344 | 344 | try { ... } |
|
||||
| fun | false | 346 | 346 | { ... } |
|
||||
| fun | false | 352 | 352 | call to i |
|
||||
| fun | false | 354 | 354 | ExprStmt |
|
||||
| fun | false | 356 | 356 | { ... } |
|
||||
| fun | false | 362 | 362 | call to j |
|
||||
| fun | false | 364 | 364 | ExprStmt |
|
||||
| fun | false | 366 | 366 | { ... } |
|
||||
| fun | false | 368 | 368 | <handler> |
|
||||
| fun | false | 369 | 369 | <handler> |
|
||||
| fun | false | 370 | 370 | try { ... } |
|
||||
| fun | false | 373 | 373 | call to k |
|
||||
| fun | false | 375 | 375 | ExprStmt |
|
||||
| fun | false | 379 | 379 | 7 |
|
||||
| fun | false | 380 | 380 | throw ... |
|
||||
| fun | false | 382 | 382 | ExprStmt |
|
||||
| fun | false | 384 | 384 | { ... } |
|
||||
| fun | false | 390 | 390 | call to l |
|
||||
| fun | false | 392 | 392 | ExprStmt |
|
||||
| fun | false | 394 | 394 | { ... } |
|
||||
| fun | false | 397 | 397 | call to m |
|
||||
| fun | false | 399 | 399 | ExprStmt |
|
||||
| fun | false | 401 | 401 | { ... } |
|
||||
| fun | false | 403 | 403 | <handler> |
|
||||
| fun | false | 404 | 404 | <handler> |
|
||||
| fun | false | 405 | 405 | try { ... } |
|
||||
| fun | false | 408 | 408 | call to n |
|
||||
| fun | false | 410 | 410 | ExprStmt |
|
||||
| fun | false | 412 | 412 | return ... |
|
||||
| fun | false | 414 | 414 | { ... } |
|
||||
| fun | true | 295 | 302 | |
|
||||
| fun | true | 297 | 295 | |
|
||||
| fun | true | 300 | 307 | |
|
||||
| fun | true | 302 | 300 | |
|
||||
| fun | true | 305 | 312 | |
|
||||
| fun | true | 307 | 305 | |
|
||||
| fun | true | 310 | 317 | |
|
||||
| fun | true | 312 | 310 | |
|
||||
| fun | true | 314 | 280 | |
|
||||
| fun | true | 320 | 358 | |
|
||||
| fun | true | 322 | 320 | |
|
||||
| fun | true | 324 | 322 | |
|
||||
| fun | true | 326 | 324 | |
|
||||
| fun | true | 326 | 351 | |
|
||||
| fun | true | 327 | 314 | |
|
||||
| fun | true | 317 | 315 | |
|
||||
| fun | true | 321 | 322 | |
|
||||
| fun | true | 322 | 343 | |
|
||||
| fun | true | 324 | 321 | |
|
||||
| fun | true | 327 | 375 | |
|
||||
| fun | true | 329 | 327 | |
|
||||
| fun | true | 335 | 358 | |
|
||||
| fun | true | 337 | 335 | |
|
||||
| fun | true | 331 | 297 | |
|
||||
| fun | true | 337 | 375 | |
|
||||
| fun | true | 339 | 337 | |
|
||||
| fun | true | 345 | 358 | |
|
||||
| fun | true | 347 | 345 | |
|
||||
| fun | true | 349 | 347 | |
|
||||
| fun | true | 351 | 339 | |
|
||||
| fun | true | 351 | 352 | |
|
||||
| fun | true | 352 | 270 | |
|
||||
| fun | true | 352 | 349 | |
|
||||
| fun | true | 353 | 329 | |
|
||||
| fun | true | 356 | 360 | |
|
||||
| fun | true | 358 | 356 | |
|
||||
| fun | true | 360 | 270 | |
|
||||
| fun | true | 362 | 353 | |
|
||||
| fun2 | false | 187 | 187 | fun2 |
|
||||
| fun2 | false | 198 | 198 | fun2 |
|
||||
| fun2 | false | 201 | 201 | { ... } |
|
||||
| fun2 | false | 206 | 206 | re-throw exception |
|
||||
| fun2 | false | 208 | 208 | ExprStmt |
|
||||
| fun2 | false | 210 | 210 | { ... } |
|
||||
| fun2 | false | 214 | 214 | 1 |
|
||||
| fun2 | false | 215 | 215 | return ... |
|
||||
| fun2 | false | 217 | 217 | { ... } |
|
||||
| fun2 | false | 219 | 219 | <handler> |
|
||||
| fun2 | false | 220 | 220 | <handler> |
|
||||
| fun2 | false | 221 | 221 | try { ... } |
|
||||
| fun2 | false | 225 | 225 | 0 |
|
||||
| fun2 | false | 226 | 226 | return ... |
|
||||
| fun2 | false | 228 | 228 | { ... } |
|
||||
| fun2 | false | 644 | 644 | { ... } |
|
||||
| fun2 | false | 649 | 649 | re-throw exception |
|
||||
| fun2 | false | 650 | 650 | ExprStmt |
|
||||
| fun2 | false | 651 | 651 | { ... } |
|
||||
| fun2 | false | 653 | 653 | 1 |
|
||||
| fun2 | false | 654 | 654 | return ... |
|
||||
| fun2 | false | 655 | 655 | { ... } |
|
||||
| fun2 | false | 656 | 656 | <handler> |
|
||||
| fun2 | false | 657 | 657 | <handler> |
|
||||
| fun2 | false | 658 | 658 | try { ... } |
|
||||
| fun2 | false | 660 | 660 | 0 |
|
||||
| fun2 | false | 661 | 661 | return ... |
|
||||
| fun2 | false | 662 | 662 | { ... } |
|
||||
| fun2 | true | 201 | 226 | |
|
||||
| fun2 | true | 206 | 198 | |
|
||||
| fun2 | true | 208 | 206 | |
|
||||
| fun2 | true | 210 | 208 | |
|
||||
| fun2 | true | 214 | 198 | |
|
||||
| fun2 | true | 215 | 214 | |
|
||||
| fun2 | true | 217 | 215 | |
|
||||
| fun2 | true | 219 | 210 | |
|
||||
| fun2 | true | 219 | 220 | |
|
||||
| fun2 | true | 220 | 217 | |
|
||||
| fun2 | true | 221 | 201 | |
|
||||
| fun2 | true | 225 | 198 | |
|
||||
| fun2 | true | 226 | 225 | |
|
||||
| fun2 | true | 228 | 221 | |
|
||||
| fun2 | true | 644 | 661 | |
|
||||
| fun2 | true | 649 | 187 | |
|
||||
| fun2 | true | 650 | 649 | |
|
||||
| fun2 | true | 651 | 650 | |
|
||||
| fun2 | true | 653 | 187 | |
|
||||
| fun2 | true | 654 | 653 | |
|
||||
| fun2 | true | 655 | 654 | |
|
||||
| fun2 | true | 656 | 651 | |
|
||||
| fun2 | true | 656 | 657 | |
|
||||
| fun2 | true | 657 | 655 | |
|
||||
| fun2 | true | 658 | 644 | |
|
||||
| fun2 | true | 660 | 187 | |
|
||||
| fun2 | true | 661 | 660 | |
|
||||
| fun2 | true | 662 | 658 | |
|
||||
| g | false | 309 | 309 | g |
|
||||
| h | false | 319 | 319 | h |
|
||||
| i | false | 334 | 334 | i |
|
||||
| j | false | 344 | 344 | j |
|
||||
| k | false | 355 | 355 | k |
|
||||
| run_fun2 | false | 182 | 182 | run_fun2 |
|
||||
| run_fun2 | false | 190 | 190 | call to fun2 |
|
||||
| run_fun2 | false | 192 | 192 | ExprStmt |
|
||||
| run_fun2 | false | 194 | 194 | return ... |
|
||||
| run_fun2 | false | 196 | 196 | { ... } |
|
||||
| run_fun2 | true | 190 | 194 | |
|
||||
| run_fun2 | true | 192 | 190 | |
|
||||
| run_fun2 | true | 194 | 182 | |
|
||||
| run_fun2 | true | 196 | 192 | |
|
||||
| fun | true | 341 | 339 | |
|
||||
| fun | true | 343 | 341 | |
|
||||
| fun | true | 343 | 368 | |
|
||||
| fun | true | 344 | 331 | |
|
||||
| fun | true | 346 | 344 | |
|
||||
| fun | true | 352 | 375 | |
|
||||
| fun | true | 354 | 352 | |
|
||||
| fun | true | 356 | 354 | |
|
||||
| fun | true | 362 | 375 | |
|
||||
| fun | true | 364 | 362 | |
|
||||
| fun | true | 366 | 364 | |
|
||||
| fun | true | 368 | 356 | |
|
||||
| fun | true | 368 | 369 | |
|
||||
| fun | true | 369 | 287 | |
|
||||
| fun | true | 369 | 366 | |
|
||||
| fun | true | 370 | 346 | |
|
||||
| fun | true | 373 | 405 | |
|
||||
| fun | true | 375 | 373 | |
|
||||
| fun | true | 379 | 380 | |
|
||||
| fun | true | 380 | 403 | |
|
||||
| fun | true | 382 | 379 | |
|
||||
| fun | true | 384 | 382 | |
|
||||
| fun | true | 390 | 410 | |
|
||||
| fun | true | 392 | 390 | |
|
||||
| fun | true | 394 | 392 | |
|
||||
| fun | true | 397 | 410 | |
|
||||
| fun | true | 399 | 397 | |
|
||||
| fun | true | 401 | 399 | |
|
||||
| fun | true | 403 | 394 | |
|
||||
| fun | true | 403 | 404 | |
|
||||
| fun | true | 404 | 401 | |
|
||||
| fun | true | 405 | 384 | |
|
||||
| fun | true | 408 | 412 | |
|
||||
| fun | true | 410 | 408 | |
|
||||
| fun | true | 412 | 287 | |
|
||||
| fun | true | 414 | 370 | |
|
||||
| fun2 | false | 204 | 204 | fun2 |
|
||||
| fun2 | false | 215 | 215 | fun2 |
|
||||
| fun2 | false | 218 | 218 | { ... } |
|
||||
| fun2 | false | 223 | 223 | re-throw exception |
|
||||
| fun2 | false | 225 | 225 | ExprStmt |
|
||||
| fun2 | false | 227 | 227 | { ... } |
|
||||
| fun2 | false | 231 | 231 | 1 |
|
||||
| fun2 | false | 232 | 232 | return ... |
|
||||
| fun2 | false | 234 | 234 | { ... } |
|
||||
| fun2 | false | 236 | 236 | <handler> |
|
||||
| fun2 | false | 237 | 237 | <handler> |
|
||||
| fun2 | false | 238 | 238 | try { ... } |
|
||||
| fun2 | false | 242 | 242 | 0 |
|
||||
| fun2 | false | 243 | 243 | return ... |
|
||||
| fun2 | false | 245 | 245 | { ... } |
|
||||
| fun2 | false | 702 | 702 | { ... } |
|
||||
| fun2 | false | 707 | 707 | re-throw exception |
|
||||
| fun2 | false | 708 | 708 | ExprStmt |
|
||||
| fun2 | false | 709 | 709 | { ... } |
|
||||
| fun2 | false | 711 | 711 | 1 |
|
||||
| fun2 | false | 712 | 712 | return ... |
|
||||
| fun2 | false | 713 | 713 | { ... } |
|
||||
| fun2 | false | 714 | 714 | <handler> |
|
||||
| fun2 | false | 715 | 715 | <handler> |
|
||||
| fun2 | false | 716 | 716 | try { ... } |
|
||||
| fun2 | false | 718 | 718 | 0 |
|
||||
| fun2 | false | 719 | 719 | return ... |
|
||||
| fun2 | false | 720 | 720 | { ... } |
|
||||
| fun2 | true | 218 | 243 | |
|
||||
| fun2 | true | 223 | 215 | |
|
||||
| fun2 | true | 225 | 223 | |
|
||||
| fun2 | true | 227 | 225 | |
|
||||
| fun2 | true | 231 | 215 | |
|
||||
| fun2 | true | 232 | 231 | |
|
||||
| fun2 | true | 234 | 232 | |
|
||||
| fun2 | true | 236 | 227 | |
|
||||
| fun2 | true | 236 | 237 | |
|
||||
| fun2 | true | 237 | 234 | |
|
||||
| fun2 | true | 238 | 218 | |
|
||||
| fun2 | true | 242 | 215 | |
|
||||
| fun2 | true | 243 | 242 | |
|
||||
| fun2 | true | 245 | 238 | |
|
||||
| fun2 | true | 702 | 719 | |
|
||||
| fun2 | true | 707 | 204 | |
|
||||
| fun2 | true | 708 | 707 | |
|
||||
| fun2 | true | 709 | 708 | |
|
||||
| fun2 | true | 711 | 204 | |
|
||||
| fun2 | true | 712 | 711 | |
|
||||
| fun2 | true | 713 | 712 | |
|
||||
| fun2 | true | 714 | 709 | |
|
||||
| fun2 | true | 714 | 715 | |
|
||||
| fun2 | true | 715 | 713 | |
|
||||
| fun2 | true | 716 | 702 | |
|
||||
| fun2 | true | 718 | 204 | |
|
||||
| fun2 | true | 719 | 718 | |
|
||||
| fun2 | true | 720 | 716 | |
|
||||
| g | false | 326 | 326 | g |
|
||||
| h | false | 336 | 336 | h |
|
||||
| i | false | 351 | 351 | i |
|
||||
| j | false | 361 | 361 | j |
|
||||
| k | false | 372 | 372 | k |
|
||||
| l | false | 389 | 389 | l |
|
||||
| m | false | 396 | 396 | m |
|
||||
| n | false | 407 | 407 | n |
|
||||
| run_fun2 | false | 199 | 199 | run_fun2 |
|
||||
| run_fun2 | false | 207 | 207 | call to fun2 |
|
||||
| run_fun2 | false | 209 | 209 | ExprStmt |
|
||||
| run_fun2 | false | 211 | 211 | return ... |
|
||||
| run_fun2 | false | 213 | 213 | { ... } |
|
||||
| run_fun2 | true | 207 | 211 | |
|
||||
| run_fun2 | true | 209 | 207 | |
|
||||
| run_fun2 | true | 211 | 199 | |
|
||||
| run_fun2 | true | 213 | 209 | |
|
||||
|
||||
@@ -29,3 +29,12 @@
|
||||
| exceptions.cpp:35:19:37:5 | <handler> | getTryStmt | exceptions.cpp:18:5:31:5 | try { ... } |
|
||||
| exceptions.cpp:35:19:37:5 | <handler> | getTryStmt.getACatchClause() | exceptions.cpp:32:19:34:5 | { ... } |
|
||||
| exceptions.cpp:35:19:37:5 | <handler> | getTryStmt.getACatchClause() | exceptions.cpp:35:19:37:5 | { ... } |
|
||||
| exceptions.cpp:42:21:44:5 | <handler> | getBlock | exceptions.cpp:42:21:44:5 | { ... } |
|
||||
| exceptions.cpp:42:21:44:5 | <handler> | getParameter | exceptions.cpp:42:18:42:18 | e |
|
||||
| exceptions.cpp:42:21:44:5 | <handler> | getTryStmt | exceptions.cpp:40:5:42:5 | try { ... } |
|
||||
| exceptions.cpp:42:21:44:5 | <handler> | getTryStmt.getACatchClause() | exceptions.cpp:42:21:44:5 | { ... } |
|
||||
| exceptions.cpp:42:21:44:5 | <handler> | getTryStmt.getACatchClause() | exceptions.cpp:44:19:46:5 | { ... } |
|
||||
| exceptions.cpp:44:19:46:5 | <handler> | getBlock | exceptions.cpp:44:19:46:5 | { ... } |
|
||||
| exceptions.cpp:44:19:46:5 | <handler> | getTryStmt | exceptions.cpp:40:5:42:5 | try { ... } |
|
||||
| exceptions.cpp:44:19:46:5 | <handler> | getTryStmt.getACatchClause() | exceptions.cpp:42:21:44:5 | { ... } |
|
||||
| exceptions.cpp:44:19:46:5 | <handler> | getTryStmt.getACatchClause() | exceptions.cpp:44:19:46:5 | { ... } |
|
||||
|
||||
@@ -1,5 +1,2 @@
|
||||
| ODASA-5692.cpp:11:18:13:3 | <handler> |
|
||||
| ODASA-5692.cpp:11:18:13:3 | <handler> |
|
||||
| ODASA-5692.cpp:14:15:15:12 | <handler> |
|
||||
| ODASA-5692.cpp:14:15:15:12 | <handler> |
|
||||
| exceptions.cpp:25:13:25:19 | ExprStmt |
|
||||
| exceptions.cpp:26:13:26:13 | ExprStmt |
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
import cpp
|
||||
|
||||
string exprString(Expr e) {
|
||||
if (e instanceof ArrayToPointerConversion) then (
|
||||
result = e.(ArrayToPointerConversion).getExpr().(Literal).getValue()
|
||||
) else (
|
||||
result = e.toString()
|
||||
)
|
||||
if (e instanceof ArrayToPointerConversion) then (
|
||||
result = e.(ArrayToPointerConversion).getExpr().(Literal).getValue()
|
||||
) else (
|
||||
result = e.toString()
|
||||
)
|
||||
}
|
||||
|
||||
from Cast c, Type cType, string cTypeName, string toStruct
|
||||
|
||||
@@ -5,31 +5,31 @@
|
||||
import cpp
|
||||
|
||||
predicate nameCheck(Declaration d) {
|
||||
count(d.toString()) = 1 and
|
||||
count(string s | d.hasName(s)) = 1 and
|
||||
d.hasName(d.toString())
|
||||
count(d.toString()) = 1 and
|
||||
count(string s | d.hasName(s)) = 1 and
|
||||
d.hasName(d.toString())
|
||||
}
|
||||
|
||||
string accessType(Field f) {
|
||||
(f.isPublic() and result = "public") or
|
||||
(f.isProtected() and result = "protected") or
|
||||
(f.isPrivate() and result = "private")
|
||||
(f.isPublic() and result = "public") or
|
||||
(f.isProtected() and result = "protected") or
|
||||
(f.isPrivate() and result = "private")
|
||||
}
|
||||
|
||||
string fieldType(Field f) {
|
||||
result = f.getType().getAQlClass() and
|
||||
(
|
||||
result.matches("%Type") or
|
||||
result = "Enum"
|
||||
)
|
||||
result = f.getType().getAQlClass() and
|
||||
(
|
||||
result.matches("%Type") or
|
||||
result = "Enum"
|
||||
)
|
||||
}
|
||||
|
||||
string pointedType(Field f) {
|
||||
if f.getType() instanceof PointerType then (
|
||||
result = f.getType().(PointerType).getBaseType().toString()
|
||||
) else (
|
||||
result = ""
|
||||
)
|
||||
if f.getType() instanceof PointerType then (
|
||||
result = f.getType().(PointerType).getBaseType().toString()
|
||||
) else (
|
||||
result = ""
|
||||
)
|
||||
}
|
||||
|
||||
from Class c, Field f
|
||||
|
||||
@@ -241,3 +241,27 @@ void macroExpansionTest() {
|
||||
MAYBE_DO(x = 1); // GOOD (the problem is in the macro)
|
||||
MAYBE_DO(if (global_setting >= 0) {x = 2;}); // BAD (the problem is in the invocation)
|
||||
}
|
||||
|
||||
int overeager_wraparound(unsigned int u32bound, unsigned long long u64bound) {
|
||||
unsigned int u32idx;
|
||||
unsigned long long u64idx;
|
||||
|
||||
for (u32idx = 1; u32idx < u32bound; u32idx++) {
|
||||
if (u32idx == 0) // BAD [NOT DETECTED]
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (u64idx = 1; u64idx < u64bound; u64idx++) {
|
||||
if (u64idx == 0) // BAD [NOT DETECTED]
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int negative_zero(double dbl) {
|
||||
if (dbl >= 0) {
|
||||
return dbl >= -dbl; // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -31,5 +31,6 @@
|
||||
| PointlessComparison.c:126:12:126:18 | ... >= ... | Comparison is always true because a >= 20. |
|
||||
| PointlessComparison.c:129:12:129:16 | ... > ... | Comparison is always false because a <= 3. |
|
||||
| PointlessComparison.c:197:7:197:11 | ... < ... | Comparison is always false because x >= 0. |
|
||||
| PointlessComparison.c:264:12:264:22 | ... >= ... | Comparison is always true because dbl >= 0 and -0 >= - .... |
|
||||
| RegressionTests.cpp:57:7:57:22 | ... <= ... | Comparison is always true because * ... <= 4294967295. |
|
||||
| Templates.cpp:9:10:9:24 | ... <= ... | Comparison is always true because local <= 32767. |
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
#define FLAGS 0x4004
|
||||
#define cap_valid(x) ((x) >= 0 && (x) <= 4)
|
||||
|
||||
void C6317_positive(int i)
|
||||
{
|
||||
if (i & !FLAGS) // BUG
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void C6317_negative(int i)
|
||||
{
|
||||
if (i & ~FLAGS)
|
||||
{
|
||||
}
|
||||
|
||||
if (i && ~FLAGS)
|
||||
{
|
||||
}
|
||||
|
||||
if (i && !FLAGS)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void bitwiseAndUsage(unsigned int l, unsigned int r)
|
||||
{
|
||||
unsigned int x;
|
||||
unsigned z = 0;
|
||||
|
||||
x = l & !r; //BUG
|
||||
x = !FLAGS & r; //BUG
|
||||
x = !FLAGS & !!r; //BUG
|
||||
|
||||
x = !!l & r; // Not a bug - double negation
|
||||
x = !!!l & r; // Not a bug - double negation
|
||||
x = !!FLAGS & r; // Not a bug - double negation
|
||||
|
||||
x = !FLAGS && r; // Not a bug - logical and
|
||||
x = !FLAGS && !!r; // Not a bug - logical and
|
||||
}
|
||||
|
||||
void bitwiseOrUsage(unsigned int l, unsigned int r)
|
||||
{
|
||||
unsigned int x;
|
||||
|
||||
x = l | !r; //BUG
|
||||
x = !FLAGS | r; //BUG
|
||||
x = !FLAGS | !!r; //BUG
|
||||
|
||||
x = !!l | r; // Not a bug - double negation
|
||||
x = !!!l | r; // Not a bug - double negation
|
||||
x = !!FLAGS | r; // Not a bug - double negation
|
||||
|
||||
x = !FLAGS || r; // Not a bug - logical or
|
||||
x = !FLAGS || !!r; // Not a bug - logical or
|
||||
}
|
||||
|
||||
void bitwiseOperatorsNotCovered(unsigned int l, unsigned int r)
|
||||
{
|
||||
unsigned int x;
|
||||
|
||||
x = l ^ !r;
|
||||
x = !l << 1;
|
||||
x = !l >> 1;
|
||||
}
|
||||
|
||||
void macroUsage(unsigned int arg1, unsigned int arg2)
|
||||
{
|
||||
if (((!cap_valid(arg1)) | arg2)) { // BUG
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
#define FLAGS 0x4004
|
||||
#define cap_valid(x) ((x) >= 0 && (x) <= 4)
|
||||
|
||||
void C6317_positive(int i)
|
||||
{
|
||||
if (i & !FLAGS) // BUG
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void C6317_negative(int i)
|
||||
{
|
||||
if (i & ~FLAGS)
|
||||
{
|
||||
}
|
||||
|
||||
if (i && ~FLAGS)
|
||||
{
|
||||
}
|
||||
|
||||
if (i && !FLAGS)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void bitwiseAndUsage(unsigned int l, unsigned int r)
|
||||
{
|
||||
unsigned int x;
|
||||
unsigned z = 0;
|
||||
|
||||
x = l & !r; //BUG
|
||||
x = !FLAGS & r; //BUG
|
||||
x = !FLAGS & !!r; //BUG
|
||||
|
||||
x = !!l & r; // Not a bug - double negation
|
||||
x = !!!l & r; // Not a bug - double negation
|
||||
x = !!FLAGS & r; // Not a bug - double negation
|
||||
|
||||
x = !FLAGS && r; // Not a bug - logical and
|
||||
x = !FLAGS && !!r; // Not a bug - logical and
|
||||
}
|
||||
|
||||
void bitwiseOrUsage(unsigned int l, unsigned int r)
|
||||
{
|
||||
unsigned int x;
|
||||
|
||||
x = l | !r; //BUG
|
||||
x = !FLAGS | r; //BUG
|
||||
x = !FLAGS | !!r; //BUG
|
||||
|
||||
x = !!l | r; // Not a bug - double negation
|
||||
x = !!!l | r; // Not a bug - double negation
|
||||
x = !!FLAGS | r; // Not a bug - double negation
|
||||
|
||||
x = !FLAGS || r; // Not a bug - logical or
|
||||
x = !FLAGS || !!r; // Not a bug - logical or
|
||||
}
|
||||
|
||||
void bitwiseOperatorsNotCovered(unsigned int l, unsigned int r)
|
||||
{
|
||||
unsigned int x;
|
||||
|
||||
x = l ^ !r;
|
||||
x = !l << 1;
|
||||
x = !l >> 1;
|
||||
}
|
||||
|
||||
void macroUsage(unsigned int arg1, unsigned int arg2)
|
||||
{
|
||||
if (((!cap_valid(arg1)) | arg2)) { // BUG
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
| IncorrectNotOperatorUsage.c:6:9:6:18 | ... & ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.c:31:9:31:14 | ... & ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.c:32:9:32:18 | ... & ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.c:33:9:33:20 | ... & ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.c:47:9:47:14 | ... \| ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.c:48:9:48:18 | ... \| ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.c:49:9:49:20 | ... \| ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.c:70:10:70:34 | ... \| ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.cpp:6:9:6:18 | ... & ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.cpp:31:9:31:14 | ... & ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.cpp:32:9:32:18 | ... & ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.cpp:33:9:33:20 | ... & ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.cpp:47:9:47:14 | ... \| ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.cpp:48:9:48:18 | ... \| ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.cpp:49:9:49:20 | ... \| ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
| IncorrectNotOperatorUsage.cpp:70:10:70:34 | ... \| ... | Usage of a logical not (!) expression as a bitwise operator. |
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.ql
|
||||
@@ -0,0 +1,121 @@
|
||||
struct HasDtor
|
||||
{
|
||||
~HasDtor();
|
||||
};
|
||||
|
||||
struct Base_NonVirtual_NoDtor
|
||||
{
|
||||
void NonVirtualFunction();
|
||||
};
|
||||
|
||||
struct Base_NonVirtual_VirtualDtor
|
||||
{
|
||||
virtual ~Base_NonVirtual_VirtualDtor();
|
||||
void NonVirtualFunction();
|
||||
};
|
||||
|
||||
struct Base_NonVirtual_NonVirtualDtor
|
||||
{
|
||||
~Base_NonVirtual_NonVirtualDtor();
|
||||
void NonVirtualFunction();
|
||||
};
|
||||
|
||||
struct Base_NonVirtual_ImplicitDtor
|
||||
{
|
||||
HasDtor m_hasDtor;
|
||||
void NonVirtualFunction();
|
||||
};
|
||||
|
||||
struct Derived_NonVirtual_NoDtor : public Base_NonVirtual_NoDtor
|
||||
{
|
||||
};
|
||||
|
||||
struct Derived_NonVirtual_VirtualDtor : public Base_NonVirtual_VirtualDtor
|
||||
{
|
||||
};
|
||||
|
||||
struct Derived_NonVirtual_NonVirtualDtor : public Base_NonVirtual_NonVirtualDtor
|
||||
{
|
||||
};
|
||||
|
||||
struct Derived_NonVirtual_ImplicitDtor : public Base_NonVirtual_ImplicitDtor
|
||||
{
|
||||
};
|
||||
|
||||
struct Base_Virtual_NoDtor
|
||||
{
|
||||
virtual void VirtualFunction();
|
||||
};
|
||||
|
||||
struct Base_Virtual_VirtualDtor
|
||||
{
|
||||
virtual ~Base_Virtual_VirtualDtor();
|
||||
virtual void VirtualFunction();
|
||||
};
|
||||
|
||||
struct Base_Virtual_NonVirtualDtor
|
||||
{
|
||||
~Base_Virtual_NonVirtualDtor();
|
||||
virtual void VirtualFunction();
|
||||
};
|
||||
|
||||
struct Base_Virtual_ImplicitDtor
|
||||
{
|
||||
HasDtor m_hasDtor;
|
||||
virtual void VirtualFunction();
|
||||
};
|
||||
|
||||
struct Base_Virtual_NonVirtualDtorWithDefinition
|
||||
{
|
||||
~Base_Virtual_NonVirtualDtorWithDefinition();
|
||||
virtual void VirtualFunction();
|
||||
};
|
||||
|
||||
Base_Virtual_NonVirtualDtorWithDefinition::~Base_Virtual_NonVirtualDtorWithDefinition()
|
||||
{
|
||||
}
|
||||
|
||||
struct Base_Virtual_NonVirtualDtorWithInlineDefinition
|
||||
{
|
||||
~Base_Virtual_NonVirtualDtorWithInlineDefinition()
|
||||
{
|
||||
}
|
||||
virtual void VirtualFunction();
|
||||
};
|
||||
|
||||
struct Base_Virtual_ProtectedNonVirtualDtor
|
||||
{
|
||||
protected:
|
||||
~Base_Virtual_ProtectedNonVirtualDtor();
|
||||
|
||||
public:
|
||||
virtual void VirtualFunction();
|
||||
};
|
||||
|
||||
struct Derived_Virtual_NoDtor : public Base_Virtual_NoDtor
|
||||
{
|
||||
};
|
||||
|
||||
struct Derived_Virtual_VirtualDtor : public Base_Virtual_VirtualDtor
|
||||
{
|
||||
};
|
||||
|
||||
struct Derived_Virtual_NonVirtualDtor : public Base_Virtual_NonVirtualDtor
|
||||
{
|
||||
};
|
||||
|
||||
struct Derived_Virtual_ImplicitDtor : public Base_Virtual_ImplicitDtor
|
||||
{
|
||||
};
|
||||
|
||||
struct Derived_Virtual_NonVirtualDtorWithDefinition: public Base_Virtual_NonVirtualDtorWithDefinition
|
||||
{
|
||||
};
|
||||
|
||||
struct Derived_Virtual_NonVirtualDtorWithInlineDefinition: public Base_Virtual_NonVirtualDtorWithInlineDefinition
|
||||
{
|
||||
};
|
||||
|
||||
struct Derived_Virtual_ProtectedNonVirtualDtor : public Base_Virtual_ProtectedNonVirtualDtor
|
||||
{
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
| NonVirtualDestructorInBaseClass.cpp:56:8:56:34 | Base_Virtual_NonVirtualDtor | A base class with a virtual function should define a virtual destructor. |
|
||||
| NonVirtualDestructorInBaseClass.cpp:68:8:68:48 | Base_Virtual_NonVirtualDtorWithDefinition | A base class with a virtual function should define a virtual destructor. |
|
||||
| NonVirtualDestructorInBaseClass.cpp:78:8:78:54 | Base_Virtual_NonVirtualDtorWithInlineDefinition | A base class with a virtual function should define a virtual destructor. |
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/OO/NonVirtualDestructorInBaseClass.ql
|
||||
@@ -171,6 +171,16 @@ class Reachability {
|
||||
static Reachability staticInstance;
|
||||
};
|
||||
|
||||
class Forgivable {
|
||||
// GOOD: wrong return type but that doesn't matter on a deleted function.
|
||||
Forgivable operator=(const Forgivable &_val) = delete;
|
||||
|
||||
private:
|
||||
// GOOD: wrong return type but that doesn't matter because this operator is
|
||||
// private and probably also unimplemented, so no code can call it.
|
||||
Forgivable operator=(int *_val);
|
||||
};
|
||||
|
||||
int main() {
|
||||
Container c;
|
||||
c = c;
|
||||
|
||||
@@ -5,3 +5,6 @@
|
||||
| test.cpp:48:2:48:26 | if (...) ... | Function g7 should return a value of type MyValue but does not return a value here |
|
||||
| test.cpp:74:1:76:1 | { ... } | Function g10 should return a value of type second but does not return a value here |
|
||||
| test.cpp:86:1:88:1 | { ... } | Function g12 should return a value of type second but does not return a value here |
|
||||
| test.cpp:108:2:111:2 | if (...) ... | Function g14 should return a value of type int but does not return a value here |
|
||||
| test.cpp:134:2:134:36 | ExprStmt | Function g16 should return a value of type int but does not return a value here |
|
||||
| test.cpp:141:3:141:37 | ExprStmt | Function g17 should return a value of type int but does not return a value here |
|
||||
|
||||
@@ -62,3 +62,25 @@ void exit(int status);
|
||||
int f10() {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int f11(int x)
|
||||
{
|
||||
if (x < 10)
|
||||
{
|
||||
return x;
|
||||
} else {
|
||||
f10(); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
int f12(int x)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
// ...
|
||||
|
||||
if (x == 10) return 1; // GOOD
|
||||
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,3 +92,75 @@ void instantiate()
|
||||
g11<int>();
|
||||
g12<int>();
|
||||
}
|
||||
|
||||
void myThrow(const char *error)
|
||||
{
|
||||
throw error;
|
||||
}
|
||||
|
||||
int g13()
|
||||
{
|
||||
myThrow("fail"); // GOOD
|
||||
}
|
||||
|
||||
int g14(int x)
|
||||
{
|
||||
if (x < 10)
|
||||
{
|
||||
myThrow("fail"); // BAD (doesn't always throw)
|
||||
}
|
||||
}
|
||||
|
||||
int g15(int x)
|
||||
{
|
||||
if (x < 10)
|
||||
{
|
||||
return x;
|
||||
} else {
|
||||
myThrow("fail"); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void myConditionalThrow(bool condition, const char *error)
|
||||
{
|
||||
if (condition)
|
||||
{
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
int g16(int x)
|
||||
{
|
||||
myConditionalThrow(x < 10, "fail"); // BAD (doesn't always throw)
|
||||
}
|
||||
|
||||
int g17(int x)
|
||||
{
|
||||
try
|
||||
{
|
||||
myConditionalThrow(x < 10, "fail");
|
||||
} catch (...) {
|
||||
return x; // BAD (doesn't always reach this return)
|
||||
}
|
||||
}
|
||||
|
||||
int g18(int x)
|
||||
{
|
||||
try
|
||||
{
|
||||
myThrow("fail");
|
||||
} catch (...) {
|
||||
return x; // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
int g19(int x)
|
||||
{
|
||||
try
|
||||
{
|
||||
myThrow("fail");
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
return x; // GOOD
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
| f | false | 210 | 210 | try { ... } |
|
||||
| f | false | 212 | 212 | return ... |
|
||||
| f | false | 214 | 214 | { ... } |
|
||||
| f | true | 157 | 166 | |
|
||||
| f | true | 159 | 157 | |
|
||||
| f | true | 163 | 164 | |
|
||||
| f | true | 164 | 183 | |
|
||||
|
||||
@@ -33,6 +33,8 @@ namespace Semmle.Extraction.Tests
|
||||
FileExistsIn.Add(file);
|
||||
if (FileExists.TryGetValue(file, out var ret))
|
||||
return ret;
|
||||
if (FileExists.TryGetValue(System.IO.Path.GetFileName(file), out ret))
|
||||
return ret;
|
||||
throw new ArgumentException("Missing FileExists " + file);
|
||||
}
|
||||
|
||||
|
||||
@@ -399,14 +399,6 @@ namespace Semmle.Extraction.CSharp
|
||||
/// </summary>
|
||||
public int TotalErrors => CompilationErrors + ExtractorErrors;
|
||||
|
||||
void AppendQuoted(StringBuilder sb, string s)
|
||||
{
|
||||
if (s.IndexOf(' ') != -1)
|
||||
sb.Append('\"').Append(s).Append('\"');
|
||||
else
|
||||
sb.Append(s);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs detailed information about this invocation,
|
||||
/// in the event that errors were detected.
|
||||
@@ -414,36 +406,23 @@ namespace Semmle.Extraction.CSharp
|
||||
/// <param name="roslynArgs">The arguments passed to Roslyn.</param>
|
||||
public void LogDiagnostics(string[] roslynArgs)
|
||||
{
|
||||
Logger.Log(Severity.Info, " Current working directory: {0}", Directory.GetCurrentDirectory());
|
||||
Logger.Log(Severity.Info, " Extractor: {0}", Environment.GetCommandLineArgs().First());
|
||||
if (extractor != null)
|
||||
Logger.Log(Severity.Info, " Extractor version: {0}", extractor.Version);
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(" Expanded command line: ");
|
||||
bool first = true;
|
||||
foreach (var arg in Environment.GetCommandLineArgs().Skip(1))
|
||||
{
|
||||
if (arg[0] == '@')
|
||||
{
|
||||
foreach (var line in File.ReadAllLines(arg.Substring(1)))
|
||||
{
|
||||
if (first) first = false;
|
||||
else sb.Append(" ");
|
||||
sb.Append(line);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first) first = false;
|
||||
else sb.Append(" ");
|
||||
AppendQuoted(sb, arg);
|
||||
}
|
||||
}
|
||||
Logger.Log(Severity.Info, sb.ToString());
|
||||
|
||||
Logger.Log(Severity.Info, " Current working directory: {0}", Directory.GetCurrentDirectory());
|
||||
|
||||
if (roslynArgs != null)
|
||||
{
|
||||
Logger.Log(Severity.Info, $" Arguments to Roslyn: {string.Join(' ', roslynArgs)}");
|
||||
|
||||
// Create a new file in the log folder.
|
||||
var argsFile = Path.Combine(Extractor.GetCSharpLogDirectory(), $"csharp.{Path.GetRandomFileName()}.txt");
|
||||
|
||||
if (roslynArgs.ArchiveCommandLine(argsFile))
|
||||
Logger.Log(Severity.Info, $" Arguments have been written to {argsFile}");
|
||||
}
|
||||
|
||||
foreach (var error in FilteredDiagnostics)
|
||||
{
|
||||
Logger.Log(Severity.Error, " Compilation error: {0}", error);
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace Semmle.Extraction.CSharp
|
||||
/// <returns>Modified list of arguments.</returns>
|
||||
static IEnumerable<string> AddDefaultResponse(string responseFile, IEnumerable<string> args)
|
||||
{
|
||||
return SuppressDefaultResponseFile(args) && File.Exists(responseFile) ?
|
||||
return SuppressDefaultResponseFile(args) || !File.Exists(responseFile) ?
|
||||
args :
|
||||
new[] { "@" + responseFile }.Concat(args);
|
||||
}
|
||||
|
||||
@@ -34,8 +34,11 @@ namespace Semmle.Extraction.CSharp
|
||||
|
||||
public void Analysed(int item, int total, string source, string output, TimeSpan time, AnalysisAction action)
|
||||
{
|
||||
Logger.Log(Severity.Info, " {0} -> {1} ({2})", source, output,
|
||||
action == AnalysisAction.Extracted ? time.ToString() : action == AnalysisAction.Excluded ? "excluded" : "up to date");
|
||||
if (action != AnalysisAction.UpToDate)
|
||||
{
|
||||
Logger.Log(Severity.Info, " {0} ({1})", source,
|
||||
action == AnalysisAction.Extracted ? time.ToString() : action == AnalysisAction.Excluded ? "excluded" : "up to date");
|
||||
}
|
||||
}
|
||||
|
||||
public void MissingNamespace(string @namespace) { }
|
||||
@@ -361,27 +364,28 @@ namespace Semmle.Extraction.CSharp
|
||||
/// <summary>
|
||||
/// Gets the path to the `csharp.log` file written to by the C# extractor.
|
||||
/// </summary>
|
||||
public static string GetCSharpLogPath()
|
||||
public static string GetCSharpLogPath() =>
|
||||
Path.Combine(GetCSharpLogDirectory(), "csharp.log");
|
||||
|
||||
public static string GetCSharpLogDirectory()
|
||||
{
|
||||
string snapshot = Environment.GetEnvironmentVariable("ODASA_SNAPSHOT");
|
||||
string buildErrorDir = Environment.GetEnvironmentVariable("ODASA_BUILD_ERROR_DIR");
|
||||
string traps = Environment.GetEnvironmentVariable("TRAP_FOLDER");
|
||||
string output = "csharp.log";
|
||||
if (!string.IsNullOrEmpty(snapshot))
|
||||
{
|
||||
snapshot = Path.Combine(snapshot, "log");
|
||||
return Path.Combine(snapshot, output);
|
||||
return Path.Combine(snapshot, "log");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(buildErrorDir))
|
||||
{
|
||||
// Used by `qltest`
|
||||
return Path.Combine(buildErrorDir, output);
|
||||
return buildErrorDir;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(traps))
|
||||
{
|
||||
return Path.Combine(traps, output);
|
||||
return traps;
|
||||
}
|
||||
return output;
|
||||
return Directory.GetCurrentDirectory();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using Xunit;
|
||||
using Semmle.Util.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Extraction.Tests
|
||||
{
|
||||
@@ -184,5 +186,24 @@ namespace Semmle.Extraction.Tests
|
||||
options = CSharp.Options.CreateWithEnvironment(new string[] {});
|
||||
Assert.True(options.Fast);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArchiveArguments()
|
||||
{
|
||||
var file1 = Path.GetTempFileName();
|
||||
var file2 = Path.GetTempFileName();
|
||||
|
||||
try
|
||||
{
|
||||
File.AppendAllText(file1, "Test");
|
||||
new string[] { "/noconfig", "@" + file1 }.ArchiveCommandLine(file2);
|
||||
Assert.Equal("Test", File.ReadAllText(file2));
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(file1);
|
||||
File.Delete(file2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,5 +14,7 @@ namespace Semmle.Extraction
|
||||
public ISymbol symbol;
|
||||
public SyntaxNode node;
|
||||
public Exception exception;
|
||||
|
||||
public override string ToString() => message;
|
||||
}
|
||||
}
|
||||
|
||||
26
csharp/extractor/Semmle.Util/CommandLineExtensions.cs
Normal file
26
csharp/extractor/Semmle.Util/CommandLineExtensions.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Util
|
||||
{
|
||||
public static class CommandLineExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Archives the first "@" argument in a list of command line arguments.
|
||||
/// Subsequent "@" arguments are ignored.
|
||||
/// </summary>
|
||||
/// <param name="commandLineArguments">The raw command line arguments.</param>
|
||||
/// <param name="filename">The full filename to write to.</param>
|
||||
/// <returns>True iff the file was written.</returns>
|
||||
public static bool ArchiveCommandLine(this IEnumerable<string> commandLineArguments, string filename)
|
||||
{
|
||||
foreach (var arg in commandLineArguments.Where(arg => arg[0] == '@').Select(arg => arg.Substring(1)))
|
||||
{
|
||||
File.Copy(arg, filename, true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ cat > "$BASEDIR/reformat.vim" <<"EOF"
|
||||
:wq
|
||||
EOF
|
||||
|
||||
find "$BASEDIR" \( -name "*.ql" -or -name "*.qll" -or -name "*.csv" \) -exec vim -u /dev/null -s reformat.vim {} \;
|
||||
find "$BASEDIR" \( -name "*.ql" -or -name "*.qll" -or -name "*.csv" -or -name "*.config" \) -exec vim -u /dev/null -s reformat.vim {} \;
|
||||
|
||||
cat > reformat.vim <<"EOF"
|
||||
:set ff=unix ts=4 et
|
||||
|
||||
@@ -6,36 +6,35 @@
|
||||
|
||||
<appSettings>
|
||||
<add key="service-dir" value="/opt/deki/bin" />
|
||||
<add key="root-uri" value="http://localhost/@api" />
|
||||
<add key="root-uri" value="http://localhost/@api" />
|
||||
<add key="apikey" value="12345" />
|
||||
<add key="script" value="/opt/deki/bin/mindtouch.deki.startup.xml" />
|
||||
</appSettings>
|
||||
|
||||
|
||||
<connectionStrings>
|
||||
<add name="connectionstring" providerName="System.Data.SqlClient"
|
||||
connectionString="Server=(local);Database=admtest;Trusted_Connection=False;uid=sa;pwd= ;" /> <!-- VIOLATION -->
|
||||
<add name="connectionstring2" providerName="System.Data.SqlClient"
|
||||
connectionString="Server=(local);Database=admtest;Trusted_Connection=False;uid=sa;password = whatever;" /> <!-- NON-VIOLATION -->
|
||||
</connectionStrings>
|
||||
<add name="connectionstring" providerName="System.Data.SqlClient"
|
||||
connectionString="Server=(local);Database=admtest;Trusted_Connection=False;uid=sa;pwd= ;" /> <!-- VIOLATION -->
|
||||
<add name="connectionstring2" providerName="System.Data.SqlClient"
|
||||
connectionString="Server=(local);Database=admtest;Trusted_Connection=False;uid=sa;password = whatever;" /> <!-- NON-VIOLATION -->
|
||||
</connectionStrings>
|
||||
|
||||
<system.web>
|
||||
<httpHandlers>
|
||||
<add verb="*" path="*"
|
||||
type="MindTouch.Dream.Http.HttpHandler, mindtouch.core"/>
|
||||
<add verb="*" path="*"
|
||||
type="MindTouch.Dream.Http.HttpHandler, mindtouch.core"/>
|
||||
</httpHandlers>
|
||||
<!--<customErrors mode="Off"/>-->
|
||||
<authentication mode="Windows|Forms|Passport|None">
|
||||
<forms name="name"
|
||||
loginUrl="url"
|
||||
protection="All|None|Encryption|Validation"
|
||||
timeout="30" path="/" >
|
||||
<credentials passwordFormat="Clear|SHA1|MD5">
|
||||
<user name="username" password="" /> <!-- VIOLATION -->
|
||||
</credentials>
|
||||
</forms>
|
||||
<passport redirectUrl="internal"/>
|
||||
</authentication>
|
||||
|
||||
<!--<customErrors mode="Off"/>-->
|
||||
<authentication mode="Windows|Forms|Passport|None">
|
||||
<forms name="name"
|
||||
loginUrl="url"
|
||||
protection="All|None|Encryption|Validation"
|
||||
timeout="30" path="/" >
|
||||
<credentials passwordFormat="Clear|SHA1|MD5">
|
||||
<user name="username" password="" /> <!-- VIOLATION -->
|
||||
</credentials>
|
||||
</forms>
|
||||
<passport redirectUrl="internal"/>
|
||||
</authentication>
|
||||
</system.web>
|
||||
|
||||
<system.net>
|
||||
|
||||
@@ -6,36 +6,35 @@
|
||||
|
||||
<appSettings>
|
||||
<add key="service-dir" value="/opt/deki/bin" />
|
||||
<add key="root-uri" value="http://localhost/@api" />
|
||||
<add key="root-uri" value="http://localhost/@api" />
|
||||
<add key="apikey" value="12345" />
|
||||
<add key="script" value="/opt/deki/bin/mindtouch.deki.startup.xml" />
|
||||
</appSettings>
|
||||
|
||||
|
||||
<connectionStrings>
|
||||
<add name="connectionstring" providerName="System.Data.SqlClient"
|
||||
connectionString="Server=(local);Database=admtest;Trusted_Connection=False;uid=sa;pwd=whatever;" /> <!-- VIOLATION -->
|
||||
<add name="connectionstring2" providerName="System.Data.SqlClient"
|
||||
connectionString="Server=(local);Database=admtest;Trusted_Connection=False;uid=sa;password = whatever;" /> <!-- VIOLATION -->
|
||||
</connectionStrings>
|
||||
<add name="connectionstring" providerName="System.Data.SqlClient"
|
||||
connectionString="Server=(local);Database=admtest;Trusted_Connection=False;uid=sa;pwd=whatever;" /> <!-- VIOLATION -->
|
||||
<add name="connectionstring2" providerName="System.Data.SqlClient"
|
||||
connectionString="Server=(local);Database=admtest;Trusted_Connection=False;uid=sa;password = whatever;" /> <!-- VIOLATION -->
|
||||
</connectionStrings>
|
||||
|
||||
<system.web>
|
||||
<httpHandlers>
|
||||
<add verb="*" path="*"
|
||||
type="MindTouch.Dream.Http.HttpHandler, mindtouch.core"/>
|
||||
<add verb="*" path="*"
|
||||
type="MindTouch.Dream.Http.HttpHandler, mindtouch.core"/>
|
||||
</httpHandlers>
|
||||
<!--<customErrors mode="Off"/>-->
|
||||
<authentication mode="Windows|Forms|Passport|None">
|
||||
<forms name="name"
|
||||
loginUrl="url"
|
||||
protection="All|None|Encryption|Validation"
|
||||
timeout="30" path="/" >
|
||||
<credentials passwordFormat="Clear|SHA1|MD5">
|
||||
<user name="username" password="password" /> <!-- VIOLATION -->
|
||||
</credentials>
|
||||
</forms>
|
||||
<passport redirectUrl="internal"/>
|
||||
</authentication>
|
||||
|
||||
<!--<customErrors mode="Off"/>-->
|
||||
<authentication mode="Windows|Forms|Passport|None">
|
||||
<forms name="name"
|
||||
loginUrl="url"
|
||||
protection="All|None|Encryption|Validation"
|
||||
timeout="30" path="/" >
|
||||
<credentials passwordFormat="Clear|SHA1|MD5">
|
||||
<user name="username" password="password" /> <!-- VIOLATION -->
|
||||
</credentials>
|
||||
</forms>
|
||||
<passport redirectUrl="internal"/>
|
||||
</authentication>
|
||||
</system.web>
|
||||
|
||||
<system.net>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.commons.StructuralComparison
|
||||
import semmle.code.csharp.controlflow.Guards
|
||||
import semmle.code.csharp.controlflow.Guards as G
|
||||
|
||||
class SameElement extends StructuralComparisonConfiguration
|
||||
{
|
||||
@@ -22,7 +22,7 @@ class SameElement extends StructuralComparisonConfiguration
|
||||
exists(MethodCall mc, IndexerRead access |
|
||||
mc.getTarget().hasName("ContainsKey")
|
||||
and
|
||||
access.getQualifier().(GuardedExpr).isGuardedBy(mc, mc.getQualifier(), _)
|
||||
access.getQualifier().(G::GuardedExpr).isGuardedBy(mc, mc.getQualifier(), _)
|
||||
and
|
||||
e1 = mc.getArgument(0)
|
||||
and
|
||||
|
||||
@@ -16,4 +16,4 @@ import semmle.code.csharp.security.dataflow.ZipSlip::ZipSlip
|
||||
|
||||
from TaintTrackingConfiguration zipTaintTracking, DataFlow::Node source, DataFlow::Node sink
|
||||
where zipTaintTracking.hasFlow(source, sink)
|
||||
select sink, "Unsanitized zip archive $@, which may contain '..', is used in a file system operation.", source, "item path"
|
||||
select sink, "Unsanitized zip archive $@, which may contain '..', is used in a file system operation.", source, "item path"
|
||||
|
||||
@@ -9,4 +9,4 @@ class Bad
|
||||
string destFileName = Path.Combine(destDirectory, entry.FullName);
|
||||
entry.ExtractToFile(destFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
...
|
||||
</customErrors>
|
||||
</system.web>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
...
|
||||
</customErrors>
|
||||
</system.web>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
</customHeaders>
|
||||
</httpProtocol>
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<system.web>
|
||||
<authentication>
|
||||
<forms
|
||||
requireSSL="true"
|
||||
requireSSL="true"
|
||||
... />
|
||||
</authentication>
|
||||
<httpCookies
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
/**
|
||||
* Generates C# stubs for use in test code.
|
||||
*
|
||||
* Extend the abstract class `GeneratedDeclaration` with the declarations that should be generated.
|
||||
* This will generate stubs for all the required dependencies as well.
|
||||
*
|
||||
*
|
||||
* Use
|
||||
* ```
|
||||
* select generatedCode()
|
||||
@@ -104,7 +104,7 @@ private abstract class GeneratedType extends ValueOrRefType, GeneratedElement {
|
||||
result = this.stubComment() +
|
||||
this.stubAttributes() +
|
||||
this.stubAbstractModifier() +
|
||||
this.stubStaticModifier() +
|
||||
this.stubStaticModifier() +
|
||||
this.stubAccessibilityModifier() +
|
||||
this.stubKeyword() + " " +
|
||||
this.getUndecoratedName() +
|
||||
|
||||
@@ -183,54 +183,16 @@ class AssignableWrite extends AssignableAccess {
|
||||
}
|
||||
}
|
||||
|
||||
private cached module AssignableDefinitionImpl {
|
||||
cached newtype TAssignableDefinition =
|
||||
TAssignmentDefinition(Assignment a) {
|
||||
not a.getLValue() instanceof TupleExpr
|
||||
}
|
||||
or
|
||||
TTupleAssignmentDefinition(AssignExpr ae, Expr leaf) {
|
||||
exists(TupleExpr te |
|
||||
ae.getLValue() = te and
|
||||
te.getAnArgument+() = leaf and
|
||||
// `leaf` is either an assignable access or a local variable declaration
|
||||
not leaf instanceof TupleExpr
|
||||
)
|
||||
}
|
||||
or
|
||||
TOutRefDefinition(AssignableAccess aa) {
|
||||
aa.isOutArgument()
|
||||
or
|
||||
isRelevantRefCall(_, aa)
|
||||
}
|
||||
or
|
||||
TMutationDefinition(MutatorOperation mo)
|
||||
or
|
||||
TLocalVariableDefinition(LocalVariableDeclExpr lvde) {
|
||||
not lvde.hasInitializer() and
|
||||
not exists(getTupleSource(TTupleAssignmentDefinition(_, lvde))) and
|
||||
not lvde = any(IsPatternExpr ipe).getVariableDeclExpr() and
|
||||
not lvde = any(TypeCase tc).getVariableDeclExpr()
|
||||
}
|
||||
or
|
||||
TImplicitParameterDefinition(Parameter p) {
|
||||
exists(Callable c |
|
||||
p = c.getAParameter() |
|
||||
c.hasBody() or
|
||||
c.(Constructor).hasInitializer()
|
||||
)
|
||||
}
|
||||
or
|
||||
TAddressOfDefinition(AddressOfExpr aoe)
|
||||
or
|
||||
TIsPatternDefinition(IsPatternExpr ipe)
|
||||
or
|
||||
TTypeCasePatternDefinition(TypeCase tc)
|
||||
or
|
||||
TInitializer(Assignable a, Expr e) {
|
||||
e = a.(Field).getInitializer() or
|
||||
e = a.(Property).getInitializer()
|
||||
}
|
||||
/** INTERNAL: Do not use. */
|
||||
module AssignableInternal {
|
||||
private predicate tupleAssignmentDefinition(AssignExpr ae, Expr leaf) {
|
||||
exists(TupleExpr te |
|
||||
ae.getLValue() = te and
|
||||
te.getAnArgument+() = leaf and
|
||||
// `leaf` is either an assignable access or a local variable declaration
|
||||
not leaf instanceof TupleExpr
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `ae` is a tuple assignment, and `left` is a sub expression
|
||||
@@ -238,7 +200,7 @@ private cached module AssignableDefinitionImpl {
|
||||
* right-hand side `right`.
|
||||
*/
|
||||
private predicate tupleAssignmentPair(AssignExpr ae, Expr left, Expr right) {
|
||||
exists(TTupleAssignmentDefinition(ae, _)) and
|
||||
tupleAssignmentDefinition(ae, _) and
|
||||
left = ae.getLValue() and
|
||||
right = ae.getRValue()
|
||||
or
|
||||
@@ -249,16 +211,6 @@ private cached module AssignableDefinitionImpl {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source expression assigned in tuple definition `def`, if any.
|
||||
*/
|
||||
cached Expr getTupleSource(TTupleAssignmentDefinition def) {
|
||||
exists(AssignExpr ae, Expr leaf |
|
||||
def = TTupleAssignmentDefinition(ae, leaf) |
|
||||
tupleAssignmentPair(ae, leaf, result)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `ref` assignment to `aa` via call `c` is relevant.
|
||||
*/
|
||||
@@ -341,19 +293,6 @@ private cached module AssignableDefinitionImpl {
|
||||
not result = TImplicitParameterDefinition(_)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `ref` assignment to `aa` via call `c` is uncertain.
|
||||
*/
|
||||
cached predicate isUncertainRefCall(Call c, AssignableAccess aa) {
|
||||
isRelevantRefCall(c, aa)
|
||||
and
|
||||
exists(ControlFlow::BasicBlock bb, Parameter p |
|
||||
isAnalyzableRefCall(c, aa, p) |
|
||||
parameterReachesWithoutDef(p, bb) and
|
||||
bb.getLastNode() = p.getCallable().getExitPoint()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `p` is an analyzable `ref` parameter and there is a path from the
|
||||
* entry point of `p`'s callable to basic block `bb` without passing through
|
||||
@@ -378,51 +317,137 @@ private cached module AssignableDefinitionImpl {
|
||||
bb.getANode() = getAnAnalyzableRefDef(_, _, p).getAControlFlowNode()
|
||||
}
|
||||
|
||||
// Not defined by dispatch in order to avoid too conservative negative recursion error
|
||||
cached Assignable getTarget(AssignableDefinition def) {
|
||||
result = def.getTargetAccess().getTarget()
|
||||
or
|
||||
exists(Expr leaf |
|
||||
def = TTupleAssignmentDefinition(_, leaf) |
|
||||
result = leaf.(LocalVariableDeclExpr).getVariable()
|
||||
)
|
||||
or
|
||||
def = any(AssignableDefinitions::ImplicitParameterDefinition p |
|
||||
result = p.getParameter()
|
||||
)
|
||||
or
|
||||
def = any(AssignableDefinitions::LocalVariableDefinition decl |
|
||||
result = decl.getDeclaration().getVariable()
|
||||
)
|
||||
or
|
||||
def = any(AssignableDefinitions::IsPatternDefinition is |
|
||||
result = is.getDeclaration().getVariable()
|
||||
)
|
||||
or
|
||||
def = any(AssignableDefinitions::TypeCasePatternDefinition case |
|
||||
result = case.getDeclaration().getVariable()
|
||||
)
|
||||
or
|
||||
def = any(AssignableDefinitions::InitializerDefinition init |
|
||||
result = init.getAssignable()
|
||||
)
|
||||
}
|
||||
private cached module Cached {
|
||||
cached newtype TAssignableDefinition =
|
||||
TAssignmentDefinition(Assignment a) {
|
||||
not a.getLValue() instanceof TupleExpr
|
||||
}
|
||||
or
|
||||
TTupleAssignmentDefinition(AssignExpr ae, Expr leaf) {
|
||||
tupleAssignmentDefinition(ae, leaf)
|
||||
}
|
||||
or
|
||||
TOutRefDefinition(AssignableAccess aa) {
|
||||
aa.isOutArgument()
|
||||
or
|
||||
isRelevantRefCall(_, aa)
|
||||
}
|
||||
or
|
||||
TMutationDefinition(MutatorOperation mo)
|
||||
or
|
||||
TLocalVariableDefinition(LocalVariableDeclExpr lvde) {
|
||||
not lvde.hasInitializer() and
|
||||
not exists(getTupleSource(TTupleAssignmentDefinition(_, lvde))) and
|
||||
not lvde = any(IsPatternExpr ipe).getVariableDeclExpr() and
|
||||
not lvde = any(TypeCase tc).getVariableDeclExpr()
|
||||
}
|
||||
or
|
||||
TImplicitParameterDefinition(Parameter p) {
|
||||
exists(Callable c |
|
||||
p = c.getAParameter() |
|
||||
c.hasBody() or
|
||||
c.(Constructor).hasInitializer()
|
||||
)
|
||||
}
|
||||
or
|
||||
TAddressOfDefinition(AddressOfExpr aoe)
|
||||
or
|
||||
TIsPatternDefinition(IsPatternExpr ipe)
|
||||
or
|
||||
TTypeCasePatternDefinition(TypeCase tc)
|
||||
or
|
||||
TInitializer(Assignable a, Expr e) {
|
||||
e = a.(Field).getInitializer() or
|
||||
e = a.(Property).getInitializer()
|
||||
}
|
||||
|
||||
// Not defined by dispatch in order to avoid too conservative negative recursion error
|
||||
cached AssignableAccess getTargetAccess(AssignableDefinition def) {
|
||||
def = TAssignmentDefinition(any(Assignment a | a.getLValue() = result))
|
||||
or
|
||||
def = TTupleAssignmentDefinition(_, result)
|
||||
or
|
||||
def = TOutRefDefinition(result)
|
||||
or
|
||||
def = TMutationDefinition(any(MutatorOperation mo | mo.getOperand() = result))
|
||||
or
|
||||
def = TAddressOfDefinition(any(AddressOfExpr aoe | aoe.getOperand() = result))
|
||||
/**
|
||||
* Gets the source expression assigned in tuple definition `def`, if any.
|
||||
*/
|
||||
cached Expr getTupleSource(TTupleAssignmentDefinition def) {
|
||||
exists(AssignExpr ae, Expr leaf |
|
||||
def = TTupleAssignmentDefinition(ae, leaf) |
|
||||
tupleAssignmentPair(ae, leaf, result)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `ref` assignment to `aa` via call `c` is uncertain.
|
||||
*/
|
||||
cached predicate isUncertainRefCall(Call c, AssignableAccess aa) {
|
||||
isRelevantRefCall(c, aa)
|
||||
and
|
||||
exists(ControlFlow::BasicBlock bb, Parameter p |
|
||||
isAnalyzableRefCall(c, aa, p) |
|
||||
parameterReachesWithoutDef(p, bb) and
|
||||
bb.getLastNode() = p.getCallable().getExitPoint()
|
||||
)
|
||||
}
|
||||
|
||||
// Not defined by dispatch in order to avoid too conservative negative recursion error
|
||||
cached Assignable getTarget(AssignableDefinition def) {
|
||||
result = def.getTargetAccess().getTarget()
|
||||
or
|
||||
exists(Expr leaf |
|
||||
def = TTupleAssignmentDefinition(_, leaf) |
|
||||
result = leaf.(LocalVariableDeclExpr).getVariable()
|
||||
)
|
||||
or
|
||||
def = any(AssignableDefinitions::ImplicitParameterDefinition p |
|
||||
result = p.getParameter()
|
||||
)
|
||||
or
|
||||
def = any(AssignableDefinitions::LocalVariableDefinition decl |
|
||||
result = decl.getDeclaration().getVariable()
|
||||
)
|
||||
or
|
||||
def = any(AssignableDefinitions::IsPatternDefinition is |
|
||||
result = is.getDeclaration().getVariable()
|
||||
)
|
||||
or
|
||||
def = any(AssignableDefinitions::TypeCasePatternDefinition case |
|
||||
result = case.getDeclaration().getVariable()
|
||||
)
|
||||
or
|
||||
def = any(AssignableDefinitions::InitializerDefinition init |
|
||||
result = init.getAssignable()
|
||||
)
|
||||
}
|
||||
|
||||
// Not defined by dispatch in order to avoid too conservative negative recursion error
|
||||
cached AssignableAccess getTargetAccess(AssignableDefinition def) {
|
||||
def = TAssignmentDefinition(any(Assignment a | a.getLValue() = result))
|
||||
or
|
||||
def = TTupleAssignmentDefinition(_, result)
|
||||
or
|
||||
def = TOutRefDefinition(result)
|
||||
or
|
||||
def = TMutationDefinition(any(MutatorOperation mo | mo.getOperand() = result))
|
||||
or
|
||||
def = TAddressOfDefinition(any(AddressOfExpr aoe | aoe.getOperand() = result))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the argument for the implicit `value` parameter in the accessor call
|
||||
* `ac`, if any.
|
||||
*/
|
||||
cached Expr getAccessorCallValueArgument(AccessorCall ac) {
|
||||
exists(AssignExpr ae |
|
||||
tupleAssignmentDefinition(ae, ac) |
|
||||
tupleAssignmentPair(ae, ac, result)
|
||||
)
|
||||
or
|
||||
exists(Assignment a |
|
||||
ac = a.getLValue() |
|
||||
result = a.getRValue() and
|
||||
not a.(AssignOperation).hasExpandedAssignment()
|
||||
)
|
||||
}
|
||||
}
|
||||
import Cached
|
||||
}
|
||||
|
||||
private import AssignableDefinitionImpl
|
||||
private import AssignableInternal
|
||||
|
||||
/**
|
||||
* An assignable definition.
|
||||
|
||||
@@ -144,7 +144,7 @@ class ForwarderAssertMethod extends AssertMethod {
|
||||
override ExceptionClass getExceptionClass() {
|
||||
result = this.getUnderlyingAssertMethod().getExceptionClass()
|
||||
}
|
||||
|
||||
|
||||
/** Gets the underlying assertion method that is being forwarded to. */
|
||||
AssertMethod getUnderlyingAssertMethod() { result = a.getAssertMethod() }
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ abstract class StructuralComparisonConfiguration extends string {
|
||||
*/
|
||||
module Internal {
|
||||
// Import all uses of the internal library to make sure caching works
|
||||
private import semmle.code.csharp.controlflow.Guards
|
||||
private import semmle.code.csharp.controlflow.Guards as G
|
||||
|
||||
/**
|
||||
* A configuration for performing structural comparisons of program elements
|
||||
|
||||
@@ -524,6 +524,7 @@ class ConditionBlock extends BasicBlock {
|
||||
//
|
||||
// In the former case, `x` and `y` control `A`, in the latter case
|
||||
// only `x & y` controls `A` if we do not take sub conditions into account.
|
||||
deprecated
|
||||
predicate controlsSubCond(BasicBlock controlled, boolean testIsTrue, Expr cond, boolean condIsTrue) {
|
||||
impliesSub(getLastNode().getElement(), cond, testIsTrue, condIsTrue) and
|
||||
controls(controlled, any(BooleanSuccessor s | s.getValue() = testIsTrue))
|
||||
@@ -542,6 +543,7 @@ class ConditionBlock extends BasicBlock {
|
||||
* Holds if `e2` is a sub expression of (Boolean) expression `e1`, and
|
||||
* if `e1` has value `b1` then `e2` must have value `b2`.
|
||||
*/
|
||||
deprecated
|
||||
private predicate impliesSub(Expr e1, Expr e2, boolean b1, boolean b2) {
|
||||
if e1 instanceof LogicalNotExpr then (
|
||||
impliesSub(e1.(LogicalNotExpr).getOperand(), e2, b1.booleanNot(), b2)
|
||||
|
||||
@@ -430,12 +430,20 @@ private predicate mustHaveMatchingCompletion(ControlFlowElement cfe) {
|
||||
cfe instanceof SpecificCatchClause
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cfe` is the element inside foreach statement `fs` that has the emptiness
|
||||
* completion.
|
||||
*/
|
||||
predicate foreachEmptiness(ForeachStmt fs, ControlFlowElement cfe) {
|
||||
cfe = fs // use `foreach` statement itself to represent the emptiness test
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a normal completion of `cfe` must be an emptiness completion. Thats is,
|
||||
* whether `cfe` determines whether to execute the body of a `foreach` statement.
|
||||
*/
|
||||
private predicate mustHaveEmptinessCompletion(ControlFlowElement cfe) {
|
||||
cfe instanceof ForeachStmt // use `foreach` statement itself to represent the emptiness test
|
||||
foreachEmptiness(_, cfe)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2593,6 +2593,15 @@ module ControlFlow {
|
||||
this = TPhiPreSsaDef(_, result)
|
||||
}
|
||||
|
||||
LocalScopeVariableRead getARead() {
|
||||
firstReadSameVar(this, result)
|
||||
or
|
||||
exists(LocalScopeVariableRead read |
|
||||
firstReadSameVar(this, read) |
|
||||
adjacentReadPairSameVar+(read, result)
|
||||
)
|
||||
}
|
||||
|
||||
Location getLocation() {
|
||||
exists(AssignableDefinition def |
|
||||
this = TExplicitPreSsaDef(_, _, def, _) |
|
||||
@@ -2720,21 +2729,29 @@ module ControlFlow {
|
||||
ssaRefRank(bb2, i2, v, _) = 1
|
||||
}
|
||||
|
||||
predicate firstReadSameVar(Definition def, LocalScopeVariableRead read) {
|
||||
exists(SimpleLocalScopeVariable v, PreBasicBlock b1, int i1, PreBasicBlock b2, int i2 |
|
||||
adjacentVarRefs(v, b1, i1, b2, i2) and
|
||||
defAt(b1, i1, def, v) and
|
||||
readAt(b2, i2, read, v)
|
||||
)
|
||||
}
|
||||
private cached module PreSsaCached {
|
||||
cached
|
||||
predicate firstReadSameVar(Definition def, LocalScopeVariableRead read) {
|
||||
exists(SimpleLocalScopeVariable v, PreBasicBlock b1, int i1, PreBasicBlock b2, int i2 |
|
||||
adjacentVarRefs(v, b1, i1, b2, i2) and
|
||||
defAt(b1, i1, def, v) and
|
||||
readAt(b2, i2, read, v)
|
||||
)
|
||||
}
|
||||
|
||||
predicate adjacentReadPairSameVar(LocalScopeVariableRead read1, LocalScopeVariableRead read2) {
|
||||
exists(SimpleLocalScopeVariable v, PreBasicBlock bb1, int i1, PreBasicBlock bb2, int i2 |
|
||||
adjacentVarRefs(v, bb1, i1, bb2, i2) and
|
||||
readAt(bb1, i1, read1, v) and
|
||||
readAt(bb2, i2, read2, v)
|
||||
)
|
||||
cached
|
||||
predicate adjacentReadPairSameVar(LocalScopeVariableRead read1, LocalScopeVariableRead read2) {
|
||||
exists(SimpleLocalScopeVariable v, PreBasicBlock bb1, int i1, PreBasicBlock bb2, int i2 |
|
||||
adjacentVarRefs(v, bb1, i1, bb2, i2) and
|
||||
readAt(bb1, i1, read1, v) and
|
||||
readAt(bb2, i2, read2, v)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate forceCachingInSameStage() { any() }
|
||||
}
|
||||
import PreSsaCached
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3327,11 +3344,7 @@ module ControlFlow {
|
||||
* Holds if condition `cb` is a read of the SSA variable in this split.
|
||||
*/
|
||||
private predicate defCondition(ConditionBlock cb) {
|
||||
exists(LocalScopeVariableRead read1, LocalScopeVariableRead read2 |
|
||||
firstReadSameVar(def, read1) |
|
||||
adjacentReadPairSameVar*(read1, read2) and
|
||||
read2 = cb.getLastElement()
|
||||
)
|
||||
cb.getLastElement() = def.getARead()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3827,6 +3840,7 @@ module ControlFlow {
|
||||
cached
|
||||
newtype TPreSsaDef =
|
||||
TExplicitPreSsaDef(PreBasicBlocks::PreBasicBlock bb, int i, AssignableDefinition def, LocalScopeVariable v) {
|
||||
PreSsa::forceCachingInSameStage() and
|
||||
PreSsa::assignableDefAt(bb, i, def, v)
|
||||
}
|
||||
or
|
||||
|
||||
@@ -3,11 +3,273 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import BasicBlocks
|
||||
private import ControlFlow::SuccessorTypes
|
||||
private import semmle.code.csharp.commons.ComparisonTest
|
||||
private import semmle.code.csharp.commons.StructuralComparison::Internal
|
||||
private import semmle.code.csharp.controlflow.BasicBlocks
|
||||
private import semmle.code.csharp.controlflow.Completion
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
|
||||
/** An abstract value. */
|
||||
abstract class AbstractValue extends TAbstractValue {
|
||||
/** Holds if taking the `s` branch out of `cfe` implies that `e` has this value. */
|
||||
abstract predicate branchImplies(ControlFlowElement cfe, ConditionalSuccessor s, Expr e);
|
||||
|
||||
/** Gets a textual representation of this abstract value. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/** Provides different types of `AbstractValues`s. */
|
||||
module AbstractValues {
|
||||
/** A Boolean value. */
|
||||
class BooleanValue extends AbstractValue, TBooleanValue {
|
||||
/** Gets the underlying Boolean value. */
|
||||
boolean getValue() { this = TBooleanValue(result) }
|
||||
|
||||
override predicate branchImplies(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||
s.(BooleanSuccessor).getValue() = this.getValue() and
|
||||
exists(BooleanCompletion c |
|
||||
s.matchesCompletion(c) |
|
||||
c.isValidFor(cfe) and
|
||||
e = cfe
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() { result = this.getValue().toString() }
|
||||
}
|
||||
|
||||
/** A value that is either `null` or non-`null`. */
|
||||
class NullValue extends AbstractValue, TNullValue {
|
||||
/** Holds if this value represents `null`. */
|
||||
predicate isNull() { this = TNullValue(true) }
|
||||
|
||||
override predicate branchImplies(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||
this = TNullValue(s.(NullnessSuccessor).getValue()) and
|
||||
exists(NullnessCompletion c |
|
||||
s.matchesCompletion(c) |
|
||||
c.isValidFor(cfe) and
|
||||
e = cfe
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
if this.isNull() then result = "null" else result = "non-null"
|
||||
}
|
||||
}
|
||||
|
||||
/** A value that represents match or non-match against a specific `case` statement. */
|
||||
class MatchValue extends AbstractValue, TMatchValue {
|
||||
/** Gets the case statement. */
|
||||
CaseStmt getCaseStmt() { this = TMatchValue(result, _) }
|
||||
|
||||
/** Holds if this value represents a match. */
|
||||
predicate isMatch() { this = TMatchValue(_, true) }
|
||||
|
||||
override predicate branchImplies(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||
this = TMatchValue(_, s.(MatchingSuccessor).getValue()) and
|
||||
exists(MatchingCompletion c, SwitchStmt ss, CaseStmt cs |
|
||||
s.matchesCompletion(c) |
|
||||
c.isValidFor(cfe) and
|
||||
switchMatching(ss, cs, cfe) and
|
||||
e = ss.getCondition() and
|
||||
cs = this.getCaseStmt()
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
exists(string s |
|
||||
s = this.getCaseStmt().toString() |
|
||||
if this.isMatch() then result = "match " + s else result = "non-match " + s
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A value that represents an empty or non-empty collection. */
|
||||
class EmptyCollectionValue extends AbstractValue, TEmptyCollectionValue {
|
||||
/** Holds if this value represents an empty collection. */
|
||||
predicate isEmpty() { this = TEmptyCollectionValue(true) }
|
||||
|
||||
override predicate branchImplies(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
|
||||
this = TEmptyCollectionValue(s.(EmptinessSuccessor).getValue()) and
|
||||
exists(EmptinessCompletion c, ForeachStmt fs |
|
||||
s.matchesCompletion(c) |
|
||||
c.isValidFor(cfe) and
|
||||
foreachEmptiness(fs, cfe) and
|
||||
e = fs.getIterableExpr()
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
if this.isEmpty() then result = "empty" else result = "non-empty"
|
||||
}
|
||||
}
|
||||
}
|
||||
private import AbstractValues
|
||||
|
||||
/**
|
||||
* An expression that evaluates to a value that can be dereferenced. That is,
|
||||
* an expression that may evaluate to `null`.
|
||||
*/
|
||||
class DereferenceableExpr extends Expr {
|
||||
DereferenceableExpr() {
|
||||
exists(Expr e, Type t |
|
||||
// There is currently a bug in the extractor: the type of `x?.Length` is
|
||||
// incorrectly `int`, while it should have been `int?`. We apply
|
||||
// `getNullEquivParent()` as a workaround
|
||||
this = getNullEquivParent*(e) and
|
||||
t = e.getType() |
|
||||
t instanceof NullableType
|
||||
or
|
||||
t instanceof RefType
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that directly tests whether this expression is `null`.
|
||||
*
|
||||
* If the returned expression evaluates to `v`, then this expression is
|
||||
* guaranteed to be `null` if `isNull` is true, and non-`null` if `isNull` is
|
||||
* false.
|
||||
*
|
||||
* For example, if the expression `x != null` evaluates to `true` then the
|
||||
* expression `x` is guaranteed to be non-`null`.
|
||||
*/
|
||||
private Expr getABooleanNullCheck(BooleanValue v, boolean isNull) {
|
||||
exists(boolean branch |
|
||||
branch = v.getValue() |
|
||||
// Comparison with `null`, for example `x != null`
|
||||
exists(ComparisonTest ct, ComparisonKind ck, NullLiteral nl |
|
||||
ct.getExpr() = result and
|
||||
ct.getAnArgument() = this and
|
||||
ct.getAnArgument() = nl and
|
||||
this != nl and
|
||||
ck = ct.getComparisonKind() |
|
||||
ck.isEquality() and isNull = branch
|
||||
or
|
||||
ck.isInequality() and isNull = branch.booleanNot()
|
||||
)
|
||||
or
|
||||
// Comparison with a non-`null` value, for example `x?.Length > 0`
|
||||
exists(ComparisonTest ct, ComparisonKind ck, Expr e |
|
||||
ct.getExpr() = result |
|
||||
ct.getAnArgument() = this and
|
||||
ct.getAnArgument() = e and
|
||||
nonNullValue(e) and
|
||||
ck = ct.getComparisonKind() and
|
||||
this != e and
|
||||
isNull = false and
|
||||
if ck.isInequality() then branch = false else branch = true
|
||||
)
|
||||
or
|
||||
// Call to `string.IsNullOrEmpty()`
|
||||
result = any(MethodCall mc |
|
||||
mc.getTarget() = any(SystemStringClass c).getIsNullOrEmptyMethod() and
|
||||
mc.getArgument(0) = this and
|
||||
branch = false and
|
||||
isNull = false
|
||||
)
|
||||
or
|
||||
result = any(IsExpr ie |
|
||||
ie.getExpr() = this and
|
||||
if ie.(IsConstantExpr).getConstant() instanceof NullLiteral then
|
||||
// E.g. `x is null`
|
||||
isNull = branch
|
||||
else
|
||||
// E.g. `x is string` or `x is ""`
|
||||
(branch = true and isNull = false)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that tests via matching whether this expression is `null`.
|
||||
*
|
||||
* If the returned element matches (`v.isMatch()`) or non-matches
|
||||
* (`not v.isMatch()`), then this expression is guaranteed to be `null`
|
||||
* if `isNull` is true, and non-`null` if `isNull` is false.
|
||||
*
|
||||
* For example, if the case statement `case string s` matches in
|
||||
*
|
||||
* ```
|
||||
* switch (o)
|
||||
* {
|
||||
* case string s:
|
||||
* return s;
|
||||
* default:
|
||||
* return "";
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* then `o` is guaranteed to be non-`null`.
|
||||
*/
|
||||
private Expr getAMatchingNullCheck(MatchValue v, boolean isNull) {
|
||||
exists(SwitchStmt ss, CaseStmt cs |
|
||||
cs = v.getCaseStmt() and
|
||||
this = ss.getCondition() and
|
||||
result = this and
|
||||
cs = ss.getACase() |
|
||||
// E.g. `case string`
|
||||
cs instanceof TypeCase and
|
||||
v.isMatch() and
|
||||
isNull = false
|
||||
or
|
||||
cs = any(ConstCase cc |
|
||||
if cc.getExpr() instanceof NullLiteral then
|
||||
// `case null`
|
||||
if v.isMatch() then isNull = true else isNull = false
|
||||
else (
|
||||
// E.g. `case ""`
|
||||
v.isMatch() and
|
||||
isNull = false
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that tests via nullness whether this expression is `null`.
|
||||
*
|
||||
* If the returned expression evaluates to `null` (`v.isNull()`) or evaluates to
|
||||
* non-`null` (`not v.isNull()`), then this expression is guaranteed to be `null`
|
||||
* if `isNull` is true, and non-`null` if `isNull` is false.
|
||||
*
|
||||
* For example, if `x` evaluates to `null` in `x ?? y` then `y` is evaluated, and
|
||||
* `x` is guaranteed to be `null`.
|
||||
*/
|
||||
private Expr getANullnessNullCheck(NullValue v, boolean isNull) {
|
||||
exists(NullnessCompletion c |
|
||||
c.isValidFor(this) |
|
||||
result = this and
|
||||
if c.isNull() then (
|
||||
v.isNull() and
|
||||
isNull = true
|
||||
)
|
||||
else (
|
||||
not v.isNull() and
|
||||
isNull = false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that tests whether this expression is `null`.
|
||||
*
|
||||
* If the returned expression has abstract value `v`, then this expression is
|
||||
* guaranteed to be `null` if `isNull` is true, and non-`null` if `isNull` is
|
||||
* false.
|
||||
*
|
||||
* For example, if the expression `x != null` evaluates to `true` then the
|
||||
* expression `x` is guaranteed to be non-`null`.
|
||||
*/
|
||||
Expr getANullCheck(AbstractValue v, boolean isNull) {
|
||||
result = this.getABooleanNullCheck(v, isNull)
|
||||
or
|
||||
result = this.getAMatchingNullCheck(v, isNull)
|
||||
or
|
||||
result = this.getANullnessNullCheck(v, isNull)
|
||||
}
|
||||
}
|
||||
|
||||
/** An expression that accesses/calls a declaration. */
|
||||
class AccessOrCallExpr extends Expr {
|
||||
private Declaration target;
|
||||
@@ -61,12 +323,11 @@ private AssignableRead getATrackedRead(Ssa::Definition def) {
|
||||
/**
|
||||
* A guarded expression.
|
||||
*
|
||||
* A guarded expression is an access or a call that is reached only
|
||||
* when a conditional containing a structurally equal expression
|
||||
* evaluates to one of `true` or `false`.
|
||||
* A guarded expression is an access or a call that is reached only when another
|
||||
* expression, `e`, has a certain abstract value, where `e` contains a sub
|
||||
* expression that is structurally equal to this expression.
|
||||
*
|
||||
* For example, the property call `x.Field.Property` on line 3 is
|
||||
* guarded in
|
||||
* For example, the property call `x.Field.Property` on line 3 is guarded in
|
||||
*
|
||||
* ```
|
||||
* string M(C x) {
|
||||
@@ -97,234 +358,77 @@ private AssignableRead getATrackedRead(Ssa::Definition def) {
|
||||
* definition).
|
||||
*/
|
||||
class GuardedExpr extends AccessOrCallExpr {
|
||||
private Expr cond0;
|
||||
private AccessOrCallExpr e0;
|
||||
private boolean b0;
|
||||
|
||||
GuardedExpr() {
|
||||
Internal::isGuardedBy(this, cond0, e0, b0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this expression is guarded by expression `cond`, which must
|
||||
* evaluate to `b`. The expression `e` is a sub expression of `cond`
|
||||
* that is structurally equal to this expression.
|
||||
*
|
||||
* In case this expression or `e` accesses an SSA variable in its
|
||||
* left-most qualifier, then so must the other (accessing the same SSA
|
||||
* variable).
|
||||
*/
|
||||
predicate isGuardedBy(Expr cond, Expr e, boolean b) {
|
||||
cond = cond0 and
|
||||
e = e0 and
|
||||
b = b0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A nullness guarded expression.
|
||||
*
|
||||
* A nullness guarded expression is an access or a call that is reached only
|
||||
* when a nullness condition containing a structurally equal expression
|
||||
* evaluates to one of `null` or non-`null`.
|
||||
*
|
||||
* For example, the second access to `x` is only evaluated when `x` is null
|
||||
* in
|
||||
*
|
||||
* ```
|
||||
* string M(string x) => x ?? x;
|
||||
* ```
|
||||
*/
|
||||
class NullnessGuardedExpr extends AccessOrCallExpr {
|
||||
private Expr e0;
|
||||
private boolean isNull0;
|
||||
private AccessOrCallExpr sub0;
|
||||
private AbstractValue v0;
|
||||
|
||||
NullnessGuardedExpr() {
|
||||
Internal::isGuardedByNullness(this, e0, isNull0)
|
||||
GuardedExpr() { isGuardedBy(this, e0, sub0, v0) }
|
||||
|
||||
/**
|
||||
* Gets an expression that guards this expression. That is, this expression is
|
||||
* only reached when the returned expression has abstract value `v`.
|
||||
*
|
||||
* The expression `sub` is a sub expression of the guarding expression that is
|
||||
* structurally equal to this expression.
|
||||
*
|
||||
* In case this expression or `sub` accesses an SSA variable in its
|
||||
* left-most qualifier, then so must the other (accessing the same SSA
|
||||
* variable).
|
||||
*/
|
||||
Expr getAGuard(Expr sub, AbstractValue v) {
|
||||
result = e0 and
|
||||
sub = sub0 and
|
||||
v = v0
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this expression is guarded by expression `cond`, which must
|
||||
* evaluate to `b`. The expression `e` is a sub expression of `cond`
|
||||
* evaluate to `b`. The expression `sub` is a sub expression of `cond`
|
||||
* that is structurally equal to this expression.
|
||||
*
|
||||
* In case this expression or `e` accesses an SSA variable in its
|
||||
* In case this expression or `sub` accesses an SSA variable in its
|
||||
* left-most qualifier, then so must the other (accessing the same SSA
|
||||
* variable).
|
||||
*/
|
||||
predicate isGuardedBy(Expr e, boolean isNull) {
|
||||
e = e0 and
|
||||
isNull = isNull0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A matching guarded expression.
|
||||
*
|
||||
* A matching guarded expression is an access or a call that is reached only
|
||||
* when a pattern, matching against a structurally equal expression, matches
|
||||
* or non-matches.
|
||||
*
|
||||
* For example, the access to `o` on line 8 is only evaluated when `case null`
|
||||
* does not match.
|
||||
*
|
||||
* ```
|
||||
* string M(object o)
|
||||
* {
|
||||
* switch (o)
|
||||
* {
|
||||
* case null:
|
||||
* return "";
|
||||
* default:
|
||||
* return o.ToString();
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class MatchingGuardedExpr extends AccessOrCallExpr {
|
||||
private AccessOrCallExpr e0;
|
||||
private CaseStmt cs0;
|
||||
private boolean isMatch0;
|
||||
|
||||
MatchingGuardedExpr() {
|
||||
Internal::isGuardedByMatching(this, e0, cs0, isMatch0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this expression is guarded by case statement `cs` matching
|
||||
* (`isMatch = true`) or non-matching (`isMatch = false`). The expression
|
||||
* `e` is structurally equal to this expression being matched against in
|
||||
* `cs`.
|
||||
*
|
||||
* In case this expression or `e` accesses an SSA variable in its
|
||||
* left-most qualifier, then so must the other (accessing the same SSA
|
||||
* variable).
|
||||
*/
|
||||
predicate isGuardedBy(AccessOrCallExpr e, CaseStmt cs, boolean isMatch) {
|
||||
e = e0 and
|
||||
cs0 = cs and
|
||||
isMatch0 = isMatch
|
||||
predicate isGuardedBy(Expr cond, Expr sub, boolean b) {
|
||||
cond = this.getAGuard(sub, any(BooleanValue v | v.getValue() = b))
|
||||
}
|
||||
}
|
||||
|
||||
/** An expression guarded by a `null` check. */
|
||||
class NullGuardedExpr extends AccessOrCallExpr {
|
||||
class NullGuardedExpr extends GuardedExpr {
|
||||
NullGuardedExpr() {
|
||||
this.getType() instanceof RefType and
|
||||
exists(Expr cond, Expr sub, boolean b |
|
||||
this.(GuardedExpr).isGuardedBy(cond, sub, b) |
|
||||
// Comparison with `null`, for example `x != null`
|
||||
exists(ComparisonTest ct, ComparisonKind ck |
|
||||
ct.getExpr() = cond and
|
||||
ct.getAnArgument() = Internal::getNullEquivParent*(sub) and
|
||||
ct.getAnArgument() instanceof NullLiteral and
|
||||
ck = ct.getComparisonKind() |
|
||||
ck.isEquality() and b = false
|
||||
or
|
||||
ck.isInequality() and b = true
|
||||
)
|
||||
or
|
||||
// Comparison with a non-`null` value, for example `x?.Length > 0`
|
||||
exists(ComparisonTest ct, ComparisonKind ck, Type t |
|
||||
ct.getExpr() = cond and
|
||||
ct.getAnArgument() = Internal::getNullEquivParent*(sub) and
|
||||
sub.getType() = t and
|
||||
(t instanceof RefType or t instanceof NullableType) and
|
||||
Internal::nonNullValue(ct.getAnArgument()) and
|
||||
ck = ct.getComparisonKind() |
|
||||
if ck.isInequality() then b = false else b = true
|
||||
)
|
||||
or
|
||||
// Call to `string.IsNullOrEmpty()`
|
||||
cond = any(MethodCall mc |
|
||||
mc.getTarget() = any(SystemStringClass c).getIsNullOrEmptyMethod() and
|
||||
mc.getArgument(0) = sub and
|
||||
b = false
|
||||
)
|
||||
or
|
||||
cond = any(IsExpr ie |
|
||||
ie.getExpr() = sub and
|
||||
if ie.(IsConstantExpr).getConstant() instanceof NullLiteral then
|
||||
// E.g. `x is null`
|
||||
b = false
|
||||
else
|
||||
// E.g. `x is string`
|
||||
b = true
|
||||
)
|
||||
)
|
||||
or
|
||||
this.(NullnessGuardedExpr).isGuardedBy(_, false)
|
||||
or
|
||||
exists(CaseStmt cs, boolean isMatch |
|
||||
this.(MatchingGuardedExpr).isGuardedBy(_, cs, isMatch) |
|
||||
// E.g. `case string`
|
||||
cs instanceof TypeCase and
|
||||
isMatch = true
|
||||
or
|
||||
cs = any(ConstCase cc |
|
||||
if cc.getExpr() instanceof NullLiteral then
|
||||
// `case null`
|
||||
isMatch = false
|
||||
else
|
||||
// E.g. `case ""`
|
||||
isMatch = true
|
||||
)
|
||||
)
|
||||
exists(Expr e, NullValue v | e = this.getAGuard(e, v) | not v.isNull())
|
||||
}
|
||||
}
|
||||
|
||||
private module Internal {
|
||||
private import semmle.code.csharp.controlflow.Completion
|
||||
private import ControlFlow::SuccessorTypes
|
||||
/** INTERNAL: Do not use. */
|
||||
module Internal {
|
||||
private import ControlFlow::Internal
|
||||
|
||||
private cached module Cached {
|
||||
cached predicate isGuardedBy(AccessOrCallExpr guarded, Expr cond, AccessOrCallExpr e, boolean b) {
|
||||
exists(BasicBlock bb |
|
||||
controls(cond, e, bb, b) and
|
||||
bb = guarded.getAControlFlowNode().getBasicBlock() and
|
||||
exists(ConditionOnExprComparisonConfig c | c.same(e, guarded)) |
|
||||
not guarded.hasSsaQualifier() and not e.hasSsaQualifier()
|
||||
or
|
||||
guarded.getSsaQualifier() = e.getSsaQualifier()
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate isGuardedByNullness(AccessOrCallExpr guarded, AccessOrCallExpr e, boolean isNull) {
|
||||
exists(BasicBlock bb |
|
||||
controlsNullness(e, bb, isNull) and
|
||||
bb = guarded.getAControlFlowNode().getBasicBlock() and
|
||||
exists(ConditionOnExprComparisonConfig c | c.same(e, guarded)) |
|
||||
not guarded.hasSsaQualifier() and not e.hasSsaQualifier()
|
||||
or
|
||||
guarded.getSsaQualifier() = e.getSsaQualifier()
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate isGuardedByMatching(AccessOrCallExpr guarded, AccessOrCallExpr e, CaseStmt cs, boolean isMatch) {
|
||||
exists(BasicBlock bb |
|
||||
controlsMatching(e, cs, bb, isMatch) and
|
||||
bb = guarded.getAControlFlowNode().getBasicBlock() and
|
||||
exists(ConditionOnExprComparisonConfig c | c.same(e, guarded)) |
|
||||
not guarded.hasSsaQualifier() and not e.hasSsaQualifier()
|
||||
or
|
||||
guarded.getSsaQualifier() = e.getSsaQualifier()
|
||||
)
|
||||
}
|
||||
}
|
||||
import Cached
|
||||
newtype TAbstractValue =
|
||||
TBooleanValue(boolean b) { b = true or b = false }
|
||||
or
|
||||
TNullValue(boolean b) { b = true or b = false }
|
||||
or
|
||||
TMatchValue(CaseStmt cs, boolean b) { b = true or b = false }
|
||||
or
|
||||
TEmptyCollectionValue(boolean b) { b = true or b = false }
|
||||
|
||||
/**
|
||||
* Gets the parent expression of `e` which is `null` iff `e` is null,
|
||||
* Gets the parent expression of `e` which is `null` only if `e` is `null`,
|
||||
* if any. For example, `result = x?.y` and `e = x`, or `result = x + 1`
|
||||
* and `e = x`.
|
||||
*/
|
||||
Expr getNullEquivParent(Expr e) {
|
||||
exists(QualifiableExpr qe |
|
||||
result = qe and
|
||||
result = any(QualifiableExpr qe |
|
||||
qe.getQualifier() = e and
|
||||
qe.isConditional() |
|
||||
qe.(FieldAccess).getTarget().getType() instanceof ValueType or
|
||||
qe.(Call).getTarget().getReturnType() instanceof ValueType
|
||||
qe.isConditional() and
|
||||
(
|
||||
result.(FieldAccess).getTarget().getType() instanceof ValueType
|
||||
or
|
||||
result.(Call).getTarget().getReturnType() instanceof ValueType
|
||||
)
|
||||
)
|
||||
or
|
||||
// In C#, `null + 1` has type `int?` with value `null`
|
||||
@@ -342,41 +446,6 @@ private module Internal {
|
||||
e.stripCasts() = any(Expr s | s.hasValue() and not s instanceof NullLiteral)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if basic block `bb` only is reached when `cond` evaluates to `b`.
|
||||
* SSA qualified expression `e` is a sub expression of `cond`.
|
||||
*/
|
||||
private predicate controls(Expr cond, AccessOrCallExpr e, BasicBlock bb, boolean b) {
|
||||
exists(ConditionBlock cb | cb.controlsSubCond(bb, _, cond, b)) and
|
||||
cond.getAChildExpr*() = e
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if basic block `bb` only is reached when `e` evaluates to `null`
|
||||
* (`isNull = true`) or when `e` evaluates to non-`null` (`isNull = false`).
|
||||
*/
|
||||
private predicate controlsNullness(Expr e, BasicBlock bb, boolean isNull) {
|
||||
exists(ConditionBlock cb, NullnessSuccessor s |
|
||||
cb.controls(bb, s) |
|
||||
isNull = s.getValue() and
|
||||
e = cb.getLastNode().getElement()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if basic block `bb` only is reached when `e` matches case `cs`
|
||||
* (`isMatch = true`) or when `e` does not match `cs` (`isMatch = false`).
|
||||
*/
|
||||
private predicate controlsMatching(Expr e, CaseStmt cs, BasicBlock bb, boolean isMatch) {
|
||||
exists(ConditionBlock cb, SwitchStmt ss, ControlFlowElement cfe, MatchingSuccessor s |
|
||||
cb.controls(bb, s) |
|
||||
cfe = cb.getLastNode().getElement() and
|
||||
switchMatching(ss, cs, cfe) and
|
||||
e = ss.getCondition() and
|
||||
isMatch = s.getValue()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper class for calculating structurally equal access/call expressions.
|
||||
*/
|
||||
@@ -403,13 +472,188 @@ private module Internal {
|
||||
pragma [noinline]
|
||||
private predicate candidateAux(AccessOrCallExpr e, Declaration target, BasicBlock bb) {
|
||||
target = e.getTarget() and
|
||||
(
|
||||
controls(_, e, bb, _)
|
||||
or
|
||||
controlsNullness(e, bb, _)
|
||||
or
|
||||
controlsMatching(e, _, bb, _)
|
||||
)
|
||||
controls(bb, _, e, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if basic block `bb` only is reached when `e` has abstract value `v`.
|
||||
* SSA qualified expression `sub` is a sub expression of `e`.
|
||||
*/
|
||||
private predicate controls(BasicBlock bb, Expr e, AccessOrCallExpr sub, AbstractValue v) {
|
||||
exists(ConditionBlock cb, ConditionalSuccessor s, AbstractValue v0, Expr cond |
|
||||
cb.controls(bb, s) |
|
||||
v0.branchImplies(cb.getLastNode().getElement(), s, cond) and
|
||||
impliesSteps(cond, v0, e, v) and
|
||||
sub = e.getAChildExpr*()
|
||||
)
|
||||
}
|
||||
|
||||
private cached module Cached {
|
||||
cached
|
||||
predicate isGuardedBy(AccessOrCallExpr guarded, Expr e, AccessOrCallExpr sub, AbstractValue v) {
|
||||
exists(BasicBlock bb |
|
||||
controls(bb, e, sub, v) and
|
||||
bb = guarded.getAControlFlowNode().getBasicBlock() and
|
||||
exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded)) |
|
||||
not guarded.hasSsaQualifier() and not sub.hasSsaQualifier()
|
||||
or
|
||||
guarded.getSsaQualifier() = sub.getSsaQualifier()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e1` having abstract value `v1` implies that `e2` has abstract
|
||||
* value `v2, using one step of reasoning.
|
||||
*/
|
||||
cached
|
||||
predicate impliesStep(Expr e1, AbstractValue v1, Expr e2, AbstractValue v2) {
|
||||
exists(BinaryOperation bo |
|
||||
bo instanceof BitwiseAndExpr or
|
||||
bo instanceof LogicalAndExpr
|
||||
|
|
||||
bo = e1 and
|
||||
e2 = bo.getAnOperand() and
|
||||
v1 = TBooleanValue(true) and
|
||||
v2 = v1
|
||||
or
|
||||
bo = e2 and
|
||||
e1 = bo.getAnOperand() and
|
||||
v1 = TBooleanValue(false) and
|
||||
v2 = v1
|
||||
)
|
||||
or
|
||||
exists(BinaryOperation bo |
|
||||
bo instanceof BitwiseOrExpr or
|
||||
bo instanceof LogicalOrExpr
|
||||
|
|
||||
bo = e1 and
|
||||
e2 = bo.getAnOperand() and
|
||||
v1 = TBooleanValue(false) and
|
||||
v2 = v1
|
||||
or
|
||||
bo = e2 and
|
||||
e1 = bo.getAnOperand() and
|
||||
v1 = TBooleanValue(true) and
|
||||
v2 = v1
|
||||
)
|
||||
or
|
||||
e1.(LogicalNotExpr).getOperand() = e2 and
|
||||
v2 = TBooleanValue(v1.(BooleanValue).getValue().booleanNot())
|
||||
or
|
||||
e1 = e2.(LogicalNotExpr).getOperand() and
|
||||
v2 = TBooleanValue(v1.(BooleanValue).getValue().booleanNot())
|
||||
or
|
||||
exists(ComparisonTest ct, boolean polarity, BoolLiteral boolLit, boolean b |
|
||||
ct.getAnArgument() = boolLit and
|
||||
b = boolLit.getBoolValue() and
|
||||
v2 = TBooleanValue(v1.(BooleanValue).getValue().booleanXor(polarity).booleanXor(b)) |
|
||||
ct.getComparisonKind().isEquality() and
|
||||
polarity = true and
|
||||
(
|
||||
// e1 === e2 == b, v1 === !(v2 xor b)
|
||||
e1 = ct.getExpr() and
|
||||
e2 = ct.getAnArgument()
|
||||
or
|
||||
// e2 === e1 == b, v1 === !(v2 xor b)
|
||||
e1 = ct.getAnArgument() and
|
||||
e2 = ct.getExpr()
|
||||
)
|
||||
or
|
||||
ct.getComparisonKind().isInequality() and
|
||||
polarity = false and
|
||||
(
|
||||
// e1 === e2 != b, v1 === v2 xor b
|
||||
e1 = ct.getExpr() and
|
||||
e2 = ct.getAnArgument()
|
||||
or
|
||||
// e2 === e1 != true, v1 === v2 xor b
|
||||
e1 = ct.getAnArgument() and
|
||||
e2 = ct.getExpr()
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(ConditionalExpr cond, boolean branch, BoolLiteral boolLit, boolean b |
|
||||
b = boolLit.getBoolValue() and
|
||||
(
|
||||
cond.getThen() = boolLit and branch = true
|
||||
or
|
||||
cond.getElse() = boolLit and branch = false
|
||||
)
|
||||
|
|
||||
e1 = cond and
|
||||
v1 = TBooleanValue(b.booleanNot()) and
|
||||
(
|
||||
// e1 === e2 ? b : x, v1 === !b, v2 === false; or
|
||||
// e1 === e2 ? x : b, v1 === !b, v2 === true
|
||||
e2 = cond.getCondition() and
|
||||
v2 = TBooleanValue(branch.booleanNot())
|
||||
or
|
||||
// e1 === x ? e2 : b, v1 === !b, v2 === v1
|
||||
e2 = cond.getThen() and
|
||||
branch = false and
|
||||
v2 = v1
|
||||
or
|
||||
// e1 === x ? b : e2, v1 === !b, v2 === v1
|
||||
e2 = cond.getElse() and
|
||||
branch = true and
|
||||
v2 = v1
|
||||
)
|
||||
or
|
||||
// e2 === e1 ? b : x, v1 === true, v2 === b; or
|
||||
// e2 === e1 ? x : b, v1 === false, v2 === b
|
||||
e1 = cond.getCondition() and
|
||||
e2 = cond and
|
||||
v1 = TBooleanValue(branch) and
|
||||
v2 = TBooleanValue(b)
|
||||
)
|
||||
or
|
||||
exists(boolean isNull |
|
||||
v2 = any(NullValue nv | if nv.isNull() then isNull = true else isNull = false) |
|
||||
e1 = e2.(DereferenceableExpr).getANullCheck(v1, isNull) and
|
||||
(e1 != e2 or v1 != v2)
|
||||
)
|
||||
or
|
||||
e1 instanceof DereferenceableExpr and
|
||||
e1 = getNullEquivParent(e2) and
|
||||
v1 instanceof NullValue and
|
||||
v1 = v2
|
||||
}
|
||||
}
|
||||
import Cached
|
||||
|
||||
/**
|
||||
* Holds if `e1` having some abstract value, `v`, implies that `e2` has the same
|
||||
* abstract value `v`.
|
||||
*/
|
||||
predicate impliesStepIdentity(Expr e1, Expr e2) {
|
||||
exists(PreSsa::Definition def |
|
||||
def.getDefinition().getSource() = e2 |
|
||||
e1 = def.getARead()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e1` having abstract value `v1` implies that `e2` has abstract value
|
||||
* `v2, using zero or more steps of reasoning.
|
||||
*/
|
||||
predicate impliesSteps(Expr e1, AbstractValue v1, Expr e2, AbstractValue v2) {
|
||||
e1.getType() instanceof BoolType and
|
||||
e1 = e2 and
|
||||
v1 = v2 and
|
||||
v1 = TBooleanValue(_)
|
||||
or
|
||||
v1.branchImplies(_, _, e1) and
|
||||
e2 = e1 and
|
||||
v2 = v1
|
||||
or
|
||||
exists(Expr mid, AbstractValue vMid |
|
||||
impliesSteps(e1, v1, mid, vMid) |
|
||||
impliesStep(mid, vMid, e2, v2)
|
||||
or
|
||||
impliesStepIdentity(mid, e2) and
|
||||
v2 = vMid
|
||||
)
|
||||
}
|
||||
}
|
||||
private import Internal
|
||||
|
||||
@@ -643,8 +643,7 @@ class PropertyCall extends AccessorCall, PropertyAccessExpr {
|
||||
|
||||
override Expr getArgument(int i) {
|
||||
i = 0 and
|
||||
this instanceof AssignableWrite and
|
||||
exists(Assignment a | a.getLValue() = this and result = a.getRValue())
|
||||
result = AssignableInternal::getAccessorCallValueArgument(this)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
@@ -681,9 +680,8 @@ class IndexerCall extends AccessorCall, IndexerAccessExpr {
|
||||
override Expr getArgument(int i) {
|
||||
result = this.(ElementAccess).getIndex(i)
|
||||
or
|
||||
this instanceof AssignableWrite and
|
||||
i = count(this.(ElementAccess).getAnIndex()) and
|
||||
exists(Assignment a | a.getLValue() = this and result = a.getRValue())
|
||||
result = AssignableInternal::getAccessorCallValueArgument(this)
|
||||
}
|
||||
|
||||
override string toString() { result = IndexerAccessExpr.super.toString() }
|
||||
|
||||
@@ -138,6 +138,10 @@ class SystemXmlSchemaXmlSchemaValidationFlags extends EnumConstant {
|
||||
}
|
||||
}
|
||||
|
||||
private Expr getBitwiseOrOperand(Expr e) {
|
||||
result = e.(BitwiseOrExpr).getAnOperand()
|
||||
}
|
||||
|
||||
/** A creation of an instance of `System.Xml.XmlReaderSettings`. */
|
||||
class XmlReaderSettingsCreation extends ObjectCreation {
|
||||
XmlReaderSettingsCreation() {
|
||||
@@ -157,10 +161,11 @@ class XmlReaderSettingsCreation extends ObjectCreation {
|
||||
/** Gets a value set for the given property in this local context. */
|
||||
private Expr getPropertyValue(Property p) {
|
||||
p = this.getType().(RefType).getAProperty() and
|
||||
exists(PropertyCall set |
|
||||
exists(PropertyCall set, Expr arg |
|
||||
set.getTarget() = p.getSetter() and
|
||||
DataFlow::localFlow(DataFlow::exprNode(this), DataFlow::exprNode(set.getQualifier())) and
|
||||
result = set.getAnArgument()
|
||||
arg = set.getAnArgument() and
|
||||
result = getBitwiseOrOperand*(arg)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ module UrlRedirect {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Anything that is setting "location" header in the response headers.
|
||||
*/
|
||||
@@ -201,12 +201,12 @@ module UrlRedirect {
|
||||
this.getExpr() = add.getArgument(1))
|
||||
or // HttpResponse.Headers["location"] = <user-provided value>
|
||||
exists(RefType cl, MicrosoftAspNetCoreHttpHttpResponse resp, IndexerAccess ci, Call cs, PropertyAccess qualifier |
|
||||
qualifier.getTarget() = resp.getHeadersProperty() and
|
||||
qualifier.getTarget() = resp.getHeadersProperty() and
|
||||
ci.getTarget() = cl.getAnIndexer() and
|
||||
qualifier = ci.getQualifier() and
|
||||
cs.getTarget() = cl.getAnIndexer().getSetter() and
|
||||
cs.getArgument(0).getValue().toLowerCase() = "location" and
|
||||
this.asExpr() = cs.getArgument(1))
|
||||
this.asExpr() = cs.getArgument(1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,8 +526,8 @@ module XSS {
|
||||
this.getExpr() = any(WebPageClass h).getWriteLiteralMethod().getACall().getAnArgument()
|
||||
}
|
||||
|
||||
override string explanation() {
|
||||
result = "System.Web.WebPages.WebPage.WriteLiteral() method"
|
||||
override string explanation() {
|
||||
result = "System.Web.WebPages.WebPage.WriteLiteral() method"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,9 +539,9 @@ module XSS {
|
||||
WebPageWriteLiteralToSink() {
|
||||
this.getExpr() = any(WebPageClass h).getWriteLiteralToMethod().getACall().getAnArgument()
|
||||
}
|
||||
|
||||
override string explanation() {
|
||||
result = "System.Web.WebPages.WebPage.WriteLiteralTo() method"
|
||||
|
||||
override string explanation() {
|
||||
result = "System.Web.WebPages.WebPage.WriteLiteralTo() method"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,9 +555,9 @@ module XSS {
|
||||
MicrosoftAspNetCoreMvcHtmlHelperRawSink() {
|
||||
this.getExpr() = any(MicrosoftAspNetCoreMvcHtmlHelperClass h).getRawMethod().getACall().getAnArgument()
|
||||
}
|
||||
|
||||
override string explanation() {
|
||||
result = "Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.Raw() method"
|
||||
|
||||
override string explanation() {
|
||||
result = "Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.Raw() method"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -569,19 +569,19 @@ module XSS {
|
||||
MicrosoftAspNetRazorPageWriteLiteralSink() {
|
||||
this.getExpr() = any(MicrosoftAspNetCoreMvcRazorPageBase h).getWriteLiteralMethod().getACall().getAnArgument()
|
||||
}
|
||||
|
||||
override string explanation() {
|
||||
result = "Microsoft.AspNetCore.Mvc.Razor.RazorPageBase.WriteLiteral() method"
|
||||
|
||||
override string explanation() {
|
||||
result = "Microsoft.AspNetCore.Mvc.Razor.RazorPageBase.WriteLiteral() method"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* HtmlString that may be rendered as is need to have sanitized value
|
||||
*/
|
||||
class MicrosoftAspNetHtmlStringSink extends AspNetCoreSink {
|
||||
MicrosoftAspNetHtmlStringSink() {
|
||||
exists (ObjectCreation c, MicrosoftAspNetCoreHttpHtmlString s |
|
||||
c.getTarget() = s.getAConstructor() and
|
||||
exists (ObjectCreation c, MicrosoftAspNetCoreHttpHtmlString s |
|
||||
c.getTarget() = s.getAConstructor() and
|
||||
this.asExpr() = c.getAnArgument())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ module ZipSlip {
|
||||
exists(PropertyAccess pa |
|
||||
this.asExpr() = pa |
|
||||
pa.getTarget().getDeclaringType().hasQualifiedName("System.IO.Compression.ZipArchiveEntry") and
|
||||
pa.getTarget().getName() = "FullName"
|
||||
pa.getTarget().getName() = "FullName"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -150,4 +150,4 @@ module ZipSlip {
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,3 +17,21 @@
|
||||
| arguments.cs:39:9:39:28 | call to method f3 | arguments.cs:39:27:39:27 | 0 | o |
|
||||
| arguments.cs:40:9:40:42 | call to method f3 | arguments.cs:40:18:40:35 | array creation of type Int32[] | args |
|
||||
| arguments.cs:40:9:40:42 | call to method f3 | arguments.cs:40:41:40:41 | 0 | o |
|
||||
| arguments.cs:54:9:54:12 | access to property Prop | arguments.cs:54:16:54:16 | 0 | value |
|
||||
| arguments.cs:55:9:55:12 | access to property Prop | arguments.cs:55:16:55:25 | access to indexer | value |
|
||||
| arguments.cs:55:16:55:25 | access to indexer | arguments.cs:55:21:55:21 | 1 | a |
|
||||
| arguments.cs:55:16:55:25 | access to indexer | arguments.cs:55:24:55:24 | 2 | b |
|
||||
| arguments.cs:56:10:56:13 | access to property Prop | arguments.cs:56:31:56:31 | 5 | value |
|
||||
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:21:56:21 | 3 | a |
|
||||
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:24:56:24 | 4 | b |
|
||||
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:34:56:34 | 6 | value |
|
||||
| arguments.cs:58:9:58:12 | access to property Prop | arguments.cs:58:9:58:17 | ... + ... | value |
|
||||
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:14:59:14 | 8 | a |
|
||||
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:17:59:17 | 9 | b |
|
||||
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:9:60:26 | ... + ... | value |
|
||||
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:14:60:15 | 10 | a |
|
||||
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:14:60:15 | 10 | a |
|
||||
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:18:60:19 | 11 | b |
|
||||
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:18:60:19 | 11 | b |
|
||||
| arguments.cs:62:16:62:27 | access to indexer | arguments.cs:62:21:62:22 | 15 | a |
|
||||
| arguments.cs:62:16:62:27 | access to indexer | arguments.cs:62:25:62:26 | 16 | b |
|
||||
|
||||
@@ -17,3 +17,23 @@
|
||||
| arguments.cs:39:9:39:28 | call to method f3 | arguments.cs:39:27:39:27 | 0 | arguments.cs:33:17:33:17 | o |
|
||||
| arguments.cs:40:9:40:42 | call to method f3 | arguments.cs:40:18:40:35 | array creation of type Int32[] | arguments.cs:33:33:33:36 | args |
|
||||
| arguments.cs:40:9:40:42 | call to method f3 | arguments.cs:40:41:40:41 | 0 | arguments.cs:33:17:33:17 | o |
|
||||
| arguments.cs:54:9:54:12 | access to property Prop | arguments.cs:54:16:54:16 | 0 | arguments.cs:48:21:48:23 | value |
|
||||
| arguments.cs:55:9:55:12 | access to property Prop | arguments.cs:55:16:55:25 | access to indexer | arguments.cs:48:21:48:23 | value |
|
||||
| arguments.cs:55:16:55:25 | access to indexer | arguments.cs:55:21:55:21 | 1 | arguments.cs:50:18:50:18 | a |
|
||||
| arguments.cs:55:16:55:25 | access to indexer | arguments.cs:55:24:55:24 | 2 | arguments.cs:50:25:50:25 | b |
|
||||
| arguments.cs:56:10:56:13 | access to property Prop | arguments.cs:56:31:56:31 | 5 | arguments.cs:48:21:48:23 | value |
|
||||
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:21:56:21 | 3 | arguments.cs:50:18:50:18 | a |
|
||||
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:24:56:24 | 4 | arguments.cs:50:25:50:25 | b |
|
||||
| arguments.cs:56:16:56:25 | access to indexer | arguments.cs:56:34:56:34 | 6 | arguments.cs:50:44:50:46 | value |
|
||||
| arguments.cs:58:9:58:12 | access to property Prop | arguments.cs:58:9:58:17 | ... + ... | arguments.cs:48:21:48:23 | value |
|
||||
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:14:59:14 | 8 | arguments.cs:50:18:50:18 | a |
|
||||
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:14:59:14 | 8 | arguments.cs:50:18:50:18 | a |
|
||||
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:17:59:17 | 9 | arguments.cs:50:25:50:25 | b |
|
||||
| arguments.cs:59:9:59:18 | access to indexer | arguments.cs:59:17:59:17 | 9 | arguments.cs:50:25:50:25 | b |
|
||||
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:9:60:26 | ... + ... | arguments.cs:50:44:50:46 | value |
|
||||
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:14:60:15 | 10 | arguments.cs:50:18:50:18 | a |
|
||||
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:14:60:15 | 10 | arguments.cs:50:18:50:18 | a |
|
||||
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:18:60:19 | 11 | arguments.cs:50:25:50:25 | b |
|
||||
| arguments.cs:60:9:60:20 | access to indexer | arguments.cs:60:18:60:19 | 11 | arguments.cs:50:25:50:25 | b |
|
||||
| arguments.cs:62:16:62:27 | access to indexer | arguments.cs:62:21:62:22 | 15 | arguments.cs:50:18:50:18 | a |
|
||||
| arguments.cs:62:16:62:27 | access to indexer | arguments.cs:62:25:62:26 | 16 | arguments.cs:50:25:50:25 | b |
|
||||
|
||||
@@ -44,4 +44,21 @@ class ArgumentsTest
|
||||
{
|
||||
f4(new object[] { null }, null);
|
||||
}
|
||||
|
||||
int Prop { get; set; }
|
||||
|
||||
int this[int a, int b] { get => a + b; set { } }
|
||||
|
||||
void f5()
|
||||
{
|
||||
Prop = 0;
|
||||
Prop = this[1, 2];
|
||||
(Prop, this[3, 4]) = (5, 6);
|
||||
Prop++;
|
||||
Prop += 7;
|
||||
this[8, 9]++;
|
||||
this[10, 11] += 12;
|
||||
var tuple = (13, 14);
|
||||
(Prop, this[15, 16]) = tuple;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,3 +17,23 @@
|
||||
| arguments.cs:33:33:33:36 | args | arguments.cs:38:15:38:18 | access to parameter args |
|
||||
| arguments.cs:33:33:33:36 | args | arguments.cs:39:18:39:21 | access to parameter args |
|
||||
| arguments.cs:33:33:33:36 | args | arguments.cs:40:18:40:35 | array creation of type Int32[] |
|
||||
| arguments.cs:48:21:48:23 | value | arguments.cs:54:16:54:16 | 0 |
|
||||
| arguments.cs:48:21:48:23 | value | arguments.cs:55:16:55:25 | access to indexer |
|
||||
| arguments.cs:48:21:48:23 | value | arguments.cs:56:31:56:31 | 5 |
|
||||
| arguments.cs:48:21:48:23 | value | arguments.cs:58:9:58:17 | ... + ... |
|
||||
| arguments.cs:50:18:50:18 | a | arguments.cs:55:21:55:21 | 1 |
|
||||
| arguments.cs:50:18:50:18 | a | arguments.cs:56:21:56:21 | 3 |
|
||||
| arguments.cs:50:18:50:18 | a | arguments.cs:59:14:59:14 | 8 |
|
||||
| arguments.cs:50:18:50:18 | a | arguments.cs:59:14:59:14 | 8 |
|
||||
| arguments.cs:50:18:50:18 | a | arguments.cs:60:14:60:15 | 10 |
|
||||
| arguments.cs:50:18:50:18 | a | arguments.cs:60:14:60:15 | 10 |
|
||||
| arguments.cs:50:18:50:18 | a | arguments.cs:62:21:62:22 | 15 |
|
||||
| arguments.cs:50:25:50:25 | b | arguments.cs:55:24:55:24 | 2 |
|
||||
| arguments.cs:50:25:50:25 | b | arguments.cs:56:24:56:24 | 4 |
|
||||
| arguments.cs:50:25:50:25 | b | arguments.cs:59:17:59:17 | 9 |
|
||||
| arguments.cs:50:25:50:25 | b | arguments.cs:59:17:59:17 | 9 |
|
||||
| arguments.cs:50:25:50:25 | b | arguments.cs:60:18:60:19 | 11 |
|
||||
| arguments.cs:50:25:50:25 | b | arguments.cs:60:18:60:19 | 11 |
|
||||
| arguments.cs:50:25:50:25 | b | arguments.cs:62:25:62:26 | 16 |
|
||||
| arguments.cs:50:44:50:46 | value | arguments.cs:56:34:56:34 | 6 |
|
||||
| arguments.cs:50:44:50:46 | value | arguments.cs:60:9:60:26 | ... + ... |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.commons.Assertions
|
||||
|
||||
select any(FailingAssertion fa)
|
||||
select any(FailingAssertion fa)
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:13:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | false |
|
||||
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:14:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | true |
|
||||
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false |
|
||||
| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:13:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | false |
|
||||
| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:14:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | true |
|
||||
| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false |
|
||||
| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:12:13:12:24 | ... > ... | Guards.cs:12:13:12:13 | access to parameter s | true |
|
||||
| Guards.cs:26:31:26:31 | access to parameter s | Guards.cs:24:13:24:21 | ... != ... | Guards.cs:24:13:24:13 | access to parameter s | true |
|
||||
| Guards.cs:33:31:33:31 | access to parameter x | Guards.cs:32:13:32:36 | !... | Guards.cs:32:35:32:35 | access to parameter x | true |
|
||||
| Guards.cs:33:31:33:31 | access to parameter x | Guards.cs:32:13:32:51 | ... & ... | Guards.cs:32:35:32:35 | access to parameter x | true |
|
||||
| Guards.cs:33:31:33:31 | access to parameter x | Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | Guards.cs:32:35:32:35 | access to parameter x | false |
|
||||
| Guards.cs:33:35:33:35 | access to parameter y | Guards.cs:32:13:32:51 | ... & ... | Guards.cs:32:42:32:42 | access to parameter y | true |
|
||||
| Guards.cs:33:35:33:35 | access to parameter y | Guards.cs:32:40:32:51 | !... | Guards.cs:32:42:32:42 | access to parameter y | true |
|
||||
| Guards.cs:33:35:33:35 | access to parameter y | Guards.cs:32:42:32:50 | ... == ... | Guards.cs:32:42:32:42 | access to parameter y | false |
|
||||
| Guards.cs:36:32:36:32 | access to parameter x | Guards.cs:35:13:35:21 | ... == ... | Guards.cs:35:13:35:13 | access to parameter x | false |
|
||||
| Guards.cs:36:36:36:36 | access to parameter y | Guards.cs:35:26:35:34 | ... == ... | Guards.cs:35:26:35:26 | access to parameter y | false |
|
||||
| Guards.cs:39:31:39:31 | access to parameter x | Guards.cs:38:15:38:23 | ... == ... | Guards.cs:38:15:38:15 | access to parameter x | false |
|
||||
| Guards.cs:39:35:39:35 | access to parameter y | Guards.cs:38:28:38:36 | ... == ... | Guards.cs:38:28:38:28 | access to parameter y | false |
|
||||
| Guards.cs:42:32:42:32 | access to parameter x | Guards.cs:41:17:41:25 | ... != ... | Guards.cs:41:17:41:17 | access to parameter x | true |
|
||||
| Guards.cs:42:36:42:36 | access to parameter y | Guards.cs:41:30:41:38 | ... != ... | Guards.cs:41:30:41:30 | access to parameter y | true |
|
||||
| Guards.cs:48:31:48:40 | access to field Field | Guards.cs:47:13:47:25 | ... != ... | Guards.cs:47:13:47:17 | access to field Field | true |
|
||||
| Guards.cs:55:27:55:27 | access to parameter g | Guards.cs:53:13:53:27 | ... == ... | Guards.cs:53:13:53:13 | access to parameter g | false |
|
||||
| Guards.cs:55:27:55:33 | access to field Field | Guards.cs:53:13:53:27 | ... == ... | Guards.cs:53:13:53:19 | access to field Field | false |
|
||||
| Guards.cs:62:27:62:27 | access to parameter g | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:13 | access to parameter g | false |
|
||||
| Guards.cs:62:27:62:36 | access to property Property | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:22 | access to property Property | false |
|
||||
| Guards.cs:62:27:62:45 | access to property Property | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:31 | access to property Property | false |
|
||||
| Guards.cs:62:27:62:51 | access to field Field | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:37 | access to field Field | false |
|
||||
| Guards.cs:63:27:63:27 | access to parameter g | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:13 | access to parameter g | false |
|
||||
| Guards.cs:63:27:63:36 | access to property Property | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:22 | access to property Property | false |
|
||||
| Guards.cs:70:31:70:31 | access to parameter s | Guards.cs:68:16:68:24 | ... != ... | Guards.cs:68:16:68:16 | access to parameter s | true |
|
||||
| Guards.cs:79:31:79:31 | access to parameter s | Guards.cs:78:13:78:26 | ... == ... | Guards.cs:78:13:78:13 | access to parameter s | true |
|
||||
| Guards.cs:81:31:81:31 | access to parameter s | Guards.cs:80:13:80:25 | ... > ... | Guards.cs:80:13:80:13 | access to parameter s | true |
|
||||
| Guards.cs:83:31:83:31 | access to parameter s | Guards.cs:82:13:82:26 | ... >= ... | Guards.cs:82:13:82:13 | access to parameter s | true |
|
||||
| Guards.cs:85:31:85:31 | access to parameter s | Guards.cs:84:13:84:26 | ... < ... | Guards.cs:84:13:84:13 | access to parameter s | true |
|
||||
| Guards.cs:87:31:87:31 | access to parameter s | Guards.cs:86:13:86:27 | ... <= ... | Guards.cs:86:13:86:13 | access to parameter s | true |
|
||||
| Guards.cs:89:31:89:31 | access to parameter s | Guards.cs:88:13:88:29 | ... != ... | Guards.cs:88:13:88:13 | access to parameter s | true |
|
||||
| Guards.cs:91:31:91:31 | access to parameter s | Guards.cs:88:13:88:29 | ... != ... | Guards.cs:88:13:88:13 | access to parameter s | false |
|
||||
| Guards.cs:93:31:93:31 | access to parameter s | Guards.cs:92:13:92:30 | ... != ... | Guards.cs:92:13:92:13 | access to parameter s | true |
|
||||
| Guards.cs:95:31:95:31 | access to parameter s | Guards.cs:92:13:92:30 | ... != ... | Guards.cs:92:13:92:13 | access to parameter s | false |
|
||||
| Guards.cs:97:31:97:31 | access to parameter s | Guards.cs:96:13:96:19 | ... == ... | Guards.cs:96:13:96:13 | access to parameter s | true |
|
||||
| Guards.cs:99:31:99:31 | access to parameter s | Guards.cs:96:13:96:19 | ... == ... | Guards.cs:96:13:96:13 | access to parameter s | false |
|
||||
| Guards.cs:106:9:106:9 | access to parameter g | Guards.cs:104:13:104:45 | ... == ... | Guards.cs:104:13:104:13 | access to parameter g | false |
|
||||
| Guards.cs:107:27:107:27 | access to parameter g | Guards.cs:104:13:104:45 | ... == ... | Guards.cs:104:13:104:13 | access to parameter g | false |
|
||||
| Guards.cs:108:27:108:27 | access to parameter g | Guards.cs:104:13:104:45 | ... == ... | Guards.cs:104:13:104:13 | access to parameter g | false |
|
||||
| Guards.cs:131:20:131:20 | access to parameter s | Guards.cs:130:13:130:21 | ... is ... | Guards.cs:130:13:130:13 | access to parameter s | true |
|
||||
| Guards.cs:132:16:132:16 | access to parameter s | Guards.cs:130:13:130:21 | ... is ... | Guards.cs:130:13:130:13 | access to parameter s | false |
|
||||
| Guards.cs:138:20:138:20 | access to parameter s | Guards.cs:137:13:137:23 | ... is ... | Guards.cs:137:13:137:13 | access to parameter s | true |
|
||||
| Guards.cs:139:16:139:16 | access to parameter s | Guards.cs:137:13:137:23 | ... is ... | Guards.cs:137:13:137:13 | access to parameter s | false |
|
||||
| Guards.cs:146:16:146:16 | access to parameter o | Guards.cs:144:13:144:25 | ... is ... | Guards.cs:144:13:144:13 | access to parameter o | false |
|
||||
@@ -0,0 +1,6 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.controlflow.Guards
|
||||
|
||||
from GuardedExpr ge, Expr e, Access a, boolean b
|
||||
where ge.isGuardedBy(e, a, b)
|
||||
select ge, e, a, b
|
||||
@@ -1,41 +1,122 @@
|
||||
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:13:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | false |
|
||||
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:14:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | true |
|
||||
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null |
|
||||
| Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false |
|
||||
| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:13:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | false |
|
||||
| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:14:10:25 | !... | Guards.cs:10:16:10:16 | access to parameter s | true |
|
||||
| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null |
|
||||
| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false |
|
||||
| Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:12:13:12:24 | ... > ... | Guards.cs:12:13:12:13 | access to parameter s | true |
|
||||
| Guards.cs:26:31:26:31 | access to parameter s | Guards.cs:24:13:24:13 | access to parameter s | Guards.cs:24:13:24:13 | access to parameter s | non-null |
|
||||
| Guards.cs:26:31:26:31 | access to parameter s | Guards.cs:24:13:24:21 | ... != ... | Guards.cs:24:13:24:13 | access to parameter s | true |
|
||||
| Guards.cs:33:31:33:31 | access to parameter x | Guards.cs:32:13:32:36 | !... | Guards.cs:32:35:32:35 | access to parameter x | true |
|
||||
| Guards.cs:33:31:33:31 | access to parameter x | Guards.cs:32:13:32:51 | ... & ... | Guards.cs:32:35:32:35 | access to parameter x | true |
|
||||
| Guards.cs:33:31:33:31 | access to parameter x | Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | Guards.cs:32:35:32:35 | access to parameter x | false |
|
||||
| Guards.cs:33:31:33:31 | access to parameter x | Guards.cs:32:35:32:35 | access to parameter x | Guards.cs:32:35:32:35 | access to parameter x | non-null |
|
||||
| Guards.cs:33:35:33:35 | access to parameter y | Guards.cs:32:13:32:51 | ... & ... | Guards.cs:32:42:32:42 | access to parameter y | true |
|
||||
| Guards.cs:33:35:33:35 | access to parameter y | Guards.cs:32:40:32:51 | !... | Guards.cs:32:42:32:42 | access to parameter y | true |
|
||||
| Guards.cs:33:35:33:35 | access to parameter y | Guards.cs:32:42:32:42 | access to parameter y | Guards.cs:32:42:32:42 | access to parameter y | non-null |
|
||||
| Guards.cs:33:35:33:35 | access to parameter y | Guards.cs:32:42:32:50 | ... == ... | Guards.cs:32:42:32:42 | access to parameter y | false |
|
||||
| Guards.cs:36:32:36:32 | access to parameter x | Guards.cs:35:13:35:13 | access to parameter x | Guards.cs:35:13:35:13 | access to parameter x | non-null |
|
||||
| Guards.cs:36:32:36:32 | access to parameter x | Guards.cs:35:13:35:21 | ... == ... | Guards.cs:35:13:35:13 | access to parameter x | false |
|
||||
| Guards.cs:36:36:36:36 | access to parameter y | Guards.cs:35:26:35:26 | access to parameter y | Guards.cs:35:26:35:26 | access to parameter y | non-null |
|
||||
| Guards.cs:36:36:36:36 | access to parameter y | Guards.cs:35:26:35:34 | ... == ... | Guards.cs:35:26:35:26 | access to parameter y | false |
|
||||
| Guards.cs:39:31:39:31 | access to parameter x | Guards.cs:38:15:38:15 | access to parameter x | Guards.cs:38:15:38:15 | access to parameter x | non-null |
|
||||
| Guards.cs:39:31:39:31 | access to parameter x | Guards.cs:38:15:38:23 | ... == ... | Guards.cs:38:15:38:15 | access to parameter x | false |
|
||||
| Guards.cs:39:35:39:35 | access to parameter y | Guards.cs:38:28:38:28 | access to parameter y | Guards.cs:38:28:38:28 | access to parameter y | non-null |
|
||||
| Guards.cs:39:35:39:35 | access to parameter y | Guards.cs:38:28:38:36 | ... == ... | Guards.cs:38:28:38:28 | access to parameter y | false |
|
||||
| Guards.cs:42:32:42:32 | access to parameter x | Guards.cs:41:17:41:17 | access to parameter x | Guards.cs:41:17:41:17 | access to parameter x | non-null |
|
||||
| Guards.cs:42:32:42:32 | access to parameter x | Guards.cs:41:17:41:25 | ... != ... | Guards.cs:41:17:41:17 | access to parameter x | true |
|
||||
| Guards.cs:42:36:42:36 | access to parameter y | Guards.cs:41:30:41:30 | access to parameter y | Guards.cs:41:30:41:30 | access to parameter y | non-null |
|
||||
| Guards.cs:42:36:42:36 | access to parameter y | Guards.cs:41:30:41:38 | ... != ... | Guards.cs:41:30:41:30 | access to parameter y | true |
|
||||
| Guards.cs:48:31:48:40 | access to field Field | Guards.cs:47:13:47:17 | access to field Field | Guards.cs:47:13:47:17 | access to field Field | non-null |
|
||||
| Guards.cs:48:31:48:40 | access to field Field | Guards.cs:47:13:47:25 | ... != ... | Guards.cs:47:13:47:17 | access to field Field | true |
|
||||
| Guards.cs:55:27:55:27 | access to parameter g | Guards.cs:53:13:53:19 | access to field Field | Guards.cs:53:13:53:13 | access to parameter g | non-null |
|
||||
| Guards.cs:55:27:55:27 | access to parameter g | Guards.cs:53:13:53:27 | ... == ... | Guards.cs:53:13:53:13 | access to parameter g | false |
|
||||
| Guards.cs:55:27:55:33 | access to field Field | Guards.cs:53:13:53:19 | access to field Field | Guards.cs:53:13:53:19 | access to field Field | non-null |
|
||||
| Guards.cs:55:27:55:33 | access to field Field | Guards.cs:53:13:53:27 | ... == ... | Guards.cs:53:13:53:19 | access to field Field | false |
|
||||
| Guards.cs:62:27:62:27 | access to parameter g | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:13 | access to parameter g | non-null |
|
||||
| Guards.cs:62:27:62:27 | access to parameter g | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:13 | access to parameter g | false |
|
||||
| Guards.cs:62:27:62:36 | access to property Property | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:22 | access to property Property | non-null |
|
||||
| Guards.cs:62:27:62:36 | access to property Property | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:22 | access to property Property | false |
|
||||
| Guards.cs:62:27:62:45 | access to property Property | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:31 | access to property Property | non-null |
|
||||
| Guards.cs:62:27:62:45 | access to property Property | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:31 | access to property Property | false |
|
||||
| Guards.cs:62:27:62:51 | access to field Field | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:37 | access to field Field | non-null |
|
||||
| Guards.cs:62:27:62:51 | access to field Field | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:37 | access to field Field | false |
|
||||
| Guards.cs:63:27:63:27 | access to parameter g | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:13 | access to parameter g | non-null |
|
||||
| Guards.cs:63:27:63:27 | access to parameter g | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:13 | access to parameter g | false |
|
||||
| Guards.cs:63:27:63:36 | access to property Property | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:22 | access to property Property | non-null |
|
||||
| Guards.cs:63:27:63:36 | access to property Property | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:22 | access to property Property | false |
|
||||
| Guards.cs:70:31:70:31 | access to parameter s | Guards.cs:68:16:68:16 | access to parameter s | Guards.cs:68:16:68:16 | access to parameter s | non-null |
|
||||
| Guards.cs:70:31:70:31 | access to parameter s | Guards.cs:68:16:68:24 | ... != ... | Guards.cs:68:16:68:16 | access to parameter s | true |
|
||||
| Guards.cs:79:31:79:31 | access to parameter s | Guards.cs:78:13:78:13 | access to parameter s | Guards.cs:78:13:78:13 | access to parameter s | non-null |
|
||||
| Guards.cs:79:31:79:31 | access to parameter s | Guards.cs:78:13:78:26 | ... == ... | Guards.cs:78:13:78:13 | access to parameter s | true |
|
||||
| Guards.cs:79:31:79:31 | access to parameter s | Guards.cs:78:15:78:21 | access to property Length | Guards.cs:78:13:78:13 | access to parameter s | non-null |
|
||||
| Guards.cs:81:31:81:31 | access to parameter s | Guards.cs:80:13:80:13 | access to parameter s | Guards.cs:80:13:80:13 | access to parameter s | non-null |
|
||||
| Guards.cs:81:31:81:31 | access to parameter s | Guards.cs:80:13:80:25 | ... > ... | Guards.cs:80:13:80:13 | access to parameter s | true |
|
||||
| Guards.cs:81:31:81:31 | access to parameter s | Guards.cs:80:15:80:21 | access to property Length | Guards.cs:80:13:80:13 | access to parameter s | non-null |
|
||||
| Guards.cs:83:31:83:31 | access to parameter s | Guards.cs:82:13:82:13 | access to parameter s | Guards.cs:82:13:82:13 | access to parameter s | non-null |
|
||||
| Guards.cs:83:31:83:31 | access to parameter s | Guards.cs:82:13:82:26 | ... >= ... | Guards.cs:82:13:82:13 | access to parameter s | true |
|
||||
| Guards.cs:83:31:83:31 | access to parameter s | Guards.cs:82:15:82:21 | access to property Length | Guards.cs:82:13:82:13 | access to parameter s | non-null |
|
||||
| Guards.cs:85:31:85:31 | access to parameter s | Guards.cs:84:13:84:13 | access to parameter s | Guards.cs:84:13:84:13 | access to parameter s | non-null |
|
||||
| Guards.cs:85:31:85:31 | access to parameter s | Guards.cs:84:13:84:26 | ... < ... | Guards.cs:84:13:84:13 | access to parameter s | true |
|
||||
| Guards.cs:85:31:85:31 | access to parameter s | Guards.cs:84:15:84:21 | access to property Length | Guards.cs:84:13:84:13 | access to parameter s | non-null |
|
||||
| Guards.cs:87:31:87:31 | access to parameter s | Guards.cs:86:13:86:13 | access to parameter s | Guards.cs:86:13:86:13 | access to parameter s | non-null |
|
||||
| Guards.cs:87:31:87:31 | access to parameter s | Guards.cs:86:13:86:27 | ... <= ... | Guards.cs:86:13:86:13 | access to parameter s | true |
|
||||
| Guards.cs:87:31:87:31 | access to parameter s | Guards.cs:86:15:86:21 | access to property Length | Guards.cs:86:13:86:13 | access to parameter s | non-null |
|
||||
| Guards.cs:89:31:89:31 | access to parameter s | Guards.cs:88:13:88:13 | access to parameter s | Guards.cs:88:13:88:13 | access to parameter s | non-null |
|
||||
| Guards.cs:89:31:89:31 | access to parameter s | Guards.cs:88:13:88:29 | ... != ... | Guards.cs:88:13:88:13 | access to parameter s | true |
|
||||
| Guards.cs:89:31:89:31 | access to parameter s | Guards.cs:88:15:88:21 | access to property Length | Guards.cs:88:13:88:13 | access to parameter s | non-null |
|
||||
| Guards.cs:91:31:91:31 | access to parameter s | Guards.cs:88:13:88:13 | access to parameter s | Guards.cs:88:13:88:13 | access to parameter s | null |
|
||||
| Guards.cs:91:31:91:31 | access to parameter s | Guards.cs:88:13:88:29 | ... != ... | Guards.cs:88:13:88:13 | access to parameter s | false |
|
||||
| Guards.cs:91:31:91:31 | access to parameter s | Guards.cs:88:15:88:21 | access to property Length | Guards.cs:88:13:88:13 | access to parameter s | null |
|
||||
| Guards.cs:93:31:93:31 | access to parameter s | Guards.cs:92:13:92:30 | ... != ... | Guards.cs:92:13:92:13 | access to parameter s | true |
|
||||
| Guards.cs:95:31:95:31 | access to parameter s | Guards.cs:92:13:92:13 | access to parameter s | Guards.cs:92:13:92:13 | access to parameter s | non-null |
|
||||
| Guards.cs:95:31:95:31 | access to parameter s | Guards.cs:92:13:92:25 | ... - ... | Guards.cs:92:13:92:13 | access to parameter s | non-null |
|
||||
| Guards.cs:95:31:95:31 | access to parameter s | Guards.cs:92:13:92:30 | ... != ... | Guards.cs:92:13:92:13 | access to parameter s | false |
|
||||
| Guards.cs:95:31:95:31 | access to parameter s | Guards.cs:92:15:92:21 | access to property Length | Guards.cs:92:13:92:13 | access to parameter s | non-null |
|
||||
| Guards.cs:97:31:97:31 | access to parameter s | Guards.cs:96:13:96:13 | access to parameter s | Guards.cs:96:13:96:13 | access to parameter s | non-null |
|
||||
| Guards.cs:97:31:97:31 | access to parameter s | Guards.cs:96:13:96:19 | ... == ... | Guards.cs:96:13:96:13 | access to parameter s | true |
|
||||
| Guards.cs:99:31:99:31 | access to parameter s | Guards.cs:96:13:96:19 | ... == ... | Guards.cs:96:13:96:13 | access to parameter s | false |
|
||||
| Guards.cs:106:9:106:9 | access to parameter g | Guards.cs:104:13:104:37 | access to field Field | Guards.cs:104:13:104:13 | access to parameter g | non-null |
|
||||
| Guards.cs:106:9:106:9 | access to parameter g | Guards.cs:104:13:104:45 | ... == ... | Guards.cs:104:13:104:13 | access to parameter g | false |
|
||||
| Guards.cs:107:27:107:27 | access to parameter g | Guards.cs:104:13:104:37 | access to field Field | Guards.cs:104:13:104:13 | access to parameter g | non-null |
|
||||
| Guards.cs:107:27:107:27 | access to parameter g | Guards.cs:104:13:104:45 | ... == ... | Guards.cs:104:13:104:13 | access to parameter g | false |
|
||||
| Guards.cs:108:27:108:27 | access to parameter g | Guards.cs:104:13:104:37 | access to field Field | Guards.cs:104:13:104:13 | access to parameter g | non-null |
|
||||
| Guards.cs:108:27:108:27 | access to parameter g | Guards.cs:104:13:104:45 | ... == ... | Guards.cs:104:13:104:13 | access to parameter g | false |
|
||||
| Guards.cs:114:14:114:14 | access to parameter g | Guards.cs:113:21:113:45 | access to field Field | Guards.cs:113:21:113:21 | access to parameter g | null |
|
||||
| Guards.cs:114:14:114:23 | access to property Property | Guards.cs:113:21:113:45 | access to field Field | Guards.cs:113:21:113:30 | access to property Property | null |
|
||||
| Guards.cs:114:14:114:32 | access to property Property | Guards.cs:113:21:113:45 | access to field Field | Guards.cs:113:21:113:39 | access to property Property | null |
|
||||
| Guards.cs:114:14:114:38 | access to field Field | Guards.cs:113:21:113:45 | access to field Field | Guards.cs:113:21:113:45 | access to field Field | null |
|
||||
| Guards.cs:116:27:116:27 | access to parameter g | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:17 | access to parameter g | non-null |
|
||||
| Guards.cs:116:27:116:36 | access to property Property | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:26 | access to property Property | non-null |
|
||||
| Guards.cs:116:27:116:45 | access to property Property | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:35 | access to property Property | non-null |
|
||||
| Guards.cs:116:27:116:51 | access to field Field | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:41 | access to field Field | non-null |
|
||||
| Guards.cs:117:9:117:9 | access to parameter g | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:17 | access to parameter g | non-null |
|
||||
| Guards.cs:118:27:118:27 | access to parameter g | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:17 | access to parameter g | non-null |
|
||||
| Guards.cs:119:27:119:27 | access to parameter g | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:17 | access to parameter g | non-null |
|
||||
| Guards.cs:125:29:125:30 | access to parameter s1 | Guards.cs:125:18:125:19 | access to parameter s1 | Guards.cs:125:18:125:19 | access to parameter s1 | non-null |
|
||||
| Guards.cs:131:20:131:20 | access to parameter s | Guards.cs:130:13:130:13 | access to parameter s | Guards.cs:130:13:130:13 | access to parameter s | null |
|
||||
| Guards.cs:131:20:131:20 | access to parameter s | Guards.cs:130:13:130:21 | ... is ... | Guards.cs:130:13:130:13 | access to parameter s | true |
|
||||
| Guards.cs:132:16:132:16 | access to parameter s | Guards.cs:130:13:130:13 | access to parameter s | Guards.cs:130:13:130:13 | access to parameter s | non-null |
|
||||
| Guards.cs:132:16:132:16 | access to parameter s | Guards.cs:130:13:130:21 | ... is ... | Guards.cs:130:13:130:13 | access to parameter s | false |
|
||||
| Guards.cs:138:20:138:20 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | non-null |
|
||||
| Guards.cs:138:20:138:20 | access to parameter s | Guards.cs:137:13:137:23 | ... is ... | Guards.cs:137:13:137:13 | access to parameter s | true |
|
||||
| Guards.cs:139:16:139:16 | access to parameter s | Guards.cs:137:13:137:23 | ... is ... | Guards.cs:137:13:137:13 | access to parameter s | false |
|
||||
| Guards.cs:146:16:146:16 | access to parameter o | Guards.cs:144:13:144:25 | ... is ... | Guards.cs:144:13:144:13 | access to parameter o | false |
|
||||
| Guards.cs:154:24:154:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | match case Action<Object>: |
|
||||
| Guards.cs:154:24:154:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-null |
|
||||
| Guards.cs:158:24:158:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | match case ...: |
|
||||
| Guards.cs:158:24:158:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action<Object>: |
|
||||
| Guards.cs:158:24:158:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action<String> a: |
|
||||
| Guards.cs:158:24:158:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-null |
|
||||
| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | match case ...: |
|
||||
| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case ...: |
|
||||
| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action<Object>: |
|
||||
| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action<String> a: |
|
||||
| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | null |
|
||||
| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case ...: |
|
||||
| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case ...: |
|
||||
| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action<Object>: |
|
||||
| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action<String> a: |
|
||||
| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-null |
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.controlflow.Guards
|
||||
|
||||
from GuardedExpr ge, Expr e, Access a, boolean b
|
||||
where ge.isGuardedBy(e, a, b)
|
||||
select ge, e, a, b
|
||||
from GuardedExpr ge, Expr sub, AbstractValue v
|
||||
select ge, ge.getAGuard(sub, v), sub, v
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
impliesStep
|
||||
| Guards.cs:10:13:10:25 | !... | false | Guards.cs:10:14:10:25 | !... | true |
|
||||
| Guards.cs:10:13:10:25 | !... | true | Guards.cs:10:14:10:25 | !... | false |
|
||||
| Guards.cs:10:14:10:25 | !... | false | Guards.cs:10:13:10:25 | !... | true |
|
||||
| Guards.cs:10:14:10:25 | !... | false | Guards.cs:10:16:10:24 | ... == ... | true |
|
||||
| Guards.cs:10:14:10:25 | !... | true | Guards.cs:10:13:10:25 | !... | false |
|
||||
| Guards.cs:10:14:10:25 | !... | true | Guards.cs:10:16:10:24 | ... == ... | false |
|
||||
| Guards.cs:10:16:10:24 | ... == ... | false | Guards.cs:10:14:10:25 | !... | true |
|
||||
| Guards.cs:10:16:10:24 | ... == ... | false | Guards.cs:10:16:10:16 | access to parameter s | non-null |
|
||||
| Guards.cs:10:16:10:24 | ... == ... | true | Guards.cs:10:14:10:25 | !... | false |
|
||||
| Guards.cs:10:16:10:24 | ... == ... | true | Guards.cs:10:16:10:16 | access to parameter s | null |
|
||||
| Guards.cs:24:13:24:21 | ... != ... | false | Guards.cs:24:13:24:13 | access to parameter s | null |
|
||||
| Guards.cs:24:13:24:21 | ... != ... | true | Guards.cs:24:13:24:13 | access to parameter s | non-null |
|
||||
| Guards.cs:32:13:32:36 | !... | false | Guards.cs:32:13:32:51 | ... & ... | false |
|
||||
| Guards.cs:32:13:32:36 | !... | false | Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | true |
|
||||
| Guards.cs:32:13:32:36 | !... | true | Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | false |
|
||||
| Guards.cs:32:13:32:51 | ... & ... | true | Guards.cs:32:13:32:36 | !... | true |
|
||||
| Guards.cs:32:13:32:51 | ... & ... | true | Guards.cs:32:40:32:51 | !... | true |
|
||||
| Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | false | Guards.cs:32:13:32:36 | !... | true |
|
||||
| Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | false | Guards.cs:32:35:32:35 | access to parameter x | non-null |
|
||||
| Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | true | Guards.cs:32:13:32:36 | !... | false |
|
||||
| Guards.cs:32:40:32:51 | !... | false | Guards.cs:32:13:32:51 | ... & ... | false |
|
||||
| Guards.cs:32:40:32:51 | !... | false | Guards.cs:32:42:32:50 | ... == ... | true |
|
||||
| Guards.cs:32:40:32:51 | !... | true | Guards.cs:32:42:32:50 | ... == ... | false |
|
||||
| Guards.cs:32:42:32:50 | ... == ... | false | Guards.cs:32:40:32:51 | !... | true |
|
||||
| Guards.cs:32:42:32:50 | ... == ... | false | Guards.cs:32:42:32:42 | access to parameter y | non-null |
|
||||
| Guards.cs:32:42:32:50 | ... == ... | true | Guards.cs:32:40:32:51 | !... | false |
|
||||
| Guards.cs:32:42:32:50 | ... == ... | true | Guards.cs:32:42:32:42 | access to parameter y | null |
|
||||
| Guards.cs:35:13:35:21 | ... == ... | false | Guards.cs:35:13:35:13 | access to parameter x | non-null |
|
||||
| Guards.cs:35:13:35:21 | ... == ... | true | Guards.cs:35:13:35:13 | access to parameter x | null |
|
||||
| Guards.cs:35:13:35:21 | ... == ... | true | Guards.cs:35:13:35:34 | ... \|\| ... | true |
|
||||
| Guards.cs:35:13:35:34 | ... \|\| ... | false | Guards.cs:35:13:35:21 | ... == ... | false |
|
||||
| Guards.cs:35:13:35:34 | ... \|\| ... | false | Guards.cs:35:26:35:34 | ... == ... | false |
|
||||
| Guards.cs:35:26:35:34 | ... == ... | false | Guards.cs:35:26:35:26 | access to parameter y | non-null |
|
||||
| Guards.cs:35:26:35:34 | ... == ... | true | Guards.cs:35:13:35:34 | ... \|\| ... | true |
|
||||
| Guards.cs:35:26:35:34 | ... == ... | true | Guards.cs:35:26:35:26 | access to parameter y | null |
|
||||
| Guards.cs:38:13:38:37 | !... | false | Guards.cs:38:15:38:36 | ... \|\| ... | true |
|
||||
| Guards.cs:38:13:38:37 | !... | true | Guards.cs:38:15:38:36 | ... \|\| ... | false |
|
||||
| Guards.cs:38:15:38:23 | ... == ... | false | Guards.cs:38:15:38:15 | access to parameter x | non-null |
|
||||
| Guards.cs:38:15:38:23 | ... == ... | true | Guards.cs:38:15:38:15 | access to parameter x | null |
|
||||
| Guards.cs:38:15:38:23 | ... == ... | true | Guards.cs:38:15:38:36 | ... \|\| ... | true |
|
||||
| Guards.cs:38:15:38:36 | ... \|\| ... | false | Guards.cs:38:13:38:37 | !... | true |
|
||||
| Guards.cs:38:15:38:36 | ... \|\| ... | false | Guards.cs:38:15:38:23 | ... == ... | false |
|
||||
| Guards.cs:38:15:38:36 | ... \|\| ... | false | Guards.cs:38:28:38:36 | ... == ... | false |
|
||||
| Guards.cs:38:15:38:36 | ... \|\| ... | true | Guards.cs:38:13:38:37 | !... | false |
|
||||
| Guards.cs:38:28:38:36 | ... == ... | false | Guards.cs:38:28:38:28 | access to parameter y | non-null |
|
||||
| Guards.cs:38:28:38:36 | ... == ... | true | Guards.cs:38:15:38:36 | ... \|\| ... | true |
|
||||
| Guards.cs:38:28:38:36 | ... == ... | true | Guards.cs:38:28:38:28 | access to parameter y | null |
|
||||
| Guards.cs:41:13:41:39 | !... | false | Guards.cs:41:14:41:39 | !... | true |
|
||||
| Guards.cs:41:13:41:39 | !... | true | Guards.cs:41:14:41:39 | !... | false |
|
||||
| Guards.cs:41:14:41:39 | !... | false | Guards.cs:41:13:41:39 | !... | true |
|
||||
| Guards.cs:41:14:41:39 | !... | false | Guards.cs:41:15:41:39 | !... | true |
|
||||
| Guards.cs:41:14:41:39 | !... | true | Guards.cs:41:13:41:39 | !... | false |
|
||||
| Guards.cs:41:14:41:39 | !... | true | Guards.cs:41:15:41:39 | !... | false |
|
||||
| Guards.cs:41:15:41:39 | !... | false | Guards.cs:41:14:41:39 | !... | true |
|
||||
| Guards.cs:41:15:41:39 | !... | false | Guards.cs:41:17:41:38 | ... && ... | true |
|
||||
| Guards.cs:41:15:41:39 | !... | true | Guards.cs:41:14:41:39 | !... | false |
|
||||
| Guards.cs:41:15:41:39 | !... | true | Guards.cs:41:17:41:38 | ... && ... | false |
|
||||
| Guards.cs:41:17:41:25 | ... != ... | false | Guards.cs:41:17:41:17 | access to parameter x | null |
|
||||
| Guards.cs:41:17:41:25 | ... != ... | false | Guards.cs:41:17:41:38 | ... && ... | false |
|
||||
| Guards.cs:41:17:41:25 | ... != ... | true | Guards.cs:41:17:41:17 | access to parameter x | non-null |
|
||||
| Guards.cs:41:17:41:38 | ... && ... | false | Guards.cs:41:15:41:39 | !... | true |
|
||||
| Guards.cs:41:17:41:38 | ... && ... | true | Guards.cs:41:15:41:39 | !... | false |
|
||||
| Guards.cs:41:17:41:38 | ... && ... | true | Guards.cs:41:17:41:25 | ... != ... | true |
|
||||
| Guards.cs:41:17:41:38 | ... && ... | true | Guards.cs:41:30:41:38 | ... != ... | true |
|
||||
| Guards.cs:41:30:41:38 | ... != ... | false | Guards.cs:41:17:41:38 | ... && ... | false |
|
||||
| Guards.cs:41:30:41:38 | ... != ... | false | Guards.cs:41:30:41:30 | access to parameter y | null |
|
||||
| Guards.cs:41:30:41:38 | ... != ... | true | Guards.cs:41:30:41:30 | access to parameter y | non-null |
|
||||
| Guards.cs:44:13:44:25 | ... != ... | false | Guards.cs:44:13:44:17 | access to field Field | null |
|
||||
| Guards.cs:44:13:44:25 | ... != ... | true | Guards.cs:44:13:44:17 | access to field Field | non-null |
|
||||
| Guards.cs:47:13:47:25 | ... != ... | false | Guards.cs:47:13:47:17 | access to field Field | null |
|
||||
| Guards.cs:47:13:47:25 | ... != ... | true | Guards.cs:47:13:47:17 | access to field Field | non-null |
|
||||
| Guards.cs:53:13:53:27 | ... == ... | false | Guards.cs:53:13:53:19 | access to field Field | non-null |
|
||||
| Guards.cs:53:13:53:27 | ... == ... | true | Guards.cs:53:13:53:19 | access to field Field | null |
|
||||
| Guards.cs:60:13:60:45 | ... == ... | false | Guards.cs:60:13:60:37 | access to field Field | non-null |
|
||||
| Guards.cs:60:13:60:45 | ... == ... | true | Guards.cs:60:13:60:37 | access to field Field | null |
|
||||
| Guards.cs:68:16:68:24 | ... != ... | false | Guards.cs:68:16:68:16 | access to parameter s | null |
|
||||
| Guards.cs:68:16:68:24 | ... != ... | true | Guards.cs:68:16:68:16 | access to parameter s | non-null |
|
||||
| Guards.cs:78:13:78:26 | ... == ... | true | Guards.cs:78:15:78:21 | access to property Length | non-null |
|
||||
| Guards.cs:78:15:78:21 | access to property Length | non-null | Guards.cs:78:13:78:13 | access to parameter s | non-null |
|
||||
| Guards.cs:78:15:78:21 | access to property Length | null | Guards.cs:78:13:78:13 | access to parameter s | null |
|
||||
| Guards.cs:80:13:80:25 | ... > ... | true | Guards.cs:80:15:80:21 | access to property Length | non-null |
|
||||
| Guards.cs:80:15:80:21 | access to property Length | non-null | Guards.cs:80:13:80:13 | access to parameter s | non-null |
|
||||
| Guards.cs:80:15:80:21 | access to property Length | null | Guards.cs:80:13:80:13 | access to parameter s | null |
|
||||
| Guards.cs:82:13:82:26 | ... >= ... | true | Guards.cs:82:15:82:21 | access to property Length | non-null |
|
||||
| Guards.cs:82:15:82:21 | access to property Length | non-null | Guards.cs:82:13:82:13 | access to parameter s | non-null |
|
||||
| Guards.cs:82:15:82:21 | access to property Length | null | Guards.cs:82:13:82:13 | access to parameter s | null |
|
||||
| Guards.cs:84:13:84:26 | ... < ... | true | Guards.cs:84:15:84:21 | access to property Length | non-null |
|
||||
| Guards.cs:84:15:84:21 | access to property Length | non-null | Guards.cs:84:13:84:13 | access to parameter s | non-null |
|
||||
| Guards.cs:84:15:84:21 | access to property Length | null | Guards.cs:84:13:84:13 | access to parameter s | null |
|
||||
| Guards.cs:86:13:86:27 | ... <= ... | true | Guards.cs:86:15:86:21 | access to property Length | non-null |
|
||||
| Guards.cs:86:15:86:21 | access to property Length | non-null | Guards.cs:86:13:86:13 | access to parameter s | non-null |
|
||||
| Guards.cs:86:15:86:21 | access to property Length | null | Guards.cs:86:13:86:13 | access to parameter s | null |
|
||||
| Guards.cs:88:13:88:29 | ... != ... | false | Guards.cs:88:15:88:21 | access to property Length | null |
|
||||
| Guards.cs:88:13:88:29 | ... != ... | true | Guards.cs:88:15:88:21 | access to property Length | non-null |
|
||||
| Guards.cs:88:15:88:21 | access to property Length | non-null | Guards.cs:88:13:88:13 | access to parameter s | non-null |
|
||||
| Guards.cs:88:15:88:21 | access to property Length | null | Guards.cs:88:13:88:13 | access to parameter s | null |
|
||||
| Guards.cs:92:13:92:25 | ... - ... | non-null | Guards.cs:92:15:92:21 | access to property Length | non-null |
|
||||
| Guards.cs:92:13:92:25 | ... - ... | null | Guards.cs:92:15:92:21 | access to property Length | null |
|
||||
| Guards.cs:92:13:92:30 | ... != ... | false | Guards.cs:92:13:92:25 | ... - ... | non-null |
|
||||
| Guards.cs:92:15:92:21 | access to property Length | non-null | Guards.cs:92:13:92:13 | access to parameter s | non-null |
|
||||
| Guards.cs:92:15:92:21 | access to property Length | null | Guards.cs:92:13:92:13 | access to parameter s | null |
|
||||
| Guards.cs:96:13:96:19 | ... == ... | true | Guards.cs:96:13:96:13 | access to parameter s | non-null |
|
||||
| Guards.cs:104:13:104:45 | ... == ... | false | Guards.cs:104:13:104:37 | access to field Field | non-null |
|
||||
| Guards.cs:104:13:104:45 | ... == ... | true | Guards.cs:104:13:104:37 | access to field Field | null |
|
||||
| Guards.cs:125:21:125:31 | call to method Equals | non-null | Guards.cs:125:18:125:19 | access to parameter s1 | non-null |
|
||||
| Guards.cs:125:21:125:31 | call to method Equals | null | Guards.cs:125:18:125:19 | access to parameter s1 | null |
|
||||
| Guards.cs:130:13:130:21 | ... is ... | false | Guards.cs:130:13:130:13 | access to parameter s | non-null |
|
||||
| Guards.cs:130:13:130:21 | ... is ... | true | Guards.cs:130:13:130:13 | access to parameter s | null |
|
||||
| Guards.cs:137:13:137:23 | ... is ... | true | Guards.cs:137:13:137:13 | access to parameter s | non-null |
|
||||
| Guards.cs:144:13:144:25 | ... is ... | true | Guards.cs:144:13:144:13 | access to parameter o | non-null |
|
||||
| Guards.cs:151:17:151:17 | access to parameter o | match case ...: | Guards.cs:151:17:151:17 | access to parameter o | non-null |
|
||||
| Guards.cs:151:17:151:17 | access to parameter o | match case ...: | Guards.cs:151:17:151:17 | access to parameter o | null |
|
||||
| Guards.cs:151:17:151:17 | access to parameter o | match case Action<Object>: | Guards.cs:151:17:151:17 | access to parameter o | non-null |
|
||||
| Guards.cs:151:17:151:17 | access to parameter o | match case Action<String> a: | Guards.cs:151:17:151:17 | access to parameter o | non-null |
|
||||
| Guards.cs:151:17:151:17 | access to parameter o | non-match case ...: | Guards.cs:151:17:151:17 | access to parameter o | non-null |
|
||||
impliesStepIdentity
|
||||
| Guards.cs:72:31:72:31 | access to parameter s | Guards.cs:71:17:71:20 | null |
|
||||
| Guards.cs:145:20:145:20 | access to local variable s | Guards.cs:144:13:144:13 | access to parameter o |
|
||||
| Guards.cs:156:24:156:24 | access to local variable a | Guards.cs:151:17:151:17 | access to parameter o |
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user