Compare commits

..

1 Commits

Author SHA1 Message Date
Nick Rolfe
ccda5fa451 Ruby: sort TRAP output 2022-08-15 10:54:38 +01:00
2262 changed files with 52991 additions and 168116 deletions

1
.github/labeler.yml vendored
View File

@@ -42,4 +42,3 @@ documentation:
"QL-for-QL":
- ql/**/*
- .github/workflows/ql-for-ql*

View File

@@ -11,10 +11,10 @@ jobs:
name: Test Linux (Ubuntu)
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.19
- name: Set up Go 1.18.1
uses: actions/setup-go@v3
with:
go-version: 1.19
go-version: 1.18.1
id: go
- name: Check out code
@@ -57,10 +57,10 @@ jobs:
name: Test MacOS
runs-on: macos-latest
steps:
- name: Set up Go 1.19
- name: Set up Go 1.18.1
uses: actions/setup-go@v3
with:
go-version: 1.19
go-version: 1.18.1
id: go
- name: Check out code
@@ -87,10 +87,10 @@ jobs:
name: Test Windows
runs-on: windows-2019
steps:
- name: Set up Go 1.19
- name: Set up Go 1.18.1
uses: actions/setup-go@v3
with:
go-version: 1.19
go-version: 1.18.1
id: go
- name: Check out code

View File

@@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v3
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
with:
languages: javascript # does not matter
- name: Get CodeQL version
@@ -27,37 +27,31 @@ jobs:
shell: bash
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
- name: Cache entire pack
id: cache-pack
uses: actions/cache@v3
with:
path: ${{ runner.temp }}/pack
key: ${{ runner.os }}-pack-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}--${{ hashFiles('.github/workflows/ql-for-ql-build.yml') }}
- name: Cache queries
if: steps.cache-pack.outputs.cache-hit != 'true'
id: cache-queries
uses: actions/cache@v3
with:
path: ${{ runner.temp }}/queries
key: queries-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}--${{ hashFiles('.github/workflows/ql-for-ql-build.yml') }}
path: ${{ runner.temp }}/query-pack.zip
key: queries-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}
- name: Build query pack
if: steps.cache-queries.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
if: steps.cache-queries.outputs.cache-hit != 'true'
run: |
cd ql/ql/src
"${CODEQL}" pack create -j 16
mv .codeql/pack/codeql/ql/0.0.0 ${{ runner.temp }}/queries
"${CODEQL}" pack create
cd .codeql/pack/codeql/ql/0.0.0
zip "${PACKZIP}" -r .
rm -rf *
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
- name: Move cache queries to pack
if: steps.cache-pack.outputs.cache-hit != 'true'
run: |
cp -r ${{ runner.temp }}/queries ${{ runner.temp }}/pack
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
PACKZIP: ${{ runner.temp }}/query-pack.zip
- name: Upload query pack
uses: actions/upload-artifact@v3
with:
name: query-pack-zip
path: ${{ runner.temp }}/query-pack.zip
### Build the extractor ###
- name: Cache entire extractor
if: steps.cache-pack.outputs.cache-hit != 'true'
id: cache-extractor
uses: actions/cache@v3
with:
@@ -68,7 +62,7 @@ jobs:
ql/target/release/ql-extractor.exe
key: ${{ runner.os }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
- name: Cache cargo
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
if: steps.cache-extractor.outputs.cache-hit != 'true'
uses: actions/cache@v3
with:
path: |
@@ -77,35 +71,73 @@ jobs:
ql/target
key: ${{ runner.os }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
- name: Check formatting
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
if: steps.cache-extractor.outputs.cache-hit != 'true'
run: cd ql; cargo fmt --all -- --check
- name: Build
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
if: steps.cache-extractor.outputs.cache-hit != 'true'
run: cd ql; cargo build --verbose
- name: Run tests
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
if: steps.cache-extractor.outputs.cache-hit != 'true'
run: cd ql; cargo test --verbose
- name: Release build
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
if: steps.cache-extractor.outputs.cache-hit != 'true'
run: cd ql; cargo build --release
- name: Generate dbscheme
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
if: steps.cache-extractor.outputs.cache-hit != 'true'
run: ql/target/release/ql-generator --dbscheme ql/ql/src/ql.dbscheme --library ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll
- uses: actions/upload-artifact@v3
with:
name: extractor-ubuntu-latest
path: |
ql/target/release/ql-autobuilder
ql/target/release/ql-autobuilder.exe
ql/target/release/ql-extractor
ql/target/release/ql-extractor.exe
retention-days: 1
### Package the queries and extractor ###
- name: Package pack
if: steps.cache-pack.outputs.cache-hit != 'true'
run: |
cp -r ql/codeql-extractor.yml ql/tools ql/ql/src/ql.dbscheme.stats ${PACK}/
mkdir -p ${PACK}/tools/linux64
cp ql/target/release/ql-autobuilder ${PACK}/tools/linux64/autobuilder
cp ql/target/release/ql-extractor ${PACK}/tools/linux64/extractor
chmod +x ${PACK}/tools/linux64/autobuilder
chmod +x ${PACK}/tools/linux64/extractor
env:
PACK: ${{ runner.temp }}/pack
- uses: actions/download-artifact@v3
with:
name: query-pack-zip
path: query-pack-zip
- uses: actions/download-artifact@v3
with:
name: extractor-ubuntu-latest
path: linux64
- run: |
unzip query-pack-zip/*.zip -d pack
cp -r ql/codeql-extractor.yml ql/tools ql/ql/src/ql.dbscheme.stats pack/
mkdir -p pack/tools/linux64
if [[ -f linux64/ql-autobuilder ]]; then
cp linux64/ql-autobuilder pack/tools/linux64/autobuilder
chmod +x pack/tools/linux64/autobuilder
fi
if [[ -f linux64/ql-extractor ]]; then
cp linux64/ql-extractor pack/tools/linux64/extractor
chmod +x pack/tools/linux64/extractor
fi
cd pack
zip -rq ../codeql-ql.zip .
rm -rf *
- uses: actions/upload-artifact@v3
with:
name: codeql-ql-pack
path: codeql-ql.zip
retention-days: 1
### Run the analysis ###
- name: Download pack
uses: actions/download-artifact@v3
with:
name: codeql-ql-pack
path: ${{ runner.temp }}/codeql-ql-pack-artifact
- name: Prepare pack
run: |
unzip "${PACK_ARTIFACT}/*.zip" -d "${PACK}"
env:
PACK_ARTIFACT: ${{ runner.temp }}/codeql-ql-pack-artifact
PACK: ${{ runner.temp }}/pack
- name: Hack codeql-action options
run: |
JSON=$(jq -nc --arg pack "${PACK}" '.database."run-queries"=["--search-path", $pack] | .resolve.queries=["--search-path", $pack] | .resolve.extractor=["--search-path", $pack] | .database.init=["--search-path", $pack]')
@@ -119,26 +151,21 @@ jobs:
echo " - ql/ql/test" >> ${CONF}
echo " - \"*/ql/lib/upgrades/\"" >> ${CONF}
echo "disable-default-queries: true" >> ${CONF}
echo "queries:" >> ${CONF}
echo " - uses: ./ql/ql/src/codeql-suites/ql-code-scanning.qls" >> ${CONF}
echo "packs:" >> ${CONF}
echo " - codeql/ql" >> ${CONF}
echo "Config file: "
cat ${CONF}
env:
CONF: ./ql-for-ql-config.yml
- name: Initialize CodeQL
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
with:
languages: ql
db-location: ${{ runner.temp }}/db
config-file: ./ql-for-ql-config.yml
- name: Move pack cache
run: |
cp -r ${PACK}/.cache ql/ql/src/.cache
env:
PACK: ${{ runner.temp }}/pack
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
uses: github/codeql-action/analyze@aa93aea877e5fb8841bcb1193f672abf6e9f2980
with:
category: "ql-for-ql"
- name: Copy sarif file to CWD

View File

@@ -25,7 +25,7 @@ jobs:
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
with:
languages: javascript # does not matter
- uses: actions/cache@v3

View File

@@ -22,7 +22,7 @@ jobs:
- uses: actions/checkout@v3
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
with:
languages: javascript # does not matter
- uses: actions/cache@v3
@@ -44,7 +44,7 @@ jobs:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
- name: Check QL formatting
run: |
find ql/ql/src "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 "${CODEQL}" query format --check-only
find ql/ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 "${CODEQL}" query format --check-only
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
- name: Check QL compilation

View File

@@ -485,39 +485,28 @@
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll"
],
"ReDoS Util Python/JS/Ruby/Java": [
"javascript/ql/lib/semmle/javascript/security/regexp/NfaUtils.qll",
"python/ql/lib/semmle/python/security/regexp/NfaUtils.qll",
"ruby/ql/lib/codeql/ruby/security/regexp/NfaUtils.qll",
"java/ql/lib/semmle/code/java/security/regexp/NfaUtils.qll"
"javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll",
"python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll",
"ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll",
"java/ql/lib/semmle/code/java/security/performance/ReDoSUtil.qll"
],
"ReDoS Exponential Python/JS/Ruby/Java": [
"javascript/ql/lib/semmle/javascript/security/regexp/ExponentialBackTracking.qll",
"python/ql/lib/semmle/python/security/regexp/ExponentialBackTracking.qll",
"ruby/ql/lib/codeql/ruby/security/regexp/ExponentialBackTracking.qll",
"java/ql/lib/semmle/code/java/security/regexp/ExponentialBackTracking.qll"
"javascript/ql/lib/semmle/javascript/security/performance/ExponentialBackTracking.qll",
"python/ql/lib/semmle/python/security/performance/ExponentialBackTracking.qll",
"ruby/ql/lib/codeql/ruby/security/performance/ExponentialBackTracking.qll",
"java/ql/lib/semmle/code/java/security/performance/ExponentialBackTracking.qll"
],
"ReDoS Polynomial Python/JS/Ruby/Java": [
"javascript/ql/lib/semmle/javascript/security/regexp/SuperlinearBackTracking.qll",
"python/ql/lib/semmle/python/security/regexp/SuperlinearBackTracking.qll",
"ruby/ql/lib/codeql/ruby/security/regexp/SuperlinearBackTracking.qll",
"java/ql/lib/semmle/code/java/security/regexp/SuperlinearBackTracking.qll"
],
"RegexpMatching Python/JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/regexp/RegexpMatching.qll",
"python/ql/lib/semmle/python/security/regexp/RegexpMatching.qll",
"ruby/ql/lib/codeql/ruby/security/regexp/RegexpMatching.qll"
"javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll",
"python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll",
"ruby/ql/lib/codeql/ruby/security/performance/SuperlinearBackTracking.qll",
"java/ql/lib/semmle/code/java/security/performance/SuperlinearBackTracking.qll"
],
"BadTagFilterQuery Python/JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll",
"python/ql/lib/semmle/python/security/BadTagFilterQuery.qll",
"ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll"
],
"OverlyLargeRange Python/JS/Ruby/Java": [
"javascript/ql/lib/semmle/javascript/security/OverlyLargeRangeQuery.qll",
"python/ql/lib/semmle/python/security/OverlyLargeRangeQuery.qll",
"ruby/ql/lib/codeql/ruby/security/OverlyLargeRangeQuery.qll",
"java/ql/lib/semmle/code/java/security/OverlyLargeRangeQuery.qll"
],
"CFG": [
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",
"ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll",
@@ -597,9 +586,5 @@
"Swift patterns test file": [
"swift/ql/test/extractor-tests/patterns/patterns.swift",
"swift/ql/test/library-tests/parent/patterns.swift"
],
"IncompleteMultiCharacterSanitization JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/IncompleteMultiCharacterSanitizationQuery.qll",
"ruby/ql/lib/codeql/ruby/security/IncompleteMultiCharacterSanitizationQuery.qll"
]
}

View File

@@ -1,3 +0,0 @@
description: Add relation for orphaned local variables
compatibility: full
orphaned_variables.rel: delete

View File

@@ -1,15 +1,3 @@
## 0.3.3
### New Features
* Added a predicate `getValueConstant` to `AttributeArgument` that yields the argument value as an `Expr` when the value is a constant expression.
* A new class predicate `MustFlowConfiguration::allowInterproceduralFlow` has been added to the `semmle.code.cpp.ir.dataflow.MustFlow` library. The new predicate can be overridden to disable interprocedural flow.
* Added subclasses of `BuiltInOperations` for `__builtin_bit_cast`, `__builtin_shuffle`, `__has_unique_object_representations`, `__is_aggregate`, and `__is_assignable`.
### Major Analysis Improvements
* The IR dataflow library now includes flow through global variables. This enables new findings in many scenarios.
## 0.3.2
### Bug Fixes

View File

@@ -0,0 +1,4 @@
---
category: majorAnalysis
---
* The IR dataflow library now includes flow through global variables. This enables new findings in many scenarios.

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* Added subclasses of `BuiltInOperations` for `__builtin_bit_cast`, `__builtin_shuffle`, `__has_unique_object_representations`, `__is_aggregate`, and `__is_assignable`.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Multiple function calls made in the same function may now receive the same global value number when the analysis can show they produce the same results.

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* A new class predicate `MustFlowConfiguration::allowInterproceduralFlow` has been added to the `semmle.code.cpp.ir.dataflow.MustFlow` library. The new predicate can be overridden to disable interprocedural flow.

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* Added a predicate `getValueConstant` to `AttributeArgument` that yields the argument value as an `Expr` when the value is a constant expression.

View File

@@ -1,6 +0,0 @@
---
category: minorAnalysis
---
* All deprecated predicates/classes/modules that have been deprecated for over a year have been
deleted.

View File

@@ -1,4 +0,0 @@
---
category: feature
---
* Added support for getting the link targets of global and namespace variables.

View File

@@ -1,5 +0,0 @@
---
category: deprecated
---
* Many classes/predicates/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.

View File

@@ -1,11 +0,0 @@
## 0.3.3
### New Features
* Added a predicate `getValueConstant` to `AttributeArgument` that yields the argument value as an `Expr` when the value is a constant expression.
* A new class predicate `MustFlowConfiguration::allowInterproceduralFlow` has been added to the `semmle.code.cpp.ir.dataflow.MustFlow` library. The new predicate can be overridden to disable interprocedural flow.
* Added subclasses of `BuiltInOperations` for `__builtin_bit_cast`, `__builtin_shuffle`, `__has_unique_object_representations`, `__is_aggregate`, and `__is_assignable`.
### Major Analysis Improvements
* The IR dataflow library now includes flow through global variables. This enables new findings in many scenarios.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.3.3
lastReleaseVersion: 0.3.2

View File

@@ -119,67 +119,27 @@ module SemanticExprConfig {
result = block.getDisplayIndex()
}
newtype TSsaVariable =
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() }
class SsaVariable instanceof IR::Instruction {
SsaVariable() { super.hasMemoryResult() }
class SsaVariable extends TSsaVariable {
string toString() { none() }
final string toString() { result = super.toString() }
Location getLocation() { none() }
IR::Instruction asInstruction() { none() }
IR::Operand asOperand() { none() }
final Location getLocation() { result = super.getLocation() }
}
class SsaInstructionVariable extends SsaVariable, TSsaInstruction {
IR::Instruction instr;
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) { v = sourceExpr }
SsaInstructionVariable() { this = TSsaInstruction(instr) }
predicate phi(SsaVariable v) { v instanceof IR::PhiInstruction }
final override string toString() { result = instr.toString() }
SsaVariable getAPhiInput(SsaVariable v) { result = v.(IR::PhiInstruction).getAnInput() }
final override Location getLocation() { result = instr.getLocation() }
final override IR::Instruction asInstruction() { result = instr }
}
class SsaOperand extends SsaVariable, TSsaOperand {
IR::Operand op;
SsaOperand() { this = TSsaOperand(op) }
final override string toString() { result = op.toString() }
final override Location getLocation() { result = op.getLocation() }
final override IR::Operand asOperand() { result = op }
}
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) { v.asInstruction() = sourceExpr }
predicate phi(SsaVariable v) { v.asInstruction() instanceof IR::PhiInstruction }
SsaVariable getAPhiInput(SsaVariable v) {
exists(IR::PhiInstruction instr |
result.asInstruction() = instr.getAnInput()
or
result.asOperand() = instr.getAnInputOperand()
)
}
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v.asInstruction() }
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v }
SemType getSsaVariableType(SsaVariable v) {
result = getSemanticType(v.asInstruction().getResultIRType())
result = getSemanticType(v.(IR::Instruction).getResultIRType())
}
BasicBlock getSsaVariableBasicBlock(SsaVariable v) {
result = v.asInstruction().getBlock()
or
result = v.asOperand().getUse().getBlock()
}
BasicBlock getSsaVariableBasicBlock(SsaVariable v) { result = v.(IR::Instruction).getBlock() }
private newtype TReadPosition =
TReadPositionBlock(IR::IRBlock block) or
@@ -209,9 +169,7 @@ module SemanticExprConfig {
final override predicate hasRead(SsaVariable v) {
exists(IR::Operand operand |
operand.getDef() = v.asInstruction() and
not operand instanceof IR::PhiInputOperand and
operand.getUse().getBlock() = block
operand.getDef() = v and not operand instanceof IR::PhiInputOperand
)
}
}
@@ -228,7 +186,7 @@ module SemanticExprConfig {
final override predicate hasRead(SsaVariable v) {
exists(IR::PhiInputOperand operand |
operand.getDef() = v.asInstruction() and
operand.getDef() = v and
operand.getPredecessorBlock() = pred and
operand.getUse().getBlock() = succ
)
@@ -247,16 +205,17 @@ module SemanticExprConfig {
exists(IR::PhiInputOperand operand |
pos = TReadPositionPhiInputEdge(operand.getPredecessorBlock(), operand.getUse().getBlock())
|
phi.asInstruction() = operand.getUse() and
(
input.asInstruction() = operand.getDef()
or
input.asOperand() = operand
)
phi = operand.getUse() and input = operand.getDef()
)
}
class Bound instanceof IRBound::Bound {
Bound() {
this instanceof IRBound::ZeroBound
or
this.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction() instanceof SsaVariable
}
string toString() { result = super.toString() }
final Location getLocation() { result = super.getLocation() }
@@ -269,13 +228,13 @@ module SemanticExprConfig {
override string toString() {
result =
min(SsaVariable v |
v.asInstruction() = bound.getValueNumber().getAnInstruction()
min(SsaVariable instr |
instr = bound.getValueNumber().getAnInstruction()
|
v
instr
order by
v.asInstruction().getBlock().getDisplayIndex(),
v.asInstruction().getDisplayIndexInBlock()
instr.(IR::Instruction).getBlock().getDisplayIndex(),
instr.(IR::Instruction).getDisplayIndexInBlock()
).toString()
}
}
@@ -283,7 +242,7 @@ module SemanticExprConfig {
predicate zeroBound(Bound bound) { bound instanceof IRBound::ZeroBound }
predicate ssaBound(Bound bound, SsaVariable v) {
v.asInstruction() = bound.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction()
v = bound.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction()
}
Expr getBoundExpr(Bound bound, int delta) {
@@ -292,20 +251,22 @@ module SemanticExprConfig {
class Guard = IRGuards::IRGuardCondition;
predicate guard(Guard guard, BasicBlock block) { block = guard.getBlock() }
predicate guard(Guard guard, BasicBlock block) {
block = guard.(IRGuards::IRGuardCondition).getBlock()
}
Expr getGuardAsExpr(Guard guard) { result = guard }
predicate equalityGuard(Guard guard, Expr e1, Expr e2, boolean polarity) {
guard.comparesEq(e1.getAUse(), e2.getAUse(), 0, true, polarity)
guard.(IRGuards::IRGuardCondition).comparesEq(e1.getAUse(), e2.getAUse(), 0, true, polarity)
}
predicate guardDirectlyControlsBlock(Guard guard, BasicBlock controlled, boolean branch) {
guard.controls(controlled, branch)
guard.(IRGuards::IRGuardCondition).controls(controlled, branch)
}
predicate guardHasBranchEdge(Guard guard, BasicBlock bb1, BasicBlock bb2, boolean branch) {
guard.controlsEdge(bb1, bb2, branch)
guard.(IRGuards::IRGuardCondition).controlsEdge(bb1, bb2, branch)
}
Guard comparisonGuard(Expr e) { result = e }
@@ -323,13 +284,9 @@ SemBasicBlock getSemanticBasicBlock(IR::IRBlock block) { result = block }
IR::IRBlock getCppBasicBlock(SemBasicBlock block) { block = result }
SemSsaVariable getSemanticSsaVariable(IR::Instruction instr) {
result.(SemanticExprConfig::SsaVariable).asInstruction() = instr
}
SemSsaVariable getSemanticSsaVariable(IR::Instruction instr) { result = instr }
IR::Instruction getCppSsaVariableInstruction(SemSsaVariable var) {
var.(SemanticExprConfig::SsaVariable).asInstruction() = result
}
IR::Instruction getCppSsaVariableInstruction(SemSsaVariable v) { v = result }
SemBound getSemanticBound(IRBound::Bound bound) { result = bound }

View File

@@ -160,7 +160,6 @@ private predicate phiModulusInit(SemSsaPhiNode phi, SemBound b, int val, int mod
/**
* Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`.
*/
pragma[nomagic]
private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int mod, int rix) {
rix = 0 and
phiModulusInit(phi, b, val, mod)
@@ -170,7 +169,7 @@ private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int
val = remainder(v1, mod)
|
exists(int v2, int m2 |
rankedPhiInput(pragma[only_bind_out](phi), inp, edge, rix) and
rankedPhiInput(phi, inp, edge, rix) and
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
ssaModulus(inp, edge, b, v2, m2) and
mod = m1.gcd(m2).gcd(v1 - v2)

View File

@@ -342,10 +342,7 @@ private class ConvertOrBoxExpr extends SemUnaryExpr {
* A cast that can be ignored for the purpose of range analysis.
*/
private class SafeCastExpr extends ConvertOrBoxExpr {
SafeCastExpr() {
conversionCannotOverflow(getTrackedType(pragma[only_bind_into](getOperand())),
getTrackedType(this))
}
SafeCastExpr() { conversionCannotOverflow(getTrackedType(getOperand()), getTrackedType(this)) }
}
/**

View File

@@ -189,12 +189,9 @@ private class BinarySignExpr extends FlowSignExpr {
BinarySignExpr() { binary = this }
override Sign getSignRestriction() {
exists(SemExpr left, SemExpr right |
binaryExprOperands(binary, left, right) and
result =
semExprSign(pragma[only_bind_out](left))
.applyBinaryOp(semExprSign(pragma[only_bind_out](right)), binary.getOpcode())
)
result =
semExprSign(binary.getLeftOperand())
.applyBinaryOp(semExprSign(binary.getRightOperand()), binary.getOpcode())
or
exists(SemDivExpr div | div = binary |
result = semExprSign(div.getLeftOperand()) and
@@ -204,10 +201,6 @@ private class BinarySignExpr extends FlowSignExpr {
}
}
private predicate binaryExprOperands(SemBinaryExpr binary, SemExpr left, SemExpr right) {
binary.getLeftOperand() = left and binary.getRightOperand() = right
}
/**
* A `Convert`, `Box`, or `Unbox` expression.
*/
@@ -228,7 +221,7 @@ private class UnarySignExpr extends FlowSignExpr {
UnarySignExpr() { unary = this and not this instanceof SemCastExpr }
override Sign getSignRestriction() {
result = semExprSign(pragma[only_bind_out](unary.getOperand())).applyUnaryOp(unary.getOpcode())
result = semExprSign(unary.getOperand()).applyUnaryOp(unary.getOpcode())
}
}

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 0.3.4-dev
version: 0.3.3-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

@@ -218,6 +218,8 @@ class Folder extends Container, @folder {
class File extends Container, @file {
override string getAbsolutePath() { files(underlyingElement(this), result) }
override string toString() { result = Container.super.toString() }
override string getAPrimaryQlClass() { result = "File" }
override Location getLocation() {

View File

@@ -41,15 +41,6 @@ class LinkTarget extends @link_target {
* translation units which contributed to this link target.
*/
Class getAClass() { link_parent(unresolveElement(result), this) }
/**
* Gets a global or namespace variable which was compiled into this
* link target, or had its declaration included by one of the translation
* units which contributed to this link target.
*/
GlobalOrNamespaceVariable getAGlobalOrNamespaceVariable() {
link_parent(unresolveElement(result), this)
}
}
/**

View File

@@ -398,8 +398,6 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
exists(DeclStmt s | s.getADeclaration() = this and s.getEnclosingFunction() = result)
or
exists(ConditionDeclExpr e | e.getVariable() = this and e.getEnclosingFunction() = result)
or
orphaned_variables(underlyingElement(this), unresolveElement(result))
}
}
@@ -473,9 +471,6 @@ class GlobalOrNamespaceVariable extends Variable, @globalvariable {
override Type getType() { globalvariables(underlyingElement(this), unresolveElement(result), _) }
override Element getEnclosingElement() { none() }
/** Gets a link target which compiled or referenced this global or namespace variable. */
LinkTarget getALinkTarget() { this = result.getAGlobalOrNamespaceVariable() }
}
/**

107
cpp/ql/lib/semmle/code/cpp/XML.qll Normal file → Executable file
View File

@@ -8,7 +8,7 @@ private class TXmlLocatable =
@xmldtd or @xmlelement or @xmlattribute or @xmlnamespace or @xmlcomment or @xmlcharacters;
/** An XML element that has a location. */
class XmlLocatable extends @xmllocatable, TXmlLocatable {
class XMLLocatable extends @xmllocatable, TXmlLocatable {
/** Gets the source location for this element. */
Location getLocation() { xmllocations(this, result) }
@@ -32,16 +32,13 @@ class XmlLocatable extends @xmllocatable, TXmlLocatable {
string toString() { none() } // overridden in subclasses
}
/** DEPRECATED: Alias for XmlLocatable */
deprecated class XMLLocatable = XmlLocatable;
/**
* An `XmlParent` is either an `XmlElement` or an `XmlFile`,
* An `XMLParent` is either an `XMLElement` or an `XMLFile`,
* both of which can contain other elements.
*/
class XmlParent extends @xmlparent {
XmlParent() {
// explicitly restrict `this` to be either an `XmlElement` or an `XmlFile`;
class XMLParent extends @xmlparent {
XMLParent() {
// explicitly restrict `this` to be either an `XMLElement` or an `XMLFile`;
// the type `@xmlparent` currently also includes non-XML files
this instanceof @xmlelement or xmlEncoding(this, _)
}
@@ -53,28 +50,28 @@ class XmlParent extends @xmlparent {
string getName() { none() } // overridden in subclasses
/** Gets the file to which this XML parent belongs. */
XmlFile getFile() { result = this or xmlElements(this, _, _, _, result) }
XMLFile getFile() { result = this or xmlElements(this, _, _, _, result) }
/** Gets the child element at a specified index of this XML parent. */
XmlElement getChild(int index) { xmlElements(result, _, this, index, _) }
XMLElement getChild(int index) { xmlElements(result, _, this, index, _) }
/** Gets a child element of this XML parent. */
XmlElement getAChild() { xmlElements(result, _, this, _, _) }
XMLElement getAChild() { xmlElements(result, _, this, _, _) }
/** Gets a child element of this XML parent with the given `name`. */
XmlElement getAChild(string name) { xmlElements(result, _, this, _, _) and result.hasName(name) }
XMLElement getAChild(string name) { xmlElements(result, _, this, _, _) and result.hasName(name) }
/** Gets a comment that is a child of this XML parent. */
XmlComment getAComment() { xmlComments(result, _, this, _) }
XMLComment getAComment() { xmlComments(result, _, this, _) }
/** Gets a character sequence that is a child of this XML parent. */
XmlCharacters getACharactersSet() { xmlChars(result, _, this, _, _, _) }
XMLCharacters getACharactersSet() { xmlChars(result, _, this, _, _, _) }
/** Gets the depth in the tree. (Overridden in XmlElement.) */
/** Gets the depth in the tree. (Overridden in XMLElement.) */
int getDepth() { result = 0 }
/** Gets the number of child XML elements of this XML parent. */
int getNumberOfChildren() { result = count(XmlElement e | xmlElements(e, _, this, _, _)) }
int getNumberOfChildren() { result = count(XMLElement e | xmlElements(e, _, this, _, _)) }
/** Gets the number of places in the body of this XML parent where text occurs. */
int getNumberOfCharacterSets() { result = count(int pos | xmlChars(_, _, this, pos, _, _)) }
@@ -95,12 +92,9 @@ class XmlParent extends @xmlparent {
string toString() { result = this.getName() }
}
/** DEPRECATED: Alias for XmlParent */
deprecated class XMLParent = XmlParent;
/** An XML file. */
class XmlFile extends XmlParent, File {
XmlFile() { xmlEncoding(this, _) }
class XMLFile extends XMLParent, File {
XMLFile() { xmlEncoding(this, _) }
/** Gets a printable representation of this XML file. */
override string toString() { result = this.getName() }
@@ -126,21 +120,15 @@ class XmlFile extends XmlParent, File {
string getEncoding() { xmlEncoding(this, result) }
/** Gets the XML file itself. */
override XmlFile getFile() { result = this }
override XMLFile getFile() { result = this }
/** Gets a top-most element in an XML file. */
XmlElement getARootElement() { result = this.getAChild() }
XMLElement getARootElement() { result = this.getAChild() }
/** Gets a DTD associated with this XML file. */
XmlDtd getADtd() { xmlDTDs(result, _, _, _, this) }
/** DEPRECATED: Alias for getADtd */
deprecated XmlDtd getADTD() { result = this.getADtd() }
XMLDTD getADTD() { xmlDTDs(result, _, _, _, this) }
}
/** DEPRECATED: Alias for XmlFile */
deprecated class XMLFile = XmlFile;
/**
* An XML document type definition (DTD).
*
@@ -152,7 +140,7 @@ deprecated class XMLFile = XmlFile;
* <!ELEMENT lastName (#PCDATA)>
* ```
*/
class XmlDtd extends XmlLocatable, @xmldtd {
class XMLDTD extends XMLLocatable, @xmldtd {
/** Gets the name of the root element of this DTD. */
string getRoot() { xmlDTDs(this, result, _, _, _) }
@@ -166,7 +154,7 @@ class XmlDtd extends XmlLocatable, @xmldtd {
predicate isPublic() { not xmlDTDs(this, _, "", _, _) }
/** Gets the parent of this DTD. */
XmlParent getParent() { xmlDTDs(this, _, _, _, result) }
XMLParent getParent() { xmlDTDs(this, _, _, _, result) }
override string toString() {
this.isPublic() and
@@ -177,9 +165,6 @@ class XmlDtd extends XmlLocatable, @xmldtd {
}
}
/** DEPRECATED: Alias for XmlDtd */
deprecated class XMLDTD = XmlDtd;
/**
* An XML element in an XML file.
*
@@ -191,7 +176,7 @@ deprecated class XMLDTD = XmlDtd;
* </manifest>
* ```
*/
class XmlElement extends @xmlelement, XmlParent, XmlLocatable {
class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
/** Holds if this XML element has the given `name`. */
predicate hasName(string name) { name = this.getName() }
@@ -199,10 +184,10 @@ class XmlElement extends @xmlelement, XmlParent, XmlLocatable {
override string getName() { xmlElements(this, result, _, _, _) }
/** Gets the XML file in which this XML element occurs. */
override XmlFile getFile() { xmlElements(this, _, _, _, result) }
override XMLFile getFile() { xmlElements(this, _, _, _, result) }
/** Gets the parent of this XML element. */
XmlParent getParent() { xmlElements(this, _, result, _, _) }
XMLParent getParent() { xmlElements(this, _, result, _, _) }
/** Gets the index of this XML element among its parent's children. */
int getIndex() { xmlElements(this, _, _, result, _) }
@@ -211,7 +196,7 @@ class XmlElement extends @xmlelement, XmlParent, XmlLocatable {
predicate hasNamespace() { xmlHasNs(this, _, _) }
/** Gets the namespace of this XML element, if any. */
XmlNamespace getNamespace() { xmlHasNs(this, result, _) }
XMLNamespace getNamespace() { xmlHasNs(this, result, _) }
/** Gets the index of this XML element among its parent's children. */
int getElementPositionIndex() { xmlElements(this, _, _, result, _) }
@@ -220,10 +205,10 @@ class XmlElement extends @xmlelement, XmlParent, XmlLocatable {
override int getDepth() { result = this.getParent().getDepth() + 1 }
/** Gets an XML attribute of this XML element. */
XmlAttribute getAnAttribute() { result.getElement() = this }
XMLAttribute getAnAttribute() { result.getElement() = this }
/** Gets the attribute with the specified `name`, if any. */
XmlAttribute getAttribute(string name) { result.getElement() = this and result.getName() = name }
XMLAttribute getAttribute(string name) { result.getElement() = this and result.getName() = name }
/** Holds if this XML element has an attribute with the specified `name`. */
predicate hasAttribute(string name) { exists(this.getAttribute(name)) }
@@ -235,9 +220,6 @@ class XmlElement extends @xmlelement, XmlParent, XmlLocatable {
override string toString() { result = this.getName() }
}
/** DEPRECATED: Alias for XmlElement */
deprecated class XMLElement = XmlElement;
/**
* An attribute that occurs inside an XML element.
*
@@ -248,18 +230,18 @@ deprecated class XMLElement = XmlElement;
* android:versionCode="1"
* ```
*/
class XmlAttribute extends @xmlattribute, XmlLocatable {
class XMLAttribute extends @xmlattribute, XMLLocatable {
/** Gets the name of this attribute. */
string getName() { xmlAttrs(this, _, result, _, _, _) }
/** Gets the XML element to which this attribute belongs. */
XmlElement getElement() { xmlAttrs(this, result, _, _, _, _) }
XMLElement getElement() { xmlAttrs(this, result, _, _, _, _) }
/** Holds if this attribute has a namespace. */
predicate hasNamespace() { xmlHasNs(this, _, _) }
/** Gets the namespace of this attribute, if any. */
XmlNamespace getNamespace() { xmlHasNs(this, result, _) }
XMLNamespace getNamespace() { xmlHasNs(this, result, _) }
/** Gets the value of this attribute. */
string getValue() { xmlAttrs(this, _, _, result, _, _) }
@@ -268,9 +250,6 @@ class XmlAttribute extends @xmlattribute, XmlLocatable {
override string toString() { result = this.getName() + "=" + this.getValue() }
}
/** DEPRECATED: Alias for XmlAttribute */
deprecated class XMLAttribute = XmlAttribute;
/**
* A namespace used in an XML file.
*
@@ -280,29 +259,23 @@ deprecated class XMLAttribute = XmlAttribute;
* xmlns:android="http://schemas.android.com/apk/res/android"
* ```
*/
class XmlNamespace extends XmlLocatable, @xmlnamespace {
class XMLNamespace extends XMLLocatable, @xmlnamespace {
/** Gets the prefix of this namespace. */
string getPrefix() { xmlNs(this, result, _, _) }
/** Gets the URI of this namespace. */
string getUri() { xmlNs(this, _, result, _) }
/** DEPRECATED: Alias for getUri */
deprecated string getURI() { result = this.getUri() }
string getURI() { xmlNs(this, _, result, _) }
/** Holds if this namespace has no prefix. */
predicate isDefault() { this.getPrefix() = "" }
override string toString() {
this.isDefault() and result = this.getUri()
this.isDefault() and result = this.getURI()
or
not this.isDefault() and result = this.getPrefix() + ":" + this.getUri()
not this.isDefault() and result = this.getPrefix() + ":" + this.getURI()
}
}
/** DEPRECATED: Alias for XmlNamespace */
deprecated class XMLNamespace = XmlNamespace;
/**
* A comment in an XML file.
*
@@ -312,20 +285,17 @@ deprecated class XMLNamespace = XmlNamespace;
* <!-- This is a comment. -->
* ```
*/
class XmlComment extends @xmlcomment, XmlLocatable {
class XMLComment extends @xmlcomment, XMLLocatable {
/** Gets the text content of this XML comment. */
string getText() { xmlComments(this, result, _, _) }
/** Gets the parent of this XML comment. */
XmlParent getParent() { xmlComments(this, _, result, _) }
XMLParent getParent() { xmlComments(this, _, result, _) }
/** Gets a printable representation of this XML comment. */
override string toString() { result = this.getText() }
}
/** DEPRECATED: Alias for XmlComment */
deprecated class XMLComment = XmlComment;
/**
* A sequence of characters that occurs between opening and
* closing tags of an XML element, excluding other elements.
@@ -336,12 +306,12 @@ deprecated class XMLComment = XmlComment;
* <content>This is a sequence of characters.</content>
* ```
*/
class XmlCharacters extends @xmlcharacters, XmlLocatable {
class XMLCharacters extends @xmlcharacters, XMLLocatable {
/** Gets the content of this character sequence. */
string getCharacters() { xmlChars(this, result, _, _, _, _) }
/** Gets the parent of this character sequence. */
XmlParent getParent() { xmlChars(this, _, result, _, _, _) }
XMLParent getParent() { xmlChars(this, _, result, _, _, _) }
/** Holds if this character sequence is CDATA. */
predicate isCDATA() { xmlChars(this, _, _, _, 1, _) }
@@ -349,6 +319,3 @@ class XmlCharacters extends @xmlcharacters, XmlLocatable {
/** Gets a printable representation of this XML character sequence. */
override string toString() { result = this.getCharacters() }
}
/** DEPRECATED: Alias for XmlCharacters */
deprecated class XMLCharacters = XmlCharacters;

View File

@@ -39,7 +39,7 @@ private module Liveness {
/**
* Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`.
*/
predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) {
private predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) {
exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain))
or
exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain))
@@ -76,10 +76,6 @@ private module Liveness {
not result + 1 = refRank(bb, _, v, _)
}
predicate lastRefIsRead(BasicBlock bb, SourceVariable v) {
maxRefRank(bb, v) = refRank(bb, _, v, Read(_))
}
/**
* Gets the (1-based) rank of the first reference to `v` inside basic block `bb`
* that is either a read or a certain write.
@@ -189,29 +185,23 @@ newtype TDefinition =
private module SsaDefReaches {
newtype TSsaRefKind =
SsaActualRead() or
SsaPhiRead() or
SsaRead() or
SsaDef()
class SsaRead = SsaActualRead or SsaPhiRead;
/**
* A classification of SSA variable references into reads and definitions.
*/
class SsaRefKind extends TSsaRefKind {
string toString() {
this = SsaActualRead() and
result = "SsaActualRead"
or
this = SsaPhiRead() and
result = "SsaPhiRead"
this = SsaRead() and
result = "SsaRead"
or
this = SsaDef() and
result = "SsaDef"
}
int getOrder() {
this instanceof SsaRead and
this = SsaRead() and
result = 0
or
this = SsaDef() and
@@ -219,80 +209,6 @@ private module SsaDefReaches {
}
}
/**
* Holds if `bb` is in the dominance frontier of a block containing a
* read of `v`.
*/
pragma[nomagic]
private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) {
exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) |
lastRefIsRead(readbb, v)
or
phiRead(readbb, v)
)
}
/**
* Holds if a phi-read node should be inserted for variable `v` at the beginning
* of basic block `bb`.
*
* Phi-read nodes are like normal phi nodes, but they are inserted based on reads
* instead of writes, and only if the dominance-frontier block does not already
* contain a reference (read or write) to `v`. Unlike normal phi nodes, this is
* an internal implementation detail that is not exposed.
*
* The motivation for adding phi-reads is to improve performance of the use-use
* calculation in cases where there is a large number of reads that can reach the
* same join-point, and from there reach a large number of basic blocks. Example:
*
* ```cs
* if (a)
* use(x);
* else if (b)
* use(x);
* else if (c)
* use(x);
* else if (d)
* use(x);
* // many more ifs ...
*
* // phi-read for `x` inserted here
*
* // program not mentioning `x`, with large basic block graph
*
* use(x);
* ```
*
* Without phi-reads, the analysis has to replicate reachability for each of
* the guarded uses of `x`. However, with phi-reads, the analysis will limit
* each conditional use of `x` to reach the basic block containing the phi-read
* node for `x`, and only that basic block will have to compute reachability
* through the remainder of the large program.
*
* Like normal reads, each phi-read node `phi-read` can be reached from exactly
* one SSA definition (without passing through another definition): Assume, for
* the sake of contradiction, that there are two reaching definitions `def1` and
* `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest
* dominating definition will prevent the other from reaching `phi-read`. So, at
* least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`.
* Then `def1` must go through one of its dominance-frontier blocks in order to
* reach `phi-read`. However, such a block will always start with a (normal) phi
* node, which contradicts reachability.
*
* Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`,
* will dominate `phi-read`. Assuming it doesn't means that the path from `def`
* to `phi-read` goes through a dominance-frontier block, and hence a phi node,
* which contradicts reachability.
*/
pragma[nomagic]
predicate phiRead(BasicBlock bb, SourceVariable v) {
inReadDominanceFrontier(bb, v) and
liveAtEntry(bb, v) and
// only if there are no other references to `v` inside `bb`
not ref(bb, _, v, _) and
not exists(Definition def | def.definesAt(v, bb, _))
}
/**
* Holds if the `i`th node of basic block `bb` is a reference to `v`,
* either a read (when `k` is `SsaRead()`) or an SSA definition (when `k`
@@ -300,16 +216,11 @@ private module SsaDefReaches {
*
* Unlike `Liveness::ref`, this includes `phi` nodes.
*/
pragma[nomagic]
predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
variableRead(bb, i, v, _) and
k = SsaActualRead()
k = SsaRead()
or
phiRead(bb, v) and
i = -1 and
k = SsaPhiRead()
or
any(Definition def).definesAt(v, bb, i) and
exists(Definition def | def.definesAt(v, bb, i)) and
k = SsaDef()
}
@@ -362,7 +273,7 @@ private module SsaDefReaches {
)
or
ssaDefReachesRank(bb, def, rnk - 1, v) and
rnk = ssaRefRank(bb, _, v, any(SsaRead k))
rnk = ssaRefRank(bb, _, v, SsaRead())
}
/**
@@ -372,7 +283,7 @@ private module SsaDefReaches {
predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
exists(int rnk |
ssaDefReachesRank(bb, def, rnk, v) and
rnk = ssaRefRank(bb, i, v, any(SsaRead k))
rnk = ssaRefRank(bb, i, v, SsaRead())
)
}
@@ -398,94 +309,45 @@ private module SsaDefReaches {
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
}
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) {
exists(ssaDefRank(def, v, bb, _, k))
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) {
exists(ssaDefRank(def, v, bb, _, _))
}
pragma[noinline]
private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) {
ssaDefReachesEndOfBlock(bb, def, _) and
not defOccursInBlock(_, bb, def.getSourceVariable(), _)
not defOccursInBlock(_, bb, def.getSourceVariable())
}
/**
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
* `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_
* predecessor of `bb2`, and the underlying variable for `def` is neither read
* nor written in any block on the path between `bb1` and `bb2`.
*
* Phi reads are considered as normal reads for this predicate.
* `bb2` is a transitive successor of `bb1`, `def` is live at the end of `bb1`,
* and the underlying variable for `def` is neither read nor written in any block
* on the path between `bb1` and `bb2`.
*/
pragma[nomagic]
private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
defOccursInBlock(def, bb1, _, _) and
predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) {
defOccursInBlock(def, bb1, _) and
bb2 = getABasicBlockSuccessor(bb1)
or
exists(BasicBlock mid |
varBlockReachesInclPhiRead(def, bb1, mid) and
varBlockReaches(def, bb1, mid) and
ssaDefReachesThroughBlock(def, mid) and
bb2 = getABasicBlockSuccessor(mid)
)
}
pragma[nomagic]
private predicate phiReadStep(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) {
varBlockReachesInclPhiRead(def, bb1, bb2) and
defOccursInBlock(def, bb2, v, SsaPhiRead())
}
pragma[nomagic]
private predicate varBlockReachesExclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
varBlockReachesInclPhiRead(pragma[only_bind_into](def), bb1, pragma[only_bind_into](bb2)) and
ssaRef(bb2, _, def.getSourceVariable(), [SsaActualRead().(TSsaRefKind), SsaDef()])
or
exists(BasicBlock mid |
varBlockReachesExclPhiRead(def, mid, bb2) and
phiReadStep(def, _, bb1, mid)
)
}
/**
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
* the underlying variable `v` of `def` is accessed in basic block `bb2`
* (either a read or a write), `bb2` is a transitive successor of `bb1`, and
* `v` is neither read nor written in any block on the path between `bb1`
* and `bb2`.
* `def` is read at index `i2` in basic block `bb2`, `bb2` is in a transitive
* successor block of `bb1`, and `def` is neither read nor written in any block
* on a path between `bb1` and `bb2`.
*/
pragma[nomagic]
predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) {
varBlockReachesExclPhiRead(def, bb1, bb2) and
not defOccursInBlock(def, bb1, _, SsaPhiRead())
}
pragma[nomagic]
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
varBlockReaches(def, bb1, bb2) and
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaActualRead()) = 1
}
/**
* Holds if `def` is accessed in basic block `bb` (either a read or a write),
* `bb1` can reach a transitive successor `bb2` where `def` is no longer live,
* and `v` is neither read nor written in any block on the path between `bb`
* and `bb2`.
*/
pragma[nomagic]
predicate varBlockReachesExit(Definition def, BasicBlock bb) {
exists(BasicBlock bb2 | varBlockReachesInclPhiRead(def, bb, bb2) |
not defOccursInBlock(def, bb2, _, _) and
not ssaDefReachesEndOfBlock(bb2, def, _)
)
or
exists(BasicBlock mid |
varBlockReachesExit(def, mid) and
phiReadStep(def, _, bb, mid)
)
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1
}
}
predicate phiReadExposedForTesting = phiRead/2;
private import SsaDefReaches
pragma[nomagic]
@@ -503,8 +365,7 @@ predicate liveThrough(BasicBlock bb, SourceVariable v) {
*/
pragma[nomagic]
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) {
exists(int last |
last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and
exists(int last | last = maxSsaRefRank(bb, v) |
ssaDefReachesRank(bb, def, last, v) and
liveAtExit(bb, v)
)
@@ -544,7 +405,7 @@ pragma[nomagic]
predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) {
ssaDefReachesReadWithinBlock(v, def, bb, i)
or
ssaRef(bb, i, v, any(SsaRead k)) and
variableRead(bb, i, v, _) and
ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and
not ssaDefReachesReadWithinBlock(v, _, bb, i)
}
@@ -560,7 +421,7 @@ pragma[nomagic]
predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
exists(int rnk |
rnk = ssaDefRank(def, _, bb1, i1, _) and
rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and
rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaRead()) and
variableRead(bb1, i2, _, _) and
bb2 = bb1
)
@@ -677,15 +538,18 @@ predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Def
*/
pragma[nomagic]
predicate lastRef(Definition def, BasicBlock bb, int i) {
// Can reach another definition
lastRefRedef(def, bb, i, _)
or
exists(SourceVariable v | lastSsaRef(def, v, bb, i) |
lastSsaRef(def, _, bb, i) and
(
// Can reach exit directly
bb instanceof ExitBasicBlock
or
// Can reach a block using one or more steps, where `def` is no longer live
varBlockReachesExit(def, bb)
exists(BasicBlock bb2 | varBlockReaches(def, bb, bb2) |
not defOccursInBlock(def, bb2, _) and
not ssaDefReachesEndOfBlock(bb2, def, _)
)
)
}

View File

@@ -22,7 +22,7 @@ module InstructionConsistency {
abstract Language::Location getLocation();
}
class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
private IRFunction irFunc;
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
@@ -37,8 +37,6 @@ module InstructionConsistency {
result =
min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString())
}
IRFunction getIRFunction() { result = irFunc }
}
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {

View File

@@ -1712,11 +1712,6 @@ class SideEffectInstruction extends Instruction {
*/
class CallSideEffectInstruction extends SideEffectInstruction {
CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect }
/** Gets the operand for the value that will be read by this instruction */
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
}
/**
@@ -1728,11 +1723,6 @@ class CallSideEffectInstruction extends SideEffectInstruction {
*/
class CallReadSideEffectInstruction extends SideEffectInstruction {
CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect }
/** Gets the operand for the value that will be read by this instruction */
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
}
/**

View File

@@ -1,4 +1,3 @@
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.cpp.models.interfaces.SideEffect as SideEffect

View File

@@ -41,92 +41,8 @@ newtype TValueNumber =
) {
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
} or
TCallValueNumber(TCallPartialValueNumber vn) { callValueNumber(_, _, vn) } or
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
private class NumberableCallInstruction extends CallInstruction {
NumberableCallInstruction() {
not this.getResultIRType() instanceof IRVoidType and
exists(SideEffect::SideEffectFunction sideEffectFunc |
sideEffectFunc = this.getStaticCallTarget()
|
sideEffectFunc.hasOnlySpecificReadSideEffects() and
sideEffectFunc.hasOnlySpecificWriteSideEffects()
)
}
}
private newtype TCallPartialValueNumber =
TNilArgument() or
TArgument(TCallPartialValueNumber head, TValueNumber arg) {
exists(NumberableCallInstruction call, int index |
callArgValueNumber(call, index, arg) and
callPartialValueNumber(call, index, head)
)
}
private predicate callValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber vn
) {
index = max(int n | callArgRank(call, n, _) | n) and
exists(TCallPartialValueNumber head, TValueNumber arg |
callPartialValueNumber(call, index, pragma[only_bind_out](head)) and
callArgValueNumber(call, index, pragma[only_bind_into](arg)) and
vn = TArgument(head, arg)
)
or
not exists(int n | callArgRank(call, n, _)) and
index = -1 and
vn = TNilArgument()
}
private predicate callPartialValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber head
) {
exists(call) and
index = 1 and
head = TNilArgument()
or
exists(TCallPartialValueNumber prev, TValueNumber prevVN |
callPartialValueNumber(call, index - 1, pragma[only_bind_out](prev)) and
callArgValueNumber(call, index - 1, pragma[only_bind_into](prevVN)) and
head = TArgument(prev, prevVN)
)
}
/**
*/
private predicate callArgValueNumber(NumberableCallInstruction call, int index, TValueNumber arg) {
exists(Instruction instr |
callArgRank(call, index, instr) and
arg = tvalueNumber(instr)
)
}
/**
* Holds if `arg` is the `index`th element in `call`'s extended argument list, including the `this`
* argument and side-effect reads.
*/
private predicate callArgRank(NumberableCallInstruction call, int index, Instruction arg) {
arg =
rank[index](int argIndex, boolean isEffect, Instruction instr |
// There is no need to include the call's read and write side effects on
// all-aliased-memory as `NumberableCallInstruction`s do not read or write
// to all-aliased-memory.
instr = call.getArgument(argIndex) and
isEffect = false
or
exists(ReadSideEffectInstruction read |
read.getPrimaryInstruction() = call and
read.getSideEffectOperand().getAnyDef() = instr and
read.getIndex() = argIndex and
isEffect = true
)
|
instr order by argIndex, isEffect
)
}
/**
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
* operand.
@@ -177,8 +93,6 @@ private predicate numberableInstruction(Instruction instr) {
instr instanceof CongruentCopyInstruction
or
instr instanceof LoadTotalOverlapInstruction
or
instr instanceof NumberableCallInstruction
}
private predicate filteredNumberableInstruction(Instruction instr) {
@@ -395,11 +309,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
or
// The value number of a copy is just the value number of its source value.
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
or
exists(TCallPartialValueNumber pvn |
callValueNumber(instr, _, pvn) and
result = TCallValueNumber(pvn)
)
)
)
}

View File

@@ -3,7 +3,7 @@ import semmle.code.cpp.ir.internal.Overlap
private import semmle.code.cpp.ir.internal.IRCppLanguage as Language
private import semmle.code.cpp.Print
private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR
private import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as OldSsa
private import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as OldSSA
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
private import semmle.code.cpp.ir.internal.IntegerInterval as Interval
private import semmle.code.cpp.ir.implementation.internal.OperandTag
@@ -572,7 +572,7 @@ private Overlap getVariableMemoryLocationOverlap(
* Holds if the def/use information for the result of `instr` can be reused from the previous
* iteration of the IR.
*/
predicate canReuseSsaForOldResult(Instruction instr) { OldSsa::canReuseSsaForMemoryResult(instr) }
predicate canReuseSsaForOldResult(Instruction instr) { OldSSA::canReuseSsaForMemoryResult(instr) }
/** DEPRECATED: Alias for canReuseSsaForOldResult */
deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1;

View File

@@ -5,9 +5,14 @@ private import Imports::OperandTag
private import Imports::Overlap
private import Imports::TInstruction
private import Imports::RawIR as RawIR
private import SsaInstructions
private import SsaOperands
private import SSAInstructions
private import SSAOperands
private import NewIR
private class OldBlock = Reachability::ReachableBlock;
private class OldInstruction = Reachability::ReachableInstruction;
import Cached
cached
@@ -53,9 +58,7 @@ private module Cached {
cached
predicate hasInstruction(TStageInstruction instr) {
instr instanceof TRawInstruction and
instr instanceof OldInstruction and
not removedInstruction(instr)
instr instanceof TRawInstruction and instr instanceof OldInstruction
or
instr = phiInstruction(_, _)
or
@@ -379,14 +382,7 @@ private module Cached {
(
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
else
if removedInstruction(oldInstruction.getSuccessor(kind))
then
// the only removed nodes are side-effect writes, but those may have Chi nodes
// skip to the following instruction in the old IR, which won't be removed
// if we start skipping specific side effects, this may no longer hold
result = getNewInstruction(oldInstruction.getSuccessor(kind).getSuccessor(kind))
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
or

View File

@@ -2,26 +2,7 @@ import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as OldIR
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSsaInstructions as SsaInstructions
/** DEPRECATED: Alias for SsaInstructions */
deprecated module SSAInstructions = SsaInstructions;
import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSsaInstructions as SSAInstructions
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import AliasedSSA as Alias
import semmle.code.cpp.ir.implementation.internal.TOperand::AliasedSsaOperands as SsaOperands
/** DEPRECATED: Alias for SsaOperands */
deprecated module SSAOperands = SsaOperands;
private import SideEffectElimination as Elim
predicate removedInstruction(Reachability::ReachableInstruction instr) {
Elim::removeableSideEffect(instr)
}
class OldBlock = Reachability::ReachableBlock;
class OldInstruction extends Reachability::ReachableInstruction {
OldInstruction() { not Elim::removeableSideEffect(this) }
}
import semmle.code.cpp.ir.implementation.internal.TOperand::AliasedSsaOperands as SSAOperands

View File

@@ -1,42 +0,0 @@
import cpp as CPP
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as Unaliased
import AliasAnalysis as Alias
import AliasConfiguration as Conf
import semmle.code.cpp.models.interfaces.SideEffect as SideEffect
private predicate noLocalSideEffectWrite(CPP::Function func) {
forall(Unaliased::AddressOperand addr | addr.getUse().getEnclosingFunction() = func |
not (
Alias::getAddressOperandAllocation(addr) instanceof Conf::VariableAllocation and
Alias::getAddressOperandAllocation(addr).(Conf::VariableAllocation).alwaysEscapes()
)
)
}
language[monotonicAggregates]
private predicate noTransitiveSideEffectWrite(CPP::Function func) {
exists(Unaliased::IRFunction irFunc | irFunc.getFunction() = func) and
noLocalSideEffectWrite(func) and
forall(Unaliased::CallInstruction call | call.getEnclosingFunction() = func |
exists(call.getStaticCallTarget())
) and
forall(Unaliased::CallInstruction call, CPP::Function callee |
call.getStaticCallTarget() = callee and
call.getEnclosingFunction() = func
|
noTransitiveSideEffectWrite(callee)
or
callee.(SideEffect::SideEffectFunction).hasOnlySpecificWriteSideEffects()
)
}
predicate removeableSideEffect(Unaliased::SideEffectInstruction instr) {
(
instr instanceof Unaliased::CallSideEffectInstruction or
instr instanceof Unaliased::CallReadSideEffectInstruction
) and
noTransitiveSideEffectWrite(instr
.getPrimaryInstruction()
.(Unaliased::CallInstruction)
.getStaticCallTarget())
}

View File

@@ -29,16 +29,15 @@ newtype TInstruction =
UnaliasedSsa::SSA::hasUnreachedInstruction(irFunc)
} or
TAliasedSsaPhiInstruction(
TRawInstruction blockStartInstr, AliasedSsa::SSA::MemoryLocation memoryLocation
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
) {
AliasedSsa::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
} or
TAliasedSsaChiInstruction(TRawInstruction primaryInstruction) {
not AliasedSsa::removedInstruction(primaryInstruction) and
AliasedSsa::SSA::hasChiInstruction(primaryInstruction)
AliasedSSA::SSA::hasChiInstruction(primaryInstruction)
} or
TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
AliasedSsa::SSA::hasUnreachedInstruction(irFunc)
AliasedSSA::SSA::hasUnreachedInstruction(irFunc)
}
/**
@@ -84,7 +83,7 @@ module AliasedSsaInstructions {
class TPhiInstruction = TAliasedSsaPhiInstruction or TUnaliasedSsaPhiInstruction;
TPhiInstruction phiInstruction(
TRawInstruction blockStartInstr, AliasedSsa::SSA::MemoryLocation memoryLocation
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
) {
result = TAliasedSsaPhiInstruction(blockStartInstr, memoryLocation)
}

View File

@@ -1,9 +1,4 @@
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSsa
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedSsa
/** DEPRECATED: Alias for AliasedSsa */
deprecated module AliasedSSA = AliasedSsa;
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SideEffectElimination as Elim
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedSSA

View File

@@ -22,7 +22,7 @@ module InstructionConsistency {
abstract Language::Location getLocation();
}
class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
private IRFunction irFunc;
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
@@ -37,8 +37,6 @@ module InstructionConsistency {
result =
min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString())
}
IRFunction getIRFunction() { result = irFunc }
}
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {

View File

@@ -1712,11 +1712,6 @@ class SideEffectInstruction extends Instruction {
*/
class CallSideEffectInstruction extends SideEffectInstruction {
CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect }
/** Gets the operand for the value that will be read by this instruction */
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
}
/**
@@ -1728,11 +1723,6 @@ class CallSideEffectInstruction extends SideEffectInstruction {
*/
class CallReadSideEffectInstruction extends SideEffectInstruction {
CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect }
/** Gets the operand for the value that will be read by this instruction */
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
}
/**

View File

@@ -1,4 +1,3 @@
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.cpp.models.interfaces.SideEffect as SideEffect

View File

@@ -41,92 +41,8 @@ newtype TValueNumber =
) {
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
} or
TCallValueNumber(TCallPartialValueNumber vn) { callValueNumber(_, _, vn) } or
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
private class NumberableCallInstruction extends CallInstruction {
NumberableCallInstruction() {
not this.getResultIRType() instanceof IRVoidType and
exists(SideEffect::SideEffectFunction sideEffectFunc |
sideEffectFunc = this.getStaticCallTarget()
|
sideEffectFunc.hasOnlySpecificReadSideEffects() and
sideEffectFunc.hasOnlySpecificWriteSideEffects()
)
}
}
private newtype TCallPartialValueNumber =
TNilArgument() or
TArgument(TCallPartialValueNumber head, TValueNumber arg) {
exists(NumberableCallInstruction call, int index |
callArgValueNumber(call, index, arg) and
callPartialValueNumber(call, index, head)
)
}
private predicate callValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber vn
) {
index = max(int n | callArgRank(call, n, _) | n) and
exists(TCallPartialValueNumber head, TValueNumber arg |
callPartialValueNumber(call, index, pragma[only_bind_out](head)) and
callArgValueNumber(call, index, pragma[only_bind_into](arg)) and
vn = TArgument(head, arg)
)
or
not exists(int n | callArgRank(call, n, _)) and
index = -1 and
vn = TNilArgument()
}
private predicate callPartialValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber head
) {
exists(call) and
index = 1 and
head = TNilArgument()
or
exists(TCallPartialValueNumber prev, TValueNumber prevVN |
callPartialValueNumber(call, index - 1, pragma[only_bind_out](prev)) and
callArgValueNumber(call, index - 1, pragma[only_bind_into](prevVN)) and
head = TArgument(prev, prevVN)
)
}
/**
*/
private predicate callArgValueNumber(NumberableCallInstruction call, int index, TValueNumber arg) {
exists(Instruction instr |
callArgRank(call, index, instr) and
arg = tvalueNumber(instr)
)
}
/**
* Holds if `arg` is the `index`th element in `call`'s extended argument list, including the `this`
* argument and side-effect reads.
*/
private predicate callArgRank(NumberableCallInstruction call, int index, Instruction arg) {
arg =
rank[index](int argIndex, boolean isEffect, Instruction instr |
// There is no need to include the call's read and write side effects on
// all-aliased-memory as `NumberableCallInstruction`s do not read or write
// to all-aliased-memory.
instr = call.getArgument(argIndex) and
isEffect = false
or
exists(ReadSideEffectInstruction read |
read.getPrimaryInstruction() = call and
read.getSideEffectOperand().getAnyDef() = instr and
read.getIndex() = argIndex and
isEffect = true
)
|
instr order by argIndex, isEffect
)
}
/**
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
* operand.
@@ -177,8 +93,6 @@ private predicate numberableInstruction(Instruction instr) {
instr instanceof CongruentCopyInstruction
or
instr instanceof LoadTotalOverlapInstruction
or
instr instanceof NumberableCallInstruction
}
private predicate filteredNumberableInstruction(Instruction instr) {
@@ -395,11 +309,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
or
// The value number of a copy is just the value number of its source value.
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
or
exists(TCallPartialValueNumber pvn |
callValueNumber(instr, _, pvn) and
result = TCallValueNumber(pvn)
)
)
)
}

View File

@@ -1501,7 +1501,7 @@ class TranslatedBlockAssignExpr extends TranslatedNonConstantExpr {
}
final override Instruction getFirstInstruction() {
// The operand evaluation order should not matter since block assignments behave like memcpy.
// The operand evaluation order should since block assignments behave like memcpy.
result = this.getLeftOperand().getFirstInstruction()
}

View File

@@ -22,7 +22,7 @@ module InstructionConsistency {
abstract Language::Location getLocation();
}
class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
private IRFunction irFunc;
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
@@ -37,8 +37,6 @@ module InstructionConsistency {
result =
min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString())
}
IRFunction getIRFunction() { result = irFunc }
}
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {

View File

@@ -1712,11 +1712,6 @@ class SideEffectInstruction extends Instruction {
*/
class CallSideEffectInstruction extends SideEffectInstruction {
CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect }
/** Gets the operand for the value that will be read by this instruction */
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
}
/**
@@ -1728,11 +1723,6 @@ class CallSideEffectInstruction extends SideEffectInstruction {
*/
class CallReadSideEffectInstruction extends SideEffectInstruction {
CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect }
/** Gets the operand for the value that will be read by this instruction */
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
}
/**

View File

@@ -1,4 +1,3 @@
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.cpp.models.interfaces.SideEffect as SideEffect

View File

@@ -41,92 +41,8 @@ newtype TValueNumber =
) {
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
} or
TCallValueNumber(TCallPartialValueNumber vn) { callValueNumber(_, _, vn) } or
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
private class NumberableCallInstruction extends CallInstruction {
NumberableCallInstruction() {
not this.getResultIRType() instanceof IRVoidType and
exists(SideEffect::SideEffectFunction sideEffectFunc |
sideEffectFunc = this.getStaticCallTarget()
|
sideEffectFunc.hasOnlySpecificReadSideEffects() and
sideEffectFunc.hasOnlySpecificWriteSideEffects()
)
}
}
private newtype TCallPartialValueNumber =
TNilArgument() or
TArgument(TCallPartialValueNumber head, TValueNumber arg) {
exists(NumberableCallInstruction call, int index |
callArgValueNumber(call, index, arg) and
callPartialValueNumber(call, index, head)
)
}
private predicate callValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber vn
) {
index = max(int n | callArgRank(call, n, _) | n) and
exists(TCallPartialValueNumber head, TValueNumber arg |
callPartialValueNumber(call, index, pragma[only_bind_out](head)) and
callArgValueNumber(call, index, pragma[only_bind_into](arg)) and
vn = TArgument(head, arg)
)
or
not exists(int n | callArgRank(call, n, _)) and
index = -1 and
vn = TNilArgument()
}
private predicate callPartialValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber head
) {
exists(call) and
index = 1 and
head = TNilArgument()
or
exists(TCallPartialValueNumber prev, TValueNumber prevVN |
callPartialValueNumber(call, index - 1, pragma[only_bind_out](prev)) and
callArgValueNumber(call, index - 1, pragma[only_bind_into](prevVN)) and
head = TArgument(prev, prevVN)
)
}
/**
*/
private predicate callArgValueNumber(NumberableCallInstruction call, int index, TValueNumber arg) {
exists(Instruction instr |
callArgRank(call, index, instr) and
arg = tvalueNumber(instr)
)
}
/**
* Holds if `arg` is the `index`th element in `call`'s extended argument list, including the `this`
* argument and side-effect reads.
*/
private predicate callArgRank(NumberableCallInstruction call, int index, Instruction arg) {
arg =
rank[index](int argIndex, boolean isEffect, Instruction instr |
// There is no need to include the call's read and write side effects on
// all-aliased-memory as `NumberableCallInstruction`s do not read or write
// to all-aliased-memory.
instr = call.getArgument(argIndex) and
isEffect = false
or
exists(ReadSideEffectInstruction read |
read.getPrimaryInstruction() = call and
read.getSideEffectOperand().getAnyDef() = instr and
read.getIndex() = argIndex and
isEffect = true
)
|
instr order by argIndex, isEffect
)
}
/**
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
* operand.
@@ -177,8 +93,6 @@ private predicate numberableInstruction(Instruction instr) {
instr instanceof CongruentCopyInstruction
or
instr instanceof LoadTotalOverlapInstruction
or
instr instanceof NumberableCallInstruction
}
private predicate filteredNumberableInstruction(Instruction instr) {
@@ -395,11 +309,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
or
// The value number of a copy is just the value number of its source value.
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
or
exists(TCallPartialValueNumber pvn |
callValueNumber(instr, _, pvn) and
result = TCallValueNumber(pvn)
)
)
)
}

View File

@@ -5,9 +5,14 @@ private import Imports::OperandTag
private import Imports::Overlap
private import Imports::TInstruction
private import Imports::RawIR as RawIR
private import SsaInstructions
private import SsaOperands
private import SSAInstructions
private import SSAOperands
private import NewIR
private class OldBlock = Reachability::ReachableBlock;
private class OldInstruction = Reachability::ReachableInstruction;
import Cached
cached
@@ -53,9 +58,7 @@ private module Cached {
cached
predicate hasInstruction(TStageInstruction instr) {
instr instanceof TRawInstruction and
instr instanceof OldInstruction and
not removedInstruction(instr)
instr instanceof TRawInstruction and instr instanceof OldInstruction
or
instr = phiInstruction(_, _)
or
@@ -379,14 +382,7 @@ private module Cached {
(
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
else
if removedInstruction(oldInstruction.getSuccessor(kind))
then
// the only removed nodes are side-effect writes, but those may have Chi nodes
// skip to the following instruction in the old IR, which won't be removed
// if we start skipping specific side effects, this may no longer hold
result = getNewInstruction(oldInstruction.getSuccessor(kind).getSuccessor(kind))
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
or

View File

@@ -3,20 +3,7 @@ import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBloc
import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as RawStage
import semmle.code.cpp.ir.implementation.internal.TInstruction::UnaliasedSsaInstructions as SsaInstructions
/** DEPRECATED: Alias for SsaInstructions */
deprecated module SSAInstructions = SsaInstructions;
import semmle.code.cpp.ir.implementation.internal.TInstruction::UnaliasedSsaInstructions as SSAInstructions
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import SimpleSSA as Alias
import semmle.code.cpp.ir.implementation.internal.TOperand::UnaliasedSsaOperands as SsaOperands
/** DEPRECATED: Alias for SsaOperands */
deprecated module SSAOperands = SsaOperands;
predicate removedInstruction(Reachability::ReachableInstruction instr) { none() }
class OldBlock = Reachability::ReachableBlock;
class OldInstruction = Reachability::ReachableInstruction;
import semmle.code.cpp.ir.implementation.internal.TOperand::UnaliasedSsaOperands as SSAOperands

View File

@@ -11,6 +11,12 @@ private class StdPair extends ClassTemplateInstantiation {
StdPair() { this.hasQualifiedName(["std", "bsl"], "pair") }
}
/**
* DEPRECATED: This is now called `StdPair` and is a private part of the
* library implementation.
*/
deprecated class StdPairClass = StdPair;
/**
* Any of the single-parameter constructors of `std::pair` that takes a reference to an
* instantiation of `std::pair`. These constructors allow conversion between pair types when the

View File

@@ -27,6 +27,13 @@ abstract class RemoteFlowSourceFunction extends Function {
predicate hasSocketInput(FunctionInput input) { none() }
}
/**
* DEPRECATED: Use `RemoteFlowSourceFunction` instead.
*
* A library function that returns data that may be read from a network connection.
*/
deprecated class RemoteFlowFunction = RemoteFlowSourceFunction;
/**
* A library function that returns data that is directly controlled by a user.
*/
@@ -37,6 +44,13 @@ abstract class LocalFlowSourceFunction extends Function {
abstract predicate hasLocalFlowSource(FunctionOutput output, string description);
}
/**
* DEPRECATED: Use `LocalFlowSourceFunction` instead.
*
* A library function that returns data that is directly controlled by a user.
*/
deprecated class LocalFlowFunction = LocalFlowSourceFunction;
/** A library function that sends data over a network connection. */
abstract class RemoteFlowSinkFunction extends Function {
/**

View File

@@ -523,11 +523,6 @@ autoderivation(
int derivation_type: @type ref
);
orphaned_variables(
int var: @localvariable ref,
int function: @function ref
)
enumconstants(
unique int id: @enumconstant,
int parent: @usertype ref,

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +0,0 @@
description: Add relation for orphaned local variables
compatibility: partial

View File

@@ -29,4 +29,7 @@ where
n = strictcount(ComplexStmt s | s = b.getAStmt()) and
n > 3 and
complexStmt = b.getAStmt()
select b, "Block with too many statements (" + n.toString() + " complex statements in the block)."
select b,
"Block with too many statements (" + n.toString() +
" complex statements in the block). Complex statements at: $@", complexStmt,
complexStmt.toString()

View File

@@ -110,4 +110,4 @@ where
emptyBlock(s, eb) and
not emptyBlockContainsNonchild(eb) and
not lineComment(eb)
select eb, "Empty block without comment."
select eb, "Empty block without comment"

View File

@@ -1,9 +1,3 @@
## 0.3.2
### Minor Analysis Improvements
* The query `cpp/bad-strncpy-size` now covers more `strncpy`-like functions than before, including `strxfrm`(`_l`), `wcsxfrm`(`_l`), and `stpncpy`. Users of this query may see an increase in results.
## 0.3.1
## 0.3.0

View File

@@ -12,4 +12,4 @@
import CommentedOutCode
from CommentedOutCode comment
select comment, "This comment appears to contain commented-out code."
select comment, "This comment appears to contain commented-out code"

View File

@@ -1,6 +1,7 @@
/**
* @name Sign check of bitwise operation
* @description Checking the sign of the result of a bitwise operation may yield unexpected results.
* @description Checking the sign of a bitwise operation often has surprising
* edge cases.
* @kind problem
* @problem.severity warning
* @precision high
@@ -25,4 +26,4 @@ where
forall(int op | op = lhs.(BitwiseAndExpr).getAnOperand().getValue().toInt() | op < 0) and
// exception for cases involving macros
not e.isAffectedByMacro()
select e, "Potentially unsafe sign check of a bitwise operation."
select e, "Potential unsafe sign check of a bitwise operation."

View File

@@ -21,4 +21,4 @@ where
FloatingPointType and
not ro.getAnOperand().isConstant() and // comparisons to constants generate too many false positives
not left.(VariableAccess).getTarget() = right.(VariableAccess).getTarget() // skip self comparison
select ro, "Equality checks on floating point values can yield unexpected results."
select ro, "Equality test on floating point values may not behave as expected."

View File

@@ -13,11 +13,10 @@
import cpp
from EnumSwitch es, float missing, float total, EnumConstant case
from EnumSwitch es, float missing, float total
where
not es.hasDefaultCase() and
missing = count(es.getAMissingCase()) and
total = missing + count(es.getASwitchCase()) and
missing / total < 0.3 and
case = es.getAMissingCase()
select es, "Switch statement does not have a case for $@.", case, case.getName()
missing / total < 0.3
select es, "Switch statement is missing case for " + es.getAMissingCase().getName()

View File

@@ -106,26 +106,6 @@ predicate inheritanceConversionTypes(
toType = convert.getResultType()
}
private signature class ConversionInstruction extends UnaryInstruction;
module Conversion<ConversionInstruction I> {
signature predicate hasTypes(I instr, Type fromType, Type toType);
module Using<hasTypes/3 project> {
pragma[nomagic]
predicate hasOperandAndTypes(I convert, Instruction unary, Type fromType, Type toType) {
project(convert, fromType, toType) and
unary = convert.getUnary()
}
}
}
pragma[nomagic]
predicate hasObjectAndField(FieldAddressInstruction fai, Instruction object, Field f) {
fai.getObjectAddress() = object and
fai.getField() = f
}
/** Gets the HashCons value of an address computed by `instr`, if any. */
TGlobalAddress globalAddress(Instruction instr) {
result = TGlobalVariable(instr.(VariableAddressInstruction).getAstVariable())
@@ -137,27 +117,25 @@ TGlobalAddress globalAddress(Instruction instr) {
result = TLoad(globalAddress(load.getSourceAddress()))
)
or
exists(Type fromType, Type toType, Instruction unary |
Conversion<ConvertInstruction>::Using<uncheckedConversionTypes/3>::hasOperandAndTypes(instr,
unary, fromType, toType) and
result = TConversion("unchecked", globalAddress(unary), fromType, toType)
exists(ConvertInstruction convert, Type fromType, Type toType | instr = convert |
uncheckedConversionTypes(convert, fromType, toType) and
result = TConversion("unchecked", globalAddress(convert.getUnary()), fromType, toType)
)
or
exists(Type fromType, Type toType, Instruction unary |
Conversion<CheckedConvertOrNullInstruction>::Using<checkedConversionTypes/3>::hasOperandAndTypes(instr,
unary, fromType, toType) and
result = TConversion("checked", globalAddress(unary), fromType, toType)
exists(CheckedConvertOrNullInstruction convert, Type fromType, Type toType | instr = convert |
checkedConversionTypes(convert, fromType, toType) and
result = TConversion("checked", globalAddress(convert.getUnary()), fromType, toType)
)
or
exists(Type fromType, Type toType, Instruction unary |
Conversion<InheritanceConversionInstruction>::Using<inheritanceConversionTypes/3>::hasOperandAndTypes(instr,
unary, fromType, toType) and
result = TConversion("inheritance", globalAddress(unary), fromType, toType)
exists(InheritanceConversionInstruction convert, Type fromType, Type toType | instr = convert |
inheritanceConversionTypes(convert, fromType, toType) and
result = TConversion("inheritance", globalAddress(convert.getUnary()), fromType, toType)
)
or
exists(FieldAddressInstruction fai, Instruction object, Field f | instr = fai |
hasObjectAndField(fai, object, f) and
result = TFieldAddress(globalAddress(object), f)
exists(FieldAddressInstruction fai | instr = fai |
result =
TFieldAddress(globalAddress(pragma[only_bind_into](fai.getObjectAddress())),
pragma[only_bind_out](fai.getField()))
)
or
result = globalAddress(instr.(PointerOffsetInstruction).getLeft())
@@ -290,11 +268,7 @@ class PathElement extends TPathElement {
predicate isSink(IRBlock block) { exists(this.asSink(block)) }
string toString() {
result =
[
this.asStore().toString(), this.asCall(_).toString(), this.asMid().toString(),
this.asSink(_).toString()
]
result = [asStore().toString(), asCall(_).toString(), asMid().toString(), asSink(_).toString()]
}
predicate hasLocationInfo(

View File

@@ -30,7 +30,7 @@ Make sure that all classes with virtual functions also have a virtual destructor
S. Meyers. <em>Effective C++ 3d ed.</em> pp 40-44. Addison-Wesley Professional, 2005.
</li>
<li>
<a href="https://devblogs.microsoft.com/oldnewthing/20040507-00/?p=39443">When should your destructor be virtual?</a>
<a href="http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspx">When should your destructor be virtual?</a>
</li>

View File

@@ -10,12 +10,6 @@ import cpp
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
import semmle.code.cpp.ir.implementation.aliased_ssa.IRConsistency as IRConsistency
class PresentIRFunction extends IRConsistency::PresentIRFunction {
override string toString() {
result = min(string name | name = this.getIRFunction().getFunction().getQualifiedName() | name)
}
}
select count(Instruction i | IRConsistency::missingOperand(i, _, _, _) | i) as missingOperand,
count(Instruction i | IRConsistency::unexpectedOperand(i, _, _, _) | i) as unexpectedOperand,
count(Instruction i | IRConsistency::duplicateOperand(i, _, _, _) | i) as duplicateOperand,

View File

@@ -21,9 +21,7 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode {
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
/** An external API which is used with untrusted data. */
private newtype TExternalApi =
/** An untrusted API method `m` where untrusted data is passed at `index`. */
TExternalApiParameter(Function f, int index) {
exists(UntrustedExternalApiDataNode n |
f = n.getExternalFunction() and

View File

@@ -21,9 +21,7 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode {
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
/** An external API which is used with untrusted data. */
private newtype TExternalApi =
/** An untrusted API method `m` where untrusted data is passed at `index`. */
TExternalApiParameter(Function f, int index) {
exists(UntrustedExternalApiDataNode n |
f = n.getExternalFunction() and

View File

@@ -19,7 +19,6 @@ import semmle.code.cpp.security.Security
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.ir.dataflow.TaintTracking2
import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.models.implementations.Strcat
import DataFlow::PathGraph
@@ -84,32 +83,6 @@ class ExecState extends DataFlow::FlowState {
DataFlow::Node getFstNode() { result = fst }
DataFlow::Node getSndNode() { result = snd }
/** Holds if this is a possible `ExecState` for `sink`. */
predicate isFeasibleForSink(DataFlow::Node sink) {
any(ExecStateConfiguration conf).hasFlow(snd, sink)
}
}
/**
* A `TaintTracking` configuration that's used to find the relevant `ExecState`s for a
* given sink. This avoids a cartesian product between all sinks and all `ExecState`s in
* `ExecTaintConfiguration::isSink`.
*/
class ExecStateConfiguration extends TaintTracking2::Configuration {
ExecStateConfiguration() { this = "ExecStateConfiguration" }
override predicate isSource(DataFlow::Node source) {
exists(ExecState state | state.getSndNode() = source)
}
override predicate isSink(DataFlow::Node sink) {
shellCommand(sinkAsArgumentIndirection(sink), _)
}
override predicate isSanitizerOut(DataFlow::Node node) {
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
}
}
class ExecTaintConfiguration extends TaintTracking::Configuration {
@@ -121,8 +94,8 @@ class ExecTaintConfiguration extends TaintTracking::Configuration {
}
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
any(ExecStateConfiguration conf).isSink(sink) and
state.(ExecState).isFeasibleForSink(sink)
shellCommand(sinkAsArgumentIndirection(sink), _) and
state instanceof ExecState
}
override predicate isAdditionalTaintStep(

View File

@@ -17,8 +17,8 @@ import semmle.code.cpp.dataflow.DataFlow
/**
* A call to `SSL_get_verify_result`.
*/
class SslGetVerifyResultCall extends FunctionCall {
SslGetVerifyResultCall() { getTarget().getName() = "SSL_get_verify_result" }
class SSLGetVerifyResultCall extends FunctionCall {
SSLGetVerifyResultCall() { getTarget().getName() = "SSL_get_verify_result" }
}
/**
@@ -29,7 +29,7 @@ class VerifyResultConfig extends DataFlow::Configuration {
VerifyResultConfig() { this = "VerifyResultConfig" }
override predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof SslGetVerifyResultCall
source.asExpr() instanceof SSLGetVerifyResultCall
}
override predicate isSink(DataFlow::Node sink) {

View File

@@ -17,33 +17,33 @@ import semmle.code.cpp.controlflow.IRGuards
/**
* A call to `SSL_get_peer_certificate`.
*/
class SslGetPeerCertificateCall extends FunctionCall {
SslGetPeerCertificateCall() {
class SSLGetPeerCertificateCall extends FunctionCall {
SSLGetPeerCertificateCall() {
getTarget().getName() = "SSL_get_peer_certificate" // SSL_get_peer_certificate(ssl)
}
Expr getSslArgument() { result = getArgument(0) }
Expr getSSLArgument() { result = getArgument(0) }
}
/**
* A call to `SSL_get_verify_result`.
*/
class SslGetVerifyResultCall extends FunctionCall {
SslGetVerifyResultCall() {
class SSLGetVerifyResultCall extends FunctionCall {
SSLGetVerifyResultCall() {
getTarget().getName() = "SSL_get_verify_result" // SSL_get_peer_certificate(ssl)
}
Expr getSslArgument() { result = getArgument(0) }
Expr getSSLArgument() { result = getArgument(0) }
}
/**
* Holds if the SSL object passed into `SSL_get_peer_certificate` is checked with
* `SSL_get_verify_result` entering `node`.
*/
predicate resultIsChecked(SslGetPeerCertificateCall getCertCall, ControlFlowNode node) {
exists(Expr ssl, SslGetVerifyResultCall check |
ssl = globalValueNumber(getCertCall.getSslArgument()).getAnExpr() and
ssl = check.getSslArgument() and
predicate resultIsChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node) {
exists(Expr ssl, SSLGetVerifyResultCall check |
ssl = globalValueNumber(getCertCall.getSSLArgument()).getAnExpr() and
ssl = check.getSSLArgument() and
node = check
)
}
@@ -53,7 +53,7 @@ predicate resultIsChecked(SslGetPeerCertificateCall getCertCall, ControlFlowNode
* `0` on the edge `node1` to `node2`.
*/
predicate certIsZero(
SslGetPeerCertificateCall getCertCall, ControlFlowNode node1, ControlFlowNode node2
SSLGetPeerCertificateCall getCertCall, ControlFlowNode node1, ControlFlowNode node2
) {
exists(Expr cert | cert = globalValueNumber(getCertCall).getAnExpr() |
exists(GuardCondition guard, Expr zero |
@@ -87,7 +87,7 @@ predicate certIsZero(
* `SSL_get_verify_result` at `node`. Note that this is only computed at the call to
* `SSL_get_peer_certificate` and at the start and end of `BasicBlock`s.
*/
predicate certNotChecked(SslGetPeerCertificateCall getCertCall, ControlFlowNode node) {
predicate certNotChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node) {
// cert is not checked at the call to `SSL_get_peer_certificate`
node = getCertCall
or
@@ -112,7 +112,7 @@ predicate certNotChecked(SslGetPeerCertificateCall getCertCall, ControlFlowNode
)
}
from SslGetPeerCertificateCall getCertCall, ControlFlowNode node
from SSLGetPeerCertificateCall getCertCall, ControlFlowNode node
where
certNotChecked(getCertCall, node) and
node instanceof Function // (function exit)

View File

@@ -26,10 +26,6 @@ class ToBufferConfiguration extends TaintTracking::Configuration {
override predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
override predicate isSanitizer(DataFlow::Node node) {
node.asExpr().getUnspecifiedType() instanceof IntegralType
}
override predicate isSink(DataFlow::Node sink) {
exists(BufferWrite::BufferWrite w | w.getASource() = sink.asExpr())
}

View File

@@ -47,17 +47,14 @@ class EnvData extends SystemData {
/**
* Data originating from a call to `mysql_get_client_info()`.
*/
class SqlClientInfo extends SystemData {
SqlClientInfo() { this.(FunctionCall).getTarget().hasName("mysql_get_client_info") }
class SQLClientInfo extends SystemData {
SQLClientInfo() { this.(FunctionCall).getTarget().hasName("mysql_get_client_info") }
override DataFlow::Node getAnExpr() { result.asConvertedExpr() = this }
override predicate isSensitive() { any() }
}
/** DEPRECATED: Alias for SqlClientInfo */
deprecated class SQLClientInfo = SqlClientInfo;
private predicate sqlConnectInfo(FunctionCall source, Expr use) {
(
source.getTarget().hasName("mysql_connect") or
@@ -69,17 +66,14 @@ private predicate sqlConnectInfo(FunctionCall source, Expr use) {
/**
* Data passed into an SQL connect function.
*/
class SqlConnectInfo extends SystemData {
SqlConnectInfo() { sqlConnectInfo(this, _) }
class SQLConnectInfo extends SystemData {
SQLConnectInfo() { sqlConnectInfo(this, _) }
override DataFlow::Node getAnExpr() { sqlConnectInfo(this, result.asConvertedExpr()) }
override predicate isSensitive() { any() }
}
/** DEPRECATED: Alias for SqlConnectInfo */
deprecated class SQLConnectInfo = SqlConnectInfo;
private predicate posixSystemInfo(FunctionCall source, DataFlow::Node use) {
// size_t confstr(int name, char *buf, size_t len)
// - various OS / system strings, such as the libc version

View File

@@ -1,5 +1,4 @@
## 0.3.2
### Minor Analysis Improvements
---
category: minorAnalysis
---
* The query `cpp/bad-strncpy-size` now covers more `strncpy`-like functions than before, including `strxfrm`(`_l`), `wcsxfrm`(`_l`), and `stpncpy`. Users of this query may see an increase in results.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The "Cleartext storage of sensitive information in buffer" (`cpp/cleartext-storage-buffer`) query has been improved to produce fewer false positives.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The alert message of many queries have been changed to make the message consistent with other languages.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.3.2
lastReleaseVersion: 0.3.1

View File

@@ -67,7 +67,7 @@ predicate findUseCharacterConversion(Expr exp, string msg) {
exists(FunctionCall fc |
fc = exp and
(
fc.getEnclosingStmt().getParentStmt*() instanceof Loop and
exists(Loop lptmp | lptmp = fc.getEnclosingStmt().getParentStmt*()) and
fc.getTarget().hasName(["mbtowc", "mbrtowc", "_mbtowc_l"]) and
not fc.getArgument(0).isConstant() and
not fc.getArgument(1).isConstant() and

View File

@@ -44,8 +44,11 @@ predicate conversionDoneLate(MulExpr mexp) {
mexp.getEnclosingElement().(ComparisonOperation).hasOperands(mexp, e0) and
e0.getType().getSize() = mexp.getConversion().getConversion().getType().getSize()
or
e0.(FunctionCall).getTarget().getParameter(argumentPosition(e0, mexp, _)).getType().getSize() =
mexp.getConversion().getConversion().getType().getSize()
e0.(FunctionCall)
.getTarget()
.getParameter(argumentPosition(e0.(FunctionCall), mexp, _))
.getType()
.getSize() = mexp.getConversion().getConversion().getType().getSize()
)
)
}
@@ -72,7 +75,7 @@ predicate signSmallerWithEqualSizes(MulExpr mexp) {
ae.getRValue().getUnderlyingType().(IntegralType).isUnsigned() and
ae.getLValue().getUnderlyingType().(IntegralType).isSigned() and
(
not mexp.getParent*() instanceof DivExpr
not exists(DivExpr de | mexp.getParent*() = de)
or
exists(DivExpr de, Expr ec |
e2.isConstant() and

View File

@@ -33,7 +33,7 @@ Make sure that all classes with virtual functions also have a virtual destructor
S. Meyers. <em>Effective C++ 3d ed.</em> pp 40-44. Addison-Wesley Professional, 2005.
</li>
<li>
<a href="https://devblogs.microsoft.com/oldnewthing/20040507-00/?p=39443">When should your destructor be virtual?</a>
<a href="http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspx">When should your destructor be virtual?</a>
</li>

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 0.3.3-dev
version: 0.3.2-dev
groups:
- cpp
- queries

View File

@@ -330,19 +330,6 @@ abstract private class Expectation extends FailureLocatable {
override Location getLocation() { result = comment.getLocation() }
}
private predicate onSameLine(ValidExpectation a, ActualResult b) {
exists(string fname, int line, Location la, Location lb |
// Join order intent:
// Take the locations of ActualResults,
// join with locations in the same file / on the same line,
// then match those against ValidExpectations.
la = a.getLocation() and
pragma[only_bind_into](lb) = b.getLocation() and
pragma[only_bind_into](la).hasLocationInfo(fname, line, _, _, _) and
lb.hasLocationInfo(fname, line, _, _, _)
)
}
private class ValidExpectation extends Expectation, TValidExpectation {
string tag;
string value;
@@ -357,7 +344,8 @@ private class ValidExpectation extends Expectation, TValidExpectation {
string getKnownFailure() { result = knownFailure }
predicate matchesActualResult(ActualResult actualResult) {
onSameLine(pragma[only_bind_into](this), actualResult) and
getLocation().getStartLine() = actualResult.getLocation().getStartLine() and
getLocation().getFile() = actualResult.getLocation().getFile() and
getTag() = actualResult.getTag() and
getValue() = actualResult.getValue()
}

View File

@@ -13,7 +13,7 @@
import cpp
private import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as IRDataFlow
private import semmle.code.cpp.dataflow.DataFlow::DataFlow as AstDataFlow
private import semmle.code.cpp.dataflow.DataFlow::DataFlow as ASTDataFlow
import TestUtilities.InlineExpectationsTest
class IRFlowTest extends InlineExpectationsTest {
@@ -49,11 +49,11 @@ class AstFlowTest extends InlineExpectationsTest {
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(
AstDataFlow::Node source, AstDataFlow::Node sink, AstDataFlow::Configuration conf, int n
ASTDataFlow::Node source, ASTDataFlow::Node sink, ASTDataFlow::Configuration conf, int n
|
tag = "ast" and
conf.hasFlow(source, sink) and
n = strictcount(AstDataFlow::Node otherSource | conf.hasFlow(otherSource, sink)) and
n = strictcount(ASTDataFlow::Node otherSource | conf.hasFlow(otherSource, sink)) and
(
n = 1 and value = ""
or

View File

@@ -4,7 +4,7 @@
*/
import cpp
import semmle.code.cpp.security.TaintTrackingImpl as AstTaintTracking
import semmle.code.cpp.security.TaintTrackingImpl as ASTTaintTracking
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
import IRDefaultTaintTracking::TaintedWithPath as TaintedWithPath
import TaintedWithPath::Private
@@ -17,7 +17,7 @@ predicate isSinkArgument(Element sink) {
)
}
predicate astTaint(Expr source, Element sink) { AstTaintTracking::tainted(source, sink) }
predicate astTaint(Expr source, Element sink) { ASTTaintTracking::tainted(source, sink) }
class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration {
override predicate isSink(Element e) { isSinkArgument(e) }

View File

@@ -5,7 +5,7 @@
*/
import cpp
import semmle.code.cpp.security.TaintTrackingImpl as AstTaintTracking
import semmle.code.cpp.security.TaintTrackingImpl as ASTTaintTracking
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
import IRDefaultTaintTracking::TaintedWithPath as TaintedWithPath
import TestUtilities.InlineExpectationsTest
@@ -18,7 +18,7 @@ predicate argToSinkCall(Element sink) {
}
predicate astTaint(Expr source, Element sink) {
AstTaintTracking::tainted(source, sink) and argToSinkCall(sink)
ASTTaintTracking::tainted(source, sink) and argToSinkCall(sink)
}
class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration {

View File

@@ -1,11 +1,11 @@
import cpp
import semmle.code.cpp.security.Security
import semmle.code.cpp.security.TaintTrackingImpl as AstTaintTracking
import semmle.code.cpp.security.TaintTrackingImpl as ASTTaintTracking
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
import TestUtilities.InlineExpectationsTest
predicate astTaint(Expr source, Element sink, string globalVar) {
AstTaintTracking::taintedIncludingGlobalVars(source, sink, globalVar) and globalVar != ""
ASTTaintTracking::taintedIncludingGlobalVars(source, sink, globalVar) and globalVar != ""
}
predicate irTaint(Expr source, Element sink, string globalVar) {

View File

@@ -7,7 +7,7 @@ string describe(File f) {
f.compiledAsCpp() and
result = "C++"
or
f instanceof XmlParent and
f instanceof XMLParent and
result = "XMLParent" // regression tests a bug in the characteristic predicate of XMLParent
}

View File

@@ -14137,30 +14137,6 @@ ir.cpp:
# 1845| Type = [Struct] B
# 1845| ValueCategory = lvalue
# 1846| getStmt(2): [ReturnStmt] return ...
# 1849| [TopLevelFunction] void magicvars()
# 1849| <params>:
# 1849| getEntryPoint(): [BlockStmt] { ... }
# 1850| getStmt(0): [DeclStmt] declaration
# 1850| getDeclarationEntry(0): [VariableDeclarationEntry] definition of pf
# 1850| Type = [PointerType] const char *
# 1850| getVariable().getInitializer(): [Initializer] initializer for pf
# 1850| getExpr(): [VariableAccess] __PRETTY_FUNCTION__
# 1850| Type = [ArrayType] const char[17]
# 1850| ValueCategory = lvalue
# 1850| getExpr().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
# 1850| Type = [PointerType] const char *
# 1850| ValueCategory = prvalue
# 1851| getStmt(1): [DeclStmt] declaration
# 1851| getDeclarationEntry(0): [VariableDeclarationEntry] definition of strfunc
# 1851| Type = [PointerType] const char *
# 1851| getVariable().getInitializer(): [Initializer] initializer for strfunc
# 1851| getExpr(): [VariableAccess] __func__
# 1851| Type = [ArrayType] const char[10]
# 1851| ValueCategory = lvalue
# 1851| getExpr().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
# 1851| Type = [PointerType] const char *
# 1851| ValueCategory = prvalue
# 1852| getStmt(2): [ReturnStmt] return ...
perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| <params>:

View File

@@ -1846,9 +1846,4 @@ namespace block_assignment {
}
}
void magicvars() {
const char *pf = __PRETTY_FUNCTION__;
const char *strfunc = __func__;
}
// semmle-extractor-options: -std=c++17 --clang

File diff suppressed because it is too large Load Diff

View File

@@ -9914,24 +9914,6 @@ ir.cpp:
# 1843| v1843_5(void) = AliasedUse : ~m?
# 1843| v1843_6(void) = ExitFunction :
# 1849| void magicvars()
# 1849| Block 0
# 1849| v1849_1(void) = EnterFunction :
# 1849| mu1849_2(unknown) = AliasedDefinition :
# 1849| mu1849_3(unknown) = InitializeNonLocal :
# 1850| r1850_1(glval<char *>) = VariableAddress[pf] :
# 1850| r1850_2(glval<char[17]>) = VariableAddress[__PRETTY_FUNCTION__] :
# 1850| r1850_3(char *) = Convert : r1850_2
# 1850| mu1850_4(char *) = Store[pf] : &:r1850_1, r1850_3
# 1851| r1851_1(glval<char *>) = VariableAddress[strfunc] :
# 1851| r1851_2(glval<char[10]>) = VariableAddress[__func__] :
# 1851| r1851_3(char *) = Convert : r1851_2
# 1851| mu1851_4(char *) = Store[strfunc] : &:r1851_1, r1851_3
# 1852| v1852_1(void) = NoOp :
# 1849| v1849_4(void) = ReturnVoid :
# 1849| v1849_5(void) = AliasedUse : ~m?
# 1849| v1849_6(void) = ExitFunction :
perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0

View File

@@ -1,7 +1,6 @@
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.ir.IR as IR
import TestUtilities.InlineExpectationsTest
@@ -38,13 +37,8 @@ private string getBoundString(SemBound b, int delta) {
b instanceof SemZeroBound and result = delta.toString()
or
result =
strictconcat(b.(SemSsaBound)
.getAVariable()
.(SemanticExprConfig::SsaVariable)
.asInstruction()
.getAst()
.toString(), ":"
) + getOffsetString(delta)
strictconcat(b.(SemSsaBound).getAVariable().(IR::Instruction).getAst().toString(), ":") +
getOffsetString(delta)
}
private string getARangeString(SemExpr e) {

View File

@@ -1050,36 +1050,46 @@ ssa.cpp:
# 240| r240_3(glval<unknown>) = FunctionAddress[Constructible] :
# 240| r240_4(int) = Constant[1] :
# 240| v240_5(void) = Call[Constructible] : func:r240_3, this:r240_1, 0:r240_4
# 240| m240_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r240_1
# 240| m240_7(Constructible) = Chi : total:m240_2, partial:m240_6
# 240| m240_6(unknown) = ^CallSideEffect : ~m239_4
# 240| m240_7(unknown) = Chi : total:m239_4, partial:m240_6
# 240| m240_8(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r240_1
# 240| m240_9(Constructible) = Chi : total:m240_2, partial:m240_8
# 241| r241_1(glval<Constructible>) = VariableAddress[c] :
# 241| r241_2(glval<unknown>) = FunctionAddress[g] :
# 241| v241_3(void) = Call[g] : func:r241_2, this:r241_1
# 241| v241_4(void) = ^IndirectReadSideEffect[-1] : &:r241_1, m240_7
# 241| m241_5(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r241_1
# 241| m241_6(Constructible) = Chi : total:m240_7, partial:m241_5
# 241| m241_4(unknown) = ^CallSideEffect : ~m240_7
# 241| m241_5(unknown) = Chi : total:m240_7, partial:m241_4
# 241| v241_6(void) = ^IndirectReadSideEffect[-1] : &:r241_1, m240_9
# 241| m241_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r241_1
# 241| m241_8(Constructible) = Chi : total:m240_9, partial:m241_7
# 242| r242_1(glval<Constructible>) = VariableAddress[c] :
# 242| r242_2(glval<unknown>) = FunctionAddress[g] :
# 242| v242_3(void) = Call[g] : func:r242_2, this:r242_1
# 242| v242_4(void) = ^IndirectReadSideEffect[-1] : &:r242_1, m241_6
# 242| m242_5(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r242_1
# 242| m242_6(Constructible) = Chi : total:m241_6, partial:m242_5
# 242| m242_4(unknown) = ^CallSideEffect : ~m241_5
# 242| m242_5(unknown) = Chi : total:m241_5, partial:m242_4
# 242| v242_6(void) = ^IndirectReadSideEffect[-1] : &:r242_1, m241_8
# 242| m242_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r242_1
# 242| m242_8(Constructible) = Chi : total:m241_8, partial:m242_7
# 243| r243_1(glval<Constructible>) = VariableAddress[c2] :
# 243| m243_2(Constructible) = Uninitialized[c2] : &:r243_1
# 243| r243_3(glval<unknown>) = FunctionAddress[Constructible] :
# 243| r243_4(int) = Constant[2] :
# 243| v243_5(void) = Call[Constructible] : func:r243_3, this:r243_1, 0:r243_4
# 243| m243_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r243_1
# 243| m243_7(Constructible) = Chi : total:m243_2, partial:m243_6
# 243| m243_6(unknown) = ^CallSideEffect : ~m242_5
# 243| m243_7(unknown) = Chi : total:m242_5, partial:m243_6
# 243| m243_8(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r243_1
# 243| m243_9(Constructible) = Chi : total:m243_2, partial:m243_8
# 244| r244_1(glval<Constructible>) = VariableAddress[c2] :
# 244| r244_2(glval<unknown>) = FunctionAddress[g] :
# 244| v244_3(void) = Call[g] : func:r244_2, this:r244_1
# 244| v244_4(void) = ^IndirectReadSideEffect[-1] : &:r244_1, m243_7
# 244| m244_5(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1
# 244| m244_6(Constructible) = Chi : total:m243_7, partial:m244_5
# 244| m244_4(unknown) = ^CallSideEffect : ~m243_7
# 244| m244_5(unknown) = Chi : total:m243_7, partial:m244_4
# 244| v244_6(void) = ^IndirectReadSideEffect[-1] : &:r244_1, m243_9
# 244| m244_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1
# 244| m244_8(Constructible) = Chi : total:m243_9, partial:m244_7
# 245| v245_1(void) = NoOp :
# 239| v239_5(void) = ReturnVoid :
# 239| v239_6(void) = AliasedUse : m239_3
# 239| v239_6(void) = AliasedUse : ~m244_5
# 239| v239_7(void) = ExitFunction :
# 247| char* VoidStarIndirectParameters(char*, int)
@@ -1381,37 +1391,43 @@ ssa.cpp:
# 294| r294_18(glval<int>) = VariableAddress[x] :
# 294| r294_19(int) = Load[x] : &:r294_18, m291_6
# 294| v294_20(void) = Call[A] : func:r294_17, this:r294_16, 0:r294_19
# 294| m294_21(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_16
# 294| m294_22(unknown) = Chi : total:m294_15, partial:m294_21
# 294| v294_23(void) = Call[A] : func:r294_9, this:r294_8, 0:r294_16
# 294| v294_24(void) = ^BufferReadSideEffect[0] : &:r294_16, ~m294_22
# 294| m294_25(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_8
# 294| m294_26(unknown) = Chi : total:m294_7, partial:m294_25
# 294| m294_27(unknown) = ^BufferMayWriteSideEffect[0] : &:r294_16
# 294| m294_28(unknown) = Chi : total:m294_22, partial:m294_27
# 294| r294_29(glval<int>) = FieldAddress[i] : r294_8
# 294| r294_30(int) = Load[?] : &:r294_29, ~m294_26
# 294| m294_31(int) = Store[j] : &:r294_1, r294_30
# 294| m294_21(unknown) = ^CallSideEffect : ~m294_14
# 294| m294_22(unknown) = Chi : total:m294_14, partial:m294_21
# 294| m294_23(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_16
# 294| m294_24(unknown) = Chi : total:m294_15, partial:m294_23
# 294| v294_25(void) = Call[A] : func:r294_9, this:r294_8, 0:r294_16
# 294| m294_26(unknown) = ^CallSideEffect : ~m294_22
# 294| m294_27(unknown) = Chi : total:m294_22, partial:m294_26
# 294| v294_28(void) = ^BufferReadSideEffect[0] : &:r294_16, ~m294_24
# 294| m294_29(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_8
# 294| m294_30(unknown) = Chi : total:m294_7, partial:m294_29
# 294| m294_31(unknown) = ^BufferMayWriteSideEffect[0] : &:r294_16
# 294| m294_32(unknown) = Chi : total:m294_24, partial:m294_31
# 294| r294_33(glval<int>) = FieldAddress[i] : r294_8
# 294| r294_34(int) = Load[?] : &:r294_33, ~m294_30
# 294| m294_35(int) = Store[j] : &:r294_1, r294_34
# 295| r295_1(glval<A *>) = VariableAddress[a] :
# 295| r295_2(glval<unknown>) = FunctionAddress[operator new] :
# 295| r295_3(unsigned long) = Constant[4] :
# 295| r295_4(void *) = Call[operator new] : func:r295_2, 0:r295_3
# 295| m295_5(unknown) = ^CallSideEffect : ~m294_14
# 295| m295_6(unknown) = Chi : total:m294_14, partial:m295_5
# 295| m295_5(unknown) = ^CallSideEffect : ~m294_27
# 295| m295_6(unknown) = Chi : total:m294_27, partial:m295_5
# 295| m295_7(unknown) = ^InitializeDynamicAllocation : &:r295_4
# 295| r295_8(A *) = Convert : r295_4
# 295| r295_9(glval<unknown>) = FunctionAddress[A] :
# 295| v295_10(void) = Call[A] : func:r295_9, this:r295_8
# 295| m295_11(A) = ^IndirectMayWriteSideEffect[-1] : &:r295_8
# 295| m295_12(unknown) = Chi : total:m295_7, partial:m295_11
# 295| m295_13(A *) = Store[a] : &:r295_1, r295_8
# 295| m295_11(unknown) = ^CallSideEffect : ~m295_6
# 295| m295_12(unknown) = Chi : total:m295_6, partial:m295_11
# 295| m295_13(A) = ^IndirectMayWriteSideEffect[-1] : &:r295_8
# 295| m295_14(unknown) = Chi : total:m295_7, partial:m295_13
# 295| m295_15(A *) = Store[a] : &:r295_1, r295_8
# 296| r296_1(glval<Point *>) = VariableAddress[#return] :
# 296| r296_2(glval<Point *>) = VariableAddress[p] :
# 296| r296_3(Point *) = Load[p] : &:r296_2, m292_9
# 296| m296_4(Point *) = Store[#return] : &:r296_1, r296_3
# 291| r291_7(glval<Point *>) = VariableAddress[#return] :
# 291| v291_8(void) = ReturnValue : &:r291_7, m296_4
# 291| v291_9(void) = AliasedUse : ~m295_6
# 291| v291_9(void) = AliasedUse : ~m295_12
# 291| v291_10(void) = ExitFunction :
# 301| int main(int, char**)

View File

@@ -1045,36 +1045,46 @@ ssa.cpp:
# 240| r240_3(glval<unknown>) = FunctionAddress[Constructible] :
# 240| r240_4(int) = Constant[1] :
# 240| v240_5(void) = Call[Constructible] : func:r240_3, this:r240_1, 0:r240_4
# 240| m240_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r240_1
# 240| m240_7(Constructible) = Chi : total:m240_2, partial:m240_6
# 240| m240_6(unknown) = ^CallSideEffect : ~m239_4
# 240| m240_7(unknown) = Chi : total:m239_4, partial:m240_6
# 240| m240_8(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r240_1
# 240| m240_9(Constructible) = Chi : total:m240_2, partial:m240_8
# 241| r241_1(glval<Constructible>) = VariableAddress[c] :
# 241| r241_2(glval<unknown>) = FunctionAddress[g] :
# 241| v241_3(void) = Call[g] : func:r241_2, this:r241_1
# 241| v241_4(void) = ^IndirectReadSideEffect[-1] : &:r241_1, m240_7
# 241| m241_5(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r241_1
# 241| m241_6(Constructible) = Chi : total:m240_7, partial:m241_5
# 241| m241_4(unknown) = ^CallSideEffect : ~m240_7
# 241| m241_5(unknown) = Chi : total:m240_7, partial:m241_4
# 241| v241_6(void) = ^IndirectReadSideEffect[-1] : &:r241_1, m240_9
# 241| m241_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r241_1
# 241| m241_8(Constructible) = Chi : total:m240_9, partial:m241_7
# 242| r242_1(glval<Constructible>) = VariableAddress[c] :
# 242| r242_2(glval<unknown>) = FunctionAddress[g] :
# 242| v242_3(void) = Call[g] : func:r242_2, this:r242_1
# 242| v242_4(void) = ^IndirectReadSideEffect[-1] : &:r242_1, m241_6
# 242| m242_5(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r242_1
# 242| m242_6(Constructible) = Chi : total:m241_6, partial:m242_5
# 242| m242_4(unknown) = ^CallSideEffect : ~m241_5
# 242| m242_5(unknown) = Chi : total:m241_5, partial:m242_4
# 242| v242_6(void) = ^IndirectReadSideEffect[-1] : &:r242_1, m241_8
# 242| m242_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r242_1
# 242| m242_8(Constructible) = Chi : total:m241_8, partial:m242_7
# 243| r243_1(glval<Constructible>) = VariableAddress[c2] :
# 243| m243_2(Constructible) = Uninitialized[c2] : &:r243_1
# 243| r243_3(glval<unknown>) = FunctionAddress[Constructible] :
# 243| r243_4(int) = Constant[2] :
# 243| v243_5(void) = Call[Constructible] : func:r243_3, this:r243_1, 0:r243_4
# 243| m243_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r243_1
# 243| m243_7(Constructible) = Chi : total:m243_2, partial:m243_6
# 243| m243_6(unknown) = ^CallSideEffect : ~m242_5
# 243| m243_7(unknown) = Chi : total:m242_5, partial:m243_6
# 243| m243_8(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r243_1
# 243| m243_9(Constructible) = Chi : total:m243_2, partial:m243_8
# 244| r244_1(glval<Constructible>) = VariableAddress[c2] :
# 244| r244_2(glval<unknown>) = FunctionAddress[g] :
# 244| v244_3(void) = Call[g] : func:r244_2, this:r244_1
# 244| v244_4(void) = ^IndirectReadSideEffect[-1] : &:r244_1, m243_7
# 244| m244_5(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1
# 244| m244_6(Constructible) = Chi : total:m243_7, partial:m244_5
# 244| m244_4(unknown) = ^CallSideEffect : ~m243_7
# 244| m244_5(unknown) = Chi : total:m243_7, partial:m244_4
# 244| v244_6(void) = ^IndirectReadSideEffect[-1] : &:r244_1, m243_9
# 244| m244_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1
# 244| m244_8(Constructible) = Chi : total:m243_9, partial:m244_7
# 245| v245_1(void) = NoOp :
# 239| v239_5(void) = ReturnVoid :
# 239| v239_6(void) = AliasedUse : m239_3
# 239| v239_6(void) = AliasedUse : ~m244_5
# 239| v239_7(void) = ExitFunction :
# 247| char* VoidStarIndirectParameters(char*, int)
@@ -1375,37 +1385,43 @@ ssa.cpp:
# 294| r294_18(glval<int>) = VariableAddress[x] :
# 294| r294_19(int) = Load[x] : &:r294_18, m291_6
# 294| v294_20(void) = Call[A] : func:r294_17, this:r294_16, 0:r294_19
# 294| m294_21(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_16
# 294| m294_22(unknown) = Chi : total:m294_15, partial:m294_21
# 294| v294_23(void) = Call[A] : func:r294_9, this:r294_8, 0:r294_16
# 294| v294_24(void) = ^BufferReadSideEffect[0] : &:r294_16, ~m294_22
# 294| m294_25(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_8
# 294| m294_26(unknown) = Chi : total:m294_7, partial:m294_25
# 294| m294_27(unknown) = ^BufferMayWriteSideEffect[0] : &:r294_16
# 294| m294_28(unknown) = Chi : total:m294_22, partial:m294_27
# 294| r294_29(glval<int>) = FieldAddress[i] : r294_8
# 294| r294_30(int) = Load[?] : &:r294_29, ~m294_26
# 294| m294_31(int) = Store[j] : &:r294_1, r294_30
# 294| m294_21(unknown) = ^CallSideEffect : ~m294_14
# 294| m294_22(unknown) = Chi : total:m294_14, partial:m294_21
# 294| m294_23(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_16
# 294| m294_24(unknown) = Chi : total:m294_15, partial:m294_23
# 294| v294_25(void) = Call[A] : func:r294_9, this:r294_8, 0:r294_16
# 294| m294_26(unknown) = ^CallSideEffect : ~m294_22
# 294| m294_27(unknown) = Chi : total:m294_22, partial:m294_26
# 294| v294_28(void) = ^BufferReadSideEffect[0] : &:r294_16, ~m294_24
# 294| m294_29(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_8
# 294| m294_30(unknown) = Chi : total:m294_7, partial:m294_29
# 294| m294_31(unknown) = ^BufferMayWriteSideEffect[0] : &:r294_16
# 294| m294_32(unknown) = Chi : total:m294_24, partial:m294_31
# 294| r294_33(glval<int>) = FieldAddress[i] : r294_8
# 294| r294_34(int) = Load[?] : &:r294_33, ~m294_30
# 294| m294_35(int) = Store[j] : &:r294_1, r294_34
# 295| r295_1(glval<A *>) = VariableAddress[a] :
# 295| r295_2(glval<unknown>) = FunctionAddress[operator new] :
# 295| r295_3(unsigned long) = Constant[4] :
# 295| r295_4(void *) = Call[operator new] : func:r295_2, 0:r295_3
# 295| m295_5(unknown) = ^CallSideEffect : ~m294_14
# 295| m295_6(unknown) = Chi : total:m294_14, partial:m295_5
# 295| m295_5(unknown) = ^CallSideEffect : ~m294_27
# 295| m295_6(unknown) = Chi : total:m294_27, partial:m295_5
# 295| m295_7(unknown) = ^InitializeDynamicAllocation : &:r295_4
# 295| r295_8(A *) = Convert : r295_4
# 295| r295_9(glval<unknown>) = FunctionAddress[A] :
# 295| v295_10(void) = Call[A] : func:r295_9, this:r295_8
# 295| m295_11(A) = ^IndirectMayWriteSideEffect[-1] : &:r295_8
# 295| m295_12(unknown) = Chi : total:m295_7, partial:m295_11
# 295| m295_13(A *) = Store[a] : &:r295_1, r295_8
# 295| m295_11(unknown) = ^CallSideEffect : ~m295_6
# 295| m295_12(unknown) = Chi : total:m295_6, partial:m295_11
# 295| m295_13(A) = ^IndirectMayWriteSideEffect[-1] : &:r295_8
# 295| m295_14(unknown) = Chi : total:m295_7, partial:m295_13
# 295| m295_15(A *) = Store[a] : &:r295_1, r295_8
# 296| r296_1(glval<Point *>) = VariableAddress[#return] :
# 296| r296_2(glval<Point *>) = VariableAddress[p] :
# 296| r296_3(Point *) = Load[p] : &:r296_2, m292_9
# 296| m296_4(Point *) = Store[#return] : &:r296_1, r296_3
# 291| r291_7(glval<Point *>) = VariableAddress[#return] :
# 291| v291_8(void) = ReturnValue : &:r291_7, m296_4
# 291| v291_9(void) = AliasedUse : ~m295_6
# 291| v291_9(void) = AliasedUse : ~m295_12
# 291| v291_10(void) = ExitFunction :
# 301| int main(int, char**)

View File

@@ -99,6 +99,8 @@ thisArgumentIsNonPointer
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
nonUniqueIRVariable
| misc.c:178:22:178:40 | VariableAddress: __PRETTY_FUNCTION__ | Variable address instruction 'VariableAddress: __PRETTY_FUNCTION__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
| misc.c:179:27:179:34 | VariableAddress: __func__ | Variable address instruction 'VariableAddress: __func__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -149,6 +149,9 @@ uniqueNodeLocation
| conditional_destructors.cpp:29:6:29:7 | EnterFunction | Node should have one location but has 2. |
| conditional_destructors.cpp:29:6:29:7 | ExitFunction | Node should have one location but has 2. |
| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal | Node should have one location but has 2. |
| conditional_destructors.cpp:29:6:29:7 | Phi | Node should have one location but has 2. |
| conditional_destructors.cpp:29:6:29:7 | Phi | Node should have one location but has 2. |
| conditional_destructors.cpp:29:6:29:7 | Phi | Node should have one location but has 2. |
| conditional_destructors.cpp:29:6:29:7 | ReturnVoid | Node should have one location but has 2. |
| conditional_destructors.cpp:29:6:29:7 | SideEffect | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | AliasedDefinition | Node should have one location but has 2. |
@@ -159,6 +162,9 @@ uniqueNodeLocation
| conditional_destructors.cpp:38:6:38:7 | EnterFunction | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | ExitFunction | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | Phi | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | Phi | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | Phi | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | ReturnVoid | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | SideEffect | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | Unreached | Node should have one location but has 2. |
@@ -555,6 +561,9 @@ uniqueNodeLocation
| forstmt.cpp:1:6:1:7 | EnterFunction | Node should have one location but has 2. |
| forstmt.cpp:1:6:1:7 | ExitFunction | Node should have one location but has 2. |
| forstmt.cpp:1:6:1:7 | InitializeNonLocal | Node should have one location but has 2. |
| forstmt.cpp:1:6:1:7 | Phi | Node should have one location but has 2. |
| forstmt.cpp:1:6:1:7 | Phi | Node should have one location but has 2. |
| forstmt.cpp:1:6:1:7 | Phi | Node should have one location but has 2. |
| forstmt.cpp:1:6:1:7 | ReturnVoid | Node should have one location but has 2. |
| forstmt.cpp:1:6:1:7 | SideEffect | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | AliasedDefinition | Node should have one location but has 2. |
@@ -565,6 +574,9 @@ uniqueNodeLocation
| forstmt.cpp:8:6:8:7 | EnterFunction | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | ExitFunction | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | InitializeNonLocal | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | Phi | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | Phi | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | Phi | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | ReturnVoid | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | SideEffect | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | Unreached | Node should have one location but has 2. |

View File

@@ -149,6 +149,8 @@ thisArgumentIsNonPointer
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
nonUniqueIRVariable
| misc.c:178:22:178:40 | VariableAddress: __PRETTY_FUNCTION__ | Variable address instruction 'VariableAddress: __PRETTY_FUNCTION__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
| misc.c:179:27:179:34 | VariableAddress: __func__ | Variable address instruction 'VariableAddress: __func__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -99,6 +99,8 @@ thisArgumentIsNonPointer
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
nonUniqueIRVariable
| misc.c:178:22:178:40 | VariableAddress: __PRETTY_FUNCTION__ | Variable address instruction 'VariableAddress: __PRETTY_FUNCTION__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
| misc.c:179:27:179:34 | VariableAddress: __func__ | Variable address instruction 'VariableAddress: __func__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

Some files were not shown because too many files have changed in this diff Show More