Merge branch 'main' of https://github.com/github/codeql into python-dataflow/flow-summaries-from-scratch

synced files have changed
This commit is contained in:
yoff 2022-08-25 09:24:05 +00:00
Родитель 4a5fa5993d b0ae12850d
Коммит 0b5d4c59dd
2460 изменённых файлов: 213327 добавлений и 79532 удалений

1
.github/labeler.yml поставляемый
Просмотреть файл

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

12
.github/workflows/go-tests.yml поставляемый
Просмотреть файл

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

117
.github/workflows/ql-for-ql-build.yml поставляемый
Просмотреть файл

@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v3
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
with:
languages: javascript # does not matter
- name: Get CodeQL version
@ -27,30 +27,37 @@ 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 }}/query-pack.zip
key: queries-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}
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') }}
- name: Build query pack
if: steps.cache-queries.outputs.cache-hit != 'true'
if: steps.cache-queries.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
run: |
cd ql/ql/src
"${CODEQL}" pack create
cd .codeql/pack/codeql/ql/0.0.0
zip "${PACKZIP}" -r .
"${CODEQL}" pack create -j 16
mv .codeql/pack/codeql/ql/0.0.0 ${{ runner.temp }}/queries
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:
@ -61,7 +68,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'
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
uses: actions/cache@v3
with:
path: |
@ -70,72 +77,35 @@ jobs:
ql/target
key: ${{ runner.os }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
- name: Check formatting
if: steps.cache-extractor.outputs.cache-hit != 'true'
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
run: cd ql; cargo fmt --all -- --check
- name: Build
if: steps.cache-extractor.outputs.cache-hit != 'true'
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
run: cd ql; cargo build --verbose
- name: Run tests
if: steps.cache-extractor.outputs.cache-hit != 'true'
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
run: cd ql; cargo test --verbose
- name: Release build
if: steps.cache-extractor.outputs.cache-hit != 'true'
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
run: cd ql; cargo build --release
- name: Generate dbscheme
if: steps.cache-extractor.outputs.cache-hit != 'true'
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.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 ###
- 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 .
- uses: actions/upload-artifact@v3
with:
name: codeql-ql-pack
path: codeql-ql.zip
retention-days: 1
- 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
### 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]')
@ -149,21 +119,26 @@ jobs:
echo " - ql/ql/test" >> ${CONF}
echo " - \"*/ql/lib/upgrades/\"" >> ${CONF}
echo "disable-default-queries: true" >> ${CONF}
echo "packs:" >> ${CONF}
echo " - codeql/ql" >> ${CONF}
echo "queries:" >> ${CONF}
echo " - uses: ./ql/ql/src/codeql-suites/ql-code-scanning.qls" >> ${CONF}
echo "Config file: "
cat ${CONF}
env:
CONF: ./ql-for-ql-config.yml
- name: Initialize CodeQL
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
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@aa93aea877e5fb8841bcb1193f672abf6e9f2980
uses: github/codeql-action/analyze@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
with:
category: "ql-for-ql"
- name: Copy sarif file to CWD

Просмотреть файл

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

4
.github/workflows/ql-for-ql-tests.yml поставляемый
Просмотреть файл

@ -22,7 +22,7 @@ jobs:
- uses: actions/checkout@v3
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
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 "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 "${CODEQL}" query format --check-only
find ql/ql/src "(" -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

Просмотреть файл

@ -486,28 +486,39 @@
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll"
],
"ReDoS Util Python/JS/Ruby/Java": [
"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"
"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"
],
"ReDoS Exponential Python/JS/Ruby/Java": [
"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"
"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"
],
"ReDoS Polynomial Python/JS/Ruby/Java": [
"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"
"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"
],
"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",
@ -587,5 +598,9 @@
"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"
]
}

Просмотреть файл

@ -0,0 +1,17 @@
class AttributeArgument extends @attribute_arg {
string toString() { none() }
}
class Attribute extends @attribute {
string toString() { none() }
}
class LocationDefault extends @location_default {
string toString() { none() }
}
from AttributeArgument arg, int kind, Attribute attr, int index, LocationDefault location
where
attribute_args(arg, kind, attr, index, location) and
not arg instanceof @attribute_arg_constant_expr
select arg, kind, attr, index, location

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,4 @@
description: Support all constant attribute arguments
compatibility: backwards
attribute_arg_constant.rel: delete
attribute_args.rel: run attribute_args.qlo

Просмотреть файл

@ -0,0 +1,13 @@
class Expr extends @expr {
string toString() { none() }
}
class Location extends @location_expr {
string toString() { none() }
}
from Expr expr, int kind, int kind_new, Location location
where
exprs(expr, kind, location) and
if expr instanceof @blockassignexpr then kind_new = 0 else kind_new = kind
select expr, kind_new, location

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,3 @@
description: Support block assignment
compatibility: partial
exprs.rel: run exprs.qlo

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

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

Просмотреть файл

@ -1,3 +1,15 @@
## 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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -1,4 +0,0 @@
---
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.

Просмотреть файл

@ -0,0 +1,4 @@
---
category: feature
---
* Added a `BlockAssignExpr` class, which models a `memcpy`-like operation used in compiler generated copy/move constructors and assignment operations.

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -0,0 +1,5 @@
---
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.

Просмотреть файл

@ -0,0 +1,11 @@
## 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.

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -160,6 +160,7 @@ 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)
@ -169,7 +170,7 @@ private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int
val = remainder(v1, mod)
|
exists(int v2, int m2 |
rankedPhiInput(phi, inp, edge, rix) and
rankedPhiInput(pragma[only_bind_out](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)

Просмотреть файл

@ -342,7 +342,10 @@ 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(getOperand()), getTrackedType(this)) }
SafeCastExpr() {
conversionCannotOverflow(getTrackedType(pragma[only_bind_into](getOperand())),
getTrackedType(this))
}
}
/**

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -218,8 +218,6 @@ 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() {

Просмотреть файл

@ -41,6 +41,15 @@ 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)
}
}
/**

Просмотреть файл

@ -12,7 +12,7 @@ private import semmle.code.cpp.internal.ResolveClass
class Specifier extends Element, @specifier {
/** Gets a dummy location for the specifier. */
override Location getLocation() {
suppressUnusedThis(this) and
exists(this) and
result instanceof UnknownDefaultLocation
}
@ -256,9 +256,13 @@ class AttributeArgument extends Element, @attribute_arg {
/**
* Gets the text for the value of this argument, if its value is
* a string or a number.
* a constant or a token.
*/
string getValueText() { attribute_arg_value(underlyingElement(this), result) }
string getValueText() {
if underlyingElement(this) instanceof @attribute_arg_constant_expr
then result = this.getValueConstant().getValue()
else attribute_arg_value(underlyingElement(this), result)
}
/**
* Gets the value of this argument, if its value is integral.
@ -270,6 +274,13 @@ class AttributeArgument extends Element, @attribute_arg {
*/
Type getValueType() { attribute_arg_type(underlyingElement(this), unresolveElement(result)) }
/**
* Gets the value of this argument, if its value is a constant.
*/
Expr getValueConstant() {
attribute_arg_constant(underlyingElement(this), unresolveElement(result))
}
/**
* Gets the attribute to which this is an argument.
*/
@ -294,11 +305,12 @@ class AttributeArgument extends Element, @attribute_arg {
(
if underlyingElement(this) instanceof @attribute_arg_type
then tail = this.getValueType().getName()
else
if underlyingElement(this) instanceof @attribute_arg_constant_expr
then tail = this.getValueConstant().toString()
else tail = this.getValueText()
) and
result = prefix + tail
)
}
}
private predicate suppressUnusedThis(Specifier s) { any() }

Просмотреть файл

@ -398,6 +398,8 @@ 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))
}
}
@ -471,6 +473,9 @@ 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 Executable file → Normal 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,13 +32,16 @@ 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, _)
}
@ -50,28 +53,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, _, _)) }
@ -92,9 +95,12 @@ 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() }
@ -120,15 +126,21 @@ 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) }
XmlDtd getADtd() { xmlDTDs(result, _, _, _, this) }
/** DEPRECATED: Alias for getADtd */
deprecated XmlDtd getADTD() { result = this.getADtd() }
}
/** DEPRECATED: Alias for XmlFile */
deprecated class XMLFile = XmlFile;
/**
* An XML document type definition (DTD).
*
@ -140,7 +152,7 @@ class XMLFile extends XMLParent, File {
* <!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, _, _, _) }
@ -154,7 +166,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
@ -165,6 +177,9 @@ class XMLDTD extends XMLLocatable, @xmldtd {
}
}
/** DEPRECATED: Alias for XmlDtd */
deprecated class XMLDTD = XmlDtd;
/**
* An XML element in an XML file.
*
@ -176,7 +191,7 @@ class XMLDTD extends XMLLocatable, @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() }
@ -184,10 +199,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, _) }
@ -196,7 +211,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, _) }
@ -205,10 +220,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)) }
@ -220,6 +235,9 @@ 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.
*
@ -230,18 +248,18 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
* 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, _, _) }
@ -250,6 +268,9 @@ 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.
*
@ -259,23 +280,29 @@ class XMLAttribute extends @xmlattribute, XMLLocatable {
* 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, _) }
string getUri() { xmlNs(this, _, result, _) }
/** DEPRECATED: Alias for getUri */
deprecated string getURI() { result = this.getUri() }
/** 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.
*
@ -285,17 +312,20 @@ class XMLNamespace extends XMLLocatable, @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.
@ -306,12 +336,12 @@ class XMLComment extends @xmlcomment, XMLLocatable {
* <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, _) }
@ -319,3 +349,6 @@ 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;

Просмотреть файл

@ -231,7 +231,7 @@ class BasicBlock extends ControlFlowNodeBase {
exists(Function f | f.getBlock() = this)
or
exists(TryStmt t, BasicBlock tryblock |
// a `Handler` preceeds the `CatchBlock`, and is always the beginning
// a `Handler` precedes the `CatchBlock`, and is always the beginning
// of a new `BasicBlock` (see `primitive_basic_block_entry_node`).
this.(Handler).getTryStmt() = t and
tryblock.isReachable() and

Просмотреть файл

@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
ap = TAccessPathNil(node.getDataFlowType())
}
predicate isAtSink() {

Просмотреть файл

@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
ap = TAccessPathNil(node.getDataFlowType())
}
predicate isAtSink() {

Просмотреть файл

@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
ap = TAccessPathNil(node.getDataFlowType())
}
predicate isAtSink() {

Просмотреть файл

@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
ap = TAccessPathNil(node.getDataFlowType())
}
predicate isAtSink() {

Просмотреть файл

@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
ap = TAccessPathNil(node.getDataFlowType())
}
predicate isAtSink() {

Просмотреть файл

@ -47,6 +47,20 @@ class AssignExpr extends Assignment, @assignexpr {
override string toString() { result = "... = ..." }
}
/**
* A compiler generated assignment operation that may occur in a compiler generated
* copy/move constructor or assignment operator, and which functions like `memcpy`
* where the size argument is based on the type of the rvalue of the assignment.
*/
class BlockAssignExpr extends Assignment, @blockassignexpr {
override string getOperator() { result = "=" }
override string getAPrimaryQlClass() { result = "BlockAssignExpr" }
/** Gets a textual representation of this assignment. */
override string toString() { result = "... = ..." }
}
/**
* A non-overloaded binary assignment operation other than `=`.
*

Просмотреть файл

@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
ap = TAccessPathNil(node.getDataFlowType())
}
predicate isAtSink() {

Просмотреть файл

@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
ap = TAccessPathNil(node.getDataFlowType())
}
predicate isAtSink() {

Просмотреть файл

@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
ap = TAccessPathNil(node.getDataFlowType())
}
predicate isAtSink() {

Просмотреть файл

@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
ap = TAccessPathNil(node.getDataFlowType())
}
predicate isAtSink() {

Просмотреть файл

@ -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`.
*/
private predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) {
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,6 +76,10 @@ 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.
@ -185,23 +189,29 @@ newtype TDefinition =
private module SsaDefReaches {
newtype TSsaRefKind =
SsaRead() or
SsaActualRead() or
SsaPhiRead() or
SsaDef()
class SsaRead = SsaActualRead or SsaPhiRead;
/**
* A classification of SSA variable references into reads and definitions.
*/
class SsaRefKind extends TSsaRefKind {
string toString() {
this = SsaRead() and
result = "SsaRead"
this = SsaActualRead() and
result = "SsaActualRead"
or
this = SsaPhiRead() and
result = "SsaPhiRead"
or
this = SsaDef() and
result = "SsaDef"
}
int getOrder() {
this = SsaRead() and
this instanceof SsaRead and
result = 0
or
this = SsaDef() and
@ -209,6 +219,80 @@ 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`
@ -216,11 +300,16 @@ 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 = SsaRead()
k = SsaActualRead()
or
exists(Definition def | def.definesAt(v, bb, i)) and
phiRead(bb, v) and
i = -1 and
k = SsaPhiRead()
or
any(Definition def).definesAt(v, bb, i) and
k = SsaDef()
}
@ -273,7 +362,7 @@ private module SsaDefReaches {
)
or
ssaDefReachesRank(bb, def, rnk - 1, v) and
rnk = ssaRefRank(bb, _, v, SsaRead())
rnk = ssaRefRank(bb, _, v, any(SsaRead k))
}
/**
@ -283,7 +372,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, SsaRead())
rnk = ssaRefRank(bb, i, v, any(SsaRead k))
)
}
@ -309,45 +398,94 @@ private module SsaDefReaches {
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
}
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) {
exists(ssaDefRank(def, v, bb, _, _))
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) {
exists(ssaDefRank(def, v, bb, _, k))
}
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 `bb1`,
* and the underlying variable for `def` is neither read nor written in any block
* on the path between `bb1` and `bb2`.
* `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.
*/
predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) {
defOccursInBlock(def, bb1, _) and
pragma[nomagic]
private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
defOccursInBlock(def, bb1, _, _) and
bb2 = getABasicBlockSuccessor(bb1)
or
exists(BasicBlock mid |
varBlockReaches(def, bb1, mid) and
varBlockReachesInclPhiRead(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),
* `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`.
* 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`.
*/
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(), SsaRead()) = 1
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)
)
}
}
predicate phiReadExposedForTesting = phiRead/2;
private import SsaDefReaches
pragma[nomagic]
@ -365,7 +503,8 @@ predicate liveThrough(BasicBlock bb, SourceVariable v) {
*/
pragma[nomagic]
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) {
exists(int last | last = maxSsaRefRank(bb, v) |
exists(int last |
last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and
ssaDefReachesRank(bb, def, last, v) and
liveAtExit(bb, v)
)
@ -405,7 +544,7 @@ pragma[nomagic]
predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) {
ssaDefReachesReadWithinBlock(v, def, bb, i)
or
variableRead(bb, i, v, _) and
ssaRef(bb, i, v, any(SsaRead k)) and
ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and
not ssaDefReachesReadWithinBlock(v, _, bb, i)
}
@ -421,7 +560,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, SsaRead()) and
rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and
variableRead(bb1, i2, _, _) and
bb2 = bb1
)
@ -538,18 +677,15 @@ 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
lastSsaRef(def, _, bb, i) and
(
exists(SourceVariable v | lastSsaRef(def, v, bb, i) |
// Can reach exit directly
bb instanceof ExitBasicBlock
or
// Can reach a block using one or more steps, where `def` is no longer live
exists(BasicBlock bb2 | varBlockReaches(def, bb, bb2) |
not defOccursInBlock(def, bb2, _) and
not ssaDefReachesEndOfBlock(bb2, def, _)
)
varBlockReachesExit(def, bb)
)
}

Просмотреть файл

@ -22,7 +22,7 @@ module InstructionConsistency {
abstract Language::Location getLocation();
}
private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
private IRFunction irFunc;
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
@ -37,6 +37,8 @@ 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 {

Просмотреть файл

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

Просмотреть файл

@ -5,8 +5,8 @@ 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;

Просмотреть файл

@ -2,7 +2,14 @@ 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
import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSsaInstructions as SsaInstructions
/** DEPRECATED: Alias for SsaInstructions */
deprecated module SSAInstructions = 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
import semmle.code.cpp.ir.implementation.internal.TOperand::AliasedSsaOperands as SsaOperands
/** DEPRECATED: Alias for SsaOperands */
deprecated module SSAOperands = SsaOperands;

Просмотреть файл

@ -29,15 +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) {
AliasedSSA::SSA::hasChiInstruction(primaryInstruction)
AliasedSsa::SSA::hasChiInstruction(primaryInstruction)
} or
TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
AliasedSSA::SSA::hasUnreachedInstruction(irFunc)
AliasedSsa::SSA::hasUnreachedInstruction(irFunc)
}
/**
@ -83,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)
}

Просмотреть файл

@ -1,4 +1,7 @@
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
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedSsa
/** DEPRECATED: Alias for AliasedSsa */
deprecated module AliasedSSA = AliasedSsa;

Просмотреть файл

@ -22,7 +22,7 @@ module InstructionConsistency {
abstract Language::Location getLocation();
}
private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
private IRFunction irFunc;
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
@ -37,6 +37,8 @@ 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 {

Просмотреть файл

@ -1450,8 +1450,6 @@ class TranslatedAssignExpr extends TranslatedNonConstantExpr {
result = this.getLeftOperand().getResult()
}
abstract Instruction getStoredValue();
final TranslatedExpr getLeftOperand() {
result = getTranslatedExpr(expr.getLValue().getFullyConverted())
}
@ -1493,6 +1491,75 @@ class TranslatedAssignExpr extends TranslatedNonConstantExpr {
}
}
class TranslatedBlockAssignExpr extends TranslatedNonConstantExpr {
override BlockAssignExpr expr;
final override TranslatedElement getChild(int id) {
id = 0 and result = this.getLeftOperand()
or
id = 1 and result = this.getRightOperand()
}
final override Instruction getFirstInstruction() {
// The operand evaluation order should not matter since block assignments behave like memcpy.
result = this.getLeftOperand().getFirstInstruction()
}
final override Instruction getResult() { result = this.getInstruction(AssignmentStoreTag()) }
final TranslatedExpr getLeftOperand() {
result = getTranslatedExpr(expr.getLValue().getFullyConverted())
}
final TranslatedExpr getRightOperand() {
result = getTranslatedExpr(expr.getRValue().getFullyConverted())
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = LoadTag() and
result = this.getInstruction(AssignmentStoreTag()) and
kind instanceof GotoEdge
or
tag = AssignmentStoreTag() and
result = this.getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getLeftOperand() and
result = this.getRightOperand().getFirstInstruction()
or
child = this.getRightOperand() and
result = this.getInstruction(LoadTag())
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
tag = LoadTag() and
opcode instanceof Opcode::Load and
resultType = getTypeForPRValue(expr.getRValue().getType())
or
tag = AssignmentStoreTag() and
opcode instanceof Opcode::Store and
// The frontend specifies that the relevant type is the one of the source.
resultType = getTypeForPRValue(expr.getRValue().getType())
}
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
tag = LoadTag() and
operandTag instanceof AddressOperandTag and
result = this.getRightOperand().getResult()
or
tag = AssignmentStoreTag() and
(
operandTag instanceof AddressOperandTag and
result = this.getLeftOperand().getResult()
or
operandTag instanceof StoreValueOperandTag and
result = this.getInstruction(LoadTag())
)
}
}
class TranslatedAssignOperation extends TranslatedNonConstantExpr {
override AssignOperation expr;

Просмотреть файл

@ -22,7 +22,7 @@ module InstructionConsistency {
abstract Language::Location getLocation();
}
private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
private IRFunction irFunc;
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
@ -37,6 +37,8 @@ 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 {

Просмотреть файл

@ -5,8 +5,8 @@ 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;

Просмотреть файл

@ -3,7 +3,14 @@ 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
import semmle.code.cpp.ir.implementation.internal.TInstruction::UnaliasedSsaInstructions as SsaInstructions
/** DEPRECATED: Alias for SsaInstructions */
deprecated module SSAInstructions = 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
import semmle.code.cpp.ir.implementation.internal.TOperand::UnaliasedSsaOperands as SsaOperands
/** DEPRECATED: Alias for SsaOperands */
deprecated module SSAOperands = SsaOperands;

Просмотреть файл

@ -218,7 +218,7 @@ private class CallAllocationExpr extends AllocationExpr, FunctionCall {
exists(target.getReallocPtrArg()) and
this.getArgument(target.getSizeArg()).getValue().toInt() = 0
) and
// these are modelled directly (and more accurately), avoid duplication
// these are modeled directly (and more accurately), avoid duplication
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
}

Просмотреть файл

@ -11,12 +11,6 @@ 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

Просмотреть файл

@ -27,13 +27,6 @@ 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.
*/
@ -44,13 +37,6 @@ 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 {
/**

Просмотреть файл

@ -50,7 +50,7 @@ VariableAccess varUse(LocalScopeVariable v) { result = v.getAnAccess() }
* Holds if `e` potentially overflows and `use` is an operand of `e` that is not guarded.
*/
predicate missingGuardAgainstOverflow(Operation e, VariableAccess use) {
// Since `e` is guarenteed to be a `BinaryArithmeticOperation`, a `UnaryArithmeticOperation` or
// Since `e` is guaranteed to be a `BinaryArithmeticOperation`, a `UnaryArithmeticOperation` or
// an `AssignArithmeticOperation` by the other constraints in this predicate, we know that
// `convertedExprMightOverflowPositively` will have a result even when `e` is not analyzable
// by `SimpleRangeAnalysis`.
@ -80,7 +80,7 @@ predicate missingGuardAgainstOverflow(Operation e, VariableAccess use) {
* Holds if `e` potentially underflows and `use` is an operand of `e` that is not guarded.
*/
predicate missingGuardAgainstUnderflow(Operation e, VariableAccess use) {
// Since `e` is guarenteed to be a `BinaryArithmeticOperation`, a `UnaryArithmeticOperation` or
// Since `e` is guaranteed to be a `BinaryArithmeticOperation`, a `UnaryArithmeticOperation` or
// an `AssignArithmeticOperation` by the other constraints in this predicate, we know that
// `convertedExprMightOverflowNegatively` will have a result even when `e` is not analyzable
// by `SimpleRangeAnalysis`.

Просмотреть файл

@ -523,6 +523,11 @@ 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,
@ -899,6 +904,7 @@ case @attribute_arg.kind of
| 1 = @attribute_arg_token
| 2 = @attribute_arg_constant
| 3 = @attribute_arg_type
| 4 = @attribute_arg_constant_expr
;
attribute_arg_value(
@ -909,6 +915,10 @@ attribute_arg_type(
unique int arg: @attribute_arg ref,
int type_id: @type ref
);
attribute_arg_constant(
unique int arg: @attribute_arg ref,
int constant: @expr ref
)
attribute_arg_name(
unique int arg: @attribute_arg ref,
string name: string ref
@ -1297,7 +1307,7 @@ funbind(
@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr
@assign_expr = @assignexpr | @assign_op_expr
@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
/*
case @allocator.form of
@ -1655,6 +1665,7 @@ case @expr.kind of
| 332 = @hasuniqueobjectrepresentations
| 333 = @builtinbitcast
| 334 = @builtinshuffle
| 335 = @blockassignexpr
;
@var_args_expr = @vastartexpr

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,2 @@
description: Support all constant attribute arguments
compatibility: partial

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,2 @@
description: Support block assignment
compatibility: backwards

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

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

Просмотреть файл

@ -1,3 +1,9 @@
## 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

Просмотреть файл

@ -68,7 +68,7 @@ class BooleanControllingAssignmentInExpr extends BooleanControllingAssignment {
// if((a = b) && use_value(a)) { ... }
// ```
// where the assignment is meant to update the value of `a` before it's used in some other boolean
// subexpression that is guarenteed to be evaluate _after_ the assignment.
// subexpression that is guaranteed to be evaluate _after_ the assignment.
this.isParenthesised() and
exists(LogicalAndExpr parent, Variable var, VariableAccess access |
var = this.getLValue().(VariableAccess).getTarget() and

Просмотреть файл

@ -51,7 +51,7 @@ predicate illDefinedDecrForStmt(
(
upperBound(initialCondition) < lowerBound(terminalCondition) and
(
// exclude cases where the loop counter is `unsigned` (where wrapping behaviour can be used deliberately)
// exclude cases where the loop counter is `unsigned` (where wrapping behavior can be used deliberately)
v.getUnspecifiedType().(IntegralType).isSigned() or
initialCondition.getValue().toInt() = 0
)

Просмотреть файл

@ -18,6 +18,7 @@
import cpp
import Buffer
private import semmle.code.cpp.valuenumbering.GlobalValueNumbering
private import semmle.code.cpp.models.implementations.Strcpy
predicate isSizePlus(Expr e, BufferSizeExpr baseSize, int plus) {
// baseSize
@ -41,33 +42,6 @@ predicate isSizePlus(Expr e, BufferSizeExpr baseSize, int plus) {
)
}
predicate strncpyFunction(Function f, int argDest, int argSrc, int argLimit) {
exists(string name | name = f.getName() |
name =
[
"strcpy_s", // strcpy_s(dst, max_amount, src)
"wcscpy_s", // wcscpy_s(dst, max_amount, src)
"_mbscpy_s" // _mbscpy_s(dst, max_amount, src)
] and
argDest = 0 and
argSrc = 2 and
argLimit = 1
or
name =
[
"strncpy", // strncpy(dst, src, max_amount)
"strncpy_l", // strncpy_l(dst, src, max_amount, locale)
"wcsncpy", // wcsncpy(dst, src, max_amount)
"_wcsncpy_l", // _wcsncpy_l(dst, src, max_amount, locale)
"_mbsncpy", // _mbsncpy(dst, src, max_amount)
"_mbsncpy_l" // _mbsncpy_l(dst, src, max_amount, locale)
] and
argDest = 0 and
argSrc = 1 and
argLimit = 2
)
}
string nthString(int num) {
num = 0 and
result = "first"
@ -96,11 +70,13 @@ int arrayExprFixedSize(Expr e) {
}
from
Function f, FunctionCall fc, int argDest, int argSrc, int argLimit, int charSize, Access copyDest,
Access copySource, string name, string nth
StrcpyFunction f, FunctionCall fc, int argDest, int argSrc, int argLimit, int charSize,
Access copyDest, Access copySource, string name, string nth
where
f = fc.getTarget() and
strncpyFunction(f, argDest, argSrc, argLimit) and
argDest = f.getParamDest() and
argSrc = f.getParamSrc() and
argLimit = f.getParamSize() and
copyDest = fc.getArgument(argDest) and
copySource = fc.getArgument(argSrc) and
// Some of the functions operate on a larger char type, like `wchar_t`, so we

Просмотреть файл

@ -106,6 +106,26 @@ 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())
@ -117,25 +137,27 @@ TGlobalAddress globalAddress(Instruction instr) {
result = TLoad(globalAddress(load.getSourceAddress()))
)
or
exists(ConvertInstruction convert, Type fromType, Type toType | instr = convert |
uncheckedConversionTypes(convert, fromType, toType) and
result = TConversion("unchecked", globalAddress(convert.getUnary()), fromType, toType)
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)
)
or
exists(CheckedConvertOrNullInstruction convert, Type fromType, Type toType | instr = convert |
checkedConversionTypes(convert, fromType, toType) and
result = TConversion("checked", globalAddress(convert.getUnary()), fromType, toType)
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)
)
or
exists(InheritanceConversionInstruction convert, Type fromType, Type toType | instr = convert |
inheritanceConversionTypes(convert, fromType, toType) and
result = TConversion("inheritance", globalAddress(convert.getUnary()), fromType, toType)
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)
)
or
exists(FieldAddressInstruction fai | instr = fai |
result =
TFieldAddress(globalAddress(pragma[only_bind_into](fai.getObjectAddress())),
pragma[only_bind_out](fai.getField()))
exists(FieldAddressInstruction fai, Instruction object, Field f | instr = fai |
hasObjectAndField(fai, object, f) and
result = TFieldAddress(globalAddress(object), f)
)
or
result = globalAddress(instr.(PointerOffsetInstruction).getLeft())
@ -268,7 +290,11 @@ class PathElement extends TPathElement {
predicate isSink(IRBlock block) { exists(this.asSink(block)) }
string toString() {
result = [asStore().toString(), asCall(_).toString(), asMid().toString(), asSink(_).toString()]
result =
[
this.asStore().toString(), this.asCall(_).toString(), this.asMid().toString(),
this.asSink(_).toString()
]
}
predicate hasLocationInfo(

Просмотреть файл

@ -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="http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspx">When should your destructor be virtual?</a>
<a href="https://devblogs.microsoft.com/oldnewthing/20040507-00/?p=39443">When should your destructor be virtual?</a>
</li>

Просмотреть файл

@ -0,0 +1,43 @@
/**
* @name Count IR inconsistencies
* @description Counts the various IR inconsistencies that may occur.
* This query is for internal use only and may change without notice.
* @kind table
* @id cpp/count-ir-inconsistencies
*/
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,
count(PhiInstruction i | IRConsistency::missingPhiOperand(i, _, _, _) | i) as missingPhiOperand,
count(Operand o | IRConsistency::missingOperandType(o, _, _, _) | o) as missingOperandType,
count(ChiInstruction i | IRConsistency::duplicateChiOperand(i, _, _, _) | i) as duplicateChiOperand,
count(Instruction i | IRConsistency::sideEffectWithoutPrimary(i, _, _, _) | i) as sideEffectWithoutPrimary,
count(Instruction i | IRConsistency::instructionWithoutSuccessor(i, _, _, _) | i) as instructionWithoutSuccessor,
count(Instruction i | IRConsistency::ambiguousSuccessors(i, _, _, _) | i) as ambiguousSuccessors,
count(Instruction i | IRConsistency::unexplainedLoop(i, _, _, _) | i) as unexplainedLoop,
count(PhiInstruction i | IRConsistency::unnecessaryPhiInstruction(i, _, _, _) | i) as unnecessaryPhiInstruction,
count(Instruction i | IRConsistency::memoryOperandDefinitionIsUnmodeled(i, _, _, _) | i) as memoryOperandDefinitionIsUnmodeled,
count(Operand o | IRConsistency::operandAcrossFunctions(o, _, _, _, _, _) | o) as operandAcrossFunctions,
count(IRFunction f | IRConsistency::containsLoopOfForwardEdges(f, _) | f) as containsLoopOfForwardEdges,
count(IRBlock i | IRConsistency::lostReachability(i, _, _, _) | i) as lostReachability,
count(string m | IRConsistency::backEdgeCountMismatch(_, m) | m) as backEdgeCountMismatch,
count(Operand o | IRConsistency::useNotDominatedByDefinition(o, _, _, _) | o) as useNotDominatedByDefinition,
count(SwitchInstruction i | IRConsistency::switchInstructionWithoutDefaultEdge(i, _, _, _) | i) as switchInstructionWithoutDefaultEdge,
count(Instruction i | IRConsistency::notMarkedAsConflated(i, _, _, _) | i) as notMarkedAsConflated,
count(Instruction i | IRConsistency::wronglyMarkedAsConflated(i, _, _, _) | i) as wronglyMarkedAsConflated,
count(MemoryOperand o | IRConsistency::invalidOverlap(o, _, _, _) | o) as invalidOverlap,
count(Instruction i | IRConsistency::nonUniqueEnclosingIRFunction(i, _, _, _) | i) as nonUniqueEnclosingIRFunction,
count(FieldAddressInstruction i | IRConsistency::fieldAddressOnNonPointer(i, _, _, _) | i) as fieldAddressOnNonPointer,
count(Instruction i | IRConsistency::thisArgumentIsNonPointer(i, _, _, _) | i) as thisArgumentIsNonPointer,
count(Instruction i | IRConsistency::nonUniqueIRVariable(i, _, _, _) | i) as nonUniqueIRVariable

Просмотреть файл

@ -21,7 +21,9 @@ 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

Просмотреть файл

@ -21,7 +21,9 @@ 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

Просмотреть файл

@ -19,6 +19,7 @@ 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
@ -83,6 +84,32 @@ 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 {
@ -94,8 +121,8 @@ class ExecTaintConfiguration extends TaintTracking::Configuration {
}
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
shellCommand(sinkAsArgumentIndirection(sink), _) and
state instanceof ExecState
any(ExecStateConfiguration conf).isSink(sink) and
state.(ExecState).isFeasibleForSink(sink)
}
override predicate isAdditionalTaintStep(

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -26,6 +26,10 @@ 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())
}

Просмотреть файл

@ -47,14 +47,17 @@ 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
@ -66,14 +69,17 @@ 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

Просмотреть файл

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

Просмотреть файл

@ -0,0 +1,5 @@
## 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.

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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="http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspx">When should your destructor be virtual?</a>
<a href="https://devblogs.microsoft.com/oldnewthing/20040507-00/?p=39443">When should your destructor be virtual?</a>
</li>

Просмотреть файл

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

Просмотреть файл

@ -330,6 +330,19 @@ 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;
@ -344,8 +357,7 @@ private class ValidExpectation extends Expectation, TValidExpectation {
string getKnownFailure() { result = knownFailure }
predicate matchesActualResult(ActualResult actualResult) {
getLocation().getStartLine() = actualResult.getLocation().getStartLine() and
getLocation().getFile() = actualResult.getLocation().getFile() and
onSameLine(pragma[only_bind_into](this), actualResult) and
getTag() = actualResult.getTag() and
getValue() = actualResult.getValue()
}

Просмотреть файл

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

Просмотреть файл

@ -1,3 +1,4 @@
| strlen.cpp:7:49:7:49 | 1 |
| strlen.cpp:11:39:11:48 | array to pointer conversion |
| strlen.cpp:11:39:11:48 | file.ext |
| strlen.cpp:12:35:12:40 | call to strlen |

Просмотреть файл

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

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