mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge branch 'master' into hresult-boolean-qhelp
This commit is contained in:
7
.gitignore
vendored
7
.gitignore
vendored
@@ -8,8 +8,7 @@
|
||||
# qltest projects and artifacts
|
||||
*/ql/test/**/*.testproj
|
||||
*/ql/test/**/*.actual
|
||||
/.vs/slnx.sqlite
|
||||
/.vs/ql/v15/Browse.VC.opendb
|
||||
/.vs/ql/v15/Browse.VC.db
|
||||
/.vs/ProjectSettings.json
|
||||
|
||||
# Visual studio temporaries, except a file used by QL4VS
|
||||
.vs/*
|
||||
!.vs/VSWorkspaceSettings.json
|
||||
|
||||
@@ -8,13 +8,17 @@
|
||||
|-----------------------------|-----------|--------------------------------------------------------------------|
|
||||
| Cast between HRESULT and a Boolean type (`cpp/hresult-boolean-conversion`) | external/cwe/cwe-253 | Finds logic errors caused by mistakenly treating the Windows `HRESULT` type as a Boolean instead of testing it with the appropriate macros. Enabled by default. |
|
||||
| Setting a DACL to `NULL` in a `SECURITY_DESCRIPTOR` (`cpp/unsafe-dacl-security-descriptor`) | external/cwe/cwe-732 | This query finds code that creates world-writable objects on Windows by setting their DACL to `NULL`. Enabled by default. |
|
||||
| Cast from char* to wchar_t* | security, external/cwe/cwe-704 | Detects potentially dangerous casts from char* to wchar_t*. Enabled by default on LGTM. |
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|----------------------------|------------------------|------------------------------------------------------------------|
|
||||
| Resource not released in destructor | Fewer false positive results | Placement new is now excluded from the query. |
|
||||
|
||||
| Missing return statement (`cpp/missing-return`) | Visible by default | The precision of this query has been increased from 'medium' to 'high', which makes it visible by default in LGTM. It was 'medium' in release 1.17 and 1.18 because it had false positives due to an extractor bug that was fixed in 1.18. |
|
||||
| Call to memory access function may overflow buffer | More correct results | Array indexing with a negative index is now detected by this query. |
|
||||
| Suspicious add with sizeof | Fewer false positive results | Arithmetic with void pointers (where allowed) is now excluded from this query. |
|
||||
| Wrong type of arguments to formatting function | Fewer false positive results | False positive results involving typedefs have been removed. Expected argument types are determined more accurately, especially for wide string and pointer types. Custom (non-standard) formatting functions are also identified more accurately. |
|
||||
|
||||
## Changes to QL libraries
|
||||
|
||||
|
||||
@@ -9,22 +9,30 @@
|
||||
* 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)
|
||||
|
||||
* 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.
|
||||
|
||||
## New queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|-----------------------------------------------|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Enabling Node.js integration for Electron web content renderers (`js/enabling-electron-renderer-node-integration`) | security, frameworks/electron, external/cwe/cwe-094 | Highlights Electron web content renderer preferences with Node.js integration enabled, indicating a violation of [CWE-94](https://cwe.mitre.org/data/definitions/94.html). Results are not shown on LGTM by default. |
|
||||
| Stored cross-site scripting (`js/stored-xss`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights uncontrolled stored values flowing into HTML content, indicating a violation of [CWE-079](https://cwe.mitre.org/data/definitions/79.html). Results shown on LGTM by default. |
|
||||
| Host header poisoning in email generation | security, external/cwe/cwe-640 | Highlights code that generates emails with links that can be hijacked by HTTP host header poisoning, indicating a violation of [CWE-640](https://cwe.mitre.org/data/definitions/640.html). Results shown on LGTM by default. |
|
||||
| Replacement of a substring with itself (`js/identity-replacement`) | correctness, security, external/cwe/cwe-116 | Highlights string replacements that replace a string with itself, which usually indicates a mistake. Results shown on LGTM by default. |
|
||||
| Stored cross-site scripting (`js/stored-xss`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights uncontrolled stored values flowing into HTML content, indicating a violation of [CWE-079](https://cwe.mitre.org/data/definitions/79.html). Results shown on LGTM by default. |
|
||||
| Unclear precedence of nested operators (`js/unclear-operator-precedence`) | maintainability, correctness, external/cwe/cwe-783 | Highlights nested binary operators whose relative precedence is easy to misunderstand. Results shown on LGTM by default. |
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|--------------------------------|----------------------------|----------------------------------------------|
|
||||
| Useless assignment to local variable | Fewer false-positive results | This rule now recognizes additional ways default values can be set. |
|
||||
| Regular expression injection | Fewer false-positive results | This rule now identifies calls to `String.prototype.search` with more precision. |
|
||||
| Unbound event handler receiver | Fewer false-positive results | This rule now recognizes additional ways class methods can be bound. |
|
||||
| Remote property injection | Fewer results | The precision of this rule has been revised to "medium". Results are no longer shown on LGTM by default. |
|
||||
| Missing CSRF middleware | Fewer false-positive results | This rule now recognizes additional CSRF protection middlewares. |
|
||||
| Server-side URL redirect | More results | This rule now recognizes redirection calls in more cases. |
|
||||
| Whitespace contradicts operator precedence | Fewer false-positive results | This rule no longer flags operators with asymmetric whitespace. |
|
||||
|
||||
## Changes to QL libraries
|
||||
|
||||
* The flow configuration framework now supports distinguishing and tracking different kinds of taint, specified by an extensible class `FlowLabel` (which can also be referred to by its alias `TaintKind`).
|
||||
@@ -119,7 +119,7 @@ class CommentBlock extends Comment {
|
||||
*/
|
||||
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and
|
||||
this.lastComment().getLocation().hasLocationInfo(filepath, _, _, endline, endcolumn)
|
||||
this.lastComment().getLocation().hasLocationInfo(_, _, _, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,13 +22,15 @@ import UnsignedGEZero
|
||||
// #define PRINTMSG(val,msg) { if (val >= PRINTLEVEL) printf(msg); }
|
||||
//
|
||||
// So to reduce the number of false positives, we do not report a result if
|
||||
// the comparison is in a macro expansion.
|
||||
// the comparison is in a macro expansion. Similarly for template
|
||||
// instantiations.
|
||||
from
|
||||
ComparisonOperation cmp, SmallSide ss,
|
||||
float left, float right, boolean value,
|
||||
string reason
|
||||
where
|
||||
not cmp.isInMacroExpansion() and
|
||||
not cmp.isFromTemplateInstantiation(_) and
|
||||
reachablePointlessComparison(cmp, left, right, value, ss) and
|
||||
|
||||
// a comparison between an enum and zero is always valid because whether
|
||||
|
||||
@@ -25,7 +25,7 @@ predicate stringType(Type t, Type charType) {
|
||||
charType = t.(ArrayType).getBaseType()
|
||||
) and (
|
||||
charType.getUnspecifiedType() instanceof CharType or
|
||||
charType.getUnspecifiedType() instanceof WideCharType
|
||||
charType.getUnspecifiedType() instanceof Wchar_t
|
||||
)
|
||||
)
|
||||
or
|
||||
|
||||
@@ -25,7 +25,8 @@ private predicate formattingFunctionCallExpectedType(FormattingFunctionCall ffc,
|
||||
ffc.getTarget() = f and
|
||||
f.getFormatParameterIndex() = i and
|
||||
ffc.getArgument(i) = fl and
|
||||
fl.getConversionType(pos) = expected
|
||||
fl.getConversionType(pos) = expected and
|
||||
count(fl.getConversionType(pos)) = 1
|
||||
)
|
||||
}
|
||||
|
||||
@@ -66,30 +67,15 @@ predicate formatOtherArgType(FormattingFunctionCall ffc, int pos, Type expected,
|
||||
class ExpectedType extends Type
|
||||
{
|
||||
ExpectedType() {
|
||||
formatArgType(_, _, this, _, _) or
|
||||
formatOtherArgType(_, _, this, _, _) or
|
||||
exists(ExpectedType t |
|
||||
this = t.(PointerType).getBaseType()
|
||||
exists(Type t |
|
||||
(
|
||||
formatArgType(_, _, t, _, _) or
|
||||
formatOtherArgType(_, _, t, _, _)
|
||||
) and this = t.getUnspecifiedType()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an 'interesting' type that can be reached from `t` by removing
|
||||
* typedefs and specifiers. Note that this does not always mean removing
|
||||
* all typedefs and specifiers as `Type.getUnspecifiedType()` would, for
|
||||
* example if the interesting type is itself a typedef.
|
||||
*/
|
||||
ExpectedType getAnUnderlyingExpectedType(Type t) {
|
||||
(
|
||||
result = t
|
||||
) or (
|
||||
result = getAnUnderlyingExpectedType(t.(TypedefType).getBaseType())
|
||||
) or (
|
||||
result = getAnUnderlyingExpectedType(t.(SpecifiedType).getBaseType())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if it is safe to display a value of type `actual` when `printf`
|
||||
* expects a value of type `expected`.
|
||||
@@ -100,59 +86,48 @@ ExpectedType getAnUnderlyingExpectedType(Type t) {
|
||||
* are converted to `double`.
|
||||
*/
|
||||
predicate trivialConversion(ExpectedType expected, Type actual) {
|
||||
formatArgType(_, _, expected, _, actual) and
|
||||
|
||||
exists(Type actualU |
|
||||
actualU = actual.getUnspecifiedType() and
|
||||
exists(Type exp, Type act |
|
||||
formatArgType(_, _, exp, _, act) and
|
||||
expected = exp.getUnspecifiedType() and
|
||||
actual = act.getUnspecifiedType()
|
||||
) and (
|
||||
(
|
||||
(
|
||||
// allow a pointer type to be displayed with `%p`
|
||||
expected instanceof VoidPointerType and actualU instanceof PointerType
|
||||
) or (
|
||||
// allow a function pointer type to be displayed with `%p`
|
||||
expected instanceof VoidPointerType and actualU instanceof FunctionPointerType and expected.getSize() = actual.getSize()
|
||||
) or (
|
||||
// allow an `enum` type to be displayed with `%i`, `%c` etc
|
||||
expected instanceof IntegralType and actualU instanceof Enum
|
||||
) or (
|
||||
// allow any `char *` type to be displayed with `%s`
|
||||
expected instanceof CharPointerType and actualU instanceof CharPointerType
|
||||
) or (
|
||||
// allow `wchar_t *`, or any pointer to an integral type of the same size, to be displayed
|
||||
// with `%ws`
|
||||
expected.(PointerType).getBaseType().hasName("wchar_t") and
|
||||
exists(Wchar_t t |
|
||||
actual.getUnspecifiedType().(PointerType).getBaseType().(IntegralType).getSize() = t.getSize()
|
||||
)
|
||||
) or (
|
||||
// allow an `int` (or anything promoted to `int`) to be displayed with `%c`
|
||||
expected instanceof CharType and actualU instanceof IntType
|
||||
) or (
|
||||
// allow an `int` (or anything promoted to `int`) to be displayed with `%wc`
|
||||
expected instanceof Wchar_t and actualU instanceof IntType
|
||||
) or (
|
||||
expected instanceof UnsignedCharType and actualU instanceof IntType
|
||||
) or (
|
||||
// allow the underlying type of a `size_t` (e.g. `unsigned long`) for
|
||||
// `%zu`, since this is the type of a `sizeof` expression
|
||||
expected instanceof Size_t and
|
||||
actual.getUnspecifiedType() = expected.getUnspecifiedType()
|
||||
) or (
|
||||
// allow the underlying type of a `ssize_t` (e.g. `long`) for `%zd`
|
||||
expected instanceof Ssize_t and
|
||||
actual.getUnspecifiedType() = expected.getUnspecifiedType()
|
||||
) or (
|
||||
// allow any integral type of the same size
|
||||
// (this permits signedness changes)
|
||||
expected.(IntegralType).getSize() = actualU.(IntegralType).getSize()
|
||||
) or (
|
||||
// allow a pointer to any integral type of the same size
|
||||
// (this permits signedness changes)
|
||||
expected.(PointerType).getBaseType().(IntegralType).getSize() = actualU.(PointerType).getBaseType().(IntegralType).getSize()
|
||||
) or (
|
||||
// allow expected, or a typedef or specified version of expected
|
||||
expected = getAnUnderlyingExpectedType(actual)
|
||||
// allow a pointer type to be displayed with `%p`
|
||||
expected instanceof VoidPointerType and actual instanceof PointerType
|
||||
) or (
|
||||
// allow a function pointer type to be displayed with `%p`
|
||||
expected instanceof VoidPointerType and actual instanceof FunctionPointerType and expected.getSize() = actual.getSize()
|
||||
) or (
|
||||
// allow an `enum` type to be displayed with `%i`, `%c` etc
|
||||
expected instanceof IntegralType and actual instanceof Enum
|
||||
) or (
|
||||
// allow any `char *` type to be displayed with `%s`
|
||||
expected instanceof CharPointerType and actual instanceof CharPointerType
|
||||
) or (
|
||||
// allow `wchar_t *`, or any pointer to an integral type of the same size, to be displayed
|
||||
// with `%ws`
|
||||
expected.(PointerType).getBaseType().hasName("wchar_t") and
|
||||
exists(Wchar_t t |
|
||||
actual.getUnspecifiedType().(PointerType).getBaseType().(IntegralType).getSize() = t.getSize()
|
||||
)
|
||||
) or (
|
||||
// allow an `int` (or anything promoted to `int`) to be displayed with `%c`
|
||||
expected instanceof CharType and actual instanceof IntType
|
||||
) or (
|
||||
// allow an `int` (or anything promoted to `int`) to be displayed with `%wc`
|
||||
expected instanceof Wchar_t and actual instanceof IntType
|
||||
) or (
|
||||
expected instanceof UnsignedCharType and actual instanceof IntType
|
||||
) or (
|
||||
// allow any integral type of the same size
|
||||
// (this permits signedness changes)
|
||||
expected.(IntegralType).getSize() = actual.(IntegralType).getSize()
|
||||
) or (
|
||||
// allow a pointer to any integral type of the same size
|
||||
// (this permits signedness changes)
|
||||
expected.(PointerType).getBaseType().(IntegralType).getSize() = actual.(PointerType).getBaseType().(IntegralType).getSize()
|
||||
) or (
|
||||
expected = actual
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -164,16 +139,16 @@ int sizeof_IntType() {
|
||||
exists(IntType it | result = it.getSize())
|
||||
}
|
||||
|
||||
from FormattingFunctionCall ffc, int n, Expr arg, ExpectedType expected, Type actual
|
||||
from FormattingFunctionCall ffc, int n, Expr arg, Type expected, Type actual
|
||||
where (
|
||||
(
|
||||
formatArgType(ffc, n, expected, arg, actual) and
|
||||
not trivialConversion(expected, actual)
|
||||
not trivialConversion(expected.getUnspecifiedType(), actual.getUnspecifiedType())
|
||||
)
|
||||
or
|
||||
(
|
||||
formatOtherArgType(ffc, n, expected, arg, actual) and
|
||||
not actual.getUnderlyingType().(IntegralType).getSize() = sizeof_IntType()
|
||||
not actual.getUnspecifiedType().(IntegralType).getSize() = sizeof_IntType()
|
||||
)
|
||||
)
|
||||
and not arg.isAffectedByMacro()
|
||||
|
||||
@@ -41,11 +41,13 @@ Type stripType(Type t) {
|
||||
result = stripType(t.(ArrayType).getBaseType()) or
|
||||
result = stripType(t.(ReferenceType).getBaseType()) or
|
||||
result = stripType(t.(SpecifiedType).getBaseType()) or
|
||||
result = stripType(t.(Decltype).getBaseType()) or
|
||||
(
|
||||
not t instanceof TypedefType and
|
||||
not t instanceof ArrayType and
|
||||
not t instanceof ReferenceType and
|
||||
not t instanceof SpecifiedType and
|
||||
not t instanceof Decltype and
|
||||
result = t
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,10 +11,21 @@
|
||||
|
||||
import cpp
|
||||
|
||||
from Initializer init, Variable v, VariableAccess va
|
||||
where init.getDeclaration() = v
|
||||
and va.getTarget() = v
|
||||
and va.getParent*() = init
|
||||
class VariableAccessInInitializer extends VariableAccess {
|
||||
Variable var;
|
||||
Initializer init;
|
||||
VariableAccessInInitializer() {
|
||||
init.getDeclaration() = var and
|
||||
init.getExpr().getAChild*() = this
|
||||
}
|
||||
|
||||
predicate initializesItself(Variable v, Initializer i) {
|
||||
v = var and i = init and var = this.getTarget()
|
||||
}
|
||||
}
|
||||
|
||||
from Initializer init, Variable v, VariableAccessInInitializer va
|
||||
where va.initializesItself(v, init)
|
||||
and (
|
||||
va.hasLValueToRValueConversion() or
|
||||
exists (Assignment assn | assn.getLValue() = va) or
|
||||
|
||||
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Semmle C/C++ Default Queries
|
||||
Bundle-SymbolicName: com.semmle.plugin.semmlecode.cpp.queries;singleton:=true
|
||||
Bundle-Version: 1.18.0.qualifier
|
||||
Bundle-Version: 1.18.1.qualifier
|
||||
Bundle-Vendor: Semmle Ltd.
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: com.semmle.plugin.qdt.ui;bundle-version="[1.18.0.qualifier,1.18.0.qualifier]"
|
||||
Require-Bundle: com.semmle.plugin.qdt.ui;bundle-version="[1.18.1.qualifier,1.18.1.qualifier]"
|
||||
|
||||
@@ -19,7 +19,7 @@ import cpp
|
||||
class AnyCharPointerType extends PointerType {
|
||||
AnyCharPointerType() {
|
||||
this.getBaseType().getUnderlyingType() instanceof CharType or
|
||||
this.getBaseType().getUnderlyingType() instanceof WideCharType
|
||||
this.getBaseType().getUnderlyingType() instanceof Wchar_t
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ class AnyCharPointerType extends PointerType {
|
||||
class AnyCharArrayType extends ArrayType {
|
||||
AnyCharArrayType() {
|
||||
this.getBaseType().getUnderlyingType() instanceof CharType or
|
||||
this.getBaseType().getUnderlyingType() instanceof WideCharType
|
||||
this.getBaseType().getUnderlyingType() instanceof Wchar_t
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
3
cpp/ql/src/Security/CWE/CWE-704/WcharCharConversion.cpp
Normal file
3
cpp/ql/src/Security/CWE/CWE-704/WcharCharConversion.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
wchar_t* pSrc;
|
||||
|
||||
pSrc = (wchar_t*)"a"; // casting a byte-string literal "a" to a wide-character string
|
||||
35
cpp/ql/src/Security/CWE/CWE-704/WcharCharConversion.qhelp
Normal file
35
cpp/ql/src/Security/CWE/CWE-704/WcharCharConversion.qhelp
Normal file
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>This rule indicates a potentially incorrect cast from an byte string (<code>char *</code>) to a wide-character string (<code>wchar_t *</code>).</p>
|
||||
<p>This cast might yield strings that are not correctly terminated; including potential buffer overruns when using such strings with some dangerous APIs.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>Do not explicitly cast byte strings to wide-character strings.</p>
|
||||
<p>For string literals, prepend the literal string with the letter "L" to indicate that the string is a wide-character string (<code>wchar_t *</code>).</p>
|
||||
<p>For converting a byte literal to a wide-character string literal, you would need to use the appropriate conversion function for the platform you are using. Please see the references section for options according to your platform.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>In the following example, an byte string literal (<code>"a"</code>) is cast to a wide-character string.</p>
|
||||
<sample src="WcharCharConversion.cpp" />
|
||||
|
||||
<p>To fix this issue, prepend the literal with the letter "L" (<code>L"a"</code>) to define it as a wide-character string.</p>
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
General resources:
|
||||
<a href="https://en.cppreference.com/w/cpp/string/multibyte/mbstowcs">std::mbstowcs</a>
|
||||
</li>
|
||||
<li>
|
||||
Microsoft specific resources:
|
||||
<a href="https://docs.microsoft.com/en-us/windows/desktop/Intl/security-considerations--international-features">Security Considerations: International Features</a>
|
||||
</li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
29
cpp/ql/src/Security/CWE/CWE-704/WcharCharConversion.ql
Normal file
29
cpp/ql/src/Security/CWE/CWE-704/WcharCharConversion.ql
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @name Cast from char* to wchar_t*
|
||||
* @description Casting a byte string to a wide-character string is likely
|
||||
* to yield a string that is incorrectly terminated or aligned.
|
||||
* This can lead to undefined behavior, including buffer overruns.
|
||||
* @kind problem
|
||||
* @id cpp/incorrect-string-type-conversion
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @tags security
|
||||
* external/cwe/cwe-704
|
||||
* external/microsoft/c/c6276
|
||||
*/
|
||||
import cpp
|
||||
|
||||
class WideCharPointerType extends PointerType {
|
||||
WideCharPointerType() {
|
||||
this.getBaseType() instanceof WideCharType
|
||||
}
|
||||
}
|
||||
|
||||
from Expr e1, Cast e2
|
||||
where
|
||||
e2 = e1.getConversion() and
|
||||
exists(WideCharPointerType w, CharPointerType c |
|
||||
w = e2.getType().getUnspecifiedType().(PointerType) and
|
||||
c = e1.getType().getUnspecifiedType().(PointerType)
|
||||
)
|
||||
select e1, "Conversion from " + e1.getType().toString() + " to " + e2.getType().toString() + ". Use of invalid string can lead to undefined behavior."
|
||||
@@ -3,7 +3,7 @@
|
||||
* @description All functions that are not void should return a value on every exit path.
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @precision medium
|
||||
* @precision high
|
||||
* @id cpp/missing-return
|
||||
* @tags reliability
|
||||
* readability
|
||||
|
||||
@@ -2,41 +2,38 @@ import semmle.code.cpp.Location
|
||||
private import semmle.code.cpp.Enclosing
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
/**
|
||||
* Get the `@element` that represents this `@element`.
|
||||
* Normally this will simply be `e`, but sometimes it is not.
|
||||
* For example, for an incomplete struct `e` the result may be a
|
||||
* complete struct with the same name.
|
||||
*/
|
||||
private cached @element resolveElement(@element e) {
|
||||
if isClass(e)
|
||||
then result = resolveClass(e)
|
||||
else result = e
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the `Element` that represents this `@element`.
|
||||
* Normally this will simply be a cast of `e`, but sometimes it is not.
|
||||
* For example, for an incomplete struct `e` the result may be a
|
||||
* complete struct with the same name.
|
||||
*/
|
||||
pragma[inline]
|
||||
Element mkElement(@element e) {
|
||||
result = resolveElement(e)
|
||||
unresolveElement(result) = e
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an `@element` that resolves to the `Element`. This should
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Gets an `@element` that resolves to the `Element`. This should
|
||||
* normally only be called from member predicates, where `e` is not
|
||||
* `this` and you need the result for an argument to a database
|
||||
* extensional.
|
||||
* See `underlyingElement` for when `e` is `this`.
|
||||
*/
|
||||
pragma[inline]
|
||||
@element unresolveElement(Element e) {
|
||||
resolveElement(result) = e
|
||||
not result instanceof @usertype and
|
||||
result = e
|
||||
or
|
||||
e = resolveClass(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the `@element` that this `Element` extends. This should normally
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Gets the `@element` that this `Element` extends. This should normally
|
||||
* only be called from member predicates, where `e` is `this` and you
|
||||
* need the result for an argument to a database extensional.
|
||||
* See `unresolveElement` for when `e` is not `this`.
|
||||
@@ -53,10 +50,6 @@ Element mkElement(@element e) {
|
||||
* `getLocation`, or `hasLocationInfo`.
|
||||
*/
|
||||
class ElementBase extends @element {
|
||||
ElementBase() {
|
||||
this = resolveElement(_)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
@@ -294,13 +294,13 @@ class AttributeArgument extends Element, @attribute_arg {
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
if exists (@attribute_arg_empty self | mkElement(self) = this)
|
||||
if exists (@attribute_arg_empty self | self = underlyingElement(this))
|
||||
then result = "empty argument"
|
||||
else exists (string prefix, string tail
|
||||
| (if exists(getName())
|
||||
then prefix = getName() + "="
|
||||
else prefix = "") and
|
||||
(if exists (@attribute_arg_type self | mkElement(self) = this)
|
||||
(if exists (@attribute_arg_type self | self = underlyingElement(this))
|
||||
then tail = getValueType().getName()
|
||||
else tail = getValueText()) and
|
||||
result = prefix + tail)
|
||||
|
||||
@@ -7,6 +7,8 @@ private import semmle.code.cpp.internal.ResolveClass
|
||||
* A C/C++ type.
|
||||
*/
|
||||
class Type extends Locatable, @type {
|
||||
Type() { isType(underlyingElement(this)) }
|
||||
|
||||
/**
|
||||
* Gets the name of this type.
|
||||
*/
|
||||
@@ -599,6 +601,10 @@ class VoidType extends BuiltInType {
|
||||
|
||||
/**
|
||||
* The C/C++ wide character type.
|
||||
*
|
||||
* Note that on some platforms `wchar_t` doesn't exist as a built-in
|
||||
* type but a typedef is provided. Consider using the `Wchar_t` QL
|
||||
* class to include these types.
|
||||
*/
|
||||
class WideCharType extends IntegralType {
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
/**
|
||||
* A library for working with XML files and their content.
|
||||
* Provides classes and predicates for working with XML files and their content.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Location
|
||||
|
||||
/** An XML element that has a location. */
|
||||
abstract class XMLLocatable extends @xmllocatable {
|
||||
/** The source location for this element. */
|
||||
/** Gets the source location for this element. */
|
||||
Location getLocation() { xmllocations(this,result) }
|
||||
|
||||
/**
|
||||
* Whether this element has the specified location information,
|
||||
* Holds if this element has the specified location information,
|
||||
* including file path, start line, start column, end line and end column.
|
||||
*/
|
||||
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
|
||||
@@ -20,7 +20,7 @@ abstract class XMLLocatable extends @xmllocatable {
|
||||
)
|
||||
}
|
||||
|
||||
/** A printable representation of this element. */
|
||||
/** Gets a printable representation of this element. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
@@ -30,46 +30,49 @@ abstract class XMLLocatable extends @xmllocatable {
|
||||
*/
|
||||
class XMLParent extends @xmlparent {
|
||||
/**
|
||||
* A printable representation of this XML parent.
|
||||
* Gets a printable representation of this XML parent.
|
||||
* (Intended to be overridden in subclasses.)
|
||||
*/
|
||||
abstract string getName();
|
||||
|
||||
/** The file to which this XML parent belongs. */
|
||||
/** Gets the file to which this XML parent belongs. */
|
||||
XMLFile getFile() { result = this or xmlElements(this,_,_,_,result) }
|
||||
|
||||
/** The child element at a specified index of this XML parent. */
|
||||
/** Gets the child element at a specified index of this XML parent. */
|
||||
XMLElement getChild(int index) { xmlElements(result, _, this, index, _) }
|
||||
|
||||
/** A child element of this XML parent. */
|
||||
/** Gets a child element of this XML parent. */
|
||||
XMLElement getAChild() { xmlElements(result,_,this,_,_) }
|
||||
|
||||
/** A child element of this XML parent with the given `name`. */
|
||||
/** Gets a child element of this XML parent with the given `name`. */
|
||||
XMLElement getAChild(string name) { xmlElements(result,_,this,_,_) and result.hasName(name) }
|
||||
|
||||
/** A comment that is a child of this XML parent. */
|
||||
/** Gets a comment that is a child of this XML parent. */
|
||||
XMLComment getAComment() { xmlComments(result,_,this,_) }
|
||||
|
||||
/** A character sequence that is a child of this XML parent. */
|
||||
/** Gets a character sequence that is a child of this XML parent. */
|
||||
XMLCharacters getACharactersSet() { xmlChars(result,_,this,_,_,_) }
|
||||
|
||||
/** The depth in the tree. (Overridden in XMLElement.) */
|
||||
/** Gets the depth in the tree. (Overridden in XMLElement.) */
|
||||
int getDepth() { result = 0 }
|
||||
|
||||
/** The number of child XML elements of this XML parent. */
|
||||
/** Gets the number of child XML elements of this XML parent. */
|
||||
int getNumberOfChildren() {
|
||||
result = count(XMLElement e | xmlElements(e,_,this,_,_))
|
||||
}
|
||||
|
||||
/** The number of places in the body of this XML parent where text occurs. */
|
||||
/** Gets the number of places in the body of this XML parent where text occurs. */
|
||||
int getNumberOfCharacterSets() {
|
||||
result = count(int pos | xmlChars(_,_,this,pos,_,_))
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Internal.
|
||||
*
|
||||
* Append the character sequences of this XML parent from left to right, separated by a space,
|
||||
* up to a specified (zero-based) index.
|
||||
*/
|
||||
deprecated
|
||||
string charsSetUpTo(int n) {
|
||||
(n = 0 and xmlChars(_,result,this,0,_,_)) or
|
||||
(n > 0 and exists(string chars | xmlChars(_,chars,this,n,_,_) |
|
||||
@@ -78,18 +81,15 @@ class XMLParent extends @xmlparent {
|
||||
|
||||
/** Append all the character sequences of this XML parent from left to right, separated by a space. */
|
||||
string allCharactersString() {
|
||||
exists(int n | n = this.getNumberOfCharacterSets() |
|
||||
(n = 0 and result = "") or
|
||||
(n > 0 and result = this.charsSetUpTo(n-1))
|
||||
)
|
||||
result = concat(string chars, int pos | xmlChars(_, chars, this, pos, _, _) | chars, " " order by pos)
|
||||
}
|
||||
|
||||
/** The text value contained in this XML parent. */
|
||||
/** Gets the text value contained in this XML parent. */
|
||||
string getTextValue() {
|
||||
result = allCharactersString()
|
||||
}
|
||||
|
||||
/** A printable representation of this XML parent. */
|
||||
/** Gets a printable representation of this XML parent. */
|
||||
string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
@@ -99,54 +99,54 @@ class XMLFile extends XMLParent, File {
|
||||
xmlEncoding(this,_)
|
||||
}
|
||||
|
||||
/** A printable representation of this XML file. */
|
||||
/** Gets a printable representation of this XML file. */
|
||||
override
|
||||
string toString() { result = XMLParent.super.toString() }
|
||||
|
||||
/** The name of this XML file. */
|
||||
/** Gets the name of this XML file. */
|
||||
override
|
||||
string getName() { files(this,result,_,_,_) }
|
||||
|
||||
/** The path of this XML file. */
|
||||
/** Gets the path of this XML file. */
|
||||
string getPath() { files(this,_,result,_,_) }
|
||||
|
||||
/** The path of the folder that contains this XML file. */
|
||||
/** Gets the path of the folder that contains this XML file. */
|
||||
string getFolder() {
|
||||
result = this.getPath().substring(0, this.getPath().length()-this.getName().length())
|
||||
}
|
||||
|
||||
/** The encoding of this XML file. */
|
||||
/** Gets the encoding of this XML file. */
|
||||
string getEncoding() { xmlEncoding(this,result) }
|
||||
|
||||
/** The XML file itself. */
|
||||
/** Gets the XML file itself. */
|
||||
override
|
||||
XMLFile getFile() { result = this }
|
||||
|
||||
/** A top-most element in an XML file. */
|
||||
/** Gets a top-most element in an XML file. */
|
||||
XMLElement getARootElement() { result = this.getAChild() }
|
||||
|
||||
/** A DTD associated with this XML file. */
|
||||
/** Gets a DTD associated with this XML file. */
|
||||
XMLDTD getADTD() { xmlDTDs(result,_,_,_,this) }
|
||||
}
|
||||
|
||||
/** A "Document Type Definition" of an XML file. */
|
||||
class XMLDTD extends @xmldtd {
|
||||
/** The name of the root element of this DTD. */
|
||||
/** Gets the name of the root element of this DTD. */
|
||||
string getRoot() { xmlDTDs(this,result,_,_,_) }
|
||||
|
||||
/** The public ID of this DTD. */
|
||||
/** Gets the public ID of this DTD. */
|
||||
string getPublicId() { xmlDTDs(this,_,result,_,_) }
|
||||
|
||||
/** The system ID of this DTD. */
|
||||
/** Gets the system ID of this DTD. */
|
||||
string getSystemId() { xmlDTDs(this,_,_,result,_) }
|
||||
|
||||
/** Whether this DTD is public. */
|
||||
/** Holds if this DTD is public. */
|
||||
predicate isPublic() { not xmlDTDs(this,_,"",_,_) }
|
||||
|
||||
/** The parent of this DTD. */
|
||||
/** Gets the parent of this DTD. */
|
||||
XMLParent getParent() { xmlDTDs(this,_,_,_,result) }
|
||||
|
||||
/** A printable representation of this DTD. */
|
||||
/** Gets a printable representation of this DTD. */
|
||||
string toString() {
|
||||
(this.isPublic() and result = this.getRoot() + " PUBLIC '" +
|
||||
this.getPublicId() + "' '" +
|
||||
@@ -159,92 +159,92 @@ class XMLDTD extends @xmldtd {
|
||||
|
||||
/** An XML tag in an XML file. */
|
||||
class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
||||
/** Whether this XML element has the given `name`. */
|
||||
/** Holds if this XML element has the given `name`. */
|
||||
predicate hasName(string name) { name = getName() }
|
||||
|
||||
/** The name of this XML element. */
|
||||
/** Gets the name of this XML element. */
|
||||
override
|
||||
string getName() { xmlElements(this,result,_,_,_) }
|
||||
|
||||
/** The XML file in which this XML element occurs. */
|
||||
/** Gets the XML file in which this XML element occurs. */
|
||||
override
|
||||
XMLFile getFile() { xmlElements(this,_,_,_,result) }
|
||||
|
||||
/** The parent of this XML element. */
|
||||
/** Gets the parent of this XML element. */
|
||||
XMLParent getParent() { xmlElements(this,_,result,_,_) }
|
||||
|
||||
/** The index of this XML element among its parent's children. */
|
||||
/** Gets the index of this XML element among its parent's children. */
|
||||
int getIndex() { xmlElements(this, _, _, result, _) }
|
||||
|
||||
/** Whether this XML element has a namespace. */
|
||||
/** Holds if this XML element has a namespace. */
|
||||
predicate hasNamespace() { xmlHasNs(this,_,_) }
|
||||
|
||||
/** The namespace of this XML element, if any. */
|
||||
/** Gets the namespace of this XML element, if any. */
|
||||
XMLNamespace getNamespace() { xmlHasNs(this,result,_) }
|
||||
|
||||
/** The index of this XML element among its parent's children. */
|
||||
/** Gets the index of this XML element among its parent's children. */
|
||||
int getElementPositionIndex() { xmlElements(this,_,_,result,_) }
|
||||
|
||||
/** The depth of this element within the XML file tree structure. */
|
||||
/** Gets the depth of this element within the XML file tree structure. */
|
||||
override
|
||||
int getDepth() { result = this.getParent().getDepth() + 1 }
|
||||
|
||||
/** An XML attribute of this XML element. */
|
||||
/** Gets an XML attribute of this XML element. */
|
||||
XMLAttribute getAnAttribute() { result.getElement() = this }
|
||||
|
||||
/** The attribute with the specified `name`, if any. */
|
||||
/** Gets the attribute with the specified `name`, if any. */
|
||||
XMLAttribute getAttribute(string name) {
|
||||
result.getElement() = this and result.getName() = name
|
||||
}
|
||||
|
||||
/** Whether this XML element has an attribute with the specified `name`. */
|
||||
/** Holds if this XML element has an attribute with the specified `name`. */
|
||||
predicate hasAttribute(string name) {
|
||||
exists(XMLAttribute a| a = this.getAttribute(name))
|
||||
}
|
||||
|
||||
/** The value of the attribute with the specified `name`, if any. */
|
||||
/** Gets the value of the attribute with the specified `name`, if any. */
|
||||
string getAttributeValue(string name) {
|
||||
result = this.getAttribute(name).getValue()
|
||||
}
|
||||
|
||||
/** A printable representation of this XML element. */
|
||||
/** Gets a printable representation of this XML element. */
|
||||
override
|
||||
string toString() { result = XMLParent.super.toString() }
|
||||
}
|
||||
|
||||
/** An attribute that occurs inside an XML element. */
|
||||
class XMLAttribute extends @xmlattribute, XMLLocatable {
|
||||
/** The name of this attribute. */
|
||||
/** Gets the name of this attribute. */
|
||||
string getName() { xmlAttrs(this,_,result,_,_,_) }
|
||||
|
||||
/** The XML element to which this attribute belongs. */
|
||||
/** Gets the XML element to which this attribute belongs. */
|
||||
XMLElement getElement() { xmlAttrs(this,result,_,_,_,_) }
|
||||
|
||||
/** Whether this attribute has a namespace. */
|
||||
/** Holds if this attribute has a namespace. */
|
||||
predicate hasNamespace() { xmlHasNs(this,_,_) }
|
||||
|
||||
/** The namespace of this attribute, if any. */
|
||||
/** Gets the namespace of this attribute, if any. */
|
||||
XMLNamespace getNamespace() { xmlHasNs(this,result,_) }
|
||||
|
||||
/** The value of this attribute. */
|
||||
/** Gets the value of this attribute. */
|
||||
string getValue() { xmlAttrs(this,_,_,result,_,_) }
|
||||
|
||||
/** A printable representation of this XML attribute. */
|
||||
/** Gets a printable representation of this XML attribute. */
|
||||
override string toString() { result = this.getName() + "=" + this.getValue() }
|
||||
}
|
||||
|
||||
/** A namespace used in an XML file */
|
||||
class XMLNamespace extends @xmlnamespace {
|
||||
/** The prefix of this namespace. */
|
||||
/** Gets the prefix of this namespace. */
|
||||
string getPrefix() { xmlNs(this,result,_,_) }
|
||||
|
||||
/** The URI of this namespace. */
|
||||
/** Gets the URI of this namespace. */
|
||||
string getURI() { xmlNs(this,_,result,_) }
|
||||
|
||||
/** Whether this namespace has no prefix. */
|
||||
/** Holds if this namespace has no prefix. */
|
||||
predicate isDefault() { this.getPrefix() = "" }
|
||||
|
||||
/** A printable representation of this XML namespace. */
|
||||
/** Gets a printable representation of this XML namespace. */
|
||||
string toString() {
|
||||
(this.isDefault() and result = this.getURI()) or
|
||||
(not this.isDefault() and result = this.getPrefix() + ":" + this.getURI())
|
||||
@@ -253,13 +253,13 @@ class XMLNamespace extends @xmlnamespace {
|
||||
|
||||
/** A comment of the form `<!-- ... -->` is an XML comment. */
|
||||
class XMLComment extends @xmlcomment, XMLLocatable {
|
||||
/** The text content of this XML comment. */
|
||||
/** Gets the text content of this XML comment. */
|
||||
string getText() { xmlComments(this,result,_,_) }
|
||||
|
||||
/** The parent of this XML comment. */
|
||||
/** Gets the parent of this XML comment. */
|
||||
XMLParent getParent() { xmlComments(this,_,result,_) }
|
||||
|
||||
/** A printable representation of this XML comment. */
|
||||
/** Gets a printable representation of this XML comment. */
|
||||
override string toString() { result = this.getText() }
|
||||
}
|
||||
|
||||
@@ -268,15 +268,15 @@ class XMLComment extends @xmlcomment, XMLLocatable {
|
||||
* closing tags of an XML element, excluding other elements.
|
||||
*/
|
||||
class XMLCharacters extends @xmlcharacters, XMLLocatable {
|
||||
/** The content of this character sequence. */
|
||||
/** Gets the content of this character sequence. */
|
||||
string getCharacters() { xmlChars(this,result,_,_,_,_) }
|
||||
|
||||
/** The parent of this character sequence. */
|
||||
/** Gets the parent of this character sequence. */
|
||||
XMLParent getParent() { xmlChars(this,_,result,_,_,_) }
|
||||
|
||||
/** Whether this character sequence is CDATA. */
|
||||
/** Holds if this character sequence is CDATA. */
|
||||
predicate isCDATA() { xmlChars(this,_,_,_,1,_) }
|
||||
|
||||
/** A printable representation of this XML character sequence. */
|
||||
/** Gets a printable representation of this XML character sequence. */
|
||||
override string toString() { result = this.getCharacters() }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import semmle.code.cpp.Type
|
||||
|
||||
/**
|
||||
* The C/C++ char* type.
|
||||
* The C/C++ `char*` type.
|
||||
*/
|
||||
class CharPointerType extends PointerType {
|
||||
|
||||
@@ -10,7 +10,7 @@ class CharPointerType extends PointerType {
|
||||
}
|
||||
|
||||
/**
|
||||
* The C/C++ int* type.
|
||||
* The C/C++ `int*` type.
|
||||
*/
|
||||
class IntPointerType extends PointerType {
|
||||
|
||||
@@ -20,7 +20,7 @@ class IntPointerType extends PointerType {
|
||||
|
||||
|
||||
/**
|
||||
* The C/C++ void* type.
|
||||
* The C/C++ `void*` type.
|
||||
*/
|
||||
class VoidPointerType extends PointerType {
|
||||
|
||||
@@ -29,7 +29,7 @@ class VoidPointerType extends PointerType {
|
||||
}
|
||||
|
||||
/**
|
||||
* The C/C++ size_t type.
|
||||
* The C/C++ `size_t` type.
|
||||
*/
|
||||
class Size_t extends Type {
|
||||
Size_t() {
|
||||
@@ -39,7 +39,7 @@ class Size_t extends Type {
|
||||
}
|
||||
|
||||
/**
|
||||
* The C/C++ ssize_t type.
|
||||
* The C/C++ `ssize_t` type.
|
||||
*/
|
||||
class Ssize_t extends Type {
|
||||
Ssize_t() {
|
||||
@@ -49,7 +49,7 @@ class Ssize_t extends Type {
|
||||
}
|
||||
|
||||
/**
|
||||
* The C/C++ ptrdiff_t type.
|
||||
* The C/C++ `ptrdiff_t` type.
|
||||
*/
|
||||
class Ptrdiff_t extends Type {
|
||||
Ptrdiff_t() {
|
||||
@@ -59,7 +59,7 @@ class Ptrdiff_t extends Type {
|
||||
}
|
||||
|
||||
/**
|
||||
* The C/C++ intmax_t type.
|
||||
* The C/C++ `intmax_t` type.
|
||||
*/
|
||||
class Intmax_t extends Type {
|
||||
Intmax_t() {
|
||||
@@ -69,7 +69,7 @@ class Intmax_t extends Type {
|
||||
}
|
||||
|
||||
/**
|
||||
* The C/C++ uintmax_t type.
|
||||
* The C/C++ `uintmax_t` type.
|
||||
*/
|
||||
class Uintmax_t extends Type {
|
||||
Uintmax_t() {
|
||||
@@ -79,7 +79,11 @@ class Uintmax_t extends Type {
|
||||
}
|
||||
|
||||
/**
|
||||
* The C/C++ wchar_t type.
|
||||
* The C/C++ `wchar_t` type.
|
||||
*
|
||||
* Note that on some platforms `wchar_t` doesn't exist as a built-in
|
||||
* type but a typedef is provided. This QL class includes both cases
|
||||
* (see also `WideCharType`).
|
||||
*/
|
||||
class Wchar_t extends Type {
|
||||
Wchar_t() {
|
||||
|
||||
@@ -220,6 +220,32 @@ class FormatLiteral extends Literal {
|
||||
getUse().getTarget().(FormattingFunction).isWideCharDefault()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default character type expected for `%s` by this format literal. Typically
|
||||
* `char` or `wchar_t`.
|
||||
*/
|
||||
Type getDefaultCharType() {
|
||||
result = getUse().getTarget().(FormattingFunction).getDefaultCharType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the non-default character type expected for `%S` by this format literal. Typically
|
||||
* `wchar_t` or `char`. On some snapshots there may be multiple results where we can't tell
|
||||
* which is correct for a particular function.
|
||||
*/
|
||||
Type getNonDefaultCharType() {
|
||||
result = getUse().getTarget().(FormattingFunction).getNonDefaultCharType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the wide character type for this format literal. This is usually `wchar_t`. On some
|
||||
* snapshots there may be multiple results where we can't tell which is correct for a
|
||||
* particular function.
|
||||
*/
|
||||
Type getWideCharType() {
|
||||
result = getUse().getTarget().(FormattingFunction).getWideCharType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this `FormatLiteral` is in a context that supports
|
||||
* Microsoft rules and extensions.
|
||||
@@ -629,7 +655,6 @@ class FormatLiteral extends Literal {
|
||||
result = getConversionType2(n) or
|
||||
result = getConversionType3(n) or
|
||||
result = getConversionType4(n) or
|
||||
result = getConversionType5(n) or
|
||||
result = getConversionType6(n) or
|
||||
result = getConversionType7(n) or
|
||||
result = getConversionType8(n) or
|
||||
@@ -696,33 +721,35 @@ class FormatLiteral extends Literal {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the 'effective' string type character, that is, 's' (meaning a char string) or
|
||||
* 'S' (meaning a wide string).
|
||||
* - in the base case this is the same as the format type character.
|
||||
* - for a `wprintf` or similar function call, the meanings are reversed.
|
||||
* - the size prefixes 'l'/'w' (long) and 'h' (short) override the
|
||||
* type character to effectively 'S' or 's' respectively.
|
||||
* Gets the string type required by the nth conversion specifier.
|
||||
* - in the base case this is the default for the formatting function
|
||||
* (e.g. `char` for `printf`, `wchar_t` for `wprintf`).
|
||||
* - the `%S` format character reverses wideness.
|
||||
* - the size prefixes 'l'/'w' and 'h' override the type character
|
||||
* to wide or single-byte characters respectively.
|
||||
*/
|
||||
private string getEffectiveStringConversionChar(int n) {
|
||||
exists(string len, string conv | this.parseConvSpec(n, _, _, _, _, _, len, conv) and (conv = "s" or conv = "S") |
|
||||
(len = "l" and result = "S") or
|
||||
(len = "w" and result = "S") or
|
||||
(len = "h" and result = "s") or
|
||||
(len != "l" and len != "w" and len != "h" and (result = "s" or result = "S") and (if isWideCharDefault() then result != conv else result = conv))
|
||||
)
|
||||
}
|
||||
|
||||
private Type getConversionType4(int n) {
|
||||
exists(string cnv, CharType t | cnv = this.getEffectiveStringConversionChar(n) |
|
||||
cnv="s" and t = result.(PointerType).getBaseType()
|
||||
and not t.isExplicitlySigned()
|
||||
and not t.isExplicitlyUnsigned()
|
||||
)
|
||||
}
|
||||
|
||||
private Type getConversionType5(int n) {
|
||||
exists(string cnv | cnv = this.getEffectiveStringConversionChar(n) |
|
||||
cnv="S" and result.(PointerType).getBaseType().hasName("wchar_t")
|
||||
exists(string len, string conv |
|
||||
this.parseConvSpec(n, _, _, _, _, _, len, conv) and
|
||||
(
|
||||
(
|
||||
(conv = "s" or conv = "S") and
|
||||
len = "h" and
|
||||
result.(PointerType).getBaseType() instanceof PlainCharType
|
||||
) or (
|
||||
(conv = "s" or conv = "S") and
|
||||
(len = "l" or len = "w") and
|
||||
result.(PointerType).getBaseType() = getWideCharType()
|
||||
) or (
|
||||
conv = "s" and
|
||||
(len != "l" and len != "w" and len != "h") and
|
||||
result.(PointerType).getBaseType() = getDefaultCharType()
|
||||
) or (
|
||||
conv = "S" and
|
||||
(len != "l" and len != "w" and len != "h") and
|
||||
result.(PointerType).getBaseType() = getNonDefaultCharType()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
485
cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll
Normal file
485
cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll
Normal file
@@ -0,0 +1,485 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.IR
|
||||
|
||||
/**
|
||||
* A Boolean condition in the AST that guards one or more basic blocks. This includes
|
||||
* operands of logical operators but not switch statements.
|
||||
*/
|
||||
class GuardCondition extends Expr {
|
||||
GuardCondition() {
|
||||
exists(IRGuardCondition ir | this = ir.getUnconvertedResultExpression())
|
||||
or
|
||||
// no binary operators in the IR
|
||||
exists(GuardCondition gc |
|
||||
this.(BinaryLogicalOperation).getAnOperand()= gc
|
||||
)
|
||||
or
|
||||
// the IR short-circuits if(!x)
|
||||
(
|
||||
// don't produce a guard condition for `y = !x` and other non-short-circuited cases
|
||||
not exists (Instruction inst | this.getFullyConverted() = inst.getAST()) and
|
||||
exists(IRGuardCondition ir | this.(NotExpr).getOperand() = ir.getAST())
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Holds if this condition controls `block`, meaning that `block` is only
|
||||
* entered if the value of this condition is `testIsTrue`.
|
||||
*
|
||||
* Illustration:
|
||||
*
|
||||
* ```
|
||||
* [ (testIsTrue) ]
|
||||
* [ this ----------------succ ---- controlled ]
|
||||
* [ | | ]
|
||||
* [ (testIsFalse) | ------ ... ]
|
||||
* [ other ]
|
||||
* ```
|
||||
*
|
||||
* The predicate holds if all paths to `controlled` go via the `testIsTrue`
|
||||
* edge of the control-flow graph. In other words, the `testIsTrue` edge
|
||||
* must dominate `controlled`. This means that `controlled` must be
|
||||
* dominated by both `this` and `succ` (the target of the `testIsTrue`
|
||||
* edge). It also means that any other edge into `succ` must be a back-edge
|
||||
* from a node which is dominated by `succ`.
|
||||
*
|
||||
* The short-circuit boolean operations have slightly surprising behavior
|
||||
* here: because the operation itself only dominates one branch (due to
|
||||
* being short-circuited) then it will only control blocks dominated by the
|
||||
* true (for `&&`) or false (for `||`) branch.
|
||||
*/
|
||||
cached predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */
|
||||
cached predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left < right + k` must be `isLessThan` in `block`.
|
||||
If `isLessThan = false` then this implies `left >= right + k`. */
|
||||
cached predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */
|
||||
cached predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left == right + k` must be `areEqual` in `block`.
|
||||
If `areEqual = false` then this implies `left != right + k`. */
|
||||
cached predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A binary logical operator in the AST that guards one or more basic blocks.
|
||||
*/
|
||||
private class GuardConditionFromBinaryLogicalOperator extends GuardCondition {
|
||||
GuardConditionFromBinaryLogicalOperator() {
|
||||
exists(GuardCondition gc |
|
||||
this.(BinaryLogicalOperation).getAnOperand()= gc
|
||||
)
|
||||
}
|
||||
|
||||
override predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
||||
exists (BinaryLogicalOperation binop, GuardCondition lhs, GuardCondition rhs
|
||||
| this = binop and
|
||||
lhs = binop.getLeftOperand() and
|
||||
rhs = binop.getRightOperand() and
|
||||
lhs.controls(controlled, testIsTrue) and
|
||||
rhs.controls(controlled, testIsTrue))
|
||||
}
|
||||
|
||||
override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) {
|
||||
exists(boolean partIsTrue, GuardCondition part |
|
||||
this.(BinaryLogicalOperation).impliesValue(part, partIsTrue, testIsTrue) |
|
||||
part.comparesLt(left, right, k, isLessThan, partIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) {
|
||||
exists(boolean testIsTrue |
|
||||
comparesLt(left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate comparesEq(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) {
|
||||
exists(boolean partIsTrue, GuardCondition part |
|
||||
this.(BinaryLogicalOperation).impliesValue(part, partIsTrue, testIsTrue) |
|
||||
part.comparesEq(left, right, k, isLessThan, partIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) {
|
||||
exists(boolean testIsTrue |
|
||||
comparesEq(left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `!` operator in the AST that guards one or more basic blocks, and does not have a corresponding
|
||||
* IR instruction.
|
||||
*/
|
||||
private class GuardConditionFromShortCircuitNot extends GuardCondition, NotExpr {
|
||||
GuardConditionFromShortCircuitNot() {
|
||||
not exists (Instruction inst | this.getFullyConverted() = inst.getAST()) and
|
||||
exists(IRGuardCondition ir | getOperand() = ir.getAST())
|
||||
}
|
||||
|
||||
override predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
||||
getOperand().(GuardCondition).controls(controlled, testIsTrue.booleanNot())
|
||||
}
|
||||
|
||||
override predicate comparesLt(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
getOperand().(GuardCondition).comparesLt(left, right, k, areEqual, testIsTrue.booleanNot())
|
||||
}
|
||||
|
||||
override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean testIsTrue) {
|
||||
getOperand().(GuardCondition).ensuresLt(left, right, k, block, testIsTrue.booleanNot())
|
||||
}
|
||||
|
||||
override predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
getOperand().(GuardCondition).comparesEq(left, right, k, areEqual, testIsTrue.booleanNot())
|
||||
}
|
||||
|
||||
override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean testIsTrue) {
|
||||
getOperand().(GuardCondition).ensuresEq(left, right, k, block, testIsTrue.booleanNot())
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A Boolean condition in the AST that guards one or more basic blocks and has a corresponding IR
|
||||
* instruction.
|
||||
*/
|
||||
private class GuardConditionFromIR extends GuardCondition {
|
||||
IRGuardCondition ir;
|
||||
|
||||
GuardConditionFromIR() {
|
||||
this = ir.getUnconvertedResultExpression()
|
||||
}
|
||||
override predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
||||
/* This condition must determine the flow of control; that is, this
|
||||
* node must be a top-level condition. */
|
||||
this.controlsBlock(controlled, testIsTrue)
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */
|
||||
override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) {
|
||||
exists(Instruction li, Instruction ri |
|
||||
li.getUnconvertedResultExpression() = left and
|
||||
ri.getUnconvertedResultExpression() = right and
|
||||
ir.comparesLt(li, ri, k, isLessThan, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left < right + k` must be `isLessThan` in `block`.
|
||||
If `isLessThan = false` then this implies `left >= right + k`. */
|
||||
override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) {
|
||||
exists(Instruction li, Instruction ri, boolean testIsTrue |
|
||||
li.getUnconvertedResultExpression() = left and
|
||||
ri.getUnconvertedResultExpression() = right and
|
||||
ir.comparesLt(li, ri, k, isLessThan, testIsTrue) and
|
||||
this.controls(block, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */
|
||||
override predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
exists(Instruction li, Instruction ri |
|
||||
li.getUnconvertedResultExpression() = left and
|
||||
ri.getUnconvertedResultExpression() = right and
|
||||
ir.comparesEq(li, ri, k, areEqual, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left == right + k` must be `areEqual` in `block`.
|
||||
If `areEqual = false` then this implies `left != right + k`. */
|
||||
override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) {
|
||||
exists(Instruction li, Instruction ri, boolean testIsTrue |
|
||||
li.getUnconvertedResultExpression() = left and
|
||||
ri.getUnconvertedResultExpression() = right and
|
||||
ir.comparesEq(li, ri, k, areEqual, testIsTrue)
|
||||
and this.controls(block, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this condition controls `block`, meaning that `block` is only
|
||||
* entered if the value of this condition is `testIsTrue`. This helper
|
||||
* predicate does not necessarily hold for binary logical operations like
|
||||
* `&&` and `||`. See the detailed explanation on predicate `controls`.
|
||||
*/
|
||||
private predicate controlsBlock(BasicBlock controlled, boolean testIsTrue) {
|
||||
exists(IRBlock irb |
|
||||
forex(IRGuardCondition inst | inst = ir | inst.controls(irb, testIsTrue)) and
|
||||
irb.getAnInstruction().getAST().(ControlFlowNode).getBasicBlock() = controlled
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Boolean condition in the IR that guards one or more basic blocks. This includes
|
||||
* operands of logical operators but not switch statements. Note that `&&` and `||`
|
||||
* don't have an explicit representation in the IR, and therefore will not appear as
|
||||
* IRGuardConditions.
|
||||
*/
|
||||
class IRGuardCondition extends Instruction {
|
||||
|
||||
IRGuardCondition() {
|
||||
is_condition(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this condition controls `block`, meaning that `block` is only
|
||||
* entered if the value of this condition is `testIsTrue`.
|
||||
*
|
||||
* Illustration:
|
||||
*
|
||||
* ```
|
||||
* [ (testIsTrue) ]
|
||||
* [ this ----------------succ ---- controlled ]
|
||||
* [ | | ]
|
||||
* [ (testIsFalse) | ------ ... ]
|
||||
* [ other ]
|
||||
* ```
|
||||
*
|
||||
* The predicate holds if all paths to `controlled` go via the `testIsTrue`
|
||||
* edge of the control-flow graph. In other words, the `testIsTrue` edge
|
||||
* must dominate `controlled`. This means that `controlled` must be
|
||||
* dominated by both `this` and `succ` (the target of the `testIsTrue`
|
||||
* edge). It also means that any other edge into `succ` must be a back-edge
|
||||
* from a node which is dominated by `succ`.
|
||||
*
|
||||
* The short-circuit boolean operations have slightly surprising behavior
|
||||
* here: because the operation itself only dominates one branch (due to
|
||||
* being short-circuited) then it will only control blocks dominated by the
|
||||
* true (for `&&`) or false (for `||`) branch.
|
||||
*/
|
||||
cached predicate controls(IRBlock controlled, boolean testIsTrue) {
|
||||
/* This condition must determine the flow of control; that is, this
|
||||
* node must be a top-level condition. */
|
||||
this.controlsBlock(controlled, testIsTrue)
|
||||
or
|
||||
exists (IRGuardCondition ne
|
||||
| this = ne.(LogicalNotInstruction).getOperand() and
|
||||
ne.controls(controlled, testIsTrue.booleanNot()))
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */
|
||||
cached predicate comparesLt(Instruction left, Instruction right, int k, boolean isLessThan, boolean testIsTrue) {
|
||||
compares_lt(this, left, right, k, isLessThan, testIsTrue)
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left < right + k` must be `isLessThan` in `block`.
|
||||
If `isLessThan = false` then this implies `left >= right + k`. */
|
||||
cached predicate ensuresLt(Instruction left, Instruction right, int k, IRBlock block, boolean isLessThan) {
|
||||
exists(boolean testIsTrue |
|
||||
compares_lt(this, left, right, k, isLessThan, testIsTrue) and this.controls(block, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */
|
||||
cached predicate comparesEq(Instruction left, Instruction right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
compares_eq(this, left, right, k, areEqual, testIsTrue)
|
||||
}
|
||||
|
||||
/** Holds if (determined by this guard) `left == right + k` must be `areEqual` in `block`.
|
||||
If `areEqual = false` then this implies `left != right + k`. */
|
||||
cached predicate ensuresEq(Instruction left, Instruction right, int k, IRBlock block, boolean areEqual) {
|
||||
exists(boolean testIsTrue |
|
||||
compares_eq(this, left, right, k, areEqual, testIsTrue) and this.controls(block, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this condition controls `block`, meaning that `block` is only
|
||||
* entered if the value of this condition is `testIsTrue`. This helper
|
||||
* predicate does not necessarily hold for binary logical operations like
|
||||
* `&&` and `||`. See the detailed explanation on predicate `controls`.
|
||||
*/
|
||||
private predicate controlsBlock(IRBlock controlled, boolean testIsTrue) {
|
||||
exists(IRBlock thisblock
|
||||
| thisblock.getAnInstruction() = this
|
||||
| exists(IRBlock succ, ConditionalBranchInstruction branch
|
||||
| testIsTrue = true and succ.getFirstInstruction() = branch.getTrueSuccessor()
|
||||
or
|
||||
testIsTrue = false and succ.getFirstInstruction() = branch.getFalseSuccessor()
|
||||
| branch.getCondition() = this and
|
||||
succ.dominates(controlled) and
|
||||
forall(IRBlock pred
|
||||
| pred.getASuccessor() = succ
|
||||
| pred = thisblock or succ.dominates(pred) or not pred.isReachableFromFunctionEntry())))
|
||||
}
|
||||
}
|
||||
|
||||
private predicate is_condition(Instruction guard) {
|
||||
exists(ConditionalBranchInstruction branch|
|
||||
branch.getCondition() = guard
|
||||
)
|
||||
or
|
||||
exists(LogicalNotInstruction cond | is_condition(cond) and cond.getOperand() = guard)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `left == right + k` is `areEqual` given that test is `testIsTrue`.
|
||||
*
|
||||
* Beware making mistaken logical implications here relating `areEqual` and `testIsTrue`.
|
||||
*/
|
||||
private predicate compares_eq(Instruction test, Instruction left, Instruction right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
/* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */
|
||||
exists(boolean eq | simple_comparison_eq(test, left, right, k, eq) |
|
||||
areEqual = true and testIsTrue = eq or areEqual = false and testIsTrue = eq.booleanNot()
|
||||
)
|
||||
// I think this is handled by forwarding in controlsBlock.
|
||||
/* or
|
||||
logical_comparison_eq(test, left, right, k, areEqual, testIsTrue) */
|
||||
or
|
||||
/* a == b + k => b == a - k */
|
||||
exists(int mk | k = -mk | compares_eq(test, right, left, mk, areEqual, testIsTrue))
|
||||
or
|
||||
complex_eq(test, left, right, k, areEqual, testIsTrue)
|
||||
or
|
||||
/* (x is true => (left == right + k)) => (!x is false => (left == right + k)) */
|
||||
exists(boolean isFalse | testIsTrue = isFalse.booleanNot() |
|
||||
compares_eq(test.(LogicalNotInstruction).getOperand(), left, right, k, areEqual, isFalse)
|
||||
)
|
||||
}
|
||||
|
||||
/** Rearrange various simple comparisons into `left == right + k` form. */
|
||||
private predicate simple_comparison_eq(CompareInstruction cmp, Instruction left, Instruction right, int k, boolean areEqual) {
|
||||
left = cmp.getLeftOperand() and cmp instanceof CompareEQInstruction and right = cmp.getRightOperand() and k = 0 and areEqual = true
|
||||
or
|
||||
left = cmp.getLeftOperand() and cmp instanceof CompareNEInstruction and right = cmp.getRightOperand() and k = 0 and areEqual = false
|
||||
}
|
||||
|
||||
private predicate complex_eq(CompareInstruction cmp, Instruction left, Instruction right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
sub_eq(cmp, left, right, k, areEqual, testIsTrue)
|
||||
or
|
||||
add_eq(cmp, left, right, k, areEqual, testIsTrue)
|
||||
}
|
||||
|
||||
|
||||
/* Simplification of inequality expressions
|
||||
* Simplify conditions in the source to the canonical form l < r + k.
|
||||
*/
|
||||
|
||||
/** Holds if `left < right + k` evaluates to `isLt` given that test is `testIsTrue`. */
|
||||
private predicate compares_lt(Instruction test, Instruction left, Instruction right, int k, boolean isLt, boolean testIsTrue) {
|
||||
/* In the simple case, the test is the comparison, so isLt = testIsTrue */
|
||||
simple_comparison_lt(test, left, right, k) and isLt = true and testIsTrue = true
|
||||
or
|
||||
simple_comparison_lt(test, left, right, k) and isLt = false and testIsTrue = false
|
||||
or
|
||||
complex_lt(test, left, right, k, isLt, testIsTrue)
|
||||
or
|
||||
/* (not (left < right + k)) => (left >= right + k) */
|
||||
exists(boolean isGe | isLt = isGe.booleanNot() |
|
||||
compares_ge(test, left, right, k, isGe, testIsTrue)
|
||||
)
|
||||
or
|
||||
/* (x is true => (left < right + k)) => (!x is false => (left < right + k)) */
|
||||
exists(boolean isFalse | testIsTrue = isFalse.booleanNot() |
|
||||
compares_lt(test.(LogicalNotInstruction).getOperand(), left, right, k, isLt, isFalse)
|
||||
)
|
||||
}
|
||||
|
||||
/** `(a < b + k) => (b > a - k) => (b >= a + (1-k))` */
|
||||
private predicate compares_ge(Instruction test, Instruction left, Instruction right, int k, boolean isGe, boolean testIsTrue) {
|
||||
exists(int onemk | k = 1 - onemk | compares_lt(test, right, left, onemk, isGe, testIsTrue))
|
||||
}
|
||||
|
||||
/** Rearrange various simple comparisons into `left < right + k` form. */
|
||||
private predicate simple_comparison_lt(CompareInstruction cmp, Instruction left, Instruction right, int k) {
|
||||
left = cmp.getLeftOperand() and cmp instanceof CompareLTInstruction and right = cmp.getRightOperand() and k = 0
|
||||
or
|
||||
left = cmp.getLeftOperand() and cmp instanceof CompareLEInstruction and right = cmp.getRightOperand() and k = 1
|
||||
or
|
||||
right = cmp.getLeftOperand() and cmp instanceof CompareGTInstruction and left = cmp.getRightOperand() and k = 0
|
||||
or
|
||||
right = cmp.getLeftOperand() and cmp instanceof CompareGEInstruction and left = cmp.getRightOperand() and k = 1
|
||||
}
|
||||
|
||||
private predicate complex_lt(CompareInstruction cmp, Instruction left, Instruction right, int k, boolean isLt, boolean testIsTrue) {
|
||||
sub_lt(cmp, left, right, k, isLt, testIsTrue)
|
||||
or
|
||||
add_lt(cmp, left, right, k, isLt, testIsTrue)
|
||||
}
|
||||
|
||||
|
||||
/* left - x < right + c => left < right + (c+x)
|
||||
left < (right - x) + c => left < right + (c-x) */
|
||||
private predicate sub_lt(CompareInstruction cmp, Instruction left, Instruction right, int k, boolean isLt, boolean testIsTrue) {
|
||||
exists(SubInstruction lhs, int c, int x | compares_lt(cmp, lhs, right, c, isLt, testIsTrue) and
|
||||
left = lhs.getLeftOperand() and x = int_value(lhs.getRightOperand())
|
||||
and k = c + x
|
||||
)
|
||||
or
|
||||
exists(SubInstruction rhs, int c, int x | compares_lt(cmp, left, rhs, c, isLt, testIsTrue) and
|
||||
right = rhs.getLeftOperand() and x = int_value(rhs.getRightOperand())
|
||||
and k = c - x
|
||||
)
|
||||
}
|
||||
|
||||
/* left + x < right + c => left < right + (c-x)
|
||||
left < (right + x) + c => left < right + (c+x) */
|
||||
private predicate add_lt(CompareInstruction cmp, Instruction left, Instruction right, int k, boolean isLt, boolean testIsTrue) {
|
||||
exists(AddInstruction lhs, int c, int x | compares_lt(cmp, lhs, right, c, isLt, testIsTrue) and
|
||||
(left = lhs.getLeftOperand() and x = int_value(lhs.getRightOperand())
|
||||
or
|
||||
left = lhs.getRightOperand() and x = int_value(lhs.getLeftOperand())
|
||||
)
|
||||
and k = c - x
|
||||
)
|
||||
or
|
||||
exists(AddInstruction rhs, int c, int x | compares_lt(cmp, left, rhs, c, isLt, testIsTrue) and
|
||||
(right = rhs.getLeftOperand() and x = int_value(rhs.getRightOperand())
|
||||
or
|
||||
right = rhs.getRightOperand() and x = int_value(rhs.getLeftOperand())
|
||||
)
|
||||
and k = c + x
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/* left - x == right + c => left == right + (c+x)
|
||||
left == (right - x) + c => left == right + (c-x) */
|
||||
private predicate sub_eq(CompareInstruction cmp, Instruction left, Instruction right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
exists(SubInstruction lhs, int c, int x | compares_eq(cmp, lhs, right, c, areEqual, testIsTrue) and
|
||||
left = lhs.getLeftOperand() and x = int_value(lhs.getRightOperand())
|
||||
and k = c + x
|
||||
)
|
||||
or
|
||||
exists(SubInstruction rhs, int c, int x | compares_eq(cmp, left, rhs, c, areEqual, testIsTrue) and
|
||||
right = rhs.getLeftOperand() and x = int_value(rhs.getRightOperand())
|
||||
and k = c - x
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/* left + x == right + c => left == right + (c-x)
|
||||
left == (right + x) + c => left == right + (c+x) */
|
||||
private predicate add_eq(CompareInstruction cmp, Instruction left, Instruction right, int k, boolean areEqual, boolean testIsTrue) {
|
||||
exists(AddInstruction lhs, int c, int x | compares_eq(cmp, lhs, right, c, areEqual, testIsTrue) and
|
||||
(left = lhs.getLeftOperand() and x = int_value(lhs.getRightOperand())
|
||||
or
|
||||
left = lhs.getRightOperand() and x = int_value(lhs.getLeftOperand())
|
||||
)
|
||||
and k = c - x
|
||||
)
|
||||
or
|
||||
exists(AddInstruction rhs, int c, int x | compares_eq(cmp, left, rhs, c, areEqual, testIsTrue) and
|
||||
(right = rhs.getLeftOperand() and x = int_value(rhs.getRightOperand())
|
||||
or
|
||||
right = rhs.getRightOperand() and x = int_value(rhs.getLeftOperand())
|
||||
)
|
||||
and k = c + x
|
||||
)
|
||||
}
|
||||
|
||||
/** The int value of integer constant expression. */
|
||||
private int int_value(Instruction i) {
|
||||
result = i.(IntegerConstantInstruction).getValue().toInt()
|
||||
}
|
||||
@@ -31,8 +31,11 @@ private cached module Cached {
|
||||
// or the node's predecessor has more than one successor,
|
||||
// then the node is the start of a new primitive basic block.
|
||||
or
|
||||
strictcount (Node pred, Node other
|
||||
| successors_extended(pred,node) and successors_extended(pred,other)) > 1
|
||||
strictcount(Node pred | successors_extended(pred, node)) > 1
|
||||
or
|
||||
exists(ControlFlowNode pred | successors_extended(pred, node) |
|
||||
strictcount(ControlFlowNode other | successors_extended(pred, other)) > 1
|
||||
)
|
||||
|
||||
// If the node has zero predecessors then it is the start of
|
||||
// a BB. However, the C++ AST contains many nodes with zero
|
||||
@@ -63,8 +66,14 @@ private cached module Cached {
|
||||
/** Holds if `node` is the `pos`th control-flow node in primitive basic block `bb`. */
|
||||
cached
|
||||
predicate primitive_basic_block_member(Node node, PrimitiveBasicBlock bb, int pos) {
|
||||
pos = getMemberIndex(node) and
|
||||
member_step*(bb, node)
|
||||
primitive_basic_block_entry_node(bb) and
|
||||
(
|
||||
pos = 0 and
|
||||
node = bb
|
||||
or
|
||||
pos = getMemberIndex(node) and
|
||||
member_step+(bb, node)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the number of control-flow nodes in the primitive basic block `bb`. */
|
||||
|
||||
@@ -54,4 +54,10 @@ cached private module Cached {
|
||||
(usertypes(t,_,1) or usertypes(t,_,2) or usertypes(t,_,3) or usertypes(t,_,6)
|
||||
or usertypes(t,_,10) or usertypes(t,_,11) or usertypes(t,_,12))
|
||||
}
|
||||
|
||||
cached predicate isType(@type t) {
|
||||
not isClass(t)
|
||||
or
|
||||
t = resolveClass(_)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,8 @@ abstract class PointerOffsetOpcode extends PointerArithmeticOpcode {}
|
||||
|
||||
abstract class CompareOpcode extends BinaryOpcode {}
|
||||
|
||||
abstract class RelationalOpcode extends CompareOpcode {}
|
||||
|
||||
abstract class CopyOpcode extends Opcode {}
|
||||
|
||||
abstract class MemoryAccessOpcode extends Opcode {}
|
||||
@@ -117,10 +119,10 @@ module Opcode {
|
||||
class LogicalNot extends UnaryOpcode, TLogicalNot { override final string toString() { result = "LogicalNot" } }
|
||||
class CompareEQ extends CompareOpcode, TCompareEQ { override final string toString() { result = "CompareEQ" } }
|
||||
class CompareNE extends CompareOpcode, TCompareNE { override final string toString() { result = "CompareNE" } }
|
||||
class CompareLT extends CompareOpcode, TCompareLT { override final string toString() { result = "CompareLT" } }
|
||||
class CompareGT extends CompareOpcode, TCompareGT { override final string toString() { result = "CompareGT" } }
|
||||
class CompareLE extends CompareOpcode, TCompareLE { override final string toString() { result = "CompareLE" } }
|
||||
class CompareGE extends CompareOpcode, TCompareGE { override final string toString() { result = "CompareGE" } }
|
||||
class CompareLT extends RelationalOpcode, TCompareLT { override final string toString() { result = "CompareLT" } }
|
||||
class CompareGT extends RelationalOpcode, TCompareGT { override final string toString() { result = "CompareGT" } }
|
||||
class CompareLE extends RelationalOpcode, TCompareLE { override final string toString() { result = "CompareLE" } }
|
||||
class CompareGE extends RelationalOpcode, TCompareGE { override final string toString() { result = "CompareGE" } }
|
||||
class PointerAdd extends PointerOffsetOpcode, TPointerAdd { override final string toString() { result = "PointerAdd" } }
|
||||
class PointerSub extends PointerOffsetOpcode, TPointerSub { override final string toString() { result = "PointerSub" } }
|
||||
class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { override final string toString() { result = "PointerDiff" } }
|
||||
|
||||
@@ -89,4 +89,12 @@ class IRBlock extends TIRBlock {
|
||||
dominates(result.getAPredecessor()) and
|
||||
not strictlyDominates(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this block is reachable from the entry point of its function
|
||||
*/
|
||||
final predicate isReachableFromFunctionEntry() {
|
||||
this = getFunctionIR().getEntryBlock() or
|
||||
getAPredecessor().isReachableFromFunctionEntry()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +133,16 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = getOpcode().toString() + ": " + getAST().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string showing the result, opcode, and operands of the instruction, equivalent to what
|
||||
* would be printed by PrintIR.ql. For example:
|
||||
*
|
||||
* `mu0_28(int) = Store r0_26, r0_27`
|
||||
*/
|
||||
final string getDumpString() {
|
||||
result = getResultString() + " = " + getOperationString() + " " + getOperandsString()
|
||||
}
|
||||
|
||||
@@ -310,11 +320,19 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Expr` whose results is computed by this instruction, if any.
|
||||
* Gets the `Expr` whose result is computed by this instruction, if any.
|
||||
*/
|
||||
final Expr getResultExpression() {
|
||||
result = Construction::getInstructionResultExpression(this)
|
||||
final Expr getConvertedResultExpression() {
|
||||
result = Construction::getInstructionConvertedResultExpression(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unconverted `Expr` whose result is computed by this instruction, if any.
|
||||
*/
|
||||
final Expr getUnconvertedResultExpression() {
|
||||
result = Construction::getInstructionUnconvertedResultExpression(this)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the
|
||||
@@ -967,28 +985,110 @@ class CompareNEInstruction extends CompareInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLTInstruction extends CompareInstruction {
|
||||
/**
|
||||
* Represents an instruction that does a relative comparison of two values, such as `<` or `>=`.
|
||||
*/
|
||||
class RelationalInstruction extends CompareInstruction {
|
||||
RelationalInstruction() {
|
||||
opcode instanceof RelationalOpcode
|
||||
}
|
||||
/**
|
||||
* Gets the operand on the "greater" (or "greater-or-equal") side
|
||||
* of this relational instruction, that is, the side that is larger
|
||||
* if the overall instruction evaluates to `true`; for example on
|
||||
* `x <= 20` this is the `20`, and on `y > 0` it is `y`.
|
||||
*/
|
||||
Instruction getGreaterOperand() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the operand on the "lesser" (or "lesser-or-equal") side
|
||||
* of this relational instruction, that is, the side that is smaller
|
||||
* if the overall instruction evaluates to `true`; for example on
|
||||
* `x <= 20` this is `x`, and on `y > 0` it is the `0`.
|
||||
*/
|
||||
Instruction getLesserOperand() {
|
||||
none()
|
||||
}
|
||||
/**
|
||||
* Holds if this relational instruction is strict (is not an "or-equal" instruction).
|
||||
*/
|
||||
predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLTInstruction extends RelationalInstruction {
|
||||
CompareLTInstruction() {
|
||||
opcode instanceof Opcode::CompareLT
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGTInstruction extends CompareInstruction {
|
||||
class CompareGTInstruction extends RelationalInstruction {
|
||||
CompareGTInstruction() {
|
||||
opcode instanceof Opcode::CompareGT
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLEInstruction extends CompareInstruction {
|
||||
CompareLEInstruction() {
|
||||
opcode instanceof Opcode::CompareLE
|
||||
override Instruction getLesserOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGEInstruction extends CompareInstruction {
|
||||
class CompareLEInstruction extends RelationalInstruction {
|
||||
CompareLEInstruction() {
|
||||
opcode instanceof Opcode::CompareLE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGEInstruction extends RelationalInstruction {
|
||||
CompareGEInstruction() {
|
||||
opcode instanceof Opcode::CompareGE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class SwitchInstruction extends Instruction {
|
||||
|
||||
@@ -197,8 +197,12 @@ cached private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached Expr getInstructionResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getResultExpression()
|
||||
cached Expr getInstructionConvertedResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getConvertedResultExpression()
|
||||
}
|
||||
|
||||
cached Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getUnconvertedResultExpression()
|
||||
}
|
||||
|
||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
|
||||
@@ -89,4 +89,12 @@ class IRBlock extends TIRBlock {
|
||||
dominates(result.getAPredecessor()) and
|
||||
not strictlyDominates(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this block is reachable from the entry point of its function
|
||||
*/
|
||||
final predicate isReachableFromFunctionEntry() {
|
||||
this = getFunctionIR().getEntryBlock() or
|
||||
getAPredecessor().isReachableFromFunctionEntry()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +133,16 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = getOpcode().toString() + ": " + getAST().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string showing the result, opcode, and operands of the instruction, equivalent to what
|
||||
* would be printed by PrintIR.ql. For example:
|
||||
*
|
||||
* `mu0_28(int) = Store r0_26, r0_27`
|
||||
*/
|
||||
final string getDumpString() {
|
||||
result = getResultString() + " = " + getOperationString() + " " + getOperandsString()
|
||||
}
|
||||
|
||||
@@ -310,11 +320,19 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Expr` whose results is computed by this instruction, if any.
|
||||
* Gets the `Expr` whose result is computed by this instruction, if any.
|
||||
*/
|
||||
final Expr getResultExpression() {
|
||||
result = Construction::getInstructionResultExpression(this)
|
||||
final Expr getConvertedResultExpression() {
|
||||
result = Construction::getInstructionConvertedResultExpression(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unconverted `Expr` whose result is computed by this instruction, if any.
|
||||
*/
|
||||
final Expr getUnconvertedResultExpression() {
|
||||
result = Construction::getInstructionUnconvertedResultExpression(this)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the
|
||||
@@ -967,28 +985,110 @@ class CompareNEInstruction extends CompareInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLTInstruction extends CompareInstruction {
|
||||
/**
|
||||
* Represents an instruction that does a relative comparison of two values, such as `<` or `>=`.
|
||||
*/
|
||||
class RelationalInstruction extends CompareInstruction {
|
||||
RelationalInstruction() {
|
||||
opcode instanceof RelationalOpcode
|
||||
}
|
||||
/**
|
||||
* Gets the operand on the "greater" (or "greater-or-equal") side
|
||||
* of this relational instruction, that is, the side that is larger
|
||||
* if the overall instruction evaluates to `true`; for example on
|
||||
* `x <= 20` this is the `20`, and on `y > 0` it is `y`.
|
||||
*/
|
||||
Instruction getGreaterOperand() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the operand on the "lesser" (or "lesser-or-equal") side
|
||||
* of this relational instruction, that is, the side that is smaller
|
||||
* if the overall instruction evaluates to `true`; for example on
|
||||
* `x <= 20` this is `x`, and on `y > 0` it is the `0`.
|
||||
*/
|
||||
Instruction getLesserOperand() {
|
||||
none()
|
||||
}
|
||||
/**
|
||||
* Holds if this relational instruction is strict (is not an "or-equal" instruction).
|
||||
*/
|
||||
predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLTInstruction extends RelationalInstruction {
|
||||
CompareLTInstruction() {
|
||||
opcode instanceof Opcode::CompareLT
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGTInstruction extends CompareInstruction {
|
||||
class CompareGTInstruction extends RelationalInstruction {
|
||||
CompareGTInstruction() {
|
||||
opcode instanceof Opcode::CompareGT
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLEInstruction extends CompareInstruction {
|
||||
CompareLEInstruction() {
|
||||
opcode instanceof Opcode::CompareLE
|
||||
override Instruction getLesserOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGEInstruction extends CompareInstruction {
|
||||
class CompareLEInstruction extends RelationalInstruction {
|
||||
CompareLEInstruction() {
|
||||
opcode instanceof Opcode::CompareLE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGEInstruction extends RelationalInstruction {
|
||||
CompareGEInstruction() {
|
||||
opcode instanceof Opcode::CompareGE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class SwitchInstruction extends Instruction {
|
||||
|
||||
@@ -74,13 +74,25 @@ cached private module Cached {
|
||||
none()
|
||||
}
|
||||
|
||||
cached Expr getInstructionResultExpression(Instruction instruction) {
|
||||
cached Expr getInstructionConvertedResultExpression(Instruction instruction) {
|
||||
exists(TranslatedExpr translatedExpr |
|
||||
translatedExpr = getTranslatedExpr(result) and
|
||||
instruction = translatedExpr.getResult()
|
||||
)
|
||||
}
|
||||
|
||||
cached Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
exists(Expr converted, TranslatedExpr translatedExpr |
|
||||
result = converted.(Conversion).getExpr+()
|
||||
or
|
||||
result = converted
|
||||
|
|
||||
not result instanceof Conversion and
|
||||
translatedExpr = getTranslatedExpr(converted) and
|
||||
instruction = translatedExpr.getResult()
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) {
|
||||
result = getInstructionTranslatedElement(instruction).getInstructionOperand(
|
||||
instruction.getTag(), tag)
|
||||
|
||||
@@ -89,4 +89,12 @@ class IRBlock extends TIRBlock {
|
||||
dominates(result.getAPredecessor()) and
|
||||
not strictlyDominates(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this block is reachable from the entry point of its function
|
||||
*/
|
||||
final predicate isReachableFromFunctionEntry() {
|
||||
this = getFunctionIR().getEntryBlock() or
|
||||
getAPredecessor().isReachableFromFunctionEntry()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +133,16 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = getOpcode().toString() + ": " + getAST().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string showing the result, opcode, and operands of the instruction, equivalent to what
|
||||
* would be printed by PrintIR.ql. For example:
|
||||
*
|
||||
* `mu0_28(int) = Store r0_26, r0_27`
|
||||
*/
|
||||
final string getDumpString() {
|
||||
result = getResultString() + " = " + getOperationString() + " " + getOperandsString()
|
||||
}
|
||||
|
||||
@@ -310,11 +320,19 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Expr` whose results is computed by this instruction, if any.
|
||||
* Gets the `Expr` whose result is computed by this instruction, if any.
|
||||
*/
|
||||
final Expr getResultExpression() {
|
||||
result = Construction::getInstructionResultExpression(this)
|
||||
final Expr getConvertedResultExpression() {
|
||||
result = Construction::getInstructionConvertedResultExpression(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unconverted `Expr` whose result is computed by this instruction, if any.
|
||||
*/
|
||||
final Expr getUnconvertedResultExpression() {
|
||||
result = Construction::getInstructionUnconvertedResultExpression(this)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the
|
||||
@@ -967,28 +985,110 @@ class CompareNEInstruction extends CompareInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLTInstruction extends CompareInstruction {
|
||||
/**
|
||||
* Represents an instruction that does a relative comparison of two values, such as `<` or `>=`.
|
||||
*/
|
||||
class RelationalInstruction extends CompareInstruction {
|
||||
RelationalInstruction() {
|
||||
opcode instanceof RelationalOpcode
|
||||
}
|
||||
/**
|
||||
* Gets the operand on the "greater" (or "greater-or-equal") side
|
||||
* of this relational instruction, that is, the side that is larger
|
||||
* if the overall instruction evaluates to `true`; for example on
|
||||
* `x <= 20` this is the `20`, and on `y > 0` it is `y`.
|
||||
*/
|
||||
Instruction getGreaterOperand() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the operand on the "lesser" (or "lesser-or-equal") side
|
||||
* of this relational instruction, that is, the side that is smaller
|
||||
* if the overall instruction evaluates to `true`; for example on
|
||||
* `x <= 20` this is `x`, and on `y > 0` it is the `0`.
|
||||
*/
|
||||
Instruction getLesserOperand() {
|
||||
none()
|
||||
}
|
||||
/**
|
||||
* Holds if this relational instruction is strict (is not an "or-equal" instruction).
|
||||
*/
|
||||
predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLTInstruction extends RelationalInstruction {
|
||||
CompareLTInstruction() {
|
||||
opcode instanceof Opcode::CompareLT
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGTInstruction extends CompareInstruction {
|
||||
class CompareGTInstruction extends RelationalInstruction {
|
||||
CompareGTInstruction() {
|
||||
opcode instanceof Opcode::CompareGT
|
||||
}
|
||||
}
|
||||
|
||||
class CompareLEInstruction extends CompareInstruction {
|
||||
CompareLEInstruction() {
|
||||
opcode instanceof Opcode::CompareLE
|
||||
override Instruction getLesserOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGEInstruction extends CompareInstruction {
|
||||
class CompareLEInstruction extends RelationalInstruction {
|
||||
CompareLEInstruction() {
|
||||
opcode instanceof Opcode::CompareLE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class CompareGEInstruction extends RelationalInstruction {
|
||||
CompareGEInstruction() {
|
||||
opcode instanceof Opcode::CompareGE
|
||||
}
|
||||
|
||||
override Instruction getLesserOperand() {
|
||||
result = getRightOperand()
|
||||
}
|
||||
|
||||
override Instruction getGreaterOperand() {
|
||||
result = getLeftOperand()
|
||||
}
|
||||
|
||||
override predicate isStrict() {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class SwitchInstruction extends Instruction {
|
||||
|
||||
@@ -197,8 +197,12 @@ cached private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached Expr getInstructionResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getResultExpression()
|
||||
cached Expr getInstructionConvertedResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getConvertedResultExpression()
|
||||
}
|
||||
|
||||
cached Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getUnconvertedResultExpression()
|
||||
}
|
||||
|
||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
|
||||
@@ -12,7 +12,8 @@ class Printf extends FormattingFunction {
|
||||
hasGlobalName("wprintf") or
|
||||
hasGlobalName("wprintf_s") or
|
||||
hasGlobalName("g_printf")
|
||||
)
|
||||
) and
|
||||
not exists(getDefinition().getFile().getRelativePath())
|
||||
}
|
||||
|
||||
override int getFormatParameterIndex() { result=0 }
|
||||
@@ -26,7 +27,15 @@ class Printf extends FormattingFunction {
|
||||
* The standard functions `fprintf`, `fwprintf` and their glib variants.
|
||||
*/
|
||||
class Fprintf extends FormattingFunction {
|
||||
Fprintf() { this instanceof TopLevelFunction and (hasGlobalName("fprintf") or hasGlobalName("fwprintf") or hasGlobalName("g_fprintf"))}
|
||||
Fprintf() {
|
||||
this instanceof TopLevelFunction and
|
||||
(
|
||||
hasGlobalName("fprintf") or
|
||||
hasGlobalName("fwprintf") or
|
||||
hasGlobalName("g_fprintf")
|
||||
) and
|
||||
not exists(getDefinition().getFile().getRelativePath())
|
||||
}
|
||||
|
||||
override int getFormatParameterIndex() { result=1 }
|
||||
override predicate isWideCharDefault() { hasGlobalName("fwprintf") }
|
||||
@@ -47,7 +56,8 @@ class Sprintf extends FormattingFunction {
|
||||
hasGlobalName("g_strdup_printf") or
|
||||
hasGlobalName("g_sprintf") or
|
||||
hasGlobalName("__builtin___sprintf_chk")
|
||||
)
|
||||
) and
|
||||
not exists(getDefinition().getFile().getRelativePath())
|
||||
}
|
||||
|
||||
override predicate isWideCharDefault() {
|
||||
@@ -100,7 +110,8 @@ class Snprintf extends FormattingFunction {
|
||||
or hasGlobalName("g_snprintf")
|
||||
or hasGlobalName("wnsprintf")
|
||||
or hasGlobalName("__builtin___snprintf_chk")
|
||||
)
|
||||
) and
|
||||
not exists(getDefinition().getFile().getRelativePath())
|
||||
}
|
||||
|
||||
override int getFormatParameterIndex() {
|
||||
@@ -133,10 +144,13 @@ class Snprintf extends FormattingFunction {
|
||||
* in the buffer.
|
||||
*/
|
||||
predicate returnsFullFormatLength() {
|
||||
hasGlobalName("snprintf") or
|
||||
hasGlobalName("g_snprintf") or
|
||||
hasGlobalName("__builtin___snprintf_chk") or
|
||||
hasGlobalName("snprintf_s")
|
||||
(
|
||||
hasGlobalName("snprintf") or
|
||||
hasGlobalName("g_snprintf") or
|
||||
hasGlobalName("__builtin___snprintf_chk") or
|
||||
hasGlobalName("snprintf_s")
|
||||
) and
|
||||
not exists(getDefinition().getFile().getRelativePath())
|
||||
}
|
||||
|
||||
override int getSizeParameterIndex() {
|
||||
@@ -158,7 +172,8 @@ class StringCchPrintf extends FormattingFunction {
|
||||
or hasGlobalName("StringCbPrintfEx")
|
||||
or hasGlobalName("StringCbPrintf_l")
|
||||
or hasGlobalName("StringCbPrintf_lEx")
|
||||
)
|
||||
) and
|
||||
not exists(getDefinition().getFile().getRelativePath())
|
||||
}
|
||||
|
||||
override int getFormatParameterIndex() {
|
||||
@@ -187,7 +202,8 @@ class Syslog extends FormattingFunction {
|
||||
Syslog() {
|
||||
this instanceof TopLevelFunction and (
|
||||
hasGlobalName("syslog")
|
||||
)
|
||||
) and
|
||||
not exists(getDefinition().getFile().getRelativePath())
|
||||
}
|
||||
|
||||
override int getFormatParameterIndex() { result=1 }
|
||||
|
||||
@@ -7,6 +7,38 @@
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Function
|
||||
|
||||
private Type stripTopLevelSpecifiersOnly(Type t) {
|
||||
(
|
||||
result = stripTopLevelSpecifiersOnly(t.(SpecifiedType).getBaseType())
|
||||
) or (
|
||||
result = t and
|
||||
not t instanceof SpecifiedType
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A type that is used as a format string by any formatting function.
|
||||
*/
|
||||
Type getAFormatterWideType() {
|
||||
exists(FormattingFunction ff |
|
||||
result = stripTopLevelSpecifiersOnly(ff.getDefaultCharType()) and
|
||||
result.getSize() != 1
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A type that is used as a format string by any formatting function, or `wchar_t` if
|
||||
* there is none.
|
||||
*/
|
||||
private Type getAFormatterWideTypeOrDefault() {
|
||||
result = getAFormatterWideType() or
|
||||
(
|
||||
not exists(getAFormatterWideType()) and
|
||||
result instanceof Wchar_t
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A standard library function that uses a `printf`-like formatting string.
|
||||
*/
|
||||
@@ -20,6 +52,43 @@ abstract class FormattingFunction extends Function {
|
||||
*/
|
||||
predicate isWideCharDefault() { none() }
|
||||
|
||||
/**
|
||||
* Gets the default character type expected for `%s` by this function. Typically
|
||||
* `char` or `wchar_t`.
|
||||
*/
|
||||
Type getDefaultCharType() {
|
||||
result = stripTopLevelSpecifiersOnly(getParameter(getFormatParameterIndex()).getType().
|
||||
getUnderlyingType().(PointerType).getBaseType())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the non-default character type expected for `%S` by this function. Typically
|
||||
* `wchar_t` or `char`. On some snapshots there may be multiple results where we can't tell
|
||||
* which is correct for a particular function.
|
||||
*/
|
||||
Type getNonDefaultCharType() {
|
||||
(
|
||||
getDefaultCharType().getSize() = 1 and
|
||||
result = getAFormatterWideTypeOrDefault()
|
||||
) or (
|
||||
getDefaultCharType().getSize() > 1 and
|
||||
result instanceof PlainCharType
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the wide character type for this function. This is usually `wchar_t`. On some
|
||||
* snapshots there may be multiple results where we can't tell which is correct for a
|
||||
* particular function.
|
||||
*/
|
||||
Type getWideCharType() {
|
||||
(
|
||||
result = getDefaultCharType() or
|
||||
result = getNonDefaultCharType()
|
||||
) and
|
||||
result.getSize() > 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the position at which the output parameter, if any, occurs.
|
||||
*/
|
||||
|
||||
@@ -633,12 +633,26 @@ class PointsToExpr extends Expr
|
||||
pragma[noopt]
|
||||
Element pointsTo()
|
||||
{
|
||||
this.interesting() and exists(int set, @element thisEntity, @element resultEntity | thisEntity = underlyingElement(this) and pointstosets(set, thisEntity) and setlocations(set, resultEntity) and resultEntity = unresolveElement(result))
|
||||
this.interesting() and
|
||||
exists(int set, @element thisEntity, @element resultEntity |
|
||||
thisEntity = underlyingElement(this) and
|
||||
pointstosets(set, thisEntity) and
|
||||
setlocations(set, resultEntity) and
|
||||
resultEntity = localUnresolveElement(result)
|
||||
)
|
||||
}
|
||||
|
||||
float confidence() { result = 1.0 / count(this.pointsTo()) }
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used above in a `pragma[noopt]` context, which prevents its
|
||||
* customary inlining. We materialise it explicitly here.
|
||||
*/
|
||||
private @element localUnresolveElement(Element e) {
|
||||
result = unresolveElement(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if anything points to an element, that is, is equivalent to:
|
||||
* ```
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
import cpp
|
||||
private import RangeAnalysisUtils
|
||||
import RangeSSA
|
||||
import SimpleRangeAnalysisCached
|
||||
|
||||
/**
|
||||
* This fixed set of lower bounds is used when the lower bounds of an
|
||||
@@ -406,27 +407,6 @@ deprecated predicate negative_overflow(Expr expr) {
|
||||
exprMightOverflowNegatively(expr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow negatively. This predicate
|
||||
* does not consider the possibility that the expression might overflow
|
||||
* due to a conversion.
|
||||
*/
|
||||
cached
|
||||
predicate exprMightOverflowNegatively(Expr expr) {
|
||||
getLowerBoundsImpl(expr) < exprMinVal(expr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow negatively. Conversions
|
||||
* are also taken into account. For example the expression
|
||||
* `(int16)(x+y)` might overflow due to the `(int16)` cast, rather than
|
||||
* due to the addition.
|
||||
*/
|
||||
cached
|
||||
predicate convertedExprMightOverflowNegatively(Expr expr) {
|
||||
exprMightOverflowNegatively(expr) or
|
||||
convertedExprMightOverflowNegatively(expr.getConversion())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow positively. This predicate
|
||||
@@ -439,39 +419,6 @@ deprecated predicate positive_overflow(Expr expr) {
|
||||
exprMightOverflowPositively(expr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow positively. This predicate
|
||||
* does not consider the possibility that the expression might overflow
|
||||
* due to a conversion.
|
||||
*/
|
||||
cached
|
||||
predicate exprMightOverflowPositively(Expr expr) {
|
||||
getUpperBoundsImpl(expr) > exprMaxVal(expr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow positively. Conversions
|
||||
* are also taken into account. For example the expression
|
||||
* `(int16)(x+y)` might overflow due to the `(int16)` cast, rather than
|
||||
* due to the addition.
|
||||
*/
|
||||
cached
|
||||
predicate convertedExprMightOverflowPositively(Expr expr) {
|
||||
exprMightOverflowPositively(expr) or
|
||||
convertedExprMightOverflowPositively(expr.getConversion())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow (either positively or
|
||||
* negatively). The possibility that the expression might overflow
|
||||
* due to an implicit or explicit cast is also considered.
|
||||
*/
|
||||
cached
|
||||
predicate convertedExprMightOverflow(Expr expr) {
|
||||
convertedExprMightOverflowNegatively(expr) or
|
||||
convertedExprMightOverflowPositively(expr)
|
||||
}
|
||||
|
||||
/** Only to be called by `getTruncatedLowerBounds`. */
|
||||
private
|
||||
float getLowerBoundsImpl(Expr expr) {
|
||||
@@ -921,28 +868,6 @@ float getDefUpperBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
unanalyzableDefBounds(def, v, _, result)
|
||||
}
|
||||
|
||||
/** Holds if the definition might overflow negatively. */
|
||||
cached
|
||||
predicate defMightOverflowNegatively(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
getDefLowerBoundsImpl(def, v) < varMinVal(v)
|
||||
}
|
||||
|
||||
/** Holds if the definition might overflow positively. */
|
||||
cached
|
||||
predicate defMightOverflowPositively(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
getDefUpperBoundsImpl(def, v) > varMaxVal(v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the definition might overflow (either positively or
|
||||
* negatively).
|
||||
*/
|
||||
cached
|
||||
predicate defMightOverflow(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
defMightOverflowNegatively(def, v) or
|
||||
defMightOverflowPositively(def, v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lower bounds for a `RangeSsaDefinition`. Most of the work is
|
||||
* done by `getDefLowerBoundsImpl`, but this is where widening is applied
|
||||
@@ -1133,63 +1058,142 @@ predicate exprTypeBounds(Expr expr, float boundValue, boolean isLowerBound) {
|
||||
(isLowerBound = false and boundValue = exprMaxVal(expr.getFullyConverted()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lower bound of the expression.
|
||||
*
|
||||
* Note: expressions in C/C++ are often implicitly or explicitly cast to a
|
||||
* different result type. Such casts can cause the value of the expression
|
||||
* to overflow or to be truncated. This predicate computes the lower bound
|
||||
* of the expression without including the effect of the casts. To compute
|
||||
* the lower bound of the expression after all the casts have been applied,
|
||||
* call `lowerBound` like this:
|
||||
*
|
||||
* `lowerBound(expr.getFullyConverted())`
|
||||
*/
|
||||
cached
|
||||
float lowerBound(Expr expr) {
|
||||
// Combine the lower bounds returned by getTruncatedLowerBounds into a
|
||||
// single minimum value.
|
||||
result = min(float lb | lb = getTruncatedLowerBounds(expr) | lb)
|
||||
}
|
||||
private cached module SimpleRangeAnalysisCached {
|
||||
/**
|
||||
* Gets the lower bound of the expression.
|
||||
*
|
||||
* Note: expressions in C/C++ are often implicitly or explicitly cast to a
|
||||
* different result type. Such casts can cause the value of the expression
|
||||
* to overflow or to be truncated. This predicate computes the lower bound
|
||||
* of the expression without including the effect of the casts. To compute
|
||||
* the lower bound of the expression after all the casts have been applied,
|
||||
* call `lowerBound` like this:
|
||||
*
|
||||
* `lowerBound(expr.getFullyConverted())`
|
||||
*/
|
||||
cached
|
||||
float lowerBound(Expr expr) {
|
||||
// Combine the lower bounds returned by getTruncatedLowerBounds into a
|
||||
// single minimum value.
|
||||
result = min(float lb | lb = getTruncatedLowerBounds(expr) | lb)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the upper bound of the expression.
|
||||
*
|
||||
* Note: expressions in C/C++ are often implicitly or explicitly cast to a
|
||||
* different result type. Such casts can cause the value of the expression
|
||||
* to overflow or to be truncated. This predicate computes the upper bound
|
||||
* of the expression without including the effect of the casts. To compute
|
||||
* the upper bound of the expression after all the casts have been applied,
|
||||
* call `upperBound` like this:
|
||||
*
|
||||
* `upperBound(expr.getFullyConverted())`
|
||||
*/
|
||||
cached
|
||||
float upperBound(Expr expr) {
|
||||
// Combine the upper bounds returned by getTruncatedUpperBounds into a
|
||||
// single maximum value.
|
||||
result = max(float ub | ub = getTruncatedUpperBounds(expr) | ub)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `expr` has a provably empty range. For example:
|
||||
*
|
||||
* 10 < expr and expr < 5
|
||||
*
|
||||
* The range of an expression can only be empty if it can never be
|
||||
* executed. For example:
|
||||
*
|
||||
* if (10 < x) {
|
||||
* if (x < 5) {
|
||||
* // Unreachable code
|
||||
* return x; // x has an empty range: 10 < x && x < 5
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
cached
|
||||
predicate exprWithEmptyRange(Expr expr) {
|
||||
analyzableExpr(expr) and
|
||||
(not exists(lowerBound(expr)) or
|
||||
not exists(upperBound(expr)) or
|
||||
lowerBound(expr) > upperBound(expr))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the upper bound of the expression.
|
||||
*
|
||||
* Note: expressions in C/C++ are often implicitly or explicitly cast to a
|
||||
* different result type. Such casts can cause the value of the expression
|
||||
* to overflow or to be truncated. This predicate computes the upper bound
|
||||
* of the expression without including the effect of the casts. To compute
|
||||
* the upper bound of the expression after all the casts have been applied,
|
||||
* call `upperBound` like this:
|
||||
*
|
||||
* `upperBound(expr.getFullyConverted())`
|
||||
*/
|
||||
cached
|
||||
float upperBound(Expr expr) {
|
||||
// Combine the upper bounds returned by getTruncatedUpperBounds into a
|
||||
// single maximum value.
|
||||
result = max(float ub | ub = getTruncatedUpperBounds(expr) | ub)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `expr` has a provably empty range. For example:
|
||||
*
|
||||
* 10 < expr and expr < 5
|
||||
*
|
||||
* The range of an expression can only be empty if it can never be
|
||||
* executed. For example:
|
||||
*
|
||||
* if (10 < x) {
|
||||
* if (x < 5) {
|
||||
* // Unreachable code
|
||||
* return x; // x has an empty range: 10 < x && x < 5
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
cached
|
||||
predicate exprWithEmptyRange(Expr expr) {
|
||||
analyzableExpr(expr) and
|
||||
(not exists(lowerBound(expr)) or
|
||||
not exists(upperBound(expr)) or
|
||||
lowerBound(expr) > upperBound(expr))
|
||||
/** Holds if the definition might overflow negatively. */
|
||||
cached
|
||||
predicate defMightOverflowNegatively(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
getDefLowerBoundsImpl(def, v) < varMinVal(v)
|
||||
}
|
||||
|
||||
/** Holds if the definition might overflow positively. */
|
||||
cached
|
||||
predicate defMightOverflowPositively(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
getDefUpperBoundsImpl(def, v) > varMaxVal(v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the definition might overflow (either positively or
|
||||
* negatively).
|
||||
*/
|
||||
cached
|
||||
predicate defMightOverflow(RangeSsaDefinition def, LocalScopeVariable v) {
|
||||
defMightOverflowNegatively(def, v) or
|
||||
defMightOverflowPositively(def, v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow negatively. This predicate
|
||||
* does not consider the possibility that the expression might overflow
|
||||
* due to a conversion.
|
||||
*/
|
||||
cached
|
||||
predicate exprMightOverflowNegatively(Expr expr) {
|
||||
getLowerBoundsImpl(expr) < exprMinVal(expr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow negatively. Conversions
|
||||
* are also taken into account. For example the expression
|
||||
* `(int16)(x+y)` might overflow due to the `(int16)` cast, rather than
|
||||
* due to the addition.
|
||||
*/
|
||||
cached
|
||||
predicate convertedExprMightOverflowNegatively(Expr expr) {
|
||||
exprMightOverflowNegatively(expr) or
|
||||
convertedExprMightOverflowNegatively(expr.getConversion())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow positively. This predicate
|
||||
* does not consider the possibility that the expression might overflow
|
||||
* due to a conversion.
|
||||
*/
|
||||
cached
|
||||
predicate exprMightOverflowPositively(Expr expr) {
|
||||
getUpperBoundsImpl(expr) > exprMaxVal(expr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow positively. Conversions
|
||||
* are also taken into account. For example the expression
|
||||
* `(int16)(x+y)` might overflow due to the `(int16)` cast, rather than
|
||||
* due to the addition.
|
||||
*/
|
||||
cached
|
||||
predicate convertedExprMightOverflowPositively(Expr expr) {
|
||||
exprMightOverflowPositively(expr) or
|
||||
convertedExprMightOverflowPositively(expr.getConversion())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow (either positively or
|
||||
* negatively). The possibility that the expression might overflow
|
||||
* due to an implicit or explicit cast is also considered.
|
||||
*/
|
||||
cached
|
||||
predicate convertedExprMightOverflow(Expr expr) {
|
||||
convertedExprMightOverflowNegatively(expr) or
|
||||
convertedExprMightOverflowPositively(expr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ predicate guardedAbs(Operation e, Expr use) {
|
||||
}
|
||||
|
||||
/** is the size of this use guarded to be less than something? */
|
||||
pragma[nomagic]
|
||||
predicate guardedLesser(Operation e, Expr use) {
|
||||
exists(IfStmt c, RelationalOperation guard |
|
||||
use = guard.getLesserOperand().getAChild*() and
|
||||
@@ -33,6 +34,7 @@ predicate guardedLesser(Operation e, Expr use) {
|
||||
}
|
||||
|
||||
/** is the size of this use guarded to be greater than something? */
|
||||
pragma[nomagic]
|
||||
predicate guardedGreater(Operation e, Expr use) {
|
||||
exists(IfStmt c, RelationalOperation guard |
|
||||
use = guard.getGreaterOperand().getAChild*() and
|
||||
|
||||
@@ -312,7 +312,7 @@ private predicate analyzableLocalScopeVariable(VariableAccess access) {
|
||||
strictcount (SsaDefinition def, Variable v | def.getAUse(v) = access | v) = 1 and
|
||||
count (SsaDefinition def, Variable v
|
||||
| def.getAUse(v) = access
|
||||
| def.getDefiningValue(v)) <= 1 and
|
||||
| def.getDefiningValue(v).getFullyConverted()) <= 1 and
|
||||
not analyzableConst(access)
|
||||
}
|
||||
|
||||
|
||||
154
cpp/ql/test/library-tests/controlflow/guards-ir/test.c
Normal file
154
cpp/ql/test/library-tests/controlflow/guards-ir/test.c
Normal file
@@ -0,0 +1,154 @@
|
||||
|
||||
int test(int x, int w, int z) {
|
||||
int j;
|
||||
long y = 50;
|
||||
|
||||
// simple comparison
|
||||
if (x > 0) {
|
||||
y = 20;
|
||||
z = 10;
|
||||
} else {
|
||||
y = 30;
|
||||
}
|
||||
|
||||
z = x + y;
|
||||
|
||||
// More complex
|
||||
if(x < 0 && y > 1)
|
||||
y = 40;
|
||||
else
|
||||
y = 20; /* The && expression does not control this block as the x<0 expression jumps here if false. */
|
||||
|
||||
|
||||
z = 10;
|
||||
|
||||
// while loop
|
||||
while(x > 0) {
|
||||
y = 10;
|
||||
x--;
|
||||
}
|
||||
|
||||
z += y;
|
||||
|
||||
// for loop
|
||||
for(j = 0; j < 10; j++) {
|
||||
y = 0;
|
||||
w = 10;
|
||||
}
|
||||
|
||||
z += w;
|
||||
|
||||
// nested control flow
|
||||
for(j = 0; j < 10; j++) {
|
||||
y = 30;
|
||||
if(z > 0)
|
||||
if(y > 0) {
|
||||
w = 0;
|
||||
break;
|
||||
} else {
|
||||
w = 20;
|
||||
}
|
||||
else {
|
||||
w = 10;
|
||||
continue;
|
||||
}
|
||||
x = 0;
|
||||
}
|
||||
|
||||
if (x == 0 || y < 0) {
|
||||
y = 60;
|
||||
z = 10;
|
||||
} else
|
||||
return z;
|
||||
|
||||
z += x;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int test2(int x, int w, int z) {
|
||||
int j;
|
||||
long y = 50;
|
||||
|
||||
// simple comparison
|
||||
if (x == 0) {
|
||||
y = 20;
|
||||
z = 10;
|
||||
} else {
|
||||
y = 30;
|
||||
}
|
||||
|
||||
z = x + y;
|
||||
|
||||
// More complex
|
||||
if(x == 0 && y != 0)
|
||||
y = 40;
|
||||
else
|
||||
y = 20;
|
||||
|
||||
|
||||
z = 10;
|
||||
|
||||
// while loop
|
||||
while(x != 0) {
|
||||
y = 10;
|
||||
x--;
|
||||
}
|
||||
|
||||
z += y;
|
||||
|
||||
// for loop
|
||||
for(j = 0; j < 10; j++) {
|
||||
y = 0;
|
||||
w = 10;
|
||||
}
|
||||
|
||||
z += w;
|
||||
|
||||
if (x == 0 || y < 0) {
|
||||
y = 60;
|
||||
z = 10;
|
||||
} else
|
||||
return z;
|
||||
|
||||
z += x;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test3_condition();
|
||||
void test3_action();
|
||||
|
||||
void test3() {
|
||||
int b = 0;
|
||||
|
||||
if (1 && test3_condition()) {
|
||||
b = 1;
|
||||
test3_action();
|
||||
}
|
||||
|
||||
if (b) {
|
||||
test3_action();
|
||||
}
|
||||
}
|
||||
|
||||
void test4(int i) {
|
||||
if (0) {
|
||||
if (i) {
|
||||
;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void test5(int x) {
|
||||
if (!x) {
|
||||
test3();
|
||||
}
|
||||
}
|
||||
|
||||
void test6(int x, int y) {
|
||||
return x && y;
|
||||
}
|
||||
|
||||
54
cpp/ql/test/library-tests/controlflow/guards-ir/test.cpp
Normal file
54
cpp/ql/test/library-tests/controlflow/guards-ir/test.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
class X
|
||||
{
|
||||
public:
|
||||
void set();
|
||||
};
|
||||
|
||||
class Y
|
||||
{
|
||||
public:
|
||||
Y* f();
|
||||
|
||||
const X* get() const { return 0; }
|
||||
X* get() { return 0; }
|
||||
};
|
||||
|
||||
Y* Y::f()
|
||||
{
|
||||
if ( get() )
|
||||
get()->set();
|
||||
return 0;
|
||||
}
|
||||
|
||||
class Error {
|
||||
public:
|
||||
Error() {}
|
||||
};
|
||||
|
||||
bool getABool();
|
||||
|
||||
void doSomething(int x) {
|
||||
if (x == -1) {
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
|
||||
void doSomethingElse(int x);
|
||||
|
||||
bool testWithCatch0(int v)
|
||||
{
|
||||
try
|
||||
{
|
||||
if( getABool() )
|
||||
{
|
||||
doSomething(v);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch(Error &e)
|
||||
{
|
||||
doSomethingElse(v);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
730
cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected
Normal file
730
cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected
Normal file
@@ -0,0 +1,730 @@
|
||||
astGuards
|
||||
| test.c:7:9:7:13 | ... > ... |
|
||||
| test.c:17:8:17:12 | ... < ... |
|
||||
| test.c:17:8:17:21 | ... && ... |
|
||||
| test.c:17:17:17:21 | ... > ... |
|
||||
| test.c:26:11:26:15 | ... > ... |
|
||||
| test.c:34:16:34:21 | ... < ... |
|
||||
| test.c:42:16:42:21 | ... < ... |
|
||||
| test.c:44:12:44:16 | ... > ... |
|
||||
| test.c:45:16:45:20 | ... > ... |
|
||||
| test.c:58:9:58:14 | ... == ... |
|
||||
| test.c:58:9:58:23 | ... \|\| ... |
|
||||
| test.c:58:19:58:23 | ... < ... |
|
||||
| test.c:75:9:75:14 | ... == ... |
|
||||
| test.c:85:8:85:13 | ... == ... |
|
||||
| test.c:85:8:85:23 | ... && ... |
|
||||
| test.c:85:18:85:23 | ... != ... |
|
||||
| test.c:94:11:94:16 | ... != ... |
|
||||
| test.c:102:16:102:21 | ... < ... |
|
||||
| test.c:109:9:109:14 | ... == ... |
|
||||
| test.c:109:9:109:23 | ... \|\| ... |
|
||||
| test.c:109:19:109:23 | ... < ... |
|
||||
| test.c:126:7:126:7 | 1 |
|
||||
| test.c:126:7:126:28 | ... && ... |
|
||||
| test.c:126:12:126:26 | call to test3_condition |
|
||||
| test.c:131:7:131:7 | b |
|
||||
| test.c:137:7:137:7 | 0 |
|
||||
| test.c:138:9:138:9 | i |
|
||||
| test.c:146:7:146:8 | ! ... |
|
||||
| test.c:146:8:146:8 | x |
|
||||
| test.c:152:10:152:10 | x |
|
||||
| test.c:152:10:152:15 | ... && ... |
|
||||
| test.c:152:15:152:15 | y |
|
||||
| test.cpp:18:8:18:10 | call to get |
|
||||
| test.cpp:31:7:31:13 | ... == ... |
|
||||
| test.cpp:42:13:42:20 | call to getABool |
|
||||
astGuardsCompare
|
||||
| 7 | 0 < x+0 when ... > ... is true |
|
||||
| 7 | 0 >= x+0 when ... > ... is false |
|
||||
| 7 | x < 0+1 when ... > ... is false |
|
||||
| 7 | x >= 0+1 when ... > ... is true |
|
||||
| 17 | 0 < x+1 when ... < ... is false |
|
||||
| 17 | 0 >= x+1 when ... && ... is true |
|
||||
| 17 | 0 >= x+1 when ... < ... is true |
|
||||
| 17 | 1 < y+0 when ... && ... is true |
|
||||
| 17 | 1 < y+0 when ... > ... is true |
|
||||
| 17 | 1 >= y+0 when ... > ... is false |
|
||||
| 17 | x < 0+0 when ... && ... is true |
|
||||
| 17 | x < 0+0 when ... < ... is true |
|
||||
| 17 | x >= 0+0 when ... < ... is false |
|
||||
| 17 | y < 1+1 when ... > ... is false |
|
||||
| 17 | y >= 1+1 when ... && ... is true |
|
||||
| 17 | y >= 1+1 when ... > ... is true |
|
||||
| 26 | 0 < x+0 when ... > ... is true |
|
||||
| 26 | 0 >= x+0 when ... > ... is false |
|
||||
| 26 | x < 0+1 when ... > ... is false |
|
||||
| 26 | x >= 0+1 when ... > ... is true |
|
||||
| 31 | - ... != x+0 when ... == ... is false |
|
||||
| 31 | - ... == x+0 when ... == ... is true |
|
||||
| 31 | x != - ...+0 when ... == ... is false |
|
||||
| 31 | x == - ...+0 when ... == ... is true |
|
||||
| 34 | 10 < j+1 when ... < ... is false |
|
||||
| 34 | 10 >= j+1 when ... < ... is true |
|
||||
| 34 | j < 10+0 when ... < ... is true |
|
||||
| 34 | j >= 10+0 when ... < ... is false |
|
||||
| 42 | 10 < j+1 when ... < ... is false |
|
||||
| 42 | 10 >= j+1 when ... < ... is true |
|
||||
| 42 | j < 10+0 when ... < ... is true |
|
||||
| 42 | j >= 10+0 when ... < ... is false |
|
||||
| 44 | 0 < z+0 when ... > ... is true |
|
||||
| 44 | 0 >= z+0 when ... > ... is false |
|
||||
| 44 | z < 0+1 when ... > ... is false |
|
||||
| 44 | z >= 0+1 when ... > ... is true |
|
||||
| 45 | 0 < y+0 when ... > ... is true |
|
||||
| 45 | 0 >= y+0 when ... > ... is false |
|
||||
| 45 | y < 0+1 when ... > ... is false |
|
||||
| 45 | y >= 0+1 when ... > ... is true |
|
||||
| 58 | 0 != x+0 when ... == ... is false |
|
||||
| 58 | 0 != x+0 when ... \|\| ... is false |
|
||||
| 58 | 0 < y+1 when ... < ... is false |
|
||||
| 58 | 0 < y+1 when ... \|\| ... is false |
|
||||
| 58 | 0 == x+0 when ... == ... is true |
|
||||
| 58 | 0 >= y+1 when ... < ... is true |
|
||||
| 58 | x != 0+0 when ... == ... is false |
|
||||
| 58 | x != 0+0 when ... \|\| ... is false |
|
||||
| 58 | x == 0+0 when ... == ... is true |
|
||||
| 58 | y < 0+0 when ... < ... is true |
|
||||
| 58 | y >= 0+0 when ... < ... is false |
|
||||
| 58 | y >= 0+0 when ... \|\| ... is false |
|
||||
| 75 | 0 != x+0 when ... == ... is false |
|
||||
| 75 | 0 == x+0 when ... == ... is true |
|
||||
| 75 | x != 0+0 when ... == ... is false |
|
||||
| 75 | x == 0+0 when ... == ... is true |
|
||||
| 85 | 0 != x+0 when ... == ... is false |
|
||||
| 85 | 0 != y+0 when ... != ... is true |
|
||||
| 85 | 0 != y+0 when ... && ... is true |
|
||||
| 85 | 0 == x+0 when ... && ... is true |
|
||||
| 85 | 0 == x+0 when ... == ... is true |
|
||||
| 85 | 0 == y+0 when ... != ... is false |
|
||||
| 85 | x != 0+0 when ... == ... is false |
|
||||
| 85 | x == 0+0 when ... && ... is true |
|
||||
| 85 | x == 0+0 when ... == ... is true |
|
||||
| 85 | y != 0+0 when ... != ... is true |
|
||||
| 85 | y != 0+0 when ... && ... is true |
|
||||
| 85 | y == 0+0 when ... != ... is false |
|
||||
| 94 | 0 != x+0 when ... != ... is true |
|
||||
| 94 | 0 == x+0 when ... != ... is false |
|
||||
| 94 | x != 0+0 when ... != ... is true |
|
||||
| 94 | x == 0+0 when ... != ... is false |
|
||||
| 102 | 10 < j+1 when ... < ... is false |
|
||||
| 102 | 10 >= j+1 when ... < ... is true |
|
||||
| 102 | j < 10+0 when ... < ... is true |
|
||||
| 102 | j >= 10+0 when ... < ... is false |
|
||||
| 109 | 0 != x+0 when ... == ... is false |
|
||||
| 109 | 0 != x+0 when ... \|\| ... is false |
|
||||
| 109 | 0 < y+1 when ... < ... is false |
|
||||
| 109 | 0 < y+1 when ... \|\| ... is false |
|
||||
| 109 | 0 == x+0 when ... == ... is true |
|
||||
| 109 | 0 >= y+1 when ... < ... is true |
|
||||
| 109 | x != 0+0 when ... == ... is false |
|
||||
| 109 | x != 0+0 when ... \|\| ... is false |
|
||||
| 109 | x == 0+0 when ... == ... is true |
|
||||
| 109 | y < 0+0 when ... < ... is true |
|
||||
| 109 | y >= 0+0 when ... < ... is false |
|
||||
| 109 | y >= 0+0 when ... \|\| ... is false |
|
||||
astGuardsControl
|
||||
| test.c:7:9:7:13 | ... > ... | false | 10 | 11 |
|
||||
| test.c:7:9:7:13 | ... > ... | true | 7 | 9 |
|
||||
| test.c:17:8:17:12 | ... < ... | true | 17 | 17 |
|
||||
| test.c:17:8:17:12 | ... < ... | true | 18 | 18 |
|
||||
| test.c:17:8:17:21 | ... && ... | true | 18 | 18 |
|
||||
| test.c:17:17:17:21 | ... > ... | true | 18 | 18 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 2 | 2 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 31 | 34 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 34 | 34 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 39 | 42 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 42 | 42 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 42 | 44 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 45 | 45 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 45 | 47 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 48 | 55 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 51 | 53 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 56 | 58 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 58 | 58 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 58 | 66 |
|
||||
| test.c:26:11:26:15 | ... > ... | false | 62 | 62 |
|
||||
| test.c:26:11:26:15 | ... > ... | true | 26 | 28 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 2 | 2 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 39 | 42 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 42 | 42 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 42 | 44 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 45 | 45 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 45 | 47 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 48 | 55 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 51 | 53 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 56 | 58 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 58 | 58 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 58 | 66 |
|
||||
| test.c:34:16:34:21 | ... < ... | false | 62 | 62 |
|
||||
| test.c:34:16:34:21 | ... < ... | true | 34 | 34 |
|
||||
| test.c:42:16:42:21 | ... < ... | true | 42 | 42 |
|
||||
| test.c:42:16:42:21 | ... < ... | true | 42 | 44 |
|
||||
| test.c:42:16:42:21 | ... < ... | true | 45 | 45 |
|
||||
| test.c:42:16:42:21 | ... < ... | true | 45 | 47 |
|
||||
| test.c:42:16:42:21 | ... < ... | true | 48 | 55 |
|
||||
| test.c:42:16:42:21 | ... < ... | true | 51 | 53 |
|
||||
| test.c:44:12:44:16 | ... > ... | false | 51 | 53 |
|
||||
| test.c:44:12:44:16 | ... > ... | true | 45 | 45 |
|
||||
| test.c:44:12:44:16 | ... > ... | true | 45 | 47 |
|
||||
| test.c:44:12:44:16 | ... > ... | true | 48 | 55 |
|
||||
| test.c:45:16:45:20 | ... > ... | false | 48 | 55 |
|
||||
| test.c:45:16:45:20 | ... > ... | true | 45 | 47 |
|
||||
| test.c:58:9:58:14 | ... == ... | false | 58 | 58 |
|
||||
| test.c:58:9:58:14 | ... == ... | false | 62 | 62 |
|
||||
| test.c:58:9:58:23 | ... \|\| ... | false | 62 | 62 |
|
||||
| test.c:58:19:58:23 | ... < ... | false | 62 | 62 |
|
||||
| test.c:75:9:75:14 | ... == ... | false | 78 | 79 |
|
||||
| test.c:75:9:75:14 | ... == ... | true | 75 | 77 |
|
||||
| test.c:85:8:85:13 | ... == ... | true | 85 | 85 |
|
||||
| test.c:85:8:85:13 | ... == ... | true | 86 | 86 |
|
||||
| test.c:85:8:85:23 | ... && ... | true | 86 | 86 |
|
||||
| test.c:85:18:85:23 | ... != ... | true | 86 | 86 |
|
||||
| test.c:94:11:94:16 | ... != ... | false | 70 | 70 |
|
||||
| test.c:94:11:94:16 | ... != ... | false | 99 | 102 |
|
||||
| test.c:94:11:94:16 | ... != ... | false | 102 | 102 |
|
||||
| test.c:94:11:94:16 | ... != ... | false | 107 | 109 |
|
||||
| test.c:94:11:94:16 | ... != ... | false | 109 | 109 |
|
||||
| test.c:94:11:94:16 | ... != ... | false | 109 | 117 |
|
||||
| test.c:94:11:94:16 | ... != ... | false | 113 | 113 |
|
||||
| test.c:94:11:94:16 | ... != ... | true | 94 | 96 |
|
||||
| test.c:102:16:102:21 | ... < ... | false | 70 | 70 |
|
||||
| test.c:102:16:102:21 | ... < ... | false | 107 | 109 |
|
||||
| test.c:102:16:102:21 | ... < ... | false | 109 | 109 |
|
||||
| test.c:102:16:102:21 | ... < ... | false | 109 | 117 |
|
||||
| test.c:102:16:102:21 | ... < ... | false | 113 | 113 |
|
||||
| test.c:102:16:102:21 | ... < ... | true | 102 | 102 |
|
||||
| test.c:109:9:109:14 | ... == ... | false | 109 | 109 |
|
||||
| test.c:109:9:109:14 | ... == ... | false | 113 | 113 |
|
||||
| test.c:109:9:109:23 | ... \|\| ... | false | 113 | 113 |
|
||||
| test.c:109:19:109:23 | ... < ... | false | 113 | 113 |
|
||||
| test.c:126:7:126:7 | 1 | true | 126 | 126 |
|
||||
| test.c:126:7:126:7 | 1 | true | 126 | 128 |
|
||||
| test.c:126:7:126:28 | ... && ... | true | 126 | 128 |
|
||||
| test.c:126:12:126:26 | call to test3_condition | true | 126 | 128 |
|
||||
| test.c:131:7:131:7 | b | true | 131 | 132 |
|
||||
| test.c:137:7:137:7 | 0 | true | 137 | 138 |
|
||||
| test.c:137:7:137:7 | 0 | true | 138 | 139 |
|
||||
| test.c:138:9:138:9 | i | true | 138 | 139 |
|
||||
| test.c:146:7:146:8 | ! ... | true | 146 | 147 |
|
||||
| test.c:146:8:146:8 | x | false | 146 | 147 |
|
||||
| test.c:152:10:152:10 | x | true | 151 | 152 |
|
||||
| test.c:152:10:152:10 | x | true | 152 | 152 |
|
||||
| test.c:152:10:152:15 | ... && ... | true | 151 | 152 |
|
||||
| test.c:152:15:152:15 | y | true | 151 | 152 |
|
||||
| test.cpp:18:8:18:10 | call to get | true | 19 | 19 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | false | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | false | 34 | 34 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | true | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | true | 31 | 32 |
|
||||
| test.cpp:42:13:42:20 | call to getABool | false | 53 | 53 |
|
||||
| test.cpp:42:13:42:20 | call to getABool | true | 43 | 45 |
|
||||
astGuardsEnsure
|
||||
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | < | test.c:7:13:7:13 | 0 | 1 | 10 | 11 |
|
||||
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | >= | test.c:7:13:7:13 | 0 | 1 | 7 | 9 |
|
||||
| test.c:7:9:7:13 | ... > ... | test.c:7:13:7:13 | 0 | < | test.c:7:9:7:9 | x | 0 | 7 | 9 |
|
||||
| test.c:7:9:7:13 | ... > ... | test.c:7:13:7:13 | 0 | >= | test.c:7:9:7:9 | x | 0 | 10 | 11 |
|
||||
| test.c:17:8:17:12 | ... < ... | test.c:17:8:17:8 | x | < | test.c:17:12:17:12 | 0 | 0 | 17 | 17 |
|
||||
| test.c:17:8:17:12 | ... < ... | test.c:17:8:17:8 | x | < | test.c:17:12:17:12 | 0 | 0 | 18 | 18 |
|
||||
| test.c:17:8:17:12 | ... < ... | test.c:17:12:17:12 | 0 | >= | test.c:17:8:17:8 | x | 1 | 17 | 17 |
|
||||
| test.c:17:8:17:12 | ... < ... | test.c:17:12:17:12 | 0 | >= | test.c:17:8:17:8 | x | 1 | 18 | 18 |
|
||||
| test.c:17:8:17:21 | ... && ... | test.c:17:8:17:8 | x | < | test.c:17:12:17:12 | 0 | 0 | 18 | 18 |
|
||||
| test.c:17:8:17:21 | ... && ... | test.c:17:12:17:12 | 0 | >= | test.c:17:8:17:8 | x | 1 | 18 | 18 |
|
||||
| test.c:17:8:17:21 | ... && ... | test.c:17:17:17:17 | y | >= | test.c:17:21:17:21 | 1 | 1 | 18 | 18 |
|
||||
| test.c:17:8:17:21 | ... && ... | test.c:17:21:17:21 | 1 | < | test.c:17:17:17:17 | y | 0 | 18 | 18 |
|
||||
| test.c:17:17:17:21 | ... > ... | test.c:17:17:17:17 | y | >= | test.c:17:21:17:21 | 1 | 1 | 18 | 18 |
|
||||
| test.c:17:17:17:21 | ... > ... | test.c:17:21:17:21 | 1 | < | test.c:17:17:17:17 | y | 0 | 18 | 18 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 2 | 2 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 31 | 34 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 34 | 34 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 39 | 42 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 42 | 42 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 42 | 44 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 45 | 45 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 45 | 47 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 48 | 55 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 51 | 53 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 56 | 58 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 58 | 58 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 58 | 66 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | test.c:26:15:26:15 | 0 | 1 | 62 | 62 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | >= | test.c:26:15:26:15 | 0 | 1 | 26 | 28 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | < | test.c:26:11:26:11 | x | 0 | 26 | 28 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 2 | 2 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 31 | 34 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 34 | 34 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 39 | 42 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 42 | 42 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 42 | 44 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 45 | 45 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 45 | 47 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 48 | 55 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 51 | 53 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 56 | 58 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 58 | 58 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 58 | 66 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:15:26:15 | 0 | >= | test.c:26:11:26:11 | x | 0 | 62 | 62 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | < | test.c:34:20:34:21 | 10 | 0 | 34 | 34 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 2 | 2 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 39 | 42 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 42 | 42 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 42 | 44 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 45 | 45 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 45 | 47 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 48 | 55 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 51 | 53 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 56 | 58 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 58 | 58 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 58 | 66 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | test.c:34:20:34:21 | 10 | 0 | 62 | 62 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 2 | 2 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 39 | 42 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 42 | 42 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 42 | 44 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 45 | 45 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 45 | 47 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 48 | 55 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 51 | 53 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 56 | 58 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 58 | 58 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 58 | 66 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | < | test.c:34:16:34:16 | j | 1 | 62 | 62 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:20:34:21 | 10 | >= | test.c:34:16:34:16 | j | 1 | 34 | 34 |
|
||||
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | test.c:42:20:42:21 | 10 | 0 | 42 | 42 |
|
||||
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | test.c:42:20:42:21 | 10 | 0 | 42 | 44 |
|
||||
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | test.c:42:20:42:21 | 10 | 0 | 45 | 45 |
|
||||
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | test.c:42:20:42:21 | 10 | 0 | 45 | 47 |
|
||||
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | test.c:42:20:42:21 | 10 | 0 | 48 | 55 |
|
||||
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | test.c:42:20:42:21 | 10 | 0 | 51 | 53 |
|
||||
| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 42 | 42 |
|
||||
| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 42 | 44 |
|
||||
| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 45 | 45 |
|
||||
| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 45 | 47 |
|
||||
| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 48 | 55 |
|
||||
| test.c:42:16:42:21 | ... < ... | test.c:42:20:42:21 | 10 | >= | test.c:42:16:42:16 | j | 1 | 51 | 53 |
|
||||
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | < | test.c:44:16:44:16 | 0 | 1 | 51 | 53 |
|
||||
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | >= | test.c:44:16:44:16 | 0 | 1 | 45 | 45 |
|
||||
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | >= | test.c:44:16:44:16 | 0 | 1 | 45 | 47 |
|
||||
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | >= | test.c:44:16:44:16 | 0 | 1 | 48 | 55 |
|
||||
| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | < | test.c:44:12:44:12 | z | 0 | 45 | 45 |
|
||||
| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | < | test.c:44:12:44:12 | z | 0 | 45 | 47 |
|
||||
| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | < | test.c:44:12:44:12 | z | 0 | 48 | 55 |
|
||||
| test.c:44:12:44:16 | ... > ... | test.c:44:16:44:16 | 0 | >= | test.c:44:12:44:12 | z | 0 | 51 | 53 |
|
||||
| test.c:45:16:45:20 | ... > ... | test.c:45:16:45:16 | y | < | test.c:45:20:45:20 | 0 | 1 | 48 | 55 |
|
||||
| test.c:45:16:45:20 | ... > ... | test.c:45:16:45:16 | y | >= | test.c:45:20:45:20 | 0 | 1 | 45 | 47 |
|
||||
| test.c:45:16:45:20 | ... > ... | test.c:45:20:45:20 | 0 | < | test.c:45:16:45:16 | y | 0 | 45 | 47 |
|
||||
| test.c:45:16:45:20 | ... > ... | test.c:45:20:45:20 | 0 | >= | test.c:45:16:45:16 | y | 0 | 48 | 55 |
|
||||
| test.c:58:9:58:14 | ... == ... | test.c:58:9:58:9 | x | != | test.c:58:14:58:14 | 0 | 0 | 58 | 58 |
|
||||
| test.c:58:9:58:14 | ... == ... | test.c:58:9:58:9 | x | != | test.c:58:14:58:14 | 0 | 0 | 62 | 62 |
|
||||
| test.c:58:9:58:14 | ... == ... | test.c:58:14:58:14 | 0 | != | test.c:58:9:58:9 | x | 0 | 58 | 58 |
|
||||
| test.c:58:9:58:14 | ... == ... | test.c:58:14:58:14 | 0 | != | test.c:58:9:58:9 | x | 0 | 62 | 62 |
|
||||
| test.c:58:9:58:23 | ... \|\| ... | test.c:58:9:58:9 | x | != | test.c:58:14:58:14 | 0 | 0 | 62 | 62 |
|
||||
| test.c:58:9:58:23 | ... \|\| ... | test.c:58:14:58:14 | 0 | != | test.c:58:9:58:9 | x | 0 | 62 | 62 |
|
||||
| test.c:58:9:58:23 | ... \|\| ... | test.c:58:19:58:19 | y | >= | test.c:58:23:58:23 | 0 | 0 | 62 | 62 |
|
||||
| test.c:58:9:58:23 | ... \|\| ... | test.c:58:23:58:23 | 0 | < | test.c:58:19:58:19 | y | 1 | 62 | 62 |
|
||||
| test.c:58:19:58:23 | ... < ... | test.c:58:19:58:19 | y | >= | test.c:58:23:58:23 | 0 | 0 | 62 | 62 |
|
||||
| test.c:58:19:58:23 | ... < ... | test.c:58:23:58:23 | 0 | < | test.c:58:19:58:19 | y | 1 | 62 | 62 |
|
||||
| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:9 | x | != | test.c:75:14:75:14 | 0 | 0 | 78 | 79 |
|
||||
| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:9 | x | == | test.c:75:14:75:14 | 0 | 0 | 75 | 77 |
|
||||
| test.c:75:9:75:14 | ... == ... | test.c:75:14:75:14 | 0 | != | test.c:75:9:75:9 | x | 0 | 78 | 79 |
|
||||
| test.c:75:9:75:14 | ... == ... | test.c:75:14:75:14 | 0 | == | test.c:75:9:75:9 | x | 0 | 75 | 77 |
|
||||
| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:8 | x | == | test.c:85:13:85:13 | 0 | 0 | 85 | 85 |
|
||||
| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:8 | x | == | test.c:85:13:85:13 | 0 | 0 | 86 | 86 |
|
||||
| test.c:85:8:85:13 | ... == ... | test.c:85:13:85:13 | 0 | == | test.c:85:8:85:8 | x | 0 | 85 | 85 |
|
||||
| test.c:85:8:85:13 | ... == ... | test.c:85:13:85:13 | 0 | == | test.c:85:8:85:8 | x | 0 | 86 | 86 |
|
||||
| test.c:85:8:85:23 | ... && ... | test.c:85:8:85:8 | x | == | test.c:85:13:85:13 | 0 | 0 | 86 | 86 |
|
||||
| test.c:85:8:85:23 | ... && ... | test.c:85:13:85:13 | 0 | == | test.c:85:8:85:8 | x | 0 | 86 | 86 |
|
||||
| test.c:85:8:85:23 | ... && ... | test.c:85:18:85:18 | y | != | test.c:85:23:85:23 | 0 | 0 | 86 | 86 |
|
||||
| test.c:85:8:85:23 | ... && ... | test.c:85:23:85:23 | 0 | != | test.c:85:18:85:18 | y | 0 | 86 | 86 |
|
||||
| test.c:85:18:85:23 | ... != ... | test.c:85:18:85:18 | y | != | test.c:85:23:85:23 | 0 | 0 | 86 | 86 |
|
||||
| test.c:85:18:85:23 | ... != ... | test.c:85:23:85:23 | 0 | != | test.c:85:18:85:18 | y | 0 | 86 | 86 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | != | test.c:94:16:94:16 | 0 | 0 | 94 | 96 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | test.c:94:16:94:16 | 0 | 0 | 70 | 70 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | test.c:94:16:94:16 | 0 | 0 | 99 | 102 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | test.c:94:16:94:16 | 0 | 0 | 102 | 102 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | test.c:94:16:94:16 | 0 | 0 | 107 | 109 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | test.c:94:16:94:16 | 0 | 0 | 109 | 109 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | test.c:94:16:94:16 | 0 | 0 | 109 | 117 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | test.c:94:16:94:16 | 0 | 0 | 113 | 113 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:16:94:16 | 0 | != | test.c:94:11:94:11 | x | 0 | 94 | 96 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:16:94:16 | 0 | == | test.c:94:11:94:11 | x | 0 | 70 | 70 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:16:94:16 | 0 | == | test.c:94:11:94:11 | x | 0 | 99 | 102 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:16:94:16 | 0 | == | test.c:94:11:94:11 | x | 0 | 102 | 102 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:16:94:16 | 0 | == | test.c:94:11:94:11 | x | 0 | 107 | 109 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:16:94:16 | 0 | == | test.c:94:11:94:11 | x | 0 | 109 | 109 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:16:94:16 | 0 | == | test.c:94:11:94:11 | x | 0 | 109 | 117 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:16:94:16 | 0 | == | test.c:94:11:94:11 | x | 0 | 113 | 113 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | < | test.c:102:20:102:21 | 10 | 0 | 102 | 102 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | test.c:102:20:102:21 | 10 | 0 | 70 | 70 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | test.c:102:20:102:21 | 10 | 0 | 107 | 109 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | test.c:102:20:102:21 | 10 | 0 | 109 | 109 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | test.c:102:20:102:21 | 10 | 0 | 109 | 117 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | test.c:102:20:102:21 | 10 | 0 | 113 | 113 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:20:102:21 | 10 | < | test.c:102:16:102:16 | j | 1 | 70 | 70 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:20:102:21 | 10 | < | test.c:102:16:102:16 | j | 1 | 107 | 109 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:20:102:21 | 10 | < | test.c:102:16:102:16 | j | 1 | 109 | 109 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:20:102:21 | 10 | < | test.c:102:16:102:16 | j | 1 | 109 | 117 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:20:102:21 | 10 | < | test.c:102:16:102:16 | j | 1 | 113 | 113 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:20:102:21 | 10 | >= | test.c:102:16:102:16 | j | 1 | 102 | 102 |
|
||||
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | test.c:109:14:109:14 | 0 | 0 | 109 | 109 |
|
||||
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | test.c:109:14:109:14 | 0 | 0 | 113 | 113 |
|
||||
| test.c:109:9:109:14 | ... == ... | test.c:109:14:109:14 | 0 | != | test.c:109:9:109:9 | x | 0 | 109 | 109 |
|
||||
| test.c:109:9:109:14 | ... == ... | test.c:109:14:109:14 | 0 | != | test.c:109:9:109:9 | x | 0 | 113 | 113 |
|
||||
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:9:109:9 | x | != | test.c:109:14:109:14 | 0 | 0 | 113 | 113 |
|
||||
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:14:109:14 | 0 | != | test.c:109:9:109:9 | x | 0 | 113 | 113 |
|
||||
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:19:109:19 | y | >= | test.c:109:23:109:23 | 0 | 0 | 113 | 113 |
|
||||
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:23:109:23 | 0 | < | test.c:109:19:109:19 | y | 1 | 113 | 113 |
|
||||
| test.c:109:19:109:23 | ... < ... | test.c:109:19:109:19 | y | >= | test.c:109:23:109:23 | 0 | 0 | 113 | 113 |
|
||||
| test.c:109:19:109:23 | ... < ... | test.c:109:23:109:23 | 0 | < | test.c:109:19:109:19 | y | 1 | 113 | 113 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | test.cpp:31:12:31:13 | - ... | 0 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | test.cpp:31:12:31:13 | - ... | 0 | 34 | 34 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | test.cpp:31:12:31:13 | - ... | 0 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | test.cpp:31:12:31:13 | - ... | 0 | 31 | 32 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:12:31:13 | - ... | != | test.cpp:31:7:31:7 | x | 0 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:12:31:13 | - ... | != | test.cpp:31:7:31:7 | x | 0 | 34 | 34 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:12:31:13 | - ... | == | test.cpp:31:7:31:7 | x | 0 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:12:31:13 | - ... | == | test.cpp:31:7:31:7 | x | 0 | 31 | 32 |
|
||||
irGuards
|
||||
| test.c:7:9:7:13 | CompareGT: ... > ... |
|
||||
| test.c:17:8:17:12 | CompareLT: ... < ... |
|
||||
| test.c:17:17:17:21 | CompareGT: ... > ... |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... |
|
||||
| test.c:44:12:44:16 | CompareGT: ... > ... |
|
||||
| test.c:45:16:45:20 | CompareGT: ... > ... |
|
||||
| test.c:58:9:58:14 | CompareEQ: ... == ... |
|
||||
| test.c:58:19:58:23 | CompareLT: ... < ... |
|
||||
| test.c:75:9:75:14 | CompareEQ: ... == ... |
|
||||
| test.c:85:8:85:13 | CompareEQ: ... == ... |
|
||||
| test.c:85:18:85:23 | CompareNE: ... != ... |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... |
|
||||
| test.c:109:9:109:14 | CompareEQ: ... == ... |
|
||||
| test.c:109:19:109:23 | CompareLT: ... < ... |
|
||||
| test.c:126:7:126:7 | Constant: 1 |
|
||||
| test.c:126:12:126:26 | Call: call to test3_condition |
|
||||
| test.c:131:7:131:7 | Load: b |
|
||||
| test.c:137:7:137:7 | Constant: 0 |
|
||||
| test.c:138:9:138:9 | Load: i |
|
||||
| test.c:146:8:146:8 | Load: x |
|
||||
| test.c:152:10:152:10 | Load: x |
|
||||
| test.c:152:15:152:15 | Load: y |
|
||||
| test.cpp:18:8:18:12 | CompareNE: (bool)... |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... |
|
||||
| test.cpp:42:13:42:20 | Call: call to getABool |
|
||||
irGuardsCompare
|
||||
| 7 | 0 < x+0 when CompareGT: ... > ... is true |
|
||||
| 7 | 0 >= x+0 when CompareGT: ... > ... is false |
|
||||
| 7 | x < 0+1 when CompareGT: ... > ... is false |
|
||||
| 7 | x >= 0+1 when CompareGT: ... > ... is true |
|
||||
| 17 | 0 < x+1 when CompareLT: ... < ... is false |
|
||||
| 17 | 0 >= x+1 when CompareLT: ... < ... is true |
|
||||
| 17 | 1 < y+0 when CompareGT: ... > ... is true |
|
||||
| 17 | 1 >= y+0 when CompareGT: ... > ... is false |
|
||||
| 17 | x < 0+0 when CompareLT: ... < ... is true |
|
||||
| 17 | x >= 0+0 when CompareLT: ... < ... is false |
|
||||
| 17 | y < 1+1 when CompareGT: ... > ... is false |
|
||||
| 17 | y >= 1+1 when CompareGT: ... > ... is true |
|
||||
| 26 | 0 < x+0 when CompareGT: ... > ... is true |
|
||||
| 26 | 0 >= x+0 when CompareGT: ... > ... is false |
|
||||
| 26 | x < 0+1 when CompareGT: ... > ... is false |
|
||||
| 26 | x >= 0+1 when CompareGT: ... > ... is true |
|
||||
| 31 | - ... != x+0 when CompareEQ: ... == ... is false |
|
||||
| 31 | - ... == x+0 when CompareEQ: ... == ... is true |
|
||||
| 31 | x != - ...+0 when CompareEQ: ... == ... is false |
|
||||
| 31 | x == - ...+0 when CompareEQ: ... == ... is true |
|
||||
| 34 | 10 < j+1 when CompareLT: ... < ... is false |
|
||||
| 34 | 10 >= j+1 when CompareLT: ... < ... is true |
|
||||
| 34 | j < 10+0 when CompareLT: ... < ... is true |
|
||||
| 34 | j >= 10+0 when CompareLT: ... < ... is false |
|
||||
| 42 | 10 < j+1 when CompareLT: ... < ... is false |
|
||||
| 42 | 10 >= j+1 when CompareLT: ... < ... is true |
|
||||
| 42 | j < 10+0 when CompareLT: ... < ... is true |
|
||||
| 42 | j >= 10+0 when CompareLT: ... < ... is false |
|
||||
| 44 | 0 < z+0 when CompareGT: ... > ... is true |
|
||||
| 44 | 0 >= z+0 when CompareGT: ... > ... is false |
|
||||
| 44 | z < 0+1 when CompareGT: ... > ... is false |
|
||||
| 44 | z >= 0+1 when CompareGT: ... > ... is true |
|
||||
| 45 | 0 < y+0 when CompareGT: ... > ... is true |
|
||||
| 45 | 0 >= y+0 when CompareGT: ... > ... is false |
|
||||
| 45 | y < 0+1 when CompareGT: ... > ... is false |
|
||||
| 45 | y >= 0+1 when CompareGT: ... > ... is true |
|
||||
| 58 | 0 != x+0 when CompareEQ: ... == ... is false |
|
||||
| 58 | 0 < y+1 when CompareLT: ... < ... is false |
|
||||
| 58 | 0 == x+0 when CompareEQ: ... == ... is true |
|
||||
| 58 | 0 >= y+1 when CompareLT: ... < ... is true |
|
||||
| 58 | x != 0+0 when CompareEQ: ... == ... is false |
|
||||
| 58 | x == 0+0 when CompareEQ: ... == ... is true |
|
||||
| 58 | y < 0+0 when CompareLT: ... < ... is true |
|
||||
| 58 | y >= 0+0 when CompareLT: ... < ... is false |
|
||||
| 75 | 0 != x+0 when CompareEQ: ... == ... is false |
|
||||
| 75 | 0 == x+0 when CompareEQ: ... == ... is true |
|
||||
| 75 | x != 0+0 when CompareEQ: ... == ... is false |
|
||||
| 75 | x == 0+0 when CompareEQ: ... == ... is true |
|
||||
| 85 | 0 != x+0 when CompareEQ: ... == ... is false |
|
||||
| 85 | 0 != y+0 when CompareNE: ... != ... is true |
|
||||
| 85 | 0 == x+0 when CompareEQ: ... == ... is true |
|
||||
| 85 | 0 == y+0 when CompareNE: ... != ... is false |
|
||||
| 85 | x != 0+0 when CompareEQ: ... == ... is false |
|
||||
| 85 | x == 0+0 when CompareEQ: ... == ... is true |
|
||||
| 85 | y != 0+0 when CompareNE: ... != ... is true |
|
||||
| 85 | y == 0+0 when CompareNE: ... != ... is false |
|
||||
| 94 | 0 != x+0 when CompareNE: ... != ... is true |
|
||||
| 94 | 0 == x+0 when CompareNE: ... != ... is false |
|
||||
| 94 | x != 0+0 when CompareNE: ... != ... is true |
|
||||
| 94 | x == 0+0 when CompareNE: ... != ... is false |
|
||||
| 102 | 10 < j+1 when CompareLT: ... < ... is false |
|
||||
| 102 | 10 >= j+1 when CompareLT: ... < ... is true |
|
||||
| 102 | j < 10+0 when CompareLT: ... < ... is true |
|
||||
| 102 | j >= 10+0 when CompareLT: ... < ... is false |
|
||||
| 109 | 0 != x+0 when CompareEQ: ... == ... is false |
|
||||
| 109 | 0 < y+1 when CompareLT: ... < ... is false |
|
||||
| 109 | 0 == x+0 when CompareEQ: ... == ... is true |
|
||||
| 109 | 0 >= y+1 when CompareLT: ... < ... is true |
|
||||
| 109 | x != 0+0 when CompareEQ: ... == ... is false |
|
||||
| 109 | x == 0+0 when CompareEQ: ... == ... is true |
|
||||
| 109 | y < 0+0 when CompareLT: ... < ... is true |
|
||||
| 109 | y >= 0+0 when CompareLT: ... < ... is false |
|
||||
irGuardsControl
|
||||
| test.c:7:9:7:13 | CompareGT: ... > ... | false | 11 | 11 |
|
||||
| test.c:7:9:7:13 | CompareGT: ... > ... | true | 8 | 8 |
|
||||
| test.c:17:8:17:12 | CompareLT: ... < ... | true | 17 | 17 |
|
||||
| test.c:17:8:17:12 | CompareLT: ... < ... | true | 18 | 18 |
|
||||
| test.c:17:17:17:21 | CompareGT: ... > ... | true | 18 | 18 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | false | 2 | 2 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | false | 31 | 31 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | false | 34 | 34 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | false | 35 | 35 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | false | 39 | 39 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | false | 42 | 42 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | false | 43 | 43 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | false | 45 | 45 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | false | 46 | 46 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | false | 49 | 49 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | false | 52 | 52 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | false | 56 | 56 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | false | 58 | 58 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | false | 59 | 59 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | false | 62 | 62 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | true | 27 | 27 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | false | 2 | 2 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | false | 39 | 39 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | false | 42 | 42 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | false | 43 | 43 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | false | 45 | 45 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | false | 46 | 46 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | false | 49 | 49 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | false | 52 | 52 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | false | 56 | 56 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | false | 58 | 58 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | false | 59 | 59 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | false | 62 | 62 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | true | 35 | 35 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | true | 42 | 42 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | true | 43 | 43 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | true | 45 | 45 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | true | 46 | 46 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | true | 49 | 49 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | true | 52 | 52 |
|
||||
| test.c:44:12:44:16 | CompareGT: ... > ... | false | 52 | 52 |
|
||||
| test.c:44:12:44:16 | CompareGT: ... > ... | true | 45 | 45 |
|
||||
| test.c:44:12:44:16 | CompareGT: ... > ... | true | 46 | 46 |
|
||||
| test.c:44:12:44:16 | CompareGT: ... > ... | true | 49 | 49 |
|
||||
| test.c:45:16:45:20 | CompareGT: ... > ... | false | 49 | 49 |
|
||||
| test.c:45:16:45:20 | CompareGT: ... > ... | true | 46 | 46 |
|
||||
| test.c:58:9:58:14 | CompareEQ: ... == ... | false | 58 | 58 |
|
||||
| test.c:58:9:58:14 | CompareEQ: ... == ... | false | 62 | 62 |
|
||||
| test.c:58:19:58:23 | CompareLT: ... < ... | false | 62 | 62 |
|
||||
| test.c:75:9:75:14 | CompareEQ: ... == ... | false | 79 | 79 |
|
||||
| test.c:75:9:75:14 | CompareEQ: ... == ... | true | 76 | 76 |
|
||||
| test.c:85:8:85:13 | CompareEQ: ... == ... | true | 85 | 85 |
|
||||
| test.c:85:8:85:13 | CompareEQ: ... == ... | true | 86 | 86 |
|
||||
| test.c:85:18:85:23 | CompareNE: ... != ... | true | 86 | 86 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | false | 70 | 70 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | false | 99 | 99 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | false | 102 | 102 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | false | 103 | 103 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | false | 107 | 107 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | false | 109 | 109 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | false | 110 | 110 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | false | 113 | 113 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | true | 95 | 95 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | false | 70 | 70 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | false | 107 | 107 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | false | 109 | 109 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | false | 110 | 110 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | false | 113 | 113 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | true | 103 | 103 |
|
||||
| test.c:109:9:109:14 | CompareEQ: ... == ... | false | 109 | 109 |
|
||||
| test.c:109:9:109:14 | CompareEQ: ... == ... | false | 113 | 113 |
|
||||
| test.c:109:19:109:23 | CompareLT: ... < ... | false | 113 | 113 |
|
||||
| test.c:126:7:126:7 | Constant: 1 | true | 126 | 126 |
|
||||
| test.c:126:7:126:7 | Constant: 1 | true | 127 | 127 |
|
||||
| test.c:126:12:126:26 | Call: call to test3_condition | true | 127 | 127 |
|
||||
| test.c:131:7:131:7 | Load: b | true | 132 | 132 |
|
||||
| test.c:137:7:137:7 | Constant: 0 | true | 138 | 138 |
|
||||
| test.c:137:7:137:7 | Constant: 0 | true | 139 | 139 |
|
||||
| test.c:138:9:138:9 | Load: i | true | 139 | 139 |
|
||||
| test.c:146:8:146:8 | Load: x | false | 147 | 147 |
|
||||
| test.c:152:10:152:10 | Load: x | true | 152 | 152 |
|
||||
| test.c:152:15:152:15 | Load: y | true | 152 | 152 |
|
||||
| test.cpp:18:8:18:12 | CompareNE: (bool)... | true | 0 | 0 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | false | 34 | 34 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | true | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | true | 32 | 32 |
|
||||
| test.cpp:42:13:42:20 | Call: call to getABool | false | 53 | 53 |
|
||||
| test.cpp:42:13:42:20 | Call: call to getABool | true | 44 | 44 |
|
||||
irGuardsEnsure
|
||||
| test.c:7:9:7:13 | CompareGT: ... > ... | test.c:7:9:7:9 | Load: x | < | test.c:7:13:7:13 | Constant: 0 | 1 | 11 | 11 |
|
||||
| test.c:7:9:7:13 | CompareGT: ... > ... | test.c:7:9:7:9 | Load: x | >= | test.c:7:13:7:13 | Constant: 0 | 1 | 8 | 8 |
|
||||
| test.c:7:9:7:13 | CompareGT: ... > ... | test.c:7:13:7:13 | Constant: 0 | < | test.c:7:9:7:9 | Load: x | 0 | 8 | 8 |
|
||||
| test.c:7:9:7:13 | CompareGT: ... > ... | test.c:7:13:7:13 | Constant: 0 | >= | test.c:7:9:7:9 | Load: x | 0 | 11 | 11 |
|
||||
| test.c:17:8:17:12 | CompareLT: ... < ... | test.c:17:8:17:8 | Load: x | < | test.c:17:12:17:12 | Constant: 0 | 0 | 17 | 17 |
|
||||
| test.c:17:8:17:12 | CompareLT: ... < ... | test.c:17:8:17:8 | Load: x | < | test.c:17:12:17:12 | Constant: 0 | 0 | 18 | 18 |
|
||||
| test.c:17:8:17:12 | CompareLT: ... < ... | test.c:17:12:17:12 | Constant: 0 | >= | test.c:17:8:17:8 | Load: x | 1 | 17 | 17 |
|
||||
| test.c:17:8:17:12 | CompareLT: ... < ... | test.c:17:12:17:12 | Constant: 0 | >= | test.c:17:8:17:8 | Load: x | 1 | 18 | 18 |
|
||||
| test.c:17:17:17:21 | CompareGT: ... > ... | test.c:17:17:17:17 | Load: y | >= | test.c:17:21:17:21 | Constant: (long)... | 1 | 18 | 18 |
|
||||
| test.c:17:17:17:21 | CompareGT: ... > ... | test.c:17:21:17:21 | Constant: (long)... | < | test.c:17:17:17:17 | Load: y | 0 | 18 | 18 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 2 | 2 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 31 | 31 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 34 | 34 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 35 | 35 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 39 | 39 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 42 | 42 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 43 | 43 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 45 | 45 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 46 | 46 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 49 | 49 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 52 | 52 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 56 | 56 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 58 | 58 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 59 | 59 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | < | test.c:26:15:26:15 | Constant: 0 | 1 | 62 | 62 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:11:26:11 | Load: x | >= | test.c:26:15:26:15 | Constant: 0 | 1 | 27 | 27 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | < | test.c:26:11:26:11 | Load: x | 0 | 27 | 27 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 2 | 2 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 31 | 31 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 34 | 34 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 35 | 35 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 39 | 39 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 42 | 42 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 43 | 43 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 45 | 45 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 46 | 46 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 49 | 49 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 52 | 52 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 56 | 56 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 58 | 58 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 59 | 59 |
|
||||
| test.c:26:11:26:15 | CompareGT: ... > ... | test.c:26:15:26:15 | Constant: 0 | >= | test.c:26:11:26:11 | Load: x | 0 | 62 | 62 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | < | test.c:34:20:34:21 | Constant: 10 | 0 | 35 | 35 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 2 | 2 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 39 | 39 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 42 | 42 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 43 | 43 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 45 | 45 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 46 | 46 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 49 | 49 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 52 | 52 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 56 | 56 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 58 | 58 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 59 | 59 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:16:34:16 | Load: j | >= | test.c:34:20:34:21 | Constant: 10 | 0 | 62 | 62 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 2 | 2 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 39 | 39 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 42 | 42 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 43 | 43 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 45 | 45 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 46 | 46 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 49 | 49 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 52 | 52 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 56 | 56 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 58 | 58 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 59 | 59 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | < | test.c:34:16:34:16 | Load: j | 1 | 62 | 62 |
|
||||
| test.c:34:16:34:21 | CompareLT: ... < ... | test.c:34:20:34:21 | Constant: 10 | >= | test.c:34:16:34:16 | Load: j | 1 | 35 | 35 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 42 | 42 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 43 | 43 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 45 | 45 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 46 | 46 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 49 | 49 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:16:42:16 | Load: j | < | test.c:42:20:42:21 | Constant: 10 | 0 | 52 | 52 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 42 | 42 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 43 | 43 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 45 | 45 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 46 | 46 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 49 | 49 |
|
||||
| test.c:42:16:42:21 | CompareLT: ... < ... | test.c:42:20:42:21 | Constant: 10 | >= | test.c:42:16:42:16 | Load: j | 1 | 52 | 52 |
|
||||
| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:12:44:12 | Load: z | < | test.c:44:16:44:16 | Constant: 0 | 1 | 52 | 52 |
|
||||
| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:12:44:12 | Load: z | >= | test.c:44:16:44:16 | Constant: 0 | 1 | 45 | 45 |
|
||||
| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:12:44:12 | Load: z | >= | test.c:44:16:44:16 | Constant: 0 | 1 | 46 | 46 |
|
||||
| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:12:44:12 | Load: z | >= | test.c:44:16:44:16 | Constant: 0 | 1 | 49 | 49 |
|
||||
| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:16:44:16 | Constant: 0 | < | test.c:44:12:44:12 | Load: z | 0 | 45 | 45 |
|
||||
| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:16:44:16 | Constant: 0 | < | test.c:44:12:44:12 | Load: z | 0 | 46 | 46 |
|
||||
| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:16:44:16 | Constant: 0 | < | test.c:44:12:44:12 | Load: z | 0 | 49 | 49 |
|
||||
| test.c:44:12:44:16 | CompareGT: ... > ... | test.c:44:16:44:16 | Constant: 0 | >= | test.c:44:12:44:12 | Load: z | 0 | 52 | 52 |
|
||||
| test.c:45:16:45:20 | CompareGT: ... > ... | test.c:45:16:45:16 | Load: y | < | test.c:45:20:45:20 | Constant: (long)... | 1 | 49 | 49 |
|
||||
| test.c:45:16:45:20 | CompareGT: ... > ... | test.c:45:16:45:16 | Load: y | >= | test.c:45:20:45:20 | Constant: (long)... | 1 | 46 | 46 |
|
||||
| test.c:45:16:45:20 | CompareGT: ... > ... | test.c:45:20:45:20 | Constant: (long)... | < | test.c:45:16:45:16 | Load: y | 0 | 46 | 46 |
|
||||
| test.c:45:16:45:20 | CompareGT: ... > ... | test.c:45:20:45:20 | Constant: (long)... | >= | test.c:45:16:45:16 | Load: y | 0 | 49 | 49 |
|
||||
| test.c:58:9:58:14 | CompareEQ: ... == ... | test.c:58:9:58:9 | Load: x | != | test.c:58:14:58:14 | Constant: 0 | 0 | 58 | 58 |
|
||||
| test.c:58:9:58:14 | CompareEQ: ... == ... | test.c:58:9:58:9 | Load: x | != | test.c:58:14:58:14 | Constant: 0 | 0 | 62 | 62 |
|
||||
| test.c:58:9:58:14 | CompareEQ: ... == ... | test.c:58:14:58:14 | Constant: 0 | != | test.c:58:9:58:9 | Load: x | 0 | 58 | 58 |
|
||||
| test.c:58:9:58:14 | CompareEQ: ... == ... | test.c:58:14:58:14 | Constant: 0 | != | test.c:58:9:58:9 | Load: x | 0 | 62 | 62 |
|
||||
| test.c:58:19:58:23 | CompareLT: ... < ... | test.c:58:19:58:19 | Load: y | >= | test.c:58:23:58:23 | Constant: (long)... | 0 | 62 | 62 |
|
||||
| test.c:58:19:58:23 | CompareLT: ... < ... | test.c:58:23:58:23 | Constant: (long)... | < | test.c:58:19:58:19 | Load: y | 1 | 62 | 62 |
|
||||
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:75:9:75:9 | Load: x | != | test.c:75:14:75:14 | Constant: 0 | 0 | 79 | 79 |
|
||||
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:75:9:75:9 | Load: x | == | test.c:75:14:75:14 | Constant: 0 | 0 | 76 | 76 |
|
||||
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:75:14:75:14 | Constant: 0 | != | test.c:75:9:75:9 | Load: x | 0 | 79 | 79 |
|
||||
| test.c:75:9:75:14 | CompareEQ: ... == ... | test.c:75:14:75:14 | Constant: 0 | == | test.c:75:9:75:9 | Load: x | 0 | 76 | 76 |
|
||||
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:85:8:85:8 | Load: x | == | test.c:85:13:85:13 | Constant: 0 | 0 | 85 | 85 |
|
||||
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:85:8:85:8 | Load: x | == | test.c:85:13:85:13 | Constant: 0 | 0 | 86 | 86 |
|
||||
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:85:13:85:13 | Constant: 0 | == | test.c:85:8:85:8 | Load: x | 0 | 85 | 85 |
|
||||
| test.c:85:8:85:13 | CompareEQ: ... == ... | test.c:85:13:85:13 | Constant: 0 | == | test.c:85:8:85:8 | Load: x | 0 | 86 | 86 |
|
||||
| test.c:85:18:85:23 | CompareNE: ... != ... | test.c:85:18:85:18 | Load: y | != | test.c:85:23:85:23 | Constant: (long)... | 0 | 86 | 86 |
|
||||
| test.c:85:18:85:23 | CompareNE: ... != ... | test.c:85:23:85:23 | Constant: (long)... | != | test.c:85:18:85:18 | Load: y | 0 | 86 | 86 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | != | test.c:94:16:94:16 | Constant: 0 | 0 | 95 | 95 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | test.c:94:16:94:16 | Constant: 0 | 0 | 70 | 70 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | test.c:94:16:94:16 | Constant: 0 | 0 | 99 | 99 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | test.c:94:16:94:16 | Constant: 0 | 0 | 102 | 102 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | test.c:94:16:94:16 | Constant: 0 | 0 | 103 | 103 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | test.c:94:16:94:16 | Constant: 0 | 0 | 107 | 107 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | test.c:94:16:94:16 | Constant: 0 | 0 | 109 | 109 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | test.c:94:16:94:16 | Constant: 0 | 0 | 110 | 110 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:11:94:11 | Load: x | == | test.c:94:16:94:16 | Constant: 0 | 0 | 113 | 113 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | != | test.c:94:11:94:11 | Load: x | 0 | 95 | 95 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | == | test.c:94:11:94:11 | Load: x | 0 | 70 | 70 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | == | test.c:94:11:94:11 | Load: x | 0 | 99 | 99 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | == | test.c:94:11:94:11 | Load: x | 0 | 102 | 102 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | == | test.c:94:11:94:11 | Load: x | 0 | 103 | 103 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | == | test.c:94:11:94:11 | Load: x | 0 | 107 | 107 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | == | test.c:94:11:94:11 | Load: x | 0 | 109 | 109 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | == | test.c:94:11:94:11 | Load: x | 0 | 110 | 110 |
|
||||
| test.c:94:11:94:16 | CompareNE: ... != ... | test.c:94:16:94:16 | Constant: 0 | == | test.c:94:11:94:11 | Load: x | 0 | 113 | 113 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | < | test.c:102:20:102:21 | Constant: 10 | 0 | 103 | 103 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | >= | test.c:102:20:102:21 | Constant: 10 | 0 | 70 | 70 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | >= | test.c:102:20:102:21 | Constant: 10 | 0 | 107 | 107 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | >= | test.c:102:20:102:21 | Constant: 10 | 0 | 109 | 109 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | >= | test.c:102:20:102:21 | Constant: 10 | 0 | 110 | 110 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:16:102:16 | Load: j | >= | test.c:102:20:102:21 | Constant: 10 | 0 | 113 | 113 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:20:102:21 | Constant: 10 | < | test.c:102:16:102:16 | Load: j | 1 | 70 | 70 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:20:102:21 | Constant: 10 | < | test.c:102:16:102:16 | Load: j | 1 | 107 | 107 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:20:102:21 | Constant: 10 | < | test.c:102:16:102:16 | Load: j | 1 | 109 | 109 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:20:102:21 | Constant: 10 | < | test.c:102:16:102:16 | Load: j | 1 | 110 | 110 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:20:102:21 | Constant: 10 | < | test.c:102:16:102:16 | Load: j | 1 | 113 | 113 |
|
||||
| test.c:102:16:102:21 | CompareLT: ... < ... | test.c:102:20:102:21 | Constant: 10 | >= | test.c:102:16:102:16 | Load: j | 1 | 103 | 103 |
|
||||
| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:9 | Load: x | != | test.c:109:14:109:14 | Constant: 0 | 0 | 109 | 109 |
|
||||
| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:9 | Load: x | != | test.c:109:14:109:14 | Constant: 0 | 0 | 113 | 113 |
|
||||
| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:14:109:14 | Constant: 0 | != | test.c:109:9:109:9 | Load: x | 0 | 109 | 109 |
|
||||
| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:14:109:14 | Constant: 0 | != | test.c:109:9:109:9 | Load: x | 0 | 113 | 113 |
|
||||
| test.c:109:19:109:23 | CompareLT: ... < ... | test.c:109:19:109:19 | Load: y | >= | test.c:109:23:109:23 | Constant: (long)... | 0 | 113 | 113 |
|
||||
| test.c:109:19:109:23 | CompareLT: ... < ... | test.c:109:23:109:23 | Constant: (long)... | < | test.c:109:19:109:19 | Load: y | 1 | 113 | 113 |
|
||||
| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:10 | Call: call to get | != | test.cpp:18:8:18:12 | Constant: (bool)... | 0 | 0 | 0 |
|
||||
| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:12 | Constant: (bool)... | != | test.cpp:18:8:18:10 | Call: call to get | 0 | 0 | 0 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | != | test.cpp:31:12:31:13 | Constant: - ... | 0 | 34 | 34 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | test.cpp:31:12:31:13 | Constant: - ... | 0 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | test.cpp:31:12:31:13 | Constant: - ... | 0 | 32 | 32 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:12:31:13 | Constant: - ... | != | test.cpp:31:7:31:7 | Load: x | 0 | 34 | 34 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:12:31:13 | Constant: - ... | == | test.cpp:31:7:31:7 | Load: x | 0 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:12:31:13 | Constant: - ... | == | test.cpp:31:7:31:7 | Load: x | 0 | 32 | 32 |
|
||||
91
cpp/ql/test/library-tests/controlflow/guards-ir/tests.ql
Normal file
91
cpp/ql/test/library-tests/controlflow/guards-ir/tests.ql
Normal file
@@ -0,0 +1,91 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.IRGuards
|
||||
|
||||
query predicate astGuards(GuardCondition guard) {
|
||||
any()
|
||||
}
|
||||
|
||||
query predicate astGuardsCompare(int startLine, string msg) {
|
||||
exists(GuardCondition guard, Expr left, Expr right, int k, string which, string op |
|
||||
exists(boolean sense |
|
||||
sense = true and which = "true"
|
||||
or sense = false and which = "false"
|
||||
|
|
||||
guard.comparesLt(left, right, k, true, sense) and op = " < "
|
||||
or
|
||||
guard.comparesLt(left, right, k, false, sense) and op = " >= "
|
||||
or
|
||||
guard.comparesEq(left, right, k, true, sense) and op = " == "
|
||||
or
|
||||
guard.comparesEq(left, right, k, false, sense) and op = " != "
|
||||
)
|
||||
and startLine = guard.getLocation().getStartLine()
|
||||
and msg = left + op + right + "+" + k + " when " + guard + " is " + which
|
||||
)
|
||||
}
|
||||
|
||||
query predicate astGuardsControl(GuardCondition guard, boolean sense, int start, int end) {
|
||||
exists(BasicBlock block |
|
||||
guard.controls(block, sense) and
|
||||
block.hasLocationInfo(_, start, _, end, _)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate astGuardsEnsure(GuardCondition guard, Expr left, string op, Expr right, int k, int start, int end)
|
||||
{
|
||||
exists(BasicBlock block |
|
||||
guard.ensuresLt(left, right, k, block, true) and op = "<"
|
||||
or
|
||||
guard.ensuresLt(left, right, k, block, false) and op = ">="
|
||||
or
|
||||
guard.ensuresEq(left, right, k, block, true) and op = "=="
|
||||
or
|
||||
guard.ensuresEq(left, right, k, block, false) and op = "!="
|
||||
|
|
||||
block.hasLocationInfo(_, start, _, end, _)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate irGuards(IRGuardCondition guard) {
|
||||
any()
|
||||
}
|
||||
|
||||
query predicate irGuardsCompare(int startLine, string msg) {
|
||||
exists(IRGuardCondition guard, Instruction left, Instruction right, int k, string which, string op |
|
||||
exists(boolean sense |
|
||||
sense = true and which = "true"
|
||||
or sense = false and which = "false"
|
||||
|
|
||||
guard.comparesLt(left, right, k, true, sense) and op = " < "
|
||||
or
|
||||
guard.comparesLt(left, right, k, false, sense) and op = " >= "
|
||||
or
|
||||
guard.comparesEq(left, right, k, true, sense) and op = " == "
|
||||
or
|
||||
guard.comparesEq(left, right, k, false, sense) and op = " != "
|
||||
)
|
||||
and startLine = guard.getLocation().getStartLine()
|
||||
and msg = left.getUnconvertedResultExpression() + op + right.getUnconvertedResultExpression() + "+" + k + " when " + guard + " is " + which
|
||||
)
|
||||
}
|
||||
query predicate irGuardsControl(IRGuardCondition guard, boolean sense, int start, int end) {
|
||||
exists(IRBlock block |
|
||||
guard.controls(block, sense) and
|
||||
block.getLocation().hasLocationInfo(_, start, _, end, _)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate irGuardsEnsure(IRGuardCondition guard, Instruction left, string op, Instruction right, int k, int start, int end)
|
||||
{
|
||||
exists(IRBlock block |
|
||||
guard.ensuresLt(left, right, k, block, true) and op = "<"
|
||||
or
|
||||
guard.ensuresLt(left, right, k, block, false) and op = ">="
|
||||
or
|
||||
guard.ensuresEq(left, right, k, block, true) and op = "=="
|
||||
or
|
||||
guard.ensuresEq(left, right, k, block, false) and op = "!="
|
||||
|
|
||||
block.getLocation().hasLocationInfo(_, start, _, end, _)
|
||||
)
|
||||
}
|
||||
@@ -34,7 +34,6 @@
|
||||
| test.cpp:8:31:8:35 | initializer for Value |
|
||||
| test.cpp:11:10:11:11 | mention of EC |
|
||||
| test.cpp:11:25:11:27 | mention of IsX<X> |
|
||||
| test.cpp:11:25:11:27 | mention of IsX<X> |
|
||||
| test.cpp:12:8:12:9 | DX<X, B> |
|
||||
| test.cpp:12:8:12:9 | definition of DX<X, B> |
|
||||
| test.cpp:13:17:13:20 | Type |
|
||||
|
||||
@@ -32,3 +32,4 @@
|
||||
| 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. |
|
||||
| RegressionTests.cpp:57:7:57:22 | ... <= ... | Comparison is always true because * ... <= 4294967295. |
|
||||
| Templates.cpp:9:10:9:24 | ... <= ... | Comparison is always true because local <= 32767. |
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
template<typename T>
|
||||
bool sometimesPointless(T param) {
|
||||
return param <= 0xFFFF; // GOOD (hypothetical instantiations are okay)
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool alwaysPointless(T param) {
|
||||
short local = param;
|
||||
return local <= 0xFFFF; // BAD (in all instantiations)
|
||||
}
|
||||
|
||||
static int caller(int i) {
|
||||
return
|
||||
sometimesPointless<short>(i) ||
|
||||
alwaysPointless<short>(i) ||
|
||||
alwaysPointless<int>(i);
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
| custom_printf.cpp:31:5:31:12 | call to myPrintf | Format expects 2 arguments but given 3 |
|
||||
| custom_printf.cpp:44:2:44:7 | call to printf | Format expects 0 arguments but given 2 |
|
||||
| macros.cpp:12:2:12:31 | call to printf | Format expects 2 arguments but given 3 |
|
||||
| macros.cpp:16:2:16:30 | call to printf | Format expects 2 arguments but given 3 |
|
||||
| test.c:7:2:7:7 | call to printf | Format expects 0 arguments but given 1 |
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
| custom_printf.cpp:29:5:29:12 | call to myPrintf | Format expects 2 arguments but given 1 |
|
||||
| custom_printf.cpp:45:2:45:7 | call to printf | Format expects 2 arguments but given 0 |
|
||||
| macros.cpp:14:2:14:37 | call to printf | Format expects 4 arguments but given 3 |
|
||||
| macros.cpp:21:2:21:36 | call to printf | Format expects 4 arguments but given 3 |
|
||||
| test.c:9:2:9:7 | call to printf | Format expects 1 arguments but given 0 |
|
||||
|
||||
@@ -41,6 +41,6 @@ void test_custom_printf2()
|
||||
{
|
||||
// notTheFormat format ...
|
||||
printf(0, "%i %i", 100, 200); // GOOD
|
||||
printf("", "%i %i", 100, 200); // GOOD [FALSE POSITIVE]
|
||||
printf("%i %i", "" ); // GOOD [FALSE POSITIVE]
|
||||
printf("", "%i %i", 100, 200); // GOOD
|
||||
printf("%i %i", "" ); // GOOD
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
| tests.cpp:18:15:18:22 | Hello | This argument should be of type 'char *' but is of type 'char16_t *' |
|
||||
| tests.cpp:19:15:19:22 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *' |
|
||||
| tests.cpp:25:17:25:23 | Hello | This argument should be of type 'wchar_t *' but is of type 'char *' |
|
||||
| tests.cpp:26:17:26:24 | Hello | This argument should be of type 'wchar_t *' but is of type 'char16_t *' |
|
||||
| tests.cpp:30:17:30:24 | Hello | This argument should be of type 'char *' but is of type 'char16_t *' |
|
||||
| tests.cpp:31:17:31:24 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *' |
|
||||
| tests.cpp:33:36:33:42 | Hello | This argument should be of type 'char16_t *' but is of type 'char *' |
|
||||
| tests.cpp:35:36:35:43 | Hello | This argument should be of type 'char16_t *' but is of type 'wchar_t *' |
|
||||
| tests.cpp:38:36:38:43 | Hello | This argument should be of type 'char *' but is of type 'char16_t *' |
|
||||
| tests.cpp:39:36:39:43 | Hello | This argument should be of type 'char *' but is of type 'wchar_t *' |
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/Format/WrongTypeFormatArguments.ql
|
||||
@@ -0,0 +1,3 @@
|
||||
| tests.cpp:8:5:8:10 | printf | char | char16_t, wchar_t | char16_t, wchar_t |
|
||||
| tests.cpp:9:5:9:11 | wprintf | wchar_t | char | wchar_t |
|
||||
| tests.cpp:10:5:10:12 | swprintf | char16_t | char | char16_t |
|
||||
@@ -0,0 +1,8 @@
|
||||
import cpp
|
||||
|
||||
from FormattingFunction f
|
||||
select
|
||||
f,
|
||||
concat(f.getDefaultCharType().toString(), ", "),
|
||||
concat(f.getNonDefaultCharType().toString(), ", "),
|
||||
concat(f.getWideCharType().toString(), ", ")
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Test for custom definitions of *wprintf using different types than the
|
||||
* platform wide character type.
|
||||
*/
|
||||
|
||||
typedef unsigned int size_t;
|
||||
|
||||
int printf(const char * format, ...);
|
||||
int wprintf(const wchar_t * format, ...); // on wchar_t
|
||||
int swprintf(char16_t * s, size_t n, const char16_t * format, ...); // on char16_t
|
||||
|
||||
#define BUF_SIZE (4096)
|
||||
|
||||
void tests() {
|
||||
char16_t buffer[BUF_SIZE];
|
||||
|
||||
printf("%s", "Hello"); // GOOD
|
||||
printf("%s", u"Hello"); // BAD: expecting char
|
||||
printf("%s", L"Hello"); // BAD: expecting char
|
||||
|
||||
printf("%S", "Hello"); // BAD: expecting wchar_t or char16_t [NOT DETECTED]
|
||||
printf("%S", u"Hello"); // GOOD
|
||||
printf("%S", L"Hello"); // GOOD
|
||||
|
||||
wprintf(L"%s", "Hello"); // BAD: expecting wchar_t
|
||||
wprintf(L"%s", u"Hello"); // BAD: expecting wchar_t
|
||||
wprintf(L"%s", L"Hello"); // GOOD
|
||||
|
||||
wprintf(L"%S", "Hello"); // GOOD
|
||||
wprintf(L"%S", u"Hello"); // BAD: expecting char
|
||||
wprintf(L"%S", L"Hello"); // BAD: expecting char
|
||||
|
||||
swprintf(buffer, BUF_SIZE, u"%s", "Hello"); // BAD: expecting char16_t
|
||||
swprintf(buffer, BUF_SIZE, u"%s", u"Hello"); // GOOD
|
||||
swprintf(buffer, BUF_SIZE, u"%s", L"Hello"); // BAD: expecting char16_t
|
||||
|
||||
swprintf(buffer, BUF_SIZE, u"%S", "Hello"); // GOOD
|
||||
swprintf(buffer, BUF_SIZE, u"%S", u"Hello"); // BAD: expecting char
|
||||
swprintf(buffer, BUF_SIZE, u"%S", L"Hello"); // BAD: expecting char
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
| tests_32.cpp:14:16:14:23 | void_ptr | This argument should be of type 'long' but is of type 'void *' |
|
||||
| tests_64.cpp:14:16:14:23 | void_ptr | This argument should be of type 'long' but is of type 'void *' |
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/Format/WrongTypeFormatArguments.ql
|
||||
@@ -0,0 +1,17 @@
|
||||
// semmle-extractor-options: --edg --target --edg linux_i686
|
||||
/*
|
||||
* Test for printf in a snapshot that contains multiple word/pointer sizes.
|
||||
*/
|
||||
|
||||
int printf(const char * format, ...);
|
||||
|
||||
void test_32()
|
||||
{
|
||||
long l;
|
||||
void *void_ptr;
|
||||
|
||||
printf("%li", l); // GOOD
|
||||
printf("%li", void_ptr); // BAD
|
||||
printf("%p", l); // BAD [NOT DETECTED]
|
||||
printf("%p", void_ptr); // GOOD
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// semmle-extractor-options: --edg --target --edg linux_x86_64
|
||||
/*
|
||||
* Test for printf in a snapshot that contains multiple word/pointer sizes.
|
||||
*/
|
||||
|
||||
int printf(const char * format, ...);
|
||||
|
||||
void test_64()
|
||||
{
|
||||
long l;
|
||||
void *void_ptr;
|
||||
|
||||
printf("%li", l); // GOOD
|
||||
printf("%li", void_ptr); // BAD
|
||||
printf("%p", l); // BAD [NOT DETECTED]
|
||||
printf("%p", void_ptr); // GOOD
|
||||
}
|
||||
@@ -11,14 +11,6 @@
|
||||
| printf1.h:45:18:45:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
|
||||
| printf1.h:46:18:46:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
|
||||
| printf1.h:47:19:47:21 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
|
||||
| printf1.h:68:19:68:21 | sst | This argument should be of type 'size_t' but is of type 'long' |
|
||||
| printf1.h:70:19:70:20 | ul | This argument should be of type 'ssize_t' but is of type 'unsigned long' |
|
||||
| printf1.h:71:19:71:20 | st | This argument should be of type 'ssize_t' but is of type 'unsigned long' |
|
||||
| printf1.h:72:19:72:20 | ST | This argument should be of type 'ssize_t' but is of type 'unsigned long' |
|
||||
| printf1.h:73:19:73:22 | c_st | This argument should be of type 'ssize_t' but is of type 'unsigned long' |
|
||||
| printf1.h:74:19:74:22 | C_ST | This argument should be of type 'ssize_t' but is of type 'unsigned long' |
|
||||
| printf1.h:75:19:75:28 | sizeof(<expr>) | This argument should be of type 'ssize_t' but is of type 'unsigned long' |
|
||||
| printf1.h:83:23:83:35 | ... - ... | This argument should be of type 'size_t' but is of type 'long' |
|
||||
| real_world.h:61:21:61:22 | & ... | This argument should be of type 'int *' but is of type 'short *' |
|
||||
| real_world.h:62:22:62:23 | & ... | This argument should be of type 'short *' but is of type 'int *' |
|
||||
| real_world.h:63:22:63:24 | & ... | This argument should be of type 'short *' but is of type 'unsigned int *' |
|
||||
|
||||
@@ -65,14 +65,14 @@ void g()
|
||||
printf("%zu", c_st); // ok
|
||||
printf("%zu", C_ST); // ok
|
||||
printf("%zu", sizeof(ul)); // ok
|
||||
printf("%zu", sst); // not ok [NOT DETECTED ON MICROSOFT]
|
||||
printf("%zu", sst); // not ok [NOT DETECTED]
|
||||
|
||||
printf("%zd", ul); // not ok
|
||||
printf("%zd", st); // not ok
|
||||
printf("%zd", ST); // not ok
|
||||
printf("%zd", c_st); // not ok
|
||||
printf("%zd", C_ST); // not ok
|
||||
printf("%zd", sizeof(ul)); // not ok
|
||||
printf("%zd", ul); // not ok [NOT DETECTED]
|
||||
printf("%zd", st); // not ok [NOT DETECTED]
|
||||
printf("%zd", ST); // not ok [NOT DETECTED]
|
||||
printf("%zd", c_st); // not ok [NOT DETECTED]
|
||||
printf("%zd", C_ST); // not ok [NOT DETECTED]
|
||||
printf("%zd", sizeof(ul)); // not ok [NOT DETECTED]
|
||||
printf("%zd", sst); // ok
|
||||
{
|
||||
char *ptr_a, *ptr_b;
|
||||
@@ -80,8 +80,8 @@ void g()
|
||||
|
||||
printf("%tu", ptr_a - ptr_b); // ok
|
||||
printf("%td", ptr_a - ptr_b); // ok
|
||||
printf("%zu", ptr_a - ptr_b); // ok (dubious) [DETECTED ON LINUX ONLY]
|
||||
printf("%zd", ptr_a - ptr_b); // ok (dubious) [DETECTED ON MICROSOFT ONLY]
|
||||
printf("%zu", ptr_a - ptr_b); // ok (dubious)
|
||||
printf("%zd", ptr_a - ptr_b); // ok (dubious)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,3 +92,12 @@ void h(int i, struct some_type *j, int k)
|
||||
// going on.
|
||||
printf("%i %R %i", i, j, k); // GOOD (as far as we can tell)
|
||||
}
|
||||
|
||||
typedef long ptrdiff_t;
|
||||
|
||||
void fun1(unsigned char* a, unsigned char* b) {
|
||||
ptrdiff_t pdt;
|
||||
|
||||
printf("%td\n", pdt); // GOOD
|
||||
printf("%td\n", a-b); // GOOD
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
| printf.cpp:45:29:45:35 | test | This argument should be of type 'char *' but is of type 'char16_t *' |
|
||||
| printf.cpp:52:29:52:35 | test | This argument should be of type 'char16_t *' but is of type 'wchar_t *' |
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/Format/WrongTypeFormatArguments.ql
|
||||
@@ -0,0 +1,2 @@
|
||||
| printf.cpp:15:5:15:12 | swprintf | char16_t | char | char16_t |
|
||||
| printf.cpp:26:5:26:11 | sprintf | char | char16_t | char16_t |
|
||||
@@ -0,0 +1,8 @@
|
||||
import cpp
|
||||
|
||||
from FormattingFunction f
|
||||
select
|
||||
f,
|
||||
concat(f.getDefaultCharType().toString(), ", "),
|
||||
concat(f.getNonDefaultCharType().toString(), ", "),
|
||||
concat(f.getWideCharType().toString(), ", ")
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Test for custom definitions of *wprintf using different types than the
|
||||
* platform wide character type.
|
||||
*/
|
||||
|
||||
#define WCHAR char16_t
|
||||
typedef void *va_list;
|
||||
#define va_start(va, other)
|
||||
#define va_end(args)
|
||||
|
||||
int vswprintf(WCHAR *dest, WCHAR *format, va_list args) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int swprintf(WCHAR *dest, WCHAR *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
int ret = vswprintf(dest, format, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sprintf(char *dest, char *format, ...);
|
||||
|
||||
// ---
|
||||
|
||||
void test1() {
|
||||
WCHAR string[20];
|
||||
|
||||
swprintf(string, u"test %s", u"test"); // GOOD
|
||||
}
|
||||
|
||||
void test2() {
|
||||
char string[20];
|
||||
|
||||
sprintf(string, "test %S", u"test"); // GOOD
|
||||
}
|
||||
|
||||
void test3() {
|
||||
char string[20];
|
||||
|
||||
sprintf(string, "test %s", u"test"); // BAD: `char16_t` string parameter read as `char` string
|
||||
}
|
||||
|
||||
|
||||
void test4() {
|
||||
char string[20];
|
||||
|
||||
sprintf(string, "test %S", L"test"); // BAD: `wchar_t` string parameter read as `char16_t` string
|
||||
}
|
||||
@@ -11,14 +11,6 @@
|
||||
| printf1.h:45:18:45:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
|
||||
| printf1.h:46:18:46:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
|
||||
| printf1.h:47:19:47:21 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
|
||||
| printf1.h:68:19:68:21 | sst | This argument should be of type 'size_t' but is of type 'long' |
|
||||
| printf1.h:70:19:70:20 | ul | This argument should be of type 'ssize_t' but is of type 'unsigned long' |
|
||||
| printf1.h:71:19:71:20 | st | This argument should be of type 'ssize_t' but is of type 'unsigned long' |
|
||||
| printf1.h:72:19:72:20 | ST | This argument should be of type 'ssize_t' but is of type 'unsigned long' |
|
||||
| printf1.h:73:19:73:22 | c_st | This argument should be of type 'ssize_t' but is of type 'unsigned long' |
|
||||
| printf1.h:74:19:74:22 | C_ST | This argument should be of type 'ssize_t' but is of type 'unsigned long' |
|
||||
| printf1.h:75:19:75:28 | sizeof(<expr>) | This argument should be of type 'ssize_t' but is of type 'unsigned long' |
|
||||
| printf1.h:83:23:83:35 | ... - ... | This argument should be of type 'size_t' but is of type 'long' |
|
||||
| real_world.h:61:21:61:22 | & ... | This argument should be of type 'int *' but is of type 'short *' |
|
||||
| real_world.h:62:22:62:23 | & ... | This argument should be of type 'short *' but is of type 'int *' |
|
||||
| real_world.h:63:22:63:24 | & ... | This argument should be of type 'short *' but is of type 'unsigned int *' |
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
| common.h:12:12:12:17 | printf | char | wchar_t | wchar_t |
|
||||
| format.h:4:13:4:17 | error | char | wchar_t | wchar_t |
|
||||
| real_world.h:8:12:8:18 | fprintf | char | wchar_t | wchar_t |
|
||||
| real_world.h:33:6:33:12 | msg_out | char | wchar_t | wchar_t |
|
||||
@@ -0,0 +1,8 @@
|
||||
import cpp
|
||||
|
||||
from FormattingFunction f
|
||||
select
|
||||
f,
|
||||
concat(f.getDefaultCharType().toString(), ", "),
|
||||
concat(f.getNonDefaultCharType().toString(), ", "),
|
||||
concat(f.getWideCharType().toString(), ", ")
|
||||
@@ -65,14 +65,14 @@ void g()
|
||||
printf("%zu", c_st); // ok
|
||||
printf("%zu", C_ST); // ok
|
||||
printf("%zu", sizeof(ul)); // ok
|
||||
printf("%zu", sst); // not ok [NOT DETECTED ON MICROSOFT]
|
||||
printf("%zu", sst); // not ok [NOT DETECTED]
|
||||
|
||||
printf("%zd", ul); // not ok
|
||||
printf("%zd", st); // not ok
|
||||
printf("%zd", ST); // not ok
|
||||
printf("%zd", c_st); // not ok
|
||||
printf("%zd", C_ST); // not ok
|
||||
printf("%zd", sizeof(ul)); // not ok
|
||||
printf("%zd", ul); // not ok [NOT DETECTED]
|
||||
printf("%zd", st); // not ok [NOT DETECTED]
|
||||
printf("%zd", ST); // not ok [NOT DETECTED]
|
||||
printf("%zd", c_st); // not ok [NOT DETECTED]
|
||||
printf("%zd", C_ST); // not ok [NOT DETECTED]
|
||||
printf("%zd", sizeof(ul)); // not ok [NOT DETECTED]
|
||||
printf("%zd", sst); // ok
|
||||
{
|
||||
char *ptr_a, *ptr_b;
|
||||
@@ -80,8 +80,8 @@ void g()
|
||||
|
||||
printf("%tu", ptr_a - ptr_b); // ok
|
||||
printf("%td", ptr_a - ptr_b); // ok
|
||||
printf("%zu", ptr_a - ptr_b); // ok (dubious) [DETECTED ON LINUX ONLY]
|
||||
printf("%zd", ptr_a - ptr_b); // ok (dubious) [DETECTED ON MICROSOFT ONLY]
|
||||
printf("%zu", ptr_a - ptr_b); // ok (dubious)
|
||||
printf("%zd", ptr_a - ptr_b); // ok (dubious)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,3 +92,12 @@ void h(int i, struct some_type *j, int k)
|
||||
// going on.
|
||||
printf("%i %R %i", i, j, k); // GOOD (as far as we can tell)
|
||||
}
|
||||
|
||||
typedef long ptrdiff_t;
|
||||
|
||||
void fun1(unsigned char* a, unsigned char* b) {
|
||||
ptrdiff_t pdt;
|
||||
|
||||
printf("%td\n", pdt); // GOOD
|
||||
printf("%td\n", a-b); // GOOD
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
| printf1.h:45:18:45:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
|
||||
| printf1.h:46:18:46:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
|
||||
| printf1.h:47:19:47:21 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
|
||||
| printf1.h:70:19:70:20 | ul | This argument should be of type 'ssize_t' but is of type 'unsigned long' |
|
||||
| printf1.h:71:19:71:20 | st | This argument should be of type 'ssize_t' but is of type 'unsigned long long' |
|
||||
| printf1.h:72:19:72:20 | ST | This argument should be of type 'ssize_t' but is of type 'unsigned long long' |
|
||||
| printf1.h:73:19:73:22 | c_st | This argument should be of type 'ssize_t' but is of type 'unsigned long long' |
|
||||
|
||||
@@ -65,9 +65,9 @@ void g()
|
||||
printf("%zu", c_st); // ok
|
||||
printf("%zu", C_ST); // ok
|
||||
printf("%zu", sizeof(ul)); // ok
|
||||
printf("%zu", sst); // not ok [NOT DETECTED ON MICROSOFT]
|
||||
printf("%zu", sst); // not ok [NOT DETECTED]
|
||||
|
||||
printf("%zd", ul); // not ok
|
||||
printf("%zd", ul); // not ok [NOT DETECTED]
|
||||
printf("%zd", st); // not ok
|
||||
printf("%zd", ST); // not ok
|
||||
printf("%zd", c_st); // not ok
|
||||
@@ -80,8 +80,8 @@ void g()
|
||||
|
||||
printf("%tu", ptr_a - ptr_b); // ok
|
||||
printf("%td", ptr_a - ptr_b); // ok
|
||||
printf("%zu", ptr_a - ptr_b); // ok (dubious) [DETECTED ON LINUX ONLY]
|
||||
printf("%zd", ptr_a - ptr_b); // ok (dubious) [DETECTED ON MICROSOFT ONLY]
|
||||
printf("%zu", ptr_a - ptr_b); // ok (dubious)
|
||||
printf("%zd", ptr_a - ptr_b); // ok (dubious) [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,3 +92,12 @@ void h(int i, struct some_type *j, int k)
|
||||
// going on.
|
||||
printf("%i %R %i", i, j, k); // GOOD (as far as we can tell)
|
||||
}
|
||||
|
||||
typedef long long ptrdiff_t;
|
||||
|
||||
void fun1(unsigned char* a, unsigned char* b) {
|
||||
ptrdiff_t pdt;
|
||||
|
||||
printf("%td\n", pdt); // GOOD
|
||||
printf("%td\n", a-b); // GOOD
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ void someFunction()
|
||||
WCHAR filename[MAX_LONGPATH];
|
||||
int linenum;
|
||||
|
||||
msg_out("Source file: %S @ %d\n", filename, linenum); // GOOD
|
||||
msg_out("Source file: %S @ %d\n", filename, linenum); // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
| printf1.h:45:18:45:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
|
||||
| printf1.h:46:18:46:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
|
||||
| printf1.h:47:19:47:21 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' |
|
||||
| printf1.h:70:19:70:20 | ul | This argument should be of type 'ssize_t' but is of type 'unsigned long' |
|
||||
| printf1.h:71:19:71:20 | st | This argument should be of type 'ssize_t' but is of type 'unsigned long long' |
|
||||
| printf1.h:72:19:72:20 | ST | This argument should be of type 'ssize_t' but is of type 'unsigned long long' |
|
||||
| printf1.h:73:19:73:22 | c_st | This argument should be of type 'ssize_t' but is of type 'unsigned long long' |
|
||||
| printf1.h:74:19:74:22 | C_ST | This argument should be of type 'ssize_t' but is of type 'unsigned long long' |
|
||||
| printf1.h:75:19:75:28 | sizeof(<expr>) | This argument should be of type 'ssize_t' but is of type 'unsigned long long' |
|
||||
| printf1.h:84:23:84:35 | ... - ... | This argument should be of type 'ssize_t' but is of type 'long long' |
|
||||
| printf1.h:130:18:130:18 | 0 | This argument should be of type 'void *' but is of type 'int' |
|
||||
| real_world.h:61:21:61:22 | & ... | This argument should be of type 'int *' but is of type 'short *' |
|
||||
| real_world.h:62:22:62:23 | & ... | This argument should be of type 'short *' but is of type 'int *' |
|
||||
| real_world.h:63:22:63:24 | & ... | This argument should be of type 'short *' but is of type 'unsigned int *' |
|
||||
|
||||
@@ -65,9 +65,9 @@ void g()
|
||||
printf("%zu", c_st); // ok
|
||||
printf("%zu", C_ST); // ok
|
||||
printf("%zu", sizeof(ul)); // ok
|
||||
printf("%zu", sst); // not ok [NOT DETECTED ON MICROSOFT]
|
||||
printf("%zu", sst); // not ok [NOT DETECTED]
|
||||
|
||||
printf("%zd", ul); // not ok
|
||||
printf("%zd", ul); // not ok [NOT DETECTED]
|
||||
printf("%zd", st); // not ok
|
||||
printf("%zd", ST); // not ok
|
||||
printf("%zd", c_st); // not ok
|
||||
@@ -80,8 +80,8 @@ void g()
|
||||
|
||||
printf("%tu", ptr_a - ptr_b); // ok
|
||||
printf("%td", ptr_a - ptr_b); // ok
|
||||
printf("%zu", ptr_a - ptr_b); // ok (dubious) [DETECTED ON LINUX ONLY]
|
||||
printf("%zd", ptr_a - ptr_b); // ok (dubious) [DETECTED ON MICROSOFT ONLY]
|
||||
printf("%zu", ptr_a - ptr_b); // ok (dubious)
|
||||
printf("%zd", ptr_a - ptr_b); // ok (dubious) [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,3 +92,40 @@ void h(int i, struct some_type *j, int k)
|
||||
// going on.
|
||||
printf("%i %R %i", i, j, k); // GOOD (as far as we can tell)
|
||||
}
|
||||
|
||||
typedef long long ptrdiff_t;
|
||||
|
||||
void fun1(unsigned char* a, unsigned char* b) {
|
||||
ptrdiff_t pdt;
|
||||
|
||||
printf("%td\n", pdt); // GOOD
|
||||
printf("%td\n", a-b); // GOOD
|
||||
}
|
||||
|
||||
typedef wchar_t WCHAR_T; // WCHAR_T -> wchar_t -> int
|
||||
typedef int MYCHAR; // MYCHAR -> int (notably not via the wchar_t typedef)
|
||||
|
||||
void fun2() {
|
||||
wchar_t *myString1;
|
||||
WCHAR_T *myString2;
|
||||
int *myString3;
|
||||
MYCHAR *myString4;
|
||||
|
||||
printf("%S", myString1); // GOOD
|
||||
printf("%S", myString2); // GOOD
|
||||
printf("%S", myString3); // GOOD
|
||||
printf("%S", myString4); // GOOD
|
||||
}
|
||||
|
||||
typedef void *VOIDPTR;
|
||||
typedef int (*FUNPTR)(int);
|
||||
|
||||
void fun3(void *p1, VOIDPTR p2, FUNPTR p3, char *p4)
|
||||
{
|
||||
printf("%p\n", p1); // GOOD
|
||||
printf("%p\n", p2); // GOOD
|
||||
printf("%p\n", p3); // GOOD
|
||||
printf("%p\n", p4); // GOOD
|
||||
printf("%p\n", p4 + 1); // GOOD
|
||||
printf("%p\n", 0); // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
@@ -171,3 +171,10 @@ void more_tests_2()
|
||||
memset(iapa, 0, sizeof(iapa)); // GOOD
|
||||
memset(iapa, 0, sizeof(intArrayPointer *)); // BAD
|
||||
}
|
||||
|
||||
void more_tests_3()
|
||||
{
|
||||
myStruct ms;
|
||||
decltype(&ms) msPtr = &ms;
|
||||
memset(msPtr, 0, sizeof(myStruct)); // GOOD
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#define NULL 0
|
||||
#define CONST const
|
||||
typedef wchar_t WCHAR; // wc, 16-bit UNICODE character
|
||||
typedef char CHAR;
|
||||
|
||||
typedef WCHAR *LPWSTR;
|
||||
typedef CONST WCHAR *LPCWSTR;
|
||||
|
||||
typedef CHAR *LPSTR;
|
||||
typedef CONST CHAR *LPCSTR;
|
||||
|
||||
void fconstWChar(LPCWSTR p) {}
|
||||
void fWChar(LPWSTR p) {}
|
||||
|
||||
void Test()
|
||||
{
|
||||
char *lpChar = NULL;
|
||||
wchar_t *lpWchar = NULL;
|
||||
LPCSTR lpcstr = "b";
|
||||
|
||||
lpWchar = (LPWSTR)"a"; // BUG
|
||||
lpWchar = (LPWSTR)lpcstr; // BUG
|
||||
|
||||
lpWchar = (wchar_t*)lpChar; // BUG
|
||||
|
||||
fconstWChar((LPCWSTR)lpChar); // BUG
|
||||
fWChar((LPWSTR)lpChar); // BUG
|
||||
|
||||
lpChar = (LPSTR)"a"; // Valid
|
||||
lpWchar = (LPWSTR)L"a"; // Valid
|
||||
|
||||
fconstWChar((LPCWSTR)lpWchar); // Valid
|
||||
fWChar(lpWchar); // Valid
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
| WcharCharConversion.cpp:21:20:21:22 | array to pointer conversion | Conversion from const char * to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:22:20:22:25 | lpcstr | Conversion from LPCSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:24:22:24:27 | lpChar | Conversion from char * to wchar_t *. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:26:23:26:28 | lpChar | Conversion from char * to LPCWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:27:17:27:22 | lpChar | Conversion from char * to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-704/WcharCharConversion.ql
|
||||
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Semmle C# Default Queries
|
||||
Bundle-SymbolicName: com.semmle.plugin.semmlecode.csharp.queries;singleton:=true
|
||||
Bundle-Version: 1.18.0.qualifier
|
||||
Bundle-Version: 1.18.1.qualifier
|
||||
Bundle-Vendor: Semmle Ltd.
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: com.semmle.plugin.qdt.ui;bundle-version="[1.18.0.qualifier, 1.18.0.qualifier]"
|
||||
Require-Bundle: com.semmle.plugin.qdt.ui;bundle-version="[1.18.1.qualifier,1.18.1.qualifier]"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<queries language="csharp"/>
|
||||
31
csharp/ql/src/Stubs/MinimalStubsFromSource.ql
Normal file
31
csharp/ql/src/Stubs/MinimalStubsFromSource.ql
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Tool to generate C# stubs from a qltest snapshot.
|
||||
*
|
||||
* It finds all declarations used in the source code,
|
||||
* and generates minimal C# stubs containing those declarations
|
||||
* and their dependencies.
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import Stubs
|
||||
|
||||
/** Declarations used by source code. */
|
||||
class UsedInSource extends GeneratedDeclaration {
|
||||
UsedInSource() {
|
||||
(
|
||||
this = any(Access a).getTarget()
|
||||
or
|
||||
this = any(Call c).getTarget()
|
||||
or
|
||||
this = any(TypeMention tm).getType()
|
||||
or
|
||||
exists(Virtualizable v | v.fromSource() | this = v.getImplementee() or this = v.getOverridee())
|
||||
or
|
||||
this = any(Attribute a).getType().getAConstructor()
|
||||
)
|
||||
and
|
||||
this.fromLibrary()
|
||||
}
|
||||
}
|
||||
|
||||
select generatedCode()
|
||||
472
csharp/ql/src/Stubs/Stubs.qll
Normal file
472
csharp/ql/src/Stubs/Stubs.qll
Normal file
@@ -0,0 +1,472 @@
|
||||
/**
|
||||
* 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()
|
||||
* ```
|
||||
* to retrieve the generated C# code.
|
||||
*/
|
||||
|
||||
import csharp
|
||||
|
||||
/** An element that should be in the generated code. */
|
||||
abstract class GeneratedElement extends Element {
|
||||
}
|
||||
|
||||
/** A member that should be in the generated code. */
|
||||
abstract class GeneratedMember extends Member, GeneratedElement {
|
||||
}
|
||||
|
||||
/** A type that should be in the generated code. */
|
||||
private abstract class GeneratedType extends ValueOrRefType, GeneratedElement {
|
||||
|
||||
GeneratedType() {
|
||||
(
|
||||
this instanceof Interface
|
||||
or
|
||||
this instanceof Class
|
||||
or
|
||||
this instanceof Struct
|
||||
or
|
||||
this instanceof Enum
|
||||
or
|
||||
this instanceof DelegateType
|
||||
)
|
||||
and
|
||||
not this instanceof ConstructedType
|
||||
and
|
||||
not this.getALocation() instanceof ExcludedAssembly
|
||||
and
|
||||
this.fromLibrary()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this type is duplicated in another assembly.
|
||||
* In this case, we use the assembly with the highest string.
|
||||
*/
|
||||
private predicate isDuplicate() {
|
||||
exists(GeneratedType dup |
|
||||
dup.getQualifiedName() = this.getQualifiedName() and
|
||||
this.getLocation().(Assembly).toString() < dup.getLocation().(Assembly).toString()
|
||||
)
|
||||
}
|
||||
|
||||
private string stubKeyword() {
|
||||
this instanceof Interface and result = "interface"
|
||||
or
|
||||
this instanceof Struct and result = "struct"
|
||||
or
|
||||
this instanceof Class and result = "class"
|
||||
or
|
||||
this instanceof Enum and result = "enum"
|
||||
}
|
||||
|
||||
private string stubAbstractModifier() {
|
||||
if this.(Class).isAbstract() then
|
||||
result = "abstract "
|
||||
else
|
||||
result = ""
|
||||
}
|
||||
|
||||
private string stubStaticModifier() {
|
||||
if this.isStatic() then result = "static "
|
||||
else result = ""
|
||||
}
|
||||
|
||||
private string stubAttributes() {
|
||||
if this.getAnAttribute().getType().getQualifiedName() = "System.FlagsAttribute" then
|
||||
result = "[System.Flags]\n"
|
||||
else
|
||||
result = ""
|
||||
}
|
||||
|
||||
private string stubComment() {
|
||||
result = "// Generated from `" + this.getQualifiedName() + "` in `" +
|
||||
min(this.getLocation().toString()) + "`\n"
|
||||
}
|
||||
|
||||
private string stubAccessibilityModifier() {
|
||||
if this.isPublic() then
|
||||
result = "public "
|
||||
else
|
||||
result = ""
|
||||
}
|
||||
|
||||
/** Gets the entire C# stub code for this type. */
|
||||
final string getStub() {
|
||||
if this.isDuplicate() then
|
||||
result = ""
|
||||
else
|
||||
result = this.stubComment() +
|
||||
this.stubAttributes() +
|
||||
this.stubAbstractModifier() +
|
||||
this.stubStaticModifier() +
|
||||
this.stubAccessibilityModifier() +
|
||||
this.stubKeyword() + " " +
|
||||
this.getUndecoratedName() +
|
||||
stubGenericArguments(this) +
|
||||
stubBaseTypesString() +
|
||||
"\n{\n" +
|
||||
stubMembers() +
|
||||
"}\n\n"
|
||||
}
|
||||
|
||||
private ValueOrRefType getAnInterestingBaseType() {
|
||||
result = this.getABaseType() and
|
||||
not result instanceof ObjectType and
|
||||
not result.getQualifiedName() = "System.ValueType"
|
||||
}
|
||||
|
||||
private string stubBaseTypesString() {
|
||||
if this instanceof Enum then
|
||||
result = ""
|
||||
else if exists(getAnInterestingBaseType()) then
|
||||
result = " : " +
|
||||
concat(int i, ValueOrRefType t |
|
||||
t = this.getAnInterestingBaseType() and (if t instanceof Class then i=0 else i=1) |
|
||||
stubClassName(t), ", " order by i
|
||||
)
|
||||
else
|
||||
result = ""
|
||||
}
|
||||
|
||||
private string stubMembers() {
|
||||
result = concat(stubMember(this.getAGeneratedMember()))
|
||||
}
|
||||
|
||||
private GeneratedMember getAGeneratedMember() {
|
||||
result.getDeclaringType() = this
|
||||
}
|
||||
|
||||
final Type getAGeneratedType() {
|
||||
result = getAnInterestingBaseType()
|
||||
or
|
||||
result = getAGeneratedMember().(Callable).getReturnType()
|
||||
or
|
||||
result = getAGeneratedMember().(Callable).getAParameter().getType()
|
||||
or
|
||||
result = getAGeneratedMember().(Property).getType()
|
||||
or
|
||||
result = getAGeneratedMember().(Field).getType()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A declaration that should be generated.
|
||||
* This is extended in client code to identify the actual
|
||||
* declarations that should be generated.
|
||||
*/
|
||||
abstract class GeneratedDeclaration extends Declaration {
|
||||
}
|
||||
|
||||
private class IndirectType extends GeneratedType {
|
||||
|
||||
IndirectType() {
|
||||
this.getASubType() instanceof GeneratedType
|
||||
or
|
||||
this.getAChildType() instanceof GeneratedType
|
||||
or
|
||||
this.(UnboundGenericType).getAConstructedGeneric().getASubType() instanceof GeneratedType
|
||||
or
|
||||
exists(GeneratedType t | this = getAContainedType(t.getAGeneratedType()).getSourceDeclaration())
|
||||
or
|
||||
exists(GeneratedDeclaration decl | decl.(Member).getDeclaringType().getSourceDeclaration() = this)
|
||||
}
|
||||
}
|
||||
|
||||
private class RootGeneratedType extends GeneratedType {
|
||||
RootGeneratedType() {
|
||||
this = any(GeneratedDeclaration decl).getSourceDeclaration()
|
||||
}
|
||||
}
|
||||
|
||||
private Type getAContainedType(Type t) {
|
||||
result = t
|
||||
or
|
||||
result = getAContainedType(t.(ConstructedType).getATypeArgument())
|
||||
}
|
||||
|
||||
private class RootGeneratedMember extends GeneratedMember {
|
||||
RootGeneratedMember() {
|
||||
this = any(GeneratedDeclaration d).getSourceDeclaration()
|
||||
}
|
||||
}
|
||||
|
||||
private predicate declarationExists(Virtualizable m) {
|
||||
m instanceof GeneratedMember
|
||||
or
|
||||
m.getLocation() instanceof ExcludedAssembly
|
||||
}
|
||||
|
||||
private class InheritedMember extends GeneratedMember, Virtualizable {
|
||||
InheritedMember() {
|
||||
declarationExists(this.getImplementee+())
|
||||
or
|
||||
declarationExists(this.getAnImplementor+())
|
||||
or
|
||||
declarationExists(this.getOverridee+())
|
||||
or
|
||||
declarationExists(this.getAnOverrider+())
|
||||
}
|
||||
}
|
||||
|
||||
/** A namespace that contains at least one generated type. */
|
||||
private class GeneratedNamespace extends Namespace, GeneratedElement {
|
||||
GeneratedNamespace() {
|
||||
this.getATypeDeclaration() instanceof GeneratedType
|
||||
or
|
||||
this.getAChildNamespace() instanceof GeneratedNamespace
|
||||
}
|
||||
|
||||
private string getPreamble() {
|
||||
if this.isGlobalNamespace() then
|
||||
result = ""
|
||||
else
|
||||
result = "namespace " + this.getName() + "\n{\n"
|
||||
}
|
||||
|
||||
private string getPostAmble() {
|
||||
if this.isGlobalNamespace() then
|
||||
result = ""
|
||||
else
|
||||
result = "}\n"
|
||||
}
|
||||
|
||||
final string getStubs() {
|
||||
result = getPreamble() +
|
||||
getTypeStubs() +
|
||||
getSubNamespaces() +
|
||||
getPostAmble()
|
||||
}
|
||||
|
||||
/** Gets the `n`th generated child namespace, indexed from 0. */
|
||||
pragma[nomagic]
|
||||
final GeneratedNamespace getChildNamespace(int n) {
|
||||
result.getParentNamespace() = this and
|
||||
result.getName() = rank[n+1](GeneratedNamespace g | g.getParentNamespace() = this | g.getName())
|
||||
}
|
||||
|
||||
final int getChildNamespaceCount() {
|
||||
result = count(GeneratedNamespace g | g.getParentNamespace() = this)
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
private string getSubNamespaces() {
|
||||
result = concat(int i | exists(getChildNamespace(i)) | getChildNamespace(i).getStubs())
|
||||
}
|
||||
|
||||
private string getTypeStubs() {
|
||||
result = concat(string s | s = any(GeneratedType gt | gt.getDeclaringNamespace() = this).getStub())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify assemblies to exclude.
|
||||
* Do not generate any types from these assemblies.
|
||||
*/
|
||||
abstract class ExcludedAssembly extends Assembly {
|
||||
}
|
||||
|
||||
/** Exclude types from these standard assemblies. */
|
||||
private class DefaultLibs extends ExcludedAssembly {
|
||||
DefaultLibs() {
|
||||
this.getName() = "System.Private.CoreLib"
|
||||
or this.getName() = "mscorlib"
|
||||
or this.getName() = "System.Runtime"
|
||||
}
|
||||
}
|
||||
|
||||
private string stubAccessibility(Member m) {
|
||||
if m.getDeclaringType() instanceof Interface or exists(m.(Virtualizable).getExplicitlyImplementedInterface()) then result = ""
|
||||
else if m.isPublic() then result = "public "
|
||||
else if m.isProtected() then result = "protected "
|
||||
else if m.isPrivate() then result = "private "
|
||||
else if m.isInternal() then result = "internal "
|
||||
else result = "unknown-accessibility"
|
||||
}
|
||||
|
||||
private string stubModifiers(Member m) {
|
||||
result = stubAccessibility(m) + stubStatic(m) + stubOverride(m)
|
||||
}
|
||||
|
||||
private string stubStatic(Member m) {
|
||||
if m.(Modifiable).isStatic() then result = "static "
|
||||
else result = ""
|
||||
}
|
||||
|
||||
private string stubOverride(Member m) {
|
||||
if m.getDeclaringType() instanceof Interface then result = ""
|
||||
else if m.(Virtualizable).isVirtual() then result = "virtual "
|
||||
else if m.(Virtualizable).isAbstract() then result = "abstract "
|
||||
else if m.(Virtualizable).isOverride() then result = "override "
|
||||
else result = ""
|
||||
}
|
||||
|
||||
private string stubQualifiedNamePrefix(ValueOrRefType t) {
|
||||
if t.getParent() instanceof GlobalNamespace then result=""
|
||||
else if t.getParent() instanceof Namespace then result = t.getParent().(Namespace).getQualifiedName() + "."
|
||||
else result = stubQualifiedNamePrefix(t.getParent()) + "."
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
private string stubClassName(Type t) {
|
||||
if t instanceof ObjectType then
|
||||
result = "object"
|
||||
else if t instanceof StringType then
|
||||
result = "string"
|
||||
else if t instanceof IntType then
|
||||
result = "int"
|
||||
else if t instanceof BoolType then
|
||||
result = "bool"
|
||||
else if t instanceof VoidType then
|
||||
result = "void"
|
||||
else if t instanceof FloatType then
|
||||
result = "float"
|
||||
else if t instanceof DoubleType then
|
||||
result = "double"
|
||||
else if t instanceof NullableType then
|
||||
result = stubClassName(t.(NullableType).getUnderlyingType()) + "?"
|
||||
else if t instanceof TypeParameter then
|
||||
result = t.getName()
|
||||
else if t instanceof ArrayType then
|
||||
result = stubClassName(t.(ArrayType).getElementType()) + "[]"
|
||||
else if t instanceof PointerType then
|
||||
result = stubClassName(t.(PointerType).getReferentType()) + "*"
|
||||
else if t instanceof TupleType then
|
||||
result = "(" + concat(int i, Type element | element = t.(TupleType).getElementType(i) | stubClassName(element), "," order by i) + ")"
|
||||
else if t instanceof ValueOrRefType then
|
||||
result = stubQualifiedNamePrefix(t) + t.getUndecoratedName() + stubGenericArguments(t)
|
||||
else
|
||||
result = "<error>"
|
||||
}
|
||||
|
||||
language[monotonicAggregates]
|
||||
private string stubGenericArguments(ValueOrRefType t) {
|
||||
if t instanceof UnboundGenericType then
|
||||
result = "<" + concat(int n | exists(t.(UnboundGenericType).getTypeParameter(n)) | t.(UnboundGenericType).getTypeParameter(n).getName(),"," order by n) + ">"
|
||||
else if t instanceof ConstructedType then
|
||||
result = "<" + concat(int n | exists(t.(ConstructedType).getTypeArgument(n)) | stubClassName(t.(ConstructedType).getTypeArgument(n)),"," order by n) + ">"
|
||||
else
|
||||
result = ""
|
||||
}
|
||||
|
||||
private string stubGenericMethodParams(Method m) {
|
||||
if m instanceof UnboundGenericMethod then
|
||||
result = "<" + concat(int n, TypeParameter param | param = m.(UnboundGenericMethod).getTypeParameter(n) | param.getName(), "," order by n) + ">"
|
||||
else
|
||||
result = ""
|
||||
}
|
||||
|
||||
private string stubImplementation(Virtualizable c) {
|
||||
if c.isAbstract() or c.getDeclaringType() instanceof Interface
|
||||
then result = ""
|
||||
else result = " => throw null"
|
||||
}
|
||||
|
||||
private string stubParameters(Parameterizable p) {
|
||||
result = concat(int i, Parameter param | param = p.getParameter(i) and not param.getType() instanceof ArglistType |
|
||||
stubParameterModifiers(param) + stubClassName(param.getType()) + " " + param.getName() + stubDefaultValue(param), ", " order by i)
|
||||
}
|
||||
|
||||
private string stubParameterModifiers(Parameter p) {
|
||||
if p.isOut() then result = "out "
|
||||
else if p.isRef() then result = "ref "
|
||||
else if p.isParams() then result = "params "
|
||||
else if p.isIn() then result = "" // Only C# 7.1 so ignore
|
||||
else if p.hasExtensionMethodModifier() then result = "this "
|
||||
else result = ""
|
||||
}
|
||||
|
||||
private string stubDefaultValue(Parameter p) {
|
||||
if p.hasDefaultValue()
|
||||
then result = " = default(" + stubClassName(p.getType()) + ")"
|
||||
else result = ""
|
||||
}
|
||||
|
||||
private string stubExplicitImplementation(Member c) {
|
||||
if exists(c.(Virtualizable).getExplicitlyImplementedInterface())
|
||||
then result = stubClassName(c.(Virtualizable).getExplicitlyImplementedInterface()) + "."
|
||||
else result = ""
|
||||
}
|
||||
|
||||
private string stubMember(Member m) {
|
||||
exists(Method c | m = c and not m.getDeclaringType() instanceof Enum |
|
||||
result = " " + stubModifiers(c) + stubClassName(c.getReturnType()) + " " +
|
||||
stubExplicitImplementation(c) + c.getName() + stubGenericMethodParams(c) +
|
||||
"(" + stubParameters(c) + ")" + stubImplementation(c) + ";\n"
|
||||
)
|
||||
or
|
||||
exists(Operator op | m = op and not m.getDeclaringType() instanceof Enum and not op instanceof ConversionOperator |
|
||||
result = " " + stubModifiers(op) + stubClassName(op.getReturnType()) + " operator " +
|
||||
op.getName() +"(" + stubParameters(op) + ") => throw null;\n"
|
||||
)
|
||||
or
|
||||
exists(ConversionOperator op | m = op |
|
||||
result = " " + stubModifiers(op) + stubExplicit(op) + "operator " +
|
||||
stubClassName(op.getReturnType()) + "(" + stubParameters(op) +
|
||||
") => throw null;\n"
|
||||
)
|
||||
or
|
||||
result = " " + m.(EnumConstant).getName() + ",\n"
|
||||
or
|
||||
exists(Property p | m = p |
|
||||
result = " " + stubModifiers(m) + stubClassName(p.getType()) + " " +
|
||||
stubExplicitImplementation(p) + p.getName() + " { " + stubGetter(p) + stubSetter(p) + "}\n"
|
||||
)
|
||||
or exists(Constructor c | m = c and not c.getDeclaringType() instanceof Enum |
|
||||
result = " " + stubModifiers(m) + c.getName() + "(" + stubParameters(c) +
|
||||
") => throw null;\n"
|
||||
)
|
||||
or exists(Indexer i | m = i |
|
||||
result = " " + stubModifiers(m) + stubClassName(i.getType()) + " this[" + stubParameters(i) +
|
||||
"] { " + stubGetter(i) + stubSetter(i) + "}\n"
|
||||
)
|
||||
or exists(Field f | f = m and not f instanceof EnumConstant |
|
||||
result = " " + stubModifiers(m) + stubClassName(f.getType()) + " " + f.getName() + ";\n"
|
||||
)
|
||||
}
|
||||
|
||||
private string stubExplicit(ConversionOperator op) {
|
||||
op instanceof ImplicitConversionOperator and result = "implicit "
|
||||
or
|
||||
op instanceof ExplicitConversionOperator and result = "explicit "
|
||||
}
|
||||
|
||||
private string stubGetter(DeclarationWithGetSetAccessors p) {
|
||||
if exists(p.getGetter()) then (
|
||||
if p.isAbstract() or p.getDeclaringType() instanceof Interface then
|
||||
result = "get; "
|
||||
else
|
||||
result = "get => throw null; "
|
||||
) else
|
||||
result = ""
|
||||
}
|
||||
|
||||
private string stubSetter(DeclarationWithGetSetAccessors p) {
|
||||
if exists(p.getSetter()) then (
|
||||
if p.isAbstract() or p.getDeclaringType() instanceof Interface then
|
||||
result = "set; "
|
||||
else
|
||||
result = "set => throw null; "
|
||||
) else
|
||||
result = ""
|
||||
}
|
||||
|
||||
private string stubSemmleExtractorOptions() {
|
||||
result = concat(string s |
|
||||
exists(CommentLine comment |
|
||||
s = "// original-extractor-options:" + comment.getText().regexpCapture("\\w*semmle-extractor-options:(.*)", 1) + "\n"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the generated C# code. */
|
||||
string generatedCode() {
|
||||
result = "// This file contains auto-generated code.\n" +
|
||||
stubSemmleExtractorOptions() + "\n" +
|
||||
any(GeneratedNamespace ns | ns.isGlobalNamespace()).getStubs()
|
||||
}
|
||||
114
csharp/ql/src/Stubs/make_stubs.py
Normal file
114
csharp/ql/src/Stubs/make_stubs.py
Normal file
@@ -0,0 +1,114 @@
|
||||
# Tool to generate 'stub.cs' files inside C# qltest projects.
|
||||
# The purpose of this is to stub out assemblies from the qltest case
|
||||
# so that the test is self-contained and will still run without them.
|
||||
#
|
||||
# To do this, it
|
||||
# 1. Performs a regular qltest to generate a snapshot
|
||||
# 2. Runs a QL query on the snapshot to find out which symbols are needed,
|
||||
# then uses QL to generate a string of C# code.
|
||||
# 3. Re-runs the test to ensure that it still compiles and passes.
|
||||
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
print('Script to generate stub.cs files for C# qltest projects')
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Please supply a qltest directory.")
|
||||
exit(1)
|
||||
|
||||
testDir = sys.argv[1]
|
||||
|
||||
if not os.path.isdir(testDir):
|
||||
print("Directory", testDir, "does not exist")
|
||||
exit(1)
|
||||
|
||||
# Does it contain a .ql file and a .cs file?
|
||||
|
||||
foundCS = False
|
||||
foundQL = False
|
||||
|
||||
for file in os.listdir(testDir):
|
||||
if file.endswith(".cs"):
|
||||
foundCS = True
|
||||
if file.endswith(".ql") or file.endswith(".qlref"):
|
||||
foundQL = True
|
||||
|
||||
if not foundQL:
|
||||
print("Test directory does not contain .ql files. Please specify a working qltest directory.")
|
||||
exit(1)
|
||||
|
||||
if not foundCS:
|
||||
print("Test directory does not contain .cs files. Please specify a working qltest directory.")
|
||||
exit(1)
|
||||
|
||||
cmd = ['odasa', 'selfTest']
|
||||
print('Running ' + ' '.join(cmd))
|
||||
if subprocess.check_call(cmd):
|
||||
print("odasa selfTest failed. Ensure odasa is on your current path.")
|
||||
exit(1)
|
||||
|
||||
csharpQueries = os.path.abspath(os.path.dirname(sys.argv[0]))
|
||||
outputFile = os.path.join(testDir, 'stubs.cs')
|
||||
|
||||
print("Stubbing qltest in", testDir)
|
||||
|
||||
if os.path.isfile(outputFile):
|
||||
os.remove(outputFile) # It would interfere with the test.
|
||||
print("Removed previous", outputFile)
|
||||
|
||||
cmd = ['odasa', 'qltest', '--optimize', '--leave-temp-files', testDir]
|
||||
print('Running ' + ' '.join(cmd))
|
||||
if subprocess.check_call(cmd):
|
||||
print("qltest failed. Please fix up the test before proceeding.")
|
||||
exit(1)
|
||||
|
||||
dbDir = os.path.join(testDir, os.path.basename(testDir) + ".testproj", "db-csharp")
|
||||
|
||||
if not os.path.isdir(dbDir):
|
||||
print("Expected database directory " + dbDir + " not found. Please contact Semmle.")
|
||||
exit(1)
|
||||
|
||||
cmd = ['odasa', 'runQuery', '--query', os.path.join(csharpQueries, 'MinimalStubsFromSource.ql'), '--db', dbDir, '--output-file', outputFile]
|
||||
print('Running ' + ' '.join(cmd))
|
||||
if subprocess.check_call(cmd):
|
||||
print('Failed to run the query to generate output file. Please contact Semmle.')
|
||||
exit(1)
|
||||
|
||||
# Remove the leading " and trailing " bytes from the file
|
||||
len = os.stat(outputFile).st_size
|
||||
f = open(outputFile, "rb")
|
||||
try:
|
||||
quote = f.read(1)
|
||||
if quote != b'"':
|
||||
print("Unexpected character in file. Please contact Semmle.")
|
||||
contents = f.read(len-3)
|
||||
quote = f.read(1)
|
||||
if quote != b'"':
|
||||
print("Unexpected end character. Please contact Semmle.", quote)
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
f = open(outputFile, "wb")
|
||||
f.write(contents)
|
||||
f.close()
|
||||
|
||||
cmd = ['odasa', 'qltest', '--optimize', testDir]
|
||||
print('Running ' + ' '.join(cmd))
|
||||
if subprocess.check_call(cmd):
|
||||
print('\nTest failed. You may need to fix up', outputFile)
|
||||
print('It may help to view', outputFile, ' in Visual Studio')
|
||||
print("Next steps:")
|
||||
print('1. Look at the compilation errors, and fix up', outputFile, 'so that the test compiles')
|
||||
print('2. Re-run odasa qltest --optimize "' + testDir + '"')
|
||||
print('3. git add "' + outputFile + '"')
|
||||
exit(1)
|
||||
|
||||
print("\nStub generation successful! Next steps:")
|
||||
print('1. Edit "semmle-extractor-options" in the .cs files to remove unused references')
|
||||
print('2. Re-run odasa qltest --optimize "' + testDir + '"')
|
||||
print('3. git add "' + outputFile + '"')
|
||||
print('4. Commit your changes.')
|
||||
|
||||
exit(0)
|
||||
@@ -64,6 +64,20 @@ private Type getTypeArgument(UnboundGenericType ugt, ConstructedType ct, int i,
|
||||
result = ct.getTypeArgument(i)
|
||||
}
|
||||
|
||||
/** A type that is an element type of an array type. */
|
||||
private class ArrayElementType extends Type {
|
||||
ArrayElementType() {
|
||||
this = any(ArrayType at).getElementType()
|
||||
}
|
||||
}
|
||||
|
||||
/** A type that is an argument in a constructed type. */
|
||||
private class TypeArgument extends Type {
|
||||
TypeArgument() {
|
||||
this = any(ConstructedType ct).getATypeArgument()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
@@ -78,125 +92,214 @@ private Type getTypeArgument(UnboundGenericType ugt, ConstructedType ct, int i,
|
||||
predicate convIdentity(Type fromType, Type toType) {
|
||||
fromType = toType
|
||||
or
|
||||
convIdentityStrict(fromType, toType)
|
||||
Identity::convIdentityStrict(fromType, toType)
|
||||
}
|
||||
|
||||
private class IdentityConvertibleType extends Type {
|
||||
IdentityConvertibleType() {
|
||||
isIdentityConvertible(this)
|
||||
private module Identity {
|
||||
private class IdentityConvertibleType extends Type {
|
||||
IdentityConvertibleType() {
|
||||
isIdentityConvertible(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class IdentityConvertibleArrayType extends IdentityConvertibleType, ArrayType { }
|
||||
private class IdentityConvertibleArrayType extends IdentityConvertibleType, ArrayType { }
|
||||
|
||||
private class IdentityConvertibleConstructedType extends IdentityConvertibleType {
|
||||
IdentityConvertibleConstructedType() {
|
||||
this instanceof ConstructedType
|
||||
}
|
||||
}
|
||||
private class IdentityConvertibleConstructedType extends IdentityConvertibleType, ConstructedType { }
|
||||
|
||||
/**
|
||||
* A type is (strictly) identity convertible if it contains at least one `object`
|
||||
* or one `dynamic` sub term.
|
||||
*/
|
||||
private predicate isIdentityConvertible(Type t) {
|
||||
t instanceof ObjectType
|
||||
or
|
||||
t instanceof DynamicType
|
||||
or
|
||||
isIdentityConvertible(t.(ArrayType).getElementType())
|
||||
or
|
||||
isIdentityConvertible(t.(ConstructedType).getATypeArgument())
|
||||
}
|
||||
|
||||
private predicate convIdentityStrict(IdentityConvertibleType fromType, IdentityConvertibleType toType) {
|
||||
convIdentityObjectDynamic(fromType, toType)
|
||||
or
|
||||
convIdentityObjectDynamic(toType, fromType)
|
||||
or
|
||||
convIdentityStrictArrayType(fromType, toType)
|
||||
or
|
||||
convIdentityStrictConstructedType(fromType, toType)
|
||||
}
|
||||
|
||||
private predicate convIdentityObjectDynamic(ObjectType fromType, DynamicType toType) {
|
||||
any()
|
||||
}
|
||||
|
||||
private predicate convIdentityStrictArrayType(IdentityConvertibleArrayType fromType, IdentityConvertibleArrayType toType) {
|
||||
convIdentityStrictArrayTypeJoin(fromType, toType, toType.getDimension(), toType.getRank())
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
private predicate convIdentityStrictArrayTypeJoin(IdentityConvertibleArrayType fromType, IdentityConvertibleArrayType toType, int dim, int rnk) {
|
||||
convIdentityStrictArrayElementType(fromType, toType.getElementType(), dim, rnk)
|
||||
}
|
||||
|
||||
private predicate convIdentityStrictArrayElementType(IdentityConvertibleArrayType fromType, ArrayElementType aet, int dim, int rnk) {
|
||||
convIdentityStrict(fromType.getElementType(), aet) and
|
||||
dim = fromType.getDimension() and
|
||||
rnk = fromType.getRank()
|
||||
}
|
||||
|
||||
/** A type that is an element type of an array type. */
|
||||
private class ArrayElementType extends Type {
|
||||
ArrayElementType() {
|
||||
this = any(ArrayType at).getElementType()
|
||||
}
|
||||
}
|
||||
|
||||
private predicate convIdentityStrictConstructedType(IdentityConvertibleConstructedType fromType, IdentityConvertibleConstructedType toType) {
|
||||
/* Semantically equivalent with
|
||||
* ```
|
||||
* ugt = fromType.getUnboundGeneric()
|
||||
* and
|
||||
* forex(int i |
|
||||
* i in [0 .. ugt.getNumberOfTypeParameters() - 1] |
|
||||
* exists(Type t1, Type t2 |
|
||||
* t1 = getTypeArgument(ugt, fromType, i, _) and
|
||||
* t2 = getTypeArgument(ugt, toType, i, _) |
|
||||
* convIdentity(t1, t2)
|
||||
* )
|
||||
* )
|
||||
* ```
|
||||
* but performance is improved by explicitly evaluating the `i`th argument
|
||||
* only when all preceding arguments are convertible.
|
||||
/**
|
||||
* A type is (strictly) identity convertible if it contains at least one `object`
|
||||
* or one `dynamic` sub term.
|
||||
*/
|
||||
exists(UnboundGenericType ugt |
|
||||
convIdentityStrictConstructedTypeFromZero(ugt, fromType, toType, ugt.getNumberOfTypeParameters() - 1)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the type arguments 0 through `i` of `fromType` and `toType` are identity convertible.
|
||||
*/
|
||||
private predicate convIdentityStrictConstructedTypeFromZero(UnboundGenericType ugt, IdentityConvertibleConstructedType fromType, IdentityConvertibleConstructedType toType, int i) {
|
||||
exists(Type toTypeArgument |
|
||||
convIdentityStrictConstructedTypeFromZeroAux(ugt, fromType, i, toTypeArgument) and
|
||||
toTypeArgument = getTypeArgument(ugt, toType, i, _) and
|
||||
fromType != toType |
|
||||
i = 0
|
||||
private predicate isIdentityConvertible(Type t) {
|
||||
t instanceof ObjectType
|
||||
or
|
||||
convIdentityStrictConstructedTypeFromZero(ugt, fromType, toType, i - 1)
|
||||
)
|
||||
}
|
||||
t instanceof DynamicType
|
||||
or
|
||||
isIdentityConvertible(t.(ArrayType).getElementType())
|
||||
or
|
||||
isIdentityConvertible(t.(ConstructedType).getATypeArgument())
|
||||
}
|
||||
|
||||
pragma [nomagic]
|
||||
private predicate convIdentityStrictConstructedTypeFromZeroAux(UnboundGenericType ugt, IdentityConvertibleConstructedType fromType, int i, Type toTypeArgument) {
|
||||
exists(Type fromTypeArgument |
|
||||
fromTypeArgument = getTypeArgument(ugt, fromType, i, _) and
|
||||
convIdentityTypeArgument(fromTypeArgument, toTypeArgument)
|
||||
)
|
||||
}
|
||||
predicate convIdentityStrict(IdentityConvertibleType fromType, IdentityConvertibleType toType) {
|
||||
convIdentityObjectDynamic(fromType, toType)
|
||||
or
|
||||
convIdentityObjectDynamic(toType, fromType)
|
||||
or
|
||||
convIdentityStrictArrayType(fromType, toType)
|
||||
or
|
||||
convIdentityStrictConstructedType(fromType, toType)
|
||||
}
|
||||
|
||||
private predicate convIdentityTypeArgument(TypeArgument fromType, TypeArgument toType) {
|
||||
convIdentity(fromType, toType)
|
||||
}
|
||||
private predicate convIdentityObjectDynamic(ObjectType fromType, DynamicType toType) {
|
||||
any()
|
||||
}
|
||||
|
||||
/** A type that is an argument in a constructed type. */
|
||||
private class TypeArgument extends Type {
|
||||
TypeArgument() {
|
||||
this = any(ConstructedType ct).getATypeArgument()
|
||||
private predicate convIdentityStrictArrayType(IdentityConvertibleArrayType fromType, IdentityConvertibleArrayType toType) {
|
||||
convIdentityStrictArrayTypeJoin(fromType, toType, toType.getDimension(), toType.getRank())
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate convIdentityStrictArrayTypeJoin(IdentityConvertibleArrayType fromType, IdentityConvertibleArrayType toType, int dim, int rnk) {
|
||||
convIdentityStrictArrayElementType(fromType, toType.getElementType(), dim, rnk)
|
||||
}
|
||||
|
||||
private predicate convIdentityStrictArrayElementType(IdentityConvertibleArrayType fromType, ArrayElementType aet, int dim, int rnk) {
|
||||
convIdentityStrict(fromType.getElementType(), aet) and
|
||||
dim = fromType.getDimension() and
|
||||
rnk = fromType.getRank()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of different type arguments supplied for the type
|
||||
* parameter at index `i` in unbound generic type `ugt`.
|
||||
*/
|
||||
private int getTypeArgumentCount(UnboundGenericType ugt, int i) {
|
||||
result = strictcount(Type arg |
|
||||
exists(IdentityConvertibleConstructedType ct |
|
||||
ct.getUnboundGeneric() = ugt |
|
||||
arg = ct.getTypeArgument(i)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private int rnk(UnboundGenericType ugt, int i) {
|
||||
result = rank[i + 1](int j, int k |
|
||||
j = getTypeArgumentCount(ugt, k) |
|
||||
k order by j, k
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the 'i'th type argument, ranked by size, of constructed type `t`. */
|
||||
private Type getTypeArgumentRanked(UnboundGenericType ugt, IdentityConvertibleConstructedType t, int i) {
|
||||
result = getTypeArgument(ugt, t, rnk(ugt, i), _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `fromTypeArgument` is identity convertible to `toTypeArgument`, and
|
||||
* both types are the `i`th type argument in _some_ constructed type.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate convTypeArguments(Type fromTypeArgument, Type toTypeArgument, int i) {
|
||||
exists(int j |
|
||||
fromTypeArgument = getTypeArgumentRanked(_, _, i) and
|
||||
toTypeArgument = getTypeArgumentRanked(_, _, j) and
|
||||
i <= j and j <= i
|
||||
|
|
||||
convIdentity(fromTypeArgument, toTypeArgument)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convTypeArgumentsSomeUnbound(UnboundGenericType ugt, TypeArgument fromTypeArgument, TypeArgument toTypeArgument, int i) {
|
||||
convTypeArguments(fromTypeArgument, toTypeArgument, i) and
|
||||
fromTypeArgument = getTypeArgumentRanked(ugt, _, i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `fromTypeArgument` is identity convertible to `toTypeArgument` and
|
||||
* both types are the `i`th type argument in _some_ constructed type
|
||||
* based on unbound generic type `ugt`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate convTypeArgumentsSameUnbound(UnboundGenericType ugt, TypeArgument fromTypeArgument, TypeArgument toTypeArgument, int i) {
|
||||
convTypeArgumentsSomeUnbound(ugt, fromTypeArgument, toTypeArgument, i) and
|
||||
toTypeArgument = getTypeArgumentRanked(ugt, _, i)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convIdentitySingle0(UnboundGenericType ugt, IdentityConvertibleConstructedType toType, TypeArgument fromTypeArgument, TypeArgument toTypeArgument) {
|
||||
convTypeArgumentsSameUnbound(ugt, fromTypeArgument, toTypeArgument, 0) and
|
||||
toTypeArgument = getTypeArgumentRanked(ugt, toType, 0) and
|
||||
ugt.getNumberOfTypeParameters() = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the type arguments of types `fromType` and `toType` are identity
|
||||
* convertible, and the number of type arguments is 1.
|
||||
*/
|
||||
predicate convIdentitySingle(UnboundGenericType ugt, IdentityConvertibleConstructedType fromType, IdentityConvertibleConstructedType toType) {
|
||||
exists(TypeArgument fromTypeArgument, TypeArgument toTypeArgument |
|
||||
convIdentitySingle0(ugt, toType, fromTypeArgument, toTypeArgument) |
|
||||
fromTypeArgument = getTypeArgumentRanked(ugt, fromType, 0)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convIdentityMultiple01Aux0(UnboundGenericType ugt, IdentityConvertibleConstructedType toType, TypeArgument fromTypeArgument0, TypeArgument toTypeArgument0, TypeArgument toTypeArgument1) {
|
||||
convTypeArgumentsSameUnbound(ugt, fromTypeArgument0, toTypeArgument0, 0) and
|
||||
toTypeArgument0 = getTypeArgumentRanked(ugt, toType, 0) and
|
||||
toTypeArgument1 = getTypeArgumentRanked(ugt, toType, 1)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convIdentityMultiple01Aux1(UnboundGenericType ugt, IdentityConvertibleConstructedType fromType, TypeArgument fromTypeArgument0, TypeArgument fromTypeArgument1, TypeArgument toTypeArgument1) {
|
||||
convTypeArgumentsSameUnbound(ugt, fromTypeArgument1, toTypeArgument1, 1) and
|
||||
fromTypeArgument0 = getTypeArgumentRanked(ugt, fromType, 0) and
|
||||
fromTypeArgument1 = getTypeArgumentRanked(ugt, fromType, 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the first two ranked type arguments of types `fromType` and `toType`
|
||||
* are identity convertible.
|
||||
*/
|
||||
private predicate convIdentityMultiple01(UnboundGenericType ugt, IdentityConvertibleConstructedType fromType, IdentityConvertibleConstructedType toType) {
|
||||
exists(Type fromTypeArgument0, Type toTypeArgument0, Type fromTypeArgument1, Type toTypeArgument1 |
|
||||
convIdentityMultiple01Aux0(ugt, toType, fromTypeArgument0, toTypeArgument0, toTypeArgument1) |
|
||||
convIdentityMultiple01Aux1(ugt, fromType, fromTypeArgument0, fromTypeArgument1, toTypeArgument1)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convIdentityMultiple2Aux(UnboundGenericType ugt, IdentityConvertibleConstructedType toType, int i, TypeArgument fromTypeArgument, TypeArgument toTypeArgument) {
|
||||
convTypeArgumentsSameUnbound(ugt, fromTypeArgument, toTypeArgument, i) and
|
||||
toTypeArgument = getTypeArgumentRanked(ugt, toType, i) and
|
||||
i >= 2
|
||||
}
|
||||
|
||||
private predicate convIdentityMultiple2(UnboundGenericType ugt, IdentityConvertibleConstructedType fromType, IdentityConvertibleConstructedType toType, int i) {
|
||||
exists(TypeArgument fromTypeArgument, TypeArgument toTypeArgument |
|
||||
convIdentityMultiple2Aux(ugt, toType, i, fromTypeArgument, toTypeArgument) |
|
||||
fromTypeArgument = getTypeArgumentRanked(ugt, fromType, i)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the ranked type arguments 0 through `i` (with `i >= 1`) of types
|
||||
* `fromType` and `toType` are identity convertible.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate convIdentityMultiple(UnboundGenericType ugt, IdentityConvertibleConstructedType fromType, IdentityConvertibleConstructedType toType, int i) {
|
||||
convIdentityMultiple01(ugt, fromType, toType) and i = 1
|
||||
or
|
||||
convIdentityMultiple(ugt, fromType, toType, i - 1) and
|
||||
convIdentityMultiple2(ugt, fromType, toType, i)
|
||||
}
|
||||
|
||||
private predicate convIdentityStrictConstructedType(IdentityConvertibleConstructedType fromType, IdentityConvertibleConstructedType toType) {
|
||||
/* Semantically equivalent with
|
||||
* ```
|
||||
* ugt = fromType.getUnboundGeneric()
|
||||
* and
|
||||
* forex(int i |
|
||||
* i in [0 .. ugt.getNumberOfTypeParameters() - 1] |
|
||||
* exists(Type t1, Type t2 |
|
||||
* t1 = getTypeArgument(ugt, fromType, i, _) and
|
||||
* t2 = getTypeArgument(ugt, toType, i, _) |
|
||||
* convIdentity(t1, t2)
|
||||
* )
|
||||
* )
|
||||
* ```
|
||||
* but performance is improved by explicitly evaluating the `i`th argument
|
||||
* only when all preceding arguments are convertible.
|
||||
*/
|
||||
fromType != toType and
|
||||
(
|
||||
convIdentitySingle(_, fromType, toType)
|
||||
or
|
||||
exists(UnboundGenericType ugt |
|
||||
convIdentityMultiple(ugt, fromType, toType, ugt.getNumberOfTypeParameters() - 1)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,9 +466,8 @@ private predicate convRefTypeNonNull(Type fromType, Type toType) {
|
||||
* This is a deliberate, small cartesian product, so we have manually lifted it to force the
|
||||
* evaluator to evaluate it in its entirety, rather than trying to optimize it in context.
|
||||
*/
|
||||
pragma [noinline]
|
||||
private
|
||||
predicate defaultDynamicConversion(Type fromType, Type toType) {
|
||||
pragma[noinline]
|
||||
private predicate defaultDynamicConversion(Type fromType, Type toType) {
|
||||
fromType instanceof RefType and toType instanceof DynamicType
|
||||
}
|
||||
|
||||
@@ -373,9 +475,8 @@ predicate defaultDynamicConversion(Type fromType, Type toType) {
|
||||
* This is a deliberate, small cartesian product, so we have manually lifted it to force the
|
||||
* evaluator to evaluate it in its entirety, rather than trying to optimize it in context.
|
||||
*/
|
||||
pragma [noinline]
|
||||
private
|
||||
predicate defaultDelegateConversion(RefType fromType, RefType toType) {
|
||||
pragma[noinline]
|
||||
private predicate defaultDelegateConversion(RefType fromType, RefType toType) {
|
||||
fromType instanceof DelegateType and toType = any(SystemDelegateClass c).getABaseType*()
|
||||
}
|
||||
|
||||
@@ -398,9 +499,8 @@ private predicate convRefTypeRefType(RefType fromType, RefType toType) {
|
||||
* This is a deliberate, small cartesian product, so we have manually lifted it to force the
|
||||
* evaluator to evaluate it in its entirety, rather than trying to optimize it in context.
|
||||
*/
|
||||
pragma [noinline]
|
||||
private
|
||||
predicate defaultArrayConversion(Type fromType, RefType toType) {
|
||||
pragma[noinline]
|
||||
private predicate defaultArrayConversion(Type fromType, RefType toType) {
|
||||
fromType instanceof ArrayType and toType = any(SystemArrayClass c).getABaseType*()
|
||||
}
|
||||
|
||||
@@ -427,7 +527,7 @@ private predicate convArrayTypeCovariance(ArrayType fromType, ArrayType toType)
|
||||
convArrayTypeCovarianceJoin(fromType, toType, toType.getDimension(), toType.getRank())
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
pragma[noinline]
|
||||
private predicate convArrayTypeCovarianceJoin(ArrayType fromType, ArrayType toType, int dim, int rnk) {
|
||||
convArrayElementType(fromType, toType.getElementType(), dim, rnk)
|
||||
}
|
||||
@@ -616,7 +716,7 @@ predicate convConversionOperator(Type fromType, Type toType) {
|
||||
}
|
||||
|
||||
/** 13.1.3.2: Variance conversion. */
|
||||
private predicate convVariance(VarianceConvertibleConstructedType fromType, VarianceConvertibleConstructedType toType) {
|
||||
private predicate convVariance(ConstructedType fromType, ConstructedType toType) {
|
||||
/* Semantically equivalent with
|
||||
* ```
|
||||
* ugt = fromType.getUnboundGeneric()
|
||||
@@ -637,95 +737,205 @@ private predicate convVariance(VarianceConvertibleConstructedType fromType, Vari
|
||||
* but performance is improved by explicitly evaluating the `i`th argument
|
||||
* only when all preceding arguments are convertible.
|
||||
*/
|
||||
exists(UnboundGenericType ugt |
|
||||
convVarianceFromZero(ugt, fromType, toType, ugt.getNumberOfTypeParameters() - 1)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the type arguments 0 through `i` of types `fromType` and `toType`
|
||||
* are variance convertible.
|
||||
*/
|
||||
private predicate convVarianceFromZero(UnboundGenericType ugt, VarianceConvertibleConstructedType fromType, VarianceConvertibleConstructedType toType, int i) {
|
||||
exists(Type toTypeArgument |
|
||||
convVarianceFromZeroAux(ugt, fromType, i, toTypeArgument) |
|
||||
toTypeArgument = getTypeArgument(ugt, toType, i, _) and
|
||||
i = 0 and
|
||||
fromType != toType
|
||||
)
|
||||
Variance::convVarianceSingle(_, fromType, toType)
|
||||
or
|
||||
exists(Type toTypeArgument |
|
||||
convVarianceFromZero(ugt, fromType, toType, i - 1) |
|
||||
toTypeArgument = getTypeArgument(ugt, toType, i, _) and
|
||||
convVarianceFromZeroAux(ugt, fromType, i, toTypeArgument)
|
||||
exists(UnboundGenericType ugt |
|
||||
Variance::convVarianceMultiple(ugt, fromType, toType, ugt.getNumberOfTypeParameters() - 1)
|
||||
)
|
||||
}
|
||||
|
||||
pragma [nomagic]
|
||||
private predicate convVarianceFromZeroAux(UnboundGenericType ugt, VarianceConvertibleConstructedType fromType, int i, Type toTypeArgument) {
|
||||
exists(Type fromTypeArgument, TypeParameter tp |
|
||||
fromTypeArgument = getTypeArgument(ugt, fromType, i, tp) |
|
||||
convIdentity(fromTypeArgument, toTypeArgument)
|
||||
private module Variance {
|
||||
/**
|
||||
* Holds if constructed type `ct` is potentially variance convertible to
|
||||
* or from another constructed type, as a result of the `i`th type
|
||||
* argument being potentially convertible.
|
||||
*/
|
||||
private predicate isVarianceConvertible(ConstructedType ct, int i) {
|
||||
exists(TypeParameter tp, Type t |
|
||||
tp = ct.getUnboundGeneric().getTypeParameter(i) and
|
||||
t = ct.getTypeArgument(i) |
|
||||
(
|
||||
// Anything that is not a type parameter is potentially convertible
|
||||
// to/from another type; if the `i`th type parameter is invariant,
|
||||
// `t` must be strictly identity convertible
|
||||
not t instanceof TypeParameter
|
||||
and
|
||||
(tp.isIn() or tp.isOut() or Identity::convIdentityStrict(t, _))
|
||||
)
|
||||
or
|
||||
exists(TypeParameter s |
|
||||
s = t |
|
||||
// A type parameter with implicit reference conversion
|
||||
exists(convTypeParameterBase(s)) and s.isRefType() and tp.isOut()
|
||||
or
|
||||
// A type parameter convertible from another type parameter
|
||||
exists(TypeParameter u | s = convTypeParameterBase(u) and u.isRefType() and tp.isIn())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private class VarianceConvertibleConstructedType extends ConstructedType {
|
||||
VarianceConvertibleConstructedType() {
|
||||
isVarianceConvertible(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of different type arguments supplied for the type
|
||||
* parameter at index `i` in unbound generic type `ugt`.
|
||||
*/
|
||||
private int getTypeArgumentCount(UnboundGenericType ugt, int i) {
|
||||
result = strictcount(Type arg |
|
||||
exists(VarianceConvertibleConstructedType ct |
|
||||
ct.getUnboundGeneric() = ugt |
|
||||
arg = ct.getTypeArgument(i)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private int rnk(UnboundGenericType ugt, int i) {
|
||||
result = rank[i + 1](int j, int k |
|
||||
j = getTypeArgumentCount(ugt, k) |
|
||||
k order by j, k
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the 'i'th type argument, ranked by size, of constructed type `t`. */
|
||||
private Type getTypeArgumentRanked(UnboundGenericType ugt, VarianceConvertibleConstructedType t, int i, TypeParameter tp) {
|
||||
result = getTypeArgument(ugt, t, rnk(ugt, i), tp)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private Type getATypeArgumentRankedOut(int i) {
|
||||
result = getTypeArgumentRanked(_, _, i, any(TypeParameter tp | tp.isOut()))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private Type getATypeArgumentRankedIn(int i) {
|
||||
result = getTypeArgumentRanked(_, _, i, any(TypeParameter tp | tp.isIn()))
|
||||
}
|
||||
|
||||
private predicate convRefTypeTypeArgumentOut(TypeArgument fromType, TypeArgument toType, int i) {
|
||||
convRefTypeNonNull(fromType, toType) and
|
||||
toType = getATypeArgumentRankedOut(i)
|
||||
}
|
||||
|
||||
private predicate convRefTypeTypeArgumentIn(TypeArgument toType, TypeArgument fromType, int i) {
|
||||
convRefTypeNonNull(toType, fromType) and
|
||||
toType = getATypeArgumentRankedIn(i)
|
||||
}
|
||||
|
||||
private newtype TVariance = TNone() or TIn() or TOut()
|
||||
|
||||
/**
|
||||
* Holds if `fromTypeArgument` is convertible to `toTypeArgument`, with variance
|
||||
* `v`, and both types are the `i`th type argument in _some_ constructed type.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate convTypeArguments(TypeArgument fromTypeArgument, TypeArgument toTypeArgument, int i, TVariance v) {
|
||||
exists(int j |
|
||||
fromTypeArgument = getTypeArgumentRanked(_, _, i, _) and
|
||||
toTypeArgument = getTypeArgumentRanked(_, _, j, _) and
|
||||
i <= j and j <= i
|
||||
|
|
||||
convIdentity(fromTypeArgument, toTypeArgument) and
|
||||
v = TNone()
|
||||
or
|
||||
convRefTypeTypeArgumentOut(fromTypeArgument, toTypeArgument, j) and
|
||||
v = TOut()
|
||||
or
|
||||
convRefTypeTypeArgumentIn(toTypeArgument, fromTypeArgument, j) and
|
||||
v = TIn()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convTypeArgumentsSomeUnbound(UnboundGenericType ugt, TypeArgument fromTypeArgument, TypeArgument toTypeArgument, int i) {
|
||||
exists(TypeParameter tp, TVariance v |
|
||||
convTypeArguments(fromTypeArgument, toTypeArgument, i, v) |
|
||||
fromTypeArgument = getTypeArgumentRanked(ugt, _, i, tp) and
|
||||
(v = TIn() implies tp.isIn()) and
|
||||
(v = TOut() implies tp.isOut())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `fromTypeArgument` is convertible to `toTypeArgument` and
|
||||
* both types are the `i`th type argument in _some_ constructed type
|
||||
* based on unbound generic type `ugt`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate convTypeArgumentsSameUnbound(UnboundGenericType ugt, TypeArgument fromTypeArgument, TypeArgument toTypeArgument, int i) {
|
||||
convTypeArgumentsSomeUnbound(ugt, fromTypeArgument, toTypeArgument, i) and
|
||||
toTypeArgument = getTypeArgumentRanked(ugt, _, i, _)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convVarianceSingle0(UnboundGenericType ugt, VarianceConvertibleConstructedType toType, TypeArgument fromTypeArgument, TypeArgument toTypeArgument) {
|
||||
convTypeArgumentsSameUnbound(ugt, fromTypeArgument, toTypeArgument, 0) and
|
||||
toTypeArgument = getTypeArgumentRanked(ugt, toType, 0, _) and
|
||||
ugt.getNumberOfTypeParameters() = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the type arguments of types `fromType` and `toType` are variance
|
||||
* convertible, and the number of type arguments is 1.
|
||||
*/
|
||||
predicate convVarianceSingle(UnboundGenericType ugt, VarianceConvertibleConstructedType fromType, VarianceConvertibleConstructedType toType) {
|
||||
exists(TypeArgument fromTypeArgument, TypeArgument toTypeArgument |
|
||||
convVarianceSingle0(ugt, toType, fromTypeArgument, toTypeArgument) |
|
||||
fromTypeArgument = getTypeArgumentRanked(ugt, fromType, 0, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convVarianceMultiple01Aux0(UnboundGenericType ugt, VarianceConvertibleConstructedType toType, TypeArgument fromTypeArgument0, TypeArgument toTypeArgument0, TypeArgument toTypeArgument1) {
|
||||
convTypeArgumentsSameUnbound(ugt, fromTypeArgument0, toTypeArgument0, 0) and
|
||||
toTypeArgument0 = getTypeArgumentRanked(ugt, toType, 0, _) and
|
||||
toTypeArgument1 = getTypeArgumentRanked(ugt, toType, 1, _)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convVarianceMultiple01Aux1(UnboundGenericType ugt, VarianceConvertibleConstructedType fromType, TypeArgument fromTypeArgument0, TypeArgument fromTypeArgument1, TypeArgument toTypeArgument1) {
|
||||
convTypeArgumentsSameUnbound(ugt, fromTypeArgument1, toTypeArgument1, 1) and
|
||||
fromTypeArgument0 = getTypeArgumentRanked(ugt, fromType, 0, _) and
|
||||
fromTypeArgument1 = getTypeArgumentRanked(ugt, fromType, 1, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the first two ranked type arguments of types `fromType` and `toType`
|
||||
* are variance convertible.
|
||||
*/
|
||||
private predicate convVarianceMultiple01(UnboundGenericType ugt, VarianceConvertibleConstructedType fromType, VarianceConvertibleConstructedType toType) {
|
||||
exists(TypeArgument fromTypeArgument0, TypeArgument toTypeArgument0, TypeArgument fromTypeArgument1, TypeArgument toTypeArgument1 |
|
||||
convVarianceMultiple01Aux0(ugt, toType, fromTypeArgument0, toTypeArgument0, toTypeArgument1) |
|
||||
convVarianceMultiple01Aux1(ugt, fromType, fromTypeArgument0, fromTypeArgument1, toTypeArgument1)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate convVarianceMultiple2Aux(UnboundGenericType ugt, VarianceConvertibleConstructedType toType, int i, TypeArgument fromTypeArgument, TypeArgument toTypeArgument) {
|
||||
convTypeArgumentsSameUnbound(ugt, fromTypeArgument, toTypeArgument, i) and
|
||||
toTypeArgument = getTypeArgumentRanked(ugt, toType, i, _) and
|
||||
i >= 2
|
||||
}
|
||||
|
||||
private predicate convVarianceMultiple2(UnboundGenericType ugt, VarianceConvertibleConstructedType fromType, VarianceConvertibleConstructedType toType, int i) {
|
||||
exists(TypeArgument fromTypeArgument, TypeArgument toTypeArgument |
|
||||
convVarianceMultiple2Aux(ugt, toType, i, fromTypeArgument, toTypeArgument) |
|
||||
fromTypeArgument = getTypeArgumentRanked(ugt, fromType, i, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the ranked type arguments 0 through `i` (with `i >= 1`) of types
|
||||
* `fromType` and `toType` are variance convertible.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate convVarianceMultiple(UnboundGenericType ugt, VarianceConvertibleConstructedType fromType, VarianceConvertibleConstructedType toType, int i) {
|
||||
convVarianceMultiple01(ugt, fromType, toType) and i = 1
|
||||
or
|
||||
convRefTypeTypeArgumentOut(fromTypeArgument, toTypeArgument, i) and
|
||||
tp.isOut()
|
||||
or
|
||||
convRefTypeTypeArgumentIn(toTypeArgument, fromTypeArgument, i) and
|
||||
tp.isIn()
|
||||
)
|
||||
}
|
||||
|
||||
pragma [nomagic]
|
||||
private predicate convRefTypeTypeArgumentOut(TypeArgument fromType, TypeArgument toType, int i) {
|
||||
exists(TypeParameter tp |
|
||||
convRefTypeNonNull(fromType, toType) |
|
||||
toType = getTypeArgument(_, _, i, tp) and
|
||||
tp.isOut()
|
||||
)
|
||||
}
|
||||
|
||||
pragma [nomagic]
|
||||
private predicate convRefTypeTypeArgumentIn(TypeArgument toType, TypeArgument fromType, int i) {
|
||||
exists(TypeParameter tp |
|
||||
convRefTypeNonNull(toType, fromType) |
|
||||
toType = getTypeArgument(_, _, i, tp) and
|
||||
tp.isIn()
|
||||
)
|
||||
}
|
||||
|
||||
private class VarianceConvertibleConstructedType extends ConstructedType {
|
||||
VarianceConvertibleConstructedType() {
|
||||
isVarianceConvertible(this, _)
|
||||
convVarianceMultiple(ugt, fromType, toType, i - 1) and
|
||||
convVarianceMultiple2(ugt, fromType, toType, i)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if constructed type `ct` is potentially variance convertible to
|
||||
* or from another constructed type, as a result of the `i`th type
|
||||
* argument being potentially convertible.
|
||||
*/
|
||||
private predicate isVarianceConvertible(ConstructedType ct, int i) {
|
||||
exists(TypeParameter tp, Type t |
|
||||
tp = ct.getUnboundGeneric().getTypeParameter(i)
|
||||
and
|
||||
t = ct.getTypeArgument(i)
|
||||
|
|
||||
(
|
||||
// Anything that is not a type parameter is potentially convertible
|
||||
// to/from another type; if the `i`th type parameter is invariant,
|
||||
// `t` must be strictly identity convertible
|
||||
not t instanceof TypeParameter
|
||||
and
|
||||
(tp.isIn() or tp.isOut() or convIdentityStrict(t, _))
|
||||
)
|
||||
or
|
||||
exists(TypeParameter s |
|
||||
s = t |
|
||||
// A type parameter with implicit reference conversion
|
||||
exists(convTypeParameterBase(s)) and s.isRefType() and tp.isOut()
|
||||
or
|
||||
// A type parameter convertible from another type parameter
|
||||
exists(TypeParameter u | s = convTypeParameterBase(u) and u.isRefType() and tp.isIn())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* A library for working with XML files and their content.
|
||||
* Provides classes and predicates for working with XML files and their content.
|
||||
*/
|
||||
|
||||
import semmle.code.csharp.Element
|
||||
@@ -18,7 +18,7 @@ class XMLLocatable extends @xmllocatable {
|
||||
not this instanceof File // in the dbscheme
|
||||
}
|
||||
|
||||
/** The source location for this element. */
|
||||
/** Gets the source location for this element. */
|
||||
Location getALocation() { xmllocations(this,result) }
|
||||
|
||||
/**
|
||||
@@ -32,7 +32,7 @@ class XMLLocatable extends @xmllocatable {
|
||||
)
|
||||
}
|
||||
|
||||
/** A printable representation of this element. */
|
||||
/** Gets a printable representation of this element. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
@@ -42,46 +42,49 @@ class XMLLocatable extends @xmllocatable {
|
||||
*/
|
||||
class XMLParent extends @xmlparent {
|
||||
/**
|
||||
* A printable representation of this XML parent.
|
||||
* Gets a printable representation of this XML parent.
|
||||
* (Intended to be overridden in subclasses.)
|
||||
*/
|
||||
abstract string getName();
|
||||
|
||||
/** The file to which this XML parent belongs. */
|
||||
/** Gets the file to which this XML parent belongs. */
|
||||
XMLFile getFile() { result = this or xmlElements(this,_,_,_,result) }
|
||||
|
||||
/** The child element at a specified index of this XML parent. */
|
||||
/** Gets the child element at a specified index of this XML parent. */
|
||||
XMLElement getChild(int index) { xmlElements(result, _, this, index, _) }
|
||||
|
||||
/** A child element of this XML parent. */
|
||||
/** Gets a child element of this XML parent. */
|
||||
XMLElement getAChild() { xmlElements(result,_,this,_,_) }
|
||||
|
||||
/** A child element of this XML parent with the given `name`. */
|
||||
/** Gets a child element of this XML parent with the given `name`. */
|
||||
XMLElement getAChild(string name) { xmlElements(result,_,this,_,_) and result.hasName(name) }
|
||||
|
||||
/** A comment that is a child of this XML parent. */
|
||||
/** Gets a comment that is a child of this XML parent. */
|
||||
XMLComment getAComment() { xmlComments(result,_,this,_) }
|
||||
|
||||
/** A character sequence that is a child of this XML parent. */
|
||||
/** Gets a character sequence that is a child of this XML parent. */
|
||||
XMLCharacters getACharactersSet() { xmlChars(result,_,this,_,_,_) }
|
||||
|
||||
/** The depth in the tree. (Overridden in XMLElement.) */
|
||||
/** Gets the depth in the tree. (Overridden in XMLElement.) */
|
||||
int getDepth() { result = 0 }
|
||||
|
||||
/** The number of child XML elements of this XML parent. */
|
||||
/** Gets the number of child XML elements of this XML parent. */
|
||||
int getNumberOfChildren() {
|
||||
result = count(XMLElement e | xmlElements(e,_,this,_,_))
|
||||
}
|
||||
|
||||
/** The number of places in the body of this XML parent where text occurs. */
|
||||
/** Gets the number of places in the body of this XML parent where text occurs. */
|
||||
int getNumberOfCharacterSets() {
|
||||
result = count(int pos | xmlChars(_,_,this,pos,_,_))
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Internal.
|
||||
*
|
||||
* Append the character sequences of this XML parent from left to right, separated by a space,
|
||||
* up to a specified (zero-based) index.
|
||||
*/
|
||||
deprecated
|
||||
string charsSetUpTo(int n) {
|
||||
(n = 0 and xmlChars(_,result,this,0,_,_)) or
|
||||
(n > 0 and exists(string chars | xmlChars(_,chars,this,n,_,_) |
|
||||
@@ -90,18 +93,15 @@ class XMLParent extends @xmlparent {
|
||||
|
||||
/** Append all the character sequences of this XML parent from left to right, separated by a space. */
|
||||
string allCharactersString() {
|
||||
exists(int n | n = this.getNumberOfCharacterSets() |
|
||||
(n = 0 and result = "") or
|
||||
(n > 0 and result = this.charsSetUpTo(n-1))
|
||||
)
|
||||
result = concat(string chars, int pos | xmlChars(_, chars, this, pos, _, _) | chars, " " order by pos)
|
||||
}
|
||||
|
||||
/** The text value contained in this XML parent. */
|
||||
/** Gets the text value contained in this XML parent. */
|
||||
string getTextValue() {
|
||||
result = allCharactersString()
|
||||
}
|
||||
|
||||
/** A printable representation of this XML parent. */
|
||||
/** Gets a printable representation of this XML parent. */
|
||||
string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
@@ -111,51 +111,52 @@ class XMLFile extends XMLParent, File {
|
||||
xmlEncoding(this,_)
|
||||
}
|
||||
|
||||
/** A printable representation of this XML file. */
|
||||
/** Gets a printable representation of this XML file. */
|
||||
override string toString() { result = XMLParent.super.toString() }
|
||||
|
||||
/** The name of this XML file. */
|
||||
/** Gets the name of this XML file. */
|
||||
override string getName() { files(this,result,_,_,_) }
|
||||
|
||||
/** The path of this XML file. */
|
||||
/** Gets the path of this XML file. */
|
||||
string getPath() { files(this,_,result,_,_) }
|
||||
|
||||
/** The path of the folder that contains this XML file. */
|
||||
/** Gets the path of the folder that contains this XML file. */
|
||||
string getFolder() {
|
||||
result = this.getPath().substring(0, this.getPath().length()-this.getName().length())
|
||||
}
|
||||
|
||||
/** The encoding of this XML file. */
|
||||
/** Gets the encoding of this XML file. */
|
||||
string getEncoding() { xmlEncoding(this,result) }
|
||||
|
||||
/** The XML file itself. */
|
||||
/** Gets the XML file itself. */
|
||||
override
|
||||
XMLFile getFile() { result = this }
|
||||
|
||||
/** A top-most element in an XML file. */
|
||||
/** Gets a top-most element in an XML file. */
|
||||
XMLElement getARootElement() { result = this.getAChild() }
|
||||
|
||||
/** A DTD associated with this XML file. */
|
||||
/** Gets a DTD associated with this XML file. */
|
||||
XMLDTD getADTD() { xmlDTDs(result,_,_,_,this) }
|
||||
}
|
||||
|
||||
/** A "Document Type Definition" of an XML file. */
|
||||
class XMLDTD extends XMLLocatable, @xmldtd {
|
||||
/** The name of the root element of this DTD. */
|
||||
/** Gets the name of the root element of this DTD. */
|
||||
string getRoot() { xmlDTDs(this,result,_,_,_) }
|
||||
|
||||
/** The public ID of this DTD. */
|
||||
/** Gets the public ID of this DTD. */
|
||||
string getPublicId() { xmlDTDs(this,_,result,_,_) }
|
||||
|
||||
/** The system ID of this DTD. */
|
||||
/** Gets the system ID of this DTD. */
|
||||
string getSystemId() { xmlDTDs(this,_,_,result,_) }
|
||||
|
||||
/** Whether this DTD is public. */
|
||||
/** Holds if this DTD is public. */
|
||||
predicate isPublic() { not xmlDTDs(this,_,"",_,_) }
|
||||
|
||||
/** The parent of this DTD. */
|
||||
/** Gets the parent of this DTD. */
|
||||
XMLParent getParent() { xmlDTDs(this,_,_,_,result) }
|
||||
|
||||
/** Gets a printable representation of this DTD. */
|
||||
override string toString() {
|
||||
(this.isPublic() and result = this.getRoot() + " PUBLIC '" +
|
||||
this.getPublicId() + "' '" +
|
||||
@@ -168,89 +169,87 @@ class XMLDTD extends XMLLocatable, @xmldtd {
|
||||
|
||||
/** An XML tag in an XML file. */
|
||||
class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
||||
/** Whether this XML element has the given `name`. */
|
||||
/** Holds if this XML element has the given `name`. */
|
||||
predicate hasName(string name) { name = getName() }
|
||||
|
||||
/** The name of this XML element. */
|
||||
override
|
||||
/** Gets the name of this XML element. */
|
||||
override string getName() { xmlElements(this,result,_,_,_) }
|
||||
|
||||
/** The XML file in which this XML element occurs. */
|
||||
/** Gets the XML file in which this XML element occurs. */
|
||||
override
|
||||
XMLFile getFile() { xmlElements(this,_,_,_,result) }
|
||||
|
||||
/** The parent of this XML element. */
|
||||
/** Gets the parent of this XML element. */
|
||||
XMLParent getParent() { xmlElements(this,_,result,_,_) }
|
||||
|
||||
/** The index of this XML element among its parent's children. */
|
||||
/** Gets the index of this XML element among its parent's children. */
|
||||
int getIndex() { xmlElements(this, _, _, result, _) }
|
||||
|
||||
/** Whether this XML element has a namespace. */
|
||||
/** Holds if this XML element has a namespace. */
|
||||
predicate hasNamespace() { xmlHasNs(this,_,_) }
|
||||
|
||||
/** The namespace of this XML element, if any. */
|
||||
/** Gets the namespace of this XML element, if any. */
|
||||
XMLNamespace getNamespace() { xmlHasNs(this,result,_) }
|
||||
|
||||
/** The index of this XML element among its parent's children. */
|
||||
/** Gets the index of this XML element among its parent's children. */
|
||||
int getElementPositionIndex() { xmlElements(this,_,_,result,_) }
|
||||
|
||||
/** The depth of this element within the XML file tree structure. */
|
||||
/** Gets the depth of this element within the XML file tree structure. */
|
||||
override
|
||||
int getDepth() { result = this.getParent().getDepth() + 1 }
|
||||
|
||||
/** An XML attribute of this XML element. */
|
||||
/** Gets an XML attribute of this XML element. */
|
||||
XMLAttribute getAnAttribute() { result.getElement() = this }
|
||||
|
||||
/** The attribute with the specified `name`, if any. */
|
||||
/** Gets the attribute with the specified `name`, if any. */
|
||||
XMLAttribute getAttribute(string name) {
|
||||
result.getElement() = this and result.getName() = name
|
||||
}
|
||||
|
||||
/** Whether this XML element has an attribute with the specified `name`. */
|
||||
/** Holds if this XML element has an attribute with the specified `name`. */
|
||||
predicate hasAttribute(string name) {
|
||||
exists(XMLAttribute a| a = this.getAttribute(name))
|
||||
}
|
||||
|
||||
/** The value of the attribute with the specified `name`, if any. */
|
||||
/** Gets the value of the attribute with the specified `name`, if any. */
|
||||
string getAttributeValue(string name) {
|
||||
result = this.getAttribute(name).getValue()
|
||||
}
|
||||
|
||||
/** A printable representation of this XML element. */
|
||||
override
|
||||
/** Gets a printable representation of this XML element. */
|
||||
override string toString() { result = XMLParent.super.toString() }
|
||||
}
|
||||
|
||||
/** An attribute that occurs inside an XML element. */
|
||||
class XMLAttribute extends @xmlattribute, XMLLocatable {
|
||||
/** The name of this attribute. */
|
||||
/** Gets the name of this attribute. */
|
||||
string getName() { xmlAttrs(this,_,result,_,_,_) }
|
||||
|
||||
/** The XML element to which this attribute belongs. */
|
||||
/** Gets the XML element to which this attribute belongs. */
|
||||
XMLElement getElement() { xmlAttrs(this,result,_,_,_,_) }
|
||||
|
||||
/** Whether this attribute has a namespace. */
|
||||
/** Holds if this attribute has a namespace. */
|
||||
predicate hasNamespace() { xmlHasNs(this,_,_) }
|
||||
|
||||
/** The namespace of this attribute, if any. */
|
||||
/** Gets the namespace of this attribute, if any. */
|
||||
XMLNamespace getNamespace() { xmlHasNs(this,result,_) }
|
||||
|
||||
/** The value of this attribute. */
|
||||
/** Gets the value of this attribute. */
|
||||
string getValue() { xmlAttrs(this,_,_,result,_,_) }
|
||||
|
||||
/** A printable representation of this XML attribute. */
|
||||
/** Gets a printable representation of this XML attribute. */
|
||||
override string toString() { result = this.getName() + "=" + this.getValue() }
|
||||
}
|
||||
|
||||
/** A namespace used in an XML file */
|
||||
class XMLNamespace extends XMLLocatable, @xmlnamespace {
|
||||
/** The prefix of this namespace. */
|
||||
/** Gets the prefix of this namespace. */
|
||||
string getPrefix() { xmlNs(this,result,_,_) }
|
||||
|
||||
/** The URI of this namespace. */
|
||||
/** Gets the URI of this namespace. */
|
||||
string getURI() { xmlNs(this,_,result,_) }
|
||||
|
||||
/** Whether this namespace has no prefix. */
|
||||
/** Holds if this namespace has no prefix. */
|
||||
predicate isDefault() { this.getPrefix() = "" }
|
||||
|
||||
override string toString() {
|
||||
@@ -261,13 +260,13 @@ class XMLNamespace extends XMLLocatable, @xmlnamespace {
|
||||
|
||||
/** A comment of the form `<!-- ... -->` is an XML comment. */
|
||||
class XMLComment extends @xmlcomment, XMLLocatable {
|
||||
/** The text content of this XML comment. */
|
||||
/** Gets the text content of this XML comment. */
|
||||
string getText() { xmlComments(this,result,_,_) }
|
||||
|
||||
/** The parent of this XML comment. */
|
||||
/** Gets the parent of this XML comment. */
|
||||
XMLParent getParent() { xmlComments(this,_,result,_) }
|
||||
|
||||
/** A printable representation of this XML comment. */
|
||||
/** Gets a printable representation of this XML comment. */
|
||||
override string toString() { result = this.getText() }
|
||||
}
|
||||
|
||||
@@ -276,15 +275,15 @@ class XMLComment extends @xmlcomment, XMLLocatable {
|
||||
* closing tags of an XML element, excluding other elements.
|
||||
*/
|
||||
class XMLCharacters extends @xmlcharacters, XMLLocatable {
|
||||
/** The content of this character sequence. */
|
||||
/** Gets the content of this character sequence. */
|
||||
string getCharacters() { xmlChars(this,result,_,_,_,_) }
|
||||
|
||||
/** The parent of this character sequence. */
|
||||
/** Gets the parent of this character sequence. */
|
||||
XMLParent getParent() { xmlChars(this,_,result,_,_,_) }
|
||||
|
||||
/** Whether this character sequence is CDATA. */
|
||||
/** Holds if this character sequence is CDATA. */
|
||||
predicate isCDATA() { xmlChars(this,_,_,_,1,_) }
|
||||
|
||||
/** A printable representation of this XML character sequence. */
|
||||
/** Gets a printable representation of this XML character sequence. */
|
||||
override string toString() { result = this.getCharacters() }
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Files/FLinesOfCommentedCode.ql
|
||||
@@ -1 +0,0 @@
|
||||
Files/FLinesOfDuplicatedCode.ql
|
||||
@@ -0,0 +1 @@
|
||||
Metrics/Files/FLinesOfCommentedCode.ql
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user