mirror of
https://github.com/github/codeql.git
synced 2026-06-02 20:30:15 +02:00
Compare commits
9 Commits
rc/1.25
...
atm/js/esb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96d796579e | ||
|
|
246f8755e4 | ||
|
|
f2e43ad5da | ||
|
|
e723c6e790 | ||
|
|
f60a82dfc3 | ||
|
|
092b0c867e | ||
|
|
9ca415f297 | ||
|
|
6d02494e61 | ||
|
|
15c3820fd9 |
@@ -1,6 +1,5 @@
|
||||
{ "provide": [ "*/ql/src/qlpack.yml",
|
||||
"*/ql/test/qlpack.yml",
|
||||
"*/ql/examples/qlpack.yml",
|
||||
"*/upgrades/qlpack.yml",
|
||||
"misc/legacy-support/*/qlpack.yml",
|
||||
"misc/suite-helpers/qlpack.yml" ] }
|
||||
|
||||
5
.github/codeql/codeql-config.yml
vendored
5
.github/codeql/codeql-config.yml
vendored
@@ -2,8 +2,3 @@ name: "CodeQL config"
|
||||
|
||||
queries:
|
||||
- uses: security-and-quality
|
||||
|
||||
paths-ignore:
|
||||
- '/cpp/'
|
||||
- '/java/'
|
||||
- '/python/'
|
||||
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"omnisharp.autoStart": false
|
||||
}
|
||||
@@ -9,7 +9,7 @@ You can use the [interactive query console](https://lgtm.com/help/lgtm/using-que
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome contributions to our standard library and standard checks. Do you have an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Before you do, though, please take the time to read our [contributing guidelines](CONTRIBUTING.md). You can also consult our [style guides](https://github.com/github/codeql/tree/main/docs) to learn how to format your code for consistency and clarity, how to write query metadata, and how to write query help documentation for your query.
|
||||
We welcome contributions to our standard library and standard checks. Do you have an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Before you do, though, please take the time to read our [contributing guidelines](CONTRIBUTING.md). You can also consult our [style guides](https://github.com/github/codeql/tree/master/docs) to learn how to format your code for consistency and clarity, how to write query metadata, and how to write query help documentation for your query.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -13,8 +13,6 @@ The following changes in version 1.25 affect C/C++ analysis in all applications.
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|----------------------------|------------------------|------------------------------------------------------------------|
|
||||
| Uncontrolled format string (`cpp/tainted-format-string`) | | This query is now displayed by default on LGTM. |
|
||||
| Uncontrolled format string (through global variable) (`cpp/tainted-format-string-through-global`) | | This query is now displayed by default on LGTM. |
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
|
||||
@@ -28,51 +28,27 @@ The following changes in version 1.25 affect C# analysis in all applications.
|
||||
such as `A<int>.B`, no longer are considered unbound generics. (Such nested types do,
|
||||
however, still have relevant `.getSourceDeclaration()`s, for example `A<>.B`.)
|
||||
* The data-flow library has been improved, which affects most security queries by potentially
|
||||
adding more results:
|
||||
- Flow through methods now takes nested field reads/writes into account.
|
||||
For example, the library is able to track flow from `"taint"` to `Sink()` via the method
|
||||
`GetF2F1()` in
|
||||
```csharp
|
||||
class C1
|
||||
{
|
||||
string F1;
|
||||
}
|
||||
adding more results. Flow through methods now takes nested field reads/writes into account.
|
||||
For example, the library is able to track flow from `"taint"` to `Sink()` via the method
|
||||
`GetF2F1()` in
|
||||
```csharp
|
||||
class C1
|
||||
{
|
||||
string F1;
|
||||
}
|
||||
|
||||
class C2
|
||||
{
|
||||
C1 F2;
|
||||
class C2
|
||||
{
|
||||
C1 F2;
|
||||
|
||||
string GetF2F1() => F2.F1; // Nested field read
|
||||
|
||||
string GetF2F1() => F2.F1; // Nested field read
|
||||
|
||||
void M()
|
||||
{
|
||||
F2 = new C1() { F1 = "taint" };
|
||||
Sink(GetF2F1()); // NEW: "taint" reaches here
|
||||
}
|
||||
}
|
||||
```
|
||||
- Flow through collections is now modeled precisely. For example, instead of modeling an array
|
||||
store `a[i] = x` as a taint-step from `x` to `a`, we now model it as a data-flow step that
|
||||
stores `x` into `a`. To get the value back out, a matching read step must be taken.
|
||||
|
||||
For source-code based data-flow analysis, the following constructs are modeled as stores into
|
||||
collections:
|
||||
- Direct array assignments, `a[i] = x`.
|
||||
- Array initializers, `new [] { x }`.
|
||||
- C# 6-style array initializers, `new C() { Array = { [i] = x } }`.
|
||||
- Call arguments that match a `params` parameter, where the C# compiler creates an array under-the-hood.
|
||||
- `yield return` statements.
|
||||
|
||||
The following source-code constructs read from a collection:
|
||||
- Direct array reads, `a[i]`.
|
||||
- `foreach` statements.
|
||||
|
||||
For calls out to library code, existing flow summaries have been refined to precisely
|
||||
capture how they interact with collection contents. For example, a call to
|
||||
`System.Collections.Generic.List<T>.Add(T)` stores the value of the argument into the
|
||||
qualifier, and a call to `System.Collections.Generic.List<T>.get_Item(int)` (that is, an
|
||||
indexer call) reads contents out of the qualifier. Moreover, the effect of
|
||||
collection-clearing methods such as `System.Collections.Generic.List<T>.Clear()` is now
|
||||
also modeled.
|
||||
void M()
|
||||
{
|
||||
F2 = new C1() { F1 = "taint" };
|
||||
Sink(GetF2F1()); // NEW: "taint" reaches here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Changes to autobuilder
|
||||
|
||||
@@ -4,26 +4,20 @@ The following changes in version 1.25 affect Java analysis in all applications.
|
||||
|
||||
## General improvements
|
||||
|
||||
The Java autobuilder has been improved to detect more Gradle Java versions.
|
||||
## New queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|-----------------------------|-----------|--------------------------------------------------------------------|
|
||||
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|------------------------------|------------------------|-----------------------------------|
|
||||
| Hard-coded credential in API call (`java/hardcoded-credential-api-call`) | More results | The query now recognizes the `BasicAWSCredentials` class of the Amazon client SDK library with hardcoded access key/secret key. |
|
||||
| Deserialization of user-controlled data (`java/unsafe-deserialization`) | Fewer false positive results | The query no longer reports results using `org.apache.commons.io.serialization.ValidatingObjectInputStream`. |
|
||||
| Use of a broken or risky cryptographic algorithm (`java/weak-cryptographic-algorithm`) | More results | The query now recognizes the `MessageDigest.getInstance` method. |
|
||||
| Use of a potentially broken or risky cryptographic algorithm (`java/potentially-weak-cryptographic-algorithm`) | More results | The query now recognizes the `MessageDigest.getInstance` method. |
|
||||
| Reading from a world writable file (`java/world-writable-file-read`) | More results | The query now recognizes more JDK file operations. |
|
||||
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
* The data-flow library has been improved with more taint flow modeling for the
|
||||
Collections framework and other classes of the JDK. This affects all security
|
||||
queries using data flow and can yield additional results.
|
||||
* The data-flow library has been improved with more taint flow modeling for the
|
||||
Spring framework. This affects all security queries using data flow and can
|
||||
yield additional results on project that rely on the Spring framework.
|
||||
* The data-flow library has been improved, which affects most security queries by potentially
|
||||
adding more results. Flow through methods now takes nested field reads/writes into account.
|
||||
For example, the library is able to track flow from `"taint"` to `sink()` via the method
|
||||
@@ -45,5 +39,3 @@ The Java autobuilder has been improved to detect more Gradle Java versions.
|
||||
}
|
||||
}
|
||||
```
|
||||
* The library has been extended with more support for Java 14 features
|
||||
(`switch` expressions and pattern-matching for `instanceof`).
|
||||
|
||||
@@ -6,34 +6,24 @@
|
||||
- [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
|
||||
- [bluebird](http://bluebirdjs.com/)
|
||||
- [express](https://www.npmjs.com/package/express)
|
||||
- [execa](https://www.npmjs.com/package/execa)
|
||||
- [fancy-log](https://www.npmjs.com/package/fancy-log)
|
||||
- [fastify](https://www.npmjs.com/package/fastify)
|
||||
- [foreground-child](https://www.npmjs.com/package/foreground-child)
|
||||
- [fstream](https://www.npmjs.com/package/fstream)
|
||||
- [jGrowl](https://github.com/stanlemon/jGrowl)
|
||||
- [jQuery](https://jquery.com/)
|
||||
- [marsdb](https://www.npmjs.com/package/marsdb)
|
||||
- [micro](https://www.npmjs.com/package/micro/)
|
||||
- [minimongo](https://www.npmjs.com/package/minimongo/)
|
||||
- [mssql](https://www.npmjs.com/package/mssql)
|
||||
- [mysql](https://www.npmjs.com/package/mysql)
|
||||
- [npmlog](https://www.npmjs.com/package/npmlog)
|
||||
- [opener](https://www.npmjs.com/package/opener)
|
||||
- [pg](https://www.npmjs.com/package/pg)
|
||||
- [sequelize](https://www.npmjs.com/package/sequelize)
|
||||
- [spanner](https://www.npmjs.com/package/spanner)
|
||||
- [sqlite](https://www.npmjs.com/package/sqlite)
|
||||
- [ssh2-streams](https://www.npmjs.com/package/ssh2-streams)
|
||||
- [ssh2](https://www.npmjs.com/package/ssh2)
|
||||
- [vue](https://www.npmjs.com/package/vue)
|
||||
- [yargs](https://www.npmjs.com/package/yargs)
|
||||
- [webpack-dev-server](https://www.npmjs.com/package/webpack-dev-server)
|
||||
|
||||
* TypeScript 3.9 is now supported.
|
||||
|
||||
* TypeScript code embedded in HTML and Vue files is now extracted and analyzed.
|
||||
|
||||
* The analysis of sanitizers has improved, leading to more accurate
|
||||
results from the security queries.
|
||||
|
||||
@@ -41,17 +31,10 @@
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|---------------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| DOM text reinterpreted as HTML (`js/xss-through-dom`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where existing text from the DOM is used as HTML. Results are shown on LGTM by default. |
|
||||
| Cross-site scripting through DOM (`js/xss-through-dom`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where existing text from the DOM is used as HTML. Results are not shown on LGTM by default. |
|
||||
| Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. |
|
||||
| Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. |
|
||||
| Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. |
|
||||
| Download of sensitive file through insecure connection (`js/insecure-download`) | security, external/cwe/cwe-829 | Highlights downloads of sensitive files through an unencrypted protocol. Results are shown on LGTM by default. |
|
||||
| Exposure of private files (`js/exposure-of-private-files`) | security, external/cwe/cwe-200 | Highlights servers that serve private files. Results are shown on LGTM by default. |
|
||||
| Creating biased random numbers from a cryptographically secure source (`js/biased-cryptographic-random`) | security, external/cwe/cwe-327 | Highlights mathematical operations on cryptographically secure numbers that can create biased results. Results are shown on LGTM by default. |
|
||||
| Storage of sensitive information in build artifact (`js/build-artifact-leak`) | security, external/cwe/cwe-312 | Highlights storage of sensitive information in build artifacts. Results are shown on LGTM by default. |
|
||||
| Improper code sanitization (`js/bad-code-sanitization`) | security, external/cwe/cwe-094, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights string concatenation where code is constructed without proper sanitization. Results are shown on LGTM by default. |
|
||||
| Disabling certificate validation (`js/disabling-certificate-validation`) | security, external/cwe-295 | Highlights locations where SSL certificate validation is disabled. Results are shown on LGTM by default. |
|
||||
| Incomplete multi-character sanitization (`js/incomplete-multi-character-sanitization`) | correctness, security, external/cwe/cwe-20, external/cwe/cwe-116 | Highlights sanitizers that fail to remove dangerous substrings completely. Results are shown on LGTM by default. |
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
@@ -60,19 +43,15 @@
|
||||
| Client-side cross-site scripting (`js/xss`) | Fewer results | This query now recognizes additional safe patterns of constructing HTML. |
|
||||
| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. |
|
||||
| Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. |
|
||||
| Exception text reinterpreted as HTML (`js/exception-xss`) | Rephrased and changed visibility | Rephrased name and alert message. Severity lowered from error to warning. Results are now shown on LGTM by default. |
|
||||
| Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. |
|
||||
| Hard-coded credentials (`js/hardcoded-credentials`) | More results | This query now recognizes hard-coded credentials sent via HTTP authorization headers. |
|
||||
| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. |
|
||||
| Insecure randomness (`js/insecure-randomness`) | Fewer results | This query now recognizes when an insecure random value is used as a fallback when secure random values are unsupported. |
|
||||
| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. |
|
||||
| Non-linear pattern (`js/non-linear-pattern`) | Fewer duplicates and message changed | This query now generates fewer duplicate alerts and has a clearer explanation in case of type annotations used in a pattern. |
|
||||
| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. |
|
||||
| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. |
|
||||
| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. |
|
||||
| Uncontrolled data used in path expression (`js/path-injection`) | Fewer results | This query no longer flags paths that have been checked to be part of a collection. |
|
||||
| Unknown directive (`js/unknown-directive`) | Fewer results | This query no longer flags directives generated by the Babel compiler. |
|
||||
| Unneeded defensive code (`js/unneeded-defensive-code`) | Fewer false-positive results | This query now recognizes checks meant to handle the `document.all` object. |
|
||||
| Unused property (`js/unused-property`) | Fewer results | This query no longer flags properties of objects that are operands of `yield` expressions. |
|
||||
| Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. |
|
||||
|
||||
@@ -108,4 +87,3 @@ The following low-precision queries are no longer run by default on LGTM (their
|
||||
- `ParameterNode.asExpr()` and `.getAstNode()` now gets the parameter's AST node, whereas previously it had no result.
|
||||
- `Expr.flow()` now has a more meaningful result for destructuring patterns. Previously this node was disconnected from the data flow graph. Now it represents the values being destructured by the pattern.
|
||||
* The global data-flow and taint-tracking libraries now model indirect parameter accesses through the `arguments` object in some cases, which may lead to additional results from some of the security queries, particularly "Prototype pollution in utility function".
|
||||
* The predicates `Type.getProperty()` and variants of `Type.getMethod()` have been deprecated due to lack of use-cases. Looking up a named property of a static type is no longer supported, favoring faster extraction times instead.
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
# Improvements to Python analysis
|
||||
|
||||
The following changes in version 1.25 affect Python analysis in all applications.
|
||||
|
||||
## General improvements
|
||||
|
||||
|
||||
## New queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|-----------------------------|-----------|--------------------------------------------------------------------|
|
||||
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|----------------------------|------------------------|------------------------------------------------------------------|
|
||||
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
* Importing `semmle.python.web.HttpRequest` will no longer import `UntrustedStringKind` transitively. `UntrustedStringKind` is the most commonly used non-abstract subclass of `ExternalStringKind`. If not imported (by one mean or another), taint-tracking queries that concern `ExternalStringKind` will not produce any results. Please ensure such queries contain an explicit import (`import semmle.python.security.strings.Untrusted`).
|
||||
* Added model of taint sources for HTTP servers using `http.server`.
|
||||
* Added taint modeling of routed parameters in Flask.
|
||||
* Improved modeling of built-in methods on strings for taint tracking.
|
||||
* Improved classification of test files.
|
||||
* New class `BoundMethodValue` represents a bound method during runtime.
|
||||
* The query `py/command-line-injection` now recognizes command execution with the `fabric` and `invoke` Python libraries.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"DataFlow Java/C++/C#/Python": [
|
||||
"DataFlow Java/C++/C#": [
|
||||
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll",
|
||||
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll",
|
||||
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll",
|
||||
@@ -18,18 +18,15 @@
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll",
|
||||
"python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll",
|
||||
"python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll"
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll"
|
||||
],
|
||||
"DataFlow Java/C++/C#/Python Common": [
|
||||
"DataFlow Java/C++/C# Common": [
|
||||
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll",
|
||||
"python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll"
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll"
|
||||
],
|
||||
"TaintTracking::Configuration Java/C++/C#/Python": [
|
||||
"TaintTracking::Configuration Java/C++/C#": [
|
||||
"cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
@@ -40,15 +37,13 @@
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll",
|
||||
"java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||
"python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
|
||||
"java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll"
|
||||
],
|
||||
"DataFlow Java/C++/C#/Python Consistency checks": [
|
||||
"DataFlow Java/C++/C# Consistency checks": [
|
||||
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll",
|
||||
"python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll"
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll"
|
||||
],
|
||||
"C++ SubBasicBlocks": [
|
||||
"cpp/ql/src/semmle/code/cpp/controlflow/SubBasicBlocks.qll",
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import re
|
||||
path = os.path
|
||||
|
||||
needs_an_re = re.compile(r'^(?!Unary)[AEIOU]') # Name requiring "an" instead of "a".
|
||||
start_qldoc_re = re.compile(r'^\s*/\*\*') # Start of a QLDoc comment
|
||||
end_qldoc_re = re.compile(r'\*/\s*$') # End of a QLDoc comment
|
||||
blank_qldoc_line_re = re.compile(r'^\s*\*\s*$') # A line in a QLDoc comment with only the '*'
|
||||
instruction_class_re = re.compile(r'^class (?P<name>[A-aa-z0-9]+)Instruction\s') # Declaration of an `Instruction` class
|
||||
opcode_base_class_re = re.compile(r'^abstract class (?P<name>[A-aa-z0-9]+)Opcode\s') # Declaration of an `Opcode` base class
|
||||
opcode_class_re = re.compile(r'^ class (?P<name>[A-aa-z0-9]+)\s') # Declaration of an `Opcode` class
|
||||
|
||||
script_dir = path.realpath(path.dirname(__file__))
|
||||
instruction_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll'))
|
||||
opcode_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll'))
|
||||
|
||||
# Scan `Instruction.qll`, keeping track of the QLDoc comment attached to each declaration of a class
|
||||
# whose name ends with `Instruction`.
|
||||
instruction_comments = {}
|
||||
in_qldoc = False
|
||||
saw_blank_line_in_qldoc = False
|
||||
qldoc_lines = []
|
||||
with open(instruction_path, 'r', encoding='utf-8') as instr:
|
||||
for line in instr:
|
||||
if in_qldoc:
|
||||
if end_qldoc_re.search(line):
|
||||
qldoc_lines.append(line)
|
||||
in_qldoc = False
|
||||
elif blank_qldoc_line_re.search(line):
|
||||
# We're going to skip any lines after the first blank line, to avoid duplicating all
|
||||
# of the verbose description.
|
||||
saw_blank_line_in_qldoc = True
|
||||
elif not saw_blank_line_in_qldoc:
|
||||
qldoc_lines.append(line)
|
||||
else:
|
||||
if start_qldoc_re.search(line):
|
||||
# Starting a new QLDoc comment.
|
||||
saw_blank_line_in_qldoc = False
|
||||
qldoc_lines.append(line)
|
||||
if not end_qldoc_re.search(line):
|
||||
in_qldoc = True
|
||||
else:
|
||||
instruction_match = instruction_class_re.search(line)
|
||||
if instruction_match:
|
||||
# Found the declaration of an `Instruction` class. Record the QLDoc comments.
|
||||
instruction_comments[instruction_match.group('name')] = qldoc_lines
|
||||
qldoc_lines = []
|
||||
|
||||
# Scan `Opcode.qll`. Whenever we see the declaration of an `Opcode` class for which we have a
|
||||
# corresponding `Instruction` class, we'll attach a copy of the `Instruction`'s QLDoc comment.
|
||||
in_qldoc = False
|
||||
qldoc_lines = []
|
||||
output_lines = []
|
||||
with open(opcode_path, 'r', encoding='utf-8') as opcode:
|
||||
for line in opcode:
|
||||
if in_qldoc:
|
||||
qldoc_lines.append(line)
|
||||
if end_qldoc_re.search(line):
|
||||
in_qldoc = False
|
||||
else:
|
||||
if start_qldoc_re.search(line):
|
||||
qldoc_lines.append(line)
|
||||
if not end_qldoc_re.search(line):
|
||||
in_qldoc = True
|
||||
else:
|
||||
name_without_suffix = None
|
||||
name = None
|
||||
indent = ''
|
||||
opcode_base_match = opcode_base_class_re.search(line)
|
||||
if opcode_base_match:
|
||||
name_without_suffix = opcode_base_match.group('name')
|
||||
name = name_without_suffix + 'Opcode'
|
||||
else:
|
||||
opcode_match = opcode_class_re.search(line)
|
||||
if opcode_match:
|
||||
name_without_suffix = opcode_match.group('name')
|
||||
name = name_without_suffix
|
||||
# Indent by two additional spaces, since opcodes are declared in the
|
||||
# `Opcode` module.
|
||||
indent = ' '
|
||||
|
||||
if name_without_suffix:
|
||||
# Found an `Opcode` that matches a known `Instruction`. Replace the QLDoc with
|
||||
# a copy of the one from the `Instruction`.
|
||||
if instruction_comments.get(name_without_suffix):
|
||||
article = 'an' if needs_an_re.search(name_without_suffix) else 'a'
|
||||
qldoc_lines = [
|
||||
indent + '/**\n',
|
||||
indent + ' * The `Opcode` for ' + article + ' `' + name_without_suffix + 'Instruction`.\n',
|
||||
indent + ' *\n',
|
||||
indent + ' * See the `' + name_without_suffix + 'Instruction` documentation for more details.\n',
|
||||
indent + ' */\n'
|
||||
]
|
||||
output_lines.extend(qldoc_lines)
|
||||
qldoc_lines = []
|
||||
output_lines.append(line)
|
||||
|
||||
# Write out the updated `Opcode.qll`
|
||||
with open(opcode_path, 'w', encoding='utf-8') as opcode:
|
||||
opcode.writelines(output_lines)
|
||||
13
cpp/autobuilder/.gitignore
vendored
13
cpp/autobuilder/.gitignore
vendored
@@ -1,13 +0,0 @@
|
||||
obj/
|
||||
TestResults/
|
||||
*.manifest
|
||||
*.pdb
|
||||
*.suo
|
||||
*.mdb
|
||||
*.vsmdi
|
||||
csharp.log
|
||||
**/bin/Debug
|
||||
**/bin/Release
|
||||
*.tlog
|
||||
.vs
|
||||
*.user
|
||||
@@ -1,296 +0,0 @@
|
||||
using Xunit;
|
||||
using Semmle.Autobuild.Shared;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.Build.Construction;
|
||||
using System.Xml;
|
||||
|
||||
namespace Semmle.Autobuild.Cpp.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Test class to script Autobuilder scenarios.
|
||||
/// For most methods, it uses two fields:
|
||||
/// - an IList to capture the the arguments passed to it
|
||||
/// - an IDictionary of possible return values.
|
||||
/// </summary>
|
||||
class TestActions : IBuildActions
|
||||
{
|
||||
/// <summary>
|
||||
/// List of strings passed to FileDelete.
|
||||
/// </summary>
|
||||
public IList<string> FileDeleteIn = new List<string>();
|
||||
|
||||
void IBuildActions.FileDelete(string file)
|
||||
{
|
||||
FileDeleteIn.Add(file);
|
||||
}
|
||||
|
||||
public IList<string> FileExistsIn = new List<string>();
|
||||
public IDictionary<string, bool> FileExists = new Dictionary<string, bool>();
|
||||
|
||||
bool IBuildActions.FileExists(string file)
|
||||
{
|
||||
FileExistsIn.Add(file);
|
||||
if (FileExists.TryGetValue(file, out var ret))
|
||||
return ret;
|
||||
if (FileExists.TryGetValue(System.IO.Path.GetFileName(file), out ret))
|
||||
return ret;
|
||||
throw new ArgumentException("Missing FileExists " + file);
|
||||
}
|
||||
|
||||
public IList<string> RunProcessIn = new List<string>();
|
||||
public IDictionary<string, int> RunProcess = new Dictionary<string, int>();
|
||||
public IDictionary<string, string> RunProcessOut = new Dictionary<string, string>();
|
||||
public IDictionary<string, string> RunProcessWorkingDirectory = new Dictionary<string, string>();
|
||||
|
||||
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env, out IList<string> stdOut)
|
||||
{
|
||||
var pattern = cmd + " " + args;
|
||||
RunProcessIn.Add(pattern);
|
||||
if (RunProcessOut.TryGetValue(pattern, out var str))
|
||||
stdOut = str.Split("\n");
|
||||
else
|
||||
throw new ArgumentException("Missing RunProcessOut " + pattern);
|
||||
RunProcessWorkingDirectory.TryGetValue(pattern, out var wd);
|
||||
if (wd != workingDirectory)
|
||||
throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern);
|
||||
if (RunProcess.TryGetValue(pattern, out var ret))
|
||||
return ret;
|
||||
throw new ArgumentException("Missing RunProcess " + pattern);
|
||||
}
|
||||
|
||||
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env)
|
||||
{
|
||||
var pattern = cmd + " " + args;
|
||||
RunProcessIn.Add(pattern);
|
||||
RunProcessWorkingDirectory.TryGetValue(pattern, out var wd);
|
||||
if (wd != workingDirectory)
|
||||
throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern);
|
||||
if (RunProcess.TryGetValue(pattern, out var ret))
|
||||
return ret;
|
||||
throw new ArgumentException("Missing RunProcess " + pattern);
|
||||
}
|
||||
|
||||
public IList<string> DirectoryDeleteIn = new List<string>();
|
||||
|
||||
void IBuildActions.DirectoryDelete(string dir, bool recursive)
|
||||
{
|
||||
DirectoryDeleteIn.Add(dir);
|
||||
}
|
||||
|
||||
public IDictionary<string, bool> DirectoryExists = new Dictionary<string, bool>();
|
||||
public IList<string> DirectoryExistsIn = new List<string>();
|
||||
|
||||
bool IBuildActions.DirectoryExists(string dir)
|
||||
{
|
||||
DirectoryExistsIn.Add(dir);
|
||||
if (DirectoryExists.TryGetValue(dir, out var ret))
|
||||
return ret;
|
||||
throw new ArgumentException("Missing DirectoryExists " + dir);
|
||||
}
|
||||
|
||||
public IDictionary<string, string?> GetEnvironmentVariable = new Dictionary<string, string?>();
|
||||
|
||||
string? IBuildActions.GetEnvironmentVariable(string name)
|
||||
{
|
||||
if (GetEnvironmentVariable.TryGetValue(name, out var ret))
|
||||
return ret;
|
||||
throw new ArgumentException("Missing GetEnvironmentVariable " + name);
|
||||
}
|
||||
|
||||
public string GetCurrentDirectory = "";
|
||||
|
||||
string IBuildActions.GetCurrentDirectory()
|
||||
{
|
||||
return GetCurrentDirectory;
|
||||
}
|
||||
|
||||
public IDictionary<string, string> EnumerateFiles = new Dictionary<string, string>();
|
||||
|
||||
IEnumerable<string> IBuildActions.EnumerateFiles(string dir)
|
||||
{
|
||||
if (EnumerateFiles.TryGetValue(dir, out var str))
|
||||
return str.Split("\n");
|
||||
throw new ArgumentException("Missing EnumerateFiles " + dir);
|
||||
}
|
||||
|
||||
public IDictionary<string, string> EnumerateDirectories = new Dictionary<string, string>();
|
||||
|
||||
IEnumerable<string> IBuildActions.EnumerateDirectories(string dir)
|
||||
{
|
||||
if (EnumerateDirectories.TryGetValue(dir, out var str))
|
||||
return string.IsNullOrEmpty(str) ? Enumerable.Empty<string>() : str.Split("\n");
|
||||
throw new ArgumentException("Missing EnumerateDirectories " + dir);
|
||||
}
|
||||
|
||||
public bool IsWindows;
|
||||
|
||||
bool IBuildActions.IsWindows() => IsWindows;
|
||||
|
||||
string IBuildActions.PathCombine(params string[] parts)
|
||||
{
|
||||
return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p)));
|
||||
}
|
||||
|
||||
string IBuildActions.GetFullPath(string path) => path;
|
||||
|
||||
void IBuildActions.WriteAllText(string filename, string contents)
|
||||
{
|
||||
}
|
||||
|
||||
public IDictionary<string, XmlDocument> LoadXml = new Dictionary<string, XmlDocument>();
|
||||
XmlDocument IBuildActions.LoadXml(string filename)
|
||||
{
|
||||
if (LoadXml.TryGetValue(filename, out var xml))
|
||||
return xml;
|
||||
throw new ArgumentException("Missing LoadXml " + filename);
|
||||
}
|
||||
|
||||
public string EnvironmentExpandEnvironmentVariables(string s)
|
||||
{
|
||||
foreach (var kvp in GetEnvironmentVariable)
|
||||
s = s.Replace($"%{kvp.Key}%", kvp.Value);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A fake solution to build.
|
||||
/// </summary>
|
||||
class TestSolution : ISolution
|
||||
{
|
||||
public IEnumerable<SolutionConfigurationInSolution> Configurations => throw new NotImplementedException();
|
||||
|
||||
public string DefaultConfigurationName => "Release";
|
||||
|
||||
public string DefaultPlatformName => "x86";
|
||||
|
||||
public string FullPath { get; set; }
|
||||
|
||||
public Version ToolsVersion => new Version("14.0");
|
||||
|
||||
public IEnumerable<IProjectOrSolution> IncludedProjects => throw new NotImplementedException();
|
||||
|
||||
public TestSolution(string path)
|
||||
{
|
||||
FullPath = path;
|
||||
}
|
||||
}
|
||||
|
||||
public class BuildScriptTests
|
||||
{
|
||||
TestActions Actions = new TestActions();
|
||||
|
||||
// Records the arguments passed to StartCallback.
|
||||
IList<string> StartCallbackIn = new List<string>();
|
||||
|
||||
void StartCallback(string s, bool silent)
|
||||
{
|
||||
StartCallbackIn.Add(s);
|
||||
}
|
||||
|
||||
// Records the arguments passed to EndCallback
|
||||
IList<string> EndCallbackIn = new List<string>();
|
||||
IList<int> EndCallbackReturn = new List<int>();
|
||||
|
||||
void EndCallback(int ret, string s, bool silent)
|
||||
{
|
||||
EndCallbackReturn.Add(ret);
|
||||
EndCallbackIn.Add(s);
|
||||
}
|
||||
|
||||
CppAutobuilder CreateAutoBuilder(bool isWindows,
|
||||
string? buildless = null, string? solution = null, string? buildCommand = null, string? ignoreErrors = null,
|
||||
string? msBuildArguments = null, string? msBuildPlatform = null, string? msBuildConfiguration = null, string? msBuildTarget = null,
|
||||
string? dotnetArguments = null, string? dotnetVersion = null, string? vsToolsVersion = null,
|
||||
string? nugetRestore = null, string? allSolutions = null,
|
||||
string cwd = @"C:\Project")
|
||||
{
|
||||
string codeqlUpperLanguage = Language.Cpp.UpperCaseName;
|
||||
Actions.GetEnvironmentVariable[$"CODEQL_AUTOBUILDER_{codeqlUpperLanguage}_NO_INDEXING"] = "false";
|
||||
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_TRAP_DIR"] = "";
|
||||
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = "";
|
||||
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{codeqlUpperLanguage.ToLowerInvariant()}";
|
||||
Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java";
|
||||
Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa";
|
||||
Actions.GetEnvironmentVariable["SEMMLE_JAVA_HOME"] = @"C:\odasa\tools\java";
|
||||
Actions.GetEnvironmentVariable["SEMMLE_PLATFORM_TOOLS"] = @"C:\odasa\tools";
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_VSTOOLS_VERSION"] = vsToolsVersion;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_ARGUMENTS"] = msBuildArguments;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_PLATFORM"] = msBuildPlatform;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_CONFIGURATION"] = msBuildConfiguration;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_TARGET"] = msBuildTarget;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_ARGUMENTS"] = dotnetArguments;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_VERSION"] = dotnetVersion;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_BUILD_COMMAND"] = buildCommand;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_SOLUTION"] = solution;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_IGNORE_ERRORS"] = ignoreErrors;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_BUILDLESS"] = buildless;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_ALL_SOLUTIONS"] = allSolutions;
|
||||
Actions.GetEnvironmentVariable["LGTM_INDEX_NUGET_RESTORE"] = nugetRestore;
|
||||
Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = isWindows ? @"C:\Program Files (x86)" : null;
|
||||
Actions.GetCurrentDirectory = cwd;
|
||||
Actions.IsWindows = isWindows;
|
||||
|
||||
var options = new AutobuildOptions(Actions, Language.Cpp);
|
||||
return new CppAutobuilder(Actions, options);
|
||||
}
|
||||
|
||||
void TestAutobuilderScript(Autobuilder autobuilder, int expectedOutput, int commandsRun)
|
||||
{
|
||||
Assert.Equal(expectedOutput, autobuilder.GetBuildScript().Run(Actions, StartCallback, EndCallback));
|
||||
|
||||
// Check expected commands actually ran
|
||||
Assert.Equal(commandsRun, StartCallbackIn.Count);
|
||||
Assert.Equal(commandsRun, EndCallbackIn.Count);
|
||||
Assert.Equal(commandsRun, EndCallbackReturn.Count);
|
||||
|
||||
var action = Actions.RunProcess.GetEnumerator();
|
||||
for (int cmd = 0; cmd < commandsRun; ++cmd)
|
||||
{
|
||||
Assert.True(action.MoveNext());
|
||||
|
||||
Assert.Equal(action.Current.Key, StartCallbackIn[cmd]);
|
||||
Assert.Equal(action.Current.Value, EndCallbackReturn[cmd]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void TestDefaultCppAutobuilder()
|
||||
{
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder(true);
|
||||
var script = autobuilder.GetBuildScript();
|
||||
|
||||
// Fails due to no solutions present.
|
||||
Assert.NotEqual(0, script.Run(Actions, StartCallback, EndCallback));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestCppAutobuilderSuccess()
|
||||
{
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test.sln"] = 1;
|
||||
Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && C:\odasa\tools\odasa index --auto msbuild C:\Project\test.sln /p:UseSharedCompilation=false /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"" /p:MvcBuildViews=true"] = 0;
|
||||
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "";
|
||||
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1;
|
||||
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0;
|
||||
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = "";
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = true;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = true;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true;
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.slx";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var autobuilder = CreateAutoBuilder(true);
|
||||
var solution = new TestSolution(@"C:\Project\test.sln");
|
||||
autobuilder.ProjectsOrSolutionsToBuild.Add(solution);
|
||||
TestAutobuilderScript(autobuilder, 0, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.FileSystem" Version="4.3.0" />
|
||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Autobuild.Cpp\Semmle.Autobuild.Cpp.csproj" />
|
||||
<ProjectReference Include="..\..\..\csharp\autobuilder\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,23 +0,0 @@
|
||||
using Semmle.Autobuild.Shared;
|
||||
|
||||
namespace Semmle.Autobuild.Cpp
|
||||
{
|
||||
public class CppAutobuilder : Autobuilder
|
||||
{
|
||||
public CppAutobuilder(IBuildActions actions, AutobuildOptions options) : base(actions, options) { }
|
||||
|
||||
public override BuildScript GetBuildScript()
|
||||
{
|
||||
if (Options.BuildCommand != null)
|
||||
return new BuildCommandRule((_, f) => f(null)).Analyse(this, false);
|
||||
|
||||
return
|
||||
// First try MSBuild
|
||||
new MsBuildRule().Analyse(this, true) |
|
||||
// Then look for a script that might be a build script
|
||||
(() => new BuildCommandAutoRule((_, f) => f(null)).Analyse(this, true)) |
|
||||
// All attempts failed: print message
|
||||
AutobuildFailure();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Autobuild.Cpp</AssemblyName>
|
||||
<RootNamespace>Semmle.Autobuild.Cpp</RootNamespace>
|
||||
<ApplicationIcon />
|
||||
<OutputType>Exe</OutputType>
|
||||
<StartupObject />
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build" Version="16.0.461" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\csharp\extractor\Semmle.Util\Semmle.Util.csproj" />
|
||||
<ProjectReference Include="..\..\..\csharp\autobuilder\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,3 +0,0 @@
|
||||
name: codeql-cpp-examples
|
||||
version: 0.0.0
|
||||
libraryPathDependencies: codeql-cpp
|
||||
@@ -15,15 +15,6 @@ import cpp
|
||||
import semmle.code.cpp.models.implementations.Strcpy
|
||||
import semmle.code.cpp.dataflow.DataFlow
|
||||
|
||||
/**
|
||||
* A string copy function that returns a string, rather than an error code (for
|
||||
* example, `strcpy` returns a string, whereas `strcpy_s` returns an error
|
||||
* code).
|
||||
*/
|
||||
class InterestingStrcpyFunction extends StrcpyFunction {
|
||||
InterestingStrcpyFunction() { getType().getUnspecifiedType() instanceof PointerType }
|
||||
}
|
||||
|
||||
predicate isBoolean(Expr e1) {
|
||||
exists(Type t1 |
|
||||
t1 = e1.getType() and
|
||||
@@ -34,12 +25,12 @@ predicate isBoolean(Expr e1) {
|
||||
predicate isStringCopyCastedAsBoolean(FunctionCall func, Expr expr1, string msg) {
|
||||
DataFlow::localExprFlow(func, expr1) and
|
||||
isBoolean(expr1.getConversion*()) and
|
||||
func.getTarget() instanceof InterestingStrcpyFunction and
|
||||
func.getTarget() instanceof StrcpyFunction and
|
||||
msg = "Return value of " + func.getTarget().getName() + " used as a Boolean."
|
||||
}
|
||||
|
||||
predicate isStringCopyUsedInLogicalOperationOrCondition(FunctionCall func, Expr expr1, string msg) {
|
||||
func.getTarget() instanceof InterestingStrcpyFunction and
|
||||
func.getTarget() instanceof StrcpyFunction and
|
||||
(
|
||||
(
|
||||
// it is being used in an equality or logical operation
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* or data representation problems.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @precision high
|
||||
* @precision medium
|
||||
* @id cpp/tainted-format-string
|
||||
* @tags reliability
|
||||
* security
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* or data representation problems.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @precision high
|
||||
* @precision medium
|
||||
* @id cpp/tainted-format-string-through-global
|
||||
* @tags reliability
|
||||
* security
|
||||
|
||||
@@ -18,7 +18,7 @@ abstract class InsecureCryptoSpec extends Locatable {
|
||||
}
|
||||
|
||||
Function getAnInsecureFunction() {
|
||||
result.getName().regexpMatch(getInsecureAlgorithmRegex()) and
|
||||
result.getName().regexpMatch(algorithmBlacklistRegex()) and
|
||||
exists(result.getACallToThisFunction())
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ class InsecureFunctionCall extends InsecureCryptoSpec, FunctionCall {
|
||||
}
|
||||
|
||||
Macro getAnInsecureMacro() {
|
||||
result.getName().regexpMatch(getInsecureAlgorithmRegex()) and
|
||||
result.getName().regexpMatch(algorithmBlacklistRegex()) and
|
||||
exists(result.getAnInvocation())
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,3 @@
|
||||
tags contain:
|
||||
- ide-contextual-queries/local-definitions
|
||||
- ide-contextual-queries/local-references
|
||||
- query: Metrics/Dependencies/ExternalDependencies.ql
|
||||
- query: Metrics/Dependencies/ExternalDependenciesSourceLinks.ql
|
||||
- query: Metrics/Files/FLinesOfCode.ql
|
||||
- query: Metrics/Files/FLinesOfCommentedOutCode.ql
|
||||
- query: Metrics/Files/FLinesOfComments.ql
|
||||
- query: Metrics/Files/FLinesOfDuplicatedCode.ql
|
||||
- query: Metrics/Files/FNumberOfTests.ql
|
||||
|
||||
@@ -20,7 +20,7 @@ import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
private import semmle.code.cpp.ir.internal.CppType
|
||||
private import semmle.code.cpp.models.interfaces.Allocation
|
||||
private import experimental.semmle.code.cpp.rangeanalysis.RangeUtils
|
||||
private import semmle.code.cpp.rangeanalysis.RangeUtils
|
||||
|
||||
private newtype TLength =
|
||||
TZeroLength() or
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
import cpp
|
||||
private import experimental.semmle.code.cpp.rangeanalysis.ArrayLengthAnalysis
|
||||
private import experimental.semmle.code.cpp.rangeanalysis.RangeAnalysis
|
||||
private import semmle.code.cpp.rangeanalysis.RangeAnalysis
|
||||
|
||||
/**
|
||||
* Gets the instruction that computes the address of memory that `i` accesses.
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* @name Print AST
|
||||
* @description Outputs a representation of a file's Abstract Syntax Tree. This
|
||||
* query is used by the VS Code extension.
|
||||
* @id cpp/print-ast
|
||||
* @kind graph
|
||||
* @tags ide-contextual-queries/print-ast
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.PrintAST
|
||||
import definitions
|
||||
|
||||
/**
|
||||
* The source file to generate an AST from.
|
||||
*/
|
||||
external string selectedSourceFile();
|
||||
|
||||
class Cfg extends PrintASTConfiguration {
|
||||
/**
|
||||
* Holds if the AST for `func` should be printed.
|
||||
* Print All functions from the selected file.
|
||||
*/
|
||||
override predicate shouldPrintFunction(Function func) {
|
||||
func.getFile() = getEncodedFile(selectedSourceFile())
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ private import semmle.code.cpp.internal.ResolveClass
|
||||
class Class extends UserType {
|
||||
Class() { isClass(underlyingElement(this)) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Class" }
|
||||
override string getCanonicalQLClass() { result = "Class" }
|
||||
|
||||
/** Gets a child declaration of this class, struct or union. */
|
||||
override Declaration getADeclaration() { result = this.getAMember() }
|
||||
@@ -768,7 +768,7 @@ class ClassDerivation extends Locatable, @derivation {
|
||||
*/
|
||||
Class getBaseClass() { result = getBaseType().getUnderlyingType() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ClassDerivation" }
|
||||
override string getCanonicalQLClass() { result = "ClassDerivation" }
|
||||
|
||||
/**
|
||||
* Gets the type from which we are deriving, without resolving any
|
||||
@@ -849,7 +849,9 @@ class ClassDerivation extends Locatable, @derivation {
|
||||
class LocalClass extends Class {
|
||||
LocalClass() { isLocal() }
|
||||
|
||||
override string getAPrimaryQlClass() { not this instanceof LocalStruct and result = "LocalClass" }
|
||||
override string getCanonicalQLClass() {
|
||||
not this instanceof LocalStruct and result = "LocalClass"
|
||||
}
|
||||
|
||||
override Function getEnclosingAccessHolder() { result = this.getEnclosingFunction() }
|
||||
}
|
||||
@@ -870,7 +872,7 @@ class LocalClass extends Class {
|
||||
class NestedClass extends Class {
|
||||
NestedClass() { this.isMember() }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
override string getCanonicalQLClass() {
|
||||
not this instanceof NestedStruct and result = "NestedClass"
|
||||
}
|
||||
|
||||
@@ -891,7 +893,7 @@ class NestedClass extends Class {
|
||||
class AbstractClass extends Class {
|
||||
AbstractClass() { exists(PureVirtualFunction f | this.getAMemberFunction() = f) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AbstractClass" }
|
||||
override string getCanonicalQLClass() { result = "AbstractClass" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,7 +934,7 @@ class TemplateClass extends Class {
|
||||
exists(result.getATemplateArgument())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TemplateClass" }
|
||||
override string getCanonicalQLClass() { result = "TemplateClass" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -953,7 +955,7 @@ class ClassTemplateInstantiation extends Class {
|
||||
|
||||
ClassTemplateInstantiation() { tc.getAnInstantiation() = this }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ClassTemplateInstantiation" }
|
||||
override string getCanonicalQLClass() { result = "ClassTemplateInstantiation" }
|
||||
|
||||
/**
|
||||
* Gets the class template from which this instantiation was instantiated.
|
||||
@@ -994,7 +996,7 @@ abstract class ClassTemplateSpecialization extends Class {
|
||||
count(int i | exists(result.getTemplateArgument(i)))
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ClassTemplateSpecialization" }
|
||||
override string getCanonicalQLClass() { result = "ClassTemplateSpecialization" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1023,7 +1025,7 @@ class FullClassTemplateSpecialization extends ClassTemplateSpecialization {
|
||||
not this instanceof ClassTemplateInstantiation
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FullClassTemplateSpecialization" }
|
||||
override string getCanonicalQLClass() { result = "FullClassTemplateSpecialization" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1062,7 +1064,7 @@ class PartialClassTemplateSpecialization extends ClassTemplateSpecialization {
|
||||
count(int i | exists(getTemplateArgument(i)))
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PartialClassTemplateSpecialization" }
|
||||
override string getCanonicalQLClass() { result = "PartialClassTemplateSpecialization" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1087,7 +1089,7 @@ deprecated class Interface extends Class {
|
||||
)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Interface" }
|
||||
override string getCanonicalQLClass() { result = "Interface" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1102,7 +1104,7 @@ deprecated class Interface extends Class {
|
||||
class VirtualClassDerivation extends ClassDerivation {
|
||||
VirtualClassDerivation() { hasSpecifier("virtual") }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VirtualClassDerivation" }
|
||||
override string getCanonicalQLClass() { result = "VirtualClassDerivation" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1122,7 +1124,7 @@ class VirtualClassDerivation extends ClassDerivation {
|
||||
class VirtualBaseClass extends Class {
|
||||
VirtualBaseClass() { exists(VirtualClassDerivation cd | cd.getBaseClass() = this) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VirtualBaseClass" }
|
||||
override string getCanonicalQLClass() { result = "VirtualBaseClass" }
|
||||
|
||||
/** A virtual class derivation of which this class/struct is the base. */
|
||||
VirtualClassDerivation getAVirtualDerivation() { result.getBaseClass() = this }
|
||||
@@ -1144,7 +1146,7 @@ class VirtualBaseClass extends Class {
|
||||
class ProxyClass extends UserType {
|
||||
ProxyClass() { usertypes(underlyingElement(this), _, 9) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ProxyClass" }
|
||||
override string getCanonicalQLClass() { result = "ProxyClass" }
|
||||
|
||||
/** Gets the location of the proxy class. */
|
||||
override Location getLocation() { result = getTemplateParameter().getDefinitionLocation() }
|
||||
|
||||
@@ -124,7 +124,7 @@ class Declaration extends Locatable, @declaration {
|
||||
* To test whether this declaration has a particular name in the global
|
||||
* namespace, use `hasGlobalName`.
|
||||
*/
|
||||
string getName() { none() } // overridden in subclasses
|
||||
abstract string getName();
|
||||
|
||||
/** Holds if this declaration has the given name. */
|
||||
predicate hasName(string name) { name = this.getName() }
|
||||
@@ -140,7 +140,7 @@ class Declaration extends Locatable, @declaration {
|
||||
}
|
||||
|
||||
/** Gets a specifier of this declaration. */
|
||||
Specifier getASpecifier() { none() } // overridden in subclasses
|
||||
abstract Specifier getASpecifier();
|
||||
|
||||
/** Holds if this declaration has a specifier with the given name. */
|
||||
predicate hasSpecifier(string name) { this.getASpecifier().hasName(name) }
|
||||
@@ -156,7 +156,7 @@ class Declaration extends Locatable, @declaration {
|
||||
* Gets the location of a declaration entry corresponding to this
|
||||
* declaration.
|
||||
*/
|
||||
Location getADeclarationLocation() { none() } // overridden in subclasses
|
||||
abstract Location getADeclarationLocation();
|
||||
|
||||
/**
|
||||
* Gets the declaration entry corresponding to this declaration that is a
|
||||
@@ -165,7 +165,7 @@ class Declaration extends Locatable, @declaration {
|
||||
DeclarationEntry getDefinition() { none() }
|
||||
|
||||
/** Gets the location of the definition, if any. */
|
||||
Location getDefinitionLocation() { none() } // overridden in subclasses
|
||||
abstract Location getDefinitionLocation();
|
||||
|
||||
/** Holds if the declaration has a definition. */
|
||||
predicate hasDefinition() { exists(this.getDefinition()) }
|
||||
@@ -289,8 +289,6 @@ class Declaration extends Locatable, @declaration {
|
||||
}
|
||||
}
|
||||
|
||||
private class TDeclarationEntry = @var_decl or @type_decl or @fun_decl;
|
||||
|
||||
/**
|
||||
* A C/C++ declaration entry. For example the following code contains five
|
||||
* declaration entries:
|
||||
@@ -306,9 +304,9 @@ private class TDeclarationEntry = @var_decl or @type_decl or @fun_decl;
|
||||
* See the comment above `Declaration` for an explanation of the relationship
|
||||
* between `Declaration` and `DeclarationEntry`.
|
||||
*/
|
||||
class DeclarationEntry extends Locatable, TDeclarationEntry {
|
||||
abstract class DeclarationEntry extends Locatable {
|
||||
/** Gets a specifier associated with this declaration entry. */
|
||||
string getASpecifier() { none() } // overridden in subclasses
|
||||
abstract string getASpecifier();
|
||||
|
||||
/**
|
||||
* Gets the name associated with the corresponding definition (where
|
||||
@@ -331,10 +329,10 @@ class DeclarationEntry extends Locatable, TDeclarationEntry {
|
||||
* `I.getADeclarationEntry()` returns `D`
|
||||
* but `D.getDeclaration()` only returns `C`
|
||||
*/
|
||||
Declaration getDeclaration() { none() } // overridden in subclasses
|
||||
abstract Declaration getDeclaration();
|
||||
|
||||
/** Gets the name associated with this declaration entry, if any. */
|
||||
string getName() { none() } // overridden in subclasses
|
||||
abstract string getName();
|
||||
|
||||
/**
|
||||
* Gets the type associated with this declaration entry.
|
||||
@@ -343,7 +341,7 @@ class DeclarationEntry extends Locatable, TDeclarationEntry {
|
||||
* For function declarations, get the return type of the function.
|
||||
* For type declarations, get the type being declared.
|
||||
*/
|
||||
Type getType() { none() } // overridden in subclasses
|
||||
abstract Type getType();
|
||||
|
||||
/**
|
||||
* Gets the type associated with this declaration entry after specifiers
|
||||
@@ -361,7 +359,7 @@ class DeclarationEntry extends Locatable, TDeclarationEntry {
|
||||
predicate hasSpecifier(string specifier) { getASpecifier() = specifier }
|
||||
|
||||
/** Holds if this declaration entry is a definition. */
|
||||
predicate isDefinition() { none() } // overridden in subclasses
|
||||
abstract predicate isDefinition();
|
||||
|
||||
override string toString() {
|
||||
if isDefinition()
|
||||
@@ -373,8 +371,6 @@ class DeclarationEntry extends Locatable, TDeclarationEntry {
|
||||
}
|
||||
}
|
||||
|
||||
private class TAccessHolder = @function or @usertype;
|
||||
|
||||
/**
|
||||
* A declaration that can potentially have more C++ access rights than its
|
||||
* enclosing element. This comprises `Class` (they have access to their own
|
||||
@@ -396,7 +392,7 @@ private class TAccessHolder = @function or @usertype;
|
||||
* the informal phrase "_R_ occurs in a member or friend of class C", where
|
||||
* `AccessHolder` corresponds to this _R_.
|
||||
*/
|
||||
class AccessHolder extends Declaration, TAccessHolder {
|
||||
abstract class AccessHolder extends Declaration {
|
||||
/**
|
||||
* Holds if `this` can access private members of class `c`.
|
||||
*
|
||||
@@ -414,7 +410,7 @@ class AccessHolder extends Declaration, TAccessHolder {
|
||||
/**
|
||||
* Gets the nearest enclosing `AccessHolder`.
|
||||
*/
|
||||
AccessHolder getEnclosingAccessHolder() { none() } // overridden in subclasses
|
||||
abstract AccessHolder getEnclosingAccessHolder();
|
||||
|
||||
/**
|
||||
* Holds if a base class `base` of `derived` _is accessible at_ `this` (N4140
|
||||
|
||||
@@ -55,21 +55,12 @@ class ElementBase extends @element {
|
||||
cached
|
||||
string toString() { none() }
|
||||
|
||||
/** DEPRECATED: use `getAPrimaryQlClass` instead. */
|
||||
deprecated string getCanonicalQLClass() { result = this.getAPrimaryQlClass() }
|
||||
|
||||
/**
|
||||
* Gets the name of a primary CodeQL class to which this element belongs.
|
||||
* Canonical QL class corresponding to this element.
|
||||
*
|
||||
* For most elements, this is simply the most precise syntactic category to
|
||||
* which they belong; for example, `AddExpr` is a primary class, but
|
||||
* `BinaryOperation` is not.
|
||||
*
|
||||
* This predicate always has a result. If no primary class can be
|
||||
* determined, the result is `"???"`. If multiple primary classes match,
|
||||
* this predicate can have multiple results.
|
||||
* ElementBase is the root class for this predicate.
|
||||
*/
|
||||
string getAPrimaryQlClass() { result = "???" }
|
||||
string getCanonicalQLClass() { result = "???" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,8 +188,7 @@ class Element extends ElementBase {
|
||||
initialisers(underlyingElement(this), unresolveElement(result), _, _) or
|
||||
exprconv(unresolveElement(result), underlyingElement(this)) or
|
||||
param_decl_bind(underlyingElement(this), _, unresolveElement(result)) or
|
||||
using_container(unresolveElement(result), underlyingElement(this)) or
|
||||
static_asserts(unresolveElement(this), _, _, _, underlyingElement(result))
|
||||
using_container(unresolveElement(result), underlyingElement(this))
|
||||
}
|
||||
|
||||
/** Gets the closest `Element` enclosing this one. */
|
||||
@@ -279,12 +269,12 @@ class StaticAssert extends Locatable, @static_assert {
|
||||
/**
|
||||
* Gets the expression which this static assertion ensures is true.
|
||||
*/
|
||||
Expr getCondition() { static_asserts(underlyingElement(this), unresolveElement(result), _, _, _) }
|
||||
Expr getCondition() { static_asserts(underlyingElement(this), unresolveElement(result), _, _) }
|
||||
|
||||
/**
|
||||
* Gets the message which will be reported by the compiler if this static assertion fails.
|
||||
*/
|
||||
string getMessage() { static_asserts(underlyingElement(this), _, result, _, _) }
|
||||
string getMessage() { static_asserts(underlyingElement(this), _, result, _) }
|
||||
|
||||
override Location getLocation() { static_asserts(underlyingElement(this), _, _, result, _) }
|
||||
override Location getLocation() { static_asserts(underlyingElement(this), _, _, result) }
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class Enum extends UserType, IntegralOrEnumType {
|
||||
enumconstants(unresolveElement(result), underlyingElement(this), index, _, _, _)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Enum" }
|
||||
override string getCanonicalQLClass() { result = "Enum" }
|
||||
|
||||
/**
|
||||
* Gets a descriptive string for the enum. This method is only intended to
|
||||
@@ -87,7 +87,7 @@ class Enum extends UserType, IntegralOrEnumType {
|
||||
class LocalEnum extends Enum {
|
||||
LocalEnum() { isLocal() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LocalEnum" }
|
||||
override string getCanonicalQLClass() { result = "LocalEnum" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,7 +105,7 @@ class LocalEnum extends Enum {
|
||||
class NestedEnum extends Enum {
|
||||
NestedEnum() { this.isMember() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NestedEnum" }
|
||||
override string getCanonicalQLClass() { result = "NestedEnum" }
|
||||
|
||||
/** Holds if this member is private. */
|
||||
predicate isPrivate() { this.hasSpecifier("private") }
|
||||
@@ -130,7 +130,7 @@ class NestedEnum extends Enum {
|
||||
class ScopedEnum extends Enum {
|
||||
ScopedEnum() { usertypes(underlyingElement(this), _, 13) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ScopedEnum" }
|
||||
override string getCanonicalQLClass() { result = "ScopedEnum" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,7 +153,7 @@ class EnumConstant extends Declaration, @enumconstant {
|
||||
enumconstants(underlyingElement(this), unresolveElement(result), _, _, _, _)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "EnumConstant" }
|
||||
override string getCanonicalQLClass() { result = "EnumConstant" }
|
||||
|
||||
override Class getDeclaringType() { result = this.getDeclaringEnum().getDeclaringType() }
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import semmle.code.cpp.exprs.Access
|
||||
class Field extends MemberVariable {
|
||||
Field() { fieldoffsets(underlyingElement(this), _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Field" }
|
||||
override string getCanonicalQLClass() { result = "Field" }
|
||||
|
||||
/**
|
||||
* Gets the offset of this field in bytes from the start of its declaring
|
||||
@@ -90,7 +90,7 @@ class Field extends MemberVariable {
|
||||
class BitField extends Field {
|
||||
BitField() { bitfield(underlyingElement(this), _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BitField" }
|
||||
override string getCanonicalQLClass() { result = "BitField" }
|
||||
|
||||
/**
|
||||
* Gets the size of this bitfield in bits (on the machine where facts
|
||||
|
||||
@@ -178,7 +178,7 @@ class Folder extends Container, @folder {
|
||||
result.hasLocationInfo(_, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Folder" }
|
||||
override string getCanonicalQLClass() { result = "Folder" }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getLocation` instead.
|
||||
@@ -246,7 +246,7 @@ class File extends Container, @file {
|
||||
|
||||
override string toString() { result = Container.super.toString() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "File" }
|
||||
override string getCanonicalQLClass() { result = "File" }
|
||||
|
||||
override Location getLocation() {
|
||||
result.getContainer() = this and
|
||||
@@ -382,7 +382,7 @@ class HeaderFile extends File {
|
||||
exists(Include i | i.getIncludedFile() = this)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "HeaderFile" }
|
||||
override string getCanonicalQLClass() { result = "HeaderFile" }
|
||||
|
||||
/**
|
||||
* Holds if this header file does not contain any declaration entries or top level
|
||||
@@ -408,7 +408,7 @@ class HeaderFile extends File {
|
||||
class CFile extends File {
|
||||
CFile() { exists(string ext | ext = this.getExtension().toLowerCase() | ext = "c" or ext = "i") }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CFile" }
|
||||
override string getCanonicalQLClass() { result = "CFile" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -436,7 +436,7 @@ class CppFile extends File {
|
||||
)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CppFile" }
|
||||
override string getCanonicalQLClass() { result = "CppFile" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,7 +27,7 @@ class FriendDecl extends Declaration, @frienddecl {
|
||||
*/
|
||||
override Location getADeclarationLocation() { result = this.getLocation() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FriendDecl" }
|
||||
override string getCanonicalQLClass() { result = "FriendDecl" }
|
||||
|
||||
/**
|
||||
* Implements the abstract method `Declaration.getDefinitionLocation`. A
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Location
|
||||
import semmle.code.cpp.Member
|
||||
import semmle.code.cpp.Class
|
||||
import semmle.code.cpp.Parameter
|
||||
import semmle.code.cpp.exprs.Call
|
||||
@@ -513,7 +514,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
|
||||
/** Gets the function which is being declared or defined. */
|
||||
override Function getDeclaration() { result = getFunction() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FunctionDeclarationEntry" }
|
||||
override string getCanonicalQLClass() { result = "FunctionDeclarationEntry" }
|
||||
|
||||
/** Gets the function which is being declared or defined. */
|
||||
Function getFunction() { fun_decls(underlyingElement(this), unresolveElement(result), _, _, _) }
|
||||
@@ -698,7 +699,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
|
||||
class TopLevelFunction extends Function {
|
||||
TopLevelFunction() { not this.isMember() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TopLevelFunction" }
|
||||
override string getCanonicalQLClass() { result = "TopLevelFunction" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -707,7 +708,7 @@ class TopLevelFunction extends Function {
|
||||
class Operator extends Function {
|
||||
Operator() { functions(underlyingElement(this), _, 5) }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
override string getCanonicalQLClass() {
|
||||
not this instanceof MemberFunction and result = "Operator"
|
||||
}
|
||||
}
|
||||
@@ -738,7 +739,7 @@ class TemplateFunction extends Function {
|
||||
is_function_template(underlyingElement(this)) and exists(getATemplateArgument())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TemplateFunction" }
|
||||
override string getCanonicalQLClass() { result = "TemplateFunction" }
|
||||
|
||||
/**
|
||||
* Gets a compiler-generated instantiation of this function template.
|
||||
@@ -778,7 +779,7 @@ class FunctionTemplateInstantiation extends Function {
|
||||
|
||||
FunctionTemplateInstantiation() { tf.getAnInstantiation() = this }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FunctionTemplateInstantiation" }
|
||||
override string getCanonicalQLClass() { result = "FunctionTemplateInstantiation" }
|
||||
|
||||
/**
|
||||
* Gets the function template from which this instantiation was instantiated.
|
||||
@@ -823,7 +824,7 @@ class FunctionTemplateInstantiation extends Function {
|
||||
class FunctionTemplateSpecialization extends Function {
|
||||
FunctionTemplateSpecialization() { this.isSpecialization() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FunctionTemplateSpecialization" }
|
||||
override string getCanonicalQLClass() { result = "FunctionTemplateSpecialization" }
|
||||
|
||||
/**
|
||||
* Gets the primary template for the specialization (the function template
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* Provides the `Initializer` class, representing C/C++ declaration initializers.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.controlflow.ControlFlowGraph
|
||||
|
||||
/**
|
||||
@@ -22,7 +18,7 @@ import semmle.code.cpp.controlflow.ControlFlowGraph
|
||||
class Initializer extends ControlFlowNode, @initialiser {
|
||||
override Location getLocation() { initialisers(underlyingElement(this), _, _, result) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Initializer" }
|
||||
override string getCanonicalQLClass() { result = "Initializer" }
|
||||
|
||||
/** Holds if this initializer is explicit in the source. */
|
||||
override predicate fromSource() { not this.getLocation() instanceof UnknownLocation }
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* Provides classes for loop iteration variables.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Variable
|
||||
|
||||
/**
|
||||
@@ -11,18 +7,14 @@ import semmle.code.cpp.Variable
|
||||
class LoopCounter extends Variable {
|
||||
LoopCounter() { exists(ForStmt f | f.getAnIterationVariable() = this) }
|
||||
|
||||
/**
|
||||
* Gets an access of this variable within loop `f`.
|
||||
*/
|
||||
// Gets an access of this variable within loop `f`.
|
||||
VariableAccess getVariableAccessInLoop(ForStmt f) {
|
||||
this.getALoop() = f and
|
||||
result.getEnclosingStmt().getParent*() = f and
|
||||
this = result.getTarget()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a loop which uses this variable as its counter.
|
||||
*/
|
||||
// Gets a loop which uses this variable as its counter.
|
||||
ForStmt getALoop() { result.getAnIterationVariable() = this }
|
||||
}
|
||||
|
||||
@@ -33,18 +25,14 @@ class LoopCounter extends Variable {
|
||||
class LoopControlVariable extends Variable {
|
||||
LoopControlVariable() { this = loopControlVariable(_) }
|
||||
|
||||
/**
|
||||
* Gets an access of this variable within loop `f`.
|
||||
*/
|
||||
// Gets an access of this variable within loop `f`.
|
||||
VariableAccess getVariableAccessInLoop(ForStmt f) {
|
||||
this.getALoop() = f and
|
||||
result.getEnclosingStmt().getParent*() = f and
|
||||
this = result.getTarget()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a loop which uses this variable as its control variable.
|
||||
*/
|
||||
// Gets a loop which uses this variable as its control variable.
|
||||
ForStmt getALoop() { this = loopControlVariable(result) }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* Proivdes the `LinkTarget` class representing linker invocations during the build process.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Class
|
||||
import semmle.code.cpp.File
|
||||
import semmle.code.cpp.Function
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* Provides classes and predicates for locations in the source code.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Element
|
||||
import semmle.code.cpp.File
|
||||
|
||||
@@ -15,16 +11,16 @@ class Location extends @location {
|
||||
/** Gets the file corresponding to this location, if any. */
|
||||
File getFile() { result = this.getContainer() }
|
||||
|
||||
/** Gets the 1-based line number (inclusive) where this location starts. */
|
||||
/** Gets the start line of this location. */
|
||||
int getStartLine() { this.fullLocationInfo(_, result, _, _, _) }
|
||||
|
||||
/** Gets the 1-based column number (inclusive) where this location starts. */
|
||||
/** Gets the start column of this location. */
|
||||
int getStartColumn() { this.fullLocationInfo(_, _, result, _, _) }
|
||||
|
||||
/** Gets the 1-based line number (inclusive) where this location ends. */
|
||||
/** Gets the end line of this location. */
|
||||
int getEndLine() { this.fullLocationInfo(_, _, _, result, _) }
|
||||
|
||||
/** Gets the 1-based column number (inclusive) where this location ends. */
|
||||
/** Gets the end column of this location. */
|
||||
int getEndColumn() { this.fullLocationInfo(_, _, _, _, result) }
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,7 @@ class Macro extends PreprocessorDirective, @ppd_define {
|
||||
*/
|
||||
override string getHead() { preproctext(underlyingElement(this), result, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Macro" }
|
||||
override string getCanonicalQLClass() { result = "Macro" }
|
||||
|
||||
/**
|
||||
* Gets the body of this macro. For example, `(((x)>(y))?(x):(y))` in
|
||||
@@ -74,7 +74,7 @@ class MacroAccess extends Locatable, @macroinvocation {
|
||||
*/
|
||||
override Location getLocation() { result = this.getOutermostMacroAccess().getActualLocation() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "MacroAccess" }
|
||||
override string getCanonicalQLClass() { result = "MacroAccess" }
|
||||
|
||||
/**
|
||||
* Gets the location of this macro access. For a nested access, where
|
||||
@@ -147,7 +147,7 @@ class MacroAccess extends Locatable, @macroinvocation {
|
||||
class MacroInvocation extends MacroAccess {
|
||||
MacroInvocation() { macroinvocations(underlyingElement(this), _, _, 1) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "MacroInvocation" }
|
||||
override string getCanonicalQLClass() { result = "MacroInvocation" }
|
||||
|
||||
/**
|
||||
* Gets an element that occurs in this macro invocation or a nested macro
|
||||
@@ -179,11 +179,6 @@ class MacroInvocation extends MacroAccess {
|
||||
result.(Stmt).getGeneratingMacro() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a function that includes an expression that is affected by this macro
|
||||
* invocation. If the macro expansion includes the end of one function and
|
||||
* the beginning of another, this predicate will get both.
|
||||
*/
|
||||
Function getEnclosingFunction() {
|
||||
result = this.getAnAffectedElement().(Expr).getEnclosingFunction()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,2 @@
|
||||
/**
|
||||
* DEPRECATED: import `semmle.code.cpp.Element` and/or `semmle.code.cpp.Type` directly as required.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Element
|
||||
import semmle.code.cpp.Type
|
||||
|
||||
@@ -25,7 +25,7 @@ import cpp
|
||||
class MemberFunction extends Function {
|
||||
MemberFunction() { this.isMember() }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
override string getCanonicalQLClass() {
|
||||
not this instanceof CopyAssignmentOperator and
|
||||
not this instanceof MoveAssignmentOperator and
|
||||
result = "MemberFunction"
|
||||
@@ -70,14 +70,6 @@ class MemberFunction extends Function {
|
||||
result = getADeclarationEntry() and result != getDefinition()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the `this` parameter associated with this member function, if any. The type
|
||||
* may have `const` and/or `volatile` qualifiers, matching the function declaration.
|
||||
*/
|
||||
PointerType getTypeOfThis() {
|
||||
member_function_this_type(underlyingElement(this), unresolveElement(result))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,7 +93,7 @@ class MemberFunction extends Function {
|
||||
class VirtualFunction extends MemberFunction {
|
||||
VirtualFunction() { this.hasSpecifier("virtual") or purefunctions(underlyingElement(this)) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VirtualFunction" }
|
||||
override string getCanonicalQLClass() { result = "VirtualFunction" }
|
||||
|
||||
/** Holds if this virtual function is pure. */
|
||||
predicate isPure() { this instanceof PureVirtualFunction }
|
||||
@@ -133,7 +125,7 @@ class VirtualFunction extends MemberFunction {
|
||||
class PureVirtualFunction extends VirtualFunction {
|
||||
PureVirtualFunction() { purefunctions(underlyingElement(this)) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PureVirtualFunction" }
|
||||
override string getCanonicalQLClass() { result = "PureVirtualFunction" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,7 +147,7 @@ class PureVirtualFunction extends VirtualFunction {
|
||||
class ConstMemberFunction extends MemberFunction {
|
||||
ConstMemberFunction() { this.hasSpecifier("const") }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConstMemberFunction" }
|
||||
override string getCanonicalQLClass() { result = "ConstMemberFunction" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,7 +165,7 @@ class ConstMemberFunction extends MemberFunction {
|
||||
class Constructor extends MemberFunction {
|
||||
Constructor() { functions(underlyingElement(this), _, 2) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Constructor" }
|
||||
override string getCanonicalQLClass() { result = "Constructor" }
|
||||
|
||||
/**
|
||||
* Holds if this constructor serves as a default constructor.
|
||||
@@ -232,7 +224,7 @@ class ConversionConstructor extends Constructor, ImplicitConversionFunction {
|
||||
not this instanceof CopyConstructor
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
override string getCanonicalQLClass() {
|
||||
not this instanceof MoveConstructor and result = "ConversionConstructor"
|
||||
}
|
||||
|
||||
@@ -290,7 +282,7 @@ class CopyConstructor extends Constructor {
|
||||
not exists(getATemplateArgument())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CopyConstructor" }
|
||||
override string getCanonicalQLClass() { result = "CopyConstructor" }
|
||||
|
||||
/**
|
||||
* Holds if we cannot determine that this constructor will become a copy
|
||||
@@ -347,7 +339,7 @@ class MoveConstructor extends Constructor {
|
||||
not exists(getATemplateArgument())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "MoveConstructor" }
|
||||
override string getCanonicalQLClass() { result = "MoveConstructor" }
|
||||
|
||||
/**
|
||||
* Holds if we cannot determine that this constructor will become a move
|
||||
@@ -398,7 +390,7 @@ class NoArgConstructor extends Constructor {
|
||||
class Destructor extends MemberFunction {
|
||||
Destructor() { functions(underlyingElement(this), _, 3) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Destructor" }
|
||||
override string getCanonicalQLClass() { result = "Destructor" }
|
||||
|
||||
/**
|
||||
* Gets a compiler-generated action which destructs a base class or member
|
||||
@@ -429,7 +421,7 @@ class Destructor extends MemberFunction {
|
||||
class ConversionOperator extends MemberFunction, ImplicitConversionFunction {
|
||||
ConversionOperator() { functions(underlyingElement(this), _, 4) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConversionOperator" }
|
||||
override string getCanonicalQLClass() { result = "ConversionOperator" }
|
||||
|
||||
override Type getSourceType() { result = this.getDeclaringType() }
|
||||
|
||||
@@ -465,7 +457,7 @@ class CopyAssignmentOperator extends Operator {
|
||||
not exists(getATemplateArgument())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CopyAssignmentOperator" }
|
||||
override string getCanonicalQLClass() { result = "CopyAssignmentOperator" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -491,5 +483,5 @@ class MoveAssignmentOperator extends Operator {
|
||||
not exists(getATemplateArgument())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "MoveAssignmentOperator" }
|
||||
override string getCanonicalQLClass() { result = "MoveAssignmentOperator" }
|
||||
}
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
/**
|
||||
* Provides classes for working with name qualifiers such as the `N::` in
|
||||
* `N::f()`.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* Provides classes for modeling namespaces, `using` directives and `using` declarations.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Element
|
||||
import semmle.code.cpp.Type
|
||||
import semmle.code.cpp.metrics.MetricNamespace
|
||||
@@ -131,7 +127,7 @@ class NamespaceDeclarationEntry extends Locatable, @namespace_decl {
|
||||
*/
|
||||
Location getBodyLocation() { namespace_decls(underlyingElement(this), _, _, result) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NamespaceDeclarationEntry" }
|
||||
override string getCanonicalQLClass() { result = "NamespaceDeclarationEntry" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
/**
|
||||
* Provides a class for reasoning about nested field accesses, for example
|
||||
* the access `myLine.start.x`.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
@@ -30,7 +25,7 @@ private Expr getUltimateQualifier(FieldAccess fa) {
|
||||
}
|
||||
|
||||
/**
|
||||
* A nested field access, for example the access `myLine.start.x`.
|
||||
* Accesses to nested fields.
|
||||
*/
|
||||
class NestedFieldAccess extends FieldAccess {
|
||||
Expr ultimateQualifier;
|
||||
@@ -40,30 +35,6 @@ class NestedFieldAccess extends FieldAccess {
|
||||
getTarget() = getANestedField(ultimateQualifier.getType().stripType())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the outermost qualifier of this nested field access. In the
|
||||
* following example, the access to `myLine.start.x` has outermost qualifier
|
||||
* `myLine`:
|
||||
* ```
|
||||
* struct Point
|
||||
* {
|
||||
* float x, y;
|
||||
* };
|
||||
*
|
||||
* struct Line
|
||||
* {
|
||||
* Point start, end;
|
||||
* };
|
||||
*
|
||||
* void init()
|
||||
* {
|
||||
* Line myLine;
|
||||
*
|
||||
* myLine.start.x = 0.0f;
|
||||
*
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
/** Gets the ultimate qualifier of this nested field access. */
|
||||
Expr getUltimateQualifier() { result = ultimateQualifier }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Class
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* Provides a class that models parameters to functions.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Location
|
||||
import semmle.code.cpp.Declaration
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
@@ -49,7 +45,7 @@ class Parameter extends LocalScopeVariable, @parameter {
|
||||
result = "p#" + this.getIndex().toString()
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Parameter" }
|
||||
override string getCanonicalQLClass() { result = "Parameter" }
|
||||
|
||||
/**
|
||||
* Gets the name of this parameter, including it's type.
|
||||
|
||||
@@ -33,13 +33,11 @@ class PreprocessorDirective extends Locatable, @preprocdirect {
|
||||
}
|
||||
}
|
||||
|
||||
private class TPreprocessorBranchDirective = @ppd_branch or @ppd_else or @ppd_endif;
|
||||
|
||||
/**
|
||||
* A C/C++ preprocessor branch related directive: `#if`, `#ifdef`,
|
||||
* `#ifndef`, `#elif`, `#else` or `#endif`.
|
||||
*/
|
||||
class PreprocessorBranchDirective extends PreprocessorDirective, TPreprocessorBranchDirective {
|
||||
abstract class PreprocessorBranchDirective extends PreprocessorDirective {
|
||||
/**
|
||||
* Gets the `#if`, `#ifdef` or `#ifndef` directive which matches this
|
||||
* branching directive.
|
||||
@@ -154,7 +152,7 @@ class PreprocessorIf extends PreprocessorBranch, @ppd_if {
|
||||
class PreprocessorIfdef extends PreprocessorBranch, @ppd_ifdef {
|
||||
override string toString() { result = "#ifdef " + this.getHead() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PreprocessorIfdef" }
|
||||
override string getCanonicalQLClass() { result = "PreprocessorIfdef" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
/**
|
||||
* Provides queries to pretty-print a C++ AST as a graph.
|
||||
*
|
||||
* By default, this will print the AST for all functions in the database. To change this behavior,
|
||||
* extend `PrintASTConfiguration` and override `shouldPrintFunction` to hold for only the functions
|
||||
* you wish to view the AST for.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
private import semmle.code.cpp.Print
|
||||
|
||||
@@ -15,9 +7,6 @@ private newtype TPrintASTConfiguration = MkPrintASTConfiguration()
|
||||
* The query can extend this class to control which functions are printed.
|
||||
*/
|
||||
class PrintASTConfiguration extends TPrintASTConfiguration {
|
||||
/**
|
||||
* Gets a textual representation of this `PrintASTConfiguration`.
|
||||
*/
|
||||
string toString() { result = "PrintASTConfiguration" }
|
||||
|
||||
/**
|
||||
@@ -107,9 +96,6 @@ private newtype TPrintASTNode =
|
||||
* A node in the output tree.
|
||||
*/
|
||||
class PrintASTNode extends TPrintASTNode {
|
||||
/**
|
||||
* Gets a textual representation of this node in the PrintAST output tree.
|
||||
*/
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
@@ -169,7 +155,7 @@ class PrintASTNode extends TPrintASTNode {
|
||||
* Retrieves the canonical QL class(es) for entity `el`
|
||||
*/
|
||||
private string qlClass(ElementBase el) {
|
||||
result = "[" + concat(el.getAPrimaryQlClass(), ",") + "] "
|
||||
result = "[" + concat(el.getCanonicalQLClass(), ",") + "] "
|
||||
// Alternative implementation -- do not delete. It is useful for QL class discovery.
|
||||
//result = "["+ concat(el.getAQlClass(), ",") + "] "
|
||||
}
|
||||
@@ -222,9 +208,6 @@ class ExprNode extends ASTNode {
|
||||
result = expr.getValueCategoryString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of this expression, if it is a constant.
|
||||
*/
|
||||
string getValue() { result = expr.getValue() }
|
||||
}
|
||||
|
||||
@@ -390,9 +373,6 @@ class ParametersNode extends PrintASTNode, TParametersNode {
|
||||
|
||||
override ASTNode getChild(int childIndex) { result.getAST() = func.getParameter(childIndex) }
|
||||
|
||||
/**
|
||||
* Gets the `Function` for which this node represents the parameters.
|
||||
*/
|
||||
final Function getFunction() { result = func }
|
||||
}
|
||||
|
||||
@@ -412,9 +392,6 @@ class ConstructorInitializersNode extends PrintASTNode, TConstructorInitializers
|
||||
result.getAST() = ctor.getInitializer(childIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Constructor` for which this node represents the initializer list.
|
||||
*/
|
||||
final Constructor getConstructor() { result = ctor }
|
||||
}
|
||||
|
||||
@@ -434,9 +411,6 @@ class DestructorDestructionsNode extends PrintASTNode, TDestructorDestructionsNo
|
||||
result.getAST() = dtor.getDestruction(childIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Destructor` for which this node represents the destruction list.
|
||||
*/
|
||||
final Destructor getDestructor() { result = dtor }
|
||||
}
|
||||
|
||||
@@ -490,9 +464,6 @@ class FunctionNode extends ASTNode {
|
||||
key = "semmle.order" and result = getOrder().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Function` this node represents.
|
||||
*/
|
||||
final Function getFunction() { result = func }
|
||||
}
|
||||
|
||||
@@ -528,16 +499,11 @@ class ArrayAggregateLiteralNode extends ExprNode {
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */
|
||||
query predicate nodes(PrintASTNode node, string key, string value) {
|
||||
node.shouldPrint() and
|
||||
value = node.getProperty(key)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `target` is a child of `source` in the AST, and property `key` of the edge has the
|
||||
* given `value`.
|
||||
*/
|
||||
query predicate edges(PrintASTNode source, PrintASTNode target, string key, string value) {
|
||||
exists(int childIndex |
|
||||
source.shouldPrint() and
|
||||
@@ -551,7 +517,6 @@ query predicate edges(PrintASTNode source, PrintASTNode target, string key, stri
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if property `key` of the graph has the given `value`. */
|
||||
query predicate graphProperties(string key, string value) {
|
||||
key = "semmle.graphKind" and value = "tree"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* Provides classes for modeling specifiers and attributes.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Element
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
@@ -16,7 +12,7 @@ class Specifier extends Element, @specifier {
|
||||
result instanceof UnknownDefaultLocation
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Specifier" }
|
||||
override string getCanonicalQLClass() { result = "Specifier" }
|
||||
|
||||
/** Gets the name of this specifier. */
|
||||
string getName() { specifiers(underlyingElement(this), result) }
|
||||
@@ -37,7 +33,7 @@ class FunctionSpecifier extends Specifier {
|
||||
this.hasName("explicit")
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FunctionSpecifier)" }
|
||||
override string getCanonicalQLClass() { result = "FunctionSpecifier)" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,7 +49,7 @@ class StorageClassSpecifier extends Specifier {
|
||||
this.hasName("mutable")
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "StorageClassSpecifier" }
|
||||
override string getCanonicalQLClass() { result = "StorageClassSpecifier" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,7 +104,7 @@ class AccessSpecifier extends Specifier {
|
||||
)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AccessSpecifier" }
|
||||
override string getCanonicalQLClass() { result = "AccessSpecifier" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,7 +234,7 @@ class FormatAttribute extends GnuAttribute {
|
||||
)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FormatAttribute" }
|
||||
override string getCanonicalQLClass() { result = "FormatAttribute" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* Provides classes for modeling `struct`s.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Type
|
||||
import semmle.code.cpp.Class
|
||||
|
||||
@@ -22,7 +18,7 @@ import semmle.code.cpp.Class
|
||||
class Struct extends Class {
|
||||
Struct() { usertypes(underlyingElement(this), _, 1) or usertypes(underlyingElement(this), _, 3) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Struct" }
|
||||
override string getCanonicalQLClass() { result = "Struct" }
|
||||
|
||||
override string explain() { result = "struct " + this.getName() }
|
||||
|
||||
@@ -43,7 +39,9 @@ class Struct extends Class {
|
||||
class LocalStruct extends Struct {
|
||||
LocalStruct() { isLocal() }
|
||||
|
||||
override string getAPrimaryQlClass() { not this instanceof LocalUnion and result = "LocalStruct" }
|
||||
override string getCanonicalQLClass() {
|
||||
not this instanceof LocalUnion and result = "LocalStruct"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,7 +58,7 @@ class LocalStruct extends Struct {
|
||||
class NestedStruct extends Struct {
|
||||
NestedStruct() { this.isMember() }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
override string getCanonicalQLClass() {
|
||||
not this instanceof NestedUnion and result = "NestedStruct"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
/**
|
||||
* Provides classes for identifying files that contain test cases. It is often
|
||||
* desirable to exclude these files from analysis.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.File
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
/**
|
||||
* Provides a hierarchy of classes for modeling C/C++ types.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Element
|
||||
import semmle.code.cpp.Member
|
||||
import semmle.code.cpp.Function
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
@@ -325,7 +322,7 @@ class BuiltInType extends Type, @builtintype {
|
||||
class ErroneousType extends BuiltInType {
|
||||
ErroneousType() { builtintypes(underlyingElement(this), _, 1, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ErroneousType" }
|
||||
override string getCanonicalQLClass() { result = "ErroneousType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -345,7 +342,7 @@ class ErroneousType extends BuiltInType {
|
||||
class UnknownType extends BuiltInType {
|
||||
UnknownType() { builtintypes(underlyingElement(this), _, 2, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "UnknownType" }
|
||||
override string getCanonicalQLClass() { result = "UnknownType" }
|
||||
}
|
||||
|
||||
private predicate isArithmeticType(@builtintype type, int kind) {
|
||||
@@ -364,7 +361,7 @@ private predicate isArithmeticType(@builtintype type, int kind) {
|
||||
class ArithmeticType extends BuiltInType {
|
||||
ArithmeticType() { isArithmeticType(underlyingElement(this), _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ArithmeticType" }
|
||||
override string getCanonicalQLClass() { result = "ArithmeticType" }
|
||||
}
|
||||
|
||||
private predicate isIntegralType(@builtintype type, int kind) {
|
||||
@@ -564,7 +561,7 @@ class IntegralType extends ArithmeticType, IntegralOrEnumType {
|
||||
class BoolType extends IntegralType {
|
||||
BoolType() { builtintypes(underlyingElement(this), _, 4, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BoolType" }
|
||||
override string getCanonicalQLClass() { result = "BoolType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -589,7 +586,7 @@ abstract class CharType extends IntegralType { }
|
||||
class PlainCharType extends CharType {
|
||||
PlainCharType() { builtintypes(underlyingElement(this), _, 5, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PlainCharType" }
|
||||
override string getCanonicalQLClass() { result = "PlainCharType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -602,7 +599,7 @@ class PlainCharType extends CharType {
|
||||
class UnsignedCharType extends CharType {
|
||||
UnsignedCharType() { builtintypes(underlyingElement(this), _, 6, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "UnsignedCharType" }
|
||||
override string getCanonicalQLClass() { result = "UnsignedCharType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -615,7 +612,7 @@ class UnsignedCharType extends CharType {
|
||||
class SignedCharType extends CharType {
|
||||
SignedCharType() { builtintypes(underlyingElement(this), _, 7, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SignedCharType" }
|
||||
override string getCanonicalQLClass() { result = "SignedCharType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -632,7 +629,7 @@ class ShortType extends IntegralType {
|
||||
builtintypes(underlyingElement(this), _, 10, _, _, _)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ShortType" }
|
||||
override string getCanonicalQLClass() { result = "ShortType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -649,7 +646,7 @@ class IntType extends IntegralType {
|
||||
builtintypes(underlyingElement(this), _, 13, _, _, _)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "IntType" }
|
||||
override string getCanonicalQLClass() { result = "IntType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -666,7 +663,7 @@ class LongType extends IntegralType {
|
||||
builtintypes(underlyingElement(this), _, 16, _, _, _)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LongType" }
|
||||
override string getCanonicalQLClass() { result = "LongType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -683,7 +680,7 @@ class LongLongType extends IntegralType {
|
||||
builtintypes(underlyingElement(this), _, 19, _, _, _)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LongLongType" }
|
||||
override string getCanonicalQLClass() { result = "LongLongType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -701,7 +698,7 @@ class Int128Type extends IntegralType {
|
||||
builtintypes(underlyingElement(this), _, 37, _, _, _)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Int128Type" }
|
||||
override string getCanonicalQLClass() { result = "Int128Type" }
|
||||
}
|
||||
|
||||
private newtype TTypeDomain =
|
||||
@@ -897,7 +894,7 @@ class DecimalFloatingPointType extends FloatingPointType {
|
||||
class FloatType extends RealNumberType, BinaryFloatingPointType {
|
||||
FloatType() { builtintypes(underlyingElement(this), _, 24, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FloatType" }
|
||||
override string getCanonicalQLClass() { result = "FloatType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -909,7 +906,7 @@ class FloatType extends RealNumberType, BinaryFloatingPointType {
|
||||
class DoubleType extends RealNumberType, BinaryFloatingPointType {
|
||||
DoubleType() { builtintypes(underlyingElement(this), _, 25, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DoubleType" }
|
||||
override string getCanonicalQLClass() { result = "DoubleType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -921,7 +918,7 @@ class DoubleType extends RealNumberType, BinaryFloatingPointType {
|
||||
class LongDoubleType extends RealNumberType, BinaryFloatingPointType {
|
||||
LongDoubleType() { builtintypes(underlyingElement(this), _, 26, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LongDoubleType" }
|
||||
override string getCanonicalQLClass() { result = "LongDoubleType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -933,7 +930,7 @@ class LongDoubleType extends RealNumberType, BinaryFloatingPointType {
|
||||
class Float128Type extends RealNumberType, BinaryFloatingPointType {
|
||||
Float128Type() { builtintypes(underlyingElement(this), _, 38, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Float128Type" }
|
||||
override string getCanonicalQLClass() { result = "Float128Type" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -945,7 +942,7 @@ class Float128Type extends RealNumberType, BinaryFloatingPointType {
|
||||
class Decimal32Type extends RealNumberType, DecimalFloatingPointType {
|
||||
Decimal32Type() { builtintypes(underlyingElement(this), _, 40, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Decimal32Type" }
|
||||
override string getCanonicalQLClass() { result = "Decimal32Type" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -957,7 +954,7 @@ class Decimal32Type extends RealNumberType, DecimalFloatingPointType {
|
||||
class Decimal64Type extends RealNumberType, DecimalFloatingPointType {
|
||||
Decimal64Type() { builtintypes(underlyingElement(this), _, 41, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Decimal64Type" }
|
||||
override string getCanonicalQLClass() { result = "Decimal64Type" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -969,7 +966,7 @@ class Decimal64Type extends RealNumberType, DecimalFloatingPointType {
|
||||
class Decimal128Type extends RealNumberType, DecimalFloatingPointType {
|
||||
Decimal128Type() { builtintypes(underlyingElement(this), _, 42, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Decimal128Type" }
|
||||
override string getCanonicalQLClass() { result = "Decimal128Type" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -981,7 +978,7 @@ class Decimal128Type extends RealNumberType, DecimalFloatingPointType {
|
||||
class VoidType extends BuiltInType {
|
||||
VoidType() { builtintypes(underlyingElement(this), _, 3, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VoidType" }
|
||||
override string getCanonicalQLClass() { result = "VoidType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -997,7 +994,7 @@ class VoidType extends BuiltInType {
|
||||
class WideCharType extends IntegralType {
|
||||
WideCharType() { builtintypes(underlyingElement(this), _, 33, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "WideCharType" }
|
||||
override string getCanonicalQLClass() { result = "WideCharType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1009,7 +1006,7 @@ class WideCharType extends IntegralType {
|
||||
class Char8Type extends IntegralType {
|
||||
Char8Type() { builtintypes(underlyingElement(this), _, 51, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Char8Type" }
|
||||
override string getCanonicalQLClass() { result = "Char8Type" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1021,7 +1018,7 @@ class Char8Type extends IntegralType {
|
||||
class Char16Type extends IntegralType {
|
||||
Char16Type() { builtintypes(underlyingElement(this), _, 43, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Char16Type" }
|
||||
override string getCanonicalQLClass() { result = "Char16Type" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1033,7 +1030,7 @@ class Char16Type extends IntegralType {
|
||||
class Char32Type extends IntegralType {
|
||||
Char32Type() { builtintypes(underlyingElement(this), _, 44, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Char32Type" }
|
||||
override string getCanonicalQLClass() { result = "Char32Type" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1048,7 +1045,7 @@ class Char32Type extends IntegralType {
|
||||
class NullPointerType extends BuiltInType {
|
||||
NullPointerType() { builtintypes(underlyingElement(this), _, 34, _, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NullPointerType" }
|
||||
override string getCanonicalQLClass() { result = "NullPointerType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1083,46 +1080,22 @@ class DerivedType extends Type, @derivedtype {
|
||||
|
||||
override Type stripType() { result = getBaseType().stripType() }
|
||||
|
||||
/**
|
||||
* Holds if this type has the `__autoreleasing` specifier or if it points to
|
||||
* a type with the `__autoreleasing` specifier.
|
||||
*
|
||||
* DEPRECATED: use `hasSpecifier` directly instead.
|
||||
*/
|
||||
deprecated predicate isAutoReleasing() {
|
||||
predicate isAutoReleasing() {
|
||||
this.hasSpecifier("__autoreleasing") or
|
||||
this.(PointerType).getBaseType().hasSpecifier("__autoreleasing")
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this type has the `__strong` specifier or if it points to
|
||||
* a type with the `__strong` specifier.
|
||||
*
|
||||
* DEPRECATED: use `hasSpecifier` directly instead.
|
||||
*/
|
||||
deprecated predicate isStrong() {
|
||||
predicate isStrong() {
|
||||
this.hasSpecifier("__strong") or
|
||||
this.(PointerType).getBaseType().hasSpecifier("__strong")
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this type has the `__unsafe_unretained` specifier or if it points
|
||||
* to a type with the `__unsafe_unretained` specifier.
|
||||
*
|
||||
* DEPRECATED: use `hasSpecifier` directly instead.
|
||||
*/
|
||||
deprecated predicate isUnsafeRetained() {
|
||||
predicate isUnsafeRetained() {
|
||||
this.hasSpecifier("__unsafe_unretained") or
|
||||
this.(PointerType).getBaseType().hasSpecifier("__unsafe_unretained")
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this type has the `__weak` specifier or if it points to
|
||||
* a type with the `__weak` specifier.
|
||||
*
|
||||
* DEPRECATED: use `hasSpecifier` directly instead.
|
||||
*/
|
||||
deprecated predicate isWeak() {
|
||||
predicate isWeak() {
|
||||
this.hasSpecifier("__weak") or
|
||||
this.(PointerType).getBaseType().hasSpecifier("__weak")
|
||||
}
|
||||
@@ -1136,7 +1109,7 @@ class DerivedType extends Type, @derivedtype {
|
||||
* ```
|
||||
*/
|
||||
class Decltype extends Type, @decltype {
|
||||
override string getAPrimaryQlClass() { result = "Decltype" }
|
||||
override string getCanonicalQLClass() { result = "Decltype" }
|
||||
|
||||
/**
|
||||
* The expression whose type is being obtained by this decltype.
|
||||
@@ -1209,7 +1182,7 @@ class Decltype extends Type, @decltype {
|
||||
class PointerType extends DerivedType {
|
||||
PointerType() { derivedtypes(underlyingElement(this), _, 1, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PointerType" }
|
||||
override string getCanonicalQLClass() { result = "PointerType" }
|
||||
|
||||
override int getPointerIndirectionLevel() {
|
||||
result = 1 + this.getBaseType().getPointerIndirectionLevel()
|
||||
@@ -1235,7 +1208,7 @@ class ReferenceType extends DerivedType {
|
||||
derivedtypes(underlyingElement(this), _, 2, _) or derivedtypes(underlyingElement(this), _, 8, _)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ReferenceType" }
|
||||
override string getCanonicalQLClass() { result = "ReferenceType" }
|
||||
|
||||
override int getPointerIndirectionLevel() { result = getBaseType().getPointerIndirectionLevel() }
|
||||
|
||||
@@ -1262,7 +1235,7 @@ class ReferenceType extends DerivedType {
|
||||
class LValueReferenceType extends ReferenceType {
|
||||
LValueReferenceType() { derivedtypes(underlyingElement(this), _, 2, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LValueReferenceType" }
|
||||
override string getCanonicalQLClass() { result = "LValueReferenceType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1278,7 +1251,7 @@ class LValueReferenceType extends ReferenceType {
|
||||
class RValueReferenceType extends ReferenceType {
|
||||
RValueReferenceType() { derivedtypes(underlyingElement(this), _, 8, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RValueReferenceType" }
|
||||
override string getCanonicalQLClass() { result = "RValueReferenceType" }
|
||||
|
||||
override string explain() { result = "rvalue " + super.explain() }
|
||||
}
|
||||
@@ -1293,7 +1266,7 @@ class RValueReferenceType extends ReferenceType {
|
||||
class SpecifiedType extends DerivedType {
|
||||
SpecifiedType() { derivedtypes(underlyingElement(this), _, 3, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SpecifiedType" }
|
||||
override string getCanonicalQLClass() { result = "SpecifiedType" }
|
||||
|
||||
override int getSize() { result = this.getBaseType().getSize() }
|
||||
|
||||
@@ -1341,12 +1314,8 @@ class SpecifiedType extends DerivedType {
|
||||
class ArrayType extends DerivedType {
|
||||
ArrayType() { derivedtypes(underlyingElement(this), _, 4, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ArrayType" }
|
||||
override string getCanonicalQLClass() { result = "ArrayType" }
|
||||
|
||||
/**
|
||||
* Holds if this array is declared to be of a constant size. See
|
||||
* `getArraySize` and `getByteSize` to get the size of the array.
|
||||
*/
|
||||
predicate hasArraySize() { arraysizes(underlyingElement(this), _, _, _) }
|
||||
|
||||
/**
|
||||
@@ -1412,7 +1381,7 @@ class GNUVectorType extends DerivedType {
|
||||
*/
|
||||
int getNumElements() { arraysizes(underlyingElement(this), result, _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "GNUVectorType" }
|
||||
override string getCanonicalQLClass() { result = "GNUVectorType" }
|
||||
|
||||
/**
|
||||
* Gets the size, in bytes, of this vector type.
|
||||
@@ -1443,7 +1412,7 @@ class GNUVectorType extends DerivedType {
|
||||
class FunctionPointerType extends FunctionPointerIshType {
|
||||
FunctionPointerType() { derivedtypes(underlyingElement(this), _, 6, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FunctionPointerType" }
|
||||
override string getCanonicalQLClass() { result = "FunctionPointerType" }
|
||||
|
||||
override int getPointerIndirectionLevel() { result = 1 }
|
||||
|
||||
@@ -1461,7 +1430,7 @@ class FunctionPointerType extends FunctionPointerIshType {
|
||||
class FunctionReferenceType extends FunctionPointerIshType {
|
||||
FunctionReferenceType() { derivedtypes(underlyingElement(this), _, 7, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FunctionReferenceType" }
|
||||
override string getCanonicalQLClass() { result = "FunctionReferenceType" }
|
||||
|
||||
override int getPointerIndirectionLevel() { result = getBaseType().getPointerIndirectionLevel() }
|
||||
|
||||
@@ -1550,7 +1519,7 @@ class PointerToMemberType extends Type, @ptrtomember {
|
||||
/** a printable representation of this named element */
|
||||
override string toString() { result = this.getName() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PointerToMemberType" }
|
||||
override string getCanonicalQLClass() { result = "PointerToMemberType" }
|
||||
|
||||
/** the name of this type */
|
||||
override string getName() { result = "..:: *" }
|
||||
@@ -1595,25 +1564,16 @@ class RoutineType extends Type, @routinetype {
|
||||
/** a printable representation of this named element */
|
||||
override string toString() { result = this.getName() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RoutineType" }
|
||||
override string getCanonicalQLClass() { result = "RoutineType" }
|
||||
|
||||
override string getName() { result = "..()(..)" }
|
||||
|
||||
/**
|
||||
* Gets the type of the `n`th parameter to this routine.
|
||||
*/
|
||||
Type getParameterType(int n) {
|
||||
routinetypeargs(underlyingElement(this), n, unresolveElement(result))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of a parameter to this routine.
|
||||
*/
|
||||
Type getAParameterType() { routinetypeargs(underlyingElement(this), _, unresolveElement(result)) }
|
||||
|
||||
/**
|
||||
* Gets the return type of this routine.
|
||||
*/
|
||||
Type getReturnType() { routinetypes(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
override string explain() {
|
||||
@@ -1672,7 +1632,7 @@ class TemplateParameter extends UserType {
|
||||
usertypes(underlyingElement(this), _, 7) or usertypes(underlyingElement(this), _, 8)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TemplateParameter" }
|
||||
override string getCanonicalQLClass() { result = "TemplateParameter" }
|
||||
|
||||
override predicate involvesTemplateParameter() { any() }
|
||||
}
|
||||
@@ -1690,7 +1650,7 @@ class TemplateParameter extends UserType {
|
||||
class TemplateTemplateParameter extends TemplateParameter {
|
||||
TemplateTemplateParameter() { usertypes(underlyingElement(this), _, 8) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TemplateTemplateParameter" }
|
||||
override string getCanonicalQLClass() { result = "TemplateTemplateParameter" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1702,7 +1662,7 @@ class TemplateTemplateParameter extends TemplateParameter {
|
||||
class AutoType extends TemplateParameter {
|
||||
AutoType() { usertypes(underlyingElement(this), "auto", 7) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AutoType" }
|
||||
override string getCanonicalQLClass() { result = "AutoType" }
|
||||
|
||||
override Location getLocation() {
|
||||
suppressUnusedThis(this) and
|
||||
@@ -1738,7 +1698,7 @@ private predicate suppressUnusedThis(Type t) { any() }
|
||||
class TypeMention extends Locatable, @type_mention {
|
||||
override string toString() { result = "type mention" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TypeMention" }
|
||||
override string getCanonicalQLClass() { result = "TypeMention" }
|
||||
|
||||
/**
|
||||
* Gets the type being referenced by this type mention.
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* Provides classes for modeling typedefs and type aliases.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Type
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
@@ -59,7 +55,7 @@ class TypedefType extends UserType {
|
||||
class CTypedefType extends TypedefType {
|
||||
CTypedefType() { usertypes(underlyingElement(this), _, 5) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CTypedefType" }
|
||||
override string getCanonicalQLClass() { result = "CTypedefType" }
|
||||
|
||||
override string explain() {
|
||||
result = "typedef {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\""
|
||||
@@ -75,7 +71,7 @@ class CTypedefType extends TypedefType {
|
||||
class UsingAliasTypedefType extends TypedefType {
|
||||
UsingAliasTypedefType() { usertypes(underlyingElement(this), _, 14) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "UsingAliasTypedefType" }
|
||||
override string getCanonicalQLClass() { result = "UsingAliasTypedefType" }
|
||||
|
||||
override string explain() {
|
||||
result = "using {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\""
|
||||
@@ -92,7 +88,7 @@ class UsingAliasTypedefType extends TypedefType {
|
||||
class LocalTypedefType extends TypedefType {
|
||||
LocalTypedefType() { isLocal() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LocalTypedefType" }
|
||||
override string getCanonicalQLClass() { result = "LocalTypedefType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,7 +101,7 @@ class LocalTypedefType extends TypedefType {
|
||||
class NestedTypedefType extends TypedefType {
|
||||
NestedTypedefType() { this.isMember() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NestedTypedefType" }
|
||||
override string getCanonicalQLClass() { result = "NestedTypedefType" }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `.hasSpecifier("private")` instead.
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* Provides classes for modeling `union`s.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Type
|
||||
import semmle.code.cpp.Struct
|
||||
|
||||
@@ -17,7 +13,7 @@ import semmle.code.cpp.Struct
|
||||
class Union extends Struct {
|
||||
Union() { usertypes(underlyingElement(this), _, 3) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Union" }
|
||||
override string getCanonicalQLClass() { result = "Union" }
|
||||
|
||||
override string explain() { result = "union " + this.getName() }
|
||||
|
||||
@@ -39,7 +35,7 @@ class Union extends Struct {
|
||||
class LocalUnion extends Union {
|
||||
LocalUnion() { isLocal() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LocalUnion" }
|
||||
override string getCanonicalQLClass() { result = "LocalUnion" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,7 +53,7 @@ class LocalUnion extends Union {
|
||||
class NestedUnion extends Union {
|
||||
NestedUnion() { this.isMember() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NestedUnion" }
|
||||
override string getCanonicalQLClass() { result = "NestedUnion" }
|
||||
|
||||
/** Holds if this member is private. */
|
||||
predicate isPrivate() { this.hasSpecifier("private") }
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
/**
|
||||
* Provides classes for modeling user-defined types such as classes, typedefs
|
||||
* and enums.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Declaration
|
||||
import semmle.code.cpp.Type
|
||||
import semmle.code.cpp.Member
|
||||
import semmle.code.cpp.Function
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
@@ -24,7 +20,7 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @
|
||||
*/
|
||||
override string getName() { usertypes(underlyingElement(this), result, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "UserType" }
|
||||
override string getCanonicalQLClass() { result = "UserType" }
|
||||
|
||||
/**
|
||||
* Gets the simple name of this type, without any template parameters. For example
|
||||
@@ -88,9 +84,6 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @
|
||||
* type exactly - but this is not apparent from its subclasses
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets a child declaration within this user-defined type.
|
||||
*/
|
||||
Declaration getADeclaration() { none() }
|
||||
|
||||
override string explain() { result = this.getName() }
|
||||
@@ -111,7 +104,7 @@ class TypeDeclarationEntry extends DeclarationEntry, @type_decl {
|
||||
|
||||
override string getName() { result = getType().getName() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TypeDeclarationEntry" }
|
||||
override string getCanonicalQLClass() { result = "TypeDeclarationEntry" }
|
||||
|
||||
/**
|
||||
* The type which is being declared or defined.
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* Provides classes for modeling variables and their declarations.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Element
|
||||
import semmle.code.cpp.exprs.Access
|
||||
import semmle.code.cpp.Initializer
|
||||
@@ -32,7 +28,7 @@ private import semmle.code.cpp.internal.ResolveClass
|
||||
* can have multiple declarations.
|
||||
*/
|
||||
class Variable extends Declaration, @variable {
|
||||
override string getAPrimaryQlClass() { result = "Variable" }
|
||||
override string getCanonicalQLClass() { result = "Variable" }
|
||||
|
||||
/** Gets the initializer of this variable, if any. */
|
||||
Initializer getInitializer() { result.getDeclaration() = this }
|
||||
@@ -190,7 +186,7 @@ class Variable extends Declaration, @variable {
|
||||
class VariableDeclarationEntry extends DeclarationEntry, @var_decl {
|
||||
override Variable getDeclaration() { result = getVariable() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VariableDeclarationEntry" }
|
||||
override string getCanonicalQLClass() { result = "VariableDeclarationEntry" }
|
||||
|
||||
/**
|
||||
* Gets the variable which is being declared or defined.
|
||||
@@ -249,7 +245,7 @@ class VariableDeclarationEntry extends DeclarationEntry, @var_decl {
|
||||
class ParameterDeclarationEntry extends VariableDeclarationEntry {
|
||||
ParameterDeclarationEntry() { param_decl_bind(underlyingElement(this), _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ParameterDeclarationEntry" }
|
||||
override string getCanonicalQLClass() { result = "ParameterDeclarationEntry" }
|
||||
|
||||
/**
|
||||
* Gets the function declaration or definition which this parameter
|
||||
@@ -325,7 +321,7 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry {
|
||||
*/
|
||||
class LocalScopeVariable extends Variable, @localscopevariable {
|
||||
/** Gets the function to which this variable belongs. */
|
||||
Function getFunction() { none() } // overridden in subclasses
|
||||
/*abstract*/ Function getFunction() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -363,7 +359,7 @@ class StackVariable extends LocalScopeVariable {
|
||||
* A local variable can be declared by a `DeclStmt` or a `ConditionDeclExpr`.
|
||||
*/
|
||||
class LocalVariable extends LocalScopeVariable, @localvariable {
|
||||
override string getAPrimaryQlClass() { result = "LocalVariable" }
|
||||
override string getCanonicalQLClass() { result = "LocalVariable" }
|
||||
|
||||
override string getName() { localvariables(underlyingElement(this), _, result) }
|
||||
|
||||
@@ -464,7 +460,7 @@ class NamespaceVariable extends GlobalOrNamespaceVariable {
|
||||
exists(Namespace n | namespacembrs(unresolveElement(n), underlyingElement(this)))
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NamespaceVariable" }
|
||||
override string getCanonicalQLClass() { result = "NamespaceVariable" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -485,7 +481,7 @@ class NamespaceVariable extends GlobalOrNamespaceVariable {
|
||||
class GlobalVariable extends GlobalOrNamespaceVariable {
|
||||
GlobalVariable() { not this instanceof NamespaceVariable }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "GlobalVariable" }
|
||||
override string getCanonicalQLClass() { result = "GlobalVariable" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -505,7 +501,7 @@ class GlobalVariable extends GlobalOrNamespaceVariable {
|
||||
class MemberVariable extends Variable, @membervariable {
|
||||
MemberVariable() { this.isMember() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "MemberVariable" }
|
||||
override string getCanonicalQLClass() { result = "MemberVariable" }
|
||||
|
||||
/** Holds if this member is private. */
|
||||
predicate isPrivate() { this.hasSpecifier("private") }
|
||||
@@ -582,7 +578,7 @@ class TemplateVariable extends Variable {
|
||||
* float a;
|
||||
* }
|
||||
*
|
||||
* template<typename T>
|
||||
* template<type T>
|
||||
* void myTemplateFunction() {
|
||||
* T b;
|
||||
* }
|
||||
|
||||
@@ -6,7 +6,7 @@ import semmle.code.cpp.Type
|
||||
class CharPointerType extends PointerType {
|
||||
CharPointerType() { this.getBaseType() instanceof CharType }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CharPointerType" }
|
||||
override string getCanonicalQLClass() { result = "CharPointerType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -15,7 +15,7 @@ class CharPointerType extends PointerType {
|
||||
class IntPointerType extends PointerType {
|
||||
IntPointerType() { this.getBaseType() instanceof IntType }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "IntPointerType" }
|
||||
override string getCanonicalQLClass() { result = "IntPointerType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -24,7 +24,7 @@ class IntPointerType extends PointerType {
|
||||
class VoidPointerType extends PointerType {
|
||||
VoidPointerType() { this.getBaseType() instanceof VoidType }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VoidPointerType" }
|
||||
override string getCanonicalQLClass() { result = "VoidPointerType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,7 +36,7 @@ class Size_t extends Type {
|
||||
this.hasName("size_t")
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Size_t" }
|
||||
override string getCanonicalQLClass() { result = "Size_t" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,7 +48,7 @@ class Ssize_t extends Type {
|
||||
this.hasName("ssize_t")
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Ssize_t" }
|
||||
override string getCanonicalQLClass() { result = "Ssize_t" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,7 +60,7 @@ class Ptrdiff_t extends Type {
|
||||
this.hasName("ptrdiff_t")
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Ptrdiff_t" }
|
||||
override string getCanonicalQLClass() { result = "Ptrdiff_t" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,7 +72,7 @@ class Intmax_t extends Type {
|
||||
this.hasName("intmax_t")
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Intmax_t" }
|
||||
override string getCanonicalQLClass() { result = "Intmax_t" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,7 +84,7 @@ class Uintmax_t extends Type {
|
||||
this.hasName("uintmax_t")
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Uintmax_t" }
|
||||
override string getCanonicalQLClass() { result = "Uintmax_t" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,7 +100,7 @@ class Wchar_t extends Type {
|
||||
this.hasName("wchar_t")
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Wchar_t" }
|
||||
override string getCanonicalQLClass() { result = "Wchar_t" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,5 +176,5 @@ class MicrosoftInt64Type extends IntegralType {
|
||||
class BuiltInVarArgsList extends Type {
|
||||
BuiltInVarArgsList() { this.hasName("__builtin_va_list") }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInVarArgsList" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInVarArgsList" }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* Provides predicates for identifying function calls that open or close a file.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,7 +20,7 @@ class PrintfFormatAttribute extends FormatAttribute {
|
||||
* function by its use of the GNU `format` attribute.
|
||||
*/
|
||||
class AttributeFormattingFunction extends FormattingFunction {
|
||||
override string getAPrimaryQlClass() { result = "AttributeFormattingFunction" }
|
||||
override string getCanonicalQLClass() { result = "AttributeFormattingFunction" }
|
||||
|
||||
AttributeFormattingFunction() {
|
||||
exists(PrintfFormatAttribute printf_attrib |
|
||||
@@ -49,18 +49,6 @@ predicate primitiveVariadicFormatter(TopLevelFunction f, int formatParamIndex) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A standard function such as `vsprintf` that has an output parameter
|
||||
* and a variable argument list of type `va_arg`.
|
||||
*/
|
||||
private predicate primitiveVariadicFormatterOutput(TopLevelFunction f, int outputParamIndex) {
|
||||
// note: this might look like the regular expression in `primitiveVariadicFormatter`, but
|
||||
// there is one important difference: the [fs] part is not optional, as these classify
|
||||
// the `printf` variants that write to a buffer.
|
||||
// Conveniently, these buffer parameters are all at index 0.
|
||||
f.getName().regexpMatch("_?_?va?[fs]n?w?printf(_s)?(_p)?(_l)?") and outputParamIndex = 0
|
||||
}
|
||||
|
||||
private predicate callsVariadicFormatter(Function f, int formatParamIndex) {
|
||||
exists(FunctionCall fc, int i |
|
||||
variadicFormatter(fc.getTarget(), i) and
|
||||
@@ -69,26 +57,6 @@ private predicate callsVariadicFormatter(Function f, int formatParamIndex) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate callsVariadicFormatterOutput(Function f, int outputParamIndex) {
|
||||
exists(FunctionCall fc, int i |
|
||||
fc.getEnclosingFunction() = f and
|
||||
variadicFormatterOutput(fc.getTarget(), i) and
|
||||
fc.getArgument(i) = f.getParameter(outputParamIndex).getAnAccess()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` is a function such as `vprintf` that takes variable argument list
|
||||
* of type `va_arg` and writes formatted output to a buffer given as a parameter at
|
||||
* index `outputParamIndex`, if any.
|
||||
*/
|
||||
private predicate variadicFormatterOutput(Function f, int outputParamIndex) {
|
||||
primitiveVariadicFormatterOutput(f, outputParamIndex)
|
||||
or
|
||||
not f.isVarargs() and
|
||||
callsVariadicFormatterOutput(f, outputParamIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` is a function such as `vprintf` that has a format parameter
|
||||
* (at `formatParamIndex`) and a variable argument list of type `va_arg`.
|
||||
@@ -105,13 +73,11 @@ predicate variadicFormatter(Function f, int formatParamIndex) {
|
||||
* string and a variable number of arguments.
|
||||
*/
|
||||
class UserDefinedFormattingFunction extends FormattingFunction {
|
||||
override string getAPrimaryQlClass() { result = "UserDefinedFormattingFunction" }
|
||||
override string getCanonicalQLClass() { result = "UserDefinedFormattingFunction" }
|
||||
|
||||
UserDefinedFormattingFunction() { isVarargs() and callsVariadicFormatter(this, _) }
|
||||
|
||||
override int getFormatParameterIndex() { callsVariadicFormatter(this, result) }
|
||||
|
||||
override int getOutputParameterIndex() { callsVariadicFormatterOutput(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,7 +86,7 @@ class UserDefinedFormattingFunction extends FormattingFunction {
|
||||
class FormattingFunctionCall extends Expr {
|
||||
FormattingFunctionCall() { this.(Call).getTarget() instanceof FormattingFunction }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FormattingFunctionCall" }
|
||||
override string getCanonicalQLClass() { result = "FormattingFunctionCall" }
|
||||
|
||||
/**
|
||||
* Gets the formatting function being called.
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* Provides a class for calculating the possible length of string expressions.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
import semmle.code.cpp.controlflow.SSA
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@ abstract class MutexType extends Type {
|
||||
abstract predicate trylockAccess(FunctionCall fc, Expr arg);
|
||||
|
||||
/**
|
||||
* Holds if `fc` is a call that unlocks mutex `arg` of this type.
|
||||
* Holds if `fc` is a call that unlocks mutex `arg`
|
||||
* of this type.
|
||||
*/
|
||||
abstract predicate unlockAccess(FunctionCall fc, Expr arg);
|
||||
|
||||
@@ -37,7 +38,8 @@ abstract class MutexType extends Type {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a call that locks or tries to lock any mutex of this type.
|
||||
* Holds if `fc` is a call that locks or tries to lock any
|
||||
* mutex of this type.
|
||||
*/
|
||||
FunctionCall getLockAccess() {
|
||||
result = getMustlockAccess() or
|
||||
@@ -45,44 +47,44 @@ abstract class MutexType extends Type {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a call that always locks any mutex of this type.
|
||||
* Holds if `fc` is a call that always locks any mutex of this type.
|
||||
*/
|
||||
FunctionCall getMustlockAccess() { this.mustlockAccess(result, _) }
|
||||
|
||||
/**
|
||||
* Gets a call that tries to lock any mutex of this type,
|
||||
* Holds if `fc` is a call that tries to lock any mutex of this type,
|
||||
* by may return without success.
|
||||
*/
|
||||
FunctionCall getTrylockAccess() { this.trylockAccess(result, _) }
|
||||
|
||||
/**
|
||||
* Gets a call that unlocks any mutex of this type.
|
||||
* Holds if `fc` is a call that unlocks any mutex of this type.
|
||||
*/
|
||||
FunctionCall getUnlockAccess() { this.unlockAccess(result, _) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use mustlockAccess(fc, arg) instead.
|
||||
* DEPRECATED: use mustlockAccess(fc, arg) instead
|
||||
*/
|
||||
deprecated Function getMustlockFunction() { result = getMustlockAccess().getTarget() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use trylockAccess(fc, arg) instead.
|
||||
* DEPRECATED: use trylockAccess(fc, arg) instead
|
||||
*/
|
||||
deprecated Function getTrylockFunction() { result = getTrylockAccess().getTarget() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use lockAccess(fc, arg) instead.
|
||||
* DEPRECATED: use lockAccess(fc, arg) instead
|
||||
*/
|
||||
deprecated Function getLockFunction() { result = getLockAccess().getTarget() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use unlockAccess(fc, arg) instead.
|
||||
* DEPRECATED: use unlockAccess(fc, arg) instead
|
||||
*/
|
||||
deprecated Function getUnlockFunction() { result = getUnlockAccess().getTarget() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a function that looks like a lock function.
|
||||
* A function that looks like a lock function.
|
||||
*/
|
||||
private Function mustlockCandidate() {
|
||||
exists(string name | name = result.getName() |
|
||||
@@ -92,7 +94,7 @@ private Function mustlockCandidate() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a function that looks like a try-lock function.
|
||||
* A function that looks like a try-lock function.
|
||||
*/
|
||||
private Function trylockCandidate() {
|
||||
exists(string name | name = result.getName() |
|
||||
@@ -102,7 +104,7 @@ private Function trylockCandidate() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a function that looks like an unlock function.
|
||||
* A function that looks like an unlock function.
|
||||
*/
|
||||
private Function unlockCandidate() {
|
||||
exists(string name | name = result.getName() |
|
||||
@@ -169,10 +171,7 @@ class DefaultMutexType extends MutexType {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `arg` is the mutex argument of a call to lock or unlock and
|
||||
* `argType` is the type of the mutex.
|
||||
*/
|
||||
/** Get the mutex argument of a call to lock or unlock. */
|
||||
private predicate lockArg(Expr arg, MutexType argType, FunctionCall call) {
|
||||
argType = arg.getUnderlyingType().stripType() and
|
||||
(
|
||||
@@ -185,31 +184,18 @@ private predicate lockArg(Expr arg, MutexType argType, FunctionCall call) {
|
||||
// `MutexType.mustlockAccess`.
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `call` is a call that locks or tries to lock its argument `arg`.
|
||||
*/
|
||||
predicate lockCall(Expr arg, FunctionCall call) {
|
||||
exists(MutexType t | lockArg(arg, t, call) and call = t.getLockAccess())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `call` is a call that always locks its argument `arg`.
|
||||
*/
|
||||
predicate mustlockCall(Expr arg, FunctionCall call) {
|
||||
exists(MutexType t | lockArg(arg, t, call) and call = t.getMustlockAccess())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `call` is a call that tries to lock its argument `arg`, but may
|
||||
* return without success.
|
||||
*/
|
||||
predicate trylockCall(Expr arg, FunctionCall call) {
|
||||
exists(MutexType t | lockArg(arg, t, call) and call = t.getTrylockAccess())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `call` is a call that unlocks its argument `arg`.
|
||||
*/
|
||||
predicate unlockCall(Expr arg, FunctionCall call) {
|
||||
exists(MutexType t | lockArg(arg, t, call) and call = t.getUnlockAccess())
|
||||
}
|
||||
|
||||
@@ -53,13 +53,26 @@ private predicate functionSignature(Function f, string qualifiedName, int nparam
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the set of viable implementations that can be called by `call`
|
||||
* might be improved by knowing the call context.
|
||||
* Holds if the call context `ctx` reduces the set of viable dispatch
|
||||
* targets of `ma` in `c`.
|
||||
*/
|
||||
predicate mayBenefitFromCallContext(Call call, Function f) { none() }
|
||||
predicate reducedViableImplInCallContext(Call call, Function f, Call ctx) { none() }
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference.
|
||||
* Gets a viable dispatch target of `ma` in the context `ctx`. This is
|
||||
* restricted to those `ma`s for which the context makes a difference.
|
||||
*/
|
||||
Function viableImplInCallContext(Call call, Call ctx) { none() }
|
||||
Function prunedViableImplInCallContext(Call call, Call ctx) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow returning from `m` to `ma` might return further and if
|
||||
* this path restricts the set of call sites that can be returned to.
|
||||
*/
|
||||
predicate reducedViableImplInReturn(Function f, Call call) { none() }
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `ma` in the context `ctx`. This is
|
||||
* restricted to those `ma`s and results for which the return flow from the
|
||||
* result to `ma` restricts the possible context `ctx`.
|
||||
*/
|
||||
Function prunedViableImplInCallContextReverse(Call call, Call ctx) { none() }
|
||||
|
||||
@@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
@@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
@@ -1051,17 +1051,6 @@ private predicate flowIntoCallNodeCand2(
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
/**
|
||||
* A node where some checking is required, and hence the big-step relation
|
||||
* is not allowed to step over.
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
@@ -1076,7 +1065,7 @@ private module LocalFlowBigStep {
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1094,7 +1083,7 @@ private module LocalFlowBigStep {
|
||||
read(node, _, next)
|
||||
)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
or
|
||||
config.isSink(node)
|
||||
}
|
||||
@@ -1124,11 +1113,11 @@ private module LocalFlowBigStep {
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1138,16 +1127,16 @@ private module LocalFlowBigStep {
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1201,8 +1190,9 @@ private predicate flowCandFwd(
|
||||
Configuration config
|
||||
) {
|
||||
flowCandFwd0(node, fromArg, argApf, apf, config) and
|
||||
not apf.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), apf.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1214,7 +1204,7 @@ private predicate flowCandFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, argApf, apf, config) and
|
||||
@@ -1240,7 +1230,7 @@ private predicate flowCandFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
// store
|
||||
@@ -1670,7 +1660,7 @@ private predicate flowFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
@@ -1698,7 +1688,7 @@ private predicate flowFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
)
|
||||
@@ -2075,7 +2065,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2302,7 +2292,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2644,7 +2634,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -2661,7 +2651,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -2774,7 +2764,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -2790,7 +2780,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -2804,7 +2794,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
|
||||
@@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
@@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
@@ -1051,17 +1051,6 @@ private predicate flowIntoCallNodeCand2(
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
/**
|
||||
* A node where some checking is required, and hence the big-step relation
|
||||
* is not allowed to step over.
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
@@ -1076,7 +1065,7 @@ private module LocalFlowBigStep {
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1094,7 +1083,7 @@ private module LocalFlowBigStep {
|
||||
read(node, _, next)
|
||||
)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
or
|
||||
config.isSink(node)
|
||||
}
|
||||
@@ -1124,11 +1113,11 @@ private module LocalFlowBigStep {
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1138,16 +1127,16 @@ private module LocalFlowBigStep {
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1201,8 +1190,9 @@ private predicate flowCandFwd(
|
||||
Configuration config
|
||||
) {
|
||||
flowCandFwd0(node, fromArg, argApf, apf, config) and
|
||||
not apf.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), apf.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1214,7 +1204,7 @@ private predicate flowCandFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, argApf, apf, config) and
|
||||
@@ -1240,7 +1230,7 @@ private predicate flowCandFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
// store
|
||||
@@ -1670,7 +1660,7 @@ private predicate flowFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
@@ -1698,7 +1688,7 @@ private predicate flowFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
)
|
||||
@@ -2075,7 +2065,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2302,7 +2292,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2644,7 +2634,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -2661,7 +2651,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -2774,7 +2764,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -2790,7 +2780,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -2804,7 +2794,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
|
||||
@@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
@@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
@@ -1051,17 +1051,6 @@ private predicate flowIntoCallNodeCand2(
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
/**
|
||||
* A node where some checking is required, and hence the big-step relation
|
||||
* is not allowed to step over.
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
@@ -1076,7 +1065,7 @@ private module LocalFlowBigStep {
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1094,7 +1083,7 @@ private module LocalFlowBigStep {
|
||||
read(node, _, next)
|
||||
)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
or
|
||||
config.isSink(node)
|
||||
}
|
||||
@@ -1124,11 +1113,11 @@ private module LocalFlowBigStep {
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1138,16 +1127,16 @@ private module LocalFlowBigStep {
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1201,8 +1190,9 @@ private predicate flowCandFwd(
|
||||
Configuration config
|
||||
) {
|
||||
flowCandFwd0(node, fromArg, argApf, apf, config) and
|
||||
not apf.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), apf.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1214,7 +1204,7 @@ private predicate flowCandFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, argApf, apf, config) and
|
||||
@@ -1240,7 +1230,7 @@ private predicate flowCandFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
// store
|
||||
@@ -1670,7 +1660,7 @@ private predicate flowFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
@@ -1698,7 +1688,7 @@ private predicate flowFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
)
|
||||
@@ -2075,7 +2065,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2302,7 +2292,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2644,7 +2634,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -2661,7 +2651,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -2774,7 +2764,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -2790,7 +2780,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -2804,7 +2794,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
|
||||
@@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
@@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
@@ -1051,17 +1051,6 @@ private predicate flowIntoCallNodeCand2(
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
/**
|
||||
* A node where some checking is required, and hence the big-step relation
|
||||
* is not allowed to step over.
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
@@ -1076,7 +1065,7 @@ private module LocalFlowBigStep {
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1094,7 +1083,7 @@ private module LocalFlowBigStep {
|
||||
read(node, _, next)
|
||||
)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
or
|
||||
config.isSink(node)
|
||||
}
|
||||
@@ -1124,11 +1113,11 @@ private module LocalFlowBigStep {
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1138,16 +1127,16 @@ private module LocalFlowBigStep {
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1201,8 +1190,9 @@ private predicate flowCandFwd(
|
||||
Configuration config
|
||||
) {
|
||||
flowCandFwd0(node, fromArg, argApf, apf, config) and
|
||||
not apf.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), apf.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1214,7 +1204,7 @@ private predicate flowCandFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, argApf, apf, config) and
|
||||
@@ -1240,7 +1230,7 @@ private predicate flowCandFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
// store
|
||||
@@ -1670,7 +1660,7 @@ private predicate flowFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
@@ -1698,7 +1688,7 @@ private predicate flowFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
)
|
||||
@@ -2075,7 +2065,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2302,7 +2292,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2644,7 +2634,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -2661,7 +2651,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -2774,7 +2764,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -2790,7 +2780,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -2804,7 +2794,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
|
||||
@@ -22,7 +22,7 @@ private module Cached {
|
||||
exists(int i |
|
||||
viableParam(call, i, p) and
|
||||
arg.argumentOf(call, i) and
|
||||
compatibleTypes(getNodeType(arg), getNodeType(p))
|
||||
compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(p))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -147,6 +147,54 @@ private module Cached {
|
||||
}
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
private predicate localFlowEntry(Node n) {
|
||||
Cand::cand(_, n) and
|
||||
(
|
||||
n instanceof ParameterNode or
|
||||
n instanceof OutNode or
|
||||
readStep(_, _, n) or
|
||||
n instanceof CastNode
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localFlowExit(Node n) {
|
||||
Cand::cand(_, n) and
|
||||
(
|
||||
n instanceof ArgumentNode
|
||||
or
|
||||
n instanceof ReturnNode
|
||||
or
|
||||
readStep(n, _, _)
|
||||
or
|
||||
n instanceof CastNode
|
||||
or
|
||||
n =
|
||||
any(PostUpdateNode pun | Cand::parameterValueFlowsToPreUpdateCand(_, pun))
|
||||
.getPreUpdateNode()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(Node node1, Node node2) {
|
||||
localFlowEntry(node1) and
|
||||
simpleLocalFlowStep(node1, node2) and
|
||||
node1 != node2
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid) and
|
||||
simpleLocalFlowStep(mid, node2) and
|
||||
not mid instanceof CastNode
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate localFlowBigStep(Node node1, Node node2) {
|
||||
localFlowStepPlus(node1, node2) and
|
||||
localFlowExit(node2)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The final flow-through calculation:
|
||||
*
|
||||
@@ -170,10 +218,10 @@ private module Cached {
|
||||
then
|
||||
// normal flow through
|
||||
read = TReadStepTypesNone() and
|
||||
compatibleTypes(getNodeType(p), getNodeType(node))
|
||||
compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node))
|
||||
or
|
||||
// getter
|
||||
compatibleTypes(read.getContentType(), getNodeType(node))
|
||||
compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node))
|
||||
else any()
|
||||
}
|
||||
|
||||
@@ -186,7 +234,7 @@ private module Cached {
|
||||
// local flow
|
||||
exists(Node mid |
|
||||
parameterValueFlow(p, mid, read) and
|
||||
simpleLocalFlowStep(mid, node)
|
||||
LocalFlowBigStep::localFlowBigStep(mid, node)
|
||||
)
|
||||
or
|
||||
// read
|
||||
@@ -195,26 +243,19 @@ private module Cached {
|
||||
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
|
||||
read.getContentType()) and
|
||||
Cand::parameterValueFlowReturnCand(p, _, true) and
|
||||
compatibleTypes(getNodeType(p), read.getContainerType())
|
||||
compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType())
|
||||
)
|
||||
or
|
||||
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlow0_0(
|
||||
ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read
|
||||
) {
|
||||
// flow through: no prior read
|
||||
exists(ArgumentNode arg |
|
||||
parameterValueFlowArg(p, arg, mustBeNone) and
|
||||
parameterValueFlowArg(p, arg, TReadStepTypesNone()) and
|
||||
argumentValueFlowsThrough(arg, read, node)
|
||||
)
|
||||
or
|
||||
// flow through: no read inside method
|
||||
exists(ArgumentNode arg |
|
||||
parameterValueFlowArg(p, arg, read) and
|
||||
argumentValueFlowsThrough(arg, mustBeNone, node)
|
||||
argumentValueFlowsThrough(arg, TReadStepTypesNone(), node)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -251,11 +292,11 @@ private module Cached {
|
||||
|
|
||||
// normal flow through
|
||||
read = TReadStepTypesNone() and
|
||||
compatibleTypes(getNodeType(arg), getNodeType(out))
|
||||
compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out))
|
||||
or
|
||||
// getter
|
||||
compatibleTypes(getNodeType(arg), read.getContainerType()) and
|
||||
compatibleTypes(read.getContentType(), getNodeType(out))
|
||||
compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and
|
||||
compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -289,67 +330,6 @@ private module Cached {
|
||||
import Final
|
||||
}
|
||||
|
||||
import FlowThrough
|
||||
|
||||
cached
|
||||
private module DispatchWithCallContext {
|
||||
/**
|
||||
* Holds if the call context `ctx` reduces the set of viable run-time
|
||||
* dispatch targets of call `call` in `c`.
|
||||
*/
|
||||
cached
|
||||
predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) {
|
||||
exists(int tgts, int ctxtgts |
|
||||
mayBenefitFromCallContext(call, c) and
|
||||
c = viableCallable(ctx) and
|
||||
ctxtgts = count(viableImplInCallContext(call, ctx)) and
|
||||
tgts = strictcount(viableCallable(call)) and
|
||||
ctxtgts < tgts
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable run-time dispatch target for the call `call` in the
|
||||
* context `ctx`. This is restricted to those calls for which a context
|
||||
* makes a difference.
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
reducedViableImplInCallContext(call, _, ctx)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if flow returning from callable `c` to call `call` might return
|
||||
* further and if this path restricts the set of call sites that can be
|
||||
* returned to.
|
||||
*/
|
||||
cached
|
||||
predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) {
|
||||
exists(int tgts, int ctxtgts |
|
||||
mayBenefitFromCallContext(call, _) and
|
||||
c = viableCallable(call) and
|
||||
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and
|
||||
tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and
|
||||
ctxtgts < tgts
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable run-time dispatch target for the call `call` in the
|
||||
* context `ctx`. This is restricted to those calls and results for which
|
||||
* the return flow from the result to `call` restricts the possible context
|
||||
* `ctx`.
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
reducedViableImplInReturn(result, call)
|
||||
}
|
||||
}
|
||||
|
||||
import DispatchWithCallContext
|
||||
|
||||
/**
|
||||
* Holds if `p` can flow to the pre-update node associated with post-update
|
||||
* node `n`, in the same callable, using only value-preserving steps.
|
||||
@@ -364,8 +344,8 @@ private module Cached {
|
||||
) {
|
||||
storeStep(node1, c, node2) and
|
||||
readStep(_, c, _) and
|
||||
contentType = getNodeType(node1) and
|
||||
containerType = getNodeType(node2)
|
||||
contentType = getErasedNodeTypeBound(node1) and
|
||||
containerType = getErasedNodeTypeBound(node2)
|
||||
or
|
||||
exists(Node n1, Node n2 |
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
@@ -374,8 +354,8 @@ private module Cached {
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
||||
or
|
||||
readStep(n2, c, n1) and
|
||||
contentType = getNodeType(n1) and
|
||||
containerType = getNodeType(n2)
|
||||
contentType = getErasedNodeTypeBound(n1) and
|
||||
containerType = getErasedNodeTypeBound(n2)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -391,6 +371,8 @@ private module Cached {
|
||||
store(node1, tc.getContent(), node2, contentType, tc.getContainerType())
|
||||
}
|
||||
|
||||
import FlowThrough
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` either improves virtual dispatch in
|
||||
* `callable` or if it allows us to prune unreachable nodes in `callable`.
|
||||
@@ -466,8 +448,8 @@ private predicate readStepWithTypes(
|
||||
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
|
||||
) {
|
||||
readStep(n1, c, n2) and
|
||||
container = getNodeType(n1) and
|
||||
content = getNodeType(n2)
|
||||
container = getErasedNodeTypeBound(n1) and
|
||||
content = getErasedNodeTypeBound(n2)
|
||||
}
|
||||
|
||||
private newtype TReadStepTypesOption =
|
||||
@@ -730,6 +712,9 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
|
||||
result = viableCallable(call) and cc instanceof CallContextReturn
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) }
|
||||
|
||||
predicate read = readStep/3;
|
||||
|
||||
/** An optional Boolean value. */
|
||||
@@ -769,13 +754,6 @@ abstract class AccessPathFront extends TAccessPathFront {
|
||||
abstract boolean toBoolNonEmpty();
|
||||
|
||||
predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) }
|
||||
|
||||
predicate isClearedAt(Node n) {
|
||||
exists(TypedContent tc |
|
||||
this.headUsesContent(tc) and
|
||||
clearsContent(n, tc.getContent())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||
|
||||
@@ -37,12 +37,21 @@ module Consistency {
|
||||
)
|
||||
}
|
||||
|
||||
query predicate uniqueType(Node n, string msg) {
|
||||
query predicate uniqueTypeBound(Node n, string msg) {
|
||||
exists(int c |
|
||||
n instanceof RelevantNode and
|
||||
c = count(getNodeType(n)) and
|
||||
c = count(n.getTypeBound()) and
|
||||
c != 1 and
|
||||
msg = "Node should have one type but has " + c + "."
|
||||
msg = "Node should have one type bound but has " + c + "."
|
||||
)
|
||||
}
|
||||
|
||||
query predicate uniqueTypeRepr(Node n, string msg) {
|
||||
exists(int c |
|
||||
n instanceof RelevantNode and
|
||||
c = count(getErasedRepr(n.getTypeBound())) and
|
||||
c != 1 and
|
||||
msg = "Node should have one type representation but has " + c + "."
|
||||
)
|
||||
}
|
||||
|
||||
@@ -95,7 +104,7 @@ module Consistency {
|
||||
msg = "Local flow step does not preserve enclosing callable."
|
||||
}
|
||||
|
||||
private DataFlowType typeRepr() { result = getNodeType(_) }
|
||||
private DataFlowType typeRepr() { result = getErasedRepr(any(Node n).getTypeBound()) }
|
||||
|
||||
query predicate compatibleTypesReflexive(DataFlowType t, string msg) {
|
||||
t = typeRepr() and
|
||||
|
||||
@@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
@@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
@@ -1051,17 +1051,6 @@ private predicate flowIntoCallNodeCand2(
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
/**
|
||||
* A node where some checking is required, and hence the big-step relation
|
||||
* is not allowed to step over.
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
@@ -1076,7 +1065,7 @@ private module LocalFlowBigStep {
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1094,7 +1083,7 @@ private module LocalFlowBigStep {
|
||||
read(node, _, next)
|
||||
)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
or
|
||||
config.isSink(node)
|
||||
}
|
||||
@@ -1124,11 +1113,11 @@ private module LocalFlowBigStep {
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1138,16 +1127,16 @@ private module LocalFlowBigStep {
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1201,8 +1190,9 @@ private predicate flowCandFwd(
|
||||
Configuration config
|
||||
) {
|
||||
flowCandFwd0(node, fromArg, argApf, apf, config) and
|
||||
not apf.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), apf.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1214,7 +1204,7 @@ private predicate flowCandFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, argApf, apf, config) and
|
||||
@@ -1240,7 +1230,7 @@ private predicate flowCandFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
// store
|
||||
@@ -1670,7 +1660,7 @@ private predicate flowFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
@@ -1698,7 +1688,7 @@ private predicate flowFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
)
|
||||
@@ -2075,7 +2065,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2302,7 +2292,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2644,7 +2634,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -2661,7 +2651,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -2774,7 +2764,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -2790,7 +2780,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -2804,7 +2794,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
|
||||
@@ -217,19 +217,16 @@ predicate readStep(Node node1, Content f, Node node2) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared at node `n`.
|
||||
* Gets a representative (boxed) type for `t` for the purpose of pruning
|
||||
* possible flow. A single type is used for all numeric types to account for
|
||||
* numeric conversions, and otherwise the erasure is used.
|
||||
*/
|
||||
predicate clearsContent(Node n, Content c) {
|
||||
none() // stub implementation
|
||||
}
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
Type getNodeType(Node n) {
|
||||
suppressUnusedNode(n) and
|
||||
Type getErasedRepr(Type t) {
|
||||
suppressUnusedType(t) and
|
||||
result instanceof VoidType // stub implementation
|
||||
}
|
||||
|
||||
/** Gets a string representation of a type returned by `getNodeType`. */
|
||||
/** Gets a string representation of a type returned by `getErasedRepr`. */
|
||||
string ppReprType(Type t) { none() } // stub implementation
|
||||
|
||||
/**
|
||||
@@ -241,7 +238,7 @@ predicate compatibleTypes(Type t1, Type t2) {
|
||||
any() // stub implementation
|
||||
}
|
||||
|
||||
private predicate suppressUnusedNode(Node n) { any() }
|
||||
private predicate suppressUnusedType(Type t) { any() }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Java QL library compatibility wrappers
|
||||
|
||||
@@ -50,25 +50,13 @@ class Node extends TNode {
|
||||
/** Gets the type of this node. */
|
||||
Type getType() { none() } // overridden in subclasses
|
||||
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. This predicate
|
||||
* only has a result on nodes that represent the value of evaluating the
|
||||
* expression. For data flowing _out of_ an expression, like when an
|
||||
* argument is passed by reference, use `asDefiningArgument` instead of
|
||||
* `asExpr`.
|
||||
*/
|
||||
/** Gets the expression corresponding to this node, if any. */
|
||||
Expr asExpr() { result = this.(ExprNode).getExpr() }
|
||||
|
||||
/** Gets the parameter corresponding to this node, if any. */
|
||||
Parameter asParameter() { result = this.(ExplicitParameterNode).getParameter() }
|
||||
|
||||
/**
|
||||
* Gets the argument that defines this `DefinitionByReferenceNode`, if any.
|
||||
* This predicate should be used instead of `asExpr` when referring to the
|
||||
* value of a reference argument _after_ the call has returned. For example,
|
||||
* in `f(&x)`, this predicate will have `&x` as its result for the `Node`
|
||||
* that represents the new value of `x`.
|
||||
*/
|
||||
/** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */
|
||||
Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() }
|
||||
|
||||
/**
|
||||
@@ -395,9 +383,7 @@ class PreConstructorInitThis extends Node, TPreConstructorInitThis {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Node` corresponding to the value of evaluating `e`. For data
|
||||
* flowing _out of_ an expression, like when an argument is passed by
|
||||
* reference, use `definitionByReferenceNodeFromArgument` instead.
|
||||
* Gets the `Node` corresponding to `e`.
|
||||
*/
|
||||
ExprNode exprNode(Expr e) { result.getExpr() = e }
|
||||
|
||||
|
||||
@@ -120,25 +120,15 @@ private module PartialDefinitions {
|
||||
)
|
||||
}
|
||||
|
||||
deprecated predicate partiallyDefines(Variable v) { innerDefinedExpr = v.getAnAccess() }
|
||||
predicate partiallyDefines(Variable v) { innerDefinedExpr = v.getAnAccess() }
|
||||
|
||||
deprecated predicate partiallyDefinesThis(ThisExpr e) { innerDefinedExpr = e }
|
||||
predicate partiallyDefinesThis(ThisExpr e) { innerDefinedExpr = e }
|
||||
|
||||
/**
|
||||
* Gets the subBasicBlock where this `PartialDefinition` is defined.
|
||||
*/
|
||||
ControlFlowNode getSubBasicBlockStart() { result = node }
|
||||
|
||||
/**
|
||||
* Holds if this `PartialDefinition` defines variable `v` at control-flow
|
||||
* node `cfn`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate partiallyDefinesVariableAt(Variable v, ControlFlowNode cfn) {
|
||||
innerDefinedExpr = v.getAnAccess() and
|
||||
cfn = node
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this partial definition may modify `inner` (or what it points
|
||||
* to) through `outer`. These expressions will never be `Conversion`s.
|
||||
@@ -198,7 +188,7 @@ module FlowVar_internal {
|
||||
predicate fullySupportedSsaVariable(Variable v) {
|
||||
v = any(SsaDefinition def).getAVariable() and
|
||||
// A partially-defined variable is handled using the partial definitions logic.
|
||||
not any(PartialDefinition p).partiallyDefinesVariableAt(v, _) and
|
||||
not any(PartialDefinition p).partiallyDefines(v) and
|
||||
// SSA variables do not exist before their first assignment, but one
|
||||
// feature of this data flow library is to track where uninitialized data
|
||||
// ends up.
|
||||
@@ -242,7 +232,7 @@ module FlowVar_internal {
|
||||
or
|
||||
assignmentLikeOperation(sbb, v, _, _)
|
||||
or
|
||||
exists(PartialDefinition p | p.partiallyDefinesVariableAt(v, sbb))
|
||||
sbb = any(PartialDefinition p | p.partiallyDefines(v)).getSubBasicBlockStart()
|
||||
or
|
||||
blockVarDefinedByVariable(sbb, v)
|
||||
)
|
||||
@@ -373,7 +363,8 @@ module FlowVar_internal {
|
||||
|
||||
override predicate definedPartiallyAt(Expr e) {
|
||||
exists(PartialDefinition p |
|
||||
p.partiallyDefinesVariableAt(v, sbb) and
|
||||
p.partiallyDefines(v) and
|
||||
sbb = p.getSubBasicBlockStart() and
|
||||
p.definesExpressions(_, e)
|
||||
)
|
||||
}
|
||||
@@ -436,7 +427,7 @@ module FlowVar_internal {
|
||||
/**
|
||||
* Gets a variable that is assigned in this loop and read outside the loop.
|
||||
*/
|
||||
Variable getARelevantVariable() {
|
||||
private Variable getARelevantVariable() {
|
||||
result = this.getAVariableAssignedInLoop() and
|
||||
exists(VariableAccess va |
|
||||
va.getTarget() = result and
|
||||
@@ -481,16 +472,10 @@ module FlowVar_internal {
|
||||
reachesWithoutAssignment(bb.getAPredecessor(), v) and
|
||||
this.bbInLoop(bb)
|
||||
) and
|
||||
not assignsToVar(bb, v)
|
||||
not assignmentLikeOperation(bb.getANode(), v, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate assignsToVar(BasicBlock bb, Variable v) {
|
||||
assignmentLikeOperation(bb.getANode(), v, _, _) and
|
||||
exists(AlwaysTrueUponEntryLoop loop | v = loop.getARelevantVariable())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `loop` always assigns to `v` before leaving through an edge
|
||||
* from `bbInside` in its condition to `bbOutside` outside the loop. Also,
|
||||
@@ -751,7 +736,7 @@ module FlowVar_internal {
|
||||
exists(Variable v | not fullySupportedSsaVariable(v) |
|
||||
assignmentLikeOperation(this, v, _, _)
|
||||
or
|
||||
exists(PartialDefinition p | p.partiallyDefinesVariableAt(v, this))
|
||||
this = any(PartialDefinition p | p.partiallyDefines(v)).getSubBasicBlockStart()
|
||||
// It is not necessary to cut the basic blocks at `Initializer` nodes
|
||||
// because the affected variable can have no _other_ value before its
|
||||
// initializer. It is not necessary to cut basic blocks at procedure
|
||||
|
||||
@@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private
|
||||
* To create a configuration, extend this class with a subclass whose
|
||||
* characteristic predicate is a unique singleton string. For example, write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
@@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
|
||||
@@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private
|
||||
* To create a configuration, extend this class with a subclass whose
|
||||
* characteristic predicate is a unique singleton string. For example, write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
@@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
/**
|
||||
* Provides classes for modeling accesses including variable accesses, enum
|
||||
* constant accesses and function accesses.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
import semmle.code.cpp.Variable
|
||||
import semmle.code.cpp.Enum
|
||||
@@ -41,7 +36,7 @@ class Access extends Expr, NameQualifiableElement, @access {
|
||||
* ```
|
||||
*/
|
||||
class EnumConstantAccess extends Access, @varaccess {
|
||||
override string getAPrimaryQlClass() { result = "EnumConstantAccess" }
|
||||
override string getCanonicalQLClass() { result = "EnumConstantAccess" }
|
||||
|
||||
EnumConstantAccess() {
|
||||
exists(EnumConstant c | varbind(underlyingElement(this), unresolveElement(c)))
|
||||
@@ -66,7 +61,7 @@ class EnumConstantAccess extends Access, @varaccess {
|
||||
* ```
|
||||
*/
|
||||
class VariableAccess extends Access, @varaccess {
|
||||
override string getAPrimaryQlClass() { result = "VariableAccess" }
|
||||
override string getCanonicalQLClass() { result = "VariableAccess" }
|
||||
|
||||
VariableAccess() {
|
||||
not exists(EnumConstant c | varbind(underlyingElement(this), unresolveElement(c)))
|
||||
@@ -171,7 +166,7 @@ class VariableAccess extends Access, @varaccess {
|
||||
* ```
|
||||
*/
|
||||
class FieldAccess extends VariableAccess {
|
||||
override string getAPrimaryQlClass() { result = "FieldAccess" }
|
||||
override string getCanonicalQLClass() { result = "FieldAccess" }
|
||||
|
||||
FieldAccess() { exists(Field f | varbind(underlyingElement(this), unresolveElement(f))) }
|
||||
|
||||
@@ -199,7 +194,7 @@ class FieldAccess extends VariableAccess {
|
||||
* ```
|
||||
*/
|
||||
class PointerFieldAccess extends FieldAccess {
|
||||
override string getAPrimaryQlClass() { result = "PointerFieldAccess" }
|
||||
override string getCanonicalQLClass() { result = "PointerFieldAccess" }
|
||||
|
||||
PointerFieldAccess() {
|
||||
exists(PointerType t |
|
||||
@@ -216,7 +211,7 @@ class PointerFieldAccess extends FieldAccess {
|
||||
* distinguish whether or not the type of `obj` is a reference type.
|
||||
*/
|
||||
class DotFieldAccess extends FieldAccess {
|
||||
override string getAPrimaryQlClass() { result = "DotFieldAccess" }
|
||||
override string getCanonicalQLClass() { result = "DotFieldAccess" }
|
||||
|
||||
DotFieldAccess() { exists(Class c | c = getQualifier().getFullyConverted().getUnspecifiedType()) }
|
||||
}
|
||||
@@ -237,7 +232,7 @@ class DotFieldAccess extends FieldAccess {
|
||||
* ```
|
||||
*/
|
||||
class ReferenceFieldAccess extends DotFieldAccess {
|
||||
override string getAPrimaryQlClass() { result = "ReferenceFieldAccess" }
|
||||
override string getCanonicalQLClass() { result = "ReferenceFieldAccess" }
|
||||
|
||||
ReferenceFieldAccess() { exprHasReferenceConversion(this.getQualifier()) }
|
||||
}
|
||||
@@ -258,7 +253,7 @@ class ReferenceFieldAccess extends DotFieldAccess {
|
||||
* ```
|
||||
*/
|
||||
class ValueFieldAccess extends DotFieldAccess {
|
||||
override string getAPrimaryQlClass() { result = "ValueFieldAccess" }
|
||||
override string getCanonicalQLClass() { result = "ValueFieldAccess" }
|
||||
|
||||
ValueFieldAccess() { not exprHasReferenceConversion(this.getQualifier()) }
|
||||
}
|
||||
@@ -312,7 +307,7 @@ private predicate exprHasReferenceConversion(Expr e) { referenceConversion(e.get
|
||||
* `ImplicitThisFieldAccess`.
|
||||
*/
|
||||
class ImplicitThisFieldAccess extends FieldAccess {
|
||||
override string getAPrimaryQlClass() { result = "ImplicitThisFieldAccess" }
|
||||
override string getCanonicalQLClass() { result = "ImplicitThisFieldAccess" }
|
||||
|
||||
ImplicitThisFieldAccess() { not exists(this.getQualifier()) }
|
||||
}
|
||||
@@ -337,7 +332,7 @@ class PointerToFieldLiteral extends ImplicitThisFieldAccess {
|
||||
|
||||
override predicate isConstant() { any() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PointerToFieldLiteral" }
|
||||
override string getCanonicalQLClass() { result = "PointerToFieldLiteral" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -354,7 +349,7 @@ class PointerToFieldLiteral extends ImplicitThisFieldAccess {
|
||||
class FunctionAccess extends Access, @routineexpr {
|
||||
FunctionAccess() { not iscall(underlyingElement(this), _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FunctionAccess" }
|
||||
override string getCanonicalQLClass() { result = "FunctionAccess" }
|
||||
|
||||
/** Gets the accessed function. */
|
||||
override Function getTarget() { funbind(underlyingElement(this), unresolveElement(result)) }
|
||||
@@ -404,7 +399,7 @@ class ParamAccessForType extends Expr, @param_ref {
|
||||
* ```
|
||||
*/
|
||||
class TypeName extends Expr, @type_operand {
|
||||
override string getAPrimaryQlClass() { result = "TypeName" }
|
||||
override string getCanonicalQLClass() { result = "TypeName" }
|
||||
|
||||
override string toString() { result = this.getType().getName() }
|
||||
}
|
||||
@@ -423,7 +418,7 @@ class TypeName extends Expr, @type_operand {
|
||||
* `OverloadedArrayExpr`.
|
||||
*/
|
||||
class ArrayExpr extends Expr, @subscriptexpr {
|
||||
override string getAPrimaryQlClass() { result = "ArrayExpr" }
|
||||
override string getCanonicalQLClass() { result = "ArrayExpr" }
|
||||
|
||||
/**
|
||||
* Gets the array or pointer expression being subscripted.
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
/**
|
||||
* Provides classes for modeling arithmetic operations such as `+`, `-`, `*`
|
||||
* and `++`.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
|
||||
/**
|
||||
@@ -19,7 +14,7 @@ class UnaryArithmeticOperation extends UnaryOperation, @un_arith_op_expr { }
|
||||
class UnaryMinusExpr extends UnaryArithmeticOperation, @arithnegexpr {
|
||||
override string getOperator() { result = "-" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "UnaryMinusExpr" }
|
||||
override string getCanonicalQLClass() { result = "UnaryMinusExpr" }
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
}
|
||||
@@ -33,7 +28,7 @@ class UnaryMinusExpr extends UnaryArithmeticOperation, @arithnegexpr {
|
||||
class UnaryPlusExpr extends UnaryArithmeticOperation, @unaryplusexpr {
|
||||
override string getOperator() { result = "+" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "UnaryPlusExpr" }
|
||||
override string getCanonicalQLClass() { result = "UnaryPlusExpr" }
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
}
|
||||
@@ -50,7 +45,7 @@ class UnaryPlusExpr extends UnaryArithmeticOperation, @unaryplusexpr {
|
||||
class ConjugationExpr extends UnaryArithmeticOperation, @conjugation {
|
||||
override string getOperator() { result = "~" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConjugationExpr" }
|
||||
override string getCanonicalQLClass() { result = "ConjugationExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +107,7 @@ class PostfixCrementOperation extends CrementOperation, @postfix_crement_expr {
|
||||
class PrefixIncrExpr extends IncrementOperation, PrefixCrementOperation, @preincrexpr {
|
||||
override string getOperator() { result = "++" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PrefixIncrExpr" }
|
||||
override string getCanonicalQLClass() { result = "PrefixIncrExpr" }
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
}
|
||||
@@ -128,7 +123,7 @@ class PrefixIncrExpr extends IncrementOperation, PrefixCrementOperation, @preinc
|
||||
class PrefixDecrExpr extends DecrementOperation, PrefixCrementOperation, @predecrexpr {
|
||||
override string getOperator() { result = "--" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PrefixDecrExpr" }
|
||||
override string getCanonicalQLClass() { result = "PrefixDecrExpr" }
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
}
|
||||
@@ -144,7 +139,7 @@ class PrefixDecrExpr extends DecrementOperation, PrefixCrementOperation, @predec
|
||||
class PostfixIncrExpr extends IncrementOperation, PostfixCrementOperation, @postincrexpr {
|
||||
override string getOperator() { result = "++" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PostfixIncrExpr" }
|
||||
override string getCanonicalQLClass() { result = "PostfixIncrExpr" }
|
||||
|
||||
override int getPrecedence() { result = 17 }
|
||||
|
||||
@@ -162,7 +157,7 @@ class PostfixIncrExpr extends IncrementOperation, PostfixCrementOperation, @post
|
||||
class PostfixDecrExpr extends DecrementOperation, PostfixCrementOperation, @postdecrexpr {
|
||||
override string getOperator() { result = "--" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PostfixDecrExpr" }
|
||||
override string getCanonicalQLClass() { result = "PostfixDecrExpr" }
|
||||
|
||||
override int getPrecedence() { result = 17 }
|
||||
|
||||
@@ -180,7 +175,7 @@ class PostfixDecrExpr extends DecrementOperation, PostfixCrementOperation, @post
|
||||
class RealPartExpr extends UnaryArithmeticOperation, @realpartexpr {
|
||||
override string getOperator() { result = "__real" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RealPartExpr" }
|
||||
override string getCanonicalQLClass() { result = "RealPartExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,7 +189,7 @@ class RealPartExpr extends UnaryArithmeticOperation, @realpartexpr {
|
||||
class ImaginaryPartExpr extends UnaryArithmeticOperation, @imagpartexpr {
|
||||
override string getOperator() { result = "__imag" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ImaginaryPartExpr" }
|
||||
override string getCanonicalQLClass() { result = "ImaginaryPartExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,7 +208,7 @@ class BinaryArithmeticOperation extends BinaryOperation, @bin_arith_op_expr { }
|
||||
class AddExpr extends BinaryArithmeticOperation, @addexpr {
|
||||
override string getOperator() { result = "+" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AddExpr" }
|
||||
override string getCanonicalQLClass() { result = "AddExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
@@ -227,7 +222,7 @@ class AddExpr extends BinaryArithmeticOperation, @addexpr {
|
||||
class SubExpr extends BinaryArithmeticOperation, @subexpr {
|
||||
override string getOperator() { result = "-" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SubExpr" }
|
||||
override string getCanonicalQLClass() { result = "SubExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
@@ -241,7 +236,7 @@ class SubExpr extends BinaryArithmeticOperation, @subexpr {
|
||||
class MulExpr extends BinaryArithmeticOperation, @mulexpr {
|
||||
override string getOperator() { result = "*" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "MulExpr" }
|
||||
override string getCanonicalQLClass() { result = "MulExpr" }
|
||||
|
||||
override int getPrecedence() { result = 14 }
|
||||
}
|
||||
@@ -255,7 +250,7 @@ class MulExpr extends BinaryArithmeticOperation, @mulexpr {
|
||||
class DivExpr extends BinaryArithmeticOperation, @divexpr {
|
||||
override string getOperator() { result = "/" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DivExpr" }
|
||||
override string getCanonicalQLClass() { result = "DivExpr" }
|
||||
|
||||
override int getPrecedence() { result = 14 }
|
||||
}
|
||||
@@ -269,7 +264,7 @@ class DivExpr extends BinaryArithmeticOperation, @divexpr {
|
||||
class RemExpr extends BinaryArithmeticOperation, @remexpr {
|
||||
override string getOperator() { result = "%" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RemExpr" }
|
||||
override string getCanonicalQLClass() { result = "RemExpr" }
|
||||
|
||||
override int getPrecedence() { result = 14 }
|
||||
}
|
||||
@@ -286,7 +281,7 @@ class RemExpr extends BinaryArithmeticOperation, @remexpr {
|
||||
class ImaginaryMulExpr extends BinaryArithmeticOperation, @jmulexpr {
|
||||
override string getOperator() { result = "*" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ImaginaryMulExpr" }
|
||||
override string getCanonicalQLClass() { result = "ImaginaryMulExpr" }
|
||||
|
||||
override int getPrecedence() { result = 14 }
|
||||
}
|
||||
@@ -303,7 +298,7 @@ class ImaginaryMulExpr extends BinaryArithmeticOperation, @jmulexpr {
|
||||
class ImaginaryDivExpr extends BinaryArithmeticOperation, @jdivexpr {
|
||||
override string getOperator() { result = "/" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ImaginaryDivExpr" }
|
||||
override string getCanonicalQLClass() { result = "ImaginaryDivExpr" }
|
||||
|
||||
override int getPrecedence() { result = 14 }
|
||||
}
|
||||
@@ -321,7 +316,7 @@ class ImaginaryDivExpr extends BinaryArithmeticOperation, @jdivexpr {
|
||||
class RealImaginaryAddExpr extends BinaryArithmeticOperation, @fjaddexpr {
|
||||
override string getOperator() { result = "+" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RealImaginaryAddExpr" }
|
||||
override string getCanonicalQLClass() { result = "RealImaginaryAddExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
@@ -339,7 +334,7 @@ class RealImaginaryAddExpr extends BinaryArithmeticOperation, @fjaddexpr {
|
||||
class ImaginaryRealAddExpr extends BinaryArithmeticOperation, @jfaddexpr {
|
||||
override string getOperator() { result = "+" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ImaginaryRealAddExpr" }
|
||||
override string getCanonicalQLClass() { result = "ImaginaryRealAddExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
@@ -357,7 +352,7 @@ class ImaginaryRealAddExpr extends BinaryArithmeticOperation, @jfaddexpr {
|
||||
class RealImaginarySubExpr extends BinaryArithmeticOperation, @fjsubexpr {
|
||||
override string getOperator() { result = "-" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RealImaginarySubExpr" }
|
||||
override string getCanonicalQLClass() { result = "RealImaginarySubExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
@@ -375,7 +370,7 @@ class RealImaginarySubExpr extends BinaryArithmeticOperation, @fjsubexpr {
|
||||
class ImaginaryRealSubExpr extends BinaryArithmeticOperation, @jfsubexpr {
|
||||
override string getOperator() { result = "-" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ImaginaryRealSubExpr" }
|
||||
override string getCanonicalQLClass() { result = "ImaginaryRealSubExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
@@ -389,7 +384,7 @@ class ImaginaryRealSubExpr extends BinaryArithmeticOperation, @jfsubexpr {
|
||||
class MinExpr extends BinaryArithmeticOperation, @minexpr {
|
||||
override string getOperator() { result = "<?" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "MinExpr" }
|
||||
override string getCanonicalQLClass() { result = "MinExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -401,7 +396,7 @@ class MinExpr extends BinaryArithmeticOperation, @minexpr {
|
||||
class MaxExpr extends BinaryArithmeticOperation, @maxexpr {
|
||||
override string getOperator() { result = ">?" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "MaxExpr" }
|
||||
override string getCanonicalQLClass() { result = "MaxExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -419,7 +414,7 @@ class PointerArithmeticOperation extends BinaryArithmeticOperation, @p_arith_op_
|
||||
class PointerAddExpr extends PointerArithmeticOperation, @paddexpr {
|
||||
override string getOperator() { result = "+" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PointerAddExpr" }
|
||||
override string getCanonicalQLClass() { result = "PointerAddExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
@@ -434,7 +429,7 @@ class PointerAddExpr extends PointerArithmeticOperation, @paddexpr {
|
||||
class PointerSubExpr extends PointerArithmeticOperation, @psubexpr {
|
||||
override string getOperator() { result = "-" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PointerSubExpr" }
|
||||
override string getCanonicalQLClass() { result = "PointerSubExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
@@ -449,7 +444,7 @@ class PointerSubExpr extends PointerArithmeticOperation, @psubexpr {
|
||||
class PointerDiffExpr extends PointerArithmeticOperation, @pdiffexpr {
|
||||
override string getOperator() { result = "-" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "PointerDiffExpr" }
|
||||
override string getCanonicalQLClass() { result = "PointerDiffExpr" }
|
||||
|
||||
override int getPrecedence() { result = 13 }
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class Assignment extends Operation, @assign_expr {
|
||||
class AssignExpr extends Assignment, @assignexpr {
|
||||
override string getOperator() { result = "=" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AssignExpr" }
|
||||
override string getCanonicalQLClass() { result = "AssignExpr" }
|
||||
|
||||
/** Gets a textual representation of this assignment. */
|
||||
override string toString() { result = "... = ..." }
|
||||
@@ -64,7 +64,7 @@ class AssignArithmeticOperation extends AssignOperation, @assign_arith_expr { }
|
||||
* ```
|
||||
*/
|
||||
class AssignAddExpr extends AssignArithmeticOperation, @assignaddexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignAddExpr" }
|
||||
override string getCanonicalQLClass() { result = "AssignAddExpr" }
|
||||
|
||||
override string getOperator() { result = "+=" }
|
||||
}
|
||||
@@ -76,7 +76,7 @@ class AssignAddExpr extends AssignArithmeticOperation, @assignaddexpr {
|
||||
* ```
|
||||
*/
|
||||
class AssignSubExpr extends AssignArithmeticOperation, @assignsubexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignSubExpr" }
|
||||
override string getCanonicalQLClass() { result = "AssignSubExpr" }
|
||||
|
||||
override string getOperator() { result = "-=" }
|
||||
}
|
||||
@@ -88,7 +88,7 @@ class AssignSubExpr extends AssignArithmeticOperation, @assignsubexpr {
|
||||
* ```
|
||||
*/
|
||||
class AssignMulExpr extends AssignArithmeticOperation, @assignmulexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignMulExpr" }
|
||||
override string getCanonicalQLClass() { result = "AssignMulExpr" }
|
||||
|
||||
override string getOperator() { result = "*=" }
|
||||
}
|
||||
@@ -100,7 +100,7 @@ class AssignMulExpr extends AssignArithmeticOperation, @assignmulexpr {
|
||||
* ```
|
||||
*/
|
||||
class AssignDivExpr extends AssignArithmeticOperation, @assigndivexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignDivExpr" }
|
||||
override string getCanonicalQLClass() { result = "AssignDivExpr" }
|
||||
|
||||
override string getOperator() { result = "/=" }
|
||||
}
|
||||
@@ -112,7 +112,7 @@ class AssignDivExpr extends AssignArithmeticOperation, @assigndivexpr {
|
||||
* ```
|
||||
*/
|
||||
class AssignRemExpr extends AssignArithmeticOperation, @assignremexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignRemExpr" }
|
||||
override string getCanonicalQLClass() { result = "AssignRemExpr" }
|
||||
|
||||
override string getOperator() { result = "%=" }
|
||||
}
|
||||
@@ -130,7 +130,7 @@ class AssignBitwiseOperation extends AssignOperation, @assign_bitwise_expr { }
|
||||
* ```
|
||||
*/
|
||||
class AssignAndExpr extends AssignBitwiseOperation, @assignandexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignAndExpr" }
|
||||
override string getCanonicalQLClass() { result = "AssignAndExpr" }
|
||||
|
||||
override string getOperator() { result = "&=" }
|
||||
}
|
||||
@@ -142,7 +142,7 @@ class AssignAndExpr extends AssignBitwiseOperation, @assignandexpr {
|
||||
* ```
|
||||
*/
|
||||
class AssignOrExpr extends AssignBitwiseOperation, @assignorexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignOrExpr" }
|
||||
override string getCanonicalQLClass() { result = "AssignOrExpr" }
|
||||
|
||||
override string getOperator() { result = "|=" }
|
||||
}
|
||||
@@ -154,7 +154,7 @@ class AssignOrExpr extends AssignBitwiseOperation, @assignorexpr {
|
||||
* ```
|
||||
*/
|
||||
class AssignXorExpr extends AssignBitwiseOperation, @assignxorexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignXorExpr" }
|
||||
override string getCanonicalQLClass() { result = "AssignXorExpr" }
|
||||
|
||||
override string getOperator() { result = "^=" }
|
||||
}
|
||||
@@ -166,7 +166,7 @@ class AssignXorExpr extends AssignBitwiseOperation, @assignxorexpr {
|
||||
* ```
|
||||
*/
|
||||
class AssignLShiftExpr extends AssignBitwiseOperation, @assignlshiftexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignLShiftExpr" }
|
||||
override string getCanonicalQLClass() { result = "AssignLShiftExpr" }
|
||||
|
||||
override string getOperator() { result = "<<=" }
|
||||
}
|
||||
@@ -178,7 +178,7 @@ class AssignLShiftExpr extends AssignBitwiseOperation, @assignlshiftexpr {
|
||||
* ```
|
||||
*/
|
||||
class AssignRShiftExpr extends AssignBitwiseOperation, @assignrshiftexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignRShiftExpr" }
|
||||
override string getCanonicalQLClass() { result = "AssignRShiftExpr" }
|
||||
|
||||
override string getOperator() { result = ">>=" }
|
||||
}
|
||||
@@ -190,7 +190,7 @@ class AssignRShiftExpr extends AssignBitwiseOperation, @assignrshiftexpr {
|
||||
* ```
|
||||
*/
|
||||
class AssignPointerAddExpr extends AssignOperation, @assignpaddexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignPointerAddExpr" }
|
||||
override string getCanonicalQLClass() { result = "AssignPointerAddExpr" }
|
||||
|
||||
override string getOperator() { result = "+=" }
|
||||
}
|
||||
@@ -202,7 +202,7 @@ class AssignPointerAddExpr extends AssignOperation, @assignpaddexpr {
|
||||
* ```
|
||||
*/
|
||||
class AssignPointerSubExpr extends AssignOperation, @assignpsubexpr {
|
||||
override string getAPrimaryQlClass() { result = "AssignPointerSubExpr" }
|
||||
override string getCanonicalQLClass() { result = "AssignPointerSubExpr" }
|
||||
|
||||
override string getOperator() { result = "-=" }
|
||||
}
|
||||
@@ -227,7 +227,7 @@ class ConditionDeclExpr extends Expr, @condition_decl {
|
||||
*/
|
||||
deprecated Expr getExpr() { result = this.getChild(0) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConditionDeclExpr" }
|
||||
override string getCanonicalQLClass() { result = "ConditionDeclExpr" }
|
||||
|
||||
/**
|
||||
* Gets the compiler-generated variable access that conceptually occurs after
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
/**
|
||||
* Provides classes for modeling bitwise operations such as `~`, `<<`, `&` and
|
||||
* `|`.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
|
||||
/**
|
||||
@@ -21,7 +16,7 @@ class ComplementExpr extends UnaryBitwiseOperation, @complementexpr {
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ComplementExpr" }
|
||||
override string getCanonicalQLClass() { result = "ComplementExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,7 +35,7 @@ class LShiftExpr extends BinaryBitwiseOperation, @lshiftexpr {
|
||||
|
||||
override int getPrecedence() { result = 12 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LShiftExpr" }
|
||||
override string getCanonicalQLClass() { result = "LShiftExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,7 +49,7 @@ class RShiftExpr extends BinaryBitwiseOperation, @rshiftexpr {
|
||||
|
||||
override int getPrecedence() { result = 12 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RShiftExpr" }
|
||||
override string getCanonicalQLClass() { result = "RShiftExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,7 +63,7 @@ class BitwiseAndExpr extends BinaryBitwiseOperation, @andexpr {
|
||||
|
||||
override int getPrecedence() { result = 8 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BitwiseAndExpr" }
|
||||
override string getCanonicalQLClass() { result = "BitwiseAndExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,7 +77,7 @@ class BitwiseOrExpr extends BinaryBitwiseOperation, @orexpr {
|
||||
|
||||
override int getPrecedence() { result = 6 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BitwiseOrExpr" }
|
||||
override string getCanonicalQLClass() { result = "BitwiseOrExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,5 +91,5 @@ class BitwiseXorExpr extends BinaryBitwiseOperation, @xorexpr {
|
||||
|
||||
override int getPrecedence() { result = 7 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BitwiseXorExpr" }
|
||||
override string getCanonicalQLClass() { result = "BitwiseXorExpr" }
|
||||
}
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
/**
|
||||
* Provides classes for modeling built-in operations. Built-in operations are
|
||||
* typically compiler specific and are used by libraries and generated code.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
|
||||
/**
|
||||
* A C/C++ built-in operation. This is the root QL class encompassing
|
||||
* A C/C++ builtin operation. This is the root QL class encompassing
|
||||
* built-in functionality.
|
||||
*/
|
||||
class BuiltInOperation extends Expr, @builtin_op {
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperation" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperation" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,7 +25,7 @@ class VarArgsExpr extends BuiltInOperation, @var_args_expr { }
|
||||
class BuiltInVarArgsStart extends BuiltInOperation, @vastartexpr {
|
||||
override string toString() { result = "__builtin_va_start" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInVarArgsStart" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInVarArgsStart" }
|
||||
|
||||
/**
|
||||
* Gets the `va_list` argument.
|
||||
@@ -55,7 +50,7 @@ class BuiltInVarArgsStart extends BuiltInOperation, @vastartexpr {
|
||||
class BuiltInVarArgsEnd extends BuiltInOperation, @vaendexpr {
|
||||
override string toString() { result = "__builtin_va_end" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInVarArgsEnd" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInVarArgsEnd" }
|
||||
|
||||
/**
|
||||
* Gets the `va_list` argument.
|
||||
@@ -73,7 +68,7 @@ class BuiltInVarArgsEnd extends BuiltInOperation, @vaendexpr {
|
||||
class BuiltInVarArg extends BuiltInOperation, @vaargexpr {
|
||||
override string toString() { result = "__builtin_va_arg" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInVarArg" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInVarArg" }
|
||||
|
||||
/**
|
||||
* Gets the `va_list` argument.
|
||||
@@ -93,7 +88,7 @@ class BuiltInVarArg extends BuiltInOperation, @vaargexpr {
|
||||
class BuiltInVarArgCopy extends BuiltInOperation, @vacopyexpr {
|
||||
override string toString() { result = "__builtin_va_copy" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInVarArgCopy" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInVarArgCopy" }
|
||||
|
||||
/**
|
||||
* Gets the destination `va_list` argument.
|
||||
@@ -115,7 +110,7 @@ class BuiltInVarArgCopy extends BuiltInOperation, @vacopyexpr {
|
||||
class BuiltInNoOp extends BuiltInOperation, @noopexpr {
|
||||
override string toString() { result = "__noop" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInNoOp" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInNoOp" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,7 +132,7 @@ deprecated class BuiltInOperationOffsetOf = BuiltInOperationBuiltInOffsetOf;
|
||||
class BuiltInOperationBuiltInOffsetOf extends BuiltInOperation, @offsetofexpr {
|
||||
override string toString() { result = "__builtin_offsetof" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInOffsetOf" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationBuiltInOffsetOf" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,7 +149,7 @@ class BuiltInOperationBuiltInOffsetOf extends BuiltInOperation, @offsetofexpr {
|
||||
class BuiltInIntAddr extends BuiltInOperation, @intaddrexpr {
|
||||
override string toString() { result = "__INTADDR__" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInIntAddr" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInIntAddr" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,7 +164,7 @@ class BuiltInIntAddr extends BuiltInOperation, @intaddrexpr {
|
||||
class BuiltInOperationHasAssign extends BuiltInOperation, @hasassignexpr {
|
||||
override string toString() { result = "__has_assign" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasAssign" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationHasAssign" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,7 +179,7 @@ class BuiltInOperationHasAssign extends BuiltInOperation, @hasassignexpr {
|
||||
class BuiltInOperationHasCopy extends BuiltInOperation, @hascopyexpr {
|
||||
override string toString() { result = "__has_copy" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasCopy" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationHasCopy" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,7 +195,7 @@ class BuiltInOperationHasCopy extends BuiltInOperation, @hascopyexpr {
|
||||
class BuiltInOperationHasNoThrowAssign extends BuiltInOperation, @hasnothrowassign {
|
||||
override string toString() { result = "__has_nothrow_assign" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowAssign" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationHasNoThrowAssign" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,7 +211,7 @@ class BuiltInOperationHasNoThrowAssign extends BuiltInOperation, @hasnothrowassi
|
||||
class BuiltInOperationHasNoThrowConstructor extends BuiltInOperation, @hasnothrowconstr {
|
||||
override string toString() { result = "__has_nothrow_constructor" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowConstructor" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationHasNoThrowConstructor" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,7 +226,7 @@ class BuiltInOperationHasNoThrowConstructor extends BuiltInOperation, @hasnothro
|
||||
class BuiltInOperationHasNoThrowCopy extends BuiltInOperation, @hasnothrowcopy {
|
||||
override string toString() { result = "__has_nothrow_copy" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowCopy" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationHasNoThrowCopy" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -247,7 +242,7 @@ class BuiltInOperationHasNoThrowCopy extends BuiltInOperation, @hasnothrowcopy {
|
||||
class BuiltInOperationHasTrivialAssign extends BuiltInOperation, @hastrivialassign {
|
||||
override string toString() { result = "__has_trivial_assign" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialAssign" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialAssign" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,7 +257,7 @@ class BuiltInOperationHasTrivialAssign extends BuiltInOperation, @hastrivialassi
|
||||
class BuiltInOperationHasTrivialConstructor extends BuiltInOperation, @hastrivialconstr {
|
||||
override string toString() { result = "__has_trivial_constructor" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialConstructor" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialConstructor" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -277,7 +272,7 @@ class BuiltInOperationHasTrivialConstructor extends BuiltInOperation, @hastrivia
|
||||
class BuiltInOperationHasTrivialCopy extends BuiltInOperation, @hastrivialcopy {
|
||||
override string toString() { result = "__has_trivial_copy" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialCopy" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialCopy" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -292,7 +287,7 @@ class BuiltInOperationHasTrivialCopy extends BuiltInOperation, @hastrivialcopy {
|
||||
class BuiltInOperationHasTrivialDestructor extends BuiltInOperation, @hastrivialdestructor {
|
||||
override string toString() { result = "__has_trivial_destructor" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialDestructor" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialDestructor" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -307,7 +302,7 @@ class BuiltInOperationHasTrivialDestructor extends BuiltInOperation, @hastrivial
|
||||
class BuiltInOperationHasUserDestructor extends BuiltInOperation, @hasuserdestr {
|
||||
override string toString() { result = "__has_user_destructor" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasUserDestructor" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationHasUserDestructor" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -325,7 +320,7 @@ class BuiltInOperationHasUserDestructor extends BuiltInOperation, @hasuserdestr
|
||||
class BuiltInOperationHasVirtualDestructor extends BuiltInOperation, @hasvirtualdestr {
|
||||
override string toString() { result = "__has_virtual_destructor" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasVirtualDestructor" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationHasVirtualDestructor" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -340,7 +335,7 @@ class BuiltInOperationHasVirtualDestructor extends BuiltInOperation, @hasvirtual
|
||||
class BuiltInOperationIsAbstract extends BuiltInOperation, @isabstractexpr {
|
||||
override string toString() { result = "__is_abstract" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsAbstract" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsAbstract" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -355,7 +350,7 @@ class BuiltInOperationIsAbstract extends BuiltInOperation, @isabstractexpr {
|
||||
class BuiltInOperationIsBaseOf extends BuiltInOperation, @isbaseofexpr {
|
||||
override string toString() { result = "__is_base_of" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsBaseOf" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsBaseOf" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -370,7 +365,7 @@ class BuiltInOperationIsBaseOf extends BuiltInOperation, @isbaseofexpr {
|
||||
class BuiltInOperationIsClass extends BuiltInOperation, @isclassexpr {
|
||||
override string toString() { result = "__is_class" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsClass" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsClass" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -385,7 +380,7 @@ class BuiltInOperationIsClass extends BuiltInOperation, @isclassexpr {
|
||||
class BuiltInOperationIsConvertibleTo extends BuiltInOperation, @isconvtoexpr {
|
||||
override string toString() { result = "__is_convertible_to" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsConvertibleTo" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsConvertibleTo" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -400,7 +395,7 @@ class BuiltInOperationIsConvertibleTo extends BuiltInOperation, @isconvtoexpr {
|
||||
class BuiltInOperationIsEmpty extends BuiltInOperation, @isemptyexpr {
|
||||
override string toString() { result = "__is_empty" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsEmpty" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsEmpty" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -415,7 +410,7 @@ class BuiltInOperationIsEmpty extends BuiltInOperation, @isemptyexpr {
|
||||
class BuiltInOperationIsEnum extends BuiltInOperation, @isenumexpr {
|
||||
override string toString() { result = "__is_enum" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsEnum" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsEnum" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -432,7 +427,7 @@ class BuiltInOperationIsEnum extends BuiltInOperation, @isenumexpr {
|
||||
class BuiltInOperationIsPod extends BuiltInOperation, @ispodexpr {
|
||||
override string toString() { result = "__is_pod" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsPod" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsPod" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -447,7 +442,7 @@ class BuiltInOperationIsPod extends BuiltInOperation, @ispodexpr {
|
||||
class BuiltInOperationIsPolymorphic extends BuiltInOperation, @ispolyexpr {
|
||||
override string toString() { result = "__is_polymorphic" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsPolymorphic" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsPolymorphic" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -462,7 +457,7 @@ class BuiltInOperationIsPolymorphic extends BuiltInOperation, @ispolyexpr {
|
||||
class BuiltInOperationIsUnion extends BuiltInOperation, @isunionexpr {
|
||||
override string toString() { result = "__is_union" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsUnion" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsUnion" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -501,7 +496,7 @@ class BuiltInOperationBuiltInTypesCompatibleP extends BuiltInOperation, @typesco
|
||||
class BuiltInOperationBuiltInShuffleVector extends BuiltInOperation, @builtinshufflevector {
|
||||
override string toString() { result = "__builtin_shufflevector" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInShuffleVector" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationBuiltInShuffleVector" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -521,7 +516,7 @@ class BuiltInOperationBuiltInShuffleVector extends BuiltInOperation, @builtinshu
|
||||
class BuiltInOperationBuiltInConvertVector extends BuiltInOperation, @builtinconvertvector {
|
||||
override string toString() { result = "__builtin_convertvector" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInConvertVector" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationBuiltInConvertVector" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -543,7 +538,7 @@ class BuiltInOperationBuiltInAddressOf extends UnaryOperation, BuiltInOperation,
|
||||
result = this.getOperand().(ReferenceDereferenceExpr).getChild(0).(Access).getTarget()
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInAddressOf" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationBuiltInAddressOf" }
|
||||
|
||||
override string getOperator() { result = "__builtin_addressof" }
|
||||
}
|
||||
@@ -565,7 +560,7 @@ class BuiltInOperationIsTriviallyConstructible extends BuiltInOperation,
|
||||
@istriviallyconstructibleexpr {
|
||||
override string toString() { result = "__is_trivially_constructible" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyConstructible" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsTriviallyConstructible" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -582,7 +577,7 @@ class BuiltInOperationIsTriviallyConstructible extends BuiltInOperation,
|
||||
class BuiltInOperationIsDestructible extends BuiltInOperation, @isdestructibleexpr {
|
||||
override string toString() { result = "__is_destructible" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsDestructible" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsDestructible" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -599,7 +594,7 @@ class BuiltInOperationIsDestructible extends BuiltInOperation, @isdestructibleex
|
||||
class BuiltInOperationIsNothrowDestructible extends BuiltInOperation, @isnothrowdestructibleexpr {
|
||||
override string toString() { result = "__is_nothrow_destructible" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowDestructible" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsNothrowDestructible" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -615,7 +610,7 @@ class BuiltInOperationIsNothrowDestructible extends BuiltInOperation, @isnothrow
|
||||
class BuiltInOperationIsTriviallyDestructible extends BuiltInOperation, @istriviallydestructibleexpr {
|
||||
override string toString() { result = "__is_trivially_destructible" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyDestructible" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsTriviallyDestructible" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -634,7 +629,7 @@ class BuiltInOperationIsTriviallyDestructible extends BuiltInOperation, @istrivi
|
||||
class BuiltInOperationIsTriviallyAssignable extends BuiltInOperation, @istriviallyassignableexpr {
|
||||
override string toString() { result = "__is_trivially_assignable" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyAssignable" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsTriviallyAssignable" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -650,7 +645,7 @@ class BuiltInOperationIsTriviallyAssignable extends BuiltInOperation, @istrivial
|
||||
class BuiltInOperationIsNothrowAssignable extends BuiltInOperation, @isnothrowassignableexpr {
|
||||
override string toString() { result = "__is_nothrow_assignable" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowAssignable" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsNothrowAssignable" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -670,7 +665,7 @@ class BuiltInOperationIsNothrowAssignable extends BuiltInOperation, @isnothrowas
|
||||
class BuiltInOperationIsStandardLayout extends BuiltInOperation, @isstandardlayoutexpr {
|
||||
override string toString() { result = "__is_standard_layout" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsStandardLayout" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsStandardLayout" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -684,7 +679,7 @@ class BuiltInOperationIsStandardLayout extends BuiltInOperation, @isstandardlayo
|
||||
class BuiltInOperationIsTriviallyCopyable extends BuiltInOperation, @istriviallycopyableexpr {
|
||||
override string toString() { result = "__is_trivially_copyable" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyCopyable" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsTriviallyCopyable" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -704,7 +699,7 @@ class BuiltInOperationIsTriviallyCopyable extends BuiltInOperation, @istrivially
|
||||
class BuiltInOperationIsLiteralType extends BuiltInOperation, @isliteraltypeexpr {
|
||||
override string toString() { result = "__is_literal_type" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsLiteralType" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsLiteralType" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -722,7 +717,7 @@ class BuiltInOperationHasTrivialMoveConstructor extends BuiltInOperation,
|
||||
@hastrivialmoveconstructorexpr {
|
||||
override string toString() { result = "__has_trivial_move_constructor" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialMoveConstructor" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialMoveConstructor" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -740,7 +735,7 @@ class BuiltInOperationHasTrivialMoveConstructor extends BuiltInOperation,
|
||||
class BuiltInOperationHasTrivialMoveAssign extends BuiltInOperation, @hastrivialmoveassignexpr {
|
||||
override string toString() { result = "__has_trivial_move_assign" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialMoveAssign" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialMoveAssign" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -756,7 +751,7 @@ class BuiltInOperationHasTrivialMoveAssign extends BuiltInOperation, @hastrivial
|
||||
class BuiltInOperationHasNothrowMoveAssign extends BuiltInOperation, @hasnothrowmoveassignexpr {
|
||||
override string toString() { result = "__has_nothrow_move_assign" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasNothrowMoveAssign" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationHasNothrowMoveAssign" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -775,7 +770,7 @@ class BuiltInOperationHasNothrowMoveAssign extends BuiltInOperation, @hasnothrow
|
||||
class BuiltInOperationIsConstructible extends BuiltInOperation, @isconstructibleexpr {
|
||||
override string toString() { result = "__is_constructible" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsConstructible" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsConstructible" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -791,7 +786,7 @@ class BuiltInOperationIsConstructible extends BuiltInOperation, @isconstructible
|
||||
class BuiltInOperationIsNothrowConstructible extends BuiltInOperation, @isnothrowconstructibleexpr {
|
||||
override string toString() { result = "__is_nothrow_constructible" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowConstructible" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsNothrowConstructible" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -806,7 +801,7 @@ class BuiltInOperationIsNothrowConstructible extends BuiltInOperation, @isnothro
|
||||
class BuiltInOperationHasFinalizer extends BuiltInOperation, @hasfinalizerexpr {
|
||||
override string toString() { result = "__has_finalizer" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasFinalizer" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationHasFinalizer" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -820,7 +815,7 @@ class BuiltInOperationHasFinalizer extends BuiltInOperation, @hasfinalizerexpr {
|
||||
class BuiltInOperationIsDelegate extends BuiltInOperation, @isdelegateexpr {
|
||||
override string toString() { result = "__is_delegate" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsDelegate" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsDelegate" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -833,7 +828,7 @@ class BuiltInOperationIsDelegate extends BuiltInOperation, @isdelegateexpr {
|
||||
class BuiltInOperationIsInterfaceClass extends BuiltInOperation, @isinterfaceclassexpr {
|
||||
override string toString() { result = "__is_interface_class" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsInterfaceClass" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsInterfaceClass" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -850,7 +845,7 @@ class BuiltInOperationIsInterfaceClass extends BuiltInOperation, @isinterfacecla
|
||||
class BuiltInOperationIsRefArray extends BuiltInOperation, @isrefarrayexpr {
|
||||
override string toString() { result = "__is_ref_array" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsRefArray" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsRefArray" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -867,7 +862,7 @@ class BuiltInOperationIsRefArray extends BuiltInOperation, @isrefarrayexpr {
|
||||
class BuiltInOperationIsRefClass extends BuiltInOperation, @isrefclassexpr {
|
||||
override string toString() { result = "__is_ref_class" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsRefClass" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsRefClass" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -885,7 +880,7 @@ class BuiltInOperationIsRefClass extends BuiltInOperation, @isrefclassexpr {
|
||||
class BuiltInOperationIsSealed extends BuiltInOperation, @issealedexpr {
|
||||
override string toString() { result = "__is_sealed" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsSealed" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsSealed" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -904,7 +899,7 @@ class BuiltInOperationIsSealed extends BuiltInOperation, @issealedexpr {
|
||||
class BuiltInOperationIsSimpleValueClass extends BuiltInOperation, @issimplevalueclassexpr {
|
||||
override string toString() { result = "__is_simple_value_class" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsSimpleValueClass" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsSimpleValueClass" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -921,7 +916,7 @@ class BuiltInOperationIsSimpleValueClass extends BuiltInOperation, @issimplevalu
|
||||
class BuiltInOperationIsValueClass extends BuiltInOperation, @isvalueclassexpr {
|
||||
override string toString() { result = "__is_value_class" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsValueClass" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsValueClass" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -939,7 +934,7 @@ class BuiltInOperationIsValueClass extends BuiltInOperation, @isvalueclassexpr {
|
||||
class BuiltInOperationIsFinal extends BuiltInOperation, @isfinalexpr {
|
||||
override string toString() { result = "__is_final" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsFinal" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInOperationIsFinal" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -954,7 +949,7 @@ class BuiltInOperationIsFinal extends BuiltInOperation, @isfinalexpr {
|
||||
class BuiltInChooseExpr extends BuiltInOperation, @builtinchooseexpr {
|
||||
override string toString() { result = "__builtin_choose_expr" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInChooseExpr" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInChooseExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -971,7 +966,7 @@ class BuiltInChooseExpr extends BuiltInOperation, @builtinchooseexpr {
|
||||
class VectorFillOperation extends UnaryOperation, @vec_fill {
|
||||
override string getOperator() { result = "(vector fill)" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VectorFillOperation" }
|
||||
override string getCanonicalQLClass() { result = "VectorFillOperation" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -980,7 +975,7 @@ class VectorFillOperation extends UnaryOperation, @vec_fill {
|
||||
class BuiltInComplexOperation extends BuiltInOperation, @builtincomplex {
|
||||
override string toString() { result = "__builtin_complex" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInComplexOperation" }
|
||||
override string getCanonicalQLClass() { result = "BuiltInComplexOperation" }
|
||||
|
||||
/** Gets the operand corresponding to the real part of the complex number. */
|
||||
Expr getRealOperand() { this.hasChild(result, 0) }
|
||||
|
||||
@@ -1,29 +1,13 @@
|
||||
/**
|
||||
* Provides classes for modeling call expressions including direct calls to
|
||||
* functions, constructor and destructor calls, and calls made through function
|
||||
* pointers.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
import semmle.code.cpp.Function
|
||||
private import semmle.code.cpp.dataflow.EscapesTree
|
||||
|
||||
private class TCall = @funbindexpr or @callexpr;
|
||||
|
||||
/**
|
||||
* A C/C++ call.
|
||||
*
|
||||
* This is the abstract root QL class for all types of calls.
|
||||
*/
|
||||
class Call extends Expr, NameQualifiableElement, TCall {
|
||||
// `@funbindexpr` (which is the dbscheme type for FunctionCall) is a union type that includes
|
||||
// `@routineexpr. This dbscheme type includes accesses to functions that are not necessarily calls to
|
||||
// that function. That's why the charpred for `FunctionCall` requires:
|
||||
// ```
|
||||
// iscall(underlyingElement(this), _)
|
||||
// ```
|
||||
// So for the charpred for `Call` we include the requirement that if this is an instance of
|
||||
// `@funbindexpr` it must be a _call_ to the function.
|
||||
Call() { this instanceof @callexpr or iscall(underlyingElement(this), _) }
|
||||
|
||||
abstract class Call extends Expr, NameQualifiableElement {
|
||||
/**
|
||||
* Gets the number of arguments (actual parameters) of this call. The count
|
||||
* does _not_ include the qualifier of the call, if any.
|
||||
@@ -90,7 +74,7 @@ class Call extends Expr, NameQualifiableElement, TCall {
|
||||
* method, and it might not exist.
|
||||
* - For a variable call, it never exists.
|
||||
*/
|
||||
Function getTarget() { none() } // overridden in subclasses
|
||||
abstract Function getTarget();
|
||||
|
||||
override int getPrecedence() { result = 17 }
|
||||
|
||||
@@ -164,7 +148,7 @@ class Call extends Expr, NameQualifiableElement, TCall {
|
||||
class FunctionCall extends Call, @funbindexpr {
|
||||
FunctionCall() { iscall(underlyingElement(this), _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FunctionCall" }
|
||||
override string getCanonicalQLClass() { result = "FunctionCall" }
|
||||
|
||||
/** Gets an explicit template argument for this call. */
|
||||
Locatable getAnExplicitTemplateArgument() { result = getExplicitTemplateArgument(_) }
|
||||
@@ -313,7 +297,7 @@ class OverloadedPointerDereferenceExpr extends FunctionCall {
|
||||
getTarget().getEffectiveNumberOfParameters() = 1
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "OverloadedPointerDereferenceExpr" }
|
||||
override string getCanonicalQLClass() { result = "OverloadedPointerDereferenceExpr" }
|
||||
|
||||
/**
|
||||
* Gets the expression this operator * applies to.
|
||||
@@ -361,7 +345,7 @@ class OverloadedPointerDereferenceExpr extends FunctionCall {
|
||||
class OverloadedArrayExpr extends FunctionCall {
|
||||
OverloadedArrayExpr() { getTarget().hasName("operator[]") }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "OverloadedArrayExpr" }
|
||||
override string getCanonicalQLClass() { result = "OverloadedArrayExpr" }
|
||||
|
||||
/**
|
||||
* Gets the expression being subscripted.
|
||||
@@ -393,7 +377,7 @@ class ExprCall extends Call, @callexpr {
|
||||
*/
|
||||
Expr getExpr() { result = this.getChild(0) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ExprCall" }
|
||||
override string getCanonicalQLClass() { result = "ExprCall" }
|
||||
|
||||
override Expr getAnArgument() { exists(int i | result = this.getChild(i) and i >= 1) }
|
||||
|
||||
@@ -417,7 +401,7 @@ class ExprCall extends Call, @callexpr {
|
||||
class VariableCall extends ExprCall {
|
||||
VariableCall() { this.getExpr() instanceof VariableAccess }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VariableCall" }
|
||||
override string getCanonicalQLClass() { result = "VariableCall" }
|
||||
|
||||
/**
|
||||
* Gets the variable which yields the function pointer to call.
|
||||
@@ -435,7 +419,7 @@ class VariableCall extends ExprCall {
|
||||
class ConstructorCall extends FunctionCall {
|
||||
ConstructorCall() { super.getTarget() instanceof Constructor }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConstructorCall" }
|
||||
override string getCanonicalQLClass() { result = "ConstructorCall" }
|
||||
|
||||
/** Gets the constructor being called. */
|
||||
override Constructor getTarget() { result = super.getTarget() }
|
||||
@@ -454,7 +438,7 @@ class ThrowExpr extends Expr, @throw_expr {
|
||||
*/
|
||||
Expr getExpr() { result = this.getChild(0) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ThrowExpr" }
|
||||
override string getCanonicalQLClass() { result = "ThrowExpr" }
|
||||
|
||||
override string toString() { result = "throw ..." }
|
||||
|
||||
@@ -470,7 +454,7 @@ class ThrowExpr extends Expr, @throw_expr {
|
||||
class ReThrowExpr extends ThrowExpr {
|
||||
ReThrowExpr() { this.getType() instanceof VoidType }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ReThrowExpr" }
|
||||
override string getCanonicalQLClass() { result = "ReThrowExpr" }
|
||||
|
||||
override string toString() { result = "re-throw exception " }
|
||||
}
|
||||
@@ -485,7 +469,7 @@ class ReThrowExpr extends ThrowExpr {
|
||||
class DestructorCall extends FunctionCall {
|
||||
DestructorCall() { super.getTarget() instanceof Destructor }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DestructorCall" }
|
||||
override string getCanonicalQLClass() { result = "DestructorCall" }
|
||||
|
||||
/** Gets the destructor being called. */
|
||||
override Destructor getTarget() { result = super.getTarget() }
|
||||
@@ -509,7 +493,7 @@ class VacuousDestructorCall extends Expr, @vacuous_destructor_call {
|
||||
*/
|
||||
Expr getQualifier() { result = this.getChild(0) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VacuousDestructorCall" }
|
||||
override string getCanonicalQLClass() { result = "VacuousDestructorCall" }
|
||||
|
||||
override string toString() { result = "(vacuous destructor call)" }
|
||||
}
|
||||
@@ -522,7 +506,7 @@ class VacuousDestructorCall extends Expr, @vacuous_destructor_call {
|
||||
* initializations.
|
||||
*/
|
||||
class ConstructorInit extends Expr, @ctorinit {
|
||||
override string getAPrimaryQlClass() { result = "ConstructorInit" }
|
||||
override string getCanonicalQLClass() { result = "ConstructorInit" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -530,7 +514,7 @@ class ConstructorInit extends Expr, @ctorinit {
|
||||
* initializer list or compiler-generated actions.
|
||||
*/
|
||||
class ConstructorBaseInit extends ConstructorInit, ConstructorCall {
|
||||
override string getAPrimaryQlClass() { result = "ConstructorBaseInit" }
|
||||
override string getCanonicalQLClass() { result = "ConstructorBaseInit" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -547,7 +531,7 @@ class ConstructorBaseInit extends ConstructorInit, ConstructorCall {
|
||||
* ```
|
||||
*/
|
||||
class ConstructorDirectInit extends ConstructorBaseInit, @ctordirectinit {
|
||||
override string getAPrimaryQlClass() { result = "ConstructorDirectInit" }
|
||||
override string getCanonicalQLClass() { result = "ConstructorDirectInit" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -567,7 +551,7 @@ class ConstructorDirectInit extends ConstructorBaseInit, @ctordirectinit {
|
||||
* ```
|
||||
*/
|
||||
class ConstructorVirtualInit extends ConstructorBaseInit, @ctorvirtualinit {
|
||||
override string getAPrimaryQlClass() { result = "ConstructorVirtualInit" }
|
||||
override string getCanonicalQLClass() { result = "ConstructorVirtualInit" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -582,7 +566,7 @@ class ConstructorVirtualInit extends ConstructorBaseInit, @ctorvirtualinit {
|
||||
* ```
|
||||
*/
|
||||
class ConstructorDelegationInit extends ConstructorBaseInit, @ctordelegatinginit {
|
||||
override string getAPrimaryQlClass() { result = "ConstructorDelegationInit" }
|
||||
override string getCanonicalQLClass() { result = "ConstructorDelegationInit" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -601,7 +585,7 @@ class ConstructorFieldInit extends ConstructorInit, @ctorfieldinit {
|
||||
/** Gets the field being initialized. */
|
||||
Field getTarget() { varbind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConstructorFieldInit" }
|
||||
override string getCanonicalQLClass() { result = "ConstructorFieldInit" }
|
||||
|
||||
/**
|
||||
* Gets the expression to which the field is initialized.
|
||||
@@ -623,7 +607,7 @@ class ConstructorFieldInit extends ConstructorInit, @ctorfieldinit {
|
||||
* compiler-generated actions.
|
||||
*/
|
||||
class DestructorDestruction extends Expr, @dtordestruct {
|
||||
override string getAPrimaryQlClass() { result = "DestructorDestruction" }
|
||||
override string getCanonicalQLClass() { result = "DestructorDestruction" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -631,7 +615,7 @@ class DestructorDestruction extends Expr, @dtordestruct {
|
||||
* compiler-generated actions.
|
||||
*/
|
||||
class DestructorBaseDestruction extends DestructorCall, DestructorDestruction {
|
||||
override string getAPrimaryQlClass() { result = "DestructorBaseDestruction" }
|
||||
override string getCanonicalQLClass() { result = "DestructorBaseDestruction" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -645,7 +629,7 @@ class DestructorBaseDestruction extends DestructorCall, DestructorDestruction {
|
||||
* ```
|
||||
*/
|
||||
class DestructorDirectDestruction extends DestructorBaseDestruction, @dtordirectdestruct {
|
||||
override string getAPrimaryQlClass() { result = "DestructorDirectDestruction" }
|
||||
override string getCanonicalQLClass() { result = "DestructorDirectDestruction" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -662,7 +646,7 @@ class DestructorDirectDestruction extends DestructorBaseDestruction, @dtordirect
|
||||
* ```
|
||||
*/
|
||||
class DestructorVirtualDestruction extends DestructorBaseDestruction, @dtorvirtualdestruct {
|
||||
override string getAPrimaryQlClass() { result = "DestructorVirtualDestruction" }
|
||||
override string getCanonicalQLClass() { result = "DestructorVirtualDestruction" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -680,7 +664,7 @@ class DestructorFieldDestruction extends DestructorDestruction, @dtorfielddestru
|
||||
/** Gets the field being destructed. */
|
||||
Field getTarget() { varbind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DestructorFieldDestruction" }
|
||||
override string getCanonicalQLClass() { result = "DestructorFieldDestruction" }
|
||||
|
||||
/** Gets the compiler-generated call to the variable's destructor. */
|
||||
DestructorCall getExpr() { result = this.getChild(0) }
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
/**
|
||||
* Provides classes for modeling C/C++ casts and conversions, as well as some
|
||||
* type-related operators such as `sizeof` and `alignof`.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
@@ -97,7 +92,7 @@ module CastConsistency {
|
||||
class CStyleCast extends Cast, @c_style_cast {
|
||||
override string toString() { result = "(" + this.getType().getName() + ")..." }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CStyleCast" }
|
||||
override string getCanonicalQLClass() { result = "CStyleCast" }
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
}
|
||||
@@ -116,7 +111,7 @@ class CStyleCast extends Cast, @c_style_cast {
|
||||
class StaticCast extends Cast, @static_cast {
|
||||
override string toString() { result = "static_cast<" + this.getType().getName() + ">..." }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "StaticCast" }
|
||||
override string getCanonicalQLClass() { result = "StaticCast" }
|
||||
|
||||
override int getPrecedence() { result = 17 }
|
||||
}
|
||||
@@ -134,7 +129,7 @@ class StaticCast extends Cast, @static_cast {
|
||||
class ConstCast extends Cast, @const_cast {
|
||||
override string toString() { result = "const_cast<" + this.getType().getName() + ">..." }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConstCast" }
|
||||
override string getCanonicalQLClass() { result = "ConstCast" }
|
||||
|
||||
override int getPrecedence() { result = 17 }
|
||||
}
|
||||
@@ -152,7 +147,7 @@ class ConstCast extends Cast, @const_cast {
|
||||
class ReinterpretCast extends Cast, @reinterpret_cast {
|
||||
override string toString() { result = "reinterpret_cast<" + this.getType().getName() + ">..." }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ReinterpretCast" }
|
||||
override string getCanonicalQLClass() { result = "ReinterpretCast" }
|
||||
|
||||
override int getPrecedence() { result = 17 }
|
||||
}
|
||||
@@ -208,7 +203,7 @@ class IntegralConversion extends ArithmeticConversion {
|
||||
isIntegralOrEnum(getExpr().getUnspecifiedType())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
override string getCanonicalQLClass() {
|
||||
not exists(qlCast(this)) and result = "IntegralConversion"
|
||||
}
|
||||
|
||||
@@ -228,7 +223,7 @@ class FloatingPointConversion extends ArithmeticConversion {
|
||||
getExpr().getUnspecifiedType() instanceof FloatingPointType
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
override string getCanonicalQLClass() {
|
||||
not exists(qlCast(this)) and result = "FloatingPointConversion"
|
||||
}
|
||||
|
||||
@@ -248,7 +243,7 @@ class FloatingPointToIntegralConversion extends ArithmeticConversion {
|
||||
getExpr().getUnspecifiedType() instanceof FloatingPointType
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
override string getCanonicalQLClass() {
|
||||
not exists(qlCast(this)) and result = "FloatingPointToIntegralConversion"
|
||||
}
|
||||
|
||||
@@ -268,7 +263,7 @@ class IntegralToFloatingPointConversion extends ArithmeticConversion {
|
||||
isIntegralOrEnum(getExpr().getUnspecifiedType())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
override string getCanonicalQLClass() {
|
||||
not exists(qlCast(this)) and result = "IntegralToFloatingPointConversion"
|
||||
}
|
||||
|
||||
@@ -294,7 +289,9 @@ class PointerConversion extends Cast {
|
||||
isPointerOrNullPointer(getExpr().getUnspecifiedType())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerConversion" }
|
||||
override string getCanonicalQLClass() {
|
||||
not exists(qlCast(this)) and result = "PointerConversion"
|
||||
}
|
||||
|
||||
override string getSemanticConversionString() { result = "pointer conversion" }
|
||||
}
|
||||
@@ -328,7 +325,7 @@ class PointerToMemberConversion extends Cast {
|
||||
)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
override string getCanonicalQLClass() {
|
||||
not exists(qlCast(this)) and result = "PointerToMemberConversion"
|
||||
}
|
||||
|
||||
@@ -349,7 +346,7 @@ class PointerToIntegralConversion extends Cast {
|
||||
isPointerOrNullPointer(getExpr().getUnspecifiedType())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
override string getCanonicalQLClass() {
|
||||
not exists(qlCast(this)) and result = "PointerToIntegralConversion"
|
||||
}
|
||||
|
||||
@@ -370,7 +367,7 @@ class IntegralToPointerConversion extends Cast {
|
||||
isIntegralOrEnum(getExpr().getUnspecifiedType())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
override string getCanonicalQLClass() {
|
||||
not exists(qlCast(this)) and result = "IntegralToPointerConversion"
|
||||
}
|
||||
|
||||
@@ -388,7 +385,7 @@ class IntegralToPointerConversion extends Cast {
|
||||
class BoolConversion extends Cast {
|
||||
BoolConversion() { conversionkinds(underlyingElement(this), 1) }
|
||||
|
||||
override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "BoolConversion" }
|
||||
override string getCanonicalQLClass() { not exists(qlCast(this)) and result = "BoolConversion" }
|
||||
|
||||
override string getSemanticConversionString() { result = "conversion to bool" }
|
||||
}
|
||||
@@ -406,7 +403,7 @@ class VoidConversion extends Cast {
|
||||
getUnspecifiedType() instanceof VoidType
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "VoidConversion" }
|
||||
override string getCanonicalQLClass() { not exists(qlCast(this)) and result = "VoidConversion" }
|
||||
|
||||
override string getSemanticConversionString() { result = "conversion to void" }
|
||||
}
|
||||
@@ -482,7 +479,7 @@ private Class getConversionClass(Expr expr) {
|
||||
class BaseClassConversion extends InheritanceConversion {
|
||||
BaseClassConversion() { conversionkinds(underlyingElement(this), 2) }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
override string getCanonicalQLClass() {
|
||||
not exists(qlCast(this)) and result = "BaseClassConversion"
|
||||
}
|
||||
|
||||
@@ -509,7 +506,7 @@ class BaseClassConversion extends InheritanceConversion {
|
||||
class DerivedClassConversion extends InheritanceConversion {
|
||||
DerivedClassConversion() { conversionkinds(underlyingElement(this), 3) }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
override string getCanonicalQLClass() {
|
||||
not exists(qlCast(this)) and result = "DerivedClassConversion"
|
||||
}
|
||||
|
||||
@@ -531,7 +528,7 @@ class DerivedClassConversion extends InheritanceConversion {
|
||||
class PointerToMemberBaseClassConversion extends Cast {
|
||||
PointerToMemberBaseClassConversion() { conversionkinds(underlyingElement(this), 4) }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
override string getCanonicalQLClass() {
|
||||
not exists(qlCast(this)) and result = "PointerToMemberBaseClassConversion"
|
||||
}
|
||||
|
||||
@@ -551,7 +548,7 @@ class PointerToMemberBaseClassConversion extends Cast {
|
||||
class PointerToMemberDerivedClassConversion extends Cast {
|
||||
PointerToMemberDerivedClassConversion() { conversionkinds(underlyingElement(this), 5) }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
override string getCanonicalQLClass() {
|
||||
not exists(qlCast(this)) and result = "PointerToMemberDerivedClassConversion"
|
||||
}
|
||||
|
||||
@@ -572,7 +569,9 @@ class PointerToMemberDerivedClassConversion extends Cast {
|
||||
class GlvalueConversion extends Cast {
|
||||
GlvalueConversion() { conversionkinds(underlyingElement(this), 6) }
|
||||
|
||||
override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "GlvalueConversion" }
|
||||
override string getCanonicalQLClass() {
|
||||
not exists(qlCast(this)) and result = "GlvalueConversion"
|
||||
}
|
||||
|
||||
override string getSemanticConversionString() { result = "glvalue conversion" }
|
||||
}
|
||||
@@ -598,7 +597,7 @@ class GlvalueConversion extends Cast {
|
||||
class PrvalueAdjustmentConversion extends Cast {
|
||||
PrvalueAdjustmentConversion() { conversionkinds(underlyingElement(this), 7) }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
override string getCanonicalQLClass() {
|
||||
not exists(qlCast(this)) and result = "PrvalueAdjustmentConversion"
|
||||
}
|
||||
|
||||
@@ -621,7 +620,7 @@ class DynamicCast extends Cast, @dynamic_cast {
|
||||
|
||||
override int getPrecedence() { result = 17 }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DynamicCast" }
|
||||
override string getCanonicalQLClass() { result = "DynamicCast" }
|
||||
|
||||
override string getSemanticConversionString() { result = "dynamic_cast" }
|
||||
}
|
||||
@@ -661,9 +660,6 @@ class UuidofOperator extends Expr, @uuidof {
|
||||
* ```
|
||||
*/
|
||||
class TypeidOperator extends Expr, @type_id {
|
||||
/**
|
||||
* Gets the type that is returned by this typeid expression.
|
||||
*/
|
||||
Type getResultType() { typeid_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
/**
|
||||
@@ -673,7 +669,7 @@ class TypeidOperator extends Expr, @type_id {
|
||||
*/
|
||||
deprecated Type getSpecifiedType() { result = this.getResultType() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TypeidOperator" }
|
||||
override string getCanonicalQLClass() { result = "TypeidOperator" }
|
||||
|
||||
/**
|
||||
* Gets the contained expression, if any (if this typeid contains
|
||||
@@ -703,7 +699,7 @@ class TypeidOperator extends Expr, @type_id {
|
||||
class SizeofPackOperator extends Expr, @sizeof_pack {
|
||||
override string toString() { result = "sizeof...(...)" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SizeofPackOperator" }
|
||||
override string getCanonicalQLClass() { result = "SizeofPackOperator" }
|
||||
|
||||
override predicate mayBeImpure() { none() }
|
||||
|
||||
@@ -726,7 +722,7 @@ class SizeofOperator extends Expr, @runtime_sizeof {
|
||||
class SizeofExprOperator extends SizeofOperator {
|
||||
SizeofExprOperator() { exists(Expr e | this.getChild(0) = e) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SizeofExprOperator" }
|
||||
override string getCanonicalQLClass() { result = "SizeofExprOperator" }
|
||||
|
||||
/** Gets the contained expression. */
|
||||
Expr getExprOperand() { result = this.getChild(0) }
|
||||
@@ -754,7 +750,7 @@ class SizeofExprOperator extends SizeofOperator {
|
||||
class SizeofTypeOperator extends SizeofOperator {
|
||||
SizeofTypeOperator() { sizeof_bind(underlyingElement(this), _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SizeofTypeOperator" }
|
||||
override string getCanonicalQLClass() { result = "SizeofTypeOperator" }
|
||||
|
||||
/** Gets the contained type. */
|
||||
Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
|
||||
@@ -833,7 +829,7 @@ class ArrayToPointerConversion extends Conversion, @array_to_pointer {
|
||||
/** Gets a textual representation of this conversion. */
|
||||
override string toString() { result = "array to pointer conversion" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ArrayToPointerConversion" }
|
||||
override string getCanonicalQLClass() { result = "ArrayToPointerConversion" }
|
||||
|
||||
override predicate mayBeImpure() { none() }
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* Provides classes for modeling comparisons such as `==`, `!=` and `<`.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
|
||||
/**
|
||||
@@ -25,7 +21,7 @@ class EqualityOperation extends ComparisonOperation, @eq_op_expr {
|
||||
* ```
|
||||
*/
|
||||
class EQExpr extends EqualityOperation, @eqexpr {
|
||||
override string getAPrimaryQlClass() { result = "EQExpr" }
|
||||
override string getCanonicalQLClass() { result = "EQExpr" }
|
||||
|
||||
override string getOperator() { result = "==" }
|
||||
}
|
||||
@@ -37,7 +33,7 @@ class EQExpr extends EqualityOperation, @eqexpr {
|
||||
* ```
|
||||
*/
|
||||
class NEExpr extends EqualityOperation, @neexpr {
|
||||
override string getAPrimaryQlClass() { result = "NEExpr" }
|
||||
override string getCanonicalQLClass() { result = "NEExpr" }
|
||||
|
||||
override string getOperator() { result = "!=" }
|
||||
}
|
||||
@@ -82,7 +78,7 @@ class RelationalOperation extends ComparisonOperation, @rel_op_expr {
|
||||
* ```
|
||||
*/
|
||||
class GTExpr extends RelationalOperation, @gtexpr {
|
||||
override string getAPrimaryQlClass() { result = "GTExpr" }
|
||||
override string getCanonicalQLClass() { result = "GTExpr" }
|
||||
|
||||
override string getOperator() { result = ">" }
|
||||
|
||||
@@ -98,7 +94,7 @@ class GTExpr extends RelationalOperation, @gtexpr {
|
||||
* ```
|
||||
*/
|
||||
class LTExpr extends RelationalOperation, @ltexpr {
|
||||
override string getAPrimaryQlClass() { result = "LTExpr" }
|
||||
override string getCanonicalQLClass() { result = "LTExpr" }
|
||||
|
||||
override string getOperator() { result = "<" }
|
||||
|
||||
@@ -114,7 +110,7 @@ class LTExpr extends RelationalOperation, @ltexpr {
|
||||
* ```
|
||||
*/
|
||||
class GEExpr extends RelationalOperation, @geexpr {
|
||||
override string getAPrimaryQlClass() { result = "GEExpr" }
|
||||
override string getCanonicalQLClass() { result = "GEExpr" }
|
||||
|
||||
override string getOperator() { result = ">=" }
|
||||
|
||||
@@ -130,7 +126,7 @@ class GEExpr extends RelationalOperation, @geexpr {
|
||||
* ```
|
||||
*/
|
||||
class LEExpr extends RelationalOperation, @leexpr {
|
||||
override string getAPrimaryQlClass() { result = "LEExpr" }
|
||||
override string getCanonicalQLClass() { result = "LEExpr" }
|
||||
|
||||
override string getOperator() { result = "<=" }
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* Provides classes modeling C/C++ expressions.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Element
|
||||
private import semmle.code.cpp.Enclosing
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
@@ -569,7 +565,7 @@ class BinaryOperation extends Operation, @bin_op_expr {
|
||||
class ParenthesizedBracedInitializerList extends Expr, @braced_init_list {
|
||||
override string toString() { result = "({...})" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ParenthesizedBracedInitializerList" }
|
||||
override string getCanonicalQLClass() { result = "ParenthesizedBracedInitializerList" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -584,7 +580,7 @@ class ParenthesizedBracedInitializerList extends Expr, @braced_init_list {
|
||||
class ParenthesisExpr extends Conversion, @parexpr {
|
||||
override string toString() { result = "(...)" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ParenthesisExpr" }
|
||||
override string getCanonicalQLClass() { result = "ParenthesisExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -595,7 +591,7 @@ class ParenthesisExpr extends Conversion, @parexpr {
|
||||
class ErrorExpr extends Expr, @errorexpr {
|
||||
override string toString() { result = "<error expr>" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ErrorExpr" }
|
||||
override string getCanonicalQLClass() { result = "ErrorExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -610,7 +606,7 @@ class ErrorExpr extends Expr, @errorexpr {
|
||||
class AssumeExpr extends Expr, @assume {
|
||||
override string toString() { result = "__assume(...)" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "AssumeExpr" }
|
||||
override string getCanonicalQLClass() { result = "AssumeExpr" }
|
||||
|
||||
/**
|
||||
* Gets the operand of the `__assume` expressions.
|
||||
@@ -625,7 +621,7 @@ class AssumeExpr extends Expr, @assume {
|
||||
* ```
|
||||
*/
|
||||
class CommaExpr extends Expr, @commaexpr {
|
||||
override string getAPrimaryQlClass() { result = "CommaExpr" }
|
||||
override string getCanonicalQLClass() { result = "CommaExpr" }
|
||||
|
||||
/**
|
||||
* Gets the left operand, which is the one whose value is discarded.
|
||||
@@ -660,7 +656,7 @@ class CommaExpr extends Expr, @commaexpr {
|
||||
* ```
|
||||
*/
|
||||
class AddressOfExpr extends UnaryOperation, @address_of {
|
||||
override string getAPrimaryQlClass() { result = "AddressOfExpr" }
|
||||
override string getCanonicalQLClass() { result = "AddressOfExpr" }
|
||||
|
||||
/** Gets the function or variable whose address is taken. */
|
||||
Declaration getAddressable() {
|
||||
@@ -692,7 +688,7 @@ class AddressOfExpr extends UnaryOperation, @address_of {
|
||||
class ReferenceToExpr extends Conversion, @reference_to {
|
||||
override string toString() { result = "(reference to)" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ReferenceToExpr" }
|
||||
override string getCanonicalQLClass() { result = "ReferenceToExpr" }
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
}
|
||||
@@ -706,7 +702,7 @@ class ReferenceToExpr extends Conversion, @reference_to {
|
||||
* ```
|
||||
*/
|
||||
class PointerDereferenceExpr extends UnaryOperation, @indirect {
|
||||
override string getAPrimaryQlClass() { result = "PointerDereferenceExpr" }
|
||||
override string getCanonicalQLClass() { result = "PointerDereferenceExpr" }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use getOperand() instead.
|
||||
@@ -744,7 +740,7 @@ class PointerDereferenceExpr extends UnaryOperation, @indirect {
|
||||
class ReferenceDereferenceExpr extends Conversion, @ref_indirect {
|
||||
override string toString() { result = "(reference dereference)" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ReferenceDereferenceExpr" }
|
||||
override string getCanonicalQLClass() { result = "ReferenceDereferenceExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -850,7 +846,7 @@ class NewOrNewArrayExpr extends Expr, @any_new_expr {
|
||||
class NewExpr extends NewOrNewArrayExpr, @new_expr {
|
||||
override string toString() { result = "new" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NewExpr" }
|
||||
override string getCanonicalQLClass() { result = "NewExpr" }
|
||||
|
||||
/**
|
||||
* Gets the type that is being allocated.
|
||||
@@ -880,7 +876,7 @@ class NewExpr extends NewOrNewArrayExpr, @new_expr {
|
||||
class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr {
|
||||
override string toString() { result = "new[]" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NewArrayExpr" }
|
||||
override string getCanonicalQLClass() { result = "NewArrayExpr" }
|
||||
|
||||
/**
|
||||
* Gets the type that is being allocated.
|
||||
@@ -928,7 +924,7 @@ class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr {
|
||||
class DeleteExpr extends Expr, @delete_expr {
|
||||
override string toString() { result = "delete" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DeleteExpr" }
|
||||
override string getCanonicalQLClass() { result = "DeleteExpr" }
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
|
||||
@@ -1002,7 +998,7 @@ class DeleteExpr extends Expr, @delete_expr {
|
||||
class DeleteArrayExpr extends Expr, @delete_array_expr {
|
||||
override string toString() { result = "delete[]" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DeleteArrayExpr" }
|
||||
override string getCanonicalQLClass() { result = "DeleteArrayExpr" }
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
|
||||
@@ -1082,7 +1078,7 @@ class StmtExpr extends Expr, @expr_stmt {
|
||||
*/
|
||||
Stmt getStmt() { result.getParent() = this }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "StmtExpr" }
|
||||
override string getCanonicalQLClass() { result = "StmtExpr" }
|
||||
|
||||
/**
|
||||
* Gets the result expression of the enclosed statement. For example,
|
||||
@@ -1107,7 +1103,7 @@ private Expr getStmtResultExpr(Stmt stmt) {
|
||||
class ThisExpr extends Expr, @thisaccess {
|
||||
override string toString() { result = "this" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ThisExpr" }
|
||||
override string getCanonicalQLClass() { result = "ThisExpr" }
|
||||
|
||||
override predicate mayBeImpure() { none() }
|
||||
|
||||
@@ -1143,7 +1139,7 @@ class BlockExpr extends Literal {
|
||||
class NoExceptExpr extends Expr, @noexceptexpr {
|
||||
override string toString() { result = "noexcept(...)" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NoExceptExpr" }
|
||||
override string getCanonicalQLClass() { result = "NoExceptExpr" }
|
||||
|
||||
/**
|
||||
* Gets the expression inside this noexcept expression.
|
||||
@@ -1175,7 +1171,7 @@ class FoldExpr extends Expr, @foldexpr {
|
||||
)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FoldExpr" }
|
||||
override string getCanonicalQLClass() { result = "FoldExpr" }
|
||||
|
||||
/** Gets the binary operator used in this fold expression, as a string. */
|
||||
string getOperatorString() { fold(underlyingElement(this), result, _) }
|
||||
@@ -1251,7 +1247,7 @@ private predicate constantTemplateLiteral(Expr e) {
|
||||
* ```
|
||||
*/
|
||||
class SpaceshipExpr extends BinaryOperation, @spaceshipexpr {
|
||||
override string getAPrimaryQlClass() { result = "SpaceshipExpr" }
|
||||
override string getCanonicalQLClass() { result = "SpaceshipExpr" }
|
||||
|
||||
override int getPrecedence() { result = 11 }
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* Provides classes for modeling lambda expressions and their captures.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
import semmle.code.cpp.Class
|
||||
|
||||
@@ -19,7 +15,7 @@ import semmle.code.cpp.Class
|
||||
class LambdaExpression extends Expr, @lambdaexpr {
|
||||
override string toString() { result = "[...](...){...}" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LambdaExpression" }
|
||||
override string getCanonicalQLClass() { result = "LambdaExpression" }
|
||||
|
||||
/**
|
||||
* Gets an implicitly or explicitly captured value of this lambda expression.
|
||||
@@ -79,7 +75,7 @@ class LambdaExpression extends Expr, @lambdaexpr {
|
||||
class Closure extends Class {
|
||||
Closure() { exists(LambdaExpression e | this = e.getType()) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Closure" }
|
||||
override string getCanonicalQLClass() { result = "Closure" }
|
||||
|
||||
/** Gets the lambda expression of which this is the type. */
|
||||
LambdaExpression getLambdaExpression() { result.getType() = this }
|
||||
@@ -105,7 +101,7 @@ class Closure extends Class {
|
||||
class LambdaCapture extends Locatable, @lambdacapture {
|
||||
override string toString() { result = getField().getName() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LambdaCapture" }
|
||||
override string getCanonicalQLClass() { result = "LambdaCapture" }
|
||||
|
||||
/**
|
||||
* Holds if this capture was made implicitly.
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
/**
|
||||
* Provides classes for modeling literals in the source code such as `0`, `'c'`
|
||||
* or `"string"`.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
|
||||
/**
|
||||
@@ -19,7 +14,7 @@ class Literal extends Expr, @literal {
|
||||
result = "Unknown literal"
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Literal" }
|
||||
override string getCanonicalQLClass() { result = "Literal" }
|
||||
|
||||
override predicate mayBeImpure() { none() }
|
||||
|
||||
@@ -40,7 +35,7 @@ class Literal extends Expr, @literal {
|
||||
class LabelLiteral extends Literal {
|
||||
LabelLiteral() { jumpinfo(underlyingElement(this), _, _) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LabelLiteral" }
|
||||
override string getCanonicalQLClass() { result = "LabelLiteral" }
|
||||
|
||||
/** Gets the corresponding label statement. */
|
||||
LabelStmt getLabel() { jumpinfo(underlyingElement(this), _, unresolveElement(result)) }
|
||||
@@ -98,7 +93,7 @@ abstract class TextLiteral extends Literal {
|
||||
class CharLiteral extends TextLiteral {
|
||||
CharLiteral() { this.getValueText().regexpMatch("(?s)\\s*L?'.*") }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CharLiteral" }
|
||||
override string getCanonicalQLClass() { result = "CharLiteral" }
|
||||
|
||||
/**
|
||||
* Gets the character of this literal. For example `L'a'` has character `"a"`.
|
||||
@@ -120,7 +115,7 @@ class StringLiteral extends TextLiteral {
|
||||
// @aggregateliteral rather than @literal.
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "StringLiteral" }
|
||||
override string getCanonicalQLClass() { result = "StringLiteral" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,7 +128,7 @@ class StringLiteral extends TextLiteral {
|
||||
class OctalLiteral extends Literal {
|
||||
OctalLiteral() { super.getValueText().regexpMatch("\\s*0[0-7]+[uUlL]*\\s*") }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "OctalLiteral" }
|
||||
override string getCanonicalQLClass() { result = "OctalLiteral" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,14 +140,14 @@ class OctalLiteral extends Literal {
|
||||
class HexLiteral extends Literal {
|
||||
HexLiteral() { super.getValueText().regexpMatch("\\s*0[xX][0-9a-fA-F]+[uUlL]*\\s*") }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "HexLiteral" }
|
||||
override string getCanonicalQLClass() { result = "HexLiteral" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ aggregate literal.
|
||||
*/
|
||||
class AggregateLiteral extends Expr, @aggregateliteral {
|
||||
override string getAPrimaryQlClass() { result = "AggregateLiteral" }
|
||||
override string getCanonicalQLClass() { result = "AggregateLiteral" }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use ClassAggregateLiteral.getFieldExpr() instead.
|
||||
@@ -184,7 +179,7 @@ class ClassAggregateLiteral extends AggregateLiteral {
|
||||
|
||||
ClassAggregateLiteral() { classType = this.getUnspecifiedType() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ClassAggregateLiteral" }
|
||||
override string getCanonicalQLClass() { result = "ClassAggregateLiteral" }
|
||||
|
||||
/**
|
||||
* Gets the expression within the aggregate literal that is used to initialize
|
||||
@@ -304,7 +299,7 @@ class ArrayAggregateLiteral extends ArrayOrVectorAggregateLiteral {
|
||||
|
||||
ArrayAggregateLiteral() { arrayType = this.getUnspecifiedType() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ArrayAggregateLiteral" }
|
||||
override string getCanonicalQLClass() { result = "ArrayAggregateLiteral" }
|
||||
|
||||
override int getArraySize() { result = arrayType.getArraySize() }
|
||||
|
||||
@@ -328,7 +323,7 @@ class VectorAggregateLiteral extends ArrayOrVectorAggregateLiteral {
|
||||
|
||||
VectorAggregateLiteral() { vectorType = this.getUnspecifiedType() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VectorAggregateLiteral" }
|
||||
override string getCanonicalQLClass() { result = "VectorAggregateLiteral" }
|
||||
|
||||
override int getArraySize() { result = vectorType.getNumElements() }
|
||||
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
/**
|
||||
* Provides classes for modeling logical operations such as `!`, `&&`, `||`, and
|
||||
* the ternary `? :` expression.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
|
||||
/**
|
||||
@@ -19,7 +14,7 @@ class UnaryLogicalOperation extends UnaryOperation, @un_log_op_expr { }
|
||||
class NotExpr extends UnaryLogicalOperation, @notexpr {
|
||||
override string getOperator() { result = "!" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NotExpr" }
|
||||
override string getCanonicalQLClass() { result = "NotExpr" }
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
}
|
||||
@@ -51,7 +46,7 @@ class BinaryLogicalOperation extends BinaryOperation, @bin_log_op_expr {
|
||||
class LogicalAndExpr extends BinaryLogicalOperation, @andlogicalexpr {
|
||||
override string getOperator() { result = "&&" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LogicalAndExpr" }
|
||||
override string getCanonicalQLClass() { result = "LogicalAndExpr" }
|
||||
|
||||
override int getPrecedence() { result = 5 }
|
||||
|
||||
@@ -72,7 +67,7 @@ class LogicalAndExpr extends BinaryLogicalOperation, @andlogicalexpr {
|
||||
class LogicalOrExpr extends BinaryLogicalOperation, @orlogicalexpr {
|
||||
override string getOperator() { result = "||" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LogicalOrExpr" }
|
||||
override string getCanonicalQLClass() { result = "LogicalOrExpr" }
|
||||
|
||||
override int getPrecedence() { result = 4 }
|
||||
|
||||
@@ -94,7 +89,7 @@ class ConditionalExpr extends Operation, @conditionalexpr {
|
||||
/** Gets the condition of this conditional expression. */
|
||||
Expr getCondition() { expr_cond_guard(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConditionalExpr" }
|
||||
override string getCanonicalQLClass() { result = "ConditionalExpr" }
|
||||
|
||||
/** Gets the 'then' expression of this conditional expression. */
|
||||
Expr getThen() {
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* DEPRECATED: Objective-C is no longer supported.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
import semmle.code.cpp.Class
|
||||
import semmle.code.cpp.ObjectiveC
|
||||
|
||||
@@ -1,47 +1,3 @@
|
||||
/**
|
||||
* Provides classes that describe the Intermediate Representation (IR) of the program.
|
||||
*
|
||||
* The IR is a representation of the semantics of the program, with very little dependence on the
|
||||
* syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`,
|
||||
* and `++i` all have the same semantic effect, but appear in the AST as three different types of
|
||||
* `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental
|
||||
* operations similar to:
|
||||
*
|
||||
* ```
|
||||
* r1(int*) = VariableAddress[i] // Compute the address of variable `i`
|
||||
* r2(int) = Load &:r1, m0 // Load the value of `i`
|
||||
* r3(int) = Constant[1] // An integer constant with the value `1`
|
||||
* r4(int) = Add r2, r3 // Add `1` to the value of `i`
|
||||
* r5(int) = Store &r1, r4 // Store the new value back into the variable `i`
|
||||
* ```
|
||||
*
|
||||
* This allows IR-based analysis to focus on the fundamental operations, rather than having to be
|
||||
* concerned with the various ways of expressing those operations in source code.
|
||||
*
|
||||
* The key classes in the IR are:
|
||||
*
|
||||
* - `IRFunction` - Contains the IR for an entire function definition, including all of that
|
||||
* function's `Instruction`s, `IRBlock`s, and `IRVariables`.
|
||||
* - `Instruction` - A single operation in the IR. An instruction specifies the operation to be
|
||||
* performed, the operands that produce the inputs to that operation, and the type of the result
|
||||
* of the operation. Control flows from an `Instruction` to one of a set of successor
|
||||
* `Instruction`s.
|
||||
* - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly
|
||||
* represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has
|
||||
* a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction`
|
||||
* that produces its value (its "definition").
|
||||
* - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is
|
||||
* created for each variable directly accessed by the function. In addition, `IRVariable`s are
|
||||
* created to represent certain temporary storage locations that do not have explicitly declared
|
||||
* variables in the source code, such as the return value of the function.
|
||||
* - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a
|
||||
* sequence of instructions such that control flow can only enter the block at the first
|
||||
* instruction, and can only leave the block from the last instruction.
|
||||
* - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType`
|
||||
* is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all
|
||||
* be represented as the `IRType` `uint4`, a four-byte unsigned integer.
|
||||
*/
|
||||
|
||||
// Most queries should operate on the aliased SSA IR, so that's what we expose
|
||||
// publicly as the "IR".
|
||||
// publically as the "IR".
|
||||
import implementation.aliased_ssa.IR
|
||||
|
||||
@@ -1,5 +1 @@
|
||||
/**
|
||||
* Module used to configure the IR generation process.
|
||||
*/
|
||||
|
||||
import implementation.IRConfiguration
|
||||
|
||||
@@ -1,11 +1 @@
|
||||
/**
|
||||
* Outputs a representation of the IR as a control flow graph.
|
||||
*
|
||||
* This file contains the actual implementation of `PrintIR.ql`. For test cases and very small
|
||||
* databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most
|
||||
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
|
||||
* `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to
|
||||
* dump.
|
||||
*/
|
||||
|
||||
import implementation.aliased_ssa.PrintIR
|
||||
|
||||
@@ -70,7 +70,7 @@ private DataFlow::Node getNodeForSource(Expr source) {
|
||||
//
|
||||
// This case goes together with the similar (but not identical) rule in
|
||||
// `nodeIsBarrierIn`.
|
||||
result = DataFlow::definitionByReferenceNodeFromArgument(source) and
|
||||
result = DataFlow::definitionByReferenceNode(source) and
|
||||
not argv(source.(VariableAccess).getTarget())
|
||||
)
|
||||
}
|
||||
@@ -210,7 +210,7 @@ private predicate nodeIsBarrierIn(DataFlow::Node node) {
|
||||
or
|
||||
// This case goes together with the similar (but not identical) rule in
|
||||
// `getNodeForSource`.
|
||||
node = DataFlow::definitionByReferenceNodeFromArgument(source)
|
||||
node = DataFlow::definitionByReferenceNode(source)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -226,13 +226,28 @@ private predicate functionSignature(Function f, string qualifiedName, int nparam
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the set of viable implementations that can be called by `call`
|
||||
* might be improved by knowing the call context.
|
||||
* Holds if the call context `ctx` reduces the set of viable dispatch
|
||||
* targets of `ma` in `c`.
|
||||
*/
|
||||
predicate mayBenefitFromCallContext(CallInstruction call, Function f) { none() }
|
||||
predicate reducedViableImplInCallContext(CallInstruction call, Function f, CallInstruction ctx) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference.
|
||||
* Gets a viable dispatch target of `ma` in the context `ctx`. This is
|
||||
* restricted to those `ma`s for which the context makes a difference.
|
||||
*/
|
||||
Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) { none() }
|
||||
Function prunedViableImplInCallContext(CallInstruction call, CallInstruction ctx) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow returning from `m` to `ma` might return further and if
|
||||
* this path restricts the set of call sites that can be returned to.
|
||||
*/
|
||||
predicate reducedViableImplInReturn(Function f, CallInstruction call) { none() }
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `ma` in the context `ctx`. This is
|
||||
* restricted to those `ma`s and results for which the return flow from the
|
||||
* result to `ma` restricts the possible context `ctx`.
|
||||
*/
|
||||
Function prunedViableImplInCallContextReverse(CallInstruction call, CallInstruction ctx) { none() }
|
||||
|
||||
@@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
@@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
@@ -1051,17 +1051,6 @@ private predicate flowIntoCallNodeCand2(
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
/**
|
||||
* A node where some checking is required, and hence the big-step relation
|
||||
* is not allowed to step over.
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
@@ -1076,7 +1065,7 @@ private module LocalFlowBigStep {
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1094,7 +1083,7 @@ private module LocalFlowBigStep {
|
||||
read(node, _, next)
|
||||
)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
or
|
||||
config.isSink(node)
|
||||
}
|
||||
@@ -1124,11 +1113,11 @@ private module LocalFlowBigStep {
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1138,16 +1127,16 @@ private module LocalFlowBigStep {
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1201,8 +1190,9 @@ private predicate flowCandFwd(
|
||||
Configuration config
|
||||
) {
|
||||
flowCandFwd0(node, fromArg, argApf, apf, config) and
|
||||
not apf.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), apf.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1214,7 +1204,7 @@ private predicate flowCandFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, argApf, apf, config) and
|
||||
@@ -1240,7 +1230,7 @@ private predicate flowCandFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
// store
|
||||
@@ -1670,7 +1660,7 @@ private predicate flowFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
@@ -1698,7 +1688,7 @@ private predicate flowFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
)
|
||||
@@ -2075,7 +2065,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2302,7 +2292,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2644,7 +2634,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -2661,7 +2651,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -2774,7 +2764,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -2790,7 +2780,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -2804,7 +2794,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
|
||||
@@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
@@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
@@ -1051,17 +1051,6 @@ private predicate flowIntoCallNodeCand2(
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
/**
|
||||
* A node where some checking is required, and hence the big-step relation
|
||||
* is not allowed to step over.
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
@@ -1076,7 +1065,7 @@ private module LocalFlowBigStep {
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1094,7 +1083,7 @@ private module LocalFlowBigStep {
|
||||
read(node, _, next)
|
||||
)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
or
|
||||
config.isSink(node)
|
||||
}
|
||||
@@ -1124,11 +1113,11 @@ private module LocalFlowBigStep {
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1138,16 +1127,16 @@ private module LocalFlowBigStep {
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1201,8 +1190,9 @@ private predicate flowCandFwd(
|
||||
Configuration config
|
||||
) {
|
||||
flowCandFwd0(node, fromArg, argApf, apf, config) and
|
||||
not apf.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), apf.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1214,7 +1204,7 @@ private predicate flowCandFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, argApf, apf, config) and
|
||||
@@ -1240,7 +1230,7 @@ private predicate flowCandFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
// store
|
||||
@@ -1670,7 +1660,7 @@ private predicate flowFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
@@ -1698,7 +1688,7 @@ private predicate flowFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
)
|
||||
@@ -2075,7 +2065,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2302,7 +2292,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2644,7 +2634,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -2661,7 +2651,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -2774,7 +2764,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -2790,7 +2780,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -2804,7 +2794,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
|
||||
@@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
@@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
@@ -1051,17 +1051,6 @@ private predicate flowIntoCallNodeCand2(
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
/**
|
||||
* A node where some checking is required, and hence the big-step relation
|
||||
* is not allowed to step over.
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
@@ -1076,7 +1065,7 @@ private module LocalFlowBigStep {
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1094,7 +1083,7 @@ private module LocalFlowBigStep {
|
||||
read(node, _, next)
|
||||
)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
or
|
||||
config.isSink(node)
|
||||
}
|
||||
@@ -1124,11 +1113,11 @@ private module LocalFlowBigStep {
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1138,16 +1127,16 @@ private module LocalFlowBigStep {
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1201,8 +1190,9 @@ private predicate flowCandFwd(
|
||||
Configuration config
|
||||
) {
|
||||
flowCandFwd0(node, fromArg, argApf, apf, config) and
|
||||
not apf.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), apf.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1214,7 +1204,7 @@ private predicate flowCandFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, argApf, apf, config) and
|
||||
@@ -1240,7 +1230,7 @@ private predicate flowCandFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
// store
|
||||
@@ -1670,7 +1660,7 @@ private predicate flowFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
@@ -1698,7 +1688,7 @@ private predicate flowFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
)
|
||||
@@ -2075,7 +2065,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2302,7 +2292,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2644,7 +2634,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -2661,7 +2651,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -2774,7 +2764,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -2790,7 +2780,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -2804,7 +2794,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
|
||||
@@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
@@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
@@ -1051,17 +1051,6 @@ private predicate flowIntoCallNodeCand2(
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
/**
|
||||
* A node where some checking is required, and hence the big-step relation
|
||||
* is not allowed to step over.
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` can be the first node in a maximal subsequence of local
|
||||
* flow steps in a dataflow path.
|
||||
@@ -1076,7 +1065,7 @@ private module LocalFlowBigStep {
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1094,7 +1083,7 @@ private module LocalFlowBigStep {
|
||||
read(node, _, next)
|
||||
)
|
||||
or
|
||||
node instanceof FlowCheckNode
|
||||
node instanceof CastNode
|
||||
or
|
||||
config.isSink(node)
|
||||
}
|
||||
@@ -1124,11 +1113,11 @@ private module LocalFlowBigStep {
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getErasedNodeTypeBound(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getErasedNodeTypeBound(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
@@ -1138,16 +1127,16 @@ private module LocalFlowBigStep {
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getErasedNodeTypeBound(node2) and
|
||||
nodeCand2(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
@@ -1201,8 +1190,9 @@ private predicate flowCandFwd(
|
||||
Configuration config
|
||||
) {
|
||||
flowCandFwd0(node, fromArg, argApf, apf, config) and
|
||||
not apf.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), apf.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1214,7 +1204,7 @@ private predicate flowCandFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, argApf, apf, config) and
|
||||
@@ -1240,7 +1230,7 @@ private predicate flowCandFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argApf = TAccessPathFrontNone() and
|
||||
apf = TFrontNil(getNodeType(node))
|
||||
apf = TFrontNil(getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
// store
|
||||
@@ -1670,7 +1660,7 @@ private predicate flowFwd0(
|
||||
config.isSource(node) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
or
|
||||
flowCand(node, _, _, _, unbind(config)) and
|
||||
@@ -1698,7 +1688,7 @@ private predicate flowFwd0(
|
||||
additionalJumpStep(mid, node, config) and
|
||||
fromArg = false and
|
||||
argAp = TAccessPathNone() and
|
||||
ap = TNil(getNodeType(node)) and
|
||||
ap = TNil(getErasedNodeTypeBound(node)) and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
)
|
||||
@@ -2075,7 +2065,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2302,7 +2292,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TNil(getNodeType(node))
|
||||
ap = TNil(getErasedNodeTypeBound(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -2644,7 +2634,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -2661,7 +2651,7 @@ private module FlowExploration {
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getErasedNodeTypeBound(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -2774,7 +2764,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -2790,7 +2780,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getErasedNodeTypeBound(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -2804,7 +2794,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
|
||||
@@ -22,7 +22,7 @@ private module Cached {
|
||||
exists(int i |
|
||||
viableParam(call, i, p) and
|
||||
arg.argumentOf(call, i) and
|
||||
compatibleTypes(getNodeType(arg), getNodeType(p))
|
||||
compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(p))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -147,6 +147,54 @@ private module Cached {
|
||||
}
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
private predicate localFlowEntry(Node n) {
|
||||
Cand::cand(_, n) and
|
||||
(
|
||||
n instanceof ParameterNode or
|
||||
n instanceof OutNode or
|
||||
readStep(_, _, n) or
|
||||
n instanceof CastNode
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localFlowExit(Node n) {
|
||||
Cand::cand(_, n) and
|
||||
(
|
||||
n instanceof ArgumentNode
|
||||
or
|
||||
n instanceof ReturnNode
|
||||
or
|
||||
readStep(n, _, _)
|
||||
or
|
||||
n instanceof CastNode
|
||||
or
|
||||
n =
|
||||
any(PostUpdateNode pun | Cand::parameterValueFlowsToPreUpdateCand(_, pun))
|
||||
.getPreUpdateNode()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(Node node1, Node node2) {
|
||||
localFlowEntry(node1) and
|
||||
simpleLocalFlowStep(node1, node2) and
|
||||
node1 != node2
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid) and
|
||||
simpleLocalFlowStep(mid, node2) and
|
||||
not mid instanceof CastNode
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate localFlowBigStep(Node node1, Node node2) {
|
||||
localFlowStepPlus(node1, node2) and
|
||||
localFlowExit(node2)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The final flow-through calculation:
|
||||
*
|
||||
@@ -170,10 +218,10 @@ private module Cached {
|
||||
then
|
||||
// normal flow through
|
||||
read = TReadStepTypesNone() and
|
||||
compatibleTypes(getNodeType(p), getNodeType(node))
|
||||
compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node))
|
||||
or
|
||||
// getter
|
||||
compatibleTypes(read.getContentType(), getNodeType(node))
|
||||
compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node))
|
||||
else any()
|
||||
}
|
||||
|
||||
@@ -186,7 +234,7 @@ private module Cached {
|
||||
// local flow
|
||||
exists(Node mid |
|
||||
parameterValueFlow(p, mid, read) and
|
||||
simpleLocalFlowStep(mid, node)
|
||||
LocalFlowBigStep::localFlowBigStep(mid, node)
|
||||
)
|
||||
or
|
||||
// read
|
||||
@@ -195,26 +243,19 @@ private module Cached {
|
||||
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
|
||||
read.getContentType()) and
|
||||
Cand::parameterValueFlowReturnCand(p, _, true) and
|
||||
compatibleTypes(getNodeType(p), read.getContainerType())
|
||||
compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType())
|
||||
)
|
||||
or
|
||||
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlow0_0(
|
||||
ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read
|
||||
) {
|
||||
// flow through: no prior read
|
||||
exists(ArgumentNode arg |
|
||||
parameterValueFlowArg(p, arg, mustBeNone) and
|
||||
parameterValueFlowArg(p, arg, TReadStepTypesNone()) and
|
||||
argumentValueFlowsThrough(arg, read, node)
|
||||
)
|
||||
or
|
||||
// flow through: no read inside method
|
||||
exists(ArgumentNode arg |
|
||||
parameterValueFlowArg(p, arg, read) and
|
||||
argumentValueFlowsThrough(arg, mustBeNone, node)
|
||||
argumentValueFlowsThrough(arg, TReadStepTypesNone(), node)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -251,11 +292,11 @@ private module Cached {
|
||||
|
|
||||
// normal flow through
|
||||
read = TReadStepTypesNone() and
|
||||
compatibleTypes(getNodeType(arg), getNodeType(out))
|
||||
compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out))
|
||||
or
|
||||
// getter
|
||||
compatibleTypes(getNodeType(arg), read.getContainerType()) and
|
||||
compatibleTypes(read.getContentType(), getNodeType(out))
|
||||
compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and
|
||||
compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -289,67 +330,6 @@ private module Cached {
|
||||
import Final
|
||||
}
|
||||
|
||||
import FlowThrough
|
||||
|
||||
cached
|
||||
private module DispatchWithCallContext {
|
||||
/**
|
||||
* Holds if the call context `ctx` reduces the set of viable run-time
|
||||
* dispatch targets of call `call` in `c`.
|
||||
*/
|
||||
cached
|
||||
predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) {
|
||||
exists(int tgts, int ctxtgts |
|
||||
mayBenefitFromCallContext(call, c) and
|
||||
c = viableCallable(ctx) and
|
||||
ctxtgts = count(viableImplInCallContext(call, ctx)) and
|
||||
tgts = strictcount(viableCallable(call)) and
|
||||
ctxtgts < tgts
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable run-time dispatch target for the call `call` in the
|
||||
* context `ctx`. This is restricted to those calls for which a context
|
||||
* makes a difference.
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
reducedViableImplInCallContext(call, _, ctx)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if flow returning from callable `c` to call `call` might return
|
||||
* further and if this path restricts the set of call sites that can be
|
||||
* returned to.
|
||||
*/
|
||||
cached
|
||||
predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) {
|
||||
exists(int tgts, int ctxtgts |
|
||||
mayBenefitFromCallContext(call, _) and
|
||||
c = viableCallable(call) and
|
||||
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and
|
||||
tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and
|
||||
ctxtgts < tgts
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable run-time dispatch target for the call `call` in the
|
||||
* context `ctx`. This is restricted to those calls and results for which
|
||||
* the return flow from the result to `call` restricts the possible context
|
||||
* `ctx`.
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
reducedViableImplInReturn(result, call)
|
||||
}
|
||||
}
|
||||
|
||||
import DispatchWithCallContext
|
||||
|
||||
/**
|
||||
* Holds if `p` can flow to the pre-update node associated with post-update
|
||||
* node `n`, in the same callable, using only value-preserving steps.
|
||||
@@ -364,8 +344,8 @@ private module Cached {
|
||||
) {
|
||||
storeStep(node1, c, node2) and
|
||||
readStep(_, c, _) and
|
||||
contentType = getNodeType(node1) and
|
||||
containerType = getNodeType(node2)
|
||||
contentType = getErasedNodeTypeBound(node1) and
|
||||
containerType = getErasedNodeTypeBound(node2)
|
||||
or
|
||||
exists(Node n1, Node n2 |
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
@@ -374,8 +354,8 @@ private module Cached {
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
||||
or
|
||||
readStep(n2, c, n1) and
|
||||
contentType = getNodeType(n1) and
|
||||
containerType = getNodeType(n2)
|
||||
contentType = getErasedNodeTypeBound(n1) and
|
||||
containerType = getErasedNodeTypeBound(n2)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -391,6 +371,8 @@ private module Cached {
|
||||
store(node1, tc.getContent(), node2, contentType, tc.getContainerType())
|
||||
}
|
||||
|
||||
import FlowThrough
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` either improves virtual dispatch in
|
||||
* `callable` or if it allows us to prune unreachable nodes in `callable`.
|
||||
@@ -466,8 +448,8 @@ private predicate readStepWithTypes(
|
||||
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
|
||||
) {
|
||||
readStep(n1, c, n2) and
|
||||
container = getNodeType(n1) and
|
||||
content = getNodeType(n2)
|
||||
container = getErasedNodeTypeBound(n1) and
|
||||
content = getErasedNodeTypeBound(n2)
|
||||
}
|
||||
|
||||
private newtype TReadStepTypesOption =
|
||||
@@ -730,6 +712,9 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
|
||||
result = viableCallable(call) and cc instanceof CallContextReturn
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) }
|
||||
|
||||
predicate read = readStep/3;
|
||||
|
||||
/** An optional Boolean value. */
|
||||
@@ -769,13 +754,6 @@ abstract class AccessPathFront extends TAccessPathFront {
|
||||
abstract boolean toBoolNonEmpty();
|
||||
|
||||
predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) }
|
||||
|
||||
predicate isClearedAt(Node n) {
|
||||
exists(TypedContent tc |
|
||||
this.headUsesContent(tc) and
|
||||
clearsContent(n, tc.getContent())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||
|
||||
@@ -37,12 +37,21 @@ module Consistency {
|
||||
)
|
||||
}
|
||||
|
||||
query predicate uniqueType(Node n, string msg) {
|
||||
query predicate uniqueTypeBound(Node n, string msg) {
|
||||
exists(int c |
|
||||
n instanceof RelevantNode and
|
||||
c = count(getNodeType(n)) and
|
||||
c = count(n.getTypeBound()) and
|
||||
c != 1 and
|
||||
msg = "Node should have one type but has " + c + "."
|
||||
msg = "Node should have one type bound but has " + c + "."
|
||||
)
|
||||
}
|
||||
|
||||
query predicate uniqueTypeRepr(Node n, string msg) {
|
||||
exists(int c |
|
||||
n instanceof RelevantNode and
|
||||
c = count(getErasedRepr(n.getTypeBound())) and
|
||||
c != 1 and
|
||||
msg = "Node should have one type representation but has " + c + "."
|
||||
)
|
||||
}
|
||||
|
||||
@@ -95,7 +104,7 @@ module Consistency {
|
||||
msg = "Local flow step does not preserve enclosing callable."
|
||||
}
|
||||
|
||||
private DataFlowType typeRepr() { result = getNodeType(_) }
|
||||
private DataFlowType typeRepr() { result = getErasedRepr(any(Node n).getTypeBound()) }
|
||||
|
||||
query predicate compatibleTypesReflexive(DataFlowType t, string msg) {
|
||||
t = typeRepr() and
|
||||
|
||||
@@ -227,31 +227,28 @@ predicate readStep(Node node1, Content f, Node node2) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared at node `n`.
|
||||
* Gets a representative (boxed) type for `t` for the purpose of pruning
|
||||
* possible flow. A single type is used for all numeric types to account for
|
||||
* numeric conversions, and otherwise the erasure is used.
|
||||
*/
|
||||
predicate clearsContent(Node n, Content c) {
|
||||
none() // stub implementation
|
||||
Type getErasedRepr(Type t) {
|
||||
suppressUnusedType(t) and
|
||||
result instanceof VoidType // stub implementation
|
||||
}
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
IRType getNodeType(Node n) {
|
||||
suppressUnusedNode(n) and
|
||||
result instanceof IRVoidType // stub implementation
|
||||
}
|
||||
|
||||
/** Gets a string representation of a type returned by `getNodeType`. */
|
||||
string ppReprType(IRType t) { none() } // stub implementation
|
||||
/** Gets a string representation of a type returned by `getErasedRepr`. */
|
||||
string ppReprType(Type t) { none() } // stub implementation
|
||||
|
||||
/**
|
||||
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
|
||||
* a node of type `t1` to a node of type `t2`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate compatibleTypes(IRType t1, IRType t2) {
|
||||
predicate compatibleTypes(Type t1, Type t2) {
|
||||
any() // stub implementation
|
||||
}
|
||||
|
||||
private predicate suppressUnusedNode(Node n) { any() }
|
||||
private predicate suppressUnusedType(Type t) { any() }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Java QL library compatibility wrappers
|
||||
@@ -271,7 +268,7 @@ class DataFlowCallable = Declaration;
|
||||
|
||||
class DataFlowExpr = Expr;
|
||||
|
||||
class DataFlowType = IRType;
|
||||
class DataFlowType = Type;
|
||||
|
||||
/** A function call relevant for data flow. */
|
||||
class DataFlowCall extends CallInstruction {
|
||||
@@ -303,4 +300,4 @@ predicate isImmutableOrUnobservable(Node n) {
|
||||
}
|
||||
|
||||
/** Holds if `n` should be hidden from path explanations. */
|
||||
predicate nodeIsHidden(Node n) { n instanceof OperandNode }
|
||||
predicate nodeIsHidden(Node n) { none() }
|
||||
|
||||
@@ -13,7 +13,6 @@ private import semmle.code.cpp.models.interfaces.DataFlow
|
||||
|
||||
private newtype TIRDataFlowNode =
|
||||
TInstructionNode(Instruction i) or
|
||||
TOperandNode(Operand op) or
|
||||
TVariableNode(Variable var)
|
||||
|
||||
/**
|
||||
@@ -33,23 +32,15 @@ class Node extends TIRDataFlowNode {
|
||||
Function getFunction() { none() } // overridden in subclasses
|
||||
|
||||
/** Gets the type of this node. */
|
||||
IRType getType() { none() } // overridden in subclasses
|
||||
Type getType() { none() } // overridden in subclasses
|
||||
|
||||
/** Gets the instruction corresponding to this node, if any. */
|
||||
Instruction asInstruction() { result = this.(InstructionNode).getInstruction() }
|
||||
|
||||
/** Gets the operands corresponding to this node, if any. */
|
||||
Operand asOperand() { result = this.(OperandNode).getOperand() }
|
||||
|
||||
/**
|
||||
* Gets the non-conversion expression corresponding to this node, if any.
|
||||
* This predicate only has a result on nodes that represent the value of
|
||||
* evaluating the expression. For data flowing _out of_ an expression, like
|
||||
* when an argument is passed by reference, use `asDefiningArgument` instead
|
||||
* of `asExpr`.
|
||||
*
|
||||
* If this node strictly (in the sense of `asConvertedExpr`) corresponds to
|
||||
* a `Conversion`, then the result is the underlying non-`Conversion` base
|
||||
* Gets the non-conversion expression corresponding to this node, if any. If
|
||||
* this node strictly (in the sense of `asConvertedExpr`) corresponds to a
|
||||
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
|
||||
* expression.
|
||||
*/
|
||||
Expr asExpr() { result = this.(ExprNode).getExpr() }
|
||||
@@ -60,13 +51,7 @@ class Node extends TIRDataFlowNode {
|
||||
*/
|
||||
Expr asConvertedExpr() { result = this.(ExprNode).getConvertedExpr() }
|
||||
|
||||
/**
|
||||
* Gets the argument that defines this `DefinitionByReferenceNode`, if any.
|
||||
* This predicate should be used instead of `asExpr` when referring to the
|
||||
* value of a reference argument _after_ the call has returned. For example,
|
||||
* in `f(&x)`, this predicate will have `&x` as its result for the `Node`
|
||||
* that represents the new value of `x`.
|
||||
*/
|
||||
/** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */
|
||||
Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() }
|
||||
|
||||
/** Gets the positional parameter corresponding to this node, if any. */
|
||||
@@ -74,7 +59,7 @@ class Node extends TIRDataFlowNode {
|
||||
|
||||
/**
|
||||
* Gets the variable corresponding to this node, if any. This can be used for
|
||||
* modeling flow in and out of global variables.
|
||||
* modelling flow in and out of global variables.
|
||||
*/
|
||||
Variable asVariable() { result = this.(VariableNode).getVariable() }
|
||||
|
||||
@@ -99,7 +84,7 @@ class Node extends TIRDataFlowNode {
|
||||
/**
|
||||
* Gets an upper bound on the type of this node.
|
||||
*/
|
||||
IRType getTypeBound() { result = getType() }
|
||||
Type getTypeBound() { result = getType() }
|
||||
|
||||
/** Gets the location of this element. */
|
||||
Location getLocation() { none() } // overridden by subclasses
|
||||
@@ -136,7 +121,7 @@ class InstructionNode extends Node, TInstructionNode {
|
||||
|
||||
override Function getFunction() { result = instr.getEnclosingFunction() }
|
||||
|
||||
override IRType getType() { result = instr.getResultIRType() }
|
||||
override Type getType() { result = instr.getResultType() }
|
||||
|
||||
override Location getLocation() { result = instr.getLocation() }
|
||||
|
||||
@@ -147,28 +132,6 @@ class InstructionNode extends Node, TInstructionNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand, viewed as a node in a data flow graph.
|
||||
*/
|
||||
class OperandNode extends Node, TOperandNode {
|
||||
Operand op;
|
||||
|
||||
OperandNode() { this = TOperandNode(op) }
|
||||
|
||||
/** Gets the operand corresponding to this node. */
|
||||
Operand getOperand() { result = op }
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override Function getFunction() { result = op.getUse().getEnclosingFunction() }
|
||||
|
||||
override IRType getType() { result = op.getIRType() }
|
||||
|
||||
override Location getLocation() { result = op.getLocation() }
|
||||
|
||||
override string toString() { result = this.getOperand().toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression, viewed as a node in a data flow graph.
|
||||
*/
|
||||
@@ -328,7 +291,7 @@ abstract class PostUpdateNode extends InstructionNode {
|
||||
* setY(&x); // a partial definition of the object `x`.
|
||||
* ```
|
||||
*/
|
||||
abstract private class PartialDefinitionNode extends PostUpdateNode {
|
||||
abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode {
|
||||
abstract Expr getDefinedExpr();
|
||||
}
|
||||
|
||||
@@ -343,11 +306,11 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
|
||||
)
|
||||
}
|
||||
|
||||
// By using an operand as the result of this predicate we avoid the dataflow inconsistency errors
|
||||
// caused by having multiple nodes sharing the same pre update node. This inconsistency error can cause
|
||||
// a tuple explosion in the big step dataflow relation since it can make many nodes be the entry node
|
||||
// into a big step.
|
||||
override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() }
|
||||
// There might be multiple `ChiInstructions` that has a particular instruction as
|
||||
// the total operand - so this definition gives consistency errors in
|
||||
// DataFlowImplConsistency::Consistency. However, it's not clear what (if any) implications
|
||||
// this consistency failure has.
|
||||
override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() }
|
||||
|
||||
override Expr getDefinedExpr() {
|
||||
result = field.getObjectAddress().getUnconvertedResultExpression()
|
||||
@@ -389,7 +352,7 @@ private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNod
|
||||
class DefinitionByReferenceNode extends InstructionNode {
|
||||
override WriteSideEffectInstruction instr;
|
||||
|
||||
/** Gets the unconverted argument corresponding to this node. */
|
||||
/** Gets the argument corresponding to this node. */
|
||||
Expr getArgument() {
|
||||
result =
|
||||
instr
|
||||
@@ -439,7 +402,7 @@ private class ArgumentIndirectionNode extends InstructionNode {
|
||||
/**
|
||||
* A `Node` corresponding to a variable in the program, as opposed to the
|
||||
* value of that variable at some particular point. This can be used for
|
||||
* modeling flow in and out of global variables.
|
||||
* modelling flow in and out of global variables.
|
||||
*/
|
||||
class VariableNode extends Node, TVariableNode {
|
||||
Variable v;
|
||||
@@ -460,7 +423,7 @@ class VariableNode extends Node, TVariableNode {
|
||||
result = v
|
||||
}
|
||||
|
||||
override IRType getType() { result.getCanonicalLanguageType().hasUnspecifiedType(v.getType(), _) }
|
||||
override Type getType() { result = v.getType() }
|
||||
|
||||
override Location getLocation() { result = v.getLocation() }
|
||||
|
||||
@@ -473,26 +436,20 @@ class VariableNode extends Node, TVariableNode {
|
||||
InstructionNode instructionNode(Instruction instr) { result.getInstruction() = instr }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `definitionByReferenceNodeFromArgument` instead.
|
||||
*
|
||||
* Gets the `Node` corresponding to a definition by reference of the variable
|
||||
* that is passed as `argument` of a call.
|
||||
*/
|
||||
deprecated DefinitionByReferenceNode definitionByReferenceNode(Expr e) { result.getArgument() = e }
|
||||
DefinitionByReferenceNode definitionByReferenceNode(Expr e) { result.getArgument() = e }
|
||||
|
||||
/**
|
||||
* Gets the `Node` corresponding to the value of evaluating `e` or any of its
|
||||
* conversions. There is no result if `e` is a `Conversion`. For data flowing
|
||||
* _out of_ an expression, like when an argument is passed by reference, use
|
||||
* `definitionByReferenceNodeFromArgument` instead.
|
||||
* Gets a `Node` corresponding to `e` or any of its conversions. There is no
|
||||
* result if `e` is a `Conversion`.
|
||||
*/
|
||||
ExprNode exprNode(Expr e) { result.getExpr() = e }
|
||||
|
||||
/**
|
||||
* Gets the `Node` corresponding to the value of evaluating `e`. Here, `e` may
|
||||
* be a `Conversion`. For data flowing _out of_ an expression, like when an
|
||||
* argument is passed by reference, use
|
||||
* `definitionByReferenceNodeFromArgument` instead.
|
||||
* Gets the `Node` corresponding to `e`, if any. Here, `e` may be a
|
||||
* `Conversion`.
|
||||
*/
|
||||
ExprNode convertedExprNode(Expr e) { result.getConvertedExpr() = e }
|
||||
|
||||
@@ -501,14 +458,6 @@ ExprNode convertedExprNode(Expr e) { result.getConvertedExpr() = e }
|
||||
*/
|
||||
ExplicitParameterNode parameterNode(Parameter p) { result.getParameter() = p }
|
||||
|
||||
/**
|
||||
* Gets the `Node` corresponding to a definition by reference of the variable
|
||||
* that is passed as unconverted `argument` of a call.
|
||||
*/
|
||||
DefinitionByReferenceNode definitionByReferenceNodeFromArgument(Expr argument) {
|
||||
result.getArgument() = argument
|
||||
}
|
||||
|
||||
/** Gets the `VariableNode` corresponding to the variable `v`. */
|
||||
VariableNode variableNode(Variable v) { result.getVariable() = v }
|
||||
|
||||
@@ -533,11 +482,7 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr
|
||||
* data flow. It may have less flow than the `localFlowStep` predicate.
|
||||
*/
|
||||
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
// Instruction -> Instruction flow
|
||||
simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction())
|
||||
or
|
||||
// Operand -> Instruction flow
|
||||
simpleOperandLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction())
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -549,16 +494,6 @@ private predicate getFieldSizeOfClass(Class c, Type type, int size) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate simpleOperandLocalFlowStep(Operand opFrom, Instruction iTo) {
|
||||
// Certain dataflow steps (for instance `PostUpdateNode.getPreUpdateNode()`) generates flow to
|
||||
// operands, so we include dataflow from those operands to the "result" of the instruction (i.e., to
|
||||
// the instruction itself).
|
||||
exists(PostUpdateNode post |
|
||||
opFrom = post.getPreUpdateNode().asOperand() and
|
||||
iTo.getAnOperand() = opFrom
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction iTo) {
|
||||
iTo.(CopyInstruction).getSourceValue() = iFrom
|
||||
@@ -724,20 +659,13 @@ predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)
|
||||
*/
|
||||
class BarrierGuard extends IRGuardCondition {
|
||||
/** Override this predicate to hold if this guard validates `instr` upon evaluating to `b`. */
|
||||
predicate checksInstr(Instruction instr, boolean b) { none() }
|
||||
|
||||
/** Override this predicate to hold if this guard validates `expr` upon evaluating to `b`. */
|
||||
predicate checks(Expr e, boolean b) { none() }
|
||||
abstract predicate checks(Instruction instr, boolean b);
|
||||
|
||||
/** Gets a node guarded by this guard. */
|
||||
final Node getAGuardedNode() {
|
||||
exists(ValueNumber value, boolean edge |
|
||||
(
|
||||
this.checksInstr(value.getAnInstruction(), edge)
|
||||
or
|
||||
this.checks(value.getAnInstruction().getConvertedResultExpression(), edge)
|
||||
) and
|
||||
result.asInstruction() = value.getAnInstruction() and
|
||||
this.checks(value.getAnInstruction(), edge) and
|
||||
this.controls(result.asInstruction().getBlock(), edge)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private
|
||||
* To create a configuration, extend this class with a subclass whose
|
||||
* characteristic predicate is a unique singleton string. For example, write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
@@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* ```
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user