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:
Aditya Sharad
2018-11-09 18:49:35 +00:00
1273 changed files with 138514 additions and 2413 deletions

View File

@@ -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

View File

@@ -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.

View File

@@ -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`.

View File

@@ -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.

View 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.

View File

@@ -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)
{
// ...
// ...
}

View File

@@ -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;

View File

@@ -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]);
}
}

View File

@@ -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

View 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
...
...
}

View File

@@ -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
}

View File

@@ -11,8 +11,8 @@
* @tags reliability
* correctness
* security
* external/cwe/190
* external/cwe/192
* external/cwe/cwe-190
* external/cwe/cwe-192
*/
import cpp

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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>&amp;</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>

View File

@@ -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."

View File

@@ -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() )
)
)
}

View File

@@ -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

View File

@@ -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
}
}
}
}

View File

@@ -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.
}

View File

@@ -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;
}

View File

@@ -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>

View 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."

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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."

View File

@@ -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
};

View File

@@ -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.

View File

@@ -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"
}

View File

@@ -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};

View File

@@ -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())
}

View File

@@ -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. */

View File

@@ -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)
}

View File

@@ -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`. */

View File

@@ -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.
*/

View File

@@ -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 | { ... } |

View File

@@ -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 | { ... } |

View File

@@ -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;
}

View File

@@ -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 | |

View File

@@ -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 | { ... } |

View File

@@ -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 |

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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. |

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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. |

View File

@@ -0,0 +1 @@
Likely Bugs/Likely Typos/IncorrectNotOperatorUsage.ql

View File

@@ -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
{
};

View File

@@ -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. |

View File

@@ -0,0 +1 @@
Likely Bugs/OO/NonVirtualDestructorInBaseClass.ql

View File

@@ -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;

View File

@@ -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 |

View File

@@ -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
// ...
}
}

View File

@@ -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
}

View File

@@ -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 | |

View File

@@ -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);
}

View 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);

View File

@@ -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);
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -14,5 +14,7 @@ namespace Semmle.Extraction
public ISymbol symbol;
public SyntaxNode node;
public Exception exception;
public override string ToString() => message;
}
}

View 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;
}
}
}

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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

View File

@@ -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"

View File

@@ -9,4 +9,4 @@ class Bad
string destFileName = Path.Combine(destDirectory, entry.FullName);
entry.ExtractToFile(destFileName);
}
}
}

View File

@@ -5,4 +5,4 @@
...
</customErrors>
</system.web>
</configuration>
</configuration>

View File

@@ -5,4 +5,4 @@
...
</customErrors>
</system.web>
</configuration>
</configuration>

View File

@@ -9,4 +9,4 @@
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
</configuration>

View File

@@ -3,7 +3,7 @@
<system.web>
<authentication>
<forms
requireSSL="true"
requireSSL="true"
... />
</authentication>
<httpCookies

View File

@@ -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() +

View File

@@ -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.

View File

@@ -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() }
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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)
}
/**

View File

@@ -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

View File

@@ -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

View File

@@ -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() }

View File

@@ -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)
)
}
}

View File

@@ -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))
}
}
}

View File

@@ -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())
}
}

View File

@@ -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 {
)
}
}
}
}

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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;
}
}

View File

@@ -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 | ... + ... |

View File

@@ -1,4 +1,4 @@
import csharp
import semmle.code.csharp.commons.Assertions
select any(FailingAssertion fa)
select any(FailingAssertion fa)

View File

@@ -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 |

View File

@@ -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

View File

@@ -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 |

View File

@@ -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

View File

@@ -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