Merge branch 'main' into redsun82/swift-logging

This commit is contained in:
Paolo Tranquilli 2023-04-17 10:27:14 +02:00
Родитель 3f139bd93b 4e49df1615
Коммит cbe247e123
1048 изменённых файлов: 147487 добавлений и 119874 удалений

102
.github/workflows/atm-check-query-suite.yml поставляемый
Просмотреть файл

@ -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"

50
.github/workflows/fast-forward.yml поставляемый Normal file
Просмотреть файл

@ -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

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше