зеркало из https://github.com/github/codeql.git
Merge branch 'main' into redsun82/swift-logging
This commit is contained in:
Коммит
cbe247e123
|
@ -1,102 +0,0 @@
|
|||
name: "ATM - Check query suite"
|
||||
|
||||
env:
|
||||
QUERY_PACK: javascript/ql/experimental/adaptivethreatmodeling/src
|
||||
QUERY_SUITE: codeql-suites/javascript-atm-code-scanning.qls
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/atm-check-query-suite.yml"
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/**"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
atm-check-query-suite:
|
||||
runs-on: ubuntu-latest-xl
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup CodeQL
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
with:
|
||||
channel: release
|
||||
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
key: atm-suite
|
||||
|
||||
- name: Install ATM model
|
||||
run: |
|
||||
set -exu
|
||||
|
||||
# Install dependencies of ATM query pack, i.e. the ATM model
|
||||
codeql pack install "${QUERY_PACK}"
|
||||
|
||||
# Retrieve model checksum
|
||||
model_checksum=$(codeql resolve extensions "${QUERY_PACK}/${QUERY_SUITE}" | jq -r '.models[0].checksum')
|
||||
|
||||
# Trust the model so that we can use it in the ATM boosted queries
|
||||
mkdir -p "$HOME/.config/codeql"
|
||||
echo "--insecurely-execute-ml-model-checksums ${model_checksum}" >> "$HOME/.config/codeql/config"
|
||||
|
||||
- name: Create test DB
|
||||
run: |
|
||||
DB_PATH="${RUNNER_TEMP}/db"
|
||||
echo "DB_PATH=${DB_PATH}" >> "${GITHUB_ENV}"
|
||||
|
||||
codeql database create "${DB_PATH}" --source-root config/atm --language javascript
|
||||
|
||||
- name: Run ATM query suite
|
||||
run: |
|
||||
SARIF_PATH="${RUNNER_TEMP}/sarif.json"
|
||||
echo "SARIF_PATH=${SARIF_PATH}" >> "${GITHUB_ENV}"
|
||||
|
||||
codeql database analyze \
|
||||
--threads=0 \
|
||||
--ram 50000 \
|
||||
--format sarif-latest \
|
||||
--output "${SARIF_PATH}" \
|
||||
--sarif-group-rules-by-pack \
|
||||
-vv \
|
||||
--compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" \
|
||||
-- \
|
||||
"${DB_PATH}" \
|
||||
"${QUERY_PACK}/${QUERY_SUITE}"
|
||||
|
||||
- name: Upload SARIF
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: javascript-ml-powered-queries.sarif
|
||||
path: "${{ env.SARIF_PATH }}"
|
||||
retention-days: 5
|
||||
|
||||
- name: Check results
|
||||
run: |
|
||||
# We should run at least the ML-powered queries in `expected_rules`.
|
||||
expected_rules="js/ml-powered/nosql-injection js/ml-powered/path-injection js/ml-powered/sql-injection js/ml-powered/xss"
|
||||
|
||||
for rule in ${expected_rules}; do
|
||||
found_rule=$(jq --arg rule "${rule}" '[.runs[0].tool.extensions[].rules | select(. != null) |
|
||||
flatten | .[].id] | any(. == $rule)' "${SARIF_PATH}")
|
||||
if [[ "${found_rule}" != "true" ]]; then
|
||||
echo "Expected SARIF output to contain rule '${rule}', but found no such rule."
|
||||
exit 1
|
||||
else
|
||||
echo "Found rule '${rule}'."
|
||||
fi
|
||||
done
|
||||
|
||||
# We should have at least one alert from an ML-powered query.
|
||||
num_alerts=$(jq '[.runs[0].results[] |
|
||||
select(.properties.score != null and (.rule.id | startswith("js/ml-powered/")))] | length' \
|
||||
"${SARIF_PATH}")
|
||||
if [[ "${num_alerts}" -eq 0 ]]; then
|
||||
echo "Expected to find at least one alert from an ML-powered query but found ${num_alerts}."
|
||||
exit 1
|
||||
else
|
||||
echo "Found ${num_alerts} alerts from ML-powered queries.";
|
||||
fi
|
|
@ -1,12 +0,0 @@
|
|||
name: ATM Model Integration Tests
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
hello-world:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: foo
|
||||
run: echo "Hello world"
|
|
@ -0,0 +1,50 @@
|
|||
# Fast-forwards the branch specified in BRANCH_NAME
|
||||
# to the github.ref/sha that this workflow is run on.
|
||||
# Used as part of the release process, to ensure
|
||||
# external query writers can always access a branch of github/codeql
|
||||
# that is compatible with the latest stable release.
|
||||
name: Fast-forward tracking branch for selected CodeQL version
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
fast-forward:
|
||||
name: Fast-forward tracking branch for selected CodeQL version
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'github/codeql'
|
||||
permissions:
|
||||
contents: write
|
||||
env:
|
||||
BRANCH_NAME: 'lgtm.com'
|
||||
steps:
|
||||
- name: Validate chosen branch
|
||||
if: ${{ !startsWith(github.ref_name, 'codeql-cli-') }}
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::error ::The $BRANCH_NAME tracking branch should only be fast-forwarded to the tip of a codeql-cli-* branch, got $GITHUB_REF_NAME instead."
|
||||
exit 1
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Git config
|
||||
shell: bash
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Fetch
|
||||
shell: bash
|
||||
run: |
|
||||
set -x
|
||||
echo "Fetching $BRANCH_NAME"
|
||||
# Explicitly unshallow and fetch to ensure the remote ref is available.
|
||||
git fetch --unshallow origin "$BRANCH_NAME"
|
||||
git checkout -b "$BRANCH_NAME" "origin/$BRANCH_NAME"
|
||||
|
||||
- name: Fast-forward
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Fast-forwarding $BRANCH_NAME to ${GITHUB_REF}@${GITHUB_SHA}"
|
||||
git merge --ff-only "$GITHUB_SHA"
|
||||
git push origin "$BRANCH_NAME"
|
|
@ -123,6 +123,10 @@
|
|||
"java/ql/src/utils/modelgenerator/internal/CaptureModels.qll",
|
||||
"csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll"
|
||||
],
|
||||
"Model as Data Generation Java/C# - CaptureModelsPrinting": [
|
||||
"java/ql/src/utils/modelgenerator/internal/CaptureModelsPrinting.qll",
|
||||
"csharp/ql/src/utils/modelgenerator/internal/CaptureModelsPrinting.qll"
|
||||
],
|
||||
"Sign Java/C#": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll"
|
||||
|
@ -596,4 +600,4 @@
|
|||
"python/ql/lib/semmle/python/security/internal/EncryptionKeySizes.qll",
|
||||
"java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll"
|
||||
]
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,4 @@
|
|||
description: Revert support for repeated initializers, which are allowed in C with designated initializers.
|
||||
compatibility: full
|
||||
aggregate_field_init.rel: reorder aggregate_field_init.rel (int aggregate, int initializer, int field, int position) aggregate initializer field
|
||||
aggregate_array_init.rel: reorder aggregate_array_init.rel (int aggregate, int initializer, int element_index, int position) aggregate initializer element_index
|
|
@ -1,3 +1,7 @@
|
|||
## 0.6.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Breaking Changes
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
category: deprecated
|
||||
---
|
||||
* The predicates single-parameter predicates `ArrayOrVectorAggregateLiteral.getElementExpr` and `ClassAggregateLiteral.getFieldExpr` have been deprecated in favor of `ArrayOrVectorAggregateLiteral.getAnElementExpr` and `ClassAggregateLiteral.getAFieldExpr`.
|
|
@ -0,0 +1,3 @@
|
|||
## 0.6.1
|
||||
|
||||
No user-facing changes.
|
|
@ -1,2 +1,2 @@
|
|||
---
|
||||
lastReleaseVersion: 0.6.0
|
||||
lastReleaseVersion: 0.6.1
|
||||
|
|
|
@ -1,17 +1,146 @@
|
|||
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow2
|
||||
private import codeql.util.Unit
|
||||
|
||||
module ProductFlow {
|
||||
abstract class Configuration extends string {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
signature module ConfigSig {
|
||||
/**
|
||||
* Holds if `(source1, source2)` is a relevant data flow source.
|
||||
*
|
||||
* `source1` and `source2` must belong to the same callable.
|
||||
*/
|
||||
predicate isSourcePair(DataFlow::Node source1, DataFlow::Node source2) { none() }
|
||||
predicate isSourcePair(DataFlow::Node source1, DataFlow::Node source2);
|
||||
|
||||
/**
|
||||
* Holds if `(sink1, sink2)` is a relevant data flow sink.
|
||||
*
|
||||
* `sink1` and `sink2` must belong to the same callable.
|
||||
*/
|
||||
predicate isSinkPair(DataFlow::Node sink1, DataFlow::Node sink2);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited through the first projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
default predicate isBarrier1(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited through the second projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
default predicate isBarrier2(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow out of `node` is prohibited in the first projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
default predicate isBarrierOut1(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow out of `node` is prohibited in the second projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
default predicate isBarrierOut2(DataFlow::Node node) { none() }
|
||||
|
||||
/*
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
|
||||
* the first projection of the product dataflow graph.
|
||||
*/
|
||||
|
||||
default predicate isAdditionalFlowStep1(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
|
||||
* the second projection of the product dataflow graph.
|
||||
*/
|
||||
default predicate isAdditionalFlowStep2(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow into `node` is prohibited in the first projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
default predicate isBarrierIn1(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow into `node` is prohibited in the second projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
default predicate isBarrierIn2(DataFlow::Node node) { none() }
|
||||
}
|
||||
|
||||
module Global<ConfigSig Config> {
|
||||
private module StateConfig implements StateConfigSig {
|
||||
class FlowState1 = Unit;
|
||||
|
||||
class FlowState2 = Unit;
|
||||
|
||||
predicate isSourcePair(
|
||||
DataFlow::Node source1, FlowState1 state1, DataFlow::Node source2, FlowState2 state2
|
||||
) {
|
||||
exists(state1) and
|
||||
exists(state2) and
|
||||
Config::isSourcePair(source1, source2)
|
||||
}
|
||||
|
||||
predicate isSinkPair(
|
||||
DataFlow::Node sink1, FlowState1 state1, DataFlow::Node sink2, FlowState2 state2
|
||||
) {
|
||||
exists(state1) and
|
||||
exists(state2) and
|
||||
Config::isSinkPair(sink1, sink2)
|
||||
}
|
||||
|
||||
predicate isBarrier1(DataFlow::Node node, FlowState1 state) {
|
||||
exists(state) and
|
||||
Config::isBarrier1(node)
|
||||
}
|
||||
|
||||
predicate isBarrier2(DataFlow::Node node, FlowState2 state) {
|
||||
exists(state) and
|
||||
Config::isBarrier2(node)
|
||||
}
|
||||
|
||||
predicate isBarrier1 = Config::isBarrier1/1;
|
||||
|
||||
predicate isBarrier2 = Config::isBarrier2/1;
|
||||
|
||||
predicate isBarrierOut1 = Config::isBarrierOut1/1;
|
||||
|
||||
predicate isBarrierOut2 = Config::isBarrierOut2/1;
|
||||
|
||||
predicate isAdditionalFlowStep1 = Config::isAdditionalFlowStep1/2;
|
||||
|
||||
predicate isAdditionalFlowStep1(
|
||||
DataFlow::Node node1, FlowState1 state1, DataFlow::Node node2, FlowState1 state2
|
||||
) {
|
||||
exists(state1) and
|
||||
exists(state2) and
|
||||
Config::isAdditionalFlowStep1(node1, node2)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep2 = Config::isAdditionalFlowStep2/2;
|
||||
|
||||
predicate isAdditionalFlowStep2(
|
||||
DataFlow::Node node1, FlowState2 state1, DataFlow::Node node2, FlowState2 state2
|
||||
) {
|
||||
exists(state1) and
|
||||
exists(state2) and
|
||||
Config::isAdditionalFlowStep2(node1, node2)
|
||||
}
|
||||
|
||||
predicate isBarrierIn1 = Config::isBarrierIn1/1;
|
||||
|
||||
predicate isBarrierIn2 = Config::isBarrierIn2/1;
|
||||
}
|
||||
|
||||
import GlobalWithState<StateConfig>
|
||||
}
|
||||
|
||||
signature module StateConfigSig {
|
||||
bindingset[this]
|
||||
class FlowState1;
|
||||
|
||||
bindingset[this]
|
||||
class FlowState2;
|
||||
|
||||
/**
|
||||
* Holds if `(source1, source2)` is a relevant data flow source with initial states `state1`
|
||||
|
@ -20,20 +149,8 @@ module ProductFlow {
|
|||
* `source1` and `source2` must belong to the same callable.
|
||||
*/
|
||||
predicate isSourcePair(
|
||||
DataFlow::Node source1, DataFlow::FlowState state1, DataFlow::Node source2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
state1 = "" and
|
||||
state2 = "" and
|
||||
this.isSourcePair(source1, source2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(sink1, sink2)` is a relevant data flow sink.
|
||||
*
|
||||
* `sink1` and `sink2` must belong to the same callable.
|
||||
*/
|
||||
predicate isSinkPair(DataFlow::Node sink1, DataFlow::Node sink2) { none() }
|
||||
DataFlow::Node source1, FlowState1 state1, DataFlow::Node source2, FlowState2 state2
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if `(sink1, sink2)` is a relevant data flow sink with final states `state1`
|
||||
|
@ -42,60 +159,51 @@ module ProductFlow {
|
|||
* `sink1` and `sink2` must belong to the same callable.
|
||||
*/
|
||||
predicate isSinkPair(
|
||||
DataFlow::Node sink1, DataFlow::FlowState state1, DataFlow::Node sink2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
state1 = "" and
|
||||
state2 = "" and
|
||||
this.isSinkPair(sink1, sink2)
|
||||
}
|
||||
DataFlow::Node sink1, FlowState1 state1, DataFlow::Node sink2, FlowState2 state2
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited through the first projection of the product
|
||||
* dataflow graph when the flow state is `state`.
|
||||
*/
|
||||
predicate isBarrier1(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
this.isBarrier1(node) and state = ""
|
||||
}
|
||||
predicate isBarrier1(DataFlow::Node node, FlowState1 state);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited through the second projection of the product
|
||||
* dataflow graph when the flow state is `state`.
|
||||
*/
|
||||
predicate isBarrier2(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
this.isBarrier2(node) and state = ""
|
||||
}
|
||||
predicate isBarrier2(DataFlow::Node node, FlowState2 state);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited through the first projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrier1(DataFlow::Node node) { none() }
|
||||
default predicate isBarrier1(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited through the second projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrier2(DataFlow::Node node) { none() }
|
||||
default predicate isBarrier2(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow out of `node` is prohibited in the first projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrierOut1(DataFlow::Node node) { none() }
|
||||
default predicate isBarrierOut1(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow out of `node` is prohibited in the second projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrierOut2(DataFlow::Node node) { none() }
|
||||
default predicate isBarrierOut2(DataFlow::Node node) { none() }
|
||||
|
||||
/*
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
|
||||
* the first projection of the product dataflow graph.
|
||||
*/
|
||||
|
||||
predicate isAdditionalFlowStep1(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
default predicate isAdditionalFlowStep1(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
|
||||
|
@ -104,19 +212,14 @@ module ProductFlow {
|
|||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep1(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
state1 instanceof DataFlow::FlowStateEmpty and
|
||||
state2 instanceof DataFlow::FlowStateEmpty and
|
||||
this.isAdditionalFlowStep1(node1, node2)
|
||||
}
|
||||
DataFlow::Node node1, FlowState1 state1, DataFlow::Node node2, FlowState1 state2
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
|
||||
* the second projection of the product dataflow graph.
|
||||
*/
|
||||
predicate isAdditionalFlowStep2(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
default predicate isAdditionalFlowStep2(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
|
||||
|
@ -125,177 +228,168 @@ module ProductFlow {
|
|||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep2(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
state1 instanceof DataFlow::FlowStateEmpty and
|
||||
state2 instanceof DataFlow::FlowStateEmpty and
|
||||
this.isAdditionalFlowStep2(node1, node2)
|
||||
}
|
||||
DataFlow::Node node1, FlowState2 state1, DataFlow::Node node2, FlowState2 state2
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if data flow into `node` is prohibited in the first projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrierIn1(DataFlow::Node node) { none() }
|
||||
default predicate isBarrierIn1(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow into `node` is prohibited in the second projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrierIn2(DataFlow::Node node) { none() }
|
||||
default predicate isBarrierIn2(DataFlow::Node node) { none() }
|
||||
}
|
||||
|
||||
predicate hasFlowPath(
|
||||
DataFlow::PathNode source1, DataFlow2::PathNode source2, DataFlow::PathNode sink1,
|
||||
DataFlow2::PathNode sink2
|
||||
module GlobalWithState<StateConfigSig Config> {
|
||||
class PathNode1 = Flow1::PathNode;
|
||||
|
||||
class PathNode2 = Flow2::PathNode;
|
||||
|
||||
module PathGraph1 = Flow1::PathGraph;
|
||||
|
||||
module PathGraph2 = Flow2::PathGraph;
|
||||
|
||||
class FlowState1 = Config::FlowState1;
|
||||
|
||||
class FlowState2 = Config::FlowState2;
|
||||
|
||||
predicate flowPath(
|
||||
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode sink1, Flow2::PathNode sink2
|
||||
) {
|
||||
reachable(this, source1, source2, sink1, sink2)
|
||||
reachable(source1, source2, sink1, sink2)
|
||||
}
|
||||
}
|
||||
|
||||
private import Internal
|
||||
private module Config1 implements DataFlow::StateConfigSig {
|
||||
class FlowState = FlowState1;
|
||||
|
||||
module Internal {
|
||||
class Conf1 extends DataFlow::Configuration {
|
||||
Conf1() { this = "Conf1" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
||||
exists(Configuration conf | conf.isSourcePair(source, state, _, _))
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
Config::isSourcePair(source, state, _, _)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
|
||||
exists(Configuration conf | conf.isSinkPair(sink, state, _, _))
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
Config::isSinkPair(sink, state, _, _)
|
||||
}
|
||||
|
||||
override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
exists(Configuration conf | conf.isBarrier1(node, state))
|
||||
}
|
||||
predicate isBarrier(DataFlow::Node node, FlowState state) { Config::isBarrier1(node, state) }
|
||||
|
||||
override predicate isBarrierOut(DataFlow::Node node) {
|
||||
exists(Configuration conf | conf.isBarrierOut1(node))
|
||||
}
|
||||
predicate isBarrierOut(DataFlow::Node node) { Config::isBarrierOut1(node) }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState1 state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
exists(Configuration conf | conf.isAdditionalFlowStep1(node1, state1, node2, state2))
|
||||
Config::isAdditionalFlowStep1(node1, state1, node2, state2)
|
||||
}
|
||||
|
||||
override predicate isBarrierIn(DataFlow::Node node) {
|
||||
exists(Configuration conf | conf.isBarrierIn1(node))
|
||||
}
|
||||
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn1(node) }
|
||||
}
|
||||
|
||||
class Conf2 extends DataFlow2::Configuration {
|
||||
Conf2() { this = "Conf2" }
|
||||
module Flow1 = DataFlow::GlobalWithState<Config1>;
|
||||
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
||||
exists(Configuration conf, DataFlow::PathNode source1 |
|
||||
conf.isSourcePair(source1.getNode(), source1.getState(), source, state) and
|
||||
any(Conf1 c).hasFlowPath(source1, _)
|
||||
module Config2 implements DataFlow::StateConfigSig {
|
||||
class FlowState = FlowState2;
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
exists(Flow1::PathNode source1 |
|
||||
Config::isSourcePair(source1.getNode(), source1.getState(), source, state) and
|
||||
Flow1::flowPath(source1, _)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
|
||||
exists(Configuration conf, DataFlow::PathNode sink1 |
|
||||
conf.isSinkPair(sink1.getNode(), sink1.getState(), sink, state) and
|
||||
any(Conf1 c).hasFlowPath(_, sink1)
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
exists(Flow1::PathNode sink1 |
|
||||
Config::isSinkPair(sink1.getNode(), sink1.getState(), sink, state) and
|
||||
Flow1::flowPath(_, sink1)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
exists(Configuration conf | conf.isBarrier2(node, state))
|
||||
}
|
||||
predicate isBarrier(DataFlow::Node node, FlowState state) { Config::isBarrier2(node, state) }
|
||||
|
||||
override predicate isBarrierOut(DataFlow::Node node) {
|
||||
exists(Configuration conf | conf.isBarrierOut2(node))
|
||||
}
|
||||
predicate isBarrierOut(DataFlow::Node node) { Config::isBarrierOut2(node) }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
exists(Configuration conf | conf.isAdditionalFlowStep2(node1, state1, node2, state2))
|
||||
Config::isAdditionalFlowStep2(node1, state1, node2, state2)
|
||||
}
|
||||
|
||||
override predicate isBarrierIn(DataFlow::Node node) {
|
||||
exists(Configuration conf | conf.isBarrierIn2(node))
|
||||
}
|
||||
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn2(node) }
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate reachableInterprocEntry(
|
||||
Configuration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2,
|
||||
DataFlow::PathNode node1, DataFlow2::PathNode node2
|
||||
) {
|
||||
conf.isSourcePair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState()) and
|
||||
node1 = source1 and
|
||||
node2 = source2
|
||||
or
|
||||
exists(
|
||||
DataFlow::PathNode midEntry1, DataFlow2::PathNode midEntry2, DataFlow::PathNode midExit1,
|
||||
DataFlow2::PathNode midExit2
|
||||
|
|
||||
reachableInterprocEntry(conf, source1, source2, midEntry1, midEntry2) and
|
||||
interprocEdgePair(midExit1, midExit2, node1, node2) and
|
||||
localPathStep1*(midEntry1, midExit1) and
|
||||
localPathStep2*(midEntry2, midExit2)
|
||||
)
|
||||
}
|
||||
module Flow2 = DataFlow::GlobalWithState<Config2>;
|
||||
|
||||
private predicate localPathStep1(DataFlow::PathNode pred, DataFlow::PathNode succ) {
|
||||
DataFlow::PathGraph::edges(pred, succ) and
|
||||
pragma[only_bind_out](pred.getNode().getEnclosingCallable()) =
|
||||
pragma[only_bind_out](succ.getNode().getEnclosingCallable())
|
||||
}
|
||||
pragma[nomagic]
|
||||
private predicate reachableInterprocEntry(
|
||||
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode node1, Flow2::PathNode node2
|
||||
) {
|
||||
Config::isSourcePair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState()) and
|
||||
node1 = source1 and
|
||||
node2 = source2
|
||||
or
|
||||
exists(
|
||||
Flow1::PathNode midEntry1, Flow2::PathNode midEntry2, Flow1::PathNode midExit1,
|
||||
Flow2::PathNode midExit2
|
||||
|
|
||||
reachableInterprocEntry(source1, source2, midEntry1, midEntry2) and
|
||||
interprocEdgePair(midExit1, midExit2, node1, node2) and
|
||||
localPathStep1*(midEntry1, midExit1) and
|
||||
localPathStep2*(midEntry2, midExit2)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localPathStep2(DataFlow2::PathNode pred, DataFlow2::PathNode succ) {
|
||||
DataFlow2::PathGraph::edges(pred, succ) and
|
||||
pragma[only_bind_out](pred.getNode().getEnclosingCallable()) =
|
||||
pragma[only_bind_out](succ.getNode().getEnclosingCallable())
|
||||
}
|
||||
private predicate localPathStep1(Flow1::PathNode pred, Flow1::PathNode succ) {
|
||||
Flow1::PathGraph::edges(pred, succ) and
|
||||
pragma[only_bind_out](pred.getNode().getEnclosingCallable()) =
|
||||
pragma[only_bind_out](succ.getNode().getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate interprocEdge1(
|
||||
Declaration predDecl, Declaration succDecl, DataFlow::PathNode pred1, DataFlow::PathNode succ1
|
||||
) {
|
||||
DataFlow::PathGraph::edges(pred1, succ1) and
|
||||
predDecl != succDecl and
|
||||
pred1.getNode().getEnclosingCallable() = predDecl and
|
||||
succ1.getNode().getEnclosingCallable() = succDecl
|
||||
}
|
||||
private predicate localPathStep2(Flow2::PathNode pred, Flow2::PathNode succ) {
|
||||
Flow2::PathGraph::edges(pred, succ) and
|
||||
pragma[only_bind_out](pred.getNode().getEnclosingCallable()) =
|
||||
pragma[only_bind_out](succ.getNode().getEnclosingCallable())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate interprocEdge2(
|
||||
Declaration predDecl, Declaration succDecl, DataFlow2::PathNode pred2, DataFlow2::PathNode succ2
|
||||
) {
|
||||
DataFlow2::PathGraph::edges(pred2, succ2) and
|
||||
predDecl != succDecl and
|
||||
pred2.getNode().getEnclosingCallable() = predDecl and
|
||||
succ2.getNode().getEnclosingCallable() = succDecl
|
||||
}
|
||||
pragma[nomagic]
|
||||
private predicate interprocEdge1(
|
||||
Declaration predDecl, Declaration succDecl, Flow1::PathNode pred1, Flow1::PathNode succ1
|
||||
) {
|
||||
Flow1::PathGraph::edges(pred1, succ1) and
|
||||
predDecl != succDecl and
|
||||
pred1.getNode().getEnclosingCallable() = predDecl and
|
||||
succ1.getNode().getEnclosingCallable() = succDecl
|
||||
}
|
||||
|
||||
private predicate interprocEdgePair(
|
||||
DataFlow::PathNode pred1, DataFlow2::PathNode pred2, DataFlow::PathNode succ1,
|
||||
DataFlow2::PathNode succ2
|
||||
) {
|
||||
exists(Declaration predDecl, Declaration succDecl |
|
||||
interprocEdge1(predDecl, succDecl, pred1, succ1) and
|
||||
interprocEdge2(predDecl, succDecl, pred2, succ2)
|
||||
)
|
||||
}
|
||||
pragma[nomagic]
|
||||
private predicate interprocEdge2(
|
||||
Declaration predDecl, Declaration succDecl, Flow2::PathNode pred2, Flow2::PathNode succ2
|
||||
) {
|
||||
Flow2::PathGraph::edges(pred2, succ2) and
|
||||
predDecl != succDecl and
|
||||
pred2.getNode().getEnclosingCallable() = predDecl and
|
||||
succ2.getNode().getEnclosingCallable() = succDecl
|
||||
}
|
||||
|
||||
private predicate reachable(
|
||||
Configuration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2,
|
||||
DataFlow::PathNode sink1, DataFlow2::PathNode sink2
|
||||
) {
|
||||
exists(DataFlow::PathNode mid1, DataFlow2::PathNode mid2 |
|
||||
reachableInterprocEntry(conf, source1, source2, mid1, mid2) and
|
||||
conf.isSinkPair(sink1.getNode(), sink1.getState(), sink2.getNode(), sink2.getState()) and
|
||||
localPathStep1*(mid1, sink1) and
|
||||
localPathStep2*(mid2, sink2)
|
||||
)
|
||||
private predicate interprocEdgePair(
|
||||
Flow1::PathNode pred1, Flow2::PathNode pred2, Flow1::PathNode succ1, Flow2::PathNode succ2
|
||||
) {
|
||||
exists(Declaration predDecl, Declaration succDecl |
|
||||
interprocEdge1(predDecl, succDecl, pred1, succ1) and
|
||||
interprocEdge2(predDecl, succDecl, pred2, succ2)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate reachable(
|
||||
Flow1::PathNode source1, Flow2::PathNode source2, Flow1::PathNode sink1, Flow2::PathNode sink2
|
||||
) {
|
||||
exists(Flow1::PathNode mid1, Flow2::PathNode mid2 |
|
||||
reachableInterprocEntry(source1, source2, mid1, mid2) and
|
||||
Config::isSinkPair(sink1.getNode(), sink1.getState(), sink2.getNode(), sink2.getState()) and
|
||||
localPathStep1*(mid1, sink1) and
|
||||
localPathStep2*(mid2, sink2)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,86 +1 @@
|
|||
import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
|
||||
private newtype TBound =
|
||||
TBoundZero() or
|
||||
TBoundValueNumber(ValueNumber vn) {
|
||||
exists(Instruction i |
|
||||
vn.getAnInstruction() = i and
|
||||
(
|
||||
i.getResultIRType() instanceof IRIntegerType or
|
||||
i.getResultIRType() instanceof IRAddressType
|
||||
) and
|
||||
not vn.getAnInstruction() instanceof ConstantInstruction
|
||||
|
|
||||
i instanceof PhiInstruction
|
||||
or
|
||||
i instanceof InitializeParameterInstruction
|
||||
or
|
||||
i instanceof CallInstruction
|
||||
or
|
||||
i instanceof VariableAddressInstruction
|
||||
or
|
||||
i instanceof FieldAddressInstruction
|
||||
or
|
||||
i.(LoadInstruction).getSourceAddress() instanceof VariableAddressInstruction
|
||||
or
|
||||
i.(LoadInstruction).getSourceAddress() instanceof FieldAddressInstruction
|
||||
or
|
||||
i.getAUse() instanceof ArgumentOperand
|
||||
or
|
||||
i instanceof PointerArithmeticInstruction
|
||||
or
|
||||
i.getAUse() instanceof AddressOperand
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A bound that may be inferred for an expression plus/minus an integer delta.
|
||||
*/
|
||||
abstract class Bound extends TBound {
|
||||
abstract string toString();
|
||||
|
||||
/** Gets an expression that equals this bound plus `delta`. */
|
||||
abstract Instruction getInstruction(int delta);
|
||||
|
||||
/** Gets an expression that equals this bound. */
|
||||
Instruction getInstruction() { result = getInstruction(0) }
|
||||
|
||||
abstract Location getLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* The bound that corresponds to the integer 0. This is used to represent all
|
||||
* integer bounds as bounds are always accompanied by an added integer delta.
|
||||
*/
|
||||
class ZeroBound extends Bound, TBoundZero {
|
||||
override string toString() { result = "0" }
|
||||
|
||||
override Instruction getInstruction(int delta) {
|
||||
result.(ConstantValueInstruction).getValue().toInt() = delta
|
||||
}
|
||||
|
||||
override Location getLocation() { result instanceof UnknownDefaultLocation }
|
||||
}
|
||||
|
||||
/**
|
||||
* A bound corresponding to the value of an `Instruction`.
|
||||
*/
|
||||
class ValueNumberBound extends Bound, TBoundValueNumber {
|
||||
ValueNumber vn;
|
||||
|
||||
ValueNumberBound() { this = TBoundValueNumber(vn) }
|
||||
|
||||
/** Gets an `Instruction` that equals this bound. */
|
||||
override Instruction getInstruction(int delta) {
|
||||
this = TBoundValueNumber(valueNumber(result)) and delta = 0
|
||||
}
|
||||
|
||||
override string toString() { result = "ValueNumberBound" }
|
||||
|
||||
override Location getLocation() { result = vn.getLocation() }
|
||||
|
||||
/** Gets the value number that equals this bound. */
|
||||
ValueNumber getValueNumber() { result = vn }
|
||||
}
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.Bound
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
import RangeAnalysisImpl
|
||||
import experimental.semmle.code.cpp.semantic.SemanticBound
|
|
@ -1,5 +1,5 @@
|
|||
name: codeql/cpp-all
|
||||
version: 0.6.1-dev
|
||||
version: 0.7.0-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
|
|
@ -752,13 +752,13 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
|
|||
expr.(VariableAccess).getQualifier() = ele and pred = "getQualifier()"
|
||||
or
|
||||
exists(Field f |
|
||||
expr.(ClassAggregateLiteral).getFieldExpr(f) = ele and
|
||||
pred = "getFieldExpr(" + f.toString() + ")"
|
||||
expr.(ClassAggregateLiteral).getAFieldExpr(f) = ele and
|
||||
pred = "getAFieldExpr(" + f.toString() + ")"
|
||||
)
|
||||
or
|
||||
exists(int n |
|
||||
expr.(ArrayOrVectorAggregateLiteral).getElementExpr(n) = ele and
|
||||
pred = "getElementExpr(" + n.toString() + ")"
|
||||
expr.(ArrayOrVectorAggregateLiteral).getAnElementExpr(n) = ele and
|
||||
pred = "getAnElementExpr(" + n.toString() + ")"
|
||||
)
|
||||
or
|
||||
expr.(AlignofExprOperator).getExprOperand() = ele and pred = "getExprOperand()"
|
||||
|
|
|
@ -133,7 +133,7 @@ class Variable extends Declaration, @variable {
|
|||
or
|
||||
exists(AssignExpr ae | ae.getLValue().(Access).getTarget() = this and result = ae.getRValue())
|
||||
or
|
||||
exists(ClassAggregateLiteral l | result = l.getFieldExpr(this))
|
||||
exists(ClassAggregateLiteral l | result = l.getAFieldExpr(this))
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -79,3 +79,13 @@ class ArgumentPosition extends int {
|
|||
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||
pragma[inline]
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||
|
||||
/**
|
||||
* Holds if flow from `call`'s argument `arg` to parameter `p` is permissible.
|
||||
*
|
||||
* This is a temporary hook to support technical debt in the Go language; do not use.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate golangSpecificParamArgFilter(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
any()
|
||||
}
|
||||
|
|
|
@ -425,7 +425,8 @@ private module Cached {
|
|||
exists(ParameterPosition ppos |
|
||||
viableParam(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p)) and
|
||||
golangSpecificParamArgFilter(call, p, arg)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -159,7 +159,7 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
|
|||
// `PostUpdateNode`, which means it must be an `ObjectInitializerNode`.
|
||||
node2.asExpr() = aggr and
|
||||
f.(FieldContent).getField() = field and
|
||||
aggr.getFieldExpr(field) = node1.asExpr()
|
||||
aggr.getAFieldExpr(field) = node1.asExpr()
|
||||
)
|
||||
or
|
||||
exists(FieldAccess fa |
|
||||
|
|
|
@ -147,7 +147,7 @@ class LambdaCapture extends Locatable, @lambdacapture {
|
|||
*/
|
||||
Expr getInitializer() {
|
||||
exists(LambdaExpression lambda | this = lambda.getCapture(_) |
|
||||
result = lambda.getInitializer().getFieldExpr(this.getField())
|
||||
result = lambda.getInitializer().getAFieldExpr(this.getField())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -187,12 +187,44 @@ class ClassAggregateLiteral extends AggregateLiteral {
|
|||
override string getAPrimaryQlClass() { result = "ClassAggregateLiteral" }
|
||||
|
||||
/**
|
||||
* Gets an expression within the aggregate literal that is used to initialize
|
||||
* field `field`, if present.
|
||||
*
|
||||
* This predicate may have multiple results since a field can be initialized
|
||||
* multiple times in the same initializer.
|
||||
*/
|
||||
Expr getAFieldExpr(Field field) { result = this.getFieldExpr(field, _) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getAFieldExpr` instead.
|
||||
*
|
||||
* Gets the expression within the aggregate literal that is used to initialize
|
||||
* field `field`, if present.
|
||||
*
|
||||
* This predicate may have multiple results since a field can be initialized
|
||||
* multiple times in the same initializer.
|
||||
*/
|
||||
Expr getFieldExpr(Field field) {
|
||||
deprecated Expr getFieldExpr(Field field) { result = this.getFieldExpr(field, _) }
|
||||
|
||||
/**
|
||||
* Gets the expression within the aggregate literal that is used to initialize
|
||||
* field `field`, if present. The expression is the `position`'th entry in the
|
||||
* aggregate literal.
|
||||
*
|
||||
* For example, if `aggr` represents the initialization literal `{.x = 123, .y = 456 .x = 789}` in
|
||||
* ```cpp
|
||||
* struct Foo { int x; int y; };
|
||||
* struct Foo foo = {.x = 123, .y = 456 .x = 789};
|
||||
* ```
|
||||
* then:
|
||||
* - `aggr.getFieldExpr(x, 0)` gives `123`.
|
||||
* - `aggr.getFieldExpr(y, 1)` gives `456`.
|
||||
* - `aggr.getFieldExpr(x, 2)` gives `789`.
|
||||
*/
|
||||
Expr getFieldExpr(Field field, int position) {
|
||||
field = classType.getAField() and
|
||||
aggregate_field_init(underlyingElement(this), unresolveElement(result), unresolveElement(field))
|
||||
aggregate_field_init(underlyingElement(this), unresolveElement(result), unresolveElement(field),
|
||||
position)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -206,7 +238,7 @@ class ClassAggregateLiteral extends AggregateLiteral {
|
|||
(
|
||||
// If the field has an explicit initializer expression, then the field is
|
||||
// initialized.
|
||||
exists(this.getFieldExpr(field))
|
||||
exists(this.getAFieldExpr(field))
|
||||
or
|
||||
// If the type is not a union, all fields without initializers are value
|
||||
// initialized.
|
||||
|
@ -230,7 +262,7 @@ class ClassAggregateLiteral extends AggregateLiteral {
|
|||
pragma[inline]
|
||||
predicate isValueInitialized(Field field) {
|
||||
this.isInitialized(field) and
|
||||
not exists(this.getFieldExpr(field))
|
||||
not exists(this.getAFieldExpr(field))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -260,11 +292,41 @@ class ArrayOrVectorAggregateLiteral extends AggregateLiteral {
|
|||
Type getElementType() { none() }
|
||||
|
||||
/**
|
||||
* Gets an expression within the aggregate literal that is used to initialize
|
||||
* element `elementIndex`, if present.
|
||||
*
|
||||
* This predicate may have multiple results since an element can be initialized
|
||||
* multiple times in the same initializer.
|
||||
*/
|
||||
Expr getAnElementExpr(int elementIndex) { result = this.getElementExpr(elementIndex, _) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getAnElementExpr` instead.
|
||||
*
|
||||
* Gets the expression within the aggregate literal that is used to initialize
|
||||
* element `elementIndex`, if present.
|
||||
*
|
||||
* This predicate may have multiple results since an element can be initialized
|
||||
* multiple times in the same initializer.
|
||||
*/
|
||||
Expr getElementExpr(int elementIndex) {
|
||||
aggregate_array_init(underlyingElement(this), unresolveElement(result), elementIndex)
|
||||
deprecated Expr getElementExpr(int elementIndex) { result = this.getElementExpr(elementIndex, _) }
|
||||
|
||||
/**
|
||||
* Gets the expression within the aggregate literal that is used to initialize
|
||||
* element `elementIndex`, if present. The expression is the `position`'th entry
|
||||
* in the aggregate literal.
|
||||
*
|
||||
* For example, if `a` represents the initialization literal `{[0] = 123, [1] = 456, [0] = 789 }` in
|
||||
* ```cpp
|
||||
* int x[2] = {[0] = 123, [1] = 456, [0] = 789 };
|
||||
* ```
|
||||
* then:
|
||||
* - `a.getElementExpr(0, 0)` gives `123`.
|
||||
* - `a.getElementExpr(1, 1)` gives `456`.
|
||||
* - `a.getElementExpr(0, 2)` gives `789`.
|
||||
*/
|
||||
Expr getElementExpr(int elementIndex, int position) {
|
||||
aggregate_array_init(underlyingElement(this), unresolveElement(result), elementIndex, position)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -289,7 +351,7 @@ class ArrayOrVectorAggregateLiteral extends AggregateLiteral {
|
|||
bindingset[elementIndex]
|
||||
predicate isValueInitialized(int elementIndex) {
|
||||
this.isInitialized(elementIndex) and
|
||||
not exists(this.getElementExpr(elementIndex))
|
||||
not exists(this.getAnElementExpr(elementIndex))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -271,3 +271,13 @@ Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) {
|
|||
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||
pragma[inline]
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||
|
||||
/**
|
||||
* Holds if flow from `call`'s argument `arg` to parameter `p` is permissible.
|
||||
*
|
||||
* This is a temporary hook to support technical debt in the Go language; do not use.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate golangSpecificParamArgFilter(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
any()
|
||||
}
|
||||
|
|
|
@ -425,7 +425,8 @@ private module Cached {
|
|||
exists(ParameterPosition ppos |
|
||||
viableParam(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p)) and
|
||||
golangSpecificParamArgFilter(call, p, arg)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -897,23 +897,6 @@ private class MyConsistencyConfiguration extends Consistency::ConsistencyConfigu
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the basic block of `node`.
|
||||
*/
|
||||
IRBlock getBasicBlock(Node node) {
|
||||
node.asInstruction().getBlock() = result
|
||||
or
|
||||
node.asOperand().getUse().getBlock() = result
|
||||
or
|
||||
node.(SsaPhiNode).getPhiNode().getBasicBlock() = result
|
||||
or
|
||||
node.(RawIndirectOperand).getOperand().getUse().getBlock() = result
|
||||
or
|
||||
node.(RawIndirectInstruction).getInstruction().getBlock() = result
|
||||
or
|
||||
result = getBasicBlock(node.(PostUpdateNode).getPreUpdateNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* A local flow relation that includes both local steps, read steps and
|
||||
* argument-to-return flow through summarized functions.
|
||||
|
@ -999,7 +982,8 @@ private int countNumberOfBranchesUsingParameter(SwitchInstruction switch, Parame
|
|||
// we pick the one with the highest edge count.
|
||||
result =
|
||||
max(SsaPhiNode phi |
|
||||
switch.getSuccessor(caseOrDefaultEdge()).getBlock().dominanceFrontier() = getBasicBlock(phi) and
|
||||
switch.getSuccessor(caseOrDefaultEdge()).getBlock().dominanceFrontier() =
|
||||
phi.getBasicBlock() and
|
||||
phi.getSourceVariable() = sv
|
||||
|
|
||||
strictcount(phi.getAnInput())
|
||||
|
|
|
@ -160,6 +160,28 @@ class Node extends TIRDataFlowNode {
|
|||
/** Gets the operands corresponding to this node, if any. */
|
||||
Operand asOperand() { result = this.(OperandNode).getOperand() }
|
||||
|
||||
/**
|
||||
* Holds if this node is at index `i` in basic block `block`.
|
||||
*
|
||||
* Note: Phi nodes are considered to be at index `-1`.
|
||||
*/
|
||||
final predicate hasIndexInBlock(IRBlock block, int i) {
|
||||
this.asInstruction() = block.getInstruction(i)
|
||||
or
|
||||
this.asOperand().getUse() = block.getInstruction(i)
|
||||
or
|
||||
this.(SsaPhiNode).getPhiNode().getBasicBlock() = block and i = -1
|
||||
or
|
||||
this.(RawIndirectOperand).getOperand().getUse() = block.getInstruction(i)
|
||||
or
|
||||
this.(RawIndirectInstruction).getInstruction() = block.getInstruction(i)
|
||||
or
|
||||
this.(PostUpdateNode).getPreUpdateNode().hasIndexInBlock(block, i)
|
||||
}
|
||||
|
||||
/** Gets the basic block of this node, if any. */
|
||||
final IRBlock getBasicBlock() { this.hasIndexInBlock(result, _) }
|
||||
|
||||
/**
|
||||
* Gets the non-conversion expression corresponding to this node, if any.
|
||||
* This predicate only has a result on nodes that represent the value of
|
||||
|
@ -530,7 +552,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
|||
*/
|
||||
final Node getAnInput(boolean fromBackEdge) {
|
||||
localFlowStep(result, this) and
|
||||
if phi.getBasicBlock().dominates(getBasicBlock(result))
|
||||
if phi.getBasicBlock().dominates(result.getBasicBlock())
|
||||
then fromBackEdge = true
|
||||
else fromBackEdge = false
|
||||
}
|
||||
|
@ -1887,7 +1909,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
|||
e = value.getAnInstruction().getConvertedResultExpression() and
|
||||
result.getConvertedExpr() = e and
|
||||
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
|
||||
g.controls(getBasicBlock(result), edge)
|
||||
g.controls(result.getBasicBlock(), edge)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -606,9 +606,9 @@ newtype TTranslatedElement =
|
|||
not ignoreExpr(expr) and
|
||||
(
|
||||
exists(Initializer init | init.getExpr().getFullyConverted() = expr) or
|
||||
exists(ClassAggregateLiteral initList | initList.getFieldExpr(_).getFullyConverted() = expr) or
|
||||
exists(ClassAggregateLiteral initList | initList.getAFieldExpr(_).getFullyConverted() = expr) or
|
||||
exists(ArrayOrVectorAggregateLiteral initList |
|
||||
initList.getElementExpr(_).getFullyConverted() = expr
|
||||
initList.getAnElementExpr(_).getFullyConverted() = expr
|
||||
) or
|
||||
exists(ReturnStmt returnStmt | returnStmt.getExpr().getFullyConverted() = expr) or
|
||||
exists(ConstructorFieldInit fieldInit | fieldInit.getExpr().getFullyConverted() = expr) or
|
||||
|
@ -619,18 +619,19 @@ newtype TTranslatedElement =
|
|||
)
|
||||
} or
|
||||
// The initialization of a field via a member of an initializer list.
|
||||
TTranslatedExplicitFieldInitialization(Expr ast, Field field, Expr expr) {
|
||||
TTranslatedExplicitFieldInitialization(Expr ast, Field field, Expr expr, int position) {
|
||||
exists(ClassAggregateLiteral initList |
|
||||
not ignoreExpr(initList) and
|
||||
ast = initList and
|
||||
expr = initList.getFieldExpr(field).getFullyConverted()
|
||||
expr = initList.getFieldExpr(field, position).getFullyConverted()
|
||||
)
|
||||
or
|
||||
exists(ConstructorFieldInit init |
|
||||
not ignoreExpr(init) and
|
||||
ast = init and
|
||||
field = init.getTarget() and
|
||||
expr = init.getExpr().getFullyConverted()
|
||||
expr = init.getExpr().getFullyConverted() and
|
||||
position = -1
|
||||
)
|
||||
} or
|
||||
// The value initialization of a field due to an omitted member of an
|
||||
|
@ -643,9 +644,11 @@ newtype TTranslatedElement =
|
|||
)
|
||||
} or
|
||||
// The initialization of an array element via a member of an initializer list.
|
||||
TTranslatedExplicitElementInitialization(ArrayOrVectorAggregateLiteral initList, int elementIndex) {
|
||||
TTranslatedExplicitElementInitialization(
|
||||
ArrayOrVectorAggregateLiteral initList, int elementIndex, int position
|
||||
) {
|
||||
not ignoreExpr(initList) and
|
||||
exists(initList.getElementExpr(elementIndex))
|
||||
exists(initList.getElementExpr(elementIndex, position))
|
||||
} or
|
||||
// The value initialization of a range of array elements that were omitted
|
||||
// from an initializer list.
|
||||
|
@ -782,7 +785,7 @@ private int getNextExplicitlyInitializedElementAfter(
|
|||
ArrayOrVectorAggregateLiteral initList, int afterElementIndex
|
||||
) {
|
||||
isFirstValueInitializedElementInRange(initList, afterElementIndex) and
|
||||
result = min(int i | exists(initList.getElementExpr(i)) and i > afterElementIndex)
|
||||
result = min(int i | exists(initList.getAnElementExpr(i)) and i > afterElementIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -795,7 +798,7 @@ private predicate isFirstValueInitializedElementInRange(
|
|||
initList.isValueInitialized(elementIndex) and
|
||||
(
|
||||
elementIndex = 0 or
|
||||
exists(initList.getElementExpr(elementIndex - 1))
|
||||
exists(initList.getAnElementExpr(elementIndex - 1))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -201,11 +201,13 @@ class TranslatedClassListInitialization extends TranslatedListInitialization {
|
|||
override ClassAggregateLiteral expr;
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
exists(TranslatedFieldInitialization fieldInit |
|
||||
result = fieldInit and
|
||||
fieldInit = getTranslatedFieldInitialization(expr, _) and
|
||||
fieldInit.getOrder() = id
|
||||
)
|
||||
result =
|
||||
rank[id + 1](TranslatedFieldInitialization fieldInit, int ord |
|
||||
fieldInit = getTranslatedFieldInitialization(expr, _) and
|
||||
fieldInit.getOrder() = ord
|
||||
|
|
||||
fieldInit order by ord, fieldInit.getPosition()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,7 +224,7 @@ class TranslatedArrayListInitialization extends TranslatedListInitialization {
|
|||
rank[id + 1](TranslatedElementInitialization init |
|
||||
init.getInitList() = expr
|
||||
|
|
||||
init order by init.getElementIndex()
|
||||
init order by init.getElementIndex(), init.getPosition()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -522,6 +524,9 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
|
|||
final InstructionTag getFieldAddressTag() { result = InitializerFieldAddressTag() }
|
||||
|
||||
final Field getField() { result = field }
|
||||
|
||||
/** Gets the position in the initializer list, or `-1` if the initialization is implicit. */
|
||||
int getPosition() { result = -1 }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -532,9 +537,10 @@ class TranslatedExplicitFieldInitialization extends TranslatedFieldInitializatio
|
|||
InitializationContext, TTranslatedExplicitFieldInitialization
|
||||
{
|
||||
Expr expr;
|
||||
int position;
|
||||
|
||||
TranslatedExplicitFieldInitialization() {
|
||||
this = TTranslatedExplicitFieldInitialization(ast, field, expr)
|
||||
this = TTranslatedExplicitFieldInitialization(ast, field, expr, position)
|
||||
}
|
||||
|
||||
override Instruction getTargetAddress() { result = getInstruction(getFieldAddressTag()) }
|
||||
|
@ -556,6 +562,8 @@ class TranslatedExplicitFieldInitialization extends TranslatedFieldInitializatio
|
|||
private TranslatedInitialization getInitialization() {
|
||||
result = getTranslatedInitialization(expr)
|
||||
}
|
||||
|
||||
override int getPosition() { result = position }
|
||||
}
|
||||
|
||||
private string getZeroValue(Type type) {
|
||||
|
@ -689,6 +697,8 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
|
|||
|
||||
abstract int getElementIndex();
|
||||
|
||||
int getPosition() { result = -1 }
|
||||
|
||||
final InstructionTag getElementAddressTag() { result = InitializerElementAddressTag() }
|
||||
|
||||
final InstructionTag getElementIndexTag() { result = InitializerElementIndexTag() }
|
||||
|
@ -706,9 +716,10 @@ class TranslatedExplicitElementInitialization extends TranslatedElementInitializ
|
|||
TTranslatedExplicitElementInitialization, InitializationContext
|
||||
{
|
||||
int elementIndex;
|
||||
int position;
|
||||
|
||||
TranslatedExplicitElementInitialization() {
|
||||
this = TTranslatedExplicitElementInitialization(initList, elementIndex)
|
||||
this = TTranslatedExplicitElementInitialization(initList, elementIndex, position)
|
||||
}
|
||||
|
||||
override Instruction getTargetAddress() { result = getInstruction(getElementAddressTag()) }
|
||||
|
@ -731,8 +742,13 @@ class TranslatedExplicitElementInitialization extends TranslatedElementInitializ
|
|||
|
||||
override int getElementIndex() { result = elementIndex }
|
||||
|
||||
override int getPosition() { result = position }
|
||||
|
||||
TranslatedInitialization getInitialization() {
|
||||
result = getTranslatedInitialization(initList.getElementExpr(elementIndex).getFullyConverted())
|
||||
result =
|
||||
getTranslatedInitialization(initList
|
||||
.getElementExpr(elementIndex, position)
|
||||
.getFullyConverted())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import experimental.semmle.code.cpp.semantic.SemanticBound
|
||||
private import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
|
||||
private import RangeAnalysis
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
||||
|
||||
/**
|
||||
* Gets the lower bound of the expression.
|
|
@ -5,7 +5,7 @@
|
|||
private import cpp as Cpp
|
||||
private import semmle.code.cpp.ir.IR as IR
|
||||
private import Semantic
|
||||
private import experimental.semmle.code.cpp.rangeanalysis.Bound as IRBound
|
||||
private import analysis.Bound as IRBound
|
||||
private import semmle.code.cpp.controlflow.IRGuards as IRGuards
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
|
||||
private newtype TBound =
|
||||
TBoundZero() or
|
||||
TBoundValueNumber(ValueNumber vn) {
|
||||
exists(Instruction i |
|
||||
vn.getAnInstruction() = i and
|
||||
(
|
||||
i.getResultIRType() instanceof IRIntegerType or
|
||||
i.getResultIRType() instanceof IRAddressType
|
||||
) and
|
||||
not vn.getAnInstruction() instanceof ConstantInstruction
|
||||
|
|
||||
i instanceof PhiInstruction
|
||||
or
|
||||
i instanceof InitializeParameterInstruction
|
||||
or
|
||||
i instanceof CallInstruction
|
||||
or
|
||||
i instanceof VariableAddressInstruction
|
||||
or
|
||||
i instanceof FieldAddressInstruction
|
||||
or
|
||||
i.(LoadInstruction).getSourceAddress() instanceof VariableAddressInstruction
|
||||
or
|
||||
i.(LoadInstruction).getSourceAddress() instanceof FieldAddressInstruction
|
||||
or
|
||||
i.getAUse() instanceof ArgumentOperand
|
||||
or
|
||||
i instanceof PointerArithmeticInstruction
|
||||
or
|
||||
i.getAUse() instanceof AddressOperand
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A bound that may be inferred for an expression plus/minus an integer delta.
|
||||
*/
|
||||
abstract class Bound extends TBound {
|
||||
abstract string toString();
|
||||
|
||||
/** Gets an expression that equals this bound plus `delta`. */
|
||||
abstract Instruction getInstruction(int delta);
|
||||
|
||||
/** Gets an expression that equals this bound. */
|
||||
Instruction getInstruction() { result = getInstruction(0) }
|
||||
|
||||
abstract Location getLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* The bound that corresponds to the integer 0. This is used to represent all
|
||||
* integer bounds as bounds are always accompanied by an added integer delta.
|
||||
*/
|
||||
class ZeroBound extends Bound, TBoundZero {
|
||||
override string toString() { result = "0" }
|
||||
|
||||
override Instruction getInstruction(int delta) {
|
||||
result.(ConstantValueInstruction).getValue().toInt() = delta
|
||||
}
|
||||
|
||||
override Location getLocation() { result instanceof UnknownDefaultLocation }
|
||||
}
|
||||
|
||||
/**
|
||||
* A bound corresponding to the value of an `Instruction`.
|
||||
*/
|
||||
class ValueNumberBound extends Bound, TBoundValueNumber {
|
||||
ValueNumber vn;
|
||||
|
||||
ValueNumberBound() { this = TBoundValueNumber(vn) }
|
||||
|
||||
/** Gets an `Instruction` that equals this bound. */
|
||||
override Instruction getInstruction(int delta) {
|
||||
this = TBoundValueNumber(valueNumber(result)) and delta = 0
|
||||
}
|
||||
|
||||
override string toString() { result = "ValueNumberBound" }
|
||||
|
||||
override Location getLocation() { result = vn.getLocation() }
|
||||
|
||||
/** Gets the value number that equals this bound. */
|
||||
ValueNumber getValueNumber() { result = vn }
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
* Simple constant analysis using the Semantic interface.
|
||||
*/
|
||||
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
private import ConstantAnalysisSpecific as Specific
|
||||
|
||||
/** An expression that always has the same integer value. */
|
|
@ -2,7 +2,7 @@
|
|||
* C++-specific implementation of constant analysis.
|
||||
*/
|
||||
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
|
||||
/**
|
||||
* Gets the constant integer value of the specified expression, if any.
|
|
@ -11,7 +11,7 @@
|
|||
*/
|
||||
|
||||
private import ModulusAnalysisSpecific::Private
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
private import ConstantAnalysis
|
||||
private import RangeUtils
|
||||
private import RangeAnalysisStage
|
|
@ -2,7 +2,7 @@
|
|||
* C++-specific implementation of modulus analysis.
|
||||
*/
|
||||
module Private {
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
|
||||
predicate ignoreExprModulus(SemExpr e) { none() }
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
import RangeAnalysisImpl
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound
|
|
@ -1,10 +1,10 @@
|
|||
private import RangeAnalysisStage
|
||||
private import RangeAnalysisSpecific
|
||||
private import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||
private import RangeUtils
|
||||
private import experimental.semmle.code.cpp.semantic.SemanticBound as SemanticBound
|
||||
private import experimental.semmle.code.cpp.semantic.SemanticLocation
|
||||
private import experimental.semmle.code.cpp.semantic.SemanticSSA
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound as SemanticBound
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticLocation
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticSSA
|
||||
|
||||
module ConstantBounds implements BoundSig<FloatDelta> {
|
||||
class SemBound instanceof SemanticBound::SemBound {
|
|
@ -2,9 +2,9 @@
|
|||
* C++-specific implementation of range analysis.
|
||||
*/
|
||||
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
private import RangeAnalysisStage
|
||||
private import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||
|
||||
module CppLangImpl implements LangSig<FloatDelta> {
|
||||
/**
|
|
@ -65,15 +65,15 @@
|
|||
|
||||
private import RangeUtils as Utils
|
||||
private import SignAnalysisCommon
|
||||
private import experimental.semmle.code.cpp.semantic.analysis.ModulusAnalysis
|
||||
import experimental.semmle.code.cpp.semantic.SemanticExpr
|
||||
import experimental.semmle.code.cpp.semantic.SemanticSSA
|
||||
import experimental.semmle.code.cpp.semantic.SemanticGuard
|
||||
import experimental.semmle.code.cpp.semantic.SemanticCFG
|
||||
import experimental.semmle.code.cpp.semantic.SemanticType
|
||||
import experimental.semmle.code.cpp.semantic.SemanticOpcode
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.ModulusAnalysis
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExpr
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticSSA
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticGuard
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticCFG
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticType
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticOpcode
|
||||
private import ConstantAnalysis
|
||||
import experimental.semmle.code.cpp.semantic.SemanticLocation
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticLocation
|
||||
|
||||
/**
|
||||
* Holds if `typ` is a small integral type with the given lower and upper bounds.
|
|
@ -2,7 +2,7 @@
|
|||
* Provides utility predicates for range analysis.
|
||||
*/
|
||||
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
private import RangeAnalysisSpecific
|
||||
private import RangeAnalysisStage as Range
|
||||
private import ConstantAnalysis
|
|
@ -1,4 +1,4 @@
|
|||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
|
||||
newtype TSign =
|
||||
TNeg() or
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
private import RangeAnalysisStage
|
||||
private import SignAnalysisSpecific as Specific
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
private import ConstantAnalysis
|
||||
private import RangeUtils
|
||||
private import Sign
|
|
@ -2,7 +2,7 @@
|
|||
* Provides C++-specific definitions for use in sign analysis.
|
||||
*/
|
||||
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
|
||||
/**
|
||||
* Workaround to allow certain expressions to have a negative sign, even if the type of the
|
|
@ -314,9 +314,8 @@ class FreadBA extends BufferAccess {
|
|||
* but not:
|
||||
* &buffer[ix]
|
||||
*/
|
||||
class ArrayExprBA extends BufferAccess {
|
||||
class ArrayExprBA extends BufferAccess, ArrayExpr {
|
||||
ArrayExprBA() {
|
||||
exists(this.(ArrayExpr).getArrayOffset().getValue().toInt()) and
|
||||
not exists(AddressOfExpr aoe | aoe.getAChild() = this) and
|
||||
// exclude accesses in macro implementation of `strcmp`,
|
||||
// which are carefully controlled but can look dangerous.
|
||||
|
|
|
@ -741,7 +741,7 @@ private predicate mk_FieldCons(
|
|||
analyzableClassAggregateLiteral(cal) and
|
||||
cal.getUnspecifiedType() = c and
|
||||
exists(Expr e |
|
||||
e = cal.getFieldExpr(f).getFullyConverted() and
|
||||
e = cal.getAFieldExpr(f).getFullyConverted() and
|
||||
f.getInitializationOrder() = i and
|
||||
(
|
||||
hc = hashCons(e) and
|
||||
|
@ -757,9 +757,9 @@ private predicate mk_FieldCons(
|
|||
private predicate analyzableClassAggregateLiteral(ClassAggregateLiteral cal) {
|
||||
forall(int i | exists(cal.getChild(i)) |
|
||||
strictcount(cal.getChild(i).getFullyConverted()) = 1 and
|
||||
strictcount(Field f | cal.getChild(i) = cal.getFieldExpr(f)) = 1 and
|
||||
strictcount(Field f | cal.getChild(i) = cal.getAFieldExpr(f)) = 1 and
|
||||
strictcount(Field f, int j |
|
||||
cal.getFieldExpr(f) = cal.getChild(i) and j = f.getInitializationOrder()
|
||||
cal.getAFieldExpr(f) = cal.getChild(i) and j = f.getInitializationOrder()
|
||||
) = 1
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1820,24 +1820,26 @@ new_array_allocated_type(
|
|||
|
||||
/**
|
||||
* The field being initialized by an initializer expression within an aggregate
|
||||
* initializer for a class/struct/union.
|
||||
* initializer for a class/struct/union. Position is used to sort repeated initializers.
|
||||
*/
|
||||
#keyset[aggregate, field]
|
||||
#keyset[aggregate, position]
|
||||
aggregate_field_init(
|
||||
int aggregate: @aggregateliteral ref,
|
||||
int initializer: @expr ref,
|
||||
int field: @membervariable ref
|
||||
int field: @membervariable ref,
|
||||
int position: int ref
|
||||
);
|
||||
|
||||
/**
|
||||
* The index of the element being initialized by an initializer expression
|
||||
* within an aggregate initializer for an array.
|
||||
* within an aggregate initializer for an array. Position is used to sort repeated initializers.
|
||||
*/
|
||||
#keyset[aggregate, element_index]
|
||||
#keyset[aggregate, position]
|
||||
aggregate_array_init(
|
||||
int aggregate: @aggregateliteral ref,
|
||||
int initializer: @expr ref,
|
||||
int element_index: int ref
|
||||
int element_index: int ref,
|
||||
int position: int ref
|
||||
);
|
||||
|
||||
@ctorinit = @ctordirectinit
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,11 @@
|
|||
class AggregateLiteral extends @aggregateliteral {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Expr extends @expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from AggregateLiteral al, Expr init, int index, int position
|
||||
where exprparents(init, position, al) and aggregate_array_init(al, init, index)
|
||||
select al, init, index, position
|
|
@ -0,0 +1,15 @@
|
|||
class AggregateLiteral extends @aggregateliteral {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Expr extends @expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Field extends @membervariable {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from AggregateLiteral al, Expr init, Field field, int position
|
||||
where exprparents(init, position, al) and aggregate_field_init(al, init, field)
|
||||
select al, init, field, position
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,4 @@
|
|||
description: Support repeated initializers, which are allowed in C with designated initializers.
|
||||
compatibility: full
|
||||
aggregate_field_init.rel: run aggregate_field_init.qlo
|
||||
aggregate_array_init.rel: run aggregate_array_init.qlo
|
|
@ -1,3 +1,7 @@
|
|||
## 0.5.6
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.5.5
|
||||
|
||||
### Deprecated Queries
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
int* f() {
|
||||
int *buff = malloc(SIZE*sizeof(int));
|
||||
do_stuff(buff);
|
||||
free(buff);
|
||||
int *new_buffer = malloc(SIZE*sizeof(int));
|
||||
free(buff); // BAD: If new_buffer is assigned the same address as buff,
|
||||
// the memory allocator will free the new buffer memory region,
|
||||
// leading to use-after-free problems and memory corruption.
|
||||
return new_buffer;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Deallocating memory more than once can lead to a double-free vulnerability. This can be exploited to
|
||||
corrupt the allocator's internal data structures, which can lead to denial-of-service attacks by crashing
|
||||
the program, or security vulnerabilities, by allowing an attacker to overwrite arbitrary memory locations.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>
|
||||
Ensure that all execution paths deallocate the allocated memory at most once. If possible, reassign
|
||||
the pointer to a null value after deallocating it. This will prevent double-free vulnerabilities since
|
||||
most deallocation functions will perform a null-pointer check before attempting to deallocate the memory.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
<example><sample src="DoubleFree.cpp" />
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
OWASP:
|
||||
<a href="https://owasp.org/www-community/vulnerabilities/Doubly_freeing_memory">Doubly freeing memory</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* @name Potential double free
|
||||
* @description Freeing a resource more than once can lead to undefined behavior and cause memory corruption.
|
||||
* @kind path-problem
|
||||
* @precision medium
|
||||
* @id cpp/double-free
|
||||
* @problem.severity warning
|
||||
* @security-severity 9.3
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-415
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
import FlowAfterFree
|
||||
import DoubleFree::PathGraph
|
||||
|
||||
predicate isFree(DataFlow::Node n, Expr e) { isFree(n, e, _) }
|
||||
|
||||
/**
|
||||
* `dealloc1` is a deallocation expression and `e` is an expression such
|
||||
* that is deallocated by a deallocation expression, and the `(dealloc1, e)` pair
|
||||
* should be excluded by the `FlowFromFree` library.
|
||||
*
|
||||
* Note that `e` is not necessarily the expression deallocated by `dealloc1`. It will
|
||||
* be bound to the second deallocation as identified by the `FlowFromFree` library.
|
||||
*/
|
||||
bindingset[dealloc1, e]
|
||||
predicate isExcludeFreePair(DeallocationExpr dealloc1, Expr e) {
|
||||
exists(DeallocationExpr dealloc2 | isFree(_, e, dealloc2) |
|
||||
dealloc1.(FunctionCall).getTarget().hasGlobalName("MmFreePagesFromMdl") and
|
||||
// From https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-mmfreepagesfrommdl:
|
||||
// "After calling MmFreePagesFromMdl, the caller must also call ExFreePool
|
||||
// to release the memory that was allocated for the MDL structure."
|
||||
isExFreePoolCall(dealloc2, _)
|
||||
)
|
||||
}
|
||||
|
||||
module DoubleFree = FlowFromFree<isFree/2, isExcludeFreePair/2>;
|
||||
|
||||
from DoubleFree::PathNode source, DoubleFree::PathNode sink, DeallocationExpr dealloc, Expr e2
|
||||
where
|
||||
DoubleFree::flowPath(source, sink) and
|
||||
isFree(source.getNode(), _, dealloc) and
|
||||
isFree(sink.getNode(), e2)
|
||||
select sink.getNode(), source, sink,
|
||||
"Memory pointed to by '" + e2.toString() + "' may already have been freed by $@.", dealloc,
|
||||
dealloc.toString()
|
|
@ -0,0 +1,129 @@
|
|||
import cpp
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
private import semmle.code.cpp.ir.IR
|
||||
|
||||
/**
|
||||
* Signature for a predicate that holds if `n.asExpr() = e` and `n` is a sink in
|
||||
* the `FlowFromFreeConfig` module.
|
||||
*/
|
||||
private signature predicate isSinkSig(DataFlow::Node n, Expr e);
|
||||
|
||||
/**
|
||||
* Holds if `dealloc` is a deallocation expression and `e` is an expression such
|
||||
* that `isFree(_, e)` holds for some `isFree` predicate satisfying `isSinkSig`,
|
||||
* and this source-sink pair should be excluded from the analysis.
|
||||
*/
|
||||
bindingset[dealloc, e]
|
||||
private signature predicate isExcludedSig(DeallocationExpr dealloc, Expr e);
|
||||
|
||||
/**
|
||||
* Holds if `(b1, i1)` strictly post-dominates `(b2, i2)`
|
||||
*/
|
||||
bindingset[i1, i2]
|
||||
predicate strictlyPostDominates(IRBlock b1, int i1, IRBlock b2, int i2) {
|
||||
b1 = b2 and
|
||||
i1 > i2
|
||||
or
|
||||
b1.strictlyPostDominates(b2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(b1, i1)` strictly dominates `(b2, i2)`
|
||||
*/
|
||||
bindingset[i1, i2]
|
||||
predicate strictlyDominates(IRBlock b1, int i1, IRBlock b2, int i2) {
|
||||
b1 = b2 and
|
||||
i1 < i2
|
||||
or
|
||||
b1.strictlyDominates(b2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a `FlowFromFreeConfig` module that can be used to find flow between
|
||||
* a pointer being freed by some deallocation function, and a user-specified sink.
|
||||
*
|
||||
* In order to reduce false positives, the set of sinks is restricted to only those
|
||||
* that satisfy at least one of the following two criteria:
|
||||
* 1. The source dominates the sink, or
|
||||
* 2. The sink post-dominates the source.
|
||||
*/
|
||||
module FlowFromFree<isSinkSig/2 isASink, isExcludedSig/2 isExcluded> {
|
||||
module FlowFromFreeConfig implements DataFlow::StateConfigSig {
|
||||
class FlowState instanceof Expr {
|
||||
FlowState() { isFree(_, this, _) }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
}
|
||||
|
||||
predicate isSource(DataFlow::Node node, FlowState state) { isFree(node, state, _) }
|
||||
|
||||
pragma[inline]
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
exists(
|
||||
Expr e, DataFlow::Node source, IRBlock b1, int i1, IRBlock b2, int i2,
|
||||
DeallocationExpr dealloc
|
||||
|
|
||||
isASink(sink, e) and
|
||||
isFree(source, state, dealloc) and
|
||||
e != state and
|
||||
source.hasIndexInBlock(b1, i1) and
|
||||
sink.hasIndexInBlock(b2, i2) and
|
||||
not isExcluded(dealloc, e)
|
||||
|
|
||||
strictlyDominates(b1, i1, b2, i2)
|
||||
or
|
||||
strictlyPostDominates(b2, i2, b1, i1)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node n) {
|
||||
n.asIndirectExpr() = any(AddressOfExpr aoe)
|
||||
or
|
||||
n.asIndirectExpr() = any(Call call).getAnArgument()
|
||||
or
|
||||
exists(Expr e |
|
||||
n.asIndirectExpr() = e.(PointerDereferenceExpr).getOperand() or
|
||||
n.asIndirectExpr() = e.(ArrayExpr).getArrayBase()
|
||||
|
|
||||
e = any(StoreInstruction store).getDestinationAddress().getUnconvertedResultExpression()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node n, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node n1, FlowState state1, DataFlow::Node n2, FlowState state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
import DataFlow::GlobalWithState<FlowFromFreeConfig>
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` is a dataflow node such that `n.asExpr() = e` and `e`
|
||||
* is being freed by a deallocation expression `dealloc`.
|
||||
*/
|
||||
predicate isFree(DataFlow::Node n, Expr e, DeallocationExpr dealloc) {
|
||||
e = dealloc.getFreedExpr() and
|
||||
e = n.asExpr() and
|
||||
// Ignore realloc functions
|
||||
not exists(dealloc.(FunctionCall).getTarget().(AllocationFunction).getReallocPtrArg())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `fc` is a function call that is the result of expanding
|
||||
* the `ExFreePool` macro.
|
||||
*/
|
||||
predicate isExFreePoolCall(FunctionCall fc, Expr e) {
|
||||
e = fc.getArgument(0) and
|
||||
(
|
||||
exists(MacroInvocation mi |
|
||||
mi.getMacroName() = "ExFreePool" and
|
||||
mi.getExpr() = fc
|
||||
)
|
||||
or
|
||||
fc.getTarget().hasGlobalName("ExFreePool")
|
||||
)
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
/**
|
||||
* @name Potential use after free
|
||||
* @description An allocated memory block is used after it has been freed. Behavior in such cases is undefined and can cause memory corruption.
|
||||
* @kind problem
|
||||
* @kind path-problem
|
||||
* @precision medium
|
||||
* @id cpp/use-after-free
|
||||
* @problem.severity warning
|
||||
* @security-severity 9.3
|
||||
|
@ -11,56 +12,158 @@
|
|||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
import semmle.code.cpp.ir.IR
|
||||
import FlowAfterFree
|
||||
import UseAfterFree::PathGraph
|
||||
|
||||
/** `e` is an expression that frees the memory pointed to by `v`. */
|
||||
predicate isFreeExpr(Expr e, StackVariable v) {
|
||||
exists(VariableAccess va | va.getTarget() = v |
|
||||
exists(FunctionCall fc | fc = e |
|
||||
fc.getTarget().hasGlobalOrStdName("free") and
|
||||
va = fc.getArgument(0)
|
||||
)
|
||||
or
|
||||
e.(DeleteExpr).getExpr() = va
|
||||
or
|
||||
e.(DeleteArrayExpr).getExpr() = va
|
||||
/**
|
||||
* Holds if `call` is a call to a function that obviously
|
||||
* doesn't dereference its `i`'th argument.
|
||||
*/
|
||||
private predicate externalCallNeverDereferences(FormattingFunctionCall call, int arg) {
|
||||
exists(int formatArg |
|
||||
pragma[only_bind_out](call.getFormatArgument(formatArg)) =
|
||||
pragma[only_bind_out](call.getArgument(arg)) and
|
||||
call.getFormat().(FormatLiteral).getConvSpec(formatArg) != "%s"
|
||||
)
|
||||
}
|
||||
|
||||
/** `e` is an expression that (may) dereference `v`. */
|
||||
predicate isDerefExpr(Expr e, StackVariable v) {
|
||||
v.getAnAccess() = e and dereferenced(e)
|
||||
or
|
||||
isDerefByCallExpr(_, _, e, v)
|
||||
predicate isUse0(DataFlow::Node n, Expr e) {
|
||||
e = n.asExpr() and
|
||||
not isFree(_, e, _) and
|
||||
(
|
||||
e = any(PointerDereferenceExpr pde).getOperand()
|
||||
or
|
||||
e = any(PointerFieldAccess pfa).getQualifier()
|
||||
or
|
||||
e = any(ArrayExpr ae).getArrayBase()
|
||||
or
|
||||
e = any(Call call).getQualifier()
|
||||
or
|
||||
// Assume any function without a body will dereference the pointer
|
||||
exists(int i, Call call, Function f |
|
||||
n.asExpr() = call.getArgument(i) and
|
||||
f = call.getTarget() and
|
||||
not f.hasEntryPoint() and
|
||||
// Exclude known functions we know won't dereference the pointer.
|
||||
// For example, a call such as `printf("%p", myPointer)`.
|
||||
not externalCallNeverDereferences(call, i)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* `va` is passed by value as (part of) the `i`th argument in
|
||||
* call `c`. The target function is either a library function
|
||||
* or a source code function that dereferences the relevant
|
||||
* parameter.
|
||||
*/
|
||||
predicate isDerefByCallExpr(Call c, int i, VariableAccess va, StackVariable v) {
|
||||
v.getAnAccess() = va and
|
||||
va = c.getAnArgumentSubExpr(i) and
|
||||
not c.passesByReference(i, va) and
|
||||
(c.getTarget().hasEntryPoint() implies isDerefExpr(_, c.getTarget().getParameter(i)))
|
||||
}
|
||||
module ParameterSinks {
|
||||
import semmle.code.cpp.ir.ValueNumbering
|
||||
|
||||
class UseAfterFreeReachability extends StackVariableReachability {
|
||||
UseAfterFreeReachability() { this = "UseAfterFree" }
|
||||
predicate flowsToUse(DataFlow::Node n) {
|
||||
isUse0(n, _)
|
||||
or
|
||||
exists(DataFlow::Node succ |
|
||||
flowsToUse(succ) and
|
||||
DataFlow::localFlowStep(n, succ)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSource(ControlFlowNode node, StackVariable v) { isFreeExpr(node, v) }
|
||||
private predicate flowsFromParam(DataFlow::Node n) {
|
||||
flowsToUse(n) and
|
||||
(
|
||||
n.asParameter().getUnspecifiedType() instanceof PointerType
|
||||
or
|
||||
exists(DataFlow::Node prev |
|
||||
flowsFromParam(prev) and
|
||||
DataFlow::localFlowStep(prev, n)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(ControlFlowNode node, StackVariable v) { isDerefExpr(node, v) }
|
||||
private predicate step(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
flowsFromParam(n1) and
|
||||
flowsFromParam(n2) and
|
||||
DataFlow::localFlowStep(n1, n2)
|
||||
}
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
|
||||
definitionBarrier(v, node) or
|
||||
isFreeExpr(node, v)
|
||||
private predicate paramToUse(DataFlow::Node n1, DataFlow::Node n2) = fastTC(step/2)(n1, n2)
|
||||
|
||||
private predicate hasFlow(
|
||||
DataFlow::Node source, InitializeParameterInstruction init, DataFlow::Node sink
|
||||
) {
|
||||
pragma[only_bind_out](source.asParameter()) = pragma[only_bind_out](init.getParameter()) and
|
||||
paramToUse(source, sink) and
|
||||
isUse0(sink, _)
|
||||
}
|
||||
|
||||
private InitializeParameterInstruction getAnAlwaysDereferencedParameter0() {
|
||||
exists(DataFlow::Node source, DataFlow::Node sink, IRBlock b1, int i1, IRBlock b2, int i2 |
|
||||
hasFlow(pragma[only_bind_into](source), result, pragma[only_bind_into](sink)) and
|
||||
source.hasIndexInBlock(b1, pragma[only_bind_into](i1)) and
|
||||
sink.hasIndexInBlock(b2, pragma[only_bind_into](i2)) and
|
||||
strictlyPostDominates(b2, i2, b1, i1)
|
||||
)
|
||||
}
|
||||
|
||||
private CallInstruction getAnAlwaysReachedCallInstruction(IRFunction f) {
|
||||
result.getBlock().postDominates(f.getEntryBlock())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate callHasTargetAndArgument(Function f, int i, CallInstruction call, Instruction argument) {
|
||||
call.getStaticCallTarget() = f and
|
||||
call.getArgument(i) = argument
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate initializeParameterInFunction(Function f, int i, InitializeParameterInstruction init) {
|
||||
pragma[only_bind_out](init.getEnclosingFunction()) = f and
|
||||
init.hasIndex(i)
|
||||
}
|
||||
|
||||
InitializeParameterInstruction getAnAlwaysDereferencedParameter() {
|
||||
result = getAnAlwaysDereferencedParameter0()
|
||||
or
|
||||
exists(
|
||||
CallInstruction call, int i, InitializeParameterInstruction p, Instruction argument,
|
||||
Function f
|
||||
|
|
||||
callHasTargetAndArgument(f, i, call, argument) and
|
||||
initializeParameterInFunction(f, i, p) and
|
||||
p = getAnAlwaysDereferencedParameter() and
|
||||
result = pragma[only_bind_out](valueNumber(argument).getAnInstruction()) and
|
||||
call = getAnAlwaysReachedCallInstruction(_)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from UseAfterFreeReachability r, StackVariable v, Expr free, Expr e
|
||||
where r.reaches(free, v, e)
|
||||
select e, "Memory pointed to by '" + v.getName().toString() + "' may have $@.", free,
|
||||
"been previously freed"
|
||||
predicate isUse(DataFlow::Node n, Expr e) {
|
||||
isUse0(n, e)
|
||||
or
|
||||
exists(CallInstruction call, int i, InitializeParameterInstruction init |
|
||||
n.asOperand().getDef().getUnconvertedResultExpression() = e and
|
||||
init = ParameterSinks::getAnAlwaysDereferencedParameter() and
|
||||
call.getArgumentOperand(i) = n.asOperand() and
|
||||
init.hasIndex(i) and
|
||||
init.getEnclosingFunction() = call.getStaticCallTarget()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* `dealloc1` is a deallocation expression, `e` is an expression that dereferences a
|
||||
* pointer, and the `(dealloc1, e)` pair should be excluded by the `FlowFromFree` library.
|
||||
*/
|
||||
bindingset[dealloc1, e]
|
||||
predicate isExcludeFreeUsePair(DeallocationExpr dealloc1, Expr e) {
|
||||
// From https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-mmfreepagesfrommdl:
|
||||
// "After calling MmFreePagesFromMdl, the caller must also call ExFreePool
|
||||
// to release the memory that was allocated for the MDL structure."
|
||||
dealloc1.(FunctionCall).getTarget().hasGlobalName("MmFreePagesFromMdl") and
|
||||
isExFreePoolCall(_, e)
|
||||
}
|
||||
|
||||
module UseAfterFree = FlowFromFree<isUse/2, isExcludeFreeUsePair/2>;
|
||||
|
||||
from UseAfterFree::PathNode source, UseAfterFree::PathNode sink, DeallocationExpr dealloc
|
||||
where
|
||||
UseAfterFree::flowPath(source, sink) and
|
||||
isFree(source.getNode(), _, dealloc)
|
||||
select sink.getNode(), source, sink, "Memory may have been previously freed by $@.", dealloc,
|
||||
dealloc.toString()
|
||||
|
|
|
@ -3,23 +3,21 @@
|
|||
* @description Checking a pointer for nullness after dereferencing it is
|
||||
* likely to be a sign that either the check can be removed, or
|
||||
* it should be moved before the dereference.
|
||||
* @kind problem
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id cpp/redundant-null-check-simple
|
||||
* @tags reliability
|
||||
* correctness
|
||||
* external/cwe/cwe-476
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note: this query is not assigned a precision yet because we don't want it
|
||||
* to be included in query suites until its performance is well understood.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.ir.ValueNumbering
|
||||
import PathGraph
|
||||
|
||||
/** An instruction that represents a null pointer. */
|
||||
class NullInstruction extends ConstantValueInstruction {
|
||||
NullInstruction() {
|
||||
this.getValue() = "0" and
|
||||
|
@ -27,6 +25,10 @@ class NullInstruction extends ConstantValueInstruction {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `checked` is an instruction that is checked against a null value,
|
||||
* and `bool` is the instruction that represents the result of the comparison
|
||||
*/
|
||||
predicate explicitNullTestOfInstruction(Instruction checked, Instruction bool) {
|
||||
bool =
|
||||
any(CompareInstruction cmp |
|
||||
|
@ -49,7 +51,7 @@ predicate explicitNullTestOfInstruction(Instruction checked, Instruction bool) {
|
|||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
predicate candidateResult(LoadInstruction checked, ValueNumber value, IRBlock dominator) {
|
||||
explicitNullTestOfInstruction(checked, _) and
|
||||
not checked.getAst().isInMacroExpansion() and
|
||||
|
@ -57,6 +59,147 @@ predicate candidateResult(LoadInstruction checked, ValueNumber value, IRBlock do
|
|||
dominator.dominates(checked.getBlock())
|
||||
}
|
||||
|
||||
/**
|
||||
* This module constructs a pretty edges relation out of the results produced by
|
||||
* the `candidateResult` predicate: We create a path using the instruction successor-
|
||||
* relation from the dereference to the null check. To avoid generating very long paths,
|
||||
* we compact the edges relation so that `edges(i1, i2)` only holds when `i2` is the first
|
||||
* instruction that is control-flow reachable from `i1` with the same global value number
|
||||
* as `i1`.
|
||||
*/
|
||||
module PathGraph {
|
||||
/**
|
||||
* Holds if `deref` is a load instruction that loads a value
|
||||
* from the address `address`. This predicate is restricted to
|
||||
* those pairs for which we will end up reporting a result.
|
||||
*/
|
||||
private predicate isSource(Instruction address, LoadInstruction deref) {
|
||||
exists(ValueNumber sourceValue |
|
||||
candidateResult(_, sourceValue, deref.getBlock()) and
|
||||
sourceValue.getAnInstruction() = address and
|
||||
deref.getSourceAddress() = address
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `checked` has global value number `vn` and is an instruction that is
|
||||
* used in a check against a null value.
|
||||
*/
|
||||
private predicate isSink(LoadInstruction checked, ValueNumber vn) {
|
||||
candidateResult(checked, vn, _)
|
||||
}
|
||||
|
||||
/** Holds if `i` is control-flow reachable from a relevant `LoadInstruction`. */
|
||||
private predicate fwdFlow(Instruction i) {
|
||||
isSource(i, _)
|
||||
or
|
||||
exists(Instruction mid |
|
||||
fwdFlow(mid) and
|
||||
mid.getASuccessor() = i
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `i` is part of a path from a relevant `LoadInstruction` to a
|
||||
* check against a null value that compares a value against an instruction
|
||||
* with global value number `vn`.
|
||||
*/
|
||||
private predicate revFlow(Instruction i, ValueNumber vn) {
|
||||
fwdFlow(i) and
|
||||
(
|
||||
isSink(i, vn)
|
||||
or
|
||||
exists(Instruction mid |
|
||||
revFlow(mid, vn) and
|
||||
i.getASuccessor() = mid
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a first control-flow successor of `i` that has the same
|
||||
* global value number as `i`.
|
||||
*/
|
||||
private Instruction getASuccessor(Instruction i) {
|
||||
exists(ValueNumber vn |
|
||||
vn.getAnInstruction() = i and
|
||||
result = getASuccessorWithValueNumber(i, vn)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a first control-flow successor of `i` that has the same
|
||||
* global value number as `i`. Furthermore, `i` has global value
|
||||
* number `vn`.
|
||||
*/
|
||||
private Instruction getASuccessorWithValueNumber(Instruction i, ValueNumber vn) {
|
||||
revFlow(i, vn) and
|
||||
result = getASuccessorWithValueNumber0(vn, i.getASuccessor()) and
|
||||
vn.getAnInstruction() = i
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Instruction getASuccessorWithValueNumber0(ValueNumber vn, Instruction i) {
|
||||
result = getASuccessorIfDifferentValueNumberTC(vn, i) and
|
||||
vn.getAnInstruction() = result
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the reflexive transitive closure of `getASuccessorIfDifferentValueNumber`.
|
||||
*/
|
||||
private Instruction getASuccessorIfDifferentValueNumberTC(ValueNumber vn, Instruction i) {
|
||||
revFlow(i, vn) and
|
||||
(
|
||||
i = result and
|
||||
vn.getAnInstruction() = i
|
||||
or
|
||||
exists(Instruction mid |
|
||||
mid = getASuccessorIfDifferentValueNumber(vn, i) and
|
||||
result = getASuccessorIfDifferentValueNumberTC(vn, mid)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an instruction that is a control-flow successor of `i` and which is not assigned
|
||||
* the global value number `vn`.
|
||||
*/
|
||||
private Instruction getASuccessorIfDifferentValueNumber(ValueNumber vn, Instruction i) {
|
||||
revFlow(i, vn) and
|
||||
revFlow(result, vn) and
|
||||
not vn.getAnInstruction() = i and
|
||||
pragma[only_bind_into](result) = pragma[only_bind_into](i).getASuccessor()
|
||||
}
|
||||
|
||||
query predicate nodes(Instruction i, string key, string val) {
|
||||
revFlow(i, _) and
|
||||
key = "semmle.label" and
|
||||
val = i.getAst().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* The control-flow successor relation, compacted by stepping
|
||||
* over instruction that don't preserve the global value number.
|
||||
*
|
||||
* There is one exception to the above preservation rule: The
|
||||
* initial step from the `LoadInstruction` (that is, the sink)
|
||||
* steps to the first control-flow reachable instruction that
|
||||
* has the same value number as the load instruction's address
|
||||
* operand.
|
||||
*/
|
||||
query predicate edges(Instruction i1, Instruction i2) {
|
||||
getASuccessor(i1) = i2
|
||||
or
|
||||
// We could write `isSource(i2, i1)` here, but that would
|
||||
// include a not-very-informative step from `*p` to `p`.
|
||||
// So we collapse `*p` -> `p` -> `q` to `*p` -> `q`.
|
||||
exists(Instruction mid |
|
||||
isSource(mid, i1) and
|
||||
getASuccessor(mid) = i2
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from LoadInstruction checked, LoadInstruction deref, ValueNumber sourceValue, IRBlock dominator
|
||||
where
|
||||
candidateResult(checked, sourceValue, dominator) and
|
||||
|
@ -67,5 +210,5 @@ where
|
|||
// the pointer was null. To follow this idea to its full generality, we
|
||||
// should also give an alert when `check` post-dominates `deref`.
|
||||
deref.getBlock() = dominator
|
||||
select checked, "This null check is redundant because $@ in any case.", deref,
|
||||
select checked, deref, checked, "This null check is redundant because $@ in any case.", deref,
|
||||
"the value is dereferenced"
|
||||
|
|
|
@ -35,7 +35,8 @@ class Configuration extends TaintTrackingConfiguration {
|
|||
op.getAnOperand() = e
|
||||
|
|
||||
op instanceof UnaryArithmeticOperation or
|
||||
op instanceof BinaryArithmeticOperation
|
||||
op instanceof BinaryArithmeticOperation or
|
||||
op instanceof AssignArithmeticOperation
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The query `cpp/tainted-arithmetic` now also flags possible overflows in arithmetic assignment operations.
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
category: newQuery
|
||||
---
|
||||
* A new query `cpp/double-free` has been added. The query finds possible cases of deallocating the same pointer twice. The precision of the query has been set to "medium".
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
category: newQuery
|
||||
---
|
||||
* The query `cpp/use-after-free` has been modernized and assigned the precision "medium". The query finds cases of where a pointer is dereferenced after its memory has been deallocated.
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
category: newQuery
|
||||
---
|
||||
* The query `cpp/redundant-null-check-simple` has been promoted to Code Scanning. The query finds cases where a pointer is compared to null after it has already been dereferenced. Such comparisons likely indicate a bug at the place where the pointer is dereferenced, or where the pointer is compared to null.
|
|
@ -0,0 +1,3 @@
|
|||
## 0.5.6
|
||||
|
||||
No user-facing changes.
|
|
@ -1,2 +1,2 @@
|
|||
---
|
||||
lastReleaseVersion: 0.5.5
|
||||
lastReleaseVersion: 0.5.6
|
||||
|
|
|
@ -11,14 +11,14 @@
|
|||
|
||||
import cpp
|
||||
import experimental.semmle.code.cpp.dataflow.ProductFlow
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
|
||||
import experimental.semmle.code.cpp.rangeanalysis.Bound
|
||||
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.Bound
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.models.interfaces.Allocation
|
||||
import semmle.code.cpp.ir.IRConfiguration
|
||||
import DataFlow::PathGraph
|
||||
import ArraySizeFlow::PathGraph1
|
||||
|
||||
// temporary - custom allocator for ffmpeg
|
||||
class AvBufferAlloc extends AllocationFunction {
|
||||
|
@ -39,14 +39,12 @@ predicate bounded(Instruction i, Bound b, int delta, boolean upper) {
|
|||
semBounded(getSemanticExpr(i), b, delta, upper, _)
|
||||
}
|
||||
|
||||
class ArraySizeConfiguration extends ProductFlow::Configuration {
|
||||
ArraySizeConfiguration() { this = "ArraySizeConfiguration" }
|
||||
|
||||
override predicate isSourcePair(DataFlow::Node source1, DataFlow::Node source2) {
|
||||
module ArraySizeConfig implements ProductFlow::ConfigSig {
|
||||
predicate isSourcePair(DataFlow::Node source1, DataFlow::Node source2) {
|
||||
source1.asConvertedExpr().(AllocationExpr).getSizeExpr() = source2.asConvertedExpr()
|
||||
}
|
||||
|
||||
override predicate isSinkPair(DataFlow::Node sink1, DataFlow::Node sink2) {
|
||||
predicate isSinkPair(DataFlow::Node sink1, DataFlow::Node sink2) {
|
||||
exists(PointerAddInstruction pai, int delta |
|
||||
isSinkPair1(sink1, sink2, pai, delta) and
|
||||
(
|
||||
|
@ -63,6 +61,8 @@ class ArraySizeConfiguration extends ProductFlow::Configuration {
|
|||
}
|
||||
}
|
||||
|
||||
module ArraySizeFlow = ProductFlow::Global<ArraySizeConfig>;
|
||||
|
||||
pragma[nomagic]
|
||||
predicate isSinkPair1(
|
||||
DataFlow::Node sink1, DataFlow::Node sink2, PointerAddInstruction pai, int delta
|
||||
|
@ -76,9 +76,9 @@ predicate isSinkPair1(
|
|||
}
|
||||
|
||||
from
|
||||
ArraySizeConfiguration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2,
|
||||
DataFlow::PathNode sink1, DataFlow2::PathNode sink2
|
||||
where conf.hasFlowPath(source1, source2, sink1, sink2)
|
||||
ArraySizeFlow::PathNode1 source1, ArraySizeFlow::PathNode2 source2,
|
||||
ArraySizeFlow::PathNode1 sink1, ArraySizeFlow::PathNode2 sink2
|
||||
where ArraySizeFlow::flowPath(source1, source2, sink1, sink2)
|
||||
// TODO: pull delta out and display it
|
||||
select sink1.getNode(), source1, sink1, "Off-by one error allocated at $@ bounded by $@.", source1,
|
||||
source1.toString(), sink2, sink2.toString()
|
||||
|
|
|
@ -17,10 +17,10 @@ import experimental.semmle.code.cpp.dataflow.ProductFlow
|
|||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.models.interfaces.Allocation
|
||||
import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
|
||||
import experimental.semmle.code.cpp.semantic.SemanticBound
|
||||
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
|
||||
import DataFlow::PathGraph
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import StringSizeFlow::PathGraph1
|
||||
import codeql.util.Unit
|
||||
|
||||
pragma[nomagic]
|
||||
Instruction getABoundIn(SemBound b, IRFunction func) {
|
||||
|
@ -31,7 +31,8 @@ Instruction getABoundIn(SemBound b, IRFunction func) {
|
|||
/**
|
||||
* Holds if `i <= b + delta`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
bindingset[i]
|
||||
pragma[inline_late]
|
||||
predicate bounded(Instruction i, Instruction b, int delta) {
|
||||
exists(SemBound bound, IRFunction func |
|
||||
semBounded(getSemanticExpr(i), bound, delta, true, _) and
|
||||
|
@ -46,7 +47,7 @@ VariableAccess getAVariableAccess(Expr e) { e.getAChild*() = result }
|
|||
* Holds if `(n, state)` pair represents the source of flow for the size
|
||||
* expression associated with `alloc`.
|
||||
*/
|
||||
predicate hasSize(AllocationExpr alloc, DataFlow::Node n, string state) {
|
||||
predicate hasSize(AllocationExpr alloc, DataFlow::Node n, int state) {
|
||||
exists(VariableAccess va, Expr size, int delta |
|
||||
size = alloc.getSizeExpr() and
|
||||
// Get the unique variable in a size expression like `x` in `malloc(x + 1)`.
|
||||
|
@ -55,7 +56,7 @@ predicate hasSize(AllocationExpr alloc, DataFlow::Node n, string state) {
|
|||
bounded(any(Instruction instr | instr.getUnconvertedResultExpression() = size),
|
||||
any(LoadInstruction load | load.getUnconvertedResultExpression() = va), delta) and
|
||||
n.asConvertedExpr() = va.getFullyConverted() and
|
||||
state = delta.toString()
|
||||
state = delta
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -77,12 +78,13 @@ predicate isSinkPairImpl(
|
|||
)
|
||||
}
|
||||
|
||||
class StringSizeConfiguration extends ProductFlow::Configuration {
|
||||
StringSizeConfiguration() { this = "StringSizeConfiguration" }
|
||||
module StringSizeConfig implements ProductFlow::StateConfigSig {
|
||||
class FlowState1 = Unit;
|
||||
|
||||
override predicate isSourcePair(
|
||||
DataFlow::Node bufSource, DataFlow::FlowState state1, DataFlow::Node sizeSource,
|
||||
DataFlow::FlowState state2
|
||||
class FlowState2 = int;
|
||||
|
||||
predicate isSourcePair(
|
||||
DataFlow::Node bufSource, FlowState1 state1, DataFlow::Node sizeSource, FlowState2 state2
|
||||
) {
|
||||
// In the case of an allocation like
|
||||
// ```cpp
|
||||
|
@ -90,30 +92,38 @@ class StringSizeConfiguration extends ProductFlow::Configuration {
|
|||
// ```
|
||||
// we use `state2` to remember that there was an offset (in this case an offset of `1`) added
|
||||
// to the size of the allocation. This state is then checked in `isSinkPair`.
|
||||
state1 instanceof DataFlow::FlowStateEmpty and
|
||||
exists(state1) and
|
||||
hasSize(bufSource.asConvertedExpr(), sizeSource, state2)
|
||||
}
|
||||
|
||||
override predicate isSinkPair(
|
||||
DataFlow::Node bufSink, DataFlow::FlowState state1, DataFlow::Node sizeSink,
|
||||
DataFlow::FlowState state2
|
||||
predicate isSinkPair(
|
||||
DataFlow::Node bufSink, FlowState1 state1, DataFlow::Node sizeSink, FlowState2 state2
|
||||
) {
|
||||
state1 instanceof DataFlow::FlowStateEmpty and
|
||||
state2 = [-32 .. 32].toString() and // An arbitrary bound because we need to bound `state2`
|
||||
exists(state1) and
|
||||
state2 = [-32 .. 32] and // An arbitrary bound because we need to bound `state2`
|
||||
exists(int delta |
|
||||
isSinkPairImpl(_, bufSink, sizeSink, delta, _) and
|
||||
delta > state2.toInt()
|
||||
delta > state2
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep2(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
predicate isBarrier1(DataFlow::Node node, FlowState1 state) { none() }
|
||||
|
||||
predicate isBarrier2(DataFlow::Node node, FlowState2 state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep1(
|
||||
DataFlow::Node node1, FlowState1 state1, DataFlow::Node node2, FlowState1 state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep2(
|
||||
DataFlow::Node node1, FlowState2 state1, DataFlow::Node node2, FlowState2 state2
|
||||
) {
|
||||
exists(AddInstruction add, Operand op, int delta, int s1, int s2 |
|
||||
s1 = [-32 .. 32] and // An arbitrary bound because we need to bound `state`
|
||||
state1 = s1.toString() and
|
||||
state2 = s2.toString() and
|
||||
state1 = s1 and
|
||||
state2 = s2 and
|
||||
add.hasOperands(node1.asOperand(), op) and
|
||||
semBounded(getSemanticExpr(op.getDef()), any(SemZeroBound zero), delta, true, _) and
|
||||
node2.asInstruction() = add and
|
||||
|
@ -122,13 +132,15 @@ class StringSizeConfiguration extends ProductFlow::Configuration {
|
|||
}
|
||||
}
|
||||
|
||||
module StringSizeFlow = ProductFlow::GlobalWithState<StringSizeConfig>;
|
||||
|
||||
from
|
||||
StringSizeConfiguration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2,
|
||||
DataFlow::PathNode sink1, DataFlow2::PathNode sink2, int overflow, int sinkState,
|
||||
StringSizeFlow::PathNode1 source1, StringSizeFlow::PathNode2 source2,
|
||||
StringSizeFlow::PathNode1 sink1, StringSizeFlow::PathNode2 sink2, int overflow, int sinkState,
|
||||
CallInstruction c, DataFlow::Node sourceNode, Expr buffer, string element
|
||||
where
|
||||
conf.hasFlowPath(source1, source2, sink1, sink2) and
|
||||
sinkState = sink2.getState().toInt() and
|
||||
StringSizeFlow::flowPath(source1, source2, sink1, sink2) and
|
||||
sinkState = sink2.getState() and
|
||||
isSinkPairImpl(c, sink1.getNode(), sink2.getNode(), overflow + sinkState, buffer) and
|
||||
overflow > 0 and
|
||||
sourceNode = source1.getNode() and
|
||||
|
|
|
@ -10,9 +10,8 @@
|
|||
* experimental
|
||||
*/
|
||||
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
|
||||
import experimental.semmle.code.cpp.semantic.SemanticBound
|
||||
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
import PointerArithmeticToDerefFlow::PathGraph
|
||||
|
@ -26,15 +25,23 @@ Instruction getABoundIn(SemBound b, IRFunction func) {
|
|||
/**
|
||||
* Holds if `i <= b + delta`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate bounded(Instruction i, Instruction b, int delta) {
|
||||
pragma[inline]
|
||||
predicate boundedImpl(Instruction i, Instruction b, int delta) {
|
||||
exists(SemBound bound, IRFunction func |
|
||||
semBounded(getSemanticExpr(i), bound, delta, true, _) and
|
||||
b = getABoundIn(bound, func) and
|
||||
i.getEnclosingIRFunction() = func
|
||||
pragma[only_bind_out](i.getEnclosingIRFunction()) = func
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[i]
|
||||
pragma[inline_late]
|
||||
predicate bounded1(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
|
||||
|
||||
bindingset[b]
|
||||
pragma[inline_late]
|
||||
predicate bounded2(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
|
||||
|
||||
module FieldAddressToPointerArithmeticConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isFieldAddressSource(_, source) }
|
||||
|
||||
|
@ -50,17 +57,13 @@ predicate isFieldAddressSource(Field f, DataFlow::Node source) {
|
|||
source.asInstruction().(FieldAddressInstruction).getField() = f
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a sink for `InvalidPointerToDerefConf` and `i` is a `StoreInstruction` that
|
||||
* writes to an address that non-strictly upper-bounds `sink`, or `i` is a `LoadInstruction` that
|
||||
* reads from an address that non-strictly upper-bounds `sink`.
|
||||
*/
|
||||
predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string operation) {
|
||||
exists(AddressOperand addr, int delta |
|
||||
bounded(addr.getDef(), sink.asInstruction(), delta) and
|
||||
delta >= 0 and
|
||||
i.getAnOperand() = addr
|
||||
|
|
||||
bindingset[delta]
|
||||
predicate isInvalidPointerDerefSinkImpl(
|
||||
int delta, Instruction i, AddressOperand addr, string operation
|
||||
) {
|
||||
delta >= 0 and
|
||||
i.getAnOperand() = addr and
|
||||
(
|
||||
i instanceof StoreInstruction and
|
||||
operation = "write"
|
||||
or
|
||||
|
@ -69,6 +72,27 @@ predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string o
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a sink for `InvalidPointerToDerefConf` and `i` is a `StoreInstruction` that
|
||||
* writes to an address that non-strictly upper-bounds `sink`, or `i` is a `LoadInstruction` that
|
||||
* reads from an address that non-strictly upper-bounds `sink`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate isInvalidPointerDerefSink1(DataFlow::Node sink, Instruction i, string operation) {
|
||||
exists(AddressOperand addr, int delta |
|
||||
bounded1(addr.getDef(), sink.asInstruction(), delta) and
|
||||
isInvalidPointerDerefSinkImpl(delta, i, addr, operation)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
predicate isInvalidPointerDerefSink2(DataFlow::Node sink, Instruction i, string operation) {
|
||||
exists(AddressOperand addr, int delta |
|
||||
bounded2(addr.getDef(), sink.asInstruction(), delta) and
|
||||
isInvalidPointerDerefSinkImpl(delta, i, addr, operation)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isConstantSizeOverflowSource(Field f, PointerAddInstruction pai, int delta) {
|
||||
exists(int size, int bound, DataFlow::Node source, DataFlow::InstructionNode sink |
|
||||
FieldAddressToPointerArithmeticFlow::flow(source, sink) and
|
||||
|
@ -88,7 +112,8 @@ module PointerArithmeticToDerefConfig implements DataFlow::ConfigSig {
|
|||
isConstantSizeOverflowSource(_, source.asInstruction(), _)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _) }
|
||||
pragma[inline]
|
||||
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink1(sink, _, _) }
|
||||
}
|
||||
|
||||
module PointerArithmeticToDerefFlow = DataFlow::Global<PointerArithmeticToDerefConfig>;
|
||||
|
@ -98,7 +123,7 @@ from
|
|||
PointerArithmeticToDerefFlow::PathNode sink, Instruction deref, string operation, int delta
|
||||
where
|
||||
PointerArithmeticToDerefFlow::flowPath(source, sink) and
|
||||
isInvalidPointerDerefSink(sink.getNode(), deref, operation) and
|
||||
isInvalidPointerDerefSink2(sink.getNode(), deref, operation) and
|
||||
isConstantSizeOverflowSource(f, source.getNode().asInstruction(), delta)
|
||||
select source, source, sink,
|
||||
"This pointer arithmetic may have an off-by-" + (delta + 1) +
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
|
||||
import cpp
|
||||
import experimental.semmle.code.cpp.dataflow.ProductFlow
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
|
||||
import experimental.semmle.code.cpp.semantic.SemanticBound
|
||||
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR
|
||||
import codeql.util.Unit
|
||||
|
||||
pragma[nomagic]
|
||||
Instruction getABoundIn(SemBound b, IRFunction func) {
|
||||
|
@ -31,8 +31,8 @@ Instruction getABoundIn(SemBound b, IRFunction func) {
|
|||
/**
|
||||
* Holds if `i <= b + delta`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate bounded(Instruction i, Instruction b, int delta) {
|
||||
pragma[inline]
|
||||
predicate boundedImpl(Instruction i, Instruction b, int delta) {
|
||||
exists(SemBound bound, IRFunction func |
|
||||
semBounded(getSemanticExpr(i), bound, delta, true, _) and
|
||||
b = getABoundIn(bound, func) and
|
||||
|
@ -40,18 +40,26 @@ predicate bounded(Instruction i, Instruction b, int delta) {
|
|||
)
|
||||
}
|
||||
|
||||
bindingset[i]
|
||||
pragma[inline_late]
|
||||
predicate bounded1(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
|
||||
|
||||
bindingset[b]
|
||||
pragma[inline_late]
|
||||
predicate bounded2(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
|
||||
|
||||
/**
|
||||
* Holds if the combination of `n` and `state` represents an appropriate
|
||||
* source for the expression `e` suitable for use-use flow.
|
||||
*/
|
||||
private predicate hasSizeImpl(Expr e, DataFlow::Node n, string state) {
|
||||
private predicate hasSizeImpl(Expr e, DataFlow::Node n, int state) {
|
||||
// The simple case: If the size is a variable access with no qualifier we can just use the
|
||||
// dataflow node for that expression and no state.
|
||||
exists(VariableAccess va |
|
||||
va = e and
|
||||
not va instanceof FieldAccess and
|
||||
n.asConvertedExpr() = va.getFullyConverted() and
|
||||
state = "0"
|
||||
state = 0
|
||||
)
|
||||
or
|
||||
// If the size is a choice between two expressions we allow both to be nodes representing the size.
|
||||
|
@ -61,13 +69,13 @@ private predicate hasSizeImpl(Expr e, DataFlow::Node n, string state) {
|
|||
// remember the constant in the state.
|
||||
exists(Expr const, Expr nonconst |
|
||||
e.(AddExpr).hasOperands(const, nonconst) and
|
||||
state = const.getValue() and
|
||||
state = const.getValue().toInt() and
|
||||
hasSizeImpl(nonconst, n, _)
|
||||
)
|
||||
or
|
||||
exists(Expr const, Expr nonconst |
|
||||
e.(SubExpr).hasOperands(const, nonconst) and
|
||||
state = "-" + const.getValue() and
|
||||
state = -const.getValue().toInt() and
|
||||
hasSizeImpl(nonconst, n, _)
|
||||
)
|
||||
}
|
||||
|
@ -76,7 +84,7 @@ private predicate hasSizeImpl(Expr e, DataFlow::Node n, string state) {
|
|||
* Holds if `(n, state)` pair represents the source of flow for the size
|
||||
* expression associated with `alloc`.
|
||||
*/
|
||||
predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, string state) {
|
||||
predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
|
||||
hasSizeImpl(alloc.getSizeExpr(), n, state)
|
||||
}
|
||||
|
||||
|
@ -100,11 +108,13 @@ predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, string state)
|
|||
* Finally, the range-analysis library will find a load from (or store to) an address that
|
||||
* is non-strictly upper-bounded by `end` (which in this case is `*p`).
|
||||
*/
|
||||
class AllocToInvalidPointerConf extends ProductFlow::Configuration {
|
||||
AllocToInvalidPointerConf() { this = "AllocToInvalidPointerConf" }
|
||||
module AllocToInvalidPointerConfig implements ProductFlow::StateConfigSig {
|
||||
class FlowState1 = Unit;
|
||||
|
||||
override predicate isSourcePair(
|
||||
DataFlow::Node source1, string state1, DataFlow::Node source2, string state2
|
||||
class FlowState2 = int;
|
||||
|
||||
predicate isSourcePair(
|
||||
DataFlow::Node source1, FlowState1 state1, DataFlow::Node source2, FlowState2 state2
|
||||
) {
|
||||
// In the case of an allocation like
|
||||
// ```cpp
|
||||
|
@ -112,37 +122,46 @@ class AllocToInvalidPointerConf extends ProductFlow::Configuration {
|
|||
// ```
|
||||
// we use `state2` to remember that there was an offset (in this case an offset of `1`) added
|
||||
// to the size of the allocation. This state is then checked in `isSinkPair`.
|
||||
state1 = "" and
|
||||
exists(state1) and
|
||||
hasSize(source1.asConvertedExpr(), source2, state2)
|
||||
}
|
||||
|
||||
override predicate isSinkPair(
|
||||
DataFlow::Node sink1, DataFlow::FlowState state1, DataFlow::Node sink2,
|
||||
DataFlow::FlowState state2
|
||||
predicate isSinkPair(
|
||||
DataFlow::Node sink1, FlowState1 state1, DataFlow::Node sink2, FlowState2 state2
|
||||
) {
|
||||
state1 = "" and
|
||||
exists(state1) and
|
||||
// We check that the delta computed by the range analysis matches the
|
||||
// state value that we set in `isSourcePair`.
|
||||
exists(int delta |
|
||||
isSinkImpl(_, sink1, sink2, delta) and
|
||||
state2 = delta.toString()
|
||||
state2 = delta
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isBarrierOut2(DataFlow::Node node) {
|
||||
predicate isBarrier1(DataFlow::Node node, FlowState1 state) { none() }
|
||||
|
||||
predicate isBarrier2(DataFlow::Node node, FlowState2 state) { none() }
|
||||
|
||||
predicate isBarrierIn1(DataFlow::Node node) { isSourcePair(node, _, _, _) }
|
||||
|
||||
predicate isBarrierOut2(DataFlow::Node node) {
|
||||
node = any(DataFlow::SsaPhiNode phi).getAnInput(true)
|
||||
}
|
||||
|
||||
override predicate isBarrierIn1(DataFlow::Node node) { this.isSourcePair(node, _, _, _) }
|
||||
predicate isAdditionalFlowStep1(
|
||||
DataFlow::Node node1, FlowState1 state1, DataFlow::Node node2, FlowState1 state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep2(
|
||||
DataFlow::Node node1, FlowState2 state1, DataFlow::Node node2, FlowState2 state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate pointerAddInstructionHasOperands(
|
||||
PointerAddInstruction pai, Instruction left, Instruction right
|
||||
) {
|
||||
pai.getLeft() = left and
|
||||
pai.getRight() = right
|
||||
}
|
||||
module AllocToInvalidPointerFlow = ProductFlow::GlobalWithState<AllocToInvalidPointerConfig>;
|
||||
|
||||
/**
|
||||
* Holds if `pai` is non-strictly upper bounded by `sink2 + delta` and `sink1` is the
|
||||
|
@ -163,8 +182,9 @@ predicate pointerAddInstructionHasBounds(
|
|||
PointerAddInstruction pai, DataFlow::Node sink1, DataFlow::Node sink2, int delta
|
||||
) {
|
||||
exists(Instruction right |
|
||||
pointerAddInstructionHasOperands(pai, sink1.asInstruction(), right) and
|
||||
bounded(right, sink2.asInstruction(), delta)
|
||||
pai.getRight() = right and
|
||||
pai.getLeft() = sink1.asInstruction() and
|
||||
bounded1(right, sink2.asInstruction(), delta)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -185,9 +205,10 @@ predicate isSinkImpl(
|
|||
* writes to an address that non-strictly upper-bounds `sink`, or `i` is a `LoadInstruction` that
|
||||
* reads from an address that non-strictly upper-bounds `sink`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string operation) {
|
||||
exists(AddressOperand addr, int delta |
|
||||
bounded(addr.getDef(), sink.asInstruction(), delta) and
|
||||
bounded1(addr.getDef(), sink.asInstruction(), delta) and
|
||||
delta >= 0 and
|
||||
i.getAnOperand() = addr
|
||||
|
|
||||
|
@ -206,6 +227,7 @@ predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string o
|
|||
module InvalidPointerToDerefConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { invalidPointerToDerefSource(_, source, _) }
|
||||
|
||||
pragma[inline]
|
||||
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _) }
|
||||
}
|
||||
|
||||
|
@ -222,18 +244,18 @@ module InvalidPointerToDerefFlow = DataFlow::Global<InvalidPointerToDerefConfig>
|
|||
predicate invalidPointerToDerefSource(
|
||||
PointerArithmeticInstruction pai, DataFlow::Node source, int delta
|
||||
) {
|
||||
exists(ProductFlow::Configuration conf, DataFlow::PathNode p, DataFlow::Node sink1 |
|
||||
p.getNode() = sink1 and
|
||||
conf.hasFlowPath(_, _, p, _) and
|
||||
exists(AllocToInvalidPointerFlow::PathNode1 p, DataFlow::Node sink1 |
|
||||
pragma[only_bind_out](p.getNode()) = sink1 and
|
||||
AllocToInvalidPointerFlow::flowPath(_, _, pragma[only_bind_into](p), _) and
|
||||
isSinkImpl(pai, sink1, _, _) and
|
||||
bounded(source.asInstruction(), pai, delta) and
|
||||
bounded2(source.asInstruction(), pai, delta) and
|
||||
delta >= 0
|
||||
)
|
||||
}
|
||||
|
||||
newtype TMergedPathNode =
|
||||
// The path nodes computed by the first projection of `AllocToInvalidPointerConf`
|
||||
TPathNode1(DataFlow::PathNode p) or
|
||||
TPathNode1(AllocToInvalidPointerFlow::PathNode1 p) or
|
||||
// The path nodes computed by `InvalidPointerToDerefConf`
|
||||
TPathNode3(InvalidPointerToDerefFlow::PathNode p) or
|
||||
// The read/write that uses the invalid pointer identified by `InvalidPointerToDerefConf`.
|
||||
|
@ -241,7 +263,7 @@ newtype TMergedPathNode =
|
|||
// pointer, but we want to raise an alert at the dereference.
|
||||
TPathNodeSink(Instruction i) {
|
||||
exists(DataFlow::Node n |
|
||||
InvalidPointerToDerefFlow::flow(_, n) and
|
||||
InvalidPointerToDerefFlow::flowTo(n) and
|
||||
isInvalidPointerDerefSink(n, i, _)
|
||||
)
|
||||
}
|
||||
|
@ -249,7 +271,7 @@ newtype TMergedPathNode =
|
|||
class MergedPathNode extends TMergedPathNode {
|
||||
string toString() { none() }
|
||||
|
||||
final DataFlow::PathNode asPathNode1() { this = TPathNode1(result) }
|
||||
final AllocToInvalidPointerFlow::PathNode1 asPathNode1() { this = TPathNode1(result) }
|
||||
|
||||
final InvalidPointerToDerefFlow::PathNode asPathNode3() { this = TPathNode3(result) }
|
||||
|
||||
|
@ -264,7 +286,7 @@ class MergedPathNode extends TMergedPathNode {
|
|||
|
||||
class PathNode1 extends MergedPathNode, TPathNode1 {
|
||||
override string toString() {
|
||||
exists(DataFlow::PathNode p |
|
||||
exists(AllocToInvalidPointerFlow::PathNode1 p |
|
||||
this = TPathNode1(p) and
|
||||
result = p.toString()
|
||||
)
|
||||
|
@ -324,7 +346,8 @@ query predicate edges(MergedPathNode node1, MergedPathNode node2) {
|
|||
* of `InvalidPointerToDerefConf`, and they are connected through `pai`.
|
||||
*/
|
||||
predicate joinOn1(
|
||||
PointerArithmeticInstruction pai, DataFlow::PathNode p1, InvalidPointerToDerefFlow::PathNode p2
|
||||
PointerArithmeticInstruction pai, AllocToInvalidPointerFlow::PathNode1 p1,
|
||||
InvalidPointerToDerefFlow::PathNode p2
|
||||
) {
|
||||
isSinkImpl(pai, p1.getNode(), _, _) and
|
||||
invalidPointerToDerefSource(pai, p2.getNode(), _)
|
||||
|
@ -335,6 +358,7 @@ predicate joinOn1(
|
|||
* that dereferences `p1`. The string `operation` describes whether the `i` is
|
||||
* a `StoreInstruction` or `LoadInstruction`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate joinOn2(InvalidPointerToDerefFlow::PathNode p1, Instruction i, string operation) {
|
||||
isInvalidPointerDerefSink(p1.getNode(), i, operation)
|
||||
}
|
||||
|
@ -343,11 +367,8 @@ predicate hasFlowPath(
|
|||
MergedPathNode source1, MergedPathNode sink, InvalidPointerToDerefFlow::PathNode source3,
|
||||
PointerArithmeticInstruction pai, string operation
|
||||
) {
|
||||
exists(
|
||||
AllocToInvalidPointerConf conf1, InvalidPointerToDerefFlow::PathNode sink3,
|
||||
DataFlow::PathNode sink1
|
||||
|
|
||||
conf1.hasFlowPath(source1.asPathNode1(), _, sink1, _) and
|
||||
exists(InvalidPointerToDerefFlow::PathNode sink3, AllocToInvalidPointerFlow::PathNode1 sink1 |
|
||||
AllocToInvalidPointerFlow::flowPath(source1.asPathNode1(), _, sink1, _) and
|
||||
joinOn1(pai, sink1, source3) and
|
||||
InvalidPointerToDerefFlow::flowPath(source3, sink3) and
|
||||
joinOn2(sink3, sink.asSinkNode(), operation)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* @name Errors When Double Free
|
||||
* @description Freeing a previously allocated resource twice can lead to various vulnerabilities in the program.
|
||||
* @kind problem
|
||||
* @id cpp/double-free
|
||||
* @id cpp/experimental-double-free
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @tags security
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: codeql/cpp-queries
|
||||
version: 0.5.6-dev
|
||||
version: 0.6.0-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
|
|
@ -4879,13 +4879,13 @@ ir.cpp:
|
|||
# 504| getExpr(): [ClassAggregateLiteral] {...}
|
||||
# 504| Type = [Struct] Point
|
||||
# 504| ValueCategory = prvalue
|
||||
# 504| getFieldExpr(x): [VariableAccess] x
|
||||
# 504| getAFieldExpr(x): [VariableAccess] x
|
||||
# 504| Type = [IntType] int
|
||||
# 504| ValueCategory = prvalue(load)
|
||||
# 504| getFieldExpr(y): [VariableAccess] f
|
||||
# 504| getAFieldExpr(y): [VariableAccess] f
|
||||
# 504| Type = [FloatType] float
|
||||
# 504| ValueCategory = prvalue(load)
|
||||
# 504| getFieldExpr(y).getFullyConverted(): [CStyleCast] (int)...
|
||||
# 504| getAFieldExpr(y).getFullyConverted(): [CStyleCast] (int)...
|
||||
# 504| Conversion = [FloatingPointToIntegralConversion] floating point to integral conversion
|
||||
# 504| Type = [IntType] int
|
||||
# 504| ValueCategory = prvalue
|
||||
|
@ -4896,7 +4896,7 @@ ir.cpp:
|
|||
# 505| getExpr(): [ClassAggregateLiteral] {...}
|
||||
# 505| Type = [Struct] Point
|
||||
# 505| ValueCategory = prvalue
|
||||
# 505| getFieldExpr(x): [VariableAccess] x
|
||||
# 505| getAFieldExpr(x): [VariableAccess] x
|
||||
# 505| Type = [IntType] int
|
||||
# 505| ValueCategory = prvalue(load)
|
||||
# 506| getStmt(2): [DeclStmt] declaration
|
||||
|
@ -4944,16 +4944,16 @@ ir.cpp:
|
|||
# 514| getExpr(): [ClassAggregateLiteral] {...}
|
||||
# 514| Type = [Struct] Rect
|
||||
# 514| ValueCategory = prvalue
|
||||
# 514| getFieldExpr(topLeft): [ClassAggregateLiteral] {...}
|
||||
# 514| getAFieldExpr(topLeft): [ClassAggregateLiteral] {...}
|
||||
# 514| Type = [Struct] Point
|
||||
# 514| ValueCategory = prvalue
|
||||
# 514| getFieldExpr(x): [VariableAccess] x
|
||||
# 514| getAFieldExpr(x): [VariableAccess] x
|
||||
# 514| Type = [IntType] int
|
||||
# 514| ValueCategory = prvalue(load)
|
||||
# 514| getFieldExpr(y): [VariableAccess] f
|
||||
# 514| getAFieldExpr(y): [VariableAccess] f
|
||||
# 514| Type = [FloatType] float
|
||||
# 514| ValueCategory = prvalue(load)
|
||||
# 514| getFieldExpr(y).getFullyConverted(): [CStyleCast] (int)...
|
||||
# 514| getAFieldExpr(y).getFullyConverted(): [CStyleCast] (int)...
|
||||
# 514| Conversion = [FloatingPointToIntegralConversion] floating point to integral conversion
|
||||
# 514| Type = [IntType] int
|
||||
# 514| ValueCategory = prvalue
|
||||
|
@ -4964,29 +4964,29 @@ ir.cpp:
|
|||
# 515| getExpr(): [ClassAggregateLiteral] {...}
|
||||
# 515| Type = [Struct] Rect
|
||||
# 515| ValueCategory = prvalue
|
||||
# 515| getFieldExpr(topLeft): [ClassAggregateLiteral] {...}
|
||||
# 515| getAFieldExpr(topLeft): [ClassAggregateLiteral] {...}
|
||||
# 515| Type = [Struct] Point
|
||||
# 515| ValueCategory = prvalue
|
||||
# 515| getFieldExpr(x): [VariableAccess] x
|
||||
# 515| getAFieldExpr(x): [VariableAccess] x
|
||||
# 515| Type = [IntType] int
|
||||
# 515| ValueCategory = prvalue(load)
|
||||
# 515| getFieldExpr(y): [VariableAccess] f
|
||||
# 515| getAFieldExpr(y): [VariableAccess] f
|
||||
# 515| Type = [FloatType] float
|
||||
# 515| ValueCategory = prvalue(load)
|
||||
# 515| getFieldExpr(y).getFullyConverted(): [CStyleCast] (int)...
|
||||
# 515| getAFieldExpr(y).getFullyConverted(): [CStyleCast] (int)...
|
||||
# 515| Conversion = [FloatingPointToIntegralConversion] floating point to integral conversion
|
||||
# 515| Type = [IntType] int
|
||||
# 515| ValueCategory = prvalue
|
||||
# 515| getFieldExpr(bottomRight): [ClassAggregateLiteral] {...}
|
||||
# 515| getAFieldExpr(bottomRight): [ClassAggregateLiteral] {...}
|
||||
# 515| Type = [Struct] Point
|
||||
# 515| ValueCategory = prvalue
|
||||
# 515| getFieldExpr(x): [VariableAccess] x
|
||||
# 515| getAFieldExpr(x): [VariableAccess] x
|
||||
# 515| Type = [IntType] int
|
||||
# 515| ValueCategory = prvalue(load)
|
||||
# 515| getFieldExpr(y): [VariableAccess] f
|
||||
# 515| getAFieldExpr(y): [VariableAccess] f
|
||||
# 515| Type = [FloatType] float
|
||||
# 515| ValueCategory = prvalue(load)
|
||||
# 515| getFieldExpr(y).getFullyConverted(): [CStyleCast] (int)...
|
||||
# 515| getAFieldExpr(y).getFullyConverted(): [CStyleCast] (int)...
|
||||
# 515| Conversion = [FloatingPointToIntegralConversion] floating point to integral conversion
|
||||
# 515| Type = [IntType] int
|
||||
# 515| ValueCategory = prvalue
|
||||
|
@ -4997,16 +4997,16 @@ ir.cpp:
|
|||
# 516| getExpr(): [ClassAggregateLiteral] {...}
|
||||
# 516| Type = [Struct] Rect
|
||||
# 516| ValueCategory = prvalue
|
||||
# 516| getFieldExpr(topLeft): [ClassAggregateLiteral] {...}
|
||||
# 516| getAFieldExpr(topLeft): [ClassAggregateLiteral] {...}
|
||||
# 516| Type = [Struct] Point
|
||||
# 516| ValueCategory = prvalue
|
||||
# 516| getFieldExpr(x): [VariableAccess] x
|
||||
# 516| getAFieldExpr(x): [VariableAccess] x
|
||||
# 516| Type = [IntType] int
|
||||
# 516| ValueCategory = prvalue(load)
|
||||
# 516| getFieldExpr(bottomRight): [ClassAggregateLiteral] {...}
|
||||
# 516| getAFieldExpr(bottomRight): [ClassAggregateLiteral] {...}
|
||||
# 516| Type = [Struct] Point
|
||||
# 516| ValueCategory = prvalue
|
||||
# 516| getFieldExpr(x): [VariableAccess] x
|
||||
# 516| getAFieldExpr(x): [VariableAccess] x
|
||||
# 516| Type = [IntType] int
|
||||
# 516| ValueCategory = prvalue(load)
|
||||
# 517| getStmt(4): [ReturnStmt] return ...
|
||||
|
@ -5031,17 +5031,17 @@ ir.cpp:
|
|||
# 521| getExpr(): [ArrayAggregateLiteral] {...}
|
||||
# 521| Type = [ArrayType] int[3]
|
||||
# 521| ValueCategory = prvalue
|
||||
# 521| getElementExpr(0): [VariableAccess] x
|
||||
# 521| getAnElementExpr(0): [VariableAccess] x
|
||||
# 521| Type = [IntType] int
|
||||
# 521| ValueCategory = prvalue(load)
|
||||
# 521| getElementExpr(1): [VariableAccess] f
|
||||
# 521| getAnElementExpr(1): [VariableAccess] f
|
||||
# 521| Type = [FloatType] float
|
||||
# 521| ValueCategory = prvalue(load)
|
||||
# 521| getElementExpr(2): [Literal] 0
|
||||
# 521| getAnElementExpr(2): [Literal] 0
|
||||
# 521| Type = [IntType] int
|
||||
# 521| Value = [Literal] 0
|
||||
# 521| ValueCategory = prvalue
|
||||
# 521| getElementExpr(1).getFullyConverted(): [CStyleCast] (int)...
|
||||
# 521| getAnElementExpr(1).getFullyConverted(): [CStyleCast] (int)...
|
||||
# 521| Conversion = [FloatingPointToIntegralConversion] floating point to integral conversion
|
||||
# 521| Type = [IntType] int
|
||||
# 521| ValueCategory = prvalue
|
||||
|
@ -5052,7 +5052,7 @@ ir.cpp:
|
|||
# 522| getExpr(): [ArrayAggregateLiteral] {...}
|
||||
# 522| Type = [ArrayType] int[3]
|
||||
# 522| ValueCategory = prvalue
|
||||
# 522| getElementExpr(0): [VariableAccess] x
|
||||
# 522| getAnElementExpr(0): [VariableAccess] x
|
||||
# 522| Type = [IntType] int
|
||||
# 522| ValueCategory = prvalue(load)
|
||||
# 523| getStmt(3): [ReturnStmt] return ...
|
||||
|
@ -5078,10 +5078,10 @@ ir.cpp:
|
|||
# 531| getExpr(): [ClassAggregateLiteral] {...}
|
||||
# 531| Type = [Union] U
|
||||
# 531| ValueCategory = prvalue
|
||||
# 531| getFieldExpr(d): [VariableAccess] f
|
||||
# 531| getAFieldExpr(d): [VariableAccess] f
|
||||
# 531| Type = [FloatType] float
|
||||
# 531| ValueCategory = prvalue(load)
|
||||
# 531| getFieldExpr(d).getFullyConverted(): [CStyleCast] (double)...
|
||||
# 531| getAFieldExpr(d).getFullyConverted(): [CStyleCast] (double)...
|
||||
# 531| Conversion = [FloatingPointConversion] floating point conversion
|
||||
# 531| Type = [DoubleType] double
|
||||
# 531| ValueCategory = prvalue
|
||||
|
@ -5262,11 +5262,11 @@ ir.cpp:
|
|||
# 577| getExpr(): [ArrayAggregateLiteral] {...}
|
||||
# 577| Type = [ArrayType] char[2]
|
||||
# 577| ValueCategory = prvalue
|
||||
# 577| getElementExpr(0): [Literal] 0
|
||||
# 577| getAnElementExpr(0): [Literal] 0
|
||||
# 577| Type = [IntType] int
|
||||
# 577| Value = [Literal] 0
|
||||
# 577| ValueCategory = prvalue
|
||||
# 577| getElementExpr(0).getFullyConverted(): [CStyleCast] (char)...
|
||||
# 577| getAnElementExpr(0).getFullyConverted(): [CStyleCast] (char)...
|
||||
# 577| Conversion = [IntegralConversion] integral conversion
|
||||
# 577| Type = [PlainCharType] char
|
||||
# 577| Value = [CStyleCast] 0
|
||||
|
@ -5278,20 +5278,20 @@ ir.cpp:
|
|||
# 578| getExpr(): [ArrayAggregateLiteral] {...}
|
||||
# 578| Type = [ArrayType] char[2]
|
||||
# 578| ValueCategory = prvalue
|
||||
# 578| getElementExpr(0): [Literal] 0
|
||||
# 578| getAnElementExpr(0): [Literal] 0
|
||||
# 578| Type = [IntType] int
|
||||
# 578| Value = [Literal] 0
|
||||
# 578| ValueCategory = prvalue
|
||||
# 578| getElementExpr(1): [Literal] 1
|
||||
# 578| getAnElementExpr(1): [Literal] 1
|
||||
# 578| Type = [IntType] int
|
||||
# 578| Value = [Literal] 1
|
||||
# 578| ValueCategory = prvalue
|
||||
# 578| getElementExpr(0).getFullyConverted(): [CStyleCast] (char)...
|
||||
# 578| getAnElementExpr(0).getFullyConverted(): [CStyleCast] (char)...
|
||||
# 578| Conversion = [IntegralConversion] integral conversion
|
||||
# 578| Type = [PlainCharType] char
|
||||
# 578| Value = [CStyleCast] 0
|
||||
# 578| ValueCategory = prvalue
|
||||
# 578| getElementExpr(1).getFullyConverted(): [CStyleCast] (char)...
|
||||
# 578| getAnElementExpr(1).getFullyConverted(): [CStyleCast] (char)...
|
||||
# 578| Conversion = [IntegralConversion] integral conversion
|
||||
# 578| Type = [PlainCharType] char
|
||||
# 578| Value = [CStyleCast] 1
|
||||
|
@ -5303,11 +5303,11 @@ ir.cpp:
|
|||
# 579| getExpr(): [ArrayAggregateLiteral] {...}
|
||||
# 579| Type = [ArrayType] char[3]
|
||||
# 579| ValueCategory = prvalue
|
||||
# 579| getElementExpr(0): [Literal] 0
|
||||
# 579| getAnElementExpr(0): [Literal] 0
|
||||
# 579| Type = [IntType] int
|
||||
# 579| Value = [Literal] 0
|
||||
# 579| ValueCategory = prvalue
|
||||
# 579| getElementExpr(0).getFullyConverted(): [CStyleCast] (char)...
|
||||
# 579| getAnElementExpr(0).getFullyConverted(): [CStyleCast] (char)...
|
||||
# 579| Conversion = [IntegralConversion] integral conversion
|
||||
# 579| Type = [PlainCharType] char
|
||||
# 579| Value = [CStyleCast] 0
|
||||
|
@ -8036,7 +8036,7 @@ ir.cpp:
|
|||
# 963| getInitializer(): [ArrayAggregateLiteral] {...}
|
||||
# 963| Type = [ArrayType] String[]
|
||||
# 963| ValueCategory = prvalue
|
||||
# 963| getElementExpr(0): [ConstructorCall] call to String
|
||||
# 963| getAnElementExpr(0): [ConstructorCall] call to String
|
||||
# 963| Type = [VoidType] void
|
||||
# 963| ValueCategory = prvalue
|
||||
# 963| getExtent(): [VariableAccess] n
|
||||
|
@ -8078,7 +8078,7 @@ ir.cpp:
|
|||
# 966| getInitializer(): [ArrayAggregateLiteral] {...}
|
||||
# 966| Type = [ArrayType] DefaultCtorWithDefaultParam[]
|
||||
# 966| ValueCategory = prvalue
|
||||
# 966| getElementExpr(0): [ConstructorCall] call to DefaultCtorWithDefaultParam
|
||||
# 966| getAnElementExpr(0): [ConstructorCall] call to DefaultCtorWithDefaultParam
|
||||
# 966| Type = [VoidType] void
|
||||
# 966| ValueCategory = prvalue
|
||||
# 966| getExtent(): [VariableAccess] n
|
||||
|
@ -8091,15 +8091,15 @@ ir.cpp:
|
|||
# 967| getInitializer(): [ArrayAggregateLiteral] {...}
|
||||
# 967| Type = [ArrayType] int[3]
|
||||
# 967| ValueCategory = prvalue
|
||||
# 967| getElementExpr(0): [Literal] 0
|
||||
# 967| getAnElementExpr(0): [Literal] 0
|
||||
# 967| Type = [IntType] int
|
||||
# 967| Value = [Literal] 0
|
||||
# 967| ValueCategory = prvalue
|
||||
# 967| getElementExpr(1): [Literal] 1
|
||||
# 967| getAnElementExpr(1): [Literal] 1
|
||||
# 967| Type = [IntType] int
|
||||
# 967| Value = [Literal] 1
|
||||
# 967| ValueCategory = prvalue
|
||||
# 967| getElementExpr(2): [Literal] 2
|
||||
# 967| getAnElementExpr(2): [Literal] 2
|
||||
# 967| Type = [IntType] int
|
||||
# 967| Value = [Literal] 2
|
||||
# 967| ValueCategory = prvalue
|
||||
|
@ -8117,11 +8117,11 @@ ir.cpp:
|
|||
# 971| getExpr(): [ArrayAggregateLiteral] {...}
|
||||
# 971| Type = [ArrayType] int[1000]
|
||||
# 971| ValueCategory = prvalue
|
||||
# 971| getElementExpr(2): [Literal] 10002
|
||||
# 971| getAnElementExpr(2): [Literal] 10002
|
||||
# 971| Type = [IntType] int
|
||||
# 971| Value = [Literal] 10002
|
||||
# 971| ValueCategory = prvalue
|
||||
# 971| getElementExpr(900): [Literal] 10900
|
||||
# 971| getAnElementExpr(900): [Literal] 10900
|
||||
# 971| Type = [IntType] int
|
||||
# 971| Value = [Literal] 10900
|
||||
# 971| ValueCategory = prvalue
|
||||
|
@ -8601,19 +8601,19 @@ ir.cpp:
|
|||
# 1043| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1043| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1043| ValueCategory = prvalue
|
||||
# 1043| getFieldExpr(s): [VariableAccess] s
|
||||
# 1043| getAFieldExpr(s): [VariableAccess] s
|
||||
# 1043| Type = [LValueReferenceType] const String &
|
||||
# 1043| ValueCategory = prvalue(load)
|
||||
# 1043| getFieldExpr(x): [VariableAccess] x
|
||||
# 1043| getAFieldExpr(x): [VariableAccess] x
|
||||
# 1043| Type = [IntType] int
|
||||
# 1043| ValueCategory = lvalue
|
||||
# 1043| getFieldExpr(s).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 1043| getAFieldExpr(s).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 1043| Type = [LValueReferenceType] const String &
|
||||
# 1043| ValueCategory = prvalue
|
||||
# 1043| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1043| Type = [SpecifiedType] const String
|
||||
# 1043| ValueCategory = lvalue
|
||||
#-----| getFieldExpr(x).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
#-----| getAFieldExpr(x).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
#-----| Type = [LValueReferenceType] int &
|
||||
#-----| ValueCategory = prvalue
|
||||
# 1044| getStmt(3): [ExprStmt] ExprStmt
|
||||
|
@ -8646,10 +8646,10 @@ ir.cpp:
|
|||
# 1045| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1045| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1045| ValueCategory = prvalue
|
||||
# 1045| getFieldExpr(s): [ConstructorCall] call to String
|
||||
# 1045| getAFieldExpr(s): [ConstructorCall] call to String
|
||||
# 1045| Type = [VoidType] void
|
||||
# 1045| ValueCategory = prvalue
|
||||
# 1045| getFieldExpr(x): [VariableAccess] x
|
||||
# 1045| getAFieldExpr(x): [VariableAccess] x
|
||||
# 1045| Type = [IntType] int
|
||||
# 1045| ValueCategory = prvalue(load)
|
||||
# 1046| getStmt(5): [ExprStmt] ExprStmt
|
||||
|
@ -8682,10 +8682,10 @@ ir.cpp:
|
|||
# 1047| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1047| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1047| ValueCategory = prvalue
|
||||
# 1047| getFieldExpr(s): [VariableAccess] s
|
||||
# 1047| getAFieldExpr(s): [VariableAccess] s
|
||||
# 1047| Type = [LValueReferenceType] const String &
|
||||
# 1047| ValueCategory = prvalue(load)
|
||||
# 1047| getFieldExpr(s).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 1047| getAFieldExpr(s).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 1047| Type = [LValueReferenceType] const String &
|
||||
# 1047| ValueCategory = prvalue
|
||||
# 1047| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
|
@ -8721,7 +8721,7 @@ ir.cpp:
|
|||
# 1049| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1049| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1049| ValueCategory = prvalue
|
||||
# 1049| getFieldExpr(s): [ConstructorCall] call to String
|
||||
# 1049| getAFieldExpr(s): [ConstructorCall] call to String
|
||||
# 1049| Type = [VoidType] void
|
||||
# 1049| ValueCategory = prvalue
|
||||
# 1050| getStmt(9): [ExprStmt] ExprStmt
|
||||
|
@ -8754,13 +8754,13 @@ ir.cpp:
|
|||
# 1051| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1051| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1051| ValueCategory = prvalue
|
||||
# 1051| getFieldExpr(s): [VariableAccess] s
|
||||
# 1051| getAFieldExpr(s): [VariableAccess] s
|
||||
# 1051| Type = [LValueReferenceType] const String &
|
||||
# 1051| ValueCategory = prvalue(load)
|
||||
# 1051| getFieldExpr(x): [VariableAccess] x
|
||||
# 1051| getAFieldExpr(x): [VariableAccess] x
|
||||
# 1051| Type = [IntType] int
|
||||
# 1051| ValueCategory = prvalue(load)
|
||||
# 1051| getFieldExpr(s).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 1051| getAFieldExpr(s).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 1051| Type = [LValueReferenceType] const String &
|
||||
# 1051| ValueCategory = prvalue
|
||||
# 1051| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
|
@ -8810,13 +8810,13 @@ ir.cpp:
|
|||
# 1054| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1054| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1054| ValueCategory = prvalue
|
||||
# 1054| getFieldExpr(s): [VariableAccess] s
|
||||
# 1054| getAFieldExpr(s): [VariableAccess] s
|
||||
# 1054| Type = [LValueReferenceType] const String &
|
||||
# 1054| ValueCategory = prvalue(load)
|
||||
# 1054| getFieldExpr(x): [VariableAccess] x
|
||||
# 1054| getAFieldExpr(x): [VariableAccess] x
|
||||
# 1054| Type = [IntType] int
|
||||
# 1054| ValueCategory = prvalue(load)
|
||||
# 1054| getFieldExpr(i): [AddExpr] ... + ...
|
||||
# 1054| getAFieldExpr(i): [AddExpr] ... + ...
|
||||
# 1054| Type = [IntType] int
|
||||
# 1054| ValueCategory = prvalue
|
||||
# 1054| getLeftOperand(): [VariableAccess] x
|
||||
|
@ -8826,16 +8826,16 @@ ir.cpp:
|
|||
# 1054| Type = [IntType] int
|
||||
# 1054| Value = [Literal] 1
|
||||
# 1054| ValueCategory = prvalue
|
||||
# 1054| getFieldExpr(j): [VariableAccess] r
|
||||
# 1054| getAFieldExpr(j): [VariableAccess] r
|
||||
# 1054| Type = [IntType] int
|
||||
# 1054| ValueCategory = lvalue
|
||||
# 1054| getFieldExpr(s).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 1054| getAFieldExpr(s).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 1054| Type = [LValueReferenceType] const String &
|
||||
# 1054| ValueCategory = prvalue
|
||||
# 1054| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1054| Type = [SpecifiedType] const String
|
||||
# 1054| ValueCategory = lvalue
|
||||
# 1054| getFieldExpr(j).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 1054| getAFieldExpr(j).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 1054| Type = [LValueReferenceType] int &
|
||||
# 1054| ValueCategory = prvalue
|
||||
# 1055| getStmt(14): [ExprStmt] ExprStmt
|
||||
|
@ -9551,19 +9551,19 @@ ir.cpp:
|
|||
# 1163| getExpr(): [VectorAggregateLiteral] {...}
|
||||
# 1163| Type = [GNUVectorType] __attribute((vector_size(16UL))) int
|
||||
# 1163| ValueCategory = prvalue
|
||||
# 1163| getElementExpr(0): [Literal] 0
|
||||
# 1163| getAnElementExpr(0): [Literal] 0
|
||||
# 1163| Type = [IntType] int
|
||||
# 1163| Value = [Literal] 0
|
||||
# 1163| ValueCategory = prvalue
|
||||
# 1163| getElementExpr(1): [Literal] 1
|
||||
# 1163| getAnElementExpr(1): [Literal] 1
|
||||
# 1163| Type = [IntType] int
|
||||
# 1163| Value = [Literal] 1
|
||||
# 1163| ValueCategory = prvalue
|
||||
# 1163| getElementExpr(2): [Literal] 2
|
||||
# 1163| getAnElementExpr(2): [Literal] 2
|
||||
# 1163| Type = [IntType] int
|
||||
# 1163| Value = [Literal] 2
|
||||
# 1163| ValueCategory = prvalue
|
||||
# 1163| getElementExpr(3): [Literal] 3
|
||||
# 1163| getAnElementExpr(3): [Literal] 3
|
||||
# 1163| Type = [IntType] int
|
||||
# 1163| Value = [Literal] 3
|
||||
# 1163| ValueCategory = prvalue
|
||||
|
@ -10077,11 +10077,11 @@ ir.cpp:
|
|||
# 1252| getExpr(): [ArrayAggregateLiteral] {...}
|
||||
# 1252| Type = [ArrayType] char[1024]
|
||||
# 1252| ValueCategory = prvalue
|
||||
# 1252| getElementExpr(0): [Literal] 0
|
||||
# 1252| getAnElementExpr(0): [Literal] 0
|
||||
# 1252| Type = [IntType] int
|
||||
# 1252| Value = [Literal] 0
|
||||
# 1252| ValueCategory = prvalue
|
||||
# 1252| getElementExpr(0).getFullyConverted(): [CStyleCast] (char)...
|
||||
# 1252| getAnElementExpr(0).getFullyConverted(): [CStyleCast] (char)...
|
||||
# 1252| Conversion = [IntegralConversion] integral conversion
|
||||
# 1252| Type = [PlainCharType] char
|
||||
# 1252| Value = [CStyleCast] 0
|
||||
|
@ -11413,11 +11413,11 @@ ir.cpp:
|
|||
# 1463| getExpr(): [ArrayAggregateLiteral] {...}
|
||||
# 1463| Type = [ArrayType] int[2]
|
||||
# 1463| ValueCategory = prvalue
|
||||
# 1463| getElementExpr(0): [Literal] 1
|
||||
# 1463| getAnElementExpr(0): [Literal] 1
|
||||
# 1463| Type = [IntType] int
|
||||
# 1463| Value = [Literal] 1
|
||||
# 1463| ValueCategory = prvalue
|
||||
# 1463| getElementExpr(1): [Literal] 2
|
||||
# 1463| getAnElementExpr(1): [Literal] 2
|
||||
# 1463| Type = [IntType] int
|
||||
# 1463| Value = [Literal] 2
|
||||
# 1463| ValueCategory = prvalue
|
||||
|
@ -12909,11 +12909,11 @@ ir.cpp:
|
|||
# 1673| getExpr(): [ArrayAggregateLiteral] {...}
|
||||
# 1673| Type = [ArrayType] int[2]
|
||||
# 1673| ValueCategory = prvalue
|
||||
# 1673| getElementExpr(0): [Literal] 1
|
||||
# 1673| getAnElementExpr(0): [Literal] 1
|
||||
# 1673| Type = [IntType] int
|
||||
# 1673| Value = [Literal] 1
|
||||
# 1673| ValueCategory = prvalue
|
||||
# 1673| getElementExpr(1): [Literal] 2
|
||||
# 1673| getAnElementExpr(1): [Literal] 2
|
||||
# 1673| Type = [IntType] int
|
||||
# 1673| Value = [Literal] 2
|
||||
# 1673| ValueCategory = prvalue
|
||||
|
@ -13021,28 +13021,28 @@ ir.cpp:
|
|||
# 1688| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1688| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1688| ValueCategory = prvalue
|
||||
# 1688| getFieldExpr(obj1): [VariableAccess] obj1
|
||||
# 1688| getAFieldExpr(obj1): [VariableAccess] obj1
|
||||
# 1688| Type = [LValueReferenceType] const CapturedLambdaMyObj &
|
||||
# 1688| ValueCategory = prvalue(load)
|
||||
# 1688| getFieldExpr(obj2): [VariableAccess] obj2
|
||||
# 1688| getAFieldExpr(obj2): [VariableAccess] obj2
|
||||
# 1688| Type = [Class] CapturedLambdaMyObj
|
||||
# 1688| ValueCategory = prvalue(load)
|
||||
# 1688| getFieldExpr(x): [VariableAccess] x
|
||||
# 1688| getAFieldExpr(x): [VariableAccess] x
|
||||
# 1688| Type = [IntType] int
|
||||
# 1688| ValueCategory = prvalue(load)
|
||||
# 1688| getFieldExpr(y): [VariableAccess] y
|
||||
# 1688| getAFieldExpr(y): [VariableAccess] y
|
||||
# 1688| Type = [LValueReferenceType] int &
|
||||
# 1688| ValueCategory = prvalue(load)
|
||||
# 1688| getFieldExpr(z): [VariableAccess] z
|
||||
# 1688| getAFieldExpr(z): [VariableAccess] z
|
||||
# 1688| Type = [RValueReferenceType] int &&
|
||||
# 1688| ValueCategory = prvalue(load)
|
||||
#-----| getFieldExpr(obj1).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
#-----| getAFieldExpr(obj1).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
#-----| Type = [SpecifiedType] const CapturedLambdaMyObj
|
||||
#-----| ValueCategory = prvalue(load)
|
||||
# 1690| getFieldExpr(y).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1690| getAFieldExpr(y).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1690| Type = [IntType] int
|
||||
# 1690| ValueCategory = prvalue(load)
|
||||
# 1690| getFieldExpr(z).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1690| getAFieldExpr(z).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1690| Type = [IntType] int
|
||||
# 1690| ValueCategory = prvalue(load)
|
||||
# 1691| getStmt(3): [ReturnStmt] return ...
|
||||
|
@ -13073,31 +13073,31 @@ ir.cpp:
|
|||
# 1689| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1689| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1689| ValueCategory = prvalue
|
||||
# 1689| getFieldExpr(obj1): [PointerFieldAccess] obj1
|
||||
# 1689| getAFieldExpr(obj1): [PointerFieldAccess] obj1
|
||||
# 1689| Type = [SpecifiedType] const CapturedLambdaMyObj
|
||||
# 1689| ValueCategory = prvalue(load)
|
||||
# 1689| getQualifier(): [ThisExpr] this
|
||||
# 1689| Type = [PointerType] lambda [] type at line 1689, col. 29 *
|
||||
# 1689| ValueCategory = prvalue(load)
|
||||
# 1689| getFieldExpr(obj2): [PointerFieldAccess] obj2
|
||||
# 1689| getAFieldExpr(obj2): [PointerFieldAccess] obj2
|
||||
# 1689| Type = [Class] CapturedLambdaMyObj
|
||||
# 1689| ValueCategory = prvalue(load)
|
||||
# 1689| getQualifier(): [ThisExpr] this
|
||||
# 1689| Type = [PointerType] lambda [] type at line 1689, col. 29 *
|
||||
# 1689| ValueCategory = prvalue(load)
|
||||
# 1689| getFieldExpr(x): [PointerFieldAccess] x
|
||||
# 1689| getAFieldExpr(x): [PointerFieldAccess] x
|
||||
# 1689| Type = [IntType] int
|
||||
# 1689| ValueCategory = prvalue(load)
|
||||
# 1689| getQualifier(): [ThisExpr] this
|
||||
# 1689| Type = [PointerType] const lambda [] type at line 1688, col. 25 *
|
||||
# 1689| ValueCategory = prvalue(load)
|
||||
# 1689| getFieldExpr(y): [PointerFieldAccess] y
|
||||
# 1689| getAFieldExpr(y): [PointerFieldAccess] y
|
||||
# 1689| Type = [IntType] int
|
||||
# 1689| ValueCategory = prvalue(load)
|
||||
# 1689| getQualifier(): [ThisExpr] this
|
||||
# 1689| Type = [PointerType] const lambda [] type at line 1688, col. 25 *
|
||||
# 1689| ValueCategory = prvalue(load)
|
||||
# 1689| getFieldExpr(z): [PointerFieldAccess] z
|
||||
# 1689| getAFieldExpr(z): [PointerFieldAccess] z
|
||||
# 1689| Type = [IntType] int
|
||||
# 1689| ValueCategory = prvalue(load)
|
||||
# 1689| getQualifier(): [ThisExpr] this
|
||||
|
@ -13161,7 +13161,7 @@ ir.cpp:
|
|||
# 1702| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1702| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1702| ValueCategory = prvalue
|
||||
# 1702| getFieldExpr((captured this)): [PointerDereferenceExpr] * ...
|
||||
# 1702| getAFieldExpr((captured this)): [PointerDereferenceExpr] * ...
|
||||
# 1702| Type = [SpecifiedType] const TrivialLambdaClass
|
||||
# 1702| ValueCategory = prvalue(load)
|
||||
# 1702| getOperand(): [ThisExpr] this
|
||||
|
@ -13208,7 +13208,7 @@ ir.cpp:
|
|||
# 1705| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1705| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1705| ValueCategory = prvalue
|
||||
# 1705| getFieldExpr((captured this)): [PointerFieldAccess] (captured this)
|
||||
# 1705| getAFieldExpr((captured this)): [PointerFieldAccess] (captured this)
|
||||
# 1705| Type = [SpecifiedType] const TrivialLambdaClass
|
||||
# 1705| ValueCategory = prvalue(load)
|
||||
# 1705| getQualifier(): [ThisExpr] this
|
||||
|
@ -13289,28 +13289,28 @@ ir.cpp:
|
|||
# 1716| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1716| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1716| ValueCategory = prvalue
|
||||
# 1716| getFieldExpr(p1): [VariableAccess] p1
|
||||
# 1716| getAFieldExpr(p1): [VariableAccess] p1
|
||||
# 1716| Type = [Class] TrivialLambdaClass
|
||||
# 1716| ValueCategory = prvalue(load)
|
||||
# 1716| getFieldExpr(p2): [VariableAccess] p2
|
||||
# 1716| getAFieldExpr(p2): [VariableAccess] p2
|
||||
# 1716| Type = [LValueReferenceType] TrivialLambdaClass &
|
||||
# 1716| ValueCategory = prvalue(load)
|
||||
# 1716| getFieldExpr(p3): [VariableAccess] p3
|
||||
# 1716| getAFieldExpr(p3): [VariableAccess] p3
|
||||
# 1716| Type = [RValueReferenceType] TrivialLambdaClass &&
|
||||
# 1716| ValueCategory = prvalue(load)
|
||||
# 1716| getFieldExpr(l1): [VariableAccess] l1
|
||||
# 1716| getAFieldExpr(l1): [VariableAccess] l1
|
||||
# 1716| Type = [SpecifiedType] const TrivialLambdaClass
|
||||
# 1716| ValueCategory = prvalue(load)
|
||||
# 1716| getFieldExpr(l2): [VariableAccess] l2
|
||||
# 1716| getAFieldExpr(l2): [VariableAccess] l2
|
||||
# 1716| Type = [LValueReferenceType] const TrivialLambdaClass &
|
||||
# 1716| ValueCategory = prvalue(load)
|
||||
#-----| getFieldExpr(p2).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
#-----| getAFieldExpr(p2).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
#-----| Type = [Class] TrivialLambdaClass
|
||||
#-----| ValueCategory = prvalue(load)
|
||||
#-----| getFieldExpr(p3).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
#-----| getAFieldExpr(p3).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
#-----| Type = [Class] TrivialLambdaClass
|
||||
#-----| ValueCategory = prvalue(load)
|
||||
#-----| getFieldExpr(l2).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
#-----| getAFieldExpr(l2).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
#-----| Type = [SpecifiedType] const TrivialLambdaClass
|
||||
#-----| ValueCategory = prvalue(load)
|
||||
# 1719| getStmt(3): [ReturnStmt] return ...
|
||||
|
@ -13341,7 +13341,7 @@ ir.cpp:
|
|||
# 1717| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1717| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1717| ValueCategory = prvalue
|
||||
# 1717| getFieldExpr(p1): [PointerFieldAccess] p1
|
||||
# 1717| getAFieldExpr(p1): [PointerFieldAccess] p1
|
||||
# 1717| Type = [Class] TrivialLambdaClass
|
||||
# 1717| ValueCategory = prvalue(load)
|
||||
# 1717| getQualifier(): [ThisExpr] this
|
||||
|
@ -14685,33 +14685,33 @@ struct_init.cpp:
|
|||
# 21| getExpr(): [ArrayAggregateLiteral] {...}
|
||||
# 21| Type = [ArrayType] Info[2]
|
||||
# 21| ValueCategory = prvalue
|
||||
# 22| getElementExpr(0): [ClassAggregateLiteral] {...}
|
||||
# 22| getAnElementExpr(0): [ClassAggregateLiteral] {...}
|
||||
# 22| Type = [Struct] Info
|
||||
# 22| ValueCategory = prvalue
|
||||
# 22| getFieldExpr(name): 1
|
||||
# 22| getAFieldExpr(name): 1
|
||||
# 22| Type = [ArrayType] const char[2]
|
||||
# 22| Value = [StringLiteral] "1"
|
||||
# 22| ValueCategory = lvalue
|
||||
# 22| getFieldExpr(handler): [FunctionAccess] handler1
|
||||
# 22| getAFieldExpr(handler): [FunctionAccess] handler1
|
||||
# 22| Type = [FunctionPointerType] ..(*)(..)
|
||||
# 22| ValueCategory = prvalue(load)
|
||||
# 22| getFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 22| getAFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 22| Type = [PointerType] const char *
|
||||
# 22| ValueCategory = prvalue
|
||||
# 23| getElementExpr(1): [ClassAggregateLiteral] {...}
|
||||
# 23| getAnElementExpr(1): [ClassAggregateLiteral] {...}
|
||||
# 23| Type = [Struct] Info
|
||||
# 23| ValueCategory = prvalue
|
||||
# 23| getFieldExpr(name): 2
|
||||
# 23| getAFieldExpr(name): 2
|
||||
# 23| Type = [ArrayType] const char[2]
|
||||
# 23| Value = [StringLiteral] "2"
|
||||
# 23| ValueCategory = lvalue
|
||||
# 23| getFieldExpr(handler): [AddressOfExpr] & ...
|
||||
# 23| getAFieldExpr(handler): [AddressOfExpr] & ...
|
||||
# 23| Type = [FunctionPointerType] ..(*)(..)
|
||||
# 23| ValueCategory = prvalue
|
||||
# 23| getOperand(): [FunctionAccess] handler2
|
||||
# 23| Type = [RoutineType] ..()(..)
|
||||
# 23| ValueCategory = lvalue
|
||||
# 23| getFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 23| getAFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 23| Type = [PointerType] const char *
|
||||
# 23| ValueCategory = prvalue
|
||||
# 25| getStmt(1): [ExprStmt] ExprStmt
|
||||
|
@ -14735,33 +14735,33 @@ struct_init.cpp:
|
|||
# 29| getExpr(): [ArrayAggregateLiteral] {...}
|
||||
# 29| Type = [ArrayType] Info[2]
|
||||
# 29| ValueCategory = prvalue
|
||||
# 30| getElementExpr(0): [ClassAggregateLiteral] {...}
|
||||
# 30| getAnElementExpr(0): [ClassAggregateLiteral] {...}
|
||||
# 30| Type = [Struct] Info
|
||||
# 30| ValueCategory = prvalue
|
||||
# 30| getFieldExpr(name): 1
|
||||
# 30| getAFieldExpr(name): 1
|
||||
# 30| Type = [ArrayType] const char[2]
|
||||
# 30| Value = [StringLiteral] "1"
|
||||
# 30| ValueCategory = lvalue
|
||||
# 30| getFieldExpr(handler): [FunctionAccess] handler1
|
||||
# 30| getAFieldExpr(handler): [FunctionAccess] handler1
|
||||
# 30| Type = [FunctionPointerType] ..(*)(..)
|
||||
# 30| ValueCategory = prvalue(load)
|
||||
# 30| getFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 30| getAFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 30| Type = [PointerType] const char *
|
||||
# 30| ValueCategory = prvalue
|
||||
# 31| getElementExpr(1): [ClassAggregateLiteral] {...}
|
||||
# 31| getAnElementExpr(1): [ClassAggregateLiteral] {...}
|
||||
# 31| Type = [Struct] Info
|
||||
# 31| ValueCategory = prvalue
|
||||
# 31| getFieldExpr(name): 2
|
||||
# 31| getAFieldExpr(name): 2
|
||||
# 31| Type = [ArrayType] const char[2]
|
||||
# 31| Value = [StringLiteral] "2"
|
||||
# 31| ValueCategory = lvalue
|
||||
# 31| getFieldExpr(handler): [AddressOfExpr] & ...
|
||||
# 31| getAFieldExpr(handler): [AddressOfExpr] & ...
|
||||
# 31| Type = [FunctionPointerType] ..(*)(..)
|
||||
# 31| ValueCategory = prvalue
|
||||
# 31| getOperand(): [FunctionAccess] handler2
|
||||
# 31| Type = [RoutineType] ..()(..)
|
||||
# 31| ValueCategory = lvalue
|
||||
# 31| getFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 31| getAFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 31| Type = [PointerType] const char *
|
||||
# 31| ValueCategory = prvalue
|
||||
# 33| getStmt(1): [ExprStmt] ExprStmt
|
||||
|
@ -14787,29 +14787,29 @@ struct_init.cpp:
|
|||
# 37| getExpr(): [ArrayAggregateLiteral] {...}
|
||||
# 37| Type = [ArrayType] Info[2]
|
||||
# 37| ValueCategory = prvalue
|
||||
# 38| getElementExpr(0): [ClassAggregateLiteral] {...}
|
||||
# 38| getAnElementExpr(0): [ClassAggregateLiteral] {...}
|
||||
# 38| Type = [Struct] Info
|
||||
# 38| ValueCategory = prvalue
|
||||
# 38| getFieldExpr(name): [VariableAccess] name1
|
||||
# 38| getAFieldExpr(name): [VariableAccess] name1
|
||||
# 38| Type = [PointerType] const char *
|
||||
# 38| ValueCategory = prvalue(load)
|
||||
# 38| getFieldExpr(handler): [FunctionAccess] handler1
|
||||
# 38| getAFieldExpr(handler): [FunctionAccess] handler1
|
||||
# 38| Type = [FunctionPointerType] ..(*)(..)
|
||||
# 38| ValueCategory = prvalue(load)
|
||||
# 39| getElementExpr(1): [ClassAggregateLiteral] {...}
|
||||
# 39| getAnElementExpr(1): [ClassAggregateLiteral] {...}
|
||||
# 39| Type = [Struct] Info
|
||||
# 39| ValueCategory = prvalue
|
||||
# 39| getFieldExpr(name): 2
|
||||
# 39| getAFieldExpr(name): 2
|
||||
# 39| Type = [ArrayType] const char[2]
|
||||
# 39| Value = [StringLiteral] "2"
|
||||
# 39| ValueCategory = lvalue
|
||||
# 39| getFieldExpr(handler): [AddressOfExpr] & ...
|
||||
# 39| getAFieldExpr(handler): [AddressOfExpr] & ...
|
||||
# 39| Type = [FunctionPointerType] ..(*)(..)
|
||||
# 39| ValueCategory = prvalue
|
||||
# 39| getOperand(): [FunctionAccess] handler2
|
||||
# 39| Type = [RoutineType] ..()(..)
|
||||
# 39| ValueCategory = lvalue
|
||||
# 39| getFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 39| getAFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 39| Type = [PointerType] const char *
|
||||
# 39| ValueCategory = prvalue
|
||||
# 41| getStmt(1): [ExprStmt] ExprStmt
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import cpp
|
||||
import experimental.semmle.code.cpp.semantic.analysis.ModulusAnalysis
|
||||
import experimental.semmle.code.cpp.semantic.Semantic
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeUtils
|
||||
import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysisSpecific
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysisImpl
|
||||
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.ModulusAnalysis
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisSpecific
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisImpl
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import cpp
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
|
||||
import experimental.semmle.code.cpp.semantic.Semantic
|
||||
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import cpp
|
||||
import experimental.semmle.code.cpp.semantic.analysis.SignAnalysisCommon
|
||||
import experimental.semmle.code.cpp.semantic.Semantic
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeUtils
|
||||
import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysisSpecific
|
||||
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.SignAnalysisCommon
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisSpecific
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
|
|
|
@ -1,3 +1,165 @@
|
|||
ssa.c:
|
||||
# 2| void named_designators()
|
||||
# 2| Block 0
|
||||
# 2| v2_1(void) = EnterFunction :
|
||||
# 2| m2_2(unknown) = AliasedDefinition :
|
||||
# 2| m2_3(unknown) = InitializeNonLocal :
|
||||
# 2| m2_4(unknown) = Chi : total:m2_2, partial:m2_3
|
||||
# 3| r3_1(glval<Foo>) = VariableAddress[foo] :
|
||||
# 3| m3_2(Foo) = Uninitialized[foo] : &:r3_1
|
||||
# 3| r3_3(glval<int[2]>) = FieldAddress[x] : r3_1
|
||||
# 3| r3_4(int) = Constant[0] :
|
||||
# 3| r3_5(glval<int>) = PointerAdd[4] : r3_3, r3_4
|
||||
# 3| r3_6(int) = Constant[1234] :
|
||||
# 3| m3_7(int) = Store[?] : &:r3_5, r3_6
|
||||
# 3| m3_8(Foo) = Chi : total:m3_2, partial:m3_7
|
||||
# 3| r3_9(int) = Constant[1] :
|
||||
# 3| r3_10(glval<int>) = PointerAdd[4] : r3_3, r3_9
|
||||
# 3| r3_11(int) = Constant[0] :
|
||||
# 3| m3_12(int) = Store[?] : &:r3_10, r3_11
|
||||
# 3| m3_13(Foo) = Chi : total:m3_8, partial:m3_12
|
||||
# 3| r3_14(glval<int[2]>) = FieldAddress[x] : r3_1
|
||||
# 3| r3_15(int) = Constant[0] :
|
||||
# 3| r3_16(glval<int>) = PointerAdd[4] : r3_14, r3_15
|
||||
# 3| r3_17(int) = Constant[0] :
|
||||
# 3| m3_18(int) = Store[?] : &:r3_16, r3_17
|
||||
# 3| m3_19(Foo) = Chi : total:m3_13, partial:m3_18
|
||||
# 3| r3_20(int) = Constant[1] :
|
||||
# 3| r3_21(glval<int>) = PointerAdd[4] : r3_14, r3_20
|
||||
# 3| r3_22(int) = Constant[5678] :
|
||||
# 3| m3_23(int) = Store[?] : &:r3_21, r3_22
|
||||
# 3| m3_24(Foo) = Chi : total:m3_19, partial:m3_23
|
||||
# 4| v4_1(void) = NoOp :
|
||||
# 2| v2_5(void) = ReturnVoid :
|
||||
# 2| v2_6(void) = AliasedUse : m2_3
|
||||
# 2| v2_7(void) = ExitFunction :
|
||||
|
||||
# 6| void repeated_designators()
|
||||
# 6| Block 0
|
||||
# 6| v6_1(void) = EnterFunction :
|
||||
# 6| m6_2(unknown) = AliasedDefinition :
|
||||
# 6| m6_3(unknown) = InitializeNonLocal :
|
||||
# 6| m6_4(unknown) = Chi : total:m6_2, partial:m6_3
|
||||
# 7| r7_1(glval<int[1]>) = VariableAddress[x] :
|
||||
# 7| m7_2(int[1]) = Uninitialized[x] : &:r7_1
|
||||
# 7| r7_3(int) = Constant[0] :
|
||||
# 7| r7_4(glval<int>) = PointerAdd[4] : r7_1, r7_3
|
||||
# 7| r7_5(int) = Constant[1234] :
|
||||
# 7| m7_6(int) = Store[?] : &:r7_4, r7_5
|
||||
# 7| r7_7(int) = Constant[0] :
|
||||
# 7| r7_8(glval<int>) = PointerAdd[4] : r7_1, r7_7
|
||||
# 7| r7_9(int) = Constant[5678] :
|
||||
# 7| m7_10(int) = Store[?] : &:r7_8, r7_9
|
||||
# 8| v8_1(void) = NoOp :
|
||||
# 6| v6_5(void) = ReturnVoid :
|
||||
# 6| v6_6(void) = AliasedUse : m6_3
|
||||
# 6| v6_7(void) = ExitFunction :
|
||||
|
||||
# 11| void named_designators_2()
|
||||
# 11| Block 0
|
||||
# 11| v11_1(void) = EnterFunction :
|
||||
# 11| m11_2(unknown) = AliasedDefinition :
|
||||
# 11| m11_3(unknown) = InitializeNonLocal :
|
||||
# 11| m11_4(unknown) = Chi : total:m11_2, partial:m11_3
|
||||
# 12| r12_1(glval<Foo2>) = VariableAddress[foo] :
|
||||
# 12| m12_2(Foo2) = Uninitialized[foo] : &:r12_1
|
||||
# 12| r12_3(glval<int>) = FieldAddress[x] : r12_1
|
||||
# 12| r12_4(int) = Constant[1234] :
|
||||
# 12| m12_5(int) = Store[?] : &:r12_3, r12_4
|
||||
# 12| m12_6(Foo2) = Chi : total:m12_2, partial:m12_5
|
||||
# 12| r12_7(glval<int>) = FieldAddress[y] : r12_1
|
||||
# 12| r12_8(int) = Constant[5678] :
|
||||
# 12| m12_9(int) = Store[?] : &:r12_7, r12_8
|
||||
# 12| m12_10(Foo2) = Chi : total:m12_6, partial:m12_9
|
||||
# 14| r14_1(glval<Foo2>) = VariableAddress[foo_swapped] :
|
||||
# 14| m14_2(Foo2) = Uninitialized[foo_swapped] : &:r14_1
|
||||
# 14| r14_3(glval<int>) = FieldAddress[x] : r14_1
|
||||
# 14| r14_4(int) = Constant[1234] :
|
||||
# 14| m14_5(int) = Store[?] : &:r14_3, r14_4
|
||||
# 14| m14_6(Foo2) = Chi : total:m14_2, partial:m14_5
|
||||
# 14| r14_7(glval<int>) = FieldAddress[y] : r14_1
|
||||
# 14| r14_8(int) = Constant[5678] :
|
||||
# 14| m14_9(int) = Store[?] : &:r14_7, r14_8
|
||||
# 14| m14_10(Foo2) = Chi : total:m14_6, partial:m14_9
|
||||
# 15| v15_1(void) = NoOp :
|
||||
# 11| v11_5(void) = ReturnVoid :
|
||||
# 11| v11_6(void) = AliasedUse : m11_3
|
||||
# 11| v11_7(void) = ExitFunction :
|
||||
|
||||
# 17| void non_repeated_designators()
|
||||
# 17| Block 0
|
||||
# 17| v17_1(void) = EnterFunction :
|
||||
# 17| m17_2(unknown) = AliasedDefinition :
|
||||
# 17| m17_3(unknown) = InitializeNonLocal :
|
||||
# 17| m17_4(unknown) = Chi : total:m17_2, partial:m17_3
|
||||
# 18| r18_1(glval<int[2]>) = VariableAddress[x] :
|
||||
# 18| m18_2(int[2]) = Uninitialized[x] : &:r18_1
|
||||
# 18| r18_3(int) = Constant[0] :
|
||||
# 18| r18_4(glval<int>) = PointerAdd[4] : r18_1, r18_3
|
||||
# 18| r18_5(int) = Constant[1234] :
|
||||
# 18| m18_6(int) = Store[?] : &:r18_4, r18_5
|
||||
# 18| m18_7(int[2]) = Chi : total:m18_2, partial:m18_6
|
||||
# 18| r18_8(int) = Constant[1] :
|
||||
# 18| r18_9(glval<int>) = PointerAdd[4] : r18_1, r18_8
|
||||
# 18| r18_10(int) = Constant[5678] :
|
||||
# 18| m18_11(int) = Store[?] : &:r18_9, r18_10
|
||||
# 18| m18_12(int[2]) = Chi : total:m18_7, partial:m18_11
|
||||
# 20| r20_1(glval<int[2]>) = VariableAddress[y] :
|
||||
# 20| m20_2(int[2]) = Uninitialized[y] : &:r20_1
|
||||
# 20| r20_3(int) = Constant[0] :
|
||||
# 20| r20_4(glval<int>) = PointerAdd[4] : r20_1, r20_3
|
||||
# 20| r20_5(int) = Constant[5678] :
|
||||
# 20| m20_6(int) = Store[?] : &:r20_4, r20_5
|
||||
# 20| m20_7(int[2]) = Chi : total:m20_2, partial:m20_6
|
||||
# 20| r20_8(int) = Constant[1] :
|
||||
# 20| r20_9(glval<int>) = PointerAdd[4] : r20_1, r20_8
|
||||
# 20| r20_10(int) = Constant[1234] :
|
||||
# 20| m20_11(int) = Store[?] : &:r20_9, r20_10
|
||||
# 20| m20_12(int[2]) = Chi : total:m20_7, partial:m20_11
|
||||
# 21| v21_1(void) = NoOp :
|
||||
# 17| v17_5(void) = ReturnVoid :
|
||||
# 17| v17_6(void) = AliasedUse : m17_3
|
||||
# 17| v17_7(void) = ExitFunction :
|
||||
|
||||
# 28| void test_foo_array_and_int()
|
||||
# 28| Block 0
|
||||
# 28| v28_1(void) = EnterFunction :
|
||||
# 28| m28_2(unknown) = AliasedDefinition :
|
||||
# 28| m28_3(unknown) = InitializeNonLocal :
|
||||
# 28| m28_4(unknown) = Chi : total:m28_2, partial:m28_3
|
||||
# 29| r29_1(glval<Foo_array_and_int>) = VariableAddress[f] :
|
||||
# 29| m29_2(Foo_array_and_int) = Uninitialized[f] : &:r29_1
|
||||
# 29| r29_3(glval<int[2]>) = FieldAddress[x] : r29_1
|
||||
# 29| r29_4(int) = Constant[0] :
|
||||
# 29| r29_5(glval<int>) = PointerAdd[4] : r29_3, r29_4
|
||||
# 29| r29_6(int) = Constant[0] :
|
||||
# 29| m29_7(int) = Store[?] : &:r29_5, r29_6
|
||||
# 29| m29_8(Foo_array_and_int) = Chi : total:m29_2, partial:m29_7
|
||||
# 29| r29_9(int) = Constant[1] :
|
||||
# 29| r29_10(glval<int>) = PointerAdd[4] : r29_3, r29_9
|
||||
# 29| r29_11(int) = Constant[1] :
|
||||
# 29| m29_12(int) = Store[?] : &:r29_10, r29_11
|
||||
# 29| m29_13(Foo_array_and_int) = Chi : total:m29_8, partial:m29_12
|
||||
# 29| r29_14(glval<int[2]>) = FieldAddress[x] : r29_1
|
||||
# 29| r29_15(int) = Constant[0] :
|
||||
# 29| r29_16(glval<int>) = PointerAdd[4] : r29_14, r29_15
|
||||
# 29| r29_17(int) = Constant[42] :
|
||||
# 29| m29_18(int) = Store[?] : &:r29_16, r29_17
|
||||
# 29| m29_19(Foo_array_and_int) = Chi : total:m29_13, partial:m29_18
|
||||
# 29| r29_20(int) = Constant[1] :
|
||||
# 29| r29_21(glval<int>) = PointerAdd[4] : r29_14, r29_20
|
||||
# 29| r29_22(int) = Constant[0] :
|
||||
# 29| m29_23(int) = Store[?] : &:r29_21, r29_22
|
||||
# 29| m29_24(Foo_array_and_int) = Chi : total:m29_19, partial:m29_23
|
||||
# 29| r29_25(glval<int>) = FieldAddress[y] : r29_1
|
||||
# 29| r29_26(int) = Constant[42] :
|
||||
# 29| m29_27(int) = Store[?] : &:r29_25, r29_26
|
||||
# 29| m29_28(Foo_array_and_int) = Chi : total:m29_24, partial:m29_27
|
||||
# 30| v30_1(void) = NoOp :
|
||||
# 28| v28_5(void) = ReturnVoid :
|
||||
# 28| v28_6(void) = AliasedUse : m28_3
|
||||
# 28| v28_7(void) = ExitFunction :
|
||||
|
||||
ssa.cpp:
|
||||
# 13| int ChiPhiNode(Point*, bool, bool)
|
||||
# 13| Block 0
|
||||
|
@ -1892,3 +2054,40 @@ ssa.cpp:
|
|||
# 401| v401_13(void) = ReturnVoid :
|
||||
# 401| v401_14(void) = AliasedUse : ~m408_10
|
||||
# 401| v401_15(void) = ExitFunction :
|
||||
|
||||
# 417| void nested_array_designators()
|
||||
# 417| Block 0
|
||||
# 417| v417_1(void) = EnterFunction :
|
||||
# 417| m417_2(unknown) = AliasedDefinition :
|
||||
# 417| m417_3(unknown) = InitializeNonLocal :
|
||||
# 417| m417_4(unknown) = Chi : total:m417_2, partial:m417_3
|
||||
# 418| r418_1(glval<int[1][2]>) = VariableAddress[x] :
|
||||
# 418| m418_2(int[1][2]) = Uninitialized[x] : &:r418_1
|
||||
# 418| r418_3(int) = Constant[0] :
|
||||
# 418| r418_4(glval<int[2]>) = PointerAdd[8] : r418_1, r418_3
|
||||
# 418| r418_5(int) = Constant[0] :
|
||||
# 418| r418_6(glval<int>) = PointerAdd[4] : r418_4, r418_5
|
||||
# 418| r418_7(int) = Constant[1234] :
|
||||
# 418| m418_8(int) = Store[?] : &:r418_6, r418_7
|
||||
# 418| m418_9(int[1][2]) = Chi : total:m418_2, partial:m418_8
|
||||
# 418| r418_10(int) = Constant[1] :
|
||||
# 418| r418_11(glval<int>) = PointerAdd[4] : r418_4, r418_10
|
||||
# 418| r418_12(int) = Constant[0] :
|
||||
# 418| m418_13(int) = Store[?] : &:r418_11, r418_12
|
||||
# 418| m418_14(int[1][2]) = Chi : total:m418_9, partial:m418_13
|
||||
# 418| r418_15(int) = Constant[0] :
|
||||
# 418| r418_16(glval<int[2]>) = PointerAdd[8] : r418_1, r418_15
|
||||
# 418| r418_17(int) = Constant[0] :
|
||||
# 418| r418_18(glval<int>) = PointerAdd[4] : r418_16, r418_17
|
||||
# 418| r418_19(int) = Constant[0] :
|
||||
# 418| m418_20(int) = Store[?] : &:r418_18, r418_19
|
||||
# 418| m418_21(int[1][2]) = Chi : total:m418_14, partial:m418_20
|
||||
# 418| r418_22(int) = Constant[1] :
|
||||
# 418| r418_23(glval<int>) = PointerAdd[4] : r418_16, r418_22
|
||||
# 418| r418_24(int) = Constant[5678] :
|
||||
# 418| m418_25(int) = Store[?] : &:r418_23, r418_24
|
||||
# 418| m418_26(int[1][2]) = Chi : total:m418_21, partial:m418_25
|
||||
# 419| v419_1(void) = NoOp :
|
||||
# 417| v417_5(void) = ReturnVoid :
|
||||
# 417| v417_6(void) = AliasedUse : m417_3
|
||||
# 417| v417_7(void) = ExitFunction :
|
||||
|
|
|
@ -1,3 +1,165 @@
|
|||
ssa.c:
|
||||
# 2| void named_designators()
|
||||
# 2| Block 0
|
||||
# 2| v2_1(void) = EnterFunction :
|
||||
# 2| m2_2(unknown) = AliasedDefinition :
|
||||
# 2| m2_3(unknown) = InitializeNonLocal :
|
||||
# 2| m2_4(unknown) = Chi : total:m2_2, partial:m2_3
|
||||
# 3| r3_1(glval<Foo>) = VariableAddress[foo] :
|
||||
# 3| m3_2(Foo) = Uninitialized[foo] : &:r3_1
|
||||
# 3| r3_3(glval<int[2]>) = FieldAddress[x] : r3_1
|
||||
# 3| r3_4(int) = Constant[0] :
|
||||
# 3| r3_5(glval<int>) = PointerAdd[4] : r3_3, r3_4
|
||||
# 3| r3_6(int) = Constant[1234] :
|
||||
# 3| m3_7(int) = Store[?] : &:r3_5, r3_6
|
||||
# 3| m3_8(Foo) = Chi : total:m3_2, partial:m3_7
|
||||
# 3| r3_9(int) = Constant[1] :
|
||||
# 3| r3_10(glval<int>) = PointerAdd[4] : r3_3, r3_9
|
||||
# 3| r3_11(int) = Constant[0] :
|
||||
# 3| m3_12(int) = Store[?] : &:r3_10, r3_11
|
||||
# 3| m3_13(Foo) = Chi : total:m3_8, partial:m3_12
|
||||
# 3| r3_14(glval<int[2]>) = FieldAddress[x] : r3_1
|
||||
# 3| r3_15(int) = Constant[0] :
|
||||
# 3| r3_16(glval<int>) = PointerAdd[4] : r3_14, r3_15
|
||||
# 3| r3_17(int) = Constant[0] :
|
||||
# 3| m3_18(int) = Store[?] : &:r3_16, r3_17
|
||||
# 3| m3_19(Foo) = Chi : total:m3_13, partial:m3_18
|
||||
# 3| r3_20(int) = Constant[1] :
|
||||
# 3| r3_21(glval<int>) = PointerAdd[4] : r3_14, r3_20
|
||||
# 3| r3_22(int) = Constant[5678] :
|
||||
# 3| m3_23(int) = Store[?] : &:r3_21, r3_22
|
||||
# 3| m3_24(Foo) = Chi : total:m3_19, partial:m3_23
|
||||
# 4| v4_1(void) = NoOp :
|
||||
# 2| v2_5(void) = ReturnVoid :
|
||||
# 2| v2_6(void) = AliasedUse : m2_3
|
||||
# 2| v2_7(void) = ExitFunction :
|
||||
|
||||
# 6| void repeated_designators()
|
||||
# 6| Block 0
|
||||
# 6| v6_1(void) = EnterFunction :
|
||||
# 6| m6_2(unknown) = AliasedDefinition :
|
||||
# 6| m6_3(unknown) = InitializeNonLocal :
|
||||
# 6| m6_4(unknown) = Chi : total:m6_2, partial:m6_3
|
||||
# 7| r7_1(glval<int[1]>) = VariableAddress[x] :
|
||||
# 7| m7_2(int[1]) = Uninitialized[x] : &:r7_1
|
||||
# 7| r7_3(int) = Constant[0] :
|
||||
# 7| r7_4(glval<int>) = PointerAdd[4] : r7_1, r7_3
|
||||
# 7| r7_5(int) = Constant[1234] :
|
||||
# 7| m7_6(int) = Store[?] : &:r7_4, r7_5
|
||||
# 7| r7_7(int) = Constant[0] :
|
||||
# 7| r7_8(glval<int>) = PointerAdd[4] : r7_1, r7_7
|
||||
# 7| r7_9(int) = Constant[5678] :
|
||||
# 7| m7_10(int) = Store[?] : &:r7_8, r7_9
|
||||
# 8| v8_1(void) = NoOp :
|
||||
# 6| v6_5(void) = ReturnVoid :
|
||||
# 6| v6_6(void) = AliasedUse : m6_3
|
||||
# 6| v6_7(void) = ExitFunction :
|
||||
|
||||
# 11| void named_designators_2()
|
||||
# 11| Block 0
|
||||
# 11| v11_1(void) = EnterFunction :
|
||||
# 11| m11_2(unknown) = AliasedDefinition :
|
||||
# 11| m11_3(unknown) = InitializeNonLocal :
|
||||
# 11| m11_4(unknown) = Chi : total:m11_2, partial:m11_3
|
||||
# 12| r12_1(glval<Foo2>) = VariableAddress[foo] :
|
||||
# 12| m12_2(Foo2) = Uninitialized[foo] : &:r12_1
|
||||
# 12| r12_3(glval<int>) = FieldAddress[x] : r12_1
|
||||
# 12| r12_4(int) = Constant[1234] :
|
||||
# 12| m12_5(int) = Store[?] : &:r12_3, r12_4
|
||||
# 12| m12_6(Foo2) = Chi : total:m12_2, partial:m12_5
|
||||
# 12| r12_7(glval<int>) = FieldAddress[y] : r12_1
|
||||
# 12| r12_8(int) = Constant[5678] :
|
||||
# 12| m12_9(int) = Store[?] : &:r12_7, r12_8
|
||||
# 12| m12_10(Foo2) = Chi : total:m12_6, partial:m12_9
|
||||
# 14| r14_1(glval<Foo2>) = VariableAddress[foo_swapped] :
|
||||
# 14| m14_2(Foo2) = Uninitialized[foo_swapped] : &:r14_1
|
||||
# 14| r14_3(glval<int>) = FieldAddress[x] : r14_1
|
||||
# 14| r14_4(int) = Constant[1234] :
|
||||
# 14| m14_5(int) = Store[?] : &:r14_3, r14_4
|
||||
# 14| m14_6(Foo2) = Chi : total:m14_2, partial:m14_5
|
||||
# 14| r14_7(glval<int>) = FieldAddress[y] : r14_1
|
||||
# 14| r14_8(int) = Constant[5678] :
|
||||
# 14| m14_9(int) = Store[?] : &:r14_7, r14_8
|
||||
# 14| m14_10(Foo2) = Chi : total:m14_6, partial:m14_9
|
||||
# 15| v15_1(void) = NoOp :
|
||||
# 11| v11_5(void) = ReturnVoid :
|
||||
# 11| v11_6(void) = AliasedUse : m11_3
|
||||
# 11| v11_7(void) = ExitFunction :
|
||||
|
||||
# 17| void non_repeated_designators()
|
||||
# 17| Block 0
|
||||
# 17| v17_1(void) = EnterFunction :
|
||||
# 17| m17_2(unknown) = AliasedDefinition :
|
||||
# 17| m17_3(unknown) = InitializeNonLocal :
|
||||
# 17| m17_4(unknown) = Chi : total:m17_2, partial:m17_3
|
||||
# 18| r18_1(glval<int[2]>) = VariableAddress[x] :
|
||||
# 18| m18_2(int[2]) = Uninitialized[x] : &:r18_1
|
||||
# 18| r18_3(int) = Constant[0] :
|
||||
# 18| r18_4(glval<int>) = PointerAdd[4] : r18_1, r18_3
|
||||
# 18| r18_5(int) = Constant[1234] :
|
||||
# 18| m18_6(int) = Store[?] : &:r18_4, r18_5
|
||||
# 18| m18_7(int[2]) = Chi : total:m18_2, partial:m18_6
|
||||
# 18| r18_8(int) = Constant[1] :
|
||||
# 18| r18_9(glval<int>) = PointerAdd[4] : r18_1, r18_8
|
||||
# 18| r18_10(int) = Constant[5678] :
|
||||
# 18| m18_11(int) = Store[?] : &:r18_9, r18_10
|
||||
# 18| m18_12(int[2]) = Chi : total:m18_7, partial:m18_11
|
||||
# 20| r20_1(glval<int[2]>) = VariableAddress[y] :
|
||||
# 20| m20_2(int[2]) = Uninitialized[y] : &:r20_1
|
||||
# 20| r20_3(int) = Constant[0] :
|
||||
# 20| r20_4(glval<int>) = PointerAdd[4] : r20_1, r20_3
|
||||
# 20| r20_5(int) = Constant[5678] :
|
||||
# 20| m20_6(int) = Store[?] : &:r20_4, r20_5
|
||||
# 20| m20_7(int[2]) = Chi : total:m20_2, partial:m20_6
|
||||
# 20| r20_8(int) = Constant[1] :
|
||||
# 20| r20_9(glval<int>) = PointerAdd[4] : r20_1, r20_8
|
||||
# 20| r20_10(int) = Constant[1234] :
|
||||
# 20| m20_11(int) = Store[?] : &:r20_9, r20_10
|
||||
# 20| m20_12(int[2]) = Chi : total:m20_7, partial:m20_11
|
||||
# 21| v21_1(void) = NoOp :
|
||||
# 17| v17_5(void) = ReturnVoid :
|
||||
# 17| v17_6(void) = AliasedUse : m17_3
|
||||
# 17| v17_7(void) = ExitFunction :
|
||||
|
||||
# 28| void test_foo_array_and_int()
|
||||
# 28| Block 0
|
||||
# 28| v28_1(void) = EnterFunction :
|
||||
# 28| m28_2(unknown) = AliasedDefinition :
|
||||
# 28| m28_3(unknown) = InitializeNonLocal :
|
||||
# 28| m28_4(unknown) = Chi : total:m28_2, partial:m28_3
|
||||
# 29| r29_1(glval<Foo_array_and_int>) = VariableAddress[f] :
|
||||
# 29| m29_2(Foo_array_and_int) = Uninitialized[f] : &:r29_1
|
||||
# 29| r29_3(glval<int[2]>) = FieldAddress[x] : r29_1
|
||||
# 29| r29_4(int) = Constant[0] :
|
||||
# 29| r29_5(glval<int>) = PointerAdd[4] : r29_3, r29_4
|
||||
# 29| r29_6(int) = Constant[0] :
|
||||
# 29| m29_7(int) = Store[?] : &:r29_5, r29_6
|
||||
# 29| m29_8(Foo_array_and_int) = Chi : total:m29_2, partial:m29_7
|
||||
# 29| r29_9(int) = Constant[1] :
|
||||
# 29| r29_10(glval<int>) = PointerAdd[4] : r29_3, r29_9
|
||||
# 29| r29_11(int) = Constant[1] :
|
||||
# 29| m29_12(int) = Store[?] : &:r29_10, r29_11
|
||||
# 29| m29_13(Foo_array_and_int) = Chi : total:m29_8, partial:m29_12
|
||||
# 29| r29_14(glval<int[2]>) = FieldAddress[x] : r29_1
|
||||
# 29| r29_15(int) = Constant[0] :
|
||||
# 29| r29_16(glval<int>) = PointerAdd[4] : r29_14, r29_15
|
||||
# 29| r29_17(int) = Constant[42] :
|
||||
# 29| m29_18(int) = Store[?] : &:r29_16, r29_17
|
||||
# 29| m29_19(Foo_array_and_int) = Chi : total:m29_13, partial:m29_18
|
||||
# 29| r29_20(int) = Constant[1] :
|
||||
# 29| r29_21(glval<int>) = PointerAdd[4] : r29_14, r29_20
|
||||
# 29| r29_22(int) = Constant[0] :
|
||||
# 29| m29_23(int) = Store[?] : &:r29_21, r29_22
|
||||
# 29| m29_24(Foo_array_and_int) = Chi : total:m29_19, partial:m29_23
|
||||
# 29| r29_25(glval<int>) = FieldAddress[y] : r29_1
|
||||
# 29| r29_26(int) = Constant[42] :
|
||||
# 29| m29_27(int) = Store[?] : &:r29_25, r29_26
|
||||
# 29| m29_28(Foo_array_and_int) = Chi : total:m29_24, partial:m29_27
|
||||
# 30| v30_1(void) = NoOp :
|
||||
# 28| v28_5(void) = ReturnVoid :
|
||||
# 28| v28_6(void) = AliasedUse : m28_3
|
||||
# 28| v28_7(void) = ExitFunction :
|
||||
|
||||
ssa.cpp:
|
||||
# 13| int ChiPhiNode(Point*, bool, bool)
|
||||
# 13| Block 0
|
||||
|
@ -1881,3 +2043,40 @@ ssa.cpp:
|
|||
# 401| v401_13(void) = ReturnVoid :
|
||||
# 401| v401_14(void) = AliasedUse : ~m408_10
|
||||
# 401| v401_15(void) = ExitFunction :
|
||||
|
||||
# 417| void nested_array_designators()
|
||||
# 417| Block 0
|
||||
# 417| v417_1(void) = EnterFunction :
|
||||
# 417| m417_2(unknown) = AliasedDefinition :
|
||||
# 417| m417_3(unknown) = InitializeNonLocal :
|
||||
# 417| m417_4(unknown) = Chi : total:m417_2, partial:m417_3
|
||||
# 418| r418_1(glval<int[1][2]>) = VariableAddress[x] :
|
||||
# 418| m418_2(int[1][2]) = Uninitialized[x] : &:r418_1
|
||||
# 418| r418_3(int) = Constant[0] :
|
||||
# 418| r418_4(glval<int[2]>) = PointerAdd[8] : r418_1, r418_3
|
||||
# 418| r418_5(int) = Constant[0] :
|
||||
# 418| r418_6(glval<int>) = PointerAdd[4] : r418_4, r418_5
|
||||
# 418| r418_7(int) = Constant[1234] :
|
||||
# 418| m418_8(int) = Store[?] : &:r418_6, r418_7
|
||||
# 418| m418_9(int[1][2]) = Chi : total:m418_2, partial:m418_8
|
||||
# 418| r418_10(int) = Constant[1] :
|
||||
# 418| r418_11(glval<int>) = PointerAdd[4] : r418_4, r418_10
|
||||
# 418| r418_12(int) = Constant[0] :
|
||||
# 418| m418_13(int) = Store[?] : &:r418_11, r418_12
|
||||
# 418| m418_14(int[1][2]) = Chi : total:m418_9, partial:m418_13
|
||||
# 418| r418_15(int) = Constant[0] :
|
||||
# 418| r418_16(glval<int[2]>) = PointerAdd[8] : r418_1, r418_15
|
||||
# 418| r418_17(int) = Constant[0] :
|
||||
# 418| r418_18(glval<int>) = PointerAdd[4] : r418_16, r418_17
|
||||
# 418| r418_19(int) = Constant[0] :
|
||||
# 418| m418_20(int) = Store[?] : &:r418_18, r418_19
|
||||
# 418| m418_21(int[1][2]) = Chi : total:m418_14, partial:m418_20
|
||||
# 418| r418_22(int) = Constant[1] :
|
||||
# 418| r418_23(glval<int>) = PointerAdd[4] : r418_16, r418_22
|
||||
# 418| r418_24(int) = Constant[5678] :
|
||||
# 418| m418_25(int) = Store[?] : &:r418_23, r418_24
|
||||
# 418| m418_26(int[1][2]) = Chi : total:m418_21, partial:m418_25
|
||||
# 419| v419_1(void) = NoOp :
|
||||
# 417| v417_5(void) = ReturnVoid :
|
||||
# 417| v417_6(void) = AliasedUse : m417_3
|
||||
# 417| v417_7(void) = ExitFunction :
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
struct Foo { int x[2]; };
|
||||
void named_designators() {
|
||||
struct Foo foo = {.x[0] = 1234, .x[1] = 5678};
|
||||
}
|
||||
|
||||
void repeated_designators() {
|
||||
int x[1] = {[0] = 1234, [0] = 5678};
|
||||
}
|
||||
|
||||
struct Foo2 { int x; int y; };
|
||||
void named_designators_2() {
|
||||
struct Foo2 foo = {.x = 1234, .y = 5678};
|
||||
|
||||
struct Foo2 foo_swapped = {.y = 5678, .x = 1234};
|
||||
}
|
||||
|
||||
void non_repeated_designators() {
|
||||
int x[2] = {[0] = 1234, [1] = 5678};
|
||||
|
||||
int y[2] = {[1] = 1234, [0] = 5678};
|
||||
}
|
||||
|
||||
struct Foo_array_and_int {
|
||||
int x[2];
|
||||
int y;
|
||||
};
|
||||
|
||||
void test_foo_array_and_int() {
|
||||
struct Foo_array_and_int f = { .x = {0, 1}, .x[0] = 42, .y = 42 };
|
||||
}
|
|
@ -412,4 +412,8 @@ void vla(int n1, int n2, int n3, bool b1) {
|
|||
} else {
|
||||
int b[n2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nested_array_designators() {
|
||||
int x[1][2] = {[0][0] = 1234, [0][1] = 5678};
|
||||
}
|
||||
|
|
|
@ -1,3 +1,143 @@
|
|||
ssa.c:
|
||||
# 2| void named_designators()
|
||||
# 2| Block 0
|
||||
# 2| v2_1(void) = EnterFunction :
|
||||
# 2| mu2_2(unknown) = AliasedDefinition :
|
||||
# 2| mu2_3(unknown) = InitializeNonLocal :
|
||||
# 3| r3_1(glval<Foo>) = VariableAddress[foo] :
|
||||
# 3| mu3_2(Foo) = Uninitialized[foo] : &:r3_1
|
||||
# 3| r3_3(glval<int[2]>) = FieldAddress[x] : r3_1
|
||||
# 3| r3_4(int) = Constant[0] :
|
||||
# 3| r3_5(glval<int>) = PointerAdd[4] : r3_3, r3_4
|
||||
# 3| r3_6(int) = Constant[1234] :
|
||||
# 3| mu3_7(int) = Store[?] : &:r3_5, r3_6
|
||||
# 3| r3_8(int) = Constant[1] :
|
||||
# 3| r3_9(glval<int>) = PointerAdd[4] : r3_3, r3_8
|
||||
# 3| r3_10(int) = Constant[0] :
|
||||
# 3| mu3_11(int) = Store[?] : &:r3_9, r3_10
|
||||
# 3| r3_12(glval<int[2]>) = FieldAddress[x] : r3_1
|
||||
# 3| r3_13(int) = Constant[0] :
|
||||
# 3| r3_14(glval<int>) = PointerAdd[4] : r3_12, r3_13
|
||||
# 3| r3_15(int) = Constant[0] :
|
||||
# 3| mu3_16(int) = Store[?] : &:r3_14, r3_15
|
||||
# 3| r3_17(int) = Constant[1] :
|
||||
# 3| r3_18(glval<int>) = PointerAdd[4] : r3_12, r3_17
|
||||
# 3| r3_19(int) = Constant[5678] :
|
||||
# 3| mu3_20(int) = Store[?] : &:r3_18, r3_19
|
||||
# 4| v4_1(void) = NoOp :
|
||||
# 2| v2_4(void) = ReturnVoid :
|
||||
# 2| v2_5(void) = AliasedUse : ~m?
|
||||
# 2| v2_6(void) = ExitFunction :
|
||||
|
||||
# 6| void repeated_designators()
|
||||
# 6| Block 0
|
||||
# 6| v6_1(void) = EnterFunction :
|
||||
# 6| mu6_2(unknown) = AliasedDefinition :
|
||||
# 6| mu6_3(unknown) = InitializeNonLocal :
|
||||
# 7| r7_1(glval<int[1]>) = VariableAddress[x] :
|
||||
# 7| mu7_2(int[1]) = Uninitialized[x] : &:r7_1
|
||||
# 7| r7_3(int) = Constant[0] :
|
||||
# 7| r7_4(glval<int>) = PointerAdd[4] : r7_1, r7_3
|
||||
# 7| r7_5(int) = Constant[1234] :
|
||||
# 7| mu7_6(int) = Store[?] : &:r7_4, r7_5
|
||||
# 7| r7_7(int) = Constant[0] :
|
||||
# 7| r7_8(glval<int>) = PointerAdd[4] : r7_1, r7_7
|
||||
# 7| r7_9(int) = Constant[5678] :
|
||||
# 7| mu7_10(int) = Store[?] : &:r7_8, r7_9
|
||||
# 8| v8_1(void) = NoOp :
|
||||
# 6| v6_4(void) = ReturnVoid :
|
||||
# 6| v6_5(void) = AliasedUse : ~m?
|
||||
# 6| v6_6(void) = ExitFunction :
|
||||
|
||||
# 11| void named_designators_2()
|
||||
# 11| Block 0
|
||||
# 11| v11_1(void) = EnterFunction :
|
||||
# 11| mu11_2(unknown) = AliasedDefinition :
|
||||
# 11| mu11_3(unknown) = InitializeNonLocal :
|
||||
# 12| r12_1(glval<Foo2>) = VariableAddress[foo] :
|
||||
# 12| mu12_2(Foo2) = Uninitialized[foo] : &:r12_1
|
||||
# 12| r12_3(glval<int>) = FieldAddress[x] : r12_1
|
||||
# 12| r12_4(int) = Constant[1234] :
|
||||
# 12| mu12_5(int) = Store[?] : &:r12_3, r12_4
|
||||
# 12| r12_6(glval<int>) = FieldAddress[y] : r12_1
|
||||
# 12| r12_7(int) = Constant[5678] :
|
||||
# 12| mu12_8(int) = Store[?] : &:r12_6, r12_7
|
||||
# 14| r14_1(glval<Foo2>) = VariableAddress[foo_swapped] :
|
||||
# 14| mu14_2(Foo2) = Uninitialized[foo_swapped] : &:r14_1
|
||||
# 14| r14_3(glval<int>) = FieldAddress[x] : r14_1
|
||||
# 14| r14_4(int) = Constant[1234] :
|
||||
# 14| mu14_5(int) = Store[?] : &:r14_3, r14_4
|
||||
# 14| r14_6(glval<int>) = FieldAddress[y] : r14_1
|
||||
# 14| r14_7(int) = Constant[5678] :
|
||||
# 14| mu14_8(int) = Store[?] : &:r14_6, r14_7
|
||||
# 15| v15_1(void) = NoOp :
|
||||
# 11| v11_4(void) = ReturnVoid :
|
||||
# 11| v11_5(void) = AliasedUse : ~m?
|
||||
# 11| v11_6(void) = ExitFunction :
|
||||
|
||||
# 17| void non_repeated_designators()
|
||||
# 17| Block 0
|
||||
# 17| v17_1(void) = EnterFunction :
|
||||
# 17| mu17_2(unknown) = AliasedDefinition :
|
||||
# 17| mu17_3(unknown) = InitializeNonLocal :
|
||||
# 18| r18_1(glval<int[2]>) = VariableAddress[x] :
|
||||
# 18| mu18_2(int[2]) = Uninitialized[x] : &:r18_1
|
||||
# 18| r18_3(int) = Constant[0] :
|
||||
# 18| r18_4(glval<int>) = PointerAdd[4] : r18_1, r18_3
|
||||
# 18| r18_5(int) = Constant[1234] :
|
||||
# 18| mu18_6(int) = Store[?] : &:r18_4, r18_5
|
||||
# 18| r18_7(int) = Constant[1] :
|
||||
# 18| r18_8(glval<int>) = PointerAdd[4] : r18_1, r18_7
|
||||
# 18| r18_9(int) = Constant[5678] :
|
||||
# 18| mu18_10(int) = Store[?] : &:r18_8, r18_9
|
||||
# 20| r20_1(glval<int[2]>) = VariableAddress[y] :
|
||||
# 20| mu20_2(int[2]) = Uninitialized[y] : &:r20_1
|
||||
# 20| r20_3(int) = Constant[0] :
|
||||
# 20| r20_4(glval<int>) = PointerAdd[4] : r20_1, r20_3
|
||||
# 20| r20_5(int) = Constant[5678] :
|
||||
# 20| mu20_6(int) = Store[?] : &:r20_4, r20_5
|
||||
# 20| r20_7(int) = Constant[1] :
|
||||
# 20| r20_8(glval<int>) = PointerAdd[4] : r20_1, r20_7
|
||||
# 20| r20_9(int) = Constant[1234] :
|
||||
# 20| mu20_10(int) = Store[?] : &:r20_8, r20_9
|
||||
# 21| v21_1(void) = NoOp :
|
||||
# 17| v17_4(void) = ReturnVoid :
|
||||
# 17| v17_5(void) = AliasedUse : ~m?
|
||||
# 17| v17_6(void) = ExitFunction :
|
||||
|
||||
# 28| void test_foo_array_and_int()
|
||||
# 28| Block 0
|
||||
# 28| v28_1(void) = EnterFunction :
|
||||
# 28| mu28_2(unknown) = AliasedDefinition :
|
||||
# 28| mu28_3(unknown) = InitializeNonLocal :
|
||||
# 29| r29_1(glval<Foo_array_and_int>) = VariableAddress[f] :
|
||||
# 29| mu29_2(Foo_array_and_int) = Uninitialized[f] : &:r29_1
|
||||
# 29| r29_3(glval<int[2]>) = FieldAddress[x] : r29_1
|
||||
# 29| r29_4(int) = Constant[0] :
|
||||
# 29| r29_5(glval<int>) = PointerAdd[4] : r29_3, r29_4
|
||||
# 29| r29_6(int) = Constant[0] :
|
||||
# 29| mu29_7(int) = Store[?] : &:r29_5, r29_6
|
||||
# 29| r29_8(int) = Constant[1] :
|
||||
# 29| r29_9(glval<int>) = PointerAdd[4] : r29_3, r29_8
|
||||
# 29| r29_10(int) = Constant[1] :
|
||||
# 29| mu29_11(int) = Store[?] : &:r29_9, r29_10
|
||||
# 29| r29_12(glval<int[2]>) = FieldAddress[x] : r29_1
|
||||
# 29| r29_13(int) = Constant[0] :
|
||||
# 29| r29_14(glval<int>) = PointerAdd[4] : r29_12, r29_13
|
||||
# 29| r29_15(int) = Constant[42] :
|
||||
# 29| mu29_16(int) = Store[?] : &:r29_14, r29_15
|
||||
# 29| r29_17(int) = Constant[1] :
|
||||
# 29| r29_18(glval<int>) = PointerAdd[4] : r29_12, r29_17
|
||||
# 29| r29_19(int) = Constant[0] :
|
||||
# 29| mu29_20(int) = Store[?] : &:r29_18, r29_19
|
||||
# 29| r29_21(glval<int>) = FieldAddress[y] : r29_1
|
||||
# 29| r29_22(int) = Constant[42] :
|
||||
# 29| mu29_23(int) = Store[?] : &:r29_21, r29_22
|
||||
# 30| v30_1(void) = NoOp :
|
||||
# 28| v28_4(void) = ReturnVoid :
|
||||
# 28| v28_5(void) = AliasedUse : ~m?
|
||||
# 28| v28_6(void) = ExitFunction :
|
||||
|
||||
ssa.cpp:
|
||||
# 13| int ChiPhiNode(Point*, bool, bool)
|
||||
# 13| Block 0
|
||||
|
@ -1768,3 +1908,35 @@ ssa.cpp:
|
|||
# 401| v401_12(void) = ReturnVoid :
|
||||
# 401| v401_13(void) = AliasedUse : ~m?
|
||||
# 401| v401_14(void) = ExitFunction :
|
||||
|
||||
# 417| void nested_array_designators()
|
||||
# 417| Block 0
|
||||
# 417| v417_1(void) = EnterFunction :
|
||||
# 417| mu417_2(unknown) = AliasedDefinition :
|
||||
# 417| mu417_3(unknown) = InitializeNonLocal :
|
||||
# 418| r418_1(glval<int[1][2]>) = VariableAddress[x] :
|
||||
# 418| mu418_2(int[1][2]) = Uninitialized[x] : &:r418_1
|
||||
# 418| r418_3(int) = Constant[0] :
|
||||
# 418| r418_4(glval<int[2]>) = PointerAdd[8] : r418_1, r418_3
|
||||
# 418| r418_5(int) = Constant[0] :
|
||||
# 418| r418_6(glval<int>) = PointerAdd[4] : r418_4, r418_5
|
||||
# 418| r418_7(int) = Constant[1234] :
|
||||
# 418| mu418_8(int) = Store[?] : &:r418_6, r418_7
|
||||
# 418| r418_9(int) = Constant[1] :
|
||||
# 418| r418_10(glval<int>) = PointerAdd[4] : r418_4, r418_9
|
||||
# 418| r418_11(int) = Constant[0] :
|
||||
# 418| mu418_12(int) = Store[?] : &:r418_10, r418_11
|
||||
# 418| r418_13(int) = Constant[0] :
|
||||
# 418| r418_14(glval<int[2]>) = PointerAdd[8] : r418_1, r418_13
|
||||
# 418| r418_15(int) = Constant[0] :
|
||||
# 418| r418_16(glval<int>) = PointerAdd[4] : r418_14, r418_15
|
||||
# 418| r418_17(int) = Constant[0] :
|
||||
# 418| mu418_18(int) = Store[?] : &:r418_16, r418_17
|
||||
# 418| r418_19(int) = Constant[1] :
|
||||
# 418| r418_20(glval<int>) = PointerAdd[4] : r418_14, r418_19
|
||||
# 418| r418_21(int) = Constant[5678] :
|
||||
# 418| mu418_22(int) = Store[?] : &:r418_20, r418_21
|
||||
# 419| v419_1(void) = NoOp :
|
||||
# 417| v417_4(void) = ReturnVoid :
|
||||
# 417| v417_5(void) = AliasedUse : ~m?
|
||||
# 417| v417_6(void) = ExitFunction :
|
||||
|
|
|
@ -1,3 +1,143 @@
|
|||
ssa.c:
|
||||
# 2| void named_designators()
|
||||
# 2| Block 0
|
||||
# 2| v2_1(void) = EnterFunction :
|
||||
# 2| mu2_2(unknown) = AliasedDefinition :
|
||||
# 2| mu2_3(unknown) = InitializeNonLocal :
|
||||
# 3| r3_1(glval<Foo>) = VariableAddress[foo] :
|
||||
# 3| mu3_2(Foo) = Uninitialized[foo] : &:r3_1
|
||||
# 3| r3_3(glval<int[2]>) = FieldAddress[x] : r3_1
|
||||
# 3| r3_4(int) = Constant[0] :
|
||||
# 3| r3_5(glval<int>) = PointerAdd[4] : r3_3, r3_4
|
||||
# 3| r3_6(int) = Constant[1234] :
|
||||
# 3| mu3_7(int) = Store[?] : &:r3_5, r3_6
|
||||
# 3| r3_8(int) = Constant[1] :
|
||||
# 3| r3_9(glval<int>) = PointerAdd[4] : r3_3, r3_8
|
||||
# 3| r3_10(int) = Constant[0] :
|
||||
# 3| mu3_11(int) = Store[?] : &:r3_9, r3_10
|
||||
# 3| r3_12(glval<int[2]>) = FieldAddress[x] : r3_1
|
||||
# 3| r3_13(int) = Constant[0] :
|
||||
# 3| r3_14(glval<int>) = PointerAdd[4] : r3_12, r3_13
|
||||
# 3| r3_15(int) = Constant[0] :
|
||||
# 3| mu3_16(int) = Store[?] : &:r3_14, r3_15
|
||||
# 3| r3_17(int) = Constant[1] :
|
||||
# 3| r3_18(glval<int>) = PointerAdd[4] : r3_12, r3_17
|
||||
# 3| r3_19(int) = Constant[5678] :
|
||||
# 3| mu3_20(int) = Store[?] : &:r3_18, r3_19
|
||||
# 4| v4_1(void) = NoOp :
|
||||
# 2| v2_4(void) = ReturnVoid :
|
||||
# 2| v2_5(void) = AliasedUse : ~m?
|
||||
# 2| v2_6(void) = ExitFunction :
|
||||
|
||||
# 6| void repeated_designators()
|
||||
# 6| Block 0
|
||||
# 6| v6_1(void) = EnterFunction :
|
||||
# 6| mu6_2(unknown) = AliasedDefinition :
|
||||
# 6| mu6_3(unknown) = InitializeNonLocal :
|
||||
# 7| r7_1(glval<int[1]>) = VariableAddress[x] :
|
||||
# 7| mu7_2(int[1]) = Uninitialized[x] : &:r7_1
|
||||
# 7| r7_3(int) = Constant[0] :
|
||||
# 7| r7_4(glval<int>) = PointerAdd[4] : r7_1, r7_3
|
||||
# 7| r7_5(int) = Constant[1234] :
|
||||
# 7| mu7_6(int) = Store[?] : &:r7_4, r7_5
|
||||
# 7| r7_7(int) = Constant[0] :
|
||||
# 7| r7_8(glval<int>) = PointerAdd[4] : r7_1, r7_7
|
||||
# 7| r7_9(int) = Constant[5678] :
|
||||
# 7| mu7_10(int) = Store[?] : &:r7_8, r7_9
|
||||
# 8| v8_1(void) = NoOp :
|
||||
# 6| v6_4(void) = ReturnVoid :
|
||||
# 6| v6_5(void) = AliasedUse : ~m?
|
||||
# 6| v6_6(void) = ExitFunction :
|
||||
|
||||
# 11| void named_designators_2()
|
||||
# 11| Block 0
|
||||
# 11| v11_1(void) = EnterFunction :
|
||||
# 11| mu11_2(unknown) = AliasedDefinition :
|
||||
# 11| mu11_3(unknown) = InitializeNonLocal :
|
||||
# 12| r12_1(glval<Foo2>) = VariableAddress[foo] :
|
||||
# 12| mu12_2(Foo2) = Uninitialized[foo] : &:r12_1
|
||||
# 12| r12_3(glval<int>) = FieldAddress[x] : r12_1
|
||||
# 12| r12_4(int) = Constant[1234] :
|
||||
# 12| mu12_5(int) = Store[?] : &:r12_3, r12_4
|
||||
# 12| r12_6(glval<int>) = FieldAddress[y] : r12_1
|
||||
# 12| r12_7(int) = Constant[5678] :
|
||||
# 12| mu12_8(int) = Store[?] : &:r12_6, r12_7
|
||||
# 14| r14_1(glval<Foo2>) = VariableAddress[foo_swapped] :
|
||||
# 14| mu14_2(Foo2) = Uninitialized[foo_swapped] : &:r14_1
|
||||
# 14| r14_3(glval<int>) = FieldAddress[x] : r14_1
|
||||
# 14| r14_4(int) = Constant[1234] :
|
||||
# 14| mu14_5(int) = Store[?] : &:r14_3, r14_4
|
||||
# 14| r14_6(glval<int>) = FieldAddress[y] : r14_1
|
||||
# 14| r14_7(int) = Constant[5678] :
|
||||
# 14| mu14_8(int) = Store[?] : &:r14_6, r14_7
|
||||
# 15| v15_1(void) = NoOp :
|
||||
# 11| v11_4(void) = ReturnVoid :
|
||||
# 11| v11_5(void) = AliasedUse : ~m?
|
||||
# 11| v11_6(void) = ExitFunction :
|
||||
|
||||
# 17| void non_repeated_designators()
|
||||
# 17| Block 0
|
||||
# 17| v17_1(void) = EnterFunction :
|
||||
# 17| mu17_2(unknown) = AliasedDefinition :
|
||||
# 17| mu17_3(unknown) = InitializeNonLocal :
|
||||
# 18| r18_1(glval<int[2]>) = VariableAddress[x] :
|
||||
# 18| mu18_2(int[2]) = Uninitialized[x] : &:r18_1
|
||||
# 18| r18_3(int) = Constant[0] :
|
||||
# 18| r18_4(glval<int>) = PointerAdd[4] : r18_1, r18_3
|
||||
# 18| r18_5(int) = Constant[1234] :
|
||||
# 18| mu18_6(int) = Store[?] : &:r18_4, r18_5
|
||||
# 18| r18_7(int) = Constant[1] :
|
||||
# 18| r18_8(glval<int>) = PointerAdd[4] : r18_1, r18_7
|
||||
# 18| r18_9(int) = Constant[5678] :
|
||||
# 18| mu18_10(int) = Store[?] : &:r18_8, r18_9
|
||||
# 20| r20_1(glval<int[2]>) = VariableAddress[y] :
|
||||
# 20| mu20_2(int[2]) = Uninitialized[y] : &:r20_1
|
||||
# 20| r20_3(int) = Constant[0] :
|
||||
# 20| r20_4(glval<int>) = PointerAdd[4] : r20_1, r20_3
|
||||
# 20| r20_5(int) = Constant[5678] :
|
||||
# 20| mu20_6(int) = Store[?] : &:r20_4, r20_5
|
||||
# 20| r20_7(int) = Constant[1] :
|
||||
# 20| r20_8(glval<int>) = PointerAdd[4] : r20_1, r20_7
|
||||
# 20| r20_9(int) = Constant[1234] :
|
||||
# 20| mu20_10(int) = Store[?] : &:r20_8, r20_9
|
||||
# 21| v21_1(void) = NoOp :
|
||||
# 17| v17_4(void) = ReturnVoid :
|
||||
# 17| v17_5(void) = AliasedUse : ~m?
|
||||
# 17| v17_6(void) = ExitFunction :
|
||||
|
||||
# 28| void test_foo_array_and_int()
|
||||
# 28| Block 0
|
||||
# 28| v28_1(void) = EnterFunction :
|
||||
# 28| mu28_2(unknown) = AliasedDefinition :
|
||||
# 28| mu28_3(unknown) = InitializeNonLocal :
|
||||
# 29| r29_1(glval<Foo_array_and_int>) = VariableAddress[f] :
|
||||
# 29| mu29_2(Foo_array_and_int) = Uninitialized[f] : &:r29_1
|
||||
# 29| r29_3(glval<int[2]>) = FieldAddress[x] : r29_1
|
||||
# 29| r29_4(int) = Constant[0] :
|
||||
# 29| r29_5(glval<int>) = PointerAdd[4] : r29_3, r29_4
|
||||
# 29| r29_6(int) = Constant[0] :
|
||||
# 29| mu29_7(int) = Store[?] : &:r29_5, r29_6
|
||||
# 29| r29_8(int) = Constant[1] :
|
||||
# 29| r29_9(glval<int>) = PointerAdd[4] : r29_3, r29_8
|
||||
# 29| r29_10(int) = Constant[1] :
|
||||
# 29| mu29_11(int) = Store[?] : &:r29_9, r29_10
|
||||
# 29| r29_12(glval<int[2]>) = FieldAddress[x] : r29_1
|
||||
# 29| r29_13(int) = Constant[0] :
|
||||
# 29| r29_14(glval<int>) = PointerAdd[4] : r29_12, r29_13
|
||||
# 29| r29_15(int) = Constant[42] :
|
||||
# 29| mu29_16(int) = Store[?] : &:r29_14, r29_15
|
||||
# 29| r29_17(int) = Constant[1] :
|
||||
# 29| r29_18(glval<int>) = PointerAdd[4] : r29_12, r29_17
|
||||
# 29| r29_19(int) = Constant[0] :
|
||||
# 29| mu29_20(int) = Store[?] : &:r29_18, r29_19
|
||||
# 29| r29_21(glval<int>) = FieldAddress[y] : r29_1
|
||||
# 29| r29_22(int) = Constant[42] :
|
||||
# 29| mu29_23(int) = Store[?] : &:r29_21, r29_22
|
||||
# 30| v30_1(void) = NoOp :
|
||||
# 28| v28_4(void) = ReturnVoid :
|
||||
# 28| v28_5(void) = AliasedUse : ~m?
|
||||
# 28| v28_6(void) = ExitFunction :
|
||||
|
||||
ssa.cpp:
|
||||
# 13| int ChiPhiNode(Point*, bool, bool)
|
||||
# 13| Block 0
|
||||
|
@ -1768,3 +1908,35 @@ ssa.cpp:
|
|||
# 401| v401_12(void) = ReturnVoid :
|
||||
# 401| v401_13(void) = AliasedUse : ~m?
|
||||
# 401| v401_14(void) = ExitFunction :
|
||||
|
||||
# 417| void nested_array_designators()
|
||||
# 417| Block 0
|
||||
# 417| v417_1(void) = EnterFunction :
|
||||
# 417| mu417_2(unknown) = AliasedDefinition :
|
||||
# 417| mu417_3(unknown) = InitializeNonLocal :
|
||||
# 418| r418_1(glval<int[1][2]>) = VariableAddress[x] :
|
||||
# 418| mu418_2(int[1][2]) = Uninitialized[x] : &:r418_1
|
||||
# 418| r418_3(int) = Constant[0] :
|
||||
# 418| r418_4(glval<int[2]>) = PointerAdd[8] : r418_1, r418_3
|
||||
# 418| r418_5(int) = Constant[0] :
|
||||
# 418| r418_6(glval<int>) = PointerAdd[4] : r418_4, r418_5
|
||||
# 418| r418_7(int) = Constant[1234] :
|
||||
# 418| mu418_8(int) = Store[?] : &:r418_6, r418_7
|
||||
# 418| r418_9(int) = Constant[1] :
|
||||
# 418| r418_10(glval<int>) = PointerAdd[4] : r418_4, r418_9
|
||||
# 418| r418_11(int) = Constant[0] :
|
||||
# 418| mu418_12(int) = Store[?] : &:r418_10, r418_11
|
||||
# 418| r418_13(int) = Constant[0] :
|
||||
# 418| r418_14(glval<int[2]>) = PointerAdd[8] : r418_1, r418_13
|
||||
# 418| r418_15(int) = Constant[0] :
|
||||
# 418| r418_16(glval<int>) = PointerAdd[4] : r418_14, r418_15
|
||||
# 418| r418_17(int) = Constant[0] :
|
||||
# 418| mu418_18(int) = Store[?] : &:r418_16, r418_17
|
||||
# 418| r418_19(int) = Constant[1] :
|
||||
# 418| r418_20(glval<int>) = PointerAdd[4] : r418_14, r418_19
|
||||
# 418| r418_21(int) = Constant[5678] :
|
||||
# 418| mu418_22(int) = Store[?] : &:r418_20, r418_21
|
||||
# 419| v419_1(void) = NoOp :
|
||||
# 417| v417_4(void) = ReturnVoid :
|
||||
# 417| v417_5(void) = AliasedUse : ~m?
|
||||
# 417| v417_6(void) = ExitFunction :
|
||||
|
|
|
@ -2,4 +2,4 @@ import cpp
|
|||
|
||||
from ArrayType a, ArrayAggregateLiteral al, int i
|
||||
where a = al.getType()
|
||||
select al, a, i, al.getElementExpr(i)
|
||||
select al, a, i, al.getAnElementExpr(i)
|
||||
|
|
|
@ -5,5 +5,5 @@ import cpp
|
|||
// (which, in the case of designated initializers, will not necessarily match
|
||||
// the order of the array elements).
|
||||
from ArrayAggregateLiteral aal, int childIndex, int elementIndex
|
||||
where aal.getElementExpr(elementIndex) = aal.getChild(childIndex)
|
||||
where aal.getAnElementExpr(elementIndex) = aal.getChild(childIndex)
|
||||
select aal, aal.getUnspecifiedType(), childIndex, aal.getChild(childIndex), elementIndex
|
||||
|
|
|
@ -4,4 +4,4 @@ from Class c, ClassAggregateLiteral al, Field f
|
|||
where
|
||||
c = al.getType() and
|
||||
f = c.getAField()
|
||||
select al, c, f, al.getFieldExpr(f)
|
||||
select al, c, f, al.getAFieldExpr(f)
|
||||
|
|
|
@ -5,5 +5,5 @@ import cpp
|
|||
// (which, in the case of designated initializers, will not necessarily match
|
||||
// the order in which the fields were declared).
|
||||
from ClassAggregateLiteral cal, int i, Field f
|
||||
where cal.getFieldExpr(f) = cal.getChild(i)
|
||||
where cal.getAFieldExpr(f) = cal.getChild(i)
|
||||
select cal, cal.getUnspecifiedType(), i, cal.getChild(i), f
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
edges
|
||||
| test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a |
|
||||
| test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a |
|
||||
| test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a |
|
||||
| test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a |
|
||||
| test_free.cpp:30:10:30:10 | a | test_free.cpp:31:27:31:27 | a |
|
||||
| test_free.cpp:35:10:35:10 | a | test_free.cpp:37:27:37:27 | a |
|
||||
| test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||
| test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||
| test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||
| test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||
| test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||
| test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||
| test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||
| test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a |
|
||||
| test_free.cpp:50:27:50:27 | a | test_free.cpp:51:10:51:10 | a |
|
||||
| test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a |
|
||||
| test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a |
|
||||
| test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a |
|
||||
| test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a |
|
||||
| test_free.cpp:101:10:101:10 | a | test_free.cpp:103:10:103:10 | a |
|
||||
| test_free.cpp:128:10:128:11 | * ... | test_free.cpp:129:10:129:11 | * ... |
|
||||
| test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a |
|
||||
| test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a |
|
||||
| test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a |
|
||||
| test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a |
|
||||
| test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a |
|
||||
| test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a |
|
||||
| test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a |
|
||||
| test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a |
|
||||
nodes
|
||||
| test_free.cpp:11:10:11:10 | a | semmle.label | a |
|
||||
| test_free.cpp:11:10:11:10 | a | semmle.label | a |
|
||||
| test_free.cpp:14:10:14:10 | a | semmle.label | a |
|
||||
| test_free.cpp:14:10:14:10 | a | semmle.label | a |
|
||||
| test_free.cpp:30:10:30:10 | a | semmle.label | a |
|
||||
| test_free.cpp:31:27:31:27 | a | semmle.label | a |
|
||||
| test_free.cpp:35:10:35:10 | a | semmle.label | a |
|
||||
| test_free.cpp:37:27:37:27 | a | semmle.label | a |
|
||||
| test_free.cpp:42:27:42:27 | a | semmle.label | a |
|
||||
| test_free.cpp:42:27:42:27 | a | semmle.label | a |
|
||||
| test_free.cpp:44:27:44:27 | a | semmle.label | a |
|
||||
| test_free.cpp:44:27:44:27 | a | semmle.label | a |
|
||||
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
|
||||
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
|
||||
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
|
||||
| test_free.cpp:46:10:46:10 | a | semmle.label | a |
|
||||
| test_free.cpp:50:27:50:27 | a | semmle.label | a |
|
||||
| test_free.cpp:51:10:51:10 | a | semmle.label | a |
|
||||
| test_free.cpp:69:10:69:10 | a | semmle.label | a |
|
||||
| test_free.cpp:69:10:69:10 | a | semmle.label | a |
|
||||
| test_free.cpp:72:14:72:14 | a | semmle.label | a |
|
||||
| test_free.cpp:72:14:72:14 | a | semmle.label | a |
|
||||
| test_free.cpp:101:10:101:10 | a | semmle.label | a |
|
||||
| test_free.cpp:103:10:103:10 | a | semmle.label | a |
|
||||
| test_free.cpp:128:10:128:11 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:129:10:129:11 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:152:27:152:27 | a | semmle.label | a |
|
||||
| test_free.cpp:152:27:152:27 | a | semmle.label | a |
|
||||
| test_free.cpp:154:10:154:10 | a | semmle.label | a |
|
||||
| test_free.cpp:154:10:154:10 | a | semmle.label | a |
|
||||
| test_free.cpp:207:10:207:10 | a | semmle.label | a |
|
||||
| test_free.cpp:207:10:207:10 | a | semmle.label | a |
|
||||
| test_free.cpp:209:10:209:10 | a | semmle.label | a |
|
||||
| test_free.cpp:209:10:209:10 | a | semmle.label | a |
|
||||
subpaths
|
||||
#select
|
||||
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | a | test_free.cpp:14:10:14:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
| test_free.cpp:31:27:31:27 | a | test_free.cpp:30:10:30:10 | a | test_free.cpp:31:27:31:27 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:30:5:30:8 | call to free | call to free |
|
||||
| test_free.cpp:37:27:37:27 | a | test_free.cpp:35:10:35:10 | a | test_free.cpp:37:27:37:27 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:35:5:35:8 | call to free | call to free |
|
||||
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||
| test_free.cpp:46:10:46:10 | a | test_free.cpp:42:27:42:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
|
||||
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
|
||||
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
|
||||
| test_free.cpp:46:10:46:10 | a | test_free.cpp:44:27:44:27 | a | test_free.cpp:46:10:46:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:44:22:44:25 | call to free | call to free |
|
||||
| test_free.cpp:51:10:51:10 | a | test_free.cpp:50:27:50:27 | a | test_free.cpp:51:10:51:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:50:22:50:25 | call to free | call to free |
|
||||
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
|
||||
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
|
||||
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
|
||||
| test_free.cpp:72:14:72:14 | a | test_free.cpp:69:10:69:10 | a | test_free.cpp:72:14:72:14 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:69:5:69:8 | call to free | call to free |
|
||||
| test_free.cpp:103:10:103:10 | a | test_free.cpp:101:10:101:10 | a | test_free.cpp:103:10:103:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:101:5:101:8 | call to free | call to free |
|
||||
| test_free.cpp:129:10:129:11 | * ... | test_free.cpp:128:10:128:11 | * ... | test_free.cpp:129:10:129:11 | * ... | Memory pointed to by '* ...' may already have been freed by $@. | test_free.cpp:128:5:128:8 | call to free | call to free |
|
||||
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | a | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |
|
||||
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |
|
||||
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |
|
||||
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | a | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |
|
|
@ -0,0 +1 @@
|
|||
Critical/DoubleFree.ql
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче