Merge branch 'main' into enable-sound-ir

This commit is contained in:
Mathias Vorreiter Pedersen
2024-04-10 17:39:13 +01:00
218 changed files with 3616 additions and 3596 deletions

View File

@@ -31,6 +31,8 @@ pip.parse(
use_repo(pip, "codegen_deps")
swift_deps = use_extension("//swift/third_party:load.bzl", "swift_deps")
# following list can be kept in sync with `bazel mod tidy`
use_repo(
swift_deps,
"binlog",

View File

@@ -9,6 +9,7 @@ dependencies:
codeql/dataflow: ${workspace}
codeql/rangeanalysis: ${workspace}
codeql/ssa: ${workspace}
codeql/typeflow: ${workspace}
codeql/tutorial: ${workspace}
codeql/util: ${workspace}
codeql/xml: ${workspace}

View File

@@ -6,6 +6,7 @@ private import DataFlowImplCommon as DataFlowImplCommon
private import DataFlowUtil
private import semmle.code.cpp.models.interfaces.PointerWrapper
private import DataFlowPrivate
private import TypeFlow
private import semmle.code.cpp.ir.ValueNumbering
/**
@@ -955,11 +956,7 @@ private module Cached {
* Holds if the address computed by `operand` is guaranteed to write
* to a specific address.
*/
private predicate isCertainAddress(Operand operand) {
valueNumberOfOperand(operand).getAnInstruction() instanceof VariableAddressInstruction
or
operand.getType() instanceof Cpp::ReferenceType
}
private predicate isCertainAddress(Operand operand) { isPointerToSingleObject(operand.getDef()) }
/**
* Holds if `address` is a use of an SSA variable rooted at `base`, and the

View File

@@ -0,0 +1,278 @@
private import cpp
private import semmle.code.cpp.ir.IR
private import codeql.typeflow.TypeFlow
private module Input implements TypeFlowInput<Location> {
/** Holds if `alloc` dynamically allocates a single object. */
private predicate isSingleObjectAllocation(AllocationExpr alloc) {
// i.e., `new int`;
alloc instanceof NewExpr
or
// i.e., `malloc(sizeof(int))`
exists(SizeofTypeOperator sizeOf | sizeOf = alloc.getSizeExpr() |
not sizeOf.getTypeOperand().getUnspecifiedType() instanceof ArrayType
)
}
/**
* Holds if `i` is the result of a dynamic allocation.
*
* `isObject` is `true` if the allocation allocated a single object,
* and `false` otherwise.
*/
private predicate isAllocation(Instruction i, boolean isObject) {
exists(AllocationExpr alloc | alloc = i.getUnconvertedResultExpression() |
if isSingleObjectAllocation(alloc) then isObject = true else isObject = false
)
}
private predicate hasExactSingleType(Instruction i) {
// The address of a variable is always a single object
i instanceof VariableAddressInstruction
or
// A reference always points to a single object
i.getResultLanguageType().hasUnspecifiedType(any(ReferenceType rt), false)
or
// `this` is never an array
i instanceof InitializeThisInstruction
or
// An allocation of a non-array object
isAllocation(i, true)
}
private predicate hasExactBufferType(Instruction i) {
// Anything with an array type is a buffer
i.getResultLanguageType().hasUnspecifiedType(any(ArrayType at), false)
or
// An allocation expression that we couldn't conclude allocated a single
// expression is assigned a buffer type.
isAllocation(i, false)
}
private newtype TTypeFlowNode =
TInstructionNode(Instruction i) or
TFunctionNode(IRFunction func)
abstract class TypeFlowNode extends TTypeFlowNode {
/** Gets a textual representation of this node. */
abstract string toString();
/**
* Gets the type of this node. This type may not be the most precise
* possible type, but will be used as a starting point of the analysis.
*/
abstract Type getType();
/** Gets the location of this node. */
abstract Location getLocation();
/** Gets the underlying `Instruction` of this node, if any. */
Instruction asInstruction() { none() }
/** Gets the underlying `IRFunction` of this node, if any. */
IRFunction asFunction() { none() }
/** Holds if the value of this node is always null. */
abstract predicate isNullValue();
}
private class InstructionNode extends TypeFlowNode, TInstructionNode {
Instruction instr;
InstructionNode() { this = TInstructionNode(instr) }
override string toString() { result = instr.toString() }
override Type getType() {
if hasExactSingleType(instr) then result.isSingle() else result.isBuffer()
}
override Location getLocation() { result = instr.getLocation() }
override Instruction asInstruction() { result = instr }
override predicate isNullValue() {
instr.(ConstantInstruction).getValue() = "0" and
instr.getResultIRType() instanceof IRAddressType
}
}
/** Gets the `TypeFlowNode` corresponding to `i`. */
additional InstructionNode instructionNode(Instruction i) { result.asInstruction() = i }
private class FunctionNode extends TypeFlowNode, TFunctionNode {
IRFunction func;
FunctionNode() { this = TFunctionNode(func) }
override string toString() { result = func.toString() }
Instruction getReturnValueInstruction() {
result = func.getReturnInstruction().(ReturnValueInstruction).getReturnValue()
}
override Type getType() { result = instructionNode(this.getReturnValueInstruction()).getType() }
override Location getLocation() { result = func.getLocation() }
override IRFunction asFunction() { result = func }
override predicate isNullValue() {
instructionNode(this.getReturnValueInstruction()).isNullValue()
}
}
/**
* Gets an ultimiate definition of `phi`. That is, an input to `phi` that is
* not itself a `PhiInstruction`.
*/
private Instruction getAnUltimateLocalDefinition(PhiInstruction phi) {
result = phi.getAnInput*() and not result instanceof PhiInstruction
}
/**
* Holds if this function is private (i.e., cannot be accessed outside its
* compilation unit). This means we can use a closed-world assumption about
* calls to this function.
*/
private predicate isPrivate(Function func) {
// static functions have internal linkage
func.isStatic()
or
// anonymous namespaces have internal linkage
func.getNamespace().getParentNamespace*().isAnonymous()
or
// private member functions are only called internally from inside the class
func.(MemberFunction).isPrivate()
}
/**
* Holds if `arg` is an argument for the parameter `p` in a private callable.
*/
pragma[nomagic]
private predicate privateParamArg(InitializeParameterInstruction p, Instruction arg) {
exists(CallInstruction call, int i, Function func |
call.getArgument(pragma[only_bind_into](i)) = arg and
func = call.getStaticCallTarget() and
func.getParameter(pragma[only_bind_into](i)) = p.getParameter() and
isPrivate(func)
)
}
predicate joinStep(TypeFlowNode n1, TypeFlowNode n2) {
// instruction -> phi
getAnUltimateLocalDefinition(n2.asInstruction()) = n1.asInstruction()
or
// return value -> function
n2.(FunctionNode).getReturnValueInstruction() = n1.asInstruction()
or
// function -> call
exists(Function func | func = n1.asFunction().getFunction() |
not func.isVirtual() and
n2.asInstruction().(CallInstruction).getStaticCallTarget() = func
)
or
// Argument -> parameter where the parameter's enclosing function
// is "private".
exists(Instruction arg, Instruction p |
privateParamArg(p, arg) and
n1.asInstruction() = arg and
n2.asInstruction() = p
)
}
/**
* Holds if knowing whether `i1` points to a single object or buffer implies
* knowing whether `i2` points to a single object or buffer.
*/
private predicate instructionStep(Instruction i1, Instruction i2) {
i2.(CopyInstruction).getSourceValue() = i1
or
i2.(CopyValueInstruction).getSourceValue() = i1
or
i2.(ConvertInstruction).getUnary() = i1
or
i2.(CheckedConvertOrNullInstruction).getUnary() = i1
or
i2.(InheritanceConversionInstruction).getUnary() = i1
or
i2.(PointerArithmeticInstruction).getLeft() = i1
}
predicate step(TypeFlowNode n1, TypeFlowNode n2) {
instructionStep(n1.asInstruction(), n2.asInstruction())
}
predicate isNullValue(TypeFlowNode n) { n.isNullValue() }
private newtype TType =
TSingle() or
TBuffer()
class Type extends TType {
string toString() {
this.isSingle() and
result = "Single"
or
this.isBuffer() and
result = "Buffer"
}
/** Holds if this type is the type that represents a single object. */
predicate isSingle() { this = TSingle() }
/** Holds if this type is the type that represents a buffer. */
predicate isBuffer() { this = TBuffer() }
/**
* Gets a super type of this type, if any.
*
* The type relation is `Single <: Buffer`.
*/
Type getASupertype() {
this.isSingle() and
result.isBuffer()
}
}
predicate exactTypeBase(TypeFlowNode n, Type t) {
exists(Instruction instr | instr = n.asInstruction() |
hasExactSingleType(instr) and t.isSingle()
or
hasExactBufferType(instr) and t.isBuffer()
)
}
pragma[nomagic]
private predicate upcastCand(TypeFlowNode n, Type t1, Type t2) {
exists(TypeFlowNode next |
step(n, next)
or
joinStep(n, next)
|
n.getType() = t1 and
next.getType() = t2 and
t1 != t2
)
}
private predicate upcast(TypeFlowNode n, Type t1) {
exists(Type t2 | upcastCand(n, t1, t2) |
// No need for transitive closure since the subtyping relation is just `Single <: Buffer`
t1.getASupertype() = t2
)
}
predicate typeFlowBaseCand(TypeFlowNode n, Type t) { upcast(n, t) }
}
private module TypeFlow = Make<Location, Input>;
/**
* Holds if `i` is an instruction that computes an address that points to a
* single object (as opposed to pointing into a buffer).
*/
pragma[nomagic]
predicate isPointerToSingleObject(Instruction i) {
TypeFlow::bestTypeFlow(Input::instructionNode(i), any(Input::Type t | t.isSingle()), _)
}

View File

@@ -506,8 +506,7 @@ private module IRDeclarationEntries {
* An entity that represents a declaration entry in the database.
*
* This class exists to work around the fact that `DeclStmt`s in some cases
* do not have `DeclarationEntry`s. Currently, this is the case for:
* - `DeclStmt`s in template instantiations.
* do not have `DeclarationEntry`s in older databases.
*
* So instead, the IR works with `IRDeclarationEntry`s that synthesize missing
* `DeclarationEntry`s when there is no result for `DeclStmt::getDeclarationEntry`.

View File

@@ -123,7 +123,7 @@ class IteratorCrementNonMemberOperator extends Operator {
}
private class IteratorCrementNonMemberOperatorModel extends IteratorCrementNonMemberOperator,
DataFlowFunction
DataFlowFunction, SideEffectFunction, AliasFunction
{
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
input = getIteratorArgumentInput(this, 0) and
@@ -131,6 +131,24 @@ private class IteratorCrementNonMemberOperatorModel extends IteratorCrementNonMe
or
input.isParameterDeref(0) and output.isReturnValueDeref()
}
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = 0 and buffer = false
}
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
// See the comment on `IteratorCrementMemberOperatorModel::hasSpecificWriteSideEffect`
// for an explanation of these values.
i = 0 and buffer = false and mustWrite = false
}
override predicate parameterNeverEscapes(int index) { none() }
override predicate parameterEscapesOnlyViaReturn(int index) { index = 0 }
}
/**
@@ -146,7 +164,7 @@ class IteratorCrementMemberOperator extends MemberFunction {
}
private class IteratorCrementMemberOperatorModel extends IteratorCrementMemberOperator,
DataFlowFunction, TaintFunction
DataFlowFunction, TaintFunction, SideEffectFunction, AliasFunction
{
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
input.isQualifierAddress() and
@@ -163,6 +181,28 @@ private class IteratorCrementMemberOperatorModel extends IteratorCrementMemberOp
input.isQualifierObject() and
output.isReturnValueDeref()
}
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
// We have two choices here: either `buffer` must be `true` or `mustWrite`
// must be `false` to ensure that the IR alias analysis doesn't think that
// `it++` completely override the value of the iterator.
// We choose `mustWrite` must be `false`. In that case, the value of
// `buffer` isn't super important (it just decides which kind of read side
// effect will be emitted).
i = -1 and buffer = false and mustWrite = false
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
}
/**
@@ -332,7 +372,7 @@ class IteratorAssignArithmeticOperator extends Function {
* non-member and member versions, use `IteratorPointerDereferenceOperator`.
*/
class IteratorPointerDereferenceMemberOperator extends MemberFunction, TaintFunction,
IteratorReferenceFunction
IteratorReferenceFunction, AliasFunction, SideEffectFunction
{
IteratorPointerDereferenceMemberOperator() {
this.getClassAndName("operator*") instanceof Iterator
@@ -345,6 +385,18 @@ class IteratorPointerDereferenceMemberOperator extends MemberFunction, TaintFunc
input.isReturnValueDeref() and
output.isQualifierObject()
}
override predicate parameterNeverEscapes(int index) { index = -1 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
/**
@@ -361,7 +413,7 @@ class IteratorPointerDereferenceNonMemberOperator extends Operator, IteratorRefe
}
private class IteratorPointerDereferenceNonMemberOperatorModel extends IteratorPointerDereferenceNonMemberOperator,
TaintFunction
TaintFunction, AliasFunction, SideEffectFunction
{
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input = getIteratorArgumentInput(this, 0) and
@@ -370,6 +422,18 @@ private class IteratorPointerDereferenceNonMemberOperatorModel extends IteratorP
input.isReturnValueDeref() and
output.isParameterDeref(0)
}
override predicate parameterNeverEscapes(int index) { index = 0 }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = 0 and buffer = false
}
}
/**
@@ -420,6 +484,71 @@ class IteratorAssignmentMemberOperator extends MemberFunction {
}
}
/**
* A member `operator==` or `operator!=` function for an iterator type.
*
* Note that this class _only_ matches member functions. To find both
* non-member and member versions, use `IteratorLogicalOperator`.
*/
class IteratorLogicalMemberOperator extends MemberFunction {
IteratorLogicalMemberOperator() {
this.getClassAndName(["operator!=", "operator=="]) instanceof Iterator
}
}
private class IteratorLogicalMemberOperatorModel extends IteratorLogicalMemberOperator,
AliasFunction, SideEffectFunction
{
override predicate parameterNeverEscapes(int index) { index = [-1, 0] }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}
/**
* A member `operator==` or `operator!=` function for an iterator type.
*
* Note that this class _only_ matches non-member functions. To find both
* non-member and member versions, use `IteratorLogicalOperator`.
*/
class IteratorLogicalNonMemberOperator extends Function {
IteratorLogicalNonMemberOperator() {
this.hasName(["operator!=", "operator=="]) and
exists(getIteratorArgumentInput(this, 0)) and
exists(getIteratorArgumentInput(this, 1))
}
}
private class IteratorLogicalNonMemberOperatorModel extends IteratorLogicalNonMemberOperator,
AliasFunction, SideEffectFunction
{
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
}
/**
* A (member or non-member) `operator==` or `operator!=` function for an iterator type.
*/
class IteratorLogicalOperator extends Function {
IteratorLogicalOperator() {
this instanceof IteratorLogicalNonMemberOperator
or
this instanceof IteratorLogicalMemberOperator
}
}
/**
* An `operator=` member function of an iterator class that is not a copy or move assignment
* operator.
@@ -428,12 +557,26 @@ class IteratorAssignmentMemberOperator extends MemberFunction {
* `operator*` and use their own `operator=` to assign to the container.
*/
private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMemberOperator,
TaintFunction
TaintFunction, SideEffectFunction, AliasFunction
{
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isParameterDeref(0) and
output.isQualifierObject()
}
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
// See the comment on `IteratorCrementMemberOperatorModel::hasSpecificWriteSideEffect`
// for an explanation of these values.
i = -1 and buffer = false and mustWrite = false
}
override predicate parameterNeverEscapes(int index) { index = 0 }
override predicate parameterEscapesOnlyViaReturn(int index) { index = -1 }
}
/**

View File

@@ -10,7 +10,9 @@
| CPP-205.cpp:2:15:5:1 | { ... } | isFromUninstantiatedTemplate(fn) |
| CPP-205.cpp:3:3:3:33 | declaration | isFromTemplateInstantiation(fn) |
| CPP-205.cpp:3:3:3:33 | declaration | isFromUninstantiatedTemplate(fn) |
| CPP-205.cpp:3:15:3:15 | declaration of y | isFromTemplateInstantiation(fn) |
| CPP-205.cpp:3:15:3:15 | declaration of y | isFromUninstantiatedTemplate(fn) |
| CPP-205.cpp:3:15:3:15 | y | isFromTemplateInstantiation(fn) |
| CPP-205.cpp:3:15:3:15 | y | isFromUninstantiatedTemplate(fn) |
| CPP-205.cpp:3:17:3:31 | 5 | isFromTemplateInstantiation(fn) |
| CPP-205.cpp:4:3:4:11 | return ... | isFromTemplateInstantiation(fn) |

View File

@@ -33,6 +33,7 @@ argHasPostUpdate
| test.cpp:67:29:67:35 | source1 | ArgumentNode is missing PostUpdateNode. |
| test.cpp:813:19:813:35 | * ... | ArgumentNode is missing PostUpdateNode. |
| test.cpp:848:23:848:25 | rpx | ArgumentNode is missing PostUpdateNode. |
| test.cpp:1057:19:1057:21 | * ... | ArgumentNode is missing PostUpdateNode. |
postWithInFlow
| BarrierGuard.cpp:49:6:49:6 | x [post update] | PostUpdateNode should not be the target of local flow. |
| BarrierGuard.cpp:60:7:60:7 | x [post update] | PostUpdateNode should not be the target of local flow. |
@@ -168,6 +169,13 @@ postWithInFlow
| test.cpp:1045:9:1045:11 | ref arg buf | PostUpdateNode should not be the target of local flow. |
| test.cpp:1051:5:1051:11 | content [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:1052:9:1052:9 | a [inner post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:1056:5:1056:7 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:1056:6:1056:7 | pp [inner post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:1062:53:1062:53 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:1072:3:1072:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:1072:4:1072:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:1073:3:1073:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:1073:4:1073:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
viableImplInCallContextTooLarge
uniqueParameterNodeAtPosition
uniqueParameterNodePosition

View File

@@ -1050,4 +1050,26 @@ void flow_out_of_address_with_local_flow() {
MyStruct a;
a.content = nullptr;
sink(&a); // $ SPURIOUS: ast
}
}
static void static_func_that_reassigns_pointer_before_sink(char** pp) { // $ ast-def=pp ir-def=*pp ir-def=**pp
*pp = "";
indirect_sink(*pp); // clean
}
void test_static_func_that_reassigns_pointer_before_sink() {
char* p = (char*)indirect_source();
static_func_that_reassigns_pointer_before_sink(&p);
}
void single_object_in_both_cases(bool b, int x, int y) {
int* p;
if(b) {
p = &x;
} else {
p = &y;
}
*p = source();
*p = 0;
sink(*p); // clean
}

View File

@@ -15,4 +15,5 @@ incorrectBaseType
| test.cpp:848:23:848:25 | (reference dereference) | Expected 'Node.getType()' to be int, but it was int * |
| test.cpp:854:10:854:36 | * ... | Expected 'Node.getType()' to be const int, but it was int |
| test.cpp:867:10:867:30 | * ... | Expected 'Node.getType()' to be const int, but it was int |
| test.cpp:1062:52:1062:53 | *& ... | Expected 'Node.getType()' to be char, but it was char * |
failures

View File

@@ -15440,6 +15440,8 @@ ir.cpp:
# 1911| Type = [CTypedefType,NestedTypedefType] pointer
# 1911| getEntryPoint(): [BlockStmt] { ... }
# 1912| getStmt(0): [DeclStmt] declaration
# 1912| getDeclarationEntry(0): [TypeDeclarationEntry] declaration of _Res
# 1912| Type = [CTypedefType,LocalTypedefType] _Res
# 1913| getStmt(1): [ReturnStmt] return ...
# 1913| getExpr(): [VariableAccess] p
# 1913| Type = [CTypedefType,NestedTypedefType] pointer
@@ -15547,6 +15549,10 @@ ir.cpp:
# 1924| <params>:
# 1924| getEntryPoint(): [BlockStmt] { ... }
# 1925| getStmt(0): [DeclStmt] declaration
# 1925| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
# 1925| Type = [ArrayType] int[10]
# 1925| getDeclarationEntry(1): [VariableDeclarationEntry] definition of y
# 1925| Type = [ArrayType] int[10]
# 1926| getStmt(1): [ExprStmt] ExprStmt
# 1926| getExpr(): [AssignExpr] ... = ...
# 1926| Type = [IntType] int
@@ -15642,7 +15648,11 @@ ir.cpp:
# 1939| <params>:
# 1939| getEntryPoint(): [BlockStmt] { ... }
# 1940| getStmt(0): [DeclStmt] declaration
# 1940| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of g
# 1940| Type = [IntType] int
# 1941| getStmt(1): [DeclStmt] declaration
# 1941| getDeclarationEntry(0): [FunctionDeclarationEntry] declaration of z
# 1941| Type = [IntType] int
# 1942| getStmt(2): [ReturnStmt] return ...
# 1942| getExpr(): [VariableAccess] g
# 1942| Type = [IntType] int
@@ -20163,6 +20173,30 @@ ir.cpp:
# 2430| Type = [ClassTemplateInstantiation,Struct] iterator<random_access_iterator_tag, char, ptrdiff_t, char *, char &>
# 2430| ValueCategory = lvalue
# 2432| getStmt(6): [ReturnStmt] return ...
# 2434| [TopLevelFunction] void param_with_destructor_by_value(ClassWithDestructor)
# 2434| <params>:
# 2434| getParameter(0): [Parameter] c
# 2434| Type = [Class] ClassWithDestructor
# 2434| getEntryPoint(): [BlockStmt] { ... }
# 2436| getStmt(0): [ReturnStmt] return ...
# 2438| [TopLevelFunction] void param_with_destructor_by_pointer(ClassWithDestructor*)
# 2438| <params>:
# 2438| getParameter(0): [Parameter] c
# 2438| Type = [PointerType] ClassWithDestructor *
# 2438| getEntryPoint(): [BlockStmt] { ... }
# 2440| getStmt(0): [ReturnStmt] return ...
# 2442| [TopLevelFunction] void param_with_destructor_by_ref(ClassWithDestructor&)
# 2442| <params>:
# 2442| getParameter(0): [Parameter] c
# 2442| Type = [LValueReferenceType] ClassWithDestructor &
# 2442| getEntryPoint(): [BlockStmt] { ... }
# 2444| getStmt(0): [ReturnStmt] return ...
# 2446| [TopLevelFunction] void param_with_destructor_by_rref(ClassWithDestructor&&)
# 2446| <params>:
# 2446| getParameter(0): [Parameter] c
# 2446| Type = [RValueReferenceType] ClassWithDestructor &&
# 2446| getEntryPoint(): [BlockStmt] { ... }
# 2448| getStmt(0): [ReturnStmt] return ...
perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| <params>:

File diff suppressed because it is too large Load Diff

View File

@@ -2431,4 +2431,20 @@ void initialization_with_temp_destructor() {
y += x;
}
void param_with_destructor_by_value(ClassWithDestructor c) {
// The call to ~ClassWithDestructor::ClassWithDestructor() seems to be missing here.
}
void param_with_destructor_by_pointer(ClassWithDestructor* c) {
// No destructor call should be here
}
void param_with_destructor_by_ref(ClassWithDestructor& c) {
// No destructor call should be here
}
void param_with_destructor_by_rref(ClassWithDestructor&& c) {
// No destructor call should be here
}
// semmle-extractor-options: -std=c++20 --clang

File diff suppressed because it is too large Load Diff

View File

@@ -6910,22 +6910,20 @@ ir.cpp:
# 1127| mu1127_25(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = ^IndirectMayWriteSideEffect[-1] : &:r0_6
#-----| r0_11(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = Load[#temp0:0] : &:r0_6, ~m?
# 1127| r1127_26(bool) = Call[operator!=] : func:r1127_20, this:r0_5, 0:r0_11
# 1127| mu1127_27(unknown) = ^CallSideEffect : ~m?
#-----| v0_12(void) = ^IndirectReadSideEffect[-1] : &:r0_5, ~m?
# 1127| v1127_28(void) = ConditionalBranch : r1127_26
# 1127| v1127_27(void) = ConditionalBranch : r1127_26
#-----| False -> Block 5
#-----| True -> Block 2
# 1127| Block 2
# 1127| r1127_29(glval<int>) = VariableAddress[e] :
# 1127| r1127_30(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
#-----| r0_13(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = Convert : r1127_30
# 1127| r1127_31(glval<unknown>) = FunctionAddress[operator*] :
# 1127| r1127_32(int &) = Call[operator*] : func:r1127_31, this:r0_13
# 1127| mu1127_33(unknown) = ^CallSideEffect : ~m?
# 1127| r1127_28(glval<int>) = VariableAddress[e] :
# 1127| r1127_29(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
#-----| r0_13(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = Convert : r1127_29
# 1127| r1127_30(glval<unknown>) = FunctionAddress[operator*] :
# 1127| r1127_31(int &) = Call[operator*] : func:r1127_30, this:r0_13
#-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_13, ~m?
# 1127| r1127_34(int) = Load[?] : &:r1127_32, ~m?
# 1127| mu1127_35(int) = Store[e] : &:r1127_29, r1127_34
# 1127| r1127_32(int) = Load[?] : &:r1127_31, ~m?
# 1127| mu1127_33(int) = Store[e] : &:r1127_28, r1127_32
# 1128| r1128_1(glval<int>) = VariableAddress[e] :
# 1128| r1128_2(int) = Load[e] : &:r1128_1, ~m?
# 1128| r1128_3(int) = Constant[0] :
@@ -6939,14 +6937,13 @@ ir.cpp:
#-----| Goto -> Block 4
# 1127| Block 4
# 1127| v1127_36(void) = NoOp :
# 1127| r1127_37(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
# 1127| r1127_38(glval<unknown>) = FunctionAddress[operator++] :
# 1127| r1127_39(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &> &) = Call[operator++] : func:r1127_38, this:r1127_37
# 1127| mu1127_40(unknown) = ^CallSideEffect : ~m?
# 1127| v1127_41(void) = ^IndirectReadSideEffect[-1] : &:r1127_37, ~m?
# 1127| mu1127_42(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = ^IndirectMayWriteSideEffect[-1] : &:r1127_37
# 1127| r1127_43(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = CopyValue : r1127_39
# 1127| v1127_34(void) = NoOp :
# 1127| r1127_35(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
# 1127| r1127_36(glval<unknown>) = FunctionAddress[operator++] :
# 1127| r1127_37(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &> &) = Call[operator++] : func:r1127_36, this:r1127_35
# 1127| v1127_38(void) = ^IndirectReadSideEffect[-1] : &:r1127_35, ~m?
# 1127| mu1127_39(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = ^IndirectMayWriteSideEffect[-1] : &:r1127_35
# 1127| r1127_40(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = CopyValue : r1127_37
#-----| Goto (back edge) -> Block 1
# 1133| Block 5
@@ -6990,34 +6987,31 @@ ir.cpp:
# 1133| mu1133_25(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = ^IndirectMayWriteSideEffect[-1] : &:r0_20
#-----| r0_25(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = Load[#temp0:0] : &:r0_20, ~m?
# 1133| r1133_26(bool) = Call[operator!=] : func:r1133_20, this:r0_19, 0:r0_25
# 1133| mu1133_27(unknown) = ^CallSideEffect : ~m?
#-----| v0_26(void) = ^IndirectReadSideEffect[-1] : &:r0_19, ~m?
# 1133| v1133_28(void) = ConditionalBranch : r1133_26
# 1133| v1133_27(void) = ConditionalBranch : r1133_26
#-----| False -> Block 10
#-----| True -> Block 8
# 1133| Block 7
# 1133| r1133_29(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
# 1133| r1133_30(glval<unknown>) = FunctionAddress[operator++] :
# 1133| r1133_31(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &> &) = Call[operator++] : func:r1133_30, this:r1133_29
# 1133| mu1133_32(unknown) = ^CallSideEffect : ~m?
# 1133| v1133_33(void) = ^IndirectReadSideEffect[-1] : &:r1133_29, ~m?
# 1133| mu1133_34(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = ^IndirectMayWriteSideEffect[-1] : &:r1133_29
# 1133| r1133_35(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = CopyValue : r1133_31
# 1133| r1133_28(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
# 1133| r1133_29(glval<unknown>) = FunctionAddress[operator++] :
# 1133| r1133_30(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &> &) = Call[operator++] : func:r1133_29, this:r1133_28
# 1133| v1133_31(void) = ^IndirectReadSideEffect[-1] : &:r1133_28, ~m?
# 1133| mu1133_32(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = ^IndirectMayWriteSideEffect[-1] : &:r1133_28
# 1133| r1133_33(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = CopyValue : r1133_30
#-----| Goto (back edge) -> Block 6
# 1133| Block 8
# 1133| r1133_36(glval<int &>) = VariableAddress[e] :
# 1133| r1133_37(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
#-----| r0_27(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = Convert : r1133_37
# 1133| r1133_38(glval<unknown>) = FunctionAddress[operator*] :
# 1133| r1133_39(int &) = Call[operator*] : func:r1133_38, this:r0_27
# 1133| mu1133_40(unknown) = ^CallSideEffect : ~m?
# 1133| r1133_34(glval<int &>) = VariableAddress[e] :
# 1133| r1133_35(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
#-----| r0_27(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = Convert : r1133_35
# 1133| r1133_36(glval<unknown>) = FunctionAddress[operator*] :
# 1133| r1133_37(int &) = Call[operator*] : func:r1133_36, this:r0_27
#-----| v0_28(void) = ^IndirectReadSideEffect[-1] : &:r0_27, ~m?
# 1133| r1133_41(glval<int>) = CopyValue : r1133_39
# 1133| r1133_42(glval<int>) = Convert : r1133_41
# 1133| r1133_43(int &) = CopyValue : r1133_42
# 1133| mu1133_44(int &) = Store[e] : &:r1133_36, r1133_43
# 1133| r1133_38(glval<int>) = CopyValue : r1133_37
# 1133| r1133_39(glval<int>) = Convert : r1133_38
# 1133| r1133_40(int &) = CopyValue : r1133_39
# 1133| mu1133_41(int &) = Store[e] : &:r1133_34, r1133_40
# 1134| r1134_1(glval<int &>) = VariableAddress[e] :
# 1134| r1134_2(int &) = Load[e] : &:r1134_1, ~m?
# 1134| r1134_3(int) = Load[?] : &:r1134_2, ~m?
@@ -12620,22 +12614,20 @@ ir.cpp:
# 2215| mu2215_34(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r0_8
#-----| r0_13(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Load[#temp0:0] : &:r0_8, ~m?
# 2215| r2215_35(bool) = Call[operator!=] : func:r2215_29, this:r0_7, 0:r0_13
# 2215| mu2215_36(unknown) = ^CallSideEffect : ~m?
#-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~m?
# 2215| v2215_37(void) = ConditionalBranch : r2215_35
# 2215| v2215_36(void) = ConditionalBranch : r2215_35
#-----| False -> Block 14
#-----| True -> Block 12
# 2215| Block 12
# 2215| r2215_38(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2215| r2215_39(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
#-----| r0_15(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2215_39
# 2215| r2215_40(glval<unknown>) = FunctionAddress[operator*] :
# 2215| r2215_41(ClassWithDestructor &) = Call[operator*] : func:r2215_40, this:r0_15
# 2215| mu2215_42(unknown) = ^CallSideEffect : ~m?
# 2215| r2215_37(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2215| r2215_38(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
#-----| r0_15(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2215_38
# 2215| r2215_39(glval<unknown>) = FunctionAddress[operator*] :
# 2215| r2215_40(ClassWithDestructor &) = Call[operator*] : func:r2215_39, this:r0_15
#-----| v0_16(void) = ^IndirectReadSideEffect[-1] : &:r0_15, ~m?
# 2215| r2215_43(ClassWithDestructor) = Load[?] : &:r2215_41, ~m?
# 2215| mu2215_44(ClassWithDestructor) = Store[y] : &:r2215_38, r2215_43
# 2215| r2215_41(ClassWithDestructor) = Load[?] : &:r2215_40, ~m?
# 2215| mu2215_42(ClassWithDestructor) = Store[y] : &:r2215_37, r2215_41
# 2216| r2216_1(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2216| r2216_2(glval<unknown>) = FunctionAddress[set_x] :
# 2216| r2216_3(char) = Constant[97] :
@@ -12643,28 +12635,27 @@ ir.cpp:
# 2216| mu2216_5(unknown) = ^CallSideEffect : ~m?
# 2216| v2216_6(void) = ^IndirectReadSideEffect[-1] : &:r2216_1, ~m?
# 2216| mu2216_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2216_1
# 2215| r2215_45(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2215| r2215_46(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2215| v2215_47(void) = Call[~ClassWithDestructor] : func:r2215_46, this:r2215_45
# 2215| mu2215_48(unknown) = ^CallSideEffect : ~m?
# 2215| v2215_49(void) = ^IndirectReadSideEffect[-1] : &:r2215_45, ~m?
# 2215| mu2215_50(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2215_45
# 2215| r2215_51(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
# 2215| r2215_52(glval<unknown>) = FunctionAddress[operator++] :
# 2215| r2215_53(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2215_52, this:r2215_51
# 2215| mu2215_54(unknown) = ^CallSideEffect : ~m?
# 2215| v2215_55(void) = ^IndirectReadSideEffect[-1] : &:r2215_51, ~m?
# 2215| mu2215_56(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2215_51
# 2215| r2215_57(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2215_53
# 2215| r2215_43(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2215| r2215_44(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2215| v2215_45(void) = Call[~ClassWithDestructor] : func:r2215_44, this:r2215_43
# 2215| mu2215_46(unknown) = ^CallSideEffect : ~m?
# 2215| v2215_47(void) = ^IndirectReadSideEffect[-1] : &:r2215_43, ~m?
# 2215| mu2215_48(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2215_43
# 2215| r2215_49(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
# 2215| r2215_50(glval<unknown>) = FunctionAddress[operator++] :
# 2215| r2215_51(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2215_50, this:r2215_49
# 2215| v2215_52(void) = ^IndirectReadSideEffect[-1] : &:r2215_49, ~m?
# 2215| mu2215_53(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2215_49
# 2215| r2215_54(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2215_51
#-----| Goto (back edge) -> Block 11
# 2215| Block 13
# 2215| r2215_58(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2215| r2215_59(glval<unknown>) = FunctionAddress[~vector] :
# 2215| v2215_60(void) = Call[~vector] : func:r2215_59, this:r2215_58
# 2215| mu2215_61(unknown) = ^CallSideEffect : ~m?
# 2215| v2215_62(void) = ^IndirectReadSideEffect[-1] : &:r2215_58, ~m?
# 2215| mu2215_63(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2215_58
# 2215| r2215_55(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2215| r2215_56(glval<unknown>) = FunctionAddress[~vector] :
# 2215| v2215_57(void) = Call[~vector] : func:r2215_56, this:r2215_55
# 2215| mu2215_58(unknown) = ^CallSideEffect : ~m?
# 2215| v2215_59(void) = ^IndirectReadSideEffect[-1] : &:r2215_55, ~m?
# 2215| mu2215_60(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2215_55
#-----| Goto -> Block 14
# 2218| Block 14
@@ -12719,22 +12710,20 @@ ir.cpp:
# 2218| mu2218_34(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r0_24
#-----| r0_29(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Load[#temp0:0] : &:r0_24, ~m?
# 2218| r2218_35(bool) = Call[operator!=] : func:r2218_29, this:r0_23, 0:r0_29
# 2218| mu2218_36(unknown) = ^CallSideEffect : ~m?
#-----| v0_30(void) = ^IndirectReadSideEffect[-1] : &:r0_23, ~m?
# 2218| v2218_37(void) = ConditionalBranch : r2218_35
# 2218| v2218_36(void) = ConditionalBranch : r2218_35
#-----| False -> Block 20
#-----| True -> Block 16
# 2218| Block 16
# 2218| r2218_38(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2218| r2218_39(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
#-----| r0_31(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2218_39
# 2218| r2218_40(glval<unknown>) = FunctionAddress[operator*] :
# 2218| r2218_41(ClassWithDestructor &) = Call[operator*] : func:r2218_40, this:r0_31
# 2218| mu2218_42(unknown) = ^CallSideEffect : ~m?
# 2218| r2218_37(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2218| r2218_38(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
#-----| r0_31(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2218_38
# 2218| r2218_39(glval<unknown>) = FunctionAddress[operator*] :
# 2218| r2218_40(ClassWithDestructor &) = Call[operator*] : func:r2218_39, this:r0_31
#-----| v0_32(void) = ^IndirectReadSideEffect[-1] : &:r0_31, ~m?
# 2218| r2218_43(ClassWithDestructor) = Load[?] : &:r2218_41, ~m?
# 2218| mu2218_44(ClassWithDestructor) = Store[y] : &:r2218_38, r2218_43
# 2218| r2218_41(ClassWithDestructor) = Load[?] : &:r2218_40, ~m?
# 2218| mu2218_42(ClassWithDestructor) = Store[y] : &:r2218_37, r2218_41
# 2219| r2219_1(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2219| r2219_2(glval<unknown>) = FunctionAddress[set_x] :
# 2219| r2219_3(char) = Constant[97] :
@@ -12757,18 +12746,18 @@ ir.cpp:
# 2221| Block 17
# 2221| v2221_1(void) = NoOp :
# 2218| r2218_45(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2218| r2218_46(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2218| v2218_47(void) = Call[~ClassWithDestructor] : func:r2218_46, this:r2218_45
# 2218| mu2218_48(unknown) = ^CallSideEffect : ~m?
# 2218| v2218_49(void) = ^IndirectReadSideEffect[-1] : &:r2218_45, ~m?
# 2218| mu2218_50(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2218_45
# 2218| r2218_51(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2218| r2218_52(glval<unknown>) = FunctionAddress[~vector] :
# 2218| v2218_53(void) = Call[~vector] : func:r2218_52, this:r2218_51
# 2218| mu2218_54(unknown) = ^CallSideEffect : ~m?
# 2218| v2218_55(void) = ^IndirectReadSideEffect[-1] : &:r2218_51, ~m?
# 2218| mu2218_56(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_51
# 2218| r2218_43(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2218| r2218_44(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2218| v2218_45(void) = Call[~ClassWithDestructor] : func:r2218_44, this:r2218_43
# 2218| mu2218_46(unknown) = ^CallSideEffect : ~m?
# 2218| v2218_47(void) = ^IndirectReadSideEffect[-1] : &:r2218_43, ~m?
# 2218| mu2218_48(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2218_43
# 2218| r2218_49(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2218| r2218_50(glval<unknown>) = FunctionAddress[~vector] :
# 2218| v2218_51(void) = Call[~vector] : func:r2218_50, this:r2218_49
# 2218| mu2218_52(unknown) = ^CallSideEffect : ~m?
# 2218| v2218_53(void) = ^IndirectReadSideEffect[-1] : &:r2218_49, ~m?
# 2218| mu2218_54(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_49
# 2233| r2233_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2233| r2233_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2233| v2233_3(void) = Call[~ClassWithDestructor] : func:r2233_2, this:r2233_1
@@ -12778,28 +12767,27 @@ ir.cpp:
#-----| Goto -> Block 1
# 2218| Block 18
# 2218| r2218_57(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2218| r2218_58(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2218| v2218_59(void) = Call[~ClassWithDestructor] : func:r2218_58, this:r2218_57
# 2218| mu2218_60(unknown) = ^CallSideEffect : ~m?
# 2218| v2218_61(void) = ^IndirectReadSideEffect[-1] : &:r2218_57, ~m?
# 2218| mu2218_62(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2218_57
# 2218| r2218_63(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
# 2218| r2218_64(glval<unknown>) = FunctionAddress[operator++] :
# 2218| r2218_65(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2218_64, this:r2218_63
# 2218| mu2218_66(unknown) = ^CallSideEffect : ~m?
# 2218| v2218_67(void) = ^IndirectReadSideEffect[-1] : &:r2218_63, ~m?
# 2218| mu2218_68(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_63
# 2218| r2218_69(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2218_65
# 2218| r2218_55(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2218| r2218_56(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2218| v2218_57(void) = Call[~ClassWithDestructor] : func:r2218_56, this:r2218_55
# 2218| mu2218_58(unknown) = ^CallSideEffect : ~m?
# 2218| v2218_59(void) = ^IndirectReadSideEffect[-1] : &:r2218_55, ~m?
# 2218| mu2218_60(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2218_55
# 2218| r2218_61(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
# 2218| r2218_62(glval<unknown>) = FunctionAddress[operator++] :
# 2218| r2218_63(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2218_62, this:r2218_61
# 2218| v2218_64(void) = ^IndirectReadSideEffect[-1] : &:r2218_61, ~m?
# 2218| mu2218_65(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_61
# 2218| r2218_66(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2218_63
#-----| Goto (back edge) -> Block 15
# 2218| Block 19
# 2218| r2218_70(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2218| r2218_71(glval<unknown>) = FunctionAddress[~vector] :
# 2218| v2218_72(void) = Call[~vector] : func:r2218_71, this:r2218_70
# 2218| mu2218_73(unknown) = ^CallSideEffect : ~m?
# 2218| v2218_74(void) = ^IndirectReadSideEffect[-1] : &:r2218_70, ~m?
# 2218| mu2218_75(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_70
# 2218| r2218_67(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2218| r2218_68(glval<unknown>) = FunctionAddress[~vector] :
# 2218| v2218_69(void) = Call[~vector] : func:r2218_68, this:r2218_67
# 2218| mu2218_70(unknown) = ^CallSideEffect : ~m?
# 2218| v2218_71(void) = ^IndirectReadSideEffect[-1] : &:r2218_67, ~m?
# 2218| mu2218_72(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_67
#-----| Goto -> Block 20
# 2224| Block 20
@@ -12850,32 +12838,29 @@ ir.cpp:
# 2224| mu2224_30(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = ^IndirectMayWriteSideEffect[-1] : &:r0_40
#-----| r0_45(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = Load[#temp0:0] : &:r0_40, ~m?
# 2224| r2224_31(bool) = Call[operator!=] : func:r2224_25, this:r0_39, 0:r0_45
# 2224| mu2224_32(unknown) = ^CallSideEffect : ~m?
#-----| v0_46(void) = ^IndirectReadSideEffect[-1] : &:r0_39, ~m?
# 2224| v2224_33(void) = ConditionalBranch : r2224_31
# 2224| v2224_32(void) = ConditionalBranch : r2224_31
#-----| False -> Block 26
#-----| True -> Block 23
# 2224| Block 22
# 2224| r2224_34(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
# 2224| r2224_35(glval<unknown>) = FunctionAddress[operator++] :
# 2224| r2224_36(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &> &) = Call[operator++] : func:r2224_35, this:r2224_34
# 2224| mu2224_37(unknown) = ^CallSideEffect : ~m?
# 2224| v2224_38(void) = ^IndirectReadSideEffect[-1] : &:r2224_34, ~m?
# 2224| mu2224_39(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = ^IndirectMayWriteSideEffect[-1] : &:r2224_34
# 2224| r2224_40(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = CopyValue : r2224_36
# 2224| r2224_33(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
# 2224| r2224_34(glval<unknown>) = FunctionAddress[operator++] :
# 2224| r2224_35(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &> &) = Call[operator++] : func:r2224_34, this:r2224_33
# 2224| v2224_36(void) = ^IndirectReadSideEffect[-1] : &:r2224_33, ~m?
# 2224| mu2224_37(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = ^IndirectMayWriteSideEffect[-1] : &:r2224_33
# 2224| r2224_38(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = CopyValue : r2224_35
#-----| Goto (back edge) -> Block 21
# 2224| Block 23
# 2224| r2224_41(glval<int>) = VariableAddress[y] :
# 2224| r2224_42(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
#-----| r0_47(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = Convert : r2224_42
# 2224| r2224_43(glval<unknown>) = FunctionAddress[operator*] :
# 2224| r2224_44(int &) = Call[operator*] : func:r2224_43, this:r0_47
# 2224| mu2224_45(unknown) = ^CallSideEffect : ~m?
# 2224| r2224_39(glval<int>) = VariableAddress[y] :
# 2224| r2224_40(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
#-----| r0_47(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = Convert : r2224_40
# 2224| r2224_41(glval<unknown>) = FunctionAddress[operator*] :
# 2224| r2224_42(int &) = Call[operator*] : func:r2224_41, this:r0_47
#-----| v0_48(void) = ^IndirectReadSideEffect[-1] : &:r0_47, ~m?
# 2224| r2224_46(int) = Load[?] : &:r2224_44, ~m?
# 2224| mu2224_47(int) = Store[y] : &:r2224_41, r2224_46
# 2224| r2224_43(int) = Load[?] : &:r2224_42, ~m?
# 2224| mu2224_44(int) = Store[y] : &:r2224_39, r2224_43
# 2225| r2225_1(glval<int>) = VariableAddress[y] :
# 2225| r2225_2(int) = Load[y] : &:r2225_1, ~m?
# 2225| r2225_3(int) = Constant[1] :
@@ -12886,12 +12871,12 @@ ir.cpp:
# 2226| Block 24
# 2226| v2226_1(void) = NoOp :
# 2224| r2224_48(glval<vector<int>>) = VariableAddress[ys] :
# 2224| r2224_49(glval<unknown>) = FunctionAddress[~vector] :
# 2224| v2224_50(void) = Call[~vector] : func:r2224_49, this:r2224_48
# 2224| mu2224_51(unknown) = ^CallSideEffect : ~m?
# 2224| v2224_52(void) = ^IndirectReadSideEffect[-1] : &:r2224_48, ~m?
# 2224| mu2224_53(vector<int>) = ^IndirectMayWriteSideEffect[-1] : &:r2224_48
# 2224| r2224_45(glval<vector<int>>) = VariableAddress[ys] :
# 2224| r2224_46(glval<unknown>) = FunctionAddress[~vector] :
# 2224| v2224_47(void) = Call[~vector] : func:r2224_46, this:r2224_45
# 2224| mu2224_48(unknown) = ^CallSideEffect : ~m?
# 2224| v2224_49(void) = ^IndirectReadSideEffect[-1] : &:r2224_45, ~m?
# 2224| mu2224_50(vector<int>) = ^IndirectMayWriteSideEffect[-1] : &:r2224_45
# 2233| r2233_7(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2233| r2233_8(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2233| v2233_9(void) = Call[~ClassWithDestructor] : func:r2233_8, this:r2233_7
@@ -12901,12 +12886,12 @@ ir.cpp:
#-----| Goto -> Block 1
# 2224| Block 25
# 2224| r2224_54(glval<vector<int>>) = VariableAddress[ys] :
# 2224| r2224_55(glval<unknown>) = FunctionAddress[~vector] :
# 2224| v2224_56(void) = Call[~vector] : func:r2224_55, this:r2224_54
# 2224| mu2224_57(unknown) = ^CallSideEffect : ~m?
# 2224| v2224_58(void) = ^IndirectReadSideEffect[-1] : &:r2224_54, ~m?
# 2224| mu2224_59(vector<int>) = ^IndirectMayWriteSideEffect[-1] : &:r2224_54
# 2224| r2224_51(glval<vector<int>>) = VariableAddress[ys] :
# 2224| r2224_52(glval<unknown>) = FunctionAddress[~vector] :
# 2224| v2224_53(void) = Call[~vector] : func:r2224_52, this:r2224_51
# 2224| mu2224_54(unknown) = ^CallSideEffect : ~m?
# 2224| v2224_55(void) = ^IndirectReadSideEffect[-1] : &:r2224_51, ~m?
# 2224| mu2224_56(vector<int>) = ^IndirectMayWriteSideEffect[-1] : &:r2224_51
#-----| Goto -> Block 26
# 2229| Block 26
@@ -12961,22 +12946,20 @@ ir.cpp:
# 2229| mu2229_34(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r0_56
#-----| r0_61(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Load[#temp0:0] : &:r0_56, ~m?
# 2229| r2229_35(bool) = Call[operator!=] : func:r2229_29, this:r0_55, 0:r0_61
# 2229| mu2229_36(unknown) = ^CallSideEffect : ~m?
#-----| v0_62(void) = ^IndirectReadSideEffect[-1] : &:r0_55, ~m?
# 2229| v2229_37(void) = ConditionalBranch : r2229_35
# 2229| v2229_36(void) = ConditionalBranch : r2229_35
#-----| False -> Block 30
#-----| True -> Block 28
# 2229| Block 28
# 2229| r2229_38(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2229| r2229_39(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
#-----| r0_63(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2229_39
# 2229| r2229_40(glval<unknown>) = FunctionAddress[operator*] :
# 2229| r2229_41(ClassWithDestructor &) = Call[operator*] : func:r2229_40, this:r0_63
# 2229| mu2229_42(unknown) = ^CallSideEffect : ~m?
# 2229| r2229_37(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2229| r2229_38(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
#-----| r0_63(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2229_38
# 2229| r2229_39(glval<unknown>) = FunctionAddress[operator*] :
# 2229| r2229_40(ClassWithDestructor &) = Call[operator*] : func:r2229_39, this:r0_63
#-----| v0_64(void) = ^IndirectReadSideEffect[-1] : &:r0_63, ~m?
# 2229| r2229_43(ClassWithDestructor) = Load[?] : &:r2229_41, ~m?
# 2229| mu2229_44(ClassWithDestructor) = Store[y] : &:r2229_38, r2229_43
# 2229| r2229_41(ClassWithDestructor) = Load[?] : &:r2229_40, ~m?
# 2229| mu2229_42(ClassWithDestructor) = Store[y] : &:r2229_37, r2229_41
# 2230| r2230_1(glval<ClassWithDestructor>) = VariableAddress[z1] :
# 2230| mu2230_2(ClassWithDestructor) = Uninitialized[z1] : &:r2230_1
# 2230| r2230_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
@@ -13001,28 +12984,27 @@ ir.cpp:
# 2232| mu2232_10(unknown) = ^CallSideEffect : ~m?
# 2232| v2232_11(void) = ^IndirectReadSideEffect[-1] : &:r2232_7, ~m?
# 2232| mu2232_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2232_7
# 2229| r2229_45(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2229| r2229_46(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2229| v2229_47(void) = Call[~ClassWithDestructor] : func:r2229_46, this:r2229_45
# 2229| mu2229_48(unknown) = ^CallSideEffect : ~m?
# 2229| v2229_49(void) = ^IndirectReadSideEffect[-1] : &:r2229_45, ~m?
# 2229| mu2229_50(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2229_45
# 2229| r2229_51(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
# 2229| r2229_52(glval<unknown>) = FunctionAddress[operator++] :
# 2229| r2229_53(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2229_52, this:r2229_51
# 2229| mu2229_54(unknown) = ^CallSideEffect : ~m?
# 2229| v2229_55(void) = ^IndirectReadSideEffect[-1] : &:r2229_51, ~m?
# 2229| mu2229_56(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2229_51
# 2229| r2229_57(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2229_53
# 2229| r2229_43(glval<ClassWithDestructor>) = VariableAddress[y] :
# 2229| r2229_44(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2229| v2229_45(void) = Call[~ClassWithDestructor] : func:r2229_44, this:r2229_43
# 2229| mu2229_46(unknown) = ^CallSideEffect : ~m?
# 2229| v2229_47(void) = ^IndirectReadSideEffect[-1] : &:r2229_43, ~m?
# 2229| mu2229_48(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2229_43
# 2229| r2229_49(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
# 2229| r2229_50(glval<unknown>) = FunctionAddress[operator++] :
# 2229| r2229_51(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2229_50, this:r2229_49
# 2229| v2229_52(void) = ^IndirectReadSideEffect[-1] : &:r2229_49, ~m?
# 2229| mu2229_53(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2229_49
# 2229| r2229_54(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2229_51
#-----| Goto (back edge) -> Block 27
# 2229| Block 29
# 2229| r2229_58(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2229| r2229_59(glval<unknown>) = FunctionAddress[~vector] :
# 2229| v2229_60(void) = Call[~vector] : func:r2229_59, this:r2229_58
# 2229| mu2229_61(unknown) = ^CallSideEffect : ~m?
# 2229| v2229_62(void) = ^IndirectReadSideEffect[-1] : &:r2229_58, ~m?
# 2229| mu2229_63(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2229_58
# 2229| r2229_55(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
# 2229| r2229_56(glval<unknown>) = FunctionAddress[~vector] :
# 2229| v2229_57(void) = Call[~vector] : func:r2229_56, this:r2229_55
# 2229| mu2229_58(unknown) = ^CallSideEffect : ~m?
# 2229| v2229_59(void) = ^IndirectReadSideEffect[-1] : &:r2229_55, ~m?
# 2229| mu2229_60(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2229_55
#-----| Goto -> Block 30
# 2233| Block 30
@@ -13610,29 +13592,27 @@ ir.cpp:
# 2307| mu2307_38(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>) = ^IndirectMayWriteSideEffect[-1] : &:r0_8
#-----| r0_13(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>) = Load[#temp0:0] : &:r0_8, ~m?
# 2307| r2307_39(bool) = Call[operator!=] : func:r2307_33, this:r0_7, 0:r0_13
# 2307| mu2307_40(unknown) = ^CallSideEffect : ~m?
#-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~m?
# 2307| v2307_41(void) = ConditionalBranch : r2307_39
# 2307| v2307_40(void) = ConditionalBranch : r2307_39
#-----| False -> Block 6
#-----| True -> Block 5
# 2307| Block 5
# 2307| r2307_42(glval<String>) = VariableAddress[s] :
# 2307| mu2307_43(String) = Uninitialized[s] : &:r2307_42
# 2307| r2307_44(glval<unknown>) = FunctionAddress[String] :
# 2307| r2307_45(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = VariableAddress[(__begin)] :
#-----| r0_15(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = Convert : r2307_45
# 2307| r2307_46(glval<unknown>) = FunctionAddress[operator*] :
# 2307| r2307_47(String &) = Call[operator*] : func:r2307_46, this:r0_15
# 2307| mu2307_48(unknown) = ^CallSideEffect : ~m?
# 2307| r2307_41(glval<String>) = VariableAddress[s] :
# 2307| mu2307_42(String) = Uninitialized[s] : &:r2307_41
# 2307| r2307_43(glval<unknown>) = FunctionAddress[String] :
# 2307| r2307_44(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = VariableAddress[(__begin)] :
#-----| r0_15(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = Convert : r2307_44
# 2307| r2307_45(glval<unknown>) = FunctionAddress[operator*] :
# 2307| r2307_46(String &) = Call[operator*] : func:r2307_45, this:r0_15
#-----| v0_16(void) = ^IndirectReadSideEffect[-1] : &:r0_15, ~m?
# 2307| r2307_49(glval<String>) = CopyValue : r2307_47
# 2307| r2307_50(glval<String>) = Convert : r2307_49
# 2307| r2307_51(String &) = CopyValue : r2307_50
# 2307| v2307_52(void) = Call[String] : func:r2307_44, this:r2307_42, 0:r2307_51
# 2307| mu2307_53(unknown) = ^CallSideEffect : ~m?
# 2307| v2307_54(void) = ^BufferReadSideEffect[0] : &:r2307_51, ~m?
# 2307| mu2307_55(String) = ^IndirectMayWriteSideEffect[-1] : &:r2307_42
# 2307| r2307_47(glval<String>) = CopyValue : r2307_46
# 2307| r2307_48(glval<String>) = Convert : r2307_47
# 2307| r2307_49(String &) = CopyValue : r2307_48
# 2307| v2307_50(void) = Call[String] : func:r2307_43, this:r2307_41, 0:r2307_49
# 2307| mu2307_51(unknown) = ^CallSideEffect : ~m?
# 2307| v2307_52(void) = ^BufferReadSideEffect[0] : &:r2307_49, ~m?
# 2307| mu2307_53(String) = ^IndirectMayWriteSideEffect[-1] : &:r2307_41
# 2308| r2308_1(glval<String>) = VariableAddress[s2] :
# 2308| mu2308_2(String) = Uninitialized[s2] : &:r2308_1
# 2308| r2308_3(glval<unknown>) = FunctionAddress[String] :
@@ -13645,19 +13625,18 @@ ir.cpp:
# 2309| mu2309_4(unknown) = ^CallSideEffect : ~m?
# 2309| v2309_5(void) = ^IndirectReadSideEffect[-1] : &:r2309_1, ~m?
# 2309| mu2309_6(String) = ^IndirectMayWriteSideEffect[-1] : &:r2309_1
# 2307| r2307_56(glval<String>) = VariableAddress[s] :
# 2307| r2307_57(glval<unknown>) = FunctionAddress[~String] :
# 2307| v2307_58(void) = Call[~String] : func:r2307_57, this:r2307_56
# 2307| mu2307_59(unknown) = ^CallSideEffect : ~m?
# 2307| v2307_60(void) = ^IndirectReadSideEffect[-1] : &:r2307_56, ~m?
# 2307| mu2307_61(String) = ^IndirectMayWriteSideEffect[-1] : &:r2307_56
# 2307| r2307_62(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = VariableAddress[(__begin)] :
# 2307| r2307_63(glval<unknown>) = FunctionAddress[operator++] :
# 2307| r2307_64(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &> &) = Call[operator++] : func:r2307_63, this:r2307_62
# 2307| mu2307_65(unknown) = ^CallSideEffect : ~m?
# 2307| v2307_66(void) = ^IndirectReadSideEffect[-1] : &:r2307_62, ~m?
# 2307| mu2307_67(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>) = ^IndirectMayWriteSideEffect[-1] : &:r2307_62
# 2307| r2307_68(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = CopyValue : r2307_64
# 2307| r2307_54(glval<String>) = VariableAddress[s] :
# 2307| r2307_55(glval<unknown>) = FunctionAddress[~String] :
# 2307| v2307_56(void) = Call[~String] : func:r2307_55, this:r2307_54
# 2307| mu2307_57(unknown) = ^CallSideEffect : ~m?
# 2307| v2307_58(void) = ^IndirectReadSideEffect[-1] : &:r2307_54, ~m?
# 2307| mu2307_59(String) = ^IndirectMayWriteSideEffect[-1] : &:r2307_54
# 2307| r2307_60(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = VariableAddress[(__begin)] :
# 2307| r2307_61(glval<unknown>) = FunctionAddress[operator++] :
# 2307| r2307_62(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &> &) = Call[operator++] : func:r2307_61, this:r2307_60
# 2307| v2307_63(void) = ^IndirectReadSideEffect[-1] : &:r2307_60, ~m?
# 2307| mu2307_64(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>) = ^IndirectMayWriteSideEffect[-1] : &:r2307_60
# 2307| r2307_65(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = CopyValue : r2307_62
#-----| Goto (back edge) -> Block 4
# 2311| Block 6
@@ -14322,22 +14301,20 @@ ir.cpp:
# 2430| mu2430_43(iterator<random_access_iterator_tag, char, ptrdiff_t, char *, char &>) = ^IndirectMayWriteSideEffect[-1] : &:r0_8
#-----| r0_13(iterator<random_access_iterator_tag, char, ptrdiff_t, char *, char &>) = Load[#temp0:0] : &:r0_8, ~m?
# 2430| r2430_44(bool) = Call[operator!=] : func:r2430_38, this:r0_7, 0:r0_13
# 2430| mu2430_45(unknown) = ^CallSideEffect : ~m?
#-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~m?
# 2430| v2430_46(void) = ConditionalBranch : r2430_44
# 2430| v2430_45(void) = ConditionalBranch : r2430_44
#-----| False -> Block 13
#-----| True -> Block 12
# 2430| Block 12
# 2430| r2430_47(glval<char>) = VariableAddress[y] :
# 2430| r2430_48(glval<iterator<random_access_iterator_tag, char, ptrdiff_t, char *, char &>>) = VariableAddress[(__begin)] :
#-----| r0_15(glval<iterator<random_access_iterator_tag, char, ptrdiff_t, char *, char &>>) = Convert : r2430_48
# 2430| r2430_49(glval<unknown>) = FunctionAddress[operator*] :
# 2430| r2430_50(char &) = Call[operator*] : func:r2430_49, this:r0_15
# 2430| mu2430_51(unknown) = ^CallSideEffect : ~m?
# 2430| r2430_46(glval<char>) = VariableAddress[y] :
# 2430| r2430_47(glval<iterator<random_access_iterator_tag, char, ptrdiff_t, char *, char &>>) = VariableAddress[(__begin)] :
#-----| r0_15(glval<iterator<random_access_iterator_tag, char, ptrdiff_t, char *, char &>>) = Convert : r2430_47
# 2430| r2430_48(glval<unknown>) = FunctionAddress[operator*] :
# 2430| r2430_49(char &) = Call[operator*] : func:r2430_48, this:r0_15
#-----| v0_16(void) = ^IndirectReadSideEffect[-1] : &:r0_15, ~m?
# 2430| r2430_52(char) = Load[?] : &:r2430_50, ~m?
# 2430| mu2430_53(char) = Store[y] : &:r2430_47, r2430_52
# 2430| r2430_50(char) = Load[?] : &:r2430_49, ~m?
# 2430| mu2430_51(char) = Store[y] : &:r2430_46, r2430_50
# 2431| r2431_1(glval<char>) = VariableAddress[x] :
# 2431| r2431_2(char) = Load[x] : &:r2431_1, ~m?
# 2431| r2431_3(int) = Convert : r2431_2
@@ -14347,13 +14324,12 @@ ir.cpp:
# 2431| r2431_7(int) = Add : r2431_6, r2431_3
# 2431| r2431_8(char) = Convert : r2431_7
# 2431| mu2431_9(char) = Store[y] : &:r2431_4, r2431_8
# 2430| r2430_54(glval<iterator<random_access_iterator_tag, char, ptrdiff_t, char *, char &>>) = VariableAddress[(__begin)] :
# 2430| r2430_55(glval<unknown>) = FunctionAddress[operator++] :
# 2430| r2430_56(iterator<random_access_iterator_tag, char, ptrdiff_t, char *, char &> &) = Call[operator++] : func:r2430_55, this:r2430_54
# 2430| mu2430_57(unknown) = ^CallSideEffect : ~m?
# 2430| v2430_58(void) = ^IndirectReadSideEffect[-1] : &:r2430_54, ~m?
# 2430| mu2430_59(iterator<random_access_iterator_tag, char, ptrdiff_t, char *, char &>) = ^IndirectMayWriteSideEffect[-1] : &:r2430_54
# 2430| r2430_60(glval<iterator<random_access_iterator_tag, char, ptrdiff_t, char *, char &>>) = CopyValue : r2430_56
# 2430| r2430_52(glval<iterator<random_access_iterator_tag, char, ptrdiff_t, char *, char &>>) = VariableAddress[(__begin)] :
# 2430| r2430_53(glval<unknown>) = FunctionAddress[operator++] :
# 2430| r2430_54(iterator<random_access_iterator_tag, char, ptrdiff_t, char *, char &> &) = Call[operator++] : func:r2430_53, this:r2430_52
# 2430| v2430_55(void) = ^IndirectReadSideEffect[-1] : &:r2430_52, ~m?
# 2430| mu2430_56(iterator<random_access_iterator_tag, char, ptrdiff_t, char *, char &>) = ^IndirectMayWriteSideEffect[-1] : &:r2430_52
# 2430| r2430_57(glval<iterator<random_access_iterator_tag, char, ptrdiff_t, char *, char &>>) = CopyValue : r2430_54
#-----| Goto (back edge) -> Block 11
# 2432| Block 13
@@ -14362,6 +14338,63 @@ ir.cpp:
# 2410| v2410_5(void) = AliasedUse : ~m?
# 2410| v2410_6(void) = ExitFunction :
# 2434| void param_with_destructor_by_value(ClassWithDestructor)
# 2434| Block 0
# 2434| v2434_1(void) = EnterFunction :
# 2434| mu2434_2(unknown) = AliasedDefinition :
# 2434| mu2434_3(unknown) = InitializeNonLocal :
# 2434| r2434_4(glval<ClassWithDestructor>) = VariableAddress[c] :
# 2434| mu2434_5(ClassWithDestructor) = InitializeParameter[c] : &:r2434_4
# 2436| v2436_1(void) = NoOp :
# 2434| v2434_6(void) = ReturnVoid :
# 2434| v2434_7(void) = AliasedUse : ~m?
# 2434| v2434_8(void) = ExitFunction :
# 2438| void param_with_destructor_by_pointer(ClassWithDestructor*)
# 2438| Block 0
# 2438| v2438_1(void) = EnterFunction :
# 2438| mu2438_2(unknown) = AliasedDefinition :
# 2438| mu2438_3(unknown) = InitializeNonLocal :
# 2438| r2438_4(glval<ClassWithDestructor *>) = VariableAddress[c] :
# 2438| mu2438_5(ClassWithDestructor *) = InitializeParameter[c] : &:r2438_4
# 2438| r2438_6(ClassWithDestructor *) = Load[c] : &:r2438_4, ~m?
# 2438| mu2438_7(unknown) = InitializeIndirection[c] : &:r2438_6
# 2440| v2440_1(void) = NoOp :
# 2438| v2438_8(void) = ReturnIndirection[c] : &:r2438_6, ~m?
# 2438| v2438_9(void) = ReturnVoid :
# 2438| v2438_10(void) = AliasedUse : ~m?
# 2438| v2438_11(void) = ExitFunction :
# 2442| void param_with_destructor_by_ref(ClassWithDestructor&)
# 2442| Block 0
# 2442| v2442_1(void) = EnterFunction :
# 2442| mu2442_2(unknown) = AliasedDefinition :
# 2442| mu2442_3(unknown) = InitializeNonLocal :
# 2442| r2442_4(glval<ClassWithDestructor &>) = VariableAddress[c] :
# 2442| mu2442_5(ClassWithDestructor &) = InitializeParameter[c] : &:r2442_4
# 2442| r2442_6(ClassWithDestructor &) = Load[c] : &:r2442_4, ~m?
# 2442| mu2442_7(unknown) = InitializeIndirection[c] : &:r2442_6
# 2444| v2444_1(void) = NoOp :
# 2442| v2442_8(void) = ReturnIndirection[c] : &:r2442_6, ~m?
# 2442| v2442_9(void) = ReturnVoid :
# 2442| v2442_10(void) = AliasedUse : ~m?
# 2442| v2442_11(void) = ExitFunction :
# 2446| void param_with_destructor_by_rref(ClassWithDestructor&&)
# 2446| Block 0
# 2446| v2446_1(void) = EnterFunction :
# 2446| mu2446_2(unknown) = AliasedDefinition :
# 2446| mu2446_3(unknown) = InitializeNonLocal :
# 2446| r2446_4(glval<ClassWithDestructor &&>) = VariableAddress[c] :
# 2446| mu2446_5(ClassWithDestructor &&) = InitializeParameter[c] : &:r2446_4
# 2446| r2446_6(ClassWithDestructor &&) = Load[c] : &:r2446_4, ~m?
# 2446| mu2446_7(unknown) = InitializeIndirection[c] : &:r2446_6
# 2448| v2448_1(void) = NoOp :
# 2446| v2446_8(void) = ReturnIndirection[c] : &:r2446_6, ~m?
# 2446| v2446_9(void) = ReturnVoid :
# 2446| v2446_10(void) = AliasedUse : ~m?
# 2446| v2446_11(void) = ExitFunction :
perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Semmle.Util.Logging;
@@ -20,44 +19,16 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
/// assembly cache.
/// </param>
/// <param name="logger">Callback for progress.</param>
public AssemblyCache(IEnumerable<string> paths, IEnumerable<string> frameworkPaths, ILogger logger)
public AssemblyCache(IEnumerable<AssemblyLookupLocation> paths, IEnumerable<string> frameworkPaths, ILogger logger)
{
this.logger = logger;
foreach (var path in paths)
{
if (File.Exists(path))
{
dllsToIndex.Add(path);
continue;
}
if (Directory.Exists(path))
{
logger.LogInfo($"Finding reference DLLs in {path}...");
AddReferenceDirectory(path);
}
else
{
logger.LogInfo("AssemblyCache: Path not found: " + path);
}
dllsToIndex.AddRange(path.GetDlls(logger));
}
IndexReferences(frameworkPaths);
}
/// <summary>
/// Finds all assemblies nested within a directory
/// and adds them to its index.
/// (Indexing is performed at a later stage by IndexReferences()).
/// </summary>
/// <param name="dir">The directory to index.</param>
private void AddReferenceDirectory(string dir)
{
foreach (var dll in new DirectoryInfo(dir).EnumerateFiles("*.dll", SearchOption.AllDirectories))
{
dllsToIndex.Add(dll.FullName);
}
}
/// <summary>
/// Indexes all DLLs we have located.
/// Because this is a potentially time-consuming operation, it is put into a separate stage.

View File

@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Semmle.Util.Logging;
namespace Semmle.Extraction.CSharp.DependencyFetching
{
/// <summary>
/// Used to represent a path to an assembly or a directory containing assemblies
/// and a selector function to determine which files to include, when indexing the assemblies.
/// </summary>
internal sealed class AssemblyLookupLocation(string path, Func<string, bool> includeFileName, bool indexSubdirectories = true)
{
public string Path => path;
public AssemblyLookupLocation(string path) : this(path, _ => true) { }
public static implicit operator AssemblyLookupLocation(string path) => new(path);
/// <summary>
/// Finds all assemblies nested within the directory `path`
/// and adds them to the a list of assembly names to index.
/// Indexing is performed at a later stage. This only collects the names.
/// </summary>
/// <param name="dllsToIndex">List of dlls to index.</param>
/// <param name="logger">Logger.</param>
private void AddReferenceDirectory(List<string> dllsToIndex, ILogger logger)
{
try
{
var dlls = new DirectoryInfo(path).EnumerateFiles("*.dll", new EnumerationOptions { RecurseSubdirectories = indexSubdirectories, MatchCasing = MatchCasing.CaseInsensitive, AttributesToSkip = FileAttributes.None });
if (!dlls.Any())
{
logger.LogWarning($"AssemblyLookupLocation: No DLLs found in the path '{path}'.");
return;
}
foreach (var dll in dlls)
{
if (includeFileName(dll.Name))
{
dllsToIndex.Add(dll.FullName);
}
else
{
logger.LogInfo($"AssemblyLookupLocation: Skipping {dll.FullName}.");
}
}
}
catch (Exception e)
{
logger.LogError($"AssemblyLookupLocation: Error while searching for DLLs in '{path}': {e.Message}");
}
}
/// <summary>
/// Returns a list of paths to all assemblies in `path` that should be indexed.
/// </summary>
/// <param name="logger">Logger</param>
public List<string> GetDlls(ILogger logger)
{
var dllsToIndex = new List<string>();
if (File.Exists(path))
{
if (includeFileName(System.IO.Path.GetFileName(path)))
{
dllsToIndex.Add(path);
}
else
{
logger.LogInfo($"AssemblyLookupLocation: Skipping {path}.");
}
return dllsToIndex;
}
if (Directory.Exists(path))
{
logger.LogInfo($"AssemblyLookupLocation: Finding reference DLLs in {path}...");
AddReferenceDirectory(dllsToIndex, logger);
}
else
{
logger.LogInfo("AssemblyLookupLocation: Path not found: " + path);
}
return dllsToIndex;
}
public override bool Equals(object? obj) =>
obj is AssemblyLookupLocation ap && path.Equals(ap.Path);
public override int GetHashCode() => path.GetHashCode();
public override string ToString() => path;
}
}

View File

@@ -0,0 +1,514 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Semmle.Util;
namespace Semmle.Extraction.CSharp.DependencyFetching
{
public sealed partial class DependencyManager
{
private void RestoreNugetPackages(List<FileInfo> allNonBinaryFiles, IEnumerable<string> allProjects, IEnumerable<string> allSolutions, HashSet<AssemblyLookupLocation> dllLocations)
{
try
{
var checkNugetFeedResponsiveness = EnvironmentVariables.GetBoolean(EnvironmentVariableNames.CheckNugetFeedResponsiveness);
if (checkNugetFeedResponsiveness && !CheckFeeds(allNonBinaryFiles))
{
DownloadMissingPackages(allNonBinaryFiles, dllLocations, withNugetConfig: false);
return;
}
using (var nuget = new NugetPackages(sourceDir.FullName, legacyPackageDirectory, logger))
{
var count = nuget.InstallPackages();
if (nuget.PackageCount > 0)
{
CompilationInfos.Add(("packages.config files", nuget.PackageCount.ToString()));
CompilationInfos.Add(("Successfully restored packages.config files", count.ToString()));
}
}
var nugetPackageDlls = legacyPackageDirectory.DirInfo.GetFiles("*.dll", new EnumerationOptions { RecurseSubdirectories = true });
var nugetPackageDllPaths = nugetPackageDlls.Select(f => f.FullName).ToHashSet();
var excludedPaths = nugetPackageDllPaths
.Where(path => IsPathInSubfolder(path, legacyPackageDirectory.DirInfo.FullName, "tools"))
.ToList();
if (nugetPackageDllPaths.Count > 0)
{
logger.LogInfo($"Restored {nugetPackageDllPaths.Count} Nuget DLLs.");
}
if (excludedPaths.Count > 0)
{
logger.LogInfo($"Excluding {excludedPaths.Count} Nuget DLLs.");
}
foreach (var excludedPath in excludedPaths)
{
logger.LogInfo($"Excluded Nuget DLL: {excludedPath}");
}
nugetPackageDllPaths.ExceptWith(excludedPaths);
dllLocations.UnionWith(nugetPackageDllPaths.Select(p => new AssemblyLookupLocation(p)));
}
catch (Exception exc)
{
logger.LogError($"Failed to restore Nuget packages with nuget.exe: {exc.Message}");
}
var restoredProjects = RestoreSolutions(allSolutions, out var assets1);
var projects = allProjects.Except(restoredProjects);
RestoreProjects(projects, out var assets2);
var dependencies = Assets.GetCompilationDependencies(logger, assets1.Union(assets2));
var paths = dependencies
.Paths
.Select(d => Path.Combine(packageDirectory.DirInfo.FullName, d))
.ToList();
dllLocations.UnionWith(paths.Select(p => new AssemblyLookupLocation(p)));
LogAllUnusedPackages(dependencies);
DownloadMissingPackages(allNonBinaryFiles, dllLocations);
}
/// <summary>
/// Executes `dotnet restore` on all solution files in solutions.
/// As opposed to RestoreProjects this is not run in parallel using PLINQ
/// as `dotnet restore` on a solution already uses multiple threads for restoring
/// the projects (this can be disabled with the `--disable-parallel` flag).
/// Populates assets with the relative paths to the assets files generated by the restore.
/// Returns a list of projects that are up to date with respect to restore.
/// </summary>
/// <param name="solutions">A list of paths to solution files.</param>
private IEnumerable<string> RestoreSolutions(IEnumerable<string> solutions, out IEnumerable<string> assets)
{
var successCount = 0;
var nugetSourceFailures = 0;
var assetFiles = new List<string>();
var projects = solutions.SelectMany(solution =>
{
logger.LogInfo($"Restoring solution {solution}...");
var res = dotnet.Restore(new(solution, packageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true));
if (res.Success)
{
successCount++;
}
if (res.HasNugetPackageSourceError)
{
nugetSourceFailures++;
}
assetFiles.AddRange(res.AssetsFilePaths);
return res.RestoredProjects;
}).ToList();
assets = assetFiles;
CompilationInfos.Add(("Successfully restored solution files", successCount.ToString()));
CompilationInfos.Add(("Failed solution restore with package source error", nugetSourceFailures.ToString()));
CompilationInfos.Add(("Restored projects through solution files", projects.Count.ToString()));
return projects;
}
/// <summary>
/// Executes `dotnet restore` on all projects in projects.
/// This is done in parallel for performance reasons.
/// Populates assets with the relative paths to the assets files generated by the restore.
/// </summary>
/// <param name="projects">A list of paths to project files.</param>
private void RestoreProjects(IEnumerable<string> projects, out IEnumerable<string> assets)
{
var successCount = 0;
var nugetSourceFailures = 0;
var assetFiles = new List<string>();
var sync = new object();
Parallel.ForEach(projects, new ParallelOptions { MaxDegreeOfParallelism = threads }, project =>
{
logger.LogInfo($"Restoring project {project}...");
var res = dotnet.Restore(new(project, packageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true));
lock (sync)
{
if (res.Success)
{
successCount++;
}
if (res.HasNugetPackageSourceError)
{
nugetSourceFailures++;
}
assetFiles.AddRange(res.AssetsFilePaths);
}
});
assets = assetFiles;
CompilationInfos.Add(("Successfully restored project files", successCount.ToString()));
CompilationInfos.Add(("Failed project restore with package source error", nugetSourceFailures.ToString()));
}
private void DownloadMissingPackages(List<FileInfo> allFiles, ISet<AssemblyLookupLocation> dllLocations, bool withNugetConfig = true)
{
var alreadyDownloadedPackages = GetRestoredPackageDirectoryNames(packageDirectory.DirInfo);
var alreadyDownloadedLegacyPackages = GetRestoredLegacyPackageNames();
var notYetDownloadedPackages = new HashSet<PackageReference>(fileContent.AllPackages);
foreach (var alreadyDownloadedPackage in alreadyDownloadedPackages)
{
notYetDownloadedPackages.Remove(new(alreadyDownloadedPackage, PackageReferenceSource.SdkCsProj));
}
foreach (var alreadyDownloadedLegacyPackage in alreadyDownloadedLegacyPackages)
{
notYetDownloadedPackages.Remove(new(alreadyDownloadedLegacyPackage, PackageReferenceSource.PackagesConfig));
}
if (notYetDownloadedPackages.Count == 0)
{
return;
}
var multipleVersions = notYetDownloadedPackages
.GroupBy(p => p.Name)
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.ToList();
foreach (var package in multipleVersions)
{
logger.LogWarning($"Found multiple not yet restored packages with name '{package}'.");
notYetDownloadedPackages.Remove(new(package, PackageReferenceSource.PackagesConfig));
}
logger.LogInfo($"Found {notYetDownloadedPackages.Count} packages that are not yet restored");
var nugetConfig = withNugetConfig
? GetNugetConfig(allFiles)
: null;
CompilationInfos.Add(("Fallback nuget restore", notYetDownloadedPackages.Count.ToString()));
var successCount = 0;
var sync = new object();
Parallel.ForEach(notYetDownloadedPackages, new ParallelOptions { MaxDegreeOfParallelism = threads }, package =>
{
var success = TryRestorePackageManually(package.Name, nugetConfig, package.PackageReferenceSource);
if (!success)
{
return;
}
lock (sync)
{
successCount++;
}
});
CompilationInfos.Add(("Successfully ran fallback nuget restore", successCount.ToString()));
dllLocations.Add(missingPackageDirectory.DirInfo.FullName);
}
private string[] GetAllNugetConfigs(List<FileInfo> allFiles) => allFiles.SelectFileNamesByName("nuget.config").ToArray();
private string? GetNugetConfig(List<FileInfo> allFiles)
{
var nugetConfigs = GetAllNugetConfigs(allFiles);
string? nugetConfig;
if (nugetConfigs.Length > 1)
{
logger.LogInfo($"Found multiple nuget.config files: {string.Join(", ", nugetConfigs)}.");
nugetConfig = allFiles
.SelectRootFiles(sourceDir)
.SelectFileNamesByName("nuget.config")
.FirstOrDefault();
if (nugetConfig == null)
{
logger.LogInfo("Could not find a top-level nuget.config file.");
}
}
else
{
nugetConfig = nugetConfigs.FirstOrDefault();
}
if (nugetConfig != null)
{
logger.LogInfo($"Using nuget.config file {nugetConfig}.");
}
return nugetConfig;
}
private void LogAllUnusedPackages(DependencyContainer dependencies)
{
var allPackageDirectories = GetAllPackageDirectories();
logger.LogInfo($"Restored {allPackageDirectories.Count} packages");
logger.LogInfo($"Found {dependencies.Packages.Count} packages in project.assets.json files");
allPackageDirectories
.Where(package => !dependencies.Packages.Contains(package))
.Order()
.ForEach(package => logger.LogInfo($"Unused package: {package}"));
}
private ICollection<string> GetAllPackageDirectories()
{
return new DirectoryInfo(packageDirectory.DirInfo.FullName)
.EnumerateDirectories("*", new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = false })
.Select(d => d.Name)
.ToList();
}
private static bool IsPathInSubfolder(string path, string rootFolder, string subFolder)
{
return path.IndexOf(
$"{Path.DirectorySeparatorChar}{subFolder}{Path.DirectorySeparatorChar}",
rootFolder.Length,
StringComparison.InvariantCultureIgnoreCase) >= 0;
}
private IEnumerable<string> GetRestoredLegacyPackageNames()
{
var oldPackageDirectories = GetRestoredPackageDirectoryNames(legacyPackageDirectory.DirInfo);
foreach (var oldPackageDirectory in oldPackageDirectories)
{
// nuget install restores packages to 'packagename.version' folders (dotnet restore to 'packagename/version' folders)
// typical folder names look like:
// newtonsoft.json.13.0.3
// there are more complex ones too, such as:
// runtime.tizen.4.0.0-armel.Microsoft.NETCore.DotNetHostResolver.2.0.0-preview2-25407-01
var match = LegacyNugetPackage().Match(oldPackageDirectory);
if (!match.Success)
{
logger.LogWarning($"Package directory '{oldPackageDirectory}' doesn't match the expected pattern.");
continue;
}
yield return match.Groups[1].Value.ToLowerInvariant();
}
}
private static IEnumerable<string> GetRestoredPackageDirectoryNames(DirectoryInfo root)
{
return Directory.GetDirectories(root.FullName)
.Select(d => Path.GetFileName(d).ToLowerInvariant());
}
private bool TryRestorePackageManually(string package, string? nugetConfig, PackageReferenceSource packageReferenceSource = PackageReferenceSource.SdkCsProj)
{
logger.LogInfo($"Restoring package {package}...");
using var tempDir = new TemporaryDirectory(ComputeTempDirectory(package, "missingpackages_workingdir"));
var success = dotnet.New(tempDir.DirInfo.FullName);
if (!success)
{
return false;
}
if (packageReferenceSource == PackageReferenceSource.PackagesConfig)
{
TryChangeTargetFrameworkMoniker(tempDir.DirInfo);
}
success = dotnet.AddPackage(tempDir.DirInfo.FullName, package);
if (!success)
{
return false;
}
var res = dotnet.Restore(new(tempDir.DirInfo.FullName, missingPackageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: false, PathToNugetConfig: nugetConfig));
if (!res.Success)
{
if (res.HasNugetPackageSourceError && nugetConfig is not null)
{
// Restore could not be completed because the listed source is unavailable. Try without the nuget.config:
res = dotnet.Restore(new(tempDir.DirInfo.FullName, missingPackageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: false, PathToNugetConfig: null, ForceReevaluation: true));
}
// TODO: the restore might fail, we could retry with
// - a prerelease (*-* instead of *) version of the package,
// - a different target framework moniker.
if (!res.Success)
{
logger.LogInfo($"Failed to restore nuget package {package}");
return false;
}
}
return true;
}
private void TryChangeTargetFrameworkMoniker(DirectoryInfo tempDir)
{
try
{
logger.LogInfo($"Changing the target framework moniker in {tempDir.FullName}...");
var csprojs = tempDir.GetFiles("*.csproj", new EnumerationOptions { RecurseSubdirectories = false, MatchCasing = MatchCasing.CaseInsensitive });
if (csprojs.Length != 1)
{
logger.LogError($"Could not find the .csproj file in {tempDir.FullName}, count = {csprojs.Length}");
return;
}
var csproj = csprojs[0];
var content = File.ReadAllText(csproj.FullName);
var matches = TargetFramework().Matches(content);
if (matches.Count == 0)
{
logger.LogError($"Could not find target framework in {csproj.FullName}");
}
else
{
content = TargetFramework().Replace(content, $"<TargetFramework>{FrameworkPackageNames.LatestNetFrameworkMoniker}</TargetFramework>", 1);
File.WriteAllText(csproj.FullName, content);
}
}
catch (Exception exc)
{
logger.LogError($"Failed to update target framework in {tempDir.FullName}: {exc}");
}
}
private static async Task ExecuteGetRequest(string address, HttpClient httpClient, CancellationToken cancellationToken)
{
using var stream = await httpClient.GetStreamAsync(address, cancellationToken);
var buffer = new byte[1024];
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
// do nothing
}
}
private bool IsFeedReachable(string feed)
{
logger.LogInfo($"Checking if Nuget feed '{feed}' is reachable...");
using HttpClient client = new();
int timeoutMilliSeconds = int.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetFeedResponsivenessInitialTimeout), out timeoutMilliSeconds)
? timeoutMilliSeconds
: 1000;
int tryCount = int.TryParse(Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetFeedResponsivenessRequestCount), out tryCount)
? tryCount
: 4;
for (var i = 0; i < tryCount; i++)
{
using var cts = new CancellationTokenSource();
cts.CancelAfter(timeoutMilliSeconds);
try
{
ExecuteGetRequest(feed, client, cts.Token).GetAwaiter().GetResult();
return true;
}
catch (Exception exc)
{
if (exc is TaskCanceledException tce &&
tce.CancellationToken == cts.Token &&
cts.Token.IsCancellationRequested)
{
logger.LogWarning($"Didn't receive answer from Nuget feed '{feed}' in {timeoutMilliSeconds}ms.");
timeoutMilliSeconds *= 2;
continue;
}
// We're only interested in timeouts.
logger.LogWarning($"Querying Nuget feed '{feed}' failed: {exc}");
return true;
}
}
logger.LogWarning($"Didn't receive answer from Nuget feed '{feed}'. Tried it {tryCount} times.");
return false;
}
private bool CheckFeeds(List<FileInfo> allFiles)
{
logger.LogInfo("Checking Nuget feeds...");
var feeds = GetAllFeeds(allFiles);
var excludedFeeds = Environment.GetEnvironmentVariable(EnvironmentVariableNames.ExcludedNugetFeedsFromResponsivenessCheck)
?.Split(" ", StringSplitOptions.RemoveEmptyEntries)
.ToHashSet() ?? [];
if (excludedFeeds.Count > 0)
{
logger.LogInfo($"Excluded Nuget feeds from responsiveness check: {string.Join(", ", excludedFeeds.OrderBy(f => f))}");
}
var allFeedsReachable = feeds.All(feed => excludedFeeds.Contains(feed) || IsFeedReachable(feed));
if (!allFeedsReachable)
{
logger.LogWarning("Found unreachable Nuget feed in C# analysis with build-mode 'none'. This may cause missing dependencies in the analysis.");
diagnosticsWriter.AddEntry(new DiagnosticMessage(
Language.CSharp,
"buildless/unreachable-feed",
"Found unreachable Nuget feed in C# analysis with build-mode 'none'",
visibility: new DiagnosticMessage.TspVisibility(statusPage: true, cliSummaryTable: true, telemetry: true),
markdownMessage: "Found unreachable Nuget feed in C# analysis with build-mode 'none'. This may cause missing dependencies in the analysis.",
severity: DiagnosticMessage.TspSeverity.Warning
));
}
CompilationInfos.Add(("All Nuget feeds reachable", allFeedsReachable ? "1" : "0"));
return allFeedsReachable;
}
private IEnumerable<string> GetFeeds(string nugetConfig)
{
logger.LogInfo($"Getting Nuget feeds from '{nugetConfig}'...");
var results = dotnet.GetNugetFeeds(nugetConfig);
var regex = EnabledNugetFeed();
foreach (var result in results)
{
var match = regex.Match(result);
if (!match.Success)
{
logger.LogError($"Failed to parse feed from '{result}'");
continue;
}
var url = match.Groups[1].Value;
if (!url.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase) &&
!url.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase))
{
logger.LogInfo($"Skipping feed '{url}' as it is not a valid URL.");
continue;
}
yield return url;
}
}
private HashSet<string> GetAllFeeds(List<FileInfo> allFiles)
{
var nugetConfigs = GetAllNugetConfigs(allFiles);
var feeds = nugetConfigs
.SelectMany(GetFeeds)
.Where(str => !string.IsNullOrWhiteSpace(str))
.ToHashSet();
if (feeds.Count > 0)
{
logger.LogInfo($"Found {feeds.Count} Nuget feeds in nuget.config files: {string.Join(", ", feeds.OrderBy(f => f))}");
}
else
{
logger.LogDebug("No Nuget feeds found in nuget.config files.");
}
return feeds;
}
[GeneratedRegex(@"<TargetFramework>.*</TargetFramework>", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)]
private static partial Regex TargetFramework();
[GeneratedRegex(@"^(.+)\.(\d+\.\d+\.\d+(-(.+))?)$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)]
private static partial Regex LegacyNugetPackage();
[GeneratedRegex(@"^E\s(.*)$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)]
private static partial Regex EnabledNugetFeed();
}
}

View File

@@ -5,7 +5,6 @@ using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Semmle.Util;
@@ -20,6 +19,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
{
private readonly AssemblyCache assemblyCache;
private readonly ILogger logger;
private readonly IDiagnosticsWriter diagnosticsWriter;
// Only used as a set, but ConcurrentDictionary is the only concurrent set in .NET.
private readonly IDictionary<string, bool> usedReferences = new ConcurrentDictionary<string, bool>();
@@ -45,13 +45,32 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
/// <summary>
/// Performs C# dependency fetching.
/// </summary>
/// <param name="options">Dependency fetching options</param>
/// <param name="srcDir">Path to directory containing source code.</param>
/// <param name="logger">Logger for dependency fetching progress.</param>
public DependencyManager(string srcDir, ILogger logger)
{
var startTime = DateTime.Now;
this.logger = logger;
var diagDirEnv = Environment.GetEnvironmentVariable(EnvironmentVariableNames.DiagnosticDir);
if (!string.IsNullOrWhiteSpace(diagDirEnv) &&
!Directory.Exists(diagDirEnv))
{
try
{
Directory.CreateDirectory(diagDirEnv);
}
catch (Exception e)
{
logger.LogError($"Failed to create diagnostic directory {diagDirEnv}: {e.Message}");
diagDirEnv = null;
}
}
this.diagnosticsWriter = new DiagnosticsStream(Path.Combine(
diagDirEnv ?? "",
$"dependency-manager-{DateTime.UtcNow:yyyyMMddHHmm}-{Environment.ProcessId}.jsonc"));
this.sourceDir = new DirectoryInfo(srcDir);
packageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName, "packages"));
@@ -71,9 +90,9 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
this.generatedSources = new();
var allProjects = allNonBinaryFiles.SelectFileNamesByExtension(".csproj").ToList();
var allSolutions = allNonBinaryFiles.SelectFileNamesByExtension(".sln").ToList();
var dllPaths = allFiles.SelectFileNamesByExtension(".dll").ToHashSet();
var dllLocations = allFiles.SelectFileNamesByExtension(".dll").Select(x => new AssemblyLookupLocation(x)).ToHashSet();
logger.LogInfo($"Found {allFiles.Count} files, {nonGeneratedSources.Count} source files, {allProjects.Count} project files, {allSolutions.Count} solution files, {dllPaths.Count} DLLs.");
logger.LogInfo($"Found {allFiles.Count} files, {nonGeneratedSources.Count} source files, {allProjects.Count} project files, {allSolutions.Count} solution files, {dllLocations.Count} DLLs.");
void startCallback(string s, bool silent)
{
@@ -102,12 +121,12 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
throw;
}
RestoreNugetPackages(allNonBinaryFiles, allProjects, allSolutions, dllPaths);
RestoreNugetPackages(allNonBinaryFiles, allProjects, allSolutions, dllLocations);
// Find DLLs in the .Net / Asp.Net Framework
// This needs to come after the nuget restore, because the nuget restore might fetch the .NET Core/Framework reference assemblies.
var frameworkLocations = AddFrameworkDlls(dllPaths);
var frameworkLocations = AddFrameworkDlls(dllLocations);
assemblyCache = new AssemblyCache(dllPaths, frameworkLocations, logger);
assemblyCache = new AssemblyCache(dllLocations, frameworkLocations, logger);
AnalyseSolutions(allSolutions);
foreach (var filename in assemblyCache.AllAssemblies.Select(a => a.Filename))
@@ -172,18 +191,17 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
]);
}
private HashSet<string> AddFrameworkDlls(HashSet<string> dllPaths)
private HashSet<string> AddFrameworkDlls(HashSet<AssemblyLookupLocation> dllLocations)
{
var frameworkLocations = new HashSet<string>();
var frameworkReferences = Environment.GetEnvironmentVariable(EnvironmentVariableNames.DotnetFrameworkReferences);
var frameworkReferencesUseSubfolders = Environment.GetEnvironmentVariable(EnvironmentVariableNames.DotnetFrameworkReferencesUseSubfolders);
_ = bool.TryParse(frameworkReferencesUseSubfolders, out var useSubfolders);
var useSubfolders = EnvironmentVariables.GetBoolean(EnvironmentVariableNames.DotnetFrameworkReferencesUseSubfolders);
if (!string.IsNullOrWhiteSpace(frameworkReferences))
{
RemoveFrameworkNugetPackages(dllPaths);
RemoveNugetPackageReference(FrameworkPackageNames.AspNetCoreFramework, dllPaths);
RemoveNugetPackageReference(FrameworkPackageNames.WindowsDesktopFramework, dllPaths);
RemoveFrameworkNugetPackages(dllLocations);
RemoveNugetPackageReference(FrameworkPackageNames.AspNetCoreFramework, dllLocations);
RemoveNugetPackageReference(FrameworkPackageNames.WindowsDesktopFramework, dllLocations);
var frameworkPaths = frameworkReferences.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries);
@@ -195,108 +213,20 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
continue;
}
if (useSubfolders)
{
dllPaths.Add(path);
frameworkLocations.Add(path);
continue;
}
try
{
var dlls = Directory.GetFiles(path, "*.dll", new EnumerationOptions { RecurseSubdirectories = false, MatchCasing = MatchCasing.CaseInsensitive });
if (dlls.Length == 0)
{
logger.LogError($"No DLLs found in specified framework reference path '{path}'.");
continue;
}
dllPaths.UnionWith(dlls);
frameworkLocations.UnionWith(dlls);
}
catch (Exception e)
{
logger.LogError($"Error while searching for DLLs in '{path}': {e.Message}");
}
dllLocations.Add(new AssemblyLookupLocation(path, _ => true, useSubfolders));
frameworkLocations.Add(path);
}
return frameworkLocations;
}
AddNetFrameworkDlls(dllPaths, frameworkLocations);
AddAspNetCoreFrameworkDlls(dllPaths, frameworkLocations);
AddMicrosoftWindowsDesktopDlls(dllPaths, frameworkLocations);
AddNetFrameworkDlls(dllLocations, frameworkLocations);
AddAspNetCoreFrameworkDlls(dllLocations, frameworkLocations);
AddMicrosoftWindowsDesktopDlls(dllLocations, frameworkLocations);
return frameworkLocations;
}
private void RestoreNugetPackages(List<FileInfo> allNonBinaryFiles, IEnumerable<string> allProjects, IEnumerable<string> allSolutions, HashSet<string> dllPaths)
{
try
{
using (var nuget = new NugetPackages(sourceDir.FullName, legacyPackageDirectory, logger))
{
var count = nuget.InstallPackages();
if (nuget.PackageCount > 0)
{
CompilationInfos.Add(("packages.config files", nuget.PackageCount.ToString()));
CompilationInfos.Add(("Successfully restored packages.config files", count.ToString()));
}
}
var nugetPackageDlls = legacyPackageDirectory.DirInfo.GetFiles("*.dll", new EnumerationOptions { RecurseSubdirectories = true });
var nugetPackageDllPaths = nugetPackageDlls.Select(f => f.FullName).ToHashSet();
var excludedPaths = nugetPackageDllPaths
.Where(path => IsPathInSubfolder(path, legacyPackageDirectory.DirInfo.FullName, "tools"))
.ToList();
if (nugetPackageDllPaths.Count > 0)
{
logger.LogInfo($"Restored {nugetPackageDllPaths.Count} Nuget DLLs.");
}
if (excludedPaths.Count > 0)
{
logger.LogInfo($"Excluding {excludedPaths.Count} Nuget DLLs.");
}
foreach (var excludedPath in excludedPaths)
{
logger.LogInfo($"Excluded Nuget DLL: {excludedPath}");
}
nugetPackageDllPaths.ExceptWith(excludedPaths);
dllPaths.UnionWith(nugetPackageDllPaths);
}
catch (Exception exc)
{
logger.LogError($"Failed to restore Nuget packages with nuget.exe: {exc.Message}");
}
var restoredProjects = RestoreSolutions(allSolutions, out var assets1);
var projects = allProjects.Except(restoredProjects);
RestoreProjects(projects, out var assets2);
var dependencies = Assets.GetCompilationDependencies(logger, assets1.Union(assets2));
var paths = dependencies
.Paths
.Select(d => Path.Combine(packageDirectory.DirInfo.FullName, d))
.ToList();
dllPaths.UnionWith(paths);
LogAllUnusedPackages(dependencies);
DownloadMissingPackages(allNonBinaryFiles, dllPaths);
}
private static bool IsPathInSubfolder(string path, string rootFolder, string subFolder)
{
return path.IndexOf(
$"{Path.DirectorySeparatorChar}{subFolder}{Path.DirectorySeparatorChar}",
rootFolder.Length,
StringComparison.InvariantCultureIgnoreCase) >= 0;
}
private void RemoveNugetAnalyzerReferences()
{
var packageFolder = packageDirectory.DirInfo.FullName.ToLowerInvariant();
@@ -332,7 +262,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
}
private void SelectNewestFrameworkPath(string frameworkPath, string frameworkType, ISet<string> dllPaths, ISet<string> frameworkLocations)
private void SelectNewestFrameworkPath(string frameworkPath, string frameworkType, ISet<AssemblyLookupLocation> dllLocations, ISet<string> frameworkLocations)
{
var versionFolders = GetPackageVersionSubDirectories(frameworkPath);
if (versionFolders.Length > 1)
@@ -348,7 +278,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
selectedFrameworkFolder = frameworkPath;
}
dllPaths.Add(selectedFrameworkFolder);
dllLocations.Add(selectedFrameworkFolder);
frameworkLocations.Add(selectedFrameworkFolder);
logger.LogInfo($"Found {frameworkType} DLLs in NuGet packages at {selectedFrameworkFolder}.");
}
@@ -361,16 +291,16 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
.ToArray();
}
private void RemoveFrameworkNugetPackages(ISet<string> dllPaths, int fromIndex = 0)
private void RemoveFrameworkNugetPackages(ISet<AssemblyLookupLocation> dllLocations, int fromIndex = 0)
{
var packagesInPrioOrder = FrameworkPackageNames.NetFrameworks;
for (var i = fromIndex; i < packagesInPrioOrder.Length; i++)
{
RemoveNugetPackageReference(packagesInPrioOrder[i], dllPaths);
RemoveNugetPackageReference(packagesInPrioOrder[i], dllLocations);
}
}
private void AddNetFrameworkDlls(ISet<string> dllPaths, ISet<string> frameworkLocations)
private void AddNetFrameworkDlls(ISet<AssemblyLookupLocation> dllLocations, ISet<string> frameworkLocations)
{
// Multiple dotnet framework packages could be present.
// The order of the packages is important, we're adding the first one that is present in the nuget cache.
@@ -390,8 +320,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
dotnetFrameworkVersionVariantCount += GetPackageVersionSubDirectories(fp.Path!).Length;
}
SelectNewestFrameworkPath(frameworkPath.Path, ".NET Framework", dllPaths, frameworkLocations);
RemoveFrameworkNugetPackages(dllPaths, frameworkPath.Index + 1);
SelectNewestFrameworkPath(frameworkPath.Path, ".NET Framework", dllLocations, frameworkLocations);
RemoveFrameworkNugetPackages(dllLocations, frameworkPath.Index + 1);
return;
}
@@ -416,14 +346,21 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
}
runtimeLocation ??= Runtime.ExecutingRuntime;
if (runtimeLocation is null)
{
runtimeLocation ??= Runtime.ExecutingRuntime;
dllLocations.Add(new AssemblyLookupLocation(runtimeLocation, name => !name.StartsWith("Semmle.")));
}
else
{
dllLocations.Add(runtimeLocation);
}
logger.LogInfo($".NET runtime location selected: {runtimeLocation}");
dllPaths.Add(runtimeLocation);
frameworkLocations.Add(runtimeLocation);
}
private void RemoveNugetPackageReference(string packagePrefix, ISet<string> dllPaths)
private void RemoveNugetPackageReference(string packagePrefix, ISet<AssemblyLookupLocation> dllLocations)
{
var packageFolder = packageDirectory.DirInfo.FullName.ToLowerInvariant();
if (packageFolder == null)
@@ -432,10 +369,10 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
var packagePathPrefix = Path.Combine(packageFolder, packagePrefix.ToLowerInvariant());
var toRemove = dllPaths.Where(s => s.StartsWith(packagePathPrefix, StringComparison.InvariantCultureIgnoreCase));
var toRemove = dllLocations.Where(s => s.Path.StartsWith(packagePathPrefix, StringComparison.InvariantCultureIgnoreCase));
foreach (var path in toRemove)
{
dllPaths.Remove(path);
dllLocations.Remove(path);
logger.LogInfo($"Removed reference {path}");
}
}
@@ -445,7 +382,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
return fileContent.IsNewProjectStructureUsed && fileContent.UseAspNetCoreDlls;
}
private void AddAspNetCoreFrameworkDlls(ISet<string> dllPaths, ISet<string> frameworkLocations)
private void AddAspNetCoreFrameworkDlls(ISet<AssemblyLookupLocation> dllLocations, ISet<string> frameworkLocations)
{
if (!IsAspNetCoreDetected())
{
@@ -455,23 +392,23 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
// First try to find ASP.NET Core assemblies in the NuGet packages
if (GetPackageDirectory(FrameworkPackageNames.AspNetCoreFramework, packageDirectory) is string aspNetCorePackage)
{
SelectNewestFrameworkPath(aspNetCorePackage, "ASP.NET Core", dllPaths, frameworkLocations);
SelectNewestFrameworkPath(aspNetCorePackage, "ASP.NET Core", dllLocations, frameworkLocations);
return;
}
if (Runtime.AspNetCoreRuntime is string aspNetCoreRuntime)
{
logger.LogInfo($"ASP.NET runtime location selected: {aspNetCoreRuntime}");
dllPaths.Add(aspNetCoreRuntime);
dllLocations.Add(aspNetCoreRuntime);
frameworkLocations.Add(aspNetCoreRuntime);
}
}
private void AddMicrosoftWindowsDesktopDlls(ISet<string> dllPaths, ISet<string> frameworkLocations)
private void AddMicrosoftWindowsDesktopDlls(ISet<AssemblyLookupLocation> dllLocations, ISet<string> frameworkLocations)
{
if (GetPackageDirectory(FrameworkPackageNames.WindowsDesktopFramework, packageDirectory) is string windowsDesktopApp)
{
SelectNewestFrameworkPath(windowsDesktopApp, "Windows Desktop App", dllPaths, frameworkLocations);
SelectNewestFrameworkPath(windowsDesktopApp, "Windows Desktop App", dllLocations, frameworkLocations);
}
}
@@ -483,27 +420,6 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
.FullName;
}
private ICollection<string> GetAllPackageDirectories()
{
return new DirectoryInfo(packageDirectory.DirInfo.FullName)
.EnumerateDirectories("*", new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = false })
.Select(d => d.Name)
.ToList();
}
private void LogAllUnusedPackages(DependencyContainer dependencies)
{
var allPackageDirectories = GetAllPackageDirectories();
logger.LogInfo($"Restored {allPackageDirectories.Count} packages");
logger.LogInfo($"Found {dependencies.Packages.Count} packages in project.assets.json files");
allPackageDirectories
.Where(package => !dependencies.Packages.Contains(package))
.Order()
.ForEach(package => logger.LogInfo($"Unused package: {package}"));
}
private void GenerateSourceFileFromImplicitUsings()
{
var usings = new HashSet<string>();
@@ -807,269 +723,6 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
}
/// <summary>
/// Executes `dotnet restore` on all solution files in solutions.
/// As opposed to RestoreProjects this is not run in parallel using PLINQ
/// as `dotnet restore` on a solution already uses multiple threads for restoring
/// the projects (this can be disabled with the `--disable-parallel` flag).
/// Populates assets with the relative paths to the assets files generated by the restore.
/// Returns a list of projects that are up to date with respect to restore.
/// </summary>
/// <param name="solutions">A list of paths to solution files.</param>
private IEnumerable<string> RestoreSolutions(IEnumerable<string> solutions, out IEnumerable<string> assets)
{
var successCount = 0;
var nugetSourceFailures = 0;
var assetFiles = new List<string>();
var projects = solutions.SelectMany(solution =>
{
logger.LogInfo($"Restoring solution {solution}...");
var res = dotnet.Restore(new(solution, packageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true));
if (res.Success)
{
successCount++;
}
if (res.HasNugetPackageSourceError)
{
nugetSourceFailures++;
}
assetFiles.AddRange(res.AssetsFilePaths);
return res.RestoredProjects;
}).ToList();
assets = assetFiles;
CompilationInfos.Add(("Successfully restored solution files", successCount.ToString()));
CompilationInfos.Add(("Failed solution restore with package source error", nugetSourceFailures.ToString()));
CompilationInfos.Add(("Restored projects through solution files", projects.Count.ToString()));
return projects;
}
/// <summary>
/// Executes `dotnet restore` on all projects in projects.
/// This is done in parallel for performance reasons.
/// Populates assets with the relative paths to the assets files generated by the restore.
/// </summary>
/// <param name="projects">A list of paths to project files.</param>
private void RestoreProjects(IEnumerable<string> projects, out IEnumerable<string> assets)
{
var successCount = 0;
var nugetSourceFailures = 0;
var assetFiles = new List<string>();
var sync = new object();
Parallel.ForEach(projects, new ParallelOptions { MaxDegreeOfParallelism = threads }, project =>
{
logger.LogInfo($"Restoring project {project}...");
var res = dotnet.Restore(new(project, packageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true));
lock (sync)
{
if (res.Success)
{
successCount++;
}
if (res.HasNugetPackageSourceError)
{
nugetSourceFailures++;
}
assetFiles.AddRange(res.AssetsFilePaths);
}
});
assets = assetFiles;
CompilationInfos.Add(("Successfully restored project files", successCount.ToString()));
CompilationInfos.Add(("Failed project restore with package source error", nugetSourceFailures.ToString()));
}
[GeneratedRegex(@"^(.+)\.(\d+\.\d+\.\d+(-(.+))?)$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)]
private static partial Regex LegacyNugetPackage();
private static IEnumerable<string> GetRestoredPackageDirectoryNames(DirectoryInfo root)
{
return Directory.GetDirectories(root.FullName)
.Select(d => Path.GetFileName(d).ToLowerInvariant());
}
private IEnumerable<string> GetRestoredLegacyPackageNames()
{
var oldPackageDirectories = GetRestoredPackageDirectoryNames(legacyPackageDirectory.DirInfo);
foreach (var oldPackageDirectory in oldPackageDirectories)
{
// nuget install restores packages to 'packagename.version' folders (dotnet restore to 'packagename/version' folders)
// typical folder names look like:
// newtonsoft.json.13.0.3
// there are more complex ones too, such as:
// runtime.tizen.4.0.0-armel.Microsoft.NETCore.DotNetHostResolver.2.0.0-preview2-25407-01
var match = LegacyNugetPackage().Match(oldPackageDirectory);
if (!match.Success)
{
logger.LogWarning($"Package directory '{oldPackageDirectory}' doesn't match the expected pattern.");
continue;
}
yield return match.Groups[1].Value.ToLowerInvariant();
}
}
private void DownloadMissingPackages(List<FileInfo> allFiles, ISet<string> dllPaths)
{
var alreadyDownloadedPackages = GetRestoredPackageDirectoryNames(packageDirectory.DirInfo);
var alreadyDownloadedLegacyPackages = GetRestoredLegacyPackageNames();
var notYetDownloadedPackages = new HashSet<PackageReference>(fileContent.AllPackages);
foreach (var alreadyDownloadedPackage in alreadyDownloadedPackages)
{
notYetDownloadedPackages.Remove(new(alreadyDownloadedPackage, PackageReferenceSource.SdkCsProj));
}
foreach (var alreadyDownloadedLegacyPackage in alreadyDownloadedLegacyPackages)
{
notYetDownloadedPackages.Remove(new(alreadyDownloadedLegacyPackage, PackageReferenceSource.PackagesConfig));
}
if (notYetDownloadedPackages.Count == 0)
{
return;
}
var multipleVersions = notYetDownloadedPackages
.GroupBy(p => p.Name)
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.ToList();
foreach (var package in multipleVersions)
{
logger.LogWarning($"Found multiple not yet restored packages with name '{package}'.");
notYetDownloadedPackages.Remove(new(package, PackageReferenceSource.PackagesConfig));
}
logger.LogInfo($"Found {notYetDownloadedPackages.Count} packages that are not yet restored");
var nugetConfigs = allFiles.SelectFileNamesByName("nuget.config").ToArray();
string? nugetConfig = null;
if (nugetConfigs.Length > 1)
{
logger.LogInfo($"Found multiple nuget.config files: {string.Join(", ", nugetConfigs)}.");
nugetConfig = allFiles
.SelectRootFiles(sourceDir)
.SelectFileNamesByName("nuget.config")
.FirstOrDefault();
if (nugetConfig == null)
{
logger.LogInfo("Could not find a top-level nuget.config file.");
}
}
else
{
nugetConfig = nugetConfigs.FirstOrDefault();
}
if (nugetConfig != null)
{
logger.LogInfo($"Using nuget.config file {nugetConfig}.");
}
CompilationInfos.Add(("Fallback nuget restore", notYetDownloadedPackages.Count.ToString()));
var successCount = 0;
var sync = new object();
Parallel.ForEach(notYetDownloadedPackages, new ParallelOptions { MaxDegreeOfParallelism = threads }, package =>
{
var success = TryRestorePackageManually(package.Name, nugetConfig, package.PackageReferenceSource);
if (!success)
{
return;
}
lock (sync)
{
successCount++;
}
});
CompilationInfos.Add(("Successfully ran fallback nuget restore", successCount.ToString()));
dllPaths.Add(missingPackageDirectory.DirInfo.FullName);
}
[GeneratedRegex(@"<TargetFramework>.*</TargetFramework>", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)]
private static partial Regex TargetFramework();
private bool TryRestorePackageManually(string package, string? nugetConfig, PackageReferenceSource packageReferenceSource = PackageReferenceSource.SdkCsProj)
{
logger.LogInfo($"Restoring package {package}...");
using var tempDir = new TemporaryDirectory(ComputeTempDirectory(package, "missingpackages_workingdir"));
var success = dotnet.New(tempDir.DirInfo.FullName);
if (!success)
{
return false;
}
if (packageReferenceSource == PackageReferenceSource.PackagesConfig)
{
TryChangeTargetFrameworkMoniker(tempDir.DirInfo);
}
success = dotnet.AddPackage(tempDir.DirInfo.FullName, package);
if (!success)
{
return false;
}
var res = dotnet.Restore(new(tempDir.DirInfo.FullName, missingPackageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: false, PathToNugetConfig: nugetConfig));
if (!res.Success)
{
if (res.HasNugetPackageSourceError && nugetConfig is not null)
{
// Restore could not be completed because the listed source is unavailable. Try without the nuget.config:
res = dotnet.Restore(new(tempDir.DirInfo.FullName, missingPackageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: false, PathToNugetConfig: null, ForceReevaluation: true));
}
// TODO: the restore might fail, we could retry with
// - a prerelease (*-* instead of *) version of the package,
// - a different target framework moniker.
if (!res.Success)
{
logger.LogInfo($"Failed to restore nuget package {package}");
return false;
}
}
return true;
}
private void TryChangeTargetFrameworkMoniker(DirectoryInfo tempDir)
{
try
{
logger.LogInfo($"Changing the target framework moniker in {tempDir.FullName}...");
var csprojs = tempDir.GetFiles("*.csproj", new EnumerationOptions { RecurseSubdirectories = false, MatchCasing = MatchCasing.CaseInsensitive });
if (csprojs.Length != 1)
{
logger.LogError($"Could not find the .csproj file in {tempDir.FullName}, count = {csprojs.Length}");
return;
}
var csproj = csprojs[0];
var content = File.ReadAllText(csproj.FullName);
var matches = TargetFramework().Matches(content);
if (matches.Count == 0)
{
logger.LogError($"Could not find target framework in {csproj.FullName}");
}
else
{
content = TargetFramework().Replace(content, $"<TargetFramework>{FrameworkPackageNames.LatestNetFrameworkMoniker}</TargetFramework>", 1);
File.WriteAllText(csproj.FullName, content);
}
}
catch (Exception exc)
{
logger.LogError($"Failed to update target framework in {tempDir.FullName}: {exc}");
}
}
public void Dispose(TemporaryDirectory? dir, string name)
{
try
@@ -1091,6 +744,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
{
Dispose(tempWorkingDirectory, "temporary working");
}
diagnosticsWriter?.Dispose();
}
}
}

View File

@@ -16,12 +16,14 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
public partial class DotNet : IDotNet
{
private readonly IDotNetCliInvoker dotnetCliInvoker;
private readonly ILogger logger;
private readonly TemporaryDirectory? tempWorkingDirectory;
private DotNet(IDotNetCliInvoker dotnetCliInvoker, ILogger logger, TemporaryDirectory? tempWorkingDirectory = null)
{
this.tempWorkingDirectory = tempWorkingDirectory;
this.dotnetCliInvoker = dotnetCliInvoker;
this.logger = logger;
Info();
}
@@ -89,17 +91,18 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
return dotnetCliInvoker.RunCommand(args);
}
public IList<string> GetListedRuntimes() => GetListed("--list-runtimes");
public IList<string> GetListedRuntimes() => GetResultList("--list-runtimes");
public IList<string> GetListedSdks() => GetListed("--list-sdks");
public IList<string> GetListedSdks() => GetResultList("--list-sdks");
private IList<string> GetListed(string args)
private IList<string> GetResultList(string args)
{
if (dotnetCliInvoker.RunCommand(args, out var artifacts))
if (dotnetCliInvoker.RunCommand(args, out var results))
{
return artifacts;
return results;
}
return new List<string>();
logger.LogWarning($"Running 'dotnet {args}' failed.");
return [];
}
public bool Exec(string execArgs)
@@ -108,6 +111,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
return dotnetCliInvoker.RunCommand(args);
}
public IList<string> GetNugetFeeds(string nugetConfig) => GetResultList($"nuget list source --format Short --configfile \"{nugetConfig}\"");
// The version number should be kept in sync with the version .NET version used for building the application.
public const string LatestDotNetSdkVersion = "8.0.101";

View File

@@ -16,5 +16,30 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
/// Controls whether to use framework dependencies from subfolders.
/// </summary>
public const string DotnetFrameworkReferencesUseSubfolders = "CODEQL_EXTRACTOR_CSHARP_BUILDLESS_DOTNET_FRAMEWORK_REFERENCES_USE_SUBFOLDERS";
/// <summary>
/// Controls whether to check the responsiveness of NuGet feeds.
/// </summary>
public const string CheckNugetFeedResponsiveness = "CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK";
/// <summary>
/// Specifies the NuGet feeds to exclude from the responsiveness check. The value is a space-separated list of feed URLs.
/// </summary>
public const string ExcludedNugetFeedsFromResponsivenessCheck = "CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_EXCLUDED";
/// <summary>
/// Specifies the timeout (as an integer) in milliseconds for the initial check of NuGet feeds responsiveness. The value is then doubled for each subsequent check.
/// </summary>
public const string NugetFeedResponsivenessInitialTimeout = "CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_TIMEOUT";
/// <summary>
/// Specifies how many requests to make to the NuGet feed to check its responsiveness.
/// </summary>
public const string NugetFeedResponsivenessRequestCount = "CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_LIMIT";
/// <summary>
/// Specifies the location of the diagnostic directory.
/// </summary>
public const string DiagnosticDir = "CODEQL_EXTRACTOR_CSHARP_DIAGNOSTIC_DIR";
}
}

View File

@@ -13,6 +13,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
IList<string> GetListedRuntimes();
IList<string> GetListedSdks();
bool Exec(string execArgs);
IList<string> GetNugetFeeds(string nugetConfig);
}
public record class RestoreSettings(string File, string PackageDirectory, bool ForceDotnetRefAssemblyFetching, string? PathToNugetConfig = null, bool ForceReevaluation = false);

View File

@@ -26,6 +26,8 @@ namespace Semmle.Extraction.Tests
public IList<string> GetListedSdks() => sdks;
public bool Exec(string execArgs) => true;
public IList<string> GetNugetFeeds(string nugetConfig) => [];
}
public class RuntimeTests

View File

@@ -27,5 +27,12 @@ namespace Semmle.Util
}
return threads;
}
public static bool GetBoolean(string name)
{
var env = Environment.GetEnvironmentVariable(name);
var _ = bool.TryParse(env, out var value);
return value;
}
}
}

View File

@@ -102,8 +102,7 @@ namespace Semmle.Util
private static async Task DownloadFileAsync(string address, string filename)
{
using var httpClient = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Get, address);
using var contentStream = await (await httpClient.SendAsync(request)).Content.ReadAsStreamAsync();
using var contentStream = await httpClient.GetStreamAsync(address);
using var stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None, 4096, true);
await contentStream.CopyToAsync(stream);
}
@@ -112,7 +111,7 @@ namespace Semmle.Util
/// Downloads the file at <paramref name="address"/> to <paramref name="fileName"/>.
/// </summary>
public static void DownloadFile(string address, string fileName) =>
DownloadFileAsync(address, fileName).Wait();
DownloadFileAsync(address, fileName).GetAwaiter().GetResult();
public static string NestPaths(ILogger logger, string? outerpath, string innerpath)
{

View File

@@ -2,4 +2,4 @@ import csharp
from Class c
where c.fromSource()
select c, c.getBaseClass().getFullyQualifiedName()
select c, c.getBaseClass().getFullyQualifiedNameDebug()

View File

@@ -0,0 +1,201 @@
| [...]/Humanizer.dll |
| [...]/Microsoft.Bcl.AsyncInterfaces.dll |
| [...]/Microsoft.Build.Framework.dll |
| [...]/Microsoft.Build.dll |
| [...]/Microsoft.CSharp.dll |
| [...]/Microsoft.CodeAnalysis.CSharp.Workspaces.dll |
| [...]/Microsoft.CodeAnalysis.CSharp.dll |
| [...]/Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll |
| [...]/Microsoft.CodeAnalysis.VisualBasic.dll |
| [...]/Microsoft.CodeAnalysis.Workspaces.dll |
| [...]/Microsoft.CodeAnalysis.dll |
| [...]/Microsoft.NET.StringTools.dll |
| [...]/Microsoft.VisualBasic.Core.dll |
| [...]/Microsoft.VisualBasic.dll |
| [...]/Microsoft.Win32.Primitives.dll |
| [...]/Microsoft.Win32.Registry.dll |
| [...]/Microsoft.Win32.SystemEvents.dll |
| [...]/Mono.Posix.NETStandard.dll |
| [...]/Newtonsoft.Json.dll |
| [...]/System.AppContext.dll |
| [...]/System.Buffers.dll |
| [...]/System.Collections.Concurrent.dll |
| [...]/System.Collections.Immutable.dll |
| [...]/System.Collections.NonGeneric.dll |
| [...]/System.Collections.Specialized.dll |
| [...]/System.Collections.dll |
| [...]/System.ComponentModel.Annotations.dll |
| [...]/System.ComponentModel.DataAnnotations.dll |
| [...]/System.ComponentModel.EventBasedAsync.dll |
| [...]/System.ComponentModel.Primitives.dll |
| [...]/System.ComponentModel.TypeConverter.dll |
| [...]/System.ComponentModel.dll |
| [...]/System.Composition.AttributedModel.dll |
| [...]/System.Composition.Convention.dll |
| [...]/System.Composition.Hosting.dll |
| [...]/System.Composition.Runtime.dll |
| [...]/System.Composition.TypedParts.dll |
| [...]/System.Configuration.ConfigurationManager.dll |
| [...]/System.Configuration.dll |
| [...]/System.Console.dll |
| [...]/System.Core.dll |
| [...]/System.Data.Common.dll |
| [...]/System.Data.DataSetExtensions.dll |
| [...]/System.Data.dll |
| [...]/System.Diagnostics.Contracts.dll |
| [...]/System.Diagnostics.Debug.dll |
| [...]/System.Diagnostics.DiagnosticSource.dll |
| [...]/System.Diagnostics.EventLog.dll |
| [...]/System.Diagnostics.FileVersionInfo.dll |
| [...]/System.Diagnostics.Process.dll |
| [...]/System.Diagnostics.StackTrace.dll |
| [...]/System.Diagnostics.TextWriterTraceListener.dll |
| [...]/System.Diagnostics.Tools.dll |
| [...]/System.Diagnostics.TraceSource.dll |
| [...]/System.Diagnostics.Tracing.dll |
| [...]/System.Drawing.Common.dll |
| [...]/System.Drawing.Primitives.dll |
| [...]/System.Drawing.dll |
| [...]/System.Dynamic.Runtime.dll |
| [...]/System.Formats.Asn1.dll |
| [...]/System.Formats.Tar.dll |
| [...]/System.Globalization.Calendars.dll |
| [...]/System.Globalization.Extensions.dll |
| [...]/System.Globalization.dll |
| [...]/System.IO.Compression.Brotli.dll |
| [...]/System.IO.Compression.FileSystem.dll |
| [...]/System.IO.Compression.ZipFile.dll |
| [...]/System.IO.Compression.dll |
| [...]/System.IO.FileSystem.AccessControl.dll |
| [...]/System.IO.FileSystem.DriveInfo.dll |
| [...]/System.IO.FileSystem.Primitives.dll |
| [...]/System.IO.FileSystem.Watcher.dll |
| [...]/System.IO.FileSystem.dll |
| [...]/System.IO.IsolatedStorage.dll |
| [...]/System.IO.MemoryMappedFiles.dll |
| [...]/System.IO.Pipelines.dll |
| [...]/System.IO.Pipes.AccessControl.dll |
| [...]/System.IO.Pipes.dll |
| [...]/System.IO.UnmanagedMemoryStream.dll |
| [...]/System.IO.dll |
| [...]/System.Linq.Expressions.dll |
| [...]/System.Linq.Parallel.dll |
| [...]/System.Linq.Queryable.dll |
| [...]/System.Linq.dll |
| [...]/System.Memory.dll |
| [...]/System.Net.Http.Json.dll |
| [...]/System.Net.Http.dll |
| [...]/System.Net.HttpListener.dll |
| [...]/System.Net.Mail.dll |
| [...]/System.Net.NameResolution.dll |
| [...]/System.Net.NetworkInformation.dll |
| [...]/System.Net.Ping.dll |
| [...]/System.Net.Primitives.dll |
| [...]/System.Net.Quic.dll |
| [...]/System.Net.Requests.dll |
| [...]/System.Net.Security.dll |
| [...]/System.Net.ServicePoint.dll |
| [...]/System.Net.Sockets.dll |
| [...]/System.Net.WebClient.dll |
| [...]/System.Net.WebHeaderCollection.dll |
| [...]/System.Net.WebProxy.dll |
| [...]/System.Net.WebSockets.Client.dll |
| [...]/System.Net.WebSockets.dll |
| [...]/System.Net.dll |
| [...]/System.Numerics.Vectors.dll |
| [...]/System.Numerics.dll |
| [...]/System.ObjectModel.dll |
| [...]/System.Private.CoreLib.dll |
| [...]/System.Private.DataContractSerialization.dll |
| [...]/System.Private.Uri.dll |
| [...]/System.Private.Xml.Linq.dll |
| [...]/System.Private.Xml.dll |
| [...]/System.Reflection.DispatchProxy.dll |
| [...]/System.Reflection.Emit.ILGeneration.dll |
| [...]/System.Reflection.Emit.Lightweight.dll |
| [...]/System.Reflection.Emit.dll |
| [...]/System.Reflection.Extensions.dll |
| [...]/System.Reflection.Metadata.dll |
| [...]/System.Reflection.MetadataLoadContext.dll |
| [...]/System.Reflection.Primitives.dll |
| [...]/System.Reflection.TypeExtensions.dll |
| [...]/System.Reflection.dll |
| [...]/System.Resources.Reader.dll |
| [...]/System.Resources.ResourceManager.dll |
| [...]/System.Resources.Writer.dll |
| [...]/System.Runtime.CompilerServices.Unsafe.dll |
| [...]/System.Runtime.CompilerServices.VisualC.dll |
| [...]/System.Runtime.Extensions.dll |
| [...]/System.Runtime.Handles.dll |
| [...]/System.Runtime.InteropServices.JavaScript.dll |
| [...]/System.Runtime.InteropServices.RuntimeInformation.dll |
| [...]/System.Runtime.InteropServices.dll |
| [...]/System.Runtime.Intrinsics.dll |
| [...]/System.Runtime.Loader.dll |
| [...]/System.Runtime.Numerics.dll |
| [...]/System.Runtime.Serialization.Formatters.dll |
| [...]/System.Runtime.Serialization.Json.dll |
| [...]/System.Runtime.Serialization.Primitives.dll |
| [...]/System.Runtime.Serialization.Xml.dll |
| [...]/System.Runtime.Serialization.dll |
| [...]/System.Runtime.dll |
| [...]/System.Security.AccessControl.dll |
| [...]/System.Security.Claims.dll |
| [...]/System.Security.Cryptography.Algorithms.dll |
| [...]/System.Security.Cryptography.Cng.dll |
| [...]/System.Security.Cryptography.Csp.dll |
| [...]/System.Security.Cryptography.Encoding.dll |
| [...]/System.Security.Cryptography.OpenSsl.dll |
| [...]/System.Security.Cryptography.Primitives.dll |
| [...]/System.Security.Cryptography.ProtectedData.dll |
| [...]/System.Security.Cryptography.X509Certificates.dll |
| [...]/System.Security.Cryptography.dll |
| [...]/System.Security.Permissions.dll |
| [...]/System.Security.Principal.Windows.dll |
| [...]/System.Security.Principal.dll |
| [...]/System.Security.SecureString.dll |
| [...]/System.Security.dll |
| [...]/System.ServiceModel.Web.dll |
| [...]/System.ServiceProcess.dll |
| [...]/System.Text.Encoding.CodePages.dll |
| [...]/System.Text.Encoding.Extensions.dll |
| [...]/System.Text.Encoding.dll |
| [...]/System.Text.Encodings.Web.dll |
| [...]/System.Text.Json.dll |
| [...]/System.Text.RegularExpressions.dll |
| [...]/System.Threading.Channels.dll |
| [...]/System.Threading.Overlapped.dll |
| [...]/System.Threading.Tasks.Dataflow.dll |
| [...]/System.Threading.Tasks.Extensions.dll |
| [...]/System.Threading.Tasks.Parallel.dll |
| [...]/System.Threading.Tasks.dll |
| [...]/System.Threading.Thread.dll |
| [...]/System.Threading.ThreadPool.dll |
| [...]/System.Threading.Timer.dll |
| [...]/System.Threading.dll |
| [...]/System.Transactions.Local.dll |
| [...]/System.Transactions.dll |
| [...]/System.ValueTuple.dll |
| [...]/System.Web.HttpUtility.dll |
| [...]/System.Web.dll |
| [...]/System.Windows.Extensions.dll |
| [...]/System.Windows.dll |
| [...]/System.Xml.Linq.dll |
| [...]/System.Xml.ReaderWriter.dll |
| [...]/System.Xml.Serialization.dll |
| [...]/System.Xml.XDocument.dll |
| [...]/System.Xml.XPath.XDocument.dll |
| [...]/System.Xml.XPath.dll |
| [...]/System.Xml.XmlDocument.dll |
| [...]/System.Xml.XmlSerializer.dll |
| [...]/System.Xml.dll |
| [...]/System.dll |
| [...]/WindowsBase.dll |
| [...]/mscorlib.dll |
| [...]/netstandard.dll |
| [...]/zh-Hant/Microsoft.CodeAnalysis.CSharp.Workspaces.resources.dll |
| [...]/zh-Hant/Microsoft.CodeAnalysis.CSharp.resources.dll |
| [...]/zh-Hant/Microsoft.CodeAnalysis.VisualBasic.Workspaces.resources.dll |
| [...]/zh-Hant/Microsoft.CodeAnalysis.VisualBasic.resources.dll |
| [...]/zh-Hant/Microsoft.CodeAnalysis.Workspaces.resources.dll |
| [...]/zh-Hant/Microsoft.CodeAnalysis.resources.dll |

View File

@@ -0,0 +1,21 @@
import csharp
private string getPath(Assembly a) {
not a.getCompilation().getOutputAssembly() = a and
exists(string s | s = a.getFile().getAbsolutePath() |
result =
"[...]" +
s.substring(s.indexOf("test-db/working/") + "test-db/working/".length() + 16 +
"/packages".length(), s.length())
or
exists(string sub | sub = "csharp/tools/" + ["osx64", "linux64"] |
result = "[...]" + s.substring(s.indexOf(sub) + sub.length(), s.length())
)
or
result = s and
not exists(s.indexOf(["test-db/working/", "csharp/tools/"]))
)
}
from Assembly a
select getPath(a)

View File

@@ -0,0 +1,6 @@
class Program
{
static void Main(string[] args)
{
}
}

View File

@@ -0,0 +1,3 @@
from create_database_utils import *
run_codeql_database_create([], lang="csharp", extra_args=["--build-mode=none"])

View File

@@ -0,0 +1 @@
| [...]/newtonsoft.json/13.0.3/lib/net6.0/Newtonsoft.Json.dll |

View File

@@ -0,0 +1,11 @@
import csharp
private string getPath(Assembly a) {
not a.getCompilation().getOutputAssembly() = a and
exists(string s | s = a.getFile().getAbsolutePath() |
result = "[...]/" + s.substring(s.indexOf("newtonsoft.json"), s.length())
)
}
from Assembly a
select getPath(a)

View File

@@ -0,0 +1,13 @@
| All Nuget feeds reachable | 0.0 |
| Fallback nuget restore | 1.0 |
| Project files on filesystem | 1.0 |
| Resolved assembly conflicts | 7.0 |
| Restored .NET framework variants | 0.0 |
| Solution files on filesystem | 1.0 |
| Source files generated | 0.0 |
| Source files on filesystem | 1.0 |
| Successfully ran fallback nuget restore | 1.0 |
| Unresolved references | 0.0 |
| UseWPF set | 0.0 |
| UseWindowsForms set | 0.0 |
| WebView extraction enabled | 1.0 |

View File

@@ -0,0 +1,15 @@
import csharp
import semmle.code.csharp.commons.Diagnostics
query predicate compilationInfo(string key, float value) {
key != "Resolved references" and
not key.matches("Compiler diagnostic count for%") and
exists(Compilation c, string infoKey, string infoValue | infoValue = c.getInfo(infoKey) |
key = infoKey and
value = infoValue.toFloat()
or
not exists(infoValue.toFloat()) and
key = infoKey + ": " + infoValue and
value = 1
)
}

View File

@@ -0,0 +1,42 @@
{
"markdownMessage": "C# analysis with build-mode 'none' completed.",
"severity": "unknown",
"source": {
"extractorName": "csharp",
"id": "csharp/autobuilder/buildless/complete",
"name": "C# analysis with build-mode 'none' completed"
},
"visibility": {
"cliSummaryTable": true,
"statusPage": false,
"telemetry": true
}
}
{
"markdownMessage": "C# with build-mode set to 'none'. This means that all C# source in the working directory will be scanned, with build tools, such as Nuget and Dotnet CLIs, only contributing information about external dependencies.",
"severity": "note",
"source": {
"extractorName": "csharp",
"id": "csharp/autobuilder/buildless/mode-active",
"name": "C# with build-mode set to 'none'"
},
"visibility": {
"cliSummaryTable": true,
"statusPage": true,
"telemetry": true
}
}
{
"markdownMessage": "Found unreachable Nuget feed in C# analysis with build-mode 'none'. This may cause missing dependencies in the analysis.",
"severity": "warning",
"source": {
"extractorName": "csharp",
"id": "csharp/autobuilder/buildless/unreachable-feed",
"name": "Found unreachable Nuget feed in C# analysis with build-mode 'none'"
},
"visibility": {
"cliSummaryTable": true,
"statusPage": true,
"telemetry": true
}
}

View File

@@ -0,0 +1,6 @@
class Program
{
static void Main(string[] args)
{
}
}

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="x" value="https://localhost:53/packages/" />
<add key="y" value="https://localhost:80/packages/" />
</packageSources>
</configuration>

View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net8.0</TargetFrameworks>
</PropertyGroup>
<Target Name="DeleteBinObjFolders" BeforeTargets="Clean">
<RemoveDir Directories=".\bin" />
<RemoveDir Directories=".\obj" />
</Target>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.002.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "proj", "proj\proj.csproj", "{6ED00460-7666-4AE9-A405-4B6C8B02279A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4ED55A1C-066C-43DF-B32E-7EAA035985EE}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,10 @@
from create_database_utils import *
from diagnostics_test_utils import *
import os
os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK"] = "true" # Enable NuGet feed check
os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_TIMEOUT"] = "1" # 1ms, the GET request should fail with such short timeout
os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_LIMIT"] = "1" # Limit the count of checks to 1
os.environ["CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_EXCLUDED"] = "https://abc.de:8000/packages/" # Exclude this feed from check
run_codeql_database_create([], lang="csharp", extra_args=["--build-mode=none"])
check_diagnostics()

View File

@@ -102,25 +102,8 @@ class NamedElement extends Element, @named_element {
final predicate hasName(string name) { name = this.getName() }
/**
* Gets the fully qualified name of this element, for example the
* fully qualified name of `M` on line 3 is `N.C.M` in
* DEPRECATED: Use `hasFullyQualifiedName` instead.
*
* ```csharp
* namespace N {
* class C {
* void M(int i, string s) { }
* }
* }
* ```
*/
cached
deprecated final string getQualifiedName() {
exists(string qualifier, string name | this.hasQualifiedName(qualifier, name) |
if qualifier = "" then result = name else result = qualifier + "." + name
)
}
/**
* Gets the fully qualified name of this element, for example the
* fully qualified name of `M` on line 3 is `N.C.M` in
*
@@ -135,21 +118,39 @@ class NamedElement extends Element, @named_element {
* Unbound generic types, such as `IList<T>`, are represented as
* ``System.Collections.Generic.IList`1``.
*/
cached
final string getFullyQualifiedName() {
deprecated final string getFullyQualifiedName() {
exists(string qualifier, string name | this.hasFullyQualifiedName(qualifier, name) |
if qualifier = "" then result = name else result = qualifier + "." + name
)
}
/**
* DEPRECATED: Use `hasFullyQualifiedName` instead.
* INTERNAL: Do not use.
*
* Holds if this element has the qualified name `qualifier`.`name`.
* This is intended for DEBUG ONLY.
* Constructing the fully qualified name for all elements in a large codebase
* puts severe stress on the string pool.
*
* Gets the fully qualified name of this element, for example the
* fully qualified name of `M` on line 3 is `N.C.M` in
*
* ```csharp
* namespace N {
* class C {
* void M(int i, string s) { }
* }
* }
* ```
*
* Unbound generic types, such as `IList<T>`, are represented as
* ``System.Collections.Generic.IList`1``.
*/
cached
deprecated predicate hasQualifiedName(string qualifier, string name) {
qualifier = "" and name = this.getName()
bindingset[this]
pragma[inline_late]
final string getFullyQualifiedNameDebug() {
exists(string qualifier, string name | this.hasFullyQualifiedName(qualifier, name) |
if qualifier = "" then result = name else result = qualifier + "." + name
)
}
/** Holds if this element has the fully qualified name `qualifier`.`name`. */

View File

@@ -71,17 +71,11 @@ class Declaration extends NamedElement, @declaration {
override string toString() { result = this.getName() }
deprecated override predicate hasQualifiedName(string qualifier, string name) {
QualifiedName<QualifiedNameInput>::hasQualifiedName(this, qualifier, name)
}
override predicate hasFullyQualifiedName(string qualifier, string name) {
QualifiedName<FullyQualifiedNameInput>::hasQualifiedName(this, qualifier, name)
}
/**
* DEPRECATED: Use `getFullyQualifiedNameWithTypes` instead.
*
* Gets the fully qualified name of this declaration, including types, for example
* the fully qualified name with types of `M` on line 3 is `N.C.M(int, string)` in
*
@@ -93,33 +87,13 @@ class Declaration extends NamedElement, @declaration {
* }
* ```
*/
deprecated string getQualifiedNameWithTypes() {
exists(string qual |
qual = this.getDeclaringType().getQualifiedName() and
deprecated string getFullyQualifiedNameWithTypes() {
exists(string fullqual, string qual, string name |
this.getDeclaringType().hasFullyQualifiedName(qual, name) and
fullqual = getQualifiedName(qual, name) and
if this instanceof NestedType
then result = qual + "+" + this.toStringWithTypes()
else result = qual + "." + this.toStringWithTypes()
)
}
/**
* Gets the fully qualified name of this declaration, including types, for example
* the fully qualified name with types of `M` on line 3 is `N.C.M(int, string)` in
*
* ```csharp
* namespace N {
* class C {
* void M(int i, string s) { }
* }
* }
* ```
*/
string getFullyQualifiedNameWithTypes() {
exists(string qual |
qual = this.getDeclaringType().getFullyQualifiedName() and
if this instanceof NestedType
then result = qual + "+" + this.toStringWithTypes()
else result = qual + "." + this.toStringWithTypes()
then result = fullqual + "+" + this.toStringWithTypes()
else result = fullqual + "." + this.toStringWithTypes()
)
}
@@ -263,17 +237,6 @@ class Member extends Modifiable, @member {
/** Gets an access to this member. */
MemberAccess getAnAccess() { result.getTarget() = this }
/**
* DEPRECATED: Use `hasFullyQualifiedName` instead.
*
* Holds if this member has name `name` and is defined in type `type`
* with namespace `namespace`.
*/
cached
deprecated final predicate hasQualifiedName(string namespace, string type, string name) {
QualifiedName<QualifiedNameInput>::hasQualifiedName(this, namespace, type, name)
}
/**
* Holds if this member has name `name` and is defined in type `type`
* with namespace `namespace`.

View File

@@ -38,16 +38,6 @@ class Namespace extends TypeContainer, Declaration, @namespace {
parent_namespace(result, this)
}
/**
* Holds if this namespace has the qualified name `qualifier`.`name`.
*
* For example if the qualified name is `System.Collections.Generic`, then
* `qualifier`=`System.Collections` and `name`=`Generic`.
*/
deprecated override predicate hasQualifiedName(string qualifier, string name) {
namespaceHasQualifiedName(this, qualifier, name)
}
/**
* Holds if this namespace has the qualified name `qualifier`.`name`.
*

View File

@@ -219,3 +219,28 @@ predicate splitQualifiedName(string qualifiedName, string qualifier, string name
name = qualifiedName
)
}
/**
* INTERNAL: Do not use.
*
* Gets the fully qualified name of this declaration, including types, for example
* the fully qualified name with types of `M` on line 3 is `N.C.M(int, string)` in
*
* ```csharp
* namespace N {
* class C {
* void M(int i, string s) { }
* }
* }
* ```
*/
bindingset[d]
string getFullyQualifiedNameWithTypes(Declaration d) {
exists(string fullqual, string qual, string name |
d.getDeclaringType().hasFullyQualifiedName(qual, name) and
fullqual = getQualifiedName(qual, name) and
if d instanceof NestedType
then result = fullqual + "+" + d.toStringWithTypes()
else result = fullqual + "." + d.toStringWithTypes()
)
}

View File

@@ -120,7 +120,7 @@ module Ssa {
result = prefix + "." + this.getAssignable()
|
if f.(Modifiable).isStatic()
then prefix = f.getDeclaringType().getFullyQualifiedName()
then prefix = f.getDeclaringType().getName()
else prefix = "this"
)
}

View File

@@ -3,6 +3,7 @@
*/
private import csharp
private import semmle.code.csharp.commons.QualifiedName
private import semmle.code.csharp.frameworks.system.linq.Expressions
private import codeql.dataflow.internal.FlowSummaryImpl
private import codeql.dataflow.internal.AccessPathSyntax as AccessPath
@@ -42,10 +43,18 @@ module Input implements InputSig<Location, DataFlowImplSpecific::CsharpDataFlow>
string encodeContent(ContentSet c, string arg) {
c = TElementContent() and result = "Element" and arg = ""
or
exists(Field f | c = TFieldContent(f) and result = "Field" and arg = f.getFullyQualifiedName())
exists(Field f, string qualifier, string name |
c = TFieldContent(f) and
f.hasFullyQualifiedName(qualifier, name) and
arg = getQualifiedName(qualifier, name) and
result = "Field"
)
or
exists(Property p |
c = TPropertyContent(p) and result = "Property" and arg = p.getFullyQualifiedName()
exists(Property p, string qualifier, string name |
c = TPropertyContent(p) and
p.hasFullyQualifiedName(qualifier, name) and
arg = getQualifiedName(qualifier, name) and
result = "Property"
)
or
exists(SyntheticField f |

View File

@@ -139,13 +139,13 @@ class ExternalApiUsedWithUntrustedData extends TExternalApi {
/** Gets a textual representation of this element. */
string toString() {
exists(Callable m, int index, string indexString |
exists(Callable m, int index, string indexString, string qualifier, string name |
if index = -1 then indexString = "qualifier" else indexString = "param " + index
|
this = TExternalApiParameter(m, index) and
m.getDeclaringType().hasFullyQualifiedName(qualifier, name) and
result =
m.getDeclaringType().getFullyQualifiedName() + "." + m.toStringWithTypes() + " [" +
indexString + "]"
getQualifiedName(qualifier, name) + "." + m.toStringWithTypes() + " [" + indexString + "]"
)
}
}

View File

@@ -1,9 +1,7 @@
import csharp
import semmle.code.csharp.commons.QualifiedName
from Attributable element, Attribute attribute, string qualifier, string name
from Attributable element, Attribute attribute
where
attribute = element.getAnAttribute() and
(attribute.fromSource() or element.(Assembly).getName() in ["attributes", "Assembly1"]) and
attribute.getType().hasFullyQualifiedName(qualifier, name)
select element, attribute, getQualifiedName(qualifier, name)
(attribute.fromSource() or element.(Assembly).getName() in ["attributes", "Assembly1"])
select element, attribute, attribute.getType().getFullyQualifiedNameDebug()

View File

@@ -3,11 +3,10 @@
*/
import csharp
import semmle.code.csharp.commons.QualifiedName
from Destructor c, string qualifier, string name
where
c.getDeclaringType().hasFullyQualifiedName(qualifier, name) and
qualifier = "Constructors" and
name = "Class"
select c, c.getDeclaringType().getFullyQualifiedName()
select c, c.getDeclaringType().getFullyQualifiedNameDebug()

View File

@@ -1,5 +1,4 @@
import csharp
private import semmle.code.csharp.commons.QualifiedName
private predicate isInteresting(Type t) {
(
@@ -20,10 +19,7 @@ query predicate typemodifiers(Type t, string modifier) {
query predicate qualifiedtypes(Type t, string qualifiedName) {
isInteresting(t) and
exists(string qualifier, string name |
t.hasFullyQualifiedName(qualifier, name) and
qualifiedName = getQualifiedName(qualifier, name)
)
qualifiedName = t.getFullyQualifiedNameDebug()
}
query predicate filetypes(Type t) {

View File

@@ -1,12 +1,10 @@
import csharp
import semmle.code.csharp.commons.QualifiedName
from LocalVariable v1, LocalVariable v2, Type t, string qualifier, string name
from LocalVariable v1, LocalVariable v2, Type t
where
v1.getFile().getStem() = "NativeInt" and
v2.getFile().getStem() = "NativeInt" and
t = v1.getType() and
t = v2.getType() and
t.hasFullyQualifiedName(qualifier, name) and
v1 != v2
select v1, v2, getQualifiedName(qualifier, name)
select v1, v2, t.getFullyQualifiedNameDebug()

View File

@@ -1,13 +1,8 @@
import csharp
import semmle.code.csharp.commons.QualifiedName
from
Method m, Method overrider, string mnamespace, string mtype, string mname, string onamespace,
string otype, string oname
from Method m, Method overrider
where
m.getAnOverrider() = overrider and
m.getFile().getStem() = "CovariantReturn" and
m.hasFullyQualifiedName(mnamespace, mtype, mname) and
overrider.hasFullyQualifiedName(onamespace, otype, oname)
select getQualifiedName(mnamespace, mtype, mname), m.getReturnType().toString(),
getQualifiedName(onamespace, otype, oname), overrider.getReturnType().toString()
m.getFile().getStem() = "CovariantReturn"
select m.getFullyQualifiedNameDebug(), m.getReturnType().toString(),
overrider.getFullyQualifiedNameDebug(), overrider.getReturnType().toString()

View File

@@ -1,5 +1,4 @@
import csharp
import semmle.code.csharp.commons.QualifiedName
private string getLocation(Member m) {
if m.fromSource() then result = m.getALocation().(SourceLocation).toString() else result = "-"
@@ -9,13 +8,9 @@ private string getIsAsync(ForeachStmt f) {
if f.isAsync() then result = "async" else result = "sync"
}
from
ForeachStmt f, string qualifier1, string type1, string qualifier2, string type2,
string qualifier3, string type3
where
f.getGetEnumerator().getDeclaringType().hasFullyQualifiedName(qualifier1, type1) and
f.getCurrent().getDeclaringType().hasFullyQualifiedName(qualifier2, type2) and
f.getMoveNext().getDeclaringType().hasFullyQualifiedName(qualifier3, type3)
select f, f.getElementType().toString(), getIsAsync(f), getQualifiedName(qualifier1, type1),
getLocation(f.getGetEnumerator()), getQualifiedName(qualifier2, type2),
getLocation(f.getCurrent()), getQualifiedName(qualifier3, type3), getLocation(f.getMoveNext())
from ForeachStmt f
select f, f.getElementType().toString(), getIsAsync(f),
f.getGetEnumerator().getDeclaringType().getFullyQualifiedNameDebug(),
getLocation(f.getGetEnumerator()), f.getCurrent().getDeclaringType().getFullyQualifiedNameDebug(),
getLocation(f.getCurrent()), f.getMoveNext().getDeclaringType().getFullyQualifiedNameDebug(),
getLocation(f.getMoveNext())

View File

@@ -7,18 +7,10 @@ query predicate records(RecordClass t, string i, RecordCloneMethod clone) {
t.fromSource()
}
private string getMemberName(Member m) {
exists(string qualifier, string name |
m.getDeclaringType().hasFullyQualifiedName(qualifier, name)
|
result = getQualifiedName(qualifier, name) + "." + m.toStringWithTypes()
)
}
query predicate members(RecordClass t, string ms, string l) {
t.fromSource() and
exists(Member m | t.hasMember(m) |
ms = getMemberName(m) and
ms = getFullyQualifiedNameWithTypes(m) and
if m.fromSource() then l = m.getLocation().toString() else l = "no location"
)
}

View File

@@ -1,19 +1,11 @@
import csharp
import semmle.code.csharp.commons.QualifiedName
private string getSignature(Method m) {
exists(string qualifier, string name |
m.getDeclaringType().hasFullyQualifiedName(qualifier, name)
|
result = getQualifiedName(qualifier, name) + "." + m.toStringWithTypes()
)
}
query predicate withExpr(WithExpr with, string type, Expr expr, ObjectInitializer init, string clone) {
type = with.getType().toStringWithTypes() and
expr = with.getExpr() and
init = with.getInitializer() and
clone = getSignature(with.getCloneMethod())
clone = getFullyQualifiedNameWithTypes(with.getCloneMethod())
}
query predicate withTarget(WithExpr with, RecordCloneMethod clone, Constructor ctor) {
@@ -25,7 +17,7 @@ query predicate cloneOverrides(string b, string o) {
exists(RecordCloneMethod base, RecordCloneMethod overrider |
base.getDeclaringType().fromSource() and
base.getAnOverrider() = overrider and
b = getSignature(base) and
o = getSignature(overrider)
b = getFullyQualifiedNameWithTypes(base) and
o = getFullyQualifiedNameWithTypes(overrider)
)
}

View File

@@ -1,8 +1,9 @@
import csharp
import semmle.code.csharp.commons.QualifiedName
import semmle.code.csharp.dispatch.Dispatch
from DispatchCall call, Callable callable
where
callable = call.getADynamicTarget() and
callable.fromSource()
select call, callable.getFullyQualifiedNameWithTypes()
select call, getFullyQualifiedNameWithTypes(callable)

View File

@@ -3,13 +3,11 @@
*/
import csharp
import semmle.code.csharp.commons.QualifiedName
from EnumConstant c, string namespace, string name
from EnumConstant c
where
c.getName() = "Green" and
c.getDeclaringType().hasFullyQualifiedName("Enums", "LongColor") and
c.getType() = c.getDeclaringType() and
c.getValue() = "1" and
c.getDeclaringType().getBaseClass().hasFullyQualifiedName(namespace, name)
select c, getQualifiedName(namespace, name)
c.getValue() = "1"
select c, c.getDeclaringType().getBaseClass().getFullyQualifiedNameDebug()

View File

@@ -1,4 +1,5 @@
import csharp
import semmle.code.csharp.commons.QualifiedName
import semmle.code.csharp.frameworks.System
from ValueOrRefType t, Method m, boolean b
@@ -6,4 +7,4 @@ where
t.fromSource() and
m = getInvokedDisposeMethod(t) and
if implementsDispose(t) then b = true else b = false
select t, m.getFullyQualifiedNameWithTypes(), b
select t, getFullyQualifiedNameWithTypes(m), b

View File

@@ -1,4 +1,5 @@
import csharp
import semmle.code.csharp.commons.QualifiedName
import semmle.code.csharp.frameworks.System
from ValueOrRefType t, Method m, boolean b
@@ -6,4 +7,4 @@ where
t.fromSource() and
m = getInvokedEqualsMethod(t) and
if implementsEquals(t) then b = true else b = false
select t, m.getFullyQualifiedNameWithTypes(), b
select t, getFullyQualifiedNameWithTypes(m), b

View File

@@ -231,18 +231,18 @@ query predicate test27(ConstructedType ct, UnboundGenericType ugt, UnboundGeneri
query predicate test28(UnboundGeneric ug, string s) {
ug.fromSource() and
s = ug.getFullyQualifiedNameWithTypes()
s = getFullyQualifiedNameWithTypes(ug)
}
query predicate test29(ConstructedGeneric cg, string s) {
cg.fromSource() and
s = cg.getFullyQualifiedNameWithTypes()
s = getFullyQualifiedNameWithTypes(cg)
}
query predicate test30(Declaration d, string s) {
d.fromSource() and
d instanceof @generic and
s = d.getFullyQualifiedNameWithTypes() and
s = getFullyQualifiedNameWithTypes(d) and
d != d.getUnboundDeclaration() and
not d instanceof Generic
}
@@ -263,21 +263,17 @@ query predicate test33(ConstructedMethod cm, string s1, string s2) {
exists(string namespace, string type, string name |
cm.hasFullyQualifiedName(namespace, type, name) and s1 = getQualifiedName(namespace, type, name)
) and
cm.getFullyQualifiedNameWithTypes() = s2
getFullyQualifiedNameWithTypes(cm) = s2
}
query predicate test34(UnboundGeneric ug, string s1, string s2) {
ug.fromSource() and
exists(string qualifier, string name |
ug.hasFullyQualifiedName(qualifier, name) and s1 = getQualifiedName(qualifier, name)
) and
ug.getFullyQualifiedNameWithTypes() = s2
s1 = ug.getFullyQualifiedNameDebug() and
s2 = getFullyQualifiedNameWithTypes(ug)
}
query predicate test35(UnboundGenericMethod gm, string s1, string s2) {
gm.fromSource() and
exists(string namespace, string type, string name |
gm.hasFullyQualifiedName(namespace, type, name) and s1 = getQualifiedName(namespace, type, name)
) and
gm.getFullyQualifiedNameWithTypes() = s2
s1 = gm.getFullyQualifiedNameDebug() and
s2 = getFullyQualifiedNameWithTypes(gm)
}

View File

@@ -1,4 +1,5 @@
import csharp
import semmle.code.csharp.commons.QualifiedName
from Overridable v1, Overridable v2, string kind
where
@@ -9,4 +10,4 @@ where
) and
v1.fromSource() and
v2.fromSource()
select v1.getFullyQualifiedNameWithTypes(), v2.getFullyQualifiedNameWithTypes(), kind
select getFullyQualifiedNameWithTypes(v1), getFullyQualifiedNameWithTypes(v2), kind

View File

@@ -1,3 +1,4 @@
import semmle.code.csharp.commons.QualifiedName
import semmle.code.csharp.Unification
class InterestingType extends @type {
@@ -7,9 +8,9 @@ class InterestingType extends @type {
}
string toString() {
result = this.(Type).getFullyQualifiedNameWithTypes()
result = getFullyQualifiedNameWithTypes(this.(Type))
or
not exists(this.(Type).getFullyQualifiedNameWithTypes()) and
not exists(getFullyQualifiedNameWithTypes(this.(Type))) and
result = this.(Type).toStringWithTypes()
}

View File

@@ -282,7 +282,7 @@ These are the same for both of the rows above as we are adding two summaries for
- The second value ``Enumerable`` is the class (type) name.
- The third value ``False`` is a flag that indicates whether or not the summary also applies to all overrides of the method.
- The fourth value ``Select<TSource,TResult>`` is the method name, along with the type parameters for the method. The names of the generic type parameters provided in the model must match the names of the generic type parameters in the method signature in the source code.
- The fifth value ``(System.Collections.Generic.IEnumerable<TSource>,System.Func<TSource,TResult>)`` is the method input type signature. The generics in the signature must match the generics in the method signature in the source code.
- The fifth value ``(System.Collections.Generic.IEnumerable<TSource>,System.Func<TSource,TResult>)`` is the method input type signature. The generics in the signature must match the generics in the method signature in the source code.
The sixth value should be left empty and is out of scope for this documentation.
The remaining values are used to define the ``access path``, the ``kind``, and the ``provenance`` (origin) of the summary definition.
@@ -309,7 +309,7 @@ That is, the first row specifies that values can flow from the elements of the q
Example: Add a ``neutral`` method
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This example shows how we can model a method as being neutral with respect to flow. We will also cover how to model a property by modeling the getter of the ``Now`` property of the ``DateTime`` class as neutral.
This example shows how we can model a method as being neutral with respect to flow. We will also cover how to model a property by modeling the getter of the ``Now`` property of the ``DateTime`` class as neutral.
A neutral model is used to define that there is no flow through a method.
.. code-block:: csharp
@@ -346,13 +346,4 @@ The first four values identify the callable (in this case the getter of the ``No
Threat models
-------------
.. include:: ../reusables/beta-note-threat-models.rst
A threat model is a named class of dataflow sources that can be enabled or disabled independently. Threat models allow you to control the set of dataflow sources that you want to consider unsafe. For example, one codebase may only consider remote HTTP requests to be tainted, whereas another may also consider data from local files to be unsafe. You can use threat models to ensure that the relevant taint sources are used in a CodeQL analysis.
The ``kind`` property of ``sourceModel`` determines which threat model a source is associated with. There are two main categories:
- ``remote`` which represents requests and responses from the network.
- ``local`` which represents data from local files (``file``), command-line arguments (``commandargs``), database reads (``database``), and environment variables(``environment``).
When running a CodeQL analysis, the ``remote`` threat model is included by default. You can optionally include other threat models as appropriate when using the CodeQL CLI and in GitHub code scanning. For more information, see `Analyzing your code with CodeQL queries <https://docs.github.com/code-security/codeql-cli/getting-started-with-the-codeql-cli/analyzing-your-code-with-codeql-queries#including-model-packs-to-add-potential-sources-of-tainted-data>`__ and `Customizing your advanced setup for code scanning <https://docs.github.com/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#extending-codeql-coverage-with-threat-models>`__.
.. include:: ../reusables/threat-model-description.rst

View File

@@ -297,13 +297,4 @@ The first four values identify the callable (in this case a method) to be modele
Threat models
-------------
.. include:: ../reusables/beta-note-threat-models.rst
A threat model is a named class of dataflow sources that can be enabled or disabled independently. Threat models allow you to control the set of dataflow sources that you want to consider unsafe. For example, one codebase may only consider remote HTTP requests to be tainted, whereas another may also consider data from local files to be unsafe. You can use threat models to ensure that the relevant taint sources are used in a CodeQL analysis.
The ``kind`` property of the ``sourceModel`` determines which threat model a source is associated with. There are two main categories:
- ``remote`` which represents requests and responses from the network.
- ``local`` which represents data from local files (``file``), command-line arguments (``commandargs``), database reads (``database``), and environment variables(``environment``).
When running a CodeQL analysis, the ``remote`` threat model is included by default. You can optionally include other threat models as appropriate when using the CodeQL CLI and in GitHub code scanning. For more information, see `Analyzing your code with CodeQL queries <https://docs.github.com/code-security/codeql-cli/getting-started-with-the-codeql-cli/analyzing-your-code-with-codeql-queries#including-model-packs-to-add-potential-sources-of-tainted-data>`__ and `Customizing your advanced setup for code scanning <https://docs.github.com/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#extending-codeql-coverage-with-threat-models>`__.
.. include:: ../reusables/threat-model-description.rst

View File

@@ -478,7 +478,7 @@ The following components are supported:
- **Element** selects an element of an array, iterator, or set object.
- **MapValue** selects a value of a map object.
- **Awaited** selects the value of a promise.
- **Instance** selects instances of a class.
- **Instance** selects instances of a class, including instances of its subclasses.
- **Fuzzy** selects all values that are derived from the current value through a combination of the other operations described in this list.
For example, this can be used to find all values that appear to originate from a particular package. This can be useful for finding method calls
from a known package, but where the receiver type is not known or is difficult to model.

View File

@@ -4,11 +4,11 @@
:stub-columns: 1
Language,Variants,Compilers,Extensions
C/C++,"C89, C99, C11, C17, C++98, C++03, C++11, C++14, C++17, C++20 [1]_ [2]_","Clang (including clang-cl [3]_ and armclang) extensions (up to Clang 12.0),
C/C++,"C89, C99, C11, C17, C++98, C++03, C++11, C++14, C++17, C++20 [1]_ [2]_","Clang (including clang-cl [3]_ and armclang) extensions (up to Clang 17.0),
GNU extensions (up to GCC 11.1),
GNU extensions (up to GCC 13.2),
Microsoft extensions (up to VS 2019),
Microsoft extensions (up to VS 2022),
Arm Compiler 5 [4]_","``.cpp``, ``.c++``, ``.cxx``, ``.hpp``, ``.hh``, ``.h++``, ``.hxx``, ``.c``, ``.cc``, ``.h``"
C#,C# up to 12,"Microsoft Visual Studio up to 2019 with .NET up to 4.8,
@@ -29,7 +29,7 @@
.. container:: footnote-group
.. [1] C++20 support is currently in beta. Supported for GCC on Linux only. Modules are *not* supported.
.. [1] C++20 support is currently in beta. Modules are *not* supported.
.. [2] Objective-C, Objective-C++, C++/CLI, and C++/CX are not supported.
.. [3] Support for the clang-cl compiler is preliminary.
.. [4] Support for the Arm Compiler (armcc) is preliminary.

View File

@@ -0,0 +1,10 @@
.. include:: ../reusables/beta-note-threat-models.rst
A threat model is a named class of dataflow sources that can be enabled or disabled independently. Threat models allow you to control the set of dataflow sources that you want to consider unsafe. For example, one codebase may only consider remote HTTP requests to be tainted, whereas another may also consider data from local files to be unsafe. You can use threat models to ensure that the relevant taint sources are used in a CodeQL analysis.
The ``kind`` property of the ``sourceModel`` determines which threat model a source is associated with. There are two main categories:
- ``remote`` which represents requests and responses from the network.
- ``local`` which represents data from local files (``file``), command-line arguments (``commandargs``), database reads (``database``), and environment variables(``environment``).
When running a CodeQL analysis, the ``remote`` threat model is included by default. You can optionally include other threat models as appropriate when using the CodeQL CLI and in GitHub code scanning. For more information, see `Analyzing your code with CodeQL queries <https://docs.github.com/code-security/codeql-cli/getting-started-with-the-codeql-cli/analyzing-your-code-with-codeql-queries#including-model-packs-to-add-potential-sources-of-tainted-data>`__ and `Customizing your advanced setup for code scanning <https://docs.github.com/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#extending-codeql-coverage-with-threat-models>`__.

View File

@@ -388,6 +388,8 @@ func extractUniverseScope() {
}
// extractObjects extracts all objects declared in the given scope
// For more information on objects, see:
// https://github.com/golang/example/blob/master/gotypes/README.md#objects
func extractObjects(tw *trap.Writer, scope *types.Scope, scopeLabel trap.Label) {
for _, name := range scope.Names() {
obj := scope.Lookup(name)
@@ -440,6 +442,8 @@ func extractMethod(tw *trap.Writer, meth *types.Func) trap.Label {
}
// extractObject extracts a single object and emits it to the objects table.
// For more information on objects, see:
// https://github.com/golang/example/blob/master/gotypes/README.md#objects
func extractObject(tw *trap.Writer, obj types.Object, lbl trap.Label) {
name := obj.Name()
isBuiltin := obj.Parent() == types.Universe
@@ -487,6 +491,8 @@ func extractObject(tw *trap.Writer, obj types.Object, lbl trap.Label) {
}
// extractObjectTypes extracts type and receiver information for all objects
// For more information on objects, see:
// https://github.com/golang/example/blob/master/gotypes/README.md#objects
func extractObjectTypes(tw *trap.Writer) {
// calling `extractType` on a named type will extract all methods defined
// on it, which will add new objects. Therefore we need to do this first
@@ -497,11 +503,13 @@ func extractObjectTypes(tw *trap.Writer) {
}
changed = tw.ForEachObject(emitObjectType)
if changed {
log.Printf("Warning: more objects were labeled while emitted object types")
log.Printf("Warning: more objects were labeled while emitting object types")
}
}
// extractObjectType extracts type and receiver information for a given object
// For more information on objects, see:
// https://github.com/golang/example/blob/master/gotypes/README.md#objects
func extractObjectType(tw *trap.Writer, obj types.Object, lbl trap.Label) {
if tp := obj.Type(); tp != nil {
extractType(tw, tp)
@@ -790,7 +798,7 @@ func extractLocalScope(tw *trap.Writer, scope *types.Scope, parentScopeLabel tra
func extractFileNode(tw *trap.Writer, nd *ast.File) {
lbl := tw.Labeler.FileLabel()
extractExpr(tw, nd.Name, lbl, 0)
extractExpr(tw, nd.Name, lbl, 0, false)
for i, decl := range nd.Decls {
extractDecl(tw, decl, lbl, i)
@@ -847,7 +855,7 @@ func emitScopeNodeInfo(tw *trap.Writer, nd ast.Node, lbl trap.Label) {
}
// extractExpr extracts AST information for the given expression and all its subexpressions
func extractExpr(tw *trap.Writer, expr ast.Expr, parent trap.Label, idx int) {
func extractExpr(tw *trap.Writer, expr ast.Expr, parent trap.Label, idx int, skipExtractingValue bool) {
if expr == nil {
return
}
@@ -900,7 +908,7 @@ func extractExpr(tw *trap.Writer, expr ast.Expr, parent trap.Label, idx int) {
return
}
kind = dbscheme.EllipsisExpr.Index()
extractExpr(tw, expr.Elt, lbl, 0)
extractExpr(tw, expr.Elt, lbl, 0, false)
case *ast.BasicLit:
if expr == nil {
return
@@ -932,28 +940,28 @@ func extractExpr(tw *trap.Writer, expr ast.Expr, parent trap.Label, idx int) {
return
}
kind = dbscheme.FuncLitExpr.Index()
extractExpr(tw, expr.Type, lbl, 0)
extractExpr(tw, expr.Type, lbl, 0, false)
extractStmt(tw, expr.Body, lbl, 1)
case *ast.CompositeLit:
if expr == nil {
return
}
kind = dbscheme.CompositeLitExpr.Index()
extractExpr(tw, expr.Type, lbl, 0)
extractExpr(tw, expr.Type, lbl, 0, false)
extractExprs(tw, expr.Elts, lbl, 1, 1)
case *ast.ParenExpr:
if expr == nil {
return
}
kind = dbscheme.ParenExpr.Index()
extractExpr(tw, expr.X, lbl, 0)
extractExpr(tw, expr.X, lbl, 0, false)
case *ast.SelectorExpr:
if expr == nil {
return
}
kind = dbscheme.SelectorExpr.Index()
extractExpr(tw, expr.X, lbl, 0)
extractExpr(tw, expr.Sel, lbl, 1)
extractExpr(tw, expr.X, lbl, 0, false)
extractExpr(tw, expr.Sel, lbl, 1, false)
case *ast.IndexExpr:
if expr == nil {
return
@@ -974,8 +982,8 @@ func extractExpr(tw *trap.Writer, expr ast.Expr, parent trap.Label, idx int) {
kind = dbscheme.IndexExpr.Index()
}
}
extractExpr(tw, expr.X, lbl, 0)
extractExpr(tw, expr.Index, lbl, 1)
extractExpr(tw, expr.X, lbl, 0, false)
extractExpr(tw, expr.Index, lbl, 1, false)
case *ast.IndexListExpr:
if expr == nil {
return
@@ -993,33 +1001,33 @@ func extractExpr(tw *trap.Writer, expr ast.Expr, parent trap.Label, idx int) {
kind = dbscheme.GenericTypeInstantiationExpr.Index()
}
}
extractExpr(tw, expr.X, lbl, 0)
extractExpr(tw, expr.X, lbl, 0, false)
extractExprs(tw, expr.Indices, lbl, 1, 1)
case *ast.SliceExpr:
if expr == nil {
return
}
kind = dbscheme.SliceExpr.Index()
extractExpr(tw, expr.X, lbl, 0)
extractExpr(tw, expr.Low, lbl, 1)
extractExpr(tw, expr.High, lbl, 2)
extractExpr(tw, expr.Max, lbl, 3)
extractExpr(tw, expr.X, lbl, 0, false)
extractExpr(tw, expr.Low, lbl, 1, false)
extractExpr(tw, expr.High, lbl, 2, false)
extractExpr(tw, expr.Max, lbl, 3, false)
case *ast.TypeAssertExpr:
if expr == nil {
return
}
kind = dbscheme.TypeAssertExpr.Index()
extractExpr(tw, expr.X, lbl, 0)
extractExpr(tw, expr.X, lbl, 0, false)
// expr.Type can be `nil` if this is the `x.(type)` in a type switch.
if expr.Type != nil {
extractExpr(tw, expr.Type, lbl, 1)
extractExpr(tw, expr.Type, lbl, 1, false)
}
case *ast.CallExpr:
if expr == nil {
return
}
kind = dbscheme.CallOrConversionExpr.Index()
extractExpr(tw, expr.Fun, lbl, 0)
extractExpr(tw, expr.Fun, lbl, 0, false)
extractExprs(tw, expr.Args, lbl, 1, 1)
if expr.Ellipsis.IsValid() {
dbscheme.HasEllipsisTable.Emit(tw, lbl)
@@ -1029,14 +1037,14 @@ func extractExpr(tw *trap.Writer, expr ast.Expr, parent trap.Label, idx int) {
return
}
kind = dbscheme.StarExpr.Index()
extractExpr(tw, expr.X, lbl, 0)
extractExpr(tw, expr.X, lbl, 0, false)
case *ast.KeyValueExpr:
if expr == nil {
return
}
kind = dbscheme.KeyValueExpr.Index()
extractExpr(tw, expr.Key, lbl, 0)
extractExpr(tw, expr.Value, lbl, 1)
extractExpr(tw, expr.Key, lbl, 0, false)
extractExpr(tw, expr.Value, lbl, 1, false)
case *ast.UnaryExpr:
if expr == nil {
return
@@ -1050,7 +1058,7 @@ func extractExpr(tw *trap.Writer, expr ast.Expr, parent trap.Label, idx int) {
}
kind = tp.Index()
}
extractExpr(tw, expr.X, lbl, 0)
extractExpr(tw, expr.X, lbl, 0, false)
case *ast.BinaryExpr:
if expr == nil {
return
@@ -1065,16 +1073,17 @@ func extractExpr(tw *trap.Writer, expr ast.Expr, parent trap.Label, idx int) {
log.Fatalf("unsupported binary operator %s", expr.Op)
}
kind = tp.Index()
extractExpr(tw, expr.X, lbl, 0)
extractExpr(tw, expr.Y, lbl, 1)
skipLeft := skipExtractingValueForLeftOperand(tw, expr)
extractExpr(tw, expr.X, lbl, 0, skipLeft)
extractExpr(tw, expr.Y, lbl, 1, false)
}
case *ast.ArrayType:
if expr == nil {
return
}
kind = dbscheme.ArrayTypeExpr.Index()
extractExpr(tw, expr.Len, lbl, 0)
extractExpr(tw, expr.Elt, lbl, 1)
extractExpr(tw, expr.Len, lbl, 0, false)
extractExpr(tw, expr.Elt, lbl, 1, false)
case *ast.StructType:
if expr == nil {
return
@@ -1103,8 +1112,8 @@ func extractExpr(tw *trap.Writer, expr ast.Expr, parent trap.Label, idx int) {
return
}
kind = dbscheme.MapTypeExpr.Index()
extractExpr(tw, expr.Key, lbl, 0)
extractExpr(tw, expr.Value, lbl, 1)
extractExpr(tw, expr.Key, lbl, 0, false)
extractExpr(tw, expr.Value, lbl, 1, false)
case *ast.ChanType:
if expr == nil {
return
@@ -1114,13 +1123,15 @@ func extractExpr(tw *trap.Writer, expr ast.Expr, parent trap.Label, idx int) {
log.Fatalf("unsupported channel direction %v", expr.Dir)
}
kind = tp.Index()
extractExpr(tw, expr.Value, lbl, 0)
extractExpr(tw, expr.Value, lbl, 0, false)
default:
log.Fatalf("unknown expression of type %T", expr)
}
dbscheme.ExprsTable.Emit(tw, lbl, kind, parent, idx)
extractNodeLocation(tw, expr, lbl)
extractValueOf(tw, expr, lbl)
if !skipExtractingValue {
extractValueOf(tw, expr, lbl)
}
}
// extractExprs extracts AST information for a list of expressions, which are children of
@@ -1130,7 +1141,7 @@ func extractExpr(tw *trap.Writer, expr ast.Expr, parent trap.Label, idx int) {
// -1 for decreasing indices)
func extractExprs(tw *trap.Writer, exprs []ast.Expr, parent trap.Label, idx int, dir int) {
for _, expr := range exprs {
extractExpr(tw, expr, parent, idx)
extractExpr(tw, expr, parent, idx, false)
idx += dir
}
}
@@ -1195,11 +1206,11 @@ func extractFields(tw *trap.Writer, fields *ast.FieldList, parent trap.Label, id
extractNodeLocation(tw, field, lbl)
if field.Names != nil {
for i, name := range field.Names {
extractExpr(tw, name, lbl, i+1)
extractExpr(tw, name, lbl, i+1, false)
}
}
extractExpr(tw, field.Type, lbl, 0)
extractExpr(tw, field.Tag, lbl, -1)
extractExpr(tw, field.Type, lbl, 0, false)
extractExpr(tw, field.Tag, lbl, -1, false)
extractDoc(tw, field.Doc, lbl)
idx += dir
}
@@ -1230,21 +1241,21 @@ func extractStmt(tw *trap.Writer, stmt ast.Stmt, parent trap.Label, idx int) {
return
}
kind = dbscheme.LabeledStmtType.Index()
extractExpr(tw, stmt.Label, lbl, 0)
extractExpr(tw, stmt.Label, lbl, 0, false)
extractStmt(tw, stmt.Stmt, lbl, 1)
case *ast.ExprStmt:
if stmt == nil {
return
}
kind = dbscheme.ExprStmtType.Index()
extractExpr(tw, stmt.X, lbl, 0)
extractExpr(tw, stmt.X, lbl, 0, false)
case *ast.SendStmt:
if stmt == nil {
return
}
kind = dbscheme.SendStmtType.Index()
extractExpr(tw, stmt.Chan, lbl, 0)
extractExpr(tw, stmt.Value, lbl, 1)
extractExpr(tw, stmt.Chan, lbl, 0, false)
extractExpr(tw, stmt.Value, lbl, 1, false)
case *ast.IncDecStmt:
if stmt == nil {
return
@@ -1256,7 +1267,7 @@ func extractStmt(tw *trap.Writer, stmt ast.Stmt, parent trap.Label, idx int) {
} else {
log.Fatalf("unsupported increment/decrement operator %v", stmt.Tok)
}
extractExpr(tw, stmt.X, lbl, 0)
extractExpr(tw, stmt.X, lbl, 0, false)
case *ast.AssignStmt:
if stmt == nil {
return
@@ -1273,13 +1284,13 @@ func extractStmt(tw *trap.Writer, stmt ast.Stmt, parent trap.Label, idx int) {
return
}
kind = dbscheme.GoStmtType.Index()
extractExpr(tw, stmt.Call, lbl, 0)
extractExpr(tw, stmt.Call, lbl, 0, false)
case *ast.DeferStmt:
if stmt == nil {
return
}
kind = dbscheme.DeferStmtType.Index()
extractExpr(tw, stmt.Call, lbl, 0)
extractExpr(tw, stmt.Call, lbl, 0, false)
case *ast.ReturnStmt:
kind = dbscheme.ReturnStmtType.Index()
extractExprs(tw, stmt.Results, lbl, 0, 1)
@@ -1299,7 +1310,7 @@ func extractStmt(tw *trap.Writer, stmt ast.Stmt, parent trap.Label, idx int) {
default:
log.Fatalf("unsupported branch statement type %v", stmt.Tok)
}
extractExpr(tw, stmt.Label, lbl, 0)
extractExpr(tw, stmt.Label, lbl, 0, false)
case *ast.BlockStmt:
if stmt == nil {
return
@@ -1313,7 +1324,7 @@ func extractStmt(tw *trap.Writer, stmt ast.Stmt, parent trap.Label, idx int) {
}
kind = dbscheme.IfStmtType.Index()
extractStmt(tw, stmt.Init, lbl, 0)
extractExpr(tw, stmt.Cond, lbl, 1)
extractExpr(tw, stmt.Cond, lbl, 1, false)
extractStmt(tw, stmt.Body, lbl, 2)
extractStmt(tw, stmt.Else, lbl, 3)
emitScopeNodeInfo(tw, stmt, lbl)
@@ -1331,7 +1342,7 @@ func extractStmt(tw *trap.Writer, stmt ast.Stmt, parent trap.Label, idx int) {
}
kind = dbscheme.ExprSwitchStmtType.Index()
extractStmt(tw, stmt.Init, lbl, 0)
extractExpr(tw, stmt.Tag, lbl, 1)
extractExpr(tw, stmt.Tag, lbl, 1, false)
extractStmt(tw, stmt.Body, lbl, 2)
emitScopeNodeInfo(tw, stmt, lbl)
case *ast.TypeSwitchStmt:
@@ -1360,7 +1371,7 @@ func extractStmt(tw *trap.Writer, stmt ast.Stmt, parent trap.Label, idx int) {
}
kind = dbscheme.ForStmtType.Index()
extractStmt(tw, stmt.Init, lbl, 0)
extractExpr(tw, stmt.Cond, lbl, 1)
extractExpr(tw, stmt.Cond, lbl, 1, false)
extractStmt(tw, stmt.Post, lbl, 2)
extractStmt(tw, stmt.Body, lbl, 3)
emitScopeNodeInfo(tw, stmt, lbl)
@@ -1369,9 +1380,9 @@ func extractStmt(tw *trap.Writer, stmt ast.Stmt, parent trap.Label, idx int) {
return
}
kind = dbscheme.RangeStmtType.Index()
extractExpr(tw, stmt.Key, lbl, 0)
extractExpr(tw, stmt.Value, lbl, 1)
extractExpr(tw, stmt.X, lbl, 2)
extractExpr(tw, stmt.Key, lbl, 0, false)
extractExpr(tw, stmt.Value, lbl, 1, false)
extractExpr(tw, stmt.X, lbl, 2, false)
extractStmt(tw, stmt.Body, lbl, 3)
emitScopeNodeInfo(tw, stmt, lbl)
default:
@@ -1426,8 +1437,8 @@ func extractDecl(tw *trap.Writer, decl ast.Decl, parent trap.Label, idx int) {
}
kind = dbscheme.FuncDeclType.Index()
extractFields(tw, decl.Recv, lbl, -1, -1)
extractExpr(tw, decl.Name, lbl, 0)
extractExpr(tw, decl.Type, lbl, 1)
extractExpr(tw, decl.Name, lbl, 0, false)
extractExpr(tw, decl.Type, lbl, 1, false)
extractStmt(tw, decl.Body, lbl, 2)
extractDoc(tw, decl.Doc, lbl)
extractTypeParamDecls(tw, decl.Type.TypeParams, lbl)
@@ -1453,8 +1464,8 @@ func extractSpec(tw *trap.Writer, spec ast.Spec, parent trap.Label, idx int) {
return
}
kind = dbscheme.ImportSpecType.Index()
extractExpr(tw, spec.Name, lbl, 0)
extractExpr(tw, spec.Path, lbl, 1)
extractExpr(tw, spec.Name, lbl, 0, false)
extractExpr(tw, spec.Path, lbl, 1, false)
extractDoc(tw, spec.Doc, lbl)
case *ast.ValueSpec:
if spec == nil {
@@ -1462,9 +1473,9 @@ func extractSpec(tw *trap.Writer, spec ast.Spec, parent trap.Label, idx int) {
}
kind = dbscheme.ValueSpecType.Index()
for i, name := range spec.Names {
extractExpr(tw, name, lbl, -(1 + i))
extractExpr(tw, name, lbl, -(1 + i), false)
}
extractExpr(tw, spec.Type, lbl, 0)
extractExpr(tw, spec.Type, lbl, 0, false)
extractExprs(tw, spec.Values, lbl, 1, 1)
extractDoc(tw, spec.Doc, lbl)
case *ast.TypeSpec:
@@ -1476,9 +1487,9 @@ func extractSpec(tw *trap.Writer, spec ast.Spec, parent trap.Label, idx int) {
} else {
kind = dbscheme.TypeDefSpecType.Index()
}
extractExpr(tw, spec.Name, lbl, 0)
extractExpr(tw, spec.Name, lbl, 0, false)
extractTypeParamDecls(tw, spec.TypeParams, lbl)
extractExpr(tw, spec.Type, lbl, 1)
extractExpr(tw, spec.Type, lbl, 1, false)
extractDoc(tw, spec.Doc, lbl)
}
dbscheme.SpecsTable.Emit(tw, lbl, kind, parent, idx)
@@ -1907,7 +1918,7 @@ func flattenBinaryExprTree(tw *trap.Writer, e ast.Expr, parent trap.Label, idx i
idx = flattenBinaryExprTree(tw, binaryexpr.X, parent, idx)
idx = flattenBinaryExprTree(tw, binaryexpr.Y, parent, idx)
} else {
extractExpr(tw, e, parent, idx)
extractExpr(tw, e, parent, idx, false)
idx = idx + 1
}
return idx
@@ -1929,10 +1940,10 @@ func extractTypeParamDecls(tw *trap.Writer, fields *ast.FieldList, parent trap.L
extractNodeLocation(tw, field, lbl)
if field.Names != nil {
for i, name := range field.Names {
extractExpr(tw, name, lbl, i+1)
extractExpr(tw, name, lbl, i+1, false)
}
}
extractExpr(tw, field.Type, lbl, 0)
extractExpr(tw, field.Type, lbl, 0, false)
extractDoc(tw, field.Doc, lbl)
idx += 1
}
@@ -2011,3 +2022,24 @@ func setTypeParamParent(tp *types.TypeParam, newobj types.Object) {
log.Fatalf("Parent of type parameter '%s %s' being set to a different value: '%s' vs '%s'", tp.String(), tp.Constraint().String(), obj, newobj)
}
}
// skipExtractingValueForLeftOperand returns true if the left operand of `be`
// should not have its value extracted because it is an intermediate value in a
// string concatenation - specifically that the right operand is a string
// literal
func skipExtractingValueForLeftOperand(tw *trap.Writer, be *ast.BinaryExpr) bool {
// check `be` has string type
tpVal := tw.Package.TypesInfo.Types[be]
if tpVal.Value == nil || tpVal.Value.Kind() != constant.String {
return false
}
// check that the right operand of `be` is a basic literal
if _, isBasicLit := be.Y.(*ast.BasicLit); !isBasicLit {
return false
}
// check that the left operand of `be` is not a basic literal
if _, isBasicLit := be.X.(*ast.BasicLit); isBasicLit {
return false
}
return true
}

View File

@@ -0,0 +1,5 @@
* ---
category: minorAnalysis
---
* Added strings.ReplaceAll, http.ParseMultipartForm sanitizers and remove path sanitizer.

View File

@@ -11,12 +11,19 @@ newtype TLocation =
TSynthLocation(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
any(DataFlow::Node n).hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
// avoid overlap with existing DB locations
not exists(File f |
locations_default(_, f, startline, startcolumn, endline, endcolumn) and
f.getAbsolutePath() = filepath
)
not existingDBLocation(filepath, startline, startcolumn, endline, endcolumn)
}
pragma[nomagic]
private predicate existingDBLocation(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
exists(File f |
locations_default(_, f, startline, startcolumn, endline, endcolumn) and
f.getAbsolutePath() = filepath
)
}
/**
* A location as given by a file, a start line, a start column,
* an end line, and an end column.

View File

@@ -5,6 +5,7 @@
import go
import semmle.go.dataflow.barrierguardutil.RegexpCheck
import DataFlow
/**
* Provides extension points for customizing the taint tracking configuration for reasoning about
@@ -74,13 +75,12 @@ module TaintedPath {
}
/**
* A call to `[file]path.Clean("/" + e)`, considered to sanitize `e` against path traversal.
* A call to `filepath.Clean("/" + e)`, considered to sanitize `e` against path traversal.
*/
class FilepathCleanSanitizer extends Sanitizer {
FilepathCleanSanitizer() {
exists(DataFlow::CallNode cleanCall, StringOps::Concatenation concatNode |
cleanCall =
any(Function f | f.hasQualifiedName(["path", "path/filepath"], "Clean")).getACall() and
cleanCall = any(Function f | f.hasQualifiedName("path/filepath", "Clean")).getACall() and
concatNode = cleanCall.getArgument(0) and
concatNode.getOperand(0).asExpr().(StringLit).getValue() = "/" and
this = cleanCall.getResult()
@@ -88,6 +88,16 @@ module TaintedPath {
}
}
/**An call to ParseMultipartForm creates multipart.Form and cleans multipart.Form.FileHeader.Filename using path.Base() */
class MultipartClean extends Sanitizer {
MultipartClean() {
exists(DataFlow::FieldReadNode frn |
frn.getField().hasQualifiedName("mime/multipart", "FileHeader", "Filename") and
this = frn
)
}
}
/**
* A check of the form `!strings.Contains(nd, "..")`, considered as a sanitizer guard for
* path traversal.
@@ -106,6 +116,21 @@ module TaintedPath {
}
}
/**
* A replacement of the form `!strings.ReplaceAll(nd, "..")` or `!strings.ReplaceAll(nd, ".")`, considered as a sanitizer for
* path traversal.
*/
class DotDotReplace extends Sanitizer {
DotDotReplace() {
exists(DataFlow::CallNode cleanCall, DataFlow::Node valueNode |
cleanCall = any(Function f | f.hasQualifiedName("strings", "ReplaceAll")).getACall() and
valueNode = cleanCall.getArgument(1) and
valueNode.asExpr().(StringLit).getValue() = ["..", "."] and
this = cleanCall.getResult()
)
}
}
/**
* A node `nd` guarded by a check that ensures it is contained within some root folder,
* considered as a sanitizer for path traversal.

View File

@@ -0,0 +1,11 @@
| tst.go:4:6:4:8 | "a" | a |
| tst.go:4:6:4:14 | ...+... | <no string value stored> |
| tst.go:4:6:4:20 | ...+... | <no string value stored> |
| tst.go:4:6:4:26 | ...+... | <no string value stored> |
| tst.go:4:6:4:32 | ...+... | <no string value stored> |
| tst.go:4:6:4:38 | ...+... | abcdef |
| tst.go:4:12:4:14 | "b" | b |
| tst.go:4:18:4:20 | "c" | c |
| tst.go:4:24:4:26 | "d" | d |
| tst.go:4:30:4:32 | "e" | e |
| tst.go:4:36:4:38 | "f" | f |

View File

@@ -0,0 +1,5 @@
package main
func main() {
_ = "a" + "b" + "c" + "d" + "e" + "f"
}

View File

@@ -0,0 +1,17 @@
import go
string checkStringValue(Expr e) {
result = e.getStringValue()
or
not exists(e.getStringValue()) and result = "<no string value stored>"
}
from Expr e
where e.getType() instanceof StringType
// We should get string values for `"a"`, `"b"`, `"c"` and `"a" + "b" + "c"
// but not `"a" + "b"`. In the extractor we avoid storing the value of
// intermediate strings in string concatenations because in pathological cases
// this could lead to a quadratic blowup in the size of string values stored,
// which then causes performance problems when we iterate through all string
// values.
select e, checkStringValue(e)

View File

@@ -2,18 +2,19 @@ edges
| TaintedPath.go:13:18:13:22 | selection of URL | TaintedPath.go:13:18:13:30 | call to Query | provenance | |
| TaintedPath.go:13:18:13:30 | call to Query | TaintedPath.go:16:29:16:40 | tainted_path | provenance | |
| TaintedPath.go:13:18:13:30 | call to Query | TaintedPath.go:20:57:20:68 | tainted_path | provenance | |
| TaintedPath.go:13:18:13:30 | call to Query | TaintedPath.go:67:39:67:56 | ...+... | provenance | |
| TaintedPath.go:20:57:20:68 | tainted_path | TaintedPath.go:20:28:20:69 | call to Join | provenance | |
| tst.go:14:2:14:39 | ... := ...[1] | tst.go:17:41:17:56 | selection of Filename | provenance | |
| TaintedPath.go:67:39:67:56 | ...+... | TaintedPath.go:67:28:67:57 | call to Clean | provenance | |
nodes
| TaintedPath.go:13:18:13:22 | selection of URL | semmle.label | selection of URL |
| TaintedPath.go:13:18:13:30 | call to Query | semmle.label | call to Query |
| TaintedPath.go:16:29:16:40 | tainted_path | semmle.label | tainted_path |
| TaintedPath.go:20:28:20:69 | call to Join | semmle.label | call to Join |
| TaintedPath.go:20:57:20:68 | tainted_path | semmle.label | tainted_path |
| tst.go:14:2:14:39 | ... := ...[1] | semmle.label | ... := ...[1] |
| tst.go:17:41:17:56 | selection of Filename | semmle.label | selection of Filename |
| TaintedPath.go:67:28:67:57 | call to Clean | semmle.label | call to Clean |
| TaintedPath.go:67:39:67:56 | ...+... | semmle.label | ...+... |
subpaths
#select
| TaintedPath.go:16:29:16:40 | tainted_path | TaintedPath.go:13:18:13:22 | selection of URL | TaintedPath.go:16:29:16:40 | tainted_path | This path depends on a $@. | TaintedPath.go:13:18:13:22 | selection of URL | user-provided value |
| TaintedPath.go:20:28:20:69 | call to Join | TaintedPath.go:13:18:13:22 | selection of URL | TaintedPath.go:20:28:20:69 | call to Join | This path depends on a $@. | TaintedPath.go:13:18:13:22 | selection of URL | user-provided value |
| tst.go:17:41:17:56 | selection of Filename | tst.go:14:2:14:39 | ... := ...[1] | tst.go:17:41:17:56 | selection of Filename | This path depends on a $@. | tst.go:14:2:14:39 | ... := ...[1] | user-provided value |
| TaintedPath.go:67:28:67:57 | call to Clean | TaintedPath.go:13:18:13:22 | selection of URL | TaintedPath.go:67:28:67:57 | call to Clean | This path depends on a $@. | TaintedPath.go:13:18:13:22 | selection of URL | user-provided value |

View File

@@ -31,6 +31,10 @@ func handler(w http.ResponseWriter, r *http.Request) {
w.Write(data)
}
// GOOD: Sanitized by strings.ReplaceAll and replaces all .. with empty string
data, _ = ioutil.ReadFile(strings.ReplaceAll(tainted_path, "..", ""))
w.Write(data)
// GOOD: This can only read inside the provided safe path
_, err := filepath.Rel("/home/user/safepath", tainted_path)
if err == nil {
@@ -53,10 +57,23 @@ func handler(w http.ResponseWriter, r *http.Request) {
w.Write(data)
}
// GOOD: Sanitized by [file]path.Clean with a prepended '/' forcing interpretation
// GOOD: Sanitized by filepath.Clean with a prepended '/' forcing interpretation
// as an absolute path, so that Clean will throw away any leading `..` components.
data, _ = ioutil.ReadFile(filepath.Clean("/" + tainted_path))
w.Write(data)
// BAD: Sanitized by path.Clean with a prepended '/' forcing interpretation
// as an absolute path, however is not sufficient for Windows paths.
data, _ = ioutil.ReadFile(path.Clean("/" + tainted_path))
w.Write(data)
// GOOD: Multipart.Form.FileHeader.Filename sanitized by filepath.Base when calling ParseMultipartForm
r.ParseMultipartForm(32 << 20)
form := r.MultipartForm
files, ok := form.File["files"]
if !ok {
return
}
data, _ = ioutil.ReadFile(files[0].Filename)
w.Write(data)
}

View File

@@ -28,25 +28,27 @@ newtype TApplicationModeEndpoint =
AutomodelJavaUtil::isFromSource(call) and
exists(Argument argExpr |
arg.asExpr() = argExpr and call = argExpr.getCall() and not argExpr.isVararg()
)
) and
not AutomodelJavaUtil::isUnexploitableType(arg.getType())
} or
TInstanceArgument(Call call, DataFlow::Node arg) {
AutomodelJavaUtil::isFromSource(call) and
arg = DataFlow::getInstanceArgument(call) and
not call instanceof ConstructorCall
not call instanceof ConstructorCall and
not AutomodelJavaUtil::isUnexploitableType(arg.getType())
} or
TImplicitVarargsArray(Call call, DataFlow::ImplicitVarargsArray arg, int idx) {
AutomodelJavaUtil::isFromSource(call) and
call = arg.getCall() and
idx = call.getCallee().getVaragsParameterIndex()
idx = call.getCallee().getVaragsParameterIndex() and
not AutomodelJavaUtil::isUnexploitableType(arg.getType())
} or
TMethodReturnValue(Call call) {
TMethodReturnValue(MethodCall call) {
AutomodelJavaUtil::isFromSource(call) and
not call instanceof ConstructorCall
not AutomodelJavaUtil::isUnexploitableType(call.getType())
} or
TOverriddenParameter(Parameter p, Method overriddenMethod) {
AutomodelJavaUtil::isFromSource(p) and
not p.getCallable().callsConstructor(_) and
p.getCallable().(Method).overrides(overriddenMethod)
}
@@ -163,7 +165,7 @@ class ImplicitVarargsArray extends CallArgument, TImplicitVarargsArray {
* may be a source.
*/
class MethodReturnValue extends ApplicationModeEndpoint, TMethodReturnValue {
Call call;
MethodCall call;
MethodReturnValue() { this = TMethodReturnValue(call) }

View File

@@ -19,11 +19,11 @@ class Test {
AtomicReference<String> reference = new AtomicReference<>(); // uninteresting (parameterless constructor)
reference.set( // $ sinkModelCandidate=set(Object):Argument[this]
args[0] // $ negativeSinkExample=set(Object):Argument[0] // modeled as a flow step
); // $ negativeSourceExample=set(Object):ReturnValue // return type is void
); // not a source candidate (return type is void)
}
public static void callSupplier(Supplier<String> supplier) {
supplier.get(); // $ sourceModelCandidate=get():ReturnValue
supplier.get(); // not a source candidate (lambda flow)
}
public static void copyFiles(Path source, Path target, CopyOption option) throws Exception {
@@ -52,7 +52,7 @@ class Test {
public static int compareFiles(File f1, File f2) {
return f1.compareTo( // $ negativeSinkExample=compareTo(File):Argument[this]
f2 // $ negativeSinkExample=compareTo(File):Argument[0] // modeled as not a sink
); // $ negativeSourceExample=compareTo(File):ReturnValue // return type is int
); // not a source candidate (return type is int)
}
public static void FilesWalkExample(Path p, FileVisitOption o) throws Exception {
@@ -66,6 +66,7 @@ class Test {
public static void WebSocketExample(URLConnection c) throws Exception {
c.getInputStream(); // $ sinkModelCandidate=getInputStream():Argument[this] positiveSourceExample=getInputStream():ReturnValue(remote) // not a source candidate (manual modeling)
c.connect(); // $ sinkModelCandidate=connect():Argument[this] // not a source candidate (return type is void)
}
public static void fileFilterExample(File f, FileFilter ff) {
@@ -102,10 +103,10 @@ class MoreTests {
Files.delete(
p // $ sinkModelCandidate=delete(Path):Argument[0] positiveSinkExample=delete(Path):Argument[0](path-injection)
); // $ negativeSourceExample=delete(Path):ReturnValue // return type is void
); // not a source candidate (return type is void)
Files.deleteIfExists(
p // $ sinkModelCandidate=deleteIfExists(Path):Argument[0] positiveSinkExample=deleteIfExists(Path):Argument[0](path-injection)
); // $ negativeSourceExample=deleteIfExists(Path):ReturnValue // return type is boolean
); // not a source candidate (return type is boolean)
}
}

View File

@@ -2,7 +2,7 @@ package com.github.codeql.test;
public class MyWriter extends java.io.Writer {
@Override
public void write(char[] cbuf, int off, int len) { // $ sinkModelCandidate=write(char[],int,int):Argument[this] sourceModelCandidate=write(char[],int,int):Parameter[this] sourceModelCandidate=write(char[],int,int):Parameter[0]
public void write(char[] cbuf, int off, int len) { // $ sinkModelCandidate=write(char[],int,int):Argument[this] positiveSinkExample=write(char[],int,int):Argument[0](file-content-store) sourceModelCandidate=write(char[],int,int):Parameter[this] sourceModelCandidate=write(char[],int,int):Parameter[0]
}
@Override

View File

@@ -1,10 +0,0 @@
# THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT.
extensions:
- addsTo:
pack: codeql/java-all
extensible: neutralModel
data:
- ["jdk.internal.access.foreign", "UnmapperProxy", "address", "()", "summary", "df-generated"]
- ["jdk.internal.access.foreign", "UnmapperProxy", "fileDescriptor", "()", "summary", "df-generated"]
- ["jdk.internal.access.foreign", "UnmapperProxy", "isSync", "()", "summary", "df-generated"]
- ["jdk.internal.access.foreign", "UnmapperProxy", "unmap", "()", "summary", "df-generated"]

View File

@@ -1,243 +0,0 @@
# THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT.
extensions:
- addsTo:
pack: codeql/java-all
extensible: summaryModel
data:
- ["jdk.internal.access", "JavaIOFileDescriptorAccess", True, "registerCleanup", "(FileDescriptor,PhantomCleanable)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaIOFilePermissionAccess", True, "newPermPlusAltPath", "(FilePermission)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaIOFilePermissionAccess", True, "newPermUsingAltPath", "(FilePermission)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaIORandomAccessFileAccess", True, "openAndDelete", "(File,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "addEnableNativeAccess", "(Module)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "addOpensToAllUnnamed", "(Module,Set,Set)", "", "Argument[1].Element", "Argument[0]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "addOpensToAllUnnamed", "(Module,Set,Set)", "", "Argument[2].Element", "Argument[0]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "createOrGetClassLoaderValueMap", "(ClassLoader)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "defineModule", "(ClassLoader,ModuleDescriptor,URI)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "defineModule", "(ClassLoader,ModuleDescriptor,URI)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "definePackage", "(ClassLoader,String,Module)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "definePackage", "(ClassLoader,String,Module)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "defineUnnamedModule", "(ClassLoader)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "getBytesNoRepl", "(String,Charset)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "getBytesUTF8NoRepl", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "getServicesCatalog", "(ModuleLayer)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "join", "(String,String,String,String[],int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "join", "(String,String,String,String[],int)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "join", "(String,String,String,String[],int)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "join", "(String,String,String,String[],int)", "", "Argument[3].ArrayElement", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "layers", "(ClassLoader)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "layers", "(ModuleLayer)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "newStringNoRepl", "(byte[],Charset)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "newStringUTF8NoRepl", "(byte[],int,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "newThreadWithAcc", "(Runnable,AccessControlContext)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "newThreadWithAcc", "(Runnable,AccessControlContext)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "setCause", "(Throwable,Throwable)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "stringConcatHelper", "(String,MethodType)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", True, "stringConcatHelper", "(String,MethodType)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", True, "collectCoordinates", "(VarHandle,int,MethodHandle)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", True, "dropCoordinates", "(VarHandle,int,Class[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", True, "filterCoordinates", "(VarHandle,int,MethodHandle[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", True, "filterValue", "(VarHandle,MethodHandle,MethodHandle)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", True, "getMethodDescriptor", "(Object)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", True, "getMethodType", "(Object)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", True, "getName", "(Object)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", True, "insertCoordinates", "(VarHandle,int,Object[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", True, "nativeMethodHandle", "(NativeEntryPoint,MethodHandle)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", True, "nativeMethodHandle", "(NativeEntryPoint,MethodHandle)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", True, "permuteCoordinates", "(VarHandle,List,int[])", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", True, "permuteCoordinates", "(VarHandle,List,int[])", "", "Argument[1].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newConfiguration", "(ModuleFinder,Map)", "", "Argument[1].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newExports", "(Set,String)", "", "Argument[0].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newExports", "(Set,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newExports", "(Set,String,Set)", "", "Argument[0].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newExports", "(Set,String,Set)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newExports", "(Set,String,Set)", "", "Argument[2].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newModuleBuilder", "(String,boolean,Set)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newModuleBuilder", "(String,boolean,Set)", "", "Argument[2].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newModuleDescriptor", "(String,ModuleDescriptor$Version,Set,Set,Set,Set,Set,Set,Set,String,int)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newModuleDescriptor", "(String,ModuleDescriptor$Version,Set,Set,Set,Set,Set,Set,Set,String,int)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newModuleDescriptor", "(String,ModuleDescriptor$Version,Set,Set,Set,Set,Set,Set,Set,String,int)", "", "Argument[2].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newModuleDescriptor", "(String,ModuleDescriptor$Version,Set,Set,Set,Set,Set,Set,Set,String,int)", "", "Argument[3].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newModuleDescriptor", "(String,ModuleDescriptor$Version,Set,Set,Set,Set,Set,Set,Set,String,int)", "", "Argument[4].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newModuleDescriptor", "(String,ModuleDescriptor$Version,Set,Set,Set,Set,Set,Set,Set,String,int)", "", "Argument[5].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newModuleDescriptor", "(String,ModuleDescriptor$Version,Set,Set,Set,Set,Set,Set,Set,String,int)", "", "Argument[6].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newModuleDescriptor", "(String,ModuleDescriptor$Version,Set,Set,Set,Set,Set,Set,Set,String,int)", "", "Argument[7].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newModuleDescriptor", "(String,ModuleDescriptor$Version,Set,Set,Set,Set,Set,Set,Set,String,int)", "", "Argument[8].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newModuleDescriptor", "(String,ModuleDescriptor$Version,Set,Set,Set,Set,Set,Set,Set,String,int)", "", "Argument[9]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newOpens", "(Set,String)", "", "Argument[0].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newOpens", "(Set,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newOpens", "(Set,String,Set)", "", "Argument[0].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newOpens", "(Set,String,Set)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newOpens", "(Set,String,Set)", "", "Argument[2].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newProvides", "(String,List)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newProvides", "(String,List)", "", "Argument[1].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newRequires", "(Set,String,ModuleDescriptor$Version)", "", "Argument[0].Element", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newRequires", "(Set,String,ModuleDescriptor$Version)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "newRequires", "(Set,String,ModuleDescriptor$Version)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", True, "packages", "(ModuleDescriptor$Builder)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "copyConstructor", "(Constructor)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "copyField", "(Field)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "copyMethod", "(Method)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "getConstructorAccessor", "(Constructor)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "getConstructorAnnotations", "(Constructor)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "getConstructorParameterAnnotations", "(Constructor)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "getConstructorSignature", "(Constructor)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "getExecutableSharedParameterTypes", "(Executable)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "getMethodAccessor", "(Method)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "getRoot", "(AccessibleObject)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "leafCopyMethod", "(Method)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "newConstructor", "(Class,Class[],Class[],int,int,String,byte[],byte[])", "", "Argument[1].ArrayElement", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "newConstructor", "(Class,Class[],Class[],int,int,String,byte[],byte[])", "", "Argument[2].ArrayElement", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "newConstructor", "(Class,Class[],Class[],int,int,String,byte[],byte[])", "", "Argument[5]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "newConstructor", "(Class,Class[],Class[],int,int,String,byte[],byte[])", "", "Argument[6]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "newConstructor", "(Class,Class[],Class[],int,int,String,byte[],byte[])", "", "Argument[7]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "setConstructorAccessor", "(Constructor,ConstructorAccessor)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", True, "setMethodAccessor", "(Method,MethodAccessor)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNetHttpCookieAccess", True, "header", "(HttpCookie)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNetHttpCookieAccess", True, "parse", "(String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNetInetAddressAccess", True, "addressBytes", "(Inet6Address)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNetInetAddressAccess", True, "getByName", "(String,InetAddress)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNetInetAddressAccess", True, "getOriginalHostName", "(InetAddress)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNetURLAccess", True, "getHandler", "(URL)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNetUriAccess", True, "create", "(String,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNetUriAccess", True, "create", "(String,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", True, "acquireScope", "(Buffer,boolean)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", True, "bufferSegment", "(Buffer)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", True, "getBufferBase", "(ByteBuffer)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", True, "newDirectByteBuffer", "(long,int,Object,MemorySegmentProxy)", "", "Argument[2]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", True, "newDirectByteBuffer", "(long,int,Object,MemorySegmentProxy)", "", "Argument[3]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", True, "newHeapByteBuffer", "(byte[],int,int,MemorySegmentProxy)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", True, "newHeapByteBuffer", "(byte[],int,int,MemorySegmentProxy)", "", "Argument[3]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", True, "newMappedByteBuffer", "(UnmapperProxy,long,int,Object,MemorySegmentProxy)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", True, "newMappedByteBuffer", "(UnmapperProxy,long,int,Object,MemorySegmentProxy)", "", "Argument[3]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", True, "newMappedByteBuffer", "(UnmapperProxy,long,int,Object,MemorySegmentProxy)", "", "Argument[4]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaSecurityAccess$ProtectionDomainCache", True, "get", "(ProtectionDomain)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaSecurityAccess$ProtectionDomainCache", True, "put", "(ProtectionDomain,PermissionCollection)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaSecurityAccess$ProtectionDomainCache", True, "put", "(ProtectionDomain,PermissionCollection)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaSecurityAccess", True, "doIntersectionPrivilege", "(PrivilegedAction,AccessControlContext)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaSecurityAccess", True, "doIntersectionPrivilege", "(PrivilegedAction,AccessControlContext,AccessControlContext)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaSecurityAccess", True, "getProtectDomains", "(AccessControlContext)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaSecuritySignatureAccess", True, "initSign", "(Signature,PrivateKey,AlgorithmParameterSpec,SecureRandom)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaSecuritySignatureAccess", True, "initSign", "(Signature,PrivateKey,AlgorithmParameterSpec,SecureRandom)", "", "Argument[2]", "Argument[0]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaSecuritySignatureAccess", True, "initSign", "(Signature,PrivateKey,AlgorithmParameterSpec,SecureRandom)", "", "Argument[3]", "Argument[0]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaSecuritySignatureAccess", True, "initVerify", "(Signature,PublicKey,AlgorithmParameterSpec)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaSecuritySignatureAccess", True, "initVerify", "(Signature,PublicKey,AlgorithmParameterSpec)", "", "Argument[2]", "Argument[0]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilCollectionAccess", True, "listFromTrustedArray", "(Object[])", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilCollectionAccess", True, "listFromTrustedArrayNullsAllowed", "(Object[])", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilJarAccess", True, "entryFor", "(JarFile,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilJarAccess", True, "entryNames", "(JarFile,CodeSource[])", "", "Argument[1].ArrayElement", "Argument[0]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilJarAccess", True, "getCodeSource", "(JarFile,URL,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilJarAccess", True, "getCodeSource", "(JarFile,URL,String)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilJarAccess", True, "getCodeSource", "(JarFile,URL,String)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilJarAccess", True, "getCodeSource", "(JarFile,URL,String)", "", "Argument[2]", "Argument[0]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilJarAccess", True, "getCodeSources", "(JarFile,URL)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilJarAccess", True, "getCodeSources", "(JarFile,URL)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilJarAccess", True, "getCodeSources", "(JarFile,URL)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilJarAccess", True, "getManifestDigests", "(JarFile)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilJarAccess", True, "getTrustedAttributes", "(Manifest,String)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilResourceBundleAccess", True, "getBundle", "(String,Locale,Module)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilResourceBundleAccess", True, "getBundle", "(String,Locale,Module)", "", "Argument[1]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilResourceBundleAccess", True, "getParent", "(ResourceBundle)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilResourceBundleAccess", True, "setLocale", "(ResourceBundle,Locale)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilResourceBundleAccess", True, "setName", "(ResourceBundle,String)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"]
- ["jdk.internal.access", "JavaUtilResourceBundleAccess", True, "setParent", "(ResourceBundle,ResourceBundle)", "", "Argument[1]", "Argument[0]", "taint", "df-generated"]
- addsTo:
pack: codeql/java-all
extensible: neutralModel
data:
- ["jdk.internal.access", "JavaBeansAccess", "getConstructorPropertiesValue", "(Constructor)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaBeansAccess", "getReadMethod", "(Class,String)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaIOAccess", "charset", "()", "summary", "df-generated"]
- ["jdk.internal.access", "JavaIOAccess", "console", "()", "summary", "df-generated"]
- ["jdk.internal.access", "JavaIOFileDescriptorAccess", "close", "(FileDescriptor)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaIOFileDescriptorAccess", "get", "(FileDescriptor)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaIOFileDescriptorAccess", "getAppend", "(FileDescriptor)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaIOFileDescriptorAccess", "getHandle", "(FileDescriptor)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaIOFileDescriptorAccess", "registerCleanup", "(FileDescriptor)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaIOFileDescriptorAccess", "set", "(FileDescriptor,int)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaIOFileDescriptorAccess", "setAppend", "(FileDescriptor,boolean)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaIOFileDescriptorAccess", "setHandle", "(FileDescriptor,long)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaIOFileDescriptorAccess", "unregisterCleanup", "(FileDescriptor)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "addEnableNativeAccessAllUnnamed", "()", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "addExports", "(Module,String)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "addExports", "(Module,String,Module)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "addExportsToAllUnnamed", "(Module,String)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "addNonExportedPackages", "(ModuleLayer)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "addOpens", "(Module,String,Module)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "addOpensToAllUnnamed", "(Module,String)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "addReads", "(Module,Module)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "addReadsAllUnnamed", "(Module)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "addUses", "(Module,Class)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "bindToLoader", "(ModuleLayer,ClassLoader)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "blockedOn", "(Interruptible)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "casAnnotationType", "(Class,AnnotationType,AnnotationType)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "classData", "(Class)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "decodeASCII", "(byte[],int,char[],int,int)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "defineClass", "(ClassLoader,Class,String,byte[],ProtectionDomain,boolean,int,Object)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "defineClass", "(ClassLoader,String,byte[],ProtectionDomain,String)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "exit", "(int)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "fastUUID", "(long,long)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "findBootstrapClassOrNull", "(String)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "findNative", "(ClassLoader,String)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "getAnnotationType", "(Class)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "getConstantPool", "(Class)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "getDeclaredAnnotationMap", "(Class)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "getDeclaredPublicMethods", "(Class,String,Class[])", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "getEnumConstantsShared", "(Class)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "getRawClassAnnotations", "(Class)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "getRawClassTypeAnnotations", "(Class)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "getRawExecutableTypeAnnotations", "(Executable)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "inflateBytesToChars", "(byte[],int,char[],int,int)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "invalidatePackageAccessCache", "()", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "invokeFinalize", "(Object)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "isEnableNativeAccess", "(Module)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "isReflectivelyExported", "(Module,String,Module)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "isReflectivelyOpened", "(Module,String,Module)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "protectionDomain", "(Class)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "registerShutdownHook", "(int,boolean,Runnable)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "stringConcatInitialCoder", "()", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangAccess", "stringConcatMix", "(long,String)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", "ensureCustomized", "(MethodHandle)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", "generateHolderClasses", "(Stream)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", "getDeclaringClass", "(Object)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", "isNative", "(Object)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", "memoryAccessVarHandle", "(Class,boolean,long,ByteOrder)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangInvokeAccess", "newMemberName", "()", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", "requires", "(ModuleDescriptor$Builder,Set,String,String)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangModuleAccess", "resolveAndBind", "(ModuleFinder,Collection,PrintStream)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangRefAccess", "runFinalization", "()", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangRefAccess", "waitForReferenceProcessing", "()", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", "getConstructorSlot", "(Constructor)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", "getExecutableTypeAnnotationBytes", "(Executable)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", "isTrustedFinalField", "(Field)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaLangReflectAccess", "newInstance", "(Constructor,Object[],Class)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaNetInetAddressAccess", "addressValue", "(Inet4Address)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", "force", "(FileDescriptor,long,boolean,long,long)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", "getBufferAddress", "(ByteBuffer)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", "getDirectBufferPool", "()", "summary", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", "isLoaded", "(long,boolean,long)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", "load", "(long,boolean,long)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", "pageSize", "()", "summary", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", "reserveMemory", "(long,long)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", "unload", "(long,boolean,long)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", "unmapper", "(ByteBuffer)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaNioAccess", "unreserveMemory", "(long,long)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaSecurityAccess", "getProtectionDomainCache", "()", "summary", "df-generated"]
- ["jdk.internal.access", "JavaSecuritySignatureAccess", "initVerify", "(Signature,Certificate,AlgorithmParameterSpec)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaSecuritySpecAccess", "clearEncodedKeySpec", "(EncodedKeySpec)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaUtilJarAccess", "ensureInitialization", "(JarFile)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaUtilJarAccess", "entries2", "(JarFile)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaUtilJarAccess", "isInitializing", "()", "summary", "df-generated"]
- ["jdk.internal.access", "JavaUtilJarAccess", "jarFileHasClassPathAttribute", "(JarFile)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaUtilJarAccess", "setEagerValidation", "(JarFile,boolean)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaUtilResourceBundleAccess", "newResourceBundle", "(Class)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaUtilZipFileAccess", "entries", "(ZipFile)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaUtilZipFileAccess", "entryNameStream", "(ZipFile)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaUtilZipFileAccess", "getExtraAttributes", "(ZipEntry)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaUtilZipFileAccess", "getManifestAndSignatureRelatedFiles", "(JarFile)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaUtilZipFileAccess", "getManifestName", "(JarFile,boolean)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaUtilZipFileAccess", "getManifestNum", "(JarFile)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaUtilZipFileAccess", "getMetaInfVersions", "(JarFile)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaUtilZipFileAccess", "setExtraAttributes", "(ZipEntry,int)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaUtilZipFileAccess", "startsWithLocHeader", "(ZipFile)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaUtilZipFileAccess", "stream", "(ZipFile)", "summary", "df-generated"]
- ["jdk.internal.access", "JavaxCryptoSpecAccess", "clearSecretKeySpec", "(SecretKeySpec)", "summary", "df-generated"]

View File

@@ -1,11 +0,0 @@
# THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT.
extensions:
- addsTo:
pack: codeql/java-all
extensible: neutralModel
data:
- ["jdk.internal.misc", "Signal$Handler", "handle", "(Signal)", "summary", "df-generated"]
- ["jdk.internal.misc", "VM$BufferPool", "getCount", "()", "summary", "df-generated"]
- ["jdk.internal.misc", "VM$BufferPool", "getMemoryUsed", "()", "summary", "df-generated"]
- ["jdk.internal.misc", "VM$BufferPool", "getName", "()", "summary", "df-generated"]
- ["jdk.internal.misc", "VM$BufferPool", "getTotalCapacity", "()", "summary", "df-generated"]

View File

@@ -1,15 +0,0 @@
# THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT.
extensions:
- addsTo:
pack: codeql/java-all
extensible: summaryModel
data:
- ["jdk.internal.org.objectweb.asm", "ClassVisitor", True, "visitAnnotation", "(String,boolean)", "", "Argument[0]", "ReturnValue", "taint", "df-generated"]
- ["jdk.internal.org.objectweb.asm", "ClassVisitor", True, "visitAnnotation", "(String,boolean)", "", "Argument[this]", "ReturnValue", "taint", "df-generated"]
- addsTo:
pack: codeql/java-all
extensible: neutralModel
data:
- ["jdk.internal.org.objectweb.asm", "ClassVisitor", "visit", "(int,int,String,String,String,String[])", "summary", "df-generated"]
- ["jdk.internal.org.objectweb.asm", "ClassVisitor", "visitAttribute", "(Attribute)", "summary", "df-generated"]
- ["jdk.internal.org.objectweb.asm", "ClassVisitor", "visitModule", "(String,int,String)", "summary", "df-generated"]

View File

@@ -32,12 +32,24 @@ where
)
or
documentable instanceof ClassOrInterface and
not documentable instanceof Record and
not exists(TypeVariable tv | tv.getGenericType() = documentable |
"<" + tv.getName() + ">" = paramTag.getParamName()
) and
msg =
"@param tag \"" + paramTag.getParamName() +
"\" does not match any actual type parameter of type \"" + documentable.getName() + "\"."
or
documentable instanceof Record and
not exists(TypeVariable tv | tv.getGenericType() = documentable |
"<" + tv.getName() + ">" = paramTag.getParamName()
) and
not documentable.(Record).getCanonicalConstructor().getAParameter().getName() =
paramTag.getParamName() and
msg =
"@param tag \"" + paramTag.getParamName() +
"\" does not match any actual type parameter or record parameter of record \"" +
documentable.getName() + "\"."
else
// The tag has no value at all.
msg = "This @param tag does not have a value."

View File

@@ -27,10 +27,23 @@ class DangerousAssignOpExpr extends AssignOp {
predicate problematicCasting(Type t, Expr e) { e.getType().(NumType).widerThan(t) }
from DangerousAssignOpExpr a, Expr e
Variable getVariable(Expr dest) {
result = dest.(VarAccess).getVariable()
or
result = dest.(ArrayAccess).getArray().(VarAccess).getVariable()
}
from DangerousAssignOpExpr a, Expr e, Top v
where
e = a.getSource() and
problematicCasting(a.getDest().getType(), e)
problematicCasting(a.getDest().getType(), e) and
(
v = getVariable(a.getDest())
or
// fallback, in case we can't easily determine the variable
not exists(getVariable(a.getDest())) and
v = a.getDest()
)
select a,
"Implicit cast of source type " + e.getType().getName() + " to narrower destination type " +
a.getDest().getType().getName() + "."
"Implicit cast of source type " + e.getType().getName() + " to narrower destination type $@.", v,
a.getDest().getType().getName()

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* The `java/unknown-javadoc-parameter` now accepts `@param` tags that apply to the parameters of a
record.

View File

@@ -120,5 +120,17 @@ public class Test<V> {
*/
interface GenericInterface<T> {}
// Diagnostic Matches: Incomplete inheritance relation for type java.lang.Object and supertype none
/**
* @param i exists
* @param k does not
*/
static record SomeRecord(int i, int j) {}
/**
* @param <T> exists
* @param <U> does not
* @param i exists
* @param k does not
*/
static record GenericRecord<T>(int i, int j) {}
}

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -source 16 -target 16

View File

@@ -12,3 +12,6 @@
| Test.java:112:6:112:12 | @param | @param tag "<X>" does not match any actual type parameter of type "GenericClass". |
| Test.java:118:6:118:12 | @param | @param tag "T" does not match any actual type parameter of type "GenericInterface". |
| Test.java:119:6:119:12 | @param | @param tag "<X>" does not match any actual type parameter of type "GenericInterface". |
| Test.java:125:6:125:12 | @param | @param tag "k" does not match any actual type parameter or record parameter of record "SomeRecord". |
| Test.java:131:6:131:12 | @param | @param tag "<U>" does not match any actual type parameter or record parameter of record "GenericRecord". |
| Test.java:133:6:133:12 | @param | @param tag "k" does not match any actual type parameter or record parameter of record "GenericRecord". |

View File

@@ -1,2 +1,4 @@
| Test.java:68:5:68:25 | ...+=... | Implicit cast of source type long to narrower destination type int. |
| Test.java:87:4:87:9 | ...+=... | Implicit cast of source type long to narrower destination type int. |
| Test.java:68:5:68:25 | ...+=... | Implicit cast of source type long to narrower destination type $@. | Test.java:64:4:64:13 | int i | int |
| Test.java:87:4:87:9 | ...+=... | Implicit cast of source type long to narrower destination type $@. | Test.java:81:4:81:13 | int i | int |
| Test.java:289:5:289:30 | ...+=... | Implicit cast of source type long to narrower destination type $@. | Test.java:285:4:285:27 | int[] arr | int |
| Test.java:293:7:293:44 | ...+=... | Implicit cast of source type long to narrower destination type $@. | Test.java:293:7:293:24 | ...[...] | int |

View File

@@ -279,12 +279,29 @@ class Test {
// subsequently cast to narrower type int
int widenedThenNarrowed = (int) (data2 + 10L);
}
// InformationLoss
{
int[] arr = new int[10];
while (arr[2] < 1000000) {
// BAD: getLargeNumber is implicitly narrowed to an integer
// which will result in overflows if it is large
arr[2] += getLargeNumber();
}
// BAD.
getAnIntArray()[0] += getLargeNumber();
}
}
public static long getLargeNumber() {
return Long.MAX_VALUE / 2;
}
public static int[] getAnIntArray() {
return new int[10];
}
public static boolean properlyBounded(int i) {
return i < Integer.MAX_VALUE;
}

View File

@@ -241,15 +241,23 @@ module API {
}
/**
* Gets a node representing an instance of this API component, that is, an object whose
* constructor is the function represented by this node.
* Gets a node representing an instance of the class represented by this node.
* This includes instances of subclasses.
*
* For example, if this node represents a use of some class `A`, then there might be a node
* representing instances of `A`, typically corresponding to expressions `new A()` at the
* source level.
* For example:
* ```js
* import { C } from "foo";
*
* This predicate may have multiple results when there are multiple constructor calls invoking this API component.
* Consider using `getAnInstantiation()` if there is a need to distinguish between individual constructor calls.
* new C(); // API::moduleImport("foo").getMember("C").getInstance()
*
* class D extends C {
* m() {
* this; // API::moduleImport("foo").getMember("C").getInstance()
* }
* }
*
* new D(); // API::moduleImport("foo").getMember("C").getInstance()
* ```
*/
cached
Node getInstance() {
@@ -891,6 +899,17 @@ module API {
(propDesc = Promises::errorProp() or propDesc = "")
}
pragma[nomagic]
private DataFlow::ClassNode getALocalSubclass(DataFlow::SourceNode node) {
result.getASuperClassNode().getALocalSource() = node
}
bindingset[node]
pragma[inline_late]
private DataFlow::ClassNode getALocalSubclassFwd(DataFlow::SourceNode node) {
result = getALocalSubclass(node)
}
/**
* Holds if `ref` is a use of a node that should have an incoming edge from `base` labeled
* `lbl` in the API graph.
@@ -927,6 +946,15 @@ module API {
or
lbl = Label::forwardingFunction() and
DataFlow::functionForwardingStep(pred.getALocalUse(), ref)
or
exists(DataFlow::ClassNode cls |
lbl = Label::instance() and
cls = getALocalSubclassFwd(pred).getADirectSubClass*()
|
ref = cls.getAReceiverNode()
or
ref = cls.getAClassReference().getAnInstantiation()
)
)
or
exists(DataFlow::Node def, DataFlow::FunctionNode fn |

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* `API::Node#getInstance()` now includes instances of subclasses, include transitive subclasses.
The same changes applies to uses of the `Instance` token in data extensions.

View File

@@ -74,6 +74,10 @@ taintFlow
| test.js:249:28:249:35 | source() | test.js:249:28:249:35 | source() |
| test.js:252:15:252:22 | source() | test.js:252:15:252:22 | source() |
| test.js:254:32:254:39 | source() | test.js:254:32:254:39 | source() |
| test.js:262:10:262:31 | this.ba ... ource() | test.js:262:10:262:31 | this.ba ... ource() |
| test.js:265:6:265:39 | new MyS ... ource() | test.js:265:6:265:39 | new MyS ... ource() |
| test.js:269:10:269:31 | this.ba ... ource() | test.js:269:10:269:31 | this.ba ... ource() |
| test.js:272:6:272:40 | new MyS ... ource() | test.js:272:6:272:40 | new MyS ... ource() |
isSink
| test.js:54:18:54:25 | source() | test-sink |
| test.js:55:22:55:29 | source() | test-sink |

View File

@@ -256,3 +256,17 @@ function fuzzy() {
fuzzyCall(source()); // OK - does not come from 'testlib'
require('blah').fuzzyCall(source()); // OK - does not come from 'testlib'
}
class MySubclass extends testlib.BaseClass {
foo() {
sink(this.baseclassSource()); // NOT OK
}
}
sink(new MySubclass().baseclassSource()); // NOT OK
class MySubclass2 extends MySubclass {
foo2() {
sink(this.baseclassSource()); // NOT OK
}
}
sink(new MySubclass2().baseclassSource()); // NOT OK

View File

@@ -80,6 +80,7 @@ class Sources extends ModelInput::SourceModelCsv {
"testlib;Member[ParamDecoratorSource].DecoratedParameter;test-source",
"testlib;Member[MethodDecorator].DecoratedMember.Parameter[0];test-source",
"testlib;Member[MethodDecoratorWithArgs].ReturnValue.DecoratedMember.Parameter[0];test-source",
"testlib;Member[BaseClass].Instance.Member[baseclassSource].ReturnValue;test-source",
]
}
}

View File

@@ -5,7 +5,6 @@ py_binary(
srcs = [
"make_zips.py",
"python_tracer.py",
"unparse.py",
],
data = [
"LICENSE-PSF.md",

View File

@@ -1,41 +0,0 @@
#!/bin/bash
set -Eeuo pipefail # see https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
set -x
CODEQL=${CODEQL:-codeql}
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
cd "$SCRIPTDIR"
# start on clean slate
rm -rf dbs
mkdir dbs
cd "$SCRIPTDIR"
export CODEQL_EXTRACTOR_PYTHON_FORCE_ENABLE_LIBRARY_EXTRACTION_UNTIL_2_17_0=
$CODEQL database create dbs/normal --language python --source-root repo_dir/
export CODEQL_EXTRACTOR_PYTHON_FORCE_ENABLE_LIBRARY_EXTRACTION_UNTIL_2_17_0=1
$CODEQL database create dbs/with-lib-extraction --language python --source-root repo_dir/
# ---
set +x
EXTRACTED_NORMAL=$(unzip -l dbs/normal/src.zip | wc -l)
EXTRACTED_WITH_LIB_EXTRACTION=$(unzip -l dbs/with-lib-extraction/src.zip | wc -l)
exitcode=0
echo "EXTRACTED_NORMAL=$EXTRACTED_NORMAL"
echo "EXTRACTED_WITH_LIB_EXTRACTION=$EXTRACTED_WITH_LIB_EXTRACTION"
if [[ ! $EXTRACTED_WITH_LIB_EXTRACTION -gt $EXTRACTED_NORMAL ]]; then
echo "ERROR: EXTRACTED_WITH_LIB_EXTRACTION not greater than EXTRACTED_NORMAL"
exitcode=1
fi
exit $exitcode

View File

@@ -17,63 +17,33 @@ mkdir dbs
# set up venvs
cd repo_dir
# make venv with some package in it (so we show that our ignore logic is correct)
python3 -m venv venv
venv/bin/pip install flask
python3 -m venv venv2
cd "$SCRIPTDIR"
# In 2.16.0 we stop extracting libraries by default, so to test this functionality we
# need to force enable it. Once we release 2.17.0 and turn off library extraction for
# good, we can remove the part of this test ensuring that dependencies in an active
# venv are still extracted (since that will no longer be the case).
export CODEQL_EXTRACTOR_PYTHON_FORCE_ENABLE_LIBRARY_EXTRACTION_UNTIL_2_17_0=1
# Create DBs with venv2 active (that does not have flask installed)
source repo_dir/venv2/bin/activate
export CODEQL_EXTRACTOR_PYTHON_DISABLE_AUTOMATIC_VENV_EXCLUDE=
$CODEQL database create dbs/normal --language python --source-root repo_dir/
export CODEQL_EXTRACTOR_PYTHON_DISABLE_AUTOMATIC_VENV_EXCLUDE=1
$CODEQL database create dbs/no-venv-ignore --language python --source-root repo_dir/
# Create DB with venv active that has flask installed. We want to ensure that we're
# still able to resolve imports to flask, but don't want to extract EVERYTHING from
# within the venv. Important note is that the test-file in the repo_dir actually imports
# flask :D
source repo_dir/venv/bin/activate
export CODEQL_EXTRACTOR_PYTHON_DISABLE_AUTOMATIC_VENV_EXCLUDE=
$CODEQL database create dbs/normal-with-flask-venv --language python --source-root repo_dir/
# ---
set +x
EXTRACTED_NORMAL=$(unzip -l dbs/normal/src.zip | wc -l)
EXTRACTED_NO_VENV_IGNORE=$(unzip -l dbs/no-venv-ignore/src.zip | wc -l)
EXTRACTED_ACTIVE_FLASK=$(unzip -l dbs/normal-with-flask-venv/src.zip | wc -l)
exitcode=0
echo "EXTRACTED_NORMAL=$EXTRACTED_NORMAL"
echo "EXTRACTED_NO_VENV_IGNORE=$EXTRACTED_NO_VENV_IGNORE"
echo "EXTRACTED_ACTIVE_FLASK=$EXTRACTED_ACTIVE_FLASK"
if [[ ! $EXTRACTED_NORMAL -lt $EXTRACTED_NO_VENV_IGNORE ]]; then
echo "ERROR: EXTRACTED_NORMAL not smaller EXTRACTED_NO_VENV_IGNORE"
exitcode=1
fi
if [[ ! $EXTRACTED_NORMAL -lt $EXTRACTED_ACTIVE_FLASK ]]; then
echo "ERROR: EXTRACTED_NORMAL not smaller EXTRACTED_ACTIVE_FLASK"
exitcode=1
fi
if [[ ! $EXTRACTED_ACTIVE_FLASK -lt $EXTRACTED_NO_VENV_IGNORE ]]; then
echo "ERROR: EXTRACTED_ACTIVE_FLASK not smaller EXTRACTED_NO_VENV_IGNORE"
exitcode=1
fi
exit $exitcode

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