diff --git a/change-notes/1.23/analysis-cpp.md b/change-notes/1.23/analysis-cpp.md
index 4c7b1d0a26c..4c2cac9f3c3 100644
--- a/change-notes/1.23/analysis-cpp.md
+++ b/change-notes/1.23/analysis-cpp.md
@@ -2,66 +2,65 @@
The following changes in version 1.23 affect C/C++ analysis in all applications.
-## General improvements
-
## New queries
| **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------|
-| Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | reliability, japanese-era | This query is a combination of two old queries that were identical in purpose but separate as an implementation detail. This new query replaces Hard-coded Japanese era start date in call (`cpp/japanese-era/constructor-or-method-with-exact-era-date`) and Hard-coded Japanese era start date in struct (`cpp/japanese-era/struct-with-exact-era-date`). |
-| Signed overflow check (`cpp/signed-overflow-check`) | correctness, security | Finds overflow checks that rely on signed integer addition to overflow, which has undefined behavior. Example: `a + b < a`. |
-| Pointer overflow check (`cpp/pointer-overflow-check`) | correctness, security | Finds overflow checks that rely on pointer addition to overflow, which has undefined behavior. Example: `ptr + a < ptr`. |
+| Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | reliability, japanese-era | This query is a combination of two old queries that were identical in purpose but separate as an implementation detail. This new query replaces Hard-coded Japanese era start date in call (`cpp/japanese-era/constructor-or-method-with-exact-era-date`) and Hard-coded Japanese era start date in struct (`cpp/japanese-era/struct-with-exact-era-date`). Results are not shown on LGTM by default. |
+| Pointer overflow check (`cpp/pointer-overflow-check`) | correctness, security | Finds overflow checks that rely on pointer addition to overflow, which has undefined behavior. Example: `ptr + a < ptr`. Results are shown on LGTM by default. |
+| Signed overflow check (`cpp/signed-overflow-check`) | correctness, security | Finds overflow checks that rely on signed integer addition to overflow, which has undefined behavior. Example: `a + b < a`. Results are shown on LGTM by default. |
+
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|----------------------------|------------------------|------------------------------------------------------------------|
-| Query name (`query id`) | Expected impact | Message. |
+| 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. |
| Hard-coded Japanese era start date in call (`cpp/japanese-era/constructor-or-method-with-exact-era-date`) | Deprecated | This query has been deprecated. Use the new combined query Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) instead. |
| Hard-coded Japanese era start date in struct (`cpp/japanese-era/struct-with-exact-era-date`) | Deprecated | This query has been deprecated. Use the new combined query Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) instead. |
| Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | More correct results | This query now checks for the beginning date of the Reiwa era (1st May 2019). |
+| Non-constant format string (`cpp/non-constant-format`) | Fewer false positive results | Fixed false positive results triggrered by mismatching declarations of a formatting function. |
| Sign check of bitwise operation (`cpp/bitwise-sign-check`) | Fewer false positive results | Results involving `>=` or `<=` are no longer reported. |
-| 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. |
-| 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. |
-| Non-constant format string (`cpp/non-constant-format`) | Fewer false positive results | Fixed false positives resulting from mistmatching declarations of a formatting function. |
-| Wrong type of arguments to formatting function (`cpp/wrong-type-format-argument`) | More correct results and fewer false positive results | This query now understands explicitly specified argument numbers in format strings, such as the `1$` in `%1$s`. |
+| Too few arguments to formatting function (`cpp/wrong-number-format-arguments`) | Fewer false positive results | Fixed false positive results triggered by mismatching declarations of a formatting function. |
+| Too many arguments to formatting function (`cpp/too-many-format-arguments`) | Fewer false positive results | Fixed false positive results triggered by mismatching declarations of a formatting function. |
+| Unclear comparison precedence (`cpp/comparison-precedence`) | Fewer false positive results | False positive results involving template classes and functions have been fixed. |
+| Wrong type of arguments to formatting function (`cpp/wrong-type-format-argument`) | More correct results and fewer false positive results | This query now understands explicitly-specified argument numbers in format strings, such as the `1$` in `%1$s`. |
## Changes to libraries
-* The data-flow library has been extended with a new feature to aid debugging.
- Instead of specifying `isSink(Node n) { any() }` on a configuration to
- explore the possible flow from a source, it is recommended to use the new
- `Configuration::hasPartialFlow` predicate, as this gives a more complete
- picture of the partial flow paths from a given source. The feature is
- disabled by default and can be enabled for individual configurations by
- overriding `int explorationLimit()`.
-* The data-flow library now supports flow out of C++ reference parameters.
-* The data-flow library now allows flow through the address-of operator (`&`).
-* The `DataFlow::DefinitionByReferenceNode` class now considers `f(x)` to be a
- 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
- 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
- `TaintTracking::localExprTaint` predicate to make it easy to use the most
- common case of local data flow and taint: from one `Expr` to another.
+* The data-flow library in `semmle.code.cpp.dataflow.DataFlow` and
+ `semmle.code.cpp.dataflow.TaintTracking` have had extensive changes:
+ * Data flow through fields is now more complete and reliable.
+ * The data-flow library has been extended with a new feature to aid debugging.
+ Previously, to explore the possible flow from all sources you could specify `isSink(Node n) { any() }` on a configuration.
+ Now you can use the new `Configuration::hasPartialFlow` predicate,
+ which gives a more complete picture of the partial flow paths from a given source, including flow that doesn't reach any sink.
+ The feature is disabled by default and can be enabled for individual configurations by overriding `int explorationLimit()`.
+ * There is now flow out of C++ reference parameters.
+ * There is now flow through the address-of operator (`&`).
+ * The `DataFlow::DefinitionByReferenceNode` class now considers `f(x)` to be a
+ 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
+ changes are in line with the user expectations we've observed.
+ * It's now 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
+ `TaintTracking::localExprTaint` predicate to make it easy to use the most
+ common case of local data flow and taint: from one `Expr` to another.
* The member predicates of the `FunctionInput` and `FunctionOutput` classes have been renamed for
- clarity (e.g. `isOutReturnPointer()` to `isReturnValueDeref()`). The existing member predicates
+ clarity (for example, `isOutReturnPointer()` to `isReturnValueDeref()`). The existing member predicates
have been deprecated, and will be removed in a future release. Code that uses the old member
predicates should be updated to use the corresponding new member predicate.
-* The predicates `Declaration.hasStdName()` and `Declaration.hasGlobalOrStdName`
- have been added, simplifying handling of C++ standard library functions.
+* The predicate `Declaration.hasGlobalOrStdName` has been added, making it
+ easier to recognize C library functions called from C++.
* The control-flow graph is now computed in QL, not in the extractor. This can
- lead to regressions (or improvements) in how queries are optimized because
+ lead to changes in how queries are optimized because
optimization in QL relies on static size estimates, and the control-flow edge
relations will now have different size estimates than before.
* Support has been added for non-type template arguments. This means that the
return type of `Declaration::getTemplateArgument()` and
- `Declaration::getATemplateArgument` have changed to `Locatable`. See the
- documentation for `Declaration::getTemplateArgument()` and
- `Declaration::getTemplateArgumentKind()` for details.
+ `Declaration::getATemplateArgument` have changed to `Locatable`. For details, see the
+ CodeQL library documentation for `Declaration::getTemplateArgument()` and
+ `Declaration::getTemplateArgumentKind()`.
diff --git a/change-notes/1.23/analysis-java.md b/change-notes/1.23/analysis-java.md
index 8c38f57e9d2..ad1f2248912 100644
--- a/change-notes/1.23/analysis-java.md
+++ b/change-notes/1.23/analysis-java.md
@@ -6,25 +6,23 @@ The following changes in version 1.23 affect Java analysis in all applications.
| **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------|
-| Continue statement that does not continue (`java/continue-in-false-loop`) | correctness | Finds `continue` statements in `do { ... } while (false)` loops. |
+| Continue statement that does not continue (`java/continue-in-false-loop`) | correctness | Finds `continue` statements in `do { ... } while (false)` loops. Results are shown on LGTM by default. |
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|------------------------------|------------------------|-----------------------------------|
-| Dereferenced variable may be null (`java/dereferenced-value-may-be-null`) | Fewer false positives | Certain indirect null guards involving two auxiliary variables known to be equal can now be detected. |
-| Non-synchronized override of synchronized method (`java/non-sync-override`) | Fewer false positives | Results are now only reported if the immediately overridden method is synchronized. |
-| Query built from user-controlled sources (`java/sql-injection`) | More results | The query now identifies arguments to `Statement.executeLargeUpdate` and `Connection.prepareCall` as SQL expressions sinks. |
-| Query built from local-user-controlled sources (`java/sql-injection-local`) | More results | The query now identifies arguments to `Statement.executeLargeUpdate` and `Connection.prepareCall` as SQL expressions sinks. |
-| Query built without neutralizing special characters (`java/concatenated-sql-query`) | More results | The query now identifies arguments to `Statement.executeLargeUpdate` and `Connection.prepareCall` as SQL expressions sinks. |
-| Useless comparison test (`java/constant-comparison`) | Fewer false positives | Additional overflow check patterns are now recognized and no longer reported. |
+| Dereferenced variable may be null (`java/dereferenced-value-may-be-null`) | Fewer false positive results | Additional indirect null guards are detected, where two auxiliary variables are known to be equal. |
+| Non-synchronized override of synchronized method (`java/non-sync-override`) | Fewer false positive results | Results are now only reported if the immediately overridden method is synchronized. |
+| Query built from local-user-controlled sources (`java/sql-injection-local`) | More results | The query now identifies arguments to `Statement.executeLargeUpdate` and `Connection.prepareCall` as sinks for SQL expressions. |
+| Query built from user-controlled sources (`java/sql-injection`) | More results | The query now identifies arguments to `Statement.executeLargeUpdate` and `Connection.prepareCall` as sinks for SQL expressions. |
+| Query built without neutralizing special characters (`java/concatenated-sql-query`) | More results | The query now identifies arguments to `Statement.executeLargeUpdate` and `Connection.prepareCall` as sinks for SQL expressions. |
+| Useless comparison test (`java/constant-comparison`) | Fewer false positive results | Additional overflow check patterns are now recognized and no longer reported. Also, a few bug fixes in the range analysis for floating-point variables gives a further reduction in false positive results. |
## Changes to libraries
-* The data-flow library has been extended with a new feature to aid debugging.
- Instead of specifying `isSink(Node n) { any() }` on a configuration to
- explore the possible flow from a source, it is recommended to use the new
- `Configuration::hasPartialFlow` predicate, as this gives a more complete
- picture of the partial flow paths from a given source. The feature is
- disabled by default and can be enabled for individual configurations by
- overriding `int explorationLimit()`.
+The data-flow library has been extended with a new feature to aid debugging.
+Previously, to explore the possible flow from all sources you could specify `isSink(Node n) { any() }` on a configuration.
+Now you can use the new `Configuration::hasPartialFlow` predicate,
+which gives a more complete picture of the partial flow paths from a given source, including flow that doesn't reach any sink.
+The feature is disabled by default and can be enabled for individual configurations by overriding `int explorationLimit()`.
diff --git a/change-notes/1.23/analysis-javascript.md b/change-notes/1.23/analysis-javascript.md
index e815f5e8ba0..4d449fb017b 100644
--- a/change-notes/1.23/analysis-javascript.md
+++ b/change-notes/1.23/analysis-javascript.md
@@ -27,7 +27,7 @@
|---------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 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. |
| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | security, correctness, external/cwe/cwe-020 | Highlights checks for `javascript:` URLs that do not take `data:` or `vbscript:` URLs into account. 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 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 into looping indefinitely. 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.|
| 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. |
| 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. |
@@ -39,19 +39,19 @@
| **Query** | **Expected impact** | **Change** |
|--------------------------------|------------------------------|---------------------------------------------------------------------------|
-| 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. |
-| Hard-coded credentials (`js/hardcoded-credentials`) | Fewer false-positive results | This rule now flags fewer password examples. |
-| Illegal invocation (`js/illegal-invocation`) | Fewer false-positive results | This rule now correctly handles methods named `call` and `apply`. |
-| Incorrect suffix check (`js/incorrect-suffix-check`) | Fewer false-positive results | The query recognizes valid checks in more cases. |
-| Network data written to file (`js/http-to-file-access`) | Fewer false-positive results | This query has been renamed to better match its intended purpose, and now only considers network data untrusted. |
-| Password in configuration file (`js/password-in-configuration-file`) | Fewer false-positive results | This rule now flags fewer password examples. |
+| Hard-coded credentials (`js/hardcoded-credentials`) | Fewer false positive results | This rule now flags fewer password examples. |
+| Illegal invocation (`js/illegal-invocation`) | Fewer false positive results | This rule now correctly handles methods named `call` and `apply`. |
+| Incomplete string escaping or encoding (`js/incomplete-sanitization`) | Fewer false positive results | This rule now recognizes additional ways delimiters can be stripped away. |
+| Incorrect suffix check (`js/incorrect-suffix-check`) | Fewer false positive results | The query recognizes valid checks in more cases. |
+| Network data written to file (`js/http-to-file-access`) | Fewer false positive results | This query has been renamed to better match its intended purpose, and now only considers network data untrusted. |
+| Password in configuration file (`js/password-in-configuration-file`) | Fewer false positive results | This rule now flags fewer password examples. |
| Prototype pollution (`js/prototype-pollution`) | More results | The query now highlights vulnerable uses of jQuery and Angular, and the results are shown on LGTM by default. |
-| 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. |
+| 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. |
| 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. |
+| 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 libraries
@@ -67,16 +67,16 @@
The following queries (deprecated since 1.17) are no longer available in the distribution:
-* Builtin redefined (js/builtin-redefinition)
-* Inefficient method definition (js/method-definition-in-constructor)
* Bad parity check (js/incomplete-parity-check)
-* Potentially misspelled property or variable name (js/wrong-capitalization)
-* Unknown JSDoc tag (js/jsdoc/unknown-tag-type)
+* Builtin redefined (js/builtin-redefinition)
+* Call to parseInt without radix (js/parseint-without-radix)
+* Inefficient method definition (js/method-definition-in-constructor)
* Invalid JSLint directive (js/jslint/invalid-directive)
* Malformed JSLint directive (js/jslint/malformed-directive)
-* Use of HTML comments (js/html-comment)
* Multi-line string literal (js/multi-line-string)
* Octal literal (js/octal-literal)
+* Potentially misspelled property or variable name (js/wrong-capitalization)
* Reserved word used as variable name (js/use-of-reserved-word)
* Trailing comma in array or object expressions (js/trailing-comma-in-array-or-object)
-* Call to parseInt without radix (js/parseint-without-radix)
+* Unknown JSDoc tag (js/jsdoc/unknown-tag-type)
+* Use of HTML comments (js/html-comment)
diff --git a/change-notes/1.23/analysis-python.md b/change-notes/1.23/analysis-python.md
index 6cea1745284..5320567af85 100644
--- a/change-notes/1.23/analysis-python.md
+++ b/change-notes/1.23/analysis-python.md
@@ -3,7 +3,19 @@
## General improvements
+### Python 3.8 support
+Python 3.8 syntax is now supported. In particular, the following constructs are parsed correctly:
+
+- Assignment expressions using the "walrus" operator, such as `while chunk := file.read(1024): ...`.
+- The positional argument separator `/`, such as in `def foo(a, /, b, *, c): ...`.
+- Self-documenting expressions in f-strings, such as `f"{var=}"`.
+
+### General query improvements
+
+Following the replacement of the `Object` API (for example, `ClassObject`) in favor of the
+`Value` API (for example, `ClassValue`) in the 1.21 release, many of the standard queries have been updated
+to use the `Value` API. This should result in more precise results.
## New queries
@@ -18,10 +30,23 @@
| **Query** | **Expected impact** | **Change** |
|----------------------------|------------------------|------------|
-| 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. |
-
+| Explicit export is undefined (`py/undefined-export`) | Fewer false positive results | Instances where an exported value may be defined in a module that lacks points-to information are no longer flagged. |
+| Module-level cyclic import (`py/unsafe-cyclic-import`) | Fewer false positive results | Instances where one of the links in an import cycle is never actually executed are no longer flagged. |
+| Non-iterable used in for loop (`py/non-iterable-in-for-loop`) | Fewer false positive results | `__aiter__` is now recognized as an iterator method. |
+| Unreachable code (`py/unreachable-statement`) | Fewer false positive results | Analysis now accounts for uses of `contextlib.suppress` to suppress exceptions. |
+| Unreachable code (`py/unreachable-statement`) | Fewer false positive results | Unreachable `else` branches that do nothing but `assert` their non-reachability are no longer flagged. |
+| Unused import (`py/unused-import`) | Fewer false positive results | Instances where a module is used in a forward-referenced type annotation, or only during type checking are no longer flagged. |
+| `__iter__` method returns a non-iterator (`py/iter-returns-non-iterator`) | Better alert message | Alert now highlights which class is expected to be an iterator. |
+| `__init__` method returns a value (`py/explicit-return-in-init`) | Fewer false positive results | Instances where the `__init__` method returns the value of a call to a procedure are no longer flagged. |
## Changes to QL libraries
* Django library now recognizes positional arguments from a `django.conf.urls.url` regex (Django version 1.x)
+* Instances of the `Value` class now support the `isAbsent` method, indicating
+ whether that `Value` lacks points-to information, but inference
+ suggests that it exists. For instance, if a file contains `import
+ django`, but `django` was not extracted properly, there will be a
+ `ModuleValue` corresponding to this "unknown" module, and the `isAbsent`
+ method will hold for this `ModuleValue`.
+* The `Expr` class now has a nullary method `pointsTo` that returns the possible
+ instances of `Value` that this expression may have.
diff --git a/change-notes/1.23/extractor-javascript.md b/change-notes/1.23/extractor-javascript.md
index 8b7a35f5b4f..f8eed613b6d 100644
--- a/change-notes/1.23/extractor-javascript.md
+++ b/change-notes/1.23/extractor-javascript.md
@@ -7,17 +7,17 @@
* 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"
-```
+ ```yaml
+ extraction:
+ javascript:
+ index:
+ filters:
+ - include: "**/node_modules"
+ - include: "**/bower_components"
+ ```
+* Additional [Flow](https://flow.org/) syntax is now supported.
* Recognition of CommonJS modules has improved. As a result, some files that were previously extracted as
global scripts are now extracted as modules.
* Top-level `await` is now supported.
-* A bug was fixed in how the TypeScript extractor handles default-exported anonymous classes.
-* A bug was fixed in how the TypeScript extractor handles computed instance field names.
+* Bugs were fixed in how the TypeScript extractor handles default-exported anonymous classes and computed-instance field names.
diff --git a/change-notes/1.24/analysis-cpp.md b/change-notes/1.24/analysis-cpp.md
index 2e7fdd422af..68795215b13 100644
--- a/change-notes/1.24/analysis-cpp.md
+++ b/change-notes/1.24/analysis-cpp.md
@@ -17,4 +17,11 @@ The following changes in version 1.24 affect C/C++ analysis in all applications.
## Changes to libraries
-*
+* The new class `StackVariable` should be used in place of `LocalScopeVariable`
+ in most cases. The difference is that `StackVariable` does not include
+ variables declared with `static` or `thread_local`.
+ * As a rule of thumb, custom queries about the _values_ of variables should
+ be changed from `LocalScopeVariable` to `StackVariable`, while queries
+ about the _name or scope_ of variables should remain unchanged.
+ * The `LocalScopeVariableReachability` library is deprecated in favor of
+ `StackVariableReachability`. The functionality is the same.
diff --git a/change-notes/1.24/analysis-csharp.md b/change-notes/1.24/analysis-csharp.md
new file mode 100644
index 00000000000..bd0c81115ab
--- /dev/null
+++ b/change-notes/1.24/analysis-csharp.md
@@ -0,0 +1,25 @@
+# Improvements to C# analysis
+
+The following changes in version 1.24 affect C# analysis in all applications.
+
+## New queries
+
+| **Query** | **Tags** | **Purpose** |
+|-----------------------------|-----------|--------------------------------------------------------------------|
+| Insecure configuration for ASP.NET requestValidationMode (`cs/insecure-request-validation-mode`) | security, external/cwe/cwe-016 | Finds where this attribute has been set to a value less than 4.5, which turns off some validation features and makes the application less secure. |
+
+## Changes to existing queries
+
+| **Query** | **Expected impact** | **Change** |
+|------------------------------|------------------------|-----------------------------------|
+
+## Removal of old queries
+
+## Changes to code extraction
+
+## Changes to libraries
+
+* The taint tracking library now tracks flow through (implicit or explicit) conversion operator calls.
+
+## Changes to autobuilder
+
diff --git a/change-notes/1.24/analysis-javascript.md b/change-notes/1.24/analysis-javascript.md
index fbe7fd00899..c6c544e2f3d 100644
--- a/change-notes/1.24/analysis-javascript.md
+++ b/change-notes/1.24/analysis-javascript.md
@@ -4,13 +4,17 @@
* Support for the following frameworks and libraries has been improved:
- [react](https://www.npmjs.com/package/react)
+ - [typeahead.js](https://www.npmjs.com/package/typeahead.js)
- [Handlebars](https://www.npmjs.com/package/handlebars)
+- Imports with the `.js` extension can now be resolved to a TypeScript file,
+ when the import refers to a file generated by TypeScript.
+
## New queries
-| **Query** | **Tags** | **Purpose** |
-|---------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-
+| **Query** | **Tags** | **Purpose** |
+|---------------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Cross-site scripting through exception (`js/xss-through-exception`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where an exception is written to the DOM. Results are not shown on LGTM by default. |
## Changes to existing queries
@@ -22,3 +26,5 @@
## Changes to libraries
+* The predicates `RegExpTerm.getSuccessor` and `RegExpTerm.getPredecessor` have been changed to reflect textual, not operational, matching order. This only makes a difference in lookbehind assertions, which are operationally matched backwards. Previously, `getSuccessor` would mimick this, so in an assertion `(?<=ab)` the term `b` would be considered the predecessor, not the successor, of `a`. Textually, however, `a` is still matched before `b`, and this is the order we now follow.
+
diff --git a/cpp/ql/src/Critical/DeadCodeCondition.ql b/cpp/ql/src/Critical/DeadCodeCondition.ql
index 45b4418f155..a769d3d4025 100644
--- a/cpp/ql/src/Critical/DeadCodeCondition.ql
+++ b/cpp/ql/src/Critical/DeadCodeCondition.ql
@@ -22,7 +22,7 @@ predicate testAndBranch(Expr e, Stmt branch) {
)
}
-predicate choice(LocalScopeVariable v, Stmt branch, string value) {
+predicate choice(StackVariable v, Stmt branch, string value) {
exists(AnalysedExpr e |
testAndBranch(e, branch) and
(
@@ -33,7 +33,7 @@ predicate choice(LocalScopeVariable v, Stmt branch, string value) {
)
}
-predicate guarded(LocalScopeVariable v, Stmt loopstart, AnalysedExpr child) {
+predicate guarded(StackVariable v, Stmt loopstart, AnalysedExpr child) {
choice(v, loopstart, _) and
loopstart.getChildStmt*() = child.getEnclosingStmt() and
(definition(v, child) or exists(child.getNullSuccessor(v)))
@@ -47,9 +47,7 @@ predicate addressLeak(Variable v, Stmt leak) {
)
}
-from
- LocalScopeVariable v, Stmt branch, AnalysedExpr cond, string context, string test,
- string testresult
+from StackVariable v, Stmt branch, AnalysedExpr cond, string context, string test, string testresult
where
choice(v, branch, context) and
forall(ControlFlowNode def | definition(v, def) and definitionReaches(def, cond) |
diff --git a/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql b/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql
index 47401c6eea5..135b9a644d1 100644
--- a/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql
+++ b/cpp/ql/src/Critical/DescriptorMayNotBeClosed.ql
@@ -23,14 +23,14 @@ predicate closeCall(FunctionCall fc, Variable v) {
)
}
-predicate openDefinition(LocalScopeVariable v, ControlFlowNode def) {
+predicate openDefinition(StackVariable v, ControlFlowNode def) {
exists(Expr expr | exprDefinition(v, def, expr) and allocateDescriptorCall(expr))
}
predicate openReaches(ControlFlowNode def, ControlFlowNode node) {
- exists(LocalScopeVariable v | openDefinition(v, def) and node = def.getASuccessor())
+ exists(StackVariable v | openDefinition(v, def) and node = def.getASuccessor())
or
- exists(LocalScopeVariable v, ControlFlowNode mid |
+ exists(StackVariable v, ControlFlowNode mid |
openDefinition(v, def) and
openReaches(def, mid) and
not errorSuccessor(v, mid) and
@@ -40,7 +40,7 @@ predicate openReaches(ControlFlowNode def, ControlFlowNode node) {
)
}
-predicate assignedToFieldOrGlobal(LocalScopeVariable v, Assignment assign) {
+predicate assignedToFieldOrGlobal(StackVariable v, Assignment assign) {
exists(Variable external |
assign.getRValue() = v.getAnAccess() and
assign.getLValue().(VariableAccess).getTarget() = external and
@@ -48,7 +48,7 @@ predicate assignedToFieldOrGlobal(LocalScopeVariable v, Assignment assign) {
)
}
-from LocalScopeVariable v, ControlFlowNode def, ReturnStmt ret
+from StackVariable v, ControlFlowNode def, ReturnStmt ret
where
openDefinition(v, def) and
openReaches(def, ret) and
diff --git a/cpp/ql/src/Critical/FileMayNotBeClosed.ql b/cpp/ql/src/Critical/FileMayNotBeClosed.ql
index fefe43aa845..c97e7cacca3 100644
--- a/cpp/ql/src/Critical/FileMayNotBeClosed.ql
+++ b/cpp/ql/src/Critical/FileMayNotBeClosed.ql
@@ -10,7 +10,7 @@
*/
import FileClosed
-import semmle.code.cpp.controlflow.LocalScopeVariableReachability
+import semmle.code.cpp.controlflow.StackVariableReachability
/**
* Extend the NullValue class used by Nullness.qll to include simple -1 as a 'null' value
@@ -68,18 +68,18 @@ predicate fcloseCallOrIndirect(FunctionCall fc, Variable v) {
)
}
-predicate fopenDefinition(LocalScopeVariable v, ControlFlowNode def) {
+predicate fopenDefinition(StackVariable v, ControlFlowNode def) {
exists(Expr expr | exprDefinition(v, def, expr) and fopenCallOrIndirect(expr))
}
-class FOpenVariableReachability extends LocalScopeVariableReachabilityWithReassignment {
+class FOpenVariableReachability extends StackVariableReachabilityWithReassignment {
FOpenVariableReachability() { this = "FOpenVariableReachability" }
- override predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v) {
+ override predicate isSourceActual(ControlFlowNode node, StackVariable v) {
fopenDefinition(v, node)
}
- override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
+ override predicate isSinkActual(ControlFlowNode node, StackVariable v) {
// node may be used in fopenReaches
exists(node.(AnalysedExpr).getNullSuccessor(v)) or
fcloseCallOrIndirect(node, v) or
@@ -88,15 +88,13 @@ class FOpenVariableReachability extends LocalScopeVariableReachabilityWithReassi
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
}
- override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
- definitionBarrier(v, node)
- }
+ override predicate isBarrier(ControlFlowNode node, StackVariable v) { definitionBarrier(v, node) }
}
/**
* The value from fopen at `def` is still held in Variable `v` upon entering `node`.
*/
-predicate fopenVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node) {
+predicate fopenVariableReaches(StackVariable v, ControlFlowNode def, ControlFlowNode node) {
exists(FOpenVariableReachability r |
// reachability
r.reachesTo(def, _, node, v)
@@ -107,25 +105,23 @@ predicate fopenVariableReaches(LocalScopeVariable v, ControlFlowNode def, Contro
)
}
-class FOpenReachability extends LocalScopeVariableReachabilityExt {
+class FOpenReachability extends StackVariableReachabilityExt {
FOpenReachability() { this = "FOpenReachability" }
- override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
- fopenDefinition(v, node)
- }
+ override predicate isSource(ControlFlowNode node, StackVariable v) { fopenDefinition(v, node) }
- override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
+ override predicate isSink(ControlFlowNode node, StackVariable v) {
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
}
override predicate isBarrier(
- ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v
+ ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, StackVariable v
) {
isSource(source, v) and
next = node.getASuccessor() and
// the file (stored in any variable `v0`) opened at `source` is closed or
// assigned to a global at node, or NULL checked on the edge node -> next.
- exists(LocalScopeVariable v0 | fopenVariableReaches(v0, source, node) |
+ exists(StackVariable v0 | fopenVariableReaches(v0, source, node) |
node.(AnalysedExpr).getNullSuccessor(v0) = next or
fcloseCallOrIndirect(node, v0) or
assignedToFieldOrGlobal(v0, node)
@@ -142,11 +138,11 @@ predicate fopenReaches(ControlFlowNode def, ControlFlowNode node) {
exists(FOpenReachability r | r.reaches(def, _, node))
}
-predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
- // assigned to anything except a LocalScopeVariable
+predicate assignedToFieldOrGlobal(StackVariable v, Expr e) {
+ // assigned to anything except a StackVariable
// (typically a field or global, but for example also *ptr = v)
e.(Assignment).getRValue() = v.getAnAccess() and
- not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
+ not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof StackVariable
or
exists(Expr midExpr, Function mid, int arg |
// indirect assignment
@@ -163,7 +159,7 @@ predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
from ControlFlowNode def, ReturnStmt ret
where
fopenReaches(def, ret) and
- not exists(LocalScopeVariable v |
+ not exists(StackVariable v |
fopenVariableReaches(v, def, ret) and
ret.getAChild*() = v.getAnAccess()
)
diff --git a/cpp/ql/src/Critical/InconsistentNullnessTesting.ql b/cpp/ql/src/Critical/InconsistentNullnessTesting.ql
index 52d551f6bfd..86e2cb4fb29 100644
--- a/cpp/ql/src/Critical/InconsistentNullnessTesting.ql
+++ b/cpp/ql/src/Critical/InconsistentNullnessTesting.ql
@@ -11,7 +11,7 @@
import cpp
-from LocalScopeVariable v, ControlFlowNode def, VariableAccess checked, VariableAccess unchecked
+from StackVariable v, ControlFlowNode def, VariableAccess checked, VariableAccess unchecked
where
checked = v.getAnAccess() and
dereferenced(checked) and
diff --git a/cpp/ql/src/Critical/LateNegativeTest.ql b/cpp/ql/src/Critical/LateNegativeTest.ql
index f7693d5c28e..098a224c818 100644
--- a/cpp/ql/src/Critical/LateNegativeTest.ql
+++ b/cpp/ql/src/Critical/LateNegativeTest.ql
@@ -13,7 +13,7 @@
import cpp
-predicate negativeCheck(LocalScopeVariable v, ComparisonOperation op) {
+predicate negativeCheck(StackVariable v, ComparisonOperation op) {
exists(int varindex, string constant, Literal lit |
op.getChild(varindex) = v.getAnAccess() and
op.getChild(1 - varindex) = lit and
@@ -38,7 +38,7 @@ predicate negativeCheck(LocalScopeVariable v, ComparisonOperation op) {
)
}
-from LocalScopeVariable v, ArrayExpr dangerous, Expr check
+from StackVariable v, ArrayExpr dangerous, Expr check
where
useUsePair(v, dangerous.getArrayOffset(), check.getAChild()) and
negativeCheck(v, check) and
diff --git a/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql b/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql
index 2bede681912..b60fa917e9a 100644
--- a/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql
+++ b/cpp/ql/src/Critical/MemoryMayNotBeFreed.ql
@@ -10,7 +10,7 @@
*/
import MemoryFreed
-import semmle.code.cpp.controlflow.LocalScopeVariableReachability
+import semmle.code.cpp.controlflow.StackVariableReachability
/**
* 'call' is either a direct call to f, or a possible call to f
@@ -97,18 +97,18 @@ predicate freeCallOrIndirect(ControlFlowNode n, Variable v) {
)
}
-predicate allocationDefinition(LocalScopeVariable v, ControlFlowNode def) {
+predicate allocationDefinition(StackVariable v, ControlFlowNode def) {
exists(Expr expr | exprDefinition(v, def, expr) and allocCallOrIndirect(expr))
}
-class AllocVariableReachability extends LocalScopeVariableReachabilityWithReassignment {
+class AllocVariableReachability extends StackVariableReachabilityWithReassignment {
AllocVariableReachability() { this = "AllocVariableReachability" }
- override predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v) {
+ override predicate isSourceActual(ControlFlowNode node, StackVariable v) {
allocationDefinition(v, node)
}
- override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
+ override predicate isSinkActual(ControlFlowNode node, StackVariable v) {
// node may be used in allocationReaches
exists(node.(AnalysedExpr).getNullSuccessor(v)) or
freeCallOrIndirect(node, v) or
@@ -117,15 +117,13 @@ class AllocVariableReachability extends LocalScopeVariableReachabilityWithReassi
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
}
- override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
- definitionBarrier(v, node)
- }
+ override predicate isBarrier(ControlFlowNode node, StackVariable v) { definitionBarrier(v, node) }
}
/**
* The value from allocation `def` is still held in Variable `v` upon entering `node`.
*/
-predicate allocatedVariableReaches(LocalScopeVariable v, ControlFlowNode def, ControlFlowNode node) {
+predicate allocatedVariableReaches(StackVariable v, ControlFlowNode def, ControlFlowNode node) {
exists(AllocVariableReachability r |
// reachability
r.reachesTo(def, _, node, v)
@@ -136,25 +134,25 @@ predicate allocatedVariableReaches(LocalScopeVariable v, ControlFlowNode def, Co
)
}
-class AllocReachability extends LocalScopeVariableReachabilityExt {
+class AllocReachability extends StackVariableReachabilityExt {
AllocReachability() { this = "AllocReachability" }
- override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
+ override predicate isSource(ControlFlowNode node, StackVariable v) {
allocationDefinition(v, node)
}
- override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
+ override predicate isSink(ControlFlowNode node, StackVariable v) {
v.getFunction() = node.(ReturnStmt).getEnclosingFunction()
}
override predicate isBarrier(
- ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, LocalScopeVariable v
+ ControlFlowNode source, ControlFlowNode node, ControlFlowNode next, StackVariable v
) {
isSource(source, v) and
next = node.getASuccessor() and
// the memory (stored in any variable `v0`) allocated at `source` is freed or
// assigned to a global at node, or NULL checked on the edge node -> next.
- exists(LocalScopeVariable v0 | allocatedVariableReaches(v0, source, node) |
+ exists(StackVariable v0 | allocatedVariableReaches(v0, source, node) |
node.(AnalysedExpr).getNullSuccessor(v0) = next or
freeCallOrIndirect(node, v0) or
assignedToFieldOrGlobal(v0, node)
@@ -171,11 +169,11 @@ predicate allocationReaches(ControlFlowNode def, ControlFlowNode node) {
exists(AllocReachability r | r.reaches(def, _, node))
}
-predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
- // assigned to anything except a LocalScopeVariable
+predicate assignedToFieldOrGlobal(StackVariable v, Expr e) {
+ // assigned to anything except a StackVariable
// (typically a field or global, but for example also *ptr = v)
e.(Assignment).getRValue() = v.getAnAccess() and
- not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable
+ not e.(Assignment).getLValue().(VariableAccess).getTarget() instanceof StackVariable
or
exists(Expr midExpr, Function mid, int arg |
// indirect assignment
@@ -192,7 +190,7 @@ predicate assignedToFieldOrGlobal(LocalScopeVariable v, Expr e) {
from ControlFlowNode def, ReturnStmt ret
where
allocationReaches(def, ret) and
- not exists(LocalScopeVariable v |
+ not exists(StackVariable v |
allocatedVariableReaches(v, def, ret) and
ret.getAChild*() = v.getAnAccess()
)
diff --git a/cpp/ql/src/Critical/MissingNegativityTest.ql b/cpp/ql/src/Critical/MissingNegativityTest.ql
index e351cba163e..565217578e0 100644
--- a/cpp/ql/src/Critical/MissingNegativityTest.ql
+++ b/cpp/ql/src/Critical/MissingNegativityTest.ql
@@ -43,7 +43,7 @@ class FunctionWithNegativeReturn extends Function {
predicate dangerousUse(IntegralReturnValue val, Expr use) {
exists(ArrayExpr ae | ae.getArrayOffset() = val and use = val)
or
- exists(LocalScopeVariable v, ControlFlowNode def, ArrayExpr ae |
+ exists(StackVariable v, ControlFlowNode def, ArrayExpr ae |
exprDefinition(v, def, val) and
use = ae.getArrayOffset() and
not boundsChecked(v, use) and
@@ -54,7 +54,7 @@ predicate dangerousUse(IntegralReturnValue val, Expr use) {
val = use and
use.getType().getUnderlyingType() instanceof PointerType
or
- exists(LocalScopeVariable v, ControlFlowNode def, AddExpr add |
+ exists(StackVariable v, ControlFlowNode def, AddExpr add |
exprDefinition(v, def, val) and
definitionUsePair(v, def, use) and
add.getAnOperand() = use and
diff --git a/cpp/ql/src/Critical/NewDelete.qll b/cpp/ql/src/Critical/NewDelete.qll
index 39b265556b0..691c9a1031d 100644
--- a/cpp/ql/src/Critical/NewDelete.qll
+++ b/cpp/ql/src/Critical/NewDelete.qll
@@ -60,7 +60,7 @@ predicate allocExprOrIndirect(Expr alloc, string kind) {
pragma[nomagic]
private predicate allocReachesVariable(Variable v, Expr alloc, string kind) {
exists(Expr mid |
- not v instanceof LocalScopeVariable and
+ not v instanceof StackVariable and
v.getAnAssignedValue() = mid and
allocReaches0(mid, alloc, kind)
)
@@ -76,7 +76,7 @@ private predicate allocReaches0(Expr e, Expr alloc, string kind) {
allocExprOrIndirect(alloc, kind) and
e = alloc
or
- exists(SsaDefinition def, LocalScopeVariable v |
+ exists(SsaDefinition def, StackVariable v |
// alloc via SSA
allocReaches0(def.getAnUltimateDefiningValue(v), alloc, kind) and
e = def.getAUse(v)
diff --git a/cpp/ql/src/Critical/OverflowCalculated.ql b/cpp/ql/src/Critical/OverflowCalculated.ql
index fbca4a20a8f..c60ed7a610d 100644
--- a/cpp/ql/src/Critical/OverflowCalculated.ql
+++ b/cpp/ql/src/Critical/OverflowCalculated.ql
@@ -18,7 +18,7 @@ class MallocCall extends FunctionCall {
Expr getAllocatedSize() {
if this.getArgument(0) instanceof VariableAccess
then
- exists(LocalScopeVariable v, ControlFlowNode def |
+ exists(StackVariable v, ControlFlowNode def |
definitionUsePair(v, def, this.getArgument(0)) and
exprDefinition(v, def, result)
)
diff --git a/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql b/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql
index 6d5cf2a58cc..353e51daa71 100644
--- a/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql
+++ b/cpp/ql/src/Critical/ReturnStackAllocatedObject.ql
@@ -20,11 +20,10 @@ class ReturnPointsToExpr extends PointsToExpr {
ReturnStmt getReturnStmt() { result.getExpr().getFullyConverted() = this }
}
-from ReturnPointsToExpr ret, LocalVariable local, float confidence
+from ReturnPointsToExpr ret, StackVariable local, float confidence
where
ret.pointsTo() = local and
ret.getReturnStmt().getEnclosingFunction() = local.getFunction() and
- not local.isStatic() and
confidence = ret.confidence() and
confidence > 0.01
select ret,
diff --git a/cpp/ql/src/Critical/Unused.ql b/cpp/ql/src/Critical/Unused.ql
index 8046d47c746..89ebde29171 100644
--- a/cpp/ql/src/Critical/Unused.ql
+++ b/cpp/ql/src/Critical/Unused.ql
@@ -20,11 +20,10 @@ class ScopeUtilityClass extends Class {
Call getAUse() { result = this.getAConstructor().getACallToThisFunction() }
}
-from LocalScopeVariable v, ControlFlowNode def
+from StackVariable v, ControlFlowNode def
where
definition(v, def) and
not definitionUsePair(v, def, _) and
- not v.isStatic() and
not v.getAnAccess().isAddressOfAccess() and
// parameter initializers are not in the call-graph at the moment
not v.(Parameter).getInitializer().getExpr() = def and
diff --git a/cpp/ql/src/Critical/UseAfterFree.ql b/cpp/ql/src/Critical/UseAfterFree.ql
index 9efbb6c3b44..8fd228ca7e4 100644
--- a/cpp/ql/src/Critical/UseAfterFree.ql
+++ b/cpp/ql/src/Critical/UseAfterFree.ql
@@ -10,10 +10,10 @@
*/
import cpp
-import semmle.code.cpp.controlflow.LocalScopeVariableReachability
+import semmle.code.cpp.controlflow.StackVariableReachability
/** `e` is an expression that frees the memory pointed to by `v`. */
-predicate isFreeExpr(Expr e, LocalScopeVariable v) {
+predicate isFreeExpr(Expr e, StackVariable v) {
exists(VariableAccess va | va.getTarget() = v |
exists(FunctionCall fc | fc = e |
fc.getTarget().hasGlobalOrStdName("free") and
@@ -27,7 +27,7 @@ predicate isFreeExpr(Expr e, LocalScopeVariable v) {
}
/** `e` is an expression that (may) dereference `v`. */
-predicate isDerefExpr(Expr e, LocalScopeVariable v) {
+predicate isDerefExpr(Expr e, StackVariable v) {
v.getAnAccess() = e and dereferenced(e)
or
isDerefByCallExpr(_, _, e, v)
@@ -39,27 +39,27 @@ predicate isDerefExpr(Expr e, LocalScopeVariable v) {
* or a source code function that dereferences the relevant
* parameter.
*/
-predicate isDerefByCallExpr(Call c, int i, VariableAccess va, LocalScopeVariable v) {
+predicate isDerefByCallExpr(Call c, int i, VariableAccess va, StackVariable v) {
v.getAnAccess() = va and
va = c.getAnArgumentSubExpr(i) and
not c.passesByReference(i, va) and
(c.getTarget().hasEntryPoint() implies isDerefExpr(_, c.getTarget().getParameter(i)))
}
-class UseAfterFreeReachability extends LocalScopeVariableReachability {
+class UseAfterFreeReachability extends StackVariableReachability {
UseAfterFreeReachability() { this = "UseAfterFree" }
- override predicate isSource(ControlFlowNode node, LocalScopeVariable v) { isFreeExpr(node, v) }
+ override predicate isSource(ControlFlowNode node, StackVariable v) { isFreeExpr(node, v) }
- override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { isDerefExpr(node, v) }
+ override predicate isSink(ControlFlowNode node, StackVariable v) { isDerefExpr(node, v) }
- override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
+ override predicate isBarrier(ControlFlowNode node, StackVariable v) {
definitionBarrier(v, node) or
isFreeExpr(node, v)
}
}
-from UseAfterFreeReachability r, LocalScopeVariable v, Expr free, Expr e
+from UseAfterFreeReachability r, StackVariable v, Expr free, Expr e
where r.reaches(free, v, e)
select e, "Memory pointed to by '" + v.getName().toString() + "' may have been previously freed $@",
free, "here"
diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.qhelp b/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.qhelp
index 621ae3273fd..7907df47957 100644
--- a/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.qhelp
+++ b/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.qhelp
@@ -18,49 +18,39 @@ optimizing compiler.
Solutions to this problem can be thought of as falling into one of two
-categories: (1) rewrite the signed expression so that overflow cannot occur
-but the signedness remains, or (2) rewrite (or cast) the signed expression
-into unsigned form.
+categories:
-
-Below we list examples of expressions where signed overflow may
-occur, along with proposed solutions. The list should not be
-considered exhaustive.
-
+
+- Rewrite the signed expression so that overflow cannot occur
+but the signedness remains.
+- Change the variables and all their uses to be unsigned.
+
-Given unsigned short i, delta and i + delta < i,
-it is possible to rewrite it as (unsigned short)(i + delta) < i.
-Note that i + deltadoes not actually overflow, due to int promotion
+The following cases all fall into the first category.
-
-Given unsigned short i, delta and i + delta < i,
-it is also possible to rewrite it as USHORT_MAX - delta. It must be true
-that delta > 0 and the limits.h or climits
+
+-
+Given
unsigned short n1, delta and n1 + delta < n1,
+it is possible to rewrite it as (unsigned short)(n1 + delta) < n1.
+Note that n1 + delta does not actually overflow, due to int promotion.
+
+
+-
+Given
unsigned short n1, delta and n1 + delta < n1,
+it is also possible to rewrite it as n1 > USHORT_MAX - delta. The
+limits.h or climits header must then be included.
+
+
+-
+Given
int n1, delta and n1 + delta < n1,
+it is possible to rewrite it as n1 > INT_MAX - delta. It must be true
+that delta >= 0 and the limits.h or climits
header has been included.
-
-
-
@@ -68,7 +58,7 @@ affected by this change.
In the following example, even though delta has been declared
unsigned short, C/C++ type promotion rules require that its
type is promoted to the larger type used in the addition and comparison,
-namely a signed int. Addition is performed on
+namely a signed int. Addition is performed on
signed integers, and may have undefined behavior if an overflow occurs.
As a result, the entire (comparison) expression may also have an undefined
result.
@@ -87,10 +77,10 @@ are avoided.
In the following example, even though both n and delta
-have been declared unsigned short, both are promoted to
+have been declared unsigned short, both are promoted to
signed int prior to addition. Because we started out with the
narrower short type, the addition is guaranteed not to overflow
-and is therefore defined. But the fact that n1 + delta never
+and is therefore defined. But the fact that n1 + delta never
overflows means that the condition n1 + delta < n1 will never
hold true, which likely is not what the programmer intended. (see also the
cpp/bad-addition-overflow-check query).
@@ -98,7 +88,7 @@ hold true, which likely is not what the programmer intended. (see also the
The next example provides a solution to the previous one. Even though
-i + delta does not overflow, casting it to an
+n1 + delta does not overflow, casting it to an
unsigned short truncates the addition modulo 2^16,
so that unsigned short "wrap around" may now be observed.
Furthermore, since the left-hand side is now of type unsigned short,
diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql b/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql
index ce1a8149c40..1cc7b74375d 100644
--- a/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql
+++ b/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql
@@ -14,6 +14,7 @@
import cpp
private import semmle.code.cpp.valuenumbering.GlobalValueNumbering
private import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
+private import semmle.code.cpp.commons.Exclusions
from RelationalOperation ro, AddExpr add, Expr expr1, Expr expr2
where
@@ -22,7 +23,7 @@ where
ro.getAnOperand() = expr2 and
globalValueNumber(expr1) = globalValueNumber(expr2) and
add.getUnspecifiedType().(IntegralType).isSigned() and
- not exists(MacroInvocation mi | mi.getAnAffectedElement() = add) and
+ not isFromMacroDefinition(ro) and
exprMightOverflowPositively(add) and
exists(Compilation c | c.getAFileCompiled() = ro.getFile() |
not c.getAnArgument() = "-fwrapv" and
diff --git a/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql b/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql
index 6a0098df131..029f11dd8c6 100644
--- a/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql
+++ b/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql
@@ -37,7 +37,7 @@ predicate flowsToExprImpl(Expr source, Expr sink, boolean pathMightOverflow) {
pathMightOverflow = false and
source.(FunctionCall).getTarget().(Snprintf).returnsFullFormatLength()
or
- exists(RangeSsaDefinition def, LocalScopeVariable v |
+ exists(RangeSsaDefinition def, StackVariable v |
flowsToDef(source, def, v, pathMightOverflow) and
sink = def.getAUse(v)
)
@@ -63,9 +63,7 @@ predicate flowsToExprImpl(Expr source, Expr sink, boolean pathMightOverflow) {
* `pathMightOverflow` is true if there is an arithmetic operation
* on the path that might overflow.
*/
-predicate flowsToDef(
- Expr source, RangeSsaDefinition def, LocalScopeVariable v, boolean pathMightOverflow
-) {
+predicate flowsToDef(Expr source, RangeSsaDefinition def, StackVariable v, boolean pathMightOverflow) {
// Might the current definition overflow?
exists(boolean otherMightOverflow | flowsToDefImpl(source, def, v, otherMightOverflow) |
if defMightOverflow(def, v)
@@ -86,7 +84,7 @@ predicate flowsToDef(
* the path. But it is a good way to reduce the number of false positives.
*/
predicate flowsToDefImpl(
- Expr source, RangeSsaDefinition def, LocalScopeVariable v, boolean pathMightOverflow
+ Expr source, RangeSsaDefinition def, StackVariable v, boolean pathMightOverflow
) {
// Assignment or initialization: `e = v;`
exists(Expr e |
diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/AssignWhereCompareMeant.ql b/cpp/ql/src/Likely Bugs/Likely Typos/AssignWhereCompareMeant.ql
index 368171a1359..c25febfc6b7 100644
--- a/cpp/ql/src/Likely Bugs/Likely Typos/AssignWhereCompareMeant.ql
+++ b/cpp/ql/src/Likely Bugs/Likely Typos/AssignWhereCompareMeant.ql
@@ -12,24 +12,24 @@
*/
import cpp
-import semmle.code.cpp.controlflow.LocalScopeVariableReachability
+import semmle.code.cpp.controlflow.StackVariableReachability
-class UndefReachability extends LocalScopeVariableReachability {
+class UndefReachability extends StackVariableReachability {
UndefReachability() { this = "UndefReachability" }
- override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
+ override predicate isSource(ControlFlowNode node, StackVariable v) {
candidateVariable(v) and
node = v.getParentScope() and
not v instanceof Parameter and
not v.hasInitializer()
}
- override predicate isSink(ControlFlowNode node, LocalScopeVariable v) {
+ override predicate isSink(ControlFlowNode node, StackVariable v) {
candidateVariable(v) and
node = v.getAnAccess()
}
- override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
+ override predicate isBarrier(ControlFlowNode node, StackVariable v) {
node.(AssignExpr).getLValue() = v.getAnAccess()
}
}
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql b/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql
index 54392d105a6..2a4b2d16507 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/ImproperNullTermination.ql
@@ -11,7 +11,7 @@
*/
import cpp
-import semmle.code.cpp.controlflow.LocalScopeVariableReachability
+import semmle.code.cpp.controlflow.StackVariableReachability
import semmle.code.cpp.commons.NullTermination
/**
@@ -22,10 +22,10 @@ DeclStmt declWithNoInit(LocalVariable v) {
not exists(v.getInitializer())
}
-class ImproperNullTerminationReachability extends LocalScopeVariableReachabilityWithReassignment {
+class ImproperNullTerminationReachability extends StackVariableReachabilityWithReassignment {
ImproperNullTerminationReachability() { this = "ImproperNullTerminationReachability" }
- override predicate isSourceActual(ControlFlowNode node, LocalScopeVariable v) {
+ override predicate isSourceActual(ControlFlowNode node, StackVariable v) {
node = declWithNoInit(v)
or
exists(Call c, VariableAccess va |
@@ -36,12 +36,12 @@ class ImproperNullTerminationReachability extends LocalScopeVariableReachability
)
}
- override predicate isSinkActual(ControlFlowNode node, LocalScopeVariable v) {
+ override predicate isSinkActual(ControlFlowNode node, StackVariable v) {
node.(VariableAccess).getTarget() = v and
variableMustBeNullTerminated(node)
}
- override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
+ override predicate isBarrier(ControlFlowNode node, StackVariable v) {
exprDefinition(v, node, _) or
mayAddNullTerminator(node, v.getAnAccess()) or
isSinkActual(node, v) // only report first use
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql b/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql
index d10addadca9..fc06ed0a500 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql
@@ -42,10 +42,8 @@ predicate hasNontrivialConversion(Expr e) {
hasNontrivialConversion(e.getConversion())
}
-from LocalScopeVariable var, VariableAccess va, ReturnStmt r
+from StackVariable var, VariableAccess va, ReturnStmt r
where
- not var.isStatic() and
- not var.isThreadLocal() and
not var.getUnspecifiedType() instanceof ReferenceType and
not r.isFromUninstantiatedTemplate(_) and
va = var.getAnAccess() and
diff --git a/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql b/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql
index e213e9e461d..57dac90c850 100644
--- a/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql
+++ b/cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql
@@ -12,7 +12,7 @@
*/
import cpp
-import semmle.code.cpp.controlflow.LocalScopeVariableReachability
+import semmle.code.cpp.controlflow.StackVariableReachability
/**
* Auxiliary predicate: Types that don't require initialization
@@ -40,23 +40,17 @@ DeclStmt declWithNoInit(LocalVariable v) {
result.getADeclaration() = v and
not exists(v.getInitializer()) and
/* The type of the variable is not stack-allocated. */
- not allocatedType(v.getType()) and
- /* The variable is not static (otherwise it is zeroed). */
- not v.isStatic() and
- /* The variable is not extern (otherwise it is zeroed). */
- not v.hasSpecifier("extern")
+ not allocatedType(v.getType())
}
-class UninitialisedLocalReachability extends LocalScopeVariableReachability {
+class UninitialisedLocalReachability extends StackVariableReachability {
UninitialisedLocalReachability() { this = "UninitialisedLocal" }
- override predicate isSource(ControlFlowNode node, LocalScopeVariable v) {
- node = declWithNoInit(v)
- }
+ override predicate isSource(ControlFlowNode node, StackVariable v) { node = declWithNoInit(v) }
- override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { useOfVarActual(v, node) }
+ override predicate isSink(ControlFlowNode node, StackVariable v) { useOfVarActual(v, node) }
- override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
+ override predicate isBarrier(ControlFlowNode node, StackVariable v) {
// only report the _first_ possibly uninitialized use
useOfVarActual(v, node) or
definitionBarrier(v, node)
diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql
index 1142cc1a45b..e137e90c716 100644
--- a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql
+++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql
@@ -84,10 +84,10 @@ predicate hasZeroParamDecl(Function f) {
}
// True if this file (or header) was compiled as a C file
-predicate isCompiledAsC(Function f) {
- exists(File file | file.compiledAsC() |
- file = f.getFile() or file.getAnIncludedFile+() = f.getFile()
- )
+predicate isCompiledAsC(File f) {
+ f.compiledAsC()
+ or
+ exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
}
from FunctionCall fc, Function f, Parameter p
@@ -95,7 +95,7 @@ where
f = fc.getTarget() and
p = f.getAParameter() and
hasZeroParamDecl(f) and
- isCompiledAsC(f) and
+ isCompiledAsC(f.getFile()) and
not f.isVarargs() and
not f instanceof BuiltInFunction and
p.getIndex() < fc.getNumberOfArguments() and
diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql
index a3e78fe61c4..705c1ec4dc8 100644
--- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql
+++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql
@@ -24,10 +24,10 @@ predicate hasZeroParamDecl(Function f) {
}
// True if this file (or header) was compiled as a C file
-predicate isCompiledAsC(Function f) {
- exists(File file | file.compiledAsC() |
- file = f.getFile() or file.getAnIncludedFile+() = f.getFile()
- )
+predicate isCompiledAsC(File f) {
+ f.compiledAsC()
+ or
+ exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
}
from FunctionCall fc, Function f
@@ -36,7 +36,7 @@ where
not f.isVarargs() and
not f instanceof BuiltInFunction and
hasZeroParamDecl(f) and
- isCompiledAsC(f) and
+ isCompiledAsC(f.getFile()) and
// There is an explicit declaration of the function whose parameter count is larger
// than the number of call arguments
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql
index b0bd7746c15..59368236bbd 100644
--- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql
+++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql
@@ -25,10 +25,10 @@ predicate hasZeroParamDecl(Function f) {
}
// True if this file (or header) was compiled as a C file
-predicate isCompiledAsC(Function f) {
- exists(File file | file.compiledAsC() |
- file = f.getFile() or file.getAnIncludedFile+() = f.getFile()
- )
+predicate isCompiledAsC(File f) {
+ f.compiledAsC()
+ or
+ exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
}
from FunctionCall fc, Function f
@@ -36,7 +36,7 @@ where
f = fc.getTarget() and
not f.isVarargs() and
hasZeroParamDecl(f) and
- isCompiledAsC(f) and
+ isCompiledAsC(f.getFile()) and
exists(f.getBlock()) and
// There must not exist a declaration with the number of parameters
// at least as large as the number of call arguments
diff --git a/cpp/ql/src/Security/CWE/CWE-129/ImproperArrayIndexValidation.ql b/cpp/ql/src/Security/CWE/CWE-129/ImproperArrayIndexValidation.ql
index 3d7379be507..c073cf37af8 100644
--- a/cpp/ql/src/Security/CWE/CWE-129/ImproperArrayIndexValidation.ql
+++ b/cpp/ql/src/Security/CWE/CWE-129/ImproperArrayIndexValidation.ql
@@ -16,7 +16,7 @@ private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
import semmle.code.cpp.security.TaintTracking
predicate hasUpperBound(VariableAccess offsetExpr) {
- exists(BasicBlock controlled, LocalScopeVariable offsetVar, SsaDefinition def |
+ exists(BasicBlock controlled, StackVariable offsetVar, SsaDefinition def |
controlled.contains(offsetExpr) and
linearBoundControls(controlled, def, offsetVar) and
offsetExpr = def.getAUse(offsetVar)
@@ -24,7 +24,7 @@ predicate hasUpperBound(VariableAccess offsetExpr) {
}
pragma[noinline]
-predicate linearBoundControls(BasicBlock controlled, SsaDefinition def, LocalScopeVariable offsetVar) {
+predicate linearBoundControls(BasicBlock controlled, SsaDefinition def, StackVariable offsetVar) {
exists(GuardCondition guard, boolean branch |
guard.controls(controlled, branch) and
cmpWithLinearBound(guard, def.getAUse(offsetVar), Lesser(), branch)
diff --git a/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql b/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
index 92f679a0f1f..aebaca36ad0 100644
--- a/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
+++ b/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
@@ -44,7 +44,7 @@ Element friendlyLoc(Expr e) {
not e instanceof Access and not e instanceof Call and result = e
}
-from Loop l, RelationalOperation rel, Expr small, Expr large
+from Loop l, RelationalOperation rel, VariableAccess small, Expr large
where
small = rel.getLesserOperand() and
large = rel.getGreaterOperand() and
@@ -60,7 +60,7 @@ where
not getComparisonSize(large.(SubExpr).getLeftOperand().getExplicitlyConverted()) <= getComparisonSize(small) and
not getComparisonSize(large.(RShiftExpr).getLeftOperand().getExplicitlyConverted()) <= getComparisonSize(small) and
// ignore loop-invariant smaller variables
- loopVariant(small.getAChild*(), l)
+ loopVariant(small, l)
select rel,
"Comparison between $@ of type " + small.getType().getName() + " and $@ of wider type " +
large.getType().getName() + ".", friendlyLoc(small), small.toString(), friendlyLoc(large),
diff --git a/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql b/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql
index 67b2f5c7eef..052cce56198 100644
--- a/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql
+++ b/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql
@@ -82,7 +82,7 @@ FunctionCall stat(Expr path, Expr buf) {
predicate referenceTo(Expr source, Expr use) {
source = use
or
- exists(SsaDefinition def, LocalScopeVariable v |
+ exists(SsaDefinition def, StackVariable v |
def.getAnUltimateDefiningValue(v) = source and def.getAUse(v) = use
)
}
@@ -109,9 +109,7 @@ where
)
) and
// checkUse and opUse refer to the same SSA variable
- exists(SsaDefinition def, LocalScopeVariable v |
- def.getAUse(v) = checkUse and def.getAUse(v) = opUse
- ) and
+ exists(SsaDefinition def, StackVariable v | def.getAUse(v) = checkUse and def.getAUse(v) = opUse) and
// opUse looks like an operation on a filename
fc = filenameOperation(opUse) and
// the return value of check is used (possibly with one step of
diff --git a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingCommon.qll b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingCommon.qll
index e2756de18fd..4854c1dc38e 100644
--- a/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingCommon.qll
+++ b/cpp/ql/src/Security/CWE/CWE-468/IncorrectPointerScalingCommon.qll
@@ -100,9 +100,9 @@ Type baseType(Type t) {
*/
predicate exprSourceType(Expr use, Type sourceType, Location sourceLoc) {
// Reaching definitions.
- if exists(SsaDefinition def, LocalScopeVariable v | use = def.getAUse(v))
+ if exists(SsaDefinition def, StackVariable v | use = def.getAUse(v))
then
- exists(SsaDefinition def, LocalScopeVariable v | use = def.getAUse(v) |
+ exists(SsaDefinition def, StackVariable v | use = def.getAUse(v) |
defSourceType(def, v, sourceType, sourceLoc)
)
else
@@ -137,7 +137,7 @@ predicate exprSourceType(Expr use, Type sourceType, Location sourceLoc) {
* Holds if there is a pointer expression with type `sourceType` at
* location `sourceLoc` which might define the value of `v` at `def`.
*/
-predicate defSourceType(SsaDefinition def, LocalScopeVariable v, Type sourceType, Location sourceLoc) {
+predicate defSourceType(SsaDefinition def, StackVariable v, Type sourceType, Location sourceLoc) {
exprSourceType(def.getDefiningValue(v), sourceType, sourceLoc)
or
defSourceType(def.getAPhiInput(v), v, sourceType, sourceLoc)
diff --git a/cpp/ql/src/jsf/4.13 Functions/AV Rule 111.ql b/cpp/ql/src/jsf/4.13 Functions/AV Rule 111.ql
index 8c62c5763aa..8cdeb486c1f 100644
--- a/cpp/ql/src/jsf/4.13 Functions/AV Rule 111.ql
+++ b/cpp/ql/src/jsf/4.13 Functions/AV Rule 111.ql
@@ -20,10 +20,9 @@ class ReturnPointsToExpr extends PointsToExpr {
ReturnStmt getReturnStmt() { result.getExpr() = this }
}
-from ReturnPointsToExpr ret, LocalVariable dest
+from ReturnPointsToExpr ret, StackVariable dest
where
ret.pointsTo() = dest and
- ret.getReturnStmt().getParentStmt().getEnclosingFunction() = dest.getFunction() and
- not dest.isStatic()
+ ret.getReturnStmt().getParentStmt().getEnclosingFunction() = dest.getFunction()
select ret.getReturnStmt(),
"AV Rule 111: A function shall not return a pointer or reference to a non-static local object."
diff --git a/cpp/ql/src/semmle/code/cpp/Enclosing.qll b/cpp/ql/src/semmle/code/cpp/Enclosing.qll
index b56f7219d07..07d39b10e83 100644
--- a/cpp/ql/src/semmle/code/cpp/Enclosing.qll
+++ b/cpp/ql/src/semmle/code/cpp/Enclosing.qll
@@ -13,6 +13,11 @@ Element stmtEnclosingElement(Stmt s) {
/**
* Gets the enclosing element of expression `e`.
*/
+// The `pragma[nomagic]` is a workaround to prevent this cached stage (and all
+// subsequent stages) from being evaluated twice. See QL-888. It has the effect
+// of making the `Conversion` class predicate get the same optimization in all
+// queries.
+pragma[nomagic]
cached
Element exprEnclosingElement(Expr e) {
result = exprEnclosingElement(e.getParent())
diff --git a/cpp/ql/src/semmle/code/cpp/Variable.qll b/cpp/ql/src/semmle/code/cpp/Variable.qll
index 194cc5333c7..221a77f1a40 100644
--- a/cpp/ql/src/semmle/code/cpp/Variable.qll
+++ b/cpp/ql/src/semmle/code/cpp/Variable.qll
@@ -307,8 +307,8 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry {
* }
* ```
*
- * Local variables can be static; use the `isStatic` member predicate to
- * detect those.
+ * See also `StackVariable`, which is the class of local-scope variables
+ * without statics and thread-locals.
*/
class LocalScopeVariable extends Variable, @localscopevariable {
/** Gets the function to which this variable belongs. */
@@ -316,12 +316,21 @@ class LocalScopeVariable extends Variable, @localscopevariable {
}
/**
- * DEPRECATED: use `LocalScopeVariable` instead.
+ * A C/C++ variable with _automatic storage duration_. In other words, a
+ * function parameter or a local variable that is not static or thread-local.
+ * For example, the variables `a` and `b` in the following code.
+ * ```
+ * void myFunction(int a) {
+ * int b;
+ * static int c;
+ * }
+ * ```
*/
-deprecated class StackVariable extends Variable {
- StackVariable() { this instanceof LocalScopeVariable }
-
- Function getFunction() { result = this.(LocalScopeVariable).getFunction() }
+class StackVariable extends LocalScopeVariable {
+ StackVariable() {
+ not this.isStatic() and
+ not this.isThreadLocal()
+ }
}
/**
@@ -496,7 +505,7 @@ class TemplateVariable extends Variable {
* `myTemplateFunction`:
* ```
* void myFunction() {
- * T a;
+ * float a;
* }
*
* template
@@ -509,9 +518,6 @@ class TemplateVariable extends Variable {
* myTemplateFunction();
* ```
*/
-class SemanticStackVariable extends LocalScopeVariable {
- SemanticStackVariable() {
- not this.isStatic() and
- not this.isFromUninstantiatedTemplate(_)
- }
+class SemanticStackVariable extends StackVariable {
+ SemanticStackVariable() { not this.isFromUninstantiatedTemplate(_) }
}
diff --git a/cpp/ql/src/semmle/code/cpp/commons/Exclusions.qll b/cpp/ql/src/semmle/code/cpp/commons/Exclusions.qll
index cae647982d2..a0dfea20046 100644
--- a/cpp/ql/src/semmle/code/cpp/commons/Exclusions.qll
+++ b/cpp/ql/src/semmle/code/cpp/commons/Exclusions.qll
@@ -94,11 +94,18 @@ predicate functionContainsPreprocCode(Function f) {
* ```
*/
predicate isFromMacroDefinition(Element e) {
- exists(MacroInvocation mi |
- // e is in mi
+ exists(MacroInvocation mi, Location eLocation, Location miLocation |
mi.getAnExpandedElement() = e and
- // and e was apparently not passed in as a macro parameter
- e.getLocation().getStartLine() = mi.getLocation().getStartLine() and
- e.getLocation().getStartColumn() = mi.getLocation().getStartColumn()
+ eLocation = e.getLocation() and
+ miLocation = mi.getLocation() and
+ // If the location of `e` coincides with the macro invocation, then `e` did
+ // not come from a macro argument. The inequalities here could also be
+ // equalities, but that confuses the join orderer into joining on the source
+ // locations too early.
+ // There are cases where the start location of a non-argument element comes
+ // right after the invocation's open parenthesis, so it appears to be more
+ // robust to match on the end location instead.
+ eLocation.getEndLine() >= miLocation.getEndLine() and
+ eLocation.getEndColumn() >= miLocation.getEndColumn()
)
}
diff --git a/cpp/ql/src/semmle/code/cpp/commons/NullTermination.qll b/cpp/ql/src/semmle/code/cpp/commons/NullTermination.qll
index 650e2bc9954..38add4ab5ef 100644
--- a/cpp/ql/src/semmle/code/cpp/commons/NullTermination.qll
+++ b/cpp/ql/src/semmle/code/cpp/commons/NullTermination.qll
@@ -3,7 +3,7 @@ private import semmle.code.cpp.models.interfaces.ArrayFunction
private import semmle.code.cpp.models.implementations.Strcat
private predicate mayAddNullTerminatorHelper(Expr e, VariableAccess va, Expr e0) {
- exists(LocalScopeVariable v0, Expr val |
+ exists(StackVariable v0, Expr val |
exprDefinition(v0, e, val) and
val.getAChild*() = va and
mayAddNullTerminator(e0, v0.getAnAccess())
@@ -41,7 +41,7 @@ predicate mayAddNullTerminator(Expr e, VariableAccess va) {
or
// Assignment to non-stack variable
exists(AssignExpr ae | e = ae |
- not ae.getLValue().(VariableAccess).getTarget() instanceof LocalScopeVariable and
+ not ae.getLValue().(VariableAccess).getTarget() instanceof StackVariable and
ae.getRValue().getAChild*() = va
)
or
diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll b/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll
index 0bac436d16e..1ab33c9a25c 100644
--- a/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll
+++ b/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll
@@ -1,5 +1,5 @@
import cpp
-private import semmle.code.cpp.controlflow.LocalScopeVariableReachability
+private import semmle.code.cpp.controlflow.StackVariableReachability
private import semmle.code.cpp.dataflow.EscapesTree
/**
@@ -108,7 +108,7 @@ library class DefOrUse extends ControlFlowNodeBase {
/*
* Implementation detail: this predicate and its private auxiliary
* predicates are instances of the more general predicates in
- * LocalScopeVariableReachability.qll, and should be kept in sync.
+ * StackVariableReachability.qll, and should be kept in sync.
*
* Unfortunately, caching of abstract predicates does not work well, so the
* predicates are duplicated for now.
diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/Guards.qll b/cpp/ql/src/semmle/code/cpp/controlflow/Guards.qll
index c64f724975d..007c1f2ecfc 100644
--- a/cpp/ql/src/semmle/code/cpp/controlflow/Guards.qll
+++ b/cpp/ql/src/semmle/code/cpp/controlflow/Guards.qll
@@ -371,7 +371,7 @@ private int int_value(Expr e) {
/** An `SsaDefinition` with an additional predicate `isLt`. */
class GuardedSsa extends SsaDefinition {
/** Holds if this `SsaDefinition` is guarded such that `this(var) < gt + k` is `testIsTrue` in `block`. */
- predicate isLt(LocalScopeVariable var, Expr gt, int k, BasicBlock block, boolean testIsTrue) {
+ predicate isLt(StackVariable var, Expr gt, int k, BasicBlock block, boolean testIsTrue) {
exists(Expr luse, GuardCondition test | this.getAUse(var) = luse |
test.ensuresLt(luse, gt, k, block, testIsTrue)
)
diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/LocalScopeVariableReachability.qll b/cpp/ql/src/semmle/code/cpp/controlflow/LocalScopeVariableReachability.qll
index 117854d39e6..32857146029 100644
--- a/cpp/ql/src/semmle/code/cpp/controlflow/LocalScopeVariableReachability.qll
+++ b/cpp/ql/src/semmle/code/cpp/controlflow/LocalScopeVariableReachability.qll
@@ -1,6 +1,12 @@
+/**
+ * DEPRECATED: Use `StackVariableReachability` instead.
+ */
+
import cpp
/**
+ * DEPRECATED: Use `StackVariableReachability` instead.
+ *
* A reachability analysis for control-flow nodes involving stack variables.
* This defines sources, sinks, and any other configurable aspect of the
* analysis. Multiple analyses can coexist. To create an analysis, extend this
@@ -18,7 +24,7 @@ import cpp
* Then, to query whether there is flow between some source and sink, call the
* `reaches` predicate on an instance of `MyAnalysisConfiguration`.
*/
-abstract class LocalScopeVariableReachability extends string {
+abstract deprecated class LocalScopeVariableReachability extends string {
bindingset[this]
LocalScopeVariableReachability() { length() >= 0 }
@@ -207,6 +213,8 @@ predicate bbSuccessorEntryReachesLoopInvariant(
}
/**
+ * DEPRECATED: Use `StackVariableReachabilityWithReassignment` instead.
+ *
* Reachability analysis for control-flow nodes involving stack variables.
* Unlike `LocalScopeVariableReachability`, this analysis takes variable
* reassignments into account.
@@ -216,7 +224,7 @@ predicate bbSuccessorEntryReachesLoopInvariant(
* `isSource` and `isSink`, and that there is a `reachesTo` predicate in
* addition to `reaches`.
*/
-abstract class LocalScopeVariableReachabilityWithReassignment extends LocalScopeVariableReachability {
+abstract deprecated class LocalScopeVariableReachabilityWithReassignment extends LocalScopeVariableReachability {
bindingset[this]
LocalScopeVariableReachabilityWithReassignment() { length() >= 0 }
@@ -314,12 +322,14 @@ abstract class LocalScopeVariableReachabilityWithReassignment extends LocalScope
}
/**
+ * DEPRECATED: Use `StackVariableReachabilityExt` instead.
+ *
* Same as `LocalScopeVariableReachability`, but `isBarrier` works on control-flow
* edges rather than nodes and is therefore parameterized by the original
* source node as well. Otherwise, this class is used like
* `LocalScopeVariableReachability`.
*/
-abstract class LocalScopeVariableReachabilityExt extends string {
+abstract deprecated class LocalScopeVariableReachabilityExt extends string {
bindingset[this]
LocalScopeVariableReachabilityExt() { length() >= 0 }
diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll b/cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll
index 8384a5b3c66..4e2e018eda3 100644
--- a/cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll
+++ b/cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll
@@ -9,11 +9,11 @@ library class StandardSSA extends SSAHelper {
/**
* A definition of one or more SSA variables, including phi node definitions.
* An _SSA variable_, as defined in the literature, is effectively the pair of
- * an `SsaDefinition d` and a `LocalScopeVariable v`, written `(d, v)` in this
+ * an `SsaDefinition d` and a `StackVariable v`, written `(d, v)` in this
* documentation. Note that definitions and uses can be coincident due to the
* presence of parameter definitions and phi nodes.
*
- * Not all `LocalScopeVariable`s of a function have SSA definitions. If the variable
+ * Not all `StackVariable`s of a function have SSA definitions. If the variable
* has its address taken, either explicitly or implicitly, then it is excluded
* from analysis. `SsaDefinition`s are not generated in locations that are
* statically seen to be unreachable.
@@ -22,21 +22,19 @@ class SsaDefinition extends ControlFlowNodeBase {
SsaDefinition() { exists(StandardSSA x | x.ssa_defn(_, this, _, _)) }
/**
- * Gets a variable corresponding to an SSA LocalScopeVariable defined by
+ * Gets a variable corresponding to an SSA StackVariable defined by
* this definition.
*/
- LocalScopeVariable getAVariable() { exists(StandardSSA x | x.ssa_defn(result, this, _, _)) }
+ StackVariable getAVariable() { exists(StandardSSA x | x.ssa_defn(result, this, _, _)) }
/**
* Gets a string representation of the SSA variable represented by the pair
* `(this, v)`.
*/
- string toString(LocalScopeVariable v) { exists(StandardSSA x | result = x.toString(this, v)) }
+ string toString(StackVariable v) { exists(StandardSSA x | result = x.toString(this, v)) }
/** Gets a use of the SSA variable represented by the pair `(this, v)`. */
- VariableAccess getAUse(LocalScopeVariable v) {
- exists(StandardSSA x | result = x.getAUse(this, v))
- }
+ VariableAccess getAUse(StackVariable v) { exists(StandardSSA x | result = x.getAUse(this, v)) }
/**
* Gets the control-flow node for this definition. This will usually be the
@@ -55,9 +53,7 @@ class SsaDefinition extends ControlFlowNodeBase {
BasicBlock getBasicBlock() { result.contains(getDefinition()) }
/** Holds if this definition is a phi node for variable `v`. */
- predicate isPhiNode(LocalScopeVariable v) {
- exists(StandardSSA x | x.phi_node(v, this.(BasicBlock)))
- }
+ predicate isPhiNode(StackVariable v) { exists(StandardSSA x | x.phi_node(v, this.(BasicBlock))) }
Location getLocation() { result = this.(ControlFlowNode).getLocation() }
@@ -68,7 +64,7 @@ class SsaDefinition extends ControlFlowNodeBase {
* Holds if the SSA variable `(result, v)` is an input to the phi definition
* `(this, v)`.
*/
- SsaDefinition getAPhiInput(LocalScopeVariable v) {
+ SsaDefinition getAPhiInput(StackVariable v) {
this.isPhiNode(v) and
result.reachesEndOfBB(v, this.(BasicBlock).getAPredecessor())
}
@@ -92,7 +88,7 @@ class SsaDefinition extends ControlFlowNodeBase {
* instead covered via `definedByParameter` and `getDefinition`,
* respectively.
*/
- Expr getDefiningValue(LocalScopeVariable v) {
+ Expr getDefiningValue(StackVariable v) {
exists(ControlFlowNode def | def = this.getDefinition() |
def = v.getInitializer().getExpr() and def = result
or
@@ -117,7 +113,7 @@ class SsaDefinition extends ControlFlowNodeBase {
}
/** Holds if `(this, v)` reaches the end of basic block `b`. */
- predicate reachesEndOfBB(LocalScopeVariable v, BasicBlock b) {
+ predicate reachesEndOfBB(StackVariable v, BasicBlock b) {
exists(StandardSSA x | x.ssaDefinitionReachesEndOfBB(v, this, b))
}
@@ -125,7 +121,7 @@ class SsaDefinition extends ControlFlowNodeBase {
* Gets a definition that ultimately defines this variable and is not
* itself a phi node.
*/
- SsaDefinition getAnUltimateSsaDefinition(LocalScopeVariable v) {
+ SsaDefinition getAnUltimateSsaDefinition(StackVariable v) {
result = this.getAPhiInput(v).getAnUltimateSsaDefinition(v)
or
v = this.getAVariable() and
@@ -138,7 +134,7 @@ class SsaDefinition extends ControlFlowNodeBase {
* recursing backwards through phi definitions. Not all definitions have a
* defining expression---see the documentation for `getDefiningValue`.
*/
- Expr getAnUltimateDefiningValue(LocalScopeVariable v) {
+ Expr getAnUltimateDefiningValue(StackVariable v) {
result = this.getAnUltimateSsaDefinition(v).getDefiningValue(v)
}
@@ -149,7 +145,7 @@ class SsaDefinition extends ControlFlowNodeBase {
* `getAnUltimateSsaDefinition` to refer to a predicate named
* `getAnUltimateSsaDefinition` in this class.
*/
- deprecated Expr getAnUltimateDefinition(LocalScopeVariable v) {
+ deprecated Expr getAnUltimateDefinition(StackVariable v) {
result = this.getAnUltimateDefiningValue(v)
}
}
diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll b/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll
index 5501fb0a394..b9b34a1d68c 100644
--- a/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll
+++ b/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll
@@ -21,11 +21,9 @@ private predicate dominanceFrontier(BasicBlock x, BasicBlock w) {
}
/**
- * Extended version of `definition` that also includes parameters but excludes
- * static variables.
+ * Extended version of `definition` that also includes parameters.
*/
-predicate var_definition(LocalScopeVariable v, ControlFlowNode node) {
- not v.isStatic() and
+predicate var_definition(StackVariable v, ControlFlowNode node) {
not addressTakenVariable(v) and
not unreachable(node) and
(
@@ -51,7 +49,7 @@ predicate var_definition(LocalScopeVariable v, ControlFlowNode node) {
* analysis because the pointer could be used to change the value at
* any moment.
*/
-private predicate addressTakenVariable(LocalScopeVariable var) {
+private predicate addressTakenVariable(StackVariable var) {
// If the type of the variable is a reference type, then it is safe (as
// far as SSA is concerned) to take its address, because this does not
// enable the variable to be modified indirectly. Obviously the
@@ -71,7 +69,7 @@ private predicate addressTakenVariable(LocalScopeVariable var) {
)
}
-private predicate isReferenceVar(LocalScopeVariable v) {
+private predicate isReferenceVar(StackVariable v) {
v.getUnspecifiedType() instanceof ReferenceType
}
@@ -79,22 +77,22 @@ private predicate isReferenceVar(LocalScopeVariable v) {
* This predicate is the same as `var_definition`, but annotated with
* the basic block and index of the control flow node.
*/
-private predicate variableUpdate(LocalScopeVariable v, ControlFlowNode n, BasicBlock b, int i) {
+private predicate variableUpdate(StackVariable v, ControlFlowNode n, BasicBlock b, int i) {
var_definition(v, n) and n = b.getNode(i)
}
-private predicate ssa_use(LocalScopeVariable v, VariableAccess node, BasicBlock b, int index) {
+private predicate ssa_use(StackVariable v, VariableAccess node, BasicBlock b, int index) {
useOfVar(v, node) and b.getNode(index) = node
}
-private predicate live_at_start_of_bb(LocalScopeVariable v, BasicBlock b) {
+private predicate live_at_start_of_bb(StackVariable v, BasicBlock b) {
exists(int i | ssa_use(v, _, b, i) | not exists(int j | variableUpdate(v, _, b, j) | j < i))
or
live_at_exit_of_bb(v, b) and not variableUpdate(v, _, b, _)
}
pragma[noinline]
-private predicate live_at_exit_of_bb(LocalScopeVariable v, BasicBlock b) {
+private predicate live_at_exit_of_bb(StackVariable v, BasicBlock b) {
live_at_start_of_bb(v, b.getASuccessor())
}
@@ -110,12 +108,12 @@ library class SSAHelper extends int {
* basic block `b`.
*/
cached
- predicate custom_phi_node(LocalScopeVariable v, BasicBlock b) { none() }
+ predicate custom_phi_node(StackVariable v, BasicBlock b) { none() }
/**
* Remove any custom phi nodes that are invalid.
*/
- private predicate sanitized_custom_phi_node(LocalScopeVariable v, BasicBlock b) {
+ private predicate sanitized_custom_phi_node(StackVariable v, BasicBlock b) {
custom_phi_node(v, b) and
not addressTakenVariable(v) and
not isReferenceVar(v) and
@@ -127,7 +125,7 @@ library class SSAHelper extends int {
* `b`.
*/
cached
- predicate phi_node(LocalScopeVariable v, BasicBlock b) {
+ predicate phi_node(StackVariable v, BasicBlock b) {
frontier_phi_node(v, b) or sanitized_custom_phi_node(v, b)
}
@@ -138,13 +136,13 @@ library class SSAHelper extends int {
* definitions). This is known as the iterated dominance frontier. See
* Modern Compiler Implementation by Andrew Appel.
*/
- private predicate frontier_phi_node(LocalScopeVariable v, BasicBlock b) {
+ private predicate frontier_phi_node(StackVariable v, BasicBlock b) {
exists(BasicBlock x | dominanceFrontier(x, b) and ssa_defn_rec(v, x)) and
/* We can also eliminate those nodes where the variable is not live on any incoming edge */
live_at_start_of_bb(v, b)
}
- private predicate ssa_defn_rec(LocalScopeVariable v, BasicBlock b) {
+ private predicate ssa_defn_rec(StackVariable v, BasicBlock b) {
phi_node(v, b)
or
variableUpdate(v, _, b, _)
@@ -155,7 +153,7 @@ library class SSAHelper extends int {
* position `index` in block `b`. This includes definitions from phi nodes.
*/
cached
- predicate ssa_defn(LocalScopeVariable v, ControlFlowNode node, BasicBlock b, int index) {
+ predicate ssa_defn(StackVariable v, ControlFlowNode node, BasicBlock b, int index) {
phi_node(v, b) and b.getStart() = node and index = -1
or
variableUpdate(v, node, b, index)
@@ -179,7 +177,7 @@ library class SSAHelper extends int {
* irrelevant indices at which there is no definition or use when traversing
* basic blocks.
*/
- private predicate defUseRank(LocalScopeVariable v, BasicBlock b, int rankix, int i) {
+ private predicate defUseRank(StackVariable v, BasicBlock b, int rankix, int i) {
i = rank[rankix](int j | ssa_defn(v, _, b, j) or ssa_use(v, _, b, j))
}
@@ -189,7 +187,7 @@ library class SSAHelper extends int {
* the extra rank at the end represents a position past the last node in
* the block.
*/
- private int lastRank(LocalScopeVariable v, BasicBlock b) {
+ private int lastRank(StackVariable v, BasicBlock b) {
result = max(int rankix | defUseRank(v, b, rankix, _)) + 1
}
@@ -197,7 +195,7 @@ library class SSAHelper extends int {
* Holds if SSA variable `(v, def)` is defined at rank index `rankix` in
* basic block `b`.
*/
- private predicate ssaDefRank(LocalScopeVariable v, ControlFlowNode def, BasicBlock b, int rankix) {
+ private predicate ssaDefRank(StackVariable v, ControlFlowNode def, BasicBlock b, int rankix) {
exists(int i |
ssa_defn(v, def, b, i) and
defUseRank(v, b, rankix, i)
@@ -210,9 +208,7 @@ library class SSAHelper extends int {
* `v` that comes _at or after_ the reached node. Reaching a node means
* that the definition is visible to any _use_ at that node.
*/
- private predicate ssaDefReachesRank(
- LocalScopeVariable v, ControlFlowNode def, BasicBlock b, int rankix
- ) {
+ private predicate ssaDefReachesRank(StackVariable v, ControlFlowNode def, BasicBlock b, int rankix) {
// A definition should not reach its own node unless a loop allows it.
// When nodes are both definitions and uses for the same variable, the
// use is understood to happen _before_ the definition. Phi nodes are
@@ -227,7 +223,7 @@ library class SSAHelper extends int {
/** Holds if SSA variable `(v, def)` reaches the end of block `b`. */
cached
- predicate ssaDefinitionReachesEndOfBB(LocalScopeVariable v, ControlFlowNode def, BasicBlock b) {
+ predicate ssaDefinitionReachesEndOfBB(StackVariable v, ControlFlowNode def, BasicBlock b) {
live_at_exit_of_bb(v, b) and ssaDefReachesRank(v, def, b, lastRank(v, b))
or
exists(BasicBlock idom |
@@ -243,7 +239,7 @@ library class SSAHelper extends int {
* reaches the end of `b`.
*/
pragma[noinline]
- private predicate noDefinitionsSinceIDominator(LocalScopeVariable v, BasicBlock idom, BasicBlock b) {
+ private predicate noDefinitionsSinceIDominator(StackVariable v, BasicBlock idom, BasicBlock b) {
bbIDominates(idom, b) and // It is sufficient to traverse the dominator graph, cf. discussion above.
live_at_exit_of_bb(v, b) and
not ssa_defn(v, _, b, _)
@@ -253,9 +249,7 @@ library class SSAHelper extends int {
* Holds if SSA variable `(v, def)` reaches `use` within the same basic
* block, where `use` is a `VariableAccess` of `v`.
*/
- private predicate ssaDefinitionReachesUseWithinBB(
- LocalScopeVariable v, ControlFlowNode def, Expr use
- ) {
+ private predicate ssaDefinitionReachesUseWithinBB(StackVariable v, ControlFlowNode def, Expr use) {
exists(BasicBlock b, int rankix, int i |
ssaDefReachesRank(v, def, b, rankix) and
defUseRank(v, b, rankix, i) and
@@ -266,7 +260,7 @@ library class SSAHelper extends int {
/**
* Holds if SSA variable `(v, def)` reaches the control-flow node `use`.
*/
- private predicate ssaDefinitionReaches(LocalScopeVariable v, ControlFlowNode def, Expr use) {
+ private predicate ssaDefinitionReaches(StackVariable v, ControlFlowNode def, Expr use) {
ssaDefinitionReachesUseWithinBB(v, def, use)
or
exists(BasicBlock b |
@@ -281,7 +275,7 @@ library class SSAHelper extends int {
* `(node, v)`.
*/
cached
- string toString(ControlFlowNode node, LocalScopeVariable v) {
+ string toString(ControlFlowNode node, StackVariable v) {
if phi_node(v, node.(BasicBlock))
then result = "SSA phi(" + v.getName() + ")"
else (
@@ -294,7 +288,7 @@ library class SSAHelper extends int {
* access of `v`.
*/
cached
- VariableAccess getAUse(ControlFlowNode def, LocalScopeVariable v) {
+ VariableAccess getAUse(ControlFlowNode def, StackVariable v) {
ssaDefinitionReaches(v, def, result) and
ssa_use(v, result, _, _)
}
diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll b/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll
index b8ffa3344f6..696184620e3 100644
--- a/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll
+++ b/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll
@@ -1,11 +1,24 @@
import cpp
/**
- * DEPRECATED: use `LocalScopeVariableReachability` instead.
- *
* A reachability analysis for control-flow nodes involving stack variables.
+ * This defines sources, sinks, and any other configurable aspect of the
+ * analysis. Multiple analyses can coexist. To create an analysis, extend this
+ * class with a subclass whose characteristic predicate is a unique singleton
+ * string. For example, write
+ *
+ * ```
+ * class MyAnalysisConfiguration extends StackVariableReachability {
+ * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
+ * // Override `isSource` and `isSink`.
+ * // Override `isBarrier`.
+ * }
+ * ```
+ *
+ * Then, to query whether there is flow between some source and sink, call the
+ * `reaches` predicate on an instance of `MyAnalysisConfiguration`.
*/
-abstract deprecated class StackVariableReachability extends string {
+abstract class StackVariableReachability extends string {
bindingset[this]
StackVariableReachability() { length() >= 0 }
@@ -24,13 +37,13 @@ abstract deprecated class StackVariableReachability extends string {
* uses basic blocks internally for better performance:
*
* ```
- * predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
+ * predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
* reachesImpl(source, v, sink)
* and
* isSink(sink, v)
* }
*
- * predicate reachesImpl(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
+ * predicate reachesImpl(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
* sink = source.getASuccessor() and isSource(source, v)
* or
* exists(ControlFlowNode mid | reachesImpl(source, v, mid) |
@@ -44,7 +57,7 @@ abstract deprecated class StackVariableReachability extends string {
* In addition to using a better performing implementation, this analysis
* accounts for loops where the condition is provably true upon entry.
*/
- predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
+ predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
/*
* Implementation detail: the predicates in this class are a generalization of
* those in DefinitionsAndUses.qll, and should be kept in sync.
@@ -71,7 +84,8 @@ abstract deprecated class StackVariableReachability extends string {
}
private predicate bbSuccessorEntryReaches(
- BasicBlock bb, StackVariable v, ControlFlowNode node, boolean skipsFirstLoopAlwaysTrueUponEntry
+ BasicBlock bb, SemanticStackVariable v, ControlFlowNode node,
+ boolean skipsFirstLoopAlwaysTrueUponEntry
) {
exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
@@ -85,11 +99,22 @@ abstract deprecated class StackVariableReachability extends string {
)
}
- private predicate bbEntryReachesLocally(BasicBlock bb, StackVariable v, ControlFlowNode node) {
- exists(int n | node = bb.getNode(n) and isSink(node, v) |
- not exists(int m | m < n | isBarrier(bb.getNode(m), v))
+ private predicate bbEntryReachesLocally(
+ BasicBlock bb, SemanticStackVariable v, ControlFlowNode node
+ ) {
+ exists(int n |
+ node = bb.getNode(n) and
+ isSink(node, v)
+ |
+ not exists(this.firstBarrierIndexIn(bb, v))
+ or
+ n <= this.firstBarrierIndexIn(bb, v)
)
}
+
+ private int firstBarrierIndexIn(BasicBlock bb, SemanticStackVariable v) {
+ result = min(int m | isBarrier(bb.getNode(m), v))
+ }
}
/**
@@ -113,26 +138,32 @@ private predicate bbLoopEntryConditionAlwaysTrueAt(BasicBlock bb, int i, Control
}
/**
- * Basic block `pred` ends with a condition belonging to a loop, and that
- * condition is provably true upon entry. Basic block `succ` is a successor
- * of `pred`, and `skipsLoop` indicates whether `succ` is the false-successor
- * of `pred`.
+ * Basic block `pred` contains all or part of the condition belonging to a loop,
+ * and there is an edge from `pred` to `succ` that concludes the condition.
+ * If the edge corrseponds with the loop condition being found to be `true`, then
+ * `skipsLoop` is `false`. Otherwise the edge corresponds with the loop condition
+ * being found to be `false` and `skipsLoop` is `true`. Non-concluding edges
+ * within a complex loop condition are not matched by this predicate.
*/
private predicate bbLoopConditionAlwaysTrueUponEntrySuccessor(
BasicBlock pred, BasicBlock succ, boolean skipsLoop
) {
- succ = pred.getASuccessor() and
- exists(ControlFlowNode last |
- last = pred.getEnd() and
- loopConditionAlwaysTrueUponEntry(_, last) and
- if succ = pred.getAFalseSuccessor() then skipsLoop = true else skipsLoop = false
+ exists(Expr cond |
+ loopConditionAlwaysTrueUponEntry(_, cond) and
+ cond.getAChild*() = pred.getEnd() and
+ succ = pred.getASuccessor() and
+ not cond.getAChild*() = succ.getStart() and
+ (
+ succ = pred.getAFalseSuccessor() and
+ skipsLoop = true
+ or
+ succ = pred.getATrueSuccessor() and
+ skipsLoop = false
+ )
)
}
/**
- * DEPRECATED: use the corresponding predicate in
- * `LocalScopeVariableReachability` instead.
- *
* Loop invariant for `bbSuccessorEntryReaches`:
*
* - `succ` is a successor of `pred`.
@@ -146,7 +177,7 @@ private predicate bbLoopConditionAlwaysTrueUponEntrySuccessor(
* is provably true upon entry, then `succ` is not allowed to skip
* that loop (`succSkipsFirstLoopAlwaysTrueUponEntry = false`).
*/
-deprecated predicate bbSuccessorEntryReachesLoopInvariant(
+predicate bbSuccessorEntryReachesLoopInvariant(
BasicBlock pred, BasicBlock succ, boolean predSkipsFirstLoopAlwaysTrueUponEntry,
boolean succSkipsFirstLoopAlwaysTrueUponEntry
) {
@@ -162,7 +193,7 @@ deprecated predicate bbSuccessorEntryReachesLoopInvariant(
// The edge from `pred` to `succ` is _not_ from a loop condition provably
// true upon entry, so the values of `predSkipsFirstLoopAlwaysTrueUponEntry`
// and `succSkipsFirstLoopAlwaysTrueUponEntry` must be the same.
- not bbLoopConditionAlwaysTrueUponEntrySuccessor(pred, _, _) and
+ not bbLoopConditionAlwaysTrueUponEntrySuccessor(pred, succ, _) and
succSkipsFirstLoopAlwaysTrueUponEntry = predSkipsFirstLoopAlwaysTrueUponEntry and
// Moreover, if `pred` contains the entry point of a loop where the
// condition is provably true upon entry, then `succ` is not allowed
@@ -176,13 +207,16 @@ deprecated predicate bbSuccessorEntryReachesLoopInvariant(
}
/**
- * DEPRECATED: use `LocalScopeVariableReachabilityWithReassignment` instead.
- *
* Reachability analysis for control-flow nodes involving stack variables.
* Unlike `StackVariableReachability`, this analysis takes variable
* reassignments into account.
+ *
+ * This class is used like `StackVariableReachability`, except that
+ * subclasses should override `isSourceActual` and `isSinkActual` instead of
+ * `isSource` and `isSink`, and that there is a `reachesTo` predicate in
+ * addition to `reaches`.
*/
-abstract deprecated class StackVariableReachabilityWithReassignment extends StackVariableReachability {
+abstract class StackVariableReachabilityWithReassignment extends StackVariableReachability {
bindingset[this]
StackVariableReachabilityWithReassignment() { length() >= 0 }
@@ -199,19 +233,19 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac
* performance:
*
* ```
- * predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
+ * predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
* reachesImpl(source, v, sink)
* and
* isSinkActual(sink, v)
* }
*
- * predicate reachesImpl(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
+ * predicate reachesImpl(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
* isSourceActual(source, v)
* and
* (
* sink = source.getASuccessor()
* or
- * exists(ControlFlowNode mid, StackVariable v0 | reachesImpl(source, v0, mid) |
+ * exists(ControlFlowNode mid, SemanticStackVariable v0 | reachesImpl(source, v0, mid) |
* // ordinary successor
* not isBarrier(mid, v) and
* sink = mid.getASuccessor() and
@@ -228,7 +262,7 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac
* In addition to using a better performing implementation, this analysis
* accounts for loops where the condition is provably true upon entry.
*/
- override predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
+ override predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
reachesTo(source, v, sink, _)
}
@@ -236,7 +270,7 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac
* As `reaches`, but also specifies the last variable it was reassigned to (`v0`).
*/
predicate reachesTo(
- ControlFlowNode source, StackVariable v, ControlFlowNode sink, StackVariable v0
+ ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink, SemanticStackVariable v0
) {
exists(ControlFlowNode def |
actualSourceReaches(source, v, def, v0) and
@@ -246,17 +280,19 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac
}
private predicate actualSourceReaches(
- ControlFlowNode source, StackVariable v, ControlFlowNode def, StackVariable v0
+ ControlFlowNode source, SemanticStackVariable v, ControlFlowNode def, SemanticStackVariable v0
) {
isSourceActual(source, v) and def = source and v0 = v
or
- exists(ControlFlowNode source1, StackVariable v1 | actualSourceReaches(source, v, source1, v1) |
+ exists(ControlFlowNode source1, SemanticStackVariable v1 |
+ actualSourceReaches(source, v, source1, v1)
+ |
reassignment(source1, v1, def, v0)
)
}
private predicate reassignment(
- ControlFlowNode source, StackVariable v, ControlFlowNode def, StackVariable v0
+ ControlFlowNode source, SemanticStackVariable v, ControlFlowNode def, SemanticStackVariable v0
) {
StackVariableReachability.super.reaches(source, v, def) and
exprDefinition(v0, def, v.getAnAccess())
@@ -278,13 +314,12 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac
}
/**
- * DEPRECATED: use `LocalScopeVariableReachabilityExt` instead.
- *
* Same as `StackVariableReachability`, but `isBarrier` works on control-flow
* edges rather than nodes and is therefore parameterized by the original
- * source node as well.
+ * source node as well. Otherwise, this class is used like
+ * `StackVariableReachability`.
*/
-abstract deprecated class StackVariableReachabilityExt extends string {
+abstract class StackVariableReachabilityExt extends string {
bindingset[this]
StackVariableReachabilityExt() { length() >= 0 }
@@ -300,7 +335,7 @@ abstract deprecated class StackVariableReachabilityExt extends string {
);
/** See `StackVariableReachability.reaches`. */
- predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
+ predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
exists(BasicBlock bb, int i |
isSource(source, v) and
bb.getNode(i) = source and
@@ -321,7 +356,7 @@ abstract deprecated class StackVariableReachabilityExt extends string {
}
private predicate bbSuccessorEntryReaches(
- ControlFlowNode source, BasicBlock bb, StackVariable v, ControlFlowNode node,
+ ControlFlowNode source, BasicBlock bb, SemanticStackVariable v, ControlFlowNode node,
boolean skipsFirstLoopAlwaysTrueUponEntry
) {
exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
@@ -338,7 +373,7 @@ abstract deprecated class StackVariableReachabilityExt extends string {
}
private predicate bbEntryReachesLocally(
- ControlFlowNode source, BasicBlock bb, StackVariable v, ControlFlowNode node
+ ControlFlowNode source, BasicBlock bb, SemanticStackVariable v, ControlFlowNode node
) {
isSource(source, v) and
exists(int n | node = bb.getNode(n) and isSink(node, v) |
diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll b/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll
index 43b1a76c837..263fb141312 100644
--- a/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll
+++ b/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll
@@ -924,7 +924,7 @@ library class LoopEntryConditionEvaluator extends ExprEvaluator {
/*
* Use primitive basic blocks in reachability analysis for better performance.
* This is similar to the pattern used in e.g. `DefinitionsAndUses` and
- * `LocalScopeVariableReachability`.
+ * `StackVariableReachability`.
*/
exists(PrimitiveBasicBlock bb1, int pos1 | bb1.getNode(pos1) = valueOrDef |
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/StackAddress.qll b/cpp/ql/src/semmle/code/cpp/dataflow/StackAddress.qll
index d0694a12932..f375bbae199 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/StackAddress.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/StackAddress.qll
@@ -61,7 +61,7 @@ predicate stackPointerFlowsToUse(Expr use, Type useType, Expr source, boolean is
stackPointerFlowsToUse(use.(PointerAddExpr).getAnOperand(), useType, source, isLocal)
or
// Indirect use of a stack address.
- exists(SsaDefinition def, LocalScopeVariable var |
+ exists(SsaDefinition def, StackVariable var |
stackPointerFlowsToDef(def, var, useType, source, isLocal) and
use = def.getAUse(var)
)
@@ -97,8 +97,7 @@ private PointerType getExprPtrType(Expr use) { result = use.getUnspecifiedType()
predicate stackReferenceFlowsToUse(Expr use, Type useType, Expr source, boolean isLocal) {
// Stack variables
- exists(LocalScopeVariable var |
- not var.isStatic() and
+ exists(StackVariable var |
use = source and
source = var.getAnAccess() and
isLocal = true and
@@ -140,7 +139,7 @@ predicate stackReferenceFlowsToUse(Expr use, Type useType, Expr source, boolean
stackPointerFlowsToUse(use.(PointerDereferenceExpr).getOperand(), useType, source, isLocal)
or
// Indirect use of a stack reference, via a reference variable.
- exists(SsaDefinition def, LocalScopeVariable var |
+ exists(SsaDefinition def, StackVariable var |
stackReferenceFlowsToDef(def, var, useType, source, isLocal) and
use = def.getAUse(var)
)
@@ -162,7 +161,7 @@ predicate stackReferenceFlowsToUse(Expr use, Type useType, Expr source, boolean
* addresses through SSA definitions.
*/
predicate stackPointerFlowsToDef(
- SsaDefinition def, LocalScopeVariable var, Type useType, Expr source, boolean isLocal
+ SsaDefinition def, StackVariable var, Type useType, Expr source, boolean isLocal
) {
stackPointerFlowsToUse(def.getDefiningValue(var), useType, source, isLocal)
or
@@ -184,7 +183,7 @@ predicate stackPointerFlowsToDef(
* int&, rather than pointers.
*/
predicate stackReferenceFlowsToDef(
- SsaDefinition def, LocalScopeVariable var, Type useType, Expr source, boolean isLocal
+ SsaDefinition def, StackVariable var, Type useType, Expr source, boolean isLocal
) {
// Check that the type of the variable is a reference type and delegate
// the rest of the work to stackReferenceFlowsToDef_Impl.
@@ -197,7 +196,7 @@ predicate stackReferenceFlowsToDef(
* predicate.
*/
predicate stackReferenceFlowsToDef_Impl(
- SsaDefinition def, LocalScopeVariable var, Type useType, Expr source, boolean isLocal
+ SsaDefinition def, StackVariable var, Type useType, Expr source, boolean isLocal
) {
stackReferenceFlowsToUse(def.getDefiningValue(var), useType, source, isLocal)
or
@@ -213,7 +212,7 @@ predicate stackReferenceFlowsToDef_Impl(
}
/** The type of the variable is a reference type, such as int&. */
-predicate isReferenceVariable(LocalScopeVariable var) {
+predicate isReferenceVariable(StackVariable var) {
var.getUnspecifiedType() instanceof ReferenceType
}
@@ -284,7 +283,7 @@ predicate memberFcnMightRunOnStack(MemberFunction fcn, Type useType) {
predicate constructorMightRunOnStack(Constructor constructor) {
exists(ConstructorCall call | call.getTarget() = constructor |
// Call to a constructor from a stack variable's initializer.
- exists(LocalScopeVariable var | var.getInitializer().getExpr() = call)
+ exists(StackVariable var | var.getInitializer().getExpr() = call)
or
// Call to a constructor from another constructor which might
// also run on the stack.
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll
index 9519a74265f..1f322a02201 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
pragma[noinline]
private predicate simpleArgumentFlowsThrough0(
+ ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
+) {
+ simpleParameterFlow(p, ret, t, config) and
+ kind = ret.getKind()
+}
+
+pragma[noinline]
+private predicate simpleArgumentFlowsThrough1(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
) {
nodeCand1(arg, unbind(config)) and
not outBarrier(arg, config) and
exists(ParameterNode p, ReturnNode ret |
- simpleParameterFlow(p, ret, t, config) and
- kind = ret.getKind() and
+ simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
viableParamArg(call, p, arg)
)
}
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
exists(DataFlowCall call, ReturnKind kind |
nodeCand1(out, unbind(config)) and
not inBarrier(out, config) and
- simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
+ simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
out = getAnOutNode(call, kind)
)
}
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll
index 9519a74265f..1f322a02201 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
pragma[noinline]
private predicate simpleArgumentFlowsThrough0(
+ ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
+) {
+ simpleParameterFlow(p, ret, t, config) and
+ kind = ret.getKind()
+}
+
+pragma[noinline]
+private predicate simpleArgumentFlowsThrough1(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
) {
nodeCand1(arg, unbind(config)) and
not outBarrier(arg, config) and
exists(ParameterNode p, ReturnNode ret |
- simpleParameterFlow(p, ret, t, config) and
- kind = ret.getKind() and
+ simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
viableParamArg(call, p, arg)
)
}
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
exists(DataFlowCall call, ReturnKind kind |
nodeCand1(out, unbind(config)) and
not inBarrier(out, config) and
- simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
+ simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
out = getAnOutNode(call, kind)
)
}
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll
index 9519a74265f..1f322a02201 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
pragma[noinline]
private predicate simpleArgumentFlowsThrough0(
+ ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
+) {
+ simpleParameterFlow(p, ret, t, config) and
+ kind = ret.getKind()
+}
+
+pragma[noinline]
+private predicate simpleArgumentFlowsThrough1(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
) {
nodeCand1(arg, unbind(config)) and
not outBarrier(arg, config) and
exists(ParameterNode p, ReturnNode ret |
- simpleParameterFlow(p, ret, t, config) and
- kind = ret.getKind() and
+ simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
viableParamArg(call, p, arg)
)
}
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
exists(DataFlowCall call, ReturnKind kind |
nodeCand1(out, unbind(config)) and
not inBarrier(out, config) and
- simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
+ simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
out = getAnOutNode(call, kind)
)
}
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll
index 9519a74265f..1f322a02201 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
pragma[noinline]
private predicate simpleArgumentFlowsThrough0(
+ ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
+) {
+ simpleParameterFlow(p, ret, t, config) and
+ kind = ret.getKind()
+}
+
+pragma[noinline]
+private predicate simpleArgumentFlowsThrough1(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
) {
nodeCand1(arg, unbind(config)) and
not outBarrier(arg, config) and
exists(ParameterNode p, ReturnNode ret |
- simpleParameterFlow(p, ret, t, config) and
- kind = ret.getKind() and
+ simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
viableParamArg(call, p, arg)
)
}
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
exists(DataFlowCall call, ReturnKind kind |
nodeCand1(out, unbind(config)) and
not inBarrier(out, config) and
- simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
+ simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
out = getAnOutNode(call, kind)
)
}
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll
index 91f5aeacc9d..87b33a79b8b 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll
@@ -360,7 +360,7 @@ private module ImplCommon {
*/
cached
predicate read(Node node1, Content f, Node node2) {
- readStep(node1, f, node2) and storeStep(_, f, _)
+ readStep(node1, f, node2)
or
exists(DataFlowCall call, ReturnKind kind |
read0(call, kind, node1, f) and
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll
index 9519a74265f..1f322a02201 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
pragma[noinline]
private predicate simpleArgumentFlowsThrough0(
+ ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
+) {
+ simpleParameterFlow(p, ret, t, config) and
+ kind = ret.getKind()
+}
+
+pragma[noinline]
+private predicate simpleArgumentFlowsThrough1(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
) {
nodeCand1(arg, unbind(config)) and
not outBarrier(arg, config) and
exists(ParameterNode p, ReturnNode ret |
- simpleParameterFlow(p, ret, t, config) and
- kind = ret.getKind() and
+ simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
viableParamArg(call, p, arg)
)
}
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
exists(DataFlowCall call, ReturnKind kind |
nodeCand1(out, unbind(config)) and
not inBarrier(out, config) and
- simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
+ simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
out = getAnOutNode(call, kind)
)
}
diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll
index abd56c6283c..5085e74a97f 100644
--- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll
+++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll
@@ -88,7 +88,7 @@ class FlowVar extends TFlowVar {
* `FlowVar` instance for the uninitialized value of that variable.
*/
cached
- abstract predicate definedByInitialValue(LocalScopeVariable v);
+ abstract predicate definedByInitialValue(StackVariable v);
/** Gets a textual representation of this element. */
cached
@@ -268,7 +268,7 @@ module FlowVar_internal {
* Holds if `sbb` is the `SubBasicBlock` where `v` receives its initial value.
* See the documentation for `FlowVar.definedByInitialValue`.
*/
- predicate blockVarDefinedByVariable(SubBasicBlock sbb, LocalScopeVariable v) {
+ predicate blockVarDefinedByVariable(SubBasicBlock sbb, StackVariable v) {
sbb = v.(Parameter).getFunction().getEntryPoint()
or
exists(DeclStmt declStmt |
@@ -279,7 +279,7 @@ module FlowVar_internal {
}
newtype TFlowVar =
- TSsaVar(SsaDefinition def, LocalScopeVariable v) {
+ TSsaVar(SsaDefinition def, StackVariable v) {
fullySupportedSsaVariable(v) and
v = def.getAVariable()
} or
@@ -303,7 +303,7 @@ module FlowVar_internal {
*/
class SsaVar extends TSsaVar, FlowVar {
SsaDefinition def;
- LocalScopeVariable v;
+ StackVariable v;
SsaVar() { this = TSsaVar(def, v) }
@@ -343,7 +343,7 @@ module FlowVar_internal {
override predicate definedPartiallyAt(Expr e) { none() }
- override predicate definedByInitialValue(LocalScopeVariable param) {
+ override predicate definedByInitialValue(StackVariable param) {
def.definedByParameter(param) and
param = v
}
@@ -407,7 +407,7 @@ module FlowVar_internal {
getAReachedBlockVarSBB(this).getANode() = p.getFunction()
}
- override predicate definedByInitialValue(LocalScopeVariable lsv) {
+ override predicate definedByInitialValue(StackVariable lsv) {
blockVarDefinedByVariable(sbb, lsv) and
lsv = v
}
@@ -647,11 +647,8 @@ module FlowVar_internal {
/**
* A local variable that is uninitialized immediately after its declaration.
*/
- class UninitializedLocalVariable extends LocalVariable {
- UninitializedLocalVariable() {
- not this.hasInitializer() and
- not this.isStatic()
- }
+ class UninitializedLocalVariable extends LocalVariable, StackVariable {
+ UninitializedLocalVariable() { not this.hasInitializer() }
}
/** Holds if `va` may be an uninitialized access to `v`. */
diff --git a/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll
index 741d63fbc44..46e672f1d98 100644
--- a/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll
+++ b/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll
@@ -62,11 +62,10 @@ abstract class CrementOperation extends UnaryArithmeticOperation {
override predicate mayBeImpure() { any() }
override predicate mayBeGloballyImpure() {
- not exists(VariableAccess va, LocalScopeVariable v |
+ not exists(VariableAccess va, StackVariable v |
va = this.getOperand() and
v = va.getTarget() and
- not va.getConversion+() instanceof ReferenceDereferenceExpr and
- not v.isStatic()
+ not va.getConversion+() instanceof ReferenceDereferenceExpr
)
}
}
diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll b/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll
index aeabe10f168..1d787f03167 100644
--- a/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll
+++ b/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll
@@ -21,11 +21,10 @@ abstract class Assignment extends Operation {
override predicate mayBeGloballyImpure() {
this.getRValue().mayBeGloballyImpure()
or
- not exists(VariableAccess va, LocalScopeVariable v |
+ not exists(VariableAccess va, StackVariable v |
va = this.getLValue() and
v = va.getTarget() and
- not va.getConversion+() instanceof ReferenceDereferenceExpr and
- not v.isStatic()
+ not va.getConversion+() instanceof ReferenceDereferenceExpr
)
}
}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll
index 9519a74265f..1f322a02201 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
pragma[noinline]
private predicate simpleArgumentFlowsThrough0(
+ ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
+) {
+ simpleParameterFlow(p, ret, t, config) and
+ kind = ret.getKind()
+}
+
+pragma[noinline]
+private predicate simpleArgumentFlowsThrough1(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
) {
nodeCand1(arg, unbind(config)) and
not outBarrier(arg, config) and
exists(ParameterNode p, ReturnNode ret |
- simpleParameterFlow(p, ret, t, config) and
- kind = ret.getKind() and
+ simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
viableParamArg(call, p, arg)
)
}
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
exists(DataFlowCall call, ReturnKind kind |
nodeCand1(out, unbind(config)) and
not inBarrier(out, config) and
- simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
+ simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
out = getAnOutNode(call, kind)
)
}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll
index 9519a74265f..1f322a02201 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
pragma[noinline]
private predicate simpleArgumentFlowsThrough0(
+ ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
+) {
+ simpleParameterFlow(p, ret, t, config) and
+ kind = ret.getKind()
+}
+
+pragma[noinline]
+private predicate simpleArgumentFlowsThrough1(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
) {
nodeCand1(arg, unbind(config)) and
not outBarrier(arg, config) and
exists(ParameterNode p, ReturnNode ret |
- simpleParameterFlow(p, ret, t, config) and
- kind = ret.getKind() and
+ simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
viableParamArg(call, p, arg)
)
}
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
exists(DataFlowCall call, ReturnKind kind |
nodeCand1(out, unbind(config)) and
not inBarrier(out, config) and
- simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
+ simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
out = getAnOutNode(call, kind)
)
}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll
index 9519a74265f..1f322a02201 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
pragma[noinline]
private predicate simpleArgumentFlowsThrough0(
+ ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
+) {
+ simpleParameterFlow(p, ret, t, config) and
+ kind = ret.getKind()
+}
+
+pragma[noinline]
+private predicate simpleArgumentFlowsThrough1(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
) {
nodeCand1(arg, unbind(config)) and
not outBarrier(arg, config) and
exists(ParameterNode p, ReturnNode ret |
- simpleParameterFlow(p, ret, t, config) and
- kind = ret.getKind() and
+ simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
viableParamArg(call, p, arg)
)
}
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
exists(DataFlowCall call, ReturnKind kind |
nodeCand1(out, unbind(config)) and
not inBarrier(out, config) and
- simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
+ simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
out = getAnOutNode(call, kind)
)
}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll
index 9519a74265f..1f322a02201 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll
@@ -510,13 +510,20 @@ private predicate simpleParameterFlow(
pragma[noinline]
private predicate simpleArgumentFlowsThrough0(
+ ParameterNode p, ReturnNode ret, ReturnKind kind, DataFlowType t, Configuration config
+) {
+ simpleParameterFlow(p, ret, t, config) and
+ kind = ret.getKind()
+}
+
+pragma[noinline]
+private predicate simpleArgumentFlowsThrough1(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
) {
nodeCand1(arg, unbind(config)) and
not outBarrier(arg, config) and
exists(ParameterNode p, ReturnNode ret |
- simpleParameterFlow(p, ret, t, config) and
- kind = ret.getKind() and
+ simpleArgumentFlowsThrough0(p, ret, kind, t, config) and
viableParamArg(call, p, arg)
)
}
@@ -534,7 +541,7 @@ private predicate simpleArgumentFlowsThrough(
exists(DataFlowCall call, ReturnKind kind |
nodeCand1(out, unbind(config)) and
not inBarrier(out, config) and
- simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
+ simpleArgumentFlowsThrough1(call, arg, kind, t, config) and
out = getAnOutNode(call, kind)
)
}
diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll
index 91f5aeacc9d..87b33a79b8b 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll
@@ -360,7 +360,7 @@ private module ImplCommon {
*/
cached
predicate read(Node node1, Content f, Node node2) {
- readStep(node1, f, node2) and storeStep(_, f, _)
+ readStep(node1, f, node2)
or
exists(DataFlowCall call, ReturnKind kind |
read0(call, kind, node1, f) and
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll
index b325aeb1bf1..241de4406e8 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll
@@ -359,24 +359,25 @@ class Instruction extends Construction::TInstruction {
*/
int getDisplayIndexInBlock() {
exists(IRBlock block |
- block = getBlock() and
- (
- exists(int index, int phiCount |
- phiCount = count(block.getAPhiInstruction()) and
- this = block.getInstruction(index) and
- result = index + phiCount
+ this = block.getInstruction(result)
+ or
+ this = rank[-result - 1](PhiInstruction phiInstr |
+ phiInstr = block.getAPhiInstruction()
+ |
+ phiInstr order by phiInstr.getUniqueId()
)
- or
- this instanceof PhiInstruction and
- this = rank[result + 1](PhiInstruction phiInstr |
- phiInstr = block.getAPhiInstruction()
- |
- phiInstr order by phiInstr.getUniqueId()
- )
- )
)
}
+ private int getLineRank() {
+ this = rank[result](Instruction instr |
+ instr.getAST().getFile() = getAST().getFile() and
+ instr.getAST().getLocation().getStartLine() = getAST().getLocation().getStartLine()
+ |
+ instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
+ )
+ }
+
/**
* Gets a human-readable string that uniquely identifies this instruction
* within the function. This string is used to refer to this instruction when
@@ -385,8 +386,7 @@ class Instruction extends Construction::TInstruction {
* Example: `r1_1`
*/
string getResultId() {
- result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" +
- getDisplayIndexInBlock().toString()
+ result = getResultPrefix() + getAST().getLocation().getStartLine() + "_" + getLineRank()
}
/**
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll
index b325aeb1bf1..241de4406e8 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll
@@ -359,24 +359,25 @@ class Instruction extends Construction::TInstruction {
*/
int getDisplayIndexInBlock() {
exists(IRBlock block |
- block = getBlock() and
- (
- exists(int index, int phiCount |
- phiCount = count(block.getAPhiInstruction()) and
- this = block.getInstruction(index) and
- result = index + phiCount
+ this = block.getInstruction(result)
+ or
+ this = rank[-result - 1](PhiInstruction phiInstr |
+ phiInstr = block.getAPhiInstruction()
+ |
+ phiInstr order by phiInstr.getUniqueId()
)
- or
- this instanceof PhiInstruction and
- this = rank[result + 1](PhiInstruction phiInstr |
- phiInstr = block.getAPhiInstruction()
- |
- phiInstr order by phiInstr.getUniqueId()
- )
- )
)
}
+ private int getLineRank() {
+ this = rank[result](Instruction instr |
+ instr.getAST().getFile() = getAST().getFile() and
+ instr.getAST().getLocation().getStartLine() = getAST().getLocation().getStartLine()
+ |
+ instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
+ )
+ }
+
/**
* Gets a human-readable string that uniquely identifies this instruction
* within the function. This string is used to refer to this instruction when
@@ -385,8 +386,7 @@ class Instruction extends Construction::TInstruction {
* Example: `r1_1`
*/
string getResultId() {
- result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" +
- getDisplayIndexInBlock().toString()
+ result = getResultPrefix() + getAST().getLocation().getStartLine() + "_" + getLineRank()
}
/**
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll
index b325aeb1bf1..241de4406e8 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll
@@ -359,24 +359,25 @@ class Instruction extends Construction::TInstruction {
*/
int getDisplayIndexInBlock() {
exists(IRBlock block |
- block = getBlock() and
- (
- exists(int index, int phiCount |
- phiCount = count(block.getAPhiInstruction()) and
- this = block.getInstruction(index) and
- result = index + phiCount
+ this = block.getInstruction(result)
+ or
+ this = rank[-result - 1](PhiInstruction phiInstr |
+ phiInstr = block.getAPhiInstruction()
+ |
+ phiInstr order by phiInstr.getUniqueId()
)
- or
- this instanceof PhiInstruction and
- this = rank[result + 1](PhiInstruction phiInstr |
- phiInstr = block.getAPhiInstruction()
- |
- phiInstr order by phiInstr.getUniqueId()
- )
- )
)
}
+ private int getLineRank() {
+ this = rank[result](Instruction instr |
+ instr.getAST().getFile() = getAST().getFile() and
+ instr.getAST().getLocation().getStartLine() = getAST().getLocation().getStartLine()
+ |
+ instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
+ )
+ }
+
/**
* Gets a human-readable string that uniquely identifies this instruction
* within the function. This string is used to refer to this instruction when
@@ -385,8 +386,7 @@ class Instruction extends Construction::TInstruction {
* Example: `r1_1`
*/
string getResultId() {
- result = getResultPrefix() + getBlock().getDisplayIndex().toString() + "_" +
- getDisplayIndexInBlock().toString()
+ result = getResultPrefix() + getAST().getLocation().getStartLine() + "_" + getLineRank()
}
/**
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll
index c6a6bc3fec9..3b44e6f555a 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll
@@ -1,5 +1,6 @@
import AliasAnalysis
private import SimpleSSAImports
+import SimpleSSAPublicImports
private class IntValue = Ints::IntValue;
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll
index 8f160f5a456..33d2bbbadec 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll
@@ -2,4 +2,3 @@ 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
diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll
new file mode 100644
index 00000000000..94e6fbf2a22
--- /dev/null
+++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll
@@ -0,0 +1 @@
+import semmle.code.cpp.ir.internal.Overlap
diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll
index 613958a0d4c..cc41429489f 100644
--- a/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll
+++ b/cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll
@@ -32,7 +32,7 @@ class StringLiteral = Cpp::StringLiteral;
class Variable = Cpp::Variable;
-class AutomaticVariable = Cpp::LocalScopeVariable;
+class AutomaticVariable = Cpp::StackVariable;
class StaticVariable = Cpp::Variable;
@@ -66,10 +66,7 @@ int getTypeSize(Type type) { result = type.getSize() }
int getPointerSize() { exists(Cpp::NullPointerType nullptr | result = nullptr.getSize()) }
-predicate isVariableAutomatic(Variable var) {
- var instanceof Cpp::LocalScopeVariable and
- not var.(Cpp::LocalScopeVariable).isStatic()
-}
+predicate isVariableAutomatic(Cpp::StackVariable var) { any() }
string getStringLiteralText(StringLiteral s) {
result = s.getValueText().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ")
diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll
index 10a91deaa3a..ea12434ac5b 100644
--- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll
+++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll
@@ -24,7 +24,7 @@ predicate nanExcludingComparison(ComparisonOperation guard, boolean polarity) {
* by virtue of the guard in `def`.
*/
private predicate excludesNan(RangeSsaDefinition def, VariableAccess v) {
- exists(VariableAccess inCond, ComparisonOperation guard, boolean branch, LocalScopeVariable lsv |
+ exists(VariableAccess inCond, ComparisonOperation guard, boolean branch, StackVariable lsv |
def.isGuardPhi(inCond, guard, branch) and
inCond.getTarget() = lsv and
v = def.getAUse(lsv) and
diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll
index 61068801978..99e6539658d 100644
--- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll
+++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll
@@ -31,7 +31,7 @@ library class RangeSSA extends SSAHelper {
/**
* Add a phi node on the out-edge of a guard.
*/
- override predicate custom_phi_node(LocalScopeVariable v, BasicBlock b) {
+ override predicate custom_phi_node(StackVariable v, BasicBlock b) {
guard_defn(v.getAnAccess(), _, b, _)
}
}
@@ -67,19 +67,19 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
RangeSsaDefinition() { exists(RangeSSA x | x.ssa_defn(_, this, _, _)) }
/**
- * Gets a variable corresponding to a SSA LocalScopeVariable defined by
+ * Gets a variable corresponding to a SSA StackVariable defined by
* this definition.
*/
- LocalScopeVariable getAVariable() { exists(RangeSSA x | x.ssa_defn(result, this, _, _)) }
+ StackVariable getAVariable() { exists(RangeSSA x | x.ssa_defn(result, this, _, _)) }
/**
* A string representation of the SSA variable represented by the pair
* `(this, v)`.
*/
- string toString(LocalScopeVariable v) { exists(RangeSSA x | result = x.toString(this, v)) }
+ string toString(StackVariable v) { exists(RangeSSA x | result = x.toString(this, v)) }
/** Gets a use of the SSA variable represented by the pair `(this, v)`. */
- VariableAccess getAUse(LocalScopeVariable v) { exists(RangeSSA x | result = x.getAUse(this, v)) }
+ VariableAccess getAUse(StackVariable v) { exists(RangeSSA x | result = x.getAUse(this, v)) }
/** Gets the control flow node for this definition. */
ControlFlowNode getDefinition() { result = this }
@@ -87,9 +87,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
BasicBlock getBasicBlock() { result.contains(getDefinition()) }
/** Whether this definition is a phi node for variable `v`. */
- predicate isPhiNode(LocalScopeVariable v) {
- exists(RangeSSA x | x.phi_node(v, this.(BasicBlock)))
- }
+ predicate isPhiNode(StackVariable v) { exists(RangeSSA x | x.phi_node(v, this.(BasicBlock))) }
/**
* If this definition is a phi node corresponding to a guard,
@@ -104,7 +102,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
/** Whether this definition is from a parameter */
predicate definedByParameter(Parameter p) { this = p.getFunction().getEntryPoint() }
- RangeSsaDefinition getAPhiInput(LocalScopeVariable v) {
+ RangeSsaDefinition getAPhiInput(StackVariable v) {
this.isPhiNode(v) and
exists(BasicBlock pred |
pred = this.(BasicBlock).getAPredecessor() and
@@ -137,7 +135,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
}
/** Gets the expression assigned to this SsaDefinition. */
- Expr getDefiningValue(LocalScopeVariable v) {
+ Expr getDefiningValue(StackVariable v) {
exists(ControlFlowNode def | def = this.getDefinition() |
def = v.getInitializer().getExpr() and def = result
or
@@ -155,7 +153,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
)
}
- predicate reachesEndOfBB(LocalScopeVariable v, BasicBlock b) {
+ predicate reachesEndOfBB(StackVariable v, BasicBlock b) {
exists(RangeSSA x | x.ssaDefinitionReachesEndOfBB(v, this, b))
}
}
diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll
index b7b646d5c8a..72dba0ab609 100644
--- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll
+++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll
@@ -120,7 +120,7 @@ private predicate analyzableExpr(Expr e) {
exists(exprMinVal(e.(Conversion).getExpr())) or
// Also allow variable accesses, provided that they have SSA
// information.
- exists(RangeSsaDefinition def, LocalScopeVariable v | e = def.getAUse(v))
+ exists(RangeSsaDefinition def, StackVariable v | e = def.getAUse(v))
)
}
@@ -136,7 +136,7 @@ private predicate analyzableExpr(Expr e) {
* here.
*/
private predicate defDependsOnDef(
- RangeSsaDefinition def, LocalScopeVariable v, RangeSsaDefinition srcDef, LocalScopeVariable srcVar
+ RangeSsaDefinition def, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar
) {
// Definitions with a defining value.
exists(Expr expr | assignmentDef(def, v, expr) | exprDependsOnDef(expr, srcDef, srcVar))
@@ -171,7 +171,7 @@ private predicate defDependsOnDef(
* Helper predicate for `defDependsOnDef`. This predicate matches
* the structure of `getLowerBoundsImpl` and `getUpperBoundsImpl`.
*/
-private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, LocalScopeVariable srcVar) {
+private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVariable srcVar) {
exists(UnaryMinusExpr negateExpr | e = negateExpr |
exprDependsOnDef(negateExpr.getOperand(), srcDef, srcVar)
)
@@ -226,7 +226,7 @@ private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, LocalScope
* the structure of `getPhiLowerBounds` and `getPhiUpperBounds`.
*/
private predicate phiDependsOnDef(
- RangeSsaDefinition phi, LocalScopeVariable v, RangeSsaDefinition srcDef, LocalScopeVariable srcVar
+ RangeSsaDefinition phi, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar
) {
exists(VariableAccess access, ComparisonOperation guard |
access = v.getAnAccess() and
@@ -241,19 +241,17 @@ private predicate phiDependsOnDef(
/** The transitive closure of `defDependsOnDef`. */
private predicate defDependsOnDefTransitively(
- RangeSsaDefinition def, LocalScopeVariable v, RangeSsaDefinition srcDef, LocalScopeVariable srcVar
+ RangeSsaDefinition def, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar
) {
defDependsOnDef(def, v, srcDef, srcVar)
or
- exists(RangeSsaDefinition midDef, LocalScopeVariable midVar |
- defDependsOnDef(def, v, midDef, midVar)
- |
+ exists(RangeSsaDefinition midDef, StackVariable midVar | defDependsOnDef(def, v, midDef, midVar) |
defDependsOnDefTransitively(midDef, midVar, srcDef, srcVar)
)
}
/** The set of definitions that depend recursively on themselves. */
-private predicate isRecursiveDef(RangeSsaDefinition def, LocalScopeVariable v) {
+private predicate isRecursiveDef(RangeSsaDefinition def, StackVariable v) {
defDependsOnDefTransitively(def, v, def, v)
}
@@ -271,7 +269,7 @@ private predicate isRecursiveDef(RangeSsaDefinition def, LocalScopeVariable v) {
*
* This predicate finds all the definitions in the first set.
*/
-private predicate assignmentDef(RangeSsaDefinition def, LocalScopeVariable v, Expr expr) {
+private predicate assignmentDef(RangeSsaDefinition def, StackVariable v, Expr expr) {
v.getUnspecifiedType() instanceof ArithmeticType and
(
def = v.getInitializer().getExpr() and def = expr
@@ -285,7 +283,7 @@ private predicate assignmentDef(RangeSsaDefinition def, LocalScopeVariable v, Ex
}
/** See comment above sourceDef. */
-private predicate analyzableDef(RangeSsaDefinition def, LocalScopeVariable v) {
+private predicate analyzableDef(RangeSsaDefinition def, StackVariable v) {
assignmentDef(def, v, _) or defDependsOnDef(def, v, _, _)
}
@@ -613,7 +611,7 @@ private float getLowerBoundsImpl(Expr expr) {
)
or
// Use SSA to get the lower bounds for a variable use.
- exists(RangeSsaDefinition def, LocalScopeVariable v | expr = def.getAUse(v) |
+ exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) |
result = getDefLowerBounds(def, v)
)
}
@@ -766,7 +764,7 @@ private float getUpperBoundsImpl(Expr expr) {
)
or
// Use SSA to get the upper bounds for a variable use.
- exists(RangeSsaDefinition def, LocalScopeVariable v | expr = def.getAUse(v) |
+ exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) |
result = getDefUpperBounds(def, v)
)
}
@@ -860,7 +858,7 @@ private float boolConversionUpperBound(Expr expr) {
* In this example, the lower bound of x is 0, but we can
* use the guard to deduce that the lower bound is 2 inside the block.
*/
-private float getPhiLowerBounds(LocalScopeVariable v, RangeSsaDefinition phi) {
+private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) {
exists(
VariableAccess access, ComparisonOperation guard, boolean branch, float defLB, float guardLB
|
@@ -877,7 +875,7 @@ private float getPhiLowerBounds(LocalScopeVariable v, RangeSsaDefinition phi) {
}
/** See comment for `getPhiLowerBounds`, above. */
-private float getPhiUpperBounds(LocalScopeVariable v, RangeSsaDefinition phi) {
+private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) {
exists(
VariableAccess access, ComparisonOperation guard, boolean branch, float defUB, float guardUB
|
@@ -894,7 +892,7 @@ private float getPhiUpperBounds(LocalScopeVariable v, RangeSsaDefinition phi) {
}
/** Only to be called by `getDefLowerBounds`. */
-private float getDefLowerBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v) {
+private float getDefLowerBoundsImpl(RangeSsaDefinition def, StackVariable v) {
// Definitions with a defining value.
exists(Expr expr | assignmentDef(def, v, expr) | result = getFullyConvertedLowerBounds(expr))
or
@@ -936,7 +934,7 @@ private float getDefLowerBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v
}
/** Only to be called by `getDefUpperBounds`. */
-private float getDefUpperBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v) {
+private float getDefUpperBoundsImpl(RangeSsaDefinition def, StackVariable v) {
// Definitions with a defining value.
exists(Expr expr | assignmentDef(def, v, expr) | result = getFullyConvertedUpperBounds(expr))
or
@@ -982,7 +980,7 @@ private float getDefUpperBoundsImpl(RangeSsaDefinition def, LocalScopeVariable v
* done by `getDefLowerBoundsImpl`, but this is where widening is applied
* to prevent the analysis from exploding due to a recursive definition.
*/
-private float getDefLowerBounds(RangeSsaDefinition def, LocalScopeVariable v) {
+private float getDefLowerBounds(RangeSsaDefinition def, StackVariable v) {
exists(float newLB, float truncatedLB |
newLB = getDefLowerBoundsImpl(def, v) and
if varMinVal(v) <= newLB and newLB <= varMaxVal(v)
@@ -1011,7 +1009,7 @@ private float getDefLowerBounds(RangeSsaDefinition def, LocalScopeVariable v) {
}
/** See comment for `getDefLowerBounds`, above. */
-private float getDefUpperBounds(RangeSsaDefinition def, LocalScopeVariable v) {
+private float getDefUpperBounds(RangeSsaDefinition def, StackVariable v) {
exists(float newUB, float truncatedUB |
newUB = getDefUpperBoundsImpl(def, v) and
if varMinVal(v) <= newUB and newUB <= varMaxVal(v)
@@ -1044,9 +1042,7 @@ private float getDefUpperBounds(RangeSsaDefinition def, LocalScopeVariable v) {
* unanalyzable definitions (such as function parameters) and make their
* bounds unknown.
*/
-private predicate unanalyzableDefBounds(
- RangeSsaDefinition def, LocalScopeVariable v, float lb, float ub
-) {
+private predicate unanalyzableDefBounds(RangeSsaDefinition def, StackVariable v, float lb, float ub) {
v = def.getAVariable() and
not analyzableDef(def, v) and
lb = varMinVal(v) and
@@ -1268,13 +1264,13 @@ private module SimpleRangeAnalysisCached {
/** Holds if the definition might overflow negatively. */
cached
- predicate defMightOverflowNegatively(RangeSsaDefinition def, LocalScopeVariable v) {
+ predicate defMightOverflowNegatively(RangeSsaDefinition def, StackVariable v) {
getDefLowerBoundsImpl(def, v) < varMinVal(v)
}
/** Holds if the definition might overflow positively. */
cached
- predicate defMightOverflowPositively(RangeSsaDefinition def, LocalScopeVariable v) {
+ predicate defMightOverflowPositively(RangeSsaDefinition def, StackVariable v) {
getDefUpperBoundsImpl(def, v) > varMaxVal(v)
}
@@ -1283,7 +1279,7 @@ private module SimpleRangeAnalysisCached {
* negatively).
*/
cached
- predicate defMightOverflow(RangeSsaDefinition def, LocalScopeVariable v) {
+ predicate defMightOverflow(RangeSsaDefinition def, StackVariable v) {
defMightOverflowNegatively(def, v) or
defMightOverflowPositively(def, v)
}
diff --git a/cpp/ql/src/semmle/code/cpp/valuenumbering/GlobalValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/valuenumbering/GlobalValueNumbering.qll
index 5c8196c15e0..f9231e24725 100644
--- a/cpp/ql/src/semmle/code/cpp/valuenumbering/GlobalValueNumbering.qll
+++ b/cpp/ql/src/semmle/code/cpp/valuenumbering/GlobalValueNumbering.qll
@@ -170,8 +170,8 @@ private newtype GVNBase =
GVN_FloatConst(float val, Type t) { mk_FloatConst(val, t, _) } or
// If the local variable does not have a defining value, then
// we use the SsaDefinition as its global value number.
- GVN_UndefinedLocalScopeVariable(LocalScopeVariable x, SsaDefinition def) {
- mk_UndefinedLocalScopeVariable(x, def, _)
+ GVN_UndefinedStackVariable(StackVariable x, SsaDefinition def) {
+ mk_UndefinedStackVariable(x, def, _)
} or
// Variables with no SSA information. As a crude (but safe)
// approximation, we use `mostRecentSideEffect` to compute a definition
@@ -235,8 +235,8 @@ class GVN extends GVNBase {
if this instanceof GVN_FloatConst
then result = "FloatConst"
else
- if this instanceof GVN_UndefinedLocalScopeVariable
- then result = "UndefinedLocalScopeVariable"
+ if this instanceof GVN_UndefinedStackVariable
+ then result = "UndefinedStackVariable"
else
if this instanceof GVN_OtherVariable
then result = "OtherVariable"
@@ -307,7 +307,7 @@ private predicate mk_FloatConst(float val, Type t, Expr e) {
t = e.getUnspecifiedType()
}
-private predicate analyzableLocalScopeVariable(VariableAccess access) {
+private predicate analyzableStackVariable(VariableAccess access) {
strictcount(SsaDefinition def | def.getAUse(_) = access | def) = 1 and
strictcount(SsaDefinition def, Variable v | def.getAUse(v) = access | v) = 1 and
count(SsaDefinition def, Variable v |
@@ -322,10 +322,10 @@ private predicate analyzableLocalScopeVariable(VariableAccess access) {
// defining value. If there is a defining value, then there is no
// need to generate a fresh `GVN` for the access because `globalValueNumber`
// will follow the chain and use the GVN of the defining value.
-private predicate mk_UndefinedLocalScopeVariable(
- LocalScopeVariable x, SsaDefinition def, VariableAccess access
+private predicate mk_UndefinedStackVariable(
+ StackVariable x, SsaDefinition def, VariableAccess access
) {
- analyzableLocalScopeVariable(access) and
+ analyzableStackVariable(access) and
access = def.getAUse(x) and
not exists(def.getDefiningValue(x))
}
@@ -515,16 +515,16 @@ GVN globalValueNumber(Expr e) {
)
or
// Local variable with a defining value.
- exists(LocalScopeVariable x, SsaDefinition def |
- analyzableLocalScopeVariable(e) and
+ exists(StackVariable x, SsaDefinition def |
+ analyzableStackVariable(e) and
e = def.getAUse(x) and
result = globalValueNumber(def.getDefiningValue(x).getFullyConverted())
)
or
// Local variable without a defining value.
- exists(LocalScopeVariable x, SsaDefinition def |
- mk_UndefinedLocalScopeVariable(x, def, e) and
- result = GVN_UndefinedLocalScopeVariable(x, def)
+ exists(StackVariable x, SsaDefinition def |
+ mk_UndefinedStackVariable(x, def, e) and
+ result = GVN_UndefinedStackVariable(x, def)
)
or
// Variable with no SSA information.
@@ -594,7 +594,7 @@ private predicate analyzableConst(Expr e) {
*/
private predicate analyzableExpr(Expr e) {
analyzableConst(e) or
- analyzableLocalScopeVariable(e) or
+ analyzableStackVariable(e) or
analyzableDotFieldAccess(e) or
analyzablePointerFieldAccess(e) or
analyzableImplicitThisFieldAccess(e) or
diff --git a/cpp/ql/src/semmle/uml/MagicDraw.qll b/cpp/ql/src/semmle/uml/MagicDraw.qll
index 6192af3e021..3cd4701a05d 100644
--- a/cpp/ql/src/semmle/uml/MagicDraw.qll
+++ b/cpp/ql/src/semmle/uml/MagicDraw.qll
@@ -112,7 +112,7 @@ class UMLType extends UMLElement {
else result = this.getUMLName()
}
- string toString() { result = this.getUMLName() }
+ override string toString() { result = this.getUMLName() }
}
/**
@@ -163,7 +163,7 @@ class UMLProperty extends UMLElement {
result.getDeclaringType() = this.getUMLType().getCType()
}
- string toString() {
+ override string toString() {
if this.isEnumConstant()
then result = "- <> " + this.getUMLName()
else result = "- " + this.getUMLName()
@@ -196,7 +196,7 @@ class UMLOperation extends UMLElement {
result.getDeclaringType() = this.getUMLType().getCType()
}
- string toString() { result = "+ " + this.getUMLName() }
+ override string toString() { result = "+ " + this.getUMLName() }
}
/**
@@ -221,7 +221,7 @@ class UMLAssociation extends UMLProperty {
/**
* Gets the C field corresponding to this property, if any.
*/
- Field getCField() {
+ override Field getCField() {
result.hasName(this.getLabel()) and
result.getDeclaringType() = this.getSource().getCType()
}
@@ -271,7 +271,7 @@ class UMLInheritance extends UMLElement {
)
}
- string toString() {
+ override string toString() {
result = this.getUMLClient().getUMLName() + " implements " + this.getUMLSupplier().getUMLName()
}
}
@@ -303,5 +303,5 @@ class UMLPackage extends UMLElement {
else result = this.getUMLName()
}
- string toString() { result = this.getUMLQualifiedName() }
+ override string toString() { result = this.getUMLQualifiedName() }
}
diff --git a/cpp/ql/test/library-tests/controlflow/controlflow/SsaCompleteness.ql b/cpp/ql/test/library-tests/controlflow/controlflow/SsaCompleteness.ql
index 7af147f73d6..5d11509470c 100644
--- a/cpp/ql/test/library-tests/controlflow/controlflow/SsaCompleteness.ql
+++ b/cpp/ql/test/library-tests/controlflow/controlflow/SsaCompleteness.ql
@@ -9,12 +9,12 @@ import cpp
import semmle.code.cpp.controlflow.SSA
/*
- * Count of number of uses of a LocalScopeVariable where no corresponding SSA definition exists,
+ * Count of number of uses of a StackVariable where no corresponding SSA definition exists,
* but at least one SSA definition for that variable can reach that use.
* Should always be zero *regardless* of the input
*/
-select count(LocalScopeVariable v, Expr use |
+select count(StackVariable v, Expr use |
exists(SsaDefinition def, BasicBlock db, BasicBlock ub |
def.getAUse(v) = use and db.contains(def.getDefinition()) and ub.contains(use)
|
diff --git a/cpp/ql/test/library-tests/controlflow/controlflow/SsaDefUsePairs.ql b/cpp/ql/test/library-tests/controlflow/controlflow/SsaDefUsePairs.ql
index 2328645e098..9bcb32918aa 100644
--- a/cpp/ql/test/library-tests/controlflow/controlflow/SsaDefUsePairs.ql
+++ b/cpp/ql/test/library-tests/controlflow/controlflow/SsaDefUsePairs.ql
@@ -7,6 +7,6 @@
import cpp
import semmle.code.cpp.controlflow.SSA
-from SsaDefinition def, LocalScopeVariable var, Expr use
+from SsaDefinition def, StackVariable var, Expr use
where def.getAUse(var) = use
select def, def.toString(var), use
diff --git a/cpp/ql/test/library-tests/controlflow/controlflow/SsaDominance.ql b/cpp/ql/test/library-tests/controlflow/controlflow/SsaDominance.ql
index 2bbf7c7707d..087b8a809fb 100644
--- a/cpp/ql/test/library-tests/controlflow/controlflow/SsaDominance.ql
+++ b/cpp/ql/test/library-tests/controlflow/controlflow/SsaDominance.ql
@@ -12,7 +12,7 @@ import semmle.code.cpp.controlflow.SSA
* Should always be zero *regardless* of the input
*/
-select count(SsaDefinition d, LocalScopeVariable v, Expr u |
+select count(SsaDefinition d, StackVariable v, Expr u |
d.getAUse(v) = u and
not exists(BasicBlock bd, BasicBlock bu |
bd.contains(mkElement(d).(ControlFlowNode)) and bu.contains(u)
diff --git a/cpp/ql/test/library-tests/controlflow/controlflow/SsaLt.ql b/cpp/ql/test/library-tests/controlflow/controlflow/SsaLt.ql
index ef422265b61..37aaaba5013 100644
--- a/cpp/ql/test/library-tests/controlflow/controlflow/SsaLt.ql
+++ b/cpp/ql/test/library-tests/controlflow/controlflow/SsaLt.ql
@@ -8,7 +8,7 @@ import cpp
import semmle.code.cpp.controlflow.SSA
import semmle.code.cpp.controlflow.Guards
-from GuardedSsa def, LocalScopeVariable var, Expr other, int k, int start, int end, string op
+from GuardedSsa def, StackVariable var, Expr other, int k, int start, int end, string op
where
exists(BasicBlock block |
def.isLt(var, other, k, block, true) and op = "<"
diff --git a/cpp/ql/test/library-tests/controlflow/controlflow/SsaPhiInputs.ql b/cpp/ql/test/library-tests/controlflow/controlflow/SsaPhiInputs.ql
index 353b6cd279c..c0ab984f671 100644
--- a/cpp/ql/test/library-tests/controlflow/controlflow/SsaPhiInputs.ql
+++ b/cpp/ql/test/library-tests/controlflow/controlflow/SsaPhiInputs.ql
@@ -8,8 +8,7 @@ import cpp
import semmle.code.cpp.controlflow.SSA
from
- File file, SsaDefinition phi, LocalScopeVariable var, SsaDefinition input, int philine,
- int inputline
+ File file, SsaDefinition phi, StackVariable var, SsaDefinition input, int philine, int inputline
where
phi.getAPhiInput(var) = input and
file = phi.getLocation().getFile() and
diff --git a/cpp/ql/test/library-tests/controlflow/controlflow/SsaUniqueness.ql b/cpp/ql/test/library-tests/controlflow/controlflow/SsaUniqueness.ql
index bff4301287f..b42b2edf61f 100644
--- a/cpp/ql/test/library-tests/controlflow/controlflow/SsaUniqueness.ql
+++ b/cpp/ql/test/library-tests/controlflow/controlflow/SsaUniqueness.ql
@@ -12,7 +12,7 @@ import semmle.code.cpp.controlflow.SSA
* Should always be zero *regardless* of the input
*/
-select count(SsaDefinition d1, SsaDefinition d2, Expr u, LocalScopeVariable v |
+select count(SsaDefinition d1, SsaDefinition d2, Expr u, StackVariable v |
d1.getAUse(v) = u and
d2.getAUse(v) = u and
not d1 = d2
diff --git a/cpp/ql/test/library-tests/controlflow_stresstest/SsaDefUsePairs.ql b/cpp/ql/test/library-tests/controlflow_stresstest/SsaDefUsePairs.ql
index 2328645e098..9bcb32918aa 100644
--- a/cpp/ql/test/library-tests/controlflow_stresstest/SsaDefUsePairs.ql
+++ b/cpp/ql/test/library-tests/controlflow_stresstest/SsaDefUsePairs.ql
@@ -7,6 +7,6 @@
import cpp
import semmle.code.cpp.controlflow.SSA
-from SsaDefinition def, LocalScopeVariable var, Expr use
+from SsaDefinition def, StackVariable var, Expr use
where def.getAUse(var) = use
select def, def.toString(var), use
diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.ql b/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.ql
index 8be3004152e..71de17cbcf1 100644
--- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.ql
+++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.ql
@@ -1,5 +1,5 @@
import semmle.code.cpp.dataflow.internal.FlowVar
-from LocalScopeVariable var, VariableAccess va
+from Variable var, VariableAccess va
where FlowVar_internal::mayBeUsedUninitialized(var, va)
select var, va
diff --git a/cpp/ql/test/library-tests/dataflow/variable/noInit.ql b/cpp/ql/test/library-tests/dataflow/variable/noInit.ql
index 8be3004152e..71de17cbcf1 100644
--- a/cpp/ql/test/library-tests/dataflow/variable/noInit.ql
+++ b/cpp/ql/test/library-tests/dataflow/variable/noInit.ql
@@ -1,5 +1,5 @@
import semmle.code.cpp.dataflow.internal.FlowVar
-from LocalScopeVariable var, VariableAccess va
+from Variable var, VariableAccess va
where FlowVar_internal::mayBeUsedUninitialized(var, va)
select var, va
diff --git a/cpp/ql/test/library-tests/defuse/definition.ql b/cpp/ql/test/library-tests/defuse/definition.ql
index adcf9e68ffa..3bb62428895 100644
--- a/cpp/ql/test/library-tests/defuse/definition.ql
+++ b/cpp/ql/test/library-tests/defuse/definition.ql
@@ -1,5 +1,5 @@
import cpp
-from LocalScopeVariable v, ControlFlowNode d
+from StackVariable v, ControlFlowNode d
where definition(v, d)
select v, d
diff --git a/cpp/ql/test/library-tests/defuse/definitionUsePairEquivalence.ql b/cpp/ql/test/library-tests/defuse/definitionUsePairEquivalence.ql
index a84e397a97e..2d4474b3302 100644
--- a/cpp/ql/test/library-tests/defuse/definitionUsePairEquivalence.ql
+++ b/cpp/ql/test/library-tests/defuse/definitionUsePairEquivalence.ql
@@ -1,24 +1,22 @@
import cpp
-import semmle.code.cpp.controlflow.LocalScopeVariableReachability
+import semmle.code.cpp.controlflow.StackVariableReachability
-// Test that def/use algorithm is an instance of LocalScopeVariableReachability
-class MyDefOrUse extends LocalScopeVariableReachability {
+// Test that def/use algorithm is an instance of StackVariableReachability
+class MyDefOrUse extends StackVariableReachability {
MyDefOrUse() { this = "MyDefUse" }
- override predicate isSource(ControlFlowNode node, LocalScopeVariable v) { definition(v, node) }
+ override predicate isSource(ControlFlowNode node, StackVariable v) { definition(v, node) }
- override predicate isSink(ControlFlowNode node, LocalScopeVariable v) { useOfVar(v, node) }
+ override predicate isSink(ControlFlowNode node, StackVariable v) { useOfVar(v, node) }
- override predicate isBarrier(ControlFlowNode node, LocalScopeVariable v) {
- definitionBarrier(v, node)
- }
+ override predicate isBarrier(ControlFlowNode node, StackVariable v) { definitionBarrier(v, node) }
}
predicate equivalence() {
- forall(LocalScopeVariable v, Expr first, Expr second | definitionUsePair(v, first, second) |
+ forall(StackVariable v, Expr first, Expr second | definitionUsePair(v, first, second) |
exists(MyDefOrUse x | x.reaches(first, v, second))
) and
- forall(LocalScopeVariable v, Expr first, Expr second |
+ forall(StackVariable v, Expr first, Expr second |
exists(MyDefOrUse x | x.reaches(first, v, second))
|
definitionUsePair(v, first, second)
diff --git a/cpp/ql/test/library-tests/defuse/exprDefinition.ql b/cpp/ql/test/library-tests/defuse/exprDefinition.ql
index 4bf86e1ae17..531cb0f7436 100644
--- a/cpp/ql/test/library-tests/defuse/exprDefinition.ql
+++ b/cpp/ql/test/library-tests/defuse/exprDefinition.ql
@@ -1,5 +1,5 @@
import cpp
-from LocalScopeVariable v, ControlFlowNode def, Expr e
+from StackVariable v, ControlFlowNode def, Expr e
where exprDefinition(v, def, e)
select v, def, e
diff --git a/cpp/ql/test/library-tests/defuse/useOfVar.ql b/cpp/ql/test/library-tests/defuse/useOfVar.ql
index c68a1d6d19a..17ea92df3cd 100644
--- a/cpp/ql/test/library-tests/defuse/useOfVar.ql
+++ b/cpp/ql/test/library-tests/defuse/useOfVar.ql
@@ -1,5 +1,5 @@
import cpp
-from LocalScopeVariable v, VariableAccess use
+from StackVariable v, VariableAccess use
where useOfVar(v, use)
select v, use
diff --git a/cpp/ql/test/library-tests/defuse/useOfVarActual.ql b/cpp/ql/test/library-tests/defuse/useOfVarActual.ql
index d3ce210f780..45794ca661d 100644
--- a/cpp/ql/test/library-tests/defuse/useOfVarActual.ql
+++ b/cpp/ql/test/library-tests/defuse/useOfVarActual.ql
@@ -1,9 +1,9 @@
import cpp
-from LocalScopeVariable v, VariableAccess use
+from StackVariable v, VariableAccess use
where
useOfVarActual(v, use) and
// Also check that `useOfVarActual` is a subset of `useOfVar`; if not
// the query will not return any results
- forall(LocalScopeVariable v0, VariableAccess use0 | useOfVarActual(v0, use0) | useOfVar(v0, use0))
+ forall(StackVariable v0, VariableAccess use0 | useOfVarActual(v0, use0) | useOfVar(v0, use0))
select v, use
diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
index 5a70e632d49..28021c12e2d 100644
--- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
+++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
@@ -1,1818 +1,1818 @@
bad_asts.cpp:
# 9| int Bad::S::MemberFunction(int)
# 9| Block 0
-# 9| v0_0(void) = EnterFunction :
-# 9| mu0_1(unknown) = AliasedDefinition :
-# 9| mu0_2(unknown) = UnmodeledDefinition :
-# 9| r0_3(glval) = InitializeThis :
-# 9| r0_4(glval) = VariableAddress[y] :
-# 9| mu0_5(int) = InitializeParameter[y] : &:r0_4
-# 10| r0_6(glval) = VariableAddress[#return] :
-# 10| r0_7(int) = Constant[6] :
-#-----| r0_8(S *) = CopyValue : r0_3
-# 10| r0_9(glval) = FieldAddress[x] : r0_8
-# 10| r0_10(int) = Load : &:r0_9, ~mu0_2
-# 10| r0_11(int) = Add : r0_7, r0_10
-# 10| r0_12(glval) = VariableAddress[y] :
-# 10| r0_13(int) = Load : &:r0_12, ~mu0_2
-# 10| r0_14(int) = Add : r0_11, r0_13
-# 10| mu0_15(int) = Store : &:r0_6, r0_14
-# 9| r0_16(glval) = VariableAddress[#return] :
-# 9| v0_17(void) = ReturnValue : &:r0_16, ~mu0_2
-# 9| v0_18(void) = UnmodeledUse : mu*
-# 9| v0_19(void) = AliasedUse : ~mu0_2
-# 9| v0_20(void) = ExitFunction :
+# 9| v9_1(void) = EnterFunction :
+# 9| mu9_2(unknown) = AliasedDefinition :
+# 9| mu9_3(unknown) = UnmodeledDefinition :
+# 9| r9_4(glval) = InitializeThis :
+# 9| r9_5(glval) = VariableAddress[y] :
+# 9| mu9_6(int) = InitializeParameter[y] : &:r9_5
+# 10| r10_1(glval) = VariableAddress[#return] :
+# 10| r10_2(int) = Constant[6] :
+#-----| r0_27(S *) = CopyValue : r9_4
+# 10| r10_3(glval) = FieldAddress[x] : r0_27
+# 10| r10_4(int) = Load : &:r10_3, ~mu9_3
+# 10| r10_5(int) = Add : r10_2, r10_4
+# 10| r10_6(glval) = VariableAddress[y] :
+# 10| r10_7(int) = Load : &:r10_6, ~mu9_3
+# 10| r10_8(int) = Add : r10_5, r10_7
+# 10| mu10_9(int) = Store : &:r10_1, r10_8
+# 9| r9_7(glval) = VariableAddress[#return] :
+# 9| v9_8(void) = ReturnValue : &:r9_7, ~mu9_3
+# 9| v9_9(void) = UnmodeledUse : mu*
+# 9| v9_10(void) = AliasedUse : ~mu9_3
+# 9| v9_11(void) = ExitFunction :
# 14| void Bad::CallBadMemberFunction()
# 14| Block 0
-# 14| v0_0(void) = EnterFunction :
-# 14| mu0_1(unknown) = AliasedDefinition :
-# 14| mu0_2(unknown) = UnmodeledDefinition :
-# 15| r0_3(glval) = VariableAddress[s] :
-# 15| mu0_4(S) = Uninitialized[s] : &:r0_3
-# 15| r0_5(glval) = FieldAddress[x] : r0_3
-# 15| r0_6(int) = Constant[0] :
-# 15| mu0_7(int) = Store : &:r0_5, r0_6
-# 16| r0_8(glval) = VariableAddress[s] :
-# 16| r0_9(glval) = FunctionAddress[MemberFunction] :
-# 16| r0_10(int) = Constant[1] :
-# 16| r0_11(int) = Call : func:r0_9, this:r0_8, 0:r0_10
-# 16| mu0_12(unknown) = ^CallSideEffect : ~mu0_2
-# 16| v0_13(void) = ^BufferReadSideEffect[-1] : &:r0_8, ~mu0_2
-# 16| mu0_14(S) = ^IndirectMayWriteSideEffect[-1] : &:r0_8
-# 17| v0_15(void) = NoOp :
-# 14| v0_16(void) = ReturnVoid :
-# 14| v0_17(void) = UnmodeledUse : mu*
-# 14| v0_18(void) = AliasedUse : ~mu0_2
-# 14| v0_19(void) = ExitFunction :
+# 14| v14_1(void) = EnterFunction :
+# 14| mu14_2(unknown) = AliasedDefinition :
+# 14| mu14_3(unknown) = UnmodeledDefinition :
+# 15| r15_1(glval) = VariableAddress[s] :
+# 15| mu15_2(S) = Uninitialized[s] : &:r15_1
+# 15| r15_3(glval) = FieldAddress[x] : r15_1
+# 15| r15_4(int) = Constant[0] :
+# 15| mu15_5(int) = Store : &:r15_3, r15_4
+# 16| r16_1(glval) = VariableAddress[s] :
+# 16| r16_2(glval) = FunctionAddress[MemberFunction] :
+# 16| r16_3(int) = Constant[1] :
+# 16| r16_4(int) = Call : func:r16_2, this:r16_1, 0:r16_3
+# 16| mu16_5(unknown) = ^CallSideEffect : ~mu14_3
+# 16| v16_6(void) = ^BufferReadSideEffect[-1] : &:r16_1, ~mu14_3
+# 16| mu16_7(S) = ^IndirectMayWriteSideEffect[-1] : &:r16_1
+# 17| v17_1(void) = NoOp :
+# 14| v14_4(void) = ReturnVoid :
+# 14| v14_5(void) = UnmodeledUse : mu*
+# 14| v14_6(void) = AliasedUse : ~mu14_3
+# 14| v14_7(void) = ExitFunction :
# 22| void Bad::Point::Point()
# 22| Block 0
-# 22| v0_0(void) = EnterFunction :
-# 22| mu0_1(unknown) = AliasedDefinition :
-# 22| mu0_2(unknown) = UnmodeledDefinition :
-# 22| r0_3(glval) = InitializeThis :
-# 23| v0_4(void) = NoOp :
-# 22| v0_5(void) = ReturnVoid :
-# 22| v0_6(void) = UnmodeledUse : mu*
-# 22| v0_7(void) = AliasedUse : ~mu0_2
-# 22| v0_8(void) = ExitFunction :
+# 22| v22_1(void) = EnterFunction :
+# 22| mu22_2(unknown) = AliasedDefinition :
+# 22| mu22_3(unknown) = UnmodeledDefinition :
+# 22| r22_4(glval) = InitializeThis :
+# 23| v23_1(void) = NoOp :
+# 22| v22_5(void) = ReturnVoid :
+# 22| v22_6(void) = UnmodeledUse : mu*
+# 22| v22_7(void) = AliasedUse : ~mu22_3
+# 22| v22_8(void) = ExitFunction :
# 26| void Bad::CallCopyConstructor(Bad::Point const&)
# 26| Block 0
-# 26| v0_0(void) = EnterFunction :
-# 26| mu0_1(unknown) = AliasedDefinition :
-# 26| mu0_2(unknown) = UnmodeledDefinition :
-# 26| r0_3(glval) = VariableAddress[a] :
-# 26| mu0_4(Point &) = InitializeParameter[a] : &:r0_3
-# 27| r0_5(glval) = VariableAddress[b] :
-# 27| r0_6(glval) = VariableAddress[a] :
-# 27| r0_7(Point &) = Load : &:r0_6, ~mu0_2
-# 27| r0_8(glval) = CopyValue : r0_7
-# 27| r0_9(glval) = Convert : r0_8
-# 27| r0_10(Point) = Load : &:r0_9, ~mu0_2
-# 27| mu0_11(Point) = Store : &:r0_5, r0_10
-# 28| v0_12(void) = NoOp :
-# 26| v0_13(void) = ReturnVoid :
-# 26| v0_14(void) = UnmodeledUse : mu*
-# 26| v0_15(void) = AliasedUse : ~mu0_2
-# 26| v0_16(void) = ExitFunction :
+# 26| v26_1(void) = EnterFunction :
+# 26| mu26_2(unknown) = AliasedDefinition :
+# 26| mu26_3(unknown) = UnmodeledDefinition :
+# 26| r26_4(glval) = VariableAddress[a] :
+# 26| mu26_5(Point &) = InitializeParameter[a] : &:r26_4
+# 27| r27_1(glval) = VariableAddress[b] :
+# 27| r27_2(glval) = VariableAddress[a] :
+# 27| r27_3(Point &) = Load : &:r27_2, ~mu26_3
+# 27| r27_4(glval) = CopyValue : r27_3
+# 27| r27_5(glval) = Convert : r27_4
+# 27| r27_6(Point) = Load : &:r27_5, ~mu26_3
+# 27| mu27_7(Point) = Store : &:r27_1, r27_6
+# 28| v28_1(void) = NoOp :
+# 26| v26_6(void) = ReturnVoid :
+# 26| v26_7(void) = UnmodeledUse : mu*
+# 26| v26_8(void) = AliasedUse : ~mu26_3
+# 26| v26_9(void) = ExitFunction :
# 30| void Bad::errorExpr()
# 30| Block 0
-# 30| v0_0(void) = EnterFunction :
-# 30| mu0_1(unknown) = AliasedDefinition :
-# 30| mu0_2(unknown) = UnmodeledDefinition :
-# 31| r0_3(glval) = VariableAddress[intref] :
-# 31| r0_4(error) = Error :
-# 31| mu0_5(int &) = Store : &:r0_3, r0_4
-# 32| r0_6(glval) = VariableAddress[x] :
-# 32| r0_7(error) = Error :
-# 32| mu0_8(int) = Store : &:r0_6, r0_7
-#-----| r0_9(glval) = Error :
-#-----| r0_10(error) = Load : &:r0_9, ~mu0_2
-# 33| r0_11(glval) = VariableAddress[x] :
-# 33| mu0_12(int) = Store : &:r0_11, r0_10
-# 34| v0_13(void) = NoOp :
-# 30| v0_14(void) = ReturnVoid :
-# 30| v0_15(void) = UnmodeledUse : mu*
-# 30| v0_16(void) = AliasedUse : ~mu0_2
-# 30| v0_17(void) = ExitFunction :
+# 30| v30_1(void) = EnterFunction :
+# 30| mu30_2(unknown) = AliasedDefinition :
+# 30| mu30_3(unknown) = UnmodeledDefinition :
+# 31| r31_1(glval) = VariableAddress[intref] :
+# 31| r31_2(error) = Error :
+# 31| mu31_3(int &) = Store : &:r31_1, r31_2
+# 32| r32_1(glval) = VariableAddress[x] :
+# 32| r32_2(error) = Error :
+# 32| mu32_3(int) = Store : &:r32_1, r32_2
+#-----| r0_36(glval) = Error :
+#-----| r0_43(error) = Load : &:r0_36, ~mu30_3
+# 33| r33_1(glval) = VariableAddress[x] :
+# 33| mu33_2(int) = Store : &:r33_1, r0_43
+# 34| v34_1(void) = NoOp :
+# 30| v30_4(void) = ReturnVoid :
+# 30| v30_5(void) = UnmodeledUse : mu*
+# 30| v30_6(void) = AliasedUse : ~mu30_3
+# 30| v30_7(void) = ExitFunction :
clang.cpp:
# 5| int* globalIntAddress()
# 5| Block 0
-# 5| v0_0(void) = EnterFunction :
-# 5| mu0_1(unknown) = AliasedDefinition :
-# 5| mu0_2(unknown) = UnmodeledDefinition :
-# 6| r0_3(glval) = VariableAddress[#return] :
-# 6| r0_4(glval) = VariableAddress[globalInt] :
-# 6| r0_5(int *) = CopyValue : r0_4
-# 6| mu0_6(int *) = Store : &:r0_3, r0_5
-# 5| r0_7(glval) = VariableAddress[#return] :
-# 5| v0_8(void) = ReturnValue : &:r0_7, ~mu0_2
-# 5| v0_9(void) = UnmodeledUse : mu*
-# 5| v0_10(void) = AliasedUse : ~mu0_2
-# 5| v0_11(void) = ExitFunction :
+# 5| v5_1(void) = EnterFunction :
+# 5| mu5_2(unknown) = AliasedDefinition :
+# 5| mu5_3(unknown) = UnmodeledDefinition :
+# 6| r6_1(glval) = VariableAddress[#return] :
+# 6| r6_2(glval) = VariableAddress[globalInt] :
+# 6| r6_3(int *) = CopyValue : r6_2
+# 6| mu6_4(int *) = Store : &:r6_1, r6_3
+# 5| r5_4(glval) = VariableAddress[#return] :
+# 5| v5_5(void) = ReturnValue : &:r5_4, ~mu5_3
+# 5| v5_6(void) = UnmodeledUse : mu*
+# 5| v5_7(void) = AliasedUse : ~mu5_3
+# 5| v5_8(void) = ExitFunction :
ir.cpp:
# 1| void Constants()
# 1| Block 0
-# 1| v0_0(void) = EnterFunction :
-# 1| mu0_1(unknown) = AliasedDefinition :
-# 1| mu0_2(unknown) = UnmodeledDefinition :
-# 2| r0_3(glval) = VariableAddress[c_i] :
-# 2| r0_4(char) = Constant[1] :
-# 2| mu0_5(char) = Store : &:r0_3, r0_4
-# 3| r0_6(glval) = VariableAddress[c_c] :
-# 3| r0_7(char) = Constant[65] :
-# 3| mu0_8(char) = Store : &:r0_6, r0_7
-# 5| r0_9(glval) = VariableAddress[sc_i] :
-# 5| r0_10(signed char) = Constant[-1] :
-# 5| mu0_11(signed char) = Store : &:r0_9, r0_10
-# 6| r0_12(glval) = VariableAddress[sc_c] :
-# 6| r0_13(signed char) = Constant[65] :
-# 6| mu0_14(signed char) = Store : &:r0_12, r0_13
-# 8| r0_15(glval) = VariableAddress[uc_i] :
-# 8| r0_16(unsigned char) = Constant[5] :
-# 8| mu0_17(unsigned char) = Store : &:r0_15, r0_16
-# 9| r0_18(glval) = VariableAddress[uc_c] :
-# 9| r0_19(unsigned char) = Constant[65] :
-# 9| mu0_20(unsigned char) = Store : &:r0_18, r0_19
-# 11| r0_21(glval) = VariableAddress[s] :
-# 11| r0_22(short) = Constant[5] :
-# 11| mu0_23(short) = Store : &:r0_21, r0_22
-# 12| r0_24(glval) = VariableAddress[us] :
-# 12| r0_25(unsigned short) = Constant[5] :
-# 12| mu0_26(unsigned short) = Store : &:r0_24, r0_25
-# 14| r0_27(glval) = VariableAddress[i] :
-# 14| r0_28(int) = Constant[5] :
-# 14| mu0_29(int) = Store : &:r0_27, r0_28
-# 15| r0_30(glval) = VariableAddress[ui] :
-# 15| r0_31(unsigned int) = Constant[5] :
-# 15| mu0_32(unsigned int) = Store : &:r0_30, r0_31
-# 17| r0_33(glval) = VariableAddress[l] :
-# 17| r0_34(long) = Constant[5] :
-# 17| mu0_35(long) = Store : &:r0_33, r0_34
-# 18| r0_36(glval) = VariableAddress[ul] :
-# 18| r0_37(unsigned long) = Constant[5] :
-# 18| mu0_38(unsigned long) = Store : &:r0_36, r0_37
-# 20| r0_39(glval) = VariableAddress[ll_i] :
-# 20| r0_40(long long) = Constant[5] :
-# 20| mu0_41(long long) = Store : &:r0_39, r0_40
-# 21| r0_42(glval) = VariableAddress[ll_ll] :
-# 21| r0_43(long long) = Constant[5] :
-# 21| mu0_44(long long) = Store : &:r0_42, r0_43
-# 22| r0_45(glval) = VariableAddress[ull_i] :
-# 22| r0_46(unsigned long long) = Constant[5] :
-# 22| mu0_47(unsigned long long) = Store : &:r0_45, r0_46
-# 23| r0_48(glval) = VariableAddress[ull_ull] :
-# 23| r0_49(unsigned long long) = Constant[5] :
-# 23| mu0_50(unsigned long long) = Store : &:r0_48, r0_49
-# 25| r0_51(glval) = VariableAddress[b_t] :
-# 25| r0_52(bool) = Constant[1] :
-# 25| mu0_53(bool) = Store : &:r0_51, r0_52
-# 26| r0_54(glval) = VariableAddress[b_f] :
-# 26| r0_55(bool) = Constant[0] :
-# 26| mu0_56(bool) = Store : &:r0_54, r0_55
-# 28| r0_57(glval) = VariableAddress[wc_i] :
-# 28| r0_58(wchar_t) = Constant[5] :
-# 28| mu0_59(wchar_t) = Store : &:r0_57, r0_58
-# 29| r0_60(glval) = VariableAddress[wc_c] :
-# 29| r0_61(wchar_t) = Constant[65] :
-# 29| mu0_62(wchar_t) = Store : &:r0_60, r0_61
-# 31| r0_63(glval) = VariableAddress[c16] :
-# 31| r0_64(char16_t) = Constant[65] :
-# 31| mu0_65(char16_t) = Store : &:r0_63, r0_64
-# 32| r0_66(glval) = VariableAddress[c32] :
-# 32| r0_67(char32_t) = Constant[65] :
-# 32| mu0_68(char32_t) = Store : &:r0_66, r0_67
-# 34| r0_69(glval) = VariableAddress[f_i] :
-# 34| r0_70(float) = Constant[1.0] :
-# 34| mu0_71(float) = Store : &:r0_69, r0_70
-# 35| r0_72(glval) = VariableAddress[f_f] :
-# 35| r0_73(float) = Constant[1.0] :
-# 35| mu0_74(float) = Store : &:r0_72, r0_73
-# 36| r0_75(glval) = VariableAddress[f_d] :
-# 36| r0_76(float) = Constant[1.0] :
-# 36| mu0_77(float) = Store : &:r0_75, r0_76
-# 38| r0_78(glval) = VariableAddress[d_i] :
-# 38| r0_79(double) = Constant[1.0] :
-# 38| mu0_80(double) = Store : &:r0_78, r0_79
-# 39| r0_81(glval) = VariableAddress[d_f] :
-# 39| r0_82(double) = Constant[1.0] :
-# 39| mu0_83(double) = Store : &:r0_81, r0_82
-# 40| r0_84(glval) = VariableAddress[d_d] :
-# 40| r0_85(double) = Constant[1.0] :
-# 40| mu0_86(double) = Store : &:r0_84, r0_85
-# 41| v0_87(void) = NoOp :
-# 1| v0_88(void) = ReturnVoid :
-# 1| v0_89(void) = UnmodeledUse : mu*
-# 1| v0_90(void) = AliasedUse : ~mu0_2
-# 1| v0_91(void) = ExitFunction :
+# 1| v1_1(void) = EnterFunction :
+# 1| mu1_2(unknown) = AliasedDefinition :
+# 1| mu1_3(unknown) = UnmodeledDefinition :
+# 2| r2_1(glval) = VariableAddress[c_i] :
+# 2| r2_2(char) = Constant[1] :
+# 2| mu2_3(char) = Store : &:r2_1, r2_2
+# 3| r3_1(glval) = VariableAddress[c_c] :
+# 3| r3_2(char) = Constant[65] :
+# 3| mu3_3(char) = Store : &:r3_1, r3_2
+# 5| r5_1(glval) = VariableAddress[sc_i] :
+# 5| r5_2(signed char) = Constant[-1] :
+# 5| mu5_3(signed char) = Store : &:r5_1, r5_2
+# 6| r6_1(glval) = VariableAddress[sc_c] :
+# 6| r6_2(signed char) = Constant[65] :
+# 6| mu6_3(signed char) = Store : &:r6_1, r6_2
+# 8| r8_1(glval) = VariableAddress[uc_i] :
+# 8| r8_2(unsigned char) = Constant[5] :
+# 8| mu8_3(unsigned char) = Store : &:r8_1, r8_2
+# 9| r9_1(glval) = VariableAddress[uc_c] :
+# 9| r9_2(unsigned char) = Constant[65] :
+# 9| mu9_3(unsigned char) = Store : &:r9_1, r9_2
+# 11| r11_1(glval) = VariableAddress[s] :
+# 11| r11_2(short) = Constant[5] :
+# 11| mu11_3(short) = Store : &:r11_1, r11_2
+# 12| r12_1(glval) = VariableAddress[us] :
+# 12| r12_2(unsigned short) = Constant[5] :
+# 12| mu12_3(unsigned short) = Store : &:r12_1, r12_2
+# 14| r14_1(glval) = VariableAddress[i] :
+# 14| r14_2(int) = Constant[5] :
+# 14| mu14_3(int) = Store : &:r14_1, r14_2
+# 15| r15_1(glval) = VariableAddress[ui] :
+# 15| r15_2(unsigned int) = Constant[5] :
+# 15| mu15_3(unsigned int) = Store : &:r15_1, r15_2
+# 17| r17_1(glval) = VariableAddress[l] :
+# 17| r17_2(long) = Constant[5] :
+# 17| mu17_3(long) = Store : &:r17_1, r17_2
+# 18| r18_1(glval) = VariableAddress[ul] :
+# 18| r18_2(unsigned long) = Constant[5] :
+# 18| mu18_3(unsigned long) = Store : &:r18_1, r18_2
+# 20| r20_1(glval) = VariableAddress[ll_i] :
+# 20| r20_2(long long) = Constant[5] :
+# 20| mu20_3(long long) = Store : &:r20_1, r20_2
+# 21| r21_1(glval) = VariableAddress[ll_ll] :
+# 21| r21_2(long long) = Constant[5] :
+# 21| mu21_3(long long) = Store : &:r21_1, r21_2
+# 22| r22_1(glval) = VariableAddress[ull_i] :
+# 22| r22_2(unsigned long long) = Constant[5] :
+# 22| mu22_3(unsigned long long) = Store : &:r22_1, r22_2
+# 23| r23_1(glval) = VariableAddress[ull_ull] :
+# 23| r23_2(unsigned long long) = Constant[5] :
+# 23| mu23_3(unsigned long long) = Store : &:r23_1, r23_2
+# 25| r25_1(glval) = VariableAddress[b_t] :
+# 25| r25_2(bool) = Constant[1] :
+# 25| mu25_3(bool) = Store : &:r25_1, r25_2
+# 26| r26_1(glval) = VariableAddress[b_f] :
+# 26| r26_2(bool) = Constant[0] :
+# 26| mu26_3(bool) = Store : &:r26_1, r26_2
+# 28| r28_1(glval) = VariableAddress[wc_i] :
+# 28| r28_2(wchar_t) = Constant[5] :
+# 28| mu28_3(wchar_t) = Store : &:r28_1, r28_2
+# 29| r29_1(glval) = VariableAddress[wc_c] :
+# 29| r29_2(wchar_t) = Constant[65] :
+# 29| mu29_3(wchar_t) = Store : &:r29_1, r29_2
+# 31| r31_1(glval) = VariableAddress[c16] :
+# 31| r31_2(char16_t) = Constant[65] :
+# 31| mu31_3(char16_t) = Store : &:r31_1, r31_2
+# 32| r32_1(glval) = VariableAddress[c32] :
+# 32| r32_2(char32_t) = Constant[65] :
+# 32| mu32_3(char32_t) = Store : &:r32_1, r32_2
+# 34| r34_1(glval) = VariableAddress[f_i] :
+# 34| r34_2(float) = Constant[1.0] :
+# 34| mu34_3(float) = Store : &:r34_1, r34_2
+# 35| r35_1(glval) = VariableAddress[f_f] :
+# 35| r35_2(float) = Constant[1.0] :
+# 35| mu35_3(float) = Store : &:r35_1, r35_2
+# 36| r36_1(glval) = VariableAddress[f_d] :
+# 36| r36_2(float) = Constant[1.0] :
+# 36| mu36_3(float) = Store : &:r36_1, r36_2
+# 38| r38_1(glval) = VariableAddress[d_i] :
+# 38| r38_2(double) = Constant[1.0] :
+# 38| mu38_3(double) = Store : &:r38_1, r38_2
+# 39| r39_1(glval) = VariableAddress[d_f] :
+# 39| r39_2(double) = Constant[1.0] :
+# 39| mu39_3(double) = Store : &:r39_1, r39_2
+# 40| r40_1(glval) = VariableAddress[d_d] :
+# 40| r40_2(double) = Constant[1.0] :
+# 40| mu40_3(double) = Store : &:r40_1, r40_2
+# 41| v41_1(void) = NoOp :
+# 1| v1_4(void) = ReturnVoid :
+# 1| v1_5(void) = UnmodeledUse : mu*
+# 1| v1_6(void) = AliasedUse : ~mu1_3
+# 1| v1_7(void) = ExitFunction :
# 43| void Foo()
# 43| Block 0
-# 43| v0_0(void) = EnterFunction :
-# 43| mu0_1(unknown) = AliasedDefinition :
-# 43| mu0_2(unknown) = UnmodeledDefinition :
-# 44| r0_3(glval) = VariableAddress[x] :
-# 44| r0_4(int) = Constant[17] :
-# 44| mu0_5(int) = Store : &:r0_3, r0_4
-# 45| r0_6(glval) = VariableAddress[y] :
-# 45| r0_7(short) = Constant[7] :
-# 45| mu0_8(short) = Store : &:r0_6, r0_7
-# 46| r0_9(glval) = VariableAddress[x] :
-# 46| r0_10(int) = Load : &:r0_9, ~mu0_2
-# 46| r0_11(glval) = VariableAddress[y] :
-# 46| r0_12(short) = Load : &:r0_11, ~mu0_2
-# 46| r0_13(int) = Convert : r0_12
-# 46| r0_14(int) = Add : r0_10, r0_13
-# 46| r0_15(short) = Convert : r0_14
-# 46| r0_16(glval) = VariableAddress[y] :
-# 46| mu0_17(short) = Store : &:r0_16, r0_15
-# 47| r0_18(glval) = VariableAddress[x] :
-# 47| r0_19(int) = Load : &:r0_18, ~mu0_2
-# 47| r0_20(glval) = VariableAddress[y] :
-# 47| r0_21(short) = Load : &:r0_20, ~mu0_2
-# 47| r0_22(int) = Convert : r0_21
-# 47| r0_23(int) = Mul : r0_19, r0_22
-# 47| r0_24(glval) = VariableAddress[x] :
-# 47| mu0_25(int) = Store : &:r0_24, r0_23
-# 48| v0_26(void) = NoOp :
-# 43| v0_27(void) = ReturnVoid :
-# 43| v0_28(void) = UnmodeledUse : mu*
-# 43| v0_29(void) = AliasedUse : ~mu0_2
-# 43| v0_30(void) = ExitFunction :
+# 43| v43_1(void) = EnterFunction :
+# 43| mu43_2(unknown) = AliasedDefinition :
+# 43| mu43_3(unknown) = UnmodeledDefinition :
+# 44| r44_1(glval) = VariableAddress[x] :
+# 44| r44_2(int) = Constant[17] :
+# 44| mu44_3(int) = Store : &:r44_1, r44_2
+# 45| r45_1(glval) = VariableAddress[y] :
+# 45| r45_2(short) = Constant[7] :
+# 45| mu45_3(short) = Store : &:r45_1, r45_2
+# 46| r46_1(glval) = VariableAddress[x] :
+# 46| r46_2(int) = Load : &:r46_1, ~mu43_3
+# 46| r46_3(glval) = VariableAddress[y] :
+# 46| r46_4(short) = Load : &:r46_3, ~mu43_3
+# 46| r46_5(int) = Convert : r46_4
+# 46| r46_6(int) = Add : r46_2, r46_5
+# 46| r46_7(short) = Convert : r46_6
+# 46| r46_8(glval) = VariableAddress[y] :
+# 46| mu46_9(short) = Store : &:r46_8, r46_7
+# 47| r47_1(glval) = VariableAddress[x] :
+# 47| r47_2(int) = Load : &:r47_1, ~mu43_3
+# 47| r47_3(glval) = VariableAddress[y] :
+# 47| r47_4(short) = Load : &:r47_3, ~mu43_3
+# 47| r47_5(int) = Convert : r47_4
+# 47| r47_6(int) = Mul : r47_2, r47_5
+# 47| r47_7(glval) = VariableAddress[x] :
+# 47| mu47_8(int) = Store : &:r47_7, r47_6
+# 48| v48_1(void) = NoOp :
+# 43| v43_4(void) = ReturnVoid :
+# 43| v43_5(void) = UnmodeledUse : mu*
+# 43| v43_6(void) = AliasedUse : ~mu43_3
+# 43| v43_7(void) = ExitFunction :
# 50| void IntegerOps(int, int)
# 50| Block 0
-# 50| v0_0(void) = EnterFunction :
-# 50| mu0_1(unknown) = AliasedDefinition :
-# 50| mu0_2(unknown) = UnmodeledDefinition :
-# 50| r0_3(glval) = VariableAddress[x] :
-# 50| mu0_4(int) = InitializeParameter[x] : &:r0_3
-# 50| r0_5(glval) = VariableAddress[y] :
-# 50| mu0_6(int) = InitializeParameter[y] : &:r0_5
-# 51| r0_7(glval) = VariableAddress[z] :
-# 51| mu0_8(int) = Uninitialized[z] : &:r0_7
-# 53| r0_9(glval) = VariableAddress[x] :
-# 53| r0_10(int) = Load : &:r0_9, ~mu0_2
-# 53| r0_11(glval) = VariableAddress[y] :
-# 53| r0_12(int) = Load : &:r0_11, ~mu0_2
-# 53| r0_13(int) = Add : r0_10, r0_12
-# 53| r0_14(glval) = VariableAddress[z] :
-# 53| mu0_15(int) = Store : &:r0_14, r0_13
-# 54| r0_16(glval) = VariableAddress[x] :
-# 54| r0_17(int) = Load : &:r0_16, ~mu0_2
-# 54| r0_18(glval) = VariableAddress[y] :
-# 54| r0_19(int) = Load : &:r0_18, ~mu0_2
-# 54| r0_20(int) = Sub : r0_17, r0_19
-# 54| r0_21(glval) = VariableAddress[z] :
-# 54| mu0_22(int) = Store : &:r0_21, r0_20
-# 55| r0_23(glval) = VariableAddress[x] :
-# 55| r0_24(int) = Load : &:r0_23, ~mu0_2
-# 55| r0_25(glval) = VariableAddress[y] :
-# 55| r0_26(int) = Load : &:r0_25, ~mu0_2
-# 55| r0_27(int) = Mul : r0_24, r0_26
-# 55| r0_28(glval) = VariableAddress[z] :
-# 55| mu0_29(int) = Store : &:r0_28, r0_27
-# 56| r0_30(glval) = VariableAddress[x] :
-# 56| r0_31(int) = Load : &:r0_30, ~mu0_2
-# 56| r0_32(glval) = VariableAddress[y] :
-# 56| r0_33(int) = Load : &:r0_32, ~mu0_2
-# 56| r0_34(int) = Div : r0_31, r0_33
-# 56| r0_35(glval) = VariableAddress[z] :
-# 56| mu0_36(int) = Store : &:r0_35, r0_34
-# 57| r0_37(glval) = VariableAddress[x] :
-# 57| r0_38(int) = Load : &:r0_37, ~mu0_2
-# 57| r0_39(glval) = VariableAddress[y] :
-# 57| r0_40(int) = Load : &:r0_39, ~mu0_2
-# 57| r0_41(int) = Rem : r0_38, r0_40
-# 57| r0_42(glval) = VariableAddress[z] :
-# 57| mu0_43(int) = Store : &:r0_42, r0_41
-# 59| r0_44(glval) = VariableAddress[x] :
-# 59| r0_45(int) = Load : &:r0_44, ~mu0_2
-# 59| r0_46(glval) = VariableAddress[y] :
-# 59| r0_47(int) = Load : &:r0_46, ~mu0_2
-# 59| r0_48(int) = BitAnd : r0_45, r0_47
-# 59| r0_49(glval) = VariableAddress[z] :
-# 59| mu0_50(int) = Store : &:r0_49, r0_48
-# 60| r0_51(glval) = VariableAddress[x] :
-# 60| r0_52(int) = Load : &:r0_51, ~mu0_2
-# 60| r0_53(glval) = VariableAddress[y] :
-# 60| r0_54(int) = Load : &:r0_53, ~mu0_2
-# 60| r0_55(int) = BitOr : r0_52, r0_54
-# 60| r0_56(glval) = VariableAddress[z] :
-# 60| mu0_57(int) = Store : &:r0_56, r0_55
-# 61| r0_58(glval) = VariableAddress[x] :
-# 61| r0_59(int) = Load : &:r0_58, ~mu0_2
-# 61| r0_60(glval) = VariableAddress[y] :
-# 61| r0_61(int) = Load : &:r0_60, ~mu0_2
-# 61| r0_62(int) = BitXor : r0_59, r0_61
-# 61| r0_63(glval) = VariableAddress[z] :
-# 61| mu0_64(int) = Store : &:r0_63, r0_62
-# 63| r0_65(glval) = VariableAddress[x] :
-# 63| r0_66(int) = Load : &:r0_65, ~mu0_2
-# 63| r0_67(glval) = VariableAddress[y] :
-# 63| r0_68(int) = Load : &:r0_67, ~mu0_2
-# 63| r0_69(int) = ShiftLeft : r0_66, r0_68
-# 63| r0_70(glval) = VariableAddress[z] :
-# 63| mu0_71(int) = Store : &:r0_70, r0_69
-# 64| r0_72(glval) = VariableAddress[x] :
-# 64| r0_73(int) = Load : &:r0_72, ~mu0_2
-# 64| r0_74(glval) = VariableAddress[y] :
-# 64| r0_75(int) = Load : &:r0_74, ~mu0_2
-# 64| r0_76(int) = ShiftRight : r0_73, r0_75
-# 64| r0_77(glval) = VariableAddress[z] :
-# 64| mu0_78(int) = Store : &:r0_77, r0_76
-# 66| r0_79(glval) = VariableAddress[x] :
-# 66| r0_80(int) = Load : &:r0_79, ~mu0_2
-# 66| r0_81(glval) = VariableAddress[z] :
-# 66| mu0_82(int) = Store : &:r0_81, r0_80
-# 68| r0_83(glval) = VariableAddress[x] :
-# 68| r0_84(int) = Load : &:r0_83, ~mu0_2
-# 68| r0_85(glval) = VariableAddress[z] :
-# 68| r0_86(int) = Load : &:r0_85, ~mu0_2
-# 68| r0_87(int) = Add : r0_86, r0_84
-# 68| mu0_88(int) = Store : &:r0_85, r0_87
-# 69| r0_89(glval) = VariableAddress[x] :
-# 69| r0_90(int) = Load : &:r0_89, ~mu0_2
-# 69| r0_91(glval) = VariableAddress[z] :
-# 69| r0_92(int) = Load : &:r0_91, ~mu0_2
-# 69| r0_93(int) = Sub : r0_92, r0_90
-# 69| mu0_94(int) = Store : &:r0_91, r0_93
-# 70| r0_95(glval) = VariableAddress[x] :
-# 70| r0_96(int) = Load : &:r0_95, ~mu0_2
-# 70| r0_97(glval) = VariableAddress[z] :
-# 70| r0_98(int) = Load : &:r0_97, ~mu0_2
-# 70| r0_99(int) = Mul : r0_98, r0_96
-# 70| mu0_100(int) = Store : &:r0_97, r0_99
-# 71| r0_101(glval) = VariableAddress[x] :
-# 71| r0_102(int) = Load : &:r0_101, ~mu0_2
-# 71| r0_103(glval) = VariableAddress[z] :
-# 71| r0_104(int) = Load : &:r0_103, ~mu0_2
-# 71| r0_105(int) = Div : r0_104, r0_102
-# 71| mu0_106(int) = Store : &:r0_103, r0_105
-# 72| r0_107(glval) = VariableAddress[x] :
-# 72| r0_108(int) = Load : &:r0_107, ~mu0_2
-# 72| r0_109(glval) = VariableAddress[z] :
-# 72| r0_110(int) = Load : &:r0_109, ~mu0_2
-# 72| r0_111(int) = Rem : r0_110, r0_108
-# 72| mu0_112(int) = Store : &:r0_109, r0_111
-# 74| r0_113(glval) = VariableAddress[x] :
-# 74| r0_114(int) = Load : &:r0_113, ~mu0_2
-# 74| r0_115(glval) = VariableAddress[z] :
-# 74| r0_116(int) = Load : &:r0_115, ~mu0_2
-# 74| r0_117(int) = BitAnd : r0_116, r0_114
-# 74| mu0_118(int) = Store : &:r0_115, r0_117
-# 75| r0_119(glval) = VariableAddress[x] :
-# 75| r0_120(int) = Load : &:r0_119, ~mu0_2
-# 75| r0_121(glval) = VariableAddress[z] :
-# 75| r0_122(int) = Load : &:r0_121, ~mu0_2
-# 75| r0_123(int) = BitOr : r0_122, r0_120
-# 75| mu0_124(int) = Store : &:r0_121, r0_123
-# 76| r0_125(glval) = VariableAddress[x] :
-# 76| r0_126(int) = Load : &:r0_125, ~mu0_2
-# 76| r0_127(glval) = VariableAddress[z] :
-# 76| r0_128(int) = Load : &:r0_127, ~mu0_2
-# 76| r0_129(int) = BitXor : r0_128, r0_126
-# 76| mu0_130(int) = Store : &:r0_127, r0_129
-# 78| r0_131(glval) = VariableAddress[x] :
-# 78| r0_132(int) = Load : &:r0_131, ~mu0_2
-# 78| r0_133(glval) = VariableAddress[z] :
-# 78| r0_134(int) = Load : &:r0_133, ~mu0_2
-# 78| r0_135(int) = ShiftLeft : r0_134, r0_132
-# 78| mu0_136(int) = Store : &:r0_133, r0_135
-# 79| r0_137(glval) = VariableAddress[x] :
-# 79| r0_138(int) = Load : &:r0_137, ~mu0_2
-# 79| r0_139(glval) = VariableAddress[z] :
-# 79| r0_140(int) = Load : &:r0_139, ~mu0_2
-# 79| r0_141(int) = ShiftRight : r0_140, r0_138
-# 79| mu0_142(int) = Store : &:r0_139, r0_141
-# 81| r0_143(glval) = VariableAddress[x] :
-# 81| r0_144(int) = Load : &:r0_143, ~mu0_2
-# 81| r0_145(int) = CopyValue : r0_144
-# 81| r0_146(glval) = VariableAddress[z] :
-# 81| mu0_147(int) = Store : &:r0_146, r0_145
-# 82| r0_148(glval) = VariableAddress[x] :
-# 82| r0_149(int) = Load : &:r0_148, ~mu0_2
-# 82| r0_150(int) = Negate : r0_149
-# 82| r0_151(glval) = VariableAddress[z] :
-# 82| mu0_152(int) = Store : &:r0_151, r0_150
-# 83| r0_153(glval) = VariableAddress[x] :
-# 83| r0_154(int) = Load : &:r0_153, ~mu0_2
-# 83| r0_155(int) = BitComplement : r0_154
-# 83| r0_156(glval) = VariableAddress[z] :
-# 83| mu0_157(int) = Store : &:r0_156, r0_155
-# 84| r0_158(glval) = VariableAddress[x] :
-# 84| r0_159(int) = Load : &:r0_158, ~mu0_2
-# 84| r0_160(int) = Constant[0] :
-# 84| r0_161(bool) = CompareNE : r0_159, r0_160
-# 84| r0_162(bool) = LogicalNot : r0_161
-# 84| r0_163(int) = Convert : r0_162
-# 84| r0_164(glval) = VariableAddress[z] :
-# 84| mu0_165(int) = Store : &:r0_164, r0_163
-# 85| v0_166(void) = NoOp :
-# 50| v0_167(void) = ReturnVoid :
-# 50| v0_168(void) = UnmodeledUse : mu*
-# 50| v0_169(void) = AliasedUse : ~mu0_2
-# 50| v0_170(void) = ExitFunction :
+# 50| v50_1(void) = EnterFunction :
+# 50| mu50_2(unknown) = AliasedDefinition :
+# 50| mu50_3(unknown) = UnmodeledDefinition :
+# 50| r50_4(glval) = VariableAddress[x] :
+# 50| mu50_5(int) = InitializeParameter[x] : &:r50_4
+# 50| r50_6(glval) = VariableAddress[y] :
+# 50| mu50_7(int) = InitializeParameter[y] : &:r50_6
+# 51| r51_1(glval) = VariableAddress[z] :
+# 51| mu51_2(int) = Uninitialized[z] : &:r51_1
+# 53| r53_1(glval) = VariableAddress[x] :
+# 53| r53_2(int) = Load : &:r53_1, ~mu50_3
+# 53| r53_3(glval) = VariableAddress[y] :
+# 53| r53_4(int) = Load : &:r53_3, ~mu50_3
+# 53| r53_5(int) = Add : r53_2, r53_4
+# 53| r53_6(glval) = VariableAddress[z] :
+# 53| mu53_7(int) = Store : &:r53_6, r53_5
+# 54| r54_1(glval) = VariableAddress[x] :
+# 54| r54_2(int) = Load : &:r54_1, ~mu50_3
+# 54| r54_3(glval) = VariableAddress[y] :
+# 54| r54_4(int) = Load : &:r54_3, ~mu50_3
+# 54| r54_5(int) = Sub : r54_2, r54_4
+# 54| r54_6(glval) = VariableAddress[z] :
+# 54| mu54_7(int) = Store : &:r54_6, r54_5
+# 55| r55_1(glval) = VariableAddress[x] :
+# 55| r55_2(int) = Load : &:r55_1, ~mu50_3
+# 55| r55_3(glval) = VariableAddress[y] :
+# 55| r55_4(int) = Load : &:r55_3, ~mu50_3
+# 55| r55_5(int) = Mul : r55_2, r55_4
+# 55| r55_6(glval) = VariableAddress[z] :
+# 55| mu55_7(int) = Store : &:r55_6, r55_5
+# 56| r56_1(glval) = VariableAddress[x] :
+# 56| r56_2(int) = Load : &:r56_1, ~mu50_3
+# 56| r56_3(glval) = VariableAddress[y] :
+# 56| r56_4(int) = Load : &:r56_3, ~mu50_3
+# 56| r56_5(int) = Div : r56_2, r56_4
+# 56| r56_6(glval) = VariableAddress[z] :
+# 56| mu56_7(int) = Store : &:r56_6, r56_5
+# 57| r57_1(glval) = VariableAddress[x] :
+# 57| r57_2(int) = Load : &:r57_1, ~mu50_3
+# 57| r57_3(glval) = VariableAddress[y] :
+# 57| r57_4(int) = Load : &:r57_3, ~mu50_3
+# 57| r57_5(int) = Rem : r57_2, r57_4
+# 57| r57_6(glval) = VariableAddress[z] :
+# 57| mu57_7(int) = Store : &:r57_6, r57_5
+# 59| r59_1(glval) = VariableAddress[x] :
+# 59| r59_2(int) = Load : &:r59_1, ~mu50_3
+# 59| r59_3(glval) = VariableAddress[y] :
+# 59| r59_4(int) = Load : &:r59_3, ~mu50_3
+# 59| r59_5(int) = BitAnd : r59_2, r59_4
+# 59| r59_6(glval) = VariableAddress[z] :
+# 59| mu59_7(int) = Store : &:r59_6, r59_5
+# 60| r60_1(glval) = VariableAddress[x] :
+# 60| r60_2(int) = Load : &:r60_1, ~mu50_3
+# 60| r60_3(glval) = VariableAddress[y] :
+# 60| r60_4(int) = Load : &:r60_3, ~mu50_3
+# 60| r60_5(int) = BitOr : r60_2, r60_4
+# 60| r60_6(glval) = VariableAddress[z] :
+# 60| mu60_7(int) = Store : &:r60_6, r60_5
+# 61| r61_1(glval) = VariableAddress[x] :
+# 61| r61_2(int) = Load : &:r61_1, ~mu50_3
+# 61| r61_3(glval) = VariableAddress[y] :
+# 61| r61_4(int) = Load : &:r61_3, ~mu50_3
+# 61| r61_5(int) = BitXor : r61_2, r61_4
+# 61| r61_6(glval) = VariableAddress[z] :
+# 61| mu61_7(int) = Store : &:r61_6, r61_5
+# 63| r63_1(glval) = VariableAddress[x] :
+# 63| r63_2(int) = Load : &:r63_1, ~mu50_3
+# 63| r63_3(glval) = VariableAddress[y] :
+# 63| r63_4(int) = Load : &:r63_3, ~mu50_3
+# 63| r63_5(int) = ShiftLeft : r63_2, r63_4
+# 63| r63_6(glval) = VariableAddress[z] :
+# 63| mu63_7(int) = Store : &:r63_6, r63_5
+# 64| r64_1(glval) = VariableAddress[x] :
+# 64| r64_2(int) = Load : &:r64_1, ~mu50_3
+# 64| r64_3(glval) = VariableAddress[y] :
+# 64| r64_4(int) = Load : &:r64_3, ~mu50_3
+# 64| r64_5(int) = ShiftRight : r64_2, r64_4
+# 64| r64_6(glval) = VariableAddress[z] :
+# 64| mu64_7(int) = Store : &:r64_6, r64_5
+# 66| r66_1(glval) = VariableAddress[x] :
+# 66| r66_2(int) = Load : &:r66_1, ~mu50_3
+# 66| r66_3(glval) = VariableAddress[z] :
+# 66| mu66_4(int) = Store : &:r66_3, r66_2
+# 68| r68_1(glval) = VariableAddress[x] :
+# 68| r68_2(int) = Load : &:r68_1, ~mu50_3
+# 68| r68_3(glval) = VariableAddress[z] :
+# 68| r68_4(int) = Load : &:r68_3, ~mu50_3
+# 68| r68_5(int) = Add : r68_4, r68_2
+# 68| mu68_6(int) = Store : &:r68_3, r68_5
+# 69| r69_1(glval) = VariableAddress[x] :
+# 69| r69_2(int) = Load : &:r69_1, ~mu50_3
+# 69| r69_3(glval) = VariableAddress[z] :
+# 69| r69_4(int) = Load : &:r69_3, ~mu50_3
+# 69| r69_5(int) = Sub : r69_4, r69_2
+# 69| mu69_6(int) = Store : &:r69_3, r69_5
+# 70| r70_1(glval) = VariableAddress[x] :
+# 70| r70_2(int) = Load : &:r70_1, ~mu50_3
+# 70| r70_3(glval) = VariableAddress[z] :
+# 70| r70_4(int) = Load : &:r70_3, ~mu50_3
+# 70| r70_5(int) = Mul : r70_4, r70_2
+# 70| mu70_6(int) = Store : &:r70_3, r70_5
+# 71| r71_1(glval) = VariableAddress[x] :
+# 71| r71_2(int) = Load : &:r71_1, ~mu50_3
+# 71| r71_3(glval) = VariableAddress[z] :
+# 71| r71_4(int) = Load : &:r71_3, ~mu50_3
+# 71| r71_5(int) = Div : r71_4, r71_2
+# 71| mu71_6(int) = Store : &:r71_3, r71_5
+# 72| r72_1(glval) = VariableAddress[x] :
+# 72| r72_2(int) = Load : &:r72_1, ~mu50_3
+# 72| r72_3(glval) = VariableAddress[z] :
+# 72| r72_4(int) = Load : &:r72_3, ~mu50_3
+# 72| r72_5(int) = Rem : r72_4, r72_2
+# 72| mu72_6(int) = Store : &:r72_3, r72_5
+# 74| r74_1(glval) = VariableAddress[x] :
+# 74| r74_2(int) = Load : &:r74_1, ~mu50_3
+# 74| r74_3(glval) = VariableAddress[z] :
+# 74| r74_4(int) = Load : &:r74_3, ~mu50_3
+# 74| r74_5(int) = BitAnd : r74_4, r74_2
+# 74| mu74_6(int) = Store : &:r74_3, r74_5
+# 75| r75_1(glval) = VariableAddress[x] :
+# 75| r75_2(int) = Load : &:r75_1, ~mu50_3
+# 75| r75_3(glval) = VariableAddress[z] :
+# 75| r75_4(int) = Load : &:r75_3, ~mu50_3
+# 75| r75_5(int) = BitOr : r75_4, r75_2
+# 75| mu75_6(int) = Store : &:r75_3, r75_5
+# 76| r76_1(glval) = VariableAddress[x] :
+# 76| r76_2(int) = Load : &:r76_1, ~mu50_3
+# 76| r76_3(glval) = VariableAddress[z] :
+# 76| r76_4(int) = Load : &:r76_3, ~mu50_3
+# 76| r76_5(int) = BitXor : r76_4, r76_2
+# 76| mu76_6(int) = Store : &:r76_3, r76_5
+# 78| r78_1(glval) = VariableAddress[x] :
+# 78| r78_2(int) = Load : &:r78_1, ~mu50_3
+# 78| r78_3(glval) = VariableAddress[z] :
+# 78| r78_4(int) = Load : &:r78_3, ~mu50_3
+# 78| r78_5(int) = ShiftLeft : r78_4, r78_2
+# 78| mu78_6(int) = Store : &:r78_3, r78_5
+# 79| r79_1(glval) = VariableAddress[x] :
+# 79| r79_2(int) = Load : &:r79_1, ~mu50_3
+# 79| r79_3(glval) = VariableAddress[z] :
+# 79| r79_4(int) = Load : &:r79_3, ~mu50_3
+# 79| r79_5(int) = ShiftRight : r79_4, r79_2
+# 79| mu79_6(int) = Store : &:r79_3, r79_5
+# 81| r81_1(glval) = VariableAddress[x] :
+# 81| r81_2(int) = Load : &:r81_1, ~mu50_3
+# 81| r81_3(int) = CopyValue : r81_2
+# 81| r81_4(glval) = VariableAddress[z] :
+# 81| mu81_5(int) = Store : &:r81_4, r81_3
+# 82| r82_1(glval) = VariableAddress[x] :
+# 82| r82_2(int) = Load : &:r82_1, ~mu50_3
+# 82| r82_3(int) = Negate : r82_2
+# 82| r82_4(glval) = VariableAddress[z] :
+# 82| mu82_5(int) = Store : &:r82_4, r82_3
+# 83| r83_1(glval) = VariableAddress[x] :
+# 83| r83_2(int) = Load : &:r83_1, ~mu50_3
+# 83| r83_3(int) = BitComplement : r83_2
+# 83| r83_4(glval) = VariableAddress[z] :
+# 83| mu83_5(int) = Store : &:r83_4, r83_3
+# 84| r84_1(glval) = VariableAddress[x] :
+# 84| r84_2(int) = Load : &:r84_1, ~mu50_3
+# 84| r84_3(int) = Constant[0] :
+# 84| r84_4(bool) = CompareNE : r84_2, r84_3
+# 84| r84_5(bool) = LogicalNot : r84_4
+# 84| r84_6(int) = Convert : r84_5
+# 84| r84_7(glval) = VariableAddress[z] :
+# 84| mu84_8(int) = Store : &:r84_7, r84_6
+# 85| v85_1(void) = NoOp :
+# 50| v50_8(void) = ReturnVoid :
+# 50| v50_9(void) = UnmodeledUse : mu*
+# 50| v50_10(void) = AliasedUse : ~mu50_3
+# 50| v50_11(void) = ExitFunction :
# 87| void IntegerCompare(int, int)
# 87| Block 0
-# 87| v0_0(void) = EnterFunction :
-# 87| mu0_1(unknown) = AliasedDefinition :
-# 87| mu0_2(unknown) = UnmodeledDefinition :
-# 87| r0_3(glval) = VariableAddress[x] :
-# 87| mu0_4(int) = InitializeParameter[x] : &:r0_3
-# 87| r0_5(glval) = VariableAddress[y] :
-# 87| mu0_6(int) = InitializeParameter[y] : &:r0_5
-# 88| r0_7(glval) = VariableAddress[b] :
-# 88| mu0_8(bool) = Uninitialized[b] : &:r0_7
-# 90| r0_9(glval