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-for-QL":
- ql/**/* - ql/**/*
- .github/workflows/ql-for-ql*

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

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

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

@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Find codeql - name: Find codeql
id: find-codeql id: find-codeql
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980 uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
with: with:
languages: javascript # does not matter languages: javascript # does not matter
- name: Get CodeQL version - name: Get CodeQL version
@ -27,30 +27,37 @@ jobs:
shell: bash shell: bash
env: env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }} 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 - name: Cache queries
if: steps.cache-pack.outputs.cache-hit != 'true'
id: cache-queries id: cache-queries
uses: actions/cache@v3 uses: actions/cache@v3
with: with:
path: ${{ runner.temp }}/query-pack.zip 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 }} 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 - 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: | run: |
cd ql/ql/src cd ql/ql/src
"${CODEQL}" pack create "${CODEQL}" pack create -j 16
cd .codeql/pack/codeql/ql/0.0.0 mv .codeql/pack/codeql/ql/0.0.0 ${{ runner.temp }}/queries
zip "${PACKZIP}" -r . 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: env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }} 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 ### ### Build the extractor ###
- name: Cache entire extractor - name: Cache entire extractor
if: steps.cache-pack.outputs.cache-hit != 'true'
id: cache-extractor id: cache-extractor
uses: actions/cache@v3 uses: actions/cache@v3
with: with:
@ -61,7 +68,7 @@ jobs:
ql/target/release/ql-extractor.exe ql/target/release/ql-extractor.exe
key: ${{ runner.os }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }} key: ${{ runner.os }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
- name: Cache cargo - 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 uses: actions/cache@v3
with: with:
path: | path: |
@ -70,72 +77,35 @@ jobs:
ql/target ql/target
key: ${{ runner.os }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }} key: ${{ runner.os }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
- name: Check formatting - 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 run: cd ql; cargo fmt --all -- --check
- name: Build - 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 run: cd ql; cargo build --verbose
- name: Run tests - 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 run: cd ql; cargo test --verbose
- name: Release build - 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 run: cd ql; cargo build --release
- name: Generate dbscheme - 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 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 ### ### Package the queries and extractor ###
- uses: actions/download-artifact@v3 - name: Package pack
with: if: steps.cache-pack.outputs.cache-hit != 'true'
name: query-pack-zip run: |
path: query-pack-zip cp -r ql/codeql-extractor.yml ql/tools ql/ql/src/ql.dbscheme.stats ${PACK}/
- uses: actions/download-artifact@v3 mkdir -p ${PACK}/tools/linux64
with: cp ql/target/release/ql-autobuilder ${PACK}/tools/linux64/autobuilder
name: extractor-ubuntu-latest cp ql/target/release/ql-extractor ${PACK}/tools/linux64/extractor
path: linux64 chmod +x ${PACK}/tools/linux64/autobuilder
- run: | chmod +x ${PACK}/tools/linux64/extractor
unzip query-pack-zip/*.zip -d pack env:
cp -r ql/codeql-extractor.yml ql/tools ql/ql/src/ql.dbscheme.stats pack/ PACK: ${{ runner.temp }}/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
### Run the analysis ### ### 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 - name: Hack codeql-action options
run: | 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]') 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/ql/test" >> ${CONF}
echo " - \"*/ql/lib/upgrades/\"" >> ${CONF} echo " - \"*/ql/lib/upgrades/\"" >> ${CONF}
echo "disable-default-queries: true" >> ${CONF} echo "disable-default-queries: true" >> ${CONF}
echo "packs:" >> ${CONF} echo "queries:" >> ${CONF}
echo " - codeql/ql" >> ${CONF} echo " - uses: ./ql/ql/src/codeql-suites/ql-code-scanning.qls" >> ${CONF}
echo "Config file: " echo "Config file: "
cat ${CONF} cat ${CONF}
env: env:
CONF: ./ql-for-ql-config.yml CONF: ./ql-for-ql-config.yml
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980 uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
with: with:
languages: ql languages: ql
db-location: ${{ runner.temp }}/db db-location: ${{ runner.temp }}/db
config-file: ./ql-for-ql-config.yml 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 - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@aa93aea877e5fb8841bcb1193f672abf6e9f2980 uses: github/codeql-action/analyze@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
with: with:
category: "ql-for-ql" category: "ql-for-ql"
- name: Copy sarif file to CWD - name: Copy sarif file to CWD

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

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

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

@ -22,7 +22,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Find codeql - name: Find codeql
id: find-codeql id: find-codeql
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980 uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
with: with:
languages: javascript # does not matter languages: javascript # does not matter
- uses: actions/cache@v3 - uses: actions/cache@v3
@ -44,7 +44,7 @@ jobs:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }} CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
- name: Check QL formatting - name: Check QL formatting
run: | 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: env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }} CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
- name: Check QL compilation - name: Check QL compilation

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

@ -486,28 +486,39 @@
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll" "ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll"
], ],
"ReDoS Util Python/JS/Ruby/Java": [ "ReDoS Util Python/JS/Ruby/Java": [
"javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll", "javascript/ql/lib/semmle/javascript/security/regexp/NfaUtils.qll",
"python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll", "python/ql/lib/semmle/python/security/regexp/NfaUtils.qll",
"ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll", "ruby/ql/lib/codeql/ruby/security/regexp/NfaUtils.qll",
"java/ql/lib/semmle/code/java/security/performance/ReDoSUtil.qll" "java/ql/lib/semmle/code/java/security/regexp/NfaUtils.qll"
], ],
"ReDoS Exponential Python/JS/Ruby/Java": [ "ReDoS Exponential Python/JS/Ruby/Java": [
"javascript/ql/lib/semmle/javascript/security/performance/ExponentialBackTracking.qll", "javascript/ql/lib/semmle/javascript/security/regexp/ExponentialBackTracking.qll",
"python/ql/lib/semmle/python/security/performance/ExponentialBackTracking.qll", "python/ql/lib/semmle/python/security/regexp/ExponentialBackTracking.qll",
"ruby/ql/lib/codeql/ruby/security/performance/ExponentialBackTracking.qll", "ruby/ql/lib/codeql/ruby/security/regexp/ExponentialBackTracking.qll",
"java/ql/lib/semmle/code/java/security/performance/ExponentialBackTracking.qll" "java/ql/lib/semmle/code/java/security/regexp/ExponentialBackTracking.qll"
], ],
"ReDoS Polynomial Python/JS/Ruby/Java": [ "ReDoS Polynomial Python/JS/Ruby/Java": [
"javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll", "javascript/ql/lib/semmle/javascript/security/regexp/SuperlinearBackTracking.qll",
"python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll", "python/ql/lib/semmle/python/security/regexp/SuperlinearBackTracking.qll",
"ruby/ql/lib/codeql/ruby/security/performance/SuperlinearBackTracking.qll", "ruby/ql/lib/codeql/ruby/security/regexp/SuperlinearBackTracking.qll",
"java/ql/lib/semmle/code/java/security/performance/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": [ "BadTagFilterQuery Python/JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll", "javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll",
"python/ql/lib/semmle/python/security/BadTagFilterQuery.qll", "python/ql/lib/semmle/python/security/BadTagFilterQuery.qll",
"ruby/ql/lib/codeql/ruby/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": [ "CFG": [
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll", "csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",
"ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll", "ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll",
@ -587,5 +598,9 @@
"Swift patterns test file": [ "Swift patterns test file": [
"swift/ql/test/extractor-tests/patterns/patterns.swift", "swift/ql/test/extractor-tests/patterns/patterns.swift",
"swift/ql/test/library-tests/parent/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 ## 0.3.2
### Bug Fixes ### 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() result = block.getDisplayIndex()
} }
class SsaVariable instanceof IR::Instruction { newtype TSsaVariable =
SsaVariable() { super.hasMemoryResult() } 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) { 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 = private newtype TReadPosition =
TReadPositionBlock(IR::IRBlock block) or TReadPositionBlock(IR::IRBlock block) or
@ -169,7 +209,9 @@ module SemanticExprConfig {
final override predicate hasRead(SsaVariable v) { final override predicate hasRead(SsaVariable v) {
exists(IR::Operand operand | 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) { final override predicate hasRead(SsaVariable v) {
exists(IR::PhiInputOperand operand | exists(IR::PhiInputOperand operand |
operand.getDef() = v and operand.getDef() = v.asInstruction() and
operand.getPredecessorBlock() = pred and operand.getPredecessorBlock() = pred and
operand.getUse().getBlock() = succ operand.getUse().getBlock() = succ
) )
@ -205,17 +247,16 @@ module SemanticExprConfig {
exists(IR::PhiInputOperand operand | exists(IR::PhiInputOperand operand |
pos = TReadPositionPhiInputEdge(operand.getPredecessorBlock(), operand.getUse().getBlock()) 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 { class Bound instanceof IRBound::Bound {
Bound() {
this instanceof IRBound::ZeroBound
or
this.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction() instanceof SsaVariable
}
string toString() { result = super.toString() } string toString() { result = super.toString() }
final Location getLocation() { result = super.getLocation() } final Location getLocation() { result = super.getLocation() }
@ -228,13 +269,13 @@ module SemanticExprConfig {
override string toString() { override string toString() {
result = result =
min(SsaVariable instr | min(SsaVariable v |
instr = bound.getValueNumber().getAnInstruction() v.asInstruction() = bound.getValueNumber().getAnInstruction()
| |
instr v
order by order by
instr.(IR::Instruction).getBlock().getDisplayIndex(), v.asInstruction().getBlock().getDisplayIndex(),
instr.(IR::Instruction).getDisplayIndexInBlock() v.asInstruction().getDisplayIndexInBlock()
).toString() ).toString()
} }
} }
@ -242,7 +283,7 @@ module SemanticExprConfig {
predicate zeroBound(Bound bound) { bound instanceof IRBound::ZeroBound } predicate zeroBound(Bound bound) { bound instanceof IRBound::ZeroBound }
predicate ssaBound(Bound bound, SsaVariable v) { 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) { Expr getBoundExpr(Bound bound, int delta) {
@ -251,22 +292,20 @@ module SemanticExprConfig {
class Guard = IRGuards::IRGuardCondition; class Guard = IRGuards::IRGuardCondition;
predicate guard(Guard guard, BasicBlock block) { predicate guard(Guard guard, BasicBlock block) { block = guard.getBlock() }
block = guard.(IRGuards::IRGuardCondition).getBlock()
}
Expr getGuardAsExpr(Guard guard) { result = guard } Expr getGuardAsExpr(Guard guard) { result = guard }
predicate equalityGuard(Guard guard, Expr e1, Expr e2, boolean polarity) { 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) { 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) { 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 } Guard comparisonGuard(Expr e) { result = e }
@ -284,9 +323,13 @@ SemBasicBlock getSemanticBasicBlock(IR::IRBlock block) { result = block }
IR::IRBlock getCppBasicBlock(SemBasicBlock block) { block = result } 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 } 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`. * 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) { private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int mod, int rix) {
rix = 0 and rix = 0 and
phiModulusInit(phi, b, val, mod) phiModulusInit(phi, b, val, mod)
@ -169,7 +170,7 @@ private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int
val = remainder(v1, mod) val = remainder(v1, mod)
| |
exists(int v2, int m2 | 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 phiModulusRankStep(phi, b, v1, m1, rix - 1) and
ssaModulus(inp, edge, b, v2, m2) and ssaModulus(inp, edge, b, v2, m2) and
mod = m1.gcd(m2).gcd(v1 - v2) 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. * A cast that can be ignored for the purpose of range analysis.
*/ */
private class SafeCastExpr extends ConvertOrBoxExpr { 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 } BinarySignExpr() { binary = this }
override Sign getSignRestriction() { override Sign getSignRestriction() {
exists(SemExpr left, SemExpr right |
binaryExprOperands(binary, left, right) and
result = result =
semExprSign(binary.getLeftOperand()) semExprSign(pragma[only_bind_out](left))
.applyBinaryOp(semExprSign(binary.getRightOperand()), binary.getOpcode()) .applyBinaryOp(semExprSign(pragma[only_bind_out](right)), binary.getOpcode())
)
or or
exists(SemDivExpr div | div = binary | exists(SemDivExpr div | div = binary |
result = semExprSign(div.getLeftOperand()) and 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. * A `Convert`, `Box`, or `Unbox` expression.
*/ */
@ -221,7 +228,7 @@ private class UnarySignExpr extends FlowSignExpr {
UnarySignExpr() { unary = this and not this instanceof SemCastExpr } UnarySignExpr() { unary = this and not this instanceof SemCastExpr }
override Sign getSignRestriction() { 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 name: codeql/cpp-all
version: 0.3.3-dev version: 0.3.4-dev
groups: cpp groups: cpp
dbscheme: semmlecode.cpp.dbscheme dbscheme: semmlecode.cpp.dbscheme
extractor: cpp extractor: cpp

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

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

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

@ -41,6 +41,15 @@ class LinkTarget extends @link_target {
* translation units which contributed to this link target. * translation units which contributed to this link target.
*/ */
Class getAClass() { link_parent(unresolveElement(result), this) } 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 { class Specifier extends Element, @specifier {
/** Gets a dummy location for the specifier. */ /** Gets a dummy location for the specifier. */
override Location getLocation() { override Location getLocation() {
suppressUnusedThis(this) and exists(this) and
result instanceof UnknownDefaultLocation 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 * 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. * 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)) } 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. * 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 if underlyingElement(this) instanceof @attribute_arg_type
then tail = this.getValueType().getName() then tail = this.getValueType().getName()
else
if underlyingElement(this) instanceof @attribute_arg_constant_expr
then tail = this.getValueConstant().toString()
else tail = this.getValueText() else tail = this.getValueText()
) and ) and
result = prefix + tail 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) exists(DeclStmt s | s.getADeclaration() = this and s.getEnclosingFunction() = result)
or or
exists(ConditionDeclExpr e | e.getVariable() = this and e.getEnclosingFunction() = result) 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 Type getType() { globalvariables(underlyingElement(this), unresolveElement(result), _) }
override Element getEnclosingElement() { none() } 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; @xmldtd or @xmlelement or @xmlattribute or @xmlnamespace or @xmlcomment or @xmlcharacters;
/** An XML element that has a location. */ /** An XML element that has a location. */
class XMLLocatable extends @xmllocatable, TXmlLocatable { class XmlLocatable extends @xmllocatable, TXmlLocatable {
/** Gets the source location for this element. */ /** Gets the source location for this element. */
Location getLocation() { xmllocations(this, result) } Location getLocation() { xmllocations(this, result) }
@ -32,13 +32,16 @@ class XMLLocatable extends @xmllocatable, TXmlLocatable {
string toString() { none() } // overridden in subclasses 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. * both of which can contain other elements.
*/ */
class XMLParent extends @xmlparent { class XmlParent extends @xmlparent {
XMLParent() { XmlParent() {
// explicitly restrict `this` to be either an `XMLElement` or an `XMLFile`; // explicitly restrict `this` to be either an `XmlElement` or an `XmlFile`;
// the type `@xmlparent` currently also includes non-XML files // the type `@xmlparent` currently also includes non-XML files
this instanceof @xmlelement or xmlEncoding(this, _) this instanceof @xmlelement or xmlEncoding(this, _)
} }
@ -50,28 +53,28 @@ class XMLParent extends @xmlparent {
string getName() { none() } // overridden in subclasses string getName() { none() } // overridden in subclasses
/** Gets the file to which this XML parent belongs. */ /** 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. */ /** 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. */ /** 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`. */ /** 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. */ /** 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. */ /** 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 } int getDepth() { result = 0 }
/** Gets the number of child XML elements of this XML parent. */ /** 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. */ /** Gets the number of places in the body of this XML parent where text occurs. */
int getNumberOfCharacterSets() { result = count(int pos | xmlChars(_, _, this, pos, _, _)) } int getNumberOfCharacterSets() { result = count(int pos | xmlChars(_, _, this, pos, _, _)) }
@ -92,9 +95,12 @@ class XMLParent extends @xmlparent {
string toString() { result = this.getName() } string toString() { result = this.getName() }
} }
/** DEPRECATED: Alias for XmlParent */
deprecated class XMLParent = XmlParent;
/** An XML file. */ /** An XML file. */
class XMLFile extends XMLParent, File { class XmlFile extends XmlParent, File {
XMLFile() { xmlEncoding(this, _) } XmlFile() { xmlEncoding(this, _) }
/** Gets a printable representation of this XML file. */ /** Gets a printable representation of this XML file. */
override string toString() { result = this.getName() } override string toString() { result = this.getName() }
@ -120,15 +126,21 @@ class XMLFile extends XMLParent, File {
string getEncoding() { xmlEncoding(this, result) } string getEncoding() { xmlEncoding(this, result) }
/** Gets the XML file itself. */ /** Gets the XML file itself. */
override XMLFile getFile() { result = this } override XmlFile getFile() { result = this }
/** Gets a top-most element in an XML file. */ /** 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. */ /** 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). * An XML document type definition (DTD).
* *
@ -140,7 +152,7 @@ class XMLFile extends XMLParent, File {
* <!ELEMENT lastName (#PCDATA)> * <!ELEMENT lastName (#PCDATA)>
* ``` * ```
*/ */
class XMLDTD extends XMLLocatable, @xmldtd { class XmlDtd extends XmlLocatable, @xmldtd {
/** Gets the name of the root element of this DTD. */ /** Gets the name of the root element of this DTD. */
string getRoot() { xmlDTDs(this, result, _, _, _) } string getRoot() { xmlDTDs(this, result, _, _, _) }
@ -154,7 +166,7 @@ class XMLDTD extends XMLLocatable, @xmldtd {
predicate isPublic() { not xmlDTDs(this, _, "", _, _) } predicate isPublic() { not xmlDTDs(this, _, "", _, _) }
/** Gets the parent of this DTD. */ /** Gets the parent of this DTD. */
XMLParent getParent() { xmlDTDs(this, _, _, _, result) } XmlParent getParent() { xmlDTDs(this, _, _, _, result) }
override string toString() { override string toString() {
this.isPublic() and 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. * An XML element in an XML file.
* *
@ -176,7 +191,7 @@ class XMLDTD extends XMLLocatable, @xmldtd {
* </manifest> * </manifest>
* ``` * ```
*/ */
class XMLElement extends @xmlelement, XMLParent, XMLLocatable { class XmlElement extends @xmlelement, XmlParent, XmlLocatable {
/** Holds if this XML element has the given `name`. */ /** Holds if this XML element has the given `name`. */
predicate hasName(string name) { name = this.getName() } predicate hasName(string name) { name = this.getName() }
@ -184,10 +199,10 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
override string getName() { xmlElements(this, result, _, _, _) } override string getName() { xmlElements(this, result, _, _, _) }
/** Gets the XML file in which this XML element occurs. */ /** 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. */ /** 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. */ /** Gets the index of this XML element among its parent's children. */
int getIndex() { xmlElements(this, _, _, result, _) } int getIndex() { xmlElements(this, _, _, result, _) }
@ -196,7 +211,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
predicate hasNamespace() { xmlHasNs(this, _, _) } predicate hasNamespace() { xmlHasNs(this, _, _) }
/** Gets the namespace of this XML element, if any. */ /** 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. */ /** Gets the index of this XML element among its parent's children. */
int getElementPositionIndex() { xmlElements(this, _, _, result, _) } int getElementPositionIndex() { xmlElements(this, _, _, result, _) }
@ -205,10 +220,10 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
override int getDepth() { result = this.getParent().getDepth() + 1 } override int getDepth() { result = this.getParent().getDepth() + 1 }
/** Gets an XML attribute of this XML element. */ /** 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. */ /** 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`. */ /** Holds if this XML element has an attribute with the specified `name`. */
predicate hasAttribute(string name) { exists(this.getAttribute(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() } override string toString() { result = this.getName() }
} }
/** DEPRECATED: Alias for XmlElement */
deprecated class XMLElement = XmlElement;
/** /**
* An attribute that occurs inside an XML element. * An attribute that occurs inside an XML element.
* *
@ -230,18 +248,18 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
* android:versionCode="1" * android:versionCode="1"
* ``` * ```
*/ */
class XMLAttribute extends @xmlattribute, XMLLocatable { class XmlAttribute extends @xmlattribute, XmlLocatable {
/** Gets the name of this attribute. */ /** Gets the name of this attribute. */
string getName() { xmlAttrs(this, _, result, _, _, _) } string getName() { xmlAttrs(this, _, result, _, _, _) }
/** Gets the XML element to which this attribute belongs. */ /** 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. */ /** Holds if this attribute has a namespace. */
predicate hasNamespace() { xmlHasNs(this, _, _) } predicate hasNamespace() { xmlHasNs(this, _, _) }
/** Gets the namespace of this attribute, if any. */ /** Gets the namespace of this attribute, if any. */
XMLNamespace getNamespace() { xmlHasNs(this, result, _) } XmlNamespace getNamespace() { xmlHasNs(this, result, _) }
/** Gets the value of this attribute. */ /** Gets the value of this attribute. */
string getValue() { xmlAttrs(this, _, _, result, _, _) } string getValue() { xmlAttrs(this, _, _, result, _, _) }
@ -250,6 +268,9 @@ class XMLAttribute extends @xmlattribute, XMLLocatable {
override string toString() { result = this.getName() + "=" + this.getValue() } override string toString() { result = this.getName() + "=" + this.getValue() }
} }
/** DEPRECATED: Alias for XmlAttribute */
deprecated class XMLAttribute = XmlAttribute;
/** /**
* A namespace used in an XML file. * 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" * 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. */ /** Gets the prefix of this namespace. */
string getPrefix() { xmlNs(this, result, _, _) } string getPrefix() { xmlNs(this, result, _, _) }
/** Gets the URI of this namespace. */ /** 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. */ /** Holds if this namespace has no prefix. */
predicate isDefault() { this.getPrefix() = "" } predicate isDefault() { this.getPrefix() = "" }
override string toString() { override string toString() {
this.isDefault() and result = this.getURI() this.isDefault() and result = this.getUri()
or 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. * A comment in an XML file.
* *
@ -285,17 +312,20 @@ class XMLNamespace extends XMLLocatable, @xmlnamespace {
* <!-- This is a comment. --> * <!-- This is a comment. -->
* ``` * ```
*/ */
class XMLComment extends @xmlcomment, XMLLocatable { class XmlComment extends @xmlcomment, XmlLocatable {
/** Gets the text content of this XML comment. */ /** Gets the text content of this XML comment. */
string getText() { xmlComments(this, result, _, _) } string getText() { xmlComments(this, result, _, _) }
/** Gets the parent of this XML comment. */ /** 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. */ /** Gets a printable representation of this XML comment. */
override string toString() { result = this.getText() } override string toString() { result = this.getText() }
} }
/** DEPRECATED: Alias for XmlComment */
deprecated class XMLComment = XmlComment;
/** /**
* A sequence of characters that occurs between opening and * A sequence of characters that occurs between opening and
* closing tags of an XML element, excluding other elements. * 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> * <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. */ /** Gets the content of this character sequence. */
string getCharacters() { xmlChars(this, result, _, _, _, _) } string getCharacters() { xmlChars(this, result, _, _, _, _) }
/** Gets the parent of this character sequence. */ /** Gets the parent of this character sequence. */
XMLParent getParent() { xmlChars(this, _, result, _, _, _) } XmlParent getParent() { xmlChars(this, _, result, _, _, _) }
/** Holds if this character sequence is CDATA. */ /** Holds if this character sequence is CDATA. */
predicate isCDATA() { xmlChars(this, _, _, _, 1, _) } predicate isCDATA() { xmlChars(this, _, _, _, 1, _) }
@ -319,3 +349,6 @@ class XMLCharacters extends @xmlcharacters, XMLLocatable {
/** Gets a printable representation of this XML character sequence. */ /** Gets a printable representation of this XML character sequence. */
override string toString() { result = this.getCharacters() } 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) exists(Function f | f.getBlock() = this)
or or
exists(TryStmt t, BasicBlock tryblock | 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`). // of a new `BasicBlock` (see `primitive_basic_block_entry_node`).
this.(Handler).getTryStmt() = t and this.(Handler).getTryStmt() = t and
tryblock.isReachable() and tryblock.isReachable() and

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

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

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

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

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

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

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

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

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

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

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

@ -47,6 +47,20 @@ class AssignExpr extends Assignment, @assignexpr {
override string toString() { result = "... = ..." } 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 `=`. * A non-overloaded binary assignment operation other than `=`.
* *

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

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

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

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

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

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

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

@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
else cc instanceof CallContextAny else cc instanceof CallContextAny
) and ) and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil ap = TAccessPathNil(node.getDataFlowType())
} }
predicate isAtSink() { 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`. * 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)) exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain))
or or
exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain)) exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain))
@ -76,6 +76,10 @@ private module Liveness {
not result + 1 = refRank(bb, _, v, _) 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` * Gets the (1-based) rank of the first reference to `v` inside basic block `bb`
* that is either a read or a certain write. * that is either a read or a certain write.
@ -185,23 +189,29 @@ newtype TDefinition =
private module SsaDefReaches { private module SsaDefReaches {
newtype TSsaRefKind = newtype TSsaRefKind =
SsaRead() or SsaActualRead() or
SsaPhiRead() or
SsaDef() SsaDef()
class SsaRead = SsaActualRead or SsaPhiRead;
/** /**
* A classification of SSA variable references into reads and definitions. * A classification of SSA variable references into reads and definitions.
*/ */
class SsaRefKind extends TSsaRefKind { class SsaRefKind extends TSsaRefKind {
string toString() { string toString() {
this = SsaRead() and this = SsaActualRead() and
result = "SsaRead" result = "SsaActualRead"
or
this = SsaPhiRead() and
result = "SsaPhiRead"
or or
this = SsaDef() and this = SsaDef() and
result = "SsaDef" result = "SsaDef"
} }
int getOrder() { int getOrder() {
this = SsaRead() and this instanceof SsaRead and
result = 0 result = 0
or or
this = SsaDef() and 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`, * 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` * 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. * Unlike `Liveness::ref`, this includes `phi` nodes.
*/ */
pragma[nomagic]
predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
variableRead(bb, i, v, _) and variableRead(bb, i, v, _) and
k = SsaRead() k = SsaActualRead()
or 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() k = SsaDef()
} }
@ -273,7 +362,7 @@ private module SsaDefReaches {
) )
or or
ssaDefReachesRank(bb, def, rnk - 1, v) and 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) { predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
exists(int rnk | exists(int rnk |
ssaDefReachesRank(bb, def, rnk, v) and 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) ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
} }
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) { predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) {
exists(ssaDefRank(def, v, bb, _, _)) exists(ssaDefRank(def, v, bb, _, k))
} }
pragma[noinline] pragma[noinline]
private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) { private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) {
ssaDefReachesEndOfBlock(bb, def, _) and 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), * 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`, * `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_
* and the underlying variable for `def` is neither read nor written in any block * predecessor of `bb2`, and the underlying variable for `def` is neither read
* on the path between `bb1` and `bb2`. * 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) { pragma[nomagic]
defOccursInBlock(def, bb1, _) and private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
defOccursInBlock(def, bb1, _, _) and
bb2 = getABasicBlockSuccessor(bb1) bb2 = getABasicBlockSuccessor(bb1)
or or
exists(BasicBlock mid | exists(BasicBlock mid |
varBlockReaches(def, bb1, mid) and varBlockReachesInclPhiRead(def, bb1, mid) and
ssaDefReachesThroughBlock(def, mid) and ssaDefReachesThroughBlock(def, mid) and
bb2 = getABasicBlockSuccessor(mid) 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), * 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 * the underlying variable `v` of `def` is accessed in basic block `bb2`
* successor block of `bb1`, and `def` is neither read nor written in any block * (either a read or a write), `bb2` is a transitive successor of `bb1`, and
* on a path between `bb1` and `bb2`. * `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) { predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
varBlockReaches(def, bb1, bb2) and 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 private import SsaDefReaches
pragma[nomagic] pragma[nomagic]
@ -365,7 +503,8 @@ predicate liveThrough(BasicBlock bb, SourceVariable v) {
*/ */
pragma[nomagic] pragma[nomagic]
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) { 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 ssaDefReachesRank(bb, def, last, v) and
liveAtExit(bb, v) liveAtExit(bb, v)
) )
@ -405,7 +544,7 @@ pragma[nomagic]
predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) { predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) {
ssaDefReachesReadWithinBlock(v, def, bb, i) ssaDefReachesReadWithinBlock(v, def, bb, i)
or or
variableRead(bb, i, v, _) and ssaRef(bb, i, v, any(SsaRead k)) and
ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and
not ssaDefReachesReadWithinBlock(v, _, bb, i) not ssaDefReachesReadWithinBlock(v, _, bb, i)
} }
@ -421,7 +560,7 @@ pragma[nomagic]
predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
exists(int rnk | exists(int rnk |
rnk = ssaDefRank(def, _, bb1, i1, _) and 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 variableRead(bb1, i2, _, _) and
bb2 = bb1 bb2 = bb1
) )
@ -538,18 +677,15 @@ predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Def
*/ */
pragma[nomagic] pragma[nomagic]
predicate lastRef(Definition def, BasicBlock bb, int i) { predicate lastRef(Definition def, BasicBlock bb, int i) {
// Can reach another definition
lastRefRedef(def, bb, i, _) lastRefRedef(def, bb, i, _)
or or
lastSsaRef(def, _, bb, i) and exists(SourceVariable v | lastSsaRef(def, v, bb, i) |
(
// Can reach exit directly // Can reach exit directly
bb instanceof ExitBasicBlock bb instanceof ExitBasicBlock
or or
// Can reach a block using one or more steps, where `def` is no longer live // Can reach a block using one or more steps, where `def` is no longer live
exists(BasicBlock bb2 | varBlockReaches(def, bb, bb2) | varBlockReachesExit(def, bb)
not defOccursInBlock(def, bb2, _) and
not ssaDefReachesEndOfBlock(bb2, def, _)
)
) )
} }

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

@ -22,7 +22,7 @@ module InstructionConsistency {
abstract Language::Location getLocation(); abstract Language::Location getLocation();
} }
private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
private IRFunction irFunc; private IRFunction irFunc;
PresentIRFunction() { this = TPresentIRFunction(irFunc) } PresentIRFunction() { this = TPresentIRFunction(irFunc) }
@ -37,6 +37,8 @@ module InstructionConsistency {
result = result =
min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString())
} }
IRFunction getIRFunction() { result = irFunc }
} }
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { 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.ir.internal.IRCppLanguage as Language
private import semmle.code.cpp.Print 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.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.IntegerConstant as Ints
private import semmle.code.cpp.ir.internal.IntegerInterval as Interval private import semmle.code.cpp.ir.internal.IntegerInterval as Interval
private import semmle.code.cpp.ir.implementation.internal.OperandTag 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 * Holds if the def/use information for the result of `instr` can be reused from the previous
* iteration of the IR. * iteration of the IR.
*/ */
predicate canReuseSsaForOldResult(Instruction instr) { OldSSA::canReuseSsaForMemoryResult(instr) } predicate canReuseSsaForOldResult(Instruction instr) { OldSsa::canReuseSsaForMemoryResult(instr) }
/** DEPRECATED: Alias for canReuseSsaForOldResult */ /** DEPRECATED: Alias for canReuseSsaForOldResult */
deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1; deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1;

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

@ -5,8 +5,8 @@ private import Imports::OperandTag
private import Imports::Overlap private import Imports::Overlap
private import Imports::TInstruction private import Imports::TInstruction
private import Imports::RawIR as RawIR private import Imports::RawIR as RawIR
private import SSAInstructions private import SsaInstructions
private import SSAOperands private import SsaOperands
private import NewIR private import NewIR
private class OldBlock = Reachability::ReachableBlock; 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.ReachableBlock as Reachability
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance 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.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 semmle.code.cpp.ir.internal.IRCppLanguage as Language
import AliasedSSA as Alias 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) UnaliasedSsa::SSA::hasUnreachedInstruction(irFunc)
} or } or
TAliasedSsaPhiInstruction( TAliasedSsaPhiInstruction(
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation TRawInstruction blockStartInstr, AliasedSsa::SSA::MemoryLocation memoryLocation
) { ) {
AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) AliasedSsa::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
} or } or
TAliasedSsaChiInstruction(TRawInstruction primaryInstruction) { TAliasedSsaChiInstruction(TRawInstruction primaryInstruction) {
AliasedSSA::SSA::hasChiInstruction(primaryInstruction) AliasedSsa::SSA::hasChiInstruction(primaryInstruction)
} or } or
TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) { TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
AliasedSSA::SSA::hasUnreachedInstruction(irFunc) AliasedSsa::SSA::hasUnreachedInstruction(irFunc)
} }
/** /**
@ -83,7 +83,7 @@ module AliasedSsaInstructions {
class TPhiInstruction = TAliasedSsaPhiInstruction or TUnaliasedSsaPhiInstruction; class TPhiInstruction = TAliasedSsaPhiInstruction or TUnaliasedSsaPhiInstruction;
TPhiInstruction phiInstruction( TPhiInstruction phiInstruction(
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation TRawInstruction blockStartInstr, AliasedSsa::SSA::MemoryLocation memoryLocation
) { ) {
result = TAliasedSsaPhiInstruction(blockStartInstr, memoryLocation) result = TAliasedSsaPhiInstruction(blockStartInstr, memoryLocation)
} }

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

@ -1,4 +1,7 @@
import semmle.code.cpp.ir.internal.IRCppLanguage as Language 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.raw.internal.IRConstruction as IRConstruction
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSsa 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(); abstract Language::Location getLocation();
} }
private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
private IRFunction irFunc; private IRFunction irFunc;
PresentIRFunction() { this = TPresentIRFunction(irFunc) } PresentIRFunction() { this = TPresentIRFunction(irFunc) }
@ -37,6 +37,8 @@ module InstructionConsistency {
result = result =
min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString())
} }
IRFunction getIRFunction() { result = irFunc }
} }
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {

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

@ -1450,8 +1450,6 @@ class TranslatedAssignExpr extends TranslatedNonConstantExpr {
result = this.getLeftOperand().getResult() result = this.getLeftOperand().getResult()
} }
abstract Instruction getStoredValue();
final TranslatedExpr getLeftOperand() { final TranslatedExpr getLeftOperand() {
result = getTranslatedExpr(expr.getLValue().getFullyConverted()) 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 { class TranslatedAssignOperation extends TranslatedNonConstantExpr {
override AssignOperation expr; override AssignOperation expr;

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

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

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

@ -5,8 +5,8 @@ private import Imports::OperandTag
private import Imports::Overlap private import Imports::Overlap
private import Imports::TInstruction private import Imports::TInstruction
private import Imports::RawIR as RawIR private import Imports::RawIR as RawIR
private import SSAInstructions private import SsaInstructions
private import SSAOperands private import SsaOperands
private import NewIR private import NewIR
private class OldBlock = Reachability::ReachableBlock; 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.raw.internal.reachability.Dominance as Dominance
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR 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.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 semmle.code.cpp.ir.internal.IRCppLanguage as Language
import SimpleSSA as Alias 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 exists(target.getReallocPtrArg()) and
this.getArgument(target.getSizeArg()).getValue().toInt() = 0 this.getArgument(target.getSizeArg()).getValue().toInt() = 0
) and ) 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) not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
} }

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

@ -11,12 +11,6 @@ private class StdPair extends ClassTemplateInstantiation {
StdPair() { this.hasQualifiedName(["std", "bsl"], "pair") } 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 * 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 * 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() } 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. * 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); 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. */ /** A library function that sends data over a network connection. */
abstract class RemoteFlowSinkFunction extends Function { 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. * Holds if `e` potentially overflows and `use` is an operand of `e` that is not guarded.
*/ */
predicate missingGuardAgainstOverflow(Operation e, VariableAccess use) { 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 // an `AssignArithmeticOperation` by the other constraints in this predicate, we know that
// `convertedExprMightOverflowPositively` will have a result even when `e` is not analyzable // `convertedExprMightOverflowPositively` will have a result even when `e` is not analyzable
// by `SimpleRangeAnalysis`. // 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. * Holds if `e` potentially underflows and `use` is an operand of `e` that is not guarded.
*/ */
predicate missingGuardAgainstUnderflow(Operation e, VariableAccess use) { 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 // an `AssignArithmeticOperation` by the other constraints in this predicate, we know that
// `convertedExprMightOverflowNegatively` will have a result even when `e` is not analyzable // `convertedExprMightOverflowNegatively` will have a result even when `e` is not analyzable
// by `SimpleRangeAnalysis`. // by `SimpleRangeAnalysis`.

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

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

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

@ -68,7 +68,7 @@ class BooleanControllingAssignmentInExpr extends BooleanControllingAssignment {
// if((a = b) && use_value(a)) { ... } // 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 // 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 this.isParenthesised() and
exists(LogicalAndExpr parent, Variable var, VariableAccess access | exists(LogicalAndExpr parent, Variable var, VariableAccess access |
var = this.getLValue().(VariableAccess).getTarget() and var = this.getLValue().(VariableAccess).getTarget() and

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

@ -51,7 +51,7 @@ predicate illDefinedDecrForStmt(
( (
upperBound(initialCondition) < lowerBound(terminalCondition) and 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 v.getUnspecifiedType().(IntegralType).isSigned() or
initialCondition.getValue().toInt() = 0 initialCondition.getValue().toInt() = 0
) )

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

@ -18,6 +18,7 @@
import cpp import cpp
import Buffer import Buffer
private import semmle.code.cpp.valuenumbering.GlobalValueNumbering private import semmle.code.cpp.valuenumbering.GlobalValueNumbering
private import semmle.code.cpp.models.implementations.Strcpy
predicate isSizePlus(Expr e, BufferSizeExpr baseSize, int plus) { predicate isSizePlus(Expr e, BufferSizeExpr baseSize, int plus) {
// baseSize // 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) { string nthString(int num) {
num = 0 and num = 0 and
result = "first" result = "first"
@ -96,11 +70,13 @@ int arrayExprFixedSize(Expr e) {
} }
from from
Function f, FunctionCall fc, int argDest, int argSrc, int argLimit, int charSize, Access copyDest, StrcpyFunction f, FunctionCall fc, int argDest, int argSrc, int argLimit, int charSize,
Access copySource, string name, string nth Access copyDest, Access copySource, string name, string nth
where where
f = fc.getTarget() and 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 copyDest = fc.getArgument(argDest) and
copySource = fc.getArgument(argSrc) and copySource = fc.getArgument(argSrc) and
// Some of the functions operate on a larger char type, like `wchar_t`, so we // Some of the functions operate on a larger char type, like `wchar_t`, so we

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

@ -106,6 +106,26 @@ predicate inheritanceConversionTypes(
toType = convert.getResultType() 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. */ /** Gets the HashCons value of an address computed by `instr`, if any. */
TGlobalAddress globalAddress(Instruction instr) { TGlobalAddress globalAddress(Instruction instr) {
result = TGlobalVariable(instr.(VariableAddressInstruction).getAstVariable()) result = TGlobalVariable(instr.(VariableAddressInstruction).getAstVariable())
@ -117,25 +137,27 @@ TGlobalAddress globalAddress(Instruction instr) {
result = TLoad(globalAddress(load.getSourceAddress())) result = TLoad(globalAddress(load.getSourceAddress()))
) )
or or
exists(ConvertInstruction convert, Type fromType, Type toType | instr = convert | exists(Type fromType, Type toType, Instruction unary |
uncheckedConversionTypes(convert, fromType, toType) and Conversion<ConvertInstruction>::Using<uncheckedConversionTypes/3>::hasOperandAndTypes(instr,
result = TConversion("unchecked", globalAddress(convert.getUnary()), fromType, toType) unary, fromType, toType) and
result = TConversion("unchecked", globalAddress(unary), fromType, toType)
) )
or or
exists(CheckedConvertOrNullInstruction convert, Type fromType, Type toType | instr = convert | exists(Type fromType, Type toType, Instruction unary |
checkedConversionTypes(convert, fromType, toType) and Conversion<CheckedConvertOrNullInstruction>::Using<checkedConversionTypes/3>::hasOperandAndTypes(instr,
result = TConversion("checked", globalAddress(convert.getUnary()), fromType, toType) unary, fromType, toType) and
result = TConversion("checked", globalAddress(unary), fromType, toType)
) )
or or
exists(InheritanceConversionInstruction convert, Type fromType, Type toType | instr = convert | exists(Type fromType, Type toType, Instruction unary |
inheritanceConversionTypes(convert, fromType, toType) and Conversion<InheritanceConversionInstruction>::Using<inheritanceConversionTypes/3>::hasOperandAndTypes(instr,
result = TConversion("inheritance", globalAddress(convert.getUnary()), fromType, toType) unary, fromType, toType) and
result = TConversion("inheritance", globalAddress(unary), fromType, toType)
) )
or or
exists(FieldAddressInstruction fai | instr = fai | exists(FieldAddressInstruction fai, Instruction object, Field f | instr = fai |
result = hasObjectAndField(fai, object, f) and
TFieldAddress(globalAddress(pragma[only_bind_into](fai.getObjectAddress())), result = TFieldAddress(globalAddress(object), f)
pragma[only_bind_out](fai.getField()))
) )
or or
result = globalAddress(instr.(PointerOffsetInstruction).getLeft()) result = globalAddress(instr.(PointerOffsetInstruction).getLeft())
@ -268,7 +290,11 @@ class PathElement extends TPathElement {
predicate isSink(IRBlock block) { exists(this.asSink(block)) } predicate isSink(IRBlock block) { exists(this.asSink(block)) }
string toString() { 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( 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. S. Meyers. <em>Effective C++ 3d ed.</em> pp 40-44. Addison-Wesley Professional, 2005.
</li> </li>
<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> </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: Alias for UntrustedExternalApiDataNode */
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode; deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
/** An external API which is used with untrusted data. */
private newtype TExternalApi = private newtype TExternalApi =
/** An untrusted API method `m` where untrusted data is passed at `index`. */
TExternalApiParameter(Function f, int index) { TExternalApiParameter(Function f, int index) {
exists(UntrustedExternalApiDataNode n | exists(UntrustedExternalApiDataNode n |
f = n.getExternalFunction() and f = n.getExternalFunction() and

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

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

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

@ -19,6 +19,7 @@ import semmle.code.cpp.security.Security
import semmle.code.cpp.valuenumbering.GlobalValueNumbering import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.ir.IR import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.dataflow.TaintTracking import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.ir.dataflow.TaintTracking2
import semmle.code.cpp.security.FlowSources import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.models.implementations.Strcat import semmle.code.cpp.models.implementations.Strcat
import DataFlow::PathGraph import DataFlow::PathGraph
@ -83,6 +84,32 @@ class ExecState extends DataFlow::FlowState {
DataFlow::Node getFstNode() { result = fst } DataFlow::Node getFstNode() { result = fst }
DataFlow::Node getSndNode() { result = snd } 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 { class ExecTaintConfiguration extends TaintTracking::Configuration {
@ -94,8 +121,8 @@ class ExecTaintConfiguration extends TaintTracking::Configuration {
} }
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
shellCommand(sinkAsArgumentIndirection(sink), _) and any(ExecStateConfiguration conf).isSink(sink) and
state instanceof ExecState state.(ExecState).isFeasibleForSink(sink)
} }
override predicate isAdditionalTaintStep( override predicate isAdditionalTaintStep(

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

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

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

@ -17,33 +17,33 @@ import semmle.code.cpp.controlflow.IRGuards
/** /**
* A call to `SSL_get_peer_certificate`. * A call to `SSL_get_peer_certificate`.
*/ */
class SSLGetPeerCertificateCall extends FunctionCall { class SslGetPeerCertificateCall extends FunctionCall {
SSLGetPeerCertificateCall() { SslGetPeerCertificateCall() {
getTarget().getName() = "SSL_get_peer_certificate" // SSL_get_peer_certificate(ssl) 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`. * A call to `SSL_get_verify_result`.
*/ */
class SSLGetVerifyResultCall extends FunctionCall { class SslGetVerifyResultCall extends FunctionCall {
SSLGetVerifyResultCall() { SslGetVerifyResultCall() {
getTarget().getName() = "SSL_get_verify_result" // SSL_get_peer_certificate(ssl) 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 * Holds if the SSL object passed into `SSL_get_peer_certificate` is checked with
* `SSL_get_verify_result` entering `node`. * `SSL_get_verify_result` entering `node`.
*/ */
predicate resultIsChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node) { predicate resultIsChecked(SslGetPeerCertificateCall getCertCall, ControlFlowNode node) {
exists(Expr ssl, SSLGetVerifyResultCall check | exists(Expr ssl, SslGetVerifyResultCall check |
ssl = globalValueNumber(getCertCall.getSSLArgument()).getAnExpr() and ssl = globalValueNumber(getCertCall.getSslArgument()).getAnExpr() and
ssl = check.getSSLArgument() and ssl = check.getSslArgument() and
node = check node = check
) )
} }
@ -53,7 +53,7 @@ predicate resultIsChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode
* `0` on the edge `node1` to `node2`. * `0` on the edge `node1` to `node2`.
*/ */
predicate certIsZero( predicate certIsZero(
SSLGetPeerCertificateCall getCertCall, ControlFlowNode node1, ControlFlowNode node2 SslGetPeerCertificateCall getCertCall, ControlFlowNode node1, ControlFlowNode node2
) { ) {
exists(Expr cert | cert = globalValueNumber(getCertCall).getAnExpr() | exists(Expr cert | cert = globalValueNumber(getCertCall).getAnExpr() |
exists(GuardCondition guard, Expr zero | 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_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. * `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` // cert is not checked at the call to `SSL_get_peer_certificate`
node = getCertCall node = getCertCall
or or
@ -112,7 +112,7 @@ predicate certNotChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode
) )
} }
from SSLGetPeerCertificateCall getCertCall, ControlFlowNode node from SslGetPeerCertificateCall getCertCall, ControlFlowNode node
where where
certNotChecked(getCertCall, node) and certNotChecked(getCertCall, node) and
node instanceof Function // (function exit) 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 isSource(DataFlow::Node source) { source instanceof FlowSource }
override predicate isSanitizer(DataFlow::Node node) {
node.asExpr().getUnspecifiedType() instanceof IntegralType
}
override predicate isSink(DataFlow::Node sink) { override predicate isSink(DataFlow::Node sink) {
exists(BufferWrite::BufferWrite w | w.getASource() = sink.asExpr()) 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()`. * Data originating from a call to `mysql_get_client_info()`.
*/ */
class SQLClientInfo extends SystemData { class SqlClientInfo extends SystemData {
SQLClientInfo() { this.(FunctionCall).getTarget().hasName("mysql_get_client_info") } SqlClientInfo() { this.(FunctionCall).getTarget().hasName("mysql_get_client_info") }
override DataFlow::Node getAnExpr() { result.asConvertedExpr() = this } override DataFlow::Node getAnExpr() { result.asConvertedExpr() = this }
override predicate isSensitive() { any() } override predicate isSensitive() { any() }
} }
/** DEPRECATED: Alias for SqlClientInfo */
deprecated class SQLClientInfo = SqlClientInfo;
private predicate sqlConnectInfo(FunctionCall source, Expr use) { private predicate sqlConnectInfo(FunctionCall source, Expr use) {
( (
source.getTarget().hasName("mysql_connect") or source.getTarget().hasName("mysql_connect") or
@ -66,14 +69,17 @@ private predicate sqlConnectInfo(FunctionCall source, Expr use) {
/** /**
* Data passed into an SQL connect function. * Data passed into an SQL connect function.
*/ */
class SQLConnectInfo extends SystemData { class SqlConnectInfo extends SystemData {
SQLConnectInfo() { sqlConnectInfo(this, _) } SqlConnectInfo() { sqlConnectInfo(this, _) }
override DataFlow::Node getAnExpr() { sqlConnectInfo(this, result.asConvertedExpr()) } override DataFlow::Node getAnExpr() { sqlConnectInfo(this, result.asConvertedExpr()) }
override predicate isSensitive() { any() } override predicate isSensitive() { any() }
} }
/** DEPRECATED: Alias for SqlConnectInfo */
deprecated class SQLConnectInfo = SqlConnectInfo;
private predicate posixSystemInfo(FunctionCall source, DataFlow::Node use) { private predicate posixSystemInfo(FunctionCall source, DataFlow::Node use) {
// size_t confstr(int name, char *buf, size_t len) // size_t confstr(int name, char *buf, size_t len)
// - various OS / system strings, such as the libc version // - 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 | exists(FunctionCall fc |
fc = exp and 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 fc.getTarget().hasName(["mbtowc", "mbrtowc", "_mbtowc_l"]) and
not fc.getArgument(0).isConstant() and not fc.getArgument(0).isConstant() and
not fc.getArgument(1).isConstant() and not fc.getArgument(1).isConstant() and

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

@ -44,11 +44,8 @@ predicate conversionDoneLate(MulExpr mexp) {
mexp.getEnclosingElement().(ComparisonOperation).hasOperands(mexp, e0) and mexp.getEnclosingElement().(ComparisonOperation).hasOperands(mexp, e0) and
e0.getType().getSize() = mexp.getConversion().getConversion().getType().getSize() e0.getType().getSize() = mexp.getConversion().getConversion().getType().getSize()
or or
e0.(FunctionCall) e0.(FunctionCall).getTarget().getParameter(argumentPosition(e0, mexp, _)).getType().getSize() =
.getTarget() mexp.getConversion().getConversion().getType().getSize()
.getParameter(argumentPosition(e0.(FunctionCall), mexp, _))
.getType()
.getSize() = mexp.getConversion().getConversion().getType().getSize()
) )
) )
} }
@ -75,7 +72,7 @@ predicate signSmallerWithEqualSizes(MulExpr mexp) {
ae.getRValue().getUnderlyingType().(IntegralType).isUnsigned() and ae.getRValue().getUnderlyingType().(IntegralType).isUnsigned() and
ae.getLValue().getUnderlyingType().(IntegralType).isSigned() and ae.getLValue().getUnderlyingType().(IntegralType).isSigned() and
( (
not exists(DivExpr de | mexp.getParent*() = de) not mexp.getParent*() instanceof DivExpr
or or
exists(DivExpr de, Expr ec | exists(DivExpr de, Expr ec |
e2.isConstant() and 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. S. Meyers. <em>Effective C++ 3d ed.</em> pp 40-44. Addison-Wesley Professional, 2005.
</li> </li>
<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> </li>

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

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

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

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

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

@ -13,7 +13,7 @@
import cpp import cpp
private import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as IRDataFlow 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 import TestUtilities.InlineExpectationsTest
class IRFlowTest extends InlineExpectationsTest { class IRFlowTest extends InlineExpectationsTest {
@ -49,11 +49,11 @@ class AstFlowTest extends InlineExpectationsTest {
override predicate hasActualResult(Location location, string element, string tag, string value) { override predicate hasActualResult(Location location, string element, string tag, string value) {
exists( 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 tag = "ast" and
conf.hasFlow(source, sink) 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 = "" n = 1 and value = ""
or 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 | array to pointer conversion |
| strlen.cpp:11:39:11:48 | file.ext | | strlen.cpp:11:39:11:48 | file.ext |
| strlen.cpp:12:35:12:40 | call to strlen | | strlen.cpp:12:35:12:40 | call to strlen |

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

@ -4,7 +4,7 @@
*/ */
import cpp 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 semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
import IRDefaultTaintTracking::TaintedWithPath as TaintedWithPath import IRDefaultTaintTracking::TaintedWithPath as TaintedWithPath
import TaintedWithPath::Private 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 { class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration {
override predicate isSink(Element e) { isSinkArgument(e) } override predicate isSink(Element e) { isSinkArgument(e) }

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