mirror of
https://github.com/github/codeql.git
synced 2026-04-29 02:35:15 +02:00
Merge branch 'main' into add-cwe-208
This commit is contained in:
@@ -1 +1 @@
|
||||
6.1.2
|
||||
6.3.1
|
||||
|
||||
@@ -1,24 +1,4 @@
|
||||
{
|
||||
"DataFlow Java/C++/C#/Go/Python/Ruby/Swift": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlow.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlow.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlow.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlow.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlow.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlow.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlow.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlow.qll"
|
||||
],
|
||||
"DataFlowImpl Java/C++/C#/Go/Python/Ruby/Swift": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll"
|
||||
],
|
||||
"DataFlow Java/C++/C#/Go/Python/Ruby/Swift Legacy Configuration": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl1.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll",
|
||||
@@ -53,16 +33,6 @@
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForPathname.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl1.qll"
|
||||
],
|
||||
"DataFlow Java/C++/C#/Go/Python/Ruby/Swift Common": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImplCommon.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplCommon.qll"
|
||||
],
|
||||
"TaintTracking Java/C++/C#/Go/Python/Ruby/Swift": [
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTracking.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTracking.qll",
|
||||
@@ -516,7 +486,6 @@
|
||||
],
|
||||
"CFG": [
|
||||
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",
|
||||
"ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll",
|
||||
"swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImplShared.qll"
|
||||
],
|
||||
"TypeTracker": [
|
||||
@@ -603,4 +572,4 @@
|
||||
"python/ql/lib/semmle/python/security/internal/EncryptionKeySizes.qll",
|
||||
"java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll"
|
||||
]
|
||||
}
|
||||
}
|
||||
2212
cpp/downgrades/d77c09d8bdc172c9201dec293de1e14c931d3f05/old.dbscheme
Normal file
2212
cpp/downgrades/d77c09d8bdc172c9201dec293de1e14c931d3f05/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Remove _Float128 type
|
||||
compatibility: full
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* 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.
|
||||
@@ -6,6 +6,7 @@ extractor: cpp
|
||||
library: true
|
||||
upgrades: upgrades
|
||||
dependencies:
|
||||
codeql/dataflow: ${workspace}
|
||||
codeql/ssa: ${workspace}
|
||||
codeql/tutorial: ${workspace}
|
||||
codeql/util: ${workspace}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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.
|
||||
@@ -1088,7 +1078,7 @@ private IRVariable getIRVariableForParameterNode(ParameterNode p) {
|
||||
|
||||
/** Holds if `v` is the source variable corresponding to the parameter represented by `p`. */
|
||||
pragma[nomagic]
|
||||
private predicate parameterNodeHasSourceVariable(ParameterNode p, Ssa::SourceIRVariable v) {
|
||||
private predicate parameterNodeHasSourceVariable(ParameterNode p, Ssa::SourceVariable v) {
|
||||
v.getIRVariable() = getIRVariableForParameterNode(p) and
|
||||
exists(Position pos | p.isParameterOf(_, pos) |
|
||||
pos instanceof DirectPosition and
|
||||
|
||||
@@ -781,26 +781,12 @@ class IndirectArgumentOutNode extends Node, TIndirectArgumentOutNode, PartialDef
|
||||
override Expr getDefinedExpr() { result = operand.getDef().getUnconvertedResultExpression() }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate indirectReturnOutNodeOperand0(CallInstruction call, Operand operand, int indirectionIndex) {
|
||||
Ssa::hasRawIndirectInstruction(call, indirectionIndex) and
|
||||
operandForFullyConvertedCall(operand, call)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate indirectReturnOutNodeInstruction0(
|
||||
CallInstruction call, Instruction instr, int indirectionIndex
|
||||
) {
|
||||
Ssa::hasRawIndirectInstruction(call, indirectionIndex) and
|
||||
instructionForFullyConvertedCall(instr, call)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is an indirect operand with columns `(operand, indirectionIndex)`, and
|
||||
* `operand` represents a use of the fully converted value of `call`.
|
||||
*/
|
||||
private predicate hasOperand(Node node, CallInstruction call, int indirectionIndex, Operand operand) {
|
||||
indirectReturnOutNodeOperand0(call, operand, indirectionIndex) and
|
||||
operandForFullyConvertedCall(operand, call) and
|
||||
hasOperandAndIndex(node, operand, indirectionIndex)
|
||||
}
|
||||
|
||||
@@ -813,7 +799,7 @@ private predicate hasOperand(Node node, CallInstruction call, int indirectionInd
|
||||
private predicate hasInstruction(
|
||||
Node node, CallInstruction call, int indirectionIndex, Instruction instr
|
||||
) {
|
||||
indirectReturnOutNodeInstruction0(call, instr, indirectionIndex) and
|
||||
instructionForFullyConvertedCall(instr, call) and
|
||||
hasInstructionAndIndex(node, instr, indirectionIndex)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,32 +10,35 @@ private import ssa0.SsaInternals as SsaInternals0
|
||||
import SsaInternalsCommon
|
||||
|
||||
private module SourceVariables {
|
||||
int getMaxIndirectionForIRVariable(IRVariable var) {
|
||||
exists(Type type, boolean isGLValue |
|
||||
var.getLanguageType().hasType(type, isGLValue) and
|
||||
if isGLValue = true
|
||||
then result = 1 + getMaxIndirectionsForType(type)
|
||||
else result = getMaxIndirectionsForType(type)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TSourceVariable =
|
||||
TSourceIRVariable(BaseIRVariable baseVar, int ind) {
|
||||
ind = [0 .. getMaxIndirectionForIRVariable(baseVar.getIRVariable())]
|
||||
} or
|
||||
TCallVariable(AllocationInstruction call, int ind) {
|
||||
ind = [0 .. countIndirectionsForCppType(getResultLanguageType(call))]
|
||||
TMkSourceVariable(SsaInternals0::SourceVariable base, int ind) {
|
||||
ind = [0 .. countIndirectionsForCppType(base.getLanguageType()) + 1]
|
||||
}
|
||||
|
||||
abstract class SourceVariable extends TSourceVariable {
|
||||
class SourceVariable extends TSourceVariable {
|
||||
SsaInternals0::SourceVariable base;
|
||||
int ind;
|
||||
|
||||
bindingset[ind]
|
||||
SourceVariable() { any() }
|
||||
SourceVariable() { this = TMkSourceVariable(base, ind) }
|
||||
|
||||
/** Gets the IR variable associated with this `SourceVariable`, if any. */
|
||||
IRVariable getIRVariable() { result = base.(BaseIRVariable).getIRVariable() }
|
||||
|
||||
/**
|
||||
* Gets the base source variable (i.e., the variable without any
|
||||
* indirections) of this source variable.
|
||||
*/
|
||||
SsaInternals0::SourceVariable getBaseVariable() { result = base }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
string toString() {
|
||||
ind = 0 and
|
||||
result = this.getBaseVariable().toString()
|
||||
or
|
||||
ind > 0 and
|
||||
result = this.getBaseVariable().toString() + " indirection"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of loads performed on the base source variable
|
||||
@@ -43,65 +46,19 @@ private module SourceVariables {
|
||||
*/
|
||||
int getIndirection() { result = ind }
|
||||
|
||||
/**
|
||||
* Gets the base source variable (i.e., the variable without any
|
||||
* indirections) of this source variable.
|
||||
*/
|
||||
abstract BaseSourceVariable getBaseVariable();
|
||||
|
||||
/** Holds if this variable is a glvalue. */
|
||||
predicate isGLValue() { none() }
|
||||
predicate isGLValue() { ind = 0 }
|
||||
|
||||
/**
|
||||
* Gets the type of this source variable. If `isGLValue()` holds, then
|
||||
* the type of this source variable should be thought of as "pointer
|
||||
* to `getType()`".
|
||||
*/
|
||||
abstract DataFlowType getType();
|
||||
}
|
||||
|
||||
class SourceIRVariable extends SourceVariable, TSourceIRVariable {
|
||||
BaseIRVariable var;
|
||||
|
||||
SourceIRVariable() { this = TSourceIRVariable(var, ind) }
|
||||
|
||||
IRVariable getIRVariable() { result = var.getIRVariable() }
|
||||
|
||||
override BaseIRVariable getBaseVariable() { result.getIRVariable() = this.getIRVariable() }
|
||||
|
||||
override string toString() {
|
||||
ind = 0 and
|
||||
result = this.getIRVariable().toString()
|
||||
or
|
||||
ind > 0 and
|
||||
result = this.getIRVariable().toString() + " indirection"
|
||||
DataFlowType getType() {
|
||||
if this.isGLValue()
|
||||
then result = base.getType()
|
||||
else result = getTypeImpl(base.getType(), ind - 1)
|
||||
}
|
||||
|
||||
override predicate isGLValue() { ind = 0 }
|
||||
|
||||
override DataFlowType getType() {
|
||||
if ind = 0 then result = var.getType() else result = getTypeImpl(var.getType(), ind - 1)
|
||||
}
|
||||
}
|
||||
|
||||
class CallVariable extends SourceVariable, TCallVariable {
|
||||
AllocationInstruction call;
|
||||
|
||||
CallVariable() { this = TCallVariable(call, ind) }
|
||||
|
||||
AllocationInstruction getCall() { result = call }
|
||||
|
||||
override BaseCallVariable getBaseVariable() { result.getCallInstruction() = call }
|
||||
|
||||
override string toString() {
|
||||
ind = 0 and
|
||||
result = "Call"
|
||||
or
|
||||
ind > 0 and
|
||||
result = "Call indirection"
|
||||
}
|
||||
|
||||
override DataFlowType getType() { result = getTypeImpl(call.getResultType(), ind) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,8 +94,9 @@ predicate hasRawIndirectInstruction(Instruction instr, int indirectionIndex) {
|
||||
|
||||
cached
|
||||
private newtype TDefOrUseImpl =
|
||||
TDefImpl(Operand address, int indirectionIndex) {
|
||||
exists(Instruction base | isDef(_, _, address, base, _, indirectionIndex) |
|
||||
TDefImpl(BaseSourceVariableInstruction base, Operand address, int indirectionIndex) {
|
||||
isDef(_, _, address, base, _, indirectionIndex) and
|
||||
(
|
||||
// We only include the definition if the SSA pruning stage
|
||||
// concluded that the definition is live after the write.
|
||||
any(SsaInternals0::Def def).getAddressOperand() = address
|
||||
@@ -148,8 +106,8 @@ private newtype TDefOrUseImpl =
|
||||
base.(VariableAddressInstruction).getAstVariable() instanceof GlobalLikeVariable
|
||||
)
|
||||
} or
|
||||
TUseImpl(Operand operand, int indirectionIndex) {
|
||||
isUse(_, operand, _, _, indirectionIndex) and
|
||||
TUseImpl(BaseSourceVariableInstruction base, Operand operand, int indirectionIndex) {
|
||||
isUse(_, operand, base, _, indirectionIndex) and
|
||||
not isDef(_, _, operand, _, _, _)
|
||||
} or
|
||||
TGlobalUse(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
|
||||
@@ -236,7 +194,7 @@ abstract private class DefOrUseImpl extends TDefOrUseImpl {
|
||||
|
||||
/**
|
||||
* Gets the instruction that computes the base of this definition or use.
|
||||
* This is always a `VariableAddressInstruction` or an `AllocationInstruction`.
|
||||
* This is always a `VariableAddressInstruction` or an `CallInstruction`.
|
||||
*/
|
||||
abstract BaseSourceVariableInstruction getBase();
|
||||
|
||||
@@ -308,15 +266,17 @@ abstract class DefImpl extends DefOrUseImpl {
|
||||
}
|
||||
|
||||
private class DirectDef extends DefImpl, TDefImpl {
|
||||
DirectDef() { this = TDefImpl(address, ind) }
|
||||
BaseSourceVariableInstruction base;
|
||||
|
||||
override BaseSourceVariableInstruction getBase() { isDef(_, _, address, result, _, _) }
|
||||
DirectDef() { this = TDefImpl(base, address, ind) }
|
||||
|
||||
override int getIndirection() { isDef(_, _, address, _, result, ind) }
|
||||
override BaseSourceVariableInstruction getBase() { result = base }
|
||||
|
||||
override Node0Impl getValue() { isDef(_, result, address, _, _, _) }
|
||||
override int getIndirection() { isDef(_, _, address, base, result, ind) }
|
||||
|
||||
override predicate isCertain() { isDef(true, _, address, _, _, ind) }
|
||||
override Node0Impl getValue() { isDef(_, result, address, base, _, _) }
|
||||
|
||||
override predicate isCertain() { isDef(true, _, address, base, _, ind) }
|
||||
}
|
||||
|
||||
private class IteratorDef extends DefImpl, TIteratorDef {
|
||||
@@ -359,6 +319,7 @@ abstract class UseImpl extends DefOrUseImpl {
|
||||
|
||||
abstract private class OperandBasedUse extends UseImpl {
|
||||
Operand operand;
|
||||
BaseSourceVariableInstruction base;
|
||||
|
||||
bindingset[ind]
|
||||
OperandBasedUse() { any() }
|
||||
@@ -366,50 +327,44 @@ abstract private class OperandBasedUse extends UseImpl {
|
||||
final override predicate hasIndexInBlock(IRBlock block, int index) {
|
||||
// See the comment in `ssa0`'s `OperandBasedUse` for an explanation of this
|
||||
// predicate's implementation.
|
||||
exists(BaseSourceVariableInstruction base | base = this.getBase() |
|
||||
if base.getAst() = any(Cpp::PostfixCrementOperation c).getOperand()
|
||||
then
|
||||
exists(Operand op, int indirectionIndex, int indirection |
|
||||
indirectionIndex = this.getIndirectionIndex() and
|
||||
indirection = this.getIndirection() and
|
||||
op =
|
||||
min(Operand cand, int i |
|
||||
isUse(_, cand, base, indirection, indirectionIndex) and
|
||||
block.getInstruction(i) = cand.getUse()
|
||||
|
|
||||
cand order by i
|
||||
) and
|
||||
block.getInstruction(index) = op.getUse()
|
||||
)
|
||||
else operand.getUse() = block.getInstruction(index)
|
||||
)
|
||||
if base.getAst() = any(Cpp::PostfixCrementOperation c).getOperand()
|
||||
then
|
||||
exists(Operand op, int indirectionIndex, int indirection |
|
||||
indirectionIndex = this.getIndirectionIndex() and
|
||||
indirection = this.getIndirection() and
|
||||
op =
|
||||
min(Operand cand, int i |
|
||||
isUse(_, cand, base, indirection, indirectionIndex) and
|
||||
block.getInstruction(i) = cand.getUse()
|
||||
|
|
||||
cand order by i
|
||||
) and
|
||||
block.getInstruction(index) = op.getUse()
|
||||
)
|
||||
else operand.getUse() = block.getInstruction(index)
|
||||
}
|
||||
|
||||
final override BaseSourceVariableInstruction getBase() { result = base }
|
||||
|
||||
final Operand getOperand() { result = operand }
|
||||
|
||||
final override Cpp::Location getLocation() { result = operand.getLocation() }
|
||||
}
|
||||
|
||||
private class DirectUse extends OperandBasedUse, TUseImpl {
|
||||
DirectUse() { this = TUseImpl(operand, ind) }
|
||||
DirectUse() { this = TUseImpl(base, operand, ind) }
|
||||
|
||||
override int getIndirection() { isUse(_, operand, _, result, ind) }
|
||||
override int getIndirection() { isUse(_, operand, base, result, ind) }
|
||||
|
||||
override BaseSourceVariableInstruction getBase() { isUse(_, operand, result, _, ind) }
|
||||
|
||||
override predicate isCertain() { isUse(true, operand, _, _, ind) }
|
||||
override predicate isCertain() { isUse(true, operand, base, _, ind) }
|
||||
|
||||
override Node getNode() { nodeHasOperand(result, operand, ind) }
|
||||
}
|
||||
|
||||
private class IteratorUse extends OperandBasedUse, TIteratorUse {
|
||||
BaseSourceVariableInstruction container;
|
||||
IteratorUse() { this = TIteratorUse(operand, base, ind) }
|
||||
|
||||
IteratorUse() { this = TIteratorUse(operand, container, ind) }
|
||||
|
||||
override int getIndirection() { isIteratorUse(container, operand, result, ind) }
|
||||
|
||||
override BaseSourceVariableInstruction getBase() { result = container }
|
||||
override int getIndirection() { isIteratorUse(base, operand, result, ind) }
|
||||
|
||||
override predicate isCertain() { none() }
|
||||
|
||||
|
||||
@@ -146,14 +146,6 @@ int countIndirectionsForCppType(LanguageType langType) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A `CallInstruction` that calls an allocation function such
|
||||
* as `malloc` or `operator new`.
|
||||
*/
|
||||
class AllocationInstruction extends CallInstruction {
|
||||
AllocationInstruction() { this.getStaticCallTarget() instanceof Cpp::AllocationFunction }
|
||||
}
|
||||
|
||||
private predicate isIndirectionType(Type t) { t instanceof Indirection }
|
||||
|
||||
private predicate hasUnspecifiedBaseType(Indirection t, Type base) {
|
||||
@@ -368,17 +360,22 @@ newtype TBaseSourceVariable =
|
||||
// Each IR variable gets its own source variable
|
||||
TBaseIRVariable(IRVariable var) or
|
||||
// Each allocation gets its own source variable
|
||||
TBaseCallVariable(AllocationInstruction call)
|
||||
TBaseCallVariable(CallInstruction call) { not call.getResultIRType() instanceof IRVoidType }
|
||||
|
||||
abstract class BaseSourceVariable extends TBaseSourceVariable {
|
||||
abstract private class AbstractBaseSourceVariable extends TBaseSourceVariable {
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
|
||||
/** Gets the type of this base source variable. */
|
||||
abstract DataFlowType getType();
|
||||
final DataFlowType getType() { this.getLanguageType().hasUnspecifiedType(result, _) }
|
||||
|
||||
/** Gets the `CppType` of this base source variable. */
|
||||
abstract CppType getLanguageType();
|
||||
}
|
||||
|
||||
class BaseIRVariable extends BaseSourceVariable, TBaseIRVariable {
|
||||
final class BaseSourceVariable = AbstractBaseSourceVariable;
|
||||
|
||||
class BaseIRVariable extends AbstractBaseSourceVariable, TBaseIRVariable {
|
||||
IRVariable var;
|
||||
|
||||
IRVariable getIRVariable() { result = var }
|
||||
@@ -387,19 +384,19 @@ class BaseIRVariable extends BaseSourceVariable, TBaseIRVariable {
|
||||
|
||||
override string toString() { result = var.toString() }
|
||||
|
||||
override DataFlowType getType() { result = var.getType() }
|
||||
override CppType getLanguageType() { result = var.getLanguageType() }
|
||||
}
|
||||
|
||||
class BaseCallVariable extends BaseSourceVariable, TBaseCallVariable {
|
||||
AllocationInstruction call;
|
||||
class BaseCallVariable extends AbstractBaseSourceVariable, TBaseCallVariable {
|
||||
CallInstruction call;
|
||||
|
||||
BaseCallVariable() { this = TBaseCallVariable(call) }
|
||||
|
||||
AllocationInstruction getCallInstruction() { result = call }
|
||||
CallInstruction getCallInstruction() { result = call }
|
||||
|
||||
override string toString() { result = call.toString() }
|
||||
|
||||
override DataFlowType getType() { result = call.getResultType() }
|
||||
override CppType getLanguageType() { result = getResultLanguageType(call) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -499,8 +496,7 @@ private class BaseIRVariableInstruction extends BaseSourceVariableInstruction,
|
||||
override BaseIRVariable getBaseSourceVariable() { result.getIRVariable() = this.getIRVariable() }
|
||||
}
|
||||
|
||||
private class BaseAllocationInstruction extends BaseSourceVariableInstruction, AllocationInstruction
|
||||
{
|
||||
private class BaseCallInstruction extends BaseSourceVariableInstruction, CallInstruction {
|
||||
override BaseCallVariable getBaseSourceVariable() { result.getCallInstruction() = this }
|
||||
}
|
||||
|
||||
|
||||
@@ -15,15 +15,12 @@ private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.SsaInternalsCommon
|
||||
|
||||
private module SourceVariables {
|
||||
class SourceVariable instanceof BaseSourceVariable {
|
||||
string toString() { result = BaseSourceVariable.super.toString() }
|
||||
|
||||
class SourceVariable extends BaseSourceVariable {
|
||||
/**
|
||||
* Gets the base source variable of this `SourceVariable`.
|
||||
*/
|
||||
BaseSourceVariable getBaseVariable() { result = this }
|
||||
}
|
||||
|
||||
class SourceIRVariable = BaseIRVariable;
|
||||
|
||||
class CallVariable = BaseCallVariable;
|
||||
}
|
||||
|
||||
import SourceVariables
|
||||
|
||||
@@ -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, _, _, _)
|
||||
|
||||
@@ -307,3 +307,8 @@ class SemConditionalExpr extends SemKnownExpr {
|
||||
branch = false and result = falseResult
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `upper = true` and `e <= bound` or `upper = false` and `e >= bound`. */
|
||||
predicate semHasConstantBoundConstantSpecific(SemExpr e, float bound, boolean upper) {
|
||||
Specific::hasConstantBoundConstantSpecific(e, bound, upper)
|
||||
}
|
||||
|
||||
@@ -434,6 +434,50 @@ module SemanticExprConfig {
|
||||
|
||||
/** Gets the expression associated with `instr`. */
|
||||
SemExpr getSemanticExpr(IR::Instruction instr) { result = Equiv::getEquivalenceClass(instr) }
|
||||
|
||||
private predicate typeBounds(SemType t, float lb, float ub) {
|
||||
exists(SemIntegerType integralType, float limit |
|
||||
integralType = t and limit = 2.pow(8 * integralType.getByteSize())
|
||||
|
|
||||
if integralType instanceof SemBooleanType
|
||||
then lb = 0 and ub = 1
|
||||
else
|
||||
if integralType.isSigned()
|
||||
then (
|
||||
lb = -(limit / 2) and ub = (limit / 2) - 1
|
||||
) else (
|
||||
lb = 0 and ub = limit - 1
|
||||
)
|
||||
)
|
||||
or
|
||||
// This covers all floating point types. The range is (-Inf, +Inf).
|
||||
t instanceof SemFloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `upper = true` and `e <= bound` or `upper = false` and `e >= bound` based
|
||||
* only on type information.
|
||||
*/
|
||||
predicate hasConstantBoundConstantSpecific(Expr e, float bound, boolean upper) {
|
||||
exists(
|
||||
SemType converted, SemType unconverted, float unconvertedLb, float convertedLb,
|
||||
float unconvertedUb, float convertedUb
|
||||
|
|
||||
unconverted = getSemanticType(e.getUnconverted().getResultIRType()) and
|
||||
converted = getSemanticType(e.getConverted().getResultIRType()) and
|
||||
typeBounds(unconverted, unconvertedLb, unconvertedUb) and
|
||||
typeBounds(converted, convertedLb, convertedUb) and
|
||||
(
|
||||
upper = true and
|
||||
unconvertedUb < convertedUb and
|
||||
bound = unconvertedUb
|
||||
or
|
||||
upper = false and
|
||||
unconvertedLb > convertedLb and
|
||||
bound = unconvertedLb
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
predicate getSemanticExpr = SemanticExprConfig::getSemanticExpr/1;
|
||||
@@ -457,3 +501,5 @@ IRBound::Bound getCppBound(SemBound bound) { bound = result }
|
||||
SemGuard getSemanticGuard(IRGuards::IRGuardCondition guard) { result = guard }
|
||||
|
||||
IRGuards::IRGuardCondition getCppGuard(SemGuard guard) { guard = result }
|
||||
|
||||
predicate hasConstantBoundConstantSpecific = SemanticExprConfig::hasConstantBoundConstantSpecific/3;
|
||||
|
||||
@@ -3,10 +3,24 @@
|
||||
*/
|
||||
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
private import codeql.util.Unit
|
||||
private import Reason as Reason
|
||||
private import RangeAnalysisStage
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||
|
||||
module CppLangImplConstant implements LangSig<FloatDelta> {
|
||||
private module Param implements Reason::ParamSig {
|
||||
class TypeReasonImpl = Unit;
|
||||
}
|
||||
|
||||
class SemReason = Reason::Make<Param>::SemReason;
|
||||
|
||||
class SemNoReason = Reason::Make<Param>::SemNoReason;
|
||||
|
||||
class SemCondReason = Reason::Make<Param>::SemCondReason;
|
||||
|
||||
class SemTypeReason = Reason::Make<Param>::SemTypeReason;
|
||||
|
||||
/**
|
||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
@@ -60,7 +74,10 @@ module CppLangImplConstant implements LangSig<FloatDelta> {
|
||||
/**
|
||||
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
|
||||
*/
|
||||
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
|
||||
predicate hasConstantBound(SemExpr e, float bound, boolean upper, SemReason reason) {
|
||||
semHasConstantBoundConstantSpecific(e, bound, upper) and
|
||||
reason instanceof SemTypeReason
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
|
||||
|
||||
@@ -61,18 +61,23 @@ private newtype TSemReason =
|
||||
guard = any(ConstantStage::SemCondReason reason).getCond()
|
||||
or
|
||||
guard = any(RelativeStage::SemCondReason reason).getCond()
|
||||
}
|
||||
} or
|
||||
TSemTypeReason()
|
||||
|
||||
ConstantStage::SemReason constantReason(SemReason reason) {
|
||||
private ConstantStage::SemReason constantReason(SemReason reason) {
|
||||
result instanceof ConstantStage::SemNoReason and reason instanceof SemNoReason
|
||||
or
|
||||
result.(ConstantStage::SemCondReason).getCond() = reason.(SemCondReason).getCond()
|
||||
or
|
||||
result instanceof ConstantStage::SemTypeReason and reason instanceof SemTypeReason
|
||||
}
|
||||
|
||||
RelativeStage::SemReason relativeReason(SemReason reason) {
|
||||
private RelativeStage::SemReason relativeReason(SemReason reason) {
|
||||
result instanceof RelativeStage::SemNoReason and reason instanceof SemNoReason
|
||||
or
|
||||
result.(RelativeStage::SemCondReason).getCond() = reason.(SemCondReason).getCond()
|
||||
or
|
||||
result instanceof RelativeStage::SemTypeReason and reason instanceof SemTypeReason
|
||||
}
|
||||
|
||||
import Public
|
||||
@@ -111,4 +116,12 @@ module Public {
|
||||
|
||||
override string toString() { result = this.getCond().toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A reason for an inferred bound that indicates that the bound is inferred
|
||||
* based on type-information.
|
||||
*/
|
||||
class SemTypeReason extends SemReason, TSemTypeReason {
|
||||
override string toString() { result = "TypeReason" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,25 @@ private import RangeAnalysisStage
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.IntDelta
|
||||
private import RangeAnalysisImpl
|
||||
private import codeql.util.Unit
|
||||
private import Reason as Reason
|
||||
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||
|
||||
module CppLangImplRelative implements LangSig<FloatDelta> {
|
||||
private module Param implements Reason::ParamSig {
|
||||
class TypeReasonImpl extends Unit {
|
||||
TypeReasonImpl() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
class SemReason = Reason::Make<Param>::SemReason;
|
||||
|
||||
class SemNoReason = Reason::Make<Param>::SemNoReason;
|
||||
|
||||
class SemCondReason = Reason::Make<Param>::SemCondReason;
|
||||
|
||||
class SemTypeReason = Reason::Make<Param>::SemTypeReason;
|
||||
|
||||
/**
|
||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
@@ -94,7 +110,7 @@ module CppLangImplRelative implements LangSig<FloatDelta> {
|
||||
/**
|
||||
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
|
||||
*/
|
||||
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
|
||||
predicate hasConstantBound(SemExpr e, float bound, boolean upper, SemReason reason) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
|
||||
|
||||
@@ -113,6 +113,37 @@ signature module DeltaSig {
|
||||
}
|
||||
|
||||
signature module LangSig<DeltaSig D> {
|
||||
/** A reason for an inferred bound. */
|
||||
class SemReason {
|
||||
/**
|
||||
* Returns `this` if `reason` is not a `SemTypeReason`. Otherwise,
|
||||
* this predicate returns `SemTypeReason`.
|
||||
*
|
||||
* This predicate ensures that we propagate `SemTypeReason` all the way
|
||||
* to the top-level of a call to `semBounded` if the inferred bound is
|
||||
* based on type-information.
|
||||
*/
|
||||
bindingset[this, reason]
|
||||
SemReason combineWith(SemReason reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* A reason for an inferred bound that indicates that the bound is inferred
|
||||
* without going through a bounding condition.
|
||||
*/
|
||||
class SemNoReason extends SemReason;
|
||||
|
||||
/** A reason for an inferred bound pointing to a condition. */
|
||||
class SemCondReason extends SemReason {
|
||||
SemGuard getCond();
|
||||
}
|
||||
|
||||
/**
|
||||
* A reason for an inferred bound that indicates that the bound is inferred
|
||||
* based on type-information.
|
||||
*/
|
||||
class SemTypeReason extends SemReason;
|
||||
|
||||
/**
|
||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
@@ -124,7 +155,7 @@ signature module LangSig<DeltaSig D> {
|
||||
/**
|
||||
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
|
||||
*/
|
||||
predicate hasConstantBound(SemExpr e, D::Delta bound, boolean upper);
|
||||
predicate hasConstantBound(SemExpr e, D::Delta bound, boolean upper, SemReason reason);
|
||||
|
||||
/**
|
||||
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
|
||||
@@ -249,6 +280,14 @@ module RangeStage<
|
||||
DeltaSig D, BoundSig<D> Bounds, OverflowSig<D> OverflowParam, LangSig<D> LangParam,
|
||||
UtilSig<D> UtilParam>
|
||||
{
|
||||
class SemReason = LangParam::SemReason;
|
||||
|
||||
class SemCondReason = LangParam::SemCondReason;
|
||||
|
||||
class SemNoReason = LangParam::SemNoReason;
|
||||
|
||||
class SemTypeReason = LangParam::SemTypeReason;
|
||||
|
||||
private import Bounds
|
||||
private import LangParam
|
||||
private import UtilParam
|
||||
@@ -509,36 +548,6 @@ module RangeStage<
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TSemReason =
|
||||
TSemNoReason() or
|
||||
TSemCondReason(SemGuard guard) { possibleReason(guard) }
|
||||
|
||||
/**
|
||||
* A reason for an inferred bound. This can either be `CondReason` if the bound
|
||||
* is due to a specific condition, or `NoReason` if the bound is inferred
|
||||
* without going through a bounding condition.
|
||||
*/
|
||||
abstract class SemReason extends TSemReason {
|
||||
/** Gets a textual representation of this reason. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A reason for an inferred bound that indicates that the bound is inferred
|
||||
* without going through a bounding condition.
|
||||
*/
|
||||
class SemNoReason extends SemReason, TSemNoReason {
|
||||
override string toString() { result = "NoReason" }
|
||||
}
|
||||
|
||||
/** A reason for an inferred bound pointing to a condition. */
|
||||
class SemCondReason extends SemReason, TSemCondReason {
|
||||
/** Gets the condition that is the reason for the bound. */
|
||||
SemGuard getCond() { this = TSemCondReason(result) }
|
||||
|
||||
override string toString() { result = this.getCond().toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e + delta` is a valid bound for `v` at `pos`.
|
||||
* - `upper = true` : `v <= e + delta`
|
||||
@@ -551,13 +560,13 @@ module RangeStage<
|
||||
semSsaUpdateStep(v, e, delta) and
|
||||
pos.hasReadOfVar(v) and
|
||||
(upper = true or upper = false) and
|
||||
reason = TSemNoReason()
|
||||
reason instanceof SemNoReason
|
||||
or
|
||||
exists(SemGuard guard, boolean testIsTrue |
|
||||
pos.hasReadOfVar(v) and
|
||||
guard = boundFlowCond(v, e, delta, upper, testIsTrue) and
|
||||
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue) and
|
||||
reason = TSemCondReason(guard)
|
||||
reason.(SemCondReason).getCond() = guard
|
||||
)
|
||||
}
|
||||
|
||||
@@ -570,7 +579,7 @@ module RangeStage<
|
||||
pos.hasReadOfVar(v) and
|
||||
guard = semEqFlowCond(v, e, delta, false, testIsTrue) and
|
||||
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue) and
|
||||
reason = TSemCondReason(guard)
|
||||
reason.(SemCondReason).getCond() = guard
|
||||
)
|
||||
}
|
||||
|
||||
@@ -700,7 +709,7 @@ module RangeStage<
|
||||
// upper = true: v <= mid + d1 <= b + d1 + d2 = b + delta
|
||||
// upper = false: v >= mid + d1 >= b + d1 + d2 = b + delta
|
||||
delta = D::fromFloat(D::toFloat(d1) + D::toFloat(d2)) and
|
||||
(if r1 instanceof SemNoReason then reason = r2 else reason = r1)
|
||||
(if r1 instanceof SemNoReason then reason = r2 else reason = r1.combineWith(r2))
|
||||
)
|
||||
or
|
||||
exists(D::Delta d, SemReason r1, SemReason r2 |
|
||||
@@ -714,9 +723,9 @@ module RangeStage<
|
||||
upper = false and delta = D::fromFloat(D::toFloat(d) + 1)
|
||||
) and
|
||||
(
|
||||
reason = r1
|
||||
reason = r1.combineWith(r2)
|
||||
or
|
||||
reason = r2 and not r2 instanceof SemNoReason
|
||||
reason = r2.combineWith(r1) and not r2 instanceof SemNoReason
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -786,7 +795,7 @@ module RangeStage<
|
||||
(upper = true or upper = false) and
|
||||
fromBackEdge0 = false and
|
||||
origdelta = D::fromFloat(0) and
|
||||
reason = TSemNoReason()
|
||||
reason instanceof SemNoReason
|
||||
|
|
||||
if semBackEdge(phi, inp, edge)
|
||||
then
|
||||
@@ -911,14 +920,15 @@ module RangeStage<
|
||||
* Holds if `e` has an upper (for `upper = true`) or lower
|
||||
* (for `upper = false`) bound of `b`.
|
||||
*/
|
||||
private predicate baseBound(SemExpr e, D::Delta b, boolean upper) {
|
||||
hasConstantBound(e, b, upper)
|
||||
private predicate baseBound(SemExpr e, D::Delta b, boolean upper, SemReason reason) {
|
||||
hasConstantBound(e, b, upper, reason)
|
||||
or
|
||||
upper = false and
|
||||
b = D::fromInt(0) and
|
||||
semPositive(e.(SemBitAndExpr).getAnOperand()) and
|
||||
// REVIEW: We let the language opt out here to preserve original results.
|
||||
not ignoreZeroLowerBound(e)
|
||||
not ignoreZeroLowerBound(e) and
|
||||
reason instanceof SemNoReason
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1044,13 +1054,12 @@ module RangeStage<
|
||||
(upper = true or upper = false) and
|
||||
fromBackEdge = false and
|
||||
origdelta = delta and
|
||||
reason = TSemNoReason()
|
||||
reason instanceof SemNoReason
|
||||
or
|
||||
baseBound(e, delta, upper) and
|
||||
baseBound(e, delta, upper, reason) and
|
||||
b instanceof SemZeroBound and
|
||||
fromBackEdge = false and
|
||||
origdelta = delta and
|
||||
reason = TSemNoReason()
|
||||
origdelta = delta
|
||||
or
|
||||
exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
|
||||
boundedSsa(v, bb, b, delta, upper, fromBackEdge, origdelta, reason) and
|
||||
@@ -1104,9 +1113,9 @@ module RangeStage<
|
||||
boundedConditionalExpr(cond, b, upper, true, d1, fbe1, od1, r1) and
|
||||
boundedConditionalExpr(cond, b, upper, false, d2, fbe2, od2, r2) and
|
||||
(
|
||||
delta = d1 and fromBackEdge = fbe1 and origdelta = od1 and reason = r1
|
||||
delta = d1 and fromBackEdge = fbe1 and origdelta = od1 and reason = r1.combineWith(r2)
|
||||
or
|
||||
delta = d2 and fromBackEdge = fbe2 and origdelta = od2 and reason = r2
|
||||
delta = d2 and fromBackEdge = fbe2 and origdelta = od2 and reason = r2.combineWith(r1)
|
||||
)
|
||||
|
|
||||
upper = true and delta = D::fromFloat(D::toFloat(d1).maximum(D::toFloat(d2)))
|
||||
@@ -1132,9 +1141,15 @@ module RangeStage<
|
||||
delta = D::fromFloat(D::toFloat(dLeft) + D::toFloat(dRight)) and
|
||||
fromBackEdge = fbeLeft.booleanOr(fbeRight)
|
||||
|
|
||||
b = bLeft and origdelta = odLeft and reason = rLeft and bRight instanceof SemZeroBound
|
||||
b = bLeft and
|
||||
origdelta = odLeft and
|
||||
reason = rLeft.combineWith(rRight) and
|
||||
bRight instanceof SemZeroBound
|
||||
or
|
||||
b = bRight and origdelta = odRight and reason = rRight and bLeft instanceof SemZeroBound
|
||||
b = bRight and
|
||||
origdelta = odRight and
|
||||
reason = rRight.combineWith(rLeft) and
|
||||
bLeft instanceof SemZeroBound
|
||||
)
|
||||
or
|
||||
exists(
|
||||
@@ -1150,9 +1165,9 @@ module RangeStage<
|
||||
(
|
||||
if D::toFloat(d1).abs() > D::toFloat(d2).abs()
|
||||
then (
|
||||
d_max = d1 and fromBackEdge = fbe1 and origdelta = od1 and reason = r1
|
||||
d_max = d1 and fromBackEdge = fbe1 and origdelta = od1 and reason = r1.combineWith(r2)
|
||||
) else (
|
||||
d_max = d2 and fromBackEdge = fbe2 and origdelta = od2 and reason = r2
|
||||
d_max = d2 and fromBackEdge = fbe2 and origdelta = od2 and reason = r2.combineWith(r1)
|
||||
)
|
||||
)
|
||||
|
|
||||
@@ -1168,11 +1183,14 @@ module RangeStage<
|
||||
boundedMulOperand(e, upper, true, dLeft, fbeLeft, odLeft, rLeft) and
|
||||
boundedMulOperand(e, upper, false, dRight, fbeRight, odRight, rRight) and
|
||||
delta = D::fromFloat(D::toFloat(dLeft) * D::toFloat(dRight)) and
|
||||
fromBackEdge = fbeLeft.booleanOr(fbeRight)
|
||||
fromBackEdge = fbeLeft.booleanOr(fbeRight) and
|
||||
b instanceof SemZeroBound
|
||||
|
|
||||
b instanceof SemZeroBound and origdelta = odLeft and reason = rLeft
|
||||
origdelta = odLeft and
|
||||
reason = rLeft.combineWith(rRight)
|
||||
or
|
||||
b instanceof SemZeroBound and origdelta = odRight and reason = rRight
|
||||
origdelta = odRight and
|
||||
reason = rRight.combineWith(rLeft)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Provides a `Make` parameterized module for constructing a `Reason` type that is used
|
||||
* when implementing the `LangSig` module.
|
||||
*/
|
||||
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
|
||||
/** The necessary parameters that must be implemented to instantiate `Make`. */
|
||||
signature module ParamSig {
|
||||
class TypeReasonImpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* The module that constructs a `Reason` type when provided with an implementation
|
||||
* of `ParamSig`.
|
||||
*/
|
||||
module Make<ParamSig Param> {
|
||||
private import Param
|
||||
|
||||
private newtype TSemReason =
|
||||
TSemNoReason() or
|
||||
TSemCondReason(SemGuard guard) or
|
||||
TSemTypeReason(TypeReasonImpl trc)
|
||||
|
||||
/**
|
||||
* A reason for an inferred bound. This can either be `CondReason` if the bound
|
||||
* is due to a specific condition, or `NoReason` if the bound is inferred
|
||||
* without going through a bounding condition.
|
||||
*/
|
||||
abstract class SemReason extends TSemReason {
|
||||
/** Gets a textual representation of this reason. */
|
||||
abstract string toString();
|
||||
|
||||
bindingset[this, reason]
|
||||
abstract SemReason combineWith(SemReason reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* A reason for an inferred bound that indicates that the bound is inferred
|
||||
* without going through a bounding condition.
|
||||
*/
|
||||
class SemNoReason extends SemReason, TSemNoReason {
|
||||
override string toString() { result = "NoReason" }
|
||||
|
||||
override SemReason combineWith(SemReason reason) { result = reason }
|
||||
}
|
||||
|
||||
/** A reason for an inferred bound pointing to a condition. */
|
||||
class SemCondReason extends SemReason, TSemCondReason {
|
||||
/** Gets the condition that is the reason for the bound. */
|
||||
SemGuard getCond() { this = TSemCondReason(result) }
|
||||
|
||||
override string toString() { result = this.getCond().toString() }
|
||||
|
||||
bindingset[this, reason]
|
||||
override SemReason combineWith(SemReason reason) {
|
||||
// Since we end up reporting a `SemReason` for the inferred bound we often pick somewhat
|
||||
// arbitrarily between two `SemReason`s during the analysis. This isn't an issue for most reasons
|
||||
// since they're mainly used for constructing alert messages. However, the `SemTypeReason` is
|
||||
// supposed to be used in query logic to filter out bounds inferred by type-based analysis if
|
||||
// the query author chooses to do so. So we need to ensure that if _any_ of the bounds that
|
||||
// contribute to the final bound depends on type information then the `SemReason` we report must
|
||||
// be a `SemTypeReason`. So when we need to combine this `SemCondReason` with a `SemTypeReason`
|
||||
// the result should always be a `SemTypeReason`.
|
||||
if reason instanceof SemTypeReason then result instanceof SemTypeReason else result = this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A reason for an inferred bound that indicates that the bound is inferred
|
||||
* based on type-information.
|
||||
*/
|
||||
class SemTypeReason extends SemReason, TSemTypeReason {
|
||||
TypeReasonImpl impl;
|
||||
|
||||
SemTypeReason() { this = TSemTypeReason(impl) }
|
||||
|
||||
override string toString() { result = "TypeReason" }
|
||||
|
||||
bindingset[this, reason]
|
||||
override SemReason combineWith(SemReason reason) { result = this and exists(reason) }
|
||||
}
|
||||
}
|
||||
@@ -171,11 +171,9 @@ private predicate invalidPointerToDerefSource(
|
||||
// `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(allocSource, pai, _, rhsSizeDelta) and
|
||||
// pai <= derefSource + deltaDerefSourceAndPai and deltaDerefSourceAndPai <= 0 is equivalent to
|
||||
// derefSource >= pai + deltaDerefSourceAndPai and deltaDerefSourceAndPai >= 0
|
||||
bounded1(pai, derefSource.asInstruction(), deltaDerefSourceAndPai) and
|
||||
deltaDerefSourceAndPai <= 0 and
|
||||
// TODO: This condition will go away once #13725 is merged, and then we can make `Barrier2`
|
||||
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::SizeBarrier::getABarrierBlock(rhsSizeDelta)
|
||||
|
||||
@@ -20,7 +20,8 @@ private Instruction getABoundIn(SemBound b, IRFunction func) {
|
||||
pragma[inline]
|
||||
private predicate boundedImpl(Instruction i, Instruction b, int delta) {
|
||||
exists(SemBound bound, IRFunction func |
|
||||
semBounded(getSemanticExpr(i), bound, delta, true, _) and
|
||||
semBounded(getSemanticExpr(i), bound, delta, true,
|
||||
any(SemReason reason | not reason instanceof SemTypeReason)) and
|
||||
b = getABoundIn(bound, func) and
|
||||
i.getEnclosingIRFunction() = func
|
||||
)
|
||||
@@ -35,5 +36,14 @@ bindingset[i]
|
||||
pragma[inline_late]
|
||||
predicate bounded1(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
|
||||
|
||||
/**
|
||||
* Holds if `i <= b + delta`.
|
||||
*
|
||||
* This predicate enforces a join-order that ensures that `b` has already been bound.
|
||||
*/
|
||||
bindingset[b]
|
||||
pragma[inline_late]
|
||||
predicate bounded2(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
|
||||
|
||||
/** Holds if `i <= b + delta`. */
|
||||
predicate bounded = boundedImpl/3;
|
||||
|
||||
@@ -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,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
|
||||
...
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@ Instruction getABoundIn(SemBound b, IRFunction func) {
|
||||
pragma[inline]
|
||||
predicate boundedImpl(Instruction i, Instruction b, int delta) {
|
||||
exists(SemBound bound, IRFunction func |
|
||||
semBounded(getSemanticExpr(i), bound, delta, true, _) and
|
||||
semBounded(getSemanticExpr(i), bound, delta, true,
|
||||
any(SemReason reason | not reason instanceof SemTypeReason)) and
|
||||
b = getABoundIn(bound, func) and
|
||||
pragma[only_bind_out](i.getEnclosingIRFunction()) = func
|
||||
)
|
||||
@@ -93,7 +94,8 @@ predicate arrayTypeHasSizes(ArrayType arr, int baseTypeSize, int size) {
|
||||
bindingset[pai]
|
||||
pragma[inline_late]
|
||||
predicate constantUpperBounded(PointerArithmeticInstruction pai, int delta) {
|
||||
semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), delta, true, _)
|
||||
semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), delta, true,
|
||||
any(SemReason reason | not reason instanceof SemTypeReason))
|
||||
}
|
||||
|
||||
bindingset[pai, size]
|
||||
|
||||
@@ -132,6 +132,8 @@ edges
|
||||
| test.cpp:304:15:304:26 | new[] | test.cpp:308:5:308:29 | ... = ... |
|
||||
| test.cpp:355:14:355:27 | new[] | test.cpp:356:15:356:23 | ... + ... |
|
||||
| test.cpp:355:14:355:27 | new[] | test.cpp:356:15:356:23 | ... + ... |
|
||||
| test.cpp:355:14:355:27 | new[] | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:355:14:355:27 | new[] | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:355:14:355:27 | new[] | test.cpp:358:14:358:26 | * ... |
|
||||
| test.cpp:355:14:355:27 | new[] | test.cpp:359:14:359:32 | * ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:356:15:356:23 | ... + ... |
|
||||
@@ -139,46 +141,93 @@ edges
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:358:14:358:26 | * ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | * ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | * ... |
|
||||
| test.cpp:377:14:377:27 | new[] | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:377:14:377:27 | new[] | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:377:14:377:27 | new[] | test.cpp:381:5:381:9 | ... ++ |
|
||||
| test.cpp:377:14:377:27 | new[] | test.cpp:381:5:381:9 | ... ++ |
|
||||
| test.cpp:377:14:377:27 | new[] | test.cpp:384:13:384:16 | * ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | * ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | * ... |
|
||||
| test.cpp:381:5:381:9 | ... ++ | test.cpp:381:5:381:9 | ... ++ |
|
||||
| test.cpp:381:5:381:9 | ... ++ | test.cpp:384:13:384:16 | * ... |
|
||||
| test.cpp:410:14:410:27 | new[] | test.cpp:411:15:411:23 | & ... |
|
||||
| test.cpp:410:14:410:27 | new[] | test.cpp:411:15:411:23 | & ... |
|
||||
| test.cpp:410:14:410:27 | new[] | test.cpp:413:5:413:8 | ... ++ |
|
||||
| test.cpp:410:14:410:27 | new[] | test.cpp:413:5:413:8 | ... ++ |
|
||||
| test.cpp:410:14:410:27 | new[] | test.cpp:415:7:415:15 | ... = ... |
|
||||
| test.cpp:411:15:411:23 | & ... | test.cpp:411:15:411:23 | & ... |
|
||||
| test.cpp:411:15:411:23 | & ... | test.cpp:415:7:415:15 | ... = ... |
|
||||
| test.cpp:411:15:411:23 | & ... | test.cpp:415:7:415:15 | ... = ... |
|
||||
| test.cpp:413:5:413:8 | ... ++ | test.cpp:413:5:413:8 | ... ++ |
|
||||
| test.cpp:413:5:413:8 | ... ++ | test.cpp:415:7:415:15 | ... = ... |
|
||||
| test.cpp:413:5:413:8 | ... ++ | test.cpp:415:7:415:15 | ... = ... |
|
||||
| test.cpp:421:14:421:27 | new[] | test.cpp:422:15:422:23 | & ... |
|
||||
| test.cpp:421:14:421:27 | new[] | test.cpp:422:15:422:23 | & ... |
|
||||
| test.cpp:421:14:421:27 | new[] | test.cpp:424:5:424:8 | ... ++ |
|
||||
| test.cpp:421:14:421:27 | new[] | test.cpp:424:5:424:8 | ... ++ |
|
||||
| test.cpp:421:14:421:27 | new[] | test.cpp:426:7:426:15 | ... = ... |
|
||||
| test.cpp:422:15:422:23 | & ... | test.cpp:422:15:422:23 | & ... |
|
||||
| test.cpp:422:15:422:23 | & ... | test.cpp:426:7:426:15 | ... = ... |
|
||||
| test.cpp:422:15:422:23 | & ... | test.cpp:426:7:426:15 | ... = ... |
|
||||
| test.cpp:424:5:424:8 | ... ++ | test.cpp:424:5:424:8 | ... ++ |
|
||||
| test.cpp:424:5:424:8 | ... ++ | test.cpp:426:7:426:15 | ... = ... |
|
||||
| test.cpp:424:5:424:8 | ... ++ | test.cpp:426:7:426:15 | ... = ... |
|
||||
| test.cpp:432:14:432:27 | new[] | test.cpp:433:15:433:23 | & ... |
|
||||
| test.cpp:432:14:432:27 | new[] | test.cpp:433:15:433:23 | & ... |
|
||||
| test.cpp:432:14:432:27 | new[] | test.cpp:436:5:436:8 | ... ++ |
|
||||
| test.cpp:432:14:432:27 | new[] | test.cpp:436:5:436:8 | ... ++ |
|
||||
| test.cpp:432:14:432:27 | new[] | test.cpp:438:7:438:15 | ... = ... |
|
||||
| test.cpp:433:15:433:23 | & ... | test.cpp:433:15:433:23 | & ... |
|
||||
| test.cpp:433:15:433:23 | & ... | test.cpp:438:7:438:15 | ... = ... |
|
||||
| test.cpp:433:15:433:23 | & ... | test.cpp:438:7:438:15 | ... = ... |
|
||||
| test.cpp:436:5:436:8 | ... ++ | test.cpp:436:5:436:8 | ... ++ |
|
||||
| test.cpp:436:5:436:8 | ... ++ | test.cpp:438:7:438:15 | ... = ... |
|
||||
| test.cpp:436:5:436:8 | ... ++ | test.cpp:438:7:438:15 | ... = ... |
|
||||
| test.cpp:444:14:444:27 | new[] | test.cpp:445:15:445:23 | & ... |
|
||||
| test.cpp:444:14:444:27 | new[] | test.cpp:445:15:445:23 | & ... |
|
||||
| test.cpp:444:14:444:27 | new[] | test.cpp:448:5:448:8 | ... ++ |
|
||||
| test.cpp:444:14:444:27 | new[] | test.cpp:448:5:448:8 | ... ++ |
|
||||
| test.cpp:444:14:444:27 | new[] | test.cpp:450:7:450:15 | ... = ... |
|
||||
| test.cpp:445:15:445:23 | & ... | test.cpp:445:15:445:23 | & ... |
|
||||
| test.cpp:445:15:445:23 | & ... | test.cpp:450:7:450:15 | ... = ... |
|
||||
| test.cpp:445:15:445:23 | & ... | test.cpp:450:7:450:15 | ... = ... |
|
||||
| test.cpp:448:5:448:8 | ... ++ | test.cpp:448:5:448:8 | ... ++ |
|
||||
| test.cpp:448:5:448:8 | ... ++ | test.cpp:450:7:450:15 | ... = ... |
|
||||
| test.cpp:448:5:448:8 | ... ++ | test.cpp:450:7:450:15 | ... = ... |
|
||||
| test.cpp:480:14:480:27 | new[] | test.cpp:481:15:481:23 | & ... |
|
||||
| test.cpp:480:14:480:27 | new[] | test.cpp:481:15:481:23 | & ... |
|
||||
| test.cpp:480:14:480:27 | new[] | test.cpp:484:5:484:8 | ... ++ |
|
||||
| test.cpp:480:14:480:27 | new[] | test.cpp:484:5:484:8 | ... ++ |
|
||||
| test.cpp:480:14:480:27 | new[] | test.cpp:486:7:486:15 | ... = ... |
|
||||
| test.cpp:481:15:481:23 | & ... | test.cpp:481:15:481:23 | & ... |
|
||||
| test.cpp:481:15:481:23 | & ... | test.cpp:486:7:486:15 | ... = ... |
|
||||
| test.cpp:481:15:481:23 | & ... | test.cpp:486:7:486:15 | ... = ... |
|
||||
| test.cpp:484:5:484:8 | ... ++ | test.cpp:484:5:484:8 | ... ++ |
|
||||
| test.cpp:484:5:484:8 | ... ++ | test.cpp:486:7:486:15 | ... = ... |
|
||||
| test.cpp:484:5:484:8 | ... ++ | test.cpp:486:7:486:15 | ... = ... |
|
||||
| test.cpp:543:14:543:27 | new[] | test.cpp:548:5:548:19 | ... = ... |
|
||||
| test.cpp:554:14:554:27 | new[] | test.cpp:559:5:559:19 | ... = ... |
|
||||
| test.cpp:642:14:642:31 | new[] | test.cpp:647:5:647:19 | ... = ... |
|
||||
| test.cpp:652:14:652:27 | new[] | test.cpp:656:3:656:6 | ... ++ |
|
||||
| test.cpp:652:14:652:27 | new[] | test.cpp:656:3:656:6 | ... ++ |
|
||||
| test.cpp:652:14:652:27 | new[] | test.cpp:662:3:662:11 | ... = ... |
|
||||
| test.cpp:656:3:656:6 | ... ++ | test.cpp:656:3:656:6 | ... ++ |
|
||||
| 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 | ... + ... |
|
||||
@@ -276,31 +325,45 @@ nodes
|
||||
| test.cpp:355:14:355:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:358:14:358:26 | * ... | semmle.label | * ... |
|
||||
| test.cpp:359:14:359:32 | * ... | semmle.label | * ... |
|
||||
| test.cpp:377:14:377:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:381:5:381:9 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:381:5:381:9 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:384:13:384:16 | * ... | semmle.label | * ... |
|
||||
| test.cpp:410:14:410:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:411:15:411:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:411:15:411:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:413:5:413:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:413:5:413:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:415:7:415:15 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:421:14:421:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:422:15:422:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:422:15:422:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:424:5:424:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:424:5:424:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:426:7:426:15 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:432:14:432:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:433:15:433:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:433:15:433:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:436:5:436:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:436:5:436:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:438:7:438:15 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:444:14:444:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:445:15:445:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:445:15:445:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:448:5:448:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:448:5:448:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:450:7:450:15 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:480:14:480:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:481:15:481:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:481:15:481:23 | & ... | semmle.label | & ... |
|
||||
| test.cpp:484:5:484:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:484:5:484:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:486:7:486:15 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:543:14:543:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:548:5:548:19 | ... = ... | semmle.label | ... = ... |
|
||||
@@ -308,8 +371,20 @@ nodes
|
||||
| test.cpp:559:5:559:19 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:642:14:642:31 | new[] | semmle.label | new[] |
|
||||
| test.cpp:647:5:647:19 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:652:14:652:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:656:3:656:6 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:656:3:656:6 | ... ++ | semmle.label | ... ++ |
|
||||
| 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 |
|
||||
@@ -343,4 +418,7 @@ subpaths
|
||||
| test.cpp:548:5:548:19 | ... = ... | test.cpp:543:14:543:27 | new[] | test.cpp:548:5:548:19 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:543:14:543:27 | new[] | new[] | test.cpp:548:8:548:14 | src_pos | src_pos |
|
||||
| test.cpp:559:5:559:19 | ... = ... | test.cpp:554:14:554:27 | new[] | test.cpp:559:5:559:19 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:554:14:554:27 | new[] | new[] | test.cpp:559:8:559:14 | src_pos | src_pos |
|
||||
| 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 |
|
||||
|
||||
@@ -17,7 +17,7 @@ void test2(int size) {
|
||||
char* q = p + size - 1; // $ alloc=L16
|
||||
char a = *q; // GOOD
|
||||
char b = *(q - 1); // GOOD
|
||||
char c = *(q + 1); // $ deref=L17->L20 // BAD
|
||||
char c = *(q + 1); // $ deref=L20 // BAD
|
||||
char d = *(q + size); // BAD [NOT DETECTED]
|
||||
char e = *(q - size); // GOOD
|
||||
char f = *(q + size + 1); // BAD [NOT DETECTED]
|
||||
@@ -198,7 +198,7 @@ void test12(unsigned len, unsigned index) {
|
||||
return;
|
||||
}
|
||||
|
||||
p[index] = '\0'; // $ deref=L195->L201 deref=L197->L201 // BAD
|
||||
p[index] = '\0'; // $ deref=L201 // BAD
|
||||
}
|
||||
|
||||
void test13(unsigned len, unsigned index) {
|
||||
@@ -210,7 +210,7 @@ void test13(unsigned len, unsigned index) {
|
||||
return;
|
||||
}
|
||||
|
||||
*q = '\0'; // $ deref=L206->L213 deref=L209->L213 // BAD
|
||||
*q = '\0'; // $ deref=L213 // BAD
|
||||
}
|
||||
|
||||
bool unknown();
|
||||
@@ -261,7 +261,7 @@ void test17(unsigned len)
|
||||
int *end = xs + len; // $ alloc=L260
|
||||
for (int *x = xs; x <= end; x++)
|
||||
{
|
||||
int i = *x; // $ deref=L261->L264 deref=L262->L264 // BAD
|
||||
int i = *x; // $ deref=L264 // BAD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ void test18(unsigned len)
|
||||
int *end = xs + len; // $ alloc=L270
|
||||
for (int *x = xs; x <= end; x++)
|
||||
{
|
||||
*x = 0; // $ deref=L271->L274 deref=L272->L274 // BAD
|
||||
*x = 0; // $ deref=L274 // BAD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,8 +355,8 @@ void test25(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = xs + size; // $ alloc=L355
|
||||
char *end_plus_one = end + 1;
|
||||
int val1 = *end_plus_one; // $ deref=L356->L358+1 deref=L357->L358+1 // BAD
|
||||
int val2 = *(end_plus_one + 1); // $ deref=L356->L359+2 deref=L357->L359+2 // BAD
|
||||
int val1 = *end_plus_one; // $ deref=L358+1 // BAD
|
||||
int val2 = *(end_plus_one + 1); // $ deref=L359+2 // BAD
|
||||
}
|
||||
|
||||
void test26(unsigned size) {
|
||||
@@ -381,7 +381,7 @@ void test27(unsigned size, bool b) {
|
||||
end++;
|
||||
}
|
||||
|
||||
int val = *end; // $ deref=L378->L384+1 deref=L381->L384+1 // BAD
|
||||
int val = *end; // $ deref=L384+1 // BAD
|
||||
}
|
||||
|
||||
void test28(unsigned size) {
|
||||
@@ -412,7 +412,7 @@ void test28_simple2(unsigned size) {
|
||||
if (xs < end) {
|
||||
xs++;
|
||||
if (xs < end + 1) {
|
||||
xs[0] = 0; // $ deref=L411->L415 deref=L412->L415 deref=L414->L415 // BAD
|
||||
xs[0] = 0; // $ deref=L415 // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -423,7 +423,7 @@ void test28_simple3(unsigned size) {
|
||||
if (xs < end) {
|
||||
xs++;
|
||||
if (xs - 1 < end) {
|
||||
xs[0] = 0; // $ deref=L422->L426 deref=L423->L426 deref=L425->L426 // BAD
|
||||
xs[0] = 0; // $ deref=L426 // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -435,7 +435,7 @@ void test28_simple4(unsigned size) {
|
||||
end++;
|
||||
xs++;
|
||||
if (xs < end) {
|
||||
xs[0] = 0; // $ deref=L433->L438 deref=L434->L438 deref=L435->L438 // BAD
|
||||
xs[0] = 0; // $ deref=L438 // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -447,7 +447,7 @@ void test28_simple5(unsigned size) {
|
||||
if (xs < end) {
|
||||
xs++;
|
||||
if (xs < end) {
|
||||
xs[0] = 0; // $ deref=L445->L450 deref=L446->L450 // BAD
|
||||
xs[0] = 0; // $ deref=L450 // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -483,7 +483,7 @@ void test28_simple8(unsigned size) {
|
||||
if (xs < end) {
|
||||
xs++;
|
||||
if (xs < end - 1) {
|
||||
xs[0] = 0; // $ deref=L481->L486+498 deref=L482->L486+498 // BAD
|
||||
xs[0] = 0; // $ deref=L486+498 // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -659,7 +659,7 @@ void test32(unsigned size) {
|
||||
xs++;
|
||||
if (xs >= end)
|
||||
return;
|
||||
xs[0] = 0; // $ GOOD
|
||||
xs[0] = 0; // $ deref=L656->L662+1 deref=L657->L662+1 GOOD [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
void test33(unsigned size, unsigned src_pos)
|
||||
@@ -698,12 +698,12 @@ void test34(unsigned size) {
|
||||
p += 1;
|
||||
}
|
||||
if (p + 1 < end) {
|
||||
int val = *p; // GOOD
|
||||
int val = *p; // $ deref=L698->L700->L701 // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
void deref(char* q) {
|
||||
char x = *q; // $ MISSING: deref=L712->L706 deref=L713->L706
|
||||
char x = *q; // $ deref=L714->L705->L706 // BAD
|
||||
}
|
||||
|
||||
void test35(unsigned long size, char* 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>:
|
||||
@@ -15030,25 +15100,28 @@ ir.cpp:
|
||||
# 1999| Value = [Literal] 5
|
||||
# 1999| ValueCategory = prvalue
|
||||
# 2000| getStmt(3): [ExprStmt] ExprStmt
|
||||
# 2000| getExpr(): [ConditionalExpr] ... ? ... : ...
|
||||
# 2000| getExpr(): [AssignExpr] ... = ...
|
||||
# 2000| Type = [IntType] int
|
||||
# 2000| ValueCategory = lvalue
|
||||
# 2000| getCondition(): [VariableAccess] a
|
||||
# 2000| Type = [BoolType] bool
|
||||
# 2000| ValueCategory = prvalue(load)
|
||||
# 2000| getThen(): [VariableAccess] x
|
||||
# 2000| getLValue(): [ConditionalExpr] ... ? ... : ...
|
||||
# 2000| Type = [IntType] int
|
||||
# 2000| ValueCategory = lvalue
|
||||
# 2000| getElse(): [AssignExpr] ... = ...
|
||||
# 2000| Type = [IntType] int
|
||||
# 2000| ValueCategory = lvalue
|
||||
# 2000| getLValue(): [VariableAccess] y
|
||||
# 2000| getCondition(): [VariableAccess] a
|
||||
# 2000| Type = [BoolType] bool
|
||||
# 2000| ValueCategory = prvalue(load)
|
||||
# 2000| getThen(): [VariableAccess] x
|
||||
# 2000| Type = [IntType] int
|
||||
# 2000| ValueCategory = lvalue
|
||||
# 2000| getRValue(): [Literal] 7
|
||||
# 2000| getElse(): [VariableAccess] y
|
||||
# 2000| Type = [IntType] int
|
||||
# 2000| Value = [Literal] 7
|
||||
# 2000| ValueCategory = prvalue
|
||||
# 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>:
|
||||
@@ -15151,31 +15224,34 @@ ir.cpp:
|
||||
# 2010| getExpr(): [AssignExpr] ... = ...
|
||||
# 2010| Type = [Struct] TernaryPodObj
|
||||
# 2010| ValueCategory = lvalue
|
||||
# 2010| getLValue(): [VariableAccess] z
|
||||
# 2010| getLValue(): [AssignExpr] ... = ...
|
||||
# 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| getLValue(): [VariableAccess] z
|
||||
# 2010| Type = [Struct] TernaryPodObj
|
||||
# 2010| ValueCategory = prvalue(load)
|
||||
# 2010| getElse(): [AssignExpr] ... = ...
|
||||
# 2010| ValueCategory = lvalue
|
||||
# 2010| getRValue(): [ConditionalExpr] ... ? ... : ...
|
||||
# 2010| Type = [Struct] TernaryPodObj
|
||||
# 2010| ValueCategory = prvalue
|
||||
# 2010| getLValue(): [VariableAccess] y
|
||||
# 2010| Type = [Struct] TernaryPodObj
|
||||
# 2010| ValueCategory = lvalue
|
||||
# 2010| getRValue(): [Literal] 0
|
||||
# 2010| Type = [Struct] TernaryPodObj
|
||||
# 2010| Value = [Literal] 0
|
||||
# 2010| ValueCategory = prvalue
|
||||
# 2010| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 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>:
|
||||
@@ -15339,38 +15415,38 @@ ir.cpp:
|
||||
# 2021| getExpr(): [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| getQualifier(): [FunctionCall] call to operator=
|
||||
# 2021| Type = [LValueReferenceType] TernaryNonPodObj &
|
||||
# 2021| ValueCategory = prvalue
|
||||
# 2021| getQualifier(): [VariableAccess] z
|
||||
# 2021| Type = [Struct] TernaryNonPodObj
|
||||
# 2021| ValueCategory = lvalue
|
||||
# 2021| getElse(): [FunctionCall] call to operator=
|
||||
# 2021| Type = [LValueReferenceType] TernaryNonPodObj &
|
||||
# 2021| ValueCategory = prvalue
|
||||
# 2021| getQualifier(): [VariableAccess] y
|
||||
# 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| getArgument(0): [ConstructorCall] call to TernaryNonPodObj
|
||||
# 2021| Type = [VoidType] void
|
||||
# 2021| ValueCategory = prvalue
|
||||
# 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| getElse().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 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)
|
||||
@@ -15380,10 +15456,86 @@ ir.cpp:
|
||||
# 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>:
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -1997,7 +1997,7 @@ 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;
|
||||
(a ? x : y) = 7;
|
||||
}
|
||||
|
||||
struct TernaryPodObj {
|
||||
@@ -2007,7 +2007,7 @@ 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();
|
||||
(z = a ? x : y) = TernaryPodObj();
|
||||
}
|
||||
|
||||
struct TernaryNonPodObj {
|
||||
@@ -2018,7 +2018,16 @@ void TernaryTestNonPodObj(bool a, TernaryNonPodObj x, TernaryNonPodObj y, Ternar
|
||||
z = a ? x : y;
|
||||
z = a ? x : TernaryNonPodObj();
|
||||
z = a ? TernaryNonPodObj() : TernaryNonPodObj();
|
||||
z = a ? x : y = 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
|
||||
|
||||
@@ -932,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 |
|
||||
@@ -9078,7 +9124,7 @@
|
||||
| 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 | m1996_3 |
|
||||
| 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 |
|
||||
@@ -9128,20 +9174,21 @@
|
||||
| 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:5 | Address | &:r2000_1 |
|
||||
| ir.cpp:2000:5:2000:5 | Condition | r2000_2 |
|
||||
| ir.cpp:2000:5:2000:5 | Load | m1996_6 |
|
||||
| ir.cpp:2000:5:2000:17 | Address | &:r2000_5 |
|
||||
| ir.cpp:2000:5:2000:17 | Address | &:r2000_8 |
|
||||
| ir.cpp:2000:5:2000:17 | Address | &:r2000_14 |
|
||||
| ir.cpp:2000:5:2000:17 | Load | m2000_4 |
|
||||
| ir.cpp:2000:5:2000:17 | Phi | from 11:m2000_9 |
|
||||
| ir.cpp:2000:5:2000:17 | Phi | from 12:m2000_15 |
|
||||
| ir.cpp:2000:9:2000:9 | StoreValue | r2000_7 |
|
||||
| ir.cpp:2000:13:2000:13 | Address | &:r2000_11 |
|
||||
| ir.cpp:2000:13:2000:13 | Unary | r2000_11 |
|
||||
| ir.cpp:2000:13:2000:17 | StoreValue | r2000_13 |
|
||||
| ir.cpp:2000:17:2000:17 | StoreValue | r2000_10 |
|
||||
| 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 |
|
||||
@@ -9218,28 +9265,30 @@
|
||||
| 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:5:2010:5 | Address | &:r2010_7 |
|
||||
| ir.cpp:2010:9:2010:9 | Address | &:r2010_1 |
|
||||
| ir.cpp:2010:9:2010:9 | Condition | r2010_2 |
|
||||
| ir.cpp:2010:9:2010:9 | Load | m2006_6 |
|
||||
| ir.cpp:2010:9:2010:35 | Address | &:r2010_5 |
|
||||
| ir.cpp:2010:9:2010:35 | Address | &:r2010_11 |
|
||||
| ir.cpp:2010:9:2010:35 | Address | &:r2010_20 |
|
||||
| ir.cpp:2010:9:2010:35 | Load | m2010_4 |
|
||||
| ir.cpp:2010:9:2010:35 | Phi | from 11:m2010_12 |
|
||||
| ir.cpp:2010:9:2010:35 | Phi | from 12:m2010_21 |
|
||||
| ir.cpp:2010:9:2010:35 | StoreValue | r2010_6 |
|
||||
| ir.cpp:2010:13:2010:13 | Address | &:r2010_9 |
|
||||
| ir.cpp:2010:13:2010:13 | Load | m2006_8 |
|
||||
| ir.cpp:2010:13:2010:13 | StoreValue | r2010_10 |
|
||||
| ir.cpp:2010:17:2010:17 | Address | &:r2010_17 |
|
||||
| ir.cpp:2010:17:2010:35 | StoreValue | r2010_19 |
|
||||
| ir.cpp:2010:21:2010:35 | Address | &:r2010_13 |
|
||||
| ir.cpp:2010:21:2010:35 | Address | &:r2010_13 |
|
||||
| ir.cpp:2010:21:2010:35 | Load | m2010_15 |
|
||||
| ir.cpp:2010:21:2010:35 | StoreValue | r2010_14 |
|
||||
| ir.cpp:2010:21:2010:35 | StoreValue | r2010_16 |
|
||||
| ir.cpp:2010:21:2010:35 | Unary | r2010_16 |
|
||||
| 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 |
|
||||
@@ -9280,7 +9329,7 @@
|
||||
| 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_14 |
|
||||
| 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 |
|
||||
@@ -9423,60 +9472,96 @@
|
||||
| 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:5 | Address | &:r2021_1 |
|
||||
| ir.cpp:2021:5:2021:5 | Address | &:r2021_1 |
|
||||
| ir.cpp:2021:5:2021:5 | Arg(this) | this:r2021_1 |
|
||||
| ir.cpp:2021:5:2021:5 | ChiPartial | partial:m2021_17 |
|
||||
| ir.cpp:2021:5:2021:5 | ChiTotal | total:m2020_20 |
|
||||
| ir.cpp:2021:5:2021:5 | SideEffect | m2020_20 |
|
||||
| ir.cpp:2021:7:2021:7 | CallTarget | func:r2021_2 |
|
||||
| ir.cpp:2021:7:2021:7 | ChiPartial | partial:m2021_13 |
|
||||
| ir.cpp:2021:7:2021:7 | ChiTotal | total:m2021_6 |
|
||||
| ir.cpp:2021:7:2021:7 | SideEffect | ~m2021_6 |
|
||||
| ir.cpp:2021:7:2021:7 | Unary | r2021_12 |
|
||||
| ir.cpp:2021:9:2021:9 | Address | &:r2021_3 |
|
||||
| ir.cpp:2021:9:2021:9 | Condition | r2021_4 |
|
||||
| ir.cpp:2021:9:2021:9 | Load | m2017_6 |
|
||||
| ir.cpp:2021:9:2021:38 | Address | &:r2021_8 |
|
||||
| ir.cpp:2021:9:2021:38 | Address | &:r2021_11 |
|
||||
| ir.cpp:2021:9:2021:38 | Address | &:r2021_21 |
|
||||
| ir.cpp:2021:9:2021:38 | Address | &:r2021_43 |
|
||||
| ir.cpp:2021:9:2021:38 | Arg(0) | 0:r2021_11 |
|
||||
| ir.cpp:2021:9:2021:38 | Load | m2021_7 |
|
||||
| ir.cpp:2021:9:2021:38 | Phi | from 11:m2021_22 |
|
||||
| ir.cpp:2021:9:2021:38 | Phi | from 11:~m2020_16 |
|
||||
| ir.cpp:2021:9:2021:38 | Phi | from 12:m2021_44 |
|
||||
| ir.cpp:2021:9:2021:38 | Phi | from 12:~m2021_37 |
|
||||
| ir.cpp:2021:9:2021:38 | SideEffect | ~m2021_14 |
|
||||
| ir.cpp:2021:9:2021:38 | Unary | r2021_9 |
|
||||
| ir.cpp:2021:9:2021:38 | Unary | r2021_10 |
|
||||
| ir.cpp:2021:13:2021:13 | StoreValue | r2021_20 |
|
||||
| ir.cpp:2021:17:2021:17 | Address | &:r2021_23 |
|
||||
| ir.cpp:2021:17:2021:17 | Address | &:r2021_23 |
|
||||
| ir.cpp:2021:17:2021:17 | Arg(this) | this:r2021_23 |
|
||||
| ir.cpp:2021:17:2021:17 | ChiPartial | partial:m2021_40 |
|
||||
| ir.cpp:2021:17:2021:17 | ChiTotal | total:m2017_10 |
|
||||
| ir.cpp:2021:17:2021:17 | SideEffect | m2017_10 |
|
||||
| ir.cpp:2021:19:2021:19 | CallTarget | func:r2021_24 |
|
||||
| ir.cpp:2021:19:2021:19 | ChiPartial | partial:m2021_36 |
|
||||
| ir.cpp:2021:19:2021:19 | ChiTotal | total:m2021_30 |
|
||||
| ir.cpp:2021:19:2021:19 | SideEffect | ~m2021_30 |
|
||||
| ir.cpp:2021:19:2021:19 | Unary | r2021_35 |
|
||||
| ir.cpp:2021:19:2021:39 | StoreValue | r2021_42 |
|
||||
| ir.cpp:2021:21:2021:38 | Address | &:r2021_25 |
|
||||
| ir.cpp:2021:21:2021:38 | Address | &:r2021_25 |
|
||||
| ir.cpp:2021:21:2021:38 | Address | &:r2021_34 |
|
||||
| ir.cpp:2021:21:2021:38 | Arg(0) | 0:r2021_34 |
|
||||
| ir.cpp:2021:21:2021:38 | Arg(this) | this:r2021_25 |
|
||||
| ir.cpp:2021:21:2021:38 | CallTarget | func:r2021_27 |
|
||||
| ir.cpp:2021:21:2021:38 | ChiPartial | partial:m2021_29 |
|
||||
| ir.cpp:2021:21:2021:38 | ChiPartial | partial:m2021_31 |
|
||||
| ir.cpp:2021:21:2021:38 | ChiTotal | total:m2020_16 |
|
||||
| ir.cpp:2021:21:2021:38 | ChiTotal | total:m2021_26 |
|
||||
| ir.cpp:2021:21:2021:38 | SideEffect | ~m2020_16 |
|
||||
| ir.cpp:2021:21:2021:38 | SideEffect | ~m2021_32 |
|
||||
| ir.cpp:2021:21:2021:38 | Unary | r2021_25 |
|
||||
| ir.cpp:2021:21:2021:38 | Unary | r2021_33 |
|
||||
| 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
|
||||
@@ -10529,9 +10571,10 @@ ir.cpp:
|
||||
# 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(glval<bool>) = VariableAddress[a] :
|
||||
# 2000| r2000_2(bool) = Load[a] : &:r2000_1, ~m?
|
||||
# 2000| v2000_3(void) = ConditionalBranch : r2000_2
|
||||
# 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
|
||||
|
||||
@@ -10548,26 +10591,24 @@ ir.cpp:
|
||||
#-----| Goto -> Block 7
|
||||
|
||||
# 2000| Block 10
|
||||
# 2000| r2000_4(glval<unknown>) = VariableAddress[#temp2000:5] :
|
||||
# 2000| r2000_5(glval<int>) = Load[#temp2000:5] : &:r2000_4, ~m?
|
||||
# 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_6(glval<int>) = VariableAddress[x] :
|
||||
# 2000| r2000_7(glval<unknown>) = VariableAddress[#temp2000:5] :
|
||||
# 2000| mu2000_8(glval<int>) = Store[#temp2000:5] : &:r2000_7, r2000_6
|
||||
# 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_9(int) = Constant[7] :
|
||||
# 2000| r2000_10(glval<int>) = VariableAddress[y] :
|
||||
# 2000| mu2000_11(int) = Store[y] : &:r2000_10, r2000_9
|
||||
# 2000| r2000_12(glval<int>) = CopyValue : r2000_10
|
||||
# 2000| r2000_13(glval<unknown>) = VariableAddress[#temp2000:5] :
|
||||
# 2000| mu2000_14(glval<int>) = Store[#temp2000:5] : &:r2000_13, r2000_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)
|
||||
@@ -10649,15 +10690,19 @@ ir.cpp:
|
||||
#-----| 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<bool>) = VariableAddress[a] :
|
||||
# 2010| r2010_2(bool) = Load[a] : &:r2010_1, ~m?
|
||||
# 2010| v2010_3(void) = ConditionalBranch : r2010_2
|
||||
# 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
|
||||
|
||||
@@ -10680,32 +10725,29 @@ ir.cpp:
|
||||
#-----| Goto -> Block 7
|
||||
|
||||
# 2010| Block 10
|
||||
# 2010| r2010_4(glval<TernaryPodObj>) = VariableAddress[#temp2010:9] :
|
||||
# 2010| r2010_5(TernaryPodObj) = Load[#temp2010:9] : &:r2010_4, ~m?
|
||||
# 2010| r2010_6(glval<TernaryPodObj>) = VariableAddress[z] :
|
||||
# 2010| mu2010_7(TernaryPodObj) = Store[z] : &:r2010_6, r2010_5
|
||||
# 2011| v2011_1(void) = NoOp :
|
||||
# 2006| v2006_12(void) = ReturnVoid :
|
||||
# 2006| v2006_13(void) = AliasedUse : ~m?
|
||||
# 2006| v2006_14(void) = ExitFunction :
|
||||
# 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_8(glval<TernaryPodObj>) = VariableAddress[x] :
|
||||
# 2010| r2010_9(TernaryPodObj) = Load[x] : &:r2010_8, ~m?
|
||||
# 2010| r2010_10(glval<TernaryPodObj>) = VariableAddress[#temp2010:9] :
|
||||
# 2010| mu2010_11(TernaryPodObj) = Store[#temp2010:9] : &:r2010_10, r2010_9
|
||||
# 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_12(glval<TernaryPodObj>) = VariableAddress[#temp2010:21] :
|
||||
# 2010| r2010_13(TernaryPodObj) = Constant[0] :
|
||||
# 2010| mu2010_14(TernaryPodObj) = Store[#temp2010:21] : &:r2010_12, r2010_13
|
||||
# 2010| r2010_15(TernaryPodObj) = Load[#temp2010:21] : &:r2010_12, ~m?
|
||||
# 2010| r2010_16(glval<TernaryPodObj>) = VariableAddress[y] :
|
||||
# 2010| mu2010_17(TernaryPodObj) = Store[y] : &:r2010_16, r2010_15
|
||||
# 2010| r2010_18(TernaryPodObj) = CopyValue : r2010_15
|
||||
# 2010| r2010_19(glval<TernaryPodObj>) = VariableAddress[#temp2010:9] :
|
||||
# 2010| mu2010_20(TernaryPodObj) = Store[#temp2010:9] : &:r2010_19, r2010_18
|
||||
# 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&)
|
||||
@@ -10931,48 +10973,104 @@ ir.cpp:
|
||||
#-----| Goto -> Block 7
|
||||
|
||||
# 2021| Block 10
|
||||
# 2021| r2021_6(glval<unknown>) = VariableAddress[#temp2021:9] :
|
||||
# 2021| r2021_7(glval<TernaryNonPodObj>) = Load[#temp2021:9] : &: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
|
||||
# 2022| v2022_1(void) = NoOp :
|
||||
# 2017| v2017_12(void) = ReturnVoid :
|
||||
# 2017| v2017_13(void) = AliasedUse : ~m?
|
||||
# 2017| v2017_14(void) = ExitFunction :
|
||||
# 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_16(glval<TernaryNonPodObj>) = VariableAddress[x] :
|
||||
# 2021| r2021_17(glval<unknown>) = VariableAddress[#temp2021:9] :
|
||||
# 2021| mu2021_18(glval<TernaryNonPodObj>) = Store[#temp2021:9] : &:r2021_17, r2021_16
|
||||
# 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_19(glval<TernaryNonPodObj>) = VariableAddress[y] :
|
||||
# 2021| r2021_20(glval<unknown>) = FunctionAddress[operator=] :
|
||||
# 2021| r2021_21(glval<TernaryNonPodObj>) = VariableAddress[#temp2021:21] :
|
||||
# 2021| mu2021_22(TernaryNonPodObj) = Uninitialized[#temp2021:21] : &:r2021_21
|
||||
# 2021| r2021_23(glval<unknown>) = FunctionAddress[TernaryNonPodObj] :
|
||||
# 2021| v2021_24(void) = Call[TernaryNonPodObj] : func:r2021_23, this:r2021_21
|
||||
# 2021| mu2021_25(unknown) = ^CallSideEffect : ~m?
|
||||
# 2021| mu2021_26(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_21
|
||||
# 2021| r2021_27(glval<TernaryNonPodObj>) = Convert : r2021_21
|
||||
# 2021| r2021_28(TernaryNonPodObj &) = CopyValue : r2021_27
|
||||
# 2021| r2021_29(TernaryNonPodObj &) = Call[operator=] : func:r2021_20, this:r2021_19, 0:r2021_28
|
||||
# 2021| mu2021_30(unknown) = ^CallSideEffect : ~m?
|
||||
# 2021| v2021_31(void) = ^IndirectReadSideEffect[-1] : &:r2021_19, ~m?
|
||||
# 2021| v2021_32(void) = ^BufferReadSideEffect[0] : &:r2021_28, ~m?
|
||||
# 2021| mu2021_33(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_19
|
||||
# 2021| r2021_34(glval<TernaryNonPodObj>) = CopyValue : r2021_29
|
||||
# 2021| r2021_35(glval<unknown>) = VariableAddress[#temp2021:9] :
|
||||
# 2021| mu2021_36(glval<TernaryNonPodObj>) = Store[#temp2021:9] : &:r2021_35, r2021_34
|
||||
# 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
|
||||
|
||||
@@ -195,18 +195,18 @@ int test13(char c, int i) {
|
||||
int z = i+1; // $ overflow=+
|
||||
range(z); // $ range="==InitializeParameter: i+1"
|
||||
range(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=- MISSING: range=>=1
|
||||
range((double)(c + i + uc + x + y + z)); // $ overflow=+ overflow=+- overflow=- MISSING: range=>=1
|
||||
range((double)(c + i + uc + x + y + z)); // $ overflow=+ overflow=+- overflow=- range=<=4294967295 MISSING: range=>=1
|
||||
return (double)(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=-
|
||||
}
|
||||
|
||||
// Regression test for ODASA-6013.
|
||||
int test14(int x) {
|
||||
int x0 = (int)(char)x;
|
||||
range(x0);
|
||||
range(x0); // $ range=<=127 range=>=-128
|
||||
int x1 = (int)(unsigned char)x;
|
||||
range(x1);
|
||||
range(x1); // $ range=<=255 range=>=0
|
||||
int x2 = (int)(unsigned short)x;
|
||||
range(x2);
|
||||
range(x2); // $ range=<=65535 range=>=0
|
||||
int x3 = (int)(unsigned int)x;
|
||||
range(x3);
|
||||
char c0 = x;
|
||||
@@ -759,9 +759,9 @@ unsigned long mult_overflow() {
|
||||
unsigned long mult_lower_bound(unsigned int ui, unsigned long ul) {
|
||||
if (ui >= 10) {
|
||||
range(ui); // $ range=>=10
|
||||
range((unsigned long)ui); // $ range=>=10
|
||||
unsigned long result = (unsigned long)ui * ui; // $ overflow=+
|
||||
range(result); // $ MISSING: range=>=100
|
||||
range((unsigned long)ui); // $ range=>=10 range=<=4294967295
|
||||
unsigned long result = (unsigned long)ui * ui; // no overflow
|
||||
range(result); // $ range=>=100 range=<=18446744065119617024
|
||||
return result; // BUG: upper bound should be >= 18446744065119617025
|
||||
}
|
||||
if (ul >= 10) {
|
||||
@@ -888,7 +888,7 @@ void notequal_variations(short n, float f) {
|
||||
}
|
||||
|
||||
if (n >= 5) {
|
||||
if (2 * n - 10 == 0) { // $ overflow=+
|
||||
if (2 * n - 10 == 0) { // no overflow
|
||||
range(n); // $ range=>=5 MISSING: range===5
|
||||
return;
|
||||
}
|
||||
@@ -936,7 +936,7 @@ void two_bounds_from_one_test(short ss, unsigned short us) {
|
||||
range(ss); // -32768 .. 32767
|
||||
}
|
||||
|
||||
if (ss + 1 < sizeof(int)) { // $ overflow=+
|
||||
if (ss + 1 < sizeof(int)) { // $ overflow=-
|
||||
range(ss); // -1 .. 2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 | | | | |
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Standalone
|
||||
|
||||
public Runtime(IDotNet dotNet) => this.dotNet = dotNet;
|
||||
|
||||
internal sealed class RuntimeVersion : IComparable<RuntimeVersion>
|
||||
internal record RuntimeVersion : IComparable<RuntimeVersion>
|
||||
{
|
||||
private readonly string dir;
|
||||
private readonly Version version;
|
||||
@@ -71,11 +71,6 @@ namespace Semmle.Extraction.CSharp.Standalone
|
||||
return c;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj) =>
|
||||
obj is not null && obj is RuntimeVersion other && other.FullPath == FullPath;
|
||||
|
||||
public override int GetHashCode() => FullPath.GetHashCode();
|
||||
|
||||
public override string ToString() => FullPath;
|
||||
}
|
||||
|
||||
@@ -97,7 +92,7 @@ namespace Semmle.Extraction.CSharp.Standalone
|
||||
var match = RuntimeRegex().Match(r);
|
||||
if (match.Success)
|
||||
{
|
||||
runtimes.AddOrUpdate(match.Groups[1].Value, new RuntimeVersion(match.Groups[6].Value, match.Groups[2].Value, match.Groups[4].Value, match.Groups[5].Value));
|
||||
runtimes.AddOrUpdateToLatest(match.Groups[1].Value, new RuntimeVersion(match.Groups[6].Value, match.Groups[2].Value, match.Groups[4].Value, match.Groups[5].Value));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@ namespace Semmle.Util
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new value or replaces the existing value (if the new value is greater than the existing)
|
||||
/// in dictionary for the given key.
|
||||
/// in this dictionary for the given key.
|
||||
/// </summary>
|
||||
public static void AddOrUpdate<T1, T2>(this Dictionary<T1, T2> dict, T1 key, T2 value) where T1 : notnull where T2 : IComparable<T2>
|
||||
public static void AddOrUpdateToLatest<T1, T2>(this Dictionary<T1, T2> dict, T1 key, T2 value) where T1 : notnull where T2 : IComparable<T2>
|
||||
{
|
||||
if (!dict.TryGetValue(key, out var existing) || existing.CompareTo(value) < 0)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The query library for `cs/hardcoded-credentials` now excludes benign properties such as `UserNameClaimType` and `AllowedUserNameCharacters` from `Microsoft.AspNetCore.Identity` options classes.
|
||||
@@ -6,6 +6,7 @@ extractor: csharp
|
||||
library: true
|
||||
upgrades: upgrades
|
||||
dependencies:
|
||||
codeql/dataflow: ${workspace}
|
||||
codeql/mad: ${workspace}
|
||||
codeql/ssa: ${workspace}
|
||||
codeql/tutorial: ${workspace}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
import csharp
|
||||
|
||||
module DataFlow {
|
||||
import semmle.code.csharp.dataflow.internal.DataFlow
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowImplSpecific
|
||||
private import codeql.dataflow.DataFlow
|
||||
import DataFlowMake<CsharpDataFlow>
|
||||
import semmle.code.csharp.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;
|
||||
}
|
||||
@@ -154,17 +154,17 @@ private module DispatchImpl {
|
||||
* call is a delegate call, or if the qualifier accesses a parameter of
|
||||
* the enclosing callable `c` (including the implicit `this` parameter).
|
||||
*/
|
||||
predicate mayBenefitFromCallContext(NonDelegateDataFlowCall call, DataFlowCallable c) {
|
||||
predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable c) {
|
||||
c = call.getEnclosingCallable() and
|
||||
call.getDispatchCall().mayBenefitFromCallContext()
|
||||
call.(NonDelegateDataFlowCall).getDispatchCall().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.
|
||||
*/
|
||||
DataFlowCallable viableImplInCallContext(NonDelegateDataFlowCall call, DataFlowCall ctx) {
|
||||
exists(DispatchCall dc | dc = call.getDispatchCall() |
|
||||
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
||||
exists(DispatchCall dc | dc = call.(NonDelegateDataFlowCall).getDispatchCall() |
|
||||
result.getUnderlyingCallable() =
|
||||
getCallableForDataFlow(dc.getADynamicTargetInCallContext(ctx.(NonDelegateDataFlowCall)
|
||||
.getDispatchCall()).getUnboundDeclaration())
|
||||
|
||||
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
|
||||
|
||||
@@ -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 C#-specific definitions for use in the data flow library.
|
||||
*/
|
||||
|
||||
private import codeql.dataflow.DataFlow
|
||||
|
||||
module Private {
|
||||
import DataFlowPrivate
|
||||
import DataFlowDispatch
|
||||
@@ -9,3 +12,12 @@ module Private {
|
||||
module Public {
|
||||
import DataFlowPublic
|
||||
}
|
||||
|
||||
module CsharpDataFlow implements InputSig {
|
||||
import Private
|
||||
import Public
|
||||
|
||||
Node exprNode(DataFlowExpr e) { result = Public::exprNode(e) }
|
||||
|
||||
predicate accessPathLimit = Private::accessPathLimit/0;
|
||||
}
|
||||
|
||||
@@ -22,11 +22,13 @@ private import semmle.code.cil.internal.SsaImpl as CilSsaImpl
|
||||
private import codeql.util.Unit
|
||||
|
||||
/** Gets the callable in which this node occurs. */
|
||||
DataFlowCallable nodeGetEnclosingCallable(NodeImpl n) { result = n.getEnclosingCallableImpl() }
|
||||
DataFlowCallable nodeGetEnclosingCallable(Node n) {
|
||||
result = n.(NodeImpl).getEnclosingCallableImpl()
|
||||
}
|
||||
|
||||
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
|
||||
predicate isParameterNode(ParameterNodeImpl p, DataFlowCallable c, ParameterPosition pos) {
|
||||
p.isParameterOf(c, pos)
|
||||
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
|
||||
p.(ParameterNodeImpl).isParameterOf(c, pos)
|
||||
}
|
||||
|
||||
/** Holds if `arg` is an `ArgumentNode` of `c` with position `pos`. */
|
||||
@@ -1739,7 +1741,7 @@ private PropertyContent getResultContent() {
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to
|
||||
* content `c`.
|
||||
*/
|
||||
predicate storeStep(Node node1, Content c, Node node2) {
|
||||
predicate storeStep(Node node1, ContentSet c, Node node2) {
|
||||
exists(StoreStepConfiguration x, ExprNode node, boolean postUpdate |
|
||||
hasNodePath(x, node1, node) and
|
||||
if postUpdate = true then node = node2.(PostUpdateNode).getPreUpdateNode() else node = node2
|
||||
@@ -1840,7 +1842,7 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a read of content `c`.
|
||||
*/
|
||||
predicate readStep(Node node1, Content c, Node node2) {
|
||||
predicate readStep(Node node1, ContentSet c, Node node2) {
|
||||
exists(ReadStepConfiguration x |
|
||||
hasNodePath(x, node1, node2) and
|
||||
fieldOrPropertyRead(node1.asExpr(), c, node2.asExpr())
|
||||
@@ -1901,7 +1903,7 @@ predicate readStep(Node node1, Content c, Node node2) {
|
||||
* any value stored inside `f` is cleared at the pre-update node associated with `x`
|
||||
* in `x.f = newValue`.
|
||||
*/
|
||||
predicate clearsContent(Node n, Content c) {
|
||||
predicate clearsContent(Node n, ContentSet c) {
|
||||
fieldOrPropertyStore(_, c, _, n.asExpr(), true)
|
||||
or
|
||||
fieldOrPropertyStore(_, c, _, n.(ObjectInitializerNode).getInitializer(), false)
|
||||
@@ -1949,10 +1951,7 @@ predicate isUnreachableInCall(Node n, DataFlowCall call) {
|
||||
class DataFlowType = Gvn::GvnType;
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
pragma[inline]
|
||||
Gvn::GvnType getNodeType(NodeImpl n) {
|
||||
pragma[only_bind_into](result) = pragma[only_bind_out](n).getDataFlowType()
|
||||
}
|
||||
Gvn::GvnType getNodeType(Node n) { result = n.(NodeImpl).getDataFlowType() }
|
||||
|
||||
/** Gets a string representation of a `DataFlowType`. */
|
||||
string ppReprType(DataFlowType t) { result = t.toString() }
|
||||
@@ -2140,12 +2139,6 @@ class CastNode extends Node {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` should never be skipped over in the `PathGraph` and in path
|
||||
* explanations.
|
||||
*/
|
||||
predicate neverSkipInPathGraph(Node n) { none() }
|
||||
|
||||
class DataFlowExpr = DotNet::Expr;
|
||||
|
||||
/** Holds if `e` is an expression that always has the same Boolean value `val`. */
|
||||
@@ -2188,8 +2181,8 @@ predicate forceHighPrecision(Content c) { c instanceof ElementContent }
|
||||
class LambdaCallKind = Unit;
|
||||
|
||||
/** Holds if `creation` is an expression that creates a delegate for `c`. */
|
||||
predicate lambdaCreation(ExprNode creation, LambdaCallKind kind, DataFlowCallable c) {
|
||||
exists(Expr e | e = creation.getExpr() |
|
||||
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) {
|
||||
exists(Expr e | e = creation.asExpr() |
|
||||
c.asCallable() =
|
||||
[
|
||||
e.(AnonymousFunctionExpr), e.(CallableAccess).getTarget().getUnboundDeclaration(),
|
||||
|
||||
@@ -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, _, _, _)
|
||||
|
||||
@@ -169,7 +169,7 @@ private class CredentialVar extends Assignable {
|
||||
exists(string name | name = this.getName() |
|
||||
name.regexpMatch("(?i).*pass(wd|word|code|phrase)(?!.*question).*")
|
||||
or
|
||||
name.regexpMatch("(?i).*(puid|username|userid).*")
|
||||
name.regexpMatch("(?i).*(puid|username|userid)(?!.*(characters|claimtype)).*")
|
||||
or
|
||||
name.regexpMatch("(?i).*(cert)(?!.*(format|name)).*")
|
||||
)
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
semmle-extractor-options: /r:System.Linq.dll
|
||||
semmle-extractor-options: /nostdlib /noconfig
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
semmle-extractor-options: /nostdlib /noconfig
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj
|
||||
@@ -0,0 +1,2 @@
|
||||
semmle-extractor-options: /nostdlib /noconfig
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj
|
||||
@@ -0,0 +1,2 @@
|
||||
semmle-extractor-options: /nostdlib /noconfig
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj
|
||||
@@ -0,0 +1,2 @@
|
||||
semmle-extractor-options: /nostdlib /noconfig
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj
|
||||
@@ -1 +1,2 @@
|
||||
semmle-extractor-options: /r:System.Threading.Thread.dll /r:System.Diagnostics.Debug.dll /langversion:preview
|
||||
semmle-extractor-options: /nostdlib /noconfig
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
semmle-extractor-options: /nostdlib /noconfig
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj
|
||||
@@ -1 +1,3 @@
|
||||
semmle-extractor-options: /nostdlib /noconfig
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj
|
||||
semmle-extractor-options: ${testdir}/../../../../resources/stubs/System.Windows.cs
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
semmle-extractor-options: /nostdlib /noconfig
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj
|
||||
@@ -0,0 +1,2 @@
|
||||
semmle-extractor-options: /nostdlib /noconfig
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj
|
||||
@@ -0,0 +1,2 @@
|
||||
semmle-extractor-options: /nostdlib /noconfig
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj
|
||||
@@ -0,0 +1,2 @@
|
||||
semmle-extractor-options: /nostdlib /noconfig
|
||||
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user