Merge remote-tracking branch 'upstream/main' into addsub

This commit is contained in:
Geoffrey White
2026-01-22 16:03:42 +00:00
370 changed files with 64480 additions and 8879 deletions

View File

@@ -17,9 +17,41 @@ permissions:
contents: read
jobs:
compile-queries:
detect-changes:
if: github.repository_owner == 'github'
runs-on: ubuntu-latest
outputs:
languages: ${{ steps.detect.outputs.languages }}
steps:
- uses: actions/checkout@v5
- name: Detect changed languages
id: detect
run: |
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
# For PRs, detect which languages have changes
changed_files=$(gh pr view ${{ github.event.pull_request.number }} --json files --jq '.files.[].path')
languages=()
for lang in actions cpp csharp go java javascript python ql ruby rust swift; do
if echo "$changed_files" | grep -qE "^($lang/|shared/)" ; then
languages+=("$lang")
fi
done
echo "languages=$(jq -c -n '$ARGS.positional' --args "${languages[@]}")" >> $GITHUB_OUTPUT
else
# For pushes to main/rc branches, run all languages
echo 'languages=["actions","cpp","csharp","go","java","javascript","python","ql","ruby","rust","swift"]' >> $GITHUB_OUTPUT
fi
env:
GH_TOKEN: ${{ github.token }}
compile-queries:
needs: detect-changes
if: github.repository_owner == 'github' && needs.detect-changes.outputs.languages != '[]'
runs-on: ubuntu-latest-xl
strategy:
fail-fast: false
matrix:
language: ${{ fromJson(needs.detect-changes.outputs.languages) }}
steps:
- uses: actions/checkout@v5
@@ -31,16 +63,16 @@ jobs:
id: query-cache
uses: ./.github/actions/cache-query-compilation
with:
key: all-queries
key: ${{ matrix.language }}-queries
- name: check formatting
run: find shared */ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 -n 3000 -P 10 codeql query format -q --check-only
run: find shared ${{ matrix.language }}/ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 -n 3000 -P 10 codeql query format -q --check-only
- name: compile queries - check-only
# run with --check-only if running in a PR (github.sha != main)
if : ${{ github.event_name == 'pull_request' }}
shell: bash
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
run: codeql query compile -q -j0 ${{ matrix.language }}/ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
- name: compile queries - full
# do full compile if running on main - this populates the cache
if : ${{ github.event_name != 'pull_request' }}
shell: bash
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
run: codeql query compile -q -j0 ${{ matrix.language }}/ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000

View File

@@ -27,6 +27,7 @@ jobs:
uses: github/codeql-action/init@main
with:
languages: javascript # does not matter
tools: nightly
- uses: ./.github/actions/os-version
id: os_version
### Build the extractor ###

View File

@@ -30,6 +30,7 @@ jobs:
uses: github/codeql-action/init@main
with:
languages: javascript # does not matter
tools: nightly
- uses: ./.github/actions/os-version
id: os_version
- uses: actions/cache@v3
@@ -75,6 +76,7 @@ jobs:
uses: github/codeql-action/init@main
with:
languages: javascript # does not matter
tools: nightly
- uses: ./.github/actions/os-version
id: os_version
- uses: actions/cache@v3

View File

@@ -0,0 +1,4 @@
---
lockVersion: 1.0.0
dependencies: {}
compiled: false

View File

@@ -0,0 +1,7 @@
name: codeql/actions-examples
groups:
- actions
- examples
dependencies:
codeql/actions-all: ${workspace}
warnOnImplicitThis: true

View File

@@ -0,0 +1,12 @@
/**
* @name Uses step with pinned SHA
* @description Finds 'uses' steps where the version is a pinned SHA.
* @id actions/examples/uses-pinned-sha
* @tags example
*/
import actions
from UsesStep uses
where uses.getVersion().regexpMatch("^[A-Fa-f0-9]{40}$")
select uses, "This 'uses' step has a pinned SHA version."

View File

@@ -1,3 +1,9 @@
## 0.4.26
### Major Analysis Improvements
* The query `actions/code-injection/medium` has been updated to include results which were incorrectly excluded while filtering out results that are reported by `actions/code-injection/critical`.
## 0.4.25
No user-facing changes.

View File

@@ -1,4 +1,5 @@
---
category: majorAnalysis
---
## 0.4.26
### Major Analysis Improvements
* The query `actions/code-injection/medium` has been updated to include results which were incorrectly excluded while filtering out results that are reported by `actions/code-injection/critical`.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.4.25
lastReleaseVersion: 0.4.26

View File

@@ -1,5 +1,5 @@
name: codeql/actions-all
version: 0.4.26-dev
version: 0.4.27-dev
library: true
warnOnImplicitThis: true
dependencies:

View File

@@ -1,3 +1,7 @@
## 0.6.18
No user-facing changes.
## 0.6.17
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 0.6.18
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.6.17
lastReleaseVersion: 0.6.18

View File

@@ -1,5 +1,5 @@
name: codeql/actions-queries
version: 0.6.18-dev
version: 0.6.19-dev
library: false
warnOnImplicitThis: true
groups: [actions, queries]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Sections for databaseMetadata and overlayChangedFiles
compatibility: full

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
class PreprocessorDirective extends @preprocdirect {
string toString() { none() }
}
class Location extends @location_default {
string toString() { none() }
}
from PreprocessorDirective ppd, int kind, int kind_new, Location l
where
preprocdirects(ppd, kind, l) and
if kind = 17 then kind_new = /* ppd_warning */ 18 else kind_new = kind
select ppd, kind_new, l

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
description: Support embed preprocessor directive
compatibility: partial
embeds.rel: delete
preprocdirects.rel: run preprocdirects.qlo

View File

@@ -1,3 +1,27 @@
## 7.0.0
### Breaking Changes
* The `_Decimal32`, `_Decimal64`, and `_Decimal128` types are no longer exposed as builtin types. Support for these gcc-specific types was incomplete, and are generally not used in C/C++ codebases.
### Deprecated APIs
* The `OverloadedArrayExpr::getArrayOffset/0` predicate has been deprecated. Use `OverloadedArrayExpr::getArrayOffset/1` and `OverloadedArrayExpr::getAnArrayOffset` instead.
### New Features
* Added subclasses of `BuiltInOperations` for the `__is_bitwise_cloneable`, `__is_invocable`, and `__is_nothrow_invocable` builtin operations.
* Added a `isThisAccess` predicate to `ParamAccessForType` that holds when the access is to the implicit object parameter.
* Predicates `getArrayOffset/1` and `getAnArrayOffset` have been added to the `OverloadedArrayExpr` class to support C++23 multidimensional subscript operators.
### Minor Analysis Improvements
* Some constants will now be represented by their unfolded expression trees. The `isConstant` predicate of `Expr` will no longer yield a result for those constants.
### Bug Fixes
* Fixed a bug in the `DataFlow::BarrierGuard<...>::getABarrierNode` predicate which caused the predicate to return `DataFlow::Node`s with incorrect indirections. If you use `getABarrierNode` to implement barriers in a dataflow/taint-tracking query it may result in more query results. You can use `DataFlow::BarrierGuard<...>::getAnIndirectBarrierNode` to remove those query results.
## 6.1.4
No user-facing changes.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Some constants will now be represented by their unfolded expression trees. The `isConstant` predicate of `Expr` will no longer yield a result for those constants.

View File

@@ -1,4 +0,0 @@
---
category: breaking
---
* The `_Decimal32`, `_Decimal64`, and `_Decimal128` types are no longer exposed as builtin types. Support for these gcc-specific types was incomplete, and are generally not used in C/C++ codebases.

View File

@@ -1,4 +0,0 @@
---
category: feature
---
* Predicates `getArrayOffset/1` and `getAnArrayOffset` have been added to the `OverloadedArrayExpr` class to support C++23 multidimensional subscript operators.

View File

@@ -1,4 +0,0 @@
---
category: deprecated
---
* The `OverloadedArrayExpr::getArrayOffset/0` predicate has been deprecated. Use `OverloadedArrayExpr::getArrayOffset/1` and `OverloadedArrayExpr::getAnArrayOffset` instead.

View File

@@ -1,4 +0,0 @@
---
category: feature
---
* Added subclasses of `BuiltInOperations` for the `__is_bitwise_cloneable`, `__is_invocable`, and `__is_nothrow_invocable` builtin operations.

View File

@@ -1,4 +0,0 @@
---
category: feature
---
* Added a `isThisAccess` predicate to `ParamAccessForType` that holds when the access is to the implicit object parameter.

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* Added a subclass `Embed` of `PreprocessorDirective` for C23 and C++26 `#embed` preprocessor directives.

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* Added modules `DataFlow::ParameterizedBarrierGuard` and `DataFlow::ParameterizedInstructionBarrierGuard`. These modules provide the same features as `DataFlow::BarrierGuard` and `DataFlow::InstructionBarrierGuard`, but allow for an additional parameter to support properly using them in dataflow configurations that uses flow states.

View File

@@ -0,0 +1,23 @@
## 7.0.0
### Breaking Changes
* The `_Decimal32`, `_Decimal64`, and `_Decimal128` types are no longer exposed as builtin types. Support for these gcc-specific types was incomplete, and are generally not used in C/C++ codebases.
### Deprecated APIs
* The `OverloadedArrayExpr::getArrayOffset/0` predicate has been deprecated. Use `OverloadedArrayExpr::getArrayOffset/1` and `OverloadedArrayExpr::getAnArrayOffset` instead.
### New Features
* Added subclasses of `BuiltInOperations` for the `__is_bitwise_cloneable`, `__is_invocable`, and `__is_nothrow_invocable` builtin operations.
* Added a `isThisAccess` predicate to `ParamAccessForType` that holds when the access is to the implicit object parameter.
* Predicates `getArrayOffset/1` and `getAnArrayOffset` have been added to the `OverloadedArrayExpr` class to support C++23 multidimensional subscript operators.
### Minor Analysis Improvements
* Some constants will now be represented by their unfolded expression trees. The `isConstant` predicate of `Expr` will no longer yield a result for those constants.
### Bug Fixes
* Fixed a bug in the `DataFlow::BarrierGuard<...>::getABarrierNode` predicate which caused the predicate to return `DataFlow::Node`s with incorrect indirections. If you use `getABarrierNode` to implement barriers in a dataflow/taint-tracking query it may result in more query results. You can use `DataFlow::BarrierGuard<...>::getAnIndirectBarrierNode` to remove those query results.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 6.1.4
lastReleaseVersion: 7.0.0

View File

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

View File

@@ -192,6 +192,15 @@ class Element extends ElementBase {
*/
predicate isAffectedByMacro() { affectedByMacro(this) }
/**
* INTERNAL: Do not use.
*
* Holds if this element is affected by the expansion of `mi`.
*/
predicate isAffectedByMacro(MacroInvocation mi) {
affectedbymacroexpansion(underlyingElement(this), unresolveElement(mi))
}
private Element getEnclosingElementPref() {
enclosingfunction(underlyingElement(this), unresolveElement(result)) or
result.(Function) = stmtEnclosingElement(this) or

View File

@@ -239,6 +239,9 @@ class MacroInvocation extends MacroAccess {
macro_argument_unexpanded(underlyingElement(this), i, result)
}
/** Gets the number of arguments for this macro invocation. */
int getNumberOfArguments() { result = count(int i | exists(this.getUnexpandedArgument(i)) | i) }
/**
* Gets the `i`th _expanded_ argument of this macro invocation, where the
* first argument has `i = 0`. The result has been expanded for macros _and_

View File

@@ -328,3 +328,27 @@ class PreprocessorPragma extends PreprocessorDirective, @ppd_pragma {
class PreprocessorLine extends PreprocessorDirective, @ppd_line {
override string toString() { result = "#line " + this.getHead() }
}
/**
* A C23 or C++26 `#embed` preprocessor directive. For example, the following code
* contains one `Embed` directive:
* ```cpp
* char arr[] = {
* #embed "bin"
* };
* ```
*/
class Embed extends PreprocessorDirective, @ppd_embed {
override string toString() { result = "#embed " + this.getIncludeText() }
/**
* Gets the token which occurs after `#embed`, for example `"filename"`
* or `<filename>`.
*/
string getIncludeText() { result = this.getHead() }
/**
* Gets the file directly embedded by this `#embed`.
*/
File getEmbeddedFile() { embeds(underlyingElement(this), unresolveElement(result)) }
}

View File

@@ -95,6 +95,7 @@
import cpp
private import new.DataFlow
private import semmle.code.cpp.controlflow.IRGuards
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as Private
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import internal.FlowSummaryImpl
@@ -367,6 +368,8 @@ private predicate elementSpec(
) {
sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or
sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or
barrierModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or
barrierGuardModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, _) or
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, _)
}
@@ -1028,6 +1031,84 @@ private module Cached {
isSinkNode(n, kind, model) and n.asNode() = node
)
}
private newtype TKindModelPair =
TMkPair(string kind, string model) { isBarrierGuardNode(_, _, kind, model) }
private GuardValue convertAcceptingValue(Public::AcceptingValue av) {
av.isTrue() and result.asBooleanValue() = true
or
av.isFalse() and result.asBooleanValue() = false
or
// NOTE: The below cases don't contribute anything currently since the
// callers immediately use `.asBooleanValue()` to convert the `GuardValue`
// to a boolean. Once we're willing to accept the breaking change of
// converting the barrier guard API to use `GuardValue`s instead `Boolean`s
// we can remove this restriction.
av.isNoException() and result.getDualValue().isThrowsException()
or
av.isZero() and result.asIntValue() = 0
or
av.isNotZero() and result.getDualValue().asIntValue() = 0
or
av.isNull() and result.isNullValue()
or
av.isNotNull() and result.isNonNullValue()
}
private predicate barrierGuardChecks(IRGuardCondition g, Expr e, boolean gv, TKindModelPair kmp) {
exists(
SourceSinkInterpretationInput::InterpretNode n, Public::AcceptingValue acceptingvalue,
string kind, string model
|
isBarrierGuardNode(n, acceptingvalue, kind, model) and
n.asNode().asExpr() = e and
kmp = TMkPair(kind, model) and
gv = convertAcceptingValue(acceptingvalue).asBooleanValue() and
n.asNode().(Private::ArgumentNode).getCall().asCallInstruction() = g
)
}
private newtype TKindModelPairIntPair =
MkKindModelPairIntPair(TKindModelPair pair, int indirectionIndex) {
indirectionIndex > 0 and
Private::nodeHasInstruction(_, _, indirectionIndex) and
exists(pair)
}
private predicate indirectBarrierGuardChecks(
IRGuardCondition g, Expr e, boolean gv, TKindModelPairIntPair kmp
) {
exists(
SourceSinkInterpretationInput::InterpretNode interpretNode,
Public::AcceptingValue acceptingvalue, string kind, string model, int indirectionIndex,
Private::ArgumentNode arg
|
isBarrierGuardNode(interpretNode, acceptingvalue, kind, model) and
arg = interpretNode.asNode() and
arg.asIndirectExpr(indirectionIndex) = e and
kmp = MkKindModelPairIntPair(TMkPair(kind, model), indirectionIndex) and
gv = convertAcceptingValue(acceptingvalue).asBooleanValue() and
arg.getCall().asCallInstruction() = g
)
}
/**
* Holds if `node` is specified as a barrier with the given kind in a MaD flow
* model.
*/
cached
predicate barrierNode(DataFlow::Node node, string kind, string model) {
exists(SourceSinkInterpretationInput::InterpretNode n |
isBarrierNode(n, kind, model) and n.asNode() = node
)
or
DataFlow::ParameterizedBarrierGuard<TKindModelPair, barrierGuardChecks/4>::getABarrierNode(TMkPair(kind,
model)) = node
or
DataFlow::ParameterizedBarrierGuard<TKindModelPairIntPair, indirectBarrierGuardChecks/4>::getAnIndirectBarrierNode(MkKindModelPairIntPair(TMkPair(kind,
model), _)) = node
}
}
import Cached
@@ -1044,6 +1125,12 @@ predicate sourceNode(DataFlow::Node node, string kind) { sourceNode(node, kind,
*/
predicate sinkNode(DataFlow::Node node, string kind) { sinkNode(node, kind, _) }
/**
* Holds if `node` is specified as a barrier with the given kind in a MaD flow
* model.
*/
predicate barrierNode(DataFlow::Node node, string kind) { barrierNode(node, kind, _) }
private predicate interpretSummary(
Function f, string input, string output, string kind, string provenance, string model
) {

View File

@@ -149,16 +149,27 @@ module SourceSinkInterpretationInput implements
}
predicate barrierElement(
Element n, string output, string kind, Public::Provenance provenance, string model
Element e, string output, string kind, Public::Provenance provenance, string model
) {
none()
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
barrierModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance, model) and
e = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}
predicate barrierGuardElement(
Element n, string input, Public::AcceptingValue acceptingvalue, string kind,
Element e, string input, Public::AcceptingValue acceptingvalue, string kind,
Public::Provenance provenance, string model
) {
none()
exists(
string package, string type, boolean subtypes, string name, string signature, string ext
|
barrierGuardModel(package, type, subtypes, name, signature, ext, input, acceptingvalue, kind,
provenance, model) and
e = interpretElement(package, type, subtypes, name, signature, ext)
)
}
private newtype TInterpretNode =

View File

@@ -23,7 +23,7 @@ class Expr extends StmtParent, @expr {
predicate hasChild(Expr e, int n) { e = this.getChild(n) }
/** Gets the enclosing function of this expression, if any. */
Function getEnclosingFunction() { result = exprEnclosingElement(this) }
override Function getEnclosingFunction() { result = exprEnclosingElement(this) }
/** Gets the nearest enclosing set of curly braces around this expression in the source, if any. */
BlockStmt getEnclosingBlock() { result = this.getEnclosingStmt().getEnclosingBlock() }

View File

@@ -156,7 +156,7 @@ class Node extends TIRDataFlowNode {
* If `isGLValue()` holds, then the type of this node
* should be thought of as "pointer to `getType()`".
*/
DataFlowType getType() { none() } // overridden in subclasses
Type getType() { none() } // overridden in subclasses
/** Gets the instruction corresponding to this node, if any. */
Instruction asInstruction() { result = this.(InstructionNode).getInstruction() }
@@ -541,7 +541,7 @@ class Node extends TIRDataFlowNode {
/**
* Gets an upper bound on the type of this node.
*/
DataFlowType getTypeBound() { result = this.getType() }
Type getTypeBound() { result = this.getType() }
/** Gets the location of this element. */
cached
@@ -585,7 +585,7 @@ private class Node0 extends Node, TNode0 {
override string toStringImpl() { result = node.toString() }
override DataFlowType getType() { result = node.getType() }
override Type getType() { result = node.getType() }
override predicate isGLValue() { node.isGLValue() }
}
@@ -704,7 +704,7 @@ class SsaSynthNode extends Node, TSsaSynthNode {
override Declaration getFunction() { result = node.getBasicBlock().getEnclosingFunction() }
override DataFlowType getType() { result = node.getSourceVariable().getType() }
override Type getType() { result = node.getSourceVariable().getType() }
override predicate isGLValue() { node.getSourceVariable().isGLValue() }
@@ -732,7 +732,7 @@ class SsaIteratorNode extends Node, TSsaIteratorNode {
override Declaration getFunction() { result = node.getFunction() }
override DataFlowType getType() { result = node.getType() }
override Type getType() { result = node.getType() }
final override Location getLocationImpl() { result = node.getLocation() }
@@ -792,7 +792,7 @@ class FinalGlobalValue extends Node, TFinalGlobalValue {
override Declaration getFunction() { result = globalUse.getIRFunction().getFunction() }
override DataFlowType getType() {
override Type getType() {
exists(int indirectionIndex |
indirectionIndex = globalUse.getIndirectionIndex() and
result = getTypeImpl(globalUse.getUnderlyingType(), indirectionIndex)
@@ -826,7 +826,7 @@ class InitialGlobalValue extends Node, TInitialGlobalValue {
final override predicate isGLValue() { globalDef.getIndirectionIndex() = 0 }
override DataFlowType getType() { result = globalDef.getUnderlyingType() }
override Type getType() { result = globalDef.getUnderlyingType() }
final override Location getLocationImpl() { result = globalDef.getLocation() }
@@ -853,7 +853,7 @@ class BodyLessParameterNodeImpl extends Node, TBodyLessParameterNodeImpl {
/** Gets the indirection index of this node. */
int getIndirectionIndex() { result = indirectionIndex }
override DataFlowType getType() {
override Type getType() {
result = getTypeImpl(p.getUnderlyingType(), this.getIndirectionIndex())
}
@@ -1117,8 +1117,8 @@ private module RawIndirectNodes {
override predicate isGLValue() { this.getOperand().isGLValue() }
override DataFlowType getType() {
exists(int sub, DataFlowType type, boolean isGLValue |
override Type getType() {
exists(int sub, Type type, boolean isGLValue |
type = getOperandType(this.getOperand(), isGLValue) and
if isGLValue = true then sub = 1 else sub = 0
|
@@ -1163,8 +1163,8 @@ private module RawIndirectNodes {
override predicate isGLValue() { this.getInstruction().isGLValue() }
override DataFlowType getType() {
exists(int sub, DataFlowType type, boolean isGLValue |
override Type getType() {
exists(int sub, Type type, boolean isGLValue |
type = getInstructionType(this.getInstruction(), isGLValue) and
if isGLValue = true then sub = 1 else sub = 0
|
@@ -1263,7 +1263,7 @@ class FinalParameterNode extends Node, TFinalParameterNode {
result.asSourceCallable() = this.getFunction()
}
override DataFlowType getType() { result = getTypeImpl(p.getUnderlyingType(), indirectionIndex) }
override Type getType() { result = getTypeImpl(p.getUnderlyingType(), indirectionIndex) }
final override Location getLocationImpl() {
// Parameters can have multiple locations. When there's a unique location we use
@@ -1539,7 +1539,7 @@ abstract class PostUpdateNode extends Node {
*/
abstract Node getPreUpdateNode();
final override DataFlowType getType() { result = this.getPreUpdateNode().getType() }
final override Type getType() { result = this.getPreUpdateNode().getType() }
}
/**
@@ -1632,9 +1632,7 @@ class VariableNode extends Node, TGlobalLikeVariableNode {
result.asSourceCallable() = v
}
override DataFlowType getType() {
result = getTypeImpl(v.getUnderlyingType(), indirectionIndex - 1)
}
override Type getType() { result = getTypeImpl(v.getUnderlyingType(), indirectionIndex - 1) }
final override Location getLocationImpl() {
// Certain variables (such as parameters) can have multiple locations.
@@ -2419,6 +2417,19 @@ class ContentSet instanceof Content {
}
}
private signature class ParamSig;
private module WithParam<ParamSig P> {
/**
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
*
* The expression `e` is expected to be a syntactic part of the guard `g`.
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
* the argument `x`.
*/
signature predicate guardChecksSig(IRGuardCondition g, Expr e, boolean branch, P param);
}
/**
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
*
@@ -2440,7 +2451,7 @@ private predicate controls(IRGuardCondition g, Node n, boolean edge) {
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module BarrierGuard<guardChecksSig/3 guardChecks> {
module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guardChecks> {
bindingset[value, n]
pragma[inline_late]
private predicate convertedExprHasValueNumber(ValueNumber value, Node n) {
@@ -2450,12 +2461,13 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
)
}
private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch) {
guardChecks(g, n.asOperand().getDef().getConvertedResultExpression(), branch)
private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch, P p) {
guardChecks(g, n.asOperand().getDef().getConvertedResultExpression(), branch, p)
}
/**
* Gets an expression node that is safely guarded by the given guard check.
* Gets an expression node that is safely guarded by the given guard check
* when the parameter is `p`.
*
* For example, given the following code:
* ```cpp
@@ -2486,19 +2498,27 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
*
* NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead.
*/
Node getABarrierNode() {
Node getABarrierNode(P p) {
exists(IRGuardCondition g, ValueNumber value, boolean edge |
convertedExprHasValueNumber(value, result) and
guardChecks(g,
pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge) and
pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge, p) and
controls(g, result, edge)
)
or
result = SsaImpl::BarrierGuard<guardChecksNode/3>::getABarrierNode()
result = SsaImpl::BarrierGuard<P, guardChecksNode/4>::getABarrierNode(p)
}
/**
* Gets an indirect expression node that is safely guarded by the given guard check.
* Gets an expression node that is safely guarded by the given guard check.
*
* See `getABarrierNode/1` for examples.
*/
Node getABarrierNode() { result = getABarrierNode(_) }
/**
* Gets an indirect expression node that is safely guarded by the given
* guard check with parameter `p`.
*
* For example, given the following code:
* ```cpp
@@ -2530,6 +2550,13 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
*
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
*/
Node getAnIndirectBarrierNode(P p) { result = getAnIndirectBarrierNode(_, p) }
/**
* Gets an indirect expression node that is safely guarded by the given guard check.
*
* See `getAnIndirectBarrierNode/1` for examples.
*/
Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
bindingset[value, n]
@@ -2544,10 +2571,10 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
}
private predicate guardChecksIndirectNode(
IRGuardCondition g, Node n, boolean branch, int indirectionIndex
IRGuardCondition g, Node n, boolean branch, int indirectionIndex, P p
) {
guardChecks(g, n.asIndirectOperand(indirectionIndex).getDef().getConvertedResultExpression(),
branch)
branch, p)
}
/**
@@ -2584,19 +2611,44 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
*
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
*/
Node getAnIndirectBarrierNode(int indirectionIndex) {
Node getAnIndirectBarrierNode(int indirectionIndex, P p) {
exists(IRGuardCondition g, ValueNumber value, boolean edge |
indirectConvertedExprHasValueNumber(indirectionIndex, value, result) and
guardChecks(g,
pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge) and
pragma[only_bind_into](value.getAnInstruction().getConvertedResultExpression()), edge, p) and
controls(g, result, edge)
)
or
result =
SsaImpl::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
SsaImpl::BarrierGuardWithIntParam<P, guardChecksIndirectNode/5>::getABarrierNode(indirectionIndex,
p)
}
}
/**
* Provides a set of barrier nodes for a guard that validates an expression.
*
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module BarrierGuard<guardChecksSig/3 guardChecks> {
private predicate guardChecks(IRGuardCondition g, Expr e, boolean branch, Unit unit) {
guardChecks(g, e, branch) and
exists(unit)
}
import ParameterizedBarrierGuard<Unit, guardChecks/4>
}
private module InstrWithParam<ParamSig P> {
/**
* Holds if the guard `g` validates the instruction `instr` upon evaluating to `branch`.
*/
signature predicate instructionGuardChecksSig(
IRGuardCondition g, Instruction instr, boolean branch, P p
);
}
/**
* Holds if the guard `g` validates the instruction `instr` upon evaluating to `branch`.
*/
@@ -2608,7 +2660,9 @@ signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction in
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> {
module ParameterizedInstructionBarrierGuard<
ParamSig P, InstrWithParam<P>::instructionGuardChecksSig/4 instructionGuardChecks>
{
bindingset[value, n]
pragma[inline_late]
private predicate operandHasValueNumber(ValueNumber value, Node n) {
@@ -2618,21 +2672,27 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
)
}
private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch) {
instructionGuardChecks(g, n.asOperand().getDef(), branch)
private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch, P p) {
instructionGuardChecks(g, n.asOperand().getDef(), branch, p)
}
/** Gets a node that is safely guarded by the given guard check. */
Node getABarrierNode() {
/**
* Gets a node that is safely guarded by the given guard check with
* parameter `p`.
*/
Node getABarrierNode(P p) {
exists(IRGuardCondition g, ValueNumber value, boolean edge |
instructionGuardChecks(g, pragma[only_bind_into](value.getAnInstruction()), edge) and
instructionGuardChecks(g, pragma[only_bind_into](value.getAnInstruction()), edge, p) and
operandHasValueNumber(value, result) and
controls(g, result, edge)
)
or
result = SsaImpl::BarrierGuard<guardChecksNode/3>::getABarrierNode()
result = SsaImpl::BarrierGuard<P, guardChecksNode/4>::getABarrierNode(p)
}
/** Gets a node that is safely guarded by the given guard check. */
Node getABarrierNode() { result = getABarrierNode(_) }
bindingset[value, n]
pragma[inline_late]
private predicate indirectOperandHasValueNumber(ValueNumber value, int indirectionIndex, Node n) {
@@ -2643,25 +2703,52 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
}
private predicate guardChecksIndirectNode(
IRGuardCondition g, Node n, boolean branch, int indirectionIndex
IRGuardCondition g, Node n, boolean branch, int indirectionIndex, P p
) {
instructionGuardChecks(g, n.asIndirectOperand(indirectionIndex).getDef(), branch)
instructionGuardChecks(g, n.asIndirectOperand(indirectionIndex).getDef(), branch, p)
}
/**
* Gets an indirect node with indirection index `indirectionIndex` that is
* safely guarded by the given guard check.
* safely guarded by the given guard check with parameter `p`.
*/
Node getAnIndirectBarrierNode(int indirectionIndex) {
Node getAnIndirectBarrierNode(int indirectionIndex, P p) {
exists(IRGuardCondition g, ValueNumber value, boolean edge |
instructionGuardChecks(g, pragma[only_bind_into](value.getAnInstruction()), edge) and
instructionGuardChecks(g, pragma[only_bind_into](value.getAnInstruction()), edge, p) and
indirectOperandHasValueNumber(value, indirectionIndex, result) and
controls(g, result, edge)
)
or
result =
SsaImpl::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
SsaImpl::BarrierGuardWithIntParam<P, guardChecksIndirectNode/5>::getABarrierNode(indirectionIndex,
p)
}
/**
* Gets an indirect node that is safely guarded by the given guard check
* with parameter `p`.
*/
Node getAnIndirectBarrierNode(P p) { result = getAnIndirectBarrierNode(_, p) }
/** Gets an indirect node that is safely guarded by the given guard check. */
Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
}
/**
* Provides a set of barrier nodes for a guard that validates an instruction.
*
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> {
private predicate instructionGuardChecks(
IRGuardCondition g, Instruction i, boolean branch, Unit unit
) {
instructionGuardChecks(g, i, branch) and
exists(unit)
}
import ParameterizedInstructionBarrierGuard<Unit, instructionGuardChecks/4>
}
/**

View File

@@ -53,7 +53,7 @@ private module SourceVariables {
* the type of this source variable should be thought of as "pointer
* to `getType()`".
*/
DataFlowType getType() {
Type getType() {
if this.isGLValue()
then result = base.getType()
else result = getTypeImpl(base.getType(), ind - 1)
@@ -940,6 +940,16 @@ module SsaCached {
SsaImpl::phiHasInputFromBlock(phi, inp, bb)
}
cached
predicate uncertainWriteDefinitionInput(Definition uncertain, Definition inp) {
SsaImpl::uncertainWriteDefinitionInput(uncertain, inp)
}
cached
predicate ssaDefReachesEndOfBlock(IRBlock bb, Definition def) {
SsaImpl::ssaDefReachesEndOfBlock(bb, def, _)
}
predicate variableRead = SsaInput::variableRead/4;
predicate variableWrite = SsaInput::variableWrite/4;
@@ -1035,13 +1045,23 @@ class SynthNode extends DataFlowIntegrationImpl::SsaNode {
SynthNode() { not this.asDefinition() instanceof SsaImpl::WriteDefinition }
}
signature predicate guardChecksNodeSig(IRGuards::IRGuardCondition g, Node e, boolean branch);
private signature class ParamSig;
signature predicate guardChecksNodeSig(
IRGuards::IRGuardCondition g, Node e, boolean branch, int indirectionIndex
);
private module ParamIntPair<ParamSig P> {
newtype TPair = MkPair(P p, int indirectionIndex) { nodeHasInstruction(_, _, indirectionIndex) }
}
module BarrierGuardWithIntParam<guardChecksNodeSig/4 guardChecksNode> {
private module WithParam<ParamSig P> {
signature predicate guardChecksNodeSig(IRGuards::IRGuardCondition g, Node e, boolean gv, P param);
}
private module IntWithParam<ParamSig P> {
signature predicate guardChecksNodeSig(
IRGuards::IRGuardCondition g, Node e, boolean gv, int indirectionIndex, P param
);
}
module BarrierGuardWithIntParam<ParamSig P, IntWithParam<P>::guardChecksNodeSig/5 guardChecksNode> {
private predicate ssaDefReachesCertainUse(Definition def, UseImpl use) {
exists(SourceVariable v, IRBlock bb, int i |
use.hasIndexInBlock(bb, i, v) and
@@ -1052,34 +1072,44 @@ module BarrierGuardWithIntParam<guardChecksNodeSig/4 guardChecksNode> {
private predicate guardChecksInstr(
IRGuards::Guards_v1::Guard g, IRGuards::GuardsInput::Expr instr, IRGuards::GuardValue gv,
int indirectionIndex
ParamIntPair<P>::TPair pair
) {
exists(Node node |
exists(Node node, int indirectionIndex, P p |
pair = ParamIntPair<P>::MkPair(p, indirectionIndex) and
nodeHasInstruction(node, instr, indirectionIndex) and
guardChecksNode(g, node, gv.asBooleanValue(), indirectionIndex)
guardChecksNode(g, node, gv.asBooleanValue(), indirectionIndex, p)
)
}
private predicate guardChecksWithWrappers(
DataFlowIntegrationInput::Guard g, SsaImpl::Definition def, IRGuards::GuardValue val,
int indirectionIndex
ParamIntPair<P>::MkPair pair
) {
IRGuards::Guards_v1::ParameterizedValidationWrapper<int, guardChecksInstr/4>::guardChecksDef(g,
def, val, indirectionIndex)
exists(Instruction e, int indirectionIndex |
IRGuards::Guards_v1::ParameterizedValidationWrapper<ParamIntPair<P>::TPair, guardChecksInstr/4>::guardChecks(g,
e, val, pair) and
pair = ParamIntPair<P>::MkPair(_, indirectionIndex)
|
indirectionIndex = 0 and
def.(Definition).getAUse().getDef() = e
or
def.(Definition).getAnIndirectUse(indirectionIndex).getDef() = e
)
}
Node getABarrierNode(int indirectionIndex) {
Node getABarrierNode(int indirectionIndex, P p) {
// Only get the SynthNodes from the shared implementation, as the ExprNodes cannot
// be matched on SourceVariable.
result.(SsaSynthNode).getSynthNode() =
DataFlowIntegrationImpl::BarrierGuardDefWithState<int, guardChecksWithWrappers/4>::getABarrierNode(indirectionIndex)
DataFlowIntegrationImpl::BarrierGuardDefWithState<ParamIntPair<P>::MkPair, guardChecksWithWrappers/4>::getABarrierNode(ParamIntPair<P>::MkPair(p,
indirectionIndex))
or
// Calculate the guarded UseImpls corresponding to ExprNodes directly.
exists(
DataFlowIntegrationInput::Guard g, IRGuards::GuardValue branch, Definition def, IRBlock bb
|
guardChecksWithWrappers(g, def, branch, indirectionIndex) and
exists(UseImpl use |
guardChecksWithWrappers(g, def, branch, ParamIntPair<P>::MkPair(p, indirectionIndex)) and
ssaDefReachesCertainUse(def, use) and
use.getBlock() = bb and
DataFlowIntegrationInput::guardControlsBlock(g, bb, branch) and
@@ -1089,15 +1119,16 @@ module BarrierGuardWithIntParam<guardChecksNodeSig/4 guardChecksNode> {
}
}
module BarrierGuard<guardChecksNodeSig/3 guardChecksNode> {
module BarrierGuard<ParamSig P, WithParam<P>::guardChecksNodeSig/4 guardChecksNode> {
private predicate guardChecksNode(
IRGuards::IRGuardCondition g, Node e, boolean branch, int indirectionIndex
IRGuards::IRGuardCondition g, Node e, boolean gv, int indirectionIndex, P p
) {
guardChecksNode(g, e, branch) and indirectionIndex = 0
indirectionIndex = 0 and
guardChecksNode(g, e, gv, p)
}
Node getABarrierNode() {
result = BarrierGuardWithIntParam<guardChecksNode/4>::getABarrierNode(0)
Node getABarrierNode(P p) {
result = BarrierGuardWithIntParam<P, guardChecksNode/5>::getABarrierNode(0, p)
}
}
@@ -1152,9 +1183,17 @@ class Definition extends SsaImpl::Definition {
private Definition getAPhiInputOrPriorDefinition() {
result = this.(PhiNode).getAnInput()
or
SsaImpl::uncertainWriteDefinitionInput(this, result)
uncertainWriteDefinitionInput(this, result)
}
/**
* Holds if this SSA definition is live at the end of basic block `bb`.
* That is, this definition reaches the end of basic block `bb`, at which
* point it is still live, without crossing another SSA definition of the
* same source variable.
*/
predicate isLiveAtEndOfBlock(IRBlock bb) { ssaDefReachesEndOfBlock(bb, this) }
/**
* Gets a definition that ultimately defines this SSA definition and is
* not itself a phi node.

View File

@@ -104,7 +104,11 @@ newtype TInstructionTag =
} or
SizeofVlaDimensionTag(int index) {
exists(VlaDeclStmt v | exists(v.getTransitiveVlaDimensionStmt(index)))
}
} or
AssertionVarAddressTag() or
AssertionVarLoadTag() or
AssertionOpTag() or
AssertionBranchTag()
class InstructionTag extends TInstructionTag {
final string toString() { result = getInstructionTagId(this) }
@@ -296,4 +300,12 @@ string getInstructionTagId(TInstructionTag tag) {
tag = CoAwaitBranchTag() and result = "CoAwaitBranch"
or
tag = BoolToIntConversionTag() and result = "BoolToIntConversion"
or
tag = AssertionVarAddressTag() and result = "AssertionVarAddress"
or
tag = AssertionVarLoadTag() and result = "AssertionVarLoad"
or
tag = AssertionOpTag() and result = "AssertionOp"
or
tag = AssertionBranchTag() and result = "AssertionBranch"
}

View File

@@ -0,0 +1,387 @@
private import cpp
private import semmle.code.cpp.ir.internal.IRUtilities
private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.CppType
private import semmle.code.cpp.ir.internal.TempVariableTag
private import InstructionTag
private import TranslatedElement
private import TranslatedStmt
private import TranslatedFunction
/**
* Holds if `s` is a statement that may be an expanded assertion in a
* release build.
*/
pragma[nomagic]
private predicate stmtCandidate(Stmt s) {
not s.isFromUninstantiatedTemplate(_) and
(
// The expansion of `__analysis_assume(x != 0);` when `__analysis_assume` is
// empty is the empty statement.
s instanceof EmptyStmt
or
// The expansion of `assert(x != 0)` when `assert` is `((void)0)` is a zero literal
// with a void type.
exists(Expr e |
e = s.(ExprStmt).getExpr() and
e.getValue() = "0" and
e.getActualType() instanceof VoidType
)
)
}
pragma[nomagic]
private predicate macroInvocationLocation(int startline, Function f, MacroInvocation mi) {
mi.getMacroName() = ["assert", "__analysis_assume"] and
mi.getNumberOfArguments() = 1 and
mi.getLocation().hasLocationInfo(_, startline, _, _, _) and
f.getEntryPoint().isAffectedByMacro(mi)
}
pragma[nomagic]
private predicate stmtParentLocation(int startline, Function f, StmtParent p) {
p.getEnclosingFunction() = f and
p.getLocation().hasLocationInfo(_, startline, _, _, _)
}
/**
* Holds if `mi` is a macro invocation with a name that is known
* to correspond to an assertion macro, and the macro invocation
* is the only thing on the line.
*/
pragma[nomagic]
private predicate assertion0(MacroInvocation mi, Stmt s, string arg) {
stmtCandidate(s) and
s =
unique(StmtParent p, int startline, Function f |
macroInvocationLocation(startline, f, mi) and
stmtParentLocation(startline, f, p) and
// Also do not count the elements from the expanded macro, i.e., when checking
// if `assert(x)` is the only thing on the line we do not count the
// generated `((void)0)` expression.
not p = mi.getAnExpandedElement()
|
p
) and
arg = mi.getUnexpandedArgument(0)
}
private Function getEnclosingFunctionForMacroInvocation(MacroInvocation mi) {
exists(Stmt s |
assertion0(mi, s, _) and
result = s.getEnclosingFunction()
)
}
/**
* Holds if `arg` has two components and the `i`'th component of the string
* `arg` is `s`, and the components are separated by an operation with
* opcode `opcode`.
*/
bindingset[arg]
pragma[inline_late]
private predicate parseArgument(string arg, string s, int i, Opcode opcode) {
s =
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?<=\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
i + 1) and
opcode instanceof Opcode::CompareLE
or
s =
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?>=\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
i + 1) and
opcode instanceof Opcode::CompareGE
or
s =
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?<\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
i + 1) and
opcode instanceof Opcode::CompareLT
or
s =
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?>\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
i + 1) and
opcode instanceof Opcode::CompareGT
or
s =
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?!=\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
i + 1) and
opcode instanceof Opcode::CompareNE
or
s =
arg.regexpCapture("([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)\\s?==\\s?([a-zA-Z_][a-zA-Z_0-9]*|[0-9]+)",
i + 1) and
opcode instanceof Opcode::CompareEQ
}
private Element getAChildScope(Element scope) { result.getParentScope() = scope }
private predicate hasAVariable(MacroInvocation mi, Stmt s, Element scope) {
assertion0(mi, s, _) and
s.getParent() = scope
or
hasAVariable(mi, s, getAChildScope(scope))
}
private LocalScopeVariable getVariable(MacroInvocation mi, int i) {
exists(string operand, string arg, Stmt s |
assertion0(mi, s, arg) and
parseArgument(arg, operand, i, _) and
result =
unique(Variable v |
v.getLocation().getStartLine() < s.getLocation().getStartLine() and
hasAVariable(mi, s, v.getParentScope()) and
v.hasName(operand)
|
v
)
)
}
/**
* Holds if the `i`'th component of the macro invocation `mi` with opcode
* `opcode` is a reference to `var`.
*/
private predicate hasVarAccessMacroArgument(MacroInvocation mi, Variable var, int i, Opcode opcode) {
exists(string arg, string s, Function f |
arg = mi.getUnexpandedArgument(0) and
f = getEnclosingFunctionForMacroInvocation(mi) and
parseArgument(arg, s, i, opcode) and
var = getVariable(mi, i)
)
}
/**
* Holds if the `i`'th component of the macro invocation `mi` with opcode
* `opcode` is a constant with the value `k`.
*/
private predicate hasConstMacroArgument(MacroInvocation mi, int k, int i, Opcode opcode) {
exists(string arg, string s |
assertion0(mi, _, arg) and
s.toInt() = k and
parseArgument(arg, s, i, opcode)
)
}
predicate hasAssertionOperand(MacroInvocation mi, int i) {
hasVarAccessMacroArgument(mi, _, i, _)
or
hasConstMacroArgument(mi, _, i, _)
}
private predicate hasAssertionOpcode(MacroInvocation mi, Opcode opcode) {
hasVarAccessMacroArgument(mi, _, _, opcode)
or
hasConstMacroArgument(mi, _, _, opcode)
}
/**
* Holds if `mi` is a macro invocation that is an assertion that should be generated
* in the control-flow graph at `s`.
*/
predicate assertion(MacroInvocation mi, Stmt s) {
assertion0(mi, s, _) and
hasAssertionOperand(mi, 0) and
hasAssertionOperand(mi, 1)
}
/** The translation of an operand of an assertion. */
abstract private class TranslatedAssertionOperand extends TranslatedElement,
TTranslatedAssertionOperand
{
MacroInvocation mi;
int index;
TranslatedAssertionOperand() { this = TTranslatedAssertionOperand(mi, index) }
MacroInvocation getMacroInvocation() { result = mi }
/**
* Gets the statement that is being replaced by the assertion that uses this
* operand.
*/
Stmt getStmt() { assertion(mi, result) }
final override Locatable getAst() { result = this.getStmt() }
final override TranslatedElement getChild(int id) { none() }
final override Declaration getFunction() { result = this.getStmt().getEnclosingFunction() }
/** Gets the instruction which holds the result of this operand. */
abstract Instruction getResult();
final override string toString() { result = "Operand of assertion: " + mi }
/** Gets the index of this operand (i.e., `0` or `1`). */
final int getIndex() { result = index }
}
/** An operand of an assertion that is a variable access. */
class TranslatedAssertionVarAccess extends TranslatedAssertionOperand {
TranslatedAssertionVarAccess() { hasVarAccessMacroArgument(mi, _, index, _) }
Variable getVariable() { hasVarAccessMacroArgument(mi, result, index, _) }
final override IRUserVariable getInstructionVariable(InstructionTag tag) {
tag = AssertionVarAddressTag() and
result.getVariable() = this.getVariable()
}
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(AssertionVarAddressTag()) and kind instanceof GotoEdge
}
final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
tag = AssertionVarAddressTag() and
kind instanceof GotoEdge and
result = this.getInstruction(AssertionVarLoadTag())
or
tag = AssertionVarLoadTag() and
result = getTranslatedAssertionMacroInvocation(mi).getChildSuccessor(this, kind)
}
final override Instruction getALastInstructionInternal() {
result = this.getInstruction(AssertionVarLoadTag())
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
exists(Variable v | v = this.getVariable() |
opcode instanceof Opcode::VariableAddress and
tag = AssertionVarAddressTag() and
resultType = getTypeForGLValue(v.getType())
or
opcode instanceof Opcode::Load and
tag = AssertionVarLoadTag() and
resultType = getTypeForPRValue(v.getType())
)
}
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
tag = AssertionVarLoadTag() and
operandTag instanceof AddressOperandTag and
result = this.getInstruction(AssertionVarAddressTag())
}
final override Instruction getResult() { result = this.getInstruction(AssertionVarLoadTag()) }
}
/** An operand of an assertion that is a constant access. */
private class TranslatedAssertionConst extends TranslatedAssertionOperand {
TranslatedAssertionConst() { hasConstMacroArgument(mi, _, index, _) }
int getConst() { hasConstMacroArgument(mi, result, index, _) }
final override string getInstructionConstantValue(InstructionTag tag) {
tag = OnlyInstructionTag() and
result = this.getConst().toString()
}
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(OnlyInstructionTag()) and
kind instanceof GotoEdge
}
final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
result = getTranslatedAssertionMacroInvocation(mi).getChildSuccessor(this, kind)
}
final override Instruction getALastInstructionInternal() {
result = this.getInstruction(OnlyInstructionTag())
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
opcode instanceof Opcode::Constant and
tag = OnlyInstructionTag() and
resultType = getIntType()
}
final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) }
}
/**
* Gets the `TranslatedAssertionMacroInvocation` corresponding to the macro
* invocation `mi`.
*/
TranslatedAssertionMacroInvocation getTranslatedAssertionMacroInvocation(MacroInvocation mi) {
result.getMacroInvocation() = mi
}
/**
* A synthesized assertion which would have otherwise been invisible because the
* database represents a release build where assertions are disabled.
*/
private class TranslatedAssertionMacroInvocation extends TranslatedStmt {
MacroInvocation mi;
TranslatedAssertionMacroInvocation() { assertion(mi, stmt) }
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getLeft().getFirstInstruction(kind)
}
TranslatedAssertionOperand getLeft() {
result.getMacroInvocation() = mi and
result.getIndex() = 0
}
TranslatedAssertionOperand getRight() {
result.getMacroInvocation() = mi and
result.getIndex() = 1
}
final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
tag = AssertionOpTag() and
kind instanceof GotoEdge and
result = this.getInstruction(AssertionBranchTag())
or
tag = AssertionBranchTag() and
kind instanceof TrueEdge and
result = this.getParent().getChildSuccessor(this, _)
}
final override TranslatedElement getChildInternal(int id) {
id = 0 and result = this.getLeft()
or
id = 1 and result = this.getRight()
}
final override Instruction getALastInstructionInternal() {
result = this.getInstruction(AssertionBranchTag())
}
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
tag = AssertionOpTag() and
resultType = getBoolType() and
hasAssertionOpcode(mi, opcode)
or
tag = AssertionBranchTag() and
resultType = getVoidType() and
opcode instanceof Opcode::ConditionalBranch
}
final override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
child = this.getLeft() and
result = this.getRight().getFirstInstruction(kind)
or
child = this.getRight() and
kind instanceof GotoEdge and
result = this.getInstruction(AssertionOpTag())
}
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
tag = AssertionOpTag() and
(
operandTag instanceof LeftOperandTag and
result = this.getLeft().getResult()
or
operandTag instanceof RightOperandTag and
result = this.getRight().getResult()
)
or
tag = AssertionBranchTag() and
operandTag instanceof ConditionOperandTag and
result = this.getInstruction(AssertionOpTag())
}
MacroInvocation getMacroInvocation() { result = mi }
}

View File

@@ -12,6 +12,7 @@ private import TranslatedFunction
private import TranslatedStmt
private import TranslatedExpr
private import IRConstruction
private import TranslatedAssertion
private import semmle.code.cpp.models.interfaces.SideEffect
private import SideEffects
@@ -138,6 +139,14 @@ private predicate ignoreExprAndDescendants(Expr expr) {
// conditionally constructed (until we have a mechanism for calling these only when the
// temporary's constructor was run)
isConditionalTemporaryDestructorCall(expr)
or
// An assertion in a release build is often defined as `#define assert(x) ((void)0)`.
// We generate a synthetic assertion in release builds, and when we do that the
// expression `((void)0)` should not be translated.
exists(MacroInvocation mi |
assertion(mi, _) and
expr = mi.getExpr().getFullyConverted()
)
}
/**
@@ -909,7 +918,8 @@ newtype TTranslatedElement =
} or
// The side effect that initializes newly-allocated memory.
TTranslatedAllocationSideEffect(AllocationExpr expr) { not ignoreSideEffects(expr) } or
TTranslatedStaticStorageDurationVarInit(Variable var) { Raw::varHasIRFunc(var) }
TTranslatedStaticStorageDurationVarInit(Variable var) { Raw::varHasIRFunc(var) } or
TTranslatedAssertionOperand(MacroInvocation mi, int index) { hasAssertionOperand(mi, index) }
/**
* Gets the index of the first explicitly initialized element in `initList`

View File

@@ -10,6 +10,7 @@ private import TranslatedElement
private import TranslatedExpr
private import TranslatedFunction
private import TranslatedInitialization
private import TranslatedAssertion
TranslatedStmt getTranslatedStmt(Stmt stmt) { result.getAst() = stmt }
@@ -324,8 +325,16 @@ abstract class TranslatedStmt extends TranslatedElement, TTranslatedStmt {
class TranslatedEmptyStmt extends TranslatedStmt {
TranslatedEmptyStmt() {
stmt instanceof EmptyStmt or
stmt instanceof LabelStmt or
// An assertion macro invocation can expand to
// an empty statement in release builds. In that case
// we synthesize the check that would have occurred.
// This is handled by `TranslatedAssertion.qll` and so
// we exclude these statements here.
not assertion(_, stmt) and
stmt instanceof EmptyStmt
or
stmt instanceof LabelStmt
or
stmt instanceof SwitchCase
}
@@ -420,6 +429,15 @@ class TranslatedDeclStmt extends TranslatedStmt {
class TranslatedExprStmt extends TranslatedStmt {
override ExprStmt stmt;
TranslatedExprStmt() {
// An assertion macro invocation typically expand to the
// expression `((void)0)` in release builds. In that case
// we synthesize the check that would have occurred.
// This is handled by `TranslatedAssertion.qll` and so
// we exclude these statements here.
not assertion(_, stmt)
}
TranslatedExpr getExpr() { result = getTranslatedExpr(stmt.getExpr().getFullyConverted()) }
override TranslatedElement getChildInternal(int id) { id = 0 and result = this.getExpr() }

View File

@@ -20,7 +20,7 @@ class Stmt extends StmtParent, @stmt {
predicate hasChild(Element e, int n) { this.getChild(n) = e }
/** Gets the enclosing function of this statement, if any. */
Function getEnclosingFunction() { result = stmtEnclosingElement(this) }
override Function getEnclosingFunction() { result = stmtEnclosingElement(this) }
/**
* Gets the nearest enclosing block of this statement in the source, if any.
@@ -159,7 +159,10 @@ private class TStmtParent = @stmt or @expr;
*
* This is normally a statement, but may be a `StmtExpr`.
*/
class StmtParent extends ControlFlowNode, TStmtParent { }
class StmtParent extends ControlFlowNode, TStmtParent {
/** Gets the enclosing function of this element, if any. */
Function getEnclosingFunction() { none() }
}
/**
* A C/C++ 'expression' statement.

View File

@@ -2353,6 +2353,7 @@ case @preprocdirect.kind of
| 14 = @ppd_ms_import
| 15 = @ppd_elifdef
| 16 = @ppd_elifndef
| 17 = @ppd_embed
| 18 = @ppd_warning
;
@@ -2379,6 +2380,11 @@ includes(
int included: @file ref
);
embeds(
unique int id: @ppd_embed ref,
int included: @file ref
);
link_targets(
int id: @link_target,
int binary: @file ref
@@ -2389,6 +2395,8 @@ link_parent(
int link_target : @link_target ref
);
/*- Database metadata -*/
/**
* The CLI will automatically emit applicable tuples for this table,
* such as `databaseMetadata("isOverlay", "true")` when building an
@@ -2399,6 +2407,8 @@ databaseMetadata(
string value: string ref
);
/*- Overlay support -*/
/**
* The CLI will automatically emit tuples for each new/modified/deleted file
* when building an overlay database.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Sections for databaseMetadata and overlayChangedFiles
compatibility: full

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Support embed preprocessor directive
compatibility: partial

View File

@@ -1,3 +1,9 @@
## 1.5.9
### Minor Analysis Improvements
* The `cpp/constant-comparison` query has been updated to not produce false positives for constants that are now represented by their unfolded expression trees.
## 1.5.8
No user-facing changes.

View File

@@ -122,7 +122,8 @@ module Config implements DataFlow::ConfigSig {
predicate isBarrier(DataFlow::Node node) {
// Block flow if the node is guarded by any <, <= or = operations.
node = DataFlow::BarrierGuard<lessThanOrEqual/3>::getABarrierNode()
node = DataFlow::BarrierGuard<lessThanOrEqual/3>::getABarrierNode() or
node = DataFlow::BarrierGuard<lessThanOrEqual/3>::getAnIndirectBarrierNode()
}
predicate observeDiffInformedIncrementalMode() { any() }

View File

@@ -1,4 +1,5 @@
---
category: minorAnalysis
---
## 1.5.9
### Minor Analysis Improvements
* The `cpp/constant-comparison` query has been updated to not produce false positives for constants that are now represented by their unfolded expression trees.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.5.8
lastReleaseVersion: 1.5.9

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 1.5.9-dev
version: 1.5.10-dev
groups:
- cpp
- queries

View File

@@ -78,7 +78,7 @@ module ModelGeneratorCommonInput implements ModelGeneratorCommonInputSig<Cpp::Lo
{
private module DataFlow = Df::DataFlow;
class Type = DataFlowPrivate::DataFlowType;
class Type = Cpp::Type;
// Note: This also includes `this`
class Parameter = DataFlow::ParameterNode;

View File

@@ -4,6 +4,46 @@ void sink(int);
void testCheckArgument(int* p) {
if (checkArgument(p)) {
sink(*p); // $ barrier barrier=1
sink(*p); // $ indirect_barrier=int barrier=int*
}
}
void testCheckArgument(int p) {
if (checkArgument(&p)) {
sink(p); // $ barrier=glval<int> indirect_barrier=int
}
}
int* get_clean_value(int* x) { return x; }
bool is_clean_value(int*);
int* get_clean_pointer(int* x) { return x; }
bool is_clean_pointer(int*);
void sink(int*);
void test_mad(int x, int* p) {
{
if(is_clean_value(&x)) {
sink(x); // $ external=int
}
}
{
if(is_clean_value(p)) {
sink(*p); // $ external=int
}
}
{
if(is_clean_pointer(p)) {
sink(p); // $ external=int*
}
}
{
if(is_clean_pointer(&x)) {
sink(x); // $ external=glval<int>
}
}
}

View File

@@ -0,0 +1,13 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: barrierModel
data:
- ["", "", False, "get_clean_pointer", "", "", "ReturnValue", "test-barrier", "manual"]
- ["", "", False, "get_clean_data", "", "", "ReturnValue[*]", "test-barrier", "manual"]
- addsTo:
pack: codeql/cpp-all
extensible: barrierGuardModel
data:
- ["", "", False, "is_clean_value", "", "", "Argument[*0]", "true", "test-barrier", "manual"]
- ["", "", False, "is_clean_pointer", "", "", "Argument[0]", "true", "test-barrier", "manual"]

View File

@@ -2,6 +2,7 @@ import cpp
import semmle.code.cpp.dataflow.new.DataFlow
import semmle.code.cpp.controlflow.IRGuards
import utils.test.InlineExpectationsTest
import semmle.code.cpp.dataflow.ExternalFlow
predicate instructionGuardChecks(IRGuardCondition gc, Instruction checked, boolean branch) {
exists(CallInstruction call |
@@ -13,26 +14,41 @@ predicate instructionGuardChecks(IRGuardCondition gc, Instruction checked, boole
module BarrierGuard = DataFlow::InstructionBarrierGuard<instructionGuardChecks/3>;
predicate indirectBarrierGuard(DataFlow::Node node, int indirectionIndex) {
node = BarrierGuard::getAnIndirectBarrierNode(indirectionIndex)
predicate indirectBarrierGuard(DataFlow::Node node, string s) {
node = BarrierGuard::getAnIndirectBarrierNode(_) and
if node.isGLValue()
then s = "glval<" + node.getType().toString().replaceAll(" ", "") + ">"
else s = node.getType().toString().replaceAll(" ", "")
}
predicate barrierGuard(DataFlow::Node node) { node = BarrierGuard::getABarrierNode() }
predicate barrierGuard(DataFlow::Node node, string s) {
node = BarrierGuard::getABarrierNode() and
if node.isGLValue()
then s = "glval<" + node.getType().toString().replaceAll(" ", "") + ">"
else s = node.getType().toString().replaceAll(" ", "")
}
predicate externalBarrierGuard(DataFlow::Node node, string s) {
barrierNode(node, "test-barrier") and
if node.isGLValue()
then s = "glval<" + node.getType().toString().replaceAll(" ", "") + ">"
else s = node.getType().toString().replaceAll(" ", "")
}
module Test implements TestSig {
string getARelevantTag() { result = "barrier" }
string getARelevantTag() { result = ["barrier", "indirect_barrier", "external"] }
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(DataFlow::Node node |
barrierGuard(node) and
value = ""
indirectBarrierGuard(node, value) and
tag = "indirect_barrier"
or
exists(int indirectionIndex |
indirectBarrierGuard(node, indirectionIndex) and
value = indirectionIndex.toString()
)
barrierGuard(node, value) and
tag = "barrier"
or
externalBarrierGuard(node, value) and
tag = "external"
|
tag = "barrier" and
element = node.toString() and
location = node.getLocation()
)

View File

@@ -25131,6 +25131,517 @@ ir.cpp:
# 2823| Type = [ArrayType] int[]
# 2823| ValueCategory = lvalue
# 2824| getStmt(5): [ReturnStmt] return ...
# 2830| [TopLevelFunction] void test_assert_simple(int, int, unsigned int, int)
# 2830| <params>:
# 2830| getParameter(0): [Parameter] x
# 2830| Type = [IntType] int
# 2830| getParameter(1): [Parameter] y
# 2830| Type = [IntType] int
# 2830| getParameter(2): [Parameter] u
# 2830| Type = [IntType] unsigned int
# 2830| getParameter(3): [Parameter] shadowed
# 2830| Type = [IntType] int
# 2830| getEntryPoint(): [BlockStmt] { ... }
# 2831| getStmt(0): [ExprStmt] ExprStmt
# 2831| getExpr(): [Literal] 0
# 2831| Type = [IntType] int
# 2831| Value = [Literal] 0
# 2831| ValueCategory = prvalue
# 2831| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2831| Type = [VoidType] void
# 2831| ValueCategory = prvalue
# 2831| getExpr(): [CStyleCast] (void)...
# 2831| Conversion = [VoidConversion] conversion to void
# 2831| Type = [VoidType] void
# 2831| ValueCategory = prvalue
# 2832| getStmt(1): [ExprStmt] ExprStmt
# 2832| getExpr(): [Literal] 0
# 2832| Type = [IntType] int
# 2832| Value = [Literal] 0
# 2832| ValueCategory = prvalue
# 2832| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2832| Type = [VoidType] void
# 2832| ValueCategory = prvalue
# 2832| getExpr(): [CStyleCast] (void)...
# 2832| Conversion = [VoidConversion] conversion to void
# 2832| Type = [VoidType] void
# 2832| ValueCategory = prvalue
# 2833| getStmt(2): [ExprStmt] ExprStmt
# 2833| getExpr(): [Literal] 0
# 2833| Type = [IntType] int
# 2833| Value = [Literal] 0
# 2833| ValueCategory = prvalue
# 2833| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2833| Type = [VoidType] void
# 2833| ValueCategory = prvalue
# 2833| getExpr(): [CStyleCast] (void)...
# 2833| Conversion = [VoidConversion] conversion to void
# 2833| Type = [VoidType] void
# 2833| ValueCategory = prvalue
# 2835| getStmt(3): [EmptyStmt] ;
# 2837| getStmt(4): [ExprStmt] ExprStmt
# 2837| getExpr(): [Literal] 0
# 2837| Type = [IntType] int
# 2837| Value = [Literal] 0
# 2837| ValueCategory = prvalue
# 2837| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2837| Type = [VoidType] void
# 2837| ValueCategory = prvalue
# 2837| getExpr(): [CStyleCast] (void)...
# 2837| Conversion = [VoidConversion] conversion to void
# 2837| Type = [VoidType] void
# 2837| ValueCategory = prvalue
# 2839| getStmt(5): [BlockStmt] { ... }
# 2840| getStmt(0): [DeclStmt] declaration
# 2840| getDeclarationEntry(0): [VariableDeclarationEntry] definition of shadowed
# 2840| Type = [IntType] int
# 2840| getVariable().getInitializer(): [Initializer] initializer for shadowed
# 2840| getExpr(): [VariableAccess] x
# 2840| Type = [IntType] int
# 2840| ValueCategory = prvalue(load)
# 2841| getStmt(1): [ExprStmt] ExprStmt
# 2841| getExpr(): [Literal] 0
# 2841| Type = [IntType] int
# 2841| Value = [Literal] 0
# 2841| ValueCategory = prvalue
# 2841| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2841| Type = [VoidType] void
# 2841| ValueCategory = prvalue
# 2841| getExpr(): [CStyleCast] (void)...
# 2841| Conversion = [VoidConversion] conversion to void
# 2841| Type = [VoidType] void
# 2841| ValueCategory = prvalue
# 2843| getStmt(6): [ReturnStmt] return ...
# 2846| [TemplateFunction,TopLevelFunction] void test_assert_in_template<T>(T, int, unsigned int)
# 2846| <params>:
# 2846| getParameter(0): [Parameter] x
# 2846| Type = [TypeTemplateParameter] T
# 2846| getParameter(1): [Parameter] y
# 2846| Type = [IntType] int
# 2846| getParameter(2): [Parameter] u
# 2846| Type = [IntType] unsigned int
# 2846| getEntryPoint(): [BlockStmt] { ... }
# 2847| getStmt(0): [ExprStmt] ExprStmt
# 2847| getExpr(): [Literal] 0
# 2847| Type = [IntType] int
# 2847| Value = [Literal] 0
# 2847| ValueCategory = prvalue
# 2847| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2847| Type = [VoidType] void
# 2847| ValueCategory = prvalue
# 2847| getExpr(): [CStyleCast] (void)...
# 2847| Conversion = [VoidConversion] conversion to void
# 2847| Type = [VoidType] void
# 2847| ValueCategory = prvalue
# 2848| getStmt(1): [ExprStmt] ExprStmt
# 2848| getExpr(): [Literal] 0
# 2848| Type = [IntType] int
# 2848| Value = [Literal] 0
# 2848| ValueCategory = prvalue
# 2848| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2848| Type = [VoidType] void
# 2848| ValueCategory = prvalue
# 2848| getExpr(): [CStyleCast] (void)...
# 2848| Conversion = [VoidConversion] conversion to void
# 2848| Type = [VoidType] void
# 2848| ValueCategory = prvalue
# 2849| getStmt(2): [ExprStmt] ExprStmt
# 2849| getExpr(): [Literal] 0
# 2849| Type = [IntType] int
# 2849| Value = [Literal] 0
# 2849| ValueCategory = prvalue
# 2849| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2849| Type = [VoidType] void
# 2849| ValueCategory = prvalue
# 2849| getExpr(): [CStyleCast] (void)...
# 2849| Conversion = [VoidConversion] conversion to void
# 2849| Type = [VoidType] void
# 2849| ValueCategory = prvalue
# 2851| getStmt(3): [EmptyStmt] ;
# 2853| getStmt(4): [ExprStmt] ExprStmt
# 2853| getExpr(): [Literal] 0
# 2853| Type = [IntType] int
# 2853| Value = [Literal] 0
# 2853| ValueCategory = prvalue
# 2853| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2853| Type = [VoidType] void
# 2853| ValueCategory = prvalue
# 2853| getExpr(): [CStyleCast] (void)...
# 2853| Conversion = [VoidConversion] conversion to void
# 2853| Type = [VoidType] void
# 2853| ValueCategory = prvalue
# 2855| getStmt(5): [BlockStmt] { ... }
# 2856| getStmt(0): [DeclStmt] declaration
# 2856| getDeclarationEntry(0): [VariableDeclarationEntry] definition of shadowed
# 2856| Type = [IntType] int
# 2856| getVariable().getInitializer(): [Initializer] initializer for shadowed
# 2856| getExpr(): [VariableAccess] x
# 2856| Type = [TypeTemplateParameter] T
# 2856| ValueCategory = lvalue
# 2856| getExpr().getFullyConverted(): [CStyleCast] (int)...
# 2856| Type = [IntType] int
# 2856| ValueCategory = prvalue
# 2857| getStmt(1): [ExprStmt] ExprStmt
# 2857| getExpr(): [Literal] 0
# 2857| Type = [IntType] int
# 2857| Value = [Literal] 0
# 2857| ValueCategory = prvalue
# 2857| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2857| Type = [VoidType] void
# 2857| ValueCategory = prvalue
# 2857| getExpr(): [CStyleCast] (void)...
# 2857| Conversion = [VoidConversion] conversion to void
# 2857| Type = [VoidType] void
# 2857| ValueCategory = prvalue
# 2859| getStmt(6): [ExprStmt] ExprStmt
# 2859| getExpr(): [Literal] 0
# 2859| Type = [IntType] int
# 2859| Value = [Literal] 0
# 2859| ValueCategory = prvalue
# 2859| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2859| Type = [VoidType] void
# 2859| ValueCategory = prvalue
# 2859| getExpr(): [CStyleCast] (void)...
# 2859| Conversion = [VoidConversion] conversion to void
# 2859| Type = [VoidType] void
# 2859| ValueCategory = prvalue
# 2860| getStmt(7): [ReturnStmt] return ...
# 2846| [FunctionTemplateInstantiation,TopLevelFunction] void test_assert_in_template<int>(int, int, unsigned int)
# 2846| <params>:
# 2846| getParameter(0): [Parameter] x
# 2846| Type = [IntType] int
# 2846| getParameter(1): [Parameter] y
# 2846| Type = [IntType] int
# 2846| getParameter(2): [Parameter] u
# 2846| Type = [IntType] unsigned int
# 2846| getEntryPoint(): [BlockStmt] { ... }
# 2847| getStmt(0): [ExprStmt] ExprStmt
# 2847| getExpr(): [Literal] 0
# 2847| Type = [IntType] int
# 2847| Value = [Literal] 0
# 2847| ValueCategory = prvalue
# 2847| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2847| Type = [VoidType] void
# 2847| ValueCategory = prvalue
# 2847| getExpr(): [CStyleCast] (void)...
# 2847| Conversion = [VoidConversion] conversion to void
# 2847| Type = [VoidType] void
# 2847| ValueCategory = prvalue
# 2848| getStmt(1): [ExprStmt] ExprStmt
# 2848| getExpr(): [Literal] 0
# 2848| Type = [IntType] int
# 2848| Value = [Literal] 0
# 2848| ValueCategory = prvalue
# 2848| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2848| Type = [VoidType] void
# 2848| ValueCategory = prvalue
# 2848| getExpr(): [CStyleCast] (void)...
# 2848| Conversion = [VoidConversion] conversion to void
# 2848| Type = [VoidType] void
# 2848| ValueCategory = prvalue
# 2849| getStmt(2): [ExprStmt] ExprStmt
# 2849| getExpr(): [Literal] 0
# 2849| Type = [IntType] int
# 2849| Value = [Literal] 0
# 2849| ValueCategory = prvalue
# 2849| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2849| Type = [VoidType] void
# 2849| ValueCategory = prvalue
# 2849| getExpr(): [CStyleCast] (void)...
# 2849| Conversion = [VoidConversion] conversion to void
# 2849| Type = [VoidType] void
# 2849| ValueCategory = prvalue
# 2851| getStmt(3): [EmptyStmt] ;
# 2853| getStmt(4): [ExprStmt] ExprStmt
# 2853| getExpr(): [Literal] 0
# 2853| Type = [IntType] int
# 2853| Value = [Literal] 0
# 2853| ValueCategory = prvalue
# 2853| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2853| Type = [VoidType] void
# 2853| ValueCategory = prvalue
# 2853| getExpr(): [CStyleCast] (void)...
# 2853| Conversion = [VoidConversion] conversion to void
# 2853| Type = [VoidType] void
# 2853| ValueCategory = prvalue
# 2855| getStmt(5): [BlockStmt] { ... }
# 2856| getStmt(0): [DeclStmt] declaration
# 2856| getDeclarationEntry(0): [VariableDeclarationEntry] definition of shadowed
# 2856| Type = [IntType] int
# 2856| getVariable().getInitializer(): [Initializer] initializer for shadowed
# 2856| getExpr(): [VariableAccess] x
# 2856| Type = [IntType] int
# 2856| ValueCategory = prvalue(load)
# 2857| getStmt(1): [ExprStmt] ExprStmt
# 2857| getExpr(): [Literal] 0
# 2857| Type = [IntType] int
# 2857| Value = [Literal] 0
# 2857| ValueCategory = prvalue
# 2857| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2857| Type = [VoidType] void
# 2857| ValueCategory = prvalue
# 2857| getExpr(): [CStyleCast] (void)...
# 2857| Conversion = [VoidConversion] conversion to void
# 2857| Type = [VoidType] void
# 2857| ValueCategory = prvalue
# 2859| getStmt(6): [ExprStmt] ExprStmt
# 2859| getExpr(): [Literal] 0
# 2859| Type = [IntType] int
# 2859| Value = [Literal] 0
# 2859| ValueCategory = prvalue
# 2859| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2859| Type = [VoidType] void
# 2859| ValueCategory = prvalue
# 2859| getExpr(): [CStyleCast] (void)...
# 2859| Conversion = [VoidConversion] conversion to void
# 2859| Type = [VoidType] void
# 2859| ValueCategory = prvalue
# 2860| getStmt(7): [ReturnStmt] return ...
# 2846| [FunctionTemplateInstantiation,TopLevelFunction] void test_assert_in_template<short>(short, int, unsigned int)
# 2846| <params>:
# 2846| getParameter(0): [Parameter] x
# 2846| Type = [ShortType] short
# 2846| getParameter(1): [Parameter] y
# 2846| Type = [IntType] int
# 2846| getParameter(2): [Parameter] u
# 2846| Type = [IntType] unsigned int
# 2846| getEntryPoint(): [BlockStmt] { ... }
# 2847| getStmt(0): [ExprStmt] ExprStmt
# 2847| getExpr(): [Literal] 0
# 2847| Type = [IntType] int
# 2847| Value = [Literal] 0
# 2847| ValueCategory = prvalue
# 2847| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2847| Type = [VoidType] void
# 2847| ValueCategory = prvalue
# 2847| getExpr(): [CStyleCast] (void)...
# 2847| Conversion = [VoidConversion] conversion to void
# 2847| Type = [VoidType] void
# 2847| ValueCategory = prvalue
# 2848| getStmt(1): [ExprStmt] ExprStmt
# 2848| getExpr(): [Literal] 0
# 2848| Type = [IntType] int
# 2848| Value = [Literal] 0
# 2848| ValueCategory = prvalue
# 2848| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2848| Type = [VoidType] void
# 2848| ValueCategory = prvalue
# 2848| getExpr(): [CStyleCast] (void)...
# 2848| Conversion = [VoidConversion] conversion to void
# 2848| Type = [VoidType] void
# 2848| ValueCategory = prvalue
# 2849| getStmt(2): [ExprStmt] ExprStmt
# 2849| getExpr(): [Literal] 0
# 2849| Type = [IntType] int
# 2849| Value = [Literal] 0
# 2849| ValueCategory = prvalue
# 2849| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2849| Type = [VoidType] void
# 2849| ValueCategory = prvalue
# 2849| getExpr(): [CStyleCast] (void)...
# 2849| Conversion = [VoidConversion] conversion to void
# 2849| Type = [VoidType] void
# 2849| ValueCategory = prvalue
# 2851| getStmt(3): [EmptyStmt] ;
# 2853| getStmt(4): [ExprStmt] ExprStmt
# 2853| getExpr(): [Literal] 0
# 2853| Type = [IntType] int
# 2853| Value = [Literal] 0
# 2853| ValueCategory = prvalue
# 2853| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2853| Type = [VoidType] void
# 2853| ValueCategory = prvalue
# 2853| getExpr(): [CStyleCast] (void)...
# 2853| Conversion = [VoidConversion] conversion to void
# 2853| Type = [VoidType] void
# 2853| ValueCategory = prvalue
# 2855| getStmt(5): [BlockStmt] { ... }
# 2856| getStmt(0): [DeclStmt] declaration
# 2856| getDeclarationEntry(0): [VariableDeclarationEntry] definition of shadowed
# 2856| Type = [IntType] int
# 2856| getVariable().getInitializer(): [Initializer] initializer for shadowed
# 2856| getExpr(): [VariableAccess] x
# 2856| Type = [ShortType] short
# 2856| ValueCategory = prvalue(load)
# 2856| getExpr().getFullyConverted(): [CStyleCast] (int)...
# 2856| Conversion = [IntegralConversion] integral conversion
# 2856| Type = [IntType] int
# 2856| ValueCategory = prvalue
# 2857| getStmt(1): [ExprStmt] ExprStmt
# 2857| getExpr(): [Literal] 0
# 2857| Type = [IntType] int
# 2857| Value = [Literal] 0
# 2857| ValueCategory = prvalue
# 2857| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2857| Type = [VoidType] void
# 2857| ValueCategory = prvalue
# 2857| getExpr(): [CStyleCast] (void)...
# 2857| Conversion = [VoidConversion] conversion to void
# 2857| Type = [VoidType] void
# 2857| ValueCategory = prvalue
# 2859| getStmt(6): [ExprStmt] ExprStmt
# 2859| getExpr(): [Literal] 0
# 2859| Type = [IntType] int
# 2859| Value = [Literal] 0
# 2859| ValueCategory = prvalue
# 2859| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2859| Type = [VoidType] void
# 2859| ValueCategory = prvalue
# 2859| getExpr(): [CStyleCast] (void)...
# 2859| Conversion = [VoidConversion] conversion to void
# 2859| Type = [VoidType] void
# 2859| ValueCategory = prvalue
# 2860| getStmt(7): [ReturnStmt] return ...
# 2867| [TopLevelFunction] void (unnamed namespace)::complex_assertions(int, bool, int)
# 2867| <params>:
# 2867| getParameter(0): [Parameter] x
# 2867| Type = [IntType] int
# 2867| getParameter(1): [Parameter] b
# 2867| Type = [BoolType] bool
# 2867| getParameter(2): [Parameter] max
# 2867| Type = [IntType] int
# 2867| getEntryPoint(): [BlockStmt] { ... }
# 2868| getStmt(0): [DeclStmt] declaration
# 2868| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
# 2868| Type = [IntType] int
# 2868| getVariable().getInitializer(): [Initializer] initializer for y
# 2868| getExpr(): [CommaExpr] ... , ...
# 2868| Type = [IntType] int
# 2868| ValueCategory = prvalue(load)
# 2868| getLeftOperand(): [Literal] 0
# 2868| Type = [IntType] int
# 2868| Value = [Literal] 0
# 2868| ValueCategory = prvalue
# 2868| getRightOperand(): [VariableAccess] x
# 2868| Type = [IntType] int
# 2868| ValueCategory = prvalue(load)
# 2868| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
# 2868| Type = [VoidType] void
# 2868| ValueCategory = prvalue
# 2868| getExpr(): [CStyleCast] (void)...
# 2868| Conversion = [VoidConversion] conversion to void
# 2868| Type = [VoidType] void
# 2868| ValueCategory = prvalue
# 2868| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2868| Type = [IntType] int
# 2868| ValueCategory = prvalue(load)
# 2869| getStmt(1): [DeclStmt] declaration
# 2869| getDeclarationEntry(0): [VariableDeclarationEntry] definition of z
# 2869| Type = [IntType] int
# 2869| getVariable().getInitializer(): [Initializer] initializer for z
# 2869| getExpr(): [ConditionalExpr] ... ? ... : ...
# 2869| Type = [IntType] int
# 2869| ValueCategory = prvalue
# 2869| getCondition(): [VariableAccess] b
# 2869| Type = [BoolType] bool
# 2869| ValueCategory = prvalue(load)
# 2869| getThen(): [CommaExpr] ... , ...
# 2869| Type = [IntType] int
# 2869| Value = [CommaExpr] 0
# 2869| ValueCategory = prvalue
# 2869| getLeftOperand(): [Literal] 0
# 2869| Type = [IntType] int
# 2869| Value = [Literal] 0
# 2869| ValueCategory = prvalue
# 2869| getRightOperand(): [Literal] 0
# 2869| Type = [IntType] int
# 2869| Value = [Literal] 0
# 2869| ValueCategory = prvalue
# 2869| getLeftOperand().getFullyConverted(): [ParenthesisExpr] (...)
# 2869| Type = [VoidType] void
# 2869| ValueCategory = prvalue
# 2869| getExpr(): [CStyleCast] (void)...
# 2869| Conversion = [VoidConversion] conversion to void
# 2869| Type = [VoidType] void
# 2869| ValueCategory = prvalue
# 2869| getElse(): [Literal] 1
# 2869| Type = [IntType] int
# 2869| Value = [Literal] 1
# 2869| ValueCategory = prvalue
# 2869| getThen().getFullyConverted(): [ParenthesisExpr] (...)
# 2869| Type = [IntType] int
# 2869| Value = [ParenthesisExpr] 0
# 2869| ValueCategory = prvalue
# 2871| getStmt(2): [TryStmt] try { ... }
# 2871| getStmt(): [BlockStmt] { ... }
# 2872| getStmt(0): [ExprStmt] ExprStmt
# 2872| getExpr(): [ThrowExpr] throw ...
# 2872| Type = [IntType] int
# 2872| ValueCategory = prvalue
# 2872| getExpr(): [Literal] 41
# 2872| Type = [IntType] int
# 2872| Value = [Literal] 41
# 2872| ValueCategory = prvalue
# 2873| getChild(1): [Handler] <handler>
# 2873| getParameter(): [Parameter] c
# 2873| Type = [IntType] int
# 2873| getBlock(): [CatchBlock] { ... }
# 2874| getStmt(0): [ExprStmt] ExprStmt
# 2874| getExpr(): [Literal] 0
# 2874| Type = [IntType] int
# 2874| Value = [Literal] 0
# 2874| ValueCategory = prvalue
# 2874| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2874| Type = [VoidType] void
# 2874| ValueCategory = prvalue
# 2874| getExpr(): [CStyleCast] (void)...
# 2874| Conversion = [VoidConversion] conversion to void
# 2874| Type = [VoidType] void
# 2874| ValueCategory = prvalue
# 2875| getStmt(1): [ExprStmt] ExprStmt
# 2875| getExpr(): [Literal] 0
# 2875| Type = [IntType] int
# 2875| Value = [Literal] 0
# 2875| ValueCategory = prvalue
# 2875| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2875| Type = [VoidType] void
# 2875| ValueCategory = prvalue
# 2875| getExpr(): [CStyleCast] (void)...
# 2875| Conversion = [VoidConversion] conversion to void
# 2875| Type = [VoidType] void
# 2875| ValueCategory = prvalue
# 2878| getStmt(3): [ExprStmt] ExprStmt
# 2878| getExpr(): [Literal] 0
# 2878| Type = [IntType] int
# 2878| Value = [Literal] 0
# 2878| ValueCategory = prvalue
# 2878| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2878| Type = [VoidType] void
# 2878| ValueCategory = prvalue
# 2878| getExpr(): [CStyleCast] (void)...
# 2878| Conversion = [VoidConversion] conversion to void
# 2878| Type = [VoidType] void
# 2878| ValueCategory = prvalue
# 2879| getStmt(4): [DeclStmt] declaration
# 2879| getDeclarationEntry(0): [VariableDeclarationEntry] definition of shadowed
# 2879| Type = [IntType] int
# 2881| getStmt(5): [TryStmt] try { ... }
# 2881| getStmt(): [BlockStmt] { ... }
# 2882| getStmt(0): [ExprStmt] ExprStmt
# 2882| getExpr(): [ThrowExpr] throw ...
# 2882| Type = [IntType] int
# 2882| ValueCategory = prvalue
# 2882| getExpr(): [Literal] 41
# 2882| Type = [IntType] int
# 2882| Value = [Literal] 41
# 2882| ValueCategory = prvalue
# 2883| getChild(1): [Handler] <handler>
# 2883| getParameter(): [Parameter] shadowed
# 2883| Type = [IntType] int
# 2883| getBlock(): [CatchBlock] { ... }
# 2884| getStmt(0): [ExprStmt] ExprStmt
# 2884| getExpr(): [Literal] 0
# 2884| Type = [IntType] int
# 2884| Value = [Literal] 0
# 2884| ValueCategory = prvalue
# 2884| getExpr().getFullyConverted(): [ParenthesisExpr] (...)
# 2884| Type = [VoidType] void
# 2884| ValueCategory = prvalue
# 2884| getExpr(): [CStyleCast] (void)...
# 2884| Conversion = [VoidConversion] conversion to void
# 2884| Type = [VoidType] void
# 2884| ValueCategory = prvalue
# 2886| getStmt(6): [ReturnStmt] return ...
ir23.cpp:
# 1| [TopLevelFunction] bool consteval_1()
# 1| <params>:

View File

@@ -20741,6 +20741,331 @@ ir.cpp:
# 2821| v2821_10(void) = AliasedUse : m2821_3
# 2821| v2821_11(void) = ExitFunction :
# 2830| void test_assert_simple(int, int, unsigned int, int)
# 2830| Block 0
# 2830| v2830_1(void) = EnterFunction :
# 2830| m2830_2(unknown) = AliasedDefinition :
# 2830| m2830_3(unknown) = InitializeNonLocal :
# 2830| m2830_4(unknown) = Chi : total:m2830_2, partial:m2830_3
# 2830| r2830_5(glval<int>) = VariableAddress[x] :
# 2830| m2830_6(int) = InitializeParameter[x] : &:r2830_5
# 2830| r2830_7(glval<int>) = VariableAddress[y] :
# 2830| m2830_8(int) = InitializeParameter[y] : &:r2830_7
# 2830| r2830_9(glval<unsigned int>) = VariableAddress[u] :
# 2830| m2830_10(unsigned int) = InitializeParameter[u] : &:r2830_9
# 2830| r2830_11(glval<int>) = VariableAddress[shadowed] :
# 2830| m2830_12(int) = InitializeParameter[shadowed] : &:r2830_11
# 2831| r2831_1(glval<int>) = VariableAddress[x] :
# 2831| r2831_2(int) = Load[x] : &:r2831_1, m2830_6
# 2831| r2831_3(int) = Constant[0] :
# 2831| r2831_4(bool) = CompareGT : r2831_2, r2831_3
# 2831| v2831_5(void) = ConditionalBranch : r2831_4
#-----| True -> Block 1
# 2832| Block 1
# 2832| r2832_1(int) = Constant[0] :
# 2832| r2832_2(glval<int>) = VariableAddress[x] :
# 2832| r2832_3(int) = Load[x] : &:r2832_2, m2830_6
# 2832| r2832_4(bool) = CompareLT : r2832_1, r2832_3
# 2832| v2832_5(void) = ConditionalBranch : r2832_4
#-----| True -> Block 2
# 2833| Block 2
# 2833| r2833_1(glval<int>) = VariableAddress[x] :
# 2833| r2833_2(int) = Load[x] : &:r2833_1, m2830_6
# 2833| r2833_3(glval<int>) = VariableAddress[y] :
# 2833| r2833_4(int) = Load[y] : &:r2833_3, m2830_8
# 2833| r2833_5(bool) = CompareLT : r2833_2, r2833_4
# 2833| v2833_6(void) = ConditionalBranch : r2833_5
#-----| True -> Block 3
# 2835| Block 3
# 2835| r2835_1(glval<int>) = VariableAddress[x] :
# 2835| r2835_2(int) = Load[x] : &:r2835_1, m2830_6
# 2835| r2835_3(int) = Constant[2] :
# 2835| r2835_4(bool) = CompareNE : r2835_2, r2835_3
# 2835| v2835_5(void) = ConditionalBranch : r2835_4
#-----| True -> Block 4
# 2837| Block 4
# 2837| r2837_1(glval<unsigned int>) = VariableAddress[u] :
# 2837| r2837_2(unsigned int) = Load[u] : &:r2837_1, m2830_10
# 2837| r2837_3(glval<int>) = VariableAddress[x] :
# 2837| r2837_4(int) = Load[x] : &:r2837_3, m2830_6
# 2837| r2837_5(bool) = CompareLT : r2837_2, r2837_4
# 2837| v2837_6(void) = ConditionalBranch : r2837_5
#-----| True -> Block 5
# 2840| Block 5
# 2840| r2840_1(glval<int>) = VariableAddress[shadowed] :
# 2840| r2840_2(glval<int>) = VariableAddress[x] :
# 2840| r2840_3(int) = Load[x] : &:r2840_2, m2830_6
# 2840| m2840_4(int) = Store[shadowed] : &:r2840_1, r2840_3
# 2841| r2841_1(int) = Constant[0] :
# 2841| v2841_2(void) = Convert : r2841_1
# 2843| v2843_1(void) = NoOp :
# 2830| v2830_13(void) = ReturnVoid :
# 2830| v2830_14(void) = AliasedUse : m2830_3
# 2830| v2830_15(void) = ExitFunction :
# 2846| void test_assert_in_template<int>(int, int, unsigned int)
# 2846| Block 0
# 2846| v2846_1(void) = EnterFunction :
# 2846| m2846_2(unknown) = AliasedDefinition :
# 2846| m2846_3(unknown) = InitializeNonLocal :
# 2846| m2846_4(unknown) = Chi : total:m2846_2, partial:m2846_3
# 2846| r2846_5(glval<int>) = VariableAddress[x] :
# 2846| m2846_6(int) = InitializeParameter[x] : &:r2846_5
# 2846| r2846_7(glval<int>) = VariableAddress[y] :
# 2846| m2846_8(int) = InitializeParameter[y] : &:r2846_7
# 2846| r2846_9(glval<unsigned int>) = VariableAddress[u] :
# 2846| m2846_10(unsigned int) = InitializeParameter[u] : &:r2846_9
# 2847| r2847_1(glval<int>) = VariableAddress[x] :
# 2847| r2847_2(int) = Load[x] : &:r2847_1, m2846_6
# 2847| r2847_3(int) = Constant[0] :
# 2847| r2847_4(bool) = CompareGT : r2847_2, r2847_3
# 2847| v2847_5(void) = ConditionalBranch : r2847_4
#-----| True -> Block 1
# 2848| Block 1
# 2848| r2848_1(int) = Constant[0] :
# 2848| r2848_2(glval<int>) = VariableAddress[x] :
# 2848| r2848_3(int) = Load[x] : &:r2848_2, m2846_6
# 2848| r2848_4(bool) = CompareLT : r2848_1, r2848_3
# 2848| v2848_5(void) = ConditionalBranch : r2848_4
#-----| True -> Block 2
# 2849| Block 2
# 2849| r2849_1(glval<int>) = VariableAddress[x] :
# 2849| r2849_2(int) = Load[x] : &:r2849_1, m2846_6
# 2849| r2849_3(glval<int>) = VariableAddress[y] :
# 2849| r2849_4(int) = Load[y] : &:r2849_3, m2846_8
# 2849| r2849_5(bool) = CompareLT : r2849_2, r2849_4
# 2849| v2849_6(void) = ConditionalBranch : r2849_5
#-----| True -> Block 3
# 2851| Block 3
# 2851| r2851_1(glval<int>) = VariableAddress[x] :
# 2851| r2851_2(int) = Load[x] : &:r2851_1, m2846_6
# 2851| r2851_3(int) = Constant[2] :
# 2851| r2851_4(bool) = CompareNE : r2851_2, r2851_3
# 2851| v2851_5(void) = ConditionalBranch : r2851_4
#-----| True -> Block 4
# 2853| Block 4
# 2853| r2853_1(glval<unsigned int>) = VariableAddress[u] :
# 2853| r2853_2(unsigned int) = Load[u] : &:r2853_1, m2846_10
# 2853| r2853_3(glval<int>) = VariableAddress[x] :
# 2853| r2853_4(int) = Load[x] : &:r2853_3, m2846_6
# 2853| r2853_5(bool) = CompareLT : r2853_2, r2853_4
# 2853| v2853_6(void) = ConditionalBranch : r2853_5
#-----| True -> Block 5
# 2856| Block 5
# 2856| r2856_1(glval<int>) = VariableAddress[shadowed] :
# 2856| r2856_2(glval<int>) = VariableAddress[x] :
# 2856| r2856_3(int) = Load[x] : &:r2856_2, m2846_6
# 2856| m2856_4(int) = Store[shadowed] : &:r2856_1, r2856_3
# 2857| r2857_1(glval<int>) = VariableAddress[shadowed] :
# 2857| r2857_2(int) = Load[shadowed] : &:r2857_1, m2856_4
# 2857| r2857_3(int) = Constant[0] :
# 2857| r2857_4(bool) = CompareGT : r2857_2, r2857_3
# 2857| v2857_5(void) = ConditionalBranch : r2857_4
#-----| True -> Block 6
# 2859| Block 6
# 2859| r2859_1(glval<int>) = VariableAddress[x] :
# 2859| r2859_2(int) = Load[x] : &:r2859_1, m2846_6
# 2859| r2859_3(int) = Constant[0] :
# 2859| r2859_4(bool) = CompareGT : r2859_2, r2859_3
# 2859| v2859_5(void) = ConditionalBranch : r2859_4
#-----| True -> Block 7
# 2860| Block 7
# 2860| v2860_1(void) = NoOp :
# 2846| v2846_11(void) = ReturnVoid :
# 2846| v2846_12(void) = AliasedUse : m2846_3
# 2846| v2846_13(void) = ExitFunction :
# 2846| void test_assert_in_template<short>(short, int, unsigned int)
# 2846| Block 0
# 2846| v2846_1(void) = EnterFunction :
# 2846| m2846_2(unknown) = AliasedDefinition :
# 2846| m2846_3(unknown) = InitializeNonLocal :
# 2846| m2846_4(unknown) = Chi : total:m2846_2, partial:m2846_3
# 2846| r2846_5(glval<short>) = VariableAddress[x] :
# 2846| m2846_6(short) = InitializeParameter[x] : &:r2846_5
# 2846| r2846_7(glval<int>) = VariableAddress[y] :
# 2846| m2846_8(int) = InitializeParameter[y] : &:r2846_7
# 2846| r2846_9(glval<unsigned int>) = VariableAddress[u] :
# 2846| m2846_10(unsigned int) = InitializeParameter[u] : &:r2846_9
# 2847| r2847_1(glval<short>) = VariableAddress[x] :
# 2847| r2847_2(short) = Load[x] : &:r2847_1, m2846_6
# 2847| r2847_3(int) = Constant[0] :
# 2847| r2847_4(bool) = CompareGT : r2847_2, r2847_3
# 2847| v2847_5(void) = ConditionalBranch : r2847_4
#-----| True -> Block 1
# 2848| Block 1
# 2848| r2848_1(int) = Constant[0] :
# 2848| r2848_2(glval<short>) = VariableAddress[x] :
# 2848| r2848_3(short) = Load[x] : &:r2848_2, m2846_6
# 2848| r2848_4(bool) = CompareLT : r2848_1, r2848_3
# 2848| v2848_5(void) = ConditionalBranch : r2848_4
#-----| True -> Block 2
# 2849| Block 2
# 2849| r2849_1(glval<short>) = VariableAddress[x] :
# 2849| r2849_2(short) = Load[x] : &:r2849_1, m2846_6
# 2849| r2849_3(glval<int>) = VariableAddress[y] :
# 2849| r2849_4(int) = Load[y] : &:r2849_3, m2846_8
# 2849| r2849_5(bool) = CompareLT : r2849_2, r2849_4
# 2849| v2849_6(void) = ConditionalBranch : r2849_5
#-----| True -> Block 3
# 2851| Block 3
# 2851| r2851_1(glval<short>) = VariableAddress[x] :
# 2851| r2851_2(short) = Load[x] : &:r2851_1, m2846_6
# 2851| r2851_3(int) = Constant[2] :
# 2851| r2851_4(bool) = CompareNE : r2851_2, r2851_3
# 2851| v2851_5(void) = ConditionalBranch : r2851_4
#-----| True -> Block 4
# 2853| Block 4
# 2853| r2853_1(glval<unsigned int>) = VariableAddress[u] :
# 2853| r2853_2(unsigned int) = Load[u] : &:r2853_1, m2846_10
# 2853| r2853_3(glval<short>) = VariableAddress[x] :
# 2853| r2853_4(short) = Load[x] : &:r2853_3, m2846_6
# 2853| r2853_5(bool) = CompareLT : r2853_2, r2853_4
# 2853| v2853_6(void) = ConditionalBranch : r2853_5
#-----| True -> Block 5
# 2856| Block 5
# 2856| r2856_1(glval<int>) = VariableAddress[shadowed] :
# 2856| r2856_2(glval<short>) = VariableAddress[x] :
# 2856| r2856_3(short) = Load[x] : &:r2856_2, m2846_6
# 2856| r2856_4(int) = Convert : r2856_3
# 2856| m2856_5(int) = Store[shadowed] : &:r2856_1, r2856_4
# 2857| r2857_1(glval<int>) = VariableAddress[shadowed] :
# 2857| r2857_2(int) = Load[shadowed] : &:r2857_1, m2856_5
# 2857| r2857_3(int) = Constant[0] :
# 2857| r2857_4(bool) = CompareGT : r2857_2, r2857_3
# 2857| v2857_5(void) = ConditionalBranch : r2857_4
#-----| True -> Block 6
# 2859| Block 6
# 2859| r2859_1(glval<short>) = VariableAddress[x] :
# 2859| r2859_2(short) = Load[x] : &:r2859_1, m2846_6
# 2859| r2859_3(int) = Constant[0] :
# 2859| r2859_4(bool) = CompareGT : r2859_2, r2859_3
# 2859| v2859_5(void) = ConditionalBranch : r2859_4
#-----| True -> Block 7
# 2860| Block 7
# 2860| v2860_1(void) = NoOp :
# 2846| v2846_11(void) = ReturnVoid :
# 2846| v2846_12(void) = AliasedUse : m2846_3
# 2846| v2846_13(void) = ExitFunction :
# 2867| void (unnamed namespace)::complex_assertions(int, bool, int)
# 2867| Block 0
# 2867| v2867_1(void) = EnterFunction :
# 2867| m2867_2(unknown) = AliasedDefinition :
# 2867| m2867_3(unknown) = InitializeNonLocal :
# 2867| m2867_4(unknown) = Chi : total:m2867_2, partial:m2867_3
# 2867| r2867_5(glval<int>) = VariableAddress[x] :
# 2867| m2867_6(int) = InitializeParameter[x] : &:r2867_5
# 2867| r2867_7(glval<bool>) = VariableAddress[b] :
# 2867| m2867_8(bool) = InitializeParameter[b] : &:r2867_7
# 2867| r2867_9(glval<int>) = VariableAddress[max] :
# 2867| m2867_10(int) = InitializeParameter[max] : &:r2867_9
# 2868| r2868_1(glval<int>) = VariableAddress[y] :
# 2868| r2868_2(int) = Constant[0] :
# 2868| v2868_3(void) = Convert : r2868_2
# 2868| r2868_4(glval<int>) = VariableAddress[x] :
# 2868| r2868_5(int) = Load[x] : &:r2868_4, m2867_6
# 2868| r2868_6(int) = CopyValue : r2868_5
# 2868| m2868_7(int) = Store[y] : &:r2868_1, r2868_6
# 2869| r2869_1(glval<int>) = VariableAddress[z] :
# 2869| r2869_2(glval<bool>) = VariableAddress[b] :
# 2869| r2869_3(bool) = Load[b] : &:r2869_2, m2867_8
# 2869| v2869_4(void) = ConditionalBranch : r2869_3
#-----| False -> Block 5
#-----| True -> Block 4
# 2867| Block 1
# 2867| v2867_11(void) = AliasedUse : m2867_3
# 2867| v2867_12(void) = ExitFunction :
# 2867| Block 2
# 2867| v2867_13(void) = Unwind :
#-----| Goto -> Block 1
# 2869| Block 3
# 2869| m2869_5(int) = Phi : from 4:m2869_11, from 5:m2869_14
# 2869| r2869_6(glval<int>) = VariableAddress[#temp2869:17] :
# 2869| r2869_7(int) = Load[#temp2869:17] : &:r2869_6, m2869_5
# 2869| m2869_8(int) = Store[z] : &:r2869_1, r2869_7
# 2872| r2872_1(glval<int>) = VariableAddress[#throw2872:13] :
# 2872| r2872_2(int) = Constant[41] :
# 2872| m2872_3(int) = Store[#throw2872:13] : &:r2872_1, r2872_2
# 2872| v2872_4(void) = ThrowValue : &:r2872_1, m2872_3
#-----| C++ Exception -> Block 6
# 2869| Block 4
# 2869| r2869_9(int) = Constant[0] :
# 2869| r2869_10(glval<int>) = VariableAddress[#temp2869:17] :
# 2869| m2869_11(int) = Store[#temp2869:17] : &:r2869_10, r2869_9
#-----| Goto -> Block 3
# 2869| Block 5
# 2869| r2869_12(int) = Constant[1] :
# 2869| r2869_13(glval<int>) = VariableAddress[#temp2869:17] :
# 2869| m2869_14(int) = Store[#temp2869:17] : &:r2869_13, r2869_12
#-----| Goto -> Block 3
# 2873| Block 6
# 2873| v2873_1(void) = CatchByType[int] :
#-----| C++ Exception -> Block 2
#-----| Goto -> Block 7
# 2873| Block 7
# 2873| r2873_2(glval<int>) = VariableAddress[c] :
# 2873| m2873_3(int) = InitializeParameter[c] : &:r2873_2
# 2874| r2874_1(glval<int>) = VariableAddress[c] :
# 2874| r2874_2(int) = Load[c] : &:r2874_1, m2873_3
# 2874| r2874_3(int) = Constant[42] :
# 2874| r2874_4(bool) = CompareLT : r2874_2, r2874_3
# 2874| v2874_5(void) = ConditionalBranch : r2874_4
#-----| True -> Block 8
# 2875| Block 8
# 2875| r2875_1(int) = Constant[0] :
# 2875| v2875_2(void) = Convert : r2875_1
# 2878| r2878_1(int) = Constant[0] :
# 2878| v2878_2(void) = Convert : r2878_1
# 2879| r2879_1(glval<int>) = VariableAddress[shadowed] :
# 2879| m2879_2(int) = Uninitialized[shadowed] : &:r2879_1
# 2882| r2882_1(glval<int>) = VariableAddress[#throw2882:13] :
# 2882| r2882_2(int) = Constant[41] :
# 2882| m2882_3(int) = Store[#throw2882:13] : &:r2882_1, r2882_2
# 2882| v2882_4(void) = ThrowValue : &:r2882_1, m2882_3
#-----| C++ Exception -> Block 9
# 2883| Block 9
# 2883| v2883_1(void) = CatchByType[int] :
#-----| C++ Exception -> Block 2
#-----| Goto -> Block 10
# 2883| Block 10
# 2883| r2883_2(glval<int>) = VariableAddress[shadowed] :
# 2883| m2883_3(int) = InitializeParameter[shadowed] : &:r2883_2
# 2884| r2884_1(int) = Constant[0] :
# 2884| v2884_2(void) = Convert : r2884_1
# 2886| v2886_1(void) = NoOp :
# 2867| v2867_14(void) = ReturnVoid :
#-----| Goto -> Block 1
ir23.cpp:
# 1| bool consteval_1()
# 1| Block 0

View File

@@ -0,0 +1,20 @@
import cpp
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.implementation.raw.internal.TranslatedAssertion
import utils.test.InlineExpectationsTest
module Test implements TestSig {
string getARelevantTag() { result = "var" }
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(TranslatedAssertionVarAccess tava, Variable v |
v = tava.getVariable() and
location = tava.getLocation() and
tava.toString() = element and
tag = "var" and
value = v.getLocation().getStartLine().toString() + ":" + v.getName()
)
}
}
import MakeTest<Test>

View File

@@ -2823,4 +2823,67 @@ void vla_sizeof_test5(int len1, size_t len2) {
size_t z = sizeof((*&tmp1)[1]);
}
// Common definitions for assertions in release builds
#define assert(x) ((void)0)
#define __analysis_assume(x)
void test_assert_simple(int x, int y, unsigned u, int shadowed) {
assert(x > 0); // $ var=2830:x
assert(0 < x); // $ var=2830:x
assert(x < y); // $ var=2830:x var=2830:y
__analysis_assume(x != 2); // $ var=2830:x
assert(u < x); // $ var=2830:u var=2830:x
{
int shadowed = x;
assert(shadowed > 0); // no assertion generated since the variable is shadowed
}
}
template<typename T>
void test_assert_in_template(T x, int y, unsigned u) {
assert(x > 0); // $ var=2846:x
assert(0 < x); // $ var=2846:x
assert(x < y); // $ var=2846:x var=2846:y
__analysis_assume(x != 2); // $ var=2846:x
assert(u < x); // $ var=2846:u var=2846:x
{
int shadowed = x;
assert(shadowed > 0); // $ var=2856:shadowed
}
assert(x> 0); // $ var=2846:x
}
template void test_assert_in_template<int>(int, int, unsigned);
template void test_assert_in_template<short>(short, int, unsigned);
namespace {
int shadowed;
void complex_assertions(int x, bool b, int max) {
int y = (assert(x > 0), x); // no assertion generated
int z = b ? (assert(x != 0), 0) : 1; // no assertion generated
try {
throw 41;
} catch (int c) {
assert(c < 42); // $ var=2873:c
assert(shadowed < 42); // no assertion generated
}
assert(shadowed > 0); // no assertion generated
int shadowed;
try {
throw 41;
} catch (int shadowed) {
assert(shadowed < 42); // no assertion generated
}
}
}
// semmle-extractor-options: -std=c++20 --clang

View File

@@ -18880,6 +18880,326 @@ ir.cpp:
# 2821| v2821_9(void) = AliasedUse : ~m?
# 2821| v2821_10(void) = ExitFunction :
# 2830| void test_assert_simple(int, int, unsigned int, int)
# 2830| Block 0
# 2830| v2830_1(void) = EnterFunction :
# 2830| mu2830_2(unknown) = AliasedDefinition :
# 2830| mu2830_3(unknown) = InitializeNonLocal :
# 2830| r2830_4(glval<int>) = VariableAddress[x] :
# 2830| mu2830_5(int) = InitializeParameter[x] : &:r2830_4
# 2830| r2830_6(glval<int>) = VariableAddress[y] :
# 2830| mu2830_7(int) = InitializeParameter[y] : &:r2830_6
# 2830| r2830_8(glval<unsigned int>) = VariableAddress[u] :
# 2830| mu2830_9(unsigned int) = InitializeParameter[u] : &:r2830_8
# 2830| r2830_10(glval<int>) = VariableAddress[shadowed] :
# 2830| mu2830_11(int) = InitializeParameter[shadowed] : &:r2830_10
# 2831| r2831_1(glval<int>) = VariableAddress[x] :
# 2831| r2831_2(int) = Load[x] : &:r2831_1, ~m?
# 2831| r2831_3(int) = Constant[0] :
# 2831| r2831_4(bool) = CompareGT : r2831_2, r2831_3
# 2831| v2831_5(void) = ConditionalBranch : r2831_4
#-----| True -> Block 1
# 2832| Block 1
# 2832| r2832_1(int) = Constant[0] :
# 2832| r2832_2(glval<int>) = VariableAddress[x] :
# 2832| r2832_3(int) = Load[x] : &:r2832_2, ~m?
# 2832| r2832_4(bool) = CompareLT : r2832_1, r2832_3
# 2832| v2832_5(void) = ConditionalBranch : r2832_4
#-----| True -> Block 2
# 2833| Block 2
# 2833| r2833_1(glval<int>) = VariableAddress[x] :
# 2833| r2833_2(int) = Load[x] : &:r2833_1, ~m?
# 2833| r2833_3(glval<int>) = VariableAddress[y] :
# 2833| r2833_4(int) = Load[y] : &:r2833_3, ~m?
# 2833| r2833_5(bool) = CompareLT : r2833_2, r2833_4
# 2833| v2833_6(void) = ConditionalBranch : r2833_5
#-----| True -> Block 3
# 2835| Block 3
# 2835| r2835_1(glval<int>) = VariableAddress[x] :
# 2835| r2835_2(int) = Load[x] : &:r2835_1, ~m?
# 2835| r2835_3(int) = Constant[2] :
# 2835| r2835_4(bool) = CompareNE : r2835_2, r2835_3
# 2835| v2835_5(void) = ConditionalBranch : r2835_4
#-----| True -> Block 4
# 2837| Block 4
# 2837| r2837_1(glval<unsigned int>) = VariableAddress[u] :
# 2837| r2837_2(unsigned int) = Load[u] : &:r2837_1, ~m?
# 2837| r2837_3(glval<int>) = VariableAddress[x] :
# 2837| r2837_4(int) = Load[x] : &:r2837_3, ~m?
# 2837| r2837_5(bool) = CompareLT : r2837_2, r2837_4
# 2837| v2837_6(void) = ConditionalBranch : r2837_5
#-----| True -> Block 5
# 2840| Block 5
# 2840| r2840_1(glval<int>) = VariableAddress[shadowed] :
# 2840| r2840_2(glval<int>) = VariableAddress[x] :
# 2840| r2840_3(int) = Load[x] : &:r2840_2, ~m?
# 2840| mu2840_4(int) = Store[shadowed] : &:r2840_1, r2840_3
# 2841| r2841_1(int) = Constant[0] :
# 2841| v2841_2(void) = Convert : r2841_1
# 2843| v2843_1(void) = NoOp :
# 2830| v2830_12(void) = ReturnVoid :
# 2830| v2830_13(void) = AliasedUse : ~m?
# 2830| v2830_14(void) = ExitFunction :
# 2846| void test_assert_in_template<int>(int, int, unsigned int)
# 2846| Block 0
# 2846| v2846_1(void) = EnterFunction :
# 2846| mu2846_2(unknown) = AliasedDefinition :
# 2846| mu2846_3(unknown) = InitializeNonLocal :
# 2846| r2846_4(glval<int>) = VariableAddress[x] :
# 2846| mu2846_5(int) = InitializeParameter[x] : &:r2846_4
# 2846| r2846_6(glval<int>) = VariableAddress[y] :
# 2846| mu2846_7(int) = InitializeParameter[y] : &:r2846_6
# 2846| r2846_8(glval<unsigned int>) = VariableAddress[u] :
# 2846| mu2846_9(unsigned int) = InitializeParameter[u] : &:r2846_8
# 2847| r2847_1(glval<int>) = VariableAddress[x] :
# 2847| r2847_2(int) = Load[x] : &:r2847_1, ~m?
# 2847| r2847_3(int) = Constant[0] :
# 2847| r2847_4(bool) = CompareGT : r2847_2, r2847_3
# 2847| v2847_5(void) = ConditionalBranch : r2847_4
#-----| True -> Block 1
# 2848| Block 1
# 2848| r2848_1(int) = Constant[0] :
# 2848| r2848_2(glval<int>) = VariableAddress[x] :
# 2848| r2848_3(int) = Load[x] : &:r2848_2, ~m?
# 2848| r2848_4(bool) = CompareLT : r2848_1, r2848_3
# 2848| v2848_5(void) = ConditionalBranch : r2848_4
#-----| True -> Block 2
# 2849| Block 2
# 2849| r2849_1(glval<int>) = VariableAddress[x] :
# 2849| r2849_2(int) = Load[x] : &:r2849_1, ~m?
# 2849| r2849_3(glval<int>) = VariableAddress[y] :
# 2849| r2849_4(int) = Load[y] : &:r2849_3, ~m?
# 2849| r2849_5(bool) = CompareLT : r2849_2, r2849_4
# 2849| v2849_6(void) = ConditionalBranch : r2849_5
#-----| True -> Block 3
# 2851| Block 3
# 2851| r2851_1(glval<int>) = VariableAddress[x] :
# 2851| r2851_2(int) = Load[x] : &:r2851_1, ~m?
# 2851| r2851_3(int) = Constant[2] :
# 2851| r2851_4(bool) = CompareNE : r2851_2, r2851_3
# 2851| v2851_5(void) = ConditionalBranch : r2851_4
#-----| True -> Block 4
# 2853| Block 4
# 2853| r2853_1(glval<unsigned int>) = VariableAddress[u] :
# 2853| r2853_2(unsigned int) = Load[u] : &:r2853_1, ~m?
# 2853| r2853_3(glval<int>) = VariableAddress[x] :
# 2853| r2853_4(int) = Load[x] : &:r2853_3, ~m?
# 2853| r2853_5(bool) = CompareLT : r2853_2, r2853_4
# 2853| v2853_6(void) = ConditionalBranch : r2853_5
#-----| True -> Block 5
# 2856| Block 5
# 2856| r2856_1(glval<int>) = VariableAddress[shadowed] :
# 2856| r2856_2(glval<int>) = VariableAddress[x] :
# 2856| r2856_3(int) = Load[x] : &:r2856_2, ~m?
# 2856| mu2856_4(int) = Store[shadowed] : &:r2856_1, r2856_3
# 2857| r2857_1(glval<int>) = VariableAddress[shadowed] :
# 2857| r2857_2(int) = Load[shadowed] : &:r2857_1, ~m?
# 2857| r2857_3(int) = Constant[0] :
# 2857| r2857_4(bool) = CompareGT : r2857_2, r2857_3
# 2857| v2857_5(void) = ConditionalBranch : r2857_4
#-----| True -> Block 6
# 2859| Block 6
# 2859| r2859_1(glval<int>) = VariableAddress[x] :
# 2859| r2859_2(int) = Load[x] : &:r2859_1, ~m?
# 2859| r2859_3(int) = Constant[0] :
# 2859| r2859_4(bool) = CompareGT : r2859_2, r2859_3
# 2859| v2859_5(void) = ConditionalBranch : r2859_4
#-----| True -> Block 7
# 2860| Block 7
# 2860| v2860_1(void) = NoOp :
# 2846| v2846_10(void) = ReturnVoid :
# 2846| v2846_11(void) = AliasedUse : ~m?
# 2846| v2846_12(void) = ExitFunction :
# 2846| void test_assert_in_template<short>(short, int, unsigned int)
# 2846| Block 0
# 2846| v2846_1(void) = EnterFunction :
# 2846| mu2846_2(unknown) = AliasedDefinition :
# 2846| mu2846_3(unknown) = InitializeNonLocal :
# 2846| r2846_4(glval<short>) = VariableAddress[x] :
# 2846| mu2846_5(short) = InitializeParameter[x] : &:r2846_4
# 2846| r2846_6(glval<int>) = VariableAddress[y] :
# 2846| mu2846_7(int) = InitializeParameter[y] : &:r2846_6
# 2846| r2846_8(glval<unsigned int>) = VariableAddress[u] :
# 2846| mu2846_9(unsigned int) = InitializeParameter[u] : &:r2846_8
# 2847| r2847_1(glval<short>) = VariableAddress[x] :
# 2847| r2847_2(short) = Load[x] : &:r2847_1, ~m?
# 2847| r2847_3(int) = Constant[0] :
# 2847| r2847_4(bool) = CompareGT : r2847_2, r2847_3
# 2847| v2847_5(void) = ConditionalBranch : r2847_4
#-----| True -> Block 1
# 2848| Block 1
# 2848| r2848_1(int) = Constant[0] :
# 2848| r2848_2(glval<short>) = VariableAddress[x] :
# 2848| r2848_3(short) = Load[x] : &:r2848_2, ~m?
# 2848| r2848_4(bool) = CompareLT : r2848_1, r2848_3
# 2848| v2848_5(void) = ConditionalBranch : r2848_4
#-----| True -> Block 2
# 2849| Block 2
# 2849| r2849_1(glval<short>) = VariableAddress[x] :
# 2849| r2849_2(short) = Load[x] : &:r2849_1, ~m?
# 2849| r2849_3(glval<int>) = VariableAddress[y] :
# 2849| r2849_4(int) = Load[y] : &:r2849_3, ~m?
# 2849| r2849_5(bool) = CompareLT : r2849_2, r2849_4
# 2849| v2849_6(void) = ConditionalBranch : r2849_5
#-----| True -> Block 3
# 2851| Block 3
# 2851| r2851_1(glval<short>) = VariableAddress[x] :
# 2851| r2851_2(short) = Load[x] : &:r2851_1, ~m?
# 2851| r2851_3(int) = Constant[2] :
# 2851| r2851_4(bool) = CompareNE : r2851_2, r2851_3
# 2851| v2851_5(void) = ConditionalBranch : r2851_4
#-----| True -> Block 4
# 2853| Block 4
# 2853| r2853_1(glval<unsigned int>) = VariableAddress[u] :
# 2853| r2853_2(unsigned int) = Load[u] : &:r2853_1, ~m?
# 2853| r2853_3(glval<short>) = VariableAddress[x] :
# 2853| r2853_4(short) = Load[x] : &:r2853_3, ~m?
# 2853| r2853_5(bool) = CompareLT : r2853_2, r2853_4
# 2853| v2853_6(void) = ConditionalBranch : r2853_5
#-----| True -> Block 5
# 2856| Block 5
# 2856| r2856_1(glval<int>) = VariableAddress[shadowed] :
# 2856| r2856_2(glval<short>) = VariableAddress[x] :
# 2856| r2856_3(short) = Load[x] : &:r2856_2, ~m?
# 2856| r2856_4(int) = Convert : r2856_3
# 2856| mu2856_5(int) = Store[shadowed] : &:r2856_1, r2856_4
# 2857| r2857_1(glval<int>) = VariableAddress[shadowed] :
# 2857| r2857_2(int) = Load[shadowed] : &:r2857_1, ~m?
# 2857| r2857_3(int) = Constant[0] :
# 2857| r2857_4(bool) = CompareGT : r2857_2, r2857_3
# 2857| v2857_5(void) = ConditionalBranch : r2857_4
#-----| True -> Block 6
# 2859| Block 6
# 2859| r2859_1(glval<short>) = VariableAddress[x] :
# 2859| r2859_2(short) = Load[x] : &:r2859_1, ~m?
# 2859| r2859_3(int) = Constant[0] :
# 2859| r2859_4(bool) = CompareGT : r2859_2, r2859_3
# 2859| v2859_5(void) = ConditionalBranch : r2859_4
#-----| True -> Block 7
# 2860| Block 7
# 2860| v2860_1(void) = NoOp :
# 2846| v2846_10(void) = ReturnVoid :
# 2846| v2846_11(void) = AliasedUse : ~m?
# 2846| v2846_12(void) = ExitFunction :
# 2867| void (unnamed namespace)::complex_assertions(int, bool, int)
# 2867| Block 0
# 2867| v2867_1(void) = EnterFunction :
# 2867| mu2867_2(unknown) = AliasedDefinition :
# 2867| mu2867_3(unknown) = InitializeNonLocal :
# 2867| r2867_4(glval<int>) = VariableAddress[x] :
# 2867| mu2867_5(int) = InitializeParameter[x] : &:r2867_4
# 2867| r2867_6(glval<bool>) = VariableAddress[b] :
# 2867| mu2867_7(bool) = InitializeParameter[b] : &:r2867_6
# 2867| r2867_8(glval<int>) = VariableAddress[max] :
# 2867| mu2867_9(int) = InitializeParameter[max] : &:r2867_8
# 2868| r2868_1(glval<int>) = VariableAddress[y] :
# 2868| r2868_2(int) = Constant[0] :
# 2868| v2868_3(void) = Convert : r2868_2
# 2868| r2868_4(glval<int>) = VariableAddress[x] :
# 2868| r2868_5(int) = Load[x] : &:r2868_4, ~m?
# 2868| r2868_6(int) = CopyValue : r2868_5
# 2868| mu2868_7(int) = Store[y] : &:r2868_1, r2868_6
# 2869| r2869_1(glval<int>) = VariableAddress[z] :
# 2869| r2869_2(glval<bool>) = VariableAddress[b] :
# 2869| r2869_3(bool) = Load[b] : &:r2869_2, ~m?
# 2869| v2869_4(void) = ConditionalBranch : r2869_3
#-----| False -> Block 5
#-----| True -> Block 4
# 2867| Block 1
# 2867| v2867_10(void) = AliasedUse : ~m?
# 2867| v2867_11(void) = ExitFunction :
# 2867| Block 2
# 2867| v2867_12(void) = Unwind :
#-----| Goto -> Block 1
# 2869| Block 3
# 2869| r2869_5(glval<int>) = VariableAddress[#temp2869:17] :
# 2869| r2869_6(int) = Load[#temp2869:17] : &:r2869_5, ~m?
# 2869| mu2869_7(int) = Store[z] : &:r2869_1, r2869_6
# 2872| r2872_1(glval<int>) = VariableAddress[#throw2872:13] :
# 2872| r2872_2(int) = Constant[41] :
# 2872| mu2872_3(int) = Store[#throw2872:13] : &:r2872_1, r2872_2
# 2872| v2872_4(void) = ThrowValue : &:r2872_1, ~m?
#-----| C++ Exception -> Block 6
# 2869| Block 4
# 2869| r2869_8(int) = Constant[0] :
# 2869| r2869_9(glval<int>) = VariableAddress[#temp2869:17] :
# 2869| mu2869_10(int) = Store[#temp2869:17] : &:r2869_9, r2869_8
#-----| Goto -> Block 3
# 2869| Block 5
# 2869| r2869_11(int) = Constant[1] :
# 2869| r2869_12(glval<int>) = VariableAddress[#temp2869:17] :
# 2869| mu2869_13(int) = Store[#temp2869:17] : &:r2869_12, r2869_11
#-----| Goto -> Block 3
# 2873| Block 6
# 2873| v2873_1(void) = CatchByType[int] :
#-----| C++ Exception -> Block 2
#-----| Goto -> Block 7
# 2873| Block 7
# 2873| r2873_2(glval<int>) = VariableAddress[c] :
# 2873| mu2873_3(int) = InitializeParameter[c] : &:r2873_2
# 2874| r2874_1(glval<int>) = VariableAddress[c] :
# 2874| r2874_2(int) = Load[c] : &:r2874_1, ~m?
# 2874| r2874_3(int) = Constant[42] :
# 2874| r2874_4(bool) = CompareLT : r2874_2, r2874_3
# 2874| v2874_5(void) = ConditionalBranch : r2874_4
#-----| True -> Block 8
# 2875| Block 8
# 2875| r2875_1(int) = Constant[0] :
# 2875| v2875_2(void) = Convert : r2875_1
# 2878| r2878_1(int) = Constant[0] :
# 2878| v2878_2(void) = Convert : r2878_1
# 2879| r2879_1(glval<int>) = VariableAddress[shadowed] :
# 2879| mu2879_2(int) = Uninitialized[shadowed] : &:r2879_1
# 2882| r2882_1(glval<int>) = VariableAddress[#throw2882:13] :
# 2882| r2882_2(int) = Constant[41] :
# 2882| mu2882_3(int) = Store[#throw2882:13] : &:r2882_1, r2882_2
# 2882| v2882_4(void) = ThrowValue : &:r2882_1, ~m?
#-----| C++ Exception -> Block 9
# 2883| Block 9
# 2883| v2883_1(void) = CatchByType[int] :
#-----| C++ Exception -> Block 2
#-----| Goto -> Block 10
# 2883| Block 10
# 2883| r2883_2(glval<int>) = VariableAddress[shadowed] :
# 2883| mu2883_3(int) = InitializeParameter[shadowed] : &:r2883_2
# 2884| r2884_1(int) = Constant[0] :
# 2884| v2884_2(void) = Convert : r2884_1
# 2886| v2886_1(void) = NoOp :
# 2867| v2867_13(void) = ReturnVoid :
#-----| Goto -> Block 1
ir23.cpp:
# 1| bool consteval_1()
# 1| Block 0

View File

@@ -1,3 +1,7 @@
## 1.7.57
No user-facing changes.
## 1.7.56
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.7.57
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.7.56
lastReleaseVersion: 1.7.57

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
version: 1.7.57-dev
version: 1.7.58-dev
groups:
- csharp
- solorigate

View File

@@ -1,3 +1,7 @@
## 1.7.57
No user-facing changes.
## 1.7.56
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.7.57
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.7.56
lastReleaseVersion: 1.7.57

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
version: 1.7.57-dev
version: 1.7.58-dev
groups:
- csharp
- solorigate

View File

@@ -1,3 +1,22 @@
## 5.4.5
### Minor Analysis Improvements
* When a code-scanning configuration specifies the `paths:` and/or `paths-ignore:` settings, these are now taken into account by the C# extractor's search for `.config`, `.props`, XML and project files.
* Updated the generated .NET “models as data” runtime models to cover .NET 10.
* C# 14: Support for *implicit* span conversions in the QL library.
* Basic extractor support for .NET 10 is now available. Extraction is supported for .NET 10 projects in both traced mode and `build mode: none`. However, code that uses language features new to C# 14 is not yet fully supported for extraction and analysis.
* Added autobuilder and `build-mode: none` support for `.slnx` solution files.
* In `build mode: none`, .NET 10 is now used by default unless a specific .NET version is specified elsewhere.
* Added implicit reads of `System.Collections.Generic.KeyValuePair.Value` at taint-tracking sinks and at inputs to additional taint steps. As a result, taint-tracking queries will now produce more results when a container is tainted.
### Bug Fixes
* Fixed two issues affecting build mode `none`:
* Corrected version sorting logic when detecting the newest .NET framework to use.
* Improved stability for .NET 10 compatibility.
* Fixed an issue where compiler-generated files were not being extracted. The extractor now runs after compilation completes to ensure all generated files are properly analyzed.
## 5.4.4
No user-facing changes.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added implicit reads of `System.Collections.Generic.KeyValuePair.Value` at taint-tracking sinks and at inputs to additional taint steps. As a result, taint-tracking queries will now produce more results when a container is tainted.

View File

@@ -1,4 +0,0 @@
---
category: fix
---
* Fixed an issue where compiler-generated files were not being extracted. The extractor now runs after compilation completes to ensure all generated files are properly analyzed.

View File

@@ -1,6 +0,0 @@
---
category: fix
---
* Fixed two issues affecting build mode `none`:
* Corrected version sorting logic when detecting the newest .NET framework to use.
* Improved stability for .NET 10 compatibility.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* In `build mode: none`, .NET 10 is now used by default unless a specific .NET version is specified elsewhere.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Basic extractor support for .NET 10 is now available. Extraction is supported for .NET 10 projects in both traced mode and `build mode: none`. However, code that uses language features new to C# 14 is not yet fully supported for extraction and analysis.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added autobuilder and `build-mode: none` support for `.slnx` solution files.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* C# 14: Support for *implicit* span conversions in the QL library.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Updated the generated .NET “models as data” runtime models to cover .NET 10.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* When a code-scanning configuration specifies the `paths:` and/or `paths-ignore:` settings, these are now taken into account by the C# extractor's search for `.config`, `.props`, XML and project files.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* C# 14: Support for null-conditional assignments (such as `c?.Prop = p`). Furthermore, the `MaybeNullExpr` class now takes null-conditional access (such as `?.`) into account when modeling potential null values.

View File

@@ -0,0 +1,18 @@
## 5.4.5
### Minor Analysis Improvements
* When a code-scanning configuration specifies the `paths:` and/or `paths-ignore:` settings, these are now taken into account by the C# extractor's search for `.config`, `.props`, XML and project files.
* Updated the generated .NET “models as data” runtime models to cover .NET 10.
* C# 14: Support for *implicit* span conversions in the QL library.
* Basic extractor support for .NET 10 is now available. Extraction is supported for .NET 10 projects in both traced mode and `build mode: none`. However, code that uses language features new to C# 14 is not yet fully supported for extraction and analysis.
* Added autobuilder and `build-mode: none` support for `.slnx` solution files.
* In `build mode: none`, .NET 10 is now used by default unless a specific .NET version is specified elsewhere.
* Added implicit reads of `System.Collections.Generic.KeyValuePair.Value` at taint-tracking sinks and at inputs to additional taint steps. As a result, taint-tracking queries will now produce more results when a container is tainted.
### Bug Fixes
* Fixed two issues affecting build mode `none`:
* Corrected version sorting logic when detecting the newest .NET framework to use.
* Improved stability for .NET 10 compatibility.
* Fixed an issue where compiler-generated files were not being extracted. The extractor now runs after compilation completes to ensure all generated files are properly analyzed.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 5.4.4
lastReleaseVersion: 5.4.5

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-all
version: 5.4.5-dev
version: 5.4.6-dev
groups: csharp
dbscheme: semmlecode.csharp.dbscheme
extractor: csharp

View File

@@ -429,7 +429,7 @@ module Expressions {
not this instanceof ObjectCreation and
not this instanceof ArrayCreation and
not this instanceof QualifiedWriteAccess and
not this instanceof AccessorWrite and
not this instanceof QualifiedAccessorWrite and
not this instanceof NoNodeExpr and
not this instanceof SwitchExpr and
not this instanceof SwitchCaseExpr and
@@ -446,21 +446,29 @@ module Expressions {
}
/**
* A qualified write access. In a qualified write access, the access itself is
* not evaluated, only the qualifier and the indexer arguments (if any).
* A qualified write access.
*
* The successor declaration in `QualifiedAccessorWrite` ensures that the access itself
* is evaluated after the qualifier and the indexer arguments (if any)
* and the right hand side of the assignment.
*
* When a qualified write access is used as an `out/ref` argument, the access itself is evaluated immediately.
*/
private class QualifiedWriteAccess extends ControlFlowTree instanceof WriteAccess, QualifiableExpr
{
QualifiedWriteAccess() {
this.hasQualifier()
or
// Member initializers like
// ```csharp
// new Dictionary<int, string>() { [0] = "Zero", [1] = "One", [2] = "Two" }
// ```
// need special treatment, because the accesses `[0]`, `[1]`, and `[2]`
// have no qualifier.
this = any(MemberInitializer mi).getLValue()
(
this.hasQualifier()
or
// Member initializers like
// ```csharp
// new Dictionary<int, string>() { [0] = "Zero", [1] = "One", [2] = "Two" }
// ```
// need special treatment, because the accesses `[0]`, `[1]`, and `[2]`
// have no qualifier.
this = any(MemberInitializer mi).getLValue()
) and
not exists(AssignableDefinitions::OutRefDefinition def | def.getTargetAccess() = this)
}
final override predicate propagatesAbnormal(AstNode child) { child = getExprChild(this, _) }
@@ -470,25 +478,25 @@ module Expressions {
final override predicate last(AstNode last, Completion c) {
// Skip the access in a qualified write access
last(getLastExprChild(this), last, c)
or
// Qualifier exits with a null completion
super.isConditional() and
last(super.getQualifier(), last, c) and
c.(NullnessCompletion).isNull()
}
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
exists(int i |
last(getExprChild(this, i), pred, c) and
c instanceof NormalCompletion and
(if i = 0 then not c.(NullnessCompletion).isNull() else any()) and
first(getExprChild(this, i + 1), succ)
)
}
}
private class StatOrDynAccessorCall_ =
@dynamic_member_access_expr or @dynamic_element_access_expr or @call_access_expr;
/** A normal or a (potential) dynamic call to an accessor. */
private class StatOrDynAccessorCall extends Expr, StatOrDynAccessorCall_ { }
/**
* An expression that writes via an accessor call, for example `x.Prop = 0`,
* An expression that writes via a qualifiable expression, for example `x.Prop = 0`,
* where `Prop` is a property.
*
* Accessor writes need special attention, because we need to model the fact
@@ -498,13 +506,21 @@ module Expressions {
* ```csharp
* x -> 0 -> set_Prop -> x.Prop = 0
* ```
*
* For consistency, control flow is implemented the same way for other qualified writes.
* For example, `x.Field = 0`, where `Field` is a field, we want a CFG that looks like
*
* ```csharp
* x -> 0 -> x.Field -> x.Field = 0
* ```
*/
class AccessorWrite extends PostOrderTree instanceof Expr {
private class QualifiedAccessorWrite extends PostOrderTree instanceof Expr {
AssignableDefinition def;
AccessorWrite() {
QualifiedAccessorWrite() {
def.getExpr() = this and
def.getTargetAccess().(WriteAccess) instanceof StatOrDynAccessorCall and
def.getTargetAccess().(WriteAccess) instanceof QualifiableExpr and
not def instanceof AssignableDefinitions::OutRefDefinition and
not this instanceof AssignOperationWithExpandedAssignment
}
@@ -512,10 +528,11 @@ module Expressions {
* Gets the `i`th accessor being called in this write. More than one call
* can happen in tuple assignments.
*/
StatOrDynAccessorCall getCall(int i) {
QualifiableExpr getAccess(int i) {
result =
rank[i + 1](AssignableDefinitions::TupleAssignmentDefinition tdef |
tdef.getExpr() = this and tdef.getTargetAccess() instanceof StatOrDynAccessorCall
tdef.getExpr() = this and
tdef.getTargetAccess() instanceof QualifiableExpr
|
tdef order by tdef.getEvaluationOrder()
).getTargetAccess()
@@ -528,7 +545,13 @@ module Expressions {
final override predicate propagatesAbnormal(AstNode child) {
child = getExprChild(this, _)
or
child = this.getCall(_)
child = this.getAccess(_)
}
final override predicate last(AstNode last, Completion c) {
PostOrderTree.super.last(last, c)
or
last(getExprChild(this, 0), last, c) and c.(NullnessCompletion).isNull()
}
final override predicate first(AstNode first) { first(getExprChild(this, 0), first) }
@@ -538,24 +561,25 @@ module Expressions {
exists(int i |
last(getExprChild(this, i), pred, c) and
c instanceof NormalCompletion and
(if i = 0 then not c.(NullnessCompletion).isNull() else any()) and
first(getExprChild(this, i + 1), succ)
)
or
// Flow from last element of last child to first accessor call
last(getLastExprChild(this), pred, c) and
succ = this.getCall(0) and
succ = this.getAccess(0) and
c instanceof NormalCompletion
or
// Flow from one call to the next
exists(int i | pred = this.getCall(i) |
succ = this.getCall(i + 1) and
exists(int i | pred = this.getAccess(i) |
succ = this.getAccess(i + 1) and
c.isValidFor(pred) and
c instanceof NormalCompletion
)
or
// Post-order: flow from last call to element itself
exists(int last | last = max(int i | exists(this.getCall(i))) |
pred = this.getCall(last) and
exists(int last | last = max(int i | exists(this.getAccess(i))) |
pred = this.getAccess(last) and
succ = this and
c.isValidFor(pred) and
c instanceof NormalCompletion
@@ -704,7 +728,9 @@ module Expressions {
private class ConditionallyQualifiedExpr extends PostOrderTree instanceof QualifiableExpr {
private Expr qualifier;
ConditionallyQualifiedExpr() { this.isConditional() and qualifier = getExprChild(this, 0) }
ConditionallyQualifiedExpr() {
this.isConditional() and qualifier = getExprChild(this, 0) and not this instanceof WriteAccess
}
final override predicate propagatesAbnormal(AstNode child) { child = qualifier }

View File

@@ -43,6 +43,13 @@ private Expr maybeNullExpr(Expr reason) {
)
or
result.(NullCoalescingExpr).getRightOperand() = maybeNullExpr(reason)
or
result =
any(QualifiableExpr qe |
qe.isConditional() and
reason = qe.getQualifier() and
not qe instanceof AssignableWrite
)
}
/** An expression that may be `null`. */

View File

@@ -1,3 +1,14 @@
## 1.6.0
### Query Metadata Changes
* Updated the `name`, `description`, and alert message of `cs/path-combine` to have more details about why it's a problem.
### Minor Analysis Improvements
* Added `NHibernate.ISession.CreateSQLQuery`, `NHibernate.IStatelessSession.CreateSQLQuery` and `NHibernate.Impl.AbstractSessionImpl.CreateSQLQuery` as SQL injection sinks.
* The `Missing cross-site request forgery token validation` query was extended to support ASP.NET Core.
## 1.5.4
No user-facing changes.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The `Missing cross-site request forgery token validation` query was extended to support ASP.NET Core.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added `NHibernate.ISession.CreateSQLQuery`, `NHibernate.IStatelessSession.CreateSQLQuery` and `NHibernate.Impl.AbstractSessionImpl.CreateSQLQuery` as SQL injection sinks.

View File

@@ -1,4 +0,0 @@
---
category: queryMetadata
---
* Updated the `name`, `description`, and alert message of `cs/path-combine` to have more details about why it's a problem.

View File

@@ -0,0 +1,10 @@
## 1.6.0
### Query Metadata Changes
* Updated the `name`, `description`, and alert message of `cs/path-combine` to have more details about why it's a problem.
### Minor Analysis Improvements
* Added `NHibernate.ISession.CreateSQLQuery`, `NHibernate.IStatelessSession.CreateSQLQuery` and `NHibernate.Impl.AbstractSessionImpl.CreateSQLQuery` as SQL injection sinks.
* The `Missing cross-site request forgery token validation` query was extended to support ASP.NET Core.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.5.4
lastReleaseVersion: 1.6.0

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-queries
version: 1.5.5-dev
version: 1.6.1-dev
groups:
- csharp
- queries

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