mirror of
https://github.com/github/codeql.git
synced 2025-12-21 11:16:30 +01:00
Merge remote-tracking branch 'upstream/master' into ir-copy-unloaded-result
This commit is contained in:
@@ -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" ] }
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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** |
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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."
|
||||||
|
|||||||
@@ -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) }
|
||||||
|
}
|
||||||
@@ -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];
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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(), _)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
@@ -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()
|
||||||
@@ -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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
25
cpp/ql/src/Microsoft/SAL/IgnoreReturnValueSAL.ql
Normal file
25
cpp/ql/src/Microsoft/SAL/IgnoreReturnValueSAL.ql
Normal 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()
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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()
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
690
cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll
Normal file
690
cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll
Normal 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()) }
|
||||||
190
cpp/ql/src/Security/CWE/CWE-457/UninitializedVariables.qll
Normal file
190
cpp/ql/src/Security/CWE/CWE-457/UninitializedVariables.qll
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
41
cpp/ql/src/semmle/code/cpp/NestedFields.qll
Normal file
41
cpp/ql/src/semmle/code/cpp/NestedFields.qll
Normal 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 }
|
||||||
|
}
|
||||||
@@ -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() }
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
83
cpp/ql/src/semmle/code/cpp/dispatch/VirtualDispatch.qll
Normal file
83
cpp/ql/src/semmle/code/cpp/dispatch/VirtualDispatch.qll
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
247
cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll
Normal file
247
cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll
Normal 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
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
|
|||||||
@@ -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" }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
private import IR
|
private import IR
|
||||||
import InstructionSanity
|
import InstructionSanity
|
||||||
|
import IRTypeSanity
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
import semmle.code.cpp.ir.internal.Overlap
|
||||||
|
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
@@ -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())
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
private import IR
|
private import IR
|
||||||
import InstructionSanity
|
import InstructionSanity
|
||||||
|
import IRTypeSanity
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
import semmle.code.cpp.ir.internal.Overlap
|
||||||
|
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
@@ -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 |
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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`.
|
||||||
|
|||||||
@@ -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() }
|
||||||
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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() }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
private import IR
|
private import IR
|
||||||
import InstructionSanity
|
import InstructionSanity
|
||||||
|
import IRTypeSanity
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
import semmle.code.cpp.ir.internal.Overlap
|
||||||
|
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
507
cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll
Normal file
507
cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll
Normal 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`."
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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`.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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
Reference in New Issue
Block a user