Merge remote-tracking branch 'upstream/master' into ir-copy-unloaded-result

This commit is contained in:
Jonas Jensen
2019-11-06 15:18:40 +01:00
614 changed files with 20022 additions and 7431 deletions

View File

@@ -1,3 +1,5 @@
{ "provide": [ "*/ql/src/qlpack.yml", { "provide": [ "*/ql/src/qlpack.yml",
"*/upgrades/qlpack.yml",
"misc/legacy-support/*/qlpack.yml", "misc/legacy-support/*/qlpack.yml",
"misc/suite-helpers/qlpack.yml" ] } "misc/suite-helpers/qlpack.yml",
"codeql/.codeqlmanifest.json" ] }

View File

@@ -22,6 +22,7 @@ The following changes in version 1.23 affect C/C++ analysis in all applications.
| Too few arguments to formatting function (`cpp/wrong-number-format-arguments`) | Fewer false positive results | Fixed false positives resulting from mistmatching declarations of a formatting function. | | Too few arguments to formatting function (`cpp/wrong-number-format-arguments`) | Fewer false positive results | Fixed false positives resulting from mistmatching declarations of a formatting function. |
| Too many arguments to formatting function (`cpp/too-many-format-arguments`) | Fewer false positive results | Fixed false positives resulting from mistmatching declarations of a formatting function. | | Too many arguments to formatting function (`cpp/too-many-format-arguments`) | Fewer false positive results | Fixed false positives resulting from mistmatching declarations of a formatting function. |
| Unclear comparison precedence (`cpp/comparison-precedence`) | Fewer false positive results | False positives involving template classes and functions have been fixed. | | Unclear comparison precedence (`cpp/comparison-precedence`) | Fewer false positive results | False positives involving template classes and functions have been fixed. |
| Comparison of narrow type with wide type in loop condition (`cpp/comparison-with-wider-type`) | Higher precision | The precision of this query has been increased to "high" as the alerts from this query have proved to be valuable on real-world projects. With this precision, results are now displayed by default in LGTM. |
## Changes to QL libraries ## Changes to QL libraries
@@ -38,6 +39,10 @@ The following changes in version 1.23 affect C/C++ analysis in all applications.
definition of `x` when `x` is a variable of pointer type. It no longer definition of `x` when `x` is a variable of pointer type. It no longer
considers deep paths such as `f(&x.myField)` to be definitions of `x`. These considers deep paths such as `f(&x.myField)` to be definitions of `x`. These
changes are in line with the user expectations we've observed. changes are in line with the user expectations we've observed.
* The data-flow library now makes it easier to specify barriers/sanitizers
arising from guards by overriding the predicate
`isBarrierGuard`/`isSanitizerGuard` on data-flow and taint-tracking
configurations respectively.
* There is now a `DataFlow::localExprFlow` predicate and a * There is now a `DataFlow::localExprFlow` predicate and a
`TaintTracking::localExprTaint` predicate to make it easy to use the most `TaintTracking::localExprTaint` predicate to make it easy to use the most
common case of local data flow and taint: from one `Expr` to another. common case of local data flow and taint: from one `Expr` to another.

View File

@@ -8,6 +8,7 @@ The following changes in version 1.23 affect C# analysis in all applications.
| **Query** | **Tags** | **Purpose** | | **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------| |-----------------------------|-----------|--------------------------------------------------------------------|
| Deserialized delegate (`cs/deserialized-delegate`) | security, external/cwe/cwe-502 | Finds unsafe deserialization of delegate types. |
| Unsafe year argument for 'DateTime' constructor (`cs/unsafe-year-construction`) | reliability, date-time | Finds incorrect manipulation of `DateTime` values, which could lead to invalid dates. | | Unsafe year argument for 'DateTime' constructor (`cs/unsafe-year-construction`) | reliability, date-time | Finds incorrect manipulation of `DateTime` values, which could lead to invalid dates. |
| Mishandling the Japanese era start date (`cs/mishandling-japanese-era`) | reliability, date-time | Finds hard-coded Japanese era start dates that could be invalid. | | Mishandling the Japanese era start date (`cs/mishandling-japanese-era`) | reliability, date-time | Finds hard-coded Japanese era start dates that could be invalid. |
@@ -43,5 +44,6 @@ The following changes in version 1.23 affect C# analysis in all applications.
* There is now a `DataFlow::localExprFlow` predicate and a * There is now a `DataFlow::localExprFlow` predicate and a
`TaintTracking::localExprTaint` predicate to make it easy to use the most `TaintTracking::localExprTaint` predicate to make it easy to use the most
common case of local data flow and taint: from one `Expr` to another. common case of local data flow and taint: from one `Expr` to another.
* Data is now tracked through null-coalescing expressions (`??`).
## Changes to autobuilder ## Changes to autobuilder

View File

@@ -2,6 +2,12 @@
The following changes in version 1.23 affect Java analysis in all applications. The following changes in version 1.23 affect Java analysis in all applications.
## New queries
| **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------|
| Continue statement that does not continue (`java/continue-in-false-loop`) | correctness | Finds `continue` statements in `do { ... } while (false)` loops. |
## Changes to existing queries ## Changes to existing queries
| **Query** | **Expected impact** | **Change** | | **Query** | **Expected impact** | **Change** |

View File

@@ -2,7 +2,7 @@
## General improvements ## General improvements
* Suppor for `globalThis` has been added. * Support for `globalThis` has been added.
* Support for the following frameworks and libraries has been improved: * Support for the following frameworks and libraries has been improved:
- [firebase](https://www.npmjs.com/package/firebase) - [firebase](https://www.npmjs.com/package/firebase)
@@ -12,22 +12,28 @@
* The call graph has been improved to resolve method calls in more cases. This may produce more security alerts. * The call graph has been improved to resolve method calls in more cases. This may produce more security alerts.
* TypeScript 3.6 and 3.7 features are now supported.
* Automatic classification of generated files has been improved, in particular files generated by Doxygen are now recognized.
## New queries ## New queries
| **Query** | **Tags** | **Purpose** | | **Query** | **Tags** | **Purpose** |
|---------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |---------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Unused index variable (`js/unused-index-variable`) | correctness | Highlights loops that iterate over an array, but do not use the index variable to access array elements, indicating a possible typo or logic error. Results are shown on LGTM by default. | | Unused index variable (`js/unused-index-variable`) | correctness | Highlights loops that iterate over an array, but do not use the index variable to access array elements, indicating a possible typo or logic error. Results are shown on LGTM by default. |
| Loop bound injection (`js/loop-bound-injection`) | security, external/cwe/cwe-834 | Highlights loops where a user-controlled object with an arbitrary .length value can trick the server to loop indefinitely. Results are not shown on LGTM by default. | | Loop bound injection (`js/loop-bound-injection`) | security, external/cwe/cwe-834 | Highlights loops where a user-controlled object with an arbitrary .length value can trick the server to loop indefinitely. Results are shown on LGTM by default. |
| Suspicious method name (`js/suspicious-method-name-declaration`) | correctness, typescript, methods | Highlights suspiciously named methods where the developer likely meant to write a constructor or function. Results are shown on LGTM by default. | | Suspicious method name (`js/suspicious-method-name-declaration`) | correctness, typescript, methods | Highlights suspiciously named methods where the developer likely meant to write a constructor or function. Results are shown on LGTM by default. |
| Shell command built from environment values (`js/shell-command-injection-from-environment`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights shell commands that may change behavior inadvertently depending on the execution environment, indicating a possible violation of [CWE-78](https://cwe.mitre.org/data/definitions/78.html). Results are shown on LGTM by default.| | Shell command built from environment values (`js/shell-command-injection-from-environment`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights shell commands that may change behavior inadvertently depending on the execution environment, indicating a possible violation of [CWE-78](https://cwe.mitre.org/data/definitions/78.html). Results are shown on LGTM by default.|
| Use of returnless function (`js/use-of-returnless-function`) | maintainability, correctness | Highlights calls where the return value is used, but the callee never returns a value. Results are shown on LGTM by default. | | Use of returnless function (`js/use-of-returnless-function`) | maintainability, correctness | Highlights calls where the return value is used, but the callee never returns a value. Results are shown on LGTM by default. |
| Useless regular expression character escape (`js/useless-regexp-character-escape`) | correctness, security, external/cwe/cwe-20 | Highlights regular expression strings with useless character escapes, indicating a possible violation of [CWE-20](https://cwe.mitre.org/data/definitions/20.html). Results are shown on LGTM by default. | | Useless regular expression character escape (`js/useless-regexp-character-escape`) | correctness, security, external/cwe/cwe-20 | Highlights regular expression strings with useless character escapes, indicating a possible violation of [CWE-20](https://cwe.mitre.org/data/definitions/20.html). Results are shown on LGTM by default. |
| Unreachable method overloads (`js/unreachable-method-overloads`) | correctness, typescript | Highlights method overloads that are impossible to use from client code. Results are shown on LGTM by default. | | Unreachable method overloads (`js/unreachable-method-overloads`) | correctness, typescript | Highlights method overloads that are impossible to use from client code. Results are shown on LGTM by default. |
| Ignoring result from pure array method (`js/ignore-array-result`) | maintainability, correctness | Highlights calls to array methods without side effects where the return value is ignored. Results are shown on LGTM by default. |
## Changes to existing queries ## Changes to existing queries
| **Query** | **Expected impact** | **Change** | | **Query** | **Expected impact** | **Change** |
|--------------------------------|------------------------------|---------------------------------------------------------------------------| |--------------------------------|------------------------------|---------------------------------------------------------------------------|
| Double escaping or unescaping (`js/double-escaping`) | More results | This rule now detects additional escaping and unescaping functions. |
| Incomplete string escaping or encoding (`js/incomplete-sanitization`) | Fewer false-positive results | This rule now recognizes additional ways delimiters can be stripped away. | | Incomplete string escaping or encoding (`js/incomplete-sanitization`) | Fewer false-positive results | This rule now recognizes additional ways delimiters can be stripped away. |
| Client-side cross-site scripting (`js/xss`) | More results, fewer false-positive results | More potential vulnerabilities involving functions that manipulate DOM attributes are now recognized, and more sanitizers are detected. | | Client-side cross-site scripting (`js/xss`) | More results, fewer false-positive results | More potential vulnerabilities involving functions that manipulate DOM attributes are now recognized, and more sanitizers are detected. |
| Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving functions that manipulate DOM event handler attributes are now recognized. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving functions that manipulate DOM event handler attributes are now recognized. |
@@ -40,6 +46,8 @@
| Reflected cross-site scripting (`js/reflected-xss`) | Fewer false-positive results | The query now recognizes more sanitizers. | | Reflected cross-site scripting (`js/reflected-xss`) | Fewer false-positive results | The query now recognizes more sanitizers. |
| Stored cross-site scripting (`js/stored-xss`) | Fewer false-positive results | The query now recognizes more sanitizers. | | Stored cross-site scripting (`js/stored-xss`) | Fewer false-positive results | The query now recognizes more sanitizers. |
| Uncontrolled command line (`js/command-line-injection`) | More results | This query now treats responses from servers as untrusted. | | Uncontrolled command line (`js/command-line-injection`) | More results | This query now treats responses from servers as untrusted. |
| Uncontrolled data used in path expression (`js/path-injection`) | Fewer false-positive results | This query now recognizes calls to Express `sendFile` as safe in some cases. |
| Unknown directive (`js/unknown-directive`) | Fewer false positive results | This query no longer flags uses of ":", which is sometimes used like a directive. |
## Changes to QL libraries ## Changes to QL libraries

View File

@@ -19,4 +19,9 @@
| **Query** | **Expected impact** | **Change** | | **Query** | **Expected impact** | **Change** |
|----------------------------|------------------------|------------| |----------------------------|------------------------|------------|
| Unreachable code | Fewer false positives | Analysis now accounts for uses of `contextlib.suppress` to suppress exceptions. | | Unreachable code | Fewer false positives | Analysis now accounts for uses of `contextlib.suppress` to suppress exceptions. |
| `__iter__` method returns a non-iterator | Better alert message | Alert now highlights which class is expected to be an iterator. |
## Changes to QL libraries
* Django library now recognizes positional arguments from a `django.conf.urls.url` regex (Django version 1.x)

View File

@@ -5,6 +5,17 @@
## Changes to code extraction ## Changes to code extraction
* Asynchronous generator methods are now parsed correctly and no longer cause a spurious syntax error. * Asynchronous generator methods are now parsed correctly and no longer cause a spurious syntax error.
* Files in `node_modules` and `bower_components` folders are no longer extracted by default. If you still want to extract files from these folders, you can add the following filters to your `lgtm.yml` file (or add them to existing filters):
```yaml
extraction:
javascript:
index:
filters:
- include: "**/node_modules"
- include: "**/bower_components"
```
* Recognition of CommonJS modules has improved. As a result, some files that were previously extracted as * Recognition of CommonJS modules has improved. As a result, some files that were previously extracted as
global scripts are now extracted as modules. global scripts are now extracted as modules.
* Top-level `await` is now supported. * Top-level `await` is now supported.

View File

@@ -76,7 +76,11 @@
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll", "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll" "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll"
],
"IR IRType": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll"
], ],
"IR Operand Tag": [ "IR Operand Tag": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll",
@@ -169,22 +173,39 @@
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintIRImports.qll" "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintIRImports.qll"
], ],
"C++ SSA SSAConstructionImports": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll"
],
"C++ SSA AliasAnalysis": [ "C++ SSA AliasAnalysis": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll" "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll"
], ],
"C++ SSA SSAConstruction": [ "C++ IR ValueNumberingImports": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingImports.qll"
],
"IR SSA SimpleSSA": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll"
],
"IR SSA SSAConstruction": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll" "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll"
], ],
"C++ SSA PrintSSA": [ "IR SSA PrintSSA": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll" "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll"
], ],
"C++ IR ValueNumber": [ "IR ValueNumber": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll" "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll"
], ],
"C++ IR ConstantAnalysis": [ "C++ IR ConstantAnalysis": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/ConstantAnalysis.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/ConstantAnalysis.qll",
@@ -235,5 +256,9 @@
"C# IR PrintIRImports": [ "C# IR PrintIRImports": [
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll", "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll" "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll"
],
"C# IR ValueNumberingImports": [
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll"
] ]
} }

View File

@@ -21,6 +21,7 @@ from Variable v
where where
v.isStatic() and v.isStatic() and
v.hasDefinition() and v.hasDefinition() and
not v.isConstexpr() and
not exists(VariableAccess a | a.getTarget() = v) and not exists(VariableAccess a | a.getTarget() = v) and
not v instanceof MemberVariable and not v instanceof MemberVariable and
not declarationHasSideEffects(v) and not declarationHasSideEffects(v) and

View File

@@ -2,36 +2,39 @@
"-//Semmle//qhelp//EN" "-//Semmle//qhelp//EN"
"qhelp.dtd"> "qhelp.dtd">
<qhelp> <qhelp>
<overview>
<p> <overview>
Checking for overflow of integer addition needs to be done with <p>
care, because automatic type promotion can prevent the check Checking for overflow of integer addition needs to be done with
from working correctly. care, because automatic type promotion can prevent the check
</p> from working as intended, with the same value (<code>true</code>
</overview> or <code>false</code>) always being returned.
<recommendation> </p>
<p> </overview>
Use an explicit cast to make sure that the result of the addition is <recommendation>
not implicitly converted to a larger type. <p>
</p> Use an explicit cast to make sure that the result of the addition is
</recommendation> not implicitly converted to a larger type.
<example> </p>
<sample src="BadAdditionOverflowCheckExample1.cpp" /> </recommendation>
<p> <example>
On a typical architecture where <tt>short</tt> is 16 bits <sample src="BadAdditionOverflowCheckExample1.cpp" />
and <tt>int</tt> is 32 bits, the operands of the addition are <p>
automatically promoted to <tt>int</tt>, so it cannot overflow On a typical architecture where <code>short</code> is 16 bits
and the result of the comparison is always false. and <code>int</code> is 32 bits, the operands of the addition are
</p> automatically promoted to <code>int</code>, so it cannot overflow
<p> and the result of the comparison is always false.
The code below implements the check correctly, by using an </p>
explicit cast to make sure that the result of the addition <p>
is <tt>unsigned short</tt>. The code below implements the check correctly, by using an
</p> explicit cast to make sure that the result of the addition
<sample src="BadAdditionOverflowCheckExample2.cpp" /> is <code>unsigned short</code> (which may overflow, in which case
</example> the comparison would evaluate to <code>true</code>).
<references> </p>
<li><a href="http://c-faq.com/expr/preservingrules.html">Preserving Rules</a></li> <sample src="BadAdditionOverflowCheckExample2.cpp" />
<li><a href="https://www.securecoding.cert.org/confluence/plugins/servlet/mobile#content/view/20086942">Understand integer conversion rules</a></li> </example>
</references> <references>
<li><a href="http://c-faq.com/expr/preservingrules.html">Preserving Rules</a></li>
<li><a href="https://www.securecoding.cert.org/confluence/plugins/servlet/mobile#content/view/20086942">Understand integer conversion rules</a></li>
</references>
</qhelp> </qhelp>

View File

@@ -1,3 +1,4 @@
bool checkOverflow(unsigned short x, unsigned short y) { bool checkOverflow(unsigned short x, unsigned short y) {
return (x + y < x); // BAD: x and y are automatically promoted to int. // BAD: comparison is always false due to type promotion
return (x + y < x);
} }

View File

@@ -18,4 +18,4 @@ where
co.getAChild() = chco and co.getAChild() = chco and
not chco.isParenthesised() and not chco.isParenthesised() and
not co.isFromUninstantiatedTemplate(_) not co.isFromUninstantiatedTemplate(_)
select co, "Check the comparison operator precedence." select co, "Comparison as an operand to another comparison."

View File

@@ -0,0 +1,174 @@
import cpp
import semmle.code.cpp.dataflow.TaintTracking
private import semmle.code.cpp.dataflow.RecursionPrevention
/**
* A buffer which includes an allocation size.
*/
abstract class BufferWithSize extends DataFlow::Node {
abstract Expr getSizeExpr();
BufferAccess getAnAccess() {
any(BufferWithSizeConfig bsc).hasFlow(this, DataFlow::exprNode(result.getPointer()))
}
}
/** An allocation function. */
abstract class Alloc extends Function { }
/**
* Allocation functions identified by the QL for C/C++ standard library.
*/
class DefaultAlloc extends Alloc {
DefaultAlloc() { allocationFunction(this) }
}
/** A buffer created through a call to an allocation function. */
class AllocBuffer extends BufferWithSize {
FunctionCall call;
AllocBuffer() {
asExpr() = call and
call.getTarget() instanceof Alloc
}
override Expr getSizeExpr() { result = call.getArgument(0) }
}
/**
* Find accesses of buffers for which we have a size expression.
*/
private class BufferWithSizeConfig extends TaintTracking::Configuration {
BufferWithSizeConfig() { this = "BufferWithSize" }
override predicate isSource(DataFlow::Node n) { n = any(BufferWithSize b) }
override predicate isSink(DataFlow::Node n) { n.asExpr() = any(BufferAccess ae).getPointer() }
override predicate isSanitizer(DataFlow::Node s) {
s = any(BufferWithSize b) and
s.asExpr().getControlFlowScope() instanceof Alloc
}
}
/**
* An access (read or write) to a buffer, provided as a pair of
* a pointer to the buffer and the length of data to be read or written.
* Extend this class to support different kinds of buffer access.
*/
abstract class BufferAccess extends Locatable {
/** Gets the pointer to the buffer being accessed. */
abstract Expr getPointer();
/** Gets the length of the data being read or written by this buffer access. */
abstract Expr getAccessedLength();
}
/**
* A buffer access through an array expression.
*/
class ArrayBufferAccess extends BufferAccess, ArrayExpr {
override Expr getPointer() { result = this.getArrayBase() }
override Expr getAccessedLength() { result = this.getArrayOffset() }
}
/**
* A buffer access through an overloaded array expression.
*/
class OverloadedArrayBufferAccess extends BufferAccess, OverloadedArrayExpr {
override Expr getPointer() { result = this.getQualifier() }
override Expr getAccessedLength() { result = this.getAnArgument() }
}
/**
* A buffer access through pointer arithmetic.
*/
class PointerArithmeticAccess extends BufferAccess, Expr {
PointerArithmeticOperation p;
PointerArithmeticAccess() {
this = p and
p.getAnOperand().getType().getUnspecifiedType() instanceof IntegralType and
not p.getParent() instanceof ComparisonOperation
}
override Expr getPointer() {
result = p.getAnOperand() and
result.getType().getUnspecifiedType() instanceof PointerType
}
override Expr getAccessedLength() {
result = p.getAnOperand() and
result.getType().getUnspecifiedType() instanceof IntegralType
}
}
/**
* A pair of buffer accesses through a call to memcpy.
*/
class MemCpy extends BufferAccess, FunctionCall {
MemCpy() { getTarget().hasName("memcpy") }
override Expr getPointer() {
result = getArgument(0) or
result = getArgument(1)
}
override Expr getAccessedLength() { result = getArgument(2) }
}
class StrncpySizeExpr extends BufferAccess, FunctionCall {
StrncpySizeExpr() { getTarget().hasName("strncpy") }
override Expr getPointer() {
result = getArgument(0) or
result = getArgument(1)
}
override Expr getAccessedLength() { result = getArgument(2) }
}
class RecvSizeExpr extends BufferAccess, FunctionCall {
RecvSizeExpr() { getTarget().hasName("recv") }
override Expr getPointer() { result = getArgument(1) }
override Expr getAccessedLength() { result = getArgument(2) }
}
class SendSizeExpr extends BufferAccess, FunctionCall {
SendSizeExpr() { getTarget().hasName("send") }
override Expr getPointer() { result = getArgument(1) }
override Expr getAccessedLength() { result = getArgument(2) }
}
class SnprintfSizeExpr extends BufferAccess, FunctionCall {
SnprintfSizeExpr() { getTarget().hasName("snprintf") }
override Expr getPointer() { result = getArgument(0) }
override Expr getAccessedLength() { result = getArgument(1) }
}
class MemcmpSizeExpr extends BufferAccess, FunctionCall {
MemcmpSizeExpr() { getTarget().hasName("Memcmp") }
override Expr getPointer() {
result = getArgument(0) or
result = getArgument(1)
}
override Expr getAccessedLength() { result = getArgument(2) }
}
class MallocSizeExpr extends BufferAccess, FunctionCall {
MallocSizeExpr() { getTarget().hasName("malloc") }
override Expr getPointer() { none() }
override Expr getAccessedLength() { result = getArgument(1) }
}

View File

@@ -0,0 +1,6 @@
int get_number_from_network();
int process_network(int[] buff, int buffSize) {
int i = ntohl(get_number_from_network());
return buff[i];
}

View File

@@ -0,0 +1,10 @@
uint32_t get_number_from_network();
int process_network(int[] buff, uint32_t buffSize) {
uint32_t i = ntohl(get_number_from_network());
if (i < buffSize) {
return buff[i];
} else {
return -1;
}
}

View File

@@ -0,0 +1,33 @@
import cpp
import semmle.code.cpp.dataflow.DataFlow
import semmle.code.cpp.controlflow.Guards
import BufferAccess
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
class NetworkFunctionCall extends FunctionCall {
NetworkFunctionCall() {
getTarget().hasName("ntohd") or
getTarget().hasName("ntohf") or
getTarget().hasName("ntohl") or
getTarget().hasName("ntohll") or
getTarget().hasName("ntohs")
}
}
class NetworkToBufferSizeConfiguration extends DataFlow::Configuration {
NetworkToBufferSizeConfiguration() { this = "NetworkToBufferSizeConfiguration" }
override predicate isSource(DataFlow::Node node) { node.asExpr() instanceof NetworkFunctionCall }
override predicate isSink(DataFlow::Node node) {
node.asExpr() = any(BufferAccess ba).getAccessedLength()
}
override predicate isBarrier(DataFlow::Node node) {
exists(GuardCondition gc, GVN gvn |
gc.getAChild*() = gvn.getAnExpr() and
globalValueNumber(node.asExpr()) = gvn and
gc.controls(node.asExpr().getBasicBlock(), _)
)
}
}

View File

@@ -0,0 +1,54 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Data received over a network connection may be received in a different byte order than
the byte order used by the local host, making the data difficult to process. To address this,
data received over the wire is usually converted to host byte order by a call to a network-to-host
byte order function, such as <code>ntohl</code>.
</p>
<p>
The use of a network-to-host byte order function is therefore a good indicator that the returned
value is unvalidated data retrieved from the network, and should not be used without further
validation. In particular, the returned value should not be used as an array index or array length
value without validation, as this could result in a buffer overflow vulnerability.
</p>
</overview>
<recommendation>
<p>
Validate data returned by network-to-host byte order functions before use and especially before
using the value as an array index or bound.
</p>
</recommendation>
<example>
<p>In the example below, network data is retrieved and passed to <code>ntohl</code> to convert
it to host byte order. The data is then used as an index in an array access expression. However,
there is no validation that the data returned by <code>ntohl</code> is within the bounds of the array,
which could lead to reading outside the bounds of the buffer.
</p>
<sample src="NtohlArrayBad.cpp" />
<p>In the corrected example, the returned data is validated against the known size of the buffer,
before being used as an array index.</p>
<sample src="NtohlArrayGood.cpp" />
</example>
<references>
<li>
<a href="https://docs.microsoft.com/en-us/windows/desktop/api/winsock/nf-winsock-ntohl">
ntohl - winsock reference
</a>
</li>
<li>
<a href="https://linux.die.net/man/3/ntohl">
ntohl - Linux man page
</a>
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,17 @@
/**
* @id cpp/network-to-host-function-as-array-bound
* @name Untrusted network-to-host usage
* @description Using the result of a network-to-host byte order function, such as ntohl, as an
* array bound or length value without checking it may result in buffer overflows or
* other vulnerabilties.
* @kind problem
* @problem.severity error
*/
import cpp
import NtohlArrayNoBound
import semmle.code.cpp.dataflow.DataFlow
from NetworkToBufferSizeConfiguration bufConfig, DataFlow::Node source, DataFlow::Node sink
where bufConfig.hasFlow(source, sink)
select sink, "Unchecked use of data from network function $@", source, source.toString()

View File

@@ -2,29 +2,45 @@ import cpp
class SALMacro extends Macro { class SALMacro extends Macro {
SALMacro() { SALMacro() {
this.getFile().getBaseName() = "sal.h" or exists(string filename | filename = this.getFile().getBaseName() |
this.getFile().getBaseName() = "specstrings_strict.h" or filename = "sal.h" or
this.getFile().getBaseName() = "specstrings.h" filename = "specstrings_strict.h" or
filename = "specstrings.h" or
filename = "w32p.h" or
filename = "minwindef.h"
) and
(
// Dialect for Windows 8 and above
this.getName().matches("\\_%\\_")
or
// Dialect for Windows 7
this.getName().matches("\\_\\_%")
)
} }
} }
pragma[noinline]
predicate isTopLevelMacroAccess(MacroAccess ma) { not exists(ma.getParentInvocation()) }
class SALAnnotation extends MacroInvocation { class SALAnnotation extends MacroInvocation {
SALAnnotation() { SALAnnotation() {
this.getMacro() instanceof SALMacro and this.getMacro() instanceof SALMacro and
not exists(this.getParentInvocation()) isTopLevelMacroAccess(this)
} }
/** Returns the `Declaration` annotated by `this`. */ /** Returns the `Declaration` annotated by `this`. */
Declaration getDeclaration() { annotatesAt(this, result.getADeclarationEntry(), _, _) } Declaration getDeclaration() {
annotatesAt(this, result.getADeclarationEntry(), _, _) and
not result instanceof Type // exclude typedefs
}
/** Returns the `DeclarationEntry` annotated by `this`. */ /** Returns the `DeclarationEntry` annotated by `this`. */
DeclarationEntry getDeclarationEntry() { annotatesAt(this, result, _, _) } DeclarationEntry getDeclarationEntry() {
annotatesAt(this, result, _, _) and
not result instanceof TypeDeclarationEntry // exclude typedefs
}
} }
/*
* Particular SAL annotations of interest
*/
class SALCheckReturn extends SALAnnotation { class SALCheckReturn extends SALAnnotation {
SALCheckReturn() { SALCheckReturn() {
exists(SALMacro m | m = this.getMacro() | exists(SALMacro m | m = this.getMacro() |
@@ -39,8 +55,8 @@ class SALNotNull extends SALAnnotation {
exists(SALMacro m | m = this.getMacro() | exists(SALMacro m | m = this.getMacro() |
not m.getName().matches("%\\_opt\\_%") and not m.getName().matches("%\\_opt\\_%") and
( (
m.getName().matches("\\_In%") or m.getName().matches("_In%") or
m.getName().matches("\\_Out%") or m.getName().matches("_Out%") or
m.getName() = "_Ret_notnull_" m.getName() = "_Ret_notnull_"
) )
) and ) and
@@ -63,42 +79,124 @@ class SALMaybeNull extends SALAnnotation {
} }
} }
/* ///////////////////////////////////////////////////////////////////////////////
* Implementation details // Implementation details
/**
* Holds if `a` annotates the declaration entry `d` and
* its start position is the `idx`th position in `file` that holds a SAL element.
*/ */
predicate annotatesAt(SALAnnotation a, DeclarationEntry d, File file, int idx) {
private predicate annotatesAt(SALAnnotation a, DeclarationEntry e, File file, int idx) { annotatesAtPosition(a.(SALElement).getStartPosition(), d, file, idx)
a = salElementAt(file, idx) and
(
// Base case: `a` right before `e`
e = salElementAt(file, idx + 1)
or
// Recursive case: `a` right before some annotation on `e`
annotatesAt(_, e, file, idx + 1)
)
}
library class SALElement extends Element {
SALElement() {
this instanceof DeclarationEntry or
this instanceof SALAnnotation
}
}
/** Gets the `idx`th `SALElement` in `file`. */
private SALElement salElementAt(File file, int idx) {
interestingLoc(file, result, interestingStartPos(file, idx))
} }
/** /**
* Holds if an SALElement element at character `result` comes at * Holds if `pos` is the `idx`th position in `file` that holds a SAL element,
* position `idx` in `file`. * which annotates the declaration entry `d` (by occurring before it without
* any other declaration entries in between).
*/ */
private int interestingStartPos(File file, int idx) { // For performance reasons, do not mention the annotation itself here,
result = rank[idx](int otherStart | interestingLoc(file, _, otherStart)) // but compute with positions instead. This performs better on databases
// with many annotations at the same position.
private predicate annotatesAtPosition(SALPosition pos, DeclarationEntry d, File file, int idx) {
pos = salRelevantPositionAt(file, idx) and
salAnnotationPos(pos) and
(
// Base case: `pos` right before `d`
d.(SALElement).getStartPosition() = salRelevantPositionAt(file, idx + 1)
or
// Recursive case: `pos` right before some annotation on `d`
annotatesAtPosition(_, d, file, idx + 1)
)
} }
/** Holds if `element` in `file` is at character `startPos`. */ /**
private predicate interestingLoc(File file, SALElement element, int startPos) { * A parameter annotated by one or more SAL annotations.
element.getLocation().charLoc(file, startPos, _) */
class SALParameter extends Parameter {
/** One of this parameter's annotations. */
SALAnnotation a;
SALParameter() { annotatesAt(a, this.getADeclarationEntry(), _, _) }
predicate isIn() { a.getMacroName().toLowerCase().matches("%\\_in%") }
predicate isOut() { a.getMacroName().toLowerCase().matches("%\\_out%") }
predicate isInOut() { a.getMacroName().toLowerCase().matches("%\\_inout%") }
}
/**
* A SAL element, i.e. a SAL annotation or a declaration entry
* that may have SAL annotations.
*/
library class SALElement extends Element {
SALElement() {
containsSALAnnotation(this.(DeclarationEntry).getFile()) or
this instanceof SALAnnotation
}
predicate hasStartPosition(File file, int line, int col) {
exists(Location loc | loc = this.getLocation() |
file = loc.getFile() and
line = loc.getStartLine() and
col = loc.getStartColumn()
)
}
predicate hasEndPosition(File file, int line, int col) {
exists(Location loc |
loc = this.(FunctionDeclarationEntry).getBlock().getLocation()
or
this = any(VariableDeclarationEntry vde |
vde.isDefinition() and
loc = vde.getVariable().getInitializer().getLocation()
)
|
file = loc.getFile() and
line = loc.getEndLine() and
col = loc.getEndColumn()
)
}
SALPosition getStartPosition() {
exists(File file, int line, int col |
this.hasStartPosition(file, line, col) and
result = MkSALPosition(file, line, col)
)
}
}
/** Holds if `file` contains a SAL annotation. */
pragma[noinline]
private predicate containsSALAnnotation(File file) { any(SALAnnotation a).getFile() = file }
/**
* A source-file position of a `SALElement`. Unlike location, this denotes a
* point in the file rather than a range.
*/
private newtype SALPosition =
MkSALPosition(File file, int line, int col) {
exists(SALElement e |
e.hasStartPosition(file, line, col)
or
e.hasEndPosition(file, line, col)
)
}
/** Holds if `pos` is the start position of a SAL annotation. */
pragma[noinline]
private predicate salAnnotationPos(SALPosition pos) {
any(SALAnnotation a).(SALElement).getStartPosition() = pos
}
/**
* Gets the `idx`th position in `file` that holds a SAL element,
* ordering positions lexicographically by their start line and start column.
*/
private SALPosition salRelevantPositionAt(File file, int idx) {
result = rank[idx](SALPosition pos, int line, int col |
pos = MkSALPosition(file, line, col)
|
pos order by line, col
)
} }

View File

@@ -0,0 +1,25 @@
/**
* @name SAL requires inspecting return value
* @description When a return value is discarded even though the SAL annotation
* requires inspecting it, a recoverable error may turn into a
* whole-program crash.
* @kind problem
* @problem.severity warning
* @tags reliability
* external/cwe/cwe-573
* external/cwe/cwe-252
* @opaque-id SM02344
* @microsoft.severity Important
* @id cpp/ignorereturnvaluesal
*/
import Microsoft.SAL
from Function f, FunctionCall call
where
call.getTarget() = f and
call instanceof ExprInVoidContext and
any(SALCheckReturn a).getDeclaration() = f and
not any(Options o).okToIgnoreReturnValue(call)
select call, "Return value of $@ discarded although a SAL annotation " + "requires inspecting it.",
f, f.getName()

View File

@@ -5,7 +5,7 @@
* @id cpp/comparison-with-wider-type * @id cpp/comparison-with-wider-type
* @kind problem * @kind problem
* @problem.severity warning * @problem.severity warning
* @precision medium * @precision high
* @tags reliability * @tags reliability
* security * security
* external/cwe/cwe-190 * external/cwe/cwe-190

View File

@@ -0,0 +1,59 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>A common pattern is to initialize a local variable by calling another function (an
"initialization" function) with the address of the local variable as a pointer argument. That
function is then responsible for writing to the memory location referenced by the pointer.</p>
<p>In some cases, the called function may not always write to the memory pointed to by the
pointer argument. In such cases, the function will typically return a "status" code, informing the
caller as to whether the initialization succeeded or not. If the caller does not check the status
code before reading the local variable, it may read unitialized memory, which can result in
unexpected behavior.</p>
</overview>
<recommendation>
<p>When using a initialization function that does not guarantee to initialize the memory pointed to
by the passed pointer, and returns a status code to indicate whether such initialization occurred,
the status code should be checked before reading from the local variable.</p>
</recommendation>
<example>
<p>In this hypothetical example we have code for managing a series of devices. The code
includes a <code>DeviceConfig</code> struct that can represent properties about each device.
The <code>initDeviceConfig</code> function can be called to initialize one of these structures, by
providing a "device number", which can be used to look up the appropriate properties in some data
store. If an invalid device number is provided, the function returns a status code of
<code>-1</code>, and does not initialize the provided pointer.</p>
<p>In the first code sample below, the <code>notify</code> function calls the
<code>initDeviceConfig</code> function with a pointer to the local variable <code>config</code>,
which is then subsequently accessed to fetch properties of the device. However, the code does not
check the return value from the function call to <code>initDeviceConfig</code>. If the
device number passed to the <code>notify</code> function was invalid, the
<code>initDeviceConfig</code> function will leave the <code>config</code> variable uninitialized,
which will result in the <code>notify</code> function accessing uninitialized memory.</p>
<sample src="ConditionallyUninitializedVariableBad.c" />
<p>To fix this, the code needs to check that the return value of the call to
<code>initDeviceConfig</code> is zero. If that is true, then the calling code can safely assume
that the local variable has been initialized.</p>
<sample src="ConditionallyUninitializedVariableGood.c" />
</example>
<references>
<li>
Wikipedia:
<a href="https://en.wikipedia.org/wiki/Uninitialized_variable">Uninitialized variable</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,33 @@
/**
* @name Conditionally uninitialized variable
* @description When an initialization function is used to initialize a local variable, but the
* returned status code is not checked, the variable may be left in an uninitialized
* state, and reading the variable may result in undefined behavior.
* @kind problem
* @problem.severity warning
* @opaque-id SM02313
* @id cpp/conditionally-uninitialized-variable
* @tags security
* external/cwe/cwe-457
*/
import cpp
import semmle.code.cpp.controlflow.SSA
private import UninitializedVariables
from
ConditionallyInitializedVariable v, ConditionalInitializationFunction f,
ConditionalInitializationCall call, string defined, Evidence e
where
exists(v.getARiskyAccess(f, call, e)) and
(
if e = DefinitionInSnapshot()
then defined = ""
else
if e = SuggestiveSALAnnotation()
then defined = "externally defined (SAL) "
else defined = "externally defined (CSV) "
)
select call,
"The status of this call to " + defined +
"$@ is not checked, potentially leaving $@ uninitialized.", f, f.getName(), v, v.getName()

View File

@@ -0,0 +1,25 @@
struct DeviceConfig {
bool isEnabled;
int channel;
};
int initDeviceConfig(DeviceConfig *ref, int deviceNumber) {
if (deviceNumber >= getMaxDevices()) {
// No device with that number, return -1 to indicate failure
return -1;
}
// Device with that number, fetch parameters and initialize struct
ref->isEnabled = fetchIsDeviceEnabled(deviceNumber);
ref->channel = fetchDeviceChannel(deviceNumber);
// Return 0 to indicate success
return 0;
}
int notify(int deviceNumber) {
DeviceConfig config;
initDeviceConfig(&config, deviceNumber);
// BAD: Using config without checking the status code that is returned
if (config->isEnabled) {
notifyChannel(config->channel);
}
}

View File

@@ -0,0 +1,27 @@
struct DeviceConfig {
bool isEnabled;
int channel;
};
int initDeviceConfig(DeviceConfig *ref, int deviceNumber) {
if (deviceNumber >= getMaxDevices()) {
// No device with that number, return -1 to indicate failure
return -1;
}
// Device with that number, fetch parameters and initialize struct
ref->isEnabled = fetchIsDeviceEnabled(deviceNumber);
ref->channel = fetchDeviceChannel(deviceNumber);
// Return 0 to indicate success
return 0;
}
void notify(int deviceNumber) {
DeviceConfig config;
int statusCode = initDeviceConfig(&config, deviceNumber);
if (statusCode == 0) {
// GOOD: Status code returned by initialization function is checked, so this is safe
if (config->isEnabled) {
notifyChannel(config->channel);
}
}
}

View File

@@ -0,0 +1,690 @@
/**
* Provides classes and predicates for identifying functions that initialize their arguments.
*/
import cpp
import external.ExternalArtifact
private import semmle.code.cpp.dispatch.VirtualDispatch
import semmle.code.cpp.NestedFields
import Microsoft.SAL
import semmle.code.cpp.controlflow.Guards
/** A context under which a function may be called. */
private newtype TContext =
/** No specific call context. */
NoContext() or
/**
* The call context is that the given other parameter is null.
*
* This context is created for all parameters that are null checked in the body of the function.
*/
ParamNull(Parameter p) { p = any(ParameterNullCheck pnc).getParameter() } or
/**
* The call context is that the given other parameter is not null.
*
* This context is created for all parameters that are null checked in the body of the function.
*/
ParamNotNull(Parameter p) { p = any(ParameterNullCheck pnc).getParameter() }
/**
* A context under which a function may be called.
*
* Some functions may conditionally initialize a parameter depending on the value of another
* parameter. Consider:
* ```
* int MyInitFunction(int* paramToBeInitialized, int* paramToCheck) {
* if (!paramToCheck) {
* // fail!
* return -1;
* }
* paramToBeInitialized = 0;
* }
* ```
* In this case, whether `paramToBeInitialized` is initialized when this function call completes
* depends on whether `paramToCheck` is or is not null. A call-context insensitive analysis will
* determine that any call to this function may leave the parameter uninitialized, even if the
* argument to paramToCheck is guaranteed to be non-null (`&foo`, for example).
*
* This class models call contexts that can be considered when calculating whether a given parameter
* initializes or not. The supported contexts are:
* - `ParamNull(otherParam)` - the given `otherParam` is considered to be null. Applies when
* exactly one parameter other than this one is null checked.
* - `ParamNotNull(otherParam)` - the given `otherParam` is considered to be not null. Applies when
* exactly one parameter other than this one is null checked.
* - `NoContext()` - applies in all other circumstances.
*/
class Context extends TContext {
string toString() {
this = NoContext() and result = "NoContext"
or
this = ParamNull(any(Parameter p | result = "ParamNull(" + p.getName() + ")"))
or
this = ParamNotNull(any(Parameter p | result = "ParamNotNull(" + p.getName() + ")"))
}
}
/**
* A check against a parameter.
*/
abstract class ParameterCheck extends Expr {
/**
* Gets a successor of this check that should be ignored for the given context.
*/
abstract ControlFlowNode getIgnoredSuccessorForContext(Context c);
}
/** A null-check expression on a parameter. */
class ParameterNullCheck extends ParameterCheck {
Parameter p;
ControlFlowNode nullSuccessor;
ControlFlowNode notNullSuccessor;
ParameterNullCheck() {
this.isCondition() and
p.getFunction() instanceof InitializationFunction and
p.getType().getUnspecifiedType() instanceof PointerType and
exists(VariableAccess va | va = p.getAnAccess() |
nullSuccessor = getATrueSuccessor() and
notNullSuccessor = getAFalseSuccessor() and
(
va = this.(NotExpr).getOperand() or
va = any(EQExpr eq | eq = this and eq.getAnOperand().getValue() = "0").getAnOperand() or
va = getAssertedFalseCondition(this) or
va = any(NEExpr eq |
eq = getAssertedFalseCondition(this) and eq.getAnOperand().getValue() = "0"
).getAnOperand()
)
or
nullSuccessor = getAFalseSuccessor() and
notNullSuccessor = getATrueSuccessor() and
(
va = this or
va = any(NEExpr eq | eq = this and eq.getAnOperand().getValue() = "0").getAnOperand() or
va = any(EQExpr eq |
eq = getAssertedFalseCondition(this) and eq.getAnOperand().getValue() = "0"
).getAnOperand()
)
)
}
/** The parameter being null-checked. */
Parameter getParameter() { result = p }
override ControlFlowNode getIgnoredSuccessorForContext(Context c) {
c = ParamNull(p) and result = notNullSuccessor
or
c = ParamNotNull(p) and result = nullSuccessor
}
/** The successor at which the parameter is confirmed to be null. */
ControlFlowNode getNullSuccessor() { result = nullSuccessor }
/** The successor at which the parameter is confirmed to be not-null. */
ControlFlowNode getNotNullSuccessor() { result = notNullSuccessor }
}
/**
* An entry in a CSV file in cond-init that contains externally defined functions that are
* conditional initializers. These files are typically produced by running the
* ConditionallyInitializedFunction companion query.
*/
class ValidatedExternalCondInitFunction extends ExternalData {
ValidatedExternalCondInitFunction() { this.getDataPath().matches("%cond-init%.csv") }
predicate isExternallyVerified(Function f, int param) {
functionSignature(f, getField(1), getField(2)) and param = getFieldAsInt(3)
}
}
/**
* The type of evidence used to determine whether a function initializes a parameter.
*/
newtype Evidence =
/**
* The function is defined in the snapshot, and the CFG has been analyzed to determine that the
* parameter is not initialized on at least one path to the exit.
*/
DefinitionInSnapshot() or
/**
* The function is externally defined, but the parameter has an `_out` SAL annotation which
* suggests that it is initialized in the function.
*/
SuggestiveSALAnnotation() or
/**
* We have been given a CSV file which indicates this parameter is conditionally initialized.
*/
ExternalEvidence()
/**
* A call to an function which initializes one or more of its parameters.
*/
class InitializationFunctionCall extends FunctionCall {
Expr initializedArgument;
InitializationFunctionCall() { initializedArgument = getAnInitializedArgument(this) }
/** Gets a parameter that is initialized by this call. */
Parameter getAnInitParameter() { result.getAnAccess() = initializedArgument }
}
/**
* A variable access which is dereferenced then assigned to.
*/
private predicate isPointerDereferenceAssignmentTarget(VariableAccess target) {
target.getParent().(PointerDereferenceExpr) = any(Assignment e).getLValue()
}
/**
* A function which initializes one or more of its parameters.
*/
class InitializationFunction extends Function {
int i;
Evidence evidence;
InitializationFunction() {
evidence = DefinitionInSnapshot() and
(
// Assignment by pointer dereferencing the parameter
isPointerDereferenceAssignmentTarget(this.getParameter(i).getAnAccess()) or
// Field wise assignment to the parameter
any(Assignment e).getLValue() = getAFieldAccess(this.getParameter(i)) or
i = this
.(MemberFunction)
.getAnOverridingFunction+()
.(InitializationFunction)
.initializedParameter() or
getParameter(i) = any(InitializationFunctionCall c).getAnInitParameter()
)
or
// If we have no definition, we look at SAL annotations
not this.isDefined() and
this.getParameter(i).(SALParameter).isOut() and
evidence = SuggestiveSALAnnotation()
or
// We have some external information that this function conditionally initializes
not this.isDefined() and
any(ValidatedExternalCondInitFunction vc).isExternallyVerified(this, i) and
evidence = ExternalEvidence()
}
/** Gets a parameter index which is initialized by this function. */
int initializedParameter() { result = i }
/** Gets a `ControlFlowNode` which assigns a new value to the parameter with the given index. */
ControlFlowNode paramReassignment(int index) {
index = i and
(
result = this.getParameter(i).getAnAccess() and
(
result = any(Assignment a).getLValue().(PointerDereferenceExpr).getOperand()
or
// Field wise assignment to the parameter
result = any(Assignment a).getLValue().(FieldAccess).getQualifier()
or
// Assignment to a nested field of the parameter
result = any(Assignment a).getLValue().(NestedFieldAccess).getUltimateQualifier()
or
result = getAnInitializedArgument(any(Call c))
or
exists(IfStmt check | result = check.getCondition().getAChild*() |
paramReassignmentCondition(check)
)
)
or
result = any(AssumeExpr e |
e.getEnclosingFunction() = this and e.getAChild().(Literal).getValue() = "0"
)
)
}
/**
* Helper predicate: holds if the `if` statement `check` contains a
* reassignment to the `i`th parameter within its `then` statement.
*/
pragma[noinline]
private predicate paramReassignmentCondition(IfStmt check) {
this.paramReassignment(i).getEnclosingStmt().getParentStmt*() = check.getThen()
}
/** Holds if `n` can be reached without the parameter at `index` being reassigned. */
predicate paramNotReassignedAt(ControlFlowNode n, int index, Context c) {
c = getAContext(index) and
(
not exists(this.getEntryPoint()) and index = i and n = this
or
n = this.getEntryPoint() and index = i
or
exists(ControlFlowNode mid | paramNotReassignedAt(mid, index, c) |
n = mid.getASuccessor() and
not n = paramReassignment(index) and
/*
* Ignore successor edges where the parameter is null, because it is then confirmed to be
* initialized.
*/
not exists(ParameterNullCheck nullCheck |
nullCheck = mid and
nullCheck = getANullCheck(index) and
n = nullCheck.getNullSuccessor()
) and
/*
* Ignore successor edges which are excluded by the given context
*/
not exists(ParameterCheck paramCheck | paramCheck = mid |
n = paramCheck.getIgnoredSuccessorForContext(c)
)
)
)
}
/** Gets a null-check on the parameter at `index`. */
private ParameterNullCheck getANullCheck(int index) {
getParameter(index) = result.getParameter()
}
/** Gets a parameter which is not at the given index. */
private Parameter getOtherParameter(int index) {
index = i and
result = getAParameter() and
not result.getIndex() = index
}
/**
* Gets a call `Context` that is applicable when considering whether parameter at the `index` can
* be conditionally initialized.
*/
Context getAContext(int index) {
index = i and
/*
* If there is one and only one other parameter which is null checked in the body of the method,
* then we have two contexts to consider - that the other param is null, or that the other param
* is not null.
*/
if
strictcount(Parameter p |
exists(Context c | c = ParamNull(p) or c = ParamNotNull(p)) and
p = getOtherParameter(index)
) = 1
then
exists(Parameter p | p = getOtherParameter(index) |
result = ParamNull(p) or result = ParamNotNull(p)
)
else
// Otherwise, only consider NoContext.
result = NoContext()
}
/**
* Holds if this function should be whitelisted - that is, not considered as conditionally
* initializing its parameters.
*/
predicate whitelisted() {
exists(string name | this.hasName(name) |
// Return value is not a success code but the output functions never fail.
name.matches("_Interlocked%")
or
// Functions that never fail, according to MSDN.
name = "QueryPerformanceCounter"
or
name = "QueryPerformanceFrequency"
or
// Functions that never fail post-Vista, according to MSDN.
name = "InitializeCriticalSectionAndSpinCount"
or
// `rand_s` writes 0 to a non-null argument if it fails, according to MSDN.
name = "rand_s"
or
// IntersectRect initializes the argument regardless of whether the input intersects
name = "IntersectRect"
or
name = "SetRect"
or
name = "UnionRect"
or
// These functions appears to have an incorrect CFG, which leads to false positives
name = "PhysicalToLogicalDPIPoint"
or
name = "LogicalToPhysicalDPIPoint"
or
// Sets NtProductType to default on error
name = "RtlGetNtProductType"
or
// Our CFG is not sophisticated enough to detect that the argument is always initialized
name = "StringCchLengthA"
or
// All paths init the argument, and always returns SUCCESS.
name = "RtlUnicodeToMultiByteSize"
or
// All paths init the argument, and always returns SUCCESS.
name = "RtlMultiByteToUnicodeSize"
or
// All paths init the argument, and always returns SUCCESS.
name = "RtlUnicodeToMultiByteN"
or
// Always initializes argument
name = "RtlGetFirstRange"
or
// Destination range is zeroed out on failure, assuming first two parameters are valid
name = "memcpy_s"
or
// This zeroes the memory unconditionally
name = "SeCreateAccessState"
)
}
}
/**
* A function which initializes one or more of its parameters, but not on all paths.
*/
class ConditionalInitializationFunction extends InitializationFunction {
Context c;
ConditionalInitializationFunction() {
c = this.getAContext(i) and
not this.whitelisted() and
exists(Type status | status = this.getType().getUnspecifiedType() |
status instanceof IntegralType or
status instanceof Enum
) and
not this.getType().getName().toLowerCase() = "size_t" and
(
/*
* If there is no definition, consider this to be conditionally initializing (based on either
* SAL or external data).
*/
not evidence = DefinitionInSnapshot()
or
/*
* If this function is defined in this snapshot, then it conditionally initializes if there
* is at least one path through the function which doesn't initialize the parameter.
*
* Explicitly ignore pure virtual functions.
*/
this.isDefined() and
this.paramNotReassignedAt(this, i, c) and
not this instanceof PureVirtualFunction
)
}
/** Gets the evidence associated with the given parameter. */
Evidence getEvidence(int param) {
/*
* Note: due to the way the predicate dispatch interacts with fields, this needs to be
* implemented on this class, not `InitializationFunction`. If implemented on the latter it
* can return evidence that does not result in conditional initialization.
*/
param = i and evidence = result
}
/** Gets the index of a parameter which is conditionally initialized. */
int conditionallyInitializedParameter(Context context) { result = i and context = c }
}
/**
* More elaborate tracking, flagging cases where the status is checked after
* the potentially uninitialized variable has been used, and ignoring cases
* where the status is not checked but there is no use of the potentially
* uninitialized variable, may be obtained via `getARiskyAccess`.
*/
class ConditionalInitializationCall extends FunctionCall {
ConditionalInitializationFunction target;
ConditionalInitializationCall() { target = getTarget(this) }
/** Gets the argument passed for the given parameter to this call. */
Expr getArgumentForParameter(Parameter p) {
p = getTarget().getAParameter() and
result = getArgument(p.getIndex())
}
/**
* Gets an argument conditionally initialized by this call.
*/
Expr getAConditionallyInitializedArgument(ConditionalInitializationFunction condTarget, Evidence e) {
condTarget = target and
exists(Context context |
result = getAConditionallyInitializedArgument(this, condTarget, context, e)
|
context = NoContext()
or
exists(Parameter otherP, Expr otherArg |
context = ParamNotNull(otherP) or
context = ParamNull(otherP)
|
otherArg = getArgumentForParameter(otherP) and
(otherArg instanceof AddressOfExpr implies context = ParamNotNull(otherP)) and
(otherArg.getType() instanceof ArrayType implies context = ParamNotNull(otherP)) and
(otherArg.getValue() = "0" implies context = ParamNull(otherP))
)
)
}
VariableAccess getAConditionallyInitializedVariable() {
not result.getTarget().getAnAssignedValue().getASuccessor+() = result and
// Should not be assigned field-wise prior to the call.
not exists(Assignment a, FieldAccess fa |
fa.getQualifier() = result.getTarget().getAnAccess() and
a.getLValue() = fa and
fa.getASuccessor+() = result
) and
result = this
.getArgument(getTarget(this)
.(ConditionalInitializationFunction)
.conditionallyInitializedParameter(_))
.(AddressOfExpr)
.getOperand()
}
Variable getStatusVariable() {
exists(AssignExpr a | a.getLValue() = result.getAnAccess() | a.getRValue() = this)
or
result.getInitializer().getExpr() = this
}
Expr getSuccessCheck() {
exists(this.getAFalseSuccessor()) and result = this
or
result = this.getParent() and
(
result instanceof NotExpr or
result.(EQExpr).getAnOperand().getValue() = "0" or
result.(GEExpr).getLesserOperand().getValue() = "0"
)
}
Expr getFailureCheck() {
result = this.getParent() and
(
result instanceof NotExpr or
result.(NEExpr).getAnOperand().getValue() = "0" or
result.(LTExpr).getLesserOperand().getValue() = "0"
)
}
private predicate inCheckedContext() {
exists(Call parent | this = parent.getAnArgument() |
parent.getTarget() instanceof Operator or
parent.getTarget().hasName("VerifyOkCatastrophic")
)
}
ControlFlowNode uncheckedReaches(LocalVariable var) {
(
not exists(var.getInitializer()) and
var = this.getAConditionallyInitializedVariable().getTarget() and
if exists(this.getFailureCheck())
then result = this.getFailureCheck().getATrueSuccessor()
else
if exists(this.getSuccessCheck())
then result = this.getSuccessCheck().getAFalseSuccessor()
else (
result = this.getASuccessor() and not this.inCheckedContext()
)
)
or
exists(ControlFlowNode mid | mid = uncheckedReaches(var) |
not mid = getStatusVariable().getAnAccess() and
not mid = var.getAnAccess() and
not exists(VariableAccess write | result = write and write = var.getAnAccess() |
write = any(AssignExpr a).getLValue() or
write = any(AddressOfExpr a).getOperand()
) and
result = mid.getASuccessor()
)
}
VariableAccess getARiskyRead(Function f) {
f = this.getTarget() and
exists(this.getFile().getRelativePath()) and
result = this.uncheckedReaches(result.getTarget()) and
not this.(GuardCondition).controls(result.getBasicBlock(), _)
}
}
/**
* Gets the position of an argument to the call which is initialized by the call.
*/
pragma[nomagic]
int initializedArgument(Call call) {
exists(InitializationFunction target |
target = getTarget(call) and
result = target.initializedParameter()
)
}
/**
* Gets an argument which is initialized by the call.
*/
Expr getAnInitializedArgument(Call call) { result = call.getArgument(initializedArgument(call)) }
/**
* Gets the position of an argument to the call to the target which is conditionally initialized by
* the call, under the given context and evidence.
*/
pragma[nomagic]
int conditionallyInitializedArgument(
Call call, ConditionalInitializationFunction target, Context c, Evidence e
) {
target = getTarget(call) and
c = target.getAContext(result) and
e = target.getEvidence(result) and
result = target.conditionallyInitializedParameter(c)
}
/**
* Gets an argument which is conditionally initialized by the call to the given target under the given context and evidence.
*/
Expr getAConditionallyInitializedArgument(
Call call, ConditionalInitializationFunction target, Context c, Evidence e
) {
result = call.getArgument(conditionallyInitializedArgument(call, target, c, e))
}
/**
* Gets the type signature for the functions parameters.
*/
string typeSig(Function f) {
result = concat(int i, Type pt |
pt = f.getParameter(i).getType()
|
pt.getUnspecifiedType().toString(), "," order by i
)
}
/**
* Holds where qualifiedName and typeSig make up the signature for the function.
*/
predicate functionSignature(Function f, string qualifiedName, string typeSig) {
qualifiedName = f.getQualifiedName() and
typeSig = typeSig(f)
}
/**
* Gets a possible definition for the undefined function by matching the undefined function name
* and parameter arity with a defined function.
*
* This is useful for identifying call to target dependencies across libraries, where the libraries
* are never statically linked together.
*/
Function getAPossibleDefinition(Function undefinedFunction) {
not undefinedFunction.isDefined() and
exists(string qn, string typeSig |
functionSignature(undefinedFunction, qn, typeSig) and functionSignature(result, qn, typeSig)
) and
result.isDefined()
}
/**
* Gets a possible target for the Call, using the name and parameter matching if we did not associate
* this call with a specific definition at link or compile time, and performing simple virtual
* dispatch resolution.
*/
Function getTarget(Call c) {
if VirtualDispatch::getAViableTarget(c).isDefined()
then
/*
* If there is at least one defined target after performing some simple virtual dispatch
* resolution, then the result is all the defined targets.
*/
result = VirtualDispatch::getAViableTarget(c) and
result.isDefined()
else
if exists(getAPossibleDefinition(VirtualDispatch::getAViableTarget(c)))
then
/*
* If we can use the heuristic matching of functions to find definitions for some of the viable
* targets, return those.
*/
result = getAPossibleDefinition(VirtualDispatch::getAViableTarget(c))
else
// Otherwise, the result is the undefined `Function` instances
result = VirtualDispatch::getAViableTarget(c)
}
/**
* Get an access of a field on `Variable` v.
*/
FieldAccess getAFieldAccess(Variable v) {
exists(VariableAccess va, Expr qualifierExpr |
// Find an access of the variable, or an AddressOfExpr that has the access
va = v.getAnAccess() and
(
qualifierExpr = va or
qualifierExpr.(AddressOfExpr).getOperand() = va
)
|
// Direct field access
qualifierExpr = result.getQualifier()
or
// Nested field access
qualifierExpr = result.(NestedFieldAccess).getUltimateQualifier()
)
}
/**
* Gets a condition which is asserted to be false by the given `ne` expression, according to this pattern:
* ```
* int a = !!result;
* if (!a) { // <- ne
* ....
* }
* ```
*/
Expr getAssertedFalseCondition(NotExpr ne) {
exists(LocalVariable v |
result = v.getInitializer().getExpr().(NotExpr).getOperand().(NotExpr).getOperand() and
ne.getOperand() = v.getAnAccess() and
nonAssignedVariable(v)
// and not passed by val?
)
}
pragma[noinline]
private predicate nonAssignedVariable(Variable v) { not exists(v.getAnAssignment()) }

View File

@@ -0,0 +1,190 @@
/**
* A module for identifying conditionally initialized variables.
*/
import cpp
import InitializationFunctions
// Optimised reachability predicates
private predicate reaches(ControlFlowNode a, ControlFlowNode b) = fastTC(successor/2)(a, b)
private predicate successor(ControlFlowNode a, ControlFlowNode b) { b = a.getASuccessor() }
class WhitelistedCallsConfig extends string {
WhitelistedCallsConfig() { this = "config" }
abstract predicate isWhitelisted(Call c);
}
abstract class WhitelistedCall extends Call {
override Function getTarget() { none() }
}
private predicate hasConditionalInitialization(
ConditionalInitializationFunction f, ConditionalInitializationCall call, LocalVariable v,
VariableAccess initAccess, Evidence e
) {
// Ignore whitelisted calls
not call instanceof WhitelistedCall and
f = getTarget(call) and
initAccess = v.getAnAccess() and
initAccess = call.getAConditionallyInitializedArgument(f, e).(AddressOfExpr).getOperand()
}
/**
* A variable that can be conditionally initialized by a call.
*/
class ConditionallyInitializedVariable extends LocalVariable {
ConditionalInitializationCall call;
ConditionalInitializationFunction f;
VariableAccess initAccess;
Evidence e;
ConditionallyInitializedVariable() {
// Find a call that conditionally initializes this variable
hasConditionalInitialization(f, call, this, initAccess, e) and
// Ignore cases where the variable is assigned prior to the call
not reaches(getAnAssignedValue(), initAccess) and
// Ignore cases where the variable is assigned field-wise prior to the call.
not exists(FieldAccess fa |
exists(Assignment a |
fa = getAFieldAccess(this) and
a.getLValue() = fa
)
|
reaches(fa, initAccess)
) and
// Ignore cases where the variable is assigned by a prior call to an initialization function
not exists(Call c |
getAnAccess() = getAnInitializedArgument(c).(AddressOfExpr).getOperand() and
reaches(c, initAccess)
) and
/*
* Static local variables with constant initializers do not have the initializer expr as part of
* the CFG, but should always be considered as initialized, so exclude them.
*/
not exists(getInitializer().getExpr())
}
/**
* Gets an access of the variable `v` which is not used as an lvalue, and not used as an argument
* to an initialization function.
*/
private VariableAccess getAReadAccess() {
result = this.getAnAccess() and
// Not used as an lvalue
not result = any(AssignExpr a).getLValue() and
// Not passed to another initialization function
not exists(Call c, int j | j = c.getTarget().(InitializationFunction).initializedParameter() |
result = c.getArgument(j).(AddressOfExpr).getOperand()
) and
// Not a pointless read
not result = any(ExprStmt es).getExpr()
}
/**
* Gets a read access of variable `v` that occurs after the `initializingCall`.
*/
private VariableAccess getAReadAccessAfterCall(ConditionalInitializationCall initializingCall) {
// Variable associated with this particular call
call = initializingCall and
// Access is a meaningful read access
result = getAReadAccess() and
// Which occurs after the call
reaches(call, result) and
/*
* Ignore risky accesses which are arguments to calls which also include another parameter to
* the original call. This is an attempt to eliminate results where the "status" can be checked
* through another parameter that assigned as part of the original call.
*/
not exists(Call c |
c.getAnArgument() = result or
c.getAnArgument().(AddressOfExpr).getOperand() = result
|
exists(LocalVariable lv |
call.getAnArgument().(AddressOfExpr).getOperand() = lv.getAnAccess() and
not lv = this
|
c.getAnArgument() = lv.getAnAccess()
)
)
}
/**
* Gets an access to the variable that is risky because the variable may not be initialized after
* the `call`, and the status of the call is never checked.
*/
VariableAccess getARiskyAccessWithNoStatusCheck(
ConditionalInitializationFunction initializingFunction,
ConditionalInitializationCall initializingCall, Evidence evidence
) {
// Variable associated with this particular call
call = initializingCall and
initializingFunction = f and
e = evidence and
result = getAReadAccessAfterCall(initializingCall) and
(
// Access is risky because status return code ignored completely
call instanceof ExprInVoidContext
or
// Access is risky because status return code ignored completely
exists(LocalVariable status | call = status.getAnAssignedValue() |
not exists(status.getAnAccess())
)
)
}
/**
* Gets an access to the variable that is risky because the variable may not be initialized after
* the `call`, and the status of the call is only checked after the risky access.
*/
VariableAccess getARiskyAccessBeforeStatusCheck(
ConditionalInitializationFunction initializingFunction,
ConditionalInitializationCall initializingCall, Evidence evidence
) {
// Variable associated with this particular call
call = initializingCall and
initializingFunction = f and
e = evidence and
result = getAReadAccessAfterCall(initializingCall) and
exists(LocalVariable status, Assignment a |
a.getRValue() = call and
call = status.getAnAssignedValue() and
// There exists a check of the status code
definitionUsePair(status, a, _) and
// And the check of the status code does not occur before the risky access
not exists(VariableAccess statusAccess |
definitionUsePair(status, a, statusAccess) and
reaches(statusAccess, result)
) and
// Ignore cases where the assignment to the status code is used directly
a instanceof ExprInVoidContext and
/*
* Ignore risky accesses which are arguments to calls which also include the status code.
* If both the risky value and status code are passed to a different function, that
* function is responsible for checking the status code.
*/
not exists(Call c |
c.getAnArgument() = result or
c.getAnArgument().(AddressOfExpr).getOperand() = result
|
definitionUsePair(status, a, c.getAnArgument())
)
)
}
/**
* Gets an access to the variable that is risky because the variable may not be initialized after
* the `call`.
*/
VariableAccess getARiskyAccess(
ConditionalInitializationFunction initializingFunction,
ConditionalInitializationCall initializingCall, Evidence evidence
) {
result = getARiskyAccessBeforeStatusCheck(initializingFunction, initializingCall, evidence) or
result = getARiskyAccessWithNoStatusCheck(initializingFunction, initializingCall, evidence)
}
}

View File

@@ -0,0 +1,41 @@
import cpp
/**
* Gets a `Field` that is nested within the given `Struct`.
*
* This identifies `Field`s which are located in the same memory
*/
private Field getANestedField(Struct s) {
result = s.getAField()
or
exists(NestedStruct ns |
s = ns.getDeclaringType() and
result = getANestedField(ns)
)
}
/**
* Unwraps a series of field accesses to determine the inner-most qualifier.
*/
private Expr getUltimateQualifier(FieldAccess fa) {
exists(Expr qualifier | qualifier = fa.getQualifier() |
result = getUltimateQualifier(qualifier)
or
not qualifier instanceof FieldAccess and result = qualifier
)
}
/**
* Accesses to nested fields.
*/
class NestedFieldAccess extends FieldAccess {
Expr ultimateQualifier;
NestedFieldAccess() {
ultimateQualifier = getUltimateQualifier(this) and
getTarget() = getANestedField(ultimateQualifier.getType().stripType())
}
/** Gets the ultimate qualifier of this nested field access. */
Expr getUltimateQualifier() { result = ultimateQualifier }
}

View File

@@ -7,3 +7,15 @@
import cpp import cpp
import PrintAST import PrintAST
/**
* Temporarily tweak this class or make a copy to control which functions are
* printed.
*/
class Cfg extends PrintASTConfiguration {
/**
* TWEAK THIS PREDICATE AS NEEDED.
* Holds if the AST for `func` should be printed.
*/
override predicate shouldPrintFunction(Function func) { any() }
}

View File

@@ -610,7 +610,9 @@ class FloatingPointType extends ArithmeticType {
( (
kind >= 24 and kind <= 32 kind >= 24 and kind <= 32
or or
kind = 38 kind >= 38 and kind <= 42
or
kind >= 45 and kind <= 50
) )
) )
} }

View File

@@ -35,7 +35,8 @@ private predicate exprInVoidContext(Expr e) {
exists(CommaExpr c | c.getLeftOperand() = e) exists(CommaExpr c | c.getLeftOperand() = e)
or or
exists(CommaExpr c | c.getRightOperand() = e and c instanceof ExprInVoidContext) exists(CommaExpr c | c.getRightOperand() = e and c instanceof ExprInVoidContext)
or
exists(ForStmt for | for.getUpdate() = e)
) and ) and
not e instanceof Qualifier and
not e.getActualType() instanceof VoidType not e.getActualType() instanceof VoidType
} }

View File

@@ -5,6 +5,8 @@
private import cpp private import cpp
private import semmle.code.cpp.dataflow.internal.FlowVar private import semmle.code.cpp.dataflow.internal.FlowVar
private import semmle.code.cpp.models.interfaces.DataFlow private import semmle.code.cpp.models.interfaces.DataFlow
private import semmle.code.cpp.controlflow.Guards
private import semmle.code.cpp.valuenumbering.GlobalValueNumbering
cached cached
private newtype TNode = private newtype TNode =
@@ -680,12 +682,16 @@ VariableAccess getAnAccessToAssignedVariable(Expr assign) {
* *
* It is important that all extending classes in scope are disjoint. * It is important that all extending classes in scope are disjoint.
*/ */
class BarrierGuard extends Expr { class BarrierGuard extends GuardCondition {
/** NOT YET SUPPORTED. Holds if this guard validates `e` upon evaluating to `branch`. */ /** Override this predicate to hold if this guard validates `e` upon evaluating to `b`. */
abstract deprecated predicate checks(Expr e, boolean branch); abstract predicate checks(Expr e, boolean b);
/** Gets a node guarded by this guard. */ /** Gets a node guarded by this guard. */
final Node getAGuardedNode() { final ExprNode getAGuardedNode() {
none() // stub exists(GVN value, boolean branch |
result.getExpr() = value.getAnExpr() and
this.checks(value.getAnExpr(), branch) and
this.controls(result.getExpr().getBasicBlock(), branch)
)
} }
} }

View File

@@ -0,0 +1,83 @@
import cpp
/**
* A module for performing simple virtual dispatch analysis.
*/
module VirtualDispatch {
/**
* Gets a possible implementation target when the given function is the static target of a virtual call.
*/
private MemberFunction getAPossibleImplementation(MemberFunction staticTarget) {
/*
* `IUnknown` is a COM interface with many sub-types, and many overrides (tens of thousands on
* some databases), so we ignore any member functions defined within that interface.
*/
not staticTarget.getDeclaringType().hasName("IUnknown") and
result = staticTarget.getAnOverridingFunction*()
}
/** Gets the static type of the qualifier expression for the given call. */
private Class getCallQualifierType(FunctionCall c) {
result = c.getQualifier().getType().stripType() and
/*
* `IUnknown` is a COM interface with many sub-types (tens of thousands on some databases), so
* we ignore any cases where the qualifier type is that interface.
*/
not result.hasName("IUnknown")
}
/**
* Gets a viable target for the given function call.
*
* If `c` is a virtual call, then we will perform a simple virtual dispatch analysis to return
* the `Function` instances which might be a viable target, based on an analysis of the declared
* type of the qualifier expression.
*
* (This analysis is imprecise: it looks for subtypes of the declared type of the qualifier expression
* and the possible implementations of `c.getTarget()` that are declared or inherited by those subtypes.
* This does not account for virtual inheritance and the ways this affects dispatch.)
*
* If `c` is not a virtual call, the result will be `c.getTarget()`.
*/
Function getAViableTarget(Call c) {
exists(Function staticTarget | staticTarget = c.getTarget() |
if c.(FunctionCall).isVirtual() and staticTarget instanceof MemberFunction
then
exists(Class qualifierType, Class qualifierSubType |
result = getAPossibleImplementation(staticTarget) and
qualifierType = getCallQualifierType(c) and
qualifierType = qualifierSubType.getABaseClass*() and
mayInherit(qualifierSubType, result) and
not cannotInherit(qualifierSubType, result)
)
else result = staticTarget
)
}
/** Holds if `f` is declared in `c` or a transitive base class of `c`. */
private predicate mayInherit(Class c, MemberFunction f) {
f.getDeclaringType() = c.getABaseClass*()
}
/**
* Holds if `c` cannot inherit the member function `f`,
* i.e. `c` or one of its supertypes overrides `f`.
*/
private predicate cannotInherit(Class c, MemberFunction f) {
exists(Class overridingType, MemberFunction override |
cannotInheritHelper(c, f, overridingType, override) and
override.overrides+(f)
)
}
pragma[noinline]
private predicate cannotInheritHelper(
Class c, MemberFunction f, Class overridingType, MemberFunction override
) {
c.getABaseClass*() = overridingType and
override.getDeclaringType() = overridingType and
overridingType.getABaseClass+() = f.getDeclaringType()
}
}

View File

@@ -540,6 +540,13 @@ class ErrorExpr extends Expr, @errorexpr {
*/ */
class AssumeExpr extends Expr, @assume { class AssumeExpr extends Expr, @assume {
override string toString() { result = "__assume(...)" } override string toString() { result = "__assume(...)" }
override string getCanonicalQLClass() { result = "AssumeExpr" }
/**
* Gets the operand of the `__assume` expressions.
*/
Expr getOperand() { this.hasChild(result, 0) }
} }
/** /**

View File

@@ -37,7 +37,7 @@ private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
} }
private predicate accessesVariable(CopyInstruction copy, Variable var) { private predicate accessesVariable(CopyInstruction copy, Variable var) {
exists(VariableAddressInstruction va | va.getVariable().getAST() = var | exists(VariableAddressInstruction va | va.getASTVariable() = var |
copy.(StoreInstruction).getDestinationAddress() = va copy.(StoreInstruction).getDestinationAddress() = va
or or
copy.(LoadInstruction).getSourceAddress() = va copy.(LoadInstruction).getSourceAddress() = va

View File

@@ -5,6 +5,7 @@
private import cpp private import cpp
private import semmle.code.cpp.ir.IR private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.controlflow.IRGuards private import semmle.code.cpp.controlflow.IRGuards
private import semmle.code.cpp.ir.ValueNumbering
/** /**
* A newtype wrapper to prevent accidental casts between `Node` and * A newtype wrapper to prevent accidental casts between `Node` and
@@ -213,6 +214,14 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
*/ */
predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) } predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
/**
* Holds if data can flow from `i1` to `i2` in zero or more
* local (intra-procedural) steps.
*/
predicate localInstructionFlow(Instruction e1, Instruction e2) {
localFlow(instructionNode(e1), instructionNode(e2))
}
/** /**
* Holds if data can flow from `e1` to `e2` in zero or more * Holds if data can flow from `e1` to `e2` in zero or more
* local (intra-procedural) steps. * local (intra-procedural) steps.
@@ -220,7 +229,7 @@ predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)) } predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)) }
/** /**
* A guard that validates some expression. * A guard that validates some instruction.
* *
* To use this in a configuration, extend the class and provide a * To use this in a configuration, extend the class and provide a
* characteristic predicate precisely specifying the guard, and override * characteristic predicate precisely specifying the guard, and override
@@ -229,11 +238,15 @@ predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)
* It is important that all extending classes in scope are disjoint. * It is important that all extending classes in scope are disjoint.
*/ */
class BarrierGuard extends IRGuardCondition { class BarrierGuard extends IRGuardCondition {
/** NOT YET SUPPORTED. Holds if this guard validates `e` upon evaluating to `b`. */ /** Override this predicate to hold if this guard validates `instr` upon evaluating to `b`. */
abstract deprecated predicate checks(Instruction e, boolean b); abstract predicate checks(Instruction instr, boolean b);
/** Gets a node guarded by this guard. */ /** Gets a node guarded by this guard. */
final Node getAGuardedNode() { final Node getAGuardedNode() {
none() // stub exists(ValueNumber value, boolean edge |
result.asInstruction() = value.getAnInstruction() and
this.checks(value.getAnInstruction(), edge) and
this.controls(result.asInstruction().getBlock(), edge)
)
} }
} }

View File

@@ -53,6 +53,14 @@ private predicate localInstructionTaintStep(Instruction nodeFrom, Instruction no
*/ */
predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { localTaintStep*(source, sink) } predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { localTaintStep*(source, sink) }
/**
* Holds if taint can flow from `i1` to `i2` in zero or more
* local (intra-procedural) steps.
*/
predicate localInstructionTaint(Instruction i1, Instruction i2) {
localTaint(DataFlow::instructionNode(i1), DataFlow::instructionNode(i2))
}
/** /**
* Holds if taint can flow from `e1` to `e2` in zero or more * Holds if taint can flow from `e1` to `e2` in zero or more
* local (intra-procedural) steps. * local (intra-procedural) steps.

View File

@@ -0,0 +1,247 @@
/**
* Minimal, language-neutral type system for the IR.
*/
private import internal.IRTypeInternal
private newtype TIRType =
TIRVoidType() or
TIRUnknownType() or
TIRErrorType() { Language::hasErrorType() } or
TIRBooleanType(int byteSize) { Language::hasBooleanType(byteSize) } or
TIRSignedIntegerType(int byteSize) { Language::hasSignedIntegerType(byteSize) } or
TIRUnsignedIntegerType(int byteSize) { Language::hasUnsignedIntegerType(byteSize) } or
TIRFloatingPointType(int byteSize) { Language::hasFloatingPointType(byteSize) } or
TIRAddressType(int byteSize) { Language::hasAddressType(byteSize) } or
TIRFunctionAddressType(int byteSize) { Language::hasFunctionAddressType(byteSize) } or
TIROpaqueType(Language::OpaqueTypeTag tag, int byteSize) {
Language::hasOpaqueType(tag, byteSize)
}
/**
* The language-neutral type of an IR `Instruction`, `Operand`, or `IRVariable`.
* The interface to `IRType` and its subclasses is the same across all languages for which the IR
* is supported, so analyses that expect to be used for multiple languages should generally use
* `IRType` rather than a language-specific type.
*
* Many types from the language-specific type system will map to a single canonical `IRType`. Two
* types that map to the same `IRType` are considered equivalent by the IR. As an example, in C++,
* all pointer types map to the same instance of `IRAddressType`.
*/
class IRType extends TIRType {
string toString() { none() }
/**
* Gets a string that uniquely identifies this `IRType`. This string is often the same as the
* result of `IRType.toString()`, but for some types it may be more verbose to ensure uniqueness.
*/
string getIdentityString() { result = toString() }
/**
* Gets the size of the type, in bytes, if known.
*
* This will hold for all `IRType` objects except `IRUnknownType`.
*/
int getByteSize() { none() }
/**
* Gets a single instance of `LanguageType` that maps to this `IRType`.
*/
Language::LanguageType getCanonicalLanguageType() { none() }
}
/**
* An unknown type. Generally used to represent results and operands that access an unknown set of
* memory locations, such as the side effects of a function call.
*/
class IRUnknownType extends IRType, TIRUnknownType {
final override string toString() { result = "unknown" }
final override int getByteSize() { none() }
final override Language::LanguageType getCanonicalLanguageType() {
result = Language::getCanonicalUnknownType()
}
}
/**
* A void type, which has no values. Used to represent the result type of an instruction that does
* not produce a result.
*/
class IRVoidType extends IRType, TIRVoidType {
final override string toString() { result = "void" }
final override int getByteSize() { result = 0 }
final override Language::LanguageType getCanonicalLanguageType() {
result = Language::getCanonicalVoidType()
}
}
/**
* An error type. Used when an error in the source code prevents the extractor from determining the
* proper type.
*/
class IRErrorType extends IRType, TIRErrorType {
final override string toString() { result = "error" }
final override int getByteSize() { result = 0 }
final override Language::LanguageType getCanonicalLanguageType() {
result = Language::getCanonicalErrorType()
}
}
private class IRSizedType extends IRType {
int byteSize;
IRSizedType() {
this = TIRBooleanType(byteSize) or
this = TIRSignedIntegerType(byteSize) or
this = TIRUnsignedIntegerType(byteSize) or
this = TIRFloatingPointType(byteSize) or
this = TIRAddressType(byteSize) or
this = TIRFunctionAddressType(byteSize) or
this = TIROpaqueType(_, byteSize)
}
final override int getByteSize() { result = byteSize }
}
/**
* A Boolean type, which can hold the values `true` (non-zero) or `false` (zero).
*/
class IRBooleanType extends IRSizedType, TIRBooleanType {
final override string toString() { result = "bool" + byteSize.toString() }
final override Language::LanguageType getCanonicalLanguageType() {
result = Language::getCanonicalBooleanType(byteSize)
}
}
/**
* A numberic type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and
* `IRFloatingPointType`.
*/
class IRNumericType extends IRSizedType {
IRNumericType() {
this = TIRSignedIntegerType(byteSize) or
this = TIRUnsignedIntegerType(byteSize) or
this = TIRFloatingPointType(byteSize)
}
}
/**
* A signed two's-complement integer. Also used to represent enums whose underlying type is a signed
* integer, as well as character types whose representation is signed.
*/
class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType {
final override string toString() { result = "int" + byteSize.toString() }
final override Language::LanguageType getCanonicalLanguageType() {
result = Language::getCanonicalSignedIntegerType(byteSize)
}
}
/**
* An unsigned two's-complement integer. Also used to represent enums whose underlying type is an
* unsigned integer, as well as character types whose representation is unsigned.
*/
class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType {
final override string toString() { result = "uint" + byteSize.toString() }
final override Language::LanguageType getCanonicalLanguageType() {
result = Language::getCanonicalUnsignedIntegerType(byteSize)
}
}
/**
* A floating-point type.
*/
class IRFloatingPointType extends IRNumericType, TIRFloatingPointType {
final override string toString() { result = "float" + byteSize.toString() }
final override Language::LanguageType getCanonicalLanguageType() {
result = Language::getCanonicalFloatingPointType(byteSize)
}
}
/**
* An address type, representing the memory address of data. Used to represent pointers, references,
* and lvalues, include those that are garbage collected.
*
* The address of a function is represented by the separate `IRFunctionAddressType`.
*/
class IRAddressType extends IRSizedType, TIRAddressType {
final override string toString() { result = "addr" + byteSize.toString() }
final override Language::LanguageType getCanonicalLanguageType() {
result = Language::getCanonicalAddressType(byteSize)
}
}
/**
* An address type, representing the memory address of code. Used to represent function pointers,
* function references, and the target of a direct function call.
*/
class IRFunctionAddressType extends IRSizedType, TIRFunctionAddressType {
final override string toString() { result = "func" + byteSize.toString() }
final override Language::LanguageType getCanonicalLanguageType() {
result = Language::getCanonicalFunctionAddressType(byteSize)
}
}
/**
* A type with known size that does not fit any of the other kinds of type. Used to represent
* classes, structs, unions, fixed-size arrays, pointers-to-member, and more.
*/
class IROpaqueType extends IRSizedType, TIROpaqueType {
Language::OpaqueTypeTag tag;
IROpaqueType() { this = TIROpaqueType(tag, byteSize) }
final override string toString() {
result = "opaque" + byteSize.toString() + "{" + tag.toString() + "}"
}
final override string getIdentityString() {
result = "opaque" + byteSize.toString() + "{" + Language::getOpaqueTagIdentityString(tag) + "}"
}
final override Language::LanguageType getCanonicalLanguageType() {
result = Language::getCanonicalOpaqueType(tag, byteSize)
}
/**
* Gets the "tag" that differentiates this type from other incompatible opaque types that have the
* same size.
*/
final Language::OpaqueTypeTag getTag() { result = tag }
}
module IRTypeSanity {
query predicate missingCanonicalLanguageType(IRType type, string message) {
not exists(type.getCanonicalLanguageType()) and
message = "Type does not have a canonical `LanguageType`"
}
query predicate multipleCanonicalLanguageTypes(IRType type, string message) {
strictcount(type.getCanonicalLanguageType()) > 1 and
message = "Type has multiple canonical `LanguageType`s: " +
concat(type.getCanonicalLanguageType().toString(), ", ")
}
query predicate missingIRType(Language::LanguageType type, string message) {
not exists(type.getIRType()) and
message = "`LanguageType` does not have a corresponding `IRType`."
}
query predicate multipleIRTypes(Language::LanguageType type, string message) {
strictcount(type.getIRType()) > 1 and
message = "`LanguageType` " + type.getAQlClass() + " has multiple `IRType`s: " +
concat(type.getIRType().toString(), ", ")
}
import Language::LanguageTypeSanity
}

View File

@@ -5,6 +5,7 @@ private newtype TMemoryAccessKind =
TBufferMayMemoryAccess() or TBufferMayMemoryAccess() or
TEscapedMemoryAccess() or TEscapedMemoryAccess() or
TEscapedMayMemoryAccess() or TEscapedMayMemoryAccess() or
TNonLocalMayMemoryAccess() or
TPhiMemoryAccess() or TPhiMemoryAccess() or
TUnmodeledMemoryAccess() or TUnmodeledMemoryAccess() or
TChiTotalMemoryAccess() or TChiTotalMemoryAccess() or
@@ -80,6 +81,14 @@ class EscapedMayMemoryAccess extends MemoryAccessKind, TEscapedMayMemoryAccess {
override string toString() { result = "escaped(may)" } override string toString() { result = "escaped(may)" }
} }
/**
* The operand or result may access all memory whose address has escaped, other than data on the
* stack frame of the current function.
*/
class NonLocalMayMemoryAccess extends MemoryAccessKind, TNonLocalMayMemoryAccess {
override string toString() { result = "nonlocal(may)" }
}
/** /**
* The operand is a Phi operand, which accesses the same memory as its * The operand is a Phi operand, which accesses the same memory as its
* definition. * definition.

View File

@@ -57,6 +57,7 @@ private newtype TOpcode =
TUnmodeledDefinition() or TUnmodeledDefinition() or
TUnmodeledUse() or TUnmodeledUse() or
TAliasedDefinition() or TAliasedDefinition() or
TAliasedUse() or
TPhi() or TPhi() or
TBuiltIn() or TBuiltIn() or
TVarArgsStart() or TVarArgsStart() or
@@ -393,6 +394,10 @@ module Opcode {
final override string toString() { result = "AliasedDefinition" } final override string toString() { result = "AliasedDefinition" }
} }
class AliasedUse extends Opcode, TAliasedUse {
final override string toString() { result = "AliasedUse" }
}
class Phi extends Opcode, TPhi { class Phi extends Opcode, TPhi {
final override string toString() { result = "Phi" } final override string toString() { result = "Phi" }
} }

View File

@@ -5,6 +5,7 @@ import IRVariable
import Operand import Operand
private import internal.IRImports as Imports private import internal.IRImports as Imports
import Imports::EdgeKind import Imports::EdgeKind
import Imports::IRType
import Imports::MemoryAccessKind import Imports::MemoryAccessKind
private newtype TIRPropertyProvider = MkIRPropertyProvider() private newtype TIRPropertyProvider = MkIRPropertyProvider()

View File

@@ -1,2 +1,3 @@
private import IR private import IR
import InstructionSanity import InstructionSanity
import IRTypeSanity

View File

@@ -5,6 +5,7 @@ import Imports::TempVariableTag
private import Imports::IRUtilities private import Imports::IRUtilities
private import Imports::TTempVariableTag private import Imports::TTempVariableTag
private import Imports::TIRVariable private import Imports::TIRVariable
private import Imports::IRType
IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) {
result.getVariable() = var and result.getVariable() = var and
@@ -24,7 +25,17 @@ abstract class IRVariable extends TIRVariable {
/** /**
* Gets the type of the variable. * Gets the type of the variable.
*/ */
abstract Language::Type getType(); final Language::Type getType() { getLanguageType().hasType(result, false) }
/**
* Gets the language-neutral type of the variable.
*/
final IRType getIRType() { result = getLanguageType().getIRType() }
/**
* Gets the type of the variable.
*/
abstract Language::LanguageType getLanguageType();
/** /**
* Gets the AST node that declared this variable, or that introduced this * Gets the AST node that declared this variable, or that introduced this
@@ -59,7 +70,7 @@ abstract class IRVariable extends TIRVariable {
*/ */
class IRUserVariable extends IRVariable, TIRUserVariable { class IRUserVariable extends IRVariable, TIRUserVariable {
Language::Variable var; Language::Variable var;
Language::Type type; Language::LanguageType type;
IRUserVariable() { this = TIRUserVariable(var, type, func) } IRUserVariable() { this = TIRUserVariable(var, type, func) }
@@ -71,7 +82,7 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
result = getVariable().toString() + " " + getVariable().getLocation().toString() result = getVariable().toString() + " " + getVariable().getLocation().toString()
} }
final override Language::Type getType() { result = type } final override Language::LanguageType getLanguageType() { result = type }
/** /**
* Gets the original user-declared variable. * Gets the original user-declared variable.
@@ -110,11 +121,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable { class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
Language::AST ast; Language::AST ast;
TempVariableTag tag; TempVariableTag tag;
Language::Type type; Language::LanguageType type;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) } IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
final override Language::Type getType() { result = type } final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast } final override Language::AST getAST() { result = ast }

View File

@@ -5,6 +5,7 @@ import IRVariable
import Operand import Operand
private import internal.InstructionImports as Imports private import internal.InstructionImports as Imports
import Imports::EdgeKind import Imports::EdgeKind
import Imports::IRType
import Imports::MemoryAccessKind import Imports::MemoryAccessKind
import Imports::Opcode import Imports::Opcode
private import Imports::OperandTag private import Imports::OperandTag
@@ -49,7 +50,8 @@ module InstructionSanity {
( (
opcode instanceof ReadSideEffectOpcode or opcode instanceof ReadSideEffectOpcode or
opcode instanceof Opcode::InlineAsm or opcode instanceof Opcode::InlineAsm or
opcode instanceof Opcode::CallSideEffect opcode instanceof Opcode::CallSideEffect or
opcode instanceof Opcode::AliasedUse
) and ) and
tag instanceof SideEffectOperandTag tag instanceof SideEffectOperandTag
) )
@@ -113,10 +115,12 @@ module InstructionSanity {
} }
query predicate missingOperandType(Operand operand, string message) { query predicate missingOperandType(Operand operand, string message) {
exists(Language::Function func | exists(Language::Function func, Instruction use |
not exists(operand.getType()) and not exists(operand.getType()) and
func = operand.getUse().getEnclosingFunction() and use = operand.getUse() and
message = "Operand missing type in function '" + Language::getIdentityString(func) + "'." func = use.getEnclosingFunction() and
message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString()
+ "' missing type in function '" + Language::getIdentityString(func) + "'."
) )
} }
@@ -260,6 +264,7 @@ module InstructionSanity {
) { ) {
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
not useOperand.getUse() instanceof UnmodeledUseInstruction and not useOperand.getUse() instanceof UnmodeledUseInstruction and
not defInstr instanceof UnmodeledDefinitionInstruction and
pointOfEvaluation(useOperand, useBlock, useIndex) and pointOfEvaluation(useOperand, useBlock, useIndex) and
defInstr = useOperand.getAnyDef() and defInstr = useOperand.getAnyDef() and
( (
@@ -321,7 +326,7 @@ class Instruction extends Construction::TInstruction {
} }
private string getResultPrefix() { private string getResultPrefix() {
if getResultType() instanceof Language::VoidType if getResultIRType() instanceof IRVoidType
then result = "v" then result = "v"
else else
if hasMemoryResult() if hasMemoryResult()
@@ -353,23 +358,6 @@ class Instruction extends Construction::TInstruction {
) )
} }
bindingset[type]
private string getValueCategoryString(string type) {
if isGLValue() then result = "glval<" + type + ">" else result = type
}
string getResultTypeString() {
exists(string valcat |
valcat = getValueCategoryString(getResultType().toString()) and
if
getResultType() instanceof Language::UnknownType and
not isGLValue() and
exists(getResultSize())
then result = valcat + "[" + getResultSize().toString() + "]"
else result = valcat
)
}
/** /**
* Gets a human-readable string that uniquely identifies this instruction * Gets a human-readable string that uniquely identifies this instruction
* within the function. This string is used to refer to this instruction when * within the function. This string is used to refer to this instruction when
@@ -389,7 +377,9 @@ class Instruction extends Construction::TInstruction {
* *
* Example: `r1_1(int*)` * Example: `r1_1(int*)`
*/ */
final string getResultString() { result = getResultId() + "(" + getResultTypeString() + ")" } final string getResultString() {
result = getResultId() + "(" + getResultLanguageType().getDumpString() + ")"
}
/** /**
* Gets a string describing the operands of this instruction, suitable for * Gets a string describing the operands of this instruction, suitable for
@@ -457,6 +447,16 @@ class Instruction extends Construction::TInstruction {
result = Construction::getInstructionUnconvertedResultExpression(this) result = Construction::getInstructionUnconvertedResultExpression(this)
} }
final Language::LanguageType getResultLanguageType() {
result = Construction::getInstructionResultType(this)
}
/**
* Gets the type of the result produced by this instruction. If the instruction does not produce
* a result, its result type will be `IRVoidType`.
*/
final IRType getResultIRType() { result = getResultLanguageType().getIRType() }
/** /**
* Gets the type of the result produced by this instruction. If the * Gets the type of the result produced by this instruction. If the
* instruction does not produce a result, its result type will be `VoidType`. * instruction does not produce a result, its result type will be `VoidType`.
@@ -464,7 +464,16 @@ class Instruction extends Construction::TInstruction {
* If `isGLValue()` holds, then the result type of this instruction should be * If `isGLValue()` holds, then the result type of this instruction should be
* thought of as "pointer to `getResultType()`". * thought of as "pointer to `getResultType()`".
*/ */
final Language::Type getResultType() { Construction::instructionHasType(this, result, _) } final Language::Type getResultType() {
exists(Language::LanguageType resultType |
resultType = getResultLanguageType() and
(
resultType.hasUnspecifiedType(result, _)
or
not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType
)
)
}
/** /**
* Holds if the result produced by this instruction is a glvalue. If this * Holds if the result produced by this instruction is a glvalue. If this
@@ -484,7 +493,7 @@ class Instruction extends Construction::TInstruction {
* result of the `Load` instruction is a prvalue of type `int`, representing * result of the `Load` instruction is a prvalue of type `int`, representing
* the integer value loaded from variable `x`. * the integer value loaded from variable `x`.
*/ */
final predicate isGLValue() { Construction::instructionHasType(this, _, true) } final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) }
/** /**
* Gets the size of the result produced by this instruction, in bytes. If the * Gets the size of the result produced by this instruction, in bytes. If the
@@ -493,16 +502,7 @@ class Instruction extends Construction::TInstruction {
* If `this.isGLValue()` holds for this instruction, the value of * If `this.isGLValue()` holds for this instruction, the value of
* `getResultSize()` will always be the size of a pointer. * `getResultSize()` will always be the size of a pointer.
*/ */
final int getResultSize() { final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() }
if isGLValue()
then
// a glvalue is always pointer-sized.
result = Language::getPointerSize()
else
if getResultType() instanceof Language::UnknownType
then result = Construction::getInstructionResultSize(this)
else result = Language::getTypeSize(getResultType())
}
/** /**
* Gets the opcode that specifies the operation performed by this instruction. * Gets the opcode that specifies the operation performed by this instruction.
@@ -1384,7 +1384,7 @@ class CatchInstruction extends Instruction {
* An instruction that catches an exception of a specific type. * An instruction that catches an exception of a specific type.
*/ */
class CatchByTypeInstruction extends CatchInstruction { class CatchByTypeInstruction extends CatchInstruction {
Language::Type exceptionType; Language::LanguageType exceptionType;
CatchByTypeInstruction() { CatchByTypeInstruction() {
getOpcode() instanceof Opcode::CatchByType and getOpcode() instanceof Opcode::CatchByType and
@@ -1396,7 +1396,7 @@ class CatchByTypeInstruction extends CatchInstruction {
/** /**
* Gets the type of exception to be caught. * Gets the type of exception to be caught.
*/ */
final Language::Type getExceptionType() { result = exceptionType } final Language::LanguageType getExceptionType() { result = exceptionType }
} }
/** /**
@@ -1423,6 +1423,13 @@ class AliasedDefinitionInstruction extends Instruction {
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess } final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
} }
/**
* An instruction that consumes all escaped memory on exit from the function.
*/
class AliasedUseInstruction extends Instruction {
AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse }
}
class UnmodeledUseInstruction extends Instruction { class UnmodeledUseInstruction extends Instruction {
UnmodeledUseInstruction() { getOpcode() instanceof Opcode::UnmodeledUse } UnmodeledUseInstruction() { getOpcode() instanceof Opcode::UnmodeledUse }

View File

@@ -1,9 +1,10 @@
private import internal.IRInternal private import internal.IRInternal
import Instruction private import Instruction
import IRBlock private import IRBlock
private import internal.OperandImports as Imports private import internal.OperandImports as Imports
import Imports::MemoryAccessKind private import Imports::MemoryAccessKind
import Imports::Overlap private import Imports::IRType
private import Imports::Overlap
private import Imports::OperandTag private import Imports::OperandTag
cached cached
@@ -143,22 +144,40 @@ class Operand extends TOperand {
* the definition type, such as in the case of a partial read or a read from a pointer that * the definition type, such as in the case of a partial read or a read from a pointer that
* has been cast to a different type. * has been cast to a different type.
*/ */
Language::Type getType() { result = getAnyDef().getResultType() } Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() }
/**
* Gets the language-neutral type of the value consumed by this operand. This is usually the same
* as the result type of the definition instruction consumed by this operand. For register
* operands, this is always the case. For some memory operands, the operand type may be different
* from the definition type, such as in the case of a partial read or a read from a pointer that
* has been cast to a different type.
*/
final IRType getIRType() { result = getLanguageType().getIRType() }
/**
* Gets the type of the value consumed by this operand. This is usually the same as the
* result type of the definition instruction consumed by this operand. For register operands,
* this is always the case. For some memory operands, the operand type may be different from
* the definition type, such as in the case of a partial read or a read from a pointer that
* has been cast to a different type.
*/
final Language::Type getType() { getLanguageType().hasType(result, _) }
/** /**
* Holds if the value consumed by this operand is a glvalue. If this * Holds if the value consumed by this operand is a glvalue. If this
* holds, the value of the operand represents the address of a location, * holds, the value of the operand represents the address of a location,
* and the type of the location is given by `getType()`. If this does * and the type of the location is given by `getType()`. If this does
* not hold, the value of the operand represents a value whose type is * not hold, the value of the operand represents a value whose type is
* given by `getResultType()`. * given by `getType()`.
*/ */
predicate isGLValue() { getAnyDef().isGLValue() } final predicate isGLValue() { getLanguageType().hasType(_, true) }
/** /**
* Gets the size of the value consumed by this operand, in bytes. If the operand does not have * Gets the size of the value consumed by this operand, in bytes. If the operand does not have
* a known constant size, this predicate does not hold. * a known constant size, this predicate does not hold.
*/ */
int getSize() { result = Language::getTypeSize(getType()) } final int getSize() { result = getLanguageType().getByteSize() }
} }
/** /**
@@ -170,11 +189,6 @@ class MemoryOperand extends Operand {
this = TPhiOperand(_, _, _, _) this = TPhiOperand(_, _, _, _)
} }
override predicate isGLValue() {
// A `MemoryOperand` can never be a glvalue
none()
}
/** /**
* Gets the kind of memory access performed by the operand. * Gets the kind of memory access performed by the operand.
*/ */
@@ -239,7 +253,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
class TypedOperand extends NonPhiMemoryOperand { class TypedOperand extends NonPhiMemoryOperand {
override TypedOperandTag tag; override TypedOperandTag tag;
final override Language::Type getType() { final override Language::LanguageType getLanguageType() {
result = Construction::getInstructionOperandType(useInstr, tag) result = Construction::getInstructionOperandType(useInstr, tag)
} }
} }
@@ -381,13 +395,10 @@ class PositionalArgumentOperand extends ArgumentOperand {
class SideEffectOperand extends TypedOperand { class SideEffectOperand extends TypedOperand {
override SideEffectOperandTag tag; override SideEffectOperandTag tag;
final override int getSize() {
if getType() instanceof Language::UnknownType
then result = Construction::getInstructionOperandSize(useInstr, tag)
else result = Language::getTypeSize(getType())
}
override MemoryAccessKind getMemoryAccess() { override MemoryAccessKind getMemoryAccess() {
useInstr instanceof AliasedUseInstruction and
result instanceof NonLocalMayMemoryAccess
or
useInstr instanceof CallSideEffectInstruction and useInstr instanceof CallSideEffectInstruction and
result instanceof EscapedMayMemoryAccess result instanceof EscapedMayMemoryAccess
or or

View File

@@ -1,5 +1,5 @@
private import internal.ValueNumberingInternal private import internal.ValueNumberingInternal
private import cpp private import internal.ValueNumberingImports
private import IR private import IR
/** /**
@@ -23,31 +23,32 @@ newtype TValueNumber =
initializeParameterValueNumber(_, irFunc, var) initializeParameterValueNumber(_, irFunc, var)
} or } or
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
TConstantValueNumber(IRFunction irFunc, Type type, string value) { TConstantValueNumber(IRFunction irFunc, IRType type, string value) {
constantValueNumber(_, irFunc, type, value) constantValueNumber(_, irFunc, type, value)
} or } or
TStringConstantValueNumber(IRFunction irFunc, Type type, string value) { TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
stringConstantValueNumber(_, irFunc, type, value) stringConstantValueNumber(_, irFunc, type, value)
} or } or
TFieldAddressValueNumber(IRFunction irFunc, Field field, ValueNumber objectAddress) { TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, ValueNumber objectAddress) {
fieldAddressValueNumber(_, irFunc, field, objectAddress) fieldAddressValueNumber(_, irFunc, field, objectAddress)
} or } or
TBinaryValueNumber( TBinaryValueNumber(
IRFunction irFunc, Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand
) { ) {
binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand) binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand)
} or } or
TPointerArithmeticValueNumber( TPointerArithmeticValueNumber(
IRFunction irFunc, Opcode opcode, Type type, int elementSize, ValueNumber leftOperand, IRFunction irFunc, Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
ValueNumber rightOperand ValueNumber rightOperand
) { ) {
pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand) pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand)
} or } or
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, Type type, ValueNumber operand) { TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand) {
unaryValueNumber(_, irFunc, opcode, type, operand) unaryValueNumber(_, irFunc, opcode, type, operand)
} or } or
TInheritanceConversionValueNumber( TInheritanceConversionValueNumber(
IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass,
ValueNumber operand
) { ) {
inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand) inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
} or } or
@@ -59,7 +60,7 @@ newtype TValueNumber =
class ValueNumber extends TValueNumber { class ValueNumber extends TValueNumber {
final string toString() { result = getExampleInstruction().getResultId() } final string toString() { result = getExampleInstruction().getResultId() }
final Location getLocation() { result = getExampleInstruction().getLocation() } final Language::Location getLocation() { result = getExampleInstruction().getLocation() }
/** /**
* Gets the instructions that have been assigned this value number. This will always produce at * Gets the instructions that have been assigned this value number. This will always produce at
@@ -150,23 +151,23 @@ private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRF
} }
private predicate constantValueNumber( private predicate constantValueNumber(
ConstantInstruction instr, IRFunction irFunc, Type type, string value ConstantInstruction instr, IRFunction irFunc, IRType type, string value
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
instr.getResultType() = type and instr.getResultIRType() = type and
instr.getValue() = value instr.getValue() = value
} }
private predicate stringConstantValueNumber( private predicate stringConstantValueNumber(
StringConstantInstruction instr, IRFunction irFunc, Type type, string value StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
instr.getResultType() = type and instr.getResultIRType() = type and
instr.getValue().getValue() = value instr.getValue().getValue() = value
} }
private predicate fieldAddressValueNumber( private predicate fieldAddressValueNumber(
FieldAddressInstruction instr, IRFunction irFunc, Field field, ValueNumber objectAddress FieldAddressInstruction instr, IRFunction irFunc, Language::Field field, ValueNumber objectAddress
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
instr.getField() = field and instr.getField() = field and
@@ -174,43 +175,43 @@ private predicate fieldAddressValueNumber(
} }
private predicate binaryValueNumber( private predicate binaryValueNumber(
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, Type type, ValueNumber leftOperand, BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand,
ValueNumber rightOperand ValueNumber rightOperand
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
not instr instanceof PointerArithmeticInstruction and not instr instanceof PointerArithmeticInstruction and
instr.getOpcode() = opcode and instr.getOpcode() = opcode and
instr.getResultType() = type and instr.getResultIRType() = type and
valueNumber(instr.getLeft()) = leftOperand and valueNumber(instr.getLeft()) = leftOperand and
valueNumber(instr.getRight()) = rightOperand valueNumber(instr.getRight()) = rightOperand
} }
private predicate pointerArithmeticValueNumber( private predicate pointerArithmeticValueNumber(
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, Type type, int elementSize, PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type,
ValueNumber leftOperand, ValueNumber rightOperand int elementSize, ValueNumber leftOperand, ValueNumber rightOperand
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
instr.getOpcode() = opcode and instr.getOpcode() = opcode and
instr.getResultType() = type and instr.getResultIRType() = type and
instr.getElementSize() = elementSize and instr.getElementSize() = elementSize and
valueNumber(instr.getLeft()) = leftOperand and valueNumber(instr.getLeft()) = leftOperand and
valueNumber(instr.getRight()) = rightOperand valueNumber(instr.getRight()) = rightOperand
} }
private predicate unaryValueNumber( private predicate unaryValueNumber(
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, Type type, ValueNumber operand UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
not instr instanceof InheritanceConversionInstruction and not instr instanceof InheritanceConversionInstruction and
not instr instanceof CopyInstruction and not instr instanceof CopyInstruction and
instr.getOpcode() = opcode and instr.getOpcode() = opcode and
instr.getResultType() = type and instr.getResultIRType() = type and
valueNumber(instr.getUnary()) = operand valueNumber(instr.getUnary()) = operand
} }
private predicate inheritanceConversionValueNumber( private predicate inheritanceConversionValueNumber(
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode, Class baseClass, InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
Class derivedClass, ValueNumber operand Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
instr.getOpcode() = opcode and instr.getOpcode() = opcode and
@@ -225,7 +226,7 @@ private predicate inheritanceConversionValueNumber(
*/ */
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) { private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
not instr.getResultType() instanceof VoidType and not instr.getResultIRType() instanceof IRVoidType and
not numberableInstruction(instr) not numberableInstruction(instr)
} }
@@ -269,38 +270,41 @@ private ValueNumber nonUniqueValueNumber(Instruction instr) {
initializeThisValueNumber(instr, irFunc) and initializeThisValueNumber(instr, irFunc) and
result = TInitializeThisValueNumber(irFunc) result = TInitializeThisValueNumber(irFunc)
or or
exists(Type type, string value | exists(IRType type, string value |
constantValueNumber(instr, irFunc, type, value) and constantValueNumber(instr, irFunc, type, value) and
result = TConstantValueNumber(irFunc, type, value) result = TConstantValueNumber(irFunc, type, value)
) )
or or
exists(Type type, string value | exists(IRType type, string value |
stringConstantValueNumber(instr, irFunc, type, value) and stringConstantValueNumber(instr, irFunc, type, value) and
result = TStringConstantValueNumber(irFunc, type, value) result = TStringConstantValueNumber(irFunc, type, value)
) )
or or
exists(Field field, ValueNumber objectAddress | exists(Language::Field field, ValueNumber objectAddress |
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
result = TFieldAddressValueNumber(irFunc, field, objectAddress) result = TFieldAddressValueNumber(irFunc, field, objectAddress)
) )
or or
exists(Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand | exists(Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand |
binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and
result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand) result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand)
) )
or or
exists(Opcode opcode, Type type, ValueNumber operand | exists(Opcode opcode, IRType type, ValueNumber operand |
unaryValueNumber(instr, irFunc, opcode, type, operand) and unaryValueNumber(instr, irFunc, opcode, type, operand) and
result = TUnaryValueNumber(irFunc, opcode, type, operand) result = TUnaryValueNumber(irFunc, opcode, type, operand)
) )
or or
exists(Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand | exists(
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
|
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand) result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
) )
or or
exists( exists(
Opcode opcode, Type type, int elementSize, ValueNumber leftOperand, ValueNumber rightOperand Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
ValueNumber rightOperand
| |
pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand, pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand,
rightOperand) and rightOperand) and

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.internal.IRCppLanguage as Language

View File

@@ -1,6 +1,6 @@
private import cpp
import AliasAnalysis import AliasAnalysis
import semmle.code.cpp.ir.internal.Overlap import semmle.code.cpp.ir.internal.Overlap
private import semmle.code.cpp.ir.internal.IRCppLanguage as Language
private import semmle.code.cpp.Print private import semmle.code.cpp.Print
private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
@@ -10,31 +10,42 @@ private import semmle.code.cpp.ir.implementation.internal.OperandTag
private class IntValue = Ints::IntValue; private class IntValue = Ints::IntValue;
private predicate hasResultMemoryAccess( private predicate hasResultMemoryAccess(
Instruction instr, IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset Instruction instr, IRVariable var, IRType type, Language::LanguageType languageType,
IntValue startBitOffset, IntValue endBitOffset
) { ) {
resultPointsTo(instr.getResultAddress(), var, startBitOffset) and resultPointsTo(instr.getResultAddress(), var, startBitOffset) and
type = instr.getResultType() and languageType = instr.getResultLanguageType() and
if exists(instr.getResultSize()) type = languageType.getIRType() and
then endBitOffset = Ints::add(startBitOffset, Ints::mul(instr.getResultSize(), 8)) if exists(type.getByteSize())
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
else endBitOffset = Ints::unknown() else endBitOffset = Ints::unknown()
} }
private predicate hasOperandMemoryAccess( private predicate hasOperandMemoryAccess(
MemoryOperand operand, IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset MemoryOperand operand, IRVariable var, IRType type, Language::LanguageType languageType,
IntValue startBitOffset, IntValue endBitOffset
) { ) {
resultPointsTo(operand.getAddressOperand().getAnyDef(), var, startBitOffset) and resultPointsTo(operand.getAddressOperand().getAnyDef(), var, startBitOffset) and
type = operand.getType() and languageType = operand.getLanguageType() and
if exists(operand.getSize()) type = languageType.getIRType() and
then endBitOffset = Ints::add(startBitOffset, Ints::mul(operand.getSize(), 8)) if exists(type.getByteSize())
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
else endBitOffset = Ints::unknown() else endBitOffset = Ints::unknown()
} }
private newtype TMemoryLocation = private newtype TMemoryLocation =
TVariableMemoryLocation(IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset) { TVariableMemoryLocation(
hasResultMemoryAccess(_, var, type, startBitOffset, endBitOffset) or IRVariable var, IRType type, Language::LanguageType languageType, IntValue startBitOffset,
hasOperandMemoryAccess(_, var, type, startBitOffset, endBitOffset) IntValue endBitOffset
) {
(
hasResultMemoryAccess(_, var, type, _, startBitOffset, endBitOffset) or
hasOperandMemoryAccess(_, var, type, _, startBitOffset, endBitOffset)
) and
languageType = type.getCanonicalLanguageType()
} or } or
TUnknownMemoryLocation(IRFunction irFunc) or TUnknownMemoryLocation(IRFunction irFunc) or
TUnknownNonLocalMemoryLocation(IRFunction irFunc) or
TUnknownVirtualVariable(IRFunction irFunc) TUnknownVirtualVariable(IRFunction irFunc)
/** /**
@@ -49,9 +60,11 @@ abstract class MemoryLocation extends TMemoryLocation {
abstract VirtualVariable getVirtualVariable(); abstract VirtualVariable getVirtualVariable();
abstract Type getType(); abstract Language::LanguageType getType();
abstract string getUniqueId(); abstract string getUniqueId();
final IRType getIRType() { result = getType().getIRType() }
} }
abstract class VirtualVariable extends MemoryLocation { } abstract class VirtualVariable extends MemoryLocation { }
@@ -62,20 +75,34 @@ abstract class VirtualVariable extends MemoryLocation { }
*/ */
class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation { class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation {
IRVariable var; IRVariable var;
Type type; IRType type;
Language::LanguageType languageType;
IntValue startBitOffset; IntValue startBitOffset;
IntValue endBitOffset; IntValue endBitOffset;
VariableMemoryLocation() { VariableMemoryLocation() {
this = TVariableMemoryLocation(var, type, startBitOffset, endBitOffset) this = TVariableMemoryLocation(var, type, languageType, startBitOffset, endBitOffset)
} }
final override string toString() { final override string toString() {
result = var.toString() + Interval::getIntervalString(startBitOffset, endBitOffset) + "<" + result = var.toString() + Interval::getIntervalString(startBitOffset, endBitOffset) + "<" +
type.toString() + ">" type.toString() + ", " + languageType.toString() + ">"
} }
final override Type getType() { result = type } final override Language::LanguageType getType() {
if
strictcount(Language::LanguageType accessType |
hasResultMemoryAccess(_, var, type, accessType, startBitOffset, endBitOffset) or
hasOperandMemoryAccess(_, var, type, accessType, startBitOffset, endBitOffset)
) = 1
then
// All of the accesses have the same `LanguageType`, so just use that.
hasResultMemoryAccess(_, var, type, result, startBitOffset, endBitOffset) or
hasOperandMemoryAccess(_, var, type, result, startBitOffset, endBitOffset)
else
// There is no single type for all accesses, so just use the canonical one for this `IRType`.
result = type.getCanonicalLanguageType()
}
final IntValue getStartBitOffset() { result = startBitOffset } final IntValue getStartBitOffset() { result = startBitOffset }
@@ -85,13 +112,14 @@ class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation {
final override string getUniqueId() { final override string getUniqueId() {
result = var.getUniqueId() + Interval::getIntervalString(startBitOffset, endBitOffset) + "<" + result = var.getUniqueId() + Interval::getIntervalString(startBitOffset, endBitOffset) + "<" +
getTypeIdentityString(type) + ">" type.getIdentityString() + ">"
} }
final override VirtualVariable getVirtualVariable() { final override VirtualVariable getVirtualVariable() {
if variableAddressEscapes(var) if variableAddressEscapes(var)
then result = TUnknownVirtualVariable(var.getEnclosingIRFunction()) then result = TUnknownVirtualVariable(var.getEnclosingIRFunction())
else result = TVariableMemoryLocation(var, var.getType(), 0, var.getType().getSize() * 8) else
result = TVariableMemoryLocation(var, var.getIRType(), _, 0, var.getIRType().getByteSize() * 8)
} }
/** /**
@@ -99,7 +127,7 @@ class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation {
*/ */
final predicate coversEntireVariable() { final predicate coversEntireVariable() {
startBitOffset = 0 and startBitOffset = 0 and
endBitOffset = var.getType().getSize() * 8 endBitOffset = var.getIRType().getByteSize() * 8
} }
} }
@@ -111,7 +139,7 @@ class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation {
class VariableVirtualVariable extends VariableMemoryLocation, VirtualVariable { class VariableVirtualVariable extends VariableMemoryLocation, VirtualVariable {
VariableVirtualVariable() { VariableVirtualVariable() {
not variableAddressEscapes(var) and not variableAddressEscapes(var) and
type = var.getType() and type = var.getIRType() and
coversEntireVariable() coversEntireVariable()
} }
} }
@@ -128,11 +156,33 @@ class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation {
final override VirtualVariable getVirtualVariable() { result = TUnknownVirtualVariable(irFunc) } final override VirtualVariable getVirtualVariable() { result = TUnknownVirtualVariable(irFunc) }
final override Type getType() { result instanceof UnknownType } final override Language::LanguageType getType() {
result = any(IRUnknownType type).getCanonicalLanguageType()
}
final override string getUniqueId() { result = "{Unknown}" } final override string getUniqueId() { result = "{Unknown}" }
} }
/**
* An access to memory that is not known to be confined to a specific `IRVariable`, but is known to
* not access memory on the current function's stack frame.
*/
class UnknownNonLocalMemoryLocation extends TUnknownNonLocalMemoryLocation, MemoryLocation {
IRFunction irFunc;
UnknownNonLocalMemoryLocation() { this = TUnknownNonLocalMemoryLocation(irFunc) }
final override string toString() { result = "{UnknownNonLocal}" }
final override VirtualVariable getVirtualVariable() { result = TUnknownVirtualVariable(irFunc) }
final override Language::LanguageType getType() {
result = any(IRUnknownType type).getCanonicalLanguageType()
}
final override string getUniqueId() { result = "{UnknownNonLocal}" }
}
/** /**
* An access to all aliased memory. * An access to all aliased memory.
*/ */
@@ -143,7 +193,9 @@ class UnknownVirtualVariable extends TUnknownVirtualVariable, VirtualVariable {
final override string toString() { result = "{AllAliased}" } final override string toString() { result = "{AllAliased}" }
final override Type getType() { result instanceof UnknownType } final override Language::LanguageType getType() {
result = any(IRUnknownType type).getCanonicalLanguageType()
}
final override string getUniqueId() { result = " " + toString() } final override string getUniqueId() { result = " " + toString() }
@@ -163,6 +215,13 @@ Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
def instanceof UnknownMemoryLocation and def instanceof UnknownMemoryLocation and
result instanceof MayPartiallyOverlap result instanceof MayPartiallyOverlap
or or
// An UnknownNonLocalMemoryLocation may partially overlap any location within the same virtual
// variable, except a local variable.
def.getVirtualVariable() = use.getVirtualVariable() and
def instanceof UnknownNonLocalMemoryLocation and
result instanceof MayPartiallyOverlap and
not use.(VariableMemoryLocation).getVariable() instanceof IRAutomaticVariable
or
exists(VariableMemoryLocation defVariableLocation | exists(VariableMemoryLocation defVariableLocation |
defVariableLocation = def and defVariableLocation = def and
( (
@@ -171,13 +230,20 @@ Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
(use instanceof UnknownMemoryLocation or use instanceof UnknownVirtualVariable) and (use instanceof UnknownMemoryLocation or use instanceof UnknownVirtualVariable) and
result instanceof MayPartiallyOverlap result instanceof MayPartiallyOverlap
or or
// A VariableMemoryLocation that is not a local variable may partially overlap an unknown
// non-local location within the same virtual variable.
def.getVirtualVariable() = use.getVirtualVariable() and
use instanceof UnknownNonLocalMemoryLocation and
result instanceof MayPartiallyOverlap and
not defVariableLocation.getVariable() instanceof IRAutomaticVariable
or
// A VariableMemoryLocation overlaps another location within the same variable based on the relationship // A VariableMemoryLocation overlaps another location within the same variable based on the relationship
// of the two offset intervals. // of the two offset intervals.
exists(Overlap intervalOverlap | exists(Overlap intervalOverlap |
intervalOverlap = getVariableMemoryLocationOverlap(def, use) and intervalOverlap = getVariableMemoryLocationOverlap(def, use) and
if intervalOverlap instanceof MustExactlyOverlap if intervalOverlap instanceof MustExactlyOverlap
then then
if def.getType() = use.getType() if def.getIRType() = use.getIRType()
then then
// The def and use types match, so it's an exact overlap. // The def and use types match, so it's an exact overlap.
result instanceof MustExactlyOverlap result instanceof MustExactlyOverlap
@@ -282,11 +348,11 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
( (
( (
kind.usesAddressOperand() and kind.usesAddressOperand() and
if hasResultMemoryAccess(instr, _, _, _, _) if hasResultMemoryAccess(instr, _, _, _, _, _)
then then
exists(IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset | exists(IRVariable var, IRType type, IntValue startBitOffset, IntValue endBitOffset |
hasResultMemoryAccess(instr, var, type, startBitOffset, endBitOffset) and hasResultMemoryAccess(instr, var, type, _, startBitOffset, endBitOffset) and
result = TVariableMemoryLocation(var, type, startBitOffset, endBitOffset) result = TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset)
) )
else result = TUnknownMemoryLocation(instr.getEnclosingIRFunction()) else result = TUnknownMemoryLocation(instr.getEnclosingIRFunction())
) )
@@ -296,6 +362,9 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
or or
kind instanceof EscapedMayMemoryAccess and kind instanceof EscapedMayMemoryAccess and
result = TUnknownMemoryLocation(instr.getEnclosingIRFunction()) result = TUnknownMemoryLocation(instr.getEnclosingIRFunction())
or
kind instanceof NonLocalMayMemoryAccess and
result = TUnknownNonLocalMemoryLocation(instr.getEnclosingIRFunction())
) )
) )
} }
@@ -306,11 +375,11 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
( (
( (
kind.usesAddressOperand() and kind.usesAddressOperand() and
if hasOperandMemoryAccess(operand, _, _, _, _) if hasOperandMemoryAccess(operand, _, _, _, _, _)
then then
exists(IRVariable var, Type type, IntValue startBitOffset, IntValue endBitOffset | exists(IRVariable var, IRType type, IntValue startBitOffset, IntValue endBitOffset |
hasOperandMemoryAccess(operand, var, type, startBitOffset, endBitOffset) and hasOperandMemoryAccess(operand, var, type, _, startBitOffset, endBitOffset) and
result = TVariableMemoryLocation(var, type, startBitOffset, endBitOffset) result = TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset)
) )
else result = TUnknownMemoryLocation(operand.getEnclosingIRFunction()) else result = TUnknownMemoryLocation(operand.getEnclosingIRFunction())
) )
@@ -320,6 +389,9 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
or or
kind instanceof EscapedMayMemoryAccess and kind instanceof EscapedMayMemoryAccess and
result = TUnknownMemoryLocation(operand.getEnclosingIRFunction()) result = TUnknownMemoryLocation(operand.getEnclosingIRFunction())
or
kind instanceof NonLocalMayMemoryAccess and
result = TUnknownNonLocalMemoryLocation(operand.getEnclosingIRFunction())
) )
) )
} }

View File

@@ -1,2 +1,3 @@
import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind
import semmle.code.cpp.ir.implementation.IRType as IRType
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.implementation.IRType as IRType
import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag
import semmle.code.cpp.ir.internal.IRUtilities as IRUtilities import semmle.code.cpp.ir.internal.IRUtilities as IRUtilities
import semmle.code.cpp.ir.internal.TempVariableTag as TTempVariableTag import semmle.code.cpp.ir.internal.TempVariableTag as TTempVariableTag

View File

@@ -1,4 +1,5 @@
import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind
import semmle.code.cpp.ir.implementation.IRType as IRType
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
import semmle.code.cpp.ir.implementation.Opcode as Opcode import semmle.code.cpp.ir.implementation.Opcode as Opcode
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
import semmle.code.cpp.ir.implementation.IRType as IRType
import semmle.code.cpp.ir.internal.Overlap as Overlap import semmle.code.cpp.ir.internal.Overlap as Overlap
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag

View File

@@ -4,34 +4,52 @@ private import Alias
private import SSAConstruction private import SSAConstruction
private import DebugSSA private import DebugSSA
bindingset[offset]
private string getKeySuffixForOffset(int offset) {
if offset % 2 = 0 then result = "" else result = "_Chi"
}
bindingset[offset]
private int getIndexForOffset(int offset) { result = offset / 2 }
/** /**
* Property provide that dumps the memory access of each result. Useful for debugging SSA * Property provide that dumps the memory access of each result. Useful for debugging SSA
* construction. * construction.
*/ */
class PropertyProvider extends IRPropertyProvider { class PropertyProvider extends IRPropertyProvider {
override string getInstructionProperty(Instruction instruction, string key) { override string getInstructionProperty(Instruction instruction, string key) {
exists(MemoryLocation location | key = "ResultMemoryLocation" and
location = getResultMemoryLocation(instruction) and result = strictconcat(MemoryLocation loc |
( loc = getResultMemoryLocation(instruction)
key = "ResultMemoryLocation" and result = location.toString() |
or loc.toString(), ","
key = "ResultVirtualVariable" and result = location.getVirtualVariable().toString()
) )
)
or or
exists(MemoryLocation location | key = "ResultVirtualVariable" and
location = getOperandMemoryLocation(instruction.getAnOperand()) and result = strictconcat(MemoryLocation loc |
( loc = getResultMemoryLocation(instruction)
key = "OperandMemoryAccess" and result = location.toString() |
or loc.getVirtualVariable().toString(), ","
key = "OperandVirtualVariable" and result = location.getVirtualVariable().toString()
) )
)
or or
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex | key = "OperandMemoryLocation" and
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and result = strictconcat(MemoryLocation loc |
defBlock.getInstruction(defIndex) = instruction and loc = getOperandMemoryLocation(instruction.getAnOperand())
key = "DefinitionRank[" + useLocation.toString() + "]" and |
loc.toString(), ","
)
or
key = "OperandVirtualVariable" and
result = strictconcat(MemoryLocation loc |
loc = getOperandMemoryLocation(instruction.getAnOperand())
|
loc.getVirtualVariable().toString(), ","
)
or
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defOffset |
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defOffset) and
defBlock.getInstruction(getIndexForOffset(defOffset)) = instruction and
key = "DefinitionRank" + getKeySuffixForOffset(defOffset) + "[" + useLocation.toString() + "]" and
result = defRank.toString() result = defRank.toString()
) )
or or
@@ -41,10 +59,11 @@ class PropertyProvider extends IRPropertyProvider {
result = useRank.toString() result = useRank.toString()
) )
or or
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex | exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defOffset |
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and hasDefinitionAtRank(useLocation, _, defBlock, defRank, defOffset) and
defBlock.getInstruction(defIndex) = instruction and defBlock.getInstruction(getIndexForOffset(defOffset)) = instruction and
key = "DefinitionReachesUse[" + useLocation.toString() + "]" and key = "DefinitionReachesUse" + getKeySuffixForOffset(defOffset) + "[" + useLocation.toString()
+ "]" and
result = strictconcat(IRBlock useBlock, int useRank, int useIndex | result = strictconcat(IRBlock useBlock, int useRank, int useIndex |
exists(Instruction useInstruction | exists(Instruction useInstruction |
hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and

View File

@@ -1,8 +1,5 @@
import SSAConstructionInternal import SSAConstructionInternal
private import cpp private import SSAConstructionImports
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.Overlap
private import NewIR private import NewIR
private class OldBlock = Reachability::ReachableBlock; private class OldBlock = Reachability::ReachableBlock;
@@ -18,7 +15,7 @@ private module Cached {
} }
cached cached
predicate functionHasIR(Function func) { predicate functionHasIR(Language::Function func) {
exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func) exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func)
} }
@@ -42,7 +39,7 @@ private module Cached {
not oldInstruction instanceof OldIR::PhiInstruction and not oldInstruction instanceof OldIR::PhiInstruction and
hasChiNode(_, oldInstruction) hasChiNode(_, oldInstruction)
} or } or
Unreached(Function function) { Unreached(Language::Function function) {
exists(OldInstruction oldInstruction | exists(OldInstruction oldInstruction |
function = oldInstruction.getEnclosingFunction() and function = oldInstruction.getEnclosingFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
@@ -50,12 +47,14 @@ private module Cached {
} }
cached cached
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, Type type) { predicate hasTempVariable(
Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
) {
exists(OldIR::IRTempVariable var | exists(OldIR::IRTempVariable var |
var.getEnclosingFunction() = func and var.getEnclosingFunction() = func and
var.getAST() = ast and var.getAST() = ast and
var.getTag() = tag and var.getTag() = tag and
var.getType() = type var.getLanguageType() = type
) )
} }
@@ -135,24 +134,12 @@ private module Cached {
} }
cached cached
Type getInstructionOperandType(Instruction instr, TypedOperandTag tag) { Language::LanguageType getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand | exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand |
oldInstruction = getOldInstruction(instr) and oldInstruction = getOldInstruction(instr) and
oldOperand = oldInstruction.getAnOperand() and oldOperand = oldInstruction.getAnOperand() and
tag = oldOperand.getOperandTag() and tag = oldOperand.getOperandTag() and
result = oldOperand.getType() result = oldOperand.getLanguageType()
)
}
cached
int getInstructionOperandSize(Instruction instr, SideEffectOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::SideEffectOperand oldOperand |
oldInstruction = getOldInstruction(instr) and
oldOperand = oldInstruction.getAnOperand() and
tag = oldOperand.getOperandTag() and
// Only return a result for operands that need an explicit result size.
oldOperand.getType() instanceof UnknownType and
result = oldOperand.getSize()
) )
} }
@@ -196,20 +183,21 @@ private module Cached {
} }
cached cached
Expr getInstructionConvertedResultExpression(Instruction instruction) { Language::Expr getInstructionConvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getConvertedResultExpression() result = getOldInstruction(instruction).getConvertedResultExpression()
} }
cached cached
Expr getInstructionUnconvertedResultExpression(Instruction instruction) { Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getUnconvertedResultExpression() result = getOldInstruction(instruction).getUnconvertedResultExpression()
} }
/** /*
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node, * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are * that node is its successor in the new successor relation, and the Chi node's successors are
* the new instructions generated from the successors of the old instruction * the new instructions generated from the successors of the old instruction
*/ */
cached cached
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
if hasChiNode(_, getOldInstruction(instruction)) if hasChiNode(_, getOldInstruction(instruction))
@@ -252,7 +240,7 @@ private module Cached {
} }
cached cached
Locatable getInstructionAST(Instruction instruction) { Language::AST getInstructionAST(Instruction instruction) {
exists(OldInstruction oldInstruction | exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) instruction = WrappedInstruction(oldInstruction)
or or
@@ -270,29 +258,25 @@ private module Cached {
} }
cached cached
predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) { Language::LanguageType getInstructionResultType(Instruction instruction) {
exists(OldInstruction oldInstruction | exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) and instruction = WrappedInstruction(oldInstruction) and
type = oldInstruction.getResultType() and result = oldInstruction.getResultLanguageType()
if oldInstruction.isGLValue() then isGLValue = true else isGLValue = false
) )
or or
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar | exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
instruction = Chi(oldInstruction) and instruction = Chi(oldInstruction) and
hasChiNode(vvar, oldInstruction) and hasChiNode(vvar, oldInstruction) and
type = vvar.getType() and result = vvar.getType()
isGLValue = false
) )
or or
exists(Alias::MemoryLocation location | exists(Alias::MemoryLocation location |
instruction = Phi(_, location) and instruction = Phi(_, location) and
type = location.getType() and result = location.getType()
isGLValue = false
) )
or or
instruction = Unreached(_) and instruction = Unreached(_) and
type instanceof VoidType and result = Language::getVoidType()
isGLValue = false
} }
cached cached
@@ -338,7 +322,7 @@ private module Cached {
} }
cached cached
Field getInstructionField(Instruction instruction) { Language::Field getInstructionField(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
} }
@@ -348,7 +332,7 @@ private module Cached {
} }
cached cached
Function getInstructionFunction(Instruction instruction) { Language::Function getInstructionFunction(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
} }
@@ -358,19 +342,19 @@ private module Cached {
} }
cached cached
StringLiteral getInstructionStringLiteral(Instruction instruction) { Language::StringLiteral getInstructionStringLiteral(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue() result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue()
} }
cached cached
BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result = getOldInstruction(instruction) result = getOldInstruction(instruction)
.(OldIR::BuiltInOperationInstruction) .(OldIR::BuiltInOperationInstruction)
.getBuiltInOperation() .getBuiltInOperation()
} }
cached cached
Type getInstructionExceptionType(Instruction instruction) { Language::LanguageType getInstructionExceptionType(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType() result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
} }
@@ -380,14 +364,9 @@ private module Cached {
} }
cached cached
int getInstructionResultSize(Instruction instruction) { predicate getInstructionInheritance(
// Only return a result for instructions that needed an explicit result size. Instruction instruction, Language::Class baseClass, Language::Class derivedClass
instruction.getResultType() instanceof UnknownType and ) {
result = getOldInstruction(instruction).getResultSize()
}
cached
predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) {
exists(OldIR::InheritanceConversionInstruction oldInstr | exists(OldIR::InheritanceConversionInstruction oldInstr |
oldInstr = getOldInstruction(instruction) and oldInstr = getOldInstruction(instruction) and
baseClass = oldInstr.getBaseClass() and baseClass = oldInstr.getBaseClass() and

View File

@@ -0,0 +1,3 @@
import semmle.code.cpp.ir.implementation.Opcode
import semmle.code.cpp.ir.implementation.internal.OperandTag
import semmle.code.cpp.ir.internal.Overlap

View File

@@ -2,4 +2,5 @@ import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as OldIR
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import AliasedSSA as Alias import AliasedSSA as Alias

View File

@@ -0,0 +1 @@
import semmle.code.cpp.ir.internal.IRCppLanguage as Language

View File

@@ -2,11 +2,11 @@ private import TIRVariableInternal
private import Imports::TempVariableTag private import Imports::TempVariableTag
newtype TIRVariable = newtype TIRVariable =
TIRUserVariable(Language::Variable var, Language::Type type, Language::Function func) { TIRUserVariable(Language::Variable var, Language::LanguageType type, Language::Function func) {
Construction::hasUserVariable(func, var, type) Construction::hasUserVariable(func, var, type)
} or } or
TIRTempVariable( TIRTempVariable(
Language::Function func, Language::AST ast, TempVariableTag tag, Language::Type type Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
) { ) {
Construction::hasTempVariable(func, ast, tag, type) Construction::hasTempVariable(func, ast, tag, type)
} }

View File

@@ -5,6 +5,7 @@ import IRVariable
import Operand import Operand
private import internal.IRImports as Imports private import internal.IRImports as Imports
import Imports::EdgeKind import Imports::EdgeKind
import Imports::IRType
import Imports::MemoryAccessKind import Imports::MemoryAccessKind
private newtype TIRPropertyProvider = MkIRPropertyProvider() private newtype TIRPropertyProvider = MkIRPropertyProvider()

View File

@@ -1,2 +1,3 @@
private import IR private import IR
import InstructionSanity import InstructionSanity
import IRTypeSanity

View File

@@ -5,6 +5,7 @@ import Imports::TempVariableTag
private import Imports::IRUtilities private import Imports::IRUtilities
private import Imports::TTempVariableTag private import Imports::TTempVariableTag
private import Imports::TIRVariable private import Imports::TIRVariable
private import Imports::IRType
IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) {
result.getVariable() = var and result.getVariable() = var and
@@ -24,7 +25,17 @@ abstract class IRVariable extends TIRVariable {
/** /**
* Gets the type of the variable. * Gets the type of the variable.
*/ */
abstract Language::Type getType(); final Language::Type getType() { getLanguageType().hasType(result, false) }
/**
* Gets the language-neutral type of the variable.
*/
final IRType getIRType() { result = getLanguageType().getIRType() }
/**
* Gets the type of the variable.
*/
abstract Language::LanguageType getLanguageType();
/** /**
* Gets the AST node that declared this variable, or that introduced this * Gets the AST node that declared this variable, or that introduced this
@@ -59,7 +70,7 @@ abstract class IRVariable extends TIRVariable {
*/ */
class IRUserVariable extends IRVariable, TIRUserVariable { class IRUserVariable extends IRVariable, TIRUserVariable {
Language::Variable var; Language::Variable var;
Language::Type type; Language::LanguageType type;
IRUserVariable() { this = TIRUserVariable(var, type, func) } IRUserVariable() { this = TIRUserVariable(var, type, func) }
@@ -71,7 +82,7 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
result = getVariable().toString() + " " + getVariable().getLocation().toString() result = getVariable().toString() + " " + getVariable().getLocation().toString()
} }
final override Language::Type getType() { result = type } final override Language::LanguageType getLanguageType() { result = type }
/** /**
* Gets the original user-declared variable. * Gets the original user-declared variable.
@@ -110,11 +121,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable { class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
Language::AST ast; Language::AST ast;
TempVariableTag tag; TempVariableTag tag;
Language::Type type; Language::LanguageType type;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) } IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
final override Language::Type getType() { result = type } final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast } final override Language::AST getAST() { result = ast }

View File

@@ -5,6 +5,7 @@ import IRVariable
import Operand import Operand
private import internal.InstructionImports as Imports private import internal.InstructionImports as Imports
import Imports::EdgeKind import Imports::EdgeKind
import Imports::IRType
import Imports::MemoryAccessKind import Imports::MemoryAccessKind
import Imports::Opcode import Imports::Opcode
private import Imports::OperandTag private import Imports::OperandTag
@@ -49,7 +50,8 @@ module InstructionSanity {
( (
opcode instanceof ReadSideEffectOpcode or opcode instanceof ReadSideEffectOpcode or
opcode instanceof Opcode::InlineAsm or opcode instanceof Opcode::InlineAsm or
opcode instanceof Opcode::CallSideEffect opcode instanceof Opcode::CallSideEffect or
opcode instanceof Opcode::AliasedUse
) and ) and
tag instanceof SideEffectOperandTag tag instanceof SideEffectOperandTag
) )
@@ -113,10 +115,12 @@ module InstructionSanity {
} }
query predicate missingOperandType(Operand operand, string message) { query predicate missingOperandType(Operand operand, string message) {
exists(Language::Function func | exists(Language::Function func, Instruction use |
not exists(operand.getType()) and not exists(operand.getType()) and
func = operand.getUse().getEnclosingFunction() and use = operand.getUse() and
message = "Operand missing type in function '" + Language::getIdentityString(func) + "'." func = use.getEnclosingFunction() and
message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString()
+ "' missing type in function '" + Language::getIdentityString(func) + "'."
) )
} }
@@ -260,6 +264,7 @@ module InstructionSanity {
) { ) {
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
not useOperand.getUse() instanceof UnmodeledUseInstruction and not useOperand.getUse() instanceof UnmodeledUseInstruction and
not defInstr instanceof UnmodeledDefinitionInstruction and
pointOfEvaluation(useOperand, useBlock, useIndex) and pointOfEvaluation(useOperand, useBlock, useIndex) and
defInstr = useOperand.getAnyDef() and defInstr = useOperand.getAnyDef() and
( (
@@ -321,7 +326,7 @@ class Instruction extends Construction::TInstruction {
} }
private string getResultPrefix() { private string getResultPrefix() {
if getResultType() instanceof Language::VoidType if getResultIRType() instanceof IRVoidType
then result = "v" then result = "v"
else else
if hasMemoryResult() if hasMemoryResult()
@@ -353,23 +358,6 @@ class Instruction extends Construction::TInstruction {
) )
} }
bindingset[type]
private string getValueCategoryString(string type) {
if isGLValue() then result = "glval<" + type + ">" else result = type
}
string getResultTypeString() {
exists(string valcat |
valcat = getValueCategoryString(getResultType().toString()) and
if
getResultType() instanceof Language::UnknownType and
not isGLValue() and
exists(getResultSize())
then result = valcat + "[" + getResultSize().toString() + "]"
else result = valcat
)
}
/** /**
* Gets a human-readable string that uniquely identifies this instruction * Gets a human-readable string that uniquely identifies this instruction
* within the function. This string is used to refer to this instruction when * within the function. This string is used to refer to this instruction when
@@ -389,7 +377,9 @@ class Instruction extends Construction::TInstruction {
* *
* Example: `r1_1(int*)` * Example: `r1_1(int*)`
*/ */
final string getResultString() { result = getResultId() + "(" + getResultTypeString() + ")" } final string getResultString() {
result = getResultId() + "(" + getResultLanguageType().getDumpString() + ")"
}
/** /**
* Gets a string describing the operands of this instruction, suitable for * Gets a string describing the operands of this instruction, suitable for
@@ -457,6 +447,16 @@ class Instruction extends Construction::TInstruction {
result = Construction::getInstructionUnconvertedResultExpression(this) result = Construction::getInstructionUnconvertedResultExpression(this)
} }
final Language::LanguageType getResultLanguageType() {
result = Construction::getInstructionResultType(this)
}
/**
* Gets the type of the result produced by this instruction. If the instruction does not produce
* a result, its result type will be `IRVoidType`.
*/
final IRType getResultIRType() { result = getResultLanguageType().getIRType() }
/** /**
* Gets the type of the result produced by this instruction. If the * Gets the type of the result produced by this instruction. If the
* instruction does not produce a result, its result type will be `VoidType`. * instruction does not produce a result, its result type will be `VoidType`.
@@ -464,7 +464,16 @@ class Instruction extends Construction::TInstruction {
* If `isGLValue()` holds, then the result type of this instruction should be * If `isGLValue()` holds, then the result type of this instruction should be
* thought of as "pointer to `getResultType()`". * thought of as "pointer to `getResultType()`".
*/ */
final Language::Type getResultType() { Construction::instructionHasType(this, result, _) } final Language::Type getResultType() {
exists(Language::LanguageType resultType |
resultType = getResultLanguageType() and
(
resultType.hasUnspecifiedType(result, _)
or
not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType
)
)
}
/** /**
* Holds if the result produced by this instruction is a glvalue. If this * Holds if the result produced by this instruction is a glvalue. If this
@@ -484,7 +493,7 @@ class Instruction extends Construction::TInstruction {
* result of the `Load` instruction is a prvalue of type `int`, representing * result of the `Load` instruction is a prvalue of type `int`, representing
* the integer value loaded from variable `x`. * the integer value loaded from variable `x`.
*/ */
final predicate isGLValue() { Construction::instructionHasType(this, _, true) } final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) }
/** /**
* Gets the size of the result produced by this instruction, in bytes. If the * Gets the size of the result produced by this instruction, in bytes. If the
@@ -493,16 +502,7 @@ class Instruction extends Construction::TInstruction {
* If `this.isGLValue()` holds for this instruction, the value of * If `this.isGLValue()` holds for this instruction, the value of
* `getResultSize()` will always be the size of a pointer. * `getResultSize()` will always be the size of a pointer.
*/ */
final int getResultSize() { final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() }
if isGLValue()
then
// a glvalue is always pointer-sized.
result = Language::getPointerSize()
else
if getResultType() instanceof Language::UnknownType
then result = Construction::getInstructionResultSize(this)
else result = Language::getTypeSize(getResultType())
}
/** /**
* Gets the opcode that specifies the operation performed by this instruction. * Gets the opcode that specifies the operation performed by this instruction.
@@ -1384,7 +1384,7 @@ class CatchInstruction extends Instruction {
* An instruction that catches an exception of a specific type. * An instruction that catches an exception of a specific type.
*/ */
class CatchByTypeInstruction extends CatchInstruction { class CatchByTypeInstruction extends CatchInstruction {
Language::Type exceptionType; Language::LanguageType exceptionType;
CatchByTypeInstruction() { CatchByTypeInstruction() {
getOpcode() instanceof Opcode::CatchByType and getOpcode() instanceof Opcode::CatchByType and
@@ -1396,7 +1396,7 @@ class CatchByTypeInstruction extends CatchInstruction {
/** /**
* Gets the type of exception to be caught. * Gets the type of exception to be caught.
*/ */
final Language::Type getExceptionType() { result = exceptionType } final Language::LanguageType getExceptionType() { result = exceptionType }
} }
/** /**
@@ -1423,6 +1423,13 @@ class AliasedDefinitionInstruction extends Instruction {
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess } final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
} }
/**
* An instruction that consumes all escaped memory on exit from the function.
*/
class AliasedUseInstruction extends Instruction {
AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse }
}
class UnmodeledUseInstruction extends Instruction { class UnmodeledUseInstruction extends Instruction {
UnmodeledUseInstruction() { getOpcode() instanceof Opcode::UnmodeledUse } UnmodeledUseInstruction() { getOpcode() instanceof Opcode::UnmodeledUse }

View File

@@ -1,9 +1,10 @@
private import internal.IRInternal private import internal.IRInternal
import Instruction private import Instruction
import IRBlock private import IRBlock
private import internal.OperandImports as Imports private import internal.OperandImports as Imports
import Imports::MemoryAccessKind private import Imports::MemoryAccessKind
import Imports::Overlap private import Imports::IRType
private import Imports::Overlap
private import Imports::OperandTag private import Imports::OperandTag
cached cached
@@ -143,22 +144,40 @@ class Operand extends TOperand {
* the definition type, such as in the case of a partial read or a read from a pointer that * the definition type, such as in the case of a partial read or a read from a pointer that
* has been cast to a different type. * has been cast to a different type.
*/ */
Language::Type getType() { result = getAnyDef().getResultType() } Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() }
/**
* Gets the language-neutral type of the value consumed by this operand. This is usually the same
* as the result type of the definition instruction consumed by this operand. For register
* operands, this is always the case. For some memory operands, the operand type may be different
* from the definition type, such as in the case of a partial read or a read from a pointer that
* has been cast to a different type.
*/
final IRType getIRType() { result = getLanguageType().getIRType() }
/**
* Gets the type of the value consumed by this operand. This is usually the same as the
* result type of the definition instruction consumed by this operand. For register operands,
* this is always the case. For some memory operands, the operand type may be different from
* the definition type, such as in the case of a partial read or a read from a pointer that
* has been cast to a different type.
*/
final Language::Type getType() { getLanguageType().hasType(result, _) }
/** /**
* Holds if the value consumed by this operand is a glvalue. If this * Holds if the value consumed by this operand is a glvalue. If this
* holds, the value of the operand represents the address of a location, * holds, the value of the operand represents the address of a location,
* and the type of the location is given by `getType()`. If this does * and the type of the location is given by `getType()`. If this does
* not hold, the value of the operand represents a value whose type is * not hold, the value of the operand represents a value whose type is
* given by `getResultType()`. * given by `getType()`.
*/ */
predicate isGLValue() { getAnyDef().isGLValue() } final predicate isGLValue() { getLanguageType().hasType(_, true) }
/** /**
* Gets the size of the value consumed by this operand, in bytes. If the operand does not have * Gets the size of the value consumed by this operand, in bytes. If the operand does not have
* a known constant size, this predicate does not hold. * a known constant size, this predicate does not hold.
*/ */
int getSize() { result = Language::getTypeSize(getType()) } final int getSize() { result = getLanguageType().getByteSize() }
} }
/** /**
@@ -170,11 +189,6 @@ class MemoryOperand extends Operand {
this = TPhiOperand(_, _, _, _) this = TPhiOperand(_, _, _, _)
} }
override predicate isGLValue() {
// A `MemoryOperand` can never be a glvalue
none()
}
/** /**
* Gets the kind of memory access performed by the operand. * Gets the kind of memory access performed by the operand.
*/ */
@@ -239,7 +253,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
class TypedOperand extends NonPhiMemoryOperand { class TypedOperand extends NonPhiMemoryOperand {
override TypedOperandTag tag; override TypedOperandTag tag;
final override Language::Type getType() { final override Language::LanguageType getLanguageType() {
result = Construction::getInstructionOperandType(useInstr, tag) result = Construction::getInstructionOperandType(useInstr, tag)
} }
} }
@@ -381,13 +395,10 @@ class PositionalArgumentOperand extends ArgumentOperand {
class SideEffectOperand extends TypedOperand { class SideEffectOperand extends TypedOperand {
override SideEffectOperandTag tag; override SideEffectOperandTag tag;
final override int getSize() {
if getType() instanceof Language::UnknownType
then result = Construction::getInstructionOperandSize(useInstr, tag)
else result = Language::getTypeSize(getType())
}
override MemoryAccessKind getMemoryAccess() { override MemoryAccessKind getMemoryAccess() {
useInstr instanceof AliasedUseInstruction and
result instanceof NonLocalMayMemoryAccess
or
useInstr instanceof CallSideEffectInstruction and useInstr instanceof CallSideEffectInstruction and
result instanceof EscapedMayMemoryAccess result instanceof EscapedMayMemoryAccess
or or

View File

@@ -1,5 +1,5 @@
private import internal.ValueNumberingInternal private import internal.ValueNumberingInternal
private import cpp private import internal.ValueNumberingImports
private import IR private import IR
/** /**
@@ -23,31 +23,32 @@ newtype TValueNumber =
initializeParameterValueNumber(_, irFunc, var) initializeParameterValueNumber(_, irFunc, var)
} or } or
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
TConstantValueNumber(IRFunction irFunc, Type type, string value) { TConstantValueNumber(IRFunction irFunc, IRType type, string value) {
constantValueNumber(_, irFunc, type, value) constantValueNumber(_, irFunc, type, value)
} or } or
TStringConstantValueNumber(IRFunction irFunc, Type type, string value) { TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
stringConstantValueNumber(_, irFunc, type, value) stringConstantValueNumber(_, irFunc, type, value)
} or } or
TFieldAddressValueNumber(IRFunction irFunc, Field field, ValueNumber objectAddress) { TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, ValueNumber objectAddress) {
fieldAddressValueNumber(_, irFunc, field, objectAddress) fieldAddressValueNumber(_, irFunc, field, objectAddress)
} or } or
TBinaryValueNumber( TBinaryValueNumber(
IRFunction irFunc, Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand
) { ) {
binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand) binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand)
} or } or
TPointerArithmeticValueNumber( TPointerArithmeticValueNumber(
IRFunction irFunc, Opcode opcode, Type type, int elementSize, ValueNumber leftOperand, IRFunction irFunc, Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
ValueNumber rightOperand ValueNumber rightOperand
) { ) {
pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand) pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand)
} or } or
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, Type type, ValueNumber operand) { TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand) {
unaryValueNumber(_, irFunc, opcode, type, operand) unaryValueNumber(_, irFunc, opcode, type, operand)
} or } or
TInheritanceConversionValueNumber( TInheritanceConversionValueNumber(
IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass,
ValueNumber operand
) { ) {
inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand) inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
} or } or
@@ -59,7 +60,7 @@ newtype TValueNumber =
class ValueNumber extends TValueNumber { class ValueNumber extends TValueNumber {
final string toString() { result = getExampleInstruction().getResultId() } final string toString() { result = getExampleInstruction().getResultId() }
final Location getLocation() { result = getExampleInstruction().getLocation() } final Language::Location getLocation() { result = getExampleInstruction().getLocation() }
/** /**
* Gets the instructions that have been assigned this value number. This will always produce at * Gets the instructions that have been assigned this value number. This will always produce at
@@ -150,23 +151,23 @@ private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRF
} }
private predicate constantValueNumber( private predicate constantValueNumber(
ConstantInstruction instr, IRFunction irFunc, Type type, string value ConstantInstruction instr, IRFunction irFunc, IRType type, string value
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
instr.getResultType() = type and instr.getResultIRType() = type and
instr.getValue() = value instr.getValue() = value
} }
private predicate stringConstantValueNumber( private predicate stringConstantValueNumber(
StringConstantInstruction instr, IRFunction irFunc, Type type, string value StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
instr.getResultType() = type and instr.getResultIRType() = type and
instr.getValue().getValue() = value instr.getValue().getValue() = value
} }
private predicate fieldAddressValueNumber( private predicate fieldAddressValueNumber(
FieldAddressInstruction instr, IRFunction irFunc, Field field, ValueNumber objectAddress FieldAddressInstruction instr, IRFunction irFunc, Language::Field field, ValueNumber objectAddress
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
instr.getField() = field and instr.getField() = field and
@@ -174,43 +175,43 @@ private predicate fieldAddressValueNumber(
} }
private predicate binaryValueNumber( private predicate binaryValueNumber(
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, Type type, ValueNumber leftOperand, BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand,
ValueNumber rightOperand ValueNumber rightOperand
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
not instr instanceof PointerArithmeticInstruction and not instr instanceof PointerArithmeticInstruction and
instr.getOpcode() = opcode and instr.getOpcode() = opcode and
instr.getResultType() = type and instr.getResultIRType() = type and
valueNumber(instr.getLeft()) = leftOperand and valueNumber(instr.getLeft()) = leftOperand and
valueNumber(instr.getRight()) = rightOperand valueNumber(instr.getRight()) = rightOperand
} }
private predicate pointerArithmeticValueNumber( private predicate pointerArithmeticValueNumber(
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, Type type, int elementSize, PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type,
ValueNumber leftOperand, ValueNumber rightOperand int elementSize, ValueNumber leftOperand, ValueNumber rightOperand
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
instr.getOpcode() = opcode and instr.getOpcode() = opcode and
instr.getResultType() = type and instr.getResultIRType() = type and
instr.getElementSize() = elementSize and instr.getElementSize() = elementSize and
valueNumber(instr.getLeft()) = leftOperand and valueNumber(instr.getLeft()) = leftOperand and
valueNumber(instr.getRight()) = rightOperand valueNumber(instr.getRight()) = rightOperand
} }
private predicate unaryValueNumber( private predicate unaryValueNumber(
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, Type type, ValueNumber operand UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
not instr instanceof InheritanceConversionInstruction and not instr instanceof InheritanceConversionInstruction and
not instr instanceof CopyInstruction and not instr instanceof CopyInstruction and
instr.getOpcode() = opcode and instr.getOpcode() = opcode and
instr.getResultType() = type and instr.getResultIRType() = type and
valueNumber(instr.getUnary()) = operand valueNumber(instr.getUnary()) = operand
} }
private predicate inheritanceConversionValueNumber( private predicate inheritanceConversionValueNumber(
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode, Class baseClass, InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
Class derivedClass, ValueNumber operand Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
instr.getOpcode() = opcode and instr.getOpcode() = opcode and
@@ -225,7 +226,7 @@ private predicate inheritanceConversionValueNumber(
*/ */
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) { private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
not instr.getResultType() instanceof VoidType and not instr.getResultIRType() instanceof IRVoidType and
not numberableInstruction(instr) not numberableInstruction(instr)
} }
@@ -269,38 +270,41 @@ private ValueNumber nonUniqueValueNumber(Instruction instr) {
initializeThisValueNumber(instr, irFunc) and initializeThisValueNumber(instr, irFunc) and
result = TInitializeThisValueNumber(irFunc) result = TInitializeThisValueNumber(irFunc)
or or
exists(Type type, string value | exists(IRType type, string value |
constantValueNumber(instr, irFunc, type, value) and constantValueNumber(instr, irFunc, type, value) and
result = TConstantValueNumber(irFunc, type, value) result = TConstantValueNumber(irFunc, type, value)
) )
or or
exists(Type type, string value | exists(IRType type, string value |
stringConstantValueNumber(instr, irFunc, type, value) and stringConstantValueNumber(instr, irFunc, type, value) and
result = TStringConstantValueNumber(irFunc, type, value) result = TStringConstantValueNumber(irFunc, type, value)
) )
or or
exists(Field field, ValueNumber objectAddress | exists(Language::Field field, ValueNumber objectAddress |
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
result = TFieldAddressValueNumber(irFunc, field, objectAddress) result = TFieldAddressValueNumber(irFunc, field, objectAddress)
) )
or or
exists(Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand | exists(Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand |
binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and
result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand) result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand)
) )
or or
exists(Opcode opcode, Type type, ValueNumber operand | exists(Opcode opcode, IRType type, ValueNumber operand |
unaryValueNumber(instr, irFunc, opcode, type, operand) and unaryValueNumber(instr, irFunc, opcode, type, operand) and
result = TUnaryValueNumber(irFunc, opcode, type, operand) result = TUnaryValueNumber(irFunc, opcode, type, operand)
) )
or or
exists(Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand | exists(
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
|
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand) result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
) )
or or
exists( exists(
Opcode opcode, Type type, int elementSize, ValueNumber leftOperand, ValueNumber rightOperand Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
ValueNumber rightOperand
| |
pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand, pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand,
rightOperand) and rightOperand) and

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.internal.IRCppLanguage as Language

View File

@@ -1,6 +1,8 @@
private import cpp private import cpp
import semmle.code.cpp.ir.implementation.raw.IR import semmle.code.cpp.ir.implementation.raw.IR
private import semmle.code.cpp.ir.implementation.internal.OperandTag private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.CppType
private import semmle.code.cpp.ir.internal.Overlap
private import semmle.code.cpp.ir.internal.TempVariableTag private import semmle.code.cpp.ir.internal.TempVariableTag
private import InstructionTag private import InstructionTag
private import TranslatedCondition private import TranslatedCondition
@@ -25,16 +27,16 @@ private module Cached {
cached cached
newtype TInstruction = newtype TInstruction =
MkInstruction(TranslatedElement element, InstructionTag tag) { MkInstruction(TranslatedElement element, InstructionTag tag) {
element.hasInstruction(_, tag, _, _) element.hasInstruction(_, tag, _)
} }
cached cached
predicate hasUserVariable(Function func, Variable var, Type type) { predicate hasUserVariable(Function func, Variable var, CppType type) {
getTranslatedFunction(func).hasUserVariable(var, type) getTranslatedFunction(func).hasUserVariable(var, type)
} }
cached cached
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, Type type) { predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, CppType type) {
exists(TranslatedElement element | exists(TranslatedElement element |
element.getAST() = ast and element.getAST() = ast and
func = element.getFunction() and func = element.getFunction() and
@@ -85,22 +87,16 @@ private module Cached {
} }
cached cached
Type getInstructionOperandType(Instruction instruction, TypedOperandTag tag) { CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) {
// For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as // For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as
// the result type of the load. // the result type of the load.
result = instruction.(LoadInstruction).getResultType() result = instruction.(LoadInstruction).getResultLanguageType()
or or
not instruction instanceof LoadInstruction and not instruction instanceof LoadInstruction and
result = getInstructionTranslatedElement(instruction) result = getInstructionTranslatedElement(instruction)
.getInstructionOperandType(getInstructionTag(instruction), tag) .getInstructionOperandType(getInstructionTag(instruction), tag)
} }
cached
int getInstructionOperandSize(Instruction instruction, SideEffectOperandTag tag) {
result = getInstructionTranslatedElement(instruction)
.getInstructionOperandSize(getInstructionTag(instruction), tag)
}
cached cached
Instruction getPhiOperandDefinition( Instruction getPhiOperandDefinition(
PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap
@@ -220,15 +216,15 @@ private module Cached {
} }
cached cached
predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) { CppType getInstructionResultType(Instruction instruction) {
getInstructionTranslatedElement(instruction) getInstructionTranslatedElement(instruction)
.hasInstruction(_, getInstructionTag(instruction), type, isGLValue) .hasInstruction(_, getInstructionTag(instruction), result)
} }
cached cached
Opcode getInstructionOpcode(Instruction instruction) { Opcode getInstructionOpcode(Instruction instruction) {
getInstructionTranslatedElement(instruction) getInstructionTranslatedElement(instruction)
.hasInstruction(result, getInstructionTag(instruction), _, _) .hasInstruction(result, getInstructionTag(instruction), _)
} }
cached cached
@@ -283,7 +279,7 @@ private module Cached {
} }
cached cached
Type getInstructionExceptionType(Instruction instruction) { CppType getInstructionExceptionType(Instruction instruction) {
result = getInstructionTranslatedElement(instruction) result = getInstructionTranslatedElement(instruction)
.getInstructionExceptionType(getInstructionTag(instruction)) .getInstructionExceptionType(getInstructionTag(instruction))
} }
@@ -310,6 +306,11 @@ private module Cached {
) )
} }
cached
predicate needsUnknownOpaqueType(int byteSize) {
exists(TranslatedElement element | element.needsUnknownOpaqueType(byteSize))
}
cached cached
int getInstructionResultSize(Instruction instruction) { int getInstructionResultSize(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag | exists(TranslatedElement element, InstructionTag tag |

View File

@@ -1,2 +1,3 @@
import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind
import semmle.code.cpp.ir.implementation.IRType as IRType
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.implementation.IRType as IRType
import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag
import semmle.code.cpp.ir.internal.IRUtilities as IRUtilities import semmle.code.cpp.ir.internal.IRUtilities as IRUtilities
import semmle.code.cpp.ir.internal.TempVariableTag as TTempVariableTag import semmle.code.cpp.ir.internal.TempVariableTag as TTempVariableTag

View File

@@ -1,4 +1,5 @@
import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind
import semmle.code.cpp.ir.implementation.IRType as IRType
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
import semmle.code.cpp.ir.implementation.Opcode as Opcode import semmle.code.cpp.ir.implementation.Opcode as Opcode
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag

View File

@@ -26,6 +26,7 @@ newtype TInstructionTag =
UnmodeledDefinitionTag() or UnmodeledDefinitionTag() or
UnmodeledUseTag() or UnmodeledUseTag() or
AliasedDefinitionTag() or AliasedDefinitionTag() or
AliasedUseTag() or
SwitchBranchTag() or SwitchBranchTag() or
CallTargetTag() or CallTargetTag() or
CallTag() or CallTag() or
@@ -119,6 +120,8 @@ string getInstructionTagId(TInstructionTag tag) {
or or
tag = AliasedDefinitionTag() and result = "AliasedDef" tag = AliasedDefinitionTag() and result = "AliasedDef"
or or
tag = AliasedUseTag() and result = "AliasedUse"
or
tag = SwitchBranchTag() and result = "SwitchBranch" tag = SwitchBranchTag() and result = "SwitchBranch"
or or
tag = CallTargetTag() and result = "CallTarget" tag = CallTargetTag() and result = "CallTarget"

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
import semmle.code.cpp.ir.implementation.IRType as IRType
import semmle.code.cpp.ir.internal.Overlap as Overlap import semmle.code.cpp.ir.internal.Overlap as Overlap
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag

View File

@@ -1,6 +1,7 @@
private import cpp private import cpp
private import semmle.code.cpp.ir.implementation.Opcode private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.internal.OperandTag private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.CppType
private import semmle.code.cpp.models.interfaces.SideEffect private import semmle.code.cpp.models.interfaces.SideEffect
private import InstructionTag private import InstructionTag
private import TranslatedElement private import TranslatedElement
@@ -33,13 +34,10 @@ abstract class TranslatedCall extends TranslatedExpr {
else result = getFirstCallTargetInstruction() else result = getFirstCallTargetInstruction()
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = CallTag() and tag = CallTag() and
opcode instanceof Opcode::Call and opcode instanceof Opcode::Call and
resultType = getCallResultType() and resultType = getTypeForPRValue(getCallResultType())
isGLValue = false
or or
hasSideEffect() and hasSideEffect() and
tag = CallSideEffectTag() and tag = CallSideEffectTag() and
@@ -47,13 +45,12 @@ abstract class TranslatedCall extends TranslatedExpr {
if hasWriteSideEffect() if hasWriteSideEffect()
then ( then (
opcode instanceof Opcode::CallSideEffect and opcode instanceof Opcode::CallSideEffect and
resultType instanceof UnknownType resultType = getUnknownType()
) else ( ) else (
opcode instanceof Opcode::CallReadSideEffect and opcode instanceof Opcode::CallReadSideEffect and
resultType instanceof VoidType resultType = getVoidType()
) )
) and )
isGLValue = false
} }
override Instruction getChildSuccessor(TranslatedElement child) { override Instruction getChildSuccessor(TranslatedElement child) {
@@ -118,11 +115,11 @@ abstract class TranslatedCall extends TranslatedExpr {
result = getEnclosingFunction().getUnmodeledDefinitionInstruction() result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
} }
final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
tag = CallSideEffectTag() and tag = CallSideEffectTag() and
hasSideEffect() and hasSideEffect() and
operandTag instanceof SideEffectOperandTag and operandTag instanceof SideEffectOperandTag and
result instanceof UnknownType result = getUnknownType()
} }
final override Instruction getResult() { result = getInstruction(CallTag()) } final override Instruction getResult() { result = getInstruction(CallTag()) }
@@ -224,18 +221,12 @@ abstract class TranslatedDirectCall extends TranslatedCall {
final override Instruction getCallTargetResult() { result = getInstruction(CallTargetTag()) } final override Instruction getCallTargetResult() { result = getInstruction(CallTargetTag()) }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue TranslatedCall.super.hasInstruction(opcode, tag, resultType)
) {
TranslatedCall.super.hasInstruction(opcode, tag, resultType, isGLValue)
or or
tag = CallTargetTag() and tag = CallTargetTag() and
opcode instanceof Opcode::FunctionAddress and opcode instanceof Opcode::FunctionAddress and
// The database does not contain a `FunctionType` for a function unless resultType = getFunctionGLValueType()
// its address was taken, so we'll just use glval<Unknown> instead of
// glval<FunctionType>.
resultType instanceof UnknownType and
isGLValue = true
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -253,7 +244,7 @@ abstract class TranslatedDirectCall extends TranslatedCall {
abstract class TranslatedCallExpr extends TranslatedNonConstantExpr, TranslatedCall { abstract class TranslatedCallExpr extends TranslatedNonConstantExpr, TranslatedCall {
override Call expr; override Call expr;
final override Type getCallResultType() { result = getResultType() } final override Type getCallResultType() { result = expr.getType() }
final override predicate hasArguments() { exists(expr.getArgument(0)) } final override predicate hasArguments() { exists(expr.getArgument(0)) }
@@ -349,9 +340,7 @@ class TranslatedSideEffects extends TranslatedElement, TTranslatedSideEffects {
) )
} }
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type t, boolean isGLValue) { override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) { none() }
none()
}
override Instruction getFirstInstruction() { result = getChild(0).getFirstInstruction() } override Instruction getFirstInstruction() { result = getChild(0).getFirstInstruction() }
@@ -359,7 +348,9 @@ class TranslatedSideEffects extends TranslatedElement, TTranslatedSideEffects {
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() }
override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() } override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
none()
}
/** /**
* Gets the `TranslatedFunction` containing this expression. * Gets the `TranslatedFunction` containing this expression.
@@ -406,34 +397,30 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff
override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type t, boolean isGLValue) { override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) {
isWrite() and isWrite() and
hasSpecificWriteSideEffect(opcode) and hasSpecificWriteSideEffect(opcode) and
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
( (
opcode instanceof BufferAccessOpcode and opcode instanceof BufferAccessOpcode and
t instanceof UnknownType type = getUnknownType()
or or
not opcode instanceof BufferAccessOpcode and not opcode instanceof BufferAccessOpcode and
( exists(Type baseType | baseType = arg.getUnspecifiedType().(DerivedType).getBaseType() |
t = arg.getUnspecifiedType().(DerivedType).getBaseType() and if baseType instanceof VoidType
not t instanceof VoidType then type = getUnknownType()
or else type = getTypeForPRValueOrUnknown(baseType)
arg.getUnspecifiedType().(DerivedType).getBaseType() instanceof VoidType and
t instanceof UnknownType
) )
or or
index = -1 and index = -1 and
not arg.getUnspecifiedType() instanceof DerivedType and not arg.getUnspecifiedType() instanceof DerivedType and
t = arg.getUnspecifiedType() type = getTypeForPRValueOrUnknown(arg.getUnspecifiedType())
) and )
isGLValue = false
or or
not isWrite() and not isWrite() and
hasSpecificReadSideEffect(opcode) and hasSpecificReadSideEffect(opcode) and
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
t instanceof VoidType and type = getVoidType()
isGLValue = false
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -459,15 +446,27 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff
.getFullyConverted()).getResult() .getFullyConverted()).getResult()
} }
override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
tag instanceof OnlyInstructionTag and if hasSpecificReadSideEffect(any(Opcode::BufferReadSideEffect op))
result = arg.getType().getUnspecifiedType().(DerivedType).getBaseType() and then
operandTag instanceof SideEffectOperandTag result = getUnknownType() and
or tag instanceof OnlyInstructionTag and
tag instanceof OnlyInstructionTag and operandTag instanceof SideEffectOperandTag
result = arg.getType().getUnspecifiedType() and else
not result instanceof DerivedType and exists(Type operandType |
operandTag instanceof SideEffectOperandTag tag instanceof OnlyInstructionTag and
operandType = arg.getType().getUnspecifiedType().(DerivedType).getBaseType() and
operandTag instanceof SideEffectOperandTag
or
tag instanceof OnlyInstructionTag and
operandType = arg.getType().getUnspecifiedType() and
not operandType instanceof DerivedType and
operandTag instanceof SideEffectOperandTag
|
// If the type we select is an incomplete type (e.g. a forward-declared `struct`), there will
// not be a `CppType` that represents that type. In that case, fall back to `UnknownCppType`.
result = getTypeForPRValueOrUnknown(operandType)
)
} }
predicate hasSpecificWriteSideEffect(Opcode op) { predicate hasSpecificWriteSideEffect(Opcode op) {
@@ -517,7 +516,7 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff
) )
or or
not call.getTarget() instanceof SideEffectFunction and not call.getTarget() instanceof SideEffectFunction and
op instanceof Opcode::IndirectReadSideEffect op instanceof Opcode::BufferReadSideEffect
} }
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) { override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {

View File

@@ -1,6 +1,7 @@
private import cpp private import cpp
private import semmle.code.cpp.ir.implementation.Opcode private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.internal.OperandTag private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.CppType
private import InstructionTag private import InstructionTag
private import TranslatedElement private import TranslatedElement
private import TranslatedExpr private import TranslatedExpr
@@ -37,9 +38,7 @@ abstract class TranslatedFlexibleCondition extends TranslatedCondition, Conditio
final override Instruction getFirstInstruction() { result = getOperand().getFirstInstruction() } final override Instruction getFirstInstruction() { result = getOperand().getFirstInstruction() }
final override predicate hasInstruction( final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
none() none()
} }
@@ -105,9 +104,7 @@ abstract class TranslatedBinaryLogicalOperation extends TranslatedNativeConditio
result = getLeftOperand().getFirstInstruction() result = getLeftOperand().getFirstInstruction()
} }
final override predicate hasInstruction( final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
none() none()
} }
@@ -163,13 +160,10 @@ class TranslatedValueCondition extends TranslatedCondition, TTranslatedValueCond
override Instruction getFirstInstruction() { result = getValueExpr().getFirstInstruction() } override Instruction getFirstInstruction() { result = getValueExpr().getFirstInstruction() }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = ValueConditionConditionalBranchTag() and tag = ValueConditionConditionalBranchTag() and
opcode instanceof Opcode::ConditionalBranch and opcode instanceof Opcode::ConditionalBranch and
resultType instanceof VoidType and resultType = getVoidType()
isGLValue = false
} }
override Instruction getChildSuccessor(TranslatedElement child) { override Instruction getChildSuccessor(TranslatedElement child) {

View File

@@ -1,7 +1,8 @@
private import cpp private import cpp
private import semmle.code.cpp.ir.implementation.Opcode private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.IRUtilities
private import semmle.code.cpp.ir.implementation.internal.OperandTag private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.CppType
private import semmle.code.cpp.ir.internal.IRUtilities
private import InstructionTag private import InstructionTag
private import TranslatedElement private import TranslatedElement
private import TranslatedExpr private import TranslatedExpr
@@ -54,19 +55,15 @@ abstract class TranslatedVariableDeclaration extends TranslatedElement, Initiali
result = getInstruction(InitializerVariableAddressTag()) result = getInstruction(InitializerVariableAddressTag())
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = InitializerVariableAddressTag() and tag = InitializerVariableAddressTag() and
opcode instanceof Opcode::VariableAddress and opcode instanceof Opcode::VariableAddress and
resultType = getVariableType(getVariable()) and resultType = getTypeForGLValue(getVariableType(getVariable()))
isGLValue = true
or or
hasUninitializedInstruction() and hasUninitializedInstruction() and
tag = InitializerStoreTag() and tag = InitializerStoreTag() and
opcode instanceof Opcode::Uninitialized and opcode instanceof Opcode::Uninitialized and
resultType = getVariableType(getVariable()) and resultType = getTypeForPRValue(getVariableType(getVariable()))
isGLValue = false
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {

View File

@@ -3,6 +3,7 @@ import semmle.code.cpp.ir.implementation.raw.IR
private import semmle.code.cpp.ir.IRConfiguration private import semmle.code.cpp.ir.IRConfiguration
private import semmle.code.cpp.ir.implementation.Opcode private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.internal.OperandTag private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.CppType
private import semmle.code.cpp.ir.internal.TempVariableTag private import semmle.code.cpp.ir.internal.TempVariableTag
private import InstructionTag private import InstructionTag
private import TranslatedCondition private import TranslatedCondition
@@ -12,11 +13,6 @@ private import TranslatedExpr
private import IRConstruction private import IRConstruction
private import semmle.code.cpp.models.interfaces.SideEffect private import semmle.code.cpp.models.interfaces.SideEffect
/**
* Gets the built-in `int` type.
*/
Type getIntType() { result.(IntType).isImplicitlySigned() }
/** /**
* Gets the "real" parent of `expr`. This predicate treats conversions as if * Gets the "real" parent of `expr`. This predicate treats conversions as if
* they were explicit nodes in the expression tree, rather than as implicit * they were explicit nodes in the expression tree, rather than as implicit
@@ -54,6 +50,9 @@ private predicate ignoreExprAndDescendants(Expr expr) {
// constant value. // constant value.
isIRConstant(getRealParent(expr)) isIRConstant(getRealParent(expr))
or or
// Ignore descendants of `__assume` expressions, since we translated these to `NoOp`.
getRealParent(expr) instanceof AssumeExpr
or
// The `DestructorCall` node for a `DestructorFieldDestruction` has a `FieldAccess` // The `DestructorCall` node for a `DestructorFieldDestruction` has a `FieldAccess`
// node as its qualifier, but that `FieldAccess` does not have a child of its own. // node as its qualifier, but that `FieldAccess` does not have a child of its own.
// We'll ignore that `FieldAccess`, and supply the receiver as part of the calling // We'll ignore that `FieldAccess`, and supply the receiver as part of the calling
@@ -67,8 +66,8 @@ private predicate ignoreExprAndDescendants(Expr expr) {
) )
or or
// Do not translate input/output variables in GNU asm statements // Do not translate input/output variables in GNU asm statements
getRealParent(expr) instanceof AsmStmt // getRealParent(expr) instanceof AsmStmt
or // or
ignoreExprAndDescendants(getRealParent(expr)) // recursive case ignoreExprAndDescendants(getRealParent(expr)) // recursive case
or or
// We do not yet translate destructors properly, so for now we ignore any // We do not yet translate destructors properly, so for now we ignore any
@@ -542,9 +541,7 @@ abstract class TranslatedElement extends TTranslatedElement {
* If the instruction does not return a result, `resultType` should be * If the instruction does not return a result, `resultType` should be
* `VoidType`. * `VoidType`.
*/ */
abstract predicate hasInstruction( abstract predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType);
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
);
/** /**
* Gets the `Function` that contains this element. * Gets the `Function` that contains this element.
@@ -584,7 +581,7 @@ abstract class TranslatedElement extends TTranslatedElement {
* `tag` must be unique for each variable generated from the same AST node * `tag` must be unique for each variable generated from the same AST node
* (not just from the same `TranslatedElement`). * (not just from the same `TranslatedElement`).
*/ */
predicate hasTempVariable(TempVariableTag tag, Type type) { none() } predicate hasTempVariable(TempVariableTag tag, CppType type) { none() }
/** /**
* If the instruction specified by `tag` is a `FunctionInstruction`, gets the * If the instruction specified by `tag` is a `FunctionInstruction`, gets the
@@ -629,6 +626,8 @@ abstract class TranslatedElement extends TTranslatedElement {
*/ */
int getInstructionResultSize(InstructionTag tag) { none() } int getInstructionResultSize(InstructionTag tag) { none() }
predicate needsUnknownOpaqueType(int byteSize) { none() }
/** /**
* If the instruction specified by `tag` is a `StringConstantInstruction`, * If the instruction specified by `tag` is a `StringConstantInstruction`,
* gets the `StringLiteral` for that instruction. * gets the `StringLiteral` for that instruction.
@@ -644,7 +643,7 @@ abstract class TranslatedElement extends TTranslatedElement {
* If the instruction specified by `tag` is a `CatchByTypeInstruction`, * If the instruction specified by `tag` is a `CatchByTypeInstruction`,
* gets the type of the exception to be caught. * gets the type of the exception to be caught.
*/ */
Type getInstructionExceptionType(InstructionTag tag) { none() } CppType getInstructionExceptionType(InstructionTag tag) { none() }
/** /**
* If the instruction specified by `tag` is an `InheritanceConversionInstruction`, * If the instruction specified by `tag` is an `InheritanceConversionInstruction`,
@@ -663,7 +662,7 @@ abstract class TranslatedElement extends TTranslatedElement {
/** /**
* Gets the type of the memory operand specified by `operandTag` on the the instruction specified by `tag`. * Gets the type of the memory operand specified by `operandTag` on the the instruction specified by `tag`.
*/ */
Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() } CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() }
/** /**
* Gets the size of the memory operand specified by `operandTag` on the the instruction specified by `tag`. * Gets the size of the memory operand specified by `operandTag` on the the instruction specified by `tag`.

View File

@@ -1,6 +1,8 @@
private import cpp private import cpp
private import semmle.code.cpp.ir.implementation.IRType
private import semmle.code.cpp.ir.implementation.Opcode private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.internal.OperandTag private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.CppType
private import semmle.code.cpp.ir.internal.TempVariableTag private import semmle.code.cpp.ir.internal.TempVariableTag
private import InstructionTag private import InstructionTag
private import TranslatedCondition private import TranslatedCondition
@@ -51,10 +53,21 @@ abstract class TranslatedExpr extends TranslatedElement {
*/ */
abstract predicate producesExprResult(); abstract predicate producesExprResult();
final CppType getResultType() {
if isResultGLValue()
then result = getTypeForGLValue(expr.getType())
else result = getTypeForPRValue(expr.getType())
}
/** /**
* Gets the type of the result produced by this expression. * Holds if the result of this `TranslatedExpr` is a glvalue.
*/ */
final Type getResultType() { result = expr.getUnspecifiedType() } predicate isResultGLValue() {
// This implementation is overridden in `TranslatedCoreExpr` to mark them
// as glvalues if they have loads on them. It's not overridden in
// `TranslatedResultCopy` since result copies never have loads.
expr.isGLValueCategory()
}
final override Locatable getAST() { result = expr } final override Locatable getAST() { result = expr }
@@ -82,6 +95,22 @@ abstract class TranslatedExpr extends TranslatedElement {
abstract class TranslatedCoreExpr extends TranslatedExpr { abstract class TranslatedCoreExpr extends TranslatedExpr {
final override string toString() { result = expr.toString() } final override string toString() { result = expr.toString() }
/**
* Holds if the result of this `TranslatedExpr` is a glvalue.
*/
override predicate isResultGLValue() {
super.isResultGLValue()
or
// If this TranslatedExpr doesn't produce the result, then it must represent
// a glvalue that is then loaded by a TranslatedLoad.
hasLoad()
}
final predicate hasLoad() {
expr.hasLValueToRValueConversion() and
not ignoreLoad(expr)
}
final override predicate producesExprResult() { final override predicate producesExprResult() {
// If there's no load, then this is the only TranslatedExpr for this // If there's no load, then this is the only TranslatedExpr for this
// expression. // expression.
@@ -89,30 +118,6 @@ abstract class TranslatedCoreExpr extends TranslatedExpr {
// If there's a result copy, then this expression's result is the copy. // If there's a result copy, then this expression's result is the copy.
not exprNeedsCopyIfNotLoaded(expr) not exprNeedsCopyIfNotLoaded(expr)
} }
private predicate hasLoad() {
expr.hasLValueToRValueConversion() and
not ignoreLoad(expr)
}
/**
* Returns `true` if the result of this `TranslatedExpr` is a glvalue, or
* `false` if the result is a prvalue.
*
* This predicate returns a `boolean` value instead of just a being a plain
* predicate because all of the subclass predicates that call it require a
* `boolean` value.
*/
final boolean isResultGLValue() {
if
expr.isGLValueCategory()
or
// If this TranslatedExpr doesn't produce the result, then it must represent
// a glvalue that is then loaded by a TranslatedLoad.
hasLoad()
then result = true
else result = false
}
} }
class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
@@ -123,38 +128,32 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() } override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
( (
tag = ConditionValueTrueTempAddressTag() or tag = ConditionValueTrueTempAddressTag() or
tag = ConditionValueFalseTempAddressTag() or tag = ConditionValueFalseTempAddressTag() or
tag = ConditionValueResultTempAddressTag() tag = ConditionValueResultTempAddressTag()
) and ) and
opcode instanceof Opcode::VariableAddress and opcode instanceof Opcode::VariableAddress and
resultType = getResultType() and resultType = getTypeForGLValue(expr.getType())
isGLValue = true
or or
( (
tag = ConditionValueTrueConstantTag() or tag = ConditionValueTrueConstantTag() or
tag = ConditionValueFalseConstantTag() tag = ConditionValueFalseConstantTag()
) and ) and
opcode instanceof Opcode::Constant and opcode instanceof Opcode::Constant and
resultType = getResultType() and resultType = getResultType()
isGLValue = isResultGLValue()
or or
( (
tag = ConditionValueTrueStoreTag() or tag = ConditionValueTrueStoreTag() or
tag = ConditionValueFalseStoreTag() tag = ConditionValueFalseStoreTag()
) and ) and
opcode instanceof Opcode::Store and opcode instanceof Opcode::Store and
resultType = getResultType() and resultType = getResultType()
isGLValue = isResultGLValue()
or or
tag = ConditionValueResultLoadTag() and tag = ConditionValueResultLoadTag() and
opcode instanceof Opcode::Load and opcode instanceof Opcode::Load and
resultType = getResultType() and resultType = getResultType()
isGLValue = isResultGLValue()
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -215,9 +214,9 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
) )
} }
override predicate hasTempVariable(TempVariableTag tag, Type type) { override predicate hasTempVariable(TempVariableTag tag, CppType type) {
tag = ConditionValueTempVar() and tag = ConditionValueTempVar() and
type = getResultType() type = getTypeForPRValue(expr.getType())
} }
override IRVariable getInstructionVariable(InstructionTag tag) { override IRVariable getInstructionVariable(InstructionTag tag) {
@@ -265,13 +264,10 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
override TranslatedElement getChild(int id) { id = 0 and result = getOperand() } override TranslatedElement getChild(int id) { id = 0 and result = getOperand() }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = LoadTag() and tag = LoadTag() and
opcode instanceof Opcode::Load and opcode instanceof Opcode::Load and
resultType = expr.getUnspecifiedType() and resultType = getResultType()
if expr.isGLValueCategory() then isGLValue = true else isGLValue = false
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -318,13 +314,10 @@ class TranslatedResultCopy extends TranslatedExpr, TTranslatedResultCopy {
override TranslatedElement getChild(int id) { id = 0 and result = getOperand() } override TranslatedElement getChild(int id) { id = 0 and result = getOperand() }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = ResultCopyTag() and tag = ResultCopyTag() and
opcode instanceof Opcode::CopyValue and opcode instanceof Opcode::CopyValue and
resultType = getOperand().getResultType() and resultType = getOperand().getResultType()
isGLValue = getOperand().isResultGLValue()
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -372,9 +365,7 @@ class TranslatedCommaExpr extends TranslatedNonConstantExpr {
child = getRightOperand() and result = getParent().getChildSuccessor(this) child = getRightOperand() and result = getParent().getChildSuccessor(this)
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
none() none()
} }
@@ -389,6 +380,10 @@ class TranslatedCommaExpr extends TranslatedNonConstantExpr {
} }
} }
private int getElementSize(Type type) {
result = max(type.getUnspecifiedType().(PointerType).getBaseType().getSize())
}
abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
override CrementOperation expr; override CrementOperation expr;
@@ -397,9 +392,9 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
final override string getInstructionConstantValue(InstructionTag tag) { final override string getInstructionConstantValue(InstructionTag tag) {
tag = CrementConstantTag() and tag = CrementConstantTag() and
exists(Type resultType | exists(Type resultType |
resultType = getResultType() and resultType = expr.getUnspecifiedType() and
( (
resultType instanceof IntegralType and result = "1" resultType instanceof IntegralOrEnumType and result = "1"
or or
resultType instanceof FloatingPointType and result = "1.0" resultType instanceof FloatingPointType and result = "1.0"
or or
@@ -408,38 +403,34 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
) )
} }
private Type getConstantType() { private CppType getConstantType() {
exists(Type resultType | exists(Type resultType |
resultType = getResultType() and resultType = expr.getUnspecifiedType() and
( (
resultType instanceof ArithmeticType and result = resultType resultType instanceof ArithmeticType and
result = getTypeForPRValue(expr.getType())
or or
resultType instanceof PointerType and result = getIntType() resultType instanceof PointerType and result = getIntType()
) )
) )
} }
final override predicate hasInstruction( final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue tag = CrementLoadTag() and
) { opcode instanceof Opcode::Load and
isGLValue = false and resultType = getTypeForPRValue(expr.getType())
( or
tag = CrementLoadTag() and tag = CrementConstantTag() and
opcode instanceof Opcode::Load and opcode instanceof Opcode::Constant and
resultType = getResultType() resultType = getConstantType()
or or
tag = CrementConstantTag() and tag = CrementOpTag() and
opcode instanceof Opcode::Constant and opcode = getOpcode() and
resultType = getConstantType() resultType = getTypeForPRValue(expr.getType())
or or
tag = CrementOpTag() and tag = CrementStoreTag() and
opcode = getOpcode() and opcode instanceof Opcode::Store and
resultType = getResultType() resultType = getTypeForPRValue(expr.getType())
or
tag = CrementStoreTag() and
opcode instanceof Opcode::Store and
resultType = getResultType()
)
} }
final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
@@ -500,7 +491,7 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
getOpcode() instanceof Opcode::PointerAdd or getOpcode() instanceof Opcode::PointerAdd or
getOpcode() instanceof Opcode::PointerSub getOpcode() instanceof Opcode::PointerSub
) and ) and
result = max(getResultType().(PointerType).getBaseType().getSize()) result = getElementSize(expr.getType())
} }
final TranslatedExpr getOperand() { final TranslatedExpr getOperand() {
@@ -509,7 +500,7 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
final Opcode getOpcode() { final Opcode getOpcode() {
exists(Type resultType | exists(Type resultType |
resultType = getResultType() and resultType = expr.getUnspecifiedType() and
( (
( (
expr instanceof IncrementOperation and expr instanceof IncrementOperation and
@@ -590,13 +581,10 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr {
override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
opcode instanceof Opcode::PointerAdd and opcode instanceof Opcode::PointerAdd and
resultType = getResultType() and resultType = getTypeForGLValue(expr.getType())
isGLValue = true
} }
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
@@ -612,7 +600,7 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr {
override int getInstructionElementSize(InstructionTag tag) { override int getInstructionElementSize(InstructionTag tag) {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
result = max(getResultType().getSize()) result = max(expr.getUnspecifiedType().getSize())
} }
private TranslatedExpr getBaseOperand() { private TranslatedExpr getBaseOperand() {
@@ -635,9 +623,7 @@ abstract class TranslatedTransparentExpr extends TranslatedNonConstantExpr {
child = getOperand() and result = getParent().getChildSuccessor(this) child = getOperand() and result = getParent().getChildSuccessor(this)
} }
final override predicate hasInstruction( final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
none() none()
} }
@@ -688,13 +674,10 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr {
final override TranslatedElement getChild(int id) { none() } final override TranslatedElement getChild(int id) { none() }
final override predicate hasInstruction( final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
opcode instanceof Opcode::CopyValue and opcode instanceof Opcode::CopyValue and
resultType = expr.getUnspecifiedType() and resultType = getResultType()
isGLValue = false
} }
final override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } final override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) }
@@ -755,13 +738,10 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess {
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() } override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
opcode instanceof Opcode::VariableAddress and opcode instanceof Opcode::VariableAddress and
resultType = getResultType() and resultType = getTypeForGLValue(expr.getType())
isGLValue = true
} }
override IRVariable getInstructionVariable(InstructionTag tag) { override IRVariable getInstructionVariable(InstructionTag tag) {
@@ -781,13 +761,10 @@ class TranslatedFieldAccess extends TranslatedVariableAccess {
result = getQualifier().getResult() result = getQualifier().getResult()
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
opcode instanceof Opcode::FieldAddress and opcode instanceof Opcode::FieldAddress and
resultType = getResultType() and resultType = getTypeForGLValue(expr.getType())
isGLValue = true
} }
override Field getInstructionField(InstructionTag tag) { override Field getInstructionField(InstructionTag tag) {
@@ -811,13 +788,10 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
kind instanceof GotoEdge kind instanceof GotoEdge
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
opcode instanceof Opcode::FunctionAddress and opcode instanceof Opcode::FunctionAddress and
resultType = expr.getUnspecifiedType() and resultType = getResultType()
isGLValue = true
} }
override Function getInstructionFunction(InstructionTag tag) { override Function getInstructionFunction(InstructionTag tag) {
@@ -859,15 +833,10 @@ abstract class TranslatedConstantExpr extends TranslatedCoreExpr, TTranslatedVal
none() none()
} }
final override predicate hasInstruction( final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
opcode = getOpcode() and opcode = getOpcode() and
resultType = getResultType() and resultType = getResultType()
if expr.isGLValueCategory() or expr.hasLValueToRValueConversion()
then isGLValue = true
else isGLValue = false
} }
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -913,13 +882,10 @@ abstract class TranslatedSingleInstructionExpr extends TranslatedNonConstantExpr
*/ */
abstract Opcode getOpcode(); abstract Opcode getOpcode();
final override predicate hasInstruction( final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
opcode = getOpcode() and opcode = getOpcode() and
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
resultType = getResultType() and resultType = getResultType()
isGLValue = isResultGLValue()
} }
final override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } final override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) }
@@ -993,13 +959,10 @@ abstract class TranslatedSingleInstructionConversion extends TranslatedConversio
child = getOperand() and result = getInstruction(OnlyInstructionTag()) child = getOperand() and result = getInstruction(OnlyInstructionTag())
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
opcode = getOpcode() and opcode = getOpcode() and
resultType = getResultType() and resultType = getResultType()
isGLValue = isResultGLValue()
} }
override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) }
@@ -1044,7 +1007,7 @@ class TranslatedDynamicCast extends TranslatedSingleInstructionConversion {
override Opcode getOpcode() { override Opcode getOpcode() {
exists(Type resultType | exists(Type resultType |
resultType = getResultType() and resultType = expr.getUnspecifiedType() and
if resultType instanceof PointerType if resultType instanceof PointerType
then then
if resultType.(PointerType).getBaseType() instanceof VoidType if resultType.(PointerType).getBaseType() instanceof VoidType
@@ -1102,19 +1065,14 @@ class TranslatedBoolConversion extends TranslatedConversion {
child = getOperand() and result = getInstruction(BoolConversionConstantTag()) child = getOperand() and result = getInstruction(BoolConversionConstantTag())
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue tag = BoolConversionConstantTag() and
) { opcode instanceof Opcode::Constant and
isGLValue = false and resultType = getOperand().getResultType()
( or
tag = BoolConversionConstantTag() and tag = BoolConversionCompareTag() and
opcode instanceof Opcode::Constant and opcode instanceof Opcode::CompareNE and
resultType = getOperand().getResultType() resultType = getBoolType()
or
tag = BoolConversionCompareTag() and
opcode instanceof Opcode::CompareNE and
resultType instanceof BoolType
)
} }
override Instruction getResult() { result = getInstruction(BoolConversionCompareTag()) } override Instruction getResult() { result = getInstruction(BoolConversionCompareTag()) }
@@ -1245,7 +1203,7 @@ class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr {
opcode instanceof Opcode::PointerSub or opcode instanceof Opcode::PointerSub or
opcode instanceof Opcode::PointerDiff opcode instanceof Opcode::PointerDiff
) and ) and
result = max(getPointerOperand().getResultType().(PointerType).getBaseType().getSize()) result = getElementSize(getPointerOperand().getExpr().getType())
) )
} }
@@ -1330,13 +1288,10 @@ class TranslatedAssignExpr extends TranslatedAssignment {
result = getInstruction(AssignmentStoreTag()) result = getInstruction(AssignmentStoreTag())
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = AssignmentStoreTag() and tag = AssignmentStoreTag() and
opcode instanceof Opcode::Store and opcode instanceof Opcode::Store and
resultType = getResultType() and resultType = getTypeForPRValue(expr.getType()) // Always a prvalue
isGLValue = false
} }
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
@@ -1413,14 +1368,16 @@ class TranslatedAssignOperation extends TranslatedAssignment {
// anyway. If we really want to model this case perfectly, we'll need the // anyway. If we really want to model this case perfectly, we'll need the
// extractor to tell us what the promoted type of the left operand would // extractor to tell us what the promoted type of the left operand would
// be. // be.
result = getLeftOperand().getResultType() result = getLeftOperand().getExpr().getType()
else else
// The right operand has already been converted to the type of the op. // The right operand has already been converted to the type of the op.
result = getRightOperand().getResultType() result = getRightOperand().getExpr().getType()
} }
private predicate leftOperandNeedsConversion() { private predicate leftOperandNeedsConversion() {
getConvertedLeftOperandType() != getLeftOperand().getResultType() getConvertedLeftOperandType().getUnspecifiedType() != getLeftOperand()
.getExpr()
.getUnspecifiedType()
} }
private Opcode getOpcode() { private Opcode getOpcode() {
@@ -1449,32 +1406,27 @@ class TranslatedAssignOperation extends TranslatedAssignment {
expr instanceof AssignPointerSubExpr and result instanceof Opcode::PointerSub expr instanceof AssignPointerSubExpr and result instanceof Opcode::PointerSub
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue tag = AssignOperationLoadTag() and
) { opcode instanceof Opcode::Load and
isGLValue = false and resultType = getTypeForPRValue(getLeftOperand().getExpr().getType())
or
tag = AssignOperationOpTag() and
opcode = getOpcode() and
resultType = getTypeForPRValue(getConvertedLeftOperandType())
or
tag = AssignmentStoreTag() and
opcode instanceof Opcode::Store and
resultType = getTypeForPRValue(expr.getType()) // Always a prvalue
or
leftOperandNeedsConversion() and
opcode instanceof Opcode::Convert and
( (
tag = AssignOperationLoadTag() and tag = AssignOperationConvertLeftTag() and
opcode instanceof Opcode::Load and resultType = getTypeForPRValue(getConvertedLeftOperandType())
resultType = getLeftOperand().getResultType()
or or
tag = AssignOperationOpTag() and tag = AssignOperationConvertResultTag() and
opcode = getOpcode() and resultType = getTypeForPRValue(getLeftOperand().getExpr().getType())
resultType = getConvertedLeftOperandType()
or
tag = AssignmentStoreTag() and
opcode instanceof Opcode::Store and
resultType = getResultType()
or
leftOperandNeedsConversion() and
opcode instanceof Opcode::Convert and
(
tag = AssignOperationConvertLeftTag() and
resultType = getConvertedLeftOperandType()
or
tag = AssignOperationConvertResultTag() and
resultType = getLeftOperand().getResultType()
)
) )
} }
@@ -1484,7 +1436,7 @@ class TranslatedAssignOperation extends TranslatedAssignment {
opcode = getOpcode() and opcode = getOpcode() and
(opcode instanceof Opcode::PointerAdd or opcode instanceof Opcode::PointerSub) (opcode instanceof Opcode::PointerAdd or opcode instanceof Opcode::PointerSub)
) and ) and
result = max(getResultType().(PointerType).getBaseType().getSize()) result = getElementSize(expr.getType())
} }
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
@@ -1566,13 +1518,10 @@ class TranslatedConstantAllocationSize extends TranslatedAllocationSize {
final override Instruction getFirstInstruction() { result = getInstruction(AllocationSizeTag()) } final override Instruction getFirstInstruction() { result = getInstruction(AllocationSizeTag()) }
final override predicate hasInstruction( final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = AllocationSizeTag() and tag = AllocationSizeTag() and
opcode instanceof Opcode::Constant and opcode instanceof Opcode::Constant and
resultType = expr.getAllocator().getParameter(0).getUnspecifiedType() and resultType = getTypeForPRValue(expr.getAllocator().getParameter(0).getType())
isGLValue = false
} }
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -1605,11 +1554,8 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
final override Instruction getFirstInstruction() { result = getExtent().getFirstInstruction() } final override Instruction getFirstInstruction() { result = getExtent().getFirstInstruction() }
final override predicate hasInstruction( final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue resultType = getTypeForPRValue(expr.getAllocator().getParameter(0).getType()) and
) {
isGLValue = false and
resultType = expr.getAllocator().getParameter(0).getUnspecifiedType() and
( (
// Convert the extent to `size_t`, because the AST doesn't do this already. // Convert the extent to `size_t`, because the AST doesn't do this already.
tag = AllocationExtentConvertTag() and opcode instanceof Opcode::Convert tag = AllocationExtentConvertTag() and opcode instanceof Opcode::Convert
@@ -1681,7 +1627,7 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect
tag = CallTargetTag() and result = expr.getAllocator() tag = CallTargetTag() and result = expr.getAllocator()
} }
final override Type getCallResultType() { result = expr.getAllocator().getUnspecifiedType() } final override Type getCallResultType() { result = expr.getAllocator().getType() }
final override TranslatedExpr getQualifier() { none() } final override TranslatedExpr getQualifier() { none() }
@@ -1736,13 +1682,10 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr, St
final override TranslatedElement getChild(int id) { id = 0 and result = getDestructorCall() } final override TranslatedElement getChild(int id) { id = 0 and result = getDestructorCall() }
final override predicate hasInstruction( final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
opcode instanceof Opcode::FieldAddress and opcode instanceof Opcode::FieldAddress and
resultType = expr.getTarget().getUnspecifiedType() and resultType = getTypeForGLValue(expr.getTarget().getType())
isGLValue = true
} }
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -1789,9 +1732,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() } override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
not resultIsVoid() and not resultIsVoid() and
( (
( (
@@ -1802,8 +1743,11 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
tag = ConditionValueResultTempAddressTag() tag = ConditionValueResultTempAddressTag()
) and ) and
opcode instanceof Opcode::VariableAddress and opcode instanceof Opcode::VariableAddress and
resultType = getResultType() and (
isGLValue = true if expr.isGLValueCategory()
then resultType = getTypeForGLValue(any(UnknownType t)) // glvalue to a glvalue
else resultType = getTypeForGLValue(expr.getType()) // glvalue to the result type
)
or or
( (
not thenIsVoid() and tag = ConditionValueTrueStoreTag() not thenIsVoid() and tag = ConditionValueTrueStoreTag()
@@ -1811,13 +1755,11 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
not elseIsVoid() and tag = ConditionValueFalseStoreTag() not elseIsVoid() and tag = ConditionValueFalseStoreTag()
) and ) and
opcode instanceof Opcode::Store and opcode instanceof Opcode::Store and
resultType = getResultType() and resultType = getResultType()
isGLValue = false
or or
tag = ConditionValueResultLoadTag() and tag = ConditionValueResultLoadTag() and
opcode instanceof Opcode::Load and opcode instanceof Opcode::Load and
resultType = getResultType() and resultType = getResultType()
isGLValue = isResultGLValue()
) )
} }
@@ -1885,7 +1827,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
) )
} }
override predicate hasTempVariable(TempVariableTag tag, Type type) { override predicate hasTempVariable(TempVariableTag tag, CppType type) {
not resultIsVoid() and not resultIsVoid() and
tag = ConditionValueTempVar() and tag = ConditionValueTempVar() and
type = getResultType() type = getResultType()
@@ -1945,7 +1887,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
} }
private predicate thenIsVoid() { private predicate thenIsVoid() {
getThen().getResultType() instanceof VoidType getThen().getResultType().getIRType() instanceof IRVoidType
or or
// A `ThrowExpr.getType()` incorrectly returns the type of exception being // A `ThrowExpr.getType()` incorrectly returns the type of exception being
// thrown, rather than `void`. Handle that case here. // thrown, rather than `void`. Handle that case here.
@@ -1953,14 +1895,14 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
} }
private predicate elseIsVoid() { private predicate elseIsVoid() {
getElse().getResultType() instanceof VoidType getElse().getResultType().getIRType() instanceof IRVoidType
or or
// A `ThrowExpr.getType()` incorrectly returns the type of exception being // A `ThrowExpr.getType()` incorrectly returns the type of exception being
// thrown, rather than `void`. Handle that case here. // thrown, rather than `void`. Handle that case here.
expr.getElse() instanceof ThrowExpr expr.getElse() instanceof ThrowExpr
} }
private predicate resultIsVoid() { getResultType() instanceof VoidType } private predicate resultIsVoid() { getResultType().getIRType() instanceof IRVoidType }
} }
/** /**
@@ -1969,13 +1911,10 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr { abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr {
override ThrowExpr expr; override ThrowExpr expr;
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = ThrowTag() and tag = ThrowTag() and
opcode = getThrowOpcode() and opcode = getThrowOpcode() and
resultType instanceof VoidType and resultType = getVoidType()
isGLValue = false
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -2002,15 +1941,12 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, InitializationContex
result = getInstruction(InitializerVariableAddressTag()) result = getInstruction(InitializerVariableAddressTag())
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue TranslatedThrowExpr.super.hasInstruction(opcode, tag, resultType)
) {
TranslatedThrowExpr.super.hasInstruction(opcode, tag, resultType, isGLValue)
or or
tag = InitializerVariableAddressTag() and tag = InitializerVariableAddressTag() and
opcode instanceof Opcode::VariableAddress and opcode instanceof Opcode::VariableAddress and
resultType = getExceptionType() and resultType = getTypeForGLValue(getExceptionType())
isGLValue = true
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -2031,9 +1967,9 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, InitializationContex
result = getIRTempVariable(expr, ThrowTempVar()) result = getIRTempVariable(expr, ThrowTempVar())
} }
final override predicate hasTempVariable(TempVariableTag tag, Type type) { final override predicate hasTempVariable(TempVariableTag tag, CppType type) {
tag = ThrowTempVar() and tag = ThrowTempVar() and
type = getExceptionType() type = getTypeForPRValue(getExceptionType())
} }
final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
@@ -2047,10 +1983,10 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, InitializationContex
) )
} }
final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
tag = ThrowTag() and tag = ThrowTag() and
operandTag instanceof LoadOperandTag and operandTag instanceof LoadOperandTag and
result = getExceptionType() result = getTypeForPRValue(getExceptionType())
} }
override Instruction getTargetAddress() { override Instruction getTargetAddress() {
@@ -2065,7 +2001,7 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, InitializationContex
final override Opcode getThrowOpcode() { result instanceof Opcode::ThrowValue } final override Opcode getThrowOpcode() { result instanceof Opcode::ThrowValue }
private Type getExceptionType() { result = expr.getUnspecifiedType() } private Type getExceptionType() { result = expr.getType() }
} }
/** /**
@@ -2123,13 +2059,10 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
) )
} }
final override predicate hasInstruction( final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
opcode = getOpcode() and opcode = getOpcode() and
resultType = getResultType() and resultType = getResultType()
isGLValue = isResultGLValue()
} }
final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
@@ -2196,13 +2129,10 @@ abstract class TranslatedNewOrNewArrayExpr extends TranslatedNonConstantExpr, In
id = 1 and result = getInitialization() id = 1 and result = getInitialization()
} }
final override predicate hasInstruction( final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
opcode instanceof Opcode::Convert and opcode instanceof Opcode::Convert and
resultType = getResultType() and resultType = getResultType()
isGLValue = false
} }
final override Instruction getFirstInstruction() { final override Instruction getFirstInstruction() {
@@ -2363,9 +2293,7 @@ class TranslatedConditionDeclExpr extends TranslatedNonConstantExpr {
child = getConditionExpr() and result = getParent().getChildSuccessor(this) child = getConditionExpr() and result = getParent().getChildSuccessor(this)
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
none() none()
} }
@@ -2414,23 +2342,18 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont
result = getInstruction(LoadTag()) result = getInstruction(LoadTag())
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = InitializerVariableAddressTag() and tag = InitializerVariableAddressTag() and
opcode instanceof Opcode::VariableAddress and opcode instanceof Opcode::VariableAddress and
resultType = getResultType() and resultType = getTypeForGLValue(expr.getType())
isGLValue = true
or or
tag = InitializerStoreTag() and tag = InitializerStoreTag() and
opcode instanceof Opcode::Uninitialized and opcode instanceof Opcode::Uninitialized and
resultType = getResultType() and resultType = getTypeForPRValue(expr.getType())
isGLValue = false
or or
tag = LoadTag() and tag = LoadTag() and
opcode instanceof Opcode::Load and opcode instanceof Opcode::Load and
resultType = getResultType() and resultType = getTypeForPRValue(expr.getType())
isGLValue = false
} }
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
@@ -2456,16 +2379,16 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont
result = getTempVariable(LambdaTempVar()) result = getTempVariable(LambdaTempVar())
} }
override predicate hasTempVariable(TempVariableTag tag, Type type) { override predicate hasTempVariable(TempVariableTag tag, CppType type) {
tag = LambdaTempVar() and tag = LambdaTempVar() and
type = getResultType() type = getTypeForPRValue(expr.getType())
} }
final override Instruction getTargetAddress() { final override Instruction getTargetAddress() {
result = getInstruction(InitializerVariableAddressTag()) result = getInstruction(InitializerVariableAddressTag())
} }
final override Type getTargetType() { result = getResultType() } final override Type getTargetType() { result = expr.getType() }
private predicate hasInitializer() { exists(getInitialization()) } private predicate hasInitializer() { exists(getInitialization()) }
@@ -2496,13 +2419,10 @@ class TranslatedStmtExpr extends TranslatedNonConstantExpr {
result = getInstruction(OnlyInstructionTag()) result = getInstruction(OnlyInstructionTag())
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
opcode instanceof Opcode::CopyValue and opcode instanceof Opcode::CopyValue and
tag instanceof OnlyInstructionTag and tag instanceof OnlyInstructionTag and
resultType = expr.getType() and resultType = getResultType()
isGLValue = false
} }
override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) }
@@ -2589,3 +2509,26 @@ private predicate exprImmediatelyDiscarded(Expr expr) {
or or
exists(ForStmt for | for.getUpdate() = expr) exists(ForStmt for | for.getUpdate() = expr)
} }
/**
* The IR translation of an `__assume` expression. We currently translate these as `NoOp`. In the
* future, we will probably want to do something better. At a minimum, we can model `__assume(0)` as
* `Unreached`.
*/
class TranslatedAssumeExpr extends TranslatedSingleInstructionExpr {
override AssumeExpr expr;
final override Opcode getOpcode() { result instanceof Opcode::NoOp }
final override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
final override TranslatedElement getChild(int id) { none() }
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
result = getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
}
final override Instruction getChildSuccessor(TranslatedElement child) { none() }
}

View File

@@ -1,6 +1,7 @@
private import cpp private import cpp
import semmle.code.cpp.ir.implementation.raw.IR import semmle.code.cpp.ir.implementation.raw.IR
private import semmle.code.cpp.ir.implementation.Opcode private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.CppType
private import semmle.code.cpp.ir.internal.IRUtilities private import semmle.code.cpp.ir.internal.IRUtilities
private import semmle.code.cpp.ir.implementation.internal.OperandTag private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.TempVariableTag private import semmle.code.cpp.ir.internal.TempVariableTag
@@ -95,6 +96,9 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
result = getInstruction(UnmodeledUseTag()) result = getInstruction(UnmodeledUseTag())
or or
tag = UnmodeledUseTag() and tag = UnmodeledUseTag() and
result = getInstruction(AliasedUseTag())
or
tag = AliasedUseTag() and
result = getInstruction(ExitFunctionTag()) result = getInstruction(ExitFunctionTag())
) )
} }
@@ -115,55 +119,46 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
or or
( (
child = getDestructorDestructionList() and child = getDestructorDestructionList() and
if getReturnType() instanceof VoidType if hasReturnValue()
then result = getInstruction(ReturnTag()) then result = getInstruction(ReturnValueAddressTag())
else result = getInstruction(ReturnValueAddressTag()) else result = getInstruction(ReturnTag())
) )
} }
final override predicate hasInstruction( final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
( (
tag = EnterFunctionTag() and tag = EnterFunctionTag() and
opcode instanceof Opcode::EnterFunction and opcode instanceof Opcode::EnterFunction and
resultType instanceof VoidType and resultType = getVoidType()
isGLValue = false
or or
tag = UnmodeledDefinitionTag() and tag = UnmodeledDefinitionTag() and
opcode instanceof Opcode::UnmodeledDefinition and opcode instanceof Opcode::UnmodeledDefinition and
resultType instanceof UnknownType and resultType = getUnknownType()
isGLValue = false
or or
tag = AliasedDefinitionTag() and tag = AliasedDefinitionTag() and
opcode instanceof Opcode::AliasedDefinition and opcode instanceof Opcode::AliasedDefinition and
resultType instanceof UnknownType and resultType = getUnknownType()
isGLValue = false
or or
tag = InitializeThisTag() and tag = InitializeThisTag() and
opcode instanceof Opcode::InitializeThis and opcode instanceof Opcode::InitializeThis and
resultType = getThisType() and resultType = getTypeForGLValue(getThisType())
isGLValue = true
or or
tag = ReturnValueAddressTag() and tag = ReturnValueAddressTag() and
opcode instanceof Opcode::VariableAddress and opcode instanceof Opcode::VariableAddress and
resultType = getReturnType() and resultType = getTypeForGLValue(getReturnType()) and
not resultType instanceof VoidType and hasReturnValue()
isGLValue = true
or or
( (
tag = ReturnTag() and tag = ReturnTag() and
resultType instanceof VoidType and resultType = getVoidType() and
isGLValue = false and if hasReturnValue()
if getReturnType() instanceof VoidType then opcode instanceof Opcode::ReturnValue
then opcode instanceof Opcode::ReturnVoid else opcode instanceof Opcode::ReturnVoid
else opcode instanceof Opcode::ReturnValue
) )
or or
tag = UnwindTag() and tag = UnwindTag() and
opcode instanceof Opcode::Unwind and opcode instanceof Opcode::Unwind and
resultType instanceof VoidType and resultType = getVoidType() and
isGLValue = false and
( (
// Only generate the `Unwind` instruction if there is any exception // Only generate the `Unwind` instruction if there is any exception
// handling present in the function. // handling present in the function.
@@ -173,13 +168,15 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
or or
tag = UnmodeledUseTag() and tag = UnmodeledUseTag() and
opcode instanceof Opcode::UnmodeledUse and opcode instanceof Opcode::UnmodeledUse and
resultType instanceof VoidType and resultType = getVoidType()
isGLValue = false or
tag = AliasedUseTag() and
opcode instanceof Opcode::AliasedUse and
resultType = getVoidType()
or or
tag = ExitFunctionTag() and tag = ExitFunctionTag() and
opcode instanceof Opcode::ExitFunction and opcode instanceof Opcode::ExitFunction and
resultType instanceof VoidType and resultType = getVoidType()
isGLValue = false
) )
} }
@@ -197,8 +194,12 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
operandTag instanceof UnmodeledUseOperandTag and operandTag instanceof UnmodeledUseOperandTag and
result = getUnmodeledDefinitionInstruction() result = getUnmodeledDefinitionInstruction()
or or
tag = AliasedUseTag() and
operandTag instanceof SideEffectOperandTag and
result = getUnmodeledDefinitionInstruction()
or
tag = ReturnTag() and tag = ReturnTag() and
not getReturnType() instanceof VoidType and hasReturnValue() and
( (
operandTag instanceof AddressOperandTag and operandTag instanceof AddressOperandTag and
result = getInstruction(ReturnValueAddressTag()) result = getInstruction(ReturnValueAddressTag())
@@ -208,11 +209,15 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
) )
} }
final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
tag = ReturnTag() and tag = ReturnTag() and
not getReturnType() instanceof VoidType and hasReturnValue() and
operandTag instanceof LoadOperandTag and operandTag instanceof LoadOperandTag and
result = getReturnType() result = getTypeForPRValue(getReturnType())
or
tag = AliasedUseTag() and
operandTag instanceof SideEffectOperandTag and
result = getUnknownType()
} }
final override IRVariable getInstructionVariable(InstructionTag tag) { final override IRVariable getInstructionVariable(InstructionTag tag) {
@@ -220,10 +225,10 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
result = getReturnVariable() result = getReturnVariable()
} }
final override predicate hasTempVariable(TempVariableTag tag, Type type) { final override predicate hasTempVariable(TempVariableTag tag, CppType type) {
tag = ReturnValueTempVar() and tag = ReturnValueTempVar() and
type = getReturnType() and hasReturnValue() and
not type instanceof VoidType type = getTypeForPRValue(getReturnType())
} }
/** /**
@@ -241,6 +246,11 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
result = getIRTempVariable(func, ReturnValueTempVar()) result = getIRTempVariable(func, ReturnValueTempVar())
} }
/**
* Holds if the function has a non-`void` return type.
*/
final predicate hasReturnValue() { not func.getUnspecifiedType() instanceof VoidType }
/** /**
* Gets the single `UnmodeledDefinition` instruction for this function. * Gets the single `UnmodeledDefinition` instruction for this function.
*/ */
@@ -271,7 +281,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
* parameters and local variables, plus any global variables or static data members that are * parameters and local variables, plus any global variables or static data members that are
* directly accessed by the function. * directly accessed by the function.
*/ */
final predicate hasUserVariable(Variable var, Type type) { final predicate hasUserVariable(Variable var, CppType type) {
( (
( (
var instanceof GlobalOrNamespaceVariable var instanceof GlobalOrNamespaceVariable
@@ -287,10 +297,10 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
or or
var.(Parameter).getCatchBlock().getEnclosingFunction() = func var.(Parameter).getCatchBlock().getEnclosingFunction() = func
) and ) and
type = getVariableType(var) type = getTypeForPRValue(getVariableType(var))
} }
final private Type getReturnType() { result = func.getUnspecifiedType() } final Type getReturnType() { result = func.getType() }
} }
/** /**
@@ -335,18 +345,14 @@ class TranslatedParameter extends TranslatedElement, TTranslatedParameter {
final override Instruction getChildSuccessor(TranslatedElement child) { none() } final override Instruction getChildSuccessor(TranslatedElement child) { none() }
final override predicate hasInstruction( final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = InitializerVariableAddressTag() and tag = InitializerVariableAddressTag() and
opcode instanceof Opcode::VariableAddress and opcode instanceof Opcode::VariableAddress and
resultType = getVariableType(param) and resultType = getTypeForGLValue(getVariableType(param))
isGLValue = true
or or
tag = InitializerStoreTag() and tag = InitializerStoreTag() and
opcode instanceof Opcode::InitializeParameter and opcode instanceof Opcode::InitializeParameter and
resultType = getVariableType(param) and resultType = getTypeForPRValue(getVariableType(param))
isGLValue = false
} }
final override IRVariable getInstructionVariable(InstructionTag tag) { final override IRVariable getInstructionVariable(InstructionTag tag) {
@@ -404,9 +410,7 @@ class TranslatedConstructorInitList extends TranslatedElement, InitializationCon
else result = getParent().getChildSuccessor(this) else result = getParent().getChildSuccessor(this)
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
none() none()
} }
@@ -469,9 +473,7 @@ class TranslatedDestructorDestructionList extends TranslatedElement,
else result = getParent().getChildSuccessor(this) else result = getParent().getChildSuccessor(this)
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
none() none()
} }

View File

@@ -1,6 +1,7 @@
private import cpp private import cpp
private import semmle.code.cpp.ir.implementation.Opcode private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.internal.OperandTag private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.CppType
private import InstructionTag private import InstructionTag
private import TranslatedElement private import TranslatedElement
private import TranslatedExpr private import TranslatedExpr
@@ -79,9 +80,7 @@ abstract class TranslatedListInitialization extends TranslatedInitialization, In
) )
} }
final override predicate hasInstruction( final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
none() none()
} }
@@ -150,13 +149,10 @@ class TranslatedSimpleDirectInitialization extends TranslatedDirectInitializatio
not expr instanceof StringLiteral not expr instanceof StringLiteral
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = InitializerStoreTag() and tag = InitializerStoreTag() and
opcode instanceof Opcode::Store and opcode instanceof Opcode::Store and
resultType = getContext().getTargetType() and resultType = getTypeForPRValue(getContext().getTargetType())
isGLValue = false
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -188,20 +184,16 @@ class TranslatedSimpleDirectInitialization extends TranslatedDirectInitializatio
class TranslatedStringLiteralInitialization extends TranslatedDirectInitialization { class TranslatedStringLiteralInitialization extends TranslatedDirectInitialization {
override StringLiteral expr; override StringLiteral expr;
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
// Load the string literal to make it a prvalue of type `char[len]` // Load the string literal to make it a prvalue of type `char[len]`
tag = InitializerLoadStringTag() and tag = InitializerLoadStringTag() and
opcode instanceof Opcode::Load and opcode instanceof Opcode::Load and
resultType = getInitializer().getResultType() and resultType = getTypeForPRValue(expr.getType())
isGLValue = false
or or
// Store the string into the target. // Store the string into the target.
tag = InitializerStoreTag() and tag = InitializerStoreTag() and
opcode instanceof Opcode::Store and opcode instanceof Opcode::Store and
resultType = getInitializer().getResultType() and resultType = getTypeForPRValue(expr.getType())
isGLValue = false
or or
exists(int startIndex, int elementCount | exists(int startIndex, int elementCount |
// If the initializer string isn't large enough to fill the target, then // If the initializer string isn't large enough to fill the target, then
@@ -213,26 +205,22 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
// space in the target array. // space in the target array.
tag = ZeroPadStringConstantTag() and tag = ZeroPadStringConstantTag() and
opcode instanceof Opcode::Constant and opcode instanceof Opcode::Constant and
resultType instanceof UnknownType and resultType = getUnknownOpaqueType(elementCount * getElementType().getSize())
isGLValue = false
or or
// The index of the first element to be zero initialized. // The index of the first element to be zero initialized.
tag = ZeroPadStringElementIndexTag() and tag = ZeroPadStringElementIndexTag() and
opcode instanceof Opcode::Constant and opcode instanceof Opcode::Constant and
resultType = getIntType() and resultType = getIntType()
isGLValue = false
or or
// Compute the address of the first element to be zero initialized. // Compute the address of the first element to be zero initialized.
tag = ZeroPadStringElementAddressTag() and tag = ZeroPadStringElementAddressTag() and
opcode instanceof Opcode::PointerAdd and opcode instanceof Opcode::PointerAdd and
resultType = getElementType() and resultType = getTypeForGLValue(getElementType())
isGLValue = true
or or
// Store the constant zero into the remainder of the string. // Store the constant zero into the remainder of the string.
tag = ZeroPadStringStoreTag() and tag = ZeroPadStringStoreTag() and
opcode instanceof Opcode::Store and opcode instanceof Opcode::Store and
resultType instanceof UnknownType and resultType = getUnknownOpaqueType(elementCount * getElementType().getSize())
isGLValue = false
) )
) )
} }
@@ -326,6 +314,13 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
) )
} }
override predicate needsUnknownOpaqueType(int byteSize) {
exists(int elementCount |
zeroInitRange(_, elementCount) and
byteSize = elementCount * getElementType().getSize()
)
}
override int getInstructionResultSize(InstructionTag tag) { override int getInstructionResultSize(InstructionTag tag) {
exists(int elementCount | exists(int elementCount |
zeroInitRange(_, elementCount) and zeroInitRange(_, elementCount) and
@@ -338,7 +333,7 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
} }
private Type getElementType() { private Type getElementType() {
result = getContext().getTargetType().(ArrayType).getBaseType().getUnspecifiedType() result = getContext().getTargetType().getUnspecifiedType().(ArrayType).getBaseType()
} }
/** /**
@@ -348,7 +343,7 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
private predicate zeroInitRange(int startIndex, int elementCount) { private predicate zeroInitRange(int startIndex, int elementCount) {
exists(int targetCount | exists(int targetCount |
startIndex = expr.getUnspecifiedType().(ArrayType).getArraySize() and startIndex = expr.getUnspecifiedType().(ArrayType).getArraySize() and
targetCount = getContext().getTargetType().(ArrayType).getArraySize() and targetCount = getContext().getTargetType().getUnspecifiedType().(ArrayType).getArraySize() and
elementCount = targetCount - startIndex and elementCount = targetCount - startIndex and
elementCount > 0 elementCount > 0
) )
@@ -359,9 +354,7 @@ class TranslatedConstructorInitialization extends TranslatedDirectInitialization
StructorCallContext { StructorCallContext {
override ConstructorCall expr; override ConstructorCall expr;
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
none() none()
} }
@@ -412,13 +405,10 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
*/ */
final int getOrder() { result = field.getInitializationOrder() } final int getOrder() { result = field.getInitializationOrder() }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = getFieldAddressTag() and tag = getFieldAddressTag() and
opcode instanceof Opcode::FieldAddress and opcode instanceof Opcode::FieldAddress and
resultType = field.getUnspecifiedType() and resultType = getTypeForGLValue(field.getType())
isGLValue = true
} }
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
@@ -481,20 +471,16 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
TTranslatedFieldValueInitialization { TTranslatedFieldValueInitialization {
TranslatedFieldValueInitialization() { this = TTranslatedFieldValueInitialization(ast, field) } TranslatedFieldValueInitialization() { this = TTranslatedFieldValueInitialization(ast, field) }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue TranslatedFieldInitialization.super.hasInstruction(opcode, tag, resultType)
) {
TranslatedFieldInitialization.super.hasInstruction(opcode, tag, resultType, isGLValue)
or or
tag = getFieldDefaultValueTag() and tag = getFieldDefaultValueTag() and
opcode instanceof Opcode::Constant and opcode instanceof Opcode::Constant and
resultType = field.getUnspecifiedType() and resultType = getTypeForPRValue(field.getType())
isGLValue = false
or or
tag = getFieldDefaultValueStoreTag() and tag = getFieldDefaultValueStoreTag() and
opcode instanceof Opcode::Store and opcode instanceof Opcode::Store and
resultType = field.getUnspecifiedType() and resultType = getTypeForPRValue(field.getUnspecifiedType())
isGLValue = false
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -557,18 +543,14 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
final override Instruction getFirstInstruction() { result = getInstruction(getElementIndexTag()) } final override Instruction getFirstInstruction() { result = getInstruction(getElementIndexTag()) }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = getElementIndexTag() and tag = getElementIndexTag() and
opcode instanceof Opcode::Constant and opcode instanceof Opcode::Constant and
resultType = getIntType() and resultType = getIntType()
isGLValue = false
or or
tag = getElementAddressTag() and tag = getElementAddressTag() and
opcode instanceof Opcode::PointerAdd and opcode instanceof Opcode::PointerAdd and
resultType = getElementType() and resultType = getTypeForGLValue(getElementType())
isGLValue = true
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -606,7 +588,7 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
final ArrayOrVectorAggregateLiteral getInitList() { result = initList } final ArrayOrVectorAggregateLiteral getInitList() { result = initList }
final Type getElementType() { result = initList.getElementType().getUnspecifiedType() } final Type getElementType() { result = initList.getElementType() }
} }
/** /**
@@ -659,20 +641,16 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
this = TTranslatedElementValueInitialization(initList, elementIndex, elementCount) this = TTranslatedElementValueInitialization(initList, elementIndex, elementCount)
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue TranslatedElementInitialization.super.hasInstruction(opcode, tag, resultType)
) {
TranslatedElementInitialization.super.hasInstruction(opcode, tag, resultType, isGLValue)
or or
tag = getElementDefaultValueTag() and tag = getElementDefaultValueTag() and
opcode instanceof Opcode::Constant and opcode instanceof Opcode::Constant and
resultType = getDefaultValueType() and resultType = getDefaultValueType()
isGLValue = false
or or
tag = getElementDefaultValueStoreTag() and tag = getElementDefaultValueStoreTag() and
opcode instanceof Opcode::Store and opcode instanceof Opcode::Store and
resultType = getDefaultValueType() and resultType = getDefaultValueType()
isGLValue = false
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -726,6 +704,10 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
override int getElementIndex() { result = elementIndex } override int getElementIndex() { result = elementIndex }
override predicate needsUnknownOpaqueType(int byteSize) {
elementCount != 0 and byteSize = elementCount * getElementType().getSize()
}
private InstructionTag getElementDefaultValueTag() { private InstructionTag getElementDefaultValueTag() {
result = InitializerElementDefaultValueTag() result = InitializerElementDefaultValueTag()
} }
@@ -734,8 +716,10 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
result = InitializerElementDefaultValueStoreTag() result = InitializerElementDefaultValueStoreTag()
} }
private Type getDefaultValueType() { private CppType getDefaultValueType() {
if elementCount = 1 then result = getElementType() else result instanceof UnknownType if elementCount = 1
then result = getTypeForPRValue(getElementType())
else result = getUnknownOpaqueType(elementCount * getElementType().getSize())
} }
} }
@@ -766,13 +750,10 @@ abstract class TranslatedStructorCallFromStructor extends TranslatedElement, Str
abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStructor { abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStructor {
final override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } final override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
final override predicate hasInstruction( final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
opcode instanceof Opcode::ConvertToBase and opcode instanceof Opcode::ConvertToBase and
resultType = call.getTarget().getDeclaringType().getUnspecifiedType() and resultType = getTypeForGLValue(call.getTarget().getDeclaringType())
isGLValue = true
} }
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -822,9 +803,7 @@ class TranslatedConstructorDelegationInit extends TranslatedConstructorCallFromC
result = getStructorCall().getFirstInstruction() result = getStructorCall().getFirstInstruction()
} }
final override predicate hasInstruction( final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
none() none()
} }

View File

@@ -1,6 +1,7 @@
private import cpp private import cpp
private import semmle.code.cpp.ir.internal.IRUtilities private import semmle.code.cpp.ir.internal.IRUtilities
private import semmle.code.cpp.ir.implementation.internal.OperandTag private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.CppType
private import semmle.code.cpp.ir.internal.TempVariableTag private import semmle.code.cpp.ir.internal.TempVariableTag
private import InstructionTag private import InstructionTag
private import TranslatedCondition private import TranslatedCondition
@@ -35,13 +36,10 @@ class TranslatedEmptyStmt extends TranslatedStmt {
override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
opcode instanceof Opcode::NoOp and opcode instanceof Opcode::NoOp and
resultType instanceof VoidType and resultType = getVoidType()
isGLValue = false
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -63,9 +61,7 @@ class TranslatedDeclStmt extends TranslatedStmt {
override TranslatedElement getChild(int id) { result = getDeclarationEntry(id) } override TranslatedElement getChild(int id) { result = getDeclarationEntry(id) }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
none() none()
} }
@@ -112,9 +108,7 @@ class TranslatedExprStmt extends TranslatedStmt {
override TranslatedElement getChild(int id) { id = 0 and result = getExpr() } override TranslatedElement getChild(int id) { id = 0 and result = getExpr() }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
none() none()
} }
@@ -145,13 +139,10 @@ class TranslatedReturnValueStmt extends TranslatedReturnStmt, InitializationCont
result = getInstruction(InitializerVariableAddressTag()) result = getInstruction(InitializerVariableAddressTag())
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = InitializerVariableAddressTag() and tag = InitializerVariableAddressTag() and
opcode instanceof Opcode::VariableAddress and opcode instanceof Opcode::VariableAddress and
resultType = getEnclosingFunction().getReturnVariable().getType() and resultType = getTypeForGLValue(getEnclosingFunction().getReturnType())
isGLValue = true
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -174,7 +165,7 @@ class TranslatedReturnValueStmt extends TranslatedReturnStmt, InitializationCont
result = getInstruction(InitializerVariableAddressTag()) result = getInstruction(InitializerVariableAddressTag())
} }
override Type getTargetType() { result = getEnclosingFunction().getReturnVariable().getType() } override Type getTargetType() { result = getEnclosingFunction().getReturnType() }
TranslatedInitialization getInitialization() { TranslatedInitialization getInitialization() {
result = getTranslatedInitialization(stmt.getExpr().getFullyConverted()) result = getTranslatedInitialization(stmt.getExpr().getFullyConverted())
@@ -188,13 +179,10 @@ class TranslatedReturnVoidStmt extends TranslatedReturnStmt {
override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
opcode instanceof Opcode::NoOp and opcode instanceof Opcode::NoOp and
resultType instanceof VoidType and resultType = getVoidType()
isGLValue = false
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -218,9 +206,7 @@ class TranslatedTryStmt extends TranslatedStmt {
result = getHandler(id - 1) result = getHandler(id - 1)
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
none() none()
} }
@@ -262,14 +248,11 @@ class TranslatedBlock extends TranslatedStmt {
override TranslatedElement getChild(int id) { result = getStmt(id) } override TranslatedElement getChild(int id) { result = getStmt(id) }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
isEmpty() and isEmpty() and
opcode instanceof Opcode::NoOp and opcode instanceof Opcode::NoOp and
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
resultType instanceof VoidType and resultType = getVoidType()
isGLValue = false
} }
override Instruction getFirstInstruction() { override Instruction getFirstInstruction() {
@@ -330,13 +313,10 @@ abstract class TranslatedHandler extends TranslatedStmt {
class TranslatedCatchByTypeHandler extends TranslatedHandler { class TranslatedCatchByTypeHandler extends TranslatedHandler {
TranslatedCatchByTypeHandler() { exists(stmt.getParameter()) } TranslatedCatchByTypeHandler() { exists(stmt.getParameter()) }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = CatchTag() and tag = CatchTag() and
opcode instanceof Opcode::CatchByType and opcode instanceof Opcode::CatchByType and
resultType instanceof VoidType and resultType = getVoidType()
isGLValue = false
} }
override TranslatedElement getChild(int id) { override TranslatedElement getChild(int id) {
@@ -362,9 +342,9 @@ class TranslatedCatchByTypeHandler extends TranslatedHandler {
) )
} }
override Type getInstructionExceptionType(InstructionTag tag) { override CppType getInstructionExceptionType(InstructionTag tag) {
tag = CatchTag() and tag = CatchTag() and
result = stmt.getParameter().getType() result = getTypeForPRValue(stmt.getParameter().getType())
} }
private TranslatedParameter getParameter() { private TranslatedParameter getParameter() {
@@ -378,13 +358,10 @@ class TranslatedCatchByTypeHandler extends TranslatedHandler {
class TranslatedCatchAnyHandler extends TranslatedHandler { class TranslatedCatchAnyHandler extends TranslatedHandler {
TranslatedCatchAnyHandler() { not exists(stmt.getParameter()) } TranslatedCatchAnyHandler() { not exists(stmt.getParameter()) }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = CatchTag() and tag = CatchTag() and
opcode instanceof Opcode::CatchAny and opcode instanceof Opcode::CatchAny and
resultType instanceof VoidType and resultType = getVoidType()
isGLValue = false
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -436,9 +413,7 @@ class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
result = getParent().getChildSuccessor(this) result = getParent().getChildSuccessor(this)
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
none() none()
} }
} }
@@ -466,9 +441,7 @@ abstract class TranslatedLoop extends TranslatedStmt, ConditionContext {
id = 1 and result = getBody() id = 1 and result = getBody()
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
none() none()
} }
@@ -597,9 +570,7 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
result = getCondition().getFirstInstruction() result = getCondition().getFirstInstruction()
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
none() none()
} }
@@ -649,13 +620,10 @@ class TranslatedJumpStmt extends TranslatedStmt {
override TranslatedElement getChild(int id) { none() } override TranslatedElement getChild(int id) { none() }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = OnlyInstructionTag() and tag = OnlyInstructionTag() and
opcode instanceof Opcode::NoOp and opcode instanceof Opcode::NoOp and
resultType instanceof VoidType and resultType = getVoidType()
isGLValue = false
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -693,13 +661,10 @@ class TranslatedSwitchStmt extends TranslatedStmt {
id = 1 and result = getBody() id = 1 and result = getBody()
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = SwitchBranchTag() and tag = SwitchBranchTag() and
opcode instanceof Opcode::Switch and opcode instanceof Opcode::Switch and
resultType instanceof VoidType and resultType = getVoidType()
isGLValue = false
} }
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
@@ -727,37 +692,20 @@ class TranslatedSwitchStmt extends TranslatedStmt {
class TranslatedAsmStmt extends TranslatedStmt { class TranslatedAsmStmt extends TranslatedStmt {
override AsmStmt stmt; override AsmStmt stmt;
override TranslatedElement getChild(int id) { none() } override TranslatedExpr getChild(int id) {
result = getTranslatedExpr(stmt.getChild(id).(Expr).getFullyConverted())
}
override Instruction getFirstInstruction() { override Instruction getFirstInstruction() {
if exists(stmt.getChild(0)) if exists(getChild(0))
then result = getInstruction(AsmInputTag(0)) then result = getChild(0).getFirstInstruction()
else result = getInstruction(AsmTag()) else result = getInstruction(AsmTag())
} }
override predicate hasInstruction( override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
Opcode opcode, InstructionTag tag, Type resultType, boolean isGLValue
) {
tag = AsmTag() and tag = AsmTag() and
opcode instanceof Opcode::InlineAsm and opcode instanceof Opcode::InlineAsm and
resultType instanceof UnknownType and resultType = getUnknownType()
isGLValue = false
or
exists(int index, VariableAccess va |
tag = AsmInputTag(index) and
stmt.getChild(index) = va and
opcode instanceof Opcode::VariableAddress and
resultType = va.getType().getUnspecifiedType() and
isGLValue = true
)
}
override IRVariable getInstructionVariable(InstructionTag tag) {
exists(int index |
tag = AsmInputTag(index) and
result = getIRUserVariable(stmt.getEnclosingFunction(),
stmt.getChild(index).(VariableAccess).getTarget())
)
} }
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
@@ -768,29 +716,28 @@ class TranslatedAsmStmt extends TranslatedStmt {
exists(int index | exists(int index |
tag = AsmTag() and tag = AsmTag() and
operandTag = asmOperand(index) and operandTag = asmOperand(index) and
result = getInstruction(AsmInputTag(index)) result = getChild(index).getResult()
) )
} }
final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
tag = AsmTag() and tag = AsmTag() and
operandTag instanceof SideEffectOperandTag and operandTag instanceof SideEffectOperandTag and
result instanceof UnknownType result = getUnknownType()
} }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = AsmTag() and tag = AsmTag() and
result = getParent().getChildSuccessor(this) and result = getParent().getChildSuccessor(this) and
kind instanceof GotoEdge kind instanceof GotoEdge
or }
override Instruction getChildSuccessor(TranslatedElement child) {
exists(int index | exists(int index |
tag = AsmInputTag(index) and child = getChild(index) and
kind instanceof GotoEdge and if exists(getChild(index + 1))
if exists(stmt.getChild(index + 1)) then result = getChild(index + 1).getFirstInstruction()
then result = getInstruction(AsmInputTag(index + 1))
else result = getInstruction(AsmTag()) else result = getInstruction(AsmTag())
) )
} }
override Instruction getChildSuccessor(TranslatedElement child) { none() }
} }

View File

@@ -5,6 +5,7 @@ import IRVariable
import Operand import Operand
private import internal.IRImports as Imports private import internal.IRImports as Imports
import Imports::EdgeKind import Imports::EdgeKind
import Imports::IRType
import Imports::MemoryAccessKind import Imports::MemoryAccessKind
private newtype TIRPropertyProvider = MkIRPropertyProvider() private newtype TIRPropertyProvider = MkIRPropertyProvider()

View File

@@ -1,2 +1,3 @@
private import IR private import IR
import InstructionSanity import InstructionSanity
import IRTypeSanity

View File

@@ -5,6 +5,7 @@ import Imports::TempVariableTag
private import Imports::IRUtilities private import Imports::IRUtilities
private import Imports::TTempVariableTag private import Imports::TTempVariableTag
private import Imports::TIRVariable private import Imports::TIRVariable
private import Imports::IRType
IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) {
result.getVariable() = var and result.getVariable() = var and
@@ -24,7 +25,17 @@ abstract class IRVariable extends TIRVariable {
/** /**
* Gets the type of the variable. * Gets the type of the variable.
*/ */
abstract Language::Type getType(); final Language::Type getType() { getLanguageType().hasType(result, false) }
/**
* Gets the language-neutral type of the variable.
*/
final IRType getIRType() { result = getLanguageType().getIRType() }
/**
* Gets the type of the variable.
*/
abstract Language::LanguageType getLanguageType();
/** /**
* Gets the AST node that declared this variable, or that introduced this * Gets the AST node that declared this variable, or that introduced this
@@ -59,7 +70,7 @@ abstract class IRVariable extends TIRVariable {
*/ */
class IRUserVariable extends IRVariable, TIRUserVariable { class IRUserVariable extends IRVariable, TIRUserVariable {
Language::Variable var; Language::Variable var;
Language::Type type; Language::LanguageType type;
IRUserVariable() { this = TIRUserVariable(var, type, func) } IRUserVariable() { this = TIRUserVariable(var, type, func) }
@@ -71,7 +82,7 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
result = getVariable().toString() + " " + getVariable().getLocation().toString() result = getVariable().toString() + " " + getVariable().getLocation().toString()
} }
final override Language::Type getType() { result = type } final override Language::LanguageType getLanguageType() { result = type }
/** /**
* Gets the original user-declared variable. * Gets the original user-declared variable.
@@ -110,11 +121,11 @@ IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable { class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
Language::AST ast; Language::AST ast;
TempVariableTag tag; TempVariableTag tag;
Language::Type type; Language::LanguageType type;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) } IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
final override Language::Type getType() { result = type } final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast } final override Language::AST getAST() { result = ast }

View File

@@ -5,6 +5,7 @@ import IRVariable
import Operand import Operand
private import internal.InstructionImports as Imports private import internal.InstructionImports as Imports
import Imports::EdgeKind import Imports::EdgeKind
import Imports::IRType
import Imports::MemoryAccessKind import Imports::MemoryAccessKind
import Imports::Opcode import Imports::Opcode
private import Imports::OperandTag private import Imports::OperandTag
@@ -49,7 +50,8 @@ module InstructionSanity {
( (
opcode instanceof ReadSideEffectOpcode or opcode instanceof ReadSideEffectOpcode or
opcode instanceof Opcode::InlineAsm or opcode instanceof Opcode::InlineAsm or
opcode instanceof Opcode::CallSideEffect opcode instanceof Opcode::CallSideEffect or
opcode instanceof Opcode::AliasedUse
) and ) and
tag instanceof SideEffectOperandTag tag instanceof SideEffectOperandTag
) )
@@ -113,10 +115,12 @@ module InstructionSanity {
} }
query predicate missingOperandType(Operand operand, string message) { query predicate missingOperandType(Operand operand, string message) {
exists(Language::Function func | exists(Language::Function func, Instruction use |
not exists(operand.getType()) and not exists(operand.getType()) and
func = operand.getUse().getEnclosingFunction() and use = operand.getUse() and
message = "Operand missing type in function '" + Language::getIdentityString(func) + "'." func = use.getEnclosingFunction() and
message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString()
+ "' missing type in function '" + Language::getIdentityString(func) + "'."
) )
} }
@@ -260,6 +264,7 @@ module InstructionSanity {
) { ) {
exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
not useOperand.getUse() instanceof UnmodeledUseInstruction and not useOperand.getUse() instanceof UnmodeledUseInstruction and
not defInstr instanceof UnmodeledDefinitionInstruction and
pointOfEvaluation(useOperand, useBlock, useIndex) and pointOfEvaluation(useOperand, useBlock, useIndex) and
defInstr = useOperand.getAnyDef() and defInstr = useOperand.getAnyDef() and
( (
@@ -321,7 +326,7 @@ class Instruction extends Construction::TInstruction {
} }
private string getResultPrefix() { private string getResultPrefix() {
if getResultType() instanceof Language::VoidType if getResultIRType() instanceof IRVoidType
then result = "v" then result = "v"
else else
if hasMemoryResult() if hasMemoryResult()
@@ -353,23 +358,6 @@ class Instruction extends Construction::TInstruction {
) )
} }
bindingset[type]
private string getValueCategoryString(string type) {
if isGLValue() then result = "glval<" + type + ">" else result = type
}
string getResultTypeString() {
exists(string valcat |
valcat = getValueCategoryString(getResultType().toString()) and
if
getResultType() instanceof Language::UnknownType and
not isGLValue() and
exists(getResultSize())
then result = valcat + "[" + getResultSize().toString() + "]"
else result = valcat
)
}
/** /**
* Gets a human-readable string that uniquely identifies this instruction * Gets a human-readable string that uniquely identifies this instruction
* within the function. This string is used to refer to this instruction when * within the function. This string is used to refer to this instruction when
@@ -389,7 +377,9 @@ class Instruction extends Construction::TInstruction {
* *
* Example: `r1_1(int*)` * Example: `r1_1(int*)`
*/ */
final string getResultString() { result = getResultId() + "(" + getResultTypeString() + ")" } final string getResultString() {
result = getResultId() + "(" + getResultLanguageType().getDumpString() + ")"
}
/** /**
* Gets a string describing the operands of this instruction, suitable for * Gets a string describing the operands of this instruction, suitable for
@@ -457,6 +447,16 @@ class Instruction extends Construction::TInstruction {
result = Construction::getInstructionUnconvertedResultExpression(this) result = Construction::getInstructionUnconvertedResultExpression(this)
} }
final Language::LanguageType getResultLanguageType() {
result = Construction::getInstructionResultType(this)
}
/**
* Gets the type of the result produced by this instruction. If the instruction does not produce
* a result, its result type will be `IRVoidType`.
*/
final IRType getResultIRType() { result = getResultLanguageType().getIRType() }
/** /**
* Gets the type of the result produced by this instruction. If the * Gets the type of the result produced by this instruction. If the
* instruction does not produce a result, its result type will be `VoidType`. * instruction does not produce a result, its result type will be `VoidType`.
@@ -464,7 +464,16 @@ class Instruction extends Construction::TInstruction {
* If `isGLValue()` holds, then the result type of this instruction should be * If `isGLValue()` holds, then the result type of this instruction should be
* thought of as "pointer to `getResultType()`". * thought of as "pointer to `getResultType()`".
*/ */
final Language::Type getResultType() { Construction::instructionHasType(this, result, _) } final Language::Type getResultType() {
exists(Language::LanguageType resultType |
resultType = getResultLanguageType() and
(
resultType.hasUnspecifiedType(result, _)
or
not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType
)
)
}
/** /**
* Holds if the result produced by this instruction is a glvalue. If this * Holds if the result produced by this instruction is a glvalue. If this
@@ -484,7 +493,7 @@ class Instruction extends Construction::TInstruction {
* result of the `Load` instruction is a prvalue of type `int`, representing * result of the `Load` instruction is a prvalue of type `int`, representing
* the integer value loaded from variable `x`. * the integer value loaded from variable `x`.
*/ */
final predicate isGLValue() { Construction::instructionHasType(this, _, true) } final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) }
/** /**
* Gets the size of the result produced by this instruction, in bytes. If the * Gets the size of the result produced by this instruction, in bytes. If the
@@ -493,16 +502,7 @@ class Instruction extends Construction::TInstruction {
* If `this.isGLValue()` holds for this instruction, the value of * If `this.isGLValue()` holds for this instruction, the value of
* `getResultSize()` will always be the size of a pointer. * `getResultSize()` will always be the size of a pointer.
*/ */
final int getResultSize() { final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() }
if isGLValue()
then
// a glvalue is always pointer-sized.
result = Language::getPointerSize()
else
if getResultType() instanceof Language::UnknownType
then result = Construction::getInstructionResultSize(this)
else result = Language::getTypeSize(getResultType())
}
/** /**
* Gets the opcode that specifies the operation performed by this instruction. * Gets the opcode that specifies the operation performed by this instruction.
@@ -1384,7 +1384,7 @@ class CatchInstruction extends Instruction {
* An instruction that catches an exception of a specific type. * An instruction that catches an exception of a specific type.
*/ */
class CatchByTypeInstruction extends CatchInstruction { class CatchByTypeInstruction extends CatchInstruction {
Language::Type exceptionType; Language::LanguageType exceptionType;
CatchByTypeInstruction() { CatchByTypeInstruction() {
getOpcode() instanceof Opcode::CatchByType and getOpcode() instanceof Opcode::CatchByType and
@@ -1396,7 +1396,7 @@ class CatchByTypeInstruction extends CatchInstruction {
/** /**
* Gets the type of exception to be caught. * Gets the type of exception to be caught.
*/ */
final Language::Type getExceptionType() { result = exceptionType } final Language::LanguageType getExceptionType() { result = exceptionType }
} }
/** /**
@@ -1423,6 +1423,13 @@ class AliasedDefinitionInstruction extends Instruction {
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess } final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
} }
/**
* An instruction that consumes all escaped memory on exit from the function.
*/
class AliasedUseInstruction extends Instruction {
AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse }
}
class UnmodeledUseInstruction extends Instruction { class UnmodeledUseInstruction extends Instruction {
UnmodeledUseInstruction() { getOpcode() instanceof Opcode::UnmodeledUse } UnmodeledUseInstruction() { getOpcode() instanceof Opcode::UnmodeledUse }

View File

@@ -1,9 +1,10 @@
private import internal.IRInternal private import internal.IRInternal
import Instruction private import Instruction
import IRBlock private import IRBlock
private import internal.OperandImports as Imports private import internal.OperandImports as Imports
import Imports::MemoryAccessKind private import Imports::MemoryAccessKind
import Imports::Overlap private import Imports::IRType
private import Imports::Overlap
private import Imports::OperandTag private import Imports::OperandTag
cached cached
@@ -143,22 +144,40 @@ class Operand extends TOperand {
* the definition type, such as in the case of a partial read or a read from a pointer that * the definition type, such as in the case of a partial read or a read from a pointer that
* has been cast to a different type. * has been cast to a different type.
*/ */
Language::Type getType() { result = getAnyDef().getResultType() } Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() }
/**
* Gets the language-neutral type of the value consumed by this operand. This is usually the same
* as the result type of the definition instruction consumed by this operand. For register
* operands, this is always the case. For some memory operands, the operand type may be different
* from the definition type, such as in the case of a partial read or a read from a pointer that
* has been cast to a different type.
*/
final IRType getIRType() { result = getLanguageType().getIRType() }
/**
* Gets the type of the value consumed by this operand. This is usually the same as the
* result type of the definition instruction consumed by this operand. For register operands,
* this is always the case. For some memory operands, the operand type may be different from
* the definition type, such as in the case of a partial read or a read from a pointer that
* has been cast to a different type.
*/
final Language::Type getType() { getLanguageType().hasType(result, _) }
/** /**
* Holds if the value consumed by this operand is a glvalue. If this * Holds if the value consumed by this operand is a glvalue. If this
* holds, the value of the operand represents the address of a location, * holds, the value of the operand represents the address of a location,
* and the type of the location is given by `getType()`. If this does * and the type of the location is given by `getType()`. If this does
* not hold, the value of the operand represents a value whose type is * not hold, the value of the operand represents a value whose type is
* given by `getResultType()`. * given by `getType()`.
*/ */
predicate isGLValue() { getAnyDef().isGLValue() } final predicate isGLValue() { getLanguageType().hasType(_, true) }
/** /**
* Gets the size of the value consumed by this operand, in bytes. If the operand does not have * Gets the size of the value consumed by this operand, in bytes. If the operand does not have
* a known constant size, this predicate does not hold. * a known constant size, this predicate does not hold.
*/ */
int getSize() { result = Language::getTypeSize(getType()) } final int getSize() { result = getLanguageType().getByteSize() }
} }
/** /**
@@ -170,11 +189,6 @@ class MemoryOperand extends Operand {
this = TPhiOperand(_, _, _, _) this = TPhiOperand(_, _, _, _)
} }
override predicate isGLValue() {
// A `MemoryOperand` can never be a glvalue
none()
}
/** /**
* Gets the kind of memory access performed by the operand. * Gets the kind of memory access performed by the operand.
*/ */
@@ -239,7 +253,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
class TypedOperand extends NonPhiMemoryOperand { class TypedOperand extends NonPhiMemoryOperand {
override TypedOperandTag tag; override TypedOperandTag tag;
final override Language::Type getType() { final override Language::LanguageType getLanguageType() {
result = Construction::getInstructionOperandType(useInstr, tag) result = Construction::getInstructionOperandType(useInstr, tag)
} }
} }
@@ -381,13 +395,10 @@ class PositionalArgumentOperand extends ArgumentOperand {
class SideEffectOperand extends TypedOperand { class SideEffectOperand extends TypedOperand {
override SideEffectOperandTag tag; override SideEffectOperandTag tag;
final override int getSize() {
if getType() instanceof Language::UnknownType
then result = Construction::getInstructionOperandSize(useInstr, tag)
else result = Language::getTypeSize(getType())
}
override MemoryAccessKind getMemoryAccess() { override MemoryAccessKind getMemoryAccess() {
useInstr instanceof AliasedUseInstruction and
result instanceof NonLocalMayMemoryAccess
or
useInstr instanceof CallSideEffectInstruction and useInstr instanceof CallSideEffectInstruction and
result instanceof EscapedMayMemoryAccess result instanceof EscapedMayMemoryAccess
or or

View File

@@ -1,5 +1,5 @@
private import internal.ValueNumberingInternal private import internal.ValueNumberingInternal
private import cpp private import internal.ValueNumberingImports
private import IR private import IR
/** /**
@@ -23,31 +23,32 @@ newtype TValueNumber =
initializeParameterValueNumber(_, irFunc, var) initializeParameterValueNumber(_, irFunc, var)
} or } or
TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or
TConstantValueNumber(IRFunction irFunc, Type type, string value) { TConstantValueNumber(IRFunction irFunc, IRType type, string value) {
constantValueNumber(_, irFunc, type, value) constantValueNumber(_, irFunc, type, value)
} or } or
TStringConstantValueNumber(IRFunction irFunc, Type type, string value) { TStringConstantValueNumber(IRFunction irFunc, IRType type, string value) {
stringConstantValueNumber(_, irFunc, type, value) stringConstantValueNumber(_, irFunc, type, value)
} or } or
TFieldAddressValueNumber(IRFunction irFunc, Field field, ValueNumber objectAddress) { TFieldAddressValueNumber(IRFunction irFunc, Language::Field field, ValueNumber objectAddress) {
fieldAddressValueNumber(_, irFunc, field, objectAddress) fieldAddressValueNumber(_, irFunc, field, objectAddress)
} or } or
TBinaryValueNumber( TBinaryValueNumber(
IRFunction irFunc, Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand
) { ) {
binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand) binaryValueNumber(_, irFunc, opcode, type, leftOperand, rightOperand)
} or } or
TPointerArithmeticValueNumber( TPointerArithmeticValueNumber(
IRFunction irFunc, Opcode opcode, Type type, int elementSize, ValueNumber leftOperand, IRFunction irFunc, Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
ValueNumber rightOperand ValueNumber rightOperand
) { ) {
pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand) pointerArithmeticValueNumber(_, irFunc, opcode, type, elementSize, leftOperand, rightOperand)
} or } or
TUnaryValueNumber(IRFunction irFunc, Opcode opcode, Type type, ValueNumber operand) { TUnaryValueNumber(IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand) {
unaryValueNumber(_, irFunc, opcode, type, operand) unaryValueNumber(_, irFunc, opcode, type, operand)
} or } or
TInheritanceConversionValueNumber( TInheritanceConversionValueNumber(
IRFunction irFunc, Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand IRFunction irFunc, Opcode opcode, Language::Class baseClass, Language::Class derivedClass,
ValueNumber operand
) { ) {
inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand) inheritanceConversionValueNumber(_, irFunc, opcode, baseClass, derivedClass, operand)
} or } or
@@ -59,7 +60,7 @@ newtype TValueNumber =
class ValueNumber extends TValueNumber { class ValueNumber extends TValueNumber {
final string toString() { result = getExampleInstruction().getResultId() } final string toString() { result = getExampleInstruction().getResultId() }
final Location getLocation() { result = getExampleInstruction().getLocation() } final Language::Location getLocation() { result = getExampleInstruction().getLocation() }
/** /**
* Gets the instructions that have been assigned this value number. This will always produce at * Gets the instructions that have been assigned this value number. This will always produce at
@@ -150,23 +151,23 @@ private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRF
} }
private predicate constantValueNumber( private predicate constantValueNumber(
ConstantInstruction instr, IRFunction irFunc, Type type, string value ConstantInstruction instr, IRFunction irFunc, IRType type, string value
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
instr.getResultType() = type and instr.getResultIRType() = type and
instr.getValue() = value instr.getValue() = value
} }
private predicate stringConstantValueNumber( private predicate stringConstantValueNumber(
StringConstantInstruction instr, IRFunction irFunc, Type type, string value StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
instr.getResultType() = type and instr.getResultIRType() = type and
instr.getValue().getValue() = value instr.getValue().getValue() = value
} }
private predicate fieldAddressValueNumber( private predicate fieldAddressValueNumber(
FieldAddressInstruction instr, IRFunction irFunc, Field field, ValueNumber objectAddress FieldAddressInstruction instr, IRFunction irFunc, Language::Field field, ValueNumber objectAddress
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
instr.getField() = field and instr.getField() = field and
@@ -174,43 +175,43 @@ private predicate fieldAddressValueNumber(
} }
private predicate binaryValueNumber( private predicate binaryValueNumber(
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, Type type, ValueNumber leftOperand, BinaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber leftOperand,
ValueNumber rightOperand ValueNumber rightOperand
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
not instr instanceof PointerArithmeticInstruction and not instr instanceof PointerArithmeticInstruction and
instr.getOpcode() = opcode and instr.getOpcode() = opcode and
instr.getResultType() = type and instr.getResultIRType() = type and
valueNumber(instr.getLeft()) = leftOperand and valueNumber(instr.getLeft()) = leftOperand and
valueNumber(instr.getRight()) = rightOperand valueNumber(instr.getRight()) = rightOperand
} }
private predicate pointerArithmeticValueNumber( private predicate pointerArithmeticValueNumber(
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, Type type, int elementSize, PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, IRType type,
ValueNumber leftOperand, ValueNumber rightOperand int elementSize, ValueNumber leftOperand, ValueNumber rightOperand
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
instr.getOpcode() = opcode and instr.getOpcode() = opcode and
instr.getResultType() = type and instr.getResultIRType() = type and
instr.getElementSize() = elementSize and instr.getElementSize() = elementSize and
valueNumber(instr.getLeft()) = leftOperand and valueNumber(instr.getLeft()) = leftOperand and
valueNumber(instr.getRight()) = rightOperand valueNumber(instr.getRight()) = rightOperand
} }
private predicate unaryValueNumber( private predicate unaryValueNumber(
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, Type type, ValueNumber operand UnaryInstruction instr, IRFunction irFunc, Opcode opcode, IRType type, ValueNumber operand
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
not instr instanceof InheritanceConversionInstruction and not instr instanceof InheritanceConversionInstruction and
not instr instanceof CopyInstruction and not instr instanceof CopyInstruction and
instr.getOpcode() = opcode and instr.getOpcode() = opcode and
instr.getResultType() = type and instr.getResultIRType() = type and
valueNumber(instr.getUnary()) = operand valueNumber(instr.getUnary()) = operand
} }
private predicate inheritanceConversionValueNumber( private predicate inheritanceConversionValueNumber(
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode, Class baseClass, InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
Class derivedClass, ValueNumber operand Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
) { ) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
instr.getOpcode() = opcode and instr.getOpcode() = opcode and
@@ -225,7 +226,7 @@ private predicate inheritanceConversionValueNumber(
*/ */
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) { private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
instr.getEnclosingIRFunction() = irFunc and instr.getEnclosingIRFunction() = irFunc and
not instr.getResultType() instanceof VoidType and not instr.getResultIRType() instanceof IRVoidType and
not numberableInstruction(instr) not numberableInstruction(instr)
} }
@@ -269,38 +270,41 @@ private ValueNumber nonUniqueValueNumber(Instruction instr) {
initializeThisValueNumber(instr, irFunc) and initializeThisValueNumber(instr, irFunc) and
result = TInitializeThisValueNumber(irFunc) result = TInitializeThisValueNumber(irFunc)
or or
exists(Type type, string value | exists(IRType type, string value |
constantValueNumber(instr, irFunc, type, value) and constantValueNumber(instr, irFunc, type, value) and
result = TConstantValueNumber(irFunc, type, value) result = TConstantValueNumber(irFunc, type, value)
) )
or or
exists(Type type, string value | exists(IRType type, string value |
stringConstantValueNumber(instr, irFunc, type, value) and stringConstantValueNumber(instr, irFunc, type, value) and
result = TStringConstantValueNumber(irFunc, type, value) result = TStringConstantValueNumber(irFunc, type, value)
) )
or or
exists(Field field, ValueNumber objectAddress | exists(Language::Field field, ValueNumber objectAddress |
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
result = TFieldAddressValueNumber(irFunc, field, objectAddress) result = TFieldAddressValueNumber(irFunc, field, objectAddress)
) )
or or
exists(Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand | exists(Opcode opcode, IRType type, ValueNumber leftOperand, ValueNumber rightOperand |
binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and binaryValueNumber(instr, irFunc, opcode, type, leftOperand, rightOperand) and
result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand) result = TBinaryValueNumber(irFunc, opcode, type, leftOperand, rightOperand)
) )
or or
exists(Opcode opcode, Type type, ValueNumber operand | exists(Opcode opcode, IRType type, ValueNumber operand |
unaryValueNumber(instr, irFunc, opcode, type, operand) and unaryValueNumber(instr, irFunc, opcode, type, operand) and
result = TUnaryValueNumber(irFunc, opcode, type, operand) result = TUnaryValueNumber(irFunc, opcode, type, operand)
) )
or or
exists(Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand | exists(
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, ValueNumber operand
|
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand) result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
) )
or or
exists( exists(
Opcode opcode, Type type, int elementSize, ValueNumber leftOperand, ValueNumber rightOperand Opcode opcode, IRType type, int elementSize, ValueNumber leftOperand,
ValueNumber rightOperand
| |
pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand, pointerArithmeticValueNumber(instr, irFunc, opcode, type, elementSize, leftOperand,
rightOperand) and rightOperand) and

View File

@@ -0,0 +1,2 @@
import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.internal.IRCppLanguage as Language

View File

@@ -1,2 +1,3 @@
import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind
import semmle.code.cpp.ir.implementation.IRType as IRType
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.implementation.IRType as IRType
import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag
import semmle.code.cpp.ir.internal.IRUtilities as IRUtilities import semmle.code.cpp.ir.internal.IRUtilities as IRUtilities
import semmle.code.cpp.ir.internal.TempVariableTag as TTempVariableTag import semmle.code.cpp.ir.internal.TempVariableTag as TTempVariableTag

View File

@@ -1,4 +1,5 @@
import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind
import semmle.code.cpp.ir.implementation.IRType as IRType
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
import semmle.code.cpp.ir.implementation.Opcode as Opcode import semmle.code.cpp.ir.implementation.Opcode as Opcode
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
import semmle.code.cpp.ir.implementation.IRType as IRType
import semmle.code.cpp.ir.internal.Overlap as Overlap import semmle.code.cpp.ir.internal.Overlap as Overlap
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag

View File

@@ -4,34 +4,52 @@ private import Alias
private import SSAConstruction private import SSAConstruction
private import DebugSSA private import DebugSSA
bindingset[offset]
private string getKeySuffixForOffset(int offset) {
if offset % 2 = 0 then result = "" else result = "_Chi"
}
bindingset[offset]
private int getIndexForOffset(int offset) { result = offset / 2 }
/** /**
* Property provide that dumps the memory access of each result. Useful for debugging SSA * Property provide that dumps the memory access of each result. Useful for debugging SSA
* construction. * construction.
*/ */
class PropertyProvider extends IRPropertyProvider { class PropertyProvider extends IRPropertyProvider {
override string getInstructionProperty(Instruction instruction, string key) { override string getInstructionProperty(Instruction instruction, string key) {
exists(MemoryLocation location | key = "ResultMemoryLocation" and
location = getResultMemoryLocation(instruction) and result = strictconcat(MemoryLocation loc |
( loc = getResultMemoryLocation(instruction)
key = "ResultMemoryLocation" and result = location.toString() |
or loc.toString(), ","
key = "ResultVirtualVariable" and result = location.getVirtualVariable().toString()
) )
)
or or
exists(MemoryLocation location | key = "ResultVirtualVariable" and
location = getOperandMemoryLocation(instruction.getAnOperand()) and result = strictconcat(MemoryLocation loc |
( loc = getResultMemoryLocation(instruction)
key = "OperandMemoryAccess" and result = location.toString() |
or loc.getVirtualVariable().toString(), ","
key = "OperandVirtualVariable" and result = location.getVirtualVariable().toString()
) )
)
or or
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex | key = "OperandMemoryLocation" and
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and result = strictconcat(MemoryLocation loc |
defBlock.getInstruction(defIndex) = instruction and loc = getOperandMemoryLocation(instruction.getAnOperand())
key = "DefinitionRank[" + useLocation.toString() + "]" and |
loc.toString(), ","
)
or
key = "OperandVirtualVariable" and
result = strictconcat(MemoryLocation loc |
loc = getOperandMemoryLocation(instruction.getAnOperand())
|
loc.getVirtualVariable().toString(), ","
)
or
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defOffset |
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defOffset) and
defBlock.getInstruction(getIndexForOffset(defOffset)) = instruction and
key = "DefinitionRank" + getKeySuffixForOffset(defOffset) + "[" + useLocation.toString() + "]" and
result = defRank.toString() result = defRank.toString()
) )
or or
@@ -41,10 +59,11 @@ class PropertyProvider extends IRPropertyProvider {
result = useRank.toString() result = useRank.toString()
) )
or or
exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defIndex | exists(MemoryLocation useLocation, IRBlock defBlock, int defRank, int defOffset |
hasDefinitionAtRank(useLocation, _, defBlock, defRank, defIndex) and hasDefinitionAtRank(useLocation, _, defBlock, defRank, defOffset) and
defBlock.getInstruction(defIndex) = instruction and defBlock.getInstruction(getIndexForOffset(defOffset)) = instruction and
key = "DefinitionReachesUse[" + useLocation.toString() + "]" and key = "DefinitionReachesUse" + getKeySuffixForOffset(defOffset) + "[" + useLocation.toString()
+ "]" and
result = strictconcat(IRBlock useBlock, int useRank, int useIndex | result = strictconcat(IRBlock useBlock, int useRank, int useIndex |
exists(Instruction useInstruction | exists(Instruction useInstruction |
hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and hasUseAtRank(useLocation, useBlock, useRank, useInstruction) and

View File

@@ -1,8 +1,5 @@
import SSAConstructionInternal import SSAConstructionInternal
private import cpp private import SSAConstructionImports
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.Overlap
private import NewIR private import NewIR
private class OldBlock = Reachability::ReachableBlock; private class OldBlock = Reachability::ReachableBlock;
@@ -18,7 +15,7 @@ private module Cached {
} }
cached cached
predicate functionHasIR(Function func) { predicate functionHasIR(Language::Function func) {
exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func) exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func)
} }
@@ -42,7 +39,7 @@ private module Cached {
not oldInstruction instanceof OldIR::PhiInstruction and not oldInstruction instanceof OldIR::PhiInstruction and
hasChiNode(_, oldInstruction) hasChiNode(_, oldInstruction)
} or } or
Unreached(Function function) { Unreached(Language::Function function) {
exists(OldInstruction oldInstruction | exists(OldInstruction oldInstruction |
function = oldInstruction.getEnclosingFunction() and function = oldInstruction.getEnclosingFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
@@ -50,12 +47,14 @@ private module Cached {
} }
cached cached
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, Type type) { predicate hasTempVariable(
Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
) {
exists(OldIR::IRTempVariable var | exists(OldIR::IRTempVariable var |
var.getEnclosingFunction() = func and var.getEnclosingFunction() = func and
var.getAST() = ast and var.getAST() = ast and
var.getTag() = tag and var.getTag() = tag and
var.getType() = type var.getLanguageType() = type
) )
} }
@@ -135,24 +134,12 @@ private module Cached {
} }
cached cached
Type getInstructionOperandType(Instruction instr, TypedOperandTag tag) { Language::LanguageType getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand | exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand |
oldInstruction = getOldInstruction(instr) and oldInstruction = getOldInstruction(instr) and
oldOperand = oldInstruction.getAnOperand() and oldOperand = oldInstruction.getAnOperand() and
tag = oldOperand.getOperandTag() and tag = oldOperand.getOperandTag() and
result = oldOperand.getType() result = oldOperand.getLanguageType()
)
}
cached
int getInstructionOperandSize(Instruction instr, SideEffectOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::SideEffectOperand oldOperand |
oldInstruction = getOldInstruction(instr) and
oldOperand = oldInstruction.getAnOperand() and
tag = oldOperand.getOperandTag() and
// Only return a result for operands that need an explicit result size.
oldOperand.getType() instanceof UnknownType and
result = oldOperand.getSize()
) )
} }
@@ -196,20 +183,21 @@ private module Cached {
} }
cached cached
Expr getInstructionConvertedResultExpression(Instruction instruction) { Language::Expr getInstructionConvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getConvertedResultExpression() result = getOldInstruction(instruction).getConvertedResultExpression()
} }
cached cached
Expr getInstructionUnconvertedResultExpression(Instruction instruction) { Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getUnconvertedResultExpression() result = getOldInstruction(instruction).getUnconvertedResultExpression()
} }
/** /*
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node, * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are * that node is its successor in the new successor relation, and the Chi node's successors are
* the new instructions generated from the successors of the old instruction * the new instructions generated from the successors of the old instruction
*/ */
cached cached
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
if hasChiNode(_, getOldInstruction(instruction)) if hasChiNode(_, getOldInstruction(instruction))
@@ -252,7 +240,7 @@ private module Cached {
} }
cached cached
Locatable getInstructionAST(Instruction instruction) { Language::AST getInstructionAST(Instruction instruction) {
exists(OldInstruction oldInstruction | exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) instruction = WrappedInstruction(oldInstruction)
or or
@@ -270,29 +258,25 @@ private module Cached {
} }
cached cached
predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) { Language::LanguageType getInstructionResultType(Instruction instruction) {
exists(OldInstruction oldInstruction | exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) and instruction = WrappedInstruction(oldInstruction) and
type = oldInstruction.getResultType() and result = oldInstruction.getResultLanguageType()
if oldInstruction.isGLValue() then isGLValue = true else isGLValue = false
) )
or or
exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar | exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar |
instruction = Chi(oldInstruction) and instruction = Chi(oldInstruction) and
hasChiNode(vvar, oldInstruction) and hasChiNode(vvar, oldInstruction) and
type = vvar.getType() and result = vvar.getType()
isGLValue = false
) )
or or
exists(Alias::MemoryLocation location | exists(Alias::MemoryLocation location |
instruction = Phi(_, location) and instruction = Phi(_, location) and
type = location.getType() and result = location.getType()
isGLValue = false
) )
or or
instruction = Unreached(_) and instruction = Unreached(_) and
type instanceof VoidType and result = Language::getVoidType()
isGLValue = false
} }
cached cached
@@ -338,7 +322,7 @@ private module Cached {
} }
cached cached
Field getInstructionField(Instruction instruction) { Language::Field getInstructionField(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
} }
@@ -348,7 +332,7 @@ private module Cached {
} }
cached cached
Function getInstructionFunction(Instruction instruction) { Language::Function getInstructionFunction(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
} }
@@ -358,19 +342,19 @@ private module Cached {
} }
cached cached
StringLiteral getInstructionStringLiteral(Instruction instruction) { Language::StringLiteral getInstructionStringLiteral(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue() result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue()
} }
cached cached
BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result = getOldInstruction(instruction) result = getOldInstruction(instruction)
.(OldIR::BuiltInOperationInstruction) .(OldIR::BuiltInOperationInstruction)
.getBuiltInOperation() .getBuiltInOperation()
} }
cached cached
Type getInstructionExceptionType(Instruction instruction) { Language::LanguageType getInstructionExceptionType(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType() result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
} }
@@ -380,14 +364,9 @@ private module Cached {
} }
cached cached
int getInstructionResultSize(Instruction instruction) { predicate getInstructionInheritance(
// Only return a result for instructions that needed an explicit result size. Instruction instruction, Language::Class baseClass, Language::Class derivedClass
instruction.getResultType() instanceof UnknownType and ) {
result = getOldInstruction(instruction).getResultSize()
}
cached
predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) {
exists(OldIR::InheritanceConversionInstruction oldInstr | exists(OldIR::InheritanceConversionInstruction oldInstr |
oldInstr = getOldInstruction(instruction) and oldInstr = getOldInstruction(instruction) and
baseClass = oldInstr.getBaseClass() and baseClass = oldInstr.getBaseClass() and

View File

@@ -0,0 +1,3 @@
import semmle.code.cpp.ir.implementation.Opcode
import semmle.code.cpp.ir.implementation.internal.OperandTag
import semmle.code.cpp.ir.internal.Overlap

View File

@@ -2,4 +2,5 @@ import semmle.code.cpp.ir.implementation.raw.IR as OldIR
import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability
import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import SimpleSSA as Alias import SimpleSSA as Alias

View File

@@ -1,24 +1,20 @@
import AliasAnalysis import AliasAnalysis
private import cpp private import SimpleSSAImports
private import semmle.code.cpp.ir.implementation.raw.IR
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.Overlap
private class IntValue = Ints::IntValue; private class IntValue = Ints::IntValue;
private predicate hasResultMemoryAccess( private predicate hasResultMemoryAccess(
Instruction instr, IRVariable var, Type type, IntValue bitOffset Instruction instr, IRVariable var, Language::LanguageType type, IntValue bitOffset
) { ) {
resultPointsTo(instr.getResultAddressOperand().getAnyDef(), var, bitOffset) and resultPointsTo(instr.getResultAddressOperand().getAnyDef(), var, bitOffset) and
type = instr.getResultType() type = instr.getResultLanguageType()
} }
private predicate hasOperandMemoryAccess( private predicate hasOperandMemoryAccess(
MemoryOperand operand, IRVariable var, Type type, IntValue bitOffset MemoryOperand operand, IRVariable var, Language::LanguageType type, IntValue bitOffset
) { ) {
resultPointsTo(operand.getAddressOperand().getAnyDef(), var, bitOffset) and resultPointsTo(operand.getAddressOperand().getAnyDef(), var, bitOffset) and
type = operand.getType() type = operand.getLanguageType()
} }
/** /**
@@ -30,17 +26,17 @@ private predicate isVariableModeled(IRVariable var) {
not variableAddressEscapes(var) and not variableAddressEscapes(var) and
// There's no need to check for the right size. An `IRVariable` never has an `UnknownType`, so the test for // There's no need to check for the right size. An `IRVariable` never has an `UnknownType`, so the test for
// `type = var.getType()` is sufficient. // `type = var.getType()` is sufficient.
forall(Instruction instr, Type type, IntValue bitOffset | forall(Instruction instr, Language::LanguageType type, IntValue bitOffset |
hasResultMemoryAccess(instr, var, type, bitOffset) hasResultMemoryAccess(instr, var, type, bitOffset)
| |
bitOffset = 0 and bitOffset = 0 and
type = var.getType() type.getIRType() = var.getIRType()
) and ) and
forall(MemoryOperand operand, Type type, IntValue bitOffset | forall(MemoryOperand operand, Language::LanguageType type, IntValue bitOffset |
hasOperandMemoryAccess(operand, var, type, bitOffset) hasOperandMemoryAccess(operand, var, type, bitOffset)
| |
bitOffset = 0 and bitOffset = 0 and
type = var.getType() type.getIRType() = var.getIRType()
) )
} }
@@ -59,7 +55,7 @@ class MemoryLocation extends TMemoryLocation {
final VirtualVariable getVirtualVariable() { result = this } final VirtualVariable getVirtualVariable() { result = this }
final Type getType() { result = var.getType() } final Language::LanguageType getType() { result = var.getLanguageType() }
final string getUniqueId() { result = var.getUniqueId() } final string getUniqueId() { result = var.getUniqueId() }
} }

View File

@@ -0,0 +1,5 @@
import semmle.code.cpp.ir.implementation.raw.IR
import semmle.code.cpp.ir.internal.IntegerConstant as Ints
import semmle.code.cpp.ir.implementation.internal.OperandTag
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.cpp.ir.internal.Overlap

View File

@@ -0,0 +1,507 @@
private import cpp
private import semmle.code.cpp.Print
private import semmle.code.cpp.ir.implementation.IRType
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
private int getPointerSize() { result = max(any(NullPointerType t).getSize()) }
/**
* Works around an extractor bug where a function reference gets a size of one byte.
*/
private int getTypeSizeWorkaround(Type type) {
exists(Type unspecifiedType |
unspecifiedType = type.getUnspecifiedType() and
(
unspecifiedType instanceof FunctionReferenceType and
result = getPointerSize()
or
exists(PointerToMemberType ptmType |
ptmType = unspecifiedType and
(
if ptmType.getBaseType().getUnspecifiedType() instanceof RoutineType
then result = getPointerSize() * 2
else result = getPointerSize()
)
)
or
exists(ArrayType arrayType |
// Treat `T[]` as `T*`.
arrayType = unspecifiedType and
not arrayType.hasArraySize() and
result = getPointerSize()
)
)
)
}
private int getTypeSize(Type type) {
if exists(getTypeSizeWorkaround(type))
then result = getTypeSizeWorkaround(type)
else result = type.getSize()
}
/**
* Holds if an `IRErrorType` should exist.
*/
predicate hasErrorType() { exists(ErroneousType t) }
/**
* Holds if an `IRBooleanType` with the specified `byteSize` should exist.
*/
predicate hasBooleanType(int byteSize) { byteSize = getTypeSize(any(BoolType type)) }
private predicate isSigned(IntegralOrEnumType type) {
type.(IntegralType).isSigned()
or
exists(Enum enumType |
// If the enum has an explicit underlying type, we'll determine signedness from that. If not,
// we'll assume unsigned. The actual rules for the implicit underlying type of an enum vary
// between compilers, so we'll need an extractor change to get this 100% right. Until then,
// unsigned is a reasonable default.
enumType = type.getUnspecifiedType() and
enumType.getExplicitUnderlyingType().getUnspecifiedType().(IntegralType).isSigned()
)
}
private predicate isSignedIntegerType(IntegralOrEnumType type) {
isSigned(type) and not type instanceof BoolType
}
private predicate isUnsignedIntegerType(IntegralOrEnumType type) {
not isSigned(type) and not type instanceof BoolType
}
/**
* Holds if an `IRSignedIntegerType` with the specified `byteSize` should exist.
*/
predicate hasSignedIntegerType(int byteSize) {
byteSize = any(IntegralOrEnumType type | isSignedIntegerType(type)).getSize()
}
/**
* Holds if an `IRUnsignedIntegerType` with the specified `byteSize` should exist.
*/
predicate hasUnsignedIntegerType(int byteSize) {
byteSize = any(IntegralOrEnumType type | isUnsignedIntegerType(type)).getSize()
}
/**
* Holds if an `IRFloatingPointType` with the specified `byteSize` should exist.
*/
predicate hasFloatingPointType(int byteSize) { byteSize = any(FloatingPointType type).getSize() }
private predicate isPointerIshType(Type type) {
type instanceof PointerType
or
type instanceof ReferenceType
or
type instanceof NullPointerType
or
// Treat `T[]` as a pointer. The only place we should see these is as the type of a parameter. If
// the corresponding decayed `T*` type is available, we'll use that, but if it's not available,
// we're stuck with `T[]`. Just treat it as a pointer.
type instanceof ArrayType and not exists(type.getSize())
}
/**
* Holds if an `IRAddressType` with the specified `byteSize` should exist.
*/
predicate hasAddressType(int byteSize) {
// This covers all pointers, all references, and because it also looks at `NullPointerType`, it
// should always return a result that makes sense for arbitrary glvalues as well.
byteSize = any(Type type | isPointerIshType(type)).getSize()
}
/**
* Holds if an `IRFunctionAddressType` with the specified `byteSize` should exist.
*/
predicate hasFunctionAddressType(int byteSize) {
byteSize = getPointerSize() or // Covers function lvalues
byteSize = getTypeSize(any(FunctionPointerIshType type))
}
private predicate isOpaqueType(Type type) {
exists(type.getSize()) and // Only include complete types
(
type instanceof ArrayType or
type instanceof Class or
type instanceof GNUVectorType
)
or
type instanceof PointerToMemberType // PTMs are missing size info
}
/**
* Holds if an `IROpaqueType` with the specified `tag` and `byteSize` should exist.
*/
predicate hasOpaqueType(Type tag, int byteSize) {
isOpaqueType(tag) and byteSize = getTypeSize(tag)
or
tag instanceof UnknownType and IRConstruction::needsUnknownOpaqueType(byteSize)
}
/**
* Gets the `IRType` that represents a prvalue of the specified `Type`.
*/
private IRType getIRTypeForPRValue(Type type) {
exists(Type unspecifiedType | unspecifiedType = type.getUnspecifiedType() |
isOpaqueType(unspecifiedType) and
exists(IROpaqueType opaqueType | opaqueType = result |
opaqueType.getByteSize() = getTypeSize(type) and
opaqueType.getTag() = unspecifiedType
)
or
unspecifiedType instanceof BoolType and result.(IRBooleanType).getByteSize() = type.getSize()
or
isSignedIntegerType(unspecifiedType) and
result.(IRSignedIntegerType).getByteSize() = type.getSize()
or
isUnsignedIntegerType(unspecifiedType) and
result.(IRUnsignedIntegerType).getByteSize() = type.getSize()
or
unspecifiedType instanceof FloatingPointType and
result.(IRFloatingPointType).getByteSize() = type.getSize()
or
isPointerIshType(unspecifiedType) and result.(IRAddressType).getByteSize() = getTypeSize(type)
or
unspecifiedType instanceof FunctionPointerIshType and
result.(IRFunctionAddressType).getByteSize() = getTypeSize(type)
or
unspecifiedType instanceof VoidType and result instanceof IRVoidType
or
unspecifiedType instanceof ErroneousType and result instanceof IRErrorType
or
unspecifiedType instanceof UnknownType and result instanceof IRUnknownType
)
}
private newtype TCppType =
TPRValueType(Type type) { exists(getIRTypeForPRValue(type)) } or
TFunctionGLValueType() or
TGLValueAddressType(Type type) or
TUnknownOpaqueType(int byteSize) { IRConstruction::needsUnknownOpaqueType(byteSize) } or
TUnknownType()
/**
* The C++ type of an IR entity.
* This cannot just be `Type` for a couple reasons:
* - Some types needed by the IR might not exist in the database (e.g. `RoutineType`s for functions
* that are always called directly)
* - Some types needed by the IR are not representable in the C++ type system (e.g. the result type
* of a `VariableAddress` where the variable is of reference type)
*/
class CppType extends TCppType {
string toString() { none() }
/** Gets a string used in IR dumps */
string getDumpString() { result = toString() }
/** Gets the size of the type in bytes, if known. */
final int getByteSize() { result = getIRType().getByteSize() }
/**
* Gets the `IRType` that represents this `CppType`. Many different `CppType`s can map to a single
* `IRType`.
*/
IRType getIRType() { none() }
/**
* Holds if the `CppType` represents a prvalue of type `Type` (if `isGLValue` is `false`), or if
* it represents a glvalue of type `Type` (if `isGLValue` is `true`).
*/
predicate hasType(Type type, boolean isGLValue) { none() }
final predicate hasUnspecifiedType(Type type, boolean isGLValue) {
exists(Type specifiedType |
hasType(specifiedType, isGLValue) and
type = specifiedType.getUnspecifiedType()
)
}
}
/**
* A `CppType` that wraps an existing `Type` (either as a prvalue or a glvalue).
*/
private class CppWrappedType extends CppType {
Type ctype;
CppWrappedType() {
this = TPRValueType(ctype) or
this = TGLValueAddressType(ctype)
}
}
/**
* A `CppType` that represents a prvalue of an existing `Type`.
*/
private class CppPRValueType extends CppWrappedType, TPRValueType {
final override string toString() { result = ctype.toString() }
final override string getDumpString() { result = ctype.getUnspecifiedType().toString() }
final override IRType getIRType() { result = getIRTypeForPRValue(ctype) }
final override predicate hasType(Type type, boolean isGLValue) {
type = ctype and
isGLValue = false
}
}
/**
* A `CppType` that has unknown type but a known size. Generally to represent synthesized types that
* occur in certain cases during IR construction, such as the type of a zero-initialized segment of
* a partially-initialized array.
*/
private class CppUnknownOpaqueType extends CppType, TUnknownOpaqueType {
int byteSize;
CppUnknownOpaqueType() { this = TUnknownOpaqueType(byteSize) }
final override string toString() { result = "unknown[" + byteSize.toString() + "]" }
final override IROpaqueType getIRType() {
result.getByteSize() = byteSize and result.getTag() instanceof UnknownType
}
override predicate hasType(Type type, boolean isGLValue) {
type instanceof UnknownType and isGLValue = false
}
}
/**
* A `CppType` that represents a glvalue of an existing `Type`.
*/
private class CppGLValueAddressType extends CppWrappedType, TGLValueAddressType {
final override string toString() { result = "glval<" + ctype.toString() + ">" }
final override string getDumpString() {
result = "glval<" + ctype.getUnspecifiedType().toString() + ">"
}
final override IRAddressType getIRType() { result.getByteSize() = getPointerSize() }
final override predicate hasType(Type type, boolean isGLValue) {
type = ctype and
isGLValue = true
}
}
/**
* A `CppType` that represents a function lvalue.
*/
private class CppFunctionGLValueType extends CppType, TFunctionGLValueType {
final override string toString() { result = "glval<unknown>" }
final override IRFunctionAddressType getIRType() { result.getByteSize() = getPointerSize() }
final override predicate hasType(Type type, boolean isGLValue) {
type instanceof UnknownType and isGLValue = true
}
}
/**
* A `CppType` that represents an unknown type.
*/
private class CppUnknownType extends CppType, TUnknownType {
final override string toString() { result = any(UnknownType type).toString() }
final override IRUnknownType getIRType() { any() }
final override predicate hasType(Type type, boolean isGLValue) {
type instanceof UnknownType and isGLValue = false
}
}
/**
* Gets the single instance of `CppUnknownType`.
*/
CppUnknownType getUnknownType() { any() }
/**
* Gets the `CppType` that represents a prvalue of type `void`.
*/
CppPRValueType getVoidType() { exists(VoidType voidType | result.hasType(voidType, false)) }
/**
* Gets the `CppType` that represents a prvalue of type `type`.
*/
CppType getTypeForPRValue(Type type) {
if type instanceof UnknownType
then result instanceof CppUnknownType
else result.hasType(type, false)
}
/**
* Gets the `CppType` that represents a prvalue of type `type`, if such a `CppType` exists.
* Otherwise, gets `CppUnknownType`.
*/
CppType getTypeForPRValueOrUnknown(Type type) {
result = getTypeForPRValue(type)
or
not exists(getTypeForPRValue(type)) and result = getUnknownType()
}
/**
* Gets the `CppType` that represents a glvalue of type `type`.
*/
CppType getTypeForGLValue(Type type) { result.hasType(type, true) }
/**
* Gets the `CppType` that represents a prvalue of type `int`.
*/
CppPRValueType getIntType() {
exists(IntType type |
type.isImplicitlySigned() and
result.hasType(type, false)
)
}
/**
* Gets the `CppType` that represents a prvalue of type `bool`.
*/
CppPRValueType getBoolType() { exists(BoolType type | result.hasType(type, false)) }
/**
* Gets the `CppType` that represents a glvalue of function type.
*/
CppFunctionGLValueType getFunctionGLValueType() { any() }
/**
* Gets the `CppType` that represents a opaque of unknown type with size `byteSize`.
*/
CppUnknownOpaqueType getUnknownOpaqueType(int byteSize) { result.getByteSize() = byteSize }
/**
* Gets the `CppType` that is the canonical type for an `IRBooleanType` with the specified
* `byteSize`.
*/
CppWrappedType getCanonicalBooleanType(int byteSize) {
exists(BoolType type | result = TPRValueType(type) and byteSize = type.getSize())
}
/**
* Compute the sorting priority of an `IntegralType` based on its signedness.
*/
private int getSignPriority(IntegralType type) {
// Explicitly unsigned types sort first. Explicitly signed types sort last. Types with no explicit
// signedness sort in between. This lets us always choose `int` over `signed int`, while also
// choosing `unsigned char`+`char` when `char` is signed, and `unsigned char`+`signed char` when
// `char` is unsigned.
if type.isExplicitlyUnsigned()
then result = 2
else
if type.isExplicitlySigned()
then result = 0
else result = 1
}
/**
* Gets the sort priority of an `IntegralType` based on its kind.
*/
private int getKindPriority(IntegralType type) {
// `CharType` sorts lower so that we prefer the plain integer types when they have the same size
// as a `CharType`.
if type instanceof CharType then result = 0 else result = 1
}
/**
* Gets the `CppType` that is the canonical type for an `IRSignedIntegerType` with the specified
* `byteSize`.
*/
CppPRValueType getCanonicalSignedIntegerType(int byteSize) {
result = TPRValueType(max(IntegralType type |
type.isSigned() and type.getSize() = byteSize
|
type order by getKindPriority(type), getSignPriority(type), type.toString() desc
))
}
/**
* Gets the `CppType` that is the canonical type for an `IRUnsignedIntegerType` with the specified
* `byteSize`.
*/
CppPRValueType getCanonicalUnsignedIntegerType(int byteSize) {
result = TPRValueType(max(IntegralType type |
type.isUnsigned() and type.getSize() = byteSize
|
type order by getKindPriority(type), getSignPriority(type), type.toString() desc
))
}
/**
* Gets the `CppType` that is the canonical type for an `IRFloatingPointType` with the specified
* `byteSize`.
*/
CppPRValueType getCanonicalFloatingPointType(int byteSize) {
result = TPRValueType(max(FloatingPointType type |
type.getSize() = byteSize
|
type order by type.toString() desc
))
}
/**
* Gets the `CppType` that is the canonical type for an `IRAddressType` with the specified
* `byteSize`.
*/
CppPRValueType getCanonicalAddressType(int byteSize) {
// We just use `NullPointerType`, since it should be unique.
exists(NullPointerType type |
type.getSize() = byteSize and
result = TPRValueType(type)
)
}
/**
* Gets the `CppType` that is the canonical type for an `IRFunctionAddressType` with the specified
* `byteSize`.
*/
CppFunctionGLValueType getCanonicalFunctionAddressType(int byteSize) {
result.getByteSize() = byteSize
}
/**
* Gets the `CppType` that is the canonical type for `IRErrorType`.
*/
CppPRValueType getCanonicalErrorType() { result = TPRValueType(any(ErroneousType type)) }
/**
* Gets the `CppType` that is the canonical type for `IRUnknownType`.
*/
CppUnknownType getCanonicalUnknownType() { any() }
/**
* Gets the `CppType` that is the canonical type for `IRVoidType`.
*/
CppPRValueType getCanonicalVoidType() { result = TPRValueType(any(VoidType type)) }
/**
* Gets the `CppType` that is the canonical type for an `IROpaqueType` with the specified `tag` and
* `byteSize`.
*/
CppType getCanonicalOpaqueType(Type tag, int byteSize) {
isOpaqueType(tag) and
result = TPRValueType(tag.getUnspecifiedType()) and
getTypeSize(tag) = byteSize
or
tag instanceof UnknownType and result = getUnknownOpaqueType(byteSize)
}
/**
* Gets a string that uniquely identifies an `IROpaqueType` tag. This may be different from the usual
* `toString()` of the tag in order to ensure uniqueness.
*/
string getOpaqueTagIdentityString(Type tag) {
hasOpaqueType(tag, _) and
result = getTypeIdentityString(tag)
}
module LanguageTypeSanity {
query predicate missingCppType(Type type, string message) {
not exists(getTypeForPRValue(type)) and
exists(type.getSize()) and
// `ProxyClass`es have a size, but only appear in uninstantiated templates
not type instanceof ProxyClass and
message = "Type does not have an associated `CppType`."
}
}

View File

@@ -1,6 +1,13 @@
private import cpp as Cpp private import cpp as Cpp
private import semmle.code.cpp.Print as Print private import semmle.code.cpp.Print as Print
private import IRUtilities private import IRUtilities
private import semmle.code.cpp.ir.implementation.IRType
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
import CppType
class LanguageType = CppType;
class OpaqueTypeTag = Cpp::Type;
class Function = Cpp::Function; class Function = Cpp::Function;

View File

@@ -80,7 +80,7 @@ private module RangeAnalysisCache {
cached cached
module RangeAnalysisPublic { module RangeAnalysisPublic {
/** /**
* Holds if `b + delta` is a valid bound for `i`. * Holds if `b + delta` is a valid bound for `i` and this is the best such delta.
* - `upper = true` : `i <= b + delta` * - `upper = true` : `i <= b + delta`
* - `upper = false` : `i >= b + delta` * - `upper = false` : `i >= b + delta`
* *
@@ -90,11 +90,12 @@ private module RangeAnalysisCache {
*/ */
cached cached
predicate boundedInstruction(Instruction i, Bound b, int delta, boolean upper, Reason reason) { predicate boundedInstruction(Instruction i, Bound b, int delta, boolean upper, Reason reason) {
boundedInstruction(i, b, delta, upper, _, _, reason) boundedInstruction(i, b, delta, upper, _, _, reason) and
bestInstructionBound(i, b, delta, upper)
} }
/** /**
* Holds if `b + delta` is a valid bound for `op`. * Holds if `b + delta` is a valid bound for `op` and this is the best such delta.
* - `upper = true` : `op <= b + delta` * - `upper = true` : `op <= b + delta`
* - `upper = false` : `op >= b + delta` * - `upper = false` : `op >= b + delta`
* *
@@ -104,9 +105,8 @@ private module RangeAnalysisCache {
*/ */
cached cached
predicate boundedOperand(Operand op, Bound b, int delta, boolean upper, Reason reason) { predicate boundedOperand(Operand op, Bound b, int delta, boolean upper, Reason reason) {
boundedNonPhiOperand(op, b, delta, upper, _, _, reason) boundedOperandCand(op, b, delta, upper, reason) and
or bestOperandBound(op, b, delta, upper)
boundedPhiOperand(op, b, delta, upper, _, _, reason)
} }
} }
@@ -124,6 +124,43 @@ private module RangeAnalysisCache {
private import RangeAnalysisCache private import RangeAnalysisCache
import RangeAnalysisPublic import RangeAnalysisPublic
/**
* Holds if `b + delta` is a valid bound for `e` and this is the best such delta.
* - `upper = true` : `e <= b + delta`
* - `upper = false` : `e >= b + delta`
*/
private predicate bestInstructionBound(Instruction i, Bound b, int delta, boolean upper) {
delta = min(int d | boundedInstruction(i, b, d, upper, _, _, _)) and upper = true
or
delta = max(int d | boundedInstruction(i, b, d, upper, _, _, _)) and upper = false
}
/**
* Holds if `b + delta` is a valid bound for `op`.
* - `upper = true` : `op <= b + delta`
* - `upper = false` : `op >= b + delta`
*
* The reason for the bound is given by `reason` and may be either a condition
* or `NoReason` if the bound was proven directly without the use of a bounding
* condition.
*/
private predicate boundedOperandCand(Operand op, Bound b, int delta, boolean upper, Reason reason) {
boundedNonPhiOperand(op, b, delta, upper, _, _, reason)
or
boundedPhiOperand(op, b, delta, upper, _, _, reason)
}
/**
* Holds if `b + delta` is a valid bound for `op` and this is the best such delta.
* - `upper = true` : `op <= b + delta`
* - `upper = false` : `op >= b + delta`
*/
private predicate bestOperandBound(Operand op, Bound b, int delta, boolean upper) {
delta = min(int d | boundedOperandCand(op, b, d, upper, _)) and upper = true
or
delta = max(int d | boundedOperandCand(op, b, d, upper, _)) and upper = false
}
/** /**
* Gets a condition that tests whether `vn` equals `bound + delta`. * Gets a condition that tests whether `vn` equals `bound + delta`.
* *

View File

@@ -0,0 +1,68 @@
int source();
void sink(int);
bool guarded(int);
void bg_basic(int source) {
if (guarded(source)) {
sink(source); // no flow
} else {
sink(source); // flow
}
}
void bg_not(int source) {
if (!guarded(source)) {
sink(source); // flow
} else {
sink(source); // no flow
}
}
void bg_and(int source, bool arbitrary) {
if (guarded(source) && arbitrary) {
sink(source); // no flow
} else {
sink(source); // flow
}
}
void bg_or(int source, bool arbitrary) {
if (guarded(source) || arbitrary) {
sink(source); // flow
} else {
sink(source); // flow
}
}
void bg_return(int source) {
if (!guarded(source)) {
return;
}
sink(source); // no flow
}
struct XY {
int x, y;
};
void bg_stackstruct(XY s1, XY s2) {
s1.x = source();
if (guarded(s1.x)) {
sink(s1.x); // no flow
} else if (guarded(s1.y)) {
sink(s1.x); // flow
} else if (guarded(s2.y)) {
sink(s1.x); // flow
}
}
void bg_structptr(XY *p1, XY *p2) {
p1->x = source();
if (guarded(p1->x)) {
sink(p1->x); // no flow [FALSE POSITIVE in AST]
} else if (guarded(p1->y)) {
sink(p1->x); // flow [NOT DETECTED in IR]
} else if (guarded(p2->x)) {
sink(p1->x); // flow [NOT DETECTED in IR]
}
}

Some files were not shown because too many files have changed in this diff Show More