mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
Merge tag 'codeql-cli/latest'
Compatible with the latest released version of the CodeQL CLI
This commit is contained in:
@@ -1,3 +1,18 @@
|
||||
## 0.9.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The `shouldPrintFunction` predicate from `PrintAstConfiguration` has been replaced by `shouldPrintDeclaration`. Users should now override `shouldPrintDeclaration` if they want to limit the declarations that should be printed.
|
||||
* The `shouldPrintFunction` predicate from `PrintIRConfiguration` has been replaced by `shouldPrintDeclaration`. Users should now override `shouldPrintDeclaration` if they want to limit the declarations that should be printed.
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* The `PrintAST` library now also prints global and namespace variables and their initializers.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `_Float128x` type is no longer exposed as a builtin type. As this type could not occur any code base, this should only affect queries that explicitly looked at the builtin types.
|
||||
|
||||
## 0.8.1
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
14
cpp/ql/lib/change-notes/released/0.9.0.md
Normal file
14
cpp/ql/lib/change-notes/released/0.9.0.md
Normal file
@@ -0,0 +1,14 @@
|
||||
## 0.9.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The `shouldPrintFunction` predicate from `PrintAstConfiguration` has been replaced by `shouldPrintDeclaration`. Users should now override `shouldPrintDeclaration` if they want to limit the declarations that should be printed.
|
||||
* The `shouldPrintFunction` predicate from `PrintIRConfiguration` has been replaced by `shouldPrintDeclaration`. Users should now override `shouldPrintDeclaration` if they want to limit the declarations that should be printed.
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* The `PrintAST` library now also prints global and namespace variables and their initializers.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `_Float128x` type is no longer exposed as a builtin type. As this type could not occur any code base, this should only affect queries that explicitly looked at the builtin types.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.8.1
|
||||
lastReleaseVersion: 0.9.0
|
||||
|
||||
@@ -18,10 +18,10 @@ external string selectedSourceFile();
|
||||
|
||||
class Cfg extends PrintAstConfiguration {
|
||||
/**
|
||||
* Holds if the AST for `func` should be printed.
|
||||
* Print All functions from the selected file.
|
||||
* Holds if the AST for `decl` should be printed.
|
||||
* Print All declarations from the selected file.
|
||||
*/
|
||||
override predicate shouldPrintFunction(Function func) {
|
||||
func.getFile() = getFileBySourceArchiveName(selectedSourceFile())
|
||||
override predicate shouldPrintDeclaration(Declaration decl) {
|
||||
decl.getFile() = getFileBySourceArchiveName(selectedSourceFile())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.8.1
|
||||
version: 0.9.0
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
library: true
|
||||
upgrades: upgrades
|
||||
dependencies:
|
||||
codeql/dataflow: ${workspace}
|
||||
codeql/ssa: ${workspace}
|
||||
codeql/tutorial: ${workspace}
|
||||
codeql/util: ${workspace}
|
||||
|
||||
@@ -6,11 +6,9 @@ private import PrintAST
|
||||
* that requests that function, or no `PrintASTConfiguration` exists.
|
||||
*/
|
||||
private predicate shouldPrintDeclaration(Declaration decl) {
|
||||
not decl instanceof Function
|
||||
not (decl instanceof Function or decl instanceof GlobalOrNamespaceVariable)
|
||||
or
|
||||
not exists(PrintAstConfiguration c)
|
||||
or
|
||||
exists(PrintAstConfiguration config | config.shouldPrintFunction(decl))
|
||||
exists(PrintAstConfiguration config | config.shouldPrintDeclaration(decl))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,13 +9,13 @@ import cpp
|
||||
import PrintAST
|
||||
|
||||
/**
|
||||
* Temporarily tweak this class or make a copy to control which functions are
|
||||
* Temporarily tweak this class or make a copy to control which declarations are
|
||||
* printed.
|
||||
*/
|
||||
class Cfg extends PrintAstConfiguration {
|
||||
/**
|
||||
* TWEAK THIS PREDICATE AS NEEDED.
|
||||
* Holds if the AST for `func` should be printed.
|
||||
* Holds if the AST for `decl` should be printed.
|
||||
*/
|
||||
override predicate shouldPrintFunction(Function func) { any() }
|
||||
override predicate shouldPrintDeclaration(Declaration decl) { any() }
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* 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.
|
||||
* By default, this will print the AST for all functions and global and namespace variables in
|
||||
* the database. To change this behavior, extend `PrintASTConfiguration` and override
|
||||
* `shouldPrintDeclaration` to hold for only the declarations you wish to view the AST for.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
@@ -12,7 +12,7 @@ private import semmle.code.cpp.Print
|
||||
private newtype TPrintAstConfiguration = MkPrintAstConfiguration()
|
||||
|
||||
/**
|
||||
* The query can extend this class to control which functions are printed.
|
||||
* The query can extend this class to control which declarations are printed.
|
||||
*/
|
||||
class PrintAstConfiguration extends TPrintAstConfiguration {
|
||||
/**
|
||||
@@ -21,14 +21,16 @@ class PrintAstConfiguration extends TPrintAstConfiguration {
|
||||
string toString() { result = "PrintASTConfiguration" }
|
||||
|
||||
/**
|
||||
* Holds if the AST for `func` should be printed. By default, holds for all
|
||||
* functions.
|
||||
* Holds if the AST for `decl` should be printed. By default, holds for all
|
||||
* functions and global and namespace variables. Currently, does not support any
|
||||
* other declaration types.
|
||||
*/
|
||||
predicate shouldPrintFunction(Function func) { any() }
|
||||
predicate shouldPrintDeclaration(Declaration decl) { any() }
|
||||
}
|
||||
|
||||
private predicate shouldPrintFunction(Function func) {
|
||||
exists(PrintAstConfiguration config | config.shouldPrintFunction(func))
|
||||
private predicate shouldPrintDeclaration(Declaration decl) {
|
||||
exists(PrintAstConfiguration config | config.shouldPrintDeclaration(decl)) and
|
||||
(decl instanceof Function or decl instanceof GlobalOrNamespaceVariable)
|
||||
}
|
||||
|
||||
bindingset[s]
|
||||
@@ -69,7 +71,7 @@ private predicate locationSortKeys(Locatable ast, string file, int line, int col
|
||||
)
|
||||
}
|
||||
|
||||
private Function getEnclosingFunction(Locatable ast) {
|
||||
private Declaration getAnEnclosingDeclaration(Locatable ast) {
|
||||
result = ast.(Expr).getEnclosingFunction()
|
||||
or
|
||||
result = ast.(Stmt).getEnclosingFunction()
|
||||
@@ -78,6 +80,10 @@ private Function getEnclosingFunction(Locatable ast) {
|
||||
or
|
||||
result = ast.(Parameter).getFunction()
|
||||
or
|
||||
result = ast.(Expr).getEnclosingDeclaration()
|
||||
or
|
||||
result = ast.(Initializer).getDeclaration()
|
||||
or
|
||||
result = ast
|
||||
}
|
||||
|
||||
@@ -86,21 +92,21 @@ private Function getEnclosingFunction(Locatable ast) {
|
||||
* nodes for things like parameter lists and constructor init lists.
|
||||
*/
|
||||
private newtype TPrintAstNode =
|
||||
TAstNode(Locatable ast) { shouldPrintFunction(getEnclosingFunction(ast)) } or
|
||||
TAstNode(Locatable ast) { shouldPrintDeclaration(getAnEnclosingDeclaration(ast)) } or
|
||||
TDeclarationEntryNode(DeclStmt stmt, DeclarationEntry entry) {
|
||||
// We create a unique node for each pair of (stmt, entry), to avoid having one node with
|
||||
// multiple parents due to extractor bug CPP-413.
|
||||
stmt.getADeclarationEntry() = entry and
|
||||
shouldPrintFunction(stmt.getEnclosingFunction())
|
||||
shouldPrintDeclaration(stmt.getEnclosingFunction())
|
||||
} or
|
||||
TParametersNode(Function func) { shouldPrintFunction(func) } or
|
||||
TParametersNode(Function func) { shouldPrintDeclaration(func) } or
|
||||
TConstructorInitializersNode(Constructor ctor) {
|
||||
ctor.hasEntryPoint() and
|
||||
shouldPrintFunction(ctor)
|
||||
shouldPrintDeclaration(ctor)
|
||||
} or
|
||||
TDestructorDestructionsNode(Destructor dtor) {
|
||||
dtor.hasEntryPoint() and
|
||||
shouldPrintFunction(dtor)
|
||||
shouldPrintDeclaration(dtor)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,10 +164,10 @@ class PrintAstNode extends TPrintAstNode {
|
||||
|
||||
/**
|
||||
* Holds if this node should be printed in the output. By default, all nodes
|
||||
* within a function are printed, but the query can override
|
||||
* `PrintASTConfiguration.shouldPrintFunction` to filter the output.
|
||||
* within functions and global and namespace variables are printed, but the query
|
||||
* can override `PrintASTConfiguration.shouldPrintDeclaration` to filter the output.
|
||||
*/
|
||||
final predicate shouldPrint() { shouldPrintFunction(this.getEnclosingFunction()) }
|
||||
final predicate shouldPrint() { shouldPrintDeclaration(this.getEnclosingDeclaration()) }
|
||||
|
||||
/**
|
||||
* Gets the children of this node.
|
||||
@@ -229,10 +235,15 @@ class PrintAstNode extends TPrintAstNode {
|
||||
abstract string getChildAccessorPredicateInternal(int childIndex);
|
||||
|
||||
/**
|
||||
* Gets the `Function` that contains this node.
|
||||
* Gets the `Declaration` that contains this node.
|
||||
*/
|
||||
private Function getEnclosingFunction() {
|
||||
result = this.getParent*().(FunctionNode).getFunction()
|
||||
private Declaration getEnclosingDeclaration() { result = this.getParent*().getDeclaration() }
|
||||
|
||||
/**
|
||||
* Gets the `Declaration` this node represents.
|
||||
*/
|
||||
private Declaration getDeclaration() {
|
||||
result = this.(AstNode).getAst() and shouldPrintDeclaration(result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -571,16 +582,53 @@ class DestructorDestructionsNode extends PrintAstNode, TDestructorDestructionsNo
|
||||
final Destructor getDestructor() { result = dtor }
|
||||
}
|
||||
|
||||
abstract private class FunctionOrGlobalOrNamespaceVariableNode extends AstNode {
|
||||
override string toString() { result = qlClass(ast) + getIdentityString(ast) }
|
||||
|
||||
private int getOrder() {
|
||||
this =
|
||||
rank[result](FunctionOrGlobalOrNamespaceVariableNode node, Declaration decl, string file,
|
||||
int line, int column |
|
||||
node.getAst() = decl and
|
||||
locationSortKeys(decl, file, line, column)
|
||||
|
|
||||
node order by file, line, column, getIdentityString(decl)
|
||||
)
|
||||
}
|
||||
|
||||
override string getProperty(string key) {
|
||||
result = super.getProperty(key)
|
||||
or
|
||||
key = "semmle.order" and result = this.getOrder().toString()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `GlobalOrNamespaceVariable`.
|
||||
*/
|
||||
class GlobalOrNamespaceVariableNode extends FunctionOrGlobalOrNamespaceVariableNode {
|
||||
GlobalOrNamespaceVariable var;
|
||||
|
||||
GlobalOrNamespaceVariableNode() { var = ast }
|
||||
|
||||
override PrintAstNode getChildInternal(int childIndex) {
|
||||
childIndex = 0 and
|
||||
result.(AstNode).getAst() = var.getInitializer()
|
||||
}
|
||||
|
||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
childIndex = 0 and result = "getInitializer()"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `Function`.
|
||||
*/
|
||||
class FunctionNode extends AstNode {
|
||||
class FunctionNode extends FunctionOrGlobalOrNamespaceVariableNode {
|
||||
Function func;
|
||||
|
||||
FunctionNode() { func = ast }
|
||||
|
||||
override string toString() { result = qlClass(func) + getIdentityString(func) }
|
||||
|
||||
override PrintAstNode getChildInternal(int childIndex) {
|
||||
childIndex = 0 and
|
||||
result.(ParametersNode).getFunction() = func
|
||||
@@ -604,31 +652,10 @@ class FunctionNode extends AstNode {
|
||||
or
|
||||
childIndex = 3 and result = "<destructions>"
|
||||
}
|
||||
|
||||
private int getOrder() {
|
||||
this =
|
||||
rank[result](FunctionNode node, Function function, string file, int line, int column |
|
||||
node.getAst() = function and
|
||||
locationSortKeys(function, file, line, column)
|
||||
|
|
||||
node order by file, line, column, getIdentityString(function)
|
||||
)
|
||||
}
|
||||
|
||||
override string getProperty(string key) {
|
||||
result = super.getProperty(key)
|
||||
or
|
||||
key = "semmle.order" and result = this.getOrder().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Function` this node represents.
|
||||
*/
|
||||
final Function getFunction() { result = func }
|
||||
}
|
||||
|
||||
private string getChildAccessorWithoutConversions(Locatable parent, Element child) {
|
||||
shouldPrintFunction(getEnclosingFunction(parent)) and
|
||||
shouldPrintDeclaration(getAnEnclosingDeclaration(parent)) and
|
||||
(
|
||||
exists(Stmt s | s = parent |
|
||||
namedStmtChildPredicates(s, child, result)
|
||||
@@ -647,7 +674,7 @@ private string getChildAccessorWithoutConversions(Locatable parent, Element chil
|
||||
}
|
||||
|
||||
private predicate namedStmtChildPredicates(Locatable s, Element e, string pred) {
|
||||
shouldPrintFunction(getEnclosingFunction(s)) and
|
||||
shouldPrintDeclaration(getAnEnclosingDeclaration(s)) and
|
||||
(
|
||||
exists(int n | s.(BlockStmt).getStmt(n) = e and pred = "getStmt(" + n + ")")
|
||||
or
|
||||
@@ -735,7 +762,7 @@ private predicate namedStmtChildPredicates(Locatable s, Element e, string pred)
|
||||
}
|
||||
|
||||
private predicate namedExprChildPredicates(Expr expr, Element ele, string pred) {
|
||||
shouldPrintFunction(expr.getEnclosingFunction()) and
|
||||
shouldPrintDeclaration(expr.getEnclosingDeclaration()) and
|
||||
(
|
||||
expr.(Access).getTarget() = ele and pred = "getTarget()"
|
||||
or
|
||||
|
||||
@@ -814,9 +814,6 @@ private predicate floatingPointTypeMapping(
|
||||
// _Float128
|
||||
kind = 49 and base = 2 and domain = TRealDomain() and realKind = 49 and extended = false
|
||||
or
|
||||
// _Float128x
|
||||
kind = 50 and base = 2 and domain = TRealDomain() and realKind = 50 and extended = true
|
||||
or
|
||||
// _Float16
|
||||
kind = 52 and base = 2 and domain = TRealDomain() and realKind = 52 and extended = false
|
||||
or
|
||||
|
||||
@@ -26,6 +26,8 @@ import cpp
|
||||
* global (inter-procedural) data flow analyses.
|
||||
*/
|
||||
deprecated module DataFlow {
|
||||
import semmle.code.cpp.dataflow.internal.DataFlow
|
||||
private import semmle.code.cpp.dataflow.internal.DataFlowImplSpecific
|
||||
private import codeql.dataflow.DataFlow
|
||||
import DataFlowMake<CppOldDataFlow>
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl1
|
||||
}
|
||||
|
||||
@@ -1,433 +0,0 @@
|
||||
/**
|
||||
* Provides an implementation of global (interprocedural) data flow. This file
|
||||
* re-exports the local (intraprocedural) data flow analysis from
|
||||
* `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed
|
||||
* through the `Global` and `GlobalWithState` modules.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
import DataFlowImplCommonPublic
|
||||
private import DataFlowImpl
|
||||
|
||||
/** An input configuration for data flow. */
|
||||
signature module ConfigSig {
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source);
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
default predicate isBarrier(Node node) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
default predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
default predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `node` should never be skipped over in the `PathGraph` and in path
|
||||
* explanations.
|
||||
*/
|
||||
default predicate neverSkip(Node node) {
|
||||
isAdditionalFlowStep(node, _) or isAdditionalFlowStep(_, node)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
default int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
default FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `flowPath`. */
|
||||
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `flowPath`. */
|
||||
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (as it is in a `path-problem` query).
|
||||
*/
|
||||
default predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/** An input configuration for data flow using flow state. */
|
||||
signature module StateConfigSig {
|
||||
bindingset[this]
|
||||
class FlowState;
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state);
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
default predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
default predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
default predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
default predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
default predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `node` should never be skipped over in the `PathGraph` and in path
|
||||
* explanations.
|
||||
*/
|
||||
default predicate neverSkip(Node node) {
|
||||
isAdditionalFlowStep(node, _) or
|
||||
isAdditionalFlowStep(_, node) or
|
||||
isAdditionalFlowStep(node, _, _, _) or
|
||||
isAdditionalFlowStep(_, _, node, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
default int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
default FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `flowPath`. */
|
||||
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `flowPath`. */
|
||||
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (as it is in a `path-problem` query).
|
||||
*/
|
||||
default predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exploration limit for `partialFlow` and `partialFlowRev`
|
||||
* measured in approximate number of interprocedural steps.
|
||||
*/
|
||||
signature int explorationLimitSig();
|
||||
|
||||
/**
|
||||
* The output of a global data flow computation.
|
||||
*/
|
||||
signature module GlobalFlowSig {
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks) and an access path.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
class PathNode;
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate flowPath(PathNode source, PathNode sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*/
|
||||
predicate flow(Node source, Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate flowTo(Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate flowToExpr(DataFlowExpr sink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a global data flow computation.
|
||||
*/
|
||||
module Global<ConfigSig Config> implements GlobalFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import DefaultState<Config>
|
||||
import Config
|
||||
}
|
||||
|
||||
import Impl<C>
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `Global` instead. */
|
||||
deprecated module Make<ConfigSig Config> implements GlobalFlowSig {
|
||||
import Global<Config>
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a global data flow computation using flow state.
|
||||
*/
|
||||
module GlobalWithState<StateConfigSig Config> implements GlobalFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import Config
|
||||
}
|
||||
|
||||
import Impl<C>
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `GlobalWithState` instead. */
|
||||
deprecated module MakeWithState<StateConfigSig Config> implements GlobalFlowSig {
|
||||
import GlobalWithState<Config>
|
||||
}
|
||||
|
||||
signature class PathNodeSig {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString();
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
);
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
Node getNode();
|
||||
}
|
||||
|
||||
signature module PathGraphSig<PathNodeSig PathNode> {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
predicate edges(PathNode a, PathNode b);
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
predicate nodes(PathNode n, string key, string val);
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a `PathGraph` from two `PathGraph`s by disjoint union.
|
||||
*/
|
||||
module MergePathGraph<
|
||||
PathNodeSig PathNode1, PathNodeSig PathNode2, PathGraphSig<PathNode1> Graph1,
|
||||
PathGraphSig<PathNode2> Graph2>
|
||||
{
|
||||
private newtype TPathNode =
|
||||
TPathNode1(PathNode1 p) or
|
||||
TPathNode2(PathNode2 p)
|
||||
|
||||
/** A node in a graph of path explanations that is formed by disjoint union of the two given graphs. */
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets this as a projection on the first given `PathGraph`. */
|
||||
PathNode1 asPathNode1() { this = TPathNode1(result) }
|
||||
|
||||
/** Gets this as a projection on the second given `PathGraph`. */
|
||||
PathNode2 asPathNode2() { this = TPathNode2(result) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() {
|
||||
result = this.asPathNode1().toString() or
|
||||
result = this.asPathNode2().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.asPathNode1().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) or
|
||||
this.asPathNode2().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
Node getNode() {
|
||||
result = this.asPathNode1().getNode() or
|
||||
result = this.asPathNode2().getNode()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
*/
|
||||
module PathGraph implements PathGraphSig<PathNode> {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b) {
|
||||
Graph1::edges(a.asPathNode1(), b.asPathNode1()) or
|
||||
Graph2::edges(a.asPathNode2(), b.asPathNode2())
|
||||
}
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
Graph1::nodes(n.asPathNode1(), key, val) or
|
||||
Graph2::nodes(n.asPathNode2(), key, val)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Graph1::subpaths(arg.asPathNode1(), par.asPathNode1(), ret.asPathNode1(), out.asPathNode1()) or
|
||||
Graph2::subpaths(arg.asPathNode2(), par.asPathNode2(), ret.asPathNode2(), out.asPathNode2())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a `PathGraph` from three `PathGraph`s by disjoint union.
|
||||
*/
|
||||
module MergePathGraph3<
|
||||
PathNodeSig PathNode1, PathNodeSig PathNode2, PathNodeSig PathNode3,
|
||||
PathGraphSig<PathNode1> Graph1, PathGraphSig<PathNode2> Graph2, PathGraphSig<PathNode3> Graph3>
|
||||
{
|
||||
private module MergedInner = MergePathGraph<PathNode1, PathNode2, Graph1, Graph2>;
|
||||
|
||||
private module Merged =
|
||||
MergePathGraph<MergedInner::PathNode, PathNode3, MergedInner::PathGraph, Graph3>;
|
||||
|
||||
/** A node in a graph of path explanations that is formed by disjoint union of the three given graphs. */
|
||||
class PathNode instanceof Merged::PathNode {
|
||||
/** Gets this as a projection on the first given `PathGraph`. */
|
||||
PathNode1 asPathNode1() { result = super.asPathNode1().asPathNode1() }
|
||||
|
||||
/** Gets this as a projection on the second given `PathGraph`. */
|
||||
PathNode2 asPathNode2() { result = super.asPathNode1().asPathNode2() }
|
||||
|
||||
/** Gets this as a projection on the third given `PathGraph`. */
|
||||
PathNode3 asPathNode3() { result = super.asPathNode2() }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
Node getNode() { result = super.getNode() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
*/
|
||||
module PathGraph = Merged::PathGraph;
|
||||
}
|
||||
@@ -5,8 +5,8 @@ private import DataFlowUtil
|
||||
/**
|
||||
* Gets a function that might be called by `call`.
|
||||
*/
|
||||
Function viableCallable(Call call) {
|
||||
result = call.getTarget()
|
||||
Function viableCallable(DataFlowCall call) {
|
||||
result = call.(Call).getTarget()
|
||||
or
|
||||
// If the target of the call does not have a body in the snapshot, it might
|
||||
// be because the target is just a header declaration, and the real target
|
||||
@@ -58,13 +58,13 @@ 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.
|
||||
*/
|
||||
predicate mayBenefitFromCallContext(Call call, Function f) { none() }
|
||||
predicate mayBenefitFromCallContext(DataFlowCall call, Function f) { 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.
|
||||
*/
|
||||
Function viableImplInCallContext(Call call, Call ctx) { none() }
|
||||
Function viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { none() }
|
||||
|
||||
/** A parameter position represented by an integer. */
|
||||
class ParameterPosition extends int {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
|
||||
@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
|
||||
@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
|
||||
@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
/**
|
||||
* Provides C++-specific definitions for use in the data flow library.
|
||||
*/
|
||||
|
||||
private import codeql.dataflow.DataFlow
|
||||
|
||||
module Private {
|
||||
import DataFlowPrivate
|
||||
import DataFlowDispatch
|
||||
@@ -9,3 +12,10 @@ module Private {
|
||||
module Public {
|
||||
import DataFlowUtil
|
||||
}
|
||||
|
||||
module CppOldDataFlow implements InputSig {
|
||||
import Private
|
||||
import Public
|
||||
|
||||
Node exprNode(DataFlowExpr e) { result = Public::exprNode(e) }
|
||||
}
|
||||
|
||||
@@ -153,10 +153,11 @@ predicate jumpStep(Node n1, Node n2) { none() }
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*/
|
||||
predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
|
||||
predicate storeStep(Node node1, ContentSet f, Node node2) {
|
||||
exists(ClassAggregateLiteral aggr, Field field |
|
||||
// The following line requires `node2` to be both an `ExprNode` and a
|
||||
// The following lines requires `node2` to be both an `ExprNode` and a
|
||||
// `PostUpdateNode`, which means it must be an `ObjectInitializerNode`.
|
||||
node2 instanceof PostUpdateNode and
|
||||
node2.asExpr() = aggr and
|
||||
f.(FieldContent).getField() = field and
|
||||
aggr.getAFieldExpr(field) = node1.asExpr()
|
||||
@@ -167,12 +168,13 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
|
||||
node1.asExpr() = a and
|
||||
a.getLValue() = fa
|
||||
) and
|
||||
node2.getPreUpdateNode().asExpr() = fa.getQualifier() and
|
||||
node2.(PostUpdateNode).getPreUpdateNode().asExpr() = fa.getQualifier() and
|
||||
f.(FieldContent).getField() = fa.getTarget()
|
||||
)
|
||||
or
|
||||
exists(ConstructorFieldInit cfi |
|
||||
node2.getPreUpdateNode().(PreConstructorInitThis).getConstructorFieldInit() = cfi and
|
||||
node2.(PostUpdateNode).getPreUpdateNode().(PreConstructorInitThis).getConstructorFieldInit() =
|
||||
cfi and
|
||||
f.(FieldContent).getField() = cfi.getTarget() and
|
||||
node1.asExpr() = cfi.getExpr()
|
||||
)
|
||||
@@ -183,7 +185,7 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
|
||||
* Thus, `node1` references an object with a field `f` whose value ends up in
|
||||
* `node2`.
|
||||
*/
|
||||
predicate readStep(Node node1, Content f, Node node2) {
|
||||
predicate readStep(Node node1, ContentSet f, Node node2) {
|
||||
exists(FieldAccess fr |
|
||||
node1.asExpr() = fr.getQualifier() and
|
||||
fr.getTarget() = f.(FieldContent).getField() and
|
||||
@@ -195,7 +197,7 @@ predicate readStep(Node node1, Content f, Node node2) {
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared at node `n`.
|
||||
*/
|
||||
predicate clearsContent(Node n, Content c) {
|
||||
predicate clearsContent(Node n, ContentSet c) {
|
||||
none() // stub implementation
|
||||
}
|
||||
|
||||
@@ -235,12 +237,6 @@ class CastNode extends Node {
|
||||
CastNode() { none() } // stub implementation
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` should never be skipped over in the `PathGraph` and in path
|
||||
* explanations.
|
||||
*/
|
||||
predicate neverSkipInPathGraph(Node n) { none() }
|
||||
|
||||
class DataFlowCallable = Function;
|
||||
|
||||
class DataFlowExpr = Expr;
|
||||
@@ -265,8 +261,6 @@ class DataFlowCall extends Expr instanceof Call {
|
||||
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
/**
|
||||
* Holds if access paths with `c` at their head always should be tracked at high
|
||||
* precision. This disables adaptive access path precision for such access paths.
|
||||
|
||||
@@ -24,6 +24,7 @@ private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> imp
|
||||
Config::allowImplicitRead(node, c)
|
||||
or
|
||||
(
|
||||
Config::isSink(node) or
|
||||
Config::isSink(node, _) or
|
||||
Config::isAdditionalFlowStep(node, _) or
|
||||
Config::isAdditionalFlowStep(node, _, _, _)
|
||||
|
||||
@@ -26,6 +26,8 @@ import cpp
|
||||
* global (inter-procedural) data flow analyses.
|
||||
*/
|
||||
module DataFlow {
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
||||
private import codeql.dataflow.DataFlow
|
||||
import DataFlowMake<CppDataFlow>
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1
|
||||
}
|
||||
|
||||
@@ -152,7 +152,19 @@ class Expr extends StmtParent, @expr {
|
||||
else result = this.getValue()
|
||||
}
|
||||
|
||||
/** Holds if this expression has a value that can be determined at compile time. */
|
||||
/**
|
||||
* Holds if this expression has a value that can be determined at compile time.
|
||||
*
|
||||
* An expression has a value that can be determined at compile time when:
|
||||
* - it is a compile-time constant, e.g., a literal value or the result of a constexpr
|
||||
* compile-time constant;
|
||||
* - it is an address of a (member) function, an address of a constexpr variable
|
||||
* initialized to a constant address, or an address of an lvalue, or any of the
|
||||
* previous with a constant value added to or subtracted from the address;
|
||||
* - it is a reference to a (member) function, a reference to a constexpr variable
|
||||
* initialized to a constant address, or a reference to an lvalue;
|
||||
* - it is a non-template parameter of a uninstantiated template.
|
||||
*/
|
||||
cached
|
||||
predicate isConstant() {
|
||||
valuebind(_, underlyingElement(this))
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* 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.
|
||||
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
|
||||
* to dump.
|
||||
*/
|
||||
|
||||
import implementation.aliased_ssa.PrintIR
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
import cpp
|
||||
|
||||
module DataFlow {
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
||||
private import codeql.dataflow.DataFlow
|
||||
import DataFlowMake<CppDataFlow>
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1
|
||||
}
|
||||
|
||||
@@ -1,433 +0,0 @@
|
||||
/**
|
||||
* Provides an implementation of global (interprocedural) data flow. This file
|
||||
* re-exports the local (intraprocedural) data flow analysis from
|
||||
* `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed
|
||||
* through the `Global` and `GlobalWithState` modules.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
import DataFlowImplCommonPublic
|
||||
private import DataFlowImpl
|
||||
|
||||
/** An input configuration for data flow. */
|
||||
signature module ConfigSig {
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source);
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
default predicate isBarrier(Node node) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
default predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
default predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `node` should never be skipped over in the `PathGraph` and in path
|
||||
* explanations.
|
||||
*/
|
||||
default predicate neverSkip(Node node) {
|
||||
isAdditionalFlowStep(node, _) or isAdditionalFlowStep(_, node)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
default int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
default FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `flowPath`. */
|
||||
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `flowPath`. */
|
||||
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (as it is in a `path-problem` query).
|
||||
*/
|
||||
default predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/** An input configuration for data flow using flow state. */
|
||||
signature module StateConfigSig {
|
||||
bindingset[this]
|
||||
class FlowState;
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state);
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
default predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
default predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
default predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
default predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
default predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `node` should never be skipped over in the `PathGraph` and in path
|
||||
* explanations.
|
||||
*/
|
||||
default predicate neverSkip(Node node) {
|
||||
isAdditionalFlowStep(node, _) or
|
||||
isAdditionalFlowStep(_, node) or
|
||||
isAdditionalFlowStep(node, _, _, _) or
|
||||
isAdditionalFlowStep(_, _, node, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
default int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
default FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `flowPath`. */
|
||||
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `flowPath`. */
|
||||
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (as it is in a `path-problem` query).
|
||||
*/
|
||||
default predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exploration limit for `partialFlow` and `partialFlowRev`
|
||||
* measured in approximate number of interprocedural steps.
|
||||
*/
|
||||
signature int explorationLimitSig();
|
||||
|
||||
/**
|
||||
* The output of a global data flow computation.
|
||||
*/
|
||||
signature module GlobalFlowSig {
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks) and an access path.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
class PathNode;
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate flowPath(PathNode source, PathNode sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*/
|
||||
predicate flow(Node source, Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate flowTo(Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate flowToExpr(DataFlowExpr sink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a global data flow computation.
|
||||
*/
|
||||
module Global<ConfigSig Config> implements GlobalFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import DefaultState<Config>
|
||||
import Config
|
||||
}
|
||||
|
||||
import Impl<C>
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `Global` instead. */
|
||||
deprecated module Make<ConfigSig Config> implements GlobalFlowSig {
|
||||
import Global<Config>
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a global data flow computation using flow state.
|
||||
*/
|
||||
module GlobalWithState<StateConfigSig Config> implements GlobalFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import Config
|
||||
}
|
||||
|
||||
import Impl<C>
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `GlobalWithState` instead. */
|
||||
deprecated module MakeWithState<StateConfigSig Config> implements GlobalFlowSig {
|
||||
import GlobalWithState<Config>
|
||||
}
|
||||
|
||||
signature class PathNodeSig {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString();
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
);
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
Node getNode();
|
||||
}
|
||||
|
||||
signature module PathGraphSig<PathNodeSig PathNode> {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
predicate edges(PathNode a, PathNode b);
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
predicate nodes(PathNode n, string key, string val);
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a `PathGraph` from two `PathGraph`s by disjoint union.
|
||||
*/
|
||||
module MergePathGraph<
|
||||
PathNodeSig PathNode1, PathNodeSig PathNode2, PathGraphSig<PathNode1> Graph1,
|
||||
PathGraphSig<PathNode2> Graph2>
|
||||
{
|
||||
private newtype TPathNode =
|
||||
TPathNode1(PathNode1 p) or
|
||||
TPathNode2(PathNode2 p)
|
||||
|
||||
/** A node in a graph of path explanations that is formed by disjoint union of the two given graphs. */
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets this as a projection on the first given `PathGraph`. */
|
||||
PathNode1 asPathNode1() { this = TPathNode1(result) }
|
||||
|
||||
/** Gets this as a projection on the second given `PathGraph`. */
|
||||
PathNode2 asPathNode2() { this = TPathNode2(result) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() {
|
||||
result = this.asPathNode1().toString() or
|
||||
result = this.asPathNode2().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.asPathNode1().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) or
|
||||
this.asPathNode2().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
Node getNode() {
|
||||
result = this.asPathNode1().getNode() or
|
||||
result = this.asPathNode2().getNode()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
*/
|
||||
module PathGraph implements PathGraphSig<PathNode> {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b) {
|
||||
Graph1::edges(a.asPathNode1(), b.asPathNode1()) or
|
||||
Graph2::edges(a.asPathNode2(), b.asPathNode2())
|
||||
}
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
Graph1::nodes(n.asPathNode1(), key, val) or
|
||||
Graph2::nodes(n.asPathNode2(), key, val)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Graph1::subpaths(arg.asPathNode1(), par.asPathNode1(), ret.asPathNode1(), out.asPathNode1()) or
|
||||
Graph2::subpaths(arg.asPathNode2(), par.asPathNode2(), ret.asPathNode2(), out.asPathNode2())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a `PathGraph` from three `PathGraph`s by disjoint union.
|
||||
*/
|
||||
module MergePathGraph3<
|
||||
PathNodeSig PathNode1, PathNodeSig PathNode2, PathNodeSig PathNode3,
|
||||
PathGraphSig<PathNode1> Graph1, PathGraphSig<PathNode2> Graph2, PathGraphSig<PathNode3> Graph3>
|
||||
{
|
||||
private module MergedInner = MergePathGraph<PathNode1, PathNode2, Graph1, Graph2>;
|
||||
|
||||
private module Merged =
|
||||
MergePathGraph<MergedInner::PathNode, PathNode3, MergedInner::PathGraph, Graph3>;
|
||||
|
||||
/** A node in a graph of path explanations that is formed by disjoint union of the three given graphs. */
|
||||
class PathNode instanceof Merged::PathNode {
|
||||
/** Gets this as a projection on the first given `PathGraph`. */
|
||||
PathNode1 asPathNode1() { result = super.asPathNode1().asPathNode1() }
|
||||
|
||||
/** Gets this as a projection on the second given `PathGraph`. */
|
||||
PathNode2 asPathNode2() { result = super.asPathNode1().asPathNode2() }
|
||||
|
||||
/** Gets this as a projection on the third given `PathGraph`. */
|
||||
PathNode3 asPathNode3() { result = super.asPathNode2() }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
Node getNode() { result = super.getNode() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
*/
|
||||
module PathGraph = Merged::PathGraph;
|
||||
}
|
||||
@@ -9,7 +9,7 @@ private import DataFlowImplCommon as DataFlowImplCommon
|
||||
* Gets a function that might be called by `call`.
|
||||
*/
|
||||
cached
|
||||
Function viableCallable(CallInstruction call) {
|
||||
DataFlowCallable viableCallable(DataFlowCall call) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
result = call.getStaticCallTarget()
|
||||
or
|
||||
@@ -235,7 +235,7 @@ 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.
|
||||
*/
|
||||
predicate mayBenefitFromCallContext(CallInstruction call, Function f) {
|
||||
predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable f) {
|
||||
mayBenefitFromCallContext(call, f, _)
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ private predicate mayBenefitFromCallContext(
|
||||
* 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.
|
||||
*/
|
||||
Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) {
|
||||
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableCallable(call) and
|
||||
exists(int i, Function f |
|
||||
mayBenefitFromCallContext(pragma[only_bind_into](call), f, i) and
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
|
||||
@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
|
||||
@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
|
||||
@@ -276,6 +276,8 @@ private module Config implements FullStateConfigSig {
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,9 @@
|
||||
/**
|
||||
* Provides IR-specific definitions for use in the data flow library.
|
||||
*/
|
||||
|
||||
private import codeql.dataflow.DataFlow
|
||||
|
||||
module Private {
|
||||
import DataFlowPrivate
|
||||
import DataFlowDispatch
|
||||
@@ -9,3 +12,10 @@ module Private {
|
||||
module Public {
|
||||
import DataFlowUtil
|
||||
}
|
||||
|
||||
module CppDataFlow implements InputSig {
|
||||
import Private
|
||||
import Public
|
||||
|
||||
Node exprNode(DataFlowExpr e) { result = Public::exprNode(e) }
|
||||
}
|
||||
|
||||
@@ -681,9 +681,7 @@ predicate storeStepImpl(Node node1, Content c, PostFieldUpdateNode node2, boolea
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*/
|
||||
predicate storeStep(Node node1, Content c, PostFieldUpdateNode node2) {
|
||||
storeStepImpl(node1, c, node2, _)
|
||||
}
|
||||
predicate storeStep(Node node1, ContentSet c, Node node2) { storeStepImpl(node1, c, node2, _) }
|
||||
|
||||
/**
|
||||
* Holds if `operandFrom` flows to `operandTo` using a sequence of conversion-like
|
||||
@@ -744,7 +742,7 @@ predicate nodeHasInstruction(Node node, Instruction instr, int indirectionIndex)
|
||||
* Thus, `node1` references an object with a field `f` whose value ends up in
|
||||
* `node2`.
|
||||
*/
|
||||
predicate readStep(Node node1, Content c, Node node2) {
|
||||
predicate readStep(Node node1, ContentSet c, Node node2) {
|
||||
exists(FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2 |
|
||||
nodeHasOperand(node2, operand, indirectionIndex2) and
|
||||
// The `1` here matches the `node2.getIndirectionIndex() = 1` conjunct
|
||||
@@ -767,7 +765,7 @@ predicate readStep(Node node1, Content c, Node node2) {
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared at node `n`.
|
||||
*/
|
||||
predicate clearsContent(Node n, Content c) {
|
||||
predicate clearsContent(Node n, ContentSet c) {
|
||||
n =
|
||||
any(PostUpdateNode pun, Content d | d.impliesClearOf(c) and storeStepImpl(_, d, pun, true) | pun)
|
||||
.getPreUpdateNode() and
|
||||
@@ -792,7 +790,7 @@ predicate clearsContent(Node n, Content c) {
|
||||
storeStepImpl(_, d, pun, true) and
|
||||
pun.getPreUpdateNode() = n
|
||||
|
|
||||
c.getIndirectionIndex() = d.getIndirectionIndex()
|
||||
c.(Content).getIndirectionIndex() = d.getIndirectionIndex()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -833,12 +831,6 @@ class CastNode extends Node {
|
||||
CastNode() { none() } // stub implementation
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` should never be skipped over in the `PathGraph` and in path
|
||||
* explanations.
|
||||
*/
|
||||
predicate neverSkipInPathGraph(Node n) { none() }
|
||||
|
||||
/**
|
||||
* A function that may contain code or a variable that may contain itself. When
|
||||
* flow crosses from one _enclosing callable_ to another, the interprocedural
|
||||
@@ -853,7 +845,7 @@ class DataFlowType = Type;
|
||||
|
||||
/** A function call relevant for data flow. */
|
||||
class DataFlowCall extends CallInstruction {
|
||||
Function getEnclosingCallable() { result = this.getEnclosingFunction() }
|
||||
DataFlowCallable getEnclosingCallable() { result = this.getEnclosingFunction() }
|
||||
}
|
||||
|
||||
module IsUnreachableInCall {
|
||||
@@ -924,8 +916,6 @@ module IsUnreachableInCall {
|
||||
|
||||
import IsUnreachableInCall
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
/**
|
||||
* Holds if access paths with `c` at their head always should be tracked at high
|
||||
* precision. This disables adaptive access path precision for such access paths.
|
||||
|
||||
@@ -24,6 +24,7 @@ private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> imp
|
||||
Config::allowImplicitRead(node, c)
|
||||
or
|
||||
(
|
||||
Config::isSink(node) or
|
||||
Config::isSink(node, _) or
|
||||
Config::isAdditionalFlowStep(node, _) or
|
||||
Config::isAdditionalFlowStep(node, _, _, _)
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* 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.
|
||||
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
|
||||
* to dump.
|
||||
*/
|
||||
|
||||
private import internal.IRInternal
|
||||
@@ -16,7 +16,7 @@ import Imports::IRConfiguration
|
||||
private newtype TPrintIRConfiguration = MkPrintIRConfiguration()
|
||||
|
||||
/**
|
||||
* The query can extend this class to control which functions are printed.
|
||||
* The query can extend this class to control which declarations are printed.
|
||||
*/
|
||||
class PrintIRConfiguration extends TPrintIRConfiguration {
|
||||
/** Gets a textual representation of this configuration. */
|
||||
@@ -24,9 +24,9 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
|
||||
|
||||
/**
|
||||
* Holds if the IR for `func` should be printed. By default, holds for all
|
||||
* functions.
|
||||
* functions, global and namespace variables, and static local variables.
|
||||
*/
|
||||
predicate shouldPrintFunction(Language::Declaration decl) { any() }
|
||||
predicate shouldPrintDeclaration(Language::Declaration decl) { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,12 +34,12 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
|
||||
*/
|
||||
private class FilteredIRConfiguration extends IRConfiguration {
|
||||
override predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) {
|
||||
shouldPrintFunction(func)
|
||||
shouldPrintDeclaration(func)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate shouldPrintFunction(Language::Declaration decl) {
|
||||
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
|
||||
private predicate shouldPrintDeclaration(Language::Declaration decl) {
|
||||
exists(PrintIRConfiguration config | config.shouldPrintDeclaration(decl))
|
||||
}
|
||||
|
||||
private predicate shouldPrintInstruction(Instruction i) {
|
||||
@@ -90,10 +90,10 @@ private string getOperandPropertyString(Operand operand) {
|
||||
}
|
||||
|
||||
private newtype TPrintableIRNode =
|
||||
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
|
||||
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
|
||||
TPrintableIRFunction(IRFunction irFunc) { shouldPrintDeclaration(irFunc.getFunction()) } or
|
||||
TPrintableIRBlock(IRBlock block) { shouldPrintDeclaration(block.getEnclosingFunction()) } or
|
||||
TPrintableInstruction(Instruction instr) {
|
||||
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
|
||||
shouldPrintInstruction(instr) and shouldPrintDeclaration(instr.getEnclosingFunction())
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* 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.
|
||||
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
|
||||
* to dump.
|
||||
*/
|
||||
|
||||
private import internal.IRInternal
|
||||
@@ -16,7 +16,7 @@ import Imports::IRConfiguration
|
||||
private newtype TPrintIRConfiguration = MkPrintIRConfiguration()
|
||||
|
||||
/**
|
||||
* The query can extend this class to control which functions are printed.
|
||||
* The query can extend this class to control which declarations are printed.
|
||||
*/
|
||||
class PrintIRConfiguration extends TPrintIRConfiguration {
|
||||
/** Gets a textual representation of this configuration. */
|
||||
@@ -24,9 +24,9 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
|
||||
|
||||
/**
|
||||
* Holds if the IR for `func` should be printed. By default, holds for all
|
||||
* functions.
|
||||
* functions, global and namespace variables, and static local variables.
|
||||
*/
|
||||
predicate shouldPrintFunction(Language::Declaration decl) { any() }
|
||||
predicate shouldPrintDeclaration(Language::Declaration decl) { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,12 +34,12 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
|
||||
*/
|
||||
private class FilteredIRConfiguration extends IRConfiguration {
|
||||
override predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) {
|
||||
shouldPrintFunction(func)
|
||||
shouldPrintDeclaration(func)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate shouldPrintFunction(Language::Declaration decl) {
|
||||
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
|
||||
private predicate shouldPrintDeclaration(Language::Declaration decl) {
|
||||
exists(PrintIRConfiguration config | config.shouldPrintDeclaration(decl))
|
||||
}
|
||||
|
||||
private predicate shouldPrintInstruction(Instruction i) {
|
||||
@@ -90,10 +90,10 @@ private string getOperandPropertyString(Operand operand) {
|
||||
}
|
||||
|
||||
private newtype TPrintableIRNode =
|
||||
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
|
||||
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
|
||||
TPrintableIRFunction(IRFunction irFunc) { shouldPrintDeclaration(irFunc.getFunction()) } or
|
||||
TPrintableIRBlock(IRBlock block) { shouldPrintDeclaration(block.getEnclosingFunction()) } or
|
||||
TPrintableInstruction(Instruction instr) {
|
||||
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
|
||||
shouldPrintInstruction(instr) and shouldPrintDeclaration(instr.getEnclosingFunction())
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* 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.
|
||||
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
|
||||
* to dump.
|
||||
*/
|
||||
|
||||
private import internal.IRInternal
|
||||
@@ -16,7 +16,7 @@ import Imports::IRConfiguration
|
||||
private newtype TPrintIRConfiguration = MkPrintIRConfiguration()
|
||||
|
||||
/**
|
||||
* The query can extend this class to control which functions are printed.
|
||||
* The query can extend this class to control which declarations are printed.
|
||||
*/
|
||||
class PrintIRConfiguration extends TPrintIRConfiguration {
|
||||
/** Gets a textual representation of this configuration. */
|
||||
@@ -24,9 +24,9 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
|
||||
|
||||
/**
|
||||
* Holds if the IR for `func` should be printed. By default, holds for all
|
||||
* functions.
|
||||
* functions, global and namespace variables, and static local variables.
|
||||
*/
|
||||
predicate shouldPrintFunction(Language::Declaration decl) { any() }
|
||||
predicate shouldPrintDeclaration(Language::Declaration decl) { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,12 +34,12 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
|
||||
*/
|
||||
private class FilteredIRConfiguration extends IRConfiguration {
|
||||
override predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) {
|
||||
shouldPrintFunction(func)
|
||||
shouldPrintDeclaration(func)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate shouldPrintFunction(Language::Declaration decl) {
|
||||
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
|
||||
private predicate shouldPrintDeclaration(Language::Declaration decl) {
|
||||
exists(PrintIRConfiguration config | config.shouldPrintDeclaration(decl))
|
||||
}
|
||||
|
||||
private predicate shouldPrintInstruction(Instruction i) {
|
||||
@@ -90,10 +90,10 @@ private string getOperandPropertyString(Operand operand) {
|
||||
}
|
||||
|
||||
private newtype TPrintableIRNode =
|
||||
TPrintableIRFunction(IRFunction irFunc) { shouldPrintFunction(irFunc.getFunction()) } or
|
||||
TPrintableIRBlock(IRBlock block) { shouldPrintFunction(block.getEnclosingFunction()) } or
|
||||
TPrintableIRFunction(IRFunction irFunc) { shouldPrintDeclaration(irFunc.getFunction()) } or
|
||||
TPrintableIRBlock(IRBlock block) { shouldPrintDeclaration(block.getEnclosingFunction()) } or
|
||||
TPrintableInstruction(Instruction instr) {
|
||||
shouldPrintInstruction(instr) and shouldPrintFunction(instr.getEnclosingFunction())
|
||||
shouldPrintInstruction(instr) and shouldPrintDeclaration(instr.getEnclosingFunction())
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,54 @@
|
||||
/**
|
||||
* This file provides the first phase of the `cpp/invalid-pointer-deref` query that identifies flow
|
||||
* from an allocation to a pointer-arithmetic instruction that constructs a pointer that is out of bounds.
|
||||
*
|
||||
* Consider the following snippet:
|
||||
* ```cpp
|
||||
* 1. char* base = (char*)malloc(size);
|
||||
* 2. char* end = base + size;
|
||||
* 3. for(int *p = base; p <= end; p++) {
|
||||
* 4. use(*p); // BUG: Should have been bounded by `p < end`.
|
||||
* 5. }
|
||||
* ```
|
||||
* this file identifies the flow from `new int[size]` to `base + size`.
|
||||
*
|
||||
* This is done using the product-flow library. The configuration tracks flow from the pair
|
||||
* `(allocation, size of allocation)` to a pair `(a, b)` where there exists a pointer-arithmetic instruction
|
||||
* `pai = a + r` such that `b` is a dataflow node where `b <= r`. Because there will be a dataflow-path from
|
||||
* `allocation` to `a` this means that the `pai` will compute a pointer that is some number of elements beyond
|
||||
* the end position of the allocation. See `pointerAddInstructionHasBounds` for the implementation of this.
|
||||
*
|
||||
* In the above example, the pair `(a, b)` is `(base, size)` with `base` and `size` coming from the expression
|
||||
* `base + size` on line 2, which is also the pointer-arithmetic instruction. In general, the pair does not necessarily
|
||||
* correspond directly to the operands of the pointer-arithmetic instruction.
|
||||
* In the following example, the pair is again `(base, size)`, but with `base` coming from line 3 and `size` from line 2,
|
||||
* and the pointer-arithmetic instruction being `base + n` on line 3:
|
||||
* ```cpp
|
||||
* 1. int* base = new int[size];
|
||||
* 2. if(n <= size) {
|
||||
* 3. int* end = base + n;
|
||||
* 4. for(int* p = base; p <= end; ++p) {
|
||||
* 5. *p = 0; // BUG: Should have been bounded by `p < end`.
|
||||
* 6. }
|
||||
* 7. }
|
||||
* ```
|
||||
*
|
||||
* Handling false positives:
|
||||
*
|
||||
* Consider a snippet such as:
|
||||
* ```cpp
|
||||
* 1. int* base = new int[size];
|
||||
* 2. int n = condition() ? size : 0;
|
||||
* 3. if(n >= size) return;
|
||||
* 4. int* end = base + n;
|
||||
* 5. for(int* p = base; p <= end; ++p) {
|
||||
* 6. *p = 0; // This is fine since `end < base + size`
|
||||
* 7. }
|
||||
* ```
|
||||
* In order to remove this false positive we define a barrier (see `SizeBarrier::SizeBarrierConfig`) that finds the
|
||||
* possible guards that compares a value to the size of the allocation. In the above example, this is the `(n >= size)`
|
||||
* guard on line 3. `SizeBarrier::getABarrierNode` then defines any node that is guarded by such a guard as a barrier
|
||||
* in the dataflow configuration.
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
@@ -42,16 +90,14 @@ predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
|
||||
* ```
|
||||
* In this case, the sink pair identified by the product flow library (without any additional barriers)
|
||||
* would be `(p, n)` (where `n` is the `n` in `p[n]`), because there exists a pointer-arithmetic
|
||||
* instruction `pai` such that:
|
||||
* 1. The left-hand of `pai` flows from the allocation, and
|
||||
* 2. The right-hand of `pai` is non-strictly upper bounded by `n` (where `n` is the `n` in `p[n]`)
|
||||
* instruction `pai = a + b` such that:
|
||||
* 1. the allocation flows to `a`, and
|
||||
* 2. `b <= n` where `n` is the `n` in `p[n]`
|
||||
* but because there's a strict comparison that compares `n` against the size of the allocation this
|
||||
* snippet is fine.
|
||||
*/
|
||||
module Barrier2 {
|
||||
private class FlowState2 = int;
|
||||
|
||||
private module BarrierConfig2 implements DataFlow::ConfigSig {
|
||||
module SizeBarrier {
|
||||
private module SizeBarrierConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
// The sources is the same as in the sources for the second
|
||||
// projection in the `AllocToInvalidPointerConfig` module.
|
||||
@@ -59,19 +105,19 @@ module Barrier2 {
|
||||
}
|
||||
|
||||
additional predicate isSink(
|
||||
DataFlow::Node left, DataFlow::Node right, IRGuardCondition g, FlowState2 state,
|
||||
boolean testIsTrue
|
||||
DataFlow::Node left, DataFlow::Node right, IRGuardCondition g, int k, boolean testIsTrue
|
||||
) {
|
||||
// The sink is any "large" side of a relational comparison.
|
||||
g.comparesLt(left.asOperand(), right.asOperand(), state, true, testIsTrue)
|
||||
// The sink is any "large" side of a relational comparison. i.e., the `right` expression
|
||||
// in a guard such as `left < right + k`.
|
||||
g.comparesLt(left.asOperand(), right.asOperand(), k, true, testIsTrue)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isSink(_, sink, _, _, _) }
|
||||
}
|
||||
|
||||
private import DataFlow::Global<BarrierConfig2>
|
||||
private import DataFlow::Global<SizeBarrierConfig>
|
||||
|
||||
private FlowState2 getAFlowStateForNode(DataFlow::Node node) {
|
||||
private int getAFlowStateForNode(DataFlow::Node node) {
|
||||
exists(DataFlow::Node source |
|
||||
flow(source, node) and
|
||||
hasSize(_, source, result)
|
||||
@@ -79,14 +125,14 @@ module Barrier2 {
|
||||
}
|
||||
|
||||
private predicate operandGuardChecks(
|
||||
IRGuardCondition g, Operand left, Operand right, FlowState2 state, boolean edge
|
||||
IRGuardCondition g, Operand left, Operand right, int state, boolean edge
|
||||
) {
|
||||
exists(DataFlow::Node nLeft, DataFlow::Node nRight, FlowState2 state0 |
|
||||
exists(DataFlow::Node nLeft, DataFlow::Node nRight, int k |
|
||||
nRight.asOperand() = right and
|
||||
nLeft.asOperand() = left and
|
||||
BarrierConfig2::isSink(nLeft, nRight, g, state0, edge) and
|
||||
SizeBarrierConfig::isSink(nLeft, nRight, g, k, edge) and
|
||||
state = getAFlowStateForNode(nRight) and
|
||||
state0 <= state
|
||||
k <= state
|
||||
)
|
||||
}
|
||||
|
||||
@@ -94,7 +140,7 @@ module Barrier2 {
|
||||
* Gets an instruction that is guarded by a guard condition which ensures that
|
||||
* the value of the instruction is upper-bounded by size of some allocation.
|
||||
*/
|
||||
Instruction getABarrierInstruction(FlowState2 state) {
|
||||
Instruction getABarrierInstruction(int state) {
|
||||
exists(IRGuardCondition g, ValueNumber value, Operand use, boolean edge |
|
||||
use = value.getAUse() and
|
||||
operandGuardChecks(pragma[only_bind_into](g), pragma[only_bind_into](use), _,
|
||||
@@ -108,7 +154,7 @@ module Barrier2 {
|
||||
* Gets a `DataFlow::Node` that is guarded by a guard condition which ensures that
|
||||
* the value of the node is upper-bounded by size of some allocation.
|
||||
*/
|
||||
DataFlow::Node getABarrierNode(FlowState2 state) {
|
||||
DataFlow::Node getABarrierNode(int state) {
|
||||
result.asOperand() = getABarrierInstruction(state).getAUse()
|
||||
}
|
||||
|
||||
@@ -116,9 +162,7 @@ module Barrier2 {
|
||||
* Gets the block of a node that is guarded (see `getABarrierInstruction` or
|
||||
* `getABarrierNode` for the definition of what it means to be guarded).
|
||||
*/
|
||||
IRBlock getABarrierBlock(FlowState2 state) {
|
||||
result.getAnInstruction() = getABarrierInstruction(state)
|
||||
}
|
||||
IRBlock getABarrierBlock(int state) { result.getAnInstruction() = getABarrierInstruction(state) }
|
||||
}
|
||||
|
||||
private module InterestingPointerAddInstruction {
|
||||
@@ -151,24 +195,8 @@ private module InterestingPointerAddInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* A product-flow configuration for flow from an (allocation, size) pair to a
|
||||
* pointer-arithmetic operation that is non-strictly upper-bounded by `allocation + size`.
|
||||
*
|
||||
* The goal of this query is to find patterns such as:
|
||||
* ```cpp
|
||||
* 1. char* begin = (char*)malloc(size);
|
||||
* 2. char* end = begin + size;
|
||||
* 3. for(int *p = begin; p <= end; p++) {
|
||||
* 4. use(*p);
|
||||
* 5. }
|
||||
* ```
|
||||
*
|
||||
* We do this by splitting the task up into two configurations:
|
||||
* 1. `AllocToInvalidPointerConfig` find flow from `malloc(size)` to `begin + size`, and
|
||||
* 2. `InvalidPointerToDerefConfig` finds flow from `begin + size` to an `end` (on line 3).
|
||||
*
|
||||
* Finally, the range-analysis library will find a load from (or store to) an address that
|
||||
* is non-strictly upper-bounded by `end` (which in this case is `*p`).
|
||||
* A product-flow configuration for flow from an `(allocation, size)` pair to a
|
||||
* pointer-arithmetic operation `pai` such that `pai <= allocation + size`.
|
||||
*/
|
||||
private module Config implements ProductFlow::StateConfigSig {
|
||||
class FlowState1 = Unit;
|
||||
@@ -176,7 +204,7 @@ private module Config implements ProductFlow::StateConfigSig {
|
||||
class FlowState2 = int;
|
||||
|
||||
predicate isSourcePair(
|
||||
DataFlow::Node source1, FlowState1 state1, DataFlow::Node source2, FlowState2 state2
|
||||
DataFlow::Node allocSource, FlowState1 unit, DataFlow::Node sizeSource, FlowState2 sizeAddend
|
||||
) {
|
||||
// In the case of an allocation like
|
||||
// ```cpp
|
||||
@@ -184,21 +212,21 @@ private module Config implements ProductFlow::StateConfigSig {
|
||||
// ```
|
||||
// we use `state2` to remember that there was an offset (in this case an offset of `1`) added
|
||||
// to the size of the allocation. This state is then checked in `isSinkPair`.
|
||||
exists(state1) and
|
||||
hasSize(source1.asConvertedExpr(), source2, state2)
|
||||
exists(unit) and
|
||||
hasSize(allocSource.asConvertedExpr(), sizeSource, sizeAddend)
|
||||
}
|
||||
|
||||
predicate isSinkPair(
|
||||
DataFlow::Node sink1, FlowState1 state1, DataFlow::Node sink2, FlowState2 state2
|
||||
DataFlow::Node allocSink, FlowState1 unit, DataFlow::Node sizeSink, FlowState2 sizeAddend
|
||||
) {
|
||||
exists(state1) and
|
||||
exists(unit) and
|
||||
// We check that the delta computed by the range analysis matches the
|
||||
// state value that we set in `isSourcePair`.
|
||||
pointerAddInstructionHasBounds0(_, sink1, sink2, state2)
|
||||
pointerAddInstructionHasBounds0(_, allocSink, sizeSink, sizeAddend)
|
||||
}
|
||||
|
||||
predicate isBarrier2(DataFlow::Node node, FlowState2 state) {
|
||||
node = Barrier2::getABarrierNode(state)
|
||||
node = SizeBarrier::getABarrierNode(state)
|
||||
}
|
||||
|
||||
predicate isBarrierIn1(DataFlow::Node node) { isSourcePair(node, _, _, _) }
|
||||
@@ -211,7 +239,7 @@ private module Config implements ProductFlow::StateConfigSig {
|
||||
private module AllocToInvalidPointerFlow = ProductFlow::GlobalWithState<Config>;
|
||||
|
||||
/**
|
||||
* Holds if `pai` is non-strictly upper bounded by `sink2 + delta` and `sink1` is the
|
||||
* Holds if `pai` is non-strictly upper bounded by `sizeSink + delta` and `allocSink` is the
|
||||
* left operand of the pointer-arithmetic operation.
|
||||
*
|
||||
* For example in,
|
||||
@@ -220,37 +248,37 @@ private module AllocToInvalidPointerFlow = ProductFlow::GlobalWithState<Config>;
|
||||
* ```
|
||||
* We will have:
|
||||
* - `pai` is `p + (size + 1)`,
|
||||
* - `sink1` is `p`
|
||||
* - `sink2` is `size`
|
||||
* - `allocSink` is `p`
|
||||
* - `sizeSink` is `size`
|
||||
* - `delta` is `1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate pointerAddInstructionHasBounds0(
|
||||
PointerAddInstruction pai, DataFlow::Node sink1, DataFlow::Node sink2, int delta
|
||||
PointerAddInstruction pai, DataFlow::Node allocSink, DataFlow::Node sizeSink, int delta
|
||||
) {
|
||||
InterestingPointerAddInstruction::isInteresting(pragma[only_bind_into](pai)) and
|
||||
exists(Instruction right, Instruction instr2 |
|
||||
exists(Instruction right, Instruction sizeInstr |
|
||||
pai.getRight() = right and
|
||||
pai.getLeft() = sink1.asInstruction() and
|
||||
instr2 = sink2.asInstruction() and
|
||||
// pai.getRight() <= sink2 + delta
|
||||
bounded1(right, instr2, delta) and
|
||||
not right = Barrier2::getABarrierInstruction(delta) and
|
||||
not instr2 = Barrier2::getABarrierInstruction(delta)
|
||||
pai.getLeft() = allocSink.asInstruction() and
|
||||
sizeInstr = sizeSink.asInstruction() and
|
||||
// pai.getRight() <= sizeSink + delta
|
||||
bounded1(right, sizeInstr, delta) and
|
||||
not right = SizeBarrier::getABarrierInstruction(delta) and
|
||||
not sizeInstr = SizeBarrier::getABarrierInstruction(delta)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `allocation` flows to `sink1` and `sink1` represents the left-hand
|
||||
* side of the pointer-arithmetic instruction `pai`, and the right-hand side of `pai`
|
||||
* is non-strictly upper bounded by the size of `alllocation` + `delta`.
|
||||
* Holds if `allocation` flows to `allocSink` and `allocSink` represents the left operand
|
||||
* of the pointer-arithmetic instruction `pai = a + b` (i.e., `allocSink = a`), and
|
||||
* `b <= allocation + delta`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate pointerAddInstructionHasBounds(
|
||||
DataFlow::Node allocation, PointerAddInstruction pai, DataFlow::Node sink1, int delta
|
||||
DataFlow::Node allocation, PointerAddInstruction pai, DataFlow::Node allocSink, int delta
|
||||
) {
|
||||
exists(DataFlow::Node sink2 |
|
||||
AllocToInvalidPointerFlow::flow(allocation, _, sink1, sink2) and
|
||||
pointerAddInstructionHasBounds0(pai, sink1, sink2, delta)
|
||||
exists(DataFlow::Node sizeSink |
|
||||
AllocToInvalidPointerFlow::flow(allocation, _, allocSink, sizeSink) and
|
||||
pointerAddInstructionHasBounds0(pai, allocSink, sizeSink, delta)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,75 @@
|
||||
* This file provides the second phase of the `cpp/invalid-pointer-deref` query that identifies flow
|
||||
* from the out-of-bounds pointer identified by the `AllocationToInvalidPointer.qll` library to
|
||||
* a dereference of the out-of-bounds pointer.
|
||||
*
|
||||
* Consider the following snippet:
|
||||
* ```cpp
|
||||
* 1. char* base = (char*)malloc(size);
|
||||
* 2. char* end = base + size;
|
||||
* 3. for(char *p = base; p <= end; p++) {
|
||||
* 4. use(*p); // BUG: Should have been bounded by `p < end`.
|
||||
* 5. }
|
||||
* ```
|
||||
* this file identifies the flow from `base + size` to `end`. We call `base + size` the "dereference source" and `end`
|
||||
* the "dereference sink" (even though `end` is not actually dereferenced we will use this term because we will perform
|
||||
* dataflow to find a use of a pointer `x` such that `x <= end` which is dereferenced. In the above example, `x` is `p`
|
||||
* on line 4).
|
||||
*
|
||||
* Merely _constructing_ a pointer that's out-of-bounds is fine if the pointer is never dereferenced (in reality, the
|
||||
* standard only guarantees that it is safe to move the pointer one element past the last element, but we ignore that
|
||||
* here). So this step is about identifying which of the out-of-bounds pointers found by `pointerAddInstructionHasBounds`
|
||||
* in `AllocationToInvalidPointer.qll` are actually being dereferenced. We do this using a regular dataflow
|
||||
* configuration (see `InvalidPointerToDerefConfig`).
|
||||
*
|
||||
* The dataflow traversal defines the set of sources as any dataflow node `n` such that there exists a pointer-arithmetic
|
||||
* instruction `pai` found by `AllocationToInvalidPointer.qll` and a `n.asInstruction() >= pai + deltaDerefSourceAndPai`.
|
||||
* Here, `deltaDerefSourceAndPai` is the constant difference between the source we track for finding a dereference and the
|
||||
* pointer-arithmetic instruction.
|
||||
*
|
||||
* The set of sinks is defined as any dataflow node `n` such that `addr <= n.asInstruction() + deltaDerefSinkAndDerefAddress`
|
||||
* for some address operand `addr` and constant difference `deltaDerefSinkAndDerefAddress`. Since an address operand is
|
||||
* always consumed by an instruction that performs a dereference this lets us identify a "bad dereference". We call the
|
||||
* instruction that consumes the address operand the "operation".
|
||||
*
|
||||
* For example, consider the flow from `base + size` to `end` above. The sink is `end` on line 3 because
|
||||
* `p <= end.asInstruction() + deltaDerefSinkAndDerefAddress`, where `p` is the address operand in `use(*p)` and
|
||||
* `deltaDerefSinkAndDerefAddress >= 0`. The load attached to `*p` is the "operation". To ensure that the path makes
|
||||
* intuitive sense, we only pick operations that are control-flow reachable from the dereference sink.
|
||||
*
|
||||
* To compute how many elements the dereference is beyond the end position of the allocation, we sum the two deltas
|
||||
* `deltaDerefSourceAndPai` and `deltaDerefSinkAndDerefAddress`. This is done in the `operationIsOffBy` predicate
|
||||
* (which is the only predicate exposed by this file).
|
||||
*
|
||||
* Handling false positives:
|
||||
*
|
||||
* Consider the following snippet:
|
||||
* ```cpp
|
||||
* 1. char *p = new char[size];
|
||||
* 2. char *end = p + size;
|
||||
* 3. if (p < end) {
|
||||
* 4. p += 1;
|
||||
* 5. }
|
||||
* 6. if (p < end) {
|
||||
* 7. int val = *p; // GOOD
|
||||
* 8. }
|
||||
* ```
|
||||
* this is safe because `p` is guarded to be strictly less than `end` on line 6 before the dereference on line 7. However, if we
|
||||
* run the query on the above without further modifications we would see an alert on line 7. This is because range analysis infers
|
||||
* that `p <= end` after the increment on line 4, and thus the result of `p += 1` is seen as a valid dereference source. This
|
||||
* node then flows to `p` on line 6 (which is a valid dereference sink since it non-strictly upper bounds an address operand), and
|
||||
* range analysis then infers that the address operand of `*p` (i.e., `p`) is non-strictly upper bounded by `p`, and thus reports
|
||||
* an alert on line 7.
|
||||
*
|
||||
* In order to handle the above false positive, we define a barrier that identifies guards such as `p < end` that ensures that a value
|
||||
* is less than the pointer-arithmetic instruction that computed the invalid pointer. This is done in the `InvalidPointerToDerefBarrier`
|
||||
* module. Since the node we are tracking is not necessarily _equal_ to the pointer-arithmetic instruction, but rather satisfies
|
||||
* `node.asInstruction() <= pai + deltaDerefSourceAndPai`, we need to account for the delta when checking if a guard is sufficiently
|
||||
* strong to infer that a future dereference is safe. To do this, we check that the guard guarantees that a node `n` satisfies
|
||||
* `n < node + k` where `node` is a node we know is equal to the value of the dereference source (i.e., it satisfies
|
||||
* `node.asInstruction() <= pai + deltaDerefSourceAndPai`) and `k <= deltaDerefSourceAndPai`. Combining this we have
|
||||
* `n < node + k <= node + deltaDerefSourceAndPai <= pai + 2*deltaDerefSourceAndPai` (TODO: Oops. This math doesn't quite work out.
|
||||
* I think this is because we need to redefine the `BarrierConfig` to start flow at the pointer-arithmetic instruction instead of
|
||||
* at the dereference source. When combined with TODO above it's easy to show that this guard ensures that the dereference is safe).
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
@@ -19,10 +88,10 @@ private module InvalidPointerToDerefBarrier {
|
||||
}
|
||||
|
||||
additional predicate isSink(
|
||||
DataFlow::Node left, DataFlow::Node right, IRGuardCondition g, int state, boolean testIsTrue
|
||||
DataFlow::Node left, DataFlow::Node right, IRGuardCondition g, int k, boolean testIsTrue
|
||||
) {
|
||||
// The sink is any "large" side of a relational comparison.
|
||||
g.comparesLt(left.asOperand(), right.asOperand(), state, true, testIsTrue)
|
||||
g.comparesLt(left.asOperand(), right.asOperand(), k, true, testIsTrue)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isSink(_, sink, _, _, _) }
|
||||
@@ -40,12 +109,12 @@ private module InvalidPointerToDerefBarrier {
|
||||
private predicate operandGuardChecks(
|
||||
IRGuardCondition g, Operand left, Operand right, int state, boolean edge
|
||||
) {
|
||||
exists(DataFlow::Node nLeft, DataFlow::Node nRight, int state0 |
|
||||
exists(DataFlow::Node nLeft, DataFlow::Node nRight, int k |
|
||||
nRight.asOperand() = right and
|
||||
nLeft.asOperand() = left and
|
||||
BarrierConfig::isSink(nLeft, nRight, g, state0, edge) and
|
||||
BarrierConfig::isSink(nLeft, nRight, g, k, edge) and
|
||||
state = getInvalidPointerToDerefSourceDelta(nRight) and
|
||||
state0 <= state
|
||||
k <= state
|
||||
)
|
||||
}
|
||||
|
||||
@@ -85,47 +154,48 @@ private module InvalidPointerToDerefConfig implements DataFlow::ConfigSig {
|
||||
private import DataFlow::Global<InvalidPointerToDerefConfig>
|
||||
|
||||
/**
|
||||
* Holds if `source1` is dataflow node that represents an allocation that flows to the
|
||||
* left-hand side of the pointer-arithmetic `pai`, and `derefSource` is a dataflow node with
|
||||
* a pointer-value that is non-strictly upper bounded by `pai + delta`.
|
||||
* Holds if `allocSource` is dataflow node that represents an allocation that flows to the
|
||||
* left-hand side of the pointer-arithmetic `pai`, and `derefSource <= pai + derefSourcePaiDelta`.
|
||||
*
|
||||
* For example, if `pai` is a pointer-arithmetic operation `p + size` in an expression such
|
||||
* as `(p + size) + 1` and `derefSource` is the node representing `(p + size) + 1`. In this
|
||||
* case `delta` is 1.
|
||||
* case `derefSourcePaiDelta` is 1.
|
||||
*/
|
||||
private predicate invalidPointerToDerefSource(
|
||||
DataFlow::Node source1, PointerArithmeticInstruction pai, DataFlow::Node derefSource, int delta
|
||||
DataFlow::Node allocSource, PointerArithmeticInstruction pai, DataFlow::Node derefSource,
|
||||
int deltaDerefSourceAndPai
|
||||
) {
|
||||
exists(int delta0 |
|
||||
// Note that `delta` is not necessarily equal to `delta0`:
|
||||
// `delta0` is the constant offset added to the size of the allocation, and
|
||||
// delta is the constant difference between the pointer-arithmetic instruction
|
||||
exists(int rhsSizeDelta |
|
||||
// Note that `deltaDerefSourceAndPai` is not necessarily equal to `rhsSizeDelta`:
|
||||
// `rhsSizeDelta` is the constant offset added to the size of the allocation, and
|
||||
// `deltaDerefSourceAndPai` is the constant difference between the pointer-arithmetic instruction
|
||||
// and the instruction computing the address for which we will search for a dereference.
|
||||
AllocToInvalidPointer::pointerAddInstructionHasBounds(source1, pai, _, delta0) and
|
||||
bounded2(derefSource.asInstruction(), pai, delta) and
|
||||
delta >= 0 and
|
||||
// TODO: This condition will go away once #13725 is merged, and then we can make `Barrier2`
|
||||
AllocToInvalidPointer::pointerAddInstructionHasBounds(allocSource, pai, _, rhsSizeDelta) and
|
||||
bounded2(derefSource.asInstruction(), pai, deltaDerefSourceAndPai) and
|
||||
deltaDerefSourceAndPai >= 0 and
|
||||
// TODO: This condition will go away once #13725 is merged, and then we can make `SizeBarrier`
|
||||
// private to `AllocationToInvalidPointer.qll`.
|
||||
not derefSource.getBasicBlock() = AllocToInvalidPointer::Barrier2::getABarrierBlock(delta0)
|
||||
not derefSource.getBasicBlock() =
|
||||
AllocToInvalidPointer::SizeBarrier::getABarrierBlock(rhsSizeDelta)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a sink for `InvalidPointerToDerefConfig` and `i` is a `StoreInstruction` that
|
||||
* writes to an address that non-strictly upper-bounds `sink`, or `i` is a `LoadInstruction` that
|
||||
* reads from an address that non-strictly upper-bounds `sink`.
|
||||
* writes to an address `addr` such that `addr <= sink`, or `i` is a `LoadInstruction` that
|
||||
* reads from an address `addr` such that `addr <= sink`.
|
||||
*/
|
||||
pragma[inline]
|
||||
private predicate isInvalidPointerDerefSink(
|
||||
DataFlow::Node sink, Instruction i, string operation, int delta
|
||||
DataFlow::Node sink, Instruction i, string operation, int deltaDerefSinkAndDerefAddress
|
||||
) {
|
||||
exists(AddressOperand addr, Instruction s, IRBlock b |
|
||||
s = sink.asInstruction() and
|
||||
bounded(addr.getDef(), s, delta) and
|
||||
delta >= 0 and
|
||||
bounded(addr.getDef(), s, deltaDerefSinkAndDerefAddress) and
|
||||
deltaDerefSinkAndDerefAddress >= 0 and
|
||||
i.getAnOperand() = addr and
|
||||
b = i.getBlock() and
|
||||
not b = InvalidPointerToDerefBarrier::getABarrierBlock(delta)
|
||||
not b = InvalidPointerToDerefBarrier::getABarrierBlock(deltaDerefSinkAndDerefAddress)
|
||||
|
|
||||
i instanceof StoreInstruction and
|
||||
operation = "write"
|
||||
@@ -165,13 +235,13 @@ private predicate paiForDereferenceSink(PointerArithmeticInstruction pai, DataFl
|
||||
*/
|
||||
private predicate derefSinkToOperation(
|
||||
DataFlow::Node derefSink, PointerArithmeticInstruction pai, DataFlow::Node operation,
|
||||
string description, int delta
|
||||
string description, int deltaDerefSinkAndDerefAddress
|
||||
) {
|
||||
exists(Instruction i |
|
||||
exists(Instruction operationInstr |
|
||||
paiForDereferenceSink(pai, pragma[only_bind_into](derefSink)) and
|
||||
isInvalidPointerDerefSink(derefSink, i, description, delta) and
|
||||
i = getASuccessor(derefSink.asInstruction()) and
|
||||
operation.asInstruction() = i
|
||||
isInvalidPointerDerefSink(derefSink, operationInstr, description, deltaDerefSinkAndDerefAddress) and
|
||||
operationInstr = getASuccessor(derefSink.asInstruction()) and
|
||||
operation.asInstruction() = operationInstr
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -608,7 +608,7 @@ case @builtintype.kind of
|
||||
| 47 = @std_float64 // _Float64
|
||||
| 48 = @float64x // _Float64x
|
||||
| 49 = @std_float128 // _Float128
|
||||
| 50 = @float128x // _Float128x
|
||||
// ... 50 _Float128x
|
||||
| 51 = @char8_t
|
||||
| 52 = @float16 // _Float16
|
||||
| 53 = @complex_float16 // _Complex _Float16
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
||||
class BuiltinType extends @builtintype {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
predicate isFloat128xBuiltinType(BuiltinType type) {
|
||||
exists(int kind | builtintypes(type, _, kind, _, _, _) | kind = 50)
|
||||
}
|
||||
|
||||
from BuiltinType type, string name, int kind, int kind_new, int size, int sign, int alignment
|
||||
where
|
||||
builtintypes(type, name, kind, size, sign, alignment) and
|
||||
if isFloat128xBuiltinType(type) then kind_new = 1 else kind_new = kind
|
||||
select type, name, kind_new, size, sign, alignment
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Remove _Float128 type
|
||||
compatibility: partial
|
||||
builtintypes.rel: run builtintypes.qlo
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.7.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.7.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
int f() {
|
||||
void f() {
|
||||
char* buf = new char[SIZE];
|
||||
....
|
||||
...
|
||||
if (error) {
|
||||
free(buf); //error handling has freed the buffer
|
||||
delete buf; //error handling has freed the buffer
|
||||
}
|
||||
...
|
||||
log_contents(buf); //but it is still used here for logging
|
||||
...
|
||||
}
|
||||
|
||||
3
cpp/ql/src/change-notes/released/0.7.2.md
Normal file
3
cpp/ql/src/change-notes/released/0.7.2.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.7.2
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.7.1
|
||||
lastReleaseVersion: 0.7.2
|
||||
|
||||
@@ -15,6 +15,51 @@
|
||||
* external/cwe/cwe-787
|
||||
*/
|
||||
|
||||
/*
|
||||
* High-level description of the query:
|
||||
*
|
||||
* The goal of this query is to identify issues such as:
|
||||
* ```cpp
|
||||
* 1. int* base = new int[size];
|
||||
* 2. int* end = base + size;
|
||||
* 3. for(int* p = base; p <= end; ++p) {
|
||||
* 4. *p = 0; // BUG: Should have been bounded by `p < end`.
|
||||
* 5. }
|
||||
* ```
|
||||
* In order to do this, we split the problem into three subtasks:
|
||||
* 1. First, we find flow from `new int[size]` to `base + size`.
|
||||
* 2. Then, we find flow from `base + size` to `end` (on line 3).
|
||||
* 3. Finally, we use range-analysis to find a write to (or read from) a pointer that may be greater than or equal to `end`.
|
||||
*
|
||||
* Step 1 is implemented in `AllocationToInvalidPointer.qll`, and step 2 is implemented by
|
||||
* `InvalidPointerToDereference.qll`. See those files for the description of these.
|
||||
*
|
||||
* This file imports both libraries and defines a final dataflow configuration that constructs the full path from
|
||||
* the allocation to the dereference of the out-of-bounds pointer. This is done for several reasons:
|
||||
* 1. It means the user is able to inspect the entire path from the allocation to the dereference, which can be useful
|
||||
* to understand the problem highlighted.
|
||||
* 2. It ensures that the call-contexts line up correctly when we transition from step 1 to step 2. See the
|
||||
* `test_missing_call_context_1` and `test_missing_call_context_2` tests for how this may flag false positives
|
||||
* without this final configuration.
|
||||
*
|
||||
* The source of the final path is an allocation that is:
|
||||
* 1. identified as flowing to an invalid pointer (by `AllocationToInvalidPointer`), and
|
||||
* 2. for which the invalid pointer flows to a dereference (as identified by `InvalidPointerToDereference`).
|
||||
*
|
||||
* The path can be described in 3 "chunks":
|
||||
* 1. One path from the allocation to the construction of the invalid pointer
|
||||
* 2. Another path from the construction of the invalid pointer to the final pointer that is about to be dereferenced.
|
||||
* 3. Finally, a single step from the dataflow node that represents the final pointer to the dereference.
|
||||
*
|
||||
* Step 1 happens when the flow state is `TInitial`, and step 2 and 3 happen when the flow state is `TPointerArith(pai)`
|
||||
* where the pointer-arithmetic instruction `pai` tracks the instruction that generated the out-of-bounds pointer. This
|
||||
* instruction is used in the construction of the alert message.
|
||||
*
|
||||
* The set of pointer-arithmetic instructions that define the `TPointerArith` flow state is restricted to be the pointer-
|
||||
* arithmetic instructions that both receive flow from the allocation (as identified by `AllocationToInvalidPointer.qll`),
|
||||
* and further flow to a dereference (as identified by `InvalidPointerToDereference.qll`).
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
import semmle.code.cpp.ir.IR
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.7.1
|
||||
version: 0.7.2
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -1308,6 +1308,11 @@ union_etc.cpp:
|
||||
# 6| Type = [IntType] int
|
||||
# 6| ValueCategory = prvalue(load)
|
||||
# 6| getStmt(1): [ReturnStmt] return ...
|
||||
# 7| [GlobalVariable] S s
|
||||
# 7| getInitializer(): [Initializer] initializer for s
|
||||
# 7| getExpr(): [ConstructorCall] call to S
|
||||
# 7| Type = [VoidType] void
|
||||
# 7| ValueCategory = prvalue
|
||||
# 9| [CopyAssignmentOperator] C& C::operator=(C const&)
|
||||
# 9| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
@@ -1332,6 +1337,7 @@ union_etc.cpp:
|
||||
# 12| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] U &&
|
||||
# 14| [GlobalVariable] C c
|
||||
# 16| [CopyAssignmentOperator] U& U::operator=(U const&)
|
||||
# 16| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
@@ -1356,6 +1362,7 @@ union_etc.cpp:
|
||||
# 18| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] C &&
|
||||
# 20| [GlobalVariable] U u
|
||||
# 22| [TopLevelFunction] int foo()
|
||||
# 22| <params>:
|
||||
# 22| getEntryPoint(): [BlockStmt] { ... }
|
||||
|
||||
@@ -221,6 +221,13 @@ edges
|
||||
| test.cpp:656:3:656:6 | ... ++ | test.cpp:662:3:662:11 | ... = ... |
|
||||
| test.cpp:656:3:656:6 | ... ++ | test.cpp:662:3:662:11 | ... = ... |
|
||||
| test.cpp:667:14:667:31 | new[] | test.cpp:675:7:675:23 | ... = ... |
|
||||
| test.cpp:695:13:695:26 | new[] | test.cpp:698:5:698:10 | ... += ... |
|
||||
| test.cpp:698:5:698:10 | ... += ... | test.cpp:701:15:701:16 | * ... |
|
||||
| test.cpp:705:18:705:18 | q | test.cpp:705:18:705:18 | q |
|
||||
| test.cpp:705:18:705:18 | q | test.cpp:706:12:706:13 | * ... |
|
||||
| test.cpp:705:18:705:18 | q | test.cpp:706:12:706:13 | * ... |
|
||||
| test.cpp:711:13:711:26 | new[] | test.cpp:714:11:714:11 | q |
|
||||
| test.cpp:714:11:714:11 | q | test.cpp:705:18:705:18 | q |
|
||||
nodes
|
||||
| test.cpp:4:15:4:20 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
|
||||
@@ -370,6 +377,14 @@ nodes
|
||||
| test.cpp:662:3:662:11 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:667:14:667:31 | new[] | semmle.label | new[] |
|
||||
| test.cpp:675:7:675:23 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:695:13:695:26 | new[] | semmle.label | new[] |
|
||||
| test.cpp:698:5:698:10 | ... += ... | semmle.label | ... += ... |
|
||||
| test.cpp:701:15:701:16 | * ... | semmle.label | * ... |
|
||||
| test.cpp:705:18:705:18 | q | semmle.label | q |
|
||||
| test.cpp:705:18:705:18 | q | semmle.label | q |
|
||||
| test.cpp:706:12:706:13 | * ... | semmle.label | * ... |
|
||||
| test.cpp:711:13:711:26 | new[] | semmle.label | new[] |
|
||||
| test.cpp:714:11:714:11 | q | semmle.label | q |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:6:14:6:15 | * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:6:14:6:15 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
|
||||
@@ -405,3 +420,5 @@ subpaths
|
||||
| test.cpp:647:5:647:19 | ... = ... | test.cpp:642:14:642:31 | new[] | test.cpp:647:5:647:19 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:642:14:642:31 | new[] | new[] | test.cpp:647:8:647:14 | src_pos | src_pos |
|
||||
| test.cpp:662:3:662:11 | ... = ... | test.cpp:652:14:652:27 | new[] | test.cpp:662:3:662:11 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:652:14:652:27 | new[] | new[] | test.cpp:653:19:653:22 | size | size |
|
||||
| test.cpp:675:7:675:23 | ... = ... | test.cpp:667:14:667:31 | new[] | test.cpp:675:7:675:23 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:667:14:667:31 | new[] | new[] | test.cpp:675:10:675:18 | ... ++ | ... ++ |
|
||||
| test.cpp:701:15:701:16 | * ... | test.cpp:695:13:695:26 | new[] | test.cpp:701:15:701:16 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:695:13:695:26 | new[] | new[] | test.cpp:696:19:696:22 | size | size |
|
||||
| test.cpp:706:12:706:13 | * ... | test.cpp:711:13:711:26 | new[] | test.cpp:706:12:706:13 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:711:13:711:26 | new[] | new[] | test.cpp:712:19:712:22 | size | size |
|
||||
|
||||
@@ -689,4 +689,28 @@ void test_missing_call_context_2(unsigned size) {
|
||||
int* p = new int[size];
|
||||
int* end_minus_one = pointer_arithmetic(p, size - 1);
|
||||
*end_minus_one = '0'; // $ deref=L680->L690->L691 // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test34(unsigned size) {
|
||||
char *p = new char[size];
|
||||
char *end = p + size + 1; // $ alloc=L695
|
||||
if (p + 1 < end) {
|
||||
p += 1;
|
||||
}
|
||||
if (p + 1 < end) {
|
||||
int val = *p; // $ deref=L698->L700->L701 // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
void deref(char* q) {
|
||||
char x = *q; // $ deref=L714->L705->L706 // BAD
|
||||
}
|
||||
|
||||
void test35(unsigned long size, char* q)
|
||||
{
|
||||
char* p = new char[size];
|
||||
char* end = p + size; // $ alloc=L711
|
||||
if(q <= end) {
|
||||
deref(q);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,3 +16,5 @@ class AddressOfGetter {
|
||||
&field;
|
||||
}
|
||||
};
|
||||
|
||||
__declspec("SAL_volatile") char* pBuf;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
| ms_var_attributes.cpp:8:15:8:20 | myInt4 | ms_var_attributes.cpp:8:1:8:9 | dllexport |
|
||||
| ms_var_attributes.cpp:9:5:9:10 | myInt5 | ms_var_attributes.h:7:1:7:9 | dllexport |
|
||||
| ms_var_attributes.cpp:12:42:12:46 | field | ms_var_attributes.cpp:12:14:12:21 | property |
|
||||
| ms_var_attributes.cpp:20:34:20:37 | pBuf | ms_var_attributes.cpp:20:12:20:12 | SAL_volatile |
|
||||
| ms_var_attributes.h:5:22:5:27 | myInt3 | ms_var_attributes.h:5:1:5:9 | dllexport |
|
||||
| var_attributes.c:1:12:1:19 | weak_var | var_attributes.c:1:36:1:39 | weak |
|
||||
| var_attributes.c:2:12:2:22 | weakref_var | var_attributes.c:2:39:2:45 | weakref |
|
||||
|
||||
@@ -1728,6 +1728,76 @@ complex.c:
|
||||
# 144| Type = [LongDoubleType] long double
|
||||
# 144| ValueCategory = prvalue
|
||||
# 145| getStmt(72): [ReturnStmt] return ...
|
||||
ir.c:
|
||||
# 5| [TopLevelFunction] int getX(MyCoords*)
|
||||
# 5| <params>:
|
||||
# 5| getParameter(0): [Parameter] coords
|
||||
# 5| Type = [PointerType] MyCoords *
|
||||
# 7| [TopLevelFunction] void MyCoordsTest(int)
|
||||
# 7| <params>:
|
||||
# 7| getParameter(0): [Parameter] pos
|
||||
# 7| Type = [IntType] int
|
||||
# 7| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 8| getStmt(0): [DeclStmt] declaration
|
||||
# 8| getDeclarationEntry(0): [VariableDeclarationEntry] definition of coords
|
||||
# 8| Type = [CTypedefType] MyCoords
|
||||
# 8| getVariable().getInitializer(): [Initializer] initializer for coords
|
||||
# 8| getExpr(): [ClassAggregateLiteral] {...}
|
||||
# 8| Type = [Struct] (unnamed class/struct/union)
|
||||
# 8| ValueCategory = prvalue
|
||||
# 8| getAFieldExpr(x): [Literal] 0
|
||||
# 8| Type = [IntType] int
|
||||
# 8| Value = [Literal] 0
|
||||
# 8| ValueCategory = prvalue
|
||||
# 9| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 9| getExpr(): [AssignExpr] ... = ...
|
||||
# 9| Type = [IntType] int
|
||||
# 9| ValueCategory = prvalue
|
||||
# 9| getLValue(): [ValueFieldAccess] x
|
||||
# 9| Type = [IntType] int
|
||||
# 9| ValueCategory = lvalue
|
||||
# 9| getQualifier(): [VariableAccess] coords
|
||||
# 9| Type = [CTypedefType] MyCoords
|
||||
# 9| ValueCategory = lvalue
|
||||
# 9| getRValue(): [AssignExpr] ... = ...
|
||||
# 9| Type = [IntType] int
|
||||
# 9| ValueCategory = prvalue
|
||||
# 9| getLValue(): [ValueFieldAccess] y
|
||||
# 9| Type = [IntType] int
|
||||
# 9| ValueCategory = lvalue
|
||||
# 9| getQualifier(): [VariableAccess] coords
|
||||
# 9| Type = [CTypedefType] MyCoords
|
||||
# 9| ValueCategory = lvalue
|
||||
# 9| getRValue(): [AddExpr] ... + ...
|
||||
# 9| Type = [IntType] int
|
||||
# 9| ValueCategory = prvalue
|
||||
# 9| getLeftOperand(): [VariableAccess] pos
|
||||
# 9| Type = [IntType] int
|
||||
# 9| ValueCategory = prvalue(load)
|
||||
# 9| getRightOperand(): [Literal] 1
|
||||
# 9| Type = [IntType] int
|
||||
# 9| Value = [Literal] 1
|
||||
# 9| ValueCategory = prvalue
|
||||
# 10| getStmt(2): [ExprStmt] ExprStmt
|
||||
# 10| getExpr(): [AssignExpr] ... = ...
|
||||
# 10| Type = [IntType] int
|
||||
# 10| ValueCategory = prvalue
|
||||
# 10| getLValue(): [ValueFieldAccess] x
|
||||
# 10| Type = [IntType] int
|
||||
# 10| ValueCategory = lvalue
|
||||
# 10| getQualifier(): [VariableAccess] coords
|
||||
# 10| Type = [CTypedefType] MyCoords
|
||||
# 10| ValueCategory = lvalue
|
||||
# 10| getRValue(): [FunctionCall] call to getX
|
||||
# 10| Type = [IntType] int
|
||||
# 10| ValueCategory = prvalue
|
||||
# 10| getArgument(0): [AddressOfExpr] & ...
|
||||
# 10| Type = [PointerType] MyCoords *
|
||||
# 10| ValueCategory = prvalue
|
||||
# 10| getOperand(): [VariableAccess] coords
|
||||
# 10| Type = [CTypedefType] MyCoords
|
||||
# 10| ValueCategory = lvalue
|
||||
# 11| getStmt(3): [ReturnStmt] return ...
|
||||
ir.cpp:
|
||||
# 1| [TopLevelFunction] void Constants()
|
||||
# 1| <params>:
|
||||
@@ -8529,6 +8599,11 @@ ir.cpp:
|
||||
# 1035| Type = [Struct] EmptyStruct
|
||||
# 1035| ValueCategory = prvalue
|
||||
# 1036| getStmt(1): [ReturnStmt] return ...
|
||||
# 1038| [GlobalVariable] (lambda [] type at line 1038, col. 12) lam
|
||||
# 1038| getInitializer(): [Initializer] initializer for lam
|
||||
# 1038| getExpr(): [LambdaExpression] [...](...){...}
|
||||
# 1038| Type = [Closure] decltype([...](...){...})
|
||||
# 1038| ValueCategory = prvalue
|
||||
# 1038| [CopyAssignmentOperator] (lambda [] type at line 1038, col. 12)& (lambda [] type at line 1038, col. 12)::operator=((lambda [] type at line 1038, col. 12) const&)
|
||||
# 1038| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
@@ -13976,6 +14051,54 @@ ir.cpp:
|
||||
# 1815| Type = [IntType] int
|
||||
# 1815| ValueCategory = prvalue(load)
|
||||
# 1817| getStmt(8): [ReturnStmt] return ...
|
||||
# 1821| [GlobalVariable] int global_2
|
||||
# 1821| getInitializer(): [Initializer] initializer for global_2
|
||||
# 1821| getExpr(): [Literal] 1
|
||||
# 1821| Type = [IntType] int
|
||||
# 1821| Value = [Literal] 1
|
||||
# 1821| ValueCategory = prvalue
|
||||
# 1823| [GlobalVariable] int const global_3
|
||||
# 1823| getInitializer(): [Initializer] initializer for global_3
|
||||
# 1823| getExpr(): [Literal] 2
|
||||
# 1823| Type = [IntType] int
|
||||
# 1823| Value = [Literal] 2
|
||||
# 1823| ValueCategory = prvalue
|
||||
# 1825| [GlobalVariable] constructor_only global_4
|
||||
# 1825| getInitializer(): [Initializer] initializer for global_4
|
||||
# 1825| getExpr(): [ConstructorCall] call to constructor_only
|
||||
# 1825| Type = [VoidType] void
|
||||
# 1825| ValueCategory = prvalue
|
||||
# 1825| getArgument(0): [Literal] 1
|
||||
# 1825| Type = [IntType] int
|
||||
# 1825| Value = [Literal] 1
|
||||
# 1825| ValueCategory = prvalue
|
||||
# 1827| [GlobalVariable] constructor_only global_5
|
||||
# 1827| getInitializer(): [Initializer] initializer for global_5
|
||||
# 1827| getExpr(): [ConstructorCall] call to constructor_only
|
||||
# 1827| Type = [VoidType] void
|
||||
# 1827| ValueCategory = prvalue
|
||||
# 1827| getArgument(0): [Literal] 2
|
||||
# 1827| Type = [IntType] int
|
||||
# 1827| Value = [Literal] 2
|
||||
# 1827| ValueCategory = prvalue
|
||||
# 1829| [GlobalVariable] char* global_string
|
||||
# 1829| getInitializer(): [Initializer] initializer for global_string
|
||||
# 1829| getExpr(): global string
|
||||
# 1829| Type = [ArrayType] const char[14]
|
||||
# 1829| Value = [StringLiteral] "global string"
|
||||
# 1829| ValueCategory = lvalue
|
||||
# 1829| getExpr().getFullyConverted(): [CStyleCast] (char *)...
|
||||
# 1829| Conversion = [PointerConversion] pointer conversion
|
||||
# 1829| Type = [CharPointerType] char *
|
||||
# 1829| ValueCategory = prvalue
|
||||
# 1829| getExpr(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 1829| Type = [PointerType] const char *
|
||||
# 1829| ValueCategory = prvalue
|
||||
# 1831| [GlobalVariable] int global_6
|
||||
# 1831| getInitializer(): [Initializer] initializer for global_6
|
||||
# 1831| getExpr(): [VariableAccess] global_2
|
||||
# 1831| Type = [IntType] int
|
||||
# 1831| ValueCategory = prvalue(load)
|
||||
# 1834| [CopyAssignmentOperator] block_assignment::A& block_assignment::A::operator=(block_assignment::A const&)
|
||||
# 1834| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
@@ -14377,6 +14500,23 @@ ir.cpp:
|
||||
# 1885| Type = [ClassTemplateInstantiation,Struct] Bar2<int>
|
||||
# 1885| ValueCategory = lvalue
|
||||
# 1886| getStmt(2): [ReturnStmt] return ...
|
||||
# 1889| [GlobalVariable] char global_template<char>
|
||||
# 1889| getInitializer(): [Initializer] initializer for global_template
|
||||
# 1889| getExpr(): [Literal] 42
|
||||
# 1889| Type = [IntType] int
|
||||
# 1889| Value = [Literal] 42
|
||||
# 1889| ValueCategory = prvalue
|
||||
# 1889| getExpr().getFullyConverted(): [CStyleCast] (char)...
|
||||
# 1889| Conversion = [IntegralConversion] integral conversion
|
||||
# 1889| Type = [PlainCharType] char
|
||||
# 1889| Value = [CStyleCast] 42
|
||||
# 1889| ValueCategory = prvalue
|
||||
# 1889| [GlobalVariable] int global_template<int>
|
||||
# 1889| getInitializer(): [Initializer] initializer for global_template
|
||||
# 1889| getExpr(): [Literal] 42
|
||||
# 1889| Type = [IntType] int
|
||||
# 1889| Value = [Literal] 42
|
||||
# 1889| ValueCategory = prvalue
|
||||
# 1891| [TopLevelFunction] int test_global_template_int()
|
||||
# 1891| <params>:
|
||||
# 1891| getEntryPoint(): [BlockStmt] { ... }
|
||||
@@ -14888,6 +15028,514 @@ ir.cpp:
|
||||
# 1993| Type = [Class] C
|
||||
# 1993| ValueCategory = lvalue
|
||||
# 1994| getStmt(3): [ReturnStmt] return ...
|
||||
# 1996| [TopLevelFunction] void TernaryTestInt(bool, int, int, int)
|
||||
# 1996| <params>:
|
||||
# 1996| getParameter(0): [Parameter] a
|
||||
# 1996| Type = [BoolType] bool
|
||||
# 1996| getParameter(1): [Parameter] x
|
||||
# 1996| Type = [IntType] int
|
||||
# 1996| getParameter(2): [Parameter] y
|
||||
# 1996| Type = [IntType] int
|
||||
# 1996| getParameter(3): [Parameter] z
|
||||
# 1996| Type = [IntType] int
|
||||
# 1996| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1997| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 1997| getExpr(): [AssignExpr] ... = ...
|
||||
# 1997| Type = [IntType] int
|
||||
# 1997| ValueCategory = lvalue
|
||||
# 1997| getLValue(): [VariableAccess] z
|
||||
# 1997| Type = [IntType] int
|
||||
# 1997| ValueCategory = lvalue
|
||||
# 1997| getRValue(): [ConditionalExpr] ... ? ... : ...
|
||||
# 1997| Type = [IntType] int
|
||||
# 1997| ValueCategory = prvalue
|
||||
# 1997| getCondition(): [VariableAccess] a
|
||||
# 1997| Type = [BoolType] bool
|
||||
# 1997| ValueCategory = prvalue(load)
|
||||
# 1997| getThen(): [VariableAccess] x
|
||||
# 1997| Type = [IntType] int
|
||||
# 1997| ValueCategory = prvalue(load)
|
||||
# 1997| getElse(): [VariableAccess] y
|
||||
# 1997| Type = [IntType] int
|
||||
# 1997| ValueCategory = prvalue(load)
|
||||
# 1998| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 1998| getExpr(): [AssignExpr] ... = ...
|
||||
# 1998| Type = [IntType] int
|
||||
# 1998| ValueCategory = lvalue
|
||||
# 1998| getLValue(): [VariableAccess] z
|
||||
# 1998| Type = [IntType] int
|
||||
# 1998| ValueCategory = lvalue
|
||||
# 1998| getRValue(): [ConditionalExpr] ... ? ... : ...
|
||||
# 1998| Type = [IntType] int
|
||||
# 1998| ValueCategory = prvalue
|
||||
# 1998| getCondition(): [VariableAccess] a
|
||||
# 1998| Type = [BoolType] bool
|
||||
# 1998| ValueCategory = prvalue(load)
|
||||
# 1998| getThen(): [VariableAccess] x
|
||||
# 1998| Type = [IntType] int
|
||||
# 1998| ValueCategory = prvalue(load)
|
||||
# 1998| getElse(): [Literal] 5
|
||||
# 1998| Type = [IntType] int
|
||||
# 1998| Value = [Literal] 5
|
||||
# 1998| ValueCategory = prvalue
|
||||
# 1999| getStmt(2): [ExprStmt] ExprStmt
|
||||
# 1999| getExpr(): [AssignExpr] ... = ...
|
||||
# 1999| Type = [IntType] int
|
||||
# 1999| ValueCategory = lvalue
|
||||
# 1999| getLValue(): [VariableAccess] z
|
||||
# 1999| Type = [IntType] int
|
||||
# 1999| ValueCategory = lvalue
|
||||
# 1999| getRValue(): [ConditionalExpr] ... ? ... : ...
|
||||
# 1999| Type = [IntType] int
|
||||
# 1999| ValueCategory = prvalue
|
||||
# 1999| getCondition(): [VariableAccess] a
|
||||
# 1999| Type = [BoolType] bool
|
||||
# 1999| ValueCategory = prvalue(load)
|
||||
# 1999| getThen(): [Literal] 3
|
||||
# 1999| Type = [IntType] int
|
||||
# 1999| Value = [Literal] 3
|
||||
# 1999| ValueCategory = prvalue
|
||||
# 1999| getElse(): [Literal] 5
|
||||
# 1999| Type = [IntType] int
|
||||
# 1999| Value = [Literal] 5
|
||||
# 1999| ValueCategory = prvalue
|
||||
# 2000| getStmt(3): [ExprStmt] ExprStmt
|
||||
# 2000| getExpr(): [AssignExpr] ... = ...
|
||||
# 2000| Type = [IntType] int
|
||||
# 2000| ValueCategory = lvalue
|
||||
# 2000| getLValue(): [ConditionalExpr] ... ? ... : ...
|
||||
# 2000| Type = [IntType] int
|
||||
# 2000| ValueCategory = lvalue
|
||||
# 2000| getCondition(): [VariableAccess] a
|
||||
# 2000| Type = [BoolType] bool
|
||||
# 2000| ValueCategory = prvalue(load)
|
||||
# 2000| getThen(): [VariableAccess] x
|
||||
# 2000| Type = [IntType] int
|
||||
# 2000| ValueCategory = lvalue
|
||||
# 2000| getElse(): [VariableAccess] y
|
||||
# 2000| Type = [IntType] int
|
||||
# 2000| ValueCategory = lvalue
|
||||
# 2000| getRValue(): [Literal] 7
|
||||
# 2000| Type = [IntType] int
|
||||
# 2000| Value = [Literal] 7
|
||||
# 2000| ValueCategory = prvalue
|
||||
# 2000| getLValue().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2000| Type = [IntType] int
|
||||
# 2000| ValueCategory = lvalue
|
||||
# 2001| getStmt(4): [ReturnStmt] return ...
|
||||
# 2003| [CopyAssignmentOperator] TernaryPodObj& TernaryPodObj::operator=(TernaryPodObj const&)
|
||||
# 2003| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const TernaryPodObj &
|
||||
# 2003| [MoveAssignmentOperator] TernaryPodObj& TernaryPodObj::operator=(TernaryPodObj&&)
|
||||
# 2003| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] TernaryPodObj &&
|
||||
# 2006| [TopLevelFunction] void TernaryTestPodObj(bool, TernaryPodObj, TernaryPodObj, TernaryPodObj)
|
||||
# 2006| <params>:
|
||||
# 2006| getParameter(0): [Parameter] a
|
||||
# 2006| Type = [BoolType] bool
|
||||
# 2006| getParameter(1): [Parameter] x
|
||||
# 2006| Type = [Struct] TernaryPodObj
|
||||
# 2006| getParameter(2): [Parameter] y
|
||||
# 2006| Type = [Struct] TernaryPodObj
|
||||
# 2006| getParameter(3): [Parameter] z
|
||||
# 2006| Type = [Struct] TernaryPodObj
|
||||
# 2006| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2007| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 2007| getExpr(): [AssignExpr] ... = ...
|
||||
# 2007| Type = [Struct] TernaryPodObj
|
||||
# 2007| ValueCategory = lvalue
|
||||
# 2007| getLValue(): [VariableAccess] z
|
||||
# 2007| Type = [Struct] TernaryPodObj
|
||||
# 2007| ValueCategory = lvalue
|
||||
# 2007| getRValue(): [ConditionalExpr] ... ? ... : ...
|
||||
# 2007| Type = [Struct] TernaryPodObj
|
||||
# 2007| ValueCategory = prvalue
|
||||
# 2007| getCondition(): [VariableAccess] a
|
||||
# 2007| Type = [BoolType] bool
|
||||
# 2007| ValueCategory = prvalue(load)
|
||||
# 2007| getThen(): [VariableAccess] x
|
||||
# 2007| Type = [Struct] TernaryPodObj
|
||||
# 2007| ValueCategory = prvalue(load)
|
||||
# 2007| getElse(): [VariableAccess] y
|
||||
# 2007| Type = [Struct] TernaryPodObj
|
||||
# 2007| ValueCategory = prvalue(load)
|
||||
# 2008| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 2008| getExpr(): [AssignExpr] ... = ...
|
||||
# 2008| Type = [Struct] TernaryPodObj
|
||||
# 2008| ValueCategory = lvalue
|
||||
# 2008| getLValue(): [VariableAccess] z
|
||||
# 2008| Type = [Struct] TernaryPodObj
|
||||
# 2008| ValueCategory = lvalue
|
||||
# 2008| getRValue(): [ConditionalExpr] ... ? ... : ...
|
||||
# 2008| Type = [Struct] TernaryPodObj
|
||||
# 2008| ValueCategory = prvalue
|
||||
# 2008| getCondition(): [VariableAccess] a
|
||||
# 2008| Type = [BoolType] bool
|
||||
# 2008| ValueCategory = prvalue(load)
|
||||
# 2008| getThen(): [VariableAccess] x
|
||||
# 2008| Type = [Struct] TernaryPodObj
|
||||
# 2008| ValueCategory = prvalue(load)
|
||||
# 2008| getElse(): [Literal] 0
|
||||
# 2008| Type = [Struct] TernaryPodObj
|
||||
# 2008| Value = [Literal] 0
|
||||
# 2008| ValueCategory = prvalue
|
||||
# 2008| getThen().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 2008| Type = [Struct] TernaryPodObj
|
||||
# 2008| ValueCategory = prvalue(load)
|
||||
# 2008| getElse().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 2008| Type = [Struct] TernaryPodObj
|
||||
# 2008| ValueCategory = prvalue(load)
|
||||
# 2008| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 2008| Type = [Struct] TernaryPodObj
|
||||
# 2008| ValueCategory = prvalue(load)
|
||||
# 2009| getStmt(2): [ExprStmt] ExprStmt
|
||||
# 2009| getExpr(): [AssignExpr] ... = ...
|
||||
# 2009| Type = [Struct] TernaryPodObj
|
||||
# 2009| ValueCategory = lvalue
|
||||
# 2009| getLValue(): [VariableAccess] z
|
||||
# 2009| Type = [Struct] TernaryPodObj
|
||||
# 2009| ValueCategory = lvalue
|
||||
# 2009| getRValue(): [ConditionalExpr] ... ? ... : ...
|
||||
# 2009| Type = [Struct] TernaryPodObj
|
||||
# 2009| ValueCategory = prvalue
|
||||
# 2009| getCondition(): [VariableAccess] a
|
||||
# 2009| Type = [BoolType] bool
|
||||
# 2009| ValueCategory = prvalue(load)
|
||||
# 2009| getThen(): [Literal] 0
|
||||
# 2009| Type = [Struct] TernaryPodObj
|
||||
# 2009| Value = [Literal] 0
|
||||
# 2009| ValueCategory = prvalue
|
||||
# 2009| getElse(): [Literal] 0
|
||||
# 2009| Type = [Struct] TernaryPodObj
|
||||
# 2009| Value = [Literal] 0
|
||||
# 2009| ValueCategory = prvalue
|
||||
# 2009| getThen().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 2009| Type = [Struct] TernaryPodObj
|
||||
# 2009| ValueCategory = prvalue(load)
|
||||
# 2009| getElse().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 2009| Type = [Struct] TernaryPodObj
|
||||
# 2009| ValueCategory = prvalue(load)
|
||||
# 2009| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 2009| Type = [Struct] TernaryPodObj
|
||||
# 2009| ValueCategory = prvalue(load)
|
||||
# 2010| getStmt(3): [ExprStmt] ExprStmt
|
||||
# 2010| getExpr(): [AssignExpr] ... = ...
|
||||
# 2010| Type = [Struct] TernaryPodObj
|
||||
# 2010| ValueCategory = lvalue
|
||||
# 2010| getLValue(): [AssignExpr] ... = ...
|
||||
# 2010| Type = [Struct] TernaryPodObj
|
||||
# 2010| ValueCategory = lvalue
|
||||
# 2010| getLValue(): [VariableAccess] z
|
||||
# 2010| Type = [Struct] TernaryPodObj
|
||||
# 2010| ValueCategory = lvalue
|
||||
# 2010| getRValue(): [ConditionalExpr] ... ? ... : ...
|
||||
# 2010| Type = [Struct] TernaryPodObj
|
||||
# 2010| ValueCategory = prvalue
|
||||
# 2010| getCondition(): [VariableAccess] a
|
||||
# 2010| Type = [BoolType] bool
|
||||
# 2010| ValueCategory = prvalue(load)
|
||||
# 2010| getThen(): [VariableAccess] x
|
||||
# 2010| Type = [Struct] TernaryPodObj
|
||||
# 2010| ValueCategory = prvalue(load)
|
||||
# 2010| getElse(): [VariableAccess] y
|
||||
# 2010| Type = [Struct] TernaryPodObj
|
||||
# 2010| ValueCategory = prvalue(load)
|
||||
# 2010| getRValue(): [Literal] 0
|
||||
# 2010| Type = [Struct] TernaryPodObj
|
||||
# 2010| Value = [Literal] 0
|
||||
# 2010| ValueCategory = prvalue
|
||||
# 2010| getLValue().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2010| Type = [Struct] TernaryPodObj
|
||||
# 2010| ValueCategory = lvalue
|
||||
# 2010| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 2010| Type = [Struct] TernaryPodObj
|
||||
# 2010| ValueCategory = prvalue(load)
|
||||
# 2011| getStmt(4): [ReturnStmt] return ...
|
||||
# 2013| [CopyAssignmentOperator] TernaryNonPodObj& TernaryNonPodObj::operator=(TernaryNonPodObj const&)
|
||||
# 2013| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const TernaryNonPodObj &
|
||||
#-----| getEntryPoint(): [BlockStmt] { ... }
|
||||
#-----| getStmt(0): [ReturnStmt] return ...
|
||||
#-----| getExpr(): [PointerDereferenceExpr] * ...
|
||||
#-----| Type = [Struct] TernaryNonPodObj
|
||||
#-----| ValueCategory = lvalue
|
||||
#-----| getOperand(): [ThisExpr] this
|
||||
#-----| Type = [PointerType] TernaryNonPodObj *
|
||||
#-----| ValueCategory = prvalue(load)
|
||||
#-----| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
#-----| Type = [LValueReferenceType] TernaryNonPodObj &
|
||||
#-----| ValueCategory = prvalue
|
||||
# 2013| [Constructor] void TernaryNonPodObj::TernaryNonPodObj()
|
||||
# 2013| <params>:
|
||||
# 2013| <initializations>:
|
||||
# 2013| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2013| getStmt(0): [ReturnStmt] return ...
|
||||
# 2013| [CopyConstructor] void TernaryNonPodObj::TernaryNonPodObj(TernaryNonPodObj const&)
|
||||
# 2013| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const TernaryNonPodObj &
|
||||
# 2013| <initializations>:
|
||||
# 2013| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2013| getStmt(0): [ReturnStmt] return ...
|
||||
# 2014| [Destructor,VirtualFunction] void TernaryNonPodObj::~TernaryNonPodObj()
|
||||
# 2014| <params>:
|
||||
# 2014| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2014| getStmt(0): [ReturnStmt] return ...
|
||||
# 2014| <destructions>:
|
||||
# 2017| [TopLevelFunction] void TernaryTestNonPodObj(bool, TernaryNonPodObj, TernaryNonPodObj, TernaryNonPodObj)
|
||||
# 2017| <params>:
|
||||
# 2017| getParameter(0): [Parameter] a
|
||||
# 2017| Type = [BoolType] bool
|
||||
# 2017| getParameter(1): [Parameter] x
|
||||
# 2017| Type = [Struct] TernaryNonPodObj
|
||||
# 2017| getParameter(2): [Parameter] y
|
||||
# 2017| Type = [Struct] TernaryNonPodObj
|
||||
# 2017| getParameter(3): [Parameter] z
|
||||
# 2017| Type = [Struct] TernaryNonPodObj
|
||||
# 2017| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2018| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 2018| getExpr(): [FunctionCall] call to operator=
|
||||
# 2018| Type = [LValueReferenceType] TernaryNonPodObj &
|
||||
# 2018| ValueCategory = prvalue
|
||||
# 2018| getQualifier(): [VariableAccess] z
|
||||
# 2018| Type = [Struct] TernaryNonPodObj
|
||||
# 2018| ValueCategory = lvalue
|
||||
# 2018| getArgument(0): [ConditionalExpr] ... ? ... : ...
|
||||
# 2018| Type = [Struct] TernaryNonPodObj
|
||||
# 2018| ValueCategory = lvalue
|
||||
# 2018| getCondition(): [VariableAccess] a
|
||||
# 2018| Type = [BoolType] bool
|
||||
# 2018| ValueCategory = prvalue(load)
|
||||
# 2018| getThen(): [VariableAccess] x
|
||||
# 2018| Type = [Struct] TernaryNonPodObj
|
||||
# 2018| ValueCategory = lvalue
|
||||
# 2018| getElse(): [VariableAccess] y
|
||||
# 2018| Type = [Struct] TernaryNonPodObj
|
||||
# 2018| ValueCategory = lvalue
|
||||
# 2018| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 2018| Type = [LValueReferenceType] const TernaryNonPodObj &
|
||||
# 2018| ValueCategory = prvalue
|
||||
# 2018| getExpr(): [CStyleCast] (const TernaryNonPodObj)...
|
||||
# 2018| Conversion = [GlvalueConversion] glvalue conversion
|
||||
# 2018| Type = [SpecifiedType] const TernaryNonPodObj
|
||||
# 2018| ValueCategory = lvalue
|
||||
# 2018| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 2018| Type = [Struct] TernaryNonPodObj
|
||||
# 2018| ValueCategory = lvalue
|
||||
# 2019| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 2019| getExpr(): [FunctionCall] call to operator=
|
||||
# 2019| Type = [LValueReferenceType] TernaryNonPodObj &
|
||||
# 2019| ValueCategory = prvalue
|
||||
# 2019| getQualifier(): [VariableAccess] z
|
||||
# 2019| Type = [Struct] TernaryNonPodObj
|
||||
# 2019| ValueCategory = lvalue
|
||||
# 2019| getArgument(0): [ConditionalExpr] ... ? ... : ...
|
||||
# 2019| Type = [Struct] TernaryNonPodObj
|
||||
# 2019| ValueCategory = prvalue
|
||||
# 2019| getCondition(): [VariableAccess] a
|
||||
# 2019| Type = [BoolType] bool
|
||||
# 2019| ValueCategory = prvalue(load)
|
||||
# 2019| getThen(): [ConstructorCall] call to TernaryNonPodObj
|
||||
# 2019| Type = [VoidType] void
|
||||
# 2019| ValueCategory = prvalue
|
||||
# 2019| getArgument(0): [VariableAccess] x
|
||||
# 2019| Type = [Struct] TernaryNonPodObj
|
||||
# 2019| ValueCategory = lvalue
|
||||
# 2019| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 2019| Type = [LValueReferenceType] const TernaryNonPodObj &
|
||||
# 2019| ValueCategory = prvalue
|
||||
# 2019| getExpr(): [CStyleCast] (const TernaryNonPodObj)...
|
||||
# 2019| Conversion = [GlvalueConversion] glvalue conversion
|
||||
# 2019| Type = [SpecifiedType] const TernaryNonPodObj
|
||||
# 2019| ValueCategory = lvalue
|
||||
# 2019| getElse(): [ConstructorCall] call to TernaryNonPodObj
|
||||
# 2019| Type = [VoidType] void
|
||||
# 2019| ValueCategory = prvalue
|
||||
# 2019| getThen().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 2019| Type = [Struct] TernaryNonPodObj
|
||||
# 2019| ValueCategory = prvalue(load)
|
||||
# 2019| getElse().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 2019| Type = [Struct] TernaryNonPodObj
|
||||
# 2019| ValueCategory = prvalue(load)
|
||||
# 2019| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 2019| Type = [LValueReferenceType] const TernaryNonPodObj &
|
||||
# 2019| ValueCategory = prvalue
|
||||
# 2019| getExpr(): [CStyleCast] (const TernaryNonPodObj)...
|
||||
# 2019| Conversion = [GlvalueConversion] glvalue conversion
|
||||
# 2019| Type = [SpecifiedType] const TernaryNonPodObj
|
||||
# 2019| ValueCategory = lvalue
|
||||
# 2019| getExpr(): [TemporaryObjectExpr] temporary object
|
||||
# 2019| Type = [Struct] TernaryNonPodObj
|
||||
# 2019| ValueCategory = lvalue
|
||||
# 2019| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 2019| Type = [Struct] TernaryNonPodObj
|
||||
# 2019| ValueCategory = lvalue
|
||||
# 2020| getStmt(2): [ExprStmt] ExprStmt
|
||||
# 2020| getExpr(): [FunctionCall] call to operator=
|
||||
# 2020| Type = [LValueReferenceType] TernaryNonPodObj &
|
||||
# 2020| ValueCategory = prvalue
|
||||
# 2020| getQualifier(): [VariableAccess] z
|
||||
# 2020| Type = [Struct] TernaryNonPodObj
|
||||
# 2020| ValueCategory = lvalue
|
||||
# 2020| getArgument(0): [ConditionalExpr] ... ? ... : ...
|
||||
# 2020| Type = [Struct] TernaryNonPodObj
|
||||
# 2020| ValueCategory = prvalue
|
||||
# 2020| getCondition(): [VariableAccess] a
|
||||
# 2020| Type = [BoolType] bool
|
||||
# 2020| ValueCategory = prvalue(load)
|
||||
# 2020| getThen(): [ConstructorCall] call to TernaryNonPodObj
|
||||
# 2020| Type = [VoidType] void
|
||||
# 2020| ValueCategory = prvalue
|
||||
# 2020| getElse(): [ConstructorCall] call to TernaryNonPodObj
|
||||
# 2020| Type = [VoidType] void
|
||||
# 2020| ValueCategory = prvalue
|
||||
# 2020| getThen().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 2020| Type = [Struct] TernaryNonPodObj
|
||||
# 2020| ValueCategory = prvalue(load)
|
||||
# 2020| getElse().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 2020| Type = [Struct] TernaryNonPodObj
|
||||
# 2020| ValueCategory = prvalue(load)
|
||||
# 2020| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 2020| Type = [LValueReferenceType] const TernaryNonPodObj &
|
||||
# 2020| ValueCategory = prvalue
|
||||
# 2020| getExpr(): [CStyleCast] (const TernaryNonPodObj)...
|
||||
# 2020| Conversion = [GlvalueConversion] glvalue conversion
|
||||
# 2020| Type = [SpecifiedType] const TernaryNonPodObj
|
||||
# 2020| ValueCategory = lvalue
|
||||
# 2020| getExpr(): [TemporaryObjectExpr] temporary object
|
||||
# 2020| Type = [Struct] TernaryNonPodObj
|
||||
# 2020| ValueCategory = lvalue
|
||||
# 2020| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 2020| Type = [Struct] TernaryNonPodObj
|
||||
# 2020| ValueCategory = lvalue
|
||||
# 2021| getStmt(3): [ExprStmt] ExprStmt
|
||||
# 2021| getExpr(): [FunctionCall] call to operator=
|
||||
# 2021| Type = [LValueReferenceType] TernaryNonPodObj &
|
||||
# 2021| ValueCategory = prvalue
|
||||
# 2021| getQualifier(): [FunctionCall] call to operator=
|
||||
# 2021| Type = [LValueReferenceType] TernaryNonPodObj &
|
||||
# 2021| ValueCategory = prvalue
|
||||
# 2021| getQualifier(): [VariableAccess] z
|
||||
# 2021| Type = [Struct] TernaryNonPodObj
|
||||
# 2021| ValueCategory = lvalue
|
||||
# 2021| getArgument(0): [ConditionalExpr] ... ? ... : ...
|
||||
# 2021| Type = [Struct] TernaryNonPodObj
|
||||
# 2021| ValueCategory = lvalue
|
||||
# 2021| getCondition(): [VariableAccess] a
|
||||
# 2021| Type = [BoolType] bool
|
||||
# 2021| ValueCategory = prvalue(load)
|
||||
# 2021| getThen(): [VariableAccess] x
|
||||
# 2021| Type = [Struct] TernaryNonPodObj
|
||||
# 2021| ValueCategory = lvalue
|
||||
# 2021| getElse(): [VariableAccess] y
|
||||
# 2021| Type = [Struct] TernaryNonPodObj
|
||||
# 2021| ValueCategory = lvalue
|
||||
# 2021| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 2021| Type = [LValueReferenceType] const TernaryNonPodObj &
|
||||
# 2021| ValueCategory = prvalue
|
||||
# 2021| getExpr(): [CStyleCast] (const TernaryNonPodObj)...
|
||||
# 2021| Conversion = [GlvalueConversion] glvalue conversion
|
||||
# 2021| Type = [SpecifiedType] const TernaryNonPodObj
|
||||
# 2021| ValueCategory = lvalue
|
||||
# 2021| getArgument(0): [ConstructorCall] call to TernaryNonPodObj
|
||||
# 2021| Type = [VoidType] void
|
||||
# 2021| ValueCategory = prvalue
|
||||
# 2021| getQualifier().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2021| Type = [Struct] TernaryNonPodObj
|
||||
# 2021| ValueCategory = lvalue
|
||||
# 2021| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 2021| Type = [Struct] TernaryNonPodObj
|
||||
# 2021| ValueCategory = lvalue
|
||||
# 2021| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 2021| Type = [LValueReferenceType] const TernaryNonPodObj &
|
||||
# 2021| ValueCategory = prvalue
|
||||
# 2021| getExpr(): [CStyleCast] (const TernaryNonPodObj)...
|
||||
# 2021| Conversion = [GlvalueConversion] glvalue conversion
|
||||
# 2021| Type = [SpecifiedType] const TernaryNonPodObj
|
||||
# 2021| ValueCategory = lvalue
|
||||
# 2021| getExpr(): [TemporaryObjectExpr] temporary object
|
||||
# 2021| Type = [Struct] TernaryNonPodObj
|
||||
# 2021| ValueCategory = lvalue
|
||||
# 2021| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 2021| Type = [Struct] TernaryNonPodObj
|
||||
# 2021| ValueCategory = lvalue
|
||||
# 2022| getStmt(4): [ReturnStmt] return ...
|
||||
# 2024| [TopLevelFunction] void CommaTestHelper(unsigned int)
|
||||
# 2024| <params>:
|
||||
# 2024| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
# 2024| Type = [IntType] unsigned int
|
||||
# 2026| [TopLevelFunction] unsigned int CommaTest(unsigned int)
|
||||
# 2026| <params>:
|
||||
# 2026| getParameter(0): [Parameter] x
|
||||
# 2026| Type = [IntType] unsigned int
|
||||
# 2026| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2027| getStmt(0): [DeclStmt] declaration
|
||||
# 2027| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
|
||||
# 2027| Type = [IntType] unsigned int
|
||||
# 2028| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 2028| getExpr(): [AssignExpr] ... = ...
|
||||
# 2028| Type = [IntType] unsigned int
|
||||
# 2028| ValueCategory = lvalue
|
||||
# 2028| getLValue(): [VariableAccess] y
|
||||
# 2028| Type = [IntType] unsigned int
|
||||
# 2028| ValueCategory = lvalue
|
||||
# 2028| getRValue(): [ConditionalExpr] ... ? ... : ...
|
||||
# 2028| Type = [IntType] unsigned int
|
||||
# 2028| ValueCategory = prvalue
|
||||
# 2028| getCondition(): [LTExpr] ... < ...
|
||||
# 2028| Type = [BoolType] bool
|
||||
# 2028| ValueCategory = prvalue
|
||||
# 2028| getLesserOperand(): [VariableAccess] x
|
||||
# 2028| Type = [IntType] unsigned int
|
||||
# 2028| ValueCategory = prvalue(load)
|
||||
# 2028| getGreaterOperand(): [Literal] 100
|
||||
# 2028| Type = [IntType] int
|
||||
# 2028| Value = [Literal] 100
|
||||
# 2028| ValueCategory = prvalue
|
||||
# 2028| getGreaterOperand().getFullyConverted(): [CStyleCast] (unsigned int)...
|
||||
# 2028| Conversion = [IntegralConversion] integral conversion
|
||||
# 2028| Type = [IntType] unsigned int
|
||||
# 2028| Value = [CStyleCast] 100
|
||||
# 2028| ValueCategory = prvalue
|
||||
# 2029| getThen(): [CommaExpr] ... , ...
|
||||
# 2029| Type = [IntType] unsigned int
|
||||
# 2029| ValueCategory = prvalue
|
||||
# 2029| getLeftOperand(): [FunctionCall] call to CommaTestHelper
|
||||
# 2029| Type = [VoidType] void
|
||||
# 2029| ValueCategory = prvalue
|
||||
# 2029| getArgument(0): [VariableAccess] x
|
||||
# 2029| Type = [IntType] unsigned int
|
||||
# 2029| ValueCategory = prvalue(load)
|
||||
# 2029| getRightOperand(): [VariableAccess] x
|
||||
# 2029| Type = [IntType] unsigned int
|
||||
# 2029| ValueCategory = prvalue(load)
|
||||
# 2030| getElse(): [CommaExpr] ... , ...
|
||||
# 2030| Type = [IntType] int
|
||||
# 2030| ValueCategory = prvalue
|
||||
# 2030| getLeftOperand(): [FunctionCall] call to CommaTestHelper
|
||||
# 2030| Type = [VoidType] void
|
||||
# 2030| ValueCategory = prvalue
|
||||
# 2030| getArgument(0): [VariableAccess] x
|
||||
# 2030| Type = [IntType] unsigned int
|
||||
# 2030| ValueCategory = prvalue(load)
|
||||
# 2030| getRightOperand(): [Literal] 10
|
||||
# 2030| Type = [IntType] int
|
||||
# 2030| Value = [Literal] 10
|
||||
# 2030| ValueCategory = prvalue
|
||||
# 2029| getThen().getFullyConverted(): [ParenthesisExpr] (...)
|
||||
# 2029| Type = [IntType] unsigned int
|
||||
# 2029| ValueCategory = prvalue
|
||||
# 2030| getElse().getFullyConverted(): [CStyleCast] (unsigned int)...
|
||||
# 2030| Conversion = [IntegralConversion] integral conversion
|
||||
# 2030| Type = [IntType] unsigned int
|
||||
# 2030| ValueCategory = prvalue
|
||||
# 2030| getExpr(): [ParenthesisExpr] (...)
|
||||
# 2030| Type = [IntType] int
|
||||
# 2030| ValueCategory = prvalue
|
||||
# 2031| getStmt(2): [ReturnStmt] return ...
|
||||
perf-regression.cpp:
|
||||
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
|
||||
# 4| <params>:
|
||||
@@ -15170,6 +15818,40 @@ struct_init.cpp:
|
||||
# 4| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] Info &&
|
||||
# 9| [GlobalVariable] Info infos_in_file[]
|
||||
# 9| getInitializer(): [Initializer] initializer for infos_in_file
|
||||
# 9| getExpr(): [ArrayAggregateLiteral] {...}
|
||||
# 9| Type = [ArrayType] Info[2]
|
||||
# 9| ValueCategory = prvalue
|
||||
# 10| getAnElementExpr(0): [ClassAggregateLiteral] {...}
|
||||
# 10| Type = [Struct] Info
|
||||
# 10| ValueCategory = prvalue
|
||||
# 10| getAFieldExpr(name): 1
|
||||
# 10| Type = [ArrayType] const char[2]
|
||||
# 10| Value = [StringLiteral] "1"
|
||||
# 10| ValueCategory = lvalue
|
||||
# 10| getAFieldExpr(handler): [FunctionAccess] handler1
|
||||
# 10| Type = [FunctionPointerType] ..(*)(..)
|
||||
# 10| ValueCategory = prvalue(load)
|
||||
# 10| getAFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 10| Type = [PointerType] const char *
|
||||
# 10| ValueCategory = prvalue
|
||||
# 11| getAnElementExpr(1): [ClassAggregateLiteral] {...}
|
||||
# 11| Type = [Struct] Info
|
||||
# 11| ValueCategory = prvalue
|
||||
# 11| getAFieldExpr(name): 3
|
||||
# 11| Type = [ArrayType] const char[2]
|
||||
# 11| Value = [StringLiteral] "3"
|
||||
# 11| ValueCategory = lvalue
|
||||
# 11| getAFieldExpr(handler): [AddressOfExpr] & ...
|
||||
# 11| Type = [FunctionPointerType] ..(*)(..)
|
||||
# 11| ValueCategory = prvalue
|
||||
# 11| getOperand(): [FunctionAccess] handler2
|
||||
# 11| Type = [RoutineType] ..()(..)
|
||||
# 11| ValueCategory = lvalue
|
||||
# 11| getAFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 11| Type = [PointerType] const char *
|
||||
# 11| ValueCategory = prvalue
|
||||
# 16| [TopLevelFunction] void let_info_escape(Info*)
|
||||
# 16| <params>:
|
||||
# 16| getParameter(0): [Parameter] info
|
||||
|
||||
@@ -7,5 +7,5 @@ private import semmle.code.cpp.PrintAST
|
||||
private import PrintConfig
|
||||
|
||||
private class PrintConfig extends PrintAstConfiguration {
|
||||
override predicate shouldPrintFunction(Function func) { shouldDumpFunction(func) }
|
||||
override predicate shouldPrintDeclaration(Declaration decl) { shouldDumpDeclaration(decl) }
|
||||
}
|
||||
|
||||
@@ -8,11 +8,11 @@ predicate locationIsInStandardHeaders(Location loc) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the AST or IR for the specified function should be printed in the test output.
|
||||
* Holds if the AST or IR for the specified declaration should be printed in the test output.
|
||||
*
|
||||
* This predicate excludes functions defined in standard headers.
|
||||
* This predicate excludes declarations defined in standard headers.
|
||||
*/
|
||||
predicate shouldDumpFunction(Declaration decl) {
|
||||
predicate shouldDumpDeclaration(Declaration decl) {
|
||||
not locationIsInStandardHeaders(decl.getLocation()) and
|
||||
(
|
||||
decl instanceof Function
|
||||
|
||||
11
cpp/ql/test/library-tests/ir/ir/ir.c
Normal file
11
cpp/ql/test/library-tests/ir/ir/ir.c
Normal file
@@ -0,0 +1,11 @@
|
||||
typedef struct {
|
||||
int x, y;
|
||||
} MyCoords;
|
||||
|
||||
int getX(MyCoords *coords);
|
||||
|
||||
void MyCoordsTest(int pos) {
|
||||
MyCoords coords = {0};
|
||||
coords.x = coords.y = pos + 1;
|
||||
coords.x = getX(&coords);
|
||||
}
|
||||
@@ -1993,4 +1993,41 @@ void SetStaticFuncPtr() {
|
||||
pfn = c.StaticMemberFunction;
|
||||
}
|
||||
|
||||
void TernaryTestInt(bool a, int x, int y, int z) {
|
||||
z = a ? x : y;
|
||||
z = a ? x : 5;
|
||||
z = a ? 3 : 5;
|
||||
(a ? x : y) = 7;
|
||||
}
|
||||
|
||||
struct TernaryPodObj {
|
||||
};
|
||||
|
||||
void TernaryTestPodObj(bool a, TernaryPodObj x, TernaryPodObj y, TernaryPodObj z) {
|
||||
z = a ? x : y;
|
||||
z = a ? x : TernaryPodObj();
|
||||
z = a ? TernaryPodObj() : TernaryPodObj();
|
||||
(z = a ? x : y) = TernaryPodObj();
|
||||
}
|
||||
|
||||
struct TernaryNonPodObj {
|
||||
virtual ~TernaryNonPodObj() {}
|
||||
};
|
||||
|
||||
void TernaryTestNonPodObj(bool a, TernaryNonPodObj x, TernaryNonPodObj y, TernaryNonPodObj z) {
|
||||
z = a ? x : y;
|
||||
z = a ? x : TernaryNonPodObj();
|
||||
z = a ? TernaryNonPodObj() : TernaryNonPodObj();
|
||||
(z = a ? x : y) = TernaryNonPodObj();
|
||||
}
|
||||
|
||||
void CommaTestHelper(unsigned int);
|
||||
|
||||
unsigned int CommaTest(unsigned int x) {
|
||||
unsigned int y;
|
||||
y = x < 100 ?
|
||||
(CommaTestHelper(x), x) :
|
||||
(CommaTestHelper(x), 10);
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++17 --clang
|
||||
|
||||
@@ -680,6 +680,10 @@
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_2 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
@@ -704,6 +708,10 @@
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_4 |
|
||||
| file://:0:0:0:0 | Address | &:r0_4 |
|
||||
| file://:0:0:0:0 | Address | &:r0_5 |
|
||||
@@ -715,6 +723,8 @@
|
||||
| file://:0:0:0:0 | Address | &:r0_5 |
|
||||
| file://:0:0:0:0 | Address | &:r0_5 |
|
||||
| file://:0:0:0:0 | Address | &:r0_5 |
|
||||
| file://:0:0:0:0 | Address | &:r0_5 |
|
||||
| file://:0:0:0:0 | Address | &:r0_6 |
|
||||
| file://:0:0:0:0 | Address | &:r0_6 |
|
||||
| file://:0:0:0:0 | Address | &:r0_7 |
|
||||
| file://:0:0:0:0 | Address | &:r0_7 |
|
||||
@@ -799,6 +809,8 @@
|
||||
| file://:0:0:0:0 | Load | m0_2 |
|
||||
| file://:0:0:0:0 | Load | m0_2 |
|
||||
| file://:0:0:0:0 | Load | m0_2 |
|
||||
| file://:0:0:0:0 | Load | m0_2 |
|
||||
| file://:0:0:0:0 | Load | m0_2 |
|
||||
| file://:0:0:0:0 | Load | m0_5 |
|
||||
| file://:0:0:0:0 | Load | m0_8 |
|
||||
| file://:0:0:0:0 | Load | m0_11 |
|
||||
@@ -814,6 +826,7 @@
|
||||
| file://:0:0:0:0 | Load | m1834_6 |
|
||||
| file://:0:0:0:0 | Load | m1834_6 |
|
||||
| file://:0:0:0:0 | Load | m1839_6 |
|
||||
| file://:0:0:0:0 | Load | m2013_6 |
|
||||
| file://:0:0:0:0 | Load | ~m0_4 |
|
||||
| file://:0:0:0:0 | Load | ~m1444_6 |
|
||||
| file://:0:0:0:0 | Load | ~m1712_10 |
|
||||
@@ -832,6 +845,8 @@
|
||||
| file://:0:0:0:0 | SideEffect | m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | m0_14 |
|
||||
| file://:0:0:0:0 | SideEffect | m1078_23 |
|
||||
| file://:0:0:0:0 | SideEffect | m1078_23 |
|
||||
@@ -869,6 +884,7 @@
|
||||
| file://:0:0:0:0 | StoreValue | r0_7 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_9 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_9 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_9 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_12 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_12 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_13 |
|
||||
@@ -895,6 +911,8 @@
|
||||
| file://:0:0:0:0 | Unary | r0_7 |
|
||||
| file://:0:0:0:0 | Unary | r0_7 |
|
||||
| file://:0:0:0:0 | Unary | r0_7 |
|
||||
| file://:0:0:0:0 | Unary | r0_7 |
|
||||
| file://:0:0:0:0 | Unary | r0_8 |
|
||||
| file://:0:0:0:0 | Unary | r0_8 |
|
||||
| file://:0:0:0:0 | Unary | r0_9 |
|
||||
| file://:0:0:0:0 | Unary | r0_9 |
|
||||
@@ -914,6 +932,52 @@
|
||||
| file://:0:0:0:0 | Unary | r0_20 |
|
||||
| file://:0:0:0:0 | Unary | r0_21 |
|
||||
| file://:0:0:0:0 | Unary | r0_21 |
|
||||
| ir.c:7:6:7:17 | ChiPartial | partial:m7_3 |
|
||||
| ir.c:7:6:7:17 | ChiTotal | total:m7_2 |
|
||||
| ir.c:7:6:7:17 | SideEffect | ~m10_6 |
|
||||
| ir.c:7:23:7:25 | Address | &:r7_5 |
|
||||
| ir.c:8:12:8:17 | Address | &:r8_1 |
|
||||
| ir.c:8:12:8:17 | Unary | r8_1 |
|
||||
| ir.c:8:12:8:17 | Unary | r8_1 |
|
||||
| ir.c:8:20:8:23 | Address | &:r8_3 |
|
||||
| ir.c:8:20:8:23 | Address | &:r8_7 |
|
||||
| ir.c:8:20:8:23 | ChiPartial | partial:m8_9 |
|
||||
| ir.c:8:20:8:23 | ChiTotal | total:m8_6 |
|
||||
| ir.c:8:20:8:23 | StoreValue | r8_8 |
|
||||
| ir.c:8:22:8:22 | ChiPartial | partial:m8_5 |
|
||||
| ir.c:8:22:8:22 | ChiTotal | total:m8_2 |
|
||||
| ir.c:8:22:8:22 | StoreValue | r8_4 |
|
||||
| ir.c:9:3:9:8 | Unary | r9_10 |
|
||||
| ir.c:9:3:9:31 | ChiPartial | partial:m9_12 |
|
||||
| ir.c:9:3:9:31 | ChiTotal | total:m9_8 |
|
||||
| ir.c:9:10:9:10 | Address | &:r9_11 |
|
||||
| ir.c:9:14:9:19 | Unary | r9_5 |
|
||||
| ir.c:9:14:9:31 | ChiPartial | partial:m9_7 |
|
||||
| ir.c:9:14:9:31 | ChiTotal | total:m8_10 |
|
||||
| ir.c:9:14:9:31 | StoreValue | r9_9 |
|
||||
| ir.c:9:21:9:21 | Address | &:r9_6 |
|
||||
| ir.c:9:25:9:27 | Address | &:r9_1 |
|
||||
| ir.c:9:25:9:27 | Left | r9_2 |
|
||||
| ir.c:9:25:9:27 | Load | m7_6 |
|
||||
| ir.c:9:25:9:31 | StoreValue | r9_4 |
|
||||
| ir.c:9:25:9:31 | Unary | r9_4 |
|
||||
| ir.c:9:31:9:31 | Right | r9_3 |
|
||||
| ir.c:10:3:10:8 | Unary | r10_10 |
|
||||
| ir.c:10:3:10:26 | ChiPartial | partial:m10_12 |
|
||||
| ir.c:10:3:10:26 | ChiTotal | total:m10_9 |
|
||||
| ir.c:10:10:10:10 | Address | &:r10_11 |
|
||||
| ir.c:10:14:10:17 | CallTarget | func:r10_1 |
|
||||
| ir.c:10:14:10:17 | ChiPartial | partial:m10_5 |
|
||||
| ir.c:10:14:10:17 | ChiTotal | total:m7_4 |
|
||||
| ir.c:10:14:10:17 | SideEffect | ~m7_4 |
|
||||
| ir.c:10:14:10:17 | StoreValue | r10_4 |
|
||||
| ir.c:10:19:10:25 | Address | &:r10_3 |
|
||||
| ir.c:10:19:10:25 | Address | &:r10_3 |
|
||||
| ir.c:10:19:10:25 | Arg(0) | 0:r10_3 |
|
||||
| ir.c:10:19:10:25 | ChiPartial | partial:m10_8 |
|
||||
| ir.c:10:19:10:25 | ChiTotal | total:m9_13 |
|
||||
| ir.c:10:19:10:25 | SideEffect | ~m9_13 |
|
||||
| ir.c:10:20:10:25 | Unary | r10_2 |
|
||||
| ir.cpp:1:6:1:14 | ChiPartial | partial:m1_3 |
|
||||
| ir.cpp:1:6:1:14 | ChiTotal | total:m1_2 |
|
||||
| ir.cpp:1:6:1:14 | SideEffect | m1_3 |
|
||||
@@ -9058,6 +9122,446 @@
|
||||
| ir.cpp:1992:23:1992:45 | StoreValue | r1992_2 |
|
||||
| ir.cpp:1993:5:1993:7 | Address | &:r1993_3 |
|
||||
| ir.cpp:1993:13:1993:32 | StoreValue | r1993_2 |
|
||||
| ir.cpp:1996:6:1996:19 | ChiPartial | partial:m1996_3 |
|
||||
| ir.cpp:1996:6:1996:19 | ChiTotal | total:m1996_2 |
|
||||
| ir.cpp:1996:6:1996:19 | SideEffect | ~m2000_9 |
|
||||
| ir.cpp:1996:26:1996:26 | Address | &:r1996_5 |
|
||||
| ir.cpp:1996:33:1996:33 | Address | &:r1996_7 |
|
||||
| ir.cpp:1996:40:1996:40 | Address | &:r1996_9 |
|
||||
| ir.cpp:1996:47:1996:47 | Address | &:r1996_11 |
|
||||
| ir.cpp:1997:5:1997:5 | Address | &:r1997_7 |
|
||||
| ir.cpp:1997:9:1997:9 | Address | &:r1997_1 |
|
||||
| ir.cpp:1997:9:1997:9 | Condition | r1997_2 |
|
||||
| ir.cpp:1997:9:1997:9 | Load | m1996_6 |
|
||||
| ir.cpp:1997:9:1997:17 | Address | &:r1997_5 |
|
||||
| ir.cpp:1997:9:1997:17 | Address | &:r1997_11 |
|
||||
| ir.cpp:1997:9:1997:17 | Address | &:r1997_15 |
|
||||
| ir.cpp:1997:9:1997:17 | Load | m1997_4 |
|
||||
| ir.cpp:1997:9:1997:17 | Phi | from 2:m1997_12 |
|
||||
| ir.cpp:1997:9:1997:17 | Phi | from 3:m1997_16 |
|
||||
| ir.cpp:1997:9:1997:17 | StoreValue | r1997_6 |
|
||||
| ir.cpp:1997:13:1997:13 | Address | &:r1997_9 |
|
||||
| ir.cpp:1997:13:1997:13 | Load | m1996_8 |
|
||||
| ir.cpp:1997:13:1997:13 | StoreValue | r1997_10 |
|
||||
| ir.cpp:1997:17:1997:17 | Address | &:r1997_13 |
|
||||
| ir.cpp:1997:17:1997:17 | Load | m1996_10 |
|
||||
| ir.cpp:1997:17:1997:17 | StoreValue | r1997_14 |
|
||||
| ir.cpp:1998:5:1998:5 | Address | &:r1998_7 |
|
||||
| ir.cpp:1998:9:1998:9 | Address | &:r1998_1 |
|
||||
| ir.cpp:1998:9:1998:9 | Condition | r1998_2 |
|
||||
| ir.cpp:1998:9:1998:9 | Load | m1996_6 |
|
||||
| ir.cpp:1998:9:1998:17 | Address | &:r1998_5 |
|
||||
| ir.cpp:1998:9:1998:17 | Address | &:r1998_11 |
|
||||
| ir.cpp:1998:9:1998:17 | Address | &:r1998_14 |
|
||||
| ir.cpp:1998:9:1998:17 | Load | m1998_4 |
|
||||
| ir.cpp:1998:9:1998:17 | Phi | from 5:m1998_12 |
|
||||
| ir.cpp:1998:9:1998:17 | Phi | from 6:m1998_15 |
|
||||
| ir.cpp:1998:9:1998:17 | StoreValue | r1998_6 |
|
||||
| ir.cpp:1998:13:1998:13 | Address | &:r1998_9 |
|
||||
| ir.cpp:1998:13:1998:13 | Load | m1996_8 |
|
||||
| ir.cpp:1998:13:1998:13 | StoreValue | r1998_10 |
|
||||
| ir.cpp:1998:17:1998:17 | StoreValue | r1998_13 |
|
||||
| ir.cpp:1999:5:1999:5 | Address | &:r1999_7 |
|
||||
| ir.cpp:1999:9:1999:9 | Address | &:r1999_1 |
|
||||
| ir.cpp:1999:9:1999:9 | Condition | r1999_2 |
|
||||
| ir.cpp:1999:9:1999:9 | Load | m1996_6 |
|
||||
| ir.cpp:1999:9:1999:17 | Address | &:r1999_5 |
|
||||
| ir.cpp:1999:9:1999:17 | Address | &:r1999_10 |
|
||||
| ir.cpp:1999:9:1999:17 | Address | &:r1999_13 |
|
||||
| ir.cpp:1999:9:1999:17 | Load | m1999_4 |
|
||||
| ir.cpp:1999:9:1999:17 | Phi | from 8:m1999_11 |
|
||||
| ir.cpp:1999:9:1999:17 | Phi | from 9:m1999_14 |
|
||||
| ir.cpp:1999:9:1999:17 | StoreValue | r1999_6 |
|
||||
| ir.cpp:1999:13:1999:13 | StoreValue | r1999_9 |
|
||||
| ir.cpp:1999:17:1999:17 | StoreValue | r1999_12 |
|
||||
| ir.cpp:2000:5:2000:19 | ChiPartial | partial:m2000_8 |
|
||||
| ir.cpp:2000:5:2000:19 | ChiTotal | total:m1996_4 |
|
||||
| ir.cpp:2000:6:2000:6 | Address | &:r2000_2 |
|
||||
| ir.cpp:2000:6:2000:6 | Condition | r2000_3 |
|
||||
| ir.cpp:2000:6:2000:6 | Load | m1996_6 |
|
||||
| ir.cpp:2000:6:2000:14 | Address | &:r2000_6 |
|
||||
| ir.cpp:2000:6:2000:14 | Address | &:r2000_7 |
|
||||
| ir.cpp:2000:6:2000:14 | Address | &:r2000_11 |
|
||||
| ir.cpp:2000:6:2000:14 | Address | &:r2000_14 |
|
||||
| ir.cpp:2000:6:2000:14 | Load | m2000_5 |
|
||||
| ir.cpp:2000:6:2000:14 | Phi | from 11:m2000_12 |
|
||||
| ir.cpp:2000:6:2000:14 | Phi | from 12:m2000_15 |
|
||||
| ir.cpp:2000:10:2000:10 | StoreValue | r2000_10 |
|
||||
| ir.cpp:2000:14:2000:14 | StoreValue | r2000_13 |
|
||||
| ir.cpp:2000:19:2000:19 | StoreValue | r2000_1 |
|
||||
| ir.cpp:2006:6:2006:22 | ChiPartial | partial:m2006_3 |
|
||||
| ir.cpp:2006:6:2006:22 | ChiTotal | total:m2006_2 |
|
||||
| ir.cpp:2006:6:2006:22 | SideEffect | m2006_3 |
|
||||
| ir.cpp:2006:29:2006:29 | Address | &:r2006_5 |
|
||||
| ir.cpp:2006:46:2006:46 | Address | &:r2006_7 |
|
||||
| ir.cpp:2006:63:2006:63 | Address | &:r2006_9 |
|
||||
| ir.cpp:2006:80:2006:80 | Address | &:r2006_11 |
|
||||
| ir.cpp:2007:5:2007:5 | Address | &:r2007_7 |
|
||||
| ir.cpp:2007:9:2007:9 | Address | &:r2007_1 |
|
||||
| ir.cpp:2007:9:2007:9 | Condition | r2007_2 |
|
||||
| ir.cpp:2007:9:2007:9 | Load | m2006_6 |
|
||||
| ir.cpp:2007:9:2007:17 | Address | &:r2007_5 |
|
||||
| ir.cpp:2007:9:2007:17 | Address | &:r2007_11 |
|
||||
| ir.cpp:2007:9:2007:17 | Address | &:r2007_15 |
|
||||
| ir.cpp:2007:9:2007:17 | Load | m2007_4 |
|
||||
| ir.cpp:2007:9:2007:17 | Phi | from 2:m2007_12 |
|
||||
| ir.cpp:2007:9:2007:17 | Phi | from 3:m2007_16 |
|
||||
| ir.cpp:2007:9:2007:17 | StoreValue | r2007_6 |
|
||||
| ir.cpp:2007:13:2007:13 | Address | &:r2007_9 |
|
||||
| ir.cpp:2007:13:2007:13 | Load | m2006_8 |
|
||||
| ir.cpp:2007:13:2007:13 | StoreValue | r2007_10 |
|
||||
| ir.cpp:2007:17:2007:17 | Address | &:r2007_13 |
|
||||
| ir.cpp:2007:17:2007:17 | Load | m2006_10 |
|
||||
| ir.cpp:2007:17:2007:17 | StoreValue | r2007_14 |
|
||||
| ir.cpp:2008:5:2008:5 | Address | &:r2008_10 |
|
||||
| ir.cpp:2008:9:2008:9 | Address | &:r2008_2 |
|
||||
| ir.cpp:2008:9:2008:9 | Address | &:r2008_6 |
|
||||
| ir.cpp:2008:9:2008:9 | Address | &:r2008_17 |
|
||||
| ir.cpp:2008:9:2008:9 | Address | &:r2008_23 |
|
||||
| ir.cpp:2008:9:2008:9 | Condition | r2008_3 |
|
||||
| ir.cpp:2008:9:2008:9 | Load | m2006_6 |
|
||||
| ir.cpp:2008:9:2008:9 | Load | m2008_5 |
|
||||
| ir.cpp:2008:9:2008:9 | Phi | from 5:m2008_18 |
|
||||
| ir.cpp:2008:9:2008:9 | Phi | from 6:m2008_24 |
|
||||
| ir.cpp:2008:9:2008:9 | StoreValue | r2008_7 |
|
||||
| ir.cpp:2008:9:2008:31 | Address | &:r2008_1 |
|
||||
| ir.cpp:2008:9:2008:31 | Address | &:r2008_1 |
|
||||
| ir.cpp:2008:9:2008:31 | Load | m2008_8 |
|
||||
| ir.cpp:2008:9:2008:31 | StoreValue | r2008_9 |
|
||||
| ir.cpp:2008:13:2008:13 | Address | &:r2008_12 |
|
||||
| ir.cpp:2008:13:2008:13 | Address | &:r2008_12 |
|
||||
| ir.cpp:2008:13:2008:13 | Address | &:r2008_13 |
|
||||
| ir.cpp:2008:13:2008:13 | Load | m2006_8 |
|
||||
| ir.cpp:2008:13:2008:13 | Load | m2008_15 |
|
||||
| ir.cpp:2008:13:2008:13 | StoreValue | r2008_14 |
|
||||
| ir.cpp:2008:13:2008:13 | StoreValue | r2008_16 |
|
||||
| ir.cpp:2008:17:2008:31 | Address | &:r2008_19 |
|
||||
| ir.cpp:2008:17:2008:31 | Address | &:r2008_19 |
|
||||
| ir.cpp:2008:17:2008:31 | Load | m2008_21 |
|
||||
| ir.cpp:2008:17:2008:31 | StoreValue | r2008_20 |
|
||||
| ir.cpp:2008:17:2008:31 | StoreValue | r2008_22 |
|
||||
| ir.cpp:2009:5:2009:5 | Address | &:r2009_10 |
|
||||
| ir.cpp:2009:9:2009:9 | Address | &:r2009_2 |
|
||||
| ir.cpp:2009:9:2009:9 | Address | &:r2009_6 |
|
||||
| ir.cpp:2009:9:2009:9 | Address | &:r2009_16 |
|
||||
| ir.cpp:2009:9:2009:9 | Address | &:r2009_22 |
|
||||
| ir.cpp:2009:9:2009:9 | Condition | r2009_3 |
|
||||
| ir.cpp:2009:9:2009:9 | Load | m2006_6 |
|
||||
| ir.cpp:2009:9:2009:9 | Load | m2009_5 |
|
||||
| ir.cpp:2009:9:2009:9 | Phi | from 8:m2009_17 |
|
||||
| ir.cpp:2009:9:2009:9 | Phi | from 9:m2009_23 |
|
||||
| ir.cpp:2009:9:2009:9 | StoreValue | r2009_7 |
|
||||
| ir.cpp:2009:9:2009:45 | Address | &:r2009_1 |
|
||||
| ir.cpp:2009:9:2009:45 | Address | &:r2009_1 |
|
||||
| ir.cpp:2009:9:2009:45 | Load | m2009_8 |
|
||||
| ir.cpp:2009:9:2009:45 | StoreValue | r2009_9 |
|
||||
| ir.cpp:2009:13:2009:27 | Address | &:r2009_12 |
|
||||
| ir.cpp:2009:13:2009:27 | Address | &:r2009_12 |
|
||||
| ir.cpp:2009:13:2009:27 | Load | m2009_14 |
|
||||
| ir.cpp:2009:13:2009:27 | StoreValue | r2009_13 |
|
||||
| ir.cpp:2009:13:2009:27 | StoreValue | r2009_15 |
|
||||
| ir.cpp:2009:31:2009:45 | Address | &:r2009_18 |
|
||||
| ir.cpp:2009:31:2009:45 | Address | &:r2009_18 |
|
||||
| ir.cpp:2009:31:2009:45 | Load | m2009_20 |
|
||||
| ir.cpp:2009:31:2009:45 | StoreValue | r2009_19 |
|
||||
| ir.cpp:2009:31:2009:45 | StoreValue | r2009_21 |
|
||||
| ir.cpp:2010:6:2010:6 | Address | &:r2010_11 |
|
||||
| ir.cpp:2010:6:2010:6 | Unary | r2010_11 |
|
||||
| ir.cpp:2010:6:2010:18 | Address | &:r2010_13 |
|
||||
| ir.cpp:2010:10:2010:10 | Address | &:r2010_5 |
|
||||
| ir.cpp:2010:10:2010:10 | Condition | r2010_6 |
|
||||
| ir.cpp:2010:10:2010:10 | Load | m2006_6 |
|
||||
| ir.cpp:2010:10:2010:18 | Address | &:r2010_9 |
|
||||
| ir.cpp:2010:10:2010:18 | Address | &:r2010_17 |
|
||||
| ir.cpp:2010:10:2010:18 | Address | &:r2010_21 |
|
||||
| ir.cpp:2010:10:2010:18 | Load | m2010_8 |
|
||||
| ir.cpp:2010:10:2010:18 | Phi | from 11:m2010_18 |
|
||||
| ir.cpp:2010:10:2010:18 | Phi | from 12:m2010_22 |
|
||||
| ir.cpp:2010:10:2010:18 | StoreValue | r2010_10 |
|
||||
| ir.cpp:2010:14:2010:14 | Address | &:r2010_15 |
|
||||
| ir.cpp:2010:14:2010:14 | Load | m2006_8 |
|
||||
| ir.cpp:2010:14:2010:14 | StoreValue | r2010_16 |
|
||||
| ir.cpp:2010:18:2010:18 | Address | &:r2010_19 |
|
||||
| ir.cpp:2010:18:2010:18 | Load | m2006_10 |
|
||||
| ir.cpp:2010:18:2010:18 | StoreValue | r2010_20 |
|
||||
| ir.cpp:2010:23:2010:37 | Address | &:r2010_1 |
|
||||
| ir.cpp:2010:23:2010:37 | Address | &:r2010_1 |
|
||||
| ir.cpp:2010:23:2010:37 | Load | m2010_3 |
|
||||
| ir.cpp:2010:23:2010:37 | StoreValue | r2010_2 |
|
||||
| ir.cpp:2010:23:2010:37 | StoreValue | r2010_4 |
|
||||
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
|
||||
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
|
||||
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
|
||||
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
|
||||
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
|
||||
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
|
||||
| ir.cpp:2013:8:2013:8 | Address | &:r2013_7 |
|
||||
| ir.cpp:2013:8:2013:8 | Address | &:r2013_7 |
|
||||
| ir.cpp:2013:8:2013:8 | Address | &:r2013_7 |
|
||||
| ir.cpp:2013:8:2013:8 | Address | &:r2013_7 |
|
||||
| ir.cpp:2013:8:2013:8 | Address | &:r2013_7 |
|
||||
| ir.cpp:2013:8:2013:8 | Address | &:r2013_7 |
|
||||
| ir.cpp:2013:8:2013:8 | Address | &:r2013_10 |
|
||||
| ir.cpp:2013:8:2013:8 | ChiPartial | partial:m2013_3 |
|
||||
| ir.cpp:2013:8:2013:8 | ChiPartial | partial:m2013_3 |
|
||||
| ir.cpp:2013:8:2013:8 | ChiPartial | partial:m2013_3 |
|
||||
| ir.cpp:2013:8:2013:8 | ChiTotal | total:m2013_2 |
|
||||
| ir.cpp:2013:8:2013:8 | ChiTotal | total:m2013_2 |
|
||||
| ir.cpp:2013:8:2013:8 | ChiTotal | total:m2013_2 |
|
||||
| ir.cpp:2013:8:2013:8 | Load | m0_10 |
|
||||
| ir.cpp:2013:8:2013:8 | Load | m2013_6 |
|
||||
| ir.cpp:2013:8:2013:8 | Load | m2013_6 |
|
||||
| ir.cpp:2013:8:2013:8 | Load | m2013_6 |
|
||||
| ir.cpp:2013:8:2013:8 | SideEffect | m2013_3 |
|
||||
| ir.cpp:2013:8:2013:8 | SideEffect | m2013_3 |
|
||||
| ir.cpp:2013:8:2013:8 | SideEffect | m2013_3 |
|
||||
| ir.cpp:2013:8:2013:8 | SideEffect | m2013_8 |
|
||||
| ir.cpp:2013:8:2013:8 | SideEffect | m2013_8 |
|
||||
| ir.cpp:2013:8:2013:8 | SideEffect | m2013_8 |
|
||||
| ir.cpp:2014:13:2014:29 | Address | &:r2014_5 |
|
||||
| ir.cpp:2014:13:2014:29 | Address | &:r2014_5 |
|
||||
| ir.cpp:2014:13:2014:29 | Address | &:r2014_7 |
|
||||
| ir.cpp:2014:13:2014:29 | Address | &:r2014_7 |
|
||||
| ir.cpp:2014:13:2014:29 | ChiPartial | partial:m2014_3 |
|
||||
| ir.cpp:2014:13:2014:29 | ChiTotal | total:m2014_2 |
|
||||
| ir.cpp:2014:13:2014:29 | Load | m2014_6 |
|
||||
| ir.cpp:2014:13:2014:29 | SideEffect | m2014_3 |
|
||||
| ir.cpp:2014:13:2014:29 | SideEffect | m2014_8 |
|
||||
| ir.cpp:2017:6:2017:25 | ChiPartial | partial:m2017_3 |
|
||||
| ir.cpp:2017:6:2017:25 | ChiTotal | total:m2017_2 |
|
||||
| ir.cpp:2017:6:2017:25 | SideEffect | ~m2021_32 |
|
||||
| ir.cpp:2017:32:2017:32 | Address | &:r2017_5 |
|
||||
| ir.cpp:2017:52:2017:52 | Address | &:r2017_7 |
|
||||
| ir.cpp:2017:72:2017:72 | Address | &:r2017_9 |
|
||||
| ir.cpp:2017:92:2017:92 | Address | &:r2017_11 |
|
||||
| ir.cpp:2018:5:2018:5 | Address | &:r2018_1 |
|
||||
| ir.cpp:2018:5:2018:5 | Address | &:r2018_1 |
|
||||
| ir.cpp:2018:5:2018:5 | Arg(this) | this:r2018_1 |
|
||||
| ir.cpp:2018:5:2018:5 | ChiPartial | partial:m2018_16 |
|
||||
| ir.cpp:2018:5:2018:5 | ChiTotal | total:m2017_12 |
|
||||
| ir.cpp:2018:5:2018:5 | SideEffect | m2017_12 |
|
||||
| ir.cpp:2018:7:2018:7 | CallTarget | func:r2018_2 |
|
||||
| ir.cpp:2018:7:2018:7 | ChiPartial | partial:m2018_12 |
|
||||
| ir.cpp:2018:7:2018:7 | ChiTotal | total:m2017_4 |
|
||||
| ir.cpp:2018:7:2018:7 | SideEffect | ~m2017_4 |
|
||||
| ir.cpp:2018:7:2018:7 | Unary | r2018_11 |
|
||||
| ir.cpp:2018:9:2018:9 | Address | &:r2018_3 |
|
||||
| ir.cpp:2018:9:2018:9 | Condition | r2018_4 |
|
||||
| ir.cpp:2018:9:2018:9 | Load | m2017_6 |
|
||||
| ir.cpp:2018:9:2018:17 | Address | &:r2018_7 |
|
||||
| ir.cpp:2018:9:2018:17 | Address | &:r2018_10 |
|
||||
| ir.cpp:2018:9:2018:17 | Address | &:r2018_20 |
|
||||
| ir.cpp:2018:9:2018:17 | Address | &:r2018_23 |
|
||||
| ir.cpp:2018:9:2018:17 | Arg(0) | 0:r2018_10 |
|
||||
| ir.cpp:2018:9:2018:17 | Load | m2018_6 |
|
||||
| ir.cpp:2018:9:2018:17 | Phi | from 2:m2018_21 |
|
||||
| ir.cpp:2018:9:2018:17 | Phi | from 3:m2018_24 |
|
||||
| ir.cpp:2018:9:2018:17 | SideEffect | ~m2018_13 |
|
||||
| ir.cpp:2018:9:2018:17 | Unary | r2018_8 |
|
||||
| ir.cpp:2018:9:2018:17 | Unary | r2018_9 |
|
||||
| ir.cpp:2018:13:2018:13 | StoreValue | r2018_19 |
|
||||
| ir.cpp:2018:17:2018:17 | StoreValue | r2018_22 |
|
||||
| ir.cpp:2019:5:2019:5 | Address | &:r2019_1 |
|
||||
| ir.cpp:2019:5:2019:5 | Address | &:r2019_1 |
|
||||
| ir.cpp:2019:5:2019:5 | Arg(this) | this:r2019_1 |
|
||||
| ir.cpp:2019:5:2019:5 | ChiPartial | partial:m2019_19 |
|
||||
| ir.cpp:2019:5:2019:5 | ChiTotal | total:m2018_17 |
|
||||
| ir.cpp:2019:5:2019:5 | SideEffect | m2018_17 |
|
||||
| ir.cpp:2019:7:2019:7 | CallTarget | func:r2019_2 |
|
||||
| ir.cpp:2019:7:2019:7 | ChiPartial | partial:m2019_15 |
|
||||
| ir.cpp:2019:7:2019:7 | ChiTotal | total:m2019_7 |
|
||||
| ir.cpp:2019:7:2019:7 | SideEffect | ~m2019_7 |
|
||||
| ir.cpp:2019:7:2019:7 | Unary | r2019_14 |
|
||||
| ir.cpp:2019:9:2019:9 | Address | &:r2019_4 |
|
||||
| ir.cpp:2019:9:2019:9 | Address | &:r2019_9 |
|
||||
| ir.cpp:2019:9:2019:9 | Address | &:r2019_35 |
|
||||
| ir.cpp:2019:9:2019:9 | Address | &:r2019_46 |
|
||||
| ir.cpp:2019:9:2019:9 | Condition | r2019_5 |
|
||||
| ir.cpp:2019:9:2019:9 | Load | m2017_6 |
|
||||
| ir.cpp:2019:9:2019:9 | Load | m2019_8 |
|
||||
| ir.cpp:2019:9:2019:9 | Phi | from 5:m2019_36 |
|
||||
| ir.cpp:2019:9:2019:9 | Phi | from 5:~m2019_30 |
|
||||
| ir.cpp:2019:9:2019:9 | Phi | from 6:m2019_47 |
|
||||
| ir.cpp:2019:9:2019:9 | Phi | from 6:~m2019_42 |
|
||||
| ir.cpp:2019:9:2019:9 | StoreValue | r2019_10 |
|
||||
| ir.cpp:2019:9:2019:34 | Address | &:r2019_3 |
|
||||
| ir.cpp:2019:9:2019:34 | Address | &:r2019_13 |
|
||||
| ir.cpp:2019:9:2019:34 | Arg(0) | 0:r2019_13 |
|
||||
| ir.cpp:2019:9:2019:34 | SideEffect | ~m2019_11 |
|
||||
| ir.cpp:2019:9:2019:34 | Unary | r2019_3 |
|
||||
| ir.cpp:2019:9:2019:34 | Unary | r2019_12 |
|
||||
| ir.cpp:2019:13:2019:13 | Address | &:r2019_22 |
|
||||
| ir.cpp:2019:13:2019:13 | Address | &:r2019_22 |
|
||||
| ir.cpp:2019:13:2019:13 | Address | &:r2019_22 |
|
||||
| ir.cpp:2019:13:2019:13 | Address | &:r2019_27 |
|
||||
| ir.cpp:2019:13:2019:13 | Arg(0) | 0:r2019_27 |
|
||||
| ir.cpp:2019:13:2019:13 | Arg(this) | this:r2019_22 |
|
||||
| ir.cpp:2019:13:2019:13 | CallTarget | func:r2019_24 |
|
||||
| ir.cpp:2019:13:2019:13 | ChiPartial | partial:m2019_29 |
|
||||
| ir.cpp:2019:13:2019:13 | ChiPartial | partial:m2019_32 |
|
||||
| ir.cpp:2019:13:2019:13 | ChiTotal | total:m2018_13 |
|
||||
| ir.cpp:2019:13:2019:13 | ChiTotal | total:m2019_23 |
|
||||
| ir.cpp:2019:13:2019:13 | Load | m2019_33 |
|
||||
| ir.cpp:2019:13:2019:13 | SideEffect | ~m2017_8 |
|
||||
| ir.cpp:2019:13:2019:13 | SideEffect | ~m2018_13 |
|
||||
| ir.cpp:2019:13:2019:13 | StoreValue | r2019_34 |
|
||||
| ir.cpp:2019:13:2019:13 | Unary | r2019_25 |
|
||||
| ir.cpp:2019:13:2019:13 | Unary | r2019_26 |
|
||||
| ir.cpp:2019:17:2019:34 | Address | &:r2019_37 |
|
||||
| ir.cpp:2019:17:2019:34 | Address | &:r2019_37 |
|
||||
| ir.cpp:2019:17:2019:34 | Address | &:r2019_37 |
|
||||
| ir.cpp:2019:17:2019:34 | Arg(this) | this:r2019_37 |
|
||||
| ir.cpp:2019:17:2019:34 | CallTarget | func:r2019_39 |
|
||||
| ir.cpp:2019:17:2019:34 | ChiPartial | partial:m2019_41 |
|
||||
| ir.cpp:2019:17:2019:34 | ChiPartial | partial:m2019_43 |
|
||||
| ir.cpp:2019:17:2019:34 | ChiTotal | total:m2018_13 |
|
||||
| ir.cpp:2019:17:2019:34 | ChiTotal | total:m2019_38 |
|
||||
| ir.cpp:2019:17:2019:34 | Load | m2019_44 |
|
||||
| ir.cpp:2019:17:2019:34 | SideEffect | ~m2018_13 |
|
||||
| ir.cpp:2019:17:2019:34 | StoreValue | r2019_45 |
|
||||
| ir.cpp:2020:5:2020:5 | Address | &:r2020_1 |
|
||||
| ir.cpp:2020:5:2020:5 | Address | &:r2020_1 |
|
||||
| ir.cpp:2020:5:2020:5 | Arg(this) | this:r2020_1 |
|
||||
| ir.cpp:2020:5:2020:5 | ChiPartial | partial:m2020_19 |
|
||||
| ir.cpp:2020:5:2020:5 | ChiTotal | total:m2019_20 |
|
||||
| ir.cpp:2020:5:2020:5 | SideEffect | m2019_20 |
|
||||
| ir.cpp:2020:7:2020:7 | CallTarget | func:r2020_2 |
|
||||
| ir.cpp:2020:7:2020:7 | ChiPartial | partial:m2020_15 |
|
||||
| ir.cpp:2020:7:2020:7 | ChiTotal | total:m2020_7 |
|
||||
| ir.cpp:2020:7:2020:7 | SideEffect | ~m2020_7 |
|
||||
| ir.cpp:2020:7:2020:7 | Unary | r2020_14 |
|
||||
| ir.cpp:2020:9:2020:9 | Address | &:r2020_4 |
|
||||
| ir.cpp:2020:9:2020:9 | Address | &:r2020_9 |
|
||||
| ir.cpp:2020:9:2020:9 | Address | &:r2020_31 |
|
||||
| ir.cpp:2020:9:2020:9 | Address | &:r2020_42 |
|
||||
| ir.cpp:2020:9:2020:9 | Condition | r2020_5 |
|
||||
| ir.cpp:2020:9:2020:9 | Load | m2017_6 |
|
||||
| ir.cpp:2020:9:2020:9 | Load | m2020_8 |
|
||||
| ir.cpp:2020:9:2020:9 | Phi | from 8:m2020_32 |
|
||||
| ir.cpp:2020:9:2020:9 | Phi | from 8:~m2020_27 |
|
||||
| ir.cpp:2020:9:2020:9 | Phi | from 9:m2020_43 |
|
||||
| ir.cpp:2020:9:2020:9 | Phi | from 9:~m2020_38 |
|
||||
| ir.cpp:2020:9:2020:9 | StoreValue | r2020_10 |
|
||||
| ir.cpp:2020:9:2020:51 | Address | &:r2020_3 |
|
||||
| ir.cpp:2020:9:2020:51 | Address | &:r2020_13 |
|
||||
| ir.cpp:2020:9:2020:51 | Arg(0) | 0:r2020_13 |
|
||||
| ir.cpp:2020:9:2020:51 | SideEffect | ~m2020_11 |
|
||||
| ir.cpp:2020:9:2020:51 | Unary | r2020_3 |
|
||||
| ir.cpp:2020:9:2020:51 | Unary | r2020_12 |
|
||||
| ir.cpp:2020:13:2020:30 | Address | &:r2020_22 |
|
||||
| ir.cpp:2020:13:2020:30 | Address | &:r2020_22 |
|
||||
| ir.cpp:2020:13:2020:30 | Address | &:r2020_22 |
|
||||
| ir.cpp:2020:13:2020:30 | Arg(this) | this:r2020_22 |
|
||||
| ir.cpp:2020:13:2020:30 | CallTarget | func:r2020_24 |
|
||||
| ir.cpp:2020:13:2020:30 | ChiPartial | partial:m2020_26 |
|
||||
| ir.cpp:2020:13:2020:30 | ChiPartial | partial:m2020_28 |
|
||||
| ir.cpp:2020:13:2020:30 | ChiTotal | total:m2019_16 |
|
||||
| ir.cpp:2020:13:2020:30 | ChiTotal | total:m2020_23 |
|
||||
| ir.cpp:2020:13:2020:30 | Load | m2020_29 |
|
||||
| ir.cpp:2020:13:2020:30 | SideEffect | ~m2019_16 |
|
||||
| ir.cpp:2020:13:2020:30 | StoreValue | r2020_30 |
|
||||
| ir.cpp:2020:34:2020:51 | Address | &:r2020_33 |
|
||||
| ir.cpp:2020:34:2020:51 | Address | &:r2020_33 |
|
||||
| ir.cpp:2020:34:2020:51 | Address | &:r2020_33 |
|
||||
| ir.cpp:2020:34:2020:51 | Arg(this) | this:r2020_33 |
|
||||
| ir.cpp:2020:34:2020:51 | CallTarget | func:r2020_35 |
|
||||
| ir.cpp:2020:34:2020:51 | ChiPartial | partial:m2020_37 |
|
||||
| ir.cpp:2020:34:2020:51 | ChiPartial | partial:m2020_39 |
|
||||
| ir.cpp:2020:34:2020:51 | ChiTotal | total:m2019_16 |
|
||||
| ir.cpp:2020:34:2020:51 | ChiTotal | total:m2020_34 |
|
||||
| ir.cpp:2020:34:2020:51 | Load | m2020_40 |
|
||||
| ir.cpp:2020:34:2020:51 | SideEffect | ~m2019_16 |
|
||||
| ir.cpp:2020:34:2020:51 | StoreValue | r2020_41 |
|
||||
| ir.cpp:2021:5:2021:19 | ChiPartial | partial:m2021_35 |
|
||||
| ir.cpp:2021:5:2021:19 | ChiTotal | total:m2021_17 |
|
||||
| ir.cpp:2021:5:2021:19 | SideEffect | m2021_17 |
|
||||
| ir.cpp:2021:6:2021:6 | Address | &:r2021_1 |
|
||||
| ir.cpp:2021:6:2021:6 | Address | &:r2021_1 |
|
||||
| ir.cpp:2021:6:2021:6 | Arg(this) | this:r2021_1 |
|
||||
| ir.cpp:2021:6:2021:6 | ChiPartial | partial:m2021_16 |
|
||||
| ir.cpp:2021:6:2021:6 | ChiTotal | total:m2020_20 |
|
||||
| ir.cpp:2021:6:2021:6 | SideEffect | m2020_20 |
|
||||
| ir.cpp:2021:8:2021:8 | CallTarget | func:r2021_2 |
|
||||
| ir.cpp:2021:8:2021:8 | ChiPartial | partial:m2021_12 |
|
||||
| ir.cpp:2021:8:2021:8 | ChiTotal | total:m2020_16 |
|
||||
| ir.cpp:2021:8:2021:8 | SideEffect | ~m2020_16 |
|
||||
| ir.cpp:2021:8:2021:8 | Unary | r2021_11 |
|
||||
| ir.cpp:2021:8:2021:19 | Address | &:r2021_18 |
|
||||
| ir.cpp:2021:8:2021:19 | Address | &:r2021_18 |
|
||||
| ir.cpp:2021:8:2021:19 | Arg(this) | this:r2021_18 |
|
||||
| ir.cpp:2021:10:2021:10 | Address | &:r2021_3 |
|
||||
| ir.cpp:2021:10:2021:10 | Condition | r2021_4 |
|
||||
| ir.cpp:2021:10:2021:10 | Load | m2017_6 |
|
||||
| ir.cpp:2021:10:2021:18 | Address | &:r2021_7 |
|
||||
| ir.cpp:2021:10:2021:18 | Address | &:r2021_10 |
|
||||
| ir.cpp:2021:10:2021:18 | Address | &:r2021_39 |
|
||||
| ir.cpp:2021:10:2021:18 | Address | &:r2021_42 |
|
||||
| ir.cpp:2021:10:2021:18 | Arg(0) | 0:r2021_10 |
|
||||
| ir.cpp:2021:10:2021:18 | Load | m2021_6 |
|
||||
| ir.cpp:2021:10:2021:18 | Phi | from 11:m2021_40 |
|
||||
| ir.cpp:2021:10:2021:18 | Phi | from 12:m2021_43 |
|
||||
| ir.cpp:2021:10:2021:18 | SideEffect | ~m2021_13 |
|
||||
| ir.cpp:2021:10:2021:18 | Unary | r2021_8 |
|
||||
| ir.cpp:2021:10:2021:18 | Unary | r2021_9 |
|
||||
| ir.cpp:2021:14:2021:14 | StoreValue | r2021_38 |
|
||||
| ir.cpp:2021:18:2021:18 | StoreValue | r2021_41 |
|
||||
| ir.cpp:2021:21:2021:21 | CallTarget | func:r2021_19 |
|
||||
| ir.cpp:2021:21:2021:21 | ChiPartial | partial:m2021_31 |
|
||||
| ir.cpp:2021:21:2021:21 | ChiTotal | total:m2021_25 |
|
||||
| ir.cpp:2021:21:2021:21 | SideEffect | ~m2021_25 |
|
||||
| ir.cpp:2021:21:2021:21 | Unary | r2021_30 |
|
||||
| ir.cpp:2021:23:2021:40 | Address | &:r2021_20 |
|
||||
| ir.cpp:2021:23:2021:40 | Address | &:r2021_20 |
|
||||
| ir.cpp:2021:23:2021:40 | Address | &:r2021_29 |
|
||||
| ir.cpp:2021:23:2021:40 | Arg(0) | 0:r2021_29 |
|
||||
| ir.cpp:2021:23:2021:40 | Arg(this) | this:r2021_20 |
|
||||
| ir.cpp:2021:23:2021:40 | CallTarget | func:r2021_22 |
|
||||
| ir.cpp:2021:23:2021:40 | ChiPartial | partial:m2021_24 |
|
||||
| ir.cpp:2021:23:2021:40 | ChiPartial | partial:m2021_26 |
|
||||
| ir.cpp:2021:23:2021:40 | ChiTotal | total:m2021_13 |
|
||||
| ir.cpp:2021:23:2021:40 | ChiTotal | total:m2021_21 |
|
||||
| ir.cpp:2021:23:2021:40 | SideEffect | ~m2021_13 |
|
||||
| ir.cpp:2021:23:2021:40 | SideEffect | ~m2021_27 |
|
||||
| ir.cpp:2021:23:2021:40 | Unary | r2021_20 |
|
||||
| ir.cpp:2021:23:2021:40 | Unary | r2021_28 |
|
||||
| ir.cpp:2026:14:2026:22 | ChiPartial | partial:m2026_3 |
|
||||
| ir.cpp:2026:14:2026:22 | ChiTotal | total:m2026_2 |
|
||||
| ir.cpp:2026:37:2026:37 | Address | &:r2026_5 |
|
||||
| ir.cpp:2027:16:2027:16 | Address | &:r2027_1 |
|
||||
| ir.cpp:2028:3:2028:3 | Address | &:r2028_9 |
|
||||
| ir.cpp:2028:7:2028:7 | Address | &:r2028_1 |
|
||||
| ir.cpp:2028:7:2028:7 | Left | r2028_2 |
|
||||
| ir.cpp:2028:7:2028:7 | Load | m2026_6 |
|
||||
| ir.cpp:2028:7:2028:13 | Condition | r2028_4 |
|
||||
| ir.cpp:2028:7:2030:28 | Address | &:r2028_7 |
|
||||
| ir.cpp:2028:7:2030:28 | Address | &:r2028_11 |
|
||||
| ir.cpp:2028:7:2030:28 | Address | &:r2028_13 |
|
||||
| ir.cpp:2028:7:2030:28 | Load | m2028_6 |
|
||||
| ir.cpp:2028:7:2030:28 | Phi | from 2:m2028_12 |
|
||||
| ir.cpp:2028:7:2030:28 | Phi | from 3:m2028_14 |
|
||||
| ir.cpp:2028:7:2030:28 | StoreValue | r2028_8 |
|
||||
| ir.cpp:2028:11:2028:13 | Right | r2028_3 |
|
||||
| ir.cpp:2029:6:2029:20 | CallTarget | func:r2029_1 |
|
||||
| ir.cpp:2029:6:2029:20 | ChiPartial | partial:m2029_5 |
|
||||
| ir.cpp:2029:6:2029:20 | ChiTotal | total:m2026_4 |
|
||||
| ir.cpp:2029:6:2029:20 | SideEffect | ~m2026_4 |
|
||||
| ir.cpp:2029:6:2029:26 | StoreValue | r2029_9 |
|
||||
| ir.cpp:2029:22:2029:22 | Address | &:r2029_2 |
|
||||
| ir.cpp:2029:22:2029:22 | Arg(0) | 0:r2029_3 |
|
||||
| ir.cpp:2029:22:2029:22 | Load | m2026_6 |
|
||||
| ir.cpp:2029:26:2029:26 | Address | &:r2029_7 |
|
||||
| ir.cpp:2029:26:2029:26 | Load | m2026_6 |
|
||||
| ir.cpp:2029:26:2029:26 | Unary | r2029_8 |
|
||||
| ir.cpp:2030:5:2030:28 | StoreValue | r2030_9 |
|
||||
| ir.cpp:2030:6:2030:20 | CallTarget | func:r2030_1 |
|
||||
| ir.cpp:2030:6:2030:20 | ChiPartial | partial:m2030_5 |
|
||||
| ir.cpp:2030:6:2030:20 | ChiTotal | total:m2026_4 |
|
||||
| ir.cpp:2030:6:2030:20 | SideEffect | ~m2026_4 |
|
||||
| ir.cpp:2030:6:2030:27 | Unary | r2030_8 |
|
||||
| ir.cpp:2030:22:2030:22 | Address | &:r2030_2 |
|
||||
| ir.cpp:2030:22:2030:22 | Arg(0) | 0:r2030_3 |
|
||||
| ir.cpp:2030:22:2030:22 | Load | m2026_6 |
|
||||
| ir.cpp:2030:26:2030:27 | Unary | r2030_7 |
|
||||
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
|
||||
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
|
||||
| perf-regression.cpp:6:3:6:5 | Address | &:r6_7 |
|
||||
|
||||
@@ -724,6 +724,48 @@ complex.c:
|
||||
# 58| v58_5(void) = AliasedUse : ~m?
|
||||
# 58| v58_6(void) = ExitFunction :
|
||||
|
||||
ir.c:
|
||||
# 7| void MyCoordsTest(int)
|
||||
# 7| Block 0
|
||||
# 7| v7_1(void) = EnterFunction :
|
||||
# 7| mu7_2(unknown) = AliasedDefinition :
|
||||
# 7| mu7_3(unknown) = InitializeNonLocal :
|
||||
# 7| r7_4(glval<int>) = VariableAddress[pos] :
|
||||
# 7| mu7_5(int) = InitializeParameter[pos] : &:r7_4
|
||||
# 8| r8_1(glval<(unnamed class/struct/union)>) = VariableAddress[coords] :
|
||||
# 8| mu8_2((unnamed class/struct/union)) = Uninitialized[coords] : &:r8_1
|
||||
# 8| r8_3(glval<int>) = FieldAddress[x] : r8_1
|
||||
# 8| r8_4(int) = Constant[0] :
|
||||
# 8| mu8_5(int) = Store[?] : &:r8_3, r8_4
|
||||
# 8| r8_6(glval<int>) = FieldAddress[y] : r8_1
|
||||
# 8| r8_7(int) = Constant[0] :
|
||||
# 8| mu8_8(int) = Store[?] : &:r8_6, r8_7
|
||||
# 9| r9_1(glval<int>) = VariableAddress[pos] :
|
||||
# 9| r9_2(int) = Load[pos] : &:r9_1, ~m?
|
||||
# 9| r9_3(int) = Constant[1] :
|
||||
# 9| r9_4(int) = Add : r9_2, r9_3
|
||||
# 9| r9_5(glval<(unnamed class/struct/union)>) = VariableAddress[coords] :
|
||||
# 9| r9_6(glval<int>) = FieldAddress[y] : r9_5
|
||||
# 9| mu9_7(int) = Store[?] : &:r9_6, r9_4
|
||||
# 9| r9_8(int) = CopyValue : r9_4
|
||||
# 9| r9_9(glval<(unnamed class/struct/union)>) = VariableAddress[coords] :
|
||||
# 9| r9_10(glval<int>) = FieldAddress[x] : r9_9
|
||||
# 9| mu9_11(int) = Store[?] : &:r9_10, r9_8
|
||||
# 10| r10_1(glval<unknown>) = FunctionAddress[getX] :
|
||||
# 10| r10_2(glval<(unnamed class/struct/union)>) = VariableAddress[coords] :
|
||||
# 10| r10_3(struct <unnamed> *) = CopyValue : r10_2
|
||||
# 10| r10_4(int) = Call[getX] : func:r10_1, 0:r10_3
|
||||
# 10| mu10_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 10| v10_6(void) = ^BufferReadSideEffect[0] : &:r10_3, ~m?
|
||||
# 10| mu10_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r10_3
|
||||
# 10| r10_8(glval<(unnamed class/struct/union)>) = VariableAddress[coords] :
|
||||
# 10| r10_9(glval<int>) = FieldAddress[x] : r10_8
|
||||
# 10| mu10_10(int) = Store[?] : &:r10_9, r10_4
|
||||
# 11| v11_1(void) = NoOp :
|
||||
# 7| v7_6(void) = ReturnVoid :
|
||||
# 7| v7_7(void) = AliasedUse : ~m?
|
||||
# 7| v7_8(void) = ExitFunction :
|
||||
|
||||
ir.cpp:
|
||||
# 1| void Constants()
|
||||
# 1| Block 0
|
||||
@@ -10456,6 +10498,579 @@ ir.cpp:
|
||||
# 1990| v1990_5(void) = AliasedUse : ~m?
|
||||
# 1990| v1990_6(void) = ExitFunction :
|
||||
|
||||
# 1996| void TernaryTestInt(bool, int, int, int)
|
||||
# 1996| Block 0
|
||||
# 1996| v1996_1(void) = EnterFunction :
|
||||
# 1996| mu1996_2(unknown) = AliasedDefinition :
|
||||
# 1996| mu1996_3(unknown) = InitializeNonLocal :
|
||||
# 1996| r1996_4(glval<bool>) = VariableAddress[a] :
|
||||
# 1996| mu1996_5(bool) = InitializeParameter[a] : &:r1996_4
|
||||
# 1996| r1996_6(glval<int>) = VariableAddress[x] :
|
||||
# 1996| mu1996_7(int) = InitializeParameter[x] : &:r1996_6
|
||||
# 1996| r1996_8(glval<int>) = VariableAddress[y] :
|
||||
# 1996| mu1996_9(int) = InitializeParameter[y] : &:r1996_8
|
||||
# 1996| r1996_10(glval<int>) = VariableAddress[z] :
|
||||
# 1996| mu1996_11(int) = InitializeParameter[z] : &:r1996_10
|
||||
# 1997| r1997_1(glval<bool>) = VariableAddress[a] :
|
||||
# 1997| r1997_2(bool) = Load[a] : &:r1997_1, ~m?
|
||||
# 1997| v1997_3(void) = ConditionalBranch : r1997_2
|
||||
#-----| False -> Block 3
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 1997| Block 1
|
||||
# 1997| r1997_4(glval<int>) = VariableAddress[#temp1997:9] :
|
||||
# 1997| r1997_5(int) = Load[#temp1997:9] : &:r1997_4, ~m?
|
||||
# 1997| r1997_6(glval<int>) = VariableAddress[z] :
|
||||
# 1997| mu1997_7(int) = Store[z] : &:r1997_6, r1997_5
|
||||
# 1998| r1998_1(glval<bool>) = VariableAddress[a] :
|
||||
# 1998| r1998_2(bool) = Load[a] : &:r1998_1, ~m?
|
||||
# 1998| v1998_3(void) = ConditionalBranch : r1998_2
|
||||
#-----| False -> Block 6
|
||||
#-----| True -> Block 5
|
||||
|
||||
# 1997| Block 2
|
||||
# 1997| r1997_8(glval<int>) = VariableAddress[x] :
|
||||
# 1997| r1997_9(int) = Load[x] : &:r1997_8, ~m?
|
||||
# 1997| r1997_10(glval<int>) = VariableAddress[#temp1997:9] :
|
||||
# 1997| mu1997_11(int) = Store[#temp1997:9] : &:r1997_10, r1997_9
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 1997| Block 3
|
||||
# 1997| r1997_12(glval<int>) = VariableAddress[y] :
|
||||
# 1997| r1997_13(int) = Load[y] : &:r1997_12, ~m?
|
||||
# 1997| r1997_14(glval<int>) = VariableAddress[#temp1997:9] :
|
||||
# 1997| mu1997_15(int) = Store[#temp1997:9] : &:r1997_14, r1997_13
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 1998| Block 4
|
||||
# 1998| r1998_4(glval<int>) = VariableAddress[#temp1998:9] :
|
||||
# 1998| r1998_5(int) = Load[#temp1998:9] : &:r1998_4, ~m?
|
||||
# 1998| r1998_6(glval<int>) = VariableAddress[z] :
|
||||
# 1998| mu1998_7(int) = Store[z] : &:r1998_6, r1998_5
|
||||
# 1999| r1999_1(glval<bool>) = VariableAddress[a] :
|
||||
# 1999| r1999_2(bool) = Load[a] : &:r1999_1, ~m?
|
||||
# 1999| v1999_3(void) = ConditionalBranch : r1999_2
|
||||
#-----| False -> Block 9
|
||||
#-----| True -> Block 8
|
||||
|
||||
# 1998| Block 5
|
||||
# 1998| r1998_8(glval<int>) = VariableAddress[x] :
|
||||
# 1998| r1998_9(int) = Load[x] : &:r1998_8, ~m?
|
||||
# 1998| r1998_10(glval<int>) = VariableAddress[#temp1998:9] :
|
||||
# 1998| mu1998_11(int) = Store[#temp1998:9] : &:r1998_10, r1998_9
|
||||
#-----| Goto -> Block 4
|
||||
|
||||
# 1998| Block 6
|
||||
# 1998| r1998_12(int) = Constant[5] :
|
||||
# 1998| r1998_13(glval<int>) = VariableAddress[#temp1998:9] :
|
||||
# 1998| mu1998_14(int) = Store[#temp1998:9] : &:r1998_13, r1998_12
|
||||
#-----| Goto -> Block 4
|
||||
|
||||
# 1999| Block 7
|
||||
# 1999| r1999_4(glval<int>) = VariableAddress[#temp1999:9] :
|
||||
# 1999| r1999_5(int) = Load[#temp1999:9] : &:r1999_4, ~m?
|
||||
# 1999| r1999_6(glval<int>) = VariableAddress[z] :
|
||||
# 1999| mu1999_7(int) = Store[z] : &:r1999_6, r1999_5
|
||||
# 2000| r2000_1(int) = Constant[7] :
|
||||
# 2000| r2000_2(glval<bool>) = VariableAddress[a] :
|
||||
# 2000| r2000_3(bool) = Load[a] : &:r2000_2, ~m?
|
||||
# 2000| v2000_4(void) = ConditionalBranch : r2000_3
|
||||
#-----| False -> Block 12
|
||||
#-----| True -> Block 11
|
||||
|
||||
# 1999| Block 8
|
||||
# 1999| r1999_8(int) = Constant[3] :
|
||||
# 1999| r1999_9(glval<int>) = VariableAddress[#temp1999:9] :
|
||||
# 1999| mu1999_10(int) = Store[#temp1999:9] : &:r1999_9, r1999_8
|
||||
#-----| Goto -> Block 7
|
||||
|
||||
# 1999| Block 9
|
||||
# 1999| r1999_11(int) = Constant[5] :
|
||||
# 1999| r1999_12(glval<int>) = VariableAddress[#temp1999:9] :
|
||||
# 1999| mu1999_13(int) = Store[#temp1999:9] : &:r1999_12, r1999_11
|
||||
#-----| Goto -> Block 7
|
||||
|
||||
# 2000| Block 10
|
||||
# 2000| r2000_5(glval<unknown>) = VariableAddress[#temp2000:6] :
|
||||
# 2000| r2000_6(glval<int>) = Load[#temp2000:6] : &:r2000_5, ~m?
|
||||
# 2000| mu2000_7(int) = Store[?] : &:r2000_6, r2000_1
|
||||
# 2001| v2001_1(void) = NoOp :
|
||||
# 1996| v1996_12(void) = ReturnVoid :
|
||||
# 1996| v1996_13(void) = AliasedUse : ~m?
|
||||
# 1996| v1996_14(void) = ExitFunction :
|
||||
|
||||
# 2000| Block 11
|
||||
# 2000| r2000_8(glval<int>) = VariableAddress[x] :
|
||||
# 2000| r2000_9(glval<unknown>) = VariableAddress[#temp2000:6] :
|
||||
# 2000| mu2000_10(glval<int>) = Store[#temp2000:6] : &:r2000_9, r2000_8
|
||||
#-----| Goto -> Block 10
|
||||
|
||||
# 2000| Block 12
|
||||
# 2000| r2000_11(glval<int>) = VariableAddress[y] :
|
||||
# 2000| r2000_12(glval<unknown>) = VariableAddress[#temp2000:6] :
|
||||
# 2000| mu2000_13(glval<int>) = Store[#temp2000:6] : &:r2000_12, r2000_11
|
||||
#-----| Goto -> Block 10
|
||||
|
||||
# 2006| void TernaryTestPodObj(bool, TernaryPodObj, TernaryPodObj, TernaryPodObj)
|
||||
# 2006| Block 0
|
||||
# 2006| v2006_1(void) = EnterFunction :
|
||||
# 2006| mu2006_2(unknown) = AliasedDefinition :
|
||||
# 2006| mu2006_3(unknown) = InitializeNonLocal :
|
||||
# 2006| r2006_4(glval<bool>) = VariableAddress[a] :
|
||||
# 2006| mu2006_5(bool) = InitializeParameter[a] : &:r2006_4
|
||||
# 2006| r2006_6(glval<TernaryPodObj>) = VariableAddress[x] :
|
||||
# 2006| mu2006_7(TernaryPodObj) = InitializeParameter[x] : &:r2006_6
|
||||
# 2006| r2006_8(glval<TernaryPodObj>) = VariableAddress[y] :
|
||||
# 2006| mu2006_9(TernaryPodObj) = InitializeParameter[y] : &:r2006_8
|
||||
# 2006| r2006_10(glval<TernaryPodObj>) = VariableAddress[z] :
|
||||
# 2006| mu2006_11(TernaryPodObj) = InitializeParameter[z] : &:r2006_10
|
||||
# 2007| r2007_1(glval<bool>) = VariableAddress[a] :
|
||||
# 2007| r2007_2(bool) = Load[a] : &:r2007_1, ~m?
|
||||
# 2007| v2007_3(void) = ConditionalBranch : r2007_2
|
||||
#-----| False -> Block 3
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 2007| Block 1
|
||||
# 2007| r2007_4(glval<TernaryPodObj>) = VariableAddress[#temp2007:9] :
|
||||
# 2007| r2007_5(TernaryPodObj) = Load[#temp2007:9] : &:r2007_4, ~m?
|
||||
# 2007| r2007_6(glval<TernaryPodObj>) = VariableAddress[z] :
|
||||
# 2007| mu2007_7(TernaryPodObj) = Store[z] : &:r2007_6, r2007_5
|
||||
# 2008| r2008_1(glval<TernaryPodObj>) = VariableAddress[#temp2008:9] :
|
||||
# 2008| r2008_2(glval<bool>) = VariableAddress[a] :
|
||||
# 2008| r2008_3(bool) = Load[a] : &:r2008_2, ~m?
|
||||
# 2008| v2008_4(void) = ConditionalBranch : r2008_3
|
||||
#-----| False -> Block 6
|
||||
#-----| True -> Block 5
|
||||
|
||||
# 2007| Block 2
|
||||
# 2007| r2007_8(glval<TernaryPodObj>) = VariableAddress[x] :
|
||||
# 2007| r2007_9(TernaryPodObj) = Load[x] : &:r2007_8, ~m?
|
||||
# 2007| r2007_10(glval<TernaryPodObj>) = VariableAddress[#temp2007:9] :
|
||||
# 2007| mu2007_11(TernaryPodObj) = Store[#temp2007:9] : &:r2007_10, r2007_9
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 2007| Block 3
|
||||
# 2007| r2007_12(glval<TernaryPodObj>) = VariableAddress[y] :
|
||||
# 2007| r2007_13(TernaryPodObj) = Load[y] : &:r2007_12, ~m?
|
||||
# 2007| r2007_14(glval<TernaryPodObj>) = VariableAddress[#temp2007:9] :
|
||||
# 2007| mu2007_15(TernaryPodObj) = Store[#temp2007:9] : &:r2007_14, r2007_13
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 2008| Block 4
|
||||
# 2008| r2008_5(glval<TernaryPodObj>) = VariableAddress[#temp2008:9] :
|
||||
# 2008| r2008_6(TernaryPodObj) = Load[#temp2008:9] : &:r2008_5, ~m?
|
||||
# 2008| mu2008_7(TernaryPodObj) = Store[#temp2008:9] : &:r2008_1, r2008_6
|
||||
# 2008| r2008_8(TernaryPodObj) = Load[#temp2008:9] : &:r2008_1, ~m?
|
||||
# 2008| r2008_9(glval<TernaryPodObj>) = VariableAddress[z] :
|
||||
# 2008| mu2008_10(TernaryPodObj) = Store[z] : &:r2008_9, r2008_8
|
||||
# 2009| r2009_1(glval<TernaryPodObj>) = VariableAddress[#temp2009:9] :
|
||||
# 2009| r2009_2(glval<bool>) = VariableAddress[a] :
|
||||
# 2009| r2009_3(bool) = Load[a] : &:r2009_2, ~m?
|
||||
# 2009| v2009_4(void) = ConditionalBranch : r2009_3
|
||||
#-----| False -> Block 9
|
||||
#-----| True -> Block 8
|
||||
|
||||
# 2008| Block 5
|
||||
# 2008| r2008_11(glval<TernaryPodObj>) = VariableAddress[#temp2008:13] :
|
||||
# 2008| r2008_12(glval<TernaryPodObj>) = VariableAddress[x] :
|
||||
# 2008| r2008_13(TernaryPodObj) = Load[x] : &:r2008_12, ~m?
|
||||
# 2008| mu2008_14(TernaryPodObj) = Store[#temp2008:13] : &:r2008_11, r2008_13
|
||||
# 2008| r2008_15(TernaryPodObj) = Load[#temp2008:13] : &:r2008_11, ~m?
|
||||
# 2008| r2008_16(glval<TernaryPodObj>) = VariableAddress[#temp2008:9] :
|
||||
# 2008| mu2008_17(TernaryPodObj) = Store[#temp2008:9] : &:r2008_16, r2008_15
|
||||
#-----| Goto -> Block 4
|
||||
|
||||
# 2008| Block 6
|
||||
# 2008| r2008_18(glval<TernaryPodObj>) = VariableAddress[#temp2008:17] :
|
||||
# 2008| r2008_19(TernaryPodObj) = Constant[0] :
|
||||
# 2008| mu2008_20(TernaryPodObj) = Store[#temp2008:17] : &:r2008_18, r2008_19
|
||||
# 2008| r2008_21(TernaryPodObj) = Load[#temp2008:17] : &:r2008_18, ~m?
|
||||
# 2008| r2008_22(glval<TernaryPodObj>) = VariableAddress[#temp2008:9] :
|
||||
# 2008| mu2008_23(TernaryPodObj) = Store[#temp2008:9] : &:r2008_22, r2008_21
|
||||
#-----| Goto -> Block 4
|
||||
|
||||
# 2009| Block 7
|
||||
# 2009| r2009_5(glval<TernaryPodObj>) = VariableAddress[#temp2009:9] :
|
||||
# 2009| r2009_6(TernaryPodObj) = Load[#temp2009:9] : &:r2009_5, ~m?
|
||||
# 2009| mu2009_7(TernaryPodObj) = Store[#temp2009:9] : &:r2009_1, r2009_6
|
||||
# 2009| r2009_8(TernaryPodObj) = Load[#temp2009:9] : &:r2009_1, ~m?
|
||||
# 2009| r2009_9(glval<TernaryPodObj>) = VariableAddress[z] :
|
||||
# 2009| mu2009_10(TernaryPodObj) = Store[z] : &:r2009_9, r2009_8
|
||||
# 2010| r2010_1(glval<TernaryPodObj>) = VariableAddress[#temp2010:23] :
|
||||
# 2010| r2010_2(TernaryPodObj) = Constant[0] :
|
||||
# 2010| mu2010_3(TernaryPodObj) = Store[#temp2010:23] : &:r2010_1, r2010_2
|
||||
# 2010| r2010_4(TernaryPodObj) = Load[#temp2010:23] : &:r2010_1, ~m?
|
||||
# 2010| r2010_5(glval<bool>) = VariableAddress[a] :
|
||||
# 2010| r2010_6(bool) = Load[a] : &:r2010_5, ~m?
|
||||
# 2010| v2010_7(void) = ConditionalBranch : r2010_6
|
||||
#-----| False -> Block 12
|
||||
#-----| True -> Block 11
|
||||
|
||||
# 2009| Block 8
|
||||
# 2009| r2009_11(glval<TernaryPodObj>) = VariableAddress[#temp2009:13] :
|
||||
# 2009| r2009_12(TernaryPodObj) = Constant[0] :
|
||||
# 2009| mu2009_13(TernaryPodObj) = Store[#temp2009:13] : &:r2009_11, r2009_12
|
||||
# 2009| r2009_14(TernaryPodObj) = Load[#temp2009:13] : &:r2009_11, ~m?
|
||||
# 2009| r2009_15(glval<TernaryPodObj>) = VariableAddress[#temp2009:9] :
|
||||
# 2009| mu2009_16(TernaryPodObj) = Store[#temp2009:9] : &:r2009_15, r2009_14
|
||||
#-----| Goto -> Block 7
|
||||
|
||||
# 2009| Block 9
|
||||
# 2009| r2009_17(glval<TernaryPodObj>) = VariableAddress[#temp2009:31] :
|
||||
# 2009| r2009_18(TernaryPodObj) = Constant[0] :
|
||||
# 2009| mu2009_19(TernaryPodObj) = Store[#temp2009:31] : &:r2009_17, r2009_18
|
||||
# 2009| r2009_20(TernaryPodObj) = Load[#temp2009:31] : &:r2009_17, ~m?
|
||||
# 2009| r2009_21(glval<TernaryPodObj>) = VariableAddress[#temp2009:9] :
|
||||
# 2009| mu2009_22(TernaryPodObj) = Store[#temp2009:9] : &:r2009_21, r2009_20
|
||||
#-----| Goto -> Block 7
|
||||
|
||||
# 2010| Block 10
|
||||
# 2010| r2010_8(glval<TernaryPodObj>) = VariableAddress[#temp2010:10] :
|
||||
# 2010| r2010_9(TernaryPodObj) = Load[#temp2010:10] : &:r2010_8, ~m?
|
||||
# 2010| r2010_10(glval<TernaryPodObj>) = VariableAddress[z] :
|
||||
# 2010| mu2010_11(TernaryPodObj) = Store[z] : &:r2010_10, r2010_9
|
||||
# 2010| r2010_12(glval<TernaryPodObj>) = CopyValue : r2010_10
|
||||
# 2010| mu2010_13(TernaryPodObj) = Store[?] : &:r2010_12, r2010_4
|
||||
# 2011| v2011_1(void) = NoOp :
|
||||
# 2006| v2006_12(void) = ReturnVoid :
|
||||
# 2006| v2006_13(void) = AliasedUse : ~m?
|
||||
# 2006| v2006_14(void) = ExitFunction :
|
||||
|
||||
# 2010| Block 11
|
||||
# 2010| r2010_14(glval<TernaryPodObj>) = VariableAddress[x] :
|
||||
# 2010| r2010_15(TernaryPodObj) = Load[x] : &:r2010_14, ~m?
|
||||
# 2010| r2010_16(glval<TernaryPodObj>) = VariableAddress[#temp2010:10] :
|
||||
# 2010| mu2010_17(TernaryPodObj) = Store[#temp2010:10] : &:r2010_16, r2010_15
|
||||
#-----| Goto -> Block 10
|
||||
|
||||
# 2010| Block 12
|
||||
# 2010| r2010_18(glval<TernaryPodObj>) = VariableAddress[y] :
|
||||
# 2010| r2010_19(TernaryPodObj) = Load[y] : &:r2010_18, ~m?
|
||||
# 2010| r2010_20(glval<TernaryPodObj>) = VariableAddress[#temp2010:10] :
|
||||
# 2010| mu2010_21(TernaryPodObj) = Store[#temp2010:10] : &:r2010_20, r2010_19
|
||||
#-----| Goto -> Block 10
|
||||
|
||||
# 2013| TernaryNonPodObj& TernaryNonPodObj::operator=(TernaryNonPodObj const&)
|
||||
# 2013| Block 0
|
||||
# 2013| v2013_1(void) = EnterFunction :
|
||||
# 2013| mu2013_2(unknown) = AliasedDefinition :
|
||||
# 2013| mu2013_3(unknown) = InitializeNonLocal :
|
||||
# 2013| r2013_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 2013| mu2013_5(glval<TernaryNonPodObj>) = InitializeParameter[#this] : &:r2013_4
|
||||
# 2013| r2013_6(glval<TernaryNonPodObj>) = Load[#this] : &:r2013_4, ~m?
|
||||
# 2013| mu2013_7(TernaryNonPodObj) = InitializeIndirection[#this] : &:r2013_6
|
||||
#-----| r0_1(glval<TernaryNonPodObj &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
#-----| mu0_2(TernaryNonPodObj &) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
|
||||
#-----| r0_3(TernaryNonPodObj &) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
|
||||
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
|
||||
#-----| r0_5(glval<TernaryNonPodObj &>) = VariableAddress[#return] :
|
||||
#-----| r0_6(glval<unknown>) = VariableAddress[#this] :
|
||||
#-----| r0_7(TernaryNonPodObj *) = Load[#this] : &:r0_6, ~m?
|
||||
#-----| r0_8(glval<TernaryNonPodObj>) = CopyValue : r0_7
|
||||
#-----| r0_9(TernaryNonPodObj &) = CopyValue : r0_8
|
||||
#-----| mu0_10(TernaryNonPodObj &) = Store[#return] : &:r0_5, r0_9
|
||||
# 2013| v2013_8(void) = ReturnIndirection[#this] : &:r2013_6, ~m?
|
||||
#-----| v0_11(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
|
||||
# 2013| r2013_9(glval<TernaryNonPodObj &>) = VariableAddress[#return] :
|
||||
# 2013| v2013_10(void) = ReturnValue : &:r2013_9, ~m?
|
||||
# 2013| v2013_11(void) = AliasedUse : ~m?
|
||||
# 2013| v2013_12(void) = ExitFunction :
|
||||
|
||||
# 2013| void TernaryNonPodObj::TernaryNonPodObj()
|
||||
# 2013| Block 0
|
||||
# 2013| v2013_1(void) = EnterFunction :
|
||||
# 2013| mu2013_2(unknown) = AliasedDefinition :
|
||||
# 2013| mu2013_3(unknown) = InitializeNonLocal :
|
||||
# 2013| r2013_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 2013| mu2013_5(glval<TernaryNonPodObj>) = InitializeParameter[#this] : &:r2013_4
|
||||
# 2013| r2013_6(glval<TernaryNonPodObj>) = Load[#this] : &:r2013_4, ~m?
|
||||
# 2013| mu2013_7(TernaryNonPodObj) = InitializeIndirection[#this] : &:r2013_6
|
||||
# 2013| v2013_8(void) = NoOp :
|
||||
# 2013| v2013_9(void) = ReturnIndirection[#this] : &:r2013_6, ~m?
|
||||
# 2013| v2013_10(void) = ReturnVoid :
|
||||
# 2013| v2013_11(void) = AliasedUse : ~m?
|
||||
# 2013| v2013_12(void) = ExitFunction :
|
||||
|
||||
# 2013| void TernaryNonPodObj::TernaryNonPodObj(TernaryNonPodObj const&)
|
||||
# 2013| Block 0
|
||||
# 2013| v2013_1(void) = EnterFunction :
|
||||
# 2013| mu2013_2(unknown) = AliasedDefinition :
|
||||
# 2013| mu2013_3(unknown) = InitializeNonLocal :
|
||||
# 2013| r2013_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 2013| mu2013_5(glval<TernaryNonPodObj>) = InitializeParameter[#this] : &:r2013_4
|
||||
# 2013| r2013_6(glval<TernaryNonPodObj>) = Load[#this] : &:r2013_4, ~m?
|
||||
# 2013| mu2013_7(TernaryNonPodObj) = InitializeIndirection[#this] : &:r2013_6
|
||||
#-----| r0_1(glval<TernaryNonPodObj &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
#-----| mu0_2(TernaryNonPodObj &) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
|
||||
#-----| r0_3(TernaryNonPodObj &) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
|
||||
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
|
||||
# 2013| v2013_8(void) = NoOp :
|
||||
# 2013| v2013_9(void) = ReturnIndirection[#this] : &:r2013_6, ~m?
|
||||
#-----| v0_5(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
|
||||
# 2013| v2013_10(void) = ReturnVoid :
|
||||
# 2013| v2013_11(void) = AliasedUse : ~m?
|
||||
# 2013| v2013_12(void) = ExitFunction :
|
||||
|
||||
# 2014| void TernaryNonPodObj::~TernaryNonPodObj()
|
||||
# 2014| Block 0
|
||||
# 2014| v2014_1(void) = EnterFunction :
|
||||
# 2014| mu2014_2(unknown) = AliasedDefinition :
|
||||
# 2014| mu2014_3(unknown) = InitializeNonLocal :
|
||||
# 2014| r2014_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 2014| mu2014_5(glval<TernaryNonPodObj>) = InitializeParameter[#this] : &:r2014_4
|
||||
# 2014| r2014_6(glval<TernaryNonPodObj>) = Load[#this] : &:r2014_4, ~m?
|
||||
# 2014| mu2014_7(TernaryNonPodObj) = InitializeIndirection[#this] : &:r2014_6
|
||||
# 2014| v2014_8(void) = NoOp :
|
||||
# 2014| v2014_9(void) = ReturnIndirection[#this] : &:r2014_6, ~m?
|
||||
# 2014| v2014_10(void) = ReturnVoid :
|
||||
# 2014| v2014_11(void) = AliasedUse : ~m?
|
||||
# 2014| v2014_12(void) = ExitFunction :
|
||||
|
||||
# 2017| void TernaryTestNonPodObj(bool, TernaryNonPodObj, TernaryNonPodObj, TernaryNonPodObj)
|
||||
# 2017| Block 0
|
||||
# 2017| v2017_1(void) = EnterFunction :
|
||||
# 2017| mu2017_2(unknown) = AliasedDefinition :
|
||||
# 2017| mu2017_3(unknown) = InitializeNonLocal :
|
||||
# 2017| r2017_4(glval<bool>) = VariableAddress[a] :
|
||||
# 2017| mu2017_5(bool) = InitializeParameter[a] : &:r2017_4
|
||||
# 2017| r2017_6(glval<TernaryNonPodObj>) = VariableAddress[x] :
|
||||
# 2017| mu2017_7(TernaryNonPodObj) = InitializeParameter[x] : &:r2017_6
|
||||
# 2017| r2017_8(glval<TernaryNonPodObj>) = VariableAddress[y] :
|
||||
# 2017| mu2017_9(TernaryNonPodObj) = InitializeParameter[y] : &:r2017_8
|
||||
# 2017| r2017_10(glval<TernaryNonPodObj>) = VariableAddress[z] :
|
||||
# 2017| mu2017_11(TernaryNonPodObj) = InitializeParameter[z] : &:r2017_10
|
||||
# 2018| r2018_1(glval<TernaryNonPodObj>) = VariableAddress[z] :
|
||||
# 2018| r2018_2(glval<unknown>) = FunctionAddress[operator=] :
|
||||
# 2018| r2018_3(glval<bool>) = VariableAddress[a] :
|
||||
# 2018| r2018_4(bool) = Load[a] : &:r2018_3, ~m?
|
||||
# 2018| v2018_5(void) = ConditionalBranch : r2018_4
|
||||
#-----| False -> Block 3
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 2018| Block 1
|
||||
# 2018| r2018_6(glval<unknown>) = VariableAddress[#temp2018:9] :
|
||||
# 2018| r2018_7(glval<TernaryNonPodObj>) = Load[#temp2018:9] : &:r2018_6, ~m?
|
||||
# 2018| r2018_8(glval<TernaryNonPodObj>) = Convert : r2018_7
|
||||
# 2018| r2018_9(TernaryNonPodObj &) = CopyValue : r2018_8
|
||||
# 2018| r2018_10(TernaryNonPodObj &) = Call[operator=] : func:r2018_2, this:r2018_1, 0:r2018_9
|
||||
# 2018| mu2018_11(unknown) = ^CallSideEffect : ~m?
|
||||
# 2018| v2018_12(void) = ^IndirectReadSideEffect[-1] : &:r2018_1, ~m?
|
||||
# 2018| v2018_13(void) = ^BufferReadSideEffect[0] : &:r2018_9, ~m?
|
||||
# 2018| mu2018_14(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2018_1
|
||||
# 2018| r2018_15(glval<TernaryNonPodObj>) = CopyValue : r2018_10
|
||||
# 2019| r2019_1(glval<TernaryNonPodObj>) = VariableAddress[z] :
|
||||
# 2019| r2019_2(glval<unknown>) = FunctionAddress[operator=] :
|
||||
# 2019| r2019_3(glval<TernaryNonPodObj>) = VariableAddress[#temp2019:9] :
|
||||
# 2019| r2019_4(glval<bool>) = VariableAddress[a] :
|
||||
# 2019| r2019_5(bool) = Load[a] : &:r2019_4, ~m?
|
||||
# 2019| v2019_6(void) = ConditionalBranch : r2019_5
|
||||
#-----| False -> Block 6
|
||||
#-----| True -> Block 5
|
||||
|
||||
# 2018| Block 2
|
||||
# 2018| r2018_16(glval<TernaryNonPodObj>) = VariableAddress[x] :
|
||||
# 2018| r2018_17(glval<unknown>) = VariableAddress[#temp2018:9] :
|
||||
# 2018| mu2018_18(glval<TernaryNonPodObj>) = Store[#temp2018:9] : &:r2018_17, r2018_16
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 2018| Block 3
|
||||
# 2018| r2018_19(glval<TernaryNonPodObj>) = VariableAddress[y] :
|
||||
# 2018| r2018_20(glval<unknown>) = VariableAddress[#temp2018:9] :
|
||||
# 2018| mu2018_21(glval<TernaryNonPodObj>) = Store[#temp2018:9] : &:r2018_20, r2018_19
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 2019| Block 4
|
||||
# 2019| r2019_7(glval<TernaryNonPodObj>) = VariableAddress[#temp2019:9] :
|
||||
# 2019| r2019_8(TernaryNonPodObj) = Load[#temp2019:9] : &:r2019_7, ~m?
|
||||
# 2019| mu2019_9(TernaryNonPodObj) = Store[#temp2019:9] : &:r2019_3, r2019_8
|
||||
# 2019| r2019_10(glval<TernaryNonPodObj>) = Convert : r2019_3
|
||||
# 2019| r2019_11(TernaryNonPodObj &) = CopyValue : r2019_10
|
||||
# 2019| r2019_12(TernaryNonPodObj &) = Call[operator=] : func:r2019_2, this:r2019_1, 0:r2019_11
|
||||
# 2019| mu2019_13(unknown) = ^CallSideEffect : ~m?
|
||||
# 2019| v2019_14(void) = ^IndirectReadSideEffect[-1] : &:r2019_1, ~m?
|
||||
# 2019| v2019_15(void) = ^BufferReadSideEffect[0] : &:r2019_11, ~m?
|
||||
# 2019| mu2019_16(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2019_1
|
||||
# 2019| r2019_17(glval<TernaryNonPodObj>) = CopyValue : r2019_12
|
||||
# 2020| r2020_1(glval<TernaryNonPodObj>) = VariableAddress[z] :
|
||||
# 2020| r2020_2(glval<unknown>) = FunctionAddress[operator=] :
|
||||
# 2020| r2020_3(glval<TernaryNonPodObj>) = VariableAddress[#temp2020:9] :
|
||||
# 2020| r2020_4(glval<bool>) = VariableAddress[a] :
|
||||
# 2020| r2020_5(bool) = Load[a] : &:r2020_4, ~m?
|
||||
# 2020| v2020_6(void) = ConditionalBranch : r2020_5
|
||||
#-----| False -> Block 9
|
||||
#-----| True -> Block 8
|
||||
|
||||
# 2019| Block 5
|
||||
# 2019| r2019_18(glval<TernaryNonPodObj>) = VariableAddress[#temp2019:13] :
|
||||
# 2019| mu2019_19(TernaryNonPodObj) = Uninitialized[#temp2019:13] : &:r2019_18
|
||||
# 2019| r2019_20(glval<unknown>) = FunctionAddress[TernaryNonPodObj] :
|
||||
# 2019| r2019_21(glval<TernaryNonPodObj>) = VariableAddress[x] :
|
||||
# 2019| r2019_22(glval<TernaryNonPodObj>) = Convert : r2019_21
|
||||
# 2019| r2019_23(TernaryNonPodObj &) = CopyValue : r2019_22
|
||||
# 2019| v2019_24(void) = Call[TernaryNonPodObj] : func:r2019_20, this:r2019_18, 0:r2019_23
|
||||
# 2019| mu2019_25(unknown) = ^CallSideEffect : ~m?
|
||||
# 2019| v2019_26(void) = ^BufferReadSideEffect[0] : &:r2019_23, ~m?
|
||||
# 2019| mu2019_27(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2019_18
|
||||
# 2019| r2019_28(TernaryNonPodObj) = Load[#temp2019:13] : &:r2019_18, ~m?
|
||||
# 2019| r2019_29(glval<TernaryNonPodObj>) = VariableAddress[#temp2019:9] :
|
||||
# 2019| mu2019_30(TernaryNonPodObj) = Store[#temp2019:9] : &:r2019_29, r2019_28
|
||||
#-----| Goto -> Block 4
|
||||
|
||||
# 2019| Block 6
|
||||
# 2019| r2019_31(glval<TernaryNonPodObj>) = VariableAddress[#temp2019:17] :
|
||||
# 2019| mu2019_32(TernaryNonPodObj) = Uninitialized[#temp2019:17] : &:r2019_31
|
||||
# 2019| r2019_33(glval<unknown>) = FunctionAddress[TernaryNonPodObj] :
|
||||
# 2019| v2019_34(void) = Call[TernaryNonPodObj] : func:r2019_33, this:r2019_31
|
||||
# 2019| mu2019_35(unknown) = ^CallSideEffect : ~m?
|
||||
# 2019| mu2019_36(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2019_31
|
||||
# 2019| r2019_37(TernaryNonPodObj) = Load[#temp2019:17] : &:r2019_31, ~m?
|
||||
# 2019| r2019_38(glval<TernaryNonPodObj>) = VariableAddress[#temp2019:9] :
|
||||
# 2019| mu2019_39(TernaryNonPodObj) = Store[#temp2019:9] : &:r2019_38, r2019_37
|
||||
#-----| Goto -> Block 4
|
||||
|
||||
# 2020| Block 7
|
||||
# 2020| r2020_7(glval<TernaryNonPodObj>) = VariableAddress[#temp2020:9] :
|
||||
# 2020| r2020_8(TernaryNonPodObj) = Load[#temp2020:9] : &:r2020_7, ~m?
|
||||
# 2020| mu2020_9(TernaryNonPodObj) = Store[#temp2020:9] : &:r2020_3, r2020_8
|
||||
# 2020| r2020_10(glval<TernaryNonPodObj>) = Convert : r2020_3
|
||||
# 2020| r2020_11(TernaryNonPodObj &) = CopyValue : r2020_10
|
||||
# 2020| r2020_12(TernaryNonPodObj &) = Call[operator=] : func:r2020_2, this:r2020_1, 0:r2020_11
|
||||
# 2020| mu2020_13(unknown) = ^CallSideEffect : ~m?
|
||||
# 2020| v2020_14(void) = ^IndirectReadSideEffect[-1] : &:r2020_1, ~m?
|
||||
# 2020| v2020_15(void) = ^BufferReadSideEffect[0] : &:r2020_11, ~m?
|
||||
# 2020| mu2020_16(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2020_1
|
||||
# 2020| r2020_17(glval<TernaryNonPodObj>) = CopyValue : r2020_12
|
||||
# 2021| r2021_1(glval<TernaryNonPodObj>) = VariableAddress[z] :
|
||||
# 2021| r2021_2(glval<unknown>) = FunctionAddress[operator=] :
|
||||
# 2021| r2021_3(glval<bool>) = VariableAddress[a] :
|
||||
# 2021| r2021_4(bool) = Load[a] : &:r2021_3, ~m?
|
||||
# 2021| v2021_5(void) = ConditionalBranch : r2021_4
|
||||
#-----| False -> Block 12
|
||||
#-----| True -> Block 11
|
||||
|
||||
# 2020| Block 8
|
||||
# 2020| r2020_18(glval<TernaryNonPodObj>) = VariableAddress[#temp2020:13] :
|
||||
# 2020| mu2020_19(TernaryNonPodObj) = Uninitialized[#temp2020:13] : &:r2020_18
|
||||
# 2020| r2020_20(glval<unknown>) = FunctionAddress[TernaryNonPodObj] :
|
||||
# 2020| v2020_21(void) = Call[TernaryNonPodObj] : func:r2020_20, this:r2020_18
|
||||
# 2020| mu2020_22(unknown) = ^CallSideEffect : ~m?
|
||||
# 2020| mu2020_23(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2020_18
|
||||
# 2020| r2020_24(TernaryNonPodObj) = Load[#temp2020:13] : &:r2020_18, ~m?
|
||||
# 2020| r2020_25(glval<TernaryNonPodObj>) = VariableAddress[#temp2020:9] :
|
||||
# 2020| mu2020_26(TernaryNonPodObj) = Store[#temp2020:9] : &:r2020_25, r2020_24
|
||||
#-----| Goto -> Block 7
|
||||
|
||||
# 2020| Block 9
|
||||
# 2020| r2020_27(glval<TernaryNonPodObj>) = VariableAddress[#temp2020:34] :
|
||||
# 2020| mu2020_28(TernaryNonPodObj) = Uninitialized[#temp2020:34] : &:r2020_27
|
||||
# 2020| r2020_29(glval<unknown>) = FunctionAddress[TernaryNonPodObj] :
|
||||
# 2020| v2020_30(void) = Call[TernaryNonPodObj] : func:r2020_29, this:r2020_27
|
||||
# 2020| mu2020_31(unknown) = ^CallSideEffect : ~m?
|
||||
# 2020| mu2020_32(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2020_27
|
||||
# 2020| r2020_33(TernaryNonPodObj) = Load[#temp2020:34] : &:r2020_27, ~m?
|
||||
# 2020| r2020_34(glval<TernaryNonPodObj>) = VariableAddress[#temp2020:9] :
|
||||
# 2020| mu2020_35(TernaryNonPodObj) = Store[#temp2020:9] : &:r2020_34, r2020_33
|
||||
#-----| Goto -> Block 7
|
||||
|
||||
# 2021| Block 10
|
||||
# 2021| r2021_6(glval<unknown>) = VariableAddress[#temp2021:10] :
|
||||
# 2021| r2021_7(glval<TernaryNonPodObj>) = Load[#temp2021:10] : &:r2021_6, ~m?
|
||||
# 2021| r2021_8(glval<TernaryNonPodObj>) = Convert : r2021_7
|
||||
# 2021| r2021_9(TernaryNonPodObj &) = CopyValue : r2021_8
|
||||
# 2021| r2021_10(TernaryNonPodObj &) = Call[operator=] : func:r2021_2, this:r2021_1, 0:r2021_9
|
||||
# 2021| mu2021_11(unknown) = ^CallSideEffect : ~m?
|
||||
# 2021| v2021_12(void) = ^IndirectReadSideEffect[-1] : &:r2021_1, ~m?
|
||||
# 2021| v2021_13(void) = ^BufferReadSideEffect[0] : &:r2021_9, ~m?
|
||||
# 2021| mu2021_14(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_1
|
||||
# 2021| r2021_15(glval<TernaryNonPodObj>) = CopyValue : r2021_10
|
||||
# 2021| r2021_16(glval<unknown>) = FunctionAddress[operator=] :
|
||||
# 2021| r2021_17(glval<TernaryNonPodObj>) = VariableAddress[#temp2021:23] :
|
||||
# 2021| mu2021_18(TernaryNonPodObj) = Uninitialized[#temp2021:23] : &:r2021_17
|
||||
# 2021| r2021_19(glval<unknown>) = FunctionAddress[TernaryNonPodObj] :
|
||||
# 2021| v2021_20(void) = Call[TernaryNonPodObj] : func:r2021_19, this:r2021_17
|
||||
# 2021| mu2021_21(unknown) = ^CallSideEffect : ~m?
|
||||
# 2021| mu2021_22(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_17
|
||||
# 2021| r2021_23(glval<TernaryNonPodObj>) = Convert : r2021_17
|
||||
# 2021| r2021_24(TernaryNonPodObj &) = CopyValue : r2021_23
|
||||
# 2021| r2021_25(TernaryNonPodObj &) = Call[operator=] : func:r2021_16, this:r2021_15, 0:r2021_24
|
||||
# 2021| mu2021_26(unknown) = ^CallSideEffect : ~m?
|
||||
# 2021| v2021_27(void) = ^IndirectReadSideEffect[-1] : &:r2021_15, ~m?
|
||||
# 2021| v2021_28(void) = ^BufferReadSideEffect[0] : &:r2021_24, ~m?
|
||||
# 2021| mu2021_29(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_15
|
||||
# 2021| r2021_30(glval<TernaryNonPodObj>) = CopyValue : r2021_25
|
||||
# 2022| v2022_1(void) = NoOp :
|
||||
# 2017| v2017_12(void) = ReturnVoid :
|
||||
# 2017| v2017_13(void) = AliasedUse : ~m?
|
||||
# 2017| v2017_14(void) = ExitFunction :
|
||||
|
||||
# 2021| Block 11
|
||||
# 2021| r2021_31(glval<TernaryNonPodObj>) = VariableAddress[x] :
|
||||
# 2021| r2021_32(glval<unknown>) = VariableAddress[#temp2021:10] :
|
||||
# 2021| mu2021_33(glval<TernaryNonPodObj>) = Store[#temp2021:10] : &:r2021_32, r2021_31
|
||||
#-----| Goto -> Block 10
|
||||
|
||||
# 2021| Block 12
|
||||
# 2021| r2021_34(glval<TernaryNonPodObj>) = VariableAddress[y] :
|
||||
# 2021| r2021_35(glval<unknown>) = VariableAddress[#temp2021:10] :
|
||||
# 2021| mu2021_36(glval<TernaryNonPodObj>) = Store[#temp2021:10] : &:r2021_35, r2021_34
|
||||
#-----| Goto -> Block 10
|
||||
|
||||
# 2026| unsigned int CommaTest(unsigned int)
|
||||
# 2026| Block 0
|
||||
# 2026| v2026_1(void) = EnterFunction :
|
||||
# 2026| mu2026_2(unknown) = AliasedDefinition :
|
||||
# 2026| mu2026_3(unknown) = InitializeNonLocal :
|
||||
# 2026| r2026_4(glval<unsigned int>) = VariableAddress[x] :
|
||||
# 2026| mu2026_5(unsigned int) = InitializeParameter[x] : &:r2026_4
|
||||
# 2027| r2027_1(glval<unsigned int>) = VariableAddress[y] :
|
||||
# 2027| mu2027_2(unsigned int) = Uninitialized[y] : &:r2027_1
|
||||
# 2028| r2028_1(glval<unsigned int>) = VariableAddress[x] :
|
||||
# 2028| r2028_2(unsigned int) = Load[x] : &:r2028_1, ~m?
|
||||
# 2028| r2028_3(unsigned int) = Constant[100] :
|
||||
# 2028| r2028_4(bool) = CompareLT : r2028_2, r2028_3
|
||||
# 2028| v2028_5(void) = ConditionalBranch : r2028_4
|
||||
#-----| False -> Block 4
|
||||
#-----| True -> Block 3
|
||||
|
||||
# 2026| Block 1
|
||||
# 2026| r2026_6(glval<unsigned int>) = VariableAddress[#return] :
|
||||
# 2026| v2026_7(void) = ReturnValue : &:r2026_6, ~m?
|
||||
# 2026| v2026_8(void) = AliasedUse : ~m?
|
||||
# 2026| v2026_9(void) = ExitFunction :
|
||||
|
||||
# 2028| Block 2
|
||||
# 2028| r2028_6(glval<unsigned int>) = VariableAddress[#temp2028:7] :
|
||||
# 2028| r2028_7(unsigned int) = Load[#temp2028:7] : &:r2028_6, ~m?
|
||||
# 2028| r2028_8(glval<unsigned int>) = VariableAddress[y] :
|
||||
# 2028| mu2028_9(unsigned int) = Store[y] : &:r2028_8, r2028_7
|
||||
# 2031| v2031_1(void) = Unreached :
|
||||
|
||||
# 2029| Block 3
|
||||
# 2029| r2029_1(glval<unknown>) = FunctionAddress[CommaTestHelper] :
|
||||
# 2029| r2029_2(glval<unsigned int>) = VariableAddress[x] :
|
||||
# 2029| r2029_3(unsigned int) = Load[x] : &:r2029_2, ~m?
|
||||
# 2029| v2029_4(void) = Call[CommaTestHelper] : func:r2029_1, 0:r2029_3
|
||||
# 2029| mu2029_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 2029| r2029_6(glval<unsigned int>) = VariableAddress[x] :
|
||||
# 2029| r2029_7(unsigned int) = Load[x] : &:r2029_6, ~m?
|
||||
# 2029| r2029_8(unsigned int) = CopyValue : r2029_7
|
||||
# 2028| r2028_10(glval<unsigned int>) = VariableAddress[#temp2028:7] :
|
||||
# 2028| mu2028_11(unsigned int) = Store[#temp2028:7] : &:r2028_10, r2029_8
|
||||
#-----| Goto -> Block 2
|
||||
|
||||
# 2030| Block 4
|
||||
# 2030| r2030_1(glval<unknown>) = FunctionAddress[CommaTestHelper] :
|
||||
# 2030| r2030_2(glval<unsigned int>) = VariableAddress[x] :
|
||||
# 2030| r2030_3(unsigned int) = Load[x] : &:r2030_2, ~m?
|
||||
# 2030| v2030_4(void) = Call[CommaTestHelper] : func:r2030_1, 0:r2030_3
|
||||
# 2030| mu2030_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 2030| r2030_6(int) = Constant[10] :
|
||||
# 2030| r2030_7(int) = CopyValue : r2030_6
|
||||
# 2030| r2030_8(unsigned int) = Convert : r2030_7
|
||||
# 2028| r2028_12(glval<unsigned int>) = VariableAddress[#temp2028:7] :
|
||||
# 2028| mu2028_13(unsigned int) = Store[#temp2028:7] : &:r2028_12, r2030_8
|
||||
#-----| Goto -> Block 2
|
||||
|
||||
perf-regression.cpp:
|
||||
# 6| void Big::Big()
|
||||
# 6| Block 0
|
||||
|
||||
@@ -7,5 +7,5 @@ private import semmle.code.cpp.ir.implementation.raw.PrintIR
|
||||
private import PrintConfig
|
||||
|
||||
private class PrintConfig extends PrintIRConfiguration {
|
||||
override predicate shouldPrintFunction(Declaration decl) { shouldDumpFunction(decl) }
|
||||
override predicate shouldPrintDeclaration(Declaration decl) { shouldDumpDeclaration(decl) }
|
||||
}
|
||||
|
||||
@@ -2157,3 +2157,46 @@ ssa.cpp:
|
||||
# 431| v431_9(void) = ReturnValue : &:r431_8, m435_4
|
||||
# 431| v431_10(void) = AliasedUse : m431_3
|
||||
# 431| v431_11(void) = ExitFunction :
|
||||
|
||||
# 438| void Conditional(bool, int, int)
|
||||
# 438| Block 0
|
||||
# 438| v438_1(void) = EnterFunction :
|
||||
# 438| m438_2(unknown) = AliasedDefinition :
|
||||
# 438| m438_3(unknown) = InitializeNonLocal :
|
||||
# 438| m438_4(unknown) = Chi : total:m438_2, partial:m438_3
|
||||
# 438| r438_5(glval<bool>) = VariableAddress[a] :
|
||||
# 438| m438_6(bool) = InitializeParameter[a] : &:r438_5
|
||||
# 438| r438_7(glval<int>) = VariableAddress[x] :
|
||||
# 438| m438_8(int) = InitializeParameter[x] : &:r438_7
|
||||
# 438| r438_9(glval<int>) = VariableAddress[y] :
|
||||
# 438| m438_10(int) = InitializeParameter[y] : &:r438_9
|
||||
# 439| r439_1(glval<int>) = VariableAddress[z] :
|
||||
# 439| r439_2(glval<bool>) = VariableAddress[a] :
|
||||
# 439| r439_3(bool) = Load[a] : &:r439_2, m438_6
|
||||
# 439| v439_4(void) = ConditionalBranch : r439_3
|
||||
#-----| False -> Block 3
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 439| Block 1
|
||||
# 439| m439_5(int) = Phi : from 2:m439_12, from 3:m439_16
|
||||
# 439| r439_6(glval<int>) = VariableAddress[#temp439:13] :
|
||||
# 439| r439_7(int) = Load[#temp439:13] : &:r439_6, m439_5
|
||||
# 439| m439_8(int) = Store[z] : &:r439_1, r439_7
|
||||
# 440| v440_1(void) = NoOp :
|
||||
# 438| v438_11(void) = ReturnVoid :
|
||||
# 438| v438_12(void) = AliasedUse : m438_3
|
||||
# 438| v438_13(void) = ExitFunction :
|
||||
|
||||
# 439| Block 2
|
||||
# 439| r439_9(glval<int>) = VariableAddress[x] :
|
||||
# 439| r439_10(int) = Load[x] : &:r439_9, m438_8
|
||||
# 439| r439_11(glval<int>) = VariableAddress[#temp439:13] :
|
||||
# 439| m439_12(int) = Store[#temp439:13] : &:r439_11, r439_10
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 439| Block 3
|
||||
# 439| r439_13(glval<int>) = VariableAddress[y] :
|
||||
# 439| r439_14(int) = Load[y] : &:r439_13, m438_10
|
||||
# 439| r439_15(glval<int>) = VariableAddress[#temp439:13] :
|
||||
# 439| m439_16(int) = Store[#temp439:13] : &:r439_15, r439_14
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
@@ -2146,3 +2146,46 @@ ssa.cpp:
|
||||
# 431| v431_9(void) = ReturnValue : &:r431_8, m435_4
|
||||
# 431| v431_10(void) = AliasedUse : m431_3
|
||||
# 431| v431_11(void) = ExitFunction :
|
||||
|
||||
# 438| void Conditional(bool, int, int)
|
||||
# 438| Block 0
|
||||
# 438| v438_1(void) = EnterFunction :
|
||||
# 438| m438_2(unknown) = AliasedDefinition :
|
||||
# 438| m438_3(unknown) = InitializeNonLocal :
|
||||
# 438| m438_4(unknown) = Chi : total:m438_2, partial:m438_3
|
||||
# 438| r438_5(glval<bool>) = VariableAddress[a] :
|
||||
# 438| m438_6(bool) = InitializeParameter[a] : &:r438_5
|
||||
# 438| r438_7(glval<int>) = VariableAddress[x] :
|
||||
# 438| m438_8(int) = InitializeParameter[x] : &:r438_7
|
||||
# 438| r438_9(glval<int>) = VariableAddress[y] :
|
||||
# 438| m438_10(int) = InitializeParameter[y] : &:r438_9
|
||||
# 439| r439_1(glval<int>) = VariableAddress[z] :
|
||||
# 439| r439_2(glval<bool>) = VariableAddress[a] :
|
||||
# 439| r439_3(bool) = Load[a] : &:r439_2, m438_6
|
||||
# 439| v439_4(void) = ConditionalBranch : r439_3
|
||||
#-----| False -> Block 3
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 439| Block 1
|
||||
# 439| m439_5(int) = Phi : from 2:m439_12, from 3:m439_16
|
||||
# 439| r439_6(glval<int>) = VariableAddress[#temp439:13] :
|
||||
# 439| r439_7(int) = Load[#temp439:13] : &:r439_6, m439_5
|
||||
# 439| m439_8(int) = Store[z] : &:r439_1, r439_7
|
||||
# 440| v440_1(void) = NoOp :
|
||||
# 438| v438_11(void) = ReturnVoid :
|
||||
# 438| v438_12(void) = AliasedUse : m438_3
|
||||
# 438| v438_13(void) = ExitFunction :
|
||||
|
||||
# 439| Block 2
|
||||
# 439| r439_9(glval<int>) = VariableAddress[x] :
|
||||
# 439| r439_10(int) = Load[x] : &:r439_9, m438_8
|
||||
# 439| r439_11(glval<int>) = VariableAddress[#temp439:13] :
|
||||
# 439| m439_12(int) = Store[#temp439:13] : &:r439_11, r439_10
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 439| Block 3
|
||||
# 439| r439_13(glval<int>) = VariableAddress[y] :
|
||||
# 439| r439_14(int) = Load[y] : &:r439_13, m438_10
|
||||
# 439| r439_15(glval<int>) = VariableAddress[#temp439:13] :
|
||||
# 439| m439_16(int) = Store[#temp439:13] : &:r439_15, r439_14
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
@@ -434,3 +434,7 @@ int noreturnTest2(int x) {
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
void Conditional(bool a, int x, int y) {
|
||||
int z = a ? x : y;
|
||||
}
|
||||
|
||||
@@ -2002,3 +2002,45 @@ ssa.cpp:
|
||||
# 431| v431_8(void) = ReturnValue : &:r431_7, m435_4
|
||||
# 431| v431_9(void) = AliasedUse : ~m?
|
||||
# 431| v431_10(void) = ExitFunction :
|
||||
|
||||
# 438| void Conditional(bool, int, int)
|
||||
# 438| Block 0
|
||||
# 438| v438_1(void) = EnterFunction :
|
||||
# 438| mu438_2(unknown) = AliasedDefinition :
|
||||
# 438| mu438_3(unknown) = InitializeNonLocal :
|
||||
# 438| r438_4(glval<bool>) = VariableAddress[a] :
|
||||
# 438| m438_5(bool) = InitializeParameter[a] : &:r438_4
|
||||
# 438| r438_6(glval<int>) = VariableAddress[x] :
|
||||
# 438| m438_7(int) = InitializeParameter[x] : &:r438_6
|
||||
# 438| r438_8(glval<int>) = VariableAddress[y] :
|
||||
# 438| m438_9(int) = InitializeParameter[y] : &:r438_8
|
||||
# 439| r439_1(glval<int>) = VariableAddress[z] :
|
||||
# 439| r439_2(glval<bool>) = VariableAddress[a] :
|
||||
# 439| r439_3(bool) = Load[a] : &:r439_2, m438_5
|
||||
# 439| v439_4(void) = ConditionalBranch : r439_3
|
||||
#-----| False -> Block 3
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 439| Block 1
|
||||
# 439| m439_5(int) = Phi : from 2:m439_12, from 3:m439_16
|
||||
# 439| r439_6(glval<int>) = VariableAddress[#temp439:13] :
|
||||
# 439| r439_7(int) = Load[#temp439:13] : &:r439_6, m439_5
|
||||
# 439| m439_8(int) = Store[z] : &:r439_1, r439_7
|
||||
# 440| v440_1(void) = NoOp :
|
||||
# 438| v438_10(void) = ReturnVoid :
|
||||
# 438| v438_11(void) = AliasedUse : ~m?
|
||||
# 438| v438_12(void) = ExitFunction :
|
||||
|
||||
# 439| Block 2
|
||||
# 439| r439_9(glval<int>) = VariableAddress[x] :
|
||||
# 439| r439_10(int) = Load[x] : &:r439_9, m438_7
|
||||
# 439| r439_11(glval<int>) = VariableAddress[#temp439:13] :
|
||||
# 439| m439_12(int) = Store[#temp439:13] : &:r439_11, r439_10
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 439| Block 3
|
||||
# 439| r439_13(glval<int>) = VariableAddress[y] :
|
||||
# 439| r439_14(int) = Load[y] : &:r439_13, m438_9
|
||||
# 439| r439_15(glval<int>) = VariableAddress[#temp439:13] :
|
||||
# 439| m439_16(int) = Store[#temp439:13] : &:r439_15, r439_14
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
@@ -2002,3 +2002,45 @@ ssa.cpp:
|
||||
# 431| v431_8(void) = ReturnValue : &:r431_7, m435_4
|
||||
# 431| v431_9(void) = AliasedUse : ~m?
|
||||
# 431| v431_10(void) = ExitFunction :
|
||||
|
||||
# 438| void Conditional(bool, int, int)
|
||||
# 438| Block 0
|
||||
# 438| v438_1(void) = EnterFunction :
|
||||
# 438| mu438_2(unknown) = AliasedDefinition :
|
||||
# 438| mu438_3(unknown) = InitializeNonLocal :
|
||||
# 438| r438_4(glval<bool>) = VariableAddress[a] :
|
||||
# 438| m438_5(bool) = InitializeParameter[a] : &:r438_4
|
||||
# 438| r438_6(glval<int>) = VariableAddress[x] :
|
||||
# 438| m438_7(int) = InitializeParameter[x] : &:r438_6
|
||||
# 438| r438_8(glval<int>) = VariableAddress[y] :
|
||||
# 438| m438_9(int) = InitializeParameter[y] : &:r438_8
|
||||
# 439| r439_1(glval<int>) = VariableAddress[z] :
|
||||
# 439| r439_2(glval<bool>) = VariableAddress[a] :
|
||||
# 439| r439_3(bool) = Load[a] : &:r439_2, m438_5
|
||||
# 439| v439_4(void) = ConditionalBranch : r439_3
|
||||
#-----| False -> Block 3
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 439| Block 1
|
||||
# 439| m439_5(int) = Phi : from 2:m439_12, from 3:m439_16
|
||||
# 439| r439_6(glval<int>) = VariableAddress[#temp439:13] :
|
||||
# 439| r439_7(int) = Load[#temp439:13] : &:r439_6, m439_5
|
||||
# 439| m439_8(int) = Store[z] : &:r439_1, r439_7
|
||||
# 440| v440_1(void) = NoOp :
|
||||
# 438| v438_10(void) = ReturnVoid :
|
||||
# 438| v438_11(void) = AliasedUse : ~m?
|
||||
# 438| v438_12(void) = ExitFunction :
|
||||
|
||||
# 439| Block 2
|
||||
# 439| r439_9(glval<int>) = VariableAddress[x] :
|
||||
# 439| r439_10(int) = Load[x] : &:r439_9, m438_7
|
||||
# 439| r439_11(glval<int>) = VariableAddress[#temp439:13] :
|
||||
# 439| m439_12(int) = Store[#temp439:13] : &:r439_11, r439_10
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 439| Block 3
|
||||
# 439| r439_13(glval<int>) = VariableAddress[y] :
|
||||
# 439| r439_14(int) = Load[y] : &:r439_13, m438_9
|
||||
# 439| r439_15(glval<int>) = VariableAddress[#temp439:13] :
|
||||
# 439| m439_16(int) = Store[#temp439:13] : &:r439_15, r439_14
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
| file://:0:0:0:0 | _Float64 |
|
||||
| file://:0:0:0:0 | _Float64x |
|
||||
| file://:0:0:0:0 | _Float128 |
|
||||
| file://:0:0:0:0 | _Float128x |
|
||||
| file://:0:0:0:0 | _Imaginary double |
|
||||
| file://:0:0:0:0 | _Imaginary float |
|
||||
| file://:0:0:0:0 | _Imaginary long double |
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
| file://:0:0:0:0 | _Float64 | 8 |
|
||||
| file://:0:0:0:0 | _Float64x | 16 |
|
||||
| file://:0:0:0:0 | _Float128 | 16 |
|
||||
| file://:0:0:0:0 | _Float128x | 32 |
|
||||
| file://:0:0:0:0 | _Imaginary double | 8 |
|
||||
| file://:0:0:0:0 | _Imaginary float | 4 |
|
||||
| file://:0:0:0:0 | _Imaginary long double | 16 |
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
| file://:0:0:0:0 | _Float64 | _Float64 |
|
||||
| file://:0:0:0:0 | _Float64x | _Float64x |
|
||||
| file://:0:0:0:0 | _Float128 | _Float128 |
|
||||
| file://:0:0:0:0 | _Float128x | _Float128x |
|
||||
| file://:0:0:0:0 | _Imaginary double | _Imaginary double |
|
||||
| file://:0:0:0:0 | _Imaginary float | _Imaginary float |
|
||||
| file://:0:0:0:0 | _Imaginary long double | _Imaginary long double |
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
| _Float64 | BinaryFloatingPointType, RealNumberType | | | | |
|
||||
| _Float64x | BinaryFloatingPointType, RealNumberType | | | | |
|
||||
| _Float128 | BinaryFloatingPointType, RealNumberType | | | | |
|
||||
| _Float128x | BinaryFloatingPointType, RealNumberType | | | | |
|
||||
| _Imaginary double | BinaryFloatingPointType, ImaginaryNumberType | | | | |
|
||||
| _Imaginary float | BinaryFloatingPointType, ImaginaryNumberType | | | | |
|
||||
| _Imaginary long double | BinaryFloatingPointType, ImaginaryNumberType | | | | |
|
||||
|
||||
Reference in New Issue
Block a user