Compare commits

..

1 Commits

Author SHA1 Message Date
Esben Sparre Andreasen
63de4ba939 boost StoredXssATM (automatically with tb boost) 2022-01-21 14:44:10 +01:00
762 changed files with 14319 additions and 50563 deletions

View File

@@ -6,7 +6,6 @@
"*/ql/examples/qlpack.yml",
"cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml",
"csharp/ql/campaigns/Solorigate/lib/qlpack.yml",
"csharp/ql/campaigns/Solorigate/src/qlpack.yml",

View File

@@ -1,103 +0,0 @@
name: Models as Data - Diff
on:
workflow_dispatch:
inputs:
projects:
description: "The projects to generate models for"
required: true
default: '["netty/netty"]'
pull_request:
branches:
- main
paths:
- "java/ql/src/utils/model-generator/**/*.*"
- ".github/workflows/mad_modelDiff.yml"
permissions:
contents: read
jobs:
model-diff:
name: Model Difference
runs-on: ubuntu-latest
if: github.repository == 'github/codeql'
strategy:
matrix:
slug: ${{fromJson(github.event.inputs.projects || '["apache/commons-codec", "apache/commons-io", "apache/commons-beanutils", "apache/commons-logging", "apache/commons-fileupload", "apache/commons-lang", "apache/commons-validator", "apache/commons-csv", "apache/dubbo"]' )}}
steps:
- name: Clone github/codeql from PR
uses: actions/checkout@v2
if: github.event.pull_request
with:
path: codeql-pr
- name: Clone github/codeql from main
uses: actions/checkout@v2
with:
path: codeql-main
ref: main
- uses: ./codeql-main/.github/actions/fetch-codeql
- name: Download database
env:
SLUG: ${{ matrix.slug }}
run: |
set -x
mkdir lib-dbs
SHORTNAME=${SLUG//[^a-zA-Z0-9_]/}
projectId=`curl -s https://lgtm.com/api/v1.0/projects/g/${SLUG} | jq .id`
curl -L "https://lgtm.com/api/v1.0/snapshots/$projectId/java" -o "$SHORTNAME.zip"
unzip -q -d "${SHORTNAME}-db" "${SHORTNAME}.zip"
mkdir "lib-dbs/$SHORTNAME/"
mv "${SHORTNAME}-db/"$(ls -1 "${SHORTNAME}"-db)/* "lib-dbs/${SHORTNAME}/"
- name: Generate Models (PR and main)
run: |
set -x
mkdir tmp-models
MODELS=`pwd`/tmp-models
DATABASES=`pwd`/lib-dbs
analyzeDatabaseWithCheckout() {
QL_VARIANT=$1
DATABASE=$2
cd codeql-$QL_VARIANT
SHORTNAME=`basename $DATABASE`
python java/ql/src/utils/model-generator/GenerateFlowModel.py $DATABASE $MODELS/${SHORTNAME}.qll
mv $MODELS/${SHORTNAME}.qll $MODELS/${SHORTNAME}Generated_${QL_VARIANT}.qll
cd ..
}
for d in $DATABASES/*/ ; do
ls -1 "$d"
analyzeDatabaseWithCheckout "main" $d
if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]
then
analyzeDatabaseWithCheckout "pr" $d
fi
done
- name: Install diff2html
if: github.event.pull_request
run: |
npm install -g diff2html-cli
- name: Generate Model Diff
if: github.event.pull_request
run: |
set -x
MODELS=`pwd`/tmp-models
ls -1 tmp-models/
for m in $MODELS/*_main.qll ; do
t="${m/main/"pr"}"
basename=`basename $m`
name="diff_${basename/_main.qll/""}"
(diff -w -u $m $t | diff2html -i stdin -F $MODELS/$name.html) || true
done
- uses: actions/upload-artifact@v2
with:
name: models
path: tmp-models/*.qll
retention-days: 20
- uses: actions/upload-artifact@v2
with:
name: diffs
path: tmp-models/*.html
retention-days: 20

View File

@@ -17,7 +17,7 @@ jobs:
CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI
strategy:
matrix:
repo:
repo:
- github/codeql
- github/codeql-go
runs-on: ubuntu-latest
@@ -35,7 +35,7 @@ jobs:
~/.cargo/registry
~/.cargo/git
ql/target
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Build Extractor
run: cd ql; env "PATH=$PATH:`dirname ${CODEQL}`" ./create-extractor-pack.sh
env:

View File

@@ -29,24 +29,24 @@ jobs:
~/.cargo/registry
~/.cargo/git
ql/target
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Build extractor
run: |
cd ql;
codeqlpath=$(dirname ${{ steps.find-codeql.outputs.codeql-path }});
env "PATH=$PATH:$codeqlpath" ./create-extractor-pack.sh
- name: Run QL tests
run: |
run: |
"${CODEQL}" test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}/ql/extractor-pack" --consistency-queries ql/ql/consistency-queries ql/ql/test
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
- name: Check QL formatting
run: |
run: |
find ql/ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 "${CODEQL}" query format --check-only
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
- name: Check QL compilation
run: |
run: |
"${CODEQL}" query compile --check-only --threads=4 --warnings=error --search-path "${{ github.workspace }}/ql/extractor-pack" "ql/ql/src" "ql/ql/examples"
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}

View File

@@ -50,7 +50,7 @@ jobs:
~/.cargo/registry
~/.cargo/git
ruby/target
key: ${{ runner.os }}-ruby-rust-cargo-${{ hashFiles('ruby/**/Cargo.lock') }}
key: ${{ runner.os }}-rust-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Check formatting
run: cargo fmt --all -- --check
- name: Build

View File

@@ -24,45 +24,27 @@ defaults:
working-directory: ruby
jobs:
qlformat:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ./.github/actions/fetch-codeql
- name: Check QL formatting
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
qlcompile:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ./.github/actions/fetch-codeql
- name: Check QL compilation
run: |
codeql query compile --check-only --threads=0 --ram 5000 --warnings=error "ql/src" "ql/examples"
env:
GITHUB_TOKEN: ${{ github.token }}
qlupgrade:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ./.github/actions/fetch-codeql
- name: Check DB upgrade scripts
run: |
echo >empty.trap
codeql dataset import -S ql/lib/upgrades/initial/ruby.dbscheme testdb empty.trap
codeql dataset upgrade testdb --additional-packs ql/lib
diff -q testdb/ruby.dbscheme ql/lib/ruby.dbscheme
qltest:
runs-on: ubuntu-latest
strategy:
matrix:
slice: ["1/2", "2/2"]
steps:
- uses: actions/checkout@v2
- uses: ./.github/actions/fetch-codeql
- uses: ./ruby/actions/create-extractor-pack
- name: Run QL tests
run: |
codeql test run --threads=0 --ram 5000 --slice ${{ matrix.slice }} --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test
codeql test run --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Check QL formatting
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
- name: Check QL compilation
run: |
codeql query compile --check-only --threads=4 --warnings=error "ql/src" "ql/examples"
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Check DB upgrade scripts
run: |
echo >empty.trap
codeql dataset import -S ql/lib/upgrades/initial/ruby.dbscheme testdb empty.trap
codeql dataset upgrade testdb --additional-packs ql/lib
diff -q testdb/ruby.dbscheme ql/lib/ruby.dbscheme

View File

@@ -7,7 +7,6 @@
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll",
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll",
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll",
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll",
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll",
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll",
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll",

View File

@@ -1,6 +1,4 @@
name: codeql/cpp-examples
groups:
- cpp
- examples
version: 0.0.2
dependencies:
codeql/cpp-all: "*"

View File

@@ -1,5 +1,3 @@
## 0.0.7
## 0.0.6
## 0.0.5

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The `Class::hasImplicitCopyConstructor` and `Class::hasImplicitCopyAssignmentOperator` methods now handle template instantiations more accurately. This should improve results for the `cpp/rule-of-two` query.

View File

@@ -1 +0,0 @@
## 0.0.7

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.0.7
lastReleaseVersion: 0.0.6

View File

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

View File

@@ -206,7 +206,9 @@ class Class extends UserType {
* it is callable by a particular caller. For C++11, there's also a question
* of whether to include members that are defaulted or deleted.
*/
deprecated predicate hasCopyConstructor() { this.getAMemberFunction() instanceof CopyConstructor }
deprecated predicate hasCopyConstructor() {
exists(CopyConstructor cc | cc = this.getAMemberFunction())
}
/**
* Holds if this class has a copy assignment operator that is either
@@ -222,7 +224,7 @@ class Class extends UserType {
* or deleted.
*/
deprecated predicate hasCopyAssignmentOperator() {
this.getAMemberFunction() instanceof CopyAssignmentOperator
exists(CopyAssignmentOperator coa | coa = this.getAMemberFunction())
}
/**
@@ -285,17 +287,7 @@ class Class extends UserType {
predicate hasImplicitCopyConstructor() {
not this.implicitCopyConstructorDeleted() and
forall(CopyConstructor cc | cc = this.getAMemberFunction() |
cc.isCompilerGenerated() and not cc.isDeleted() and not cc.isDefaulted()
) and
(
not this instanceof ClassTemplateInstantiation
or
this.(ClassTemplateInstantiation).getTemplate().hasImplicitCopyConstructor()
) and
(
not this instanceof PartialClassTemplateSpecialization
or
this.(PartialClassTemplateSpecialization).getPrimaryTemplate().hasImplicitCopyConstructor()
cc.isCompilerGenerated() and not cc.isDeleted()
)
}
@@ -310,19 +302,7 @@ class Class extends UserType {
predicate hasImplicitCopyAssignmentOperator() {
not this.implicitCopyAssignmentOperatorDeleted() and
forall(CopyAssignmentOperator ca | ca = this.getAMemberFunction() |
ca.isCompilerGenerated() and not ca.isDeleted() and not ca.isDefaulted()
) and
(
not this instanceof ClassTemplateInstantiation
or
this.(ClassTemplateInstantiation).getTemplate().hasImplicitCopyAssignmentOperator()
) and
(
not this instanceof PartialClassTemplateSpecialization
or
this.(PartialClassTemplateSpecialization)
.getPrimaryTemplate()
.hasImplicitCopyAssignmentOperator()
ca.isCompilerGenerated() and not ca.isDeleted()
)
}
@@ -333,12 +313,6 @@ class Class extends UserType {
* http://en.cppreference.com/w/cpp/language/copy_constructor#Deleted_implicitly-declared_copy_constructor
*/
predicate implicitCopyConstructorDeleted() {
forex(CopyConstructor cc | cc = this.getAConstructor() |
cc.isDeleted()
or
not cc.isCompilerGenerated()
)
or
// - T has non-static data members that cannot be copied (have deleted,
// inaccessible, or ambiguous copy constructors);
exists(Type t | t = this.getAFieldSubobjectType().getUnspecifiedType() |
@@ -346,6 +320,34 @@ class Class extends UserType {
// constructors are considered equal.
this.cannotAccessCopyConstructorOnAny(t)
)
or
// - T has direct or virtual base class that cannot be copied (has deleted,
// inaccessible, or ambiguous copy constructors);
exists(Class c | c = this.getADirectOrVirtualBase() |
// Note: Overload resolution is not implemented -- all copy
// constructors are considered equal.
this.cannotAccessCopyConstructorOnThis(c)
)
or
// - T has direct or virtual base class with a deleted or inaccessible
// destructor;
exists(Class base | base = this.getADirectOrVirtualBase() |
this.cannotAccessDestructor(base, this)
)
or
// - T has a user-defined move constructor or move assignment operator;
exists(MoveConstructor mc | mc = this.getAMemberFunction() | not mc.isCompilerGenerated())
or
exists(MoveAssignmentOperator ma | ma = this.getAMemberFunction() |
not ma.isCompilerGenerated()
)
or
// - T is a union and has a variant member with non-trivial copy
// constructor (since C++11)
none() // Not implemented
or
// - T has a data member of rvalue reference type.
exists(Type t | t = this.getAFieldSubobjectType() | t instanceof RValueReferenceType)
}
/**
@@ -355,12 +357,34 @@ class Class extends UserType {
* http://en.cppreference.com/w/cpp/language/copy_assignment#Deleted_implicitly-declared_copy_assignment_operator
*/
predicate implicitCopyAssignmentOperatorDeleted() {
forex(CopyAssignmentOperator ca | ca = this.getAMemberFunction() |
ca.isDeleted()
or
not ca.isCompilerGenerated()
// - T has a user-declared move constructor;
exists(MoveConstructor mc | mc = this.getAMemberFunction() | not mc.isCompilerGenerated())
or
// - T has a user-declared move assignment operator.
exists(MoveAssignmentOperator ma | ma = this.getAMemberFunction() |
not ma.isCompilerGenerated()
)
or
// - T has a non-static data member of non-class type (or array thereof)
// that is const;
exists(Type t | t = this.getAFieldSubobjectType() |
// The rule for this case refers only to non-class types only, but our
// implementation extends it to cover class types too. Class types are
// supposed to be covered by the rule below on data members that
// cannot be copy-assigned. Copy-assigning a const class-typed member
// would call an overload of type
// `const C& operator=(const C&) const;`. Such an overload is unlikely
// to exist because it contradicts the intention of "const": it allows
// assigning to a const object. But since we have not implemented the
// ability to distinguish between overloads, we cannot distinguish that
// overload from the ordinary `C& operator=(const C&);`. Instead, we
// require class types to be non-const in this clause.
/* not t instanceof Class and */ t.isConst()
)
or
// - T has a non-static data member of a reference type;
exists(Type t | t = this.getAFieldSubobjectType() | t instanceof ReferenceType)
or
// - T has a non-static data member or a direct or virtual base class that
// cannot be copy-assigned (overload resolution for the copy assignment
// fails, or selects a deleted or inaccessible function);
@@ -369,6 +393,15 @@ class Class extends UserType {
// operators are considered equal.
this.cannotAccessCopyAssignmentOperatorOnAny(t)
)
or
exists(Class c | c = this.getADirectOrVirtualBase() |
// Note: Overload resolution is not implemented -- all copy assignment
// operators are considered equal.
this.cannotAccessCopyAssignmentOperatorOnThis(c)
)
// - T is a union-like class, and has a variant member whose corresponding
// assignment operator is non-trivial.
// Not implemented
}
/** Gets the destructor of this class, struct or union, if any. */
@@ -854,7 +887,7 @@ class NestedClass extends Class {
* pure virtual function.
*/
class AbstractClass extends Class {
AbstractClass() { this.getAMemberFunction() instanceof PureVirtualFunction }
AbstractClass() { exists(PureVirtualFunction f | this.getAMemberFunction() = f) }
override string getAPrimaryQlClass() { result = "AbstractClass" }
}

View File

@@ -286,13 +286,13 @@ class AttributeArgument extends Element, @attribute_arg {
override Location getLocation() { attribute_args(underlyingElement(this), _, _, _, result) }
override string toString() {
if underlyingElement(this) instanceof @attribute_arg_empty
if exists(@attribute_arg_empty self | self = underlyingElement(this))
then result = "empty argument"
else
exists(string prefix, string tail |
(if exists(this.getName()) then prefix = this.getName() + "=" else prefix = "") and
(
if underlyingElement(this) instanceof @attribute_arg_type
if exists(@attribute_arg_type self | self = underlyingElement(this))
then tail = this.getValueType().getName()
else tail = this.getValueText()
) and

View File

@@ -233,7 +233,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
XMLAttribute getAttribute(string name) { result.getElement() = this and result.getName() = name }
/** Holds if this XML element has an attribute with the specified `name`. */
predicate hasAttribute(string name) { exists(this.getAttribute(name)) }
predicate hasAttribute(string name) { exists(XMLAttribute a | a = this.getAttribute(name)) }
/** Gets the value of the attribute with the specified `name`, if any. */
string getAttributeValue(string name) { result = this.getAttribute(name).getValue() }

View File

@@ -1122,7 +1122,7 @@ class FormatLiteral extends Literal {
* conversion specifier of this format string; has no result if this cannot
* be determined.
*/
int getMaxConvertedLength(int n) { result = max(this.getMaxConvertedLength(n, _)) }
int getMaxConvertedLength(int n) { result = max(getMaxConvertedLength(n, _)) }
/**
* Gets the maximum length of the string that can be produced by the nth
@@ -1353,7 +1353,7 @@ class FormatLiteral extends Literal {
* determining whether a buffer overflow is caused by long float to string
* conversions.
*/
int getMaxConvertedLengthLimited(int n) { result = max(this.getMaxConvertedLengthLimited(n, _)) }
int getMaxConvertedLengthLimited(int n) { result = max(getMaxConvertedLengthLimited(n, _)) }
/**
* Gets the maximum length of the string that can be produced by the nth

View File

@@ -29,7 +29,7 @@ class GuardCondition extends Expr {
exists(IRGuardCondition ir | this = ir.getUnconvertedResultExpression())
or
// no binary operators in the IR
this.(BinaryLogicalOperation).getAnOperand() instanceof GuardCondition
exists(GuardCondition gc | this.(BinaryLogicalOperation).getAnOperand() = gc)
or
// the IR short-circuits if(!x)
// don't produce a guard condition for `y = !x` and other non-short-circuited cases
@@ -98,7 +98,7 @@ class GuardCondition extends Expr {
*/
private class GuardConditionFromBinaryLogicalOperator extends GuardCondition {
GuardConditionFromBinaryLogicalOperator() {
this.(BinaryLogicalOperation).getAnOperand() instanceof GuardCondition
exists(GuardCondition gc | this.(BinaryLogicalOperation).getAnOperand() = gc)
}
override predicate controls(BasicBlock controlled, boolean testIsTrue) {

View File

@@ -1290,7 +1290,7 @@ class DataFlowCallOption extends TDataFlowCallOption {
}
}
/** A `Content` tagged with the type of a containing object. */
/** Content tagged with the type of a containing object. */
class TypedContent extends MkTypedContent {
private Content c;
private DataFlowType t;

View File

@@ -48,7 +48,7 @@ private class Argument extends Expr {
*/
class ArgumentNode extends Node {
ArgumentNode() {
this.asExpr() instanceof Argument or
exists(Argument arg | this.asExpr() = arg) or
this = getInstanceArgument(_)
}

View File

@@ -84,8 +84,8 @@ class VariableAccess extends Access, @varaccess {
exists(Assignment a | a.getLValue() = this) or
exists(CrementOperation c | c.getOperand() = this) or
exists(AddressOfExpr addof | addof.getOperand() = this) or
this.getConversion() instanceof ReferenceToExpr or
this.getConversion() instanceof ArrayToPointerConversion
exists(ReferenceToExpr rte | this.getConversion() = rte) or
exists(ArrayToPointerConversion atpc | this.getConversion() = atpc)
}
/**
@@ -104,8 +104,8 @@ class VariableAccess extends Access, @varaccess {
predicate isRValue() {
not exists(AssignExpr ae | ae.getLValue() = this) and
not exists(AddressOfExpr addof | addof.getOperand() = this) and
not this.getConversion() instanceof ReferenceToExpr and
not this.getConversion() instanceof ArrayToPointerConversion
not exists(ReferenceToExpr rte | this.getConversion() = rte) and
not exists(ArrayToPointerConversion atpc | this.getConversion() = atpc)
}
/**
@@ -218,7 +218,9 @@ class PointerFieldAccess extends FieldAccess {
class DotFieldAccess extends FieldAccess {
override string getAPrimaryQlClass() { result = "DotFieldAccess" }
DotFieldAccess() { this.getQualifier().getFullyConverted().getUnspecifiedType() instanceof Class }
DotFieldAccess() {
exists(Class c | c = this.getQualifier().getFullyConverted().getUnspecifiedType())
}
}
/**

View File

@@ -35,7 +35,7 @@ class Call extends Expr, NameQualifiableElement, TCall {
*
* For example, `ptr->f()` has a qualifier, whereas plain `f()` does not.
*/
predicate hasQualifier() { exists(this.getChild(-1)) }
predicate hasQualifier() { exists(Expr e | this.getChild(-1) = e) }
/**
* Gets the expression to the left of the function name or function pointer variable name.

View File

@@ -724,7 +724,7 @@ class SizeofOperator extends Expr, @runtime_sizeof {
* ```
*/
class SizeofExprOperator extends SizeofOperator {
SizeofExprOperator() { exists(this.getChild(0)) }
SizeofExprOperator() { exists(Expr e | this.getChild(0) = e) }
override string getAPrimaryQlClass() { result = "SizeofExprOperator" }
@@ -787,7 +787,7 @@ class AlignofOperator extends Expr, @runtime_alignof {
* ```
*/
class AlignofExprOperator extends AlignofOperator {
AlignofExprOperator() { exists(this.getChild(0)) }
AlignofExprOperator() { exists(Expr e | this.getChild(0) = e) }
/**
* Gets the contained expression.

View File

@@ -1,8 +1,3 @@
/**
* An IR taint tracking library that uses an IR DataFlow configuration to track
* taint from user inputs as defined by `semmle.code.cpp.security.Security`.
*/
import cpp
import semmle.code.cpp.security.Security
private import semmle.code.cpp.ir.dataflow.DataFlow

View File

@@ -1290,7 +1290,7 @@ class DataFlowCallOption extends TDataFlowCallOption {
}
}
/** A `Content` tagged with the type of a containing object. */
/** Content tagged with the type of a containing object. */
class TypedContent extends MkTypedContent {
private Content c;
private DataFlowType t;

View File

@@ -111,45 +111,6 @@ private predicate hasDefaultSideEffect(Call call, ParameterIndex i, boolean buff
)
}
/**
* A `Call` or `NewOrNewArrayExpr`.
*
* Both kinds of expression invoke a function as part of their evaluation. This class provides a
* way to treat both kinds of function similarly, and to get the invoked `Function`.
*/
class CallOrAllocationExpr extends Expr {
CallOrAllocationExpr() {
this instanceof Call
or
this instanceof NewOrNewArrayExpr
}
/** Gets the `Function` invoked by this expression, if known. */
final Function getTarget() {
result = this.(Call).getTarget()
or
result = this.(NewOrNewArrayExpr).getAllocator()
}
}
/**
* Returns the side effect opcode, if any, that represents any side effects not specifically modeled
* by an argument side effect.
*/
Opcode getCallSideEffectOpcode(CallOrAllocationExpr expr) {
not exists(expr.getTarget().(SideEffectFunction)) and result instanceof Opcode::CallSideEffect
or
exists(SideEffectFunction sideEffectFunction |
sideEffectFunction = expr.getTarget() and
if not sideEffectFunction.hasOnlySpecificWriteSideEffects()
then result instanceof Opcode::CallSideEffect
else (
not sideEffectFunction.hasOnlySpecificReadSideEffects() and
result instanceof Opcode::CallReadSideEffect
)
)
}
/**
* Returns a side effect opcode for parameter index `i` of the specified call.
*

View File

@@ -49,6 +49,19 @@ abstract class TranslatedCall extends TranslatedExpr {
tag = CallTag() and
opcode instanceof Opcode::Call and
resultType = getTypeForPRValue(getCallResultType())
or
hasSideEffect() and
tag = CallSideEffectTag() and
(
if hasWriteSideEffect()
then (
opcode instanceof Opcode::CallSideEffect and
resultType = getUnknownType()
) else (
opcode instanceof Opcode::CallReadSideEffect and
resultType = getVoidType()
)
)
}
override Instruction getChildSuccessor(TranslatedElement child) {
@@ -71,8 +84,25 @@ abstract class TranslatedCall extends TranslatedExpr {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
kind instanceof GotoEdge and
tag = CallTag() and
result = getSideEffects().getFirstInstruction()
(
(
tag = CallTag() and
if hasSideEffect()
then result = getInstruction(CallSideEffectTag())
else
if hasPreciseSideEffect()
then result = getSideEffects().getFirstInstruction()
else result = getParent().getChildSuccessor(this)
)
or
(
hasSideEffect() and
tag = CallSideEffectTag() and
if hasPreciseSideEffect()
then result = getSideEffects().getFirstInstruction()
else result = getParent().getChildSuccessor(this)
)
)
}
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
@@ -91,6 +121,15 @@ abstract class TranslatedCall extends TranslatedExpr {
)
}
final override CppType getInstructionMemoryOperandType(
InstructionTag tag, TypedOperandTag operandTag
) {
tag = CallSideEffectTag() and
hasSideEffect() and
operandTag instanceof SideEffectOperandTag and
result = getUnknownType()
}
final override Instruction getResult() { result = getInstruction(CallTag()) }
/**
@@ -161,31 +200,40 @@ abstract class TranslatedCall extends TranslatedExpr {
*/
abstract predicate hasArguments();
predicate hasReadSideEffect() { any() }
predicate hasWriteSideEffect() { any() }
private predicate hasSideEffect() { hasReadSideEffect() or hasWriteSideEffect() }
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
hasSideEffect() and
tag = CallSideEffectTag() and
result = getResult()
}
predicate hasPreciseSideEffect() { exists(getSideEffects()) }
final TranslatedSideEffects getSideEffects() { result.getExpr() = expr }
}
/**
* The IR translation of the side effects of the parent `TranslatedElement`.
*
* This object does not itself generate the side effect instructions. Instead, its children provide
* the actual side effects, with this object acting as a placeholder so the parent only needs to
* insert this one element at the point where all the side effects are supposed to occur.
*/
abstract class TranslatedSideEffects extends TranslatedElement {
/** Gets the expression whose side effects are being modeled. */
abstract Expr getExpr();
final override Locatable getAST() { result = getExpr() }
final override Function getFunction() { result = getExpr().getEnclosingFunction() }
final override TranslatedElement getChild(int i) {
override TranslatedElement getChild(int i) {
result =
rank[i + 1](TranslatedSideEffect tse, int group, int indexInGroup |
tse.getPrimaryExpr() = getExpr() and
tse.sortOrder(group, indexInGroup)
rank[i + 1](TranslatedSideEffect tse, int isWrite, int index |
(
tse.getCall() = getExpr() and
tse.getArgumentIndex() = index and
if tse.isWrite() then isWrite = 1 else isWrite = 0
)
|
tse order by group, indexInGroup
tse order by isWrite, index
)
}
@@ -198,21 +246,12 @@ abstract class TranslatedSideEffects extends TranslatedElement {
)
}
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) {
none()
/**
* Gets the `TranslatedFunction` containing this expression.
*/
final TranslatedFunction getEnclosingFunction() {
result = getTranslatedFunction(getExpr().getEnclosingFunction())
}
final override Instruction getFirstInstruction() {
result = getChild(0).getFirstInstruction()
or
// Some functions, like `std::move()`, have no side effects whatsoever.
not exists(getChild(0)) and result = getParent().getChildSuccessor(this)
}
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
/** Gets the primary instruction to be associated with each side effect instruction. */
abstract Instruction getPrimaryInstruction();
}
/**
@@ -286,6 +325,14 @@ class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
tag = CallTargetTag() and result = expr.getTarget()
}
override predicate hasReadSideEffect() {
not expr.getTarget().(SideEffectFunction).hasOnlySpecificReadSideEffects()
}
override predicate hasWriteSideEffect() {
not expr.getTarget().(SideEffectFunction).hasOnlySpecificWriteSideEffects()
}
override Instruction getQualifierResult() {
hasQualifier() and
result = getQualifier().getResult()
@@ -316,116 +363,209 @@ class TranslatedStructorCall extends TranslatedFunctionCall {
override predicate hasQualifier() { any() }
}
/**
* The IR translation of the side effects of a function call, including the implicit allocator
* call in a `new` or `new[]` expression.
*/
class TranslatedAllocationSideEffects extends TranslatedSideEffects,
TTranslatedAllocationSideEffects {
AllocationExpr expr;
TranslatedAllocationSideEffects() { this = TTranslatedAllocationSideEffects(expr) }
final override AllocationExpr getExpr() { result = expr }
override string toString() { result = "(allocation side effects for " + expr.toString() + ")" }
override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) {
opcode instanceof Opcode::InitializeDynamicAllocation and
tag = OnlyInstructionTag() and
type = getUnknownType()
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
kind = EdgeKind::gotoEdge() and
if exists(getChild(0))
then result = getChild(0).getFirstInstruction()
else result = getParent().getChildSuccessor(this)
}
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
tag = OnlyInstructionTag() and
operandTag = addressOperand() and
result = getPrimaryInstructionForSideEffect(OnlyInstructionTag())
}
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
tag = OnlyInstructionTag() and
if expr instanceof NewOrNewArrayExpr
then result = getTranslatedAllocatorCall(expr).getInstruction(CallTag())
else result = getTranslatedCallInstruction(expr)
}
}
class TranslatedCallSideEffects extends TranslatedSideEffects, TTranslatedCallSideEffects {
Expr expr;
Call expr;
TranslatedCallSideEffects() { this = TTranslatedCallSideEffects(expr) }
final override string toString() { result = "(side effects for " + expr.toString() + ")" }
override string toString() { result = "(side effects for " + expr.toString() + ")" }
final override Expr getExpr() { result = expr }
override Call getExpr() { result = expr }
final override Instruction getPrimaryInstruction() {
expr instanceof Call and result = getTranslatedCallInstruction(expr)
or
expr instanceof NewOrNewArrayExpr and
result = getTranslatedAllocatorCall(expr).getInstruction(CallTag())
}
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) { none() }
/** Returns the sort group index for argument read side effects. */
private int argumentReadGroup() { result = 1 }
override Instruction getFirstInstruction() { result = getChild(0).getFirstInstruction() }
/** Returns the sort group index for conservative call side effects. */
private int callSideEffectGroup() {
result = 0 // Make this group first for now to preserve the existing ordering
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
/** Returns the sort group index for argument write side effects. */
private int argumentWriteGroup() { result = 2 }
/** Returns the sort group index for dynamic allocation side effects. */
private int initializeAllocationGroup() { result = 3 }
/**
* The IR translation of a single side effect of a call.
*/
abstract class TranslatedSideEffect extends TranslatedElement {
final override TranslatedElement getChild(int n) { none() }
final override Instruction getChildSuccessor(TranslatedElement child) { none() }
final override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) {
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
tag = OnlyInstructionTag() and
sideEffectInstruction(opcode, type)
result = getTranslatedCallInstruction(expr)
}
}
class TranslatedStructorCallSideEffects extends TranslatedCallSideEffects {
TranslatedStructorCallSideEffects() {
getParent().(TranslatedStructorCall).hasQualifier() and
getASideEffectOpcode(expr, -1) instanceof WriteSideEffectOpcode
}
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType t) {
tag instanceof OnlyInstructionTag and
t = getTypeForPRValue(expr.getTarget().getDeclaringType()) and
opcode = getASideEffectOpcode(expr, -1).(WriteSideEffectOpcode)
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
(
if exists(getChild(0))
then result = getChild(0).getFirstInstruction()
else result = getParent().getChildSuccessor(this)
) and
tag = OnlyInstructionTag() and
kind instanceof GotoEdge
}
override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
tag instanceof OnlyInstructionTag and
operandTag instanceof AddressOperandTag and
result = getParent().(TranslatedStructorCall).getQualifierResult()
}
final override int getInstructionIndex(InstructionTag tag) {
tag = OnlyInstructionTag() and
result = -1
}
}
class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEffect {
Call call;
Expr arg;
int index;
SideEffectOpcode sideEffectOpcode;
TranslatedSideEffect() {
this = TTranslatedArgumentSideEffect(call, arg, index, sideEffectOpcode)
}
override Locatable getAST() { result = arg }
Expr getExpr() { result = arg }
Call getCall() { result = call }
int getArgumentIndex() { result = index }
predicate isWrite() { sideEffectOpcode instanceof WriteSideEffectOpcode }
override string toString() {
isWrite() and
result = "(write side effect for " + arg.toString() + ")"
or
not isWrite() and
result = "(read side effect for " + arg.toString() + ")"
}
override TranslatedElement getChild(int n) { none() }
override Instruction getChildSuccessor(TranslatedElement child) { none() }
override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) {
tag = OnlyInstructionTag() and
opcode = sideEffectOpcode and
(
isWrite() and
(
opcode instanceof BufferAccessOpcode and
type = getUnknownType()
or
not opcode instanceof BufferAccessOpcode and
exists(Type baseType | baseType = arg.getUnspecifiedType().(DerivedType).getBaseType() |
if baseType instanceof VoidType
then type = getUnknownType()
else type = getTypeForPRValueOrUnknown(baseType)
)
or
index = -1 and
not arg.getUnspecifiedType() instanceof DerivedType and
type = getTypeForPRValueOrUnknown(arg.getUnspecifiedType())
)
or
not isWrite() and
type = getVoidType()
)
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
result = getParent().getChildSuccessor(this) and
tag = OnlyInstructionTag() and
kind instanceof GotoEdge
}
final override Function getFunction() { result = getParent().getFunction() }
final override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
tag = OnlyInstructionTag() and
result = getParent().(TranslatedSideEffects).getPrimaryInstruction()
}
/**
* Gets the expression that caused this side effect.
*
* All side effects with the same `getPrimaryExpr()` will appear in the same contiguous sequence
* in the IR.
*/
abstract Expr getPrimaryExpr();
/**
* Gets the order in which this side effect should be sorted with respect to other side effects
* for the same expression.
*
* Side effects are sorted first by `group`, and then by `indexInGroup`.
*/
abstract predicate sortOrder(int group, int indexInGroup);
/**
* Gets the opcode and result type for the side effect instruction.
*/
abstract predicate sideEffectInstruction(Opcode opcode, CppType type);
}
/**
* The IR translation of a single argument side effect for a call.
*/
abstract class TranslatedArgumentSideEffect extends TranslatedSideEffect {
Call call;
int index;
SideEffectOpcode sideEffectOpcode;
// All subclass charpreds must bind the `index` field.
bindingset[index]
TranslatedArgumentSideEffect() { any() }
override string toString() {
isWrite() and
result = "(write side effect for " + getArgString() + ")"
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
tag instanceof OnlyInstructionTag and
operandTag instanceof AddressOperandTag and
result = getTranslatedExpr(arg).getResult()
or
not isWrite() and
result = "(read side effect for " + getArgString() + ")"
tag instanceof OnlyInstructionTag and
operandTag instanceof BufferSizeOperandTag and
result =
getTranslatedExpr(call.getArgument(call.getTarget()
.(SideEffectFunction)
.getParameterSizeIndex(index)).getFullyConverted()).getResult()
}
override Call getPrimaryExpr() { result = call }
override CppType getInstructionMemoryOperandType(InstructionTag tag, TypedOperandTag operandTag) {
not isWrite() and
if sideEffectOpcode instanceof BufferAccessOpcode
then
result = getUnknownType() and
tag instanceof OnlyInstructionTag and
operandTag instanceof SideEffectOperandTag
else
exists(Type operandType |
tag instanceof OnlyInstructionTag and
operandType = arg.getType().getUnspecifiedType().(DerivedType).getBaseType() and
operandTag instanceof SideEffectOperandTag
or
tag instanceof OnlyInstructionTag and
operandType = arg.getType().getUnspecifiedType() and
not operandType instanceof DerivedType and
operandTag instanceof SideEffectOperandTag
|
// If the type we select is an incomplete type (e.g. a forward-declared `struct`), there will
// not be a `CppType` that represents that type. In that case, fall back to `UnknownCppType`.
result = getTypeForPRValueOrUnknown(operandType)
)
}
override predicate sortOrder(int group, int indexInGroup) {
indexInGroup = index and
if isWrite() then group = argumentWriteGroup() else group = argumentReadGroup()
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
tag = OnlyInstructionTag() and
result = getTranslatedCallInstruction(call)
}
final override int getInstructionIndex(InstructionTag tag) {
@@ -437,199 +577,11 @@ abstract class TranslatedArgumentSideEffect extends TranslatedSideEffect {
* Gets the `TranslatedFunction` containing this expression.
*/
final TranslatedFunction getEnclosingFunction() {
result = getTranslatedFunction(call.getEnclosingFunction())
result = getTranslatedFunction(arg.getEnclosingFunction())
}
final override predicate sideEffectInstruction(Opcode opcode, CppType type) {
opcode = sideEffectOpcode and
(
isWrite() and
(
opcode instanceof BufferAccessOpcode and
type = getUnknownType()
or
not opcode instanceof BufferAccessOpcode and
exists(Type indirectionType | indirectionType = getIndirectionType() |
if indirectionType instanceof VoidType
then type = getUnknownType()
else type = getTypeForPRValueOrUnknown(indirectionType)
)
)
or
not isWrite() and
type = getVoidType()
)
}
final override CppType getInstructionMemoryOperandType(
InstructionTag tag, TypedOperandTag operandTag
) {
not isWrite() and
if sideEffectOpcode instanceof BufferAccessOpcode
then
result = getUnknownType() and
tag instanceof OnlyInstructionTag and
operandTag instanceof SideEffectOperandTag
else
exists(Type operandType |
tag instanceof OnlyInstructionTag and
operandType = getIndirectionType() and
operandTag instanceof SideEffectOperandTag
|
// If the type we select is an incomplete type (e.g. a forward-declared `struct`), there will
// not be a `CppType` that represents that type. In that case, fall back to `UnknownCppType`.
result = getTypeForPRValueOrUnknown(operandType)
)
}
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
tag instanceof OnlyInstructionTag and
operandTag instanceof AddressOperandTag and
result = getArgInstruction()
or
tag instanceof OnlyInstructionTag and
operandTag instanceof BufferSizeOperandTag and
result =
getTranslatedExpr(call.getArgument(call.getTarget()
.(SideEffectFunction)
.getParameterSizeIndex(index)).getFullyConverted()).getResult()
}
/** Holds if this side effect is a write side effect, rather than a read side effect. */
final predicate isWrite() { sideEffectOpcode instanceof WriteSideEffectOpcode }
/** Gets a text representation of the argument. */
abstract string getArgString();
/** Gets the `Instruction` whose result is the value of the argument. */
abstract Instruction getArgInstruction();
/** Gets the type pointed to by the argument. */
abstract Type getIndirectionType();
}
/**
* The IR translation of an argument side effect where the argument has an `Expr` object in the AST.
*
* This generally applies to all positional arguments, as well as qualifier (`this`) arguments for
* calls other than constructor calls.
*/
class TranslatedArgumentExprSideEffect extends TranslatedArgumentSideEffect,
TTranslatedArgumentExprSideEffect {
Expr arg;
TranslatedArgumentExprSideEffect() {
this = TTranslatedArgumentExprSideEffect(call, arg, index, sideEffectOpcode)
}
final override Locatable getAST() { result = arg }
final override Type getIndirectionType() {
result = arg.getUnspecifiedType().(DerivedType).getBaseType()
or
// Sometimes the qualifier type gets the type of the class itself, rather than a pointer to the
// class.
index = -1 and
not arg.getUnspecifiedType() instanceof DerivedType and
result = arg.getUnspecifiedType()
}
final override string getArgString() { result = arg.toString() }
final override Instruction getArgInstruction() { result = getTranslatedExpr(arg).getResult() }
}
/**
* The IR translation of an argument side effect for `*this` on a call, where there is no `Expr`
* object that represents the `this` argument.
*
* The applies only to constructor calls, as the AST has explioit qualifier `Expr`s for all other
* calls to non-static member functions.
*/
class TranslatedStructorQualifierSideEffect extends TranslatedArgumentSideEffect,
TTranslatedStructorQualifierSideEffect {
TranslatedStructorQualifierSideEffect() {
this = TTranslatedStructorQualifierSideEffect(call, sideEffectOpcode) and
index = -1
}
final override Locatable getAST() { result = call }
final override Type getIndirectionType() { result = call.getTarget().getDeclaringType() }
final override string getArgString() { result = "this" }
final override Instruction getArgInstruction() {
exists(TranslatedStructorCall structorCall |
structorCall.getExpr() = call and
result = structorCall.getQualifierResult()
)
}
}
/** The IR translation of the non-argument-specific side effect of a call. */
class TranslatedCallSideEffect extends TranslatedSideEffect, TTranslatedCallSideEffect {
Expr expr;
SideEffectOpcode sideEffectOpcode;
TranslatedCallSideEffect() { this = TTranslatedCallSideEffect(expr, sideEffectOpcode) }
override Locatable getAST() { result = expr }
override Expr getPrimaryExpr() { result = expr }
override predicate sortOrder(int group, int indexInGroup) {
group = callSideEffectGroup() and indexInGroup = 0
}
override string toString() { result = "(call side effect for '" + expr.toString() + "')" }
override predicate sideEffectInstruction(Opcode opcode, CppType type) {
opcode = sideEffectOpcode and
(
opcode instanceof Opcode::CallSideEffect and
type = getUnknownType()
or
opcode instanceof Opcode::CallReadSideEffect and
type = getVoidType()
)
}
override CppType getInstructionMemoryOperandType(InstructionTag tag, TypedOperandTag operandTag) {
tag instanceof OnlyInstructionTag and
operandTag instanceof SideEffectOperandTag and
result = getUnknownType()
}
}
/**
* The IR translation of the allocation side effect of a call to a memory allocation function.
*
* This side effect provides a definition for the newly-allocated memory.
*/
class TranslatedAllocationSideEffect extends TranslatedSideEffect, TTranslatedAllocationSideEffect {
AllocationExpr expr;
TranslatedAllocationSideEffect() { this = TTranslatedAllocationSideEffect(expr) }
override Locatable getAST() { result = expr }
override Expr getPrimaryExpr() { result = expr }
override predicate sortOrder(int group, int indexInGroup) {
group = initializeAllocationGroup() and indexInGroup = 0
}
override string toString() { result = "(allocation side effect for '" + expr.toString() + "')" }
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
tag = OnlyInstructionTag() and
operandTag = addressOperand() and
result = getPrimaryInstructionForSideEffect(OnlyInstructionTag())
}
override predicate sideEffectInstruction(Opcode opcode, CppType type) {
opcode instanceof Opcode::InitializeDynamicAllocation and
type = getUnknownType()
}
/**
* Gets the `Function` containing this expression.
*/
override Function getFunction() { result = arg.getEnclosingFunction() }
}

View File

@@ -135,20 +135,6 @@ private predicate ignoreExpr(Expr expr) {
ignoreExprAndDescendants(expr)
}
/**
* Holds if the side effects of `expr` should be ignoredf for the purposes of IR generation.
*
* In cases involving `constexpr`, a call can wind up as a constant expression. `ignoreExpr()` will
* not hold for such a call, since we do need to translate the call (as a constant), but we need to
* ignore all of the side effects of that call, since we will not actually be generating a `Call`
* instruction.
*/
private predicate ignoreSideEffects(Expr expr) {
ignoreExpr(expr)
or
isIRConstant(expr)
}
/**
* Holds if `func` contains an AST that cannot be translated into IR. This is mostly used to work
* around extractor bugs. Once the relevant extractor bugs are fixed, this predicate can be removed.
@@ -635,34 +621,32 @@ newtype TTranslatedElement =
// The declaration/initialization part of a `ConditionDeclExpr`
TTranslatedConditionDecl(ConditionDeclExpr expr) { not ignoreExpr(expr) } or
// The side effects of a `Call`
TTranslatedCallSideEffects(CallOrAllocationExpr expr) { not ignoreSideEffects(expr) } or
// The non-argument-specific side effect of a `Call`
TTranslatedCallSideEffect(Expr expr, SideEffectOpcode opcode) {
not ignoreSideEffects(expr) and
opcode = getCallSideEffectOpcode(expr)
TTranslatedCallSideEffects(Call expr) {
// Exclude allocations such as `malloc` (which happen to also be function calls).
// Both `TranslatedCallSideEffects` and `TranslatedAllocationSideEffects` generate
// the same side effects for its children as they both extend the `TranslatedSideEffects`
// class.
// Note: We can separate allocation side effects and call side effects into two
// translated elements as no call can be both a `ConstructorCall` and an `AllocationExpr`.
not expr instanceof AllocationExpr and
(
exists(TTranslatedArgumentSideEffect(expr, _, _, _)) or
expr instanceof ConstructorCall
)
} or
// The side effects of an allocation, i.e. `new`, `new[]` or `malloc`
TTranslatedAllocationSideEffects(AllocationExpr expr) { not ignoreExpr(expr) } or
// A precise side effect of an argument to a `Call`
TTranslatedArgumentExprSideEffect(Call call, Expr expr, int n, SideEffectOpcode opcode) {
TTranslatedArgumentSideEffect(Call call, Expr expr, int n, SideEffectOpcode opcode) {
not ignoreExpr(expr) and
not ignoreSideEffects(call) and
not ignoreExpr(call) and
(
n >= 0 and expr = call.getArgument(n).getFullyConverted()
or
n = -1 and expr = call.getQualifier().getFullyConverted()
) and
opcode = getASideEffectOpcode(call, n)
} or
// Constructor calls lack a qualifier (`this`) expression, so we need to handle the side effects
// on `*this` without an `Expr`.
TTranslatedStructorQualifierSideEffect(Call call, SideEffectOpcode opcode) {
not ignoreSideEffects(call) and
// Don't bother with destructor calls for now, since we won't see very many of them in the IR
// until we start injecting implicit destructor calls.
call instanceof ConstructorCall and
opcode = getASideEffectOpcode(call, -1)
} or
// The side effect that initializes newly-allocated memory.
TTranslatedAllocationSideEffect(AllocationExpr expr) { not ignoreSideEffects(expr) }
}
/**
* Gets the index of the first explicitly initialized element in `initList`

View File

@@ -308,45 +308,45 @@ class MetricClass extends Class {
}
private string getAUsedHalsteadN1Operator() {
this.getAnEnclosedExpression() instanceof CommaExpr and result = "comma"
exists(CommaExpr e | e = this.getAnEnclosedExpression()) and result = "comma"
or
this.getAnEnclosedExpression() instanceof ReferenceToExpr and result = "refTo"
exists(ReferenceToExpr e | e = this.getAnEnclosedExpression()) and result = "refTo"
or
this.getAnEnclosedExpression() instanceof PointerDereferenceExpr and result = "dereference"
exists(PointerDereferenceExpr e | e = this.getAnEnclosedExpression()) and result = "dereference"
or
this.getAnEnclosedExpression() instanceof CStyleCast and result = "cCast"
exists(CStyleCast e | e = this.getAnEnclosedExpression()) and result = "cCast"
or
this.getAnEnclosedExpression() instanceof StaticCast and result = "staticCast"
exists(StaticCast e | e = this.getAnEnclosedExpression()) and result = "staticCast"
or
this.getAnEnclosedExpression() instanceof ConstCast and result = "constCast"
exists(ConstCast e | e = this.getAnEnclosedExpression()) and result = "constCast"
or
this.getAnEnclosedExpression() instanceof ReinterpretCast and result = "reinterpretCast"
exists(ReinterpretCast e | e = this.getAnEnclosedExpression()) and result = "reinterpretCast"
or
this.getAnEnclosedExpression() instanceof DynamicCast and result = "dynamicCast"
exists(DynamicCast e | e = this.getAnEnclosedExpression()) and result = "dynamicCast"
or
this.getAnEnclosedExpression() instanceof SizeofExprOperator and result = "sizeofExpr"
exists(SizeofExprOperator e | e = this.getAnEnclosedExpression()) and result = "sizeofExpr"
or
this.getAnEnclosedExpression() instanceof SizeofTypeOperator and result = "sizeofType"
exists(SizeofTypeOperator e | e = this.getAnEnclosedExpression()) and result = "sizeofType"
or
this.getAnEnclosedStmt() instanceof IfStmt and result = "ifVal"
exists(IfStmt e | e = this.getAnEnclosedStmt()) and result = "ifVal"
or
this.getAnEnclosedStmt() instanceof SwitchStmt and result = "switchVal"
exists(SwitchStmt e | e = this.getAnEnclosedStmt()) and result = "switchVal"
or
this.getAnEnclosedStmt() instanceof ForStmt and result = "forVal"
exists(ForStmt e | e = this.getAnEnclosedStmt()) and result = "forVal"
or
this.getAnEnclosedStmt() instanceof DoStmt and result = "doVal"
exists(DoStmt e | e = this.getAnEnclosedStmt()) and result = "doVal"
or
this.getAnEnclosedStmt() instanceof WhileStmt and result = "whileVal"
exists(WhileStmt e | e = this.getAnEnclosedStmt()) and result = "whileVal"
or
this.getAnEnclosedStmt() instanceof GotoStmt and result = "gotoVal"
exists(GotoStmt e | e = this.getAnEnclosedStmt()) and result = "gotoVal"
or
this.getAnEnclosedStmt() instanceof ContinueStmt and result = "continueVal"
exists(ContinueStmt e | e = this.getAnEnclosedStmt()) and result = "continueVal"
or
this.getAnEnclosedStmt() instanceof BreakStmt and result = "breakVal"
exists(BreakStmt e | e = this.getAnEnclosedStmt()) and result = "breakVal"
or
this.getAnEnclosedStmt() instanceof ReturnStmt and result = "returnVal"
exists(ReturnStmt e | e = this.getAnEnclosedStmt()) and result = "returnVal"
or
this.getAnEnclosedStmt() instanceof SwitchCase and result = "caseVal"
exists(SwitchCase e | e = this.getAnEnclosedStmt()) and result = "caseVal"
or
exists(IfStmt s | s = this.getAnEnclosedStmt() and s.hasElse()) and
result = "elseVal"

View File

@@ -11,14 +11,15 @@ import semmle.code.cpp.models.interfaces.SideEffect
import semmle.code.cpp.models.interfaces.FlowSource
/**
* The standard functions `fgets` and `fgetws`.
* The standard functions `gets` and `fgets`.
*/
private class FgetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, AliasFunction,
private class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, AliasFunction,
SideEffectFunction, RemoteFlowSourceFunction {
FgetsFunction() {
GetsFunction() {
// gets(str)
// fgets(str, num, stream)
// fgetws(wstr, num, stream)
this.hasGlobalOrStdOrBslName(["fgets", "fgetws"])
this.hasGlobalOrStdOrBslName(["gets", "fgets", "fgetws"])
}
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
@@ -50,61 +51,18 @@ private class FgetsFunction extends DataFlowFunction, TaintFunction, ArrayFuncti
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
output.isParameterDeref(0) and
description = "String read by " + this.getName()
or
output.isReturnValue() and
description = "String read by " + this.getName()
}
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
not this.hasName("gets") and
bufParam = 0 and
countParam = 1
}
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
override predicate hasSocketInput(FunctionInput input) { input.isParameterDeref(2) }
}
/**
* The standard functions `gets`.
*/
private class GetsFunction extends DataFlowFunction, ArrayFunction, AliasFunction,
SideEffectFunction, LocalFlowSourceFunction {
GetsFunction() {
// gets(str)
this.hasGlobalOrStdOrBslName("gets")
override predicate hasArrayWithUnknownSize(int bufParam) {
this.hasName("gets") and
bufParam = 0
}
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
input.isParameter(0) and
output.isReturnValue()
}
override predicate parameterNeverEscapes(int index) { none() }
override predicate parameterEscapesOnlyViaReturn(int index) { index = 0 }
override predicate parameterIsAlwaysReturned(int index) { index = 0 }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = 0 and
buffer = true and
mustWrite = true
}
override predicate hasLocalFlowSource(FunctionOutput output, string description) {
output.isParameterDeref(0) and
description = "String read by " + this.getName()
or
output.isReturnValue() and
description = "String read by " + this.getName()
}
override predicate hasArrayWithUnknownSize(int bufParam) { bufParam = 0 }
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
}

View File

@@ -20,9 +20,8 @@ abstract class RemoteFlowSourceFunction extends Function {
abstract predicate hasRemoteFlowSource(FunctionOutput output, string description);
/**
* Holds if remote data from this source comes from a socket or stream
* described by `input`. There is no result if none is specified by a
* parameter.
* Holds if remote data from this source comes from a socket described by
* `input`. There is no result if a socket is not specified.
*/
predicate hasSocketInput(FunctionInput input) { none() }
}
@@ -60,9 +59,8 @@ abstract class RemoteFlowSinkFunction extends Function {
abstract predicate hasRemoteFlowSink(FunctionInput input, string description);
/**
* Holds if data put into this sink is transmitted through a socket or stream
* described by `input`. There is no result if none is specified by a
* parameter.
* Holds if data put into this sink is transmitted through a socket described
* by `input`. There is no result if a socket is not specified.
*/
predicate hasSocketInput(FunctionInput input) { none() }
}

View File

@@ -397,7 +397,7 @@ class PaddedType extends Class {
// Support only single inheritance for now. If multiple inheritance is
// supported, be sure to fix up the calls to getABaseClass*() to correctly
// handle the presence of multiple base class subojects with the same type.
not exists(this.getDerivation(1))
not exists(ClassDerivation cd | cd = this.getDerivation(1))
}
/**

View File

@@ -72,7 +72,7 @@ predicate lvalue(Element e) {
or
exists(Cast c | lvalue(c) and e.(Expr).getConversion() = c)
or
e.(Expr).getConversion() instanceof ReferenceToExpr
exists(ReferenceToExpr toref | e.(Expr).getConversion() = toref)
or
// If f is a function-pointer, then the following two
// calls are equivalent: f() and (*f)()

View File

@@ -76,7 +76,7 @@ abstract class BufferWrite extends Expr {
* can be found), specifying the reason for the estimation.
*/
int getMaxData(BufferWriteEstimationReason reason) {
reason instanceof UnspecifiedEstimateReason and result = this.getMaxData()
reason instanceof UnspecifiedEstimateReason and result = getMaxData()
}
/**
@@ -85,7 +85,7 @@ abstract class BufferWrite extends Expr {
* much smaller (8 bytes) than their true maximum length. This can be
* helpful in determining the cause of a buffer overflow issue.
*/
int getMaxDataLimited() { result = this.getMaxData() }
int getMaxDataLimited() { result = getMaxData() }
/**
* Gets an upper bound to the amount of data that's being written (if one
@@ -94,7 +94,7 @@ abstract class BufferWrite extends Expr {
* than their true maximum length. This can be helpful in determining the
* cause of a buffer overflow issue.
*/
int getMaxDataLimited(BufferWriteEstimationReason reason) { result = this.getMaxData(reason) }
int getMaxDataLimited(BufferWriteEstimationReason reason) { result = getMaxData(reason) }
/**
* Gets the size of a single character of the type this
@@ -159,11 +159,9 @@ class StrCopyBW extends BufferWriteCall {
this.getArgument(this.getParamSrc()).(AnalysedString).getMaxLength() * this.getCharSize()
}
override int getMaxData(BufferWriteEstimationReason reason) {
result = this.getMaxDataImpl(reason)
}
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
override int getMaxData() { result = max(this.getMaxDataImpl(_)) }
override int getMaxData() { result = max(getMaxDataImpl(_)) }
}
/**
@@ -205,11 +203,9 @@ class StrCatBW extends BufferWriteCall {
this.getArgument(this.getParamSrc()).(AnalysedString).getMaxLength() * this.getCharSize()
}
override int getMaxData(BufferWriteEstimationReason reason) {
result = this.getMaxDataImpl(reason)
}
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
override int getMaxData() { result = max(this.getMaxDataImpl(_)) }
override int getMaxData() { result = max(getMaxDataImpl(_)) }
}
/**
@@ -273,11 +269,9 @@ class SprintfBW extends BufferWriteCall {
)
}
override int getMaxData(BufferWriteEstimationReason reason) {
result = this.getMaxDataImpl(reason)
}
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
override int getMaxData() { result = max(this.getMaxDataImpl(_)) }
override int getMaxData() { result = max(getMaxDataImpl(_)) }
private int getMaxDataLimitedImpl(BufferWriteEstimationReason reason) {
exists(FormatLiteral fl |
@@ -287,10 +281,10 @@ class SprintfBW extends BufferWriteCall {
}
override int getMaxDataLimited(BufferWriteEstimationReason reason) {
result = this.getMaxDataLimitedImpl(reason)
result = getMaxDataLimitedImpl(reason)
}
override int getMaxDataLimited() { result = max(this.getMaxDataLimitedImpl(_)) }
override int getMaxDataLimited() { result = max(getMaxDataLimitedImpl(_)) }
}
/**
@@ -388,11 +382,9 @@ class SnprintfBW extends BufferWriteCall {
)
}
override int getMaxData(BufferWriteEstimationReason reason) {
result = this.getMaxDataImpl(reason)
}
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
override int getMaxData() { result = max(this.getMaxDataImpl(_)) }
override int getMaxData() { result = max(getMaxDataImpl(_)) }
private int getMaxDataLimitedImpl(BufferWriteEstimationReason reason) {
exists(FormatLiteral fl |
@@ -402,10 +394,10 @@ class SnprintfBW extends BufferWriteCall {
}
override int getMaxDataLimited(BufferWriteEstimationReason reason) {
result = this.getMaxDataLimitedImpl(reason)
result = getMaxDataLimitedImpl(reason)
}
override int getMaxDataLimited() { result = max(this.getMaxDataLimitedImpl(_)) }
override int getMaxDataLimited() { result = max(getMaxDataLimitedImpl(_)) }
}
/**
@@ -503,11 +495,9 @@ class ScanfBW extends BufferWrite {
)
}
override int getMaxData(BufferWriteEstimationReason reason) {
result = this.getMaxDataImpl(reason)
}
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
override int getMaxData() { result = max(this.getMaxDataImpl(_)) }
override int getMaxData() { result = max(getMaxDataImpl(_)) }
override string getBWDesc() {
exists(FunctionCall fc |
@@ -546,9 +536,7 @@ class RealpathBW extends BufferWriteCall {
this = this // Suppress a compiler warning
}
override int getMaxData(BufferWriteEstimationReason reason) {
result = this.getMaxDataImpl(reason)
}
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
override int getMaxData() { result = max(this.getMaxDataImpl(_)) }
override int getMaxData() { result = max(getMaxDataImpl(_)) }
}

View File

@@ -1,10 +1,7 @@
/*
* Support for tracking tainted data through the program. This is an alias for
* `semmle.code.cpp.ir.dataflow.DefaultTaintTracking` provided for backwards
* compatibility.
* Support for tracking tainted data through the program.
*
* Prefer to use `semmle.code.cpp.dataflow.TaintTracking` or
* `semmle.code.cpp.ir.dataflow.TaintTracking` when designing new queries.
* Prefer to use `semmle.code.cpp.dataflow.TaintTracking` when designing new queries.
*/
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking

View File

@@ -258,7 +258,7 @@ private predicate insideFunctionValueMoveTo(Element src, Element dest) {
format.getConversionChar(sourceArg - ffc.getTarget().getNumberOfParameters()) = ["s", "S"]
)
or
not c.(FormattingFunctionCall).getFormat() instanceof FormatLiteral
not exists(FormatLiteral fl | fl = c.(FormattingFunctionCall).getFormat())
or
not c instanceof FormattingFunctionCall
) and

View File

@@ -271,7 +271,7 @@ class IfStmt extends ConditionalStmt, @stmt_if {
* if (b) { x = 1; }
* ```
*/
predicate hasElse() { exists(this.getElse()) }
predicate hasElse() { exists(Stmt s | this.getElse() = s) }
override string toString() { result = "if (...) ... " }
@@ -357,7 +357,7 @@ class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if {
* if constexpr (b) { x = 1; }
* ```
*/
predicate hasElse() { exists(this.getElse()) }
predicate hasElse() { exists(Stmt s | this.getElse() = s) }
override string toString() { result = "if constexpr (...) ... " }

View File

@@ -6,22 +6,122 @@
*/
class Person extends string {
Person() {
this =
[
"Ronil", "Dina", "Ravi", "Bruce", "Jo", "Aida", "Esme", "Charlie", "Fred", "Meera", "Maya",
"Chad", "Tiana", "Laura", "George", "Will", "Mary", "Almira", "Susannah", "Rhoda",
"Cynthia", "Eunice", "Olive", "Virginia", "Angeline", "Helen", "Cornelia", "Harriet",
"Mahala", "Abby", "Margaret", "Deb", "Minerva", "Severus", "Lavina", "Adeline", "Cath",
"Elisa", "Lucretia", "Anne", "Eleanor", "Joanna", "Adam", "Agnes", "Rosanna", "Clara",
"Melissa", "Amy", "Isabel", "Jemima", "Cordelia", "Melinda", "Delila", "Jeremiah", "Elijah",
"Hester", "Walter", "Oliver", "Hugh", "Aaron", "Reuben", "Eli", "Amos", "Augustus",
"Theodore", "Ira", "Timothy", "Cyrus", "Horace", "Simon", "Asa", "Frank", "Nelson",
"Leonard", "Harrison", "Anthony", "Louis", "Milton", "Noah", "Cornelius", "Abdul", "Warren",
"Harvey", "Dennis", "Wesley", "Sylvester", "Gilbert", "Sullivan", "Edmund", "Wilson",
"Perry", "Matthew", "Simba", "Nala", "Rafiki", "Shenzi", "Ernest", "Gertrude", "Oscar",
"Lilian", "Raymond", "Elgar", "Elmer", "Herbert", "Maude", "Mae", "Otto", "Edwin",
"Ophelia", "Parsley", "Sage", "Rosemary", "Thyme", "Garfunkel", "King Basil", "Stephen"
]
this = "Ronil" or
this = "Dina" or
this = "Ravi" or
this = "Bruce" or
this = "Jo" or
this = "Aida" or
this = "Esme" or
this = "Charlie" or
this = "Fred" or
this = "Meera" or
this = "Maya" or
this = "Chad" or
this = "Tiana" or
this = "Laura" or
this = "George" or
this = "Will" or
this = "Mary" or
this = "Almira" or
this = "Susannah" or
this = "Rhoda" or
this = "Cynthia" or
this = "Eunice" or
this = "Olive" or
this = "Virginia" or
this = "Angeline" or
this = "Helen" or
this = "Cornelia" or
this = "Harriet" or
this = "Mahala" or
this = "Abby" or
this = "Margaret" or
this = "Deb" or
this = "Minerva" or
this = "Severus" or
this = "Lavina" or
this = "Adeline" or
this = "Cath" or
this = "Elisa" or
this = "Lucretia" or
this = "Anne" or
this = "Eleanor" or
this = "Joanna" or
this = "Adam" or
this = "Agnes" or
this = "Rosanna" or
this = "Clara" or
this = "Melissa" or
this = "Amy" or
this = "Isabel" or
this = "Jemima" or
this = "Cordelia" or
this = "Melinda" or
this = "Delila" or
this = "Jeremiah" or
this = "Elijah" or
this = "Hester" or
this = "Walter" or
this = "Oliver" or
this = "Hugh" or
this = "Aaron" or
this = "Reuben" or
this = "Eli" or
this = "Amos" or
this = "Augustus" or
this = "Theodore" or
this = "Ira" or
this = "Timothy" or
this = "Cyrus" or
this = "Horace" or
this = "Simon" or
this = "Asa" or
this = "Frank" or
this = "Nelson" or
this = "Leonard" or
this = "Harrison" or
this = "Anthony" or
this = "Louis" or
this = "Milton" or
this = "Noah" or
this = "Cornelius" or
this = "Abdul" or
this = "Warren" or
this = "Harvey" or
this = "Dennis" or
this = "Wesley" or
this = "Sylvester" or
this = "Gilbert" or
this = "Sullivan" or
this = "Edmund" or
this = "Wilson" or
this = "Perry" or
this = "Matthew" or
this = "Simba" or
this = "Nala" or
this = "Rafiki" or
this = "Shenzi" or
this = "Ernest" or
this = "Gertrude" or
this = "Oscar" or
this = "Lilian" or
this = "Raymond" or
this = "Elgar" or
this = "Elmer" or
this = "Herbert" or
this = "Maude" or
this = "Mae" or
this = "Otto" or
this = "Edwin" or
this = "Ophelia" or
this = "Parsley" or
this = "Sage" or
this = "Rosemary" or
this = "Thyme" or
this = "Garfunkel" or
this = "King Basil" or
this = "Stephen"
}
/** Gets the hair color of the person. If the person is bald, there is no result. */
@@ -836,12 +936,25 @@ class Person extends string {
/** Holds if the person is deceased. */
predicate isDeceased() {
this =
[
"Ernest", "Gertrude", "Oscar", "Lilian", "Edwin", "Raymond", "Elgar", "Elmer", "Herbert",
"Maude", "Mae", "Otto", "Ophelia", "Parsley", "Sage", "Rosemary", "Thyme", "Garfunkel",
"King Basil"
]
this = "Ernest" or
this = "Gertrude" or
this = "Oscar" or
this = "Lilian" or
this = "Edwin" or
this = "Raymond" or
this = "Elgar" or
this = "Elmer" or
this = "Herbert" or
this = "Maude" or
this = "Mae" or
this = "Otto" or
this = "Ophelia" or
this = "Parsley" or
this = "Sage" or
this = "Rosemary" or
this = "Thyme" or
this = "Garfunkel" or
this = "King Basil"
}
/** Gets a parent of the person (alive or deceased). */
@@ -1082,7 +1195,12 @@ class Person extends string {
}
/** Holds if the person is allowed in the region. Initially, all villagers are allowed in every region. */
predicate isAllowedIn(string region) { region = ["north", "south", "east", "west"] }
predicate isAllowedIn(string region) {
region = "north" or
region = "south" or
region = "east" or
region = "west"
}
}
/** Returns a parent of the person. */

View File

@@ -18,7 +18,6 @@ where
not lv1.isCompilerGenerated() and
not lv2.isCompilerGenerated() and
not lv1.getParentScope().(BlockStmt).isInMacroExpansion() and
not lv2.getParentScope().(BlockStmt).isInMacroExpansion() and
not lv1.getName() = "(unnamed local variable)"
not lv2.getParentScope().(BlockStmt).isInMacroExpansion()
select lv1, "Variable " + lv1.getName() + " hides another variable of the same name (on $@).", lv2,
"line " + lv2.getLocation().getStartLine().toString()

View File

@@ -1,5 +1,3 @@
## 0.0.7
## 0.0.6
## 0.0.5

View File

@@ -30,8 +30,8 @@ where
// the next statement isn't breaking out of a switch
not s.(BreakStmt).getBreakable() instanceof SwitchStmt and
// the next statement isn't a loop that can be jumped into
not s.(Loop).getStmt().getAChild*() instanceof LabelStmt and
not s.(Loop).getStmt().getAChild*() instanceof SwitchCase and
not exists(LabelStmt ls | s.(Loop).getStmt().getAChild*() = ls) and
not exists(SwitchCase sc | s.(Loop).getStmt().getAChild*() = sc) and
// no preprocessor logic applies
not functionContainsPreprocCode(js.getEnclosingFunction())
select js, "This statement makes $@ unreachable.", s, s.toString()

View File

@@ -55,7 +55,7 @@ abstract class LeapYearFieldAccess extends YearFieldAccess {
op.getAnOperand() = this and
(
op instanceof AssignArithmeticOperation or
op.getAnOperand() instanceof BinaryArithmeticOperation or
exists(BinaryArithmeticOperation bao | bao = op.getAnOperand()) or
op instanceof CrementOperation
)
)
@@ -212,7 +212,9 @@ class ChecksForLeapYearFunctionCall extends FunctionCall {
class LeapYearCheckConfiguration extends DataFlow::Configuration {
LeapYearCheckConfiguration() { this = "LeapYearCheckConfiguration" }
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof VariableAccess }
override predicate isSource(DataFlow::Node source) {
exists(VariableAccess va | va = source.asExpr())
}
override predicate isSink(DataFlow::Node sink) {
exists(ChecksForLeapYearFunctionCall fc | sink.asExpr() = fc.getAnArgument())

View File

@@ -4,4 +4,4 @@ Record* fixRecord(Record* r) {
myRecord.fix();
return &myRecord; //returns reference to myRecord, which is a stack-allocated object
}
}

View File

@@ -3,169 +3,68 @@
* @description A function returns a pointer to a stack-allocated region of
* memory. This memory is deallocated at the end of the function,
* which may lead the caller to dereference a dangling pointer.
* @kind path-problem
* @kind problem
* @id cpp/return-stack-allocated-memory
* @problem.severity warning
* @security-severity 9.3
* @precision high
* @tags reliability
* security
* external/cwe/cwe-825
*/
import cpp
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow
import semmle.code.cpp.dataflow.EscapesTree
import semmle.code.cpp.models.interfaces.PointerWrapper
import semmle.code.cpp.dataflow.DataFlow
/** Holds if `f` has a name that we intrepret as evidence of intentionally returning the value of the stack pointer. */
predicate intentionallyReturnsStackPointer(Function f) {
f.getName().toLowerCase().matches(["%stack%", "%sp%"])
/**
* Holds if `n1` may flow to `n2`, ignoring flow through fields because these
* are currently modeled as an overapproximation that assumes all objects may
* alias.
*/
predicate conservativeDataFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
DataFlow::localFlowStep(n1, n2) and
not n2.asExpr() instanceof FieldAccess and
not hasNontrivialConversion(n2.asExpr())
}
/**
* Holds if `source` is a node that represents the use of a stack variable
* Holds if `e` has a conversion that changes it from lvalue to pointer or
* back. As the data-flow library does not support conversions, we cannot track
* data flow through such expressions.
*/
predicate isSource(Node source) {
exists(VariableAddressInstruction var, Function func |
var = source.asInstruction() and
func = var.getEnclosingFunction() and
var.getASTVariable() instanceof StackVariable and
// Pointer-to-member types aren't properly handled in the dbscheme.
not var.getResultType() instanceof PointerToMemberType and
// Rule out FPs caused by extraction errors.
not any(ErrorExpr e).getEnclosingFunction() = func and
not intentionallyReturnsStackPointer(func)
)
}
/**
* Holds if `sink` is a node that represents the `StoreInstruction` that is subsequently used in
* a `ReturnValueInstruction`. We use the `StoreInstruction` instead of the instruction that defines the
* `ReturnValueInstruction`'s source value oprand because the former has better location information.
*/
predicate isSink(Node sink) {
exists(StoreInstruction store |
store.getDestinationAddress().(VariableAddressInstruction).getIRVariable() instanceof
IRReturnVariable and
sink.asOperand() = store.getSourceValueOperand()
)
}
/** Holds if `node1` _must_ flow to `node2`. */
predicate step(Node node1, Node node2) {
instructionToOperandStep(node1.asInstruction(), node2.asOperand())
or
operandToInstructionStep(node1.asOperand(), node2.asInstruction())
}
predicate instructionToOperandStep(Instruction instr, Operand operand) { operand.getDef() = instr }
/**
* Holds if `operand` flows to the result of `instr`.
*
* This predicate ignores flow through `PhiInstruction`s to create a 'must flow' relation. It also
* intentionally conflates addresses of fields and their object, and pointer offsets with their
* base pointer as this allows us to detect cases where an object's address flows to a return statement
* via a field. For example:
*
* ```cpp
* struct S { int x, y };
* int* test() {
* S s;
* return &s.x; // BAD: &s.x is an address of a variable on the stack.
* }
* ```
*/
predicate operandToInstructionStep(Operand operand, Instruction instr) {
instr.(CopyInstruction).getSourceValueOperand() = operand
or
instr.(ConvertInstruction).getUnaryOperand() = operand
or
instr.(CheckedConvertOrNullInstruction).getUnaryOperand() = operand
or
instr.(InheritanceConversionInstruction).getUnaryOperand() = operand
or
instr.(FieldAddressInstruction).getObjectAddressOperand() = operand
or
instr.(PointerOffsetInstruction).getLeftOperand() = operand
}
/** Holds if a source node flows to `n`. */
predicate branchlessLocalFlow0(Node n) {
isSource(n)
or
exists(Node mid |
branchlessLocalFlow0(mid) and
step(mid, n)
)
}
/** Holds if `n` is reachable through some source node, and `n` also eventually reaches a sink. */
predicate branchlessLocalFlow1(Node n) {
branchlessLocalFlow0(n) and
(
isSink(n)
predicate hasNontrivialConversion(Expr e) {
e instanceof Conversion and
not (
e instanceof Cast
or
exists(Node mid |
branchlessLocalFlow1(mid) and
step(n, mid)
e instanceof ParenthesisExpr
)
or
// A smart pointer can be stack-allocated while the data it points to is heap-allocated.
// So we exclude such "conversions" from this predicate.
e = any(PointerWrapper wrapper).getAnUnwrapperFunction().getACallToThisFunction()
or
hasNontrivialConversion(e.getConversion())
}
from StackVariable var, VariableAccess va, ReturnStmt r
where
not var.getUnspecifiedType() instanceof ReferenceType and
not r.isFromUninstantiatedTemplate(_) and
va = var.getAnAccess() and
(
// To check if the address escapes directly from `e` in `return e`, we need
// to check the fully-converted `e` in case there are implicit
// array-to-pointer conversions or reference conversions.
variableAddressEscapesTree(va, r.getExpr().getFullyConverted())
or
// The data flow library doesn't support conversions, so here we check that
// the address escapes into some expression `pointerToLocal`, which flows
// in one or more steps to a returned expression.
exists(Expr pointerToLocal |
variableAddressEscapesTree(va, pointerToLocal.getFullyConverted()) and
not hasNontrivialConversion(pointerToLocal) and
conservativeDataFlowStep+(DataFlow::exprNode(pointerToLocal), DataFlow::exprNode(r.getExpr()))
)
)
}
newtype TLocalPathNode =
TLocalPathNodeMid(Node n) {
branchlessLocalFlow1(n) and
(
isSource(n) or
exists(LocalPathNodeMid mid | step(mid.getNode(), n))
)
}
abstract class LocalPathNode extends TLocalPathNode {
Node n;
/** Gets the underlying node. */
Node getNode() { result = n }
/** Gets a textual representation of this node. */
string toString() { result = n.toString() }
/** Gets the location of this element. */
Location getLocation() { result = n.getLocation() }
/** Gets a successor `LocalPathNode`, if any. */
LocalPathNode getASuccessor() { step(this.getNode(), result.getNode()) }
}
class LocalPathNodeMid extends LocalPathNode, TLocalPathNodeMid {
LocalPathNodeMid() { this = TLocalPathNodeMid(n) }
}
class LocalPathNodeSink extends LocalPathNodeMid {
LocalPathNodeSink() { isSink(this.getNode()) }
}
/**
* Holds if `source` is a source node, `sink` is a sink node, and there's flow
* from `source` to `sink` using `step` relation.
*/
predicate hasFlow(LocalPathNode source, LocalPathNodeSink sink) {
isSource(source.getNode()) and
source.getASuccessor+() = sink
}
predicate reach(LocalPathNode n) { n instanceof LocalPathNodeSink or reach(n.getASuccessor()) }
query predicate edges(LocalPathNode a, LocalPathNode b) { a.getASuccessor() = b and reach(b) }
query predicate nodes(LocalPathNode n, string key, string val) {
reach(n) and key = "semmle.label" and val = n.toString()
}
from LocalPathNode source, LocalPathNodeSink sink, VariableAddressInstruction var
where
hasFlow(source, sink) and
source.getNode().asInstruction() = var
select sink.getNode(), source, sink, "May return stack-allocated memory from $@.", var.getAST(),
var.getAST().toString()
select r, "May return stack-allocated memory from $@.", va, va.toString()

View File

@@ -12,33 +12,23 @@
*/
import cpp
import semmle.code.cpp.security.BufferWrite as BufferWrite
import semmle.code.cpp.security.BufferWrite
import semmle.code.cpp.security.TaintTracking
import semmle.code.cpp.security.SensitiveExprs
import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.ir.dataflow.TaintTracking
import DataFlow::PathGraph
import TaintedWithPath
/**
* Taint flow from user input to a buffer write.
*/
class ToBufferConfiguration extends TaintTracking::Configuration {
ToBufferConfiguration() { this = "ToBufferConfiguration" }
override predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
override predicate isSink(DataFlow::Node sink) {
exists(BufferWrite::BufferWrite w | w.getASource() = sink.asExpr())
}
class Configuration extends TaintTrackingConfiguration {
override predicate isSink(Element tainted) { exists(BufferWrite w | w.getASource() = tainted) }
}
from
ToBufferConfiguration config, BufferWrite::BufferWrite w, DataFlow::PathNode sourceNode,
DataFlow::PathNode sinkNode, FlowSource source, SensitiveExpr dest
BufferWrite w, Expr taintedArg, Expr taintSource, PathNode sourceNode, PathNode sinkNode,
string taintCause, SensitiveExpr dest
where
config.hasFlowPath(sourceNode, sinkNode) and
sourceNode.getNode() = source and
w.getASource() = sinkNode.getNode().asExpr() and
taintedWithPath(taintSource, taintedArg, sourceNode, sinkNode) and
isUserInput(taintSource, taintCause) and
w.getASource() = taintedArg and
dest = w.getDest()
select w, sourceNode, sinkNode,
"This write into buffer '" + dest.toString() + "' may contain unencrypted data from $@", source,
"user input (" + source.getSourceType() + ")"
"This write into buffer '" + dest.toString() + "' may contain unencrypted data from $@",
taintSource, "user input (" + taintCause + ")"

View File

@@ -2,7 +2,7 @@
* @name Cleartext storage of sensitive information in file
* @description Storing sensitive information in cleartext can expose it
* to an attacker.
* @kind path-problem
* @kind problem
* @problem.severity warning
* @security-severity 7.5
* @precision high
@@ -17,19 +17,6 @@ import semmle.code.cpp.security.SensitiveExprs
import semmle.code.cpp.security.FileWrite
import semmle.code.cpp.dataflow.DataFlow
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.dataflow.TaintTracking
import DataFlow::PathGraph
/**
* Taint flow from a sensitive expression to a `FileWrite` sink.
*/
class FromSensitiveConfiguration extends TaintTracking::Configuration {
FromSensitiveConfiguration() { this = "FromSensitiveConfiguration" }
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof SensitiveExpr }
override predicate isSink(DataFlow::Node sink) { any(FileWrite w).getASource() = sink.asExpr() }
}
/**
* An operation on a filename.
@@ -56,18 +43,12 @@ predicate isFileName(GVN gvn) {
)
}
from
FromSensitiveConfiguration config, SensitiveExpr source, DataFlow::PathNode sourceNode, Expr mid,
DataFlow::PathNode midNode, FileWrite w, Expr dest
from FileWrite w, SensitiveExpr source, Expr mid, Expr dest
where
config.hasFlowPath(sourceNode, midNode) and
sourceNode.getNode().asExpr() = source and
midNode.getNode().asExpr() = mid and
DataFlow::localFlow(DataFlow::exprNode(source), DataFlow::exprNode(mid)) and
mid = w.getASource() and
dest = w.getDest() and
not dest.(VariableAccess).getTarget().getName() = ["stdin", "stdout", "stderr"] and // exclude calls with standard streams
not isFileName(globalValueNumber(source)) and // file names are not passwords
not exists(string convChar | convChar = w.getSourceConvChar(mid) | not convChar = ["s", "S"]) // ignore things written with other conversion characters
select w, sourceNode, midNode,
"This write into file '" + dest.toString() + "' may contain unencrypted data from $@", source,
"this source."
select w, "This write into file '" + dest.toString() + "' may contain unencrypted data from $@",
source, "this source."

View File

@@ -27,7 +27,6 @@ class SensitiveNode extends DataFlow::Node {
this.asExpr() = any(SensitiveVariable sv).getInitializer().getExpr() or
this.asExpr().(VariableAccess).getTarget() =
any(SensitiveVariable sv).(GlobalOrNamespaceVariable) or
this.asExpr().(VariableAccess).getTarget() = any(SensitiveVariable v | v instanceof Field) or
this.asUninitialized() instanceof SensitiveVariable or
this.asParameter() instanceof SensitiveVariable or
this.asExpr().(FunctionCall).getTarget() instanceof SensitiveFunction
@@ -59,10 +58,7 @@ class Send extends SendRecv instanceof RemoteFlowSinkFunction {
call.getTarget() = this and
exists(FunctionInput input, int arg |
super.hasSocketInput(input) and
(
input.isParameter(arg) or
input.isParameterDeref(arg)
) and
input.isParameter(arg) and
result = call.getArgument(arg)
)
}
@@ -85,10 +81,7 @@ class Recv extends SendRecv instanceof RemoteFlowSourceFunction {
call.getTarget() = this and
exists(FunctionInput input, int arg |
super.hasSocketInput(input) and
(
input.isParameter(arg) or
input.isParameterDeref(arg)
) and
input.isParameter(arg) and
result = call.getArgument(arg)
)
}
@@ -112,8 +105,8 @@ class Recv extends SendRecv instanceof RemoteFlowSourceFunction {
* practice it usually isn't very important which query reports a result as
* long as its reported exactly once.
*
* We do exclude function calls that specify an apparently constant socket,
* which is likely to mean standard input, standard output or a similar channel.
* We do exclude function calls that specify a constant socket, which is
* likely to mean standard input, standard output or a similar channel.
*/
abstract class NetworkSendRecv extends FunctionCall {
SendRecv target;
@@ -132,13 +125,6 @@ abstract class NetworkSendRecv extends FunctionCall {
v.getInitializer().getExpr() instanceof Literal and
g = globalValueNumber(v.getAnAccess())
)
or
// result of a function call with literal inputs (likely constant)
exists(FunctionCall fc |
forex(Expr arg | arg = fc.getAnArgument() | arg instanceof Literal) and
g = globalValueNumber(fc)
)
// (this is far from exhaustive)
)
)
}
@@ -161,28 +147,18 @@ class NetworkRecv extends NetworkSendRecv {
}
/**
* An expression that is an argument or return value from an encryption /
* decryption call. This is quite inclusive to minimize false positives, for
* example `SecureZeroMemory` is not an encryption routine but a clue that
* encryption may be present.
* An expression that is an argument or return value from an encryption or
* decryption call.
*/
class Encrypted extends Expr {
Encrypted() {
exists(FunctionCall fc |
fc.getTarget()
.getName()
.toLowerCase()
.regexpMatch(".*(crypt|encode|decode|hash|securezero).*") and
fc.getTarget().getName().toLowerCase().regexpMatch(".*(crypt|encode|decode).*") and
(
this = fc or
this = fc.getAnArgument()
)
)
or
exists(Type t |
this.getType().refersTo(t) and
t.getName().toLowerCase().regexpMatch(".*(crypt|encode|decode|hash|securezero).*")
)
}
}

View File

@@ -34,7 +34,9 @@ class SetSecurityDescriptorDaclFunctionCall extends FunctionCall {
class NullDaclConfig extends DataFlow::Configuration {
NullDaclConfig() { this = "NullDaclConfig" }
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NullValue }
override predicate isSource(DataFlow::Node source) {
exists(NullValue nullExpr | source.asExpr() = nullExpr)
}
override predicate isSink(DataFlow::Node sink) {
exists(SetSecurityDescriptorDaclFunctionCall call, VariableAccess val | val = sink.asExpr() |

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The "Cleartext transmission of sensitive information" (`cpp/cleartext-transmission`) query has been improved in several ways to reduce false positive results.

View File

@@ -1,5 +0,0 @@
---
category: minorAnalysis
---
* The `cpp/return-stack-allocated-memory` query has been improved to produce fewer false positives. The
query has also been converted to a `path-problem` query.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The "Cleartext transmission of sensitive information" (`cpp/cleartext-transmission`) query now finds more results, where a password is stored in a struct field or class member variable.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The `cpp/cleartext-storage-file` query has been upgraded with non-local taint flow and has been converted to a `path-problem` query.

View File

@@ -1,4 +0,0 @@
---
category: newQuery
---
* The `security` tag has been added to the `cpp/return-stack-allocated-memory` query. As a result, its results will now appear by default.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The `cpp/cleartext-storage-buffer` query has been updated to use the `semmle.code.cpp.dataflow.TaintTracking` library.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Fix an issue with the `cpp/declaration-hides-variable` query where it would report variables that are unnamed in a database.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The `cpp/cleartext-storage-file` query has been improved, removing false positives where data is written to a standard output stream.

View File

@@ -1 +0,0 @@
## 0.0.7

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.0.7
lastReleaseVersion: 0.0.6

View File

@@ -1,9 +0,0 @@
void test(){
int a = 8;
int b = 9;
//Useless NonEquals
if(a==8 && a != 7) {}
while(a==8 && a!=7){}
}

View File

@@ -1,18 +0,0 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Comparison operations like <code>a==8 &amp;&amp; a!=7</code> contain a useless part : the non-equal part. This rule finds tests of this kind within an <code>if</code> or a <code>while</code> statement</p>
</overview>
<recommendation>
<p>Remove the useless comparisons</p>
</recommendation>
<example>
<sample src="UselessTest.cpp" />
</example>
</qhelp>

View File

@@ -1,43 +0,0 @@
/**
* @name Useless Test
* @description A boolean condition that is guaranteed to never be evaluated should be deleted.
* @kind problem
* @problem.severity warning
* @id cpp/uselesstest
* @tags reliability
* readability
*/
import cpp
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
predicate sameExpr(Expr e1, Expr e2) { globalValueNumber(e1).getAnExpr() = e2 }
Element nearestParent(Expr e) {
if
e.getParent().(Expr).getConversion*() instanceof ParenthesisExpr or
e.getParent() instanceof IfStmt or
e.getParent() instanceof WhileStmt
then result = e.getParent()
else result = nearestParent(e.getParent())
}
from LogicalAndExpr b, EQExpr eq, NEExpr ne
where
(
b.getAChild*() = eq and
b.getAChild*() = ne and
eq.getParent() instanceof LogicalAndExpr and
ne.getParent() instanceof LogicalAndExpr
) and
(
eq.getLeftOperand() instanceof VariableAccess and ne.getLeftOperand() instanceof VariableAccess
or
eq.getLeftOperand() instanceof PointerDereferenceExpr and
ne.getLeftOperand() instanceof PointerDereferenceExpr
) and
eq.getRightOperand() instanceof Literal and
ne.getRightOperand() instanceof Literal and
nearestParent(eq) = nearestParent(ne) and
sameExpr(eq.getLeftOperand(), ne.getLeftOperand())
select ne, "Useless Test"

View File

@@ -24,10 +24,10 @@ class CallUsedToHandleErrors extends FunctionCall {
not exists(this.(ControlFlowNode).getASuccessor())
or
// call throwing an exception
this.(ControlFlowNode).getASuccessor() instanceof ThrowExpr
exists(ThrowExpr tex | tex = this.(ControlFlowNode).getASuccessor())
or
// call logging a message, possibly an error
this.(ControlFlowNode).getASuccessor() instanceof FormattingFunction
exists(FormattingFunction ff | ff = this.(ControlFlowNode).getASuccessor())
or
// enabling recursive search
exists(CallUsedToHandleErrors fr | getTarget() = fr.getEnclosingFunction())
@@ -37,9 +37,9 @@ class CallUsedToHandleErrors extends FunctionCall {
/** Holds if the conditions for a call outside the wrapper function are met. */
predicate conditionsOutsideWrapper(FunctionCall fcp) {
fcp.getNumberOfArguments() > 0 and
not fcp.getEnclosingStmt().getParentStmt*() instanceof ConditionalStmt and
not fcp.getEnclosingStmt().getParentStmt*() instanceof Loop and
not fcp.getEnclosingStmt().getParentStmt*() instanceof ReturnStmt and
not exists(ConditionalStmt cdtmp | fcp.getEnclosingStmt().getParentStmt*() = cdtmp) and
not exists(Loop lptmp | fcp.getEnclosingStmt().getParentStmt*() = lptmp) and
not exists(ReturnStmt rttmp | fcp.getEnclosingStmt().getParentStmt*() = rttmp) and
not exists(FunctionCall fctmp2 | fcp = fctmp2.getAnArgument().getAChild*()) and
not exists(Assignment astmp | fcp = astmp.getRValue().getAChild*()) and
not exists(Initializer intmp | fcp = intmp.getExpr().getAChild*()) and

View File

@@ -92,7 +92,7 @@ where
) and
exists(Variable vrtmp |
vrtmp = fc.getArgument(0).(VariableAccess).getTarget() and
vrtmp = fctmp.getArgument(0).(AddressOfExpr).getAddressable() and
vrtmp = fctmp.getArgument(0).(AddressOfExpr).getAddressable().(Variable) and
not vrtmp instanceof Field
)
) and

View File

@@ -26,7 +26,7 @@ class CallMayNotReturn extends FunctionCall {
// call to another function that may not return
exists(CallMayNotReturn exit | getTarget() = exit.getEnclosingFunction())
or
this.(ControlFlowNode).getASuccessor() instanceof ThrowExpr
exists(ThrowExpr tex | tex = this.(ControlFlowNode).getASuccessor())
}
}
@@ -127,7 +127,7 @@ predicate similarArguments(FunctionCall fc, FunctionCall fc1) {
from FunctionCall fc, FunctionCall fc1
where
not fc.getASuccessor*() instanceof CallMayNotReturn and
not exists(CallMayNotReturn fctmp | fctmp = fc.getASuccessor*()) and
not exists(IfStmt ifs | ifs.getCondition().getAChild*() = fc) and
(
// detecting a repeated call situation within one function

View File

@@ -15,6 +15,6 @@ from EqualityOperation e, PointerToMemberType t, Class c
where
e.getAnOperand().getType() = t and
t.getClass() = c and
c.getAMemberFunction() instanceof VirtualFunction
exists(VirtualFunction f | c.getAMemberFunction() = f)
select e,
"AV Rule 97.1: Neither operand of an equality operator shall be a pointer to a virtual member function."

View File

@@ -1,8 +1,6 @@
name: codeql/cpp-queries
version: 0.0.8-dev
groups:
- cpp
- queries
version: 0.0.7-dev
groups: cpp
dependencies:
codeql/cpp-all: "*"
codeql/suite-helpers: "*"

View File

@@ -93,7 +93,7 @@
private import InlineExpectationsTestPrivate
/**
* The base class for tests with inline expectations. The test extends this class to provide the actual
* Base class for tests with inline expectations. The test extends this class to provide the actual
* results of the query, which are then compared with the expected results in comments to produce a
* list of failure messages that point out where the actual results differ from the expected
* results.

View File

@@ -2665,7 +2665,7 @@
| ir.cpp:617:15:617:21 | Unary | r617_4 |
| ir.cpp:617:15:617:22 | CallTarget | func:r617_3 |
| ir.cpp:617:15:617:22 | ChiPartial | partial:m617_7 |
| ir.cpp:617:15:617:22 | ChiPartial | partial:m617_10 |
| ir.cpp:617:15:617:22 | ChiPartial | partial:m617_9 |
| ir.cpp:617:15:617:22 | ChiTotal | total:m616_6 |
| ir.cpp:617:15:617:22 | ChiTotal | total:m617_2 |
| ir.cpp:617:15:617:22 | SideEffect | ~m616_6 |
@@ -2680,7 +2680,7 @@
| ir.cpp:619:12:619:13 | Arg(this) | this:r619_1 |
| ir.cpp:619:16:619:30 | CallTarget | func:r619_3 |
| ir.cpp:619:16:619:30 | ChiPartial | partial:m619_7 |
| ir.cpp:619:16:619:30 | ChiPartial | partial:m619_10 |
| ir.cpp:619:16:619:30 | ChiPartial | partial:m619_9 |
| ir.cpp:619:16:619:30 | ChiTotal | total:m618_5 |
| ir.cpp:619:16:619:30 | ChiTotal | total:m619_2 |
| ir.cpp:619:16:619:30 | SideEffect | ~m618_5 |
@@ -2906,7 +2906,7 @@
| ir.cpp:658:5:658:5 | ChiPartial | partial:m658_3 |
| ir.cpp:658:5:658:5 | ChiTotal | total:m658_2 |
| ir.cpp:658:5:658:5 | Load | m658_6 |
| ir.cpp:658:5:658:5 | SideEffect | m662_10 |
| ir.cpp:658:5:658:5 | SideEffect | m662_9 |
| ir.cpp:658:5:658:5 | SideEffect | ~m662_7 |
| ir.cpp:658:5:658:5 | Unary | m658_6 |
| ir.cpp:658:5:658:5 | Unary | m658_6 |
@@ -2929,7 +2929,7 @@
| ir.cpp:662:9:662:19 | Arg(this) | this:r662_1 |
| ir.cpp:662:9:662:19 | CallTarget | func:r662_2 |
| ir.cpp:662:9:662:19 | ChiPartial | partial:m662_6 |
| ir.cpp:662:9:662:19 | ChiPartial | partial:m662_9 |
| ir.cpp:662:9:662:19 | ChiPartial | partial:m662_8 |
| ir.cpp:662:9:662:19 | ChiTotal | total:m661_4 |
| ir.cpp:662:9:662:19 | ChiTotal | total:m663_5 |
| ir.cpp:662:9:662:19 | SideEffect | ~m663_5 |
@@ -3147,10 +3147,10 @@
| ir.cpp:736:5:736:19 | Arg(this) | this:r736_1 |
| ir.cpp:736:5:736:19 | CallTarget | func:r736_3 |
| ir.cpp:736:5:736:19 | ChiPartial | partial:m736_7 |
| ir.cpp:736:5:736:19 | ChiPartial | partial:m736_10 |
| ir.cpp:736:5:736:19 | ChiPartial | partial:m736_9 |
| ir.cpp:736:5:736:19 | ChiTotal | total:m724_4 |
| ir.cpp:736:5:736:19 | ChiTotal | total:m736_2 |
| ir.cpp:736:5:736:19 | Load | m736_11 |
| ir.cpp:736:5:736:19 | Load | m736_10 |
| ir.cpp:736:5:736:19 | SideEffect | ~m724_4 |
| ir.cpp:736:18:736:18 | Address | &:r736_4 |
| ir.cpp:736:18:736:18 | Address | &:r736_5 |
@@ -3673,11 +3673,11 @@
| ir.cpp:809:7:809:13 | Arg(this) | this:r809_3 |
| ir.cpp:809:7:809:13 | CallTarget | func:r809_5 |
| ir.cpp:809:7:809:13 | ChiPartial | partial:m809_10 |
| ir.cpp:809:7:809:13 | ChiPartial | partial:m809_13 |
| ir.cpp:809:7:809:13 | ChiPartial | partial:m809_12 |
| ir.cpp:809:7:809:13 | ChiTotal | total:m808_8 |
| ir.cpp:809:7:809:13 | ChiTotal | total:m809_4 |
| ir.cpp:809:7:809:13 | SideEffect | ~m808_8 |
| ir.cpp:809:7:809:13 | SideEffect | ~m809_14 |
| ir.cpp:809:7:809:13 | SideEffect | ~m809_13 |
| ir.cpp:809:7:809:13 | Unary | r809_3 |
| ir.cpp:809:7:809:13 | Unary | r809_15 |
| ir.cpp:809:13:809:13 | Address | &:r809_8 |
@@ -3703,11 +3703,11 @@
| ir.cpp:810:7:810:26 | Arg(this) | this:r810_3 |
| ir.cpp:810:7:810:26 | CallTarget | func:r810_5 |
| ir.cpp:810:7:810:26 | ChiPartial | partial:m810_10 |
| ir.cpp:810:7:810:26 | ChiPartial | partial:m810_13 |
| ir.cpp:810:7:810:26 | ChiPartial | partial:m810_12 |
| ir.cpp:810:7:810:26 | ChiTotal | total:m809_19 |
| ir.cpp:810:7:810:26 | ChiTotal | total:m810_4 |
| ir.cpp:810:7:810:26 | SideEffect | ~m809_19 |
| ir.cpp:810:7:810:26 | SideEffect | ~m810_14 |
| ir.cpp:810:7:810:26 | SideEffect | ~m810_13 |
| ir.cpp:810:7:810:26 | Unary | r810_3 |
| ir.cpp:810:7:810:26 | Unary | r810_15 |
| ir.cpp:810:25:810:25 | Address | &:r810_8 |
@@ -3819,11 +3819,11 @@
| ir.cpp:823:7:823:13 | Arg(this) | this:r823_3 |
| ir.cpp:823:7:823:13 | CallTarget | func:r823_5 |
| ir.cpp:823:7:823:13 | ChiPartial | partial:m823_11 |
| ir.cpp:823:7:823:13 | ChiPartial | partial:m823_14 |
| ir.cpp:823:7:823:13 | ChiPartial | partial:m823_13 |
| ir.cpp:823:7:823:13 | ChiTotal | total:m822_9 |
| ir.cpp:823:7:823:13 | ChiTotal | total:m823_4 |
| ir.cpp:823:7:823:13 | SideEffect | ~m822_9 |
| ir.cpp:823:7:823:13 | SideEffect | ~m823_15 |
| ir.cpp:823:7:823:13 | SideEffect | ~m823_14 |
| ir.cpp:823:7:823:13 | Unary | r823_3 |
| ir.cpp:823:7:823:13 | Unary | r823_16 |
| ir.cpp:823:13:823:13 | Address | &:r823_9 |
@@ -3850,11 +3850,11 @@
| ir.cpp:824:7:824:26 | Arg(this) | this:r824_3 |
| ir.cpp:824:7:824:26 | CallTarget | func:r824_5 |
| ir.cpp:824:7:824:26 | ChiPartial | partial:m824_11 |
| ir.cpp:824:7:824:26 | ChiPartial | partial:m824_14 |
| ir.cpp:824:7:824:26 | ChiPartial | partial:m824_13 |
| ir.cpp:824:7:824:26 | ChiTotal | total:m823_20 |
| ir.cpp:824:7:824:26 | ChiTotal | total:m824_4 |
| ir.cpp:824:7:824:26 | SideEffect | ~m823_20 |
| ir.cpp:824:7:824:26 | SideEffect | ~m824_15 |
| ir.cpp:824:7:824:26 | SideEffect | ~m824_14 |
| ir.cpp:824:7:824:26 | Unary | r824_3 |
| ir.cpp:824:7:824:26 | Unary | r824_16 |
| ir.cpp:824:25:824:25 | Address | &:r824_9 |
@@ -4059,11 +4059,11 @@
| ir.cpp:867:1:867:14 | ChiPartial | partial:m867_3 |
| ir.cpp:867:1:867:14 | ChiTotal | total:m867_2 |
| ir.cpp:867:1:867:14 | Load | m867_6 |
| ir.cpp:867:1:867:14 | SideEffect | m868_9 |
| ir.cpp:867:1:867:14 | SideEffect | m868_8 |
| ir.cpp:867:1:867:14 | SideEffect | ~m868_6 |
| ir.cpp:868:3:868:12 | CallTarget | func:r868_1 |
| ir.cpp:868:3:868:12 | ChiPartial | partial:m868_5 |
| ir.cpp:868:3:868:12 | ChiPartial | partial:m868_8 |
| ir.cpp:868:3:868:12 | ChiPartial | partial:m868_7 |
| ir.cpp:868:3:868:12 | ChiTotal | total:m867_4 |
| ir.cpp:868:3:868:12 | ChiTotal | total:m867_8 |
| ir.cpp:868:3:868:12 | SideEffect | ~m867_4 |
@@ -4310,7 +4310,7 @@
| ir.cpp:954:3:954:27 | CallTarget | func:r954_9 |
| ir.cpp:954:3:954:27 | ChiPartial | partial:m954_5 |
| ir.cpp:954:3:954:27 | ChiPartial | partial:m954_13 |
| ir.cpp:954:3:954:27 | ChiPartial | partial:m954_16 |
| ir.cpp:954:3:954:27 | ChiPartial | partial:m954_15 |
| ir.cpp:954:3:954:27 | ChiTotal | total:m953_11 |
| ir.cpp:954:3:954:27 | ChiTotal | total:m954_6 |
| ir.cpp:954:3:954:27 | ChiTotal | total:m954_7 |
@@ -5386,10 +5386,10 @@
| ir.cpp:1154:5:1154:19 | Arg(this) | this:r1154_1 |
| ir.cpp:1154:5:1154:19 | CallTarget | func:r1154_3 |
| ir.cpp:1154:5:1154:19 | ChiPartial | partial:m1154_7 |
| ir.cpp:1154:5:1154:19 | ChiPartial | partial:m1154_10 |
| ir.cpp:1154:5:1154:19 | ChiPartial | partial:m1154_9 |
| ir.cpp:1154:5:1154:19 | ChiTotal | total:m1142_4 |
| ir.cpp:1154:5:1154:19 | ChiTotal | total:m1154_2 |
| ir.cpp:1154:5:1154:19 | Load | m1154_11 |
| ir.cpp:1154:5:1154:19 | Load | m1154_10 |
| ir.cpp:1154:5:1154:19 | SideEffect | ~m1142_4 |
| ir.cpp:1154:18:1154:18 | Address | &:r1154_4 |
| ir.cpp:1154:18:1154:18 | Address | &:r1154_5 |
@@ -5496,14 +5496,14 @@
| ir.cpp:1178:8:1178:23 | Address | &:r1178_5 |
| ir.cpp:1178:8:1178:23 | ChiPartial | partial:m1178_3 |
| ir.cpp:1178:8:1178:23 | ChiTotal | total:m1178_2 |
| ir.cpp:1178:8:1178:23 | Load | m1179_11 |
| ir.cpp:1178:8:1178:23 | Load | m1179_10 |
| ir.cpp:1178:8:1178:23 | SideEffect | ~m1179_8 |
| ir.cpp:1179:3:1179:23 | Address | &:r1179_1 |
| ir.cpp:1179:3:1179:23 | Address | &:r1179_1 |
| ir.cpp:1179:3:1179:23 | Arg(this) | this:r1179_1 |
| ir.cpp:1179:3:1179:23 | CallTarget | func:r1179_3 |
| ir.cpp:1179:3:1179:23 | ChiPartial | partial:m1179_7 |
| ir.cpp:1179:3:1179:23 | ChiPartial | partial:m1179_10 |
| ir.cpp:1179:3:1179:23 | ChiPartial | partial:m1179_9 |
| ir.cpp:1179:3:1179:23 | ChiTotal | total:m1178_4 |
| ir.cpp:1179:3:1179:23 | ChiTotal | total:m1179_2 |
| ir.cpp:1179:3:1179:23 | SideEffect | ~m1178_4 |
@@ -5651,7 +5651,7 @@
| ir.cpp:1242:19:1242:19 | Address | &:r1242_5 |
| ir.cpp:1242:19:1242:19 | Arg(this) | this:r1242_5 |
| ir.cpp:1242:19:1242:19 | ChiPartial | partial:m1242_16 |
| ir.cpp:1242:19:1242:19 | ChiTotal | total:m1242_14 |
| ir.cpp:1242:19:1242:19 | ChiTotal | total:m1242_13 |
| ir.cpp:1242:19:1242:19 | Condition | r1242_3 |
| ir.cpp:1242:19:1242:19 | Load | ~m1242_1 |
| ir.cpp:1242:19:1242:19 | Phi | from 0:~m1240_4 |
@@ -5659,7 +5659,7 @@
| ir.cpp:1242:19:1242:19 | StoreValue | r1242_15 |
| ir.cpp:1242:20:1242:29 | CallTarget | func:r1242_6 |
| ir.cpp:1242:20:1242:29 | ChiPartial | partial:m1242_10 |
| ir.cpp:1242:20:1242:29 | ChiPartial | partial:m1242_13 |
| ir.cpp:1242:20:1242:29 | ChiPartial | partial:m1242_12 |
| ir.cpp:1242:20:1242:29 | ChiTotal | total:m1242_1 |
| ir.cpp:1242:20:1242:29 | ChiTotal | total:m1242_11 |
| ir.cpp:1242:20:1242:29 | SideEffect | ~m1242_1 |
@@ -5672,7 +5672,7 @@
| ir.cpp:1243:19:1243:19 | Address | &:r1243_5 |
| ir.cpp:1243:19:1243:19 | Arg(this) | this:r1243_5 |
| ir.cpp:1243:19:1243:19 | ChiPartial | partial:m1243_16 |
| ir.cpp:1243:19:1243:19 | ChiTotal | total:m1243_14 |
| ir.cpp:1243:19:1243:19 | ChiTotal | total:m1243_13 |
| ir.cpp:1243:19:1243:19 | Condition | r1243_3 |
| ir.cpp:1243:19:1243:19 | Load | ~m1243_1 |
| ir.cpp:1243:19:1243:19 | Phi | from 2:~m1242_1 |
@@ -5680,7 +5680,7 @@
| ir.cpp:1243:19:1243:19 | StoreValue | r1243_15 |
| ir.cpp:1243:20:1243:28 | CallTarget | func:r1243_6 |
| ir.cpp:1243:20:1243:28 | ChiPartial | partial:m1243_10 |
| ir.cpp:1243:20:1243:28 | ChiPartial | partial:m1243_13 |
| ir.cpp:1243:20:1243:28 | ChiPartial | partial:m1243_12 |
| ir.cpp:1243:20:1243:28 | ChiTotal | total:m1243_1 |
| ir.cpp:1243:20:1243:28 | ChiTotal | total:m1243_11 |
| ir.cpp:1243:20:1243:28 | SideEffect | ~m1243_1 |
@@ -6200,12 +6200,12 @@
| ir.cpp:1370:23:1370:27 | Arg(this) | this:r1370_2 |
| ir.cpp:1370:23:1370:27 | CallTarget | func:r1370_4 |
| ir.cpp:1370:23:1370:27 | ChiPartial | partial:m1370_8 |
| ir.cpp:1370:23:1370:27 | ChiPartial | partial:m1370_11 |
| ir.cpp:1370:23:1370:27 | ChiPartial | partial:m1370_10 |
| ir.cpp:1370:23:1370:27 | ChiTotal | total:m1369_7 |
| ir.cpp:1370:23:1370:27 | ChiTotal | total:m1370_3 |
| ir.cpp:1370:23:1370:27 | SideEffect | ~m1365_3 |
| ir.cpp:1370:23:1370:27 | SideEffect | ~m1369_7 |
| ir.cpp:1370:23:1370:27 | SideEffect | ~m1370_12 |
| ir.cpp:1370:23:1370:27 | SideEffect | ~m1370_11 |
| ir.cpp:1370:23:1370:27 | Unary | r1370_2 |
| ir.cpp:1370:23:1370:27 | Unary | r1370_5 |
| ir.cpp:1371:5:1371:15 | CallTarget | func:r1371_1 |
@@ -6221,10 +6221,10 @@
| ir.cpp:1371:17:1371:17 | Arg(this) | this:r1371_2 |
| ir.cpp:1371:17:1371:17 | CallTarget | func:r1371_4 |
| ir.cpp:1371:17:1371:17 | ChiPartial | partial:m1371_9 |
| ir.cpp:1371:17:1371:17 | ChiPartial | partial:m1371_12 |
| ir.cpp:1371:17:1371:17 | ChiPartial | partial:m1371_11 |
| ir.cpp:1371:17:1371:17 | ChiTotal | total:m1370_16 |
| ir.cpp:1371:17:1371:17 | ChiTotal | total:m1371_3 |
| ir.cpp:1371:17:1371:17 | Load | m1371_13 |
| ir.cpp:1371:17:1371:17 | Load | m1371_12 |
| ir.cpp:1371:17:1371:17 | SideEffect | ~m1366_6 |
| ir.cpp:1371:17:1371:17 | SideEffect | ~m1370_16 |
| ir.cpp:1371:17:1371:17 | Unary | r1371_5 |
@@ -6242,10 +6242,10 @@
| ir.cpp:1372:25:1372:29 | Arg(this) | this:r1372_2 |
| ir.cpp:1372:25:1372:29 | CallTarget | func:r1372_4 |
| ir.cpp:1372:25:1372:29 | ChiPartial | partial:m1372_8 |
| ir.cpp:1372:25:1372:29 | ChiPartial | partial:m1372_11 |
| ir.cpp:1372:25:1372:29 | ChiPartial | partial:m1372_10 |
| ir.cpp:1372:25:1372:29 | ChiTotal | total:m1371_17 |
| ir.cpp:1372:25:1372:29 | ChiTotal | total:m1372_3 |
| ir.cpp:1372:25:1372:29 | Load | m1372_12 |
| ir.cpp:1372:25:1372:29 | Load | m1372_11 |
| ir.cpp:1372:25:1372:29 | SideEffect | ~m1365_3 |
| ir.cpp:1372:25:1372:29 | SideEffect | ~m1371_17 |
| ir.cpp:1372:25:1372:29 | Unary | r1372_5 |
@@ -6414,10 +6414,10 @@
| ir.cpp:1396:17:1396:17 | Arg(this) | this:r1396_2 |
| ir.cpp:1396:17:1396:17 | CallTarget | func:r1396_4 |
| ir.cpp:1396:17:1396:17 | ChiPartial | partial:m1396_9 |
| ir.cpp:1396:17:1396:17 | ChiPartial | partial:m1396_12 |
| ir.cpp:1396:17:1396:17 | ChiPartial | partial:m1396_11 |
| ir.cpp:1396:17:1396:17 | ChiTotal | total:m1395_7 |
| ir.cpp:1396:17:1396:17 | ChiTotal | total:m1396_3 |
| ir.cpp:1396:17:1396:17 | Load | m1396_13 |
| ir.cpp:1396:17:1396:17 | Load | m1396_12 |
| ir.cpp:1396:17:1396:17 | SideEffect | ~m1392_6 |
| ir.cpp:1396:17:1396:17 | SideEffect | ~m1395_7 |
| ir.cpp:1396:17:1396:17 | Unary | r1396_5 |
@@ -6741,7 +6741,7 @@
| smart_ptr.cpp:19:20:19:21 | ChiPartial | partial:m19_18 |
| smart_ptr.cpp:19:20:19:21 | ChiTotal | total:m17_8 |
| smart_ptr.cpp:19:20:19:21 | ChiTotal | total:m18_8 |
| smart_ptr.cpp:19:20:19:21 | Load | m19_12 |
| smart_ptr.cpp:19:20:19:21 | Load | m19_11 |
| smart_ptr.cpp:19:20:19:21 | SideEffect | m18_9 |
| smart_ptr.cpp:19:20:19:21 | SideEffect | ~m17_8 |
| smart_ptr.cpp:19:20:19:21 | SideEffect | ~m18_8 |
@@ -6766,7 +6766,7 @@
| smart_ptr.cpp:31:26:31:37 | CallTarget | func:r31_4 |
| smart_ptr.cpp:31:26:31:37 | ChiPartial | partial:m31_9 |
| smart_ptr.cpp:31:26:31:37 | ChiTotal | total:m28_4 |
| smart_ptr.cpp:31:26:31:37 | Load | m31_12 |
| smart_ptr.cpp:31:26:31:37 | Load | m31_11 |
| smart_ptr.cpp:31:26:31:37 | SideEffect | m29_2 |
| smart_ptr.cpp:31:26:31:37 | SideEffect | ~m28_4 |
| smart_ptr.cpp:31:26:31:37 | SideEffect | ~m31_16 |
@@ -6791,7 +6791,7 @@
| smart_ptr.cpp:35:30:35:49 | ChiPartial | partial:m35_18 |
| smart_ptr.cpp:35:30:35:49 | ChiTotal | total:m31_16 |
| smart_ptr.cpp:35:30:35:49 | ChiTotal | total:m35_16 |
| smart_ptr.cpp:35:30:35:49 | Load | m35_12 |
| smart_ptr.cpp:35:30:35:49 | Load | m35_11 |
| smart_ptr.cpp:35:30:35:49 | SideEffect | m33_2 |
| smart_ptr.cpp:35:30:35:49 | SideEffect | ~m31_16 |
| smart_ptr.cpp:35:30:35:49 | SideEffect | ~m35_16 |
@@ -6816,7 +6816,7 @@
| smart_ptr.cpp:39:37:39:51 | ChiPartial | partial:m39_18 |
| smart_ptr.cpp:39:37:39:51 | ChiTotal | total:m35_19 |
| smart_ptr.cpp:39:37:39:51 | ChiTotal | total:m39_16 |
| smart_ptr.cpp:39:37:39:51 | Load | m39_12 |
| smart_ptr.cpp:39:37:39:51 | Load | m39_11 |
| smart_ptr.cpp:39:37:39:51 | SideEffect | m37_2 |
| smart_ptr.cpp:39:37:39:51 | SideEffect | ~m35_19 |
| smart_ptr.cpp:39:37:39:51 | SideEffect | ~m39_16 |
@@ -6841,7 +6841,7 @@
| smart_ptr.cpp:43:37:43:51 | ChiPartial | partial:m43_18 |
| smart_ptr.cpp:43:37:43:51 | ChiTotal | total:m39_19 |
| smart_ptr.cpp:43:37:43:51 | ChiTotal | total:m43_16 |
| smart_ptr.cpp:43:37:43:51 | Load | m43_12 |
| smart_ptr.cpp:43:37:43:51 | Load | m43_11 |
| smart_ptr.cpp:43:37:43:51 | SideEffect | m41_2 |
| smart_ptr.cpp:43:37:43:51 | SideEffect | ~m39_19 |
| smart_ptr.cpp:43:37:43:51 | SideEffect | ~m43_16 |
@@ -6863,7 +6863,7 @@
| smart_ptr.cpp:47:43:47:63 | CallTarget | func:r47_4 |
| smart_ptr.cpp:47:43:47:63 | ChiPartial | partial:m47_9 |
| smart_ptr.cpp:47:43:47:63 | ChiTotal | total:m43_19 |
| smart_ptr.cpp:47:43:47:63 | Load | m47_12 |
| smart_ptr.cpp:47:43:47:63 | Load | m47_11 |
| smart_ptr.cpp:47:43:47:63 | SideEffect | m45_2 |
| smart_ptr.cpp:47:43:47:63 | SideEffect | ~m43_19 |
| smart_ptr.cpp:47:43:47:63 | SideEffect | ~m47_16 |

View File

@@ -3362,8 +3362,8 @@ ir.cpp:
# 617| r617_5(char *) = Convert : r617_4
# 617| v617_6(void) = Call[String] : func:r617_3, this:r617_1, 0:r617_5
# 617| mu617_7(unknown) = ^CallSideEffect : ~m?
# 617| v617_8(void) = ^BufferReadSideEffect[0] : &:r617_5, ~m?
# 617| mu617_9(String) = ^IndirectMayWriteSideEffect[-1] : &:r617_1
# 617| mu617_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r617_1
# 617| v617_9(void) = ^BufferReadSideEffect[0] : &:r617_5, ~m?
# 618| r618_1(glval<String>) = VariableAddress[s3] :
# 618| r618_2(glval<unknown>) = FunctionAddress[ReturnObject] :
# 618| r618_3(String) = Call[ReturnObject] : func:r618_2
@@ -3376,8 +3376,8 @@ ir.cpp:
# 619| r619_5(char *) = Convert : r619_4
# 619| v619_6(void) = Call[String] : func:r619_3, this:r619_1, 0:r619_5
# 619| mu619_7(unknown) = ^CallSideEffect : ~m?
# 619| v619_8(void) = ^BufferReadSideEffect[0] : &:r619_5, ~m?
# 619| mu619_9(String) = ^IndirectMayWriteSideEffect[-1] : &:r619_1
# 619| mu619_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r619_1
# 619| v619_9(void) = ^BufferReadSideEffect[0] : &:r619_5, ~m?
# 620| v620_1(void) = NoOp :
# 615| v615_4(void) = ReturnVoid :
# 615| v615_5(void) = AliasedUse : ~m?
@@ -3628,8 +3628,8 @@ ir.cpp:
# 662| r662_4(char *) = Convert : r662_3
# 662| v662_5(void) = Call[String] : func:r662_2, this:r662_1, 0:r662_4
# 662| mu662_6(unknown) = ^CallSideEffect : ~m?
# 662| v662_7(void) = ^BufferReadSideEffect[0] : &:r662_4, ~m?
# 662| mu662_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r662_1
# 662| mu662_7(String) = ^IndirectMayWriteSideEffect[-1] : &:r662_1
# 662| v662_8(void) = ^BufferReadSideEffect[0] : &:r662_4, ~m?
# 664| v664_1(void) = NoOp :
# 658| v658_8(void) = ReturnIndirection[#this] : &:r658_6, ~m?
# 658| v658_9(void) = ReturnVoid :
@@ -3924,8 +3924,8 @@ ir.cpp:
# 731| r731_15(char *) = Convert : r731_14
# 731| v731_16(void) = Call[String] : func:r731_13, this:r731_11, 0:r731_15
# 731| mu731_17(unknown) = ^CallSideEffect : ~m?
# 731| v731_18(void) = ^BufferReadSideEffect[0] : &:r731_15, ~m?
# 731| mu731_19(String) = ^IndirectMayWriteSideEffect[-1] : &:r731_11
# 731| mu731_18(String) = ^IndirectMayWriteSideEffect[-1] : &:r731_11
# 731| v731_19(void) = ^BufferReadSideEffect[0] : &:r731_15, ~m?
# 731| v731_20(void) = ThrowValue : &:r731_11, ~m?
#-----| Exception -> Block 9
@@ -3952,8 +3952,8 @@ ir.cpp:
# 736| r736_5(char *) = Load[s] : &:r736_4, ~m?
# 736| v736_6(void) = Call[String] : func:r736_3, this:r736_1, 0:r736_5
# 736| mu736_7(unknown) = ^CallSideEffect : ~m?
# 736| v736_8(void) = ^BufferReadSideEffect[0] : &:r736_5, ~m?
# 736| mu736_9(String) = ^IndirectMayWriteSideEffect[-1] : &:r736_1
# 736| mu736_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r736_1
# 736| v736_9(void) = ^BufferReadSideEffect[0] : &:r736_5, ~m?
# 736| v736_10(void) = ThrowValue : &:r736_1, ~m?
#-----| Exception -> Block 2
@@ -4518,8 +4518,8 @@ ir.cpp:
# 809| r809_8(Base &) = CopyValue : r809_7
# 809| v809_9(void) = Call[Base] : func:r809_5, this:r809_3, 0:r809_8
# 809| mu809_10(unknown) = ^CallSideEffect : ~m?
# 809| v809_11(void) = ^BufferReadSideEffect[0] : &:r809_8, ~m?
# 809| mu809_12(Base) = ^IndirectMayWriteSideEffect[-1] : &:r809_3
# 809| mu809_11(Base) = ^IndirectMayWriteSideEffect[-1] : &:r809_3
# 809| v809_12(void) = ^BufferReadSideEffect[0] : &:r809_8, ~m?
# 809| r809_13(glval<Base>) = Convert : r809_3
# 809| r809_14(Base &) = CopyValue : r809_13
# 809| r809_15(Base &) = Call[operator=] : func:r809_2, this:r809_1, 0:r809_14
@@ -4538,8 +4538,8 @@ ir.cpp:
# 810| r810_8(Base &) = CopyValue : r810_7
# 810| v810_9(void) = Call[Base] : func:r810_5, this:r810_3, 0:r810_8
# 810| mu810_10(unknown) = ^CallSideEffect : ~m?
# 810| v810_11(void) = ^BufferReadSideEffect[0] : &:r810_8, ~m?
# 810| mu810_12(Base) = ^IndirectMayWriteSideEffect[-1] : &:r810_3
# 810| mu810_11(Base) = ^IndirectMayWriteSideEffect[-1] : &:r810_3
# 810| v810_12(void) = ^BufferReadSideEffect[0] : &:r810_8, ~m?
# 810| r810_13(glval<Base>) = Convert : r810_3
# 810| r810_14(Base &) = CopyValue : r810_13
# 810| r810_15(Base &) = Call[operator=] : func:r810_2, this:r810_1, 0:r810_14
@@ -4630,8 +4630,8 @@ ir.cpp:
# 823| r823_9(Base &) = CopyValue : r823_8
# 823| v823_10(void) = Call[Base] : func:r823_5, this:r823_3, 0:r823_9
# 823| mu823_11(unknown) = ^CallSideEffect : ~m?
# 823| v823_12(void) = ^BufferReadSideEffect[0] : &:r823_9, ~m?
# 823| mu823_13(Base) = ^IndirectMayWriteSideEffect[-1] : &:r823_3
# 823| mu823_12(Base) = ^IndirectMayWriteSideEffect[-1] : &:r823_3
# 823| v823_13(void) = ^BufferReadSideEffect[0] : &:r823_9, ~m?
# 823| r823_14(glval<Base>) = Convert : r823_3
# 823| r823_15(Base &) = CopyValue : r823_14
# 823| r823_16(Base &) = Call[operator=] : func:r823_2, this:r823_1, 0:r823_15
@@ -4651,8 +4651,8 @@ ir.cpp:
# 824| r824_9(Base &) = CopyValue : r824_8
# 824| v824_10(void) = Call[Base] : func:r824_5, this:r824_3, 0:r824_9
# 824| mu824_11(unknown) = ^CallSideEffect : ~m?
# 824| v824_12(void) = ^BufferReadSideEffect[0] : &:r824_9, ~m?
# 824| mu824_13(Base) = ^IndirectMayWriteSideEffect[-1] : &:r824_3
# 824| mu824_12(Base) = ^IndirectMayWriteSideEffect[-1] : &:r824_3
# 824| v824_13(void) = ^BufferReadSideEffect[0] : &:r824_9, ~m?
# 824| r824_14(glval<Base>) = Convert : r824_3
# 824| r824_15(Base &) = CopyValue : r824_14
# 824| r824_16(Base &) = Call[operator=] : func:r824_2, this:r824_1, 0:r824_15
@@ -4876,8 +4876,8 @@ ir.cpp:
# 868| r868_3(char *) = Convert : r868_2
# 868| v868_4(void) = Call[String] : func:r868_1, this:mu867_5, 0:r868_3
# 868| mu868_5(unknown) = ^CallSideEffect : ~m?
# 868| v868_6(void) = ^BufferReadSideEffect[0] : &:r868_3, ~m?
# 868| mu868_7(String) = ^IndirectMayWriteSideEffect[-1] : &:mu867_5
# 868| mu868_6(String) = ^IndirectMayWriteSideEffect[-1] : &:mu867_5
# 868| v868_7(void) = ^BufferReadSideEffect[0] : &:r868_3, ~m?
# 869| v869_1(void) = NoOp :
# 867| v867_8(void) = ReturnIndirection[#this] : &:r867_6, ~m?
# 867| v867_9(void) = ReturnVoid :
@@ -5177,8 +5177,8 @@ ir.cpp:
# 954| r954_10(char *) = Convert : r954_9
# 954| v954_11(void) = Call[String] : func:r954_8, this:r954_7, 0:r954_10
# 954| mu954_12(unknown) = ^CallSideEffect : ~m?
# 954| v954_13(void) = ^BufferReadSideEffect[0] : &:r954_10, ~m?
# 954| mu954_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r954_7
# 954| mu954_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r954_7
# 954| v954_14(void) = ^BufferReadSideEffect[0] : &:r954_10, ~m?
# 955| r955_1(glval<unknown>) = FunctionAddress[operator new] :
# 955| r955_2(unsigned long) = Constant[256] :
# 955| r955_3(align_val_t) = Constant[128] :
@@ -6423,8 +6423,8 @@ ir.cpp:
# 1149| r1149_15(char *) = Convert : r1149_14
# 1149| v1149_16(void) = Call[String] : func:r1149_13, this:r1149_11, 0:r1149_15
# 1149| mu1149_17(unknown) = ^CallSideEffect : ~m?
# 1149| v1149_18(void) = ^BufferReadSideEffect[0] : &:r1149_15, ~m?
# 1149| mu1149_19(String) = ^IndirectMayWriteSideEffect[-1] : &:r1149_11
# 1149| mu1149_18(String) = ^IndirectMayWriteSideEffect[-1] : &:r1149_11
# 1149| v1149_19(void) = ^BufferReadSideEffect[0] : &:r1149_15, ~m?
# 1149| v1149_20(void) = ThrowValue : &:r1149_11, ~m?
#-----| Exception -> Block 9
@@ -6451,8 +6451,8 @@ ir.cpp:
# 1154| r1154_5(char *) = Load[s] : &:r1154_4, ~m?
# 1154| v1154_6(void) = Call[String] : func:r1154_3, this:r1154_1, 0:r1154_5
# 1154| mu1154_7(unknown) = ^CallSideEffect : ~m?
# 1154| v1154_8(void) = ^BufferReadSideEffect[0] : &:r1154_5, ~m?
# 1154| mu1154_9(String) = ^IndirectMayWriteSideEffect[-1] : &:r1154_1
# 1154| mu1154_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r1154_1
# 1154| v1154_9(void) = ^BufferReadSideEffect[0] : &:r1154_5, ~m?
# 1154| v1154_10(void) = ThrowValue : &:r1154_1, ~m?
#-----| Exception -> Block 2
@@ -6577,8 +6577,8 @@ ir.cpp:
# 1179| r1179_5(char *) = Convert : r1179_4
# 1179| v1179_6(void) = Call[String] : func:r1179_3, this:r1179_1, 0:r1179_5
# 1179| mu1179_7(unknown) = ^CallSideEffect : ~m?
# 1179| v1179_8(void) = ^BufferReadSideEffect[0] : &:r1179_5, ~m?
# 1179| mu1179_9(String) = ^IndirectMayWriteSideEffect[-1] : &:r1179_1
# 1179| mu1179_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r1179_1
# 1179| v1179_9(void) = ^BufferReadSideEffect[0] : &:r1179_5, ~m?
# 1178| r1178_4(glval<String>) = VariableAddress[#return] :
# 1178| v1178_5(void) = ReturnValue : &:r1178_4, ~m?
# 1178| v1178_6(void) = AliasedUse : ~m?
@@ -6832,8 +6832,8 @@ ir.cpp:
# 1242| r1242_7(char *) = Convert : r1242_6
# 1242| v1242_8(void) = Call[String] : func:r1242_5, this:r1242_4, 0:r1242_7
# 1242| mu1242_9(unknown) = ^CallSideEffect : ~m?
# 1242| v1242_10(void) = ^BufferReadSideEffect[0] : &:r1242_7, ~m?
# 1242| mu1242_11(String) = ^IndirectMayWriteSideEffect[-1] : &:r1242_4
# 1242| mu1242_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r1242_4
# 1242| v1242_11(void) = ^BufferReadSideEffect[0] : &:r1242_7, ~m?
# 1242| r1242_12(bool) = Constant[1] :
# 1242| mu1242_13(bool) = Store[b#init] : &:r1242_1, r1242_12
#-----| Goto -> Block 4
@@ -6852,8 +6852,8 @@ ir.cpp:
# 1243| r1243_7(char *) = Load[dynamic] : &:r1243_6, ~m?
# 1243| v1243_8(void) = Call[String] : func:r1243_5, this:r1243_4, 0:r1243_7
# 1243| mu1243_9(unknown) = ^CallSideEffect : ~m?
# 1243| v1243_10(void) = ^BufferReadSideEffect[0] : &:r1243_7, ~m?
# 1243| mu1243_11(String) = ^IndirectMayWriteSideEffect[-1] : &:r1243_4
# 1243| mu1243_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r1243_4
# 1243| v1243_11(void) = ^BufferReadSideEffect[0] : &:r1243_7, ~m?
# 1243| r1243_12(bool) = Constant[1] :
# 1243| mu1243_13(bool) = Store[c#init] : &:r1243_1, r1243_12
#-----| Goto -> Block 6
@@ -7481,8 +7481,8 @@ ir.cpp:
# 1370| r1370_6(char *) = Convert : r1370_5
# 1370| v1370_7(void) = Call[String] : func:r1370_4, this:r1370_2, 0:r1370_6
# 1370| mu1370_8(unknown) = ^CallSideEffect : ~m?
# 1370| v1370_9(void) = ^BufferReadSideEffect[0] : &:r1370_6, ~m?
# 1370| mu1370_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r1370_2
# 1370| mu1370_9(String) = ^IndirectMayWriteSideEffect[-1] : &:r1370_2
# 1370| v1370_10(void) = ^BufferReadSideEffect[0] : &:r1370_6, ~m?
# 1370| r1370_11(String &) = CopyValue : r1370_2
# 1370| v1370_12(void) = Call[acceptRef] : func:r1370_1, 0:r1370_11
# 1370| mu1370_13(unknown) = ^CallSideEffect : ~m?
@@ -7496,8 +7496,8 @@ ir.cpp:
# 1371| r1371_7(String &) = CopyValue : r1371_6
# 1371| v1371_8(void) = Call[String] : func:r1371_4, this:r1371_2, 0:r1371_7
# 1371| mu1371_9(unknown) = ^CallSideEffect : ~m?
# 1371| v1371_10(void) = ^BufferReadSideEffect[0] : &:r1371_7, ~m?
# 1371| mu1371_11(String) = ^IndirectMayWriteSideEffect[-1] : &:r1371_2
# 1371| mu1371_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r1371_2
# 1371| v1371_11(void) = ^BufferReadSideEffect[0] : &:r1371_7, ~m?
# 1371| r1371_12(String) = Load[#temp1371:17] : &:r1371_2, ~m?
# 1371| v1371_13(void) = Call[acceptValue] : func:r1371_1, 0:r1371_12
# 1371| mu1371_14(unknown) = ^CallSideEffect : ~m?
@@ -7509,8 +7509,8 @@ ir.cpp:
# 1372| r1372_6(char *) = Convert : r1372_5
# 1372| v1372_7(void) = Call[String] : func:r1372_4, this:r1372_2, 0:r1372_6
# 1372| mu1372_8(unknown) = ^CallSideEffect : ~m?
# 1372| v1372_9(void) = ^BufferReadSideEffect[0] : &:r1372_6, ~m?
# 1372| mu1372_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r1372_2
# 1372| mu1372_9(String) = ^IndirectMayWriteSideEffect[-1] : &:r1372_2
# 1372| v1372_10(void) = ^BufferReadSideEffect[0] : &:r1372_6, ~m?
# 1372| r1372_11(String) = Load[#temp1372:25] : &:r1372_2, ~m?
# 1372| v1372_12(void) = Call[acceptValue] : func:r1372_1, 0:r1372_11
# 1372| mu1372_13(unknown) = ^CallSideEffect : ~m?
@@ -7652,8 +7652,8 @@ ir.cpp:
# 1396| r1396_7(copy_constructor &) = CopyValue : r1396_6
# 1396| v1396_8(void) = Call[copy_constructor] : func:r1396_4, this:r1396_2, 0:r1396_7
# 1396| mu1396_9(unknown) = ^CallSideEffect : ~m?
# 1396| v1396_10(void) = ^BufferReadSideEffect[0] : &:r1396_7, ~m?
# 1396| mu1396_11(copy_constructor) = ^IndirectMayWriteSideEffect[-1] : &:r1396_2
# 1396| mu1396_10(copy_constructor) = ^IndirectMayWriteSideEffect[-1] : &:r1396_2
# 1396| v1396_11(void) = ^BufferReadSideEffect[0] : &:r1396_7, ~m?
# 1396| r1396_12(copy_constructor) = Load[#temp1396:17] : &:r1396_2, ~m?
# 1396| v1396_13(void) = Call[acceptValue] : func:r1396_1, 0:r1396_12
# 1396| mu1396_14(unknown) = ^CallSideEffect : ~m?
@@ -7967,8 +7967,8 @@ smart_ptr.cpp:
# 19| r19_7(shared_ptr<float> &) = CopyValue : r19_6
# 19| v19_8(void) = Call[shared_ptr] : func:r19_4, this:r19_2, 0:r19_7
# 19| mu19_9(unknown) = ^CallSideEffect : ~m?
# 19| v19_10(void) = ^IndirectReadSideEffect[0] : &:r19_7, ~m?
# 19| mu19_11(shared_ptr<float>) = ^IndirectMustWriteSideEffect[-1] : &:r19_2
# 19| mu19_10(shared_ptr<float>) = ^IndirectMustWriteSideEffect[-1] : &:r19_2
# 19| v19_11(void) = ^IndirectReadSideEffect[0] : &:r19_7, ~m?
# 19| r19_12(shared_ptr<float>) = Load[#temp19:20] : &:r19_2, ~m?
# 19| v19_13(void) = Call[shared_ptr_arg] : func:r19_1, 0:r19_12
# 19| mu19_14(unknown) = ^CallSideEffect : ~m?
@@ -7996,8 +7996,8 @@ smart_ptr.cpp:
# 31| r31_7(shared_ptr<const int> &) = CopyValue : r31_6
# 31| v31_8(void) = Call[shared_ptr] : func:r31_4, this:r31_2, 0:r31_7
# 31| mu31_9(unknown) = ^CallSideEffect : ~m?
# 31| v31_10(void) = ^IndirectReadSideEffect[0] : &:r31_7, ~m?
# 31| mu31_11(shared_ptr<const int>) = ^IndirectMustWriteSideEffect[-1] : &:r31_2
# 31| mu31_10(shared_ptr<const int>) = ^IndirectMustWriteSideEffect[-1] : &:r31_2
# 31| v31_11(void) = ^IndirectReadSideEffect[0] : &:r31_7, ~m?
# 31| r31_12(shared_ptr<const int>) = Load[#temp31:26] : &:r31_2, ~m?
# 31| v31_13(void) = Call[shared_ptr_const_int] : func:r31_1, 0:r31_12
# 31| mu31_14(unknown) = ^CallSideEffect : ~m?
@@ -8013,8 +8013,8 @@ smart_ptr.cpp:
# 35| r35_7(shared_ptr<int *const> &) = CopyValue : r35_6
# 35| v35_8(void) = Call[shared_ptr] : func:r35_4, this:r35_2, 0:r35_7
# 35| mu35_9(unknown) = ^CallSideEffect : ~m?
# 35| v35_10(void) = ^IndirectReadSideEffect[0] : &:r35_7, ~m?
# 35| mu35_11(shared_ptr<int *const>) = ^IndirectMustWriteSideEffect[-1] : &:r35_2
# 35| mu35_10(shared_ptr<int *const>) = ^IndirectMustWriteSideEffect[-1] : &:r35_2
# 35| v35_11(void) = ^IndirectReadSideEffect[0] : &:r35_7, ~m?
# 35| r35_12(shared_ptr<int *const>) = Load[#temp35:30] : &:r35_2, ~m?
# 35| v35_13(void) = Call[shared_ptr_const_int_ptr] : func:r35_1, 0:r35_12
# 35| mu35_14(unknown) = ^CallSideEffect : ~m?
@@ -8031,8 +8031,8 @@ smart_ptr.cpp:
# 39| r39_7(shared_ptr<shared_ptr<const int>> &) = CopyValue : r39_6
# 39| v39_8(void) = Call[shared_ptr] : func:r39_4, this:r39_2, 0:r39_7
# 39| mu39_9(unknown) = ^CallSideEffect : ~m?
# 39| v39_10(void) = ^IndirectReadSideEffect[0] : &:r39_7, ~m?
# 39| mu39_11(shared_ptr<shared_ptr<const int>>) = ^IndirectMustWriteSideEffect[-1] : &:r39_2
# 39| mu39_10(shared_ptr<shared_ptr<const int>>) = ^IndirectMustWriteSideEffect[-1] : &:r39_2
# 39| v39_11(void) = ^IndirectReadSideEffect[0] : &:r39_7, ~m?
# 39| r39_12(shared_ptr<shared_ptr<const int>>) = Load[#temp39:37] : &:r39_2, ~m?
# 39| v39_13(void) = Call[shared_ptr_shared_ptr_const_int] : func:r39_1, 0:r39_12
# 39| mu39_14(unknown) = ^CallSideEffect : ~m?
@@ -8049,8 +8049,8 @@ smart_ptr.cpp:
# 43| r43_7(shared_ptr<const shared_ptr<int>> &) = CopyValue : r43_6
# 43| v43_8(void) = Call[shared_ptr] : func:r43_4, this:r43_2, 0:r43_7
# 43| mu43_9(unknown) = ^CallSideEffect : ~m?
# 43| v43_10(void) = ^IndirectReadSideEffect[0] : &:r43_7, ~m?
# 43| mu43_11(shared_ptr<const shared_ptr<int>>) = ^IndirectMustWriteSideEffect[-1] : &:r43_2
# 43| mu43_10(shared_ptr<const shared_ptr<int>>) = ^IndirectMustWriteSideEffect[-1] : &:r43_2
# 43| v43_11(void) = ^IndirectReadSideEffect[0] : &:r43_7, ~m?
# 43| r43_12(shared_ptr<const shared_ptr<int>>) = Load[#temp43:37] : &:r43_2, ~m?
# 43| v43_13(void) = Call[shared_ptr_const_shared_ptr_int] : func:r43_1, 0:r43_12
# 43| mu43_14(unknown) = ^CallSideEffect : ~m?
@@ -8067,8 +8067,8 @@ smart_ptr.cpp:
# 47| r47_7(shared_ptr<const shared_ptr<const int>> &) = CopyValue : r47_6
# 47| v47_8(void) = Call[shared_ptr] : func:r47_4, this:r47_2, 0:r47_7
# 47| mu47_9(unknown) = ^CallSideEffect : ~m?
# 47| v47_10(void) = ^IndirectReadSideEffect[0] : &:r47_7, ~m?
# 47| mu47_11(shared_ptr<const shared_ptr<const int>>) = ^IndirectMustWriteSideEffect[-1] : &:r47_2
# 47| mu47_10(shared_ptr<const shared_ptr<const int>>) = ^IndirectMustWriteSideEffect[-1] : &:r47_2
# 47| v47_11(void) = ^IndirectReadSideEffect[0] : &:r47_7, ~m?
# 47| r47_12(shared_ptr<const shared_ptr<const int>>) = Load[#temp47:43] : &:r47_2, ~m?
# 47| v47_13(void) = Call[shared_ptr_const_shared_ptr_const_int] : func:r47_1, 0:r47_12
# 47| mu47_14(unknown) = ^CallSideEffect : ~m?

View File

@@ -1398,13 +1398,13 @@ ssa.cpp:
# 294| v294_25(void) = Call[A] : func:r294_9, this:r294_8, 0:r294_16
# 294| m294_26(unknown) = ^CallSideEffect : ~m294_22
# 294| m294_27(unknown) = Chi : total:m294_22, partial:m294_26
# 294| v294_28(void) = ^BufferReadSideEffect[0] : &:r294_16, ~m294_24
# 294| m294_29(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_8
# 294| m294_30(unknown) = Chi : total:m294_7, partial:m294_29
# 294| m294_28(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_8
# 294| m294_29(unknown) = Chi : total:m294_7, partial:m294_28
# 294| v294_30(void) = ^BufferReadSideEffect[0] : &:r294_16, ~m294_24
# 294| m294_31(unknown) = ^BufferMayWriteSideEffect[0] : &:r294_16
# 294| m294_32(unknown) = Chi : total:m294_24, partial:m294_31
# 294| r294_33(glval<int>) = FieldAddress[i] : r294_8
# 294| r294_34(int) = Load[?] : &:r294_33, ~m294_30
# 294| r294_34(int) = Load[?] : &:r294_33, ~m294_29
# 294| m294_35(int) = Store[j] : &:r294_1, r294_34
# 295| r295_1(glval<A *>) = VariableAddress[a] :
# 295| r295_2(glval<unknown>) = FunctionAddress[operator new] :

View File

@@ -1392,13 +1392,13 @@ ssa.cpp:
# 294| v294_25(void) = Call[A] : func:r294_9, this:r294_8, 0:r294_16
# 294| m294_26(unknown) = ^CallSideEffect : ~m294_22
# 294| m294_27(unknown) = Chi : total:m294_22, partial:m294_26
# 294| v294_28(void) = ^BufferReadSideEffect[0] : &:r294_16, ~m294_24
# 294| m294_29(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_8
# 294| m294_30(unknown) = Chi : total:m294_7, partial:m294_29
# 294| m294_28(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_8
# 294| m294_29(unknown) = Chi : total:m294_7, partial:m294_28
# 294| v294_30(void) = ^BufferReadSideEffect[0] : &:r294_16, ~m294_24
# 294| m294_31(unknown) = ^BufferMayWriteSideEffect[0] : &:r294_16
# 294| m294_32(unknown) = Chi : total:m294_24, partial:m294_31
# 294| r294_33(glval<int>) = FieldAddress[i] : r294_8
# 294| r294_34(int) = Load[?] : &:r294_33, ~m294_30
# 294| r294_34(int) = Load[?] : &:r294_33, ~m294_29
# 294| m294_35(int) = Store[j] : &:r294_1, r294_34
# 295| r295_1(glval<A *>) = VariableAddress[a] :
# 295| r295_2(glval<unknown>) = FunctionAddress[operator new] :

View File

@@ -1285,8 +1285,8 @@ ssa.cpp:
# 294| mu294_20(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_14
# 294| v294_21(void) = Call[A] : func:r294_8, this:r294_7, 0:r294_14
# 294| mu294_22(unknown) = ^CallSideEffect : ~m?
# 294| v294_23(void) = ^BufferReadSideEffect[0] : &:r294_14, ~m?
# 294| mu294_24(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_7
# 294| mu294_23(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_7
# 294| v294_24(void) = ^BufferReadSideEffect[0] : &:r294_14, ~m?
# 294| mu294_25(unknown) = ^BufferMayWriteSideEffect[0] : &:r294_14
# 294| r294_26(glval<int>) = FieldAddress[i] : r294_7
# 294| r294_27(int) = Load[?] : &:r294_26, ~m?

View File

@@ -1285,8 +1285,8 @@ ssa.cpp:
# 294| mu294_20(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_14
# 294| v294_21(void) = Call[A] : func:r294_8, this:r294_7, 0:r294_14
# 294| mu294_22(unknown) = ^CallSideEffect : ~m?
# 294| v294_23(void) = ^BufferReadSideEffect[0] : &:r294_14, ~m?
# 294| mu294_24(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_7
# 294| mu294_23(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_7
# 294| v294_24(void) = ^BufferReadSideEffect[0] : &:r294_14, ~m?
# 294| mu294_25(unknown) = ^BufferMayWriteSideEffect[0] : &:r294_14
# 294| r294_26(glval<int>) = FieldAddress[i] : r294_7
# 294| r294_27(int) = Load[?] : &:r294_26, ~m?

View File

@@ -11,7 +11,6 @@
| difference::Base | can | does NOT | have implicit copy assignment |
| difference::OnlyAssign | can | does | have implicit copy assignment |
| difference::OnlyCtor | can NOT | does NOT | have implicit copy assignment |
| instantiated_explicit_ctor::Wrapper<int> | can | does | have implicit copy assignment |
| moves::MoveAssign | can NOT | does NOT | have implicit copy assignment |
| moves::MoveCtor | can NOT | does NOT | have implicit copy assignment |
| private_cc::C | can | does NOT | have implicit copy assignment |

View File

@@ -131,21 +131,3 @@ namespace difference {
class OnlyAssign : Base {
};
}
namespace instantiated_explicit_ctor {
template<class T>
class Wrapper {
public:
Wrapper(Wrapper<T> &other) {
m_t = other.m_t;
}
Wrapper() {
m_t = 0;
}
private:
T m_t;
};
Wrapper<int> wrapped_int;
}

View File

@@ -11,7 +11,6 @@
| difference::Base | can | does NOT | have implicit copy constructor |
| difference::OnlyAssign | can NOT | does NOT | have implicit copy constructor |
| difference::OnlyCtor | can | does | have implicit copy constructor |
| instantiated_explicit_ctor::Wrapper<int> | can | does NOT | have implicit copy constructor |
| moves::MoveAssign | can NOT | does NOT | have implicit copy constructor |
| moves::MoveCtor | can NOT | does NOT | have implicit copy constructor |
| private_cc::C | can | does NOT | have implicit copy constructor |

View File

@@ -86,9 +86,5 @@
| copy.cpp:131:9:131:9 | OnlyAssign | deleted | |
| copy.cpp:131:9:131:9 | operator= | | |
| copy.cpp:131:9:131:9 | operator= | | |
| copy.cpp:137:9:137:9 | operator= | | |
| copy.cpp:139:5:139:11 | Wrapper | | |
| copy.cpp:143:5:143:5 | Wrapper | | |
| copy.cpp:143:5:143:11 | Wrapper | | |
| file://:0:0:0:0 | operator= | | |
| file://:0:0:0:0 | operator= | | |

View File

@@ -1,4 +1,4 @@
// semmle-extractor-options: -std=c++17
void f(void) {
if (1) {
int i;
@@ -30,12 +30,3 @@ void nestedRangeBasedFor() {
for (auto y : ys) // GOOD
x = y = 0;
}
void structuredBinding() {
int xs[1] = {1};
auto [x] = xs;
{
auto [x] = xs; // BAD [NOT DETECTED]
auto [y] = xs; // GOOD
}
}

View File

@@ -117,8 +117,12 @@ struct HasVPV {
}
};
// NOT OK: the relevant copy constructor of ProtectedVolatile is
// accessible, so our class will get a generated copy constructor.
// FALSE NEGATIVE: the relevant copy constructor of ProtectedVolatile is
// accessible, so our class will get a generated copy constructor. Our query
// thinks the copy constructor is inaccessible because it picks up the other
// copy constructor. To fix this, our library should be changed to distinguish
// between copy constructors and resolve overloading properly instead of
// assuming that there is at most one.
struct HasPV {
ProtectedVolatile pv;
HasPV& operator=(const HasPV& that) {

View File

@@ -1,6 +1,6 @@
| RuleOfTwo.cpp:4:3:4:17 | CopyButNoAssign | No matching copy assignment operator in class CopyButNoAssign. It is good practice to match a copy constructor with a copy assignment operator. |
| RuleOfTwo.cpp:10:20:10:28 | operator= | No matching copy constructor in class AssignButNoCopy. It is good practice to match a copy assignment operator with a copy constructor. |
| RuleOfTwo.cpp:81:18:81:26 | operator= | No matching copy constructor in class MyClassFriend. It is good practice to match a copy assignment operator with a copy constructor. |
| RuleOfTwo.cpp:140:3:140:20 | IsAProtectedAssign | No matching copy assignment operator in class IsAProtectedAssign. It is good practice to match a copy constructor with a copy assignment operator. |
| RuleOfTwo.cpp:163:19:163:27 | operator= | No matching copy constructor in class IsAProtectedCC. It is good practice to match a copy assignment operator with a copy constructor. |
| RuleOfTwo.cpp:308:5:308:8 | R1_C | No matching copy assignment operator in class R1_C. It is good practice to match a copy constructor with a copy assignment operator. |
| RuleOfTwo.cpp:144:3:144:20 | IsAProtectedAssign | No matching copy assignment operator in class IsAProtectedAssign. It is good practice to match a copy constructor with a copy assignment operator. |
| RuleOfTwo.cpp:167:19:167:27 | operator= | No matching copy constructor in class IsAProtectedCC. It is good practice to match a copy assignment operator with a copy constructor. |
| RuleOfTwo.cpp:312:5:312:8 | R1_C | No matching copy assignment operator in class R1_C. It is good practice to match a copy constructor with a copy assignment operator. |

View File

@@ -1,231 +1,8 @@
edges
| test.cpp:17:9:17:11 | & ... | test.cpp:17:9:17:11 | StoreValue |
| test.cpp:17:10:17:11 | Unary | test.cpp:17:9:17:11 | & ... |
| test.cpp:17:10:17:11 | mc | test.cpp:17:10:17:11 | Unary |
| test.cpp:23:17:23:19 | & ... | test.cpp:23:17:23:19 | StoreValue |
| test.cpp:23:17:23:19 | Store | test.cpp:25:9:25:11 | Load |
| test.cpp:23:17:23:19 | StoreValue | test.cpp:23:17:23:19 | Store |
| test.cpp:23:18:23:19 | Unary | test.cpp:23:17:23:19 | & ... |
| test.cpp:23:18:23:19 | mc | test.cpp:23:18:23:19 | Unary |
| test.cpp:25:9:25:11 | Load | test.cpp:25:9:25:11 | ptr |
| test.cpp:25:9:25:11 | ptr | test.cpp:25:9:25:11 | StoreValue |
| test.cpp:39:17:39:18 | (reference to) | test.cpp:39:17:39:18 | StoreValue |
| test.cpp:39:17:39:18 | Store | test.cpp:41:10:41:12 | Load |
| test.cpp:39:17:39:18 | StoreValue | test.cpp:39:17:39:18 | Store |
| test.cpp:39:17:39:18 | Unary | test.cpp:39:17:39:18 | (reference to) |
| test.cpp:39:17:39:18 | mc | test.cpp:39:17:39:18 | Unary |
| test.cpp:41:9:41:12 | & ... | test.cpp:41:9:41:12 | StoreValue |
| test.cpp:41:10:41:12 | (reference dereference) | test.cpp:41:10:41:12 | Unary |
| test.cpp:41:10:41:12 | Load | test.cpp:41:10:41:12 | ref |
| test.cpp:41:10:41:12 | Unary | test.cpp:41:9:41:12 | & ... |
| test.cpp:41:10:41:12 | Unary | test.cpp:41:10:41:12 | (reference dereference) |
| test.cpp:41:10:41:12 | ref | test.cpp:41:10:41:12 | Unary |
| test.cpp:47:9:47:10 | (reference to) | test.cpp:47:9:47:10 | StoreValue |
| test.cpp:47:9:47:10 | Unary | test.cpp:47:9:47:10 | (reference to) |
| test.cpp:47:9:47:10 | mc | test.cpp:47:9:47:10 | Unary |
| test.cpp:54:9:54:15 | & ... | test.cpp:54:9:54:15 | StoreValue |
| test.cpp:54:11:54:12 | Unary | test.cpp:54:14:54:14 | a |
| test.cpp:54:11:54:12 | mc | test.cpp:54:11:54:12 | Unary |
| test.cpp:54:14:54:14 | Unary | test.cpp:54:9:54:15 | & ... |
| test.cpp:54:14:54:14 | a | test.cpp:54:14:54:14 | Unary |
| test.cpp:89:3:89:11 | Store | test.cpp:92:9:92:11 | Load |
| test.cpp:89:9:89:11 | & ... | test.cpp:89:9:89:11 | StoreValue |
| test.cpp:89:9:89:11 | StoreValue | test.cpp:89:3:89:11 | Store |
| test.cpp:89:10:89:11 | Unary | test.cpp:89:9:89:11 | & ... |
| test.cpp:89:10:89:11 | mc | test.cpp:89:10:89:11 | Unary |
| test.cpp:92:9:92:11 | Load | test.cpp:92:9:92:11 | ptr |
| test.cpp:92:9:92:11 | ptr | test.cpp:92:9:92:11 | StoreValue |
| test.cpp:112:9:112:11 | Unary | test.cpp:112:9:112:11 | array to pointer conversion |
| test.cpp:112:9:112:11 | arr | test.cpp:112:9:112:11 | Unary |
| test.cpp:112:9:112:11 | array to pointer conversion | test.cpp:112:9:112:11 | StoreValue |
| test.cpp:119:9:119:18 | & ... | test.cpp:119:9:119:18 | StoreValue |
| test.cpp:119:11:119:13 | Left | test.cpp:119:11:119:17 | access to array |
| test.cpp:119:11:119:13 | Unary | test.cpp:119:11:119:13 | array to pointer conversion |
| test.cpp:119:11:119:13 | arr | test.cpp:119:11:119:13 | Unary |
| test.cpp:119:11:119:13 | array to pointer conversion | test.cpp:119:11:119:13 | Left |
| test.cpp:119:11:119:17 | Unary | test.cpp:119:9:119:18 | & ... |
| test.cpp:119:11:119:17 | access to array | test.cpp:119:11:119:17 | Unary |
| test.cpp:134:2:134:14 | Store | test.cpp:135:2:135:4 | Load |
| test.cpp:134:8:134:10 | Left | test.cpp:134:8:134:14 | ... + ... |
| test.cpp:134:8:134:10 | Unary | test.cpp:134:8:134:10 | array to pointer conversion |
| test.cpp:134:8:134:10 | arr | test.cpp:134:8:134:10 | Unary |
| test.cpp:134:8:134:10 | array to pointer conversion | test.cpp:134:8:134:10 | Left |
| test.cpp:134:8:134:14 | ... + ... | test.cpp:134:8:134:14 | StoreValue |
| test.cpp:134:8:134:14 | StoreValue | test.cpp:134:2:134:14 | Store |
| test.cpp:135:2:135:4 | Left | test.cpp:135:2:135:6 | PointerAdd |
| test.cpp:135:2:135:4 | Load | test.cpp:135:2:135:4 | ptr |
| test.cpp:135:2:135:4 | ptr | test.cpp:135:2:135:4 | Left |
| test.cpp:135:2:135:6 | PointerAdd | test.cpp:135:2:135:6 | StoreValue |
| test.cpp:135:2:135:6 | Store | test.cpp:137:9:137:11 | Load |
| test.cpp:135:2:135:6 | StoreValue | test.cpp:135:2:135:6 | Store |
| test.cpp:137:9:137:11 | Load | test.cpp:137:9:137:11 | ptr |
| test.cpp:137:9:137:11 | ptr | test.cpp:137:9:137:11 | StoreValue |
| test.cpp:170:26:170:41 | (void *)... | test.cpp:170:26:170:41 | StoreValue |
| test.cpp:170:26:170:41 | Store | test.cpp:171:10:171:23 | Load |
| test.cpp:170:26:170:41 | StoreValue | test.cpp:170:26:170:41 | Store |
| test.cpp:170:34:170:41 | & ... | test.cpp:170:34:170:41 | Unary |
| test.cpp:170:34:170:41 | Unary | test.cpp:170:26:170:41 | (void *)... |
| test.cpp:170:35:170:41 | Unary | test.cpp:170:34:170:41 | & ... |
| test.cpp:170:35:170:41 | myLocal | test.cpp:170:35:170:41 | Unary |
| test.cpp:171:10:171:23 | Load | test.cpp:171:10:171:23 | pointerToLocal |
| test.cpp:171:10:171:23 | pointerToLocal | test.cpp:171:10:171:23 | StoreValue |
| test.cpp:176:25:176:34 | Store | test.cpp:177:10:177:23 | Load |
| test.cpp:176:25:176:34 | StoreValue | test.cpp:176:25:176:34 | Store |
| test.cpp:176:25:176:34 | Unary | test.cpp:176:25:176:34 | array to pointer conversion |
| test.cpp:176:25:176:34 | array to pointer conversion | test.cpp:176:25:176:34 | StoreValue |
| test.cpp:176:25:176:34 | localArray | test.cpp:176:25:176:34 | Unary |
| test.cpp:177:10:177:23 | (void *)... | test.cpp:177:10:177:23 | StoreValue |
| test.cpp:177:10:177:23 | Load | test.cpp:177:10:177:23 | pointerToLocal |
| test.cpp:177:10:177:23 | Unary | test.cpp:177:10:177:23 | (void *)... |
| test.cpp:177:10:177:23 | pointerToLocal | test.cpp:177:10:177:23 | Unary |
| test.cpp:182:21:182:27 | (reference to) | test.cpp:182:21:182:27 | StoreValue |
| test.cpp:182:21:182:27 | Store | test.cpp:183:10:183:19 | Load |
| test.cpp:182:21:182:27 | StoreValue | test.cpp:182:21:182:27 | Store |
| test.cpp:182:21:182:27 | Unary | test.cpp:182:21:182:27 | (reference to) |
| test.cpp:182:21:182:27 | myLocal | test.cpp:182:21:182:27 | Unary |
| test.cpp:183:10:183:19 | (reference dereference) | test.cpp:183:10:183:19 | Unary |
| test.cpp:183:10:183:19 | (reference to) | test.cpp:183:10:183:19 | StoreValue |
| test.cpp:183:10:183:19 | Load | test.cpp:183:10:183:19 | refToLocal |
| test.cpp:183:10:183:19 | Unary | test.cpp:183:10:183:19 | (reference dereference) |
| test.cpp:183:10:183:19 | Unary | test.cpp:183:10:183:19 | (reference to) |
| test.cpp:183:10:183:19 | refToLocal | test.cpp:183:10:183:19 | Unary |
| test.cpp:189:16:189:16 | (reference to) | test.cpp:189:16:189:16 | StoreValue |
| test.cpp:189:16:189:16 | Store | test.cpp:190:10:190:13 | Load |
| test.cpp:189:16:189:16 | StoreValue | test.cpp:189:16:189:16 | Store |
| test.cpp:189:16:189:16 | Unary | test.cpp:189:16:189:16 | (reference to) |
| test.cpp:189:16:189:16 | p | test.cpp:189:16:189:16 | Unary |
| test.cpp:190:10:190:13 | (reference dereference) | test.cpp:190:10:190:13 | Unary |
| test.cpp:190:10:190:13 | (reference to) | test.cpp:190:10:190:13 | StoreValue |
| test.cpp:190:10:190:13 | Load | test.cpp:190:10:190:13 | pRef |
| test.cpp:190:10:190:13 | Unary | test.cpp:190:10:190:13 | (reference dereference) |
| test.cpp:190:10:190:13 | Unary | test.cpp:190:10:190:13 | (reference to) |
| test.cpp:190:10:190:13 | pRef | test.cpp:190:10:190:13 | Unary |
nodes
| test.cpp:17:9:17:11 | & ... | semmle.label | & ... |
| test.cpp:17:9:17:11 | StoreValue | semmle.label | StoreValue |
| test.cpp:17:10:17:11 | Unary | semmle.label | Unary |
| test.cpp:17:10:17:11 | mc | semmle.label | mc |
| test.cpp:23:17:23:19 | & ... | semmle.label | & ... |
| test.cpp:23:17:23:19 | Store | semmle.label | Store |
| test.cpp:23:17:23:19 | StoreValue | semmle.label | StoreValue |
| test.cpp:23:18:23:19 | Unary | semmle.label | Unary |
| test.cpp:23:18:23:19 | mc | semmle.label | mc |
| test.cpp:25:9:25:11 | Load | semmle.label | Load |
| test.cpp:25:9:25:11 | StoreValue | semmle.label | StoreValue |
| test.cpp:25:9:25:11 | ptr | semmle.label | ptr |
| test.cpp:39:17:39:18 | (reference to) | semmle.label | (reference to) |
| test.cpp:39:17:39:18 | Store | semmle.label | Store |
| test.cpp:39:17:39:18 | StoreValue | semmle.label | StoreValue |
| test.cpp:39:17:39:18 | Unary | semmle.label | Unary |
| test.cpp:39:17:39:18 | mc | semmle.label | mc |
| test.cpp:41:9:41:12 | & ... | semmle.label | & ... |
| test.cpp:41:9:41:12 | StoreValue | semmle.label | StoreValue |
| test.cpp:41:10:41:12 | (reference dereference) | semmle.label | (reference dereference) |
| test.cpp:41:10:41:12 | Load | semmle.label | Load |
| test.cpp:41:10:41:12 | Unary | semmle.label | Unary |
| test.cpp:41:10:41:12 | Unary | semmle.label | Unary |
| test.cpp:41:10:41:12 | ref | semmle.label | ref |
| test.cpp:47:9:47:10 | (reference to) | semmle.label | (reference to) |
| test.cpp:47:9:47:10 | StoreValue | semmle.label | StoreValue |
| test.cpp:47:9:47:10 | Unary | semmle.label | Unary |
| test.cpp:47:9:47:10 | mc | semmle.label | mc |
| test.cpp:54:9:54:15 | & ... | semmle.label | & ... |
| test.cpp:54:9:54:15 | StoreValue | semmle.label | StoreValue |
| test.cpp:54:11:54:12 | Unary | semmle.label | Unary |
| test.cpp:54:11:54:12 | mc | semmle.label | mc |
| test.cpp:54:14:54:14 | Unary | semmle.label | Unary |
| test.cpp:54:14:54:14 | a | semmle.label | a |
| test.cpp:89:3:89:11 | Store | semmle.label | Store |
| test.cpp:89:9:89:11 | & ... | semmle.label | & ... |
| test.cpp:89:9:89:11 | StoreValue | semmle.label | StoreValue |
| test.cpp:89:10:89:11 | Unary | semmle.label | Unary |
| test.cpp:89:10:89:11 | mc | semmle.label | mc |
| test.cpp:92:9:92:11 | Load | semmle.label | Load |
| test.cpp:92:9:92:11 | StoreValue | semmle.label | StoreValue |
| test.cpp:92:9:92:11 | ptr | semmle.label | ptr |
| test.cpp:112:9:112:11 | StoreValue | semmle.label | StoreValue |
| test.cpp:112:9:112:11 | Unary | semmle.label | Unary |
| test.cpp:112:9:112:11 | arr | semmle.label | arr |
| test.cpp:112:9:112:11 | array to pointer conversion | semmle.label | array to pointer conversion |
| test.cpp:119:9:119:18 | & ... | semmle.label | & ... |
| test.cpp:119:9:119:18 | StoreValue | semmle.label | StoreValue |
| test.cpp:119:11:119:13 | Left | semmle.label | Left |
| test.cpp:119:11:119:13 | Unary | semmle.label | Unary |
| test.cpp:119:11:119:13 | arr | semmle.label | arr |
| test.cpp:119:11:119:13 | array to pointer conversion | semmle.label | array to pointer conversion |
| test.cpp:119:11:119:17 | Unary | semmle.label | Unary |
| test.cpp:119:11:119:17 | access to array | semmle.label | access to array |
| test.cpp:134:2:134:14 | Store | semmle.label | Store |
| test.cpp:134:8:134:10 | Left | semmle.label | Left |
| test.cpp:134:8:134:10 | Unary | semmle.label | Unary |
| test.cpp:134:8:134:10 | arr | semmle.label | arr |
| test.cpp:134:8:134:10 | array to pointer conversion | semmle.label | array to pointer conversion |
| test.cpp:134:8:134:14 | ... + ... | semmle.label | ... + ... |
| test.cpp:134:8:134:14 | StoreValue | semmle.label | StoreValue |
| test.cpp:135:2:135:4 | Left | semmle.label | Left |
| test.cpp:135:2:135:4 | Load | semmle.label | Load |
| test.cpp:135:2:135:4 | ptr | semmle.label | ptr |
| test.cpp:135:2:135:6 | PointerAdd | semmle.label | PointerAdd |
| test.cpp:135:2:135:6 | Store | semmle.label | Store |
| test.cpp:135:2:135:6 | StoreValue | semmle.label | StoreValue |
| test.cpp:137:9:137:11 | Load | semmle.label | Load |
| test.cpp:137:9:137:11 | StoreValue | semmle.label | StoreValue |
| test.cpp:137:9:137:11 | ptr | semmle.label | ptr |
| test.cpp:170:26:170:41 | (void *)... | semmle.label | (void *)... |
| test.cpp:170:26:170:41 | Store | semmle.label | Store |
| test.cpp:170:26:170:41 | StoreValue | semmle.label | StoreValue |
| test.cpp:170:34:170:41 | & ... | semmle.label | & ... |
| test.cpp:170:34:170:41 | Unary | semmle.label | Unary |
| test.cpp:170:35:170:41 | Unary | semmle.label | Unary |
| test.cpp:170:35:170:41 | myLocal | semmle.label | myLocal |
| test.cpp:171:10:171:23 | Load | semmle.label | Load |
| test.cpp:171:10:171:23 | StoreValue | semmle.label | StoreValue |
| test.cpp:171:10:171:23 | pointerToLocal | semmle.label | pointerToLocal |
| test.cpp:176:25:176:34 | Store | semmle.label | Store |
| test.cpp:176:25:176:34 | StoreValue | semmle.label | StoreValue |
| test.cpp:176:25:176:34 | Unary | semmle.label | Unary |
| test.cpp:176:25:176:34 | array to pointer conversion | semmle.label | array to pointer conversion |
| test.cpp:176:25:176:34 | localArray | semmle.label | localArray |
| test.cpp:177:10:177:23 | (void *)... | semmle.label | (void *)... |
| test.cpp:177:10:177:23 | Load | semmle.label | Load |
| test.cpp:177:10:177:23 | StoreValue | semmle.label | StoreValue |
| test.cpp:177:10:177:23 | Unary | semmle.label | Unary |
| test.cpp:177:10:177:23 | pointerToLocal | semmle.label | pointerToLocal |
| test.cpp:182:21:182:27 | (reference to) | semmle.label | (reference to) |
| test.cpp:182:21:182:27 | Store | semmle.label | Store |
| test.cpp:182:21:182:27 | StoreValue | semmle.label | StoreValue |
| test.cpp:182:21:182:27 | Unary | semmle.label | Unary |
| test.cpp:182:21:182:27 | myLocal | semmle.label | myLocal |
| test.cpp:183:10:183:19 | (reference dereference) | semmle.label | (reference dereference) |
| test.cpp:183:10:183:19 | (reference to) | semmle.label | (reference to) |
| test.cpp:183:10:183:19 | Load | semmle.label | Load |
| test.cpp:183:10:183:19 | StoreValue | semmle.label | StoreValue |
| test.cpp:183:10:183:19 | Unary | semmle.label | Unary |
| test.cpp:183:10:183:19 | Unary | semmle.label | Unary |
| test.cpp:183:10:183:19 | refToLocal | semmle.label | refToLocal |
| test.cpp:189:16:189:16 | (reference to) | semmle.label | (reference to) |
| test.cpp:189:16:189:16 | Store | semmle.label | Store |
| test.cpp:189:16:189:16 | StoreValue | semmle.label | StoreValue |
| test.cpp:189:16:189:16 | Unary | semmle.label | Unary |
| test.cpp:189:16:189:16 | p | semmle.label | p |
| test.cpp:190:10:190:13 | (reference dereference) | semmle.label | (reference dereference) |
| test.cpp:190:10:190:13 | (reference to) | semmle.label | (reference to) |
| test.cpp:190:10:190:13 | Load | semmle.label | Load |
| test.cpp:190:10:190:13 | StoreValue | semmle.label | StoreValue |
| test.cpp:190:10:190:13 | Unary | semmle.label | Unary |
| test.cpp:190:10:190:13 | Unary | semmle.label | Unary |
| test.cpp:190:10:190:13 | pRef | semmle.label | pRef |
#select
| test.cpp:17:9:17:11 | StoreValue | test.cpp:17:10:17:11 | mc | test.cpp:17:9:17:11 | StoreValue | May return stack-allocated memory from $@. | test.cpp:17:10:17:11 | mc | mc |
| test.cpp:25:9:25:11 | StoreValue | test.cpp:23:18:23:19 | mc | test.cpp:25:9:25:11 | StoreValue | May return stack-allocated memory from $@. | test.cpp:23:18:23:19 | mc | mc |
| test.cpp:41:9:41:12 | StoreValue | test.cpp:39:17:39:18 | mc | test.cpp:41:9:41:12 | StoreValue | May return stack-allocated memory from $@. | test.cpp:39:17:39:18 | mc | mc |
| test.cpp:47:9:47:10 | StoreValue | test.cpp:47:9:47:10 | mc | test.cpp:47:9:47:10 | StoreValue | May return stack-allocated memory from $@. | test.cpp:47:9:47:10 | mc | mc |
| test.cpp:54:9:54:15 | StoreValue | test.cpp:54:11:54:12 | mc | test.cpp:54:9:54:15 | StoreValue | May return stack-allocated memory from $@. | test.cpp:54:11:54:12 | mc | mc |
| test.cpp:92:9:92:11 | StoreValue | test.cpp:89:10:89:11 | mc | test.cpp:92:9:92:11 | StoreValue | May return stack-allocated memory from $@. | test.cpp:89:10:89:11 | mc | mc |
| test.cpp:112:9:112:11 | StoreValue | test.cpp:112:9:112:11 | arr | test.cpp:112:9:112:11 | StoreValue | May return stack-allocated memory from $@. | test.cpp:112:9:112:11 | arr | arr |
| test.cpp:119:9:119:18 | StoreValue | test.cpp:119:11:119:13 | arr | test.cpp:119:9:119:18 | StoreValue | May return stack-allocated memory from $@. | test.cpp:119:11:119:13 | arr | arr |
| test.cpp:137:9:137:11 | StoreValue | test.cpp:134:8:134:10 | arr | test.cpp:137:9:137:11 | StoreValue | May return stack-allocated memory from $@. | test.cpp:134:8:134:10 | arr | arr |
| test.cpp:171:10:171:23 | StoreValue | test.cpp:170:35:170:41 | myLocal | test.cpp:171:10:171:23 | StoreValue | May return stack-allocated memory from $@. | test.cpp:170:35:170:41 | myLocal | myLocal |
| test.cpp:177:10:177:23 | StoreValue | test.cpp:176:25:176:34 | localArray | test.cpp:177:10:177:23 | StoreValue | May return stack-allocated memory from $@. | test.cpp:176:25:176:34 | localArray | localArray |
| test.cpp:183:10:183:19 | StoreValue | test.cpp:182:21:182:27 | myLocal | test.cpp:183:10:183:19 | StoreValue | May return stack-allocated memory from $@. | test.cpp:182:21:182:27 | myLocal | myLocal |
| test.cpp:190:10:190:13 | StoreValue | test.cpp:189:16:189:16 | p | test.cpp:190:10:190:13 | StoreValue | May return stack-allocated memory from $@. | test.cpp:189:16:189:16 | p | p |
| test.cpp:17:2:17:12 | return ... | May return stack-allocated memory from $@. | test.cpp:17:10:17:11 | mc | mc |
| test.cpp:25:2:25:12 | return ... | May return stack-allocated memory from $@. | test.cpp:23:18:23:19 | mc | mc |
| test.cpp:47:2:47:11 | return ... | May return stack-allocated memory from $@. | test.cpp:47:9:47:10 | mc | mc |
| test.cpp:54:2:54:16 | return ... | May return stack-allocated memory from $@. | test.cpp:54:11:54:12 | mc | mc |
| test.cpp:92:2:92:12 | return ... | May return stack-allocated memory from $@. | test.cpp:89:10:89:11 | mc | mc |
| test.cpp:112:2:112:12 | return ... | May return stack-allocated memory from $@. | test.cpp:112:9:112:11 | arr | arr |
| test.cpp:119:2:119:19 | return ... | May return stack-allocated memory from $@. | test.cpp:119:11:119:13 | arr | arr |
| test.cpp:171:3:171:24 | return ... | May return stack-allocated memory from $@. | test.cpp:170:35:170:41 | myLocal | myLocal |

View File

@@ -38,7 +38,7 @@ MyClass *test4()
MyClass mc;
MyClass &ref = mc;
return &ref; // BAD
return &ref; // BAD [NOT DETECTED]
}
MyClass &test5()
@@ -134,7 +134,7 @@ char *testArray4()
ptr = arr + 1;
ptr++;
return ptr; // BAD
return ptr; // BAD [NOT DETECTED]
}
char *testArray5()
@@ -174,20 +174,20 @@ void *conversionBeforeDataFlow() {
void *arrayConversionBeforeDataFlow() {
int localArray[4];
int *pointerToLocal = localArray; // has conversion
return pointerToLocal; // BAD
return pointerToLocal; // BAD [NOT DETECTED]
}
int &dataFlowThroughReference() {
int myLocal;
int &refToLocal = myLocal; // has conversion
return refToLocal; // BAD
return refToLocal; // BAD [NOT DETECTED]
}
int *&conversionInFlow() {
int myLocal;
int *p = &myLocal;
int *&pRef = p; // has conversion in the middle of data flow
return pRef; // BAD
return pRef; // BAD [NOT DETECTED]
}
namespace std {
@@ -215,9 +215,4 @@ auto make_read_port()
auto port = std::shared_ptr<int>(new int);
auto ptr = port.get();
return ptr; // GOOD
}
void* get_sp() {
int p;
return (void*)&p; // GOOD: The function name makes it sound like the programmer intended to get the value of the stack pointer.
}

View File

@@ -1,10 +1,18 @@
edges
| test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input |
| test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input |
| test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input |
| test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input |
| test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input indirection |
| test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input indirection |
subpaths
nodes
| test2.cpp:110:3:110:6 | call to gets | semmle.label | call to gets |
| test.cpp:54:17:54:20 | argv | semmle.label | argv |
| test.cpp:54:17:54:20 | argv | semmle.label | argv |
| test.cpp:58:25:58:29 | input | semmle.label | input |
subpaths
| test.cpp:58:25:58:29 | input | semmle.label | input |
| test.cpp:58:25:58:29 | input | semmle.label | input |
| test.cpp:58:25:58:29 | input indirection | semmle.label | input indirection |
| test.cpp:58:25:58:29 | input indirection | semmle.label | input indirection |
#select
| test2.cpp:110:3:110:6 | call to gets | test2.cpp:110:3:110:6 | call to gets | test2.cpp:110:3:110:6 | call to gets | This write into buffer 'password' may contain unencrypted data from $@ | test2.cpp:110:3:110:6 | call to gets | user input (String read by gets) |
| test.cpp:58:3:58:9 | call to sprintf | test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | This write into buffer 'passwd' may contain unencrypted data from $@ | test.cpp:54:17:54:20 | argv | user input (a command-line argument) |
| test.cpp:58:3:58:9 | call to sprintf | test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | This write into buffer 'passwd' may contain unencrypted data from $@ | test.cpp:54:17:54:20 | argv | user input (argv) |

View File

@@ -1,42 +1,10 @@
edges
| test2.cpp:52:44:52:57 | password_tries | test2.cpp:52:40:52:58 | * ... |
| test2.cpp:62:18:62:25 | password | test2.cpp:65:31:65:34 | cpy1 |
| test2.cpp:72:17:72:24 | password | test2.cpp:73:30:73:32 | buf |
| test2.cpp:72:17:72:24 | password | test2.cpp:76:30:76:32 | buf |
| test2.cpp:98:45:98:52 | password | test2.cpp:99:27:99:32 | buffer |
nodes
| test2.cpp:43:36:43:43 | password | semmle.label | password |
| test2.cpp:44:37:44:45 | thepasswd | semmle.label | thepasswd |
| test2.cpp:50:41:50:53 | passwd_config | semmle.label | passwd_config |
| test2.cpp:52:40:52:58 | * ... | semmle.label | * ... |
| test2.cpp:52:44:52:57 | password_tries | semmle.label | password_tries |
| test2.cpp:54:41:54:52 | widepassword | semmle.label | widepassword |
| test2.cpp:55:40:55:51 | widepassword | semmle.label | widepassword |
| test2.cpp:57:39:57:49 | call to getPassword | semmle.label | call to getPassword |
| test2.cpp:62:18:62:25 | password | semmle.label | password |
| test2.cpp:65:31:65:34 | cpy1 | semmle.label | cpy1 |
| test2.cpp:72:17:72:24 | password | semmle.label | password |
| test2.cpp:73:30:73:32 | buf | semmle.label | buf |
| test2.cpp:76:30:76:32 | buf | semmle.label | buf |
| test2.cpp:86:36:86:43 | password | semmle.label | password |
| test2.cpp:91:50:91:63 | passwd_config2 | semmle.label | passwd_config2 |
| test2.cpp:98:45:98:52 | password | semmle.label | password |
| test2.cpp:99:27:99:32 | buffer | semmle.label | buffer |
| test.cpp:45:9:45:19 | thePassword | semmle.label | thePassword |
| test.cpp:70:38:70:48 | thePassword | semmle.label | thePassword |
| test.cpp:73:43:73:53 | thePassword | semmle.label | thePassword |
subpaths
#select
| test2.cpp:43:2:43:8 | call to fprintf | test2.cpp:43:36:43:43 | password | test2.cpp:43:36:43:43 | password | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:43:36:43:43 | password | this source. |
| test2.cpp:44:2:44:8 | call to fprintf | test2.cpp:44:37:44:45 | thepasswd | test2.cpp:44:37:44:45 | thepasswd | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:44:37:44:45 | thepasswd | this source. |
| test2.cpp:50:2:50:8 | call to fprintf | test2.cpp:50:41:50:53 | passwd_config | test2.cpp:50:41:50:53 | passwd_config | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:50:41:50:53 | passwd_config | this source. |
| test2.cpp:54:2:54:8 | call to fprintf | test2.cpp:54:41:54:52 | widepassword | test2.cpp:54:41:54:52 | widepassword | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:54:41:54:52 | widepassword | this source. |
| test2.cpp:55:2:55:8 | call to fprintf | test2.cpp:55:40:55:51 | widepassword | test2.cpp:55:40:55:51 | widepassword | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:55:40:55:51 | widepassword | this source. |
| test2.cpp:57:2:57:8 | call to fprintf | test2.cpp:57:39:57:49 | call to getPassword | test2.cpp:57:39:57:49 | call to getPassword | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:57:39:57:49 | call to getPassword | this source. |
| test2.cpp:65:3:65:9 | call to fprintf | test2.cpp:62:18:62:25 | password | test2.cpp:65:31:65:34 | cpy1 | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:62:18:62:25 | password | this source. |
| test2.cpp:73:3:73:9 | call to fprintf | test2.cpp:72:17:72:24 | password | test2.cpp:73:30:73:32 | buf | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:72:17:72:24 | password | this source. |
| test2.cpp:76:3:76:9 | call to fprintf | test2.cpp:72:17:72:24 | password | test2.cpp:76:30:76:32 | buf | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:72:17:72:24 | password | this source. |
| test2.cpp:99:3:99:9 | call to fprintf | test2.cpp:98:45:98:52 | password | test2.cpp:99:27:99:32 | buffer | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:98:45:98:52 | password | this source. |
| test.cpp:45:3:45:7 | call to fputs | test.cpp:45:9:45:19 | thePassword | test.cpp:45:9:45:19 | thePassword | This write into file 'file' may contain unencrypted data from $@ | test.cpp:45:9:45:19 | thePassword | this source. |
| test.cpp:70:35:70:35 | call to operator<< | test.cpp:70:38:70:48 | thePassword | test.cpp:70:38:70:48 | thePassword | This write into file 'mystream' may contain unencrypted data from $@ | test.cpp:70:38:70:48 | thePassword | this source. |
| test.cpp:73:37:73:41 | call to write | test.cpp:73:43:73:53 | thePassword | test.cpp:73:43:73:53 | thePassword | This write into file 'mystream' may contain unencrypted data from $@ | test.cpp:73:43:73:53 | thePassword | this source. |
| test2.cpp:43:2:43:8 | call to fprintf | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:43:36:43:43 | password | this source. |
| test2.cpp:44:2:44:8 | call to fprintf | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:44:37:44:45 | thepasswd | this source. |
| test2.cpp:50:2:50:8 | call to fprintf | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:50:41:50:53 | passwd_config | this source. |
| test2.cpp:54:2:54:8 | call to fprintf | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:54:41:54:52 | widepassword | this source. |
| test2.cpp:55:2:55:8 | call to fprintf | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:55:40:55:51 | widepassword | this source. |
| test2.cpp:57:2:57:8 | call to fprintf | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:57:39:57:49 | call to getPassword | this source. |
| test2.cpp:65:3:65:9 | call to fprintf | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:62:18:62:25 | password | this source. |
| test.cpp:45:3:45:7 | call to fputs | This write into file 'file' may contain unencrypted data from $@ | test.cpp:45:9:45:19 | thePassword | this source. |
| test.cpp:70:35:70:35 | call to operator<< | This write into file 'mystream' may contain unencrypted data from $@ | test.cpp:70:38:70:48 | thePassword | this source. |
| test.cpp:73:37:73:41 | call to write | This write into file 'mystream' may contain unencrypted data from $@ | test.cpp:73:43:73:53 | thePassword | this source. |

View File

@@ -1,5 +1,4 @@
edges
| test2.cpp:63:24:63:31 | password | test2.cpp:63:16:63:20 | call to crypt |
| test3.cpp:17:28:17:36 | password1 | test3.cpp:22:15:22:23 | password1 |
| test3.cpp:17:51:17:59 | password2 | test3.cpp:26:15:26:23 | password2 |
| test3.cpp:45:8:45:15 | password | test3.cpp:47:15:47:22 | password |
@@ -38,8 +37,10 @@ edges
| test3.cpp:214:8:214:15 | password | test3.cpp:217:30:217:37 | password |
| test3.cpp:214:8:214:15 | password | test3.cpp:219:15:219:26 | password_ptr |
| test3.cpp:217:18:217:28 | call to rtn_encrypt | test3.cpp:219:15:219:26 | password_ptr |
| test3.cpp:225:34:225:41 | password | test3.cpp:227:22:227:29 | password |
| test3.cpp:225:34:225:41 | password | test3.cpp:228:26:228:33 | password |
| test3.cpp:239:7:239:14 | password | test3.cpp:241:8:241:15 | password |
| test3.cpp:239:7:239:14 | password | test3.cpp:242:8:242:15 | password |
| test3.cpp:252:8:252:16 | password1 | test3.cpp:254:15:254:23 | password1 |
| test3.cpp:252:8:252:16 | password1 | test3.cpp:256:3:256:19 | call to decrypt_to_buffer |
| test3.cpp:252:8:252:16 | password1 | test3.cpp:256:21:256:29 | password1 |
@@ -83,22 +84,11 @@ edges
| test3.cpp:350:9:350:16 | password | test3.cpp:352:16:352:23 | password |
| test3.cpp:350:9:350:16 | password | test3.cpp:353:4:353:18 | call to decrypt_inplace |
| test3.cpp:350:9:350:16 | password | test3.cpp:353:20:353:27 | password |
| test3.cpp:366:8:366:15 | password | test3.cpp:368:15:368:22 | password |
| test3.cpp:366:8:366:15 | password | test3.cpp:374:3:374:18 | call to SecureZeroBuffer |
| test3.cpp:366:8:366:15 | password | test3.cpp:374:20:374:27 | password |
| test3.cpp:386:8:386:15 | password | test3.cpp:388:15:388:22 | password |
| test3.cpp:398:18:398:25 | password | test3.cpp:400:15:400:23 | & ... |
| test3.cpp:398:18:398:25 | password | test3.cpp:400:16:400:23 | password |
| test3.cpp:398:18:398:25 | password | test3.cpp:400:33:400:40 | password |
| test3.cpp:421:21:421:28 | password | test3.cpp:421:3:421:17 | call to decrypt_inplace |
| test.cpp:41:23:41:43 | cleartext password! | test.cpp:48:21:48:27 | call to encrypt |
| test.cpp:41:23:41:43 | cleartext password! | test.cpp:48:29:48:39 | thePassword |
| test.cpp:66:23:66:43 | cleartext password! | test.cpp:76:21:76:27 | call to encrypt |
| test.cpp:66:23:66:43 | cleartext password! | test.cpp:76:29:76:39 | thePassword |
nodes
| test2.cpp:63:16:63:20 | call to crypt | semmle.label | call to crypt |
| test2.cpp:63:24:63:31 | password | semmle.label | password |
| test2.cpp:63:24:63:31 | password | semmle.label | password |
| test3.cpp:17:28:17:36 | password1 | semmle.label | password1 |
| test3.cpp:17:51:17:59 | password2 | semmle.label | password2 |
| test3.cpp:22:15:22:23 | password1 | semmle.label | password1 |
@@ -154,9 +144,11 @@ nodes
| test3.cpp:217:30:217:37 | password | semmle.label | password |
| test3.cpp:219:15:219:26 | password_ptr | semmle.label | password_ptr |
| test3.cpp:225:34:225:41 | password | semmle.label | password |
| test3.cpp:227:22:227:29 | password | semmle.label | password |
| test3.cpp:228:26:228:33 | password | semmle.label | password |
| test3.cpp:239:7:239:14 | password | semmle.label | password |
| test3.cpp:241:8:241:15 | password | semmle.label | password |
| test3.cpp:242:8:242:15 | password | semmle.label | password |
| test3.cpp:252:8:252:16 | password1 | semmle.label | password1 |
| test3.cpp:252:24:252:32 | password2 | semmle.label | password2 |
| test3.cpp:254:15:254:23 | password1 | semmle.label | password1 |
@@ -203,21 +195,6 @@ nodes
| test3.cpp:352:16:352:23 | password | semmle.label | password |
| test3.cpp:353:4:353:18 | call to decrypt_inplace | semmle.label | call to decrypt_inplace |
| test3.cpp:353:20:353:27 | password | semmle.label | password |
| test3.cpp:366:8:366:15 | password | semmle.label | password |
| test3.cpp:368:15:368:22 | password | semmle.label | password |
| test3.cpp:374:3:374:18 | call to SecureZeroBuffer | semmle.label | call to SecureZeroBuffer |
| test3.cpp:374:20:374:27 | password | semmle.label | password |
| test3.cpp:386:8:386:15 | password | semmle.label | password |
| test3.cpp:388:15:388:22 | password | semmle.label | password |
| test3.cpp:398:18:398:25 | password | semmle.label | password |
| test3.cpp:400:15:400:23 | & ... | semmle.label | & ... |
| test3.cpp:400:16:400:23 | password | semmle.label | password |
| test3.cpp:400:33:400:40 | password | semmle.label | password |
| test3.cpp:414:17:414:24 | password | semmle.label | password |
| test3.cpp:420:17:420:24 | password | semmle.label | password |
| test3.cpp:421:3:421:17 | call to decrypt_inplace | semmle.label | call to decrypt_inplace |
| test3.cpp:421:21:421:28 | password | semmle.label | password |
| test3.cpp:421:21:421:28 | password | semmle.label | password |
| test.cpp:41:23:41:43 | cleartext password! | semmle.label | cleartext password! |
| test.cpp:48:21:48:27 | call to encrypt | semmle.label | call to encrypt |
| test.cpp:48:29:48:39 | thePassword | semmle.label | thePassword |
@@ -241,12 +218,11 @@ subpaths
| test3.cpp:140:3:140:6 | call to send | test3.cpp:129:39:129:47 | password1 | test3.cpp:140:15:140:17 | ptr | This operation transmits 'ptr', which may contain unencrypted sensitive data from $@ | test3.cpp:129:39:129:47 | password1 | password1 |
| test3.cpp:146:3:146:6 | call to send | test3.cpp:126:9:126:23 | global_password | test3.cpp:146:15:146:18 | data | This operation transmits 'data', which may contain unencrypted sensitive data from $@ | test3.cpp:126:9:126:23 | global_password | global_password |
| test3.cpp:159:3:159:6 | call to send | test3.cpp:152:29:152:36 | password | test3.cpp:159:15:159:20 | buffer | This operation transmits 'buffer', which may contain unencrypted sensitive data from $@ | test3.cpp:152:29:152:36 | password | password |
| test3.cpp:227:2:227:5 | call to send | test3.cpp:225:34:225:41 | password | test3.cpp:227:22:227:29 | password | This operation transmits 'password', which may contain unencrypted sensitive data from $@ | test3.cpp:225:34:225:41 | password | password |
| test3.cpp:228:2:228:5 | call to send | test3.cpp:225:34:225:41 | password | test3.cpp:228:26:228:33 | password | This operation transmits 'password', which may contain unencrypted sensitive data from $@ | test3.cpp:225:34:225:41 | password | password |
| test3.cpp:241:2:241:6 | call to fgets | test3.cpp:239:7:239:14 | password | test3.cpp:241:8:241:15 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:239:7:239:14 | password | password |
| test3.cpp:242:2:242:6 | call to fgets | test3.cpp:239:7:239:14 | password | test3.cpp:242:8:242:15 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:239:7:239:14 | password | password |
| test3.cpp:272:3:272:6 | call to send | test3.cpp:268:19:268:26 | password | test3.cpp:272:15:272:18 | data | This operation transmits 'data', which may contain unencrypted sensitive data from $@ | test3.cpp:268:19:268:26 | password | password |
| test3.cpp:295:2:295:5 | call to send | test3.cpp:308:58:308:66 | password2 | test3.cpp:295:14:295:17 | data | This operation transmits 'data', which may contain unencrypted sensitive data from $@ | test3.cpp:308:58:308:66 | password2 | password2 |
| test3.cpp:300:2:300:5 | call to send | test3.cpp:308:58:308:66 | password2 | test3.cpp:300:14:300:17 | data | This operation transmits 'data', which may contain unencrypted sensitive data from $@ | test3.cpp:308:58:308:66 | password2 | password2 |
| test3.cpp:341:4:341:7 | call to recv | test3.cpp:339:9:339:16 | password | test3.cpp:341:16:341:23 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:339:9:339:16 | password | password |
| test3.cpp:388:3:388:6 | call to recv | test3.cpp:386:8:386:15 | password | test3.cpp:388:15:388:22 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:386:8:386:15 | password | password |
| test3.cpp:414:3:414:6 | call to recv | test3.cpp:414:17:414:24 | password | test3.cpp:414:17:414:24 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:414:17:414:24 | password | password |
| test3.cpp:420:3:420:6 | call to recv | test3.cpp:420:17:420:24 | password | test3.cpp:420:17:420:24 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:420:17:420:24 | password | password |

View File

@@ -70,15 +70,8 @@ void tests(FILE *log, myStruct &s)
char buf[1024];
strcpy(buf, s.password);
fprintf(log, "buf = %s\n", buf); // BAD
fprintf(log, "buf = %s\n", buf); // BAD [NOT DETECTED]
strcpy(buf, s.password_hash);
fprintf(log, "buf = %s\n", buf); // GOOD [FALSE POSITIVE]
}
{
char buf[1024];
strcpy(buf, s.password_hash);
fprintf(log, "buf = %s\n", buf); // GOOD
}
@@ -96,17 +89,6 @@ void tests(FILE *log, myStruct &s)
char buffer[1024];
snprintf(buffer, 1024, "password = %s", s.password);
fprintf(log, "log: %s", buffer); // BAD
fprintf(log, "log: %s", buffer); // BAD [NOT DETECTED]
}
}
char *gets(char *s);
void test_gets()
{
{
char password[1024];
gets(password); // BAD
}
}

View File

@@ -224,7 +224,7 @@ int get_socket(int from);
void test_more_stdio(const char *password)
{
send(get_socket(1), password, 128, val()); // GOOD: `getsocket(1)` is probably standard output
send(get_socket(1), password, 128, val()); // GOOD: `getsocket(1)` is probably standard output [FALSE POSITIVE]
send(get_socket(val()), password, 128, val()); // BAD
}
@@ -239,7 +239,7 @@ void test_fgets(FILE *stream)
char password[128];
fgets(password, 128, stream); // BAD
fgets(password, 128, STDIN_STREAM); // GOOD: `STDIN_STREAM` is probably standard input
fgets(password, 128, STDIN_STREAM); // GOOD: `STDIN_STREAM` is probably standard input [FALSE POSITIVE]
}
void encrypt_to_buffer(const char *input, char* output);
@@ -356,68 +356,3 @@ void test_loops()
}
}
}
void DoDisguisedOperation(char *buffer, size_t size);
void SecureZeroBuffer(char *buffer, size_t size);
void test_securezero()
{
{
char password[256];
recv(val(), password, 256, val()); // GOOD: password is (probably) encrypted
DoDisguisedOperation(password, 256); // decryption (disguised)
// ...
SecureZeroBuffer(password, 256); // evidence we may have been doing decryption
}
}
struct encrypted_data
{
char data[256];
};
void test_more_clues()
{
{
char password[256];
recv(val(), password, 256, val()); // BAD: not encrypted
}
{
char encrypted_password[256];
recv(val(), encrypted_password, 256, val()); // GOOD: password is (probably) encrypted
}
{
encrypted_data password;
recv(val(), &password, sizeof(password), val()); // GOOD: password is (probably) encrypted
}
}
struct packet
{
char password[256];
};
void test_member_password()
{
{
packet p;
recv(val(), p.password, 256, val()); // BAD: not encrypted
}
{
packet p;
recv(val(), p.password, 256, val()); // GOOD: password is encrypted [FALSE POSITIVE]
decrypt_inplace(p.password); // proof that `password` was in fact encrypted
}
}

View File

@@ -1,2 +0,0 @@
description: Remove unused legacy relations.
compatibility: backwards

View File

@@ -1,2 +0,0 @@
description: Support for compiler-generated event accessors.
compatibility: backwards

File diff suppressed because it is too large Load Diff

View File

@@ -6,15 +6,11 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class Accessor : Method
{
private readonly IPropertySymbol property;
protected Accessor(Context cx, IMethodSymbol init, IPropertySymbol property)
: base(cx, init)
{
this.property = property;
}
protected Accessor(Context cx, IMethodSymbol init)
: base(cx, init) { }
/// <summary>
/// Gets the property symbol associated with accessor `symbol`, or `null`
/// Gets the property symbol associated accessor `symbol`, or `null`
/// if there is no associated symbol.
/// </summary>
public static IPropertySymbol? GetPropertySymbol(IMethodSymbol symbol)
@@ -30,30 +26,42 @@ namespace Semmle.Extraction.CSharp.Entities
return props.SingleOrDefault();
}
/// <summary>
/// Gets the property symbol associated with this accessor.
/// </summary>
private IPropertySymbol? PropertySymbol => GetPropertySymbol(Symbol);
public new Accessor OriginalDefinition => Create(Context, Symbol.OriginalDefinition);
public override void Populate(TextWriter trapFile)
{
PopulateMethod(trapFile);
PopulateModifiers(trapFile);
ContainingType!.PopulateGenerics();
var parent = Property.Create(Context, property);
var prop = PropertySymbol;
if (prop is null)
{
Context.ModelError(Symbol, "Unhandled accessor associated symbol");
return;
}
var parent = Property.Create(Context, prop);
int kind;
Accessor unboundAccessor;
if (SymbolEqualityComparer.Default.Equals(Symbol, property.GetMethod))
if (SymbolEqualityComparer.Default.Equals(Symbol, prop.GetMethod))
{
kind = 1;
var orig = property.OriginalDefinition;
unboundAccessor = Create(Context, orig.GetMethod!, orig);
unboundAccessor = Create(Context, prop.OriginalDefinition.GetMethod!);
}
else if (SymbolEqualityComparer.Default.Equals(Symbol, property.SetMethod))
else if (SymbolEqualityComparer.Default.Equals(Symbol, prop.SetMethod))
{
kind = 2;
var orig = property.OriginalDefinition;
unboundAccessor = Create(Context, orig.SetMethod!, orig);
unboundAccessor = Create(Context, prop.OriginalDefinition.SetMethod!);
}
else
{
Context.ModelError(Symbol, $"Unhandled accessor method {Symbol.ToDisplayString()}");
Context.ModelError(Symbol, "Unhandled accessor kind");
return;
}
@@ -75,14 +83,14 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
public static Accessor Create(Context cx, IMethodSymbol symbol, IPropertySymbol prop) =>
AccessorFactory.Instance.CreateEntity(cx, symbol, (symbol, prop));
public static new Accessor Create(Context cx, IMethodSymbol symbol) =>
AccessorFactory.Instance.CreateEntityFromSymbol(cx, symbol);
private class AccessorFactory : CachedEntityFactory<(IMethodSymbol, IPropertySymbol), Accessor>
private class AccessorFactory : CachedEntityFactory<IMethodSymbol, Accessor>
{
public static AccessorFactory Instance { get; } = new AccessorFactory();
public override Accessor Create(Context cx, (IMethodSymbol, IPropertySymbol) init) => new(cx, init.Item1, init.Item2);
public override Accessor Create(Context cx, IMethodSymbol init) => new Accessor(cx, init);
}
}
}

View File

@@ -3,46 +3,44 @@ using System.IO;
namespace Semmle.Extraction.CSharp.Entities
{
internal class EventAccessor : Method
internal class EventAccessor : Accessor
{
private readonly IEventSymbol @event;
private EventAccessor(Context cx, IMethodSymbol init, IEventSymbol @event)
: base(cx, init)
{
this.@event = @event;
}
private EventAccessor(Context cx, IMethodSymbol init)
: base(cx, init) { }
/// <summary>
/// Gets the event symbol associated with accessor `symbol`, or `null`
/// if there is no associated symbol.
/// Gets the event symbol associated with this accessor.
/// </summary>
public static IEventSymbol? GetEventSymbol(IMethodSymbol symbol) =>
symbol.AssociatedSymbol as IEventSymbol;
private IEventSymbol? EventSymbol => Symbol.AssociatedSymbol as IEventSymbol;
public override void Populate(TextWriter trapFile)
{
PopulateMethod(trapFile);
ContainingType!.PopulateGenerics();
var @event = EventSymbol;
if (@event is null)
{
Context.ModelError(Symbol, "Unhandled event accessor associated symbol");
return;
}
var parent = Event.Create(Context, @event);
int kind;
EventAccessor unboundAccessor;
if (SymbolEqualityComparer.Default.Equals(Symbol, @event.AddMethod))
{
kind = 1;
var orig = @event.OriginalDefinition;
unboundAccessor = Create(Context, orig.AddMethod!, orig);
unboundAccessor = Create(Context, @event.OriginalDefinition.AddMethod!);
}
else if (SymbolEqualityComparer.Default.Equals(Symbol, @event.RemoveMethod))
{
kind = 2;
var orig = @event.OriginalDefinition;
unboundAccessor = Create(Context, orig.RemoveMethod!, orig);
unboundAccessor = Create(Context, @event.OriginalDefinition.RemoveMethod!);
}
else
{
Context.ModelError(Symbol, $"Undhandled event accessor kind {Symbol.ToDisplayString()}");
Context.ModelError(Symbol, "Undhandled event accessor kind");
return;
}
@@ -52,21 +50,16 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.event_accessor_location(this, l);
Overrides(trapFile);
if (Symbol.FromSource() && Block is null)
{
trapFile.compiler_generated(this);
}
}
public static EventAccessor Create(Context cx, IMethodSymbol symbol, IEventSymbol @event) =>
EventAccessorFactory.Instance.CreateEntity(cx, symbol, (symbol, @event));
public static new EventAccessor Create(Context cx, IMethodSymbol symbol) =>
EventAccessorFactory.Instance.CreateEntityFromSymbol(cx, symbol);
private class EventAccessorFactory : CachedEntityFactory<(IMethodSymbol, IEventSymbol), EventAccessor>
private class EventAccessorFactory : CachedEntityFactory<IMethodSymbol, EventAccessor>
{
public static EventAccessorFactory Instance { get; } = new EventAccessorFactory();
public override EventAccessor Create(Context cx, (IMethodSymbol, IEventSymbol) init) => new EventAccessor(cx, init.Item1, init.Item2);
public override EventAccessor Create(Context cx, IMethodSymbol init) => new EventAccessor(cx, init);
}
}
}

View File

@@ -45,7 +45,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
else if (body is BlockSyntax blockBody)
Statements.Block.Create(Context, blockBody, this, 0);
else
Context.ModelError(body, $"Unhandled lambda body of type {body.GetType()}");
Context.ModelError(body, "Unhandled lambda body");
});
}

View File

@@ -96,7 +96,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
kind = ExprKind.NAMESPACE_ACCESS;
break;
default:
info.Context.ModelError(info.Node, $"Unhandled symbol for member access of kind {symbol.Kind}");
info.Context.ModelError(info.Node, "Unhandled symbol for member access");
kind = ExprKind.UNKNOWN;
break;
}

View File

@@ -43,8 +43,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
if (Syntax.Initializer is not null)
{
var kind = Syntax.Initializer.Kind();
switch (kind)
switch (Syntax.Initializer.Kind())
{
case SyntaxKind.CollectionInitializerExpression:
CollectionInitializer.Create(new ExpressionNodeInfo(Context, Syntax.Initializer, this, -1).SetType(Type));
@@ -53,7 +52,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
ObjectInitializer.Create(new ExpressionNodeInfo(Context, Syntax.Initializer, this, -1).SetType(Type));
break;
default:
Context.ModelError(Syntax.Initializer, $"Unhandled initializer in object creation of kind {kind}");
Context.ModelError(Syntax.Initializer, "Unhandled initializer in object creation");
break;
}
}

View File

@@ -68,7 +68,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
case DiscardDesignationSyntax discard:
return new Expressions.Discard(cx, discard, parent, child);
default:
throw new InternalError($"var pattern designation of type {varPattern.Designation.GetType()} is unhandled");
throw new InternalError("var pattern designation is unhandled");
}
case DiscardPatternSyntax dp:

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