Merge branch 'main' into fix/update-gson-model

This commit is contained in:
Eric Bickle
2024-01-02 14:05:33 -08:00
committed by GitHub
383 changed files with 23119 additions and 2317 deletions

View File

@@ -454,10 +454,6 @@
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll", "ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll",
"swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll" "swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll"
], ],
"SummaryTypeTracker": [
"python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll",
"ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll"
],
"IncompleteUrlSubstringSanitization": [ "IncompleteUrlSubstringSanitization": [
"javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qll", "javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qll",
"ruby/ql/src/queries/security/cwe-020/IncompleteUrlSubstringSanitization.qll" "ruby/ql/src/queries/security/cwe-020/IncompleteUrlSubstringSanitization.qll"

View File

@@ -0,0 +1,17 @@
class AttributeArg extends @attribute_arg {
string toString() { none() }
}
class Attribute extends @attribute {
string toString() { none() }
}
class Location extends @location_default {
string toString() { none() }
}
from AttributeArg arg, int kind, int kind_new, Attribute attr, int index, Location location
where
attribute_args(arg, kind, attr, index, location) and
if arg instanceof @attribute_arg_expr then kind_new = 0 else kind_new = kind
select arg, kind_new, attr, index, location

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
description: Support expression attribute arguments
compatibility: partial
attribute_arg_expr.rel: delete
attribute_args.rel: run attribute_args.qlo

View File

@@ -1,3 +1,7 @@
## 0.12.2
No user-facing changes.
## 0.12.1 ## 0.12.1
### New Features ### New Features

View File

@@ -0,0 +1,4 @@
---
category: fix
---
* Under certain circumstances a function declaration that is not also a definition could be associated with a `Function` that did not have the definition as a `FunctionDeclarationEntry`. This is now fixed when only one definition exists, and a unique `Function` will exist that has both the declaration and the definition as a `FunctionDeclarationEntry`.

View File

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

View File

@@ -1,2 +1,2 @@
--- ---
lastReleaseVersion: 0.12.1 lastReleaseVersion: 0.12.2

View File

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

View File

@@ -7,6 +7,7 @@ import semmle.code.cpp.Location
private import semmle.code.cpp.Enclosing private import semmle.code.cpp.Enclosing
private import semmle.code.cpp.internal.ResolveClass private import semmle.code.cpp.internal.ResolveClass
private import semmle.code.cpp.internal.ResolveGlobalVariable private import semmle.code.cpp.internal.ResolveGlobalVariable
private import semmle.code.cpp.internal.ResolveFunction
/** /**
* Get the `Element` that represents this `@element`. * Get the `Element` that represents this `@element`.
@@ -30,11 +31,14 @@ pragma[inline]
@element unresolveElement(Element e) { @element unresolveElement(Element e) {
not result instanceof @usertype and not result instanceof @usertype and
not result instanceof @variable and not result instanceof @variable and
not result instanceof @function and
result = e result = e
or or
e = resolveClass(result) e = resolveClass(result)
or or
e = resolveGlobalVariable(result) e = resolveGlobalVariable(result)
or
e = resolveFunction(result)
} }
/** /**

View File

@@ -9,6 +9,7 @@ import semmle.code.cpp.exprs.Call
import semmle.code.cpp.metrics.MetricFunction import semmle.code.cpp.metrics.MetricFunction
import semmle.code.cpp.Linkage import semmle.code.cpp.Linkage
private import semmle.code.cpp.internal.ResolveClass private import semmle.code.cpp.internal.ResolveClass
private import semmle.code.cpp.internal.ResolveFunction
/** /**
* A C/C++ function [N4140 8.3.5]. Both member functions and non-member * A C/C++ function [N4140 8.3.5]. Both member functions and non-member
@@ -25,6 +26,8 @@ private import semmle.code.cpp.internal.ResolveClass
* in more detail in `Declaration.qll`. * in more detail in `Declaration.qll`.
*/ */
class Function extends Declaration, ControlFlowNode, AccessHolder, @function { class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
Function() { isFunction(underlyingElement(this)) }
override string getName() { functions(underlyingElement(this), result, _) } override string getName() { functions(underlyingElement(this), result, _) }
/** /**

View File

@@ -281,6 +281,11 @@ class AttributeArgument extends Element, @attribute_arg {
attribute_arg_constant(underlyingElement(this), unresolveElement(result)) attribute_arg_constant(underlyingElement(this), unresolveElement(result))
} }
/**
* Gets the value of this argument, if its value is an expression.
*/
Expr getValueExpr() { attribute_arg_expr(underlyingElement(this), unresolveElement(result)) }
/** /**
* Gets the attribute to which this is an argument. * Gets the attribute to which this is an argument.
*/ */
@@ -308,7 +313,10 @@ class AttributeArgument extends Element, @attribute_arg {
else else
if underlyingElement(this) instanceof @attribute_arg_constant_expr if underlyingElement(this) instanceof @attribute_arg_constant_expr
then tail = this.getValueConstant().toString() then tail = this.getValueConstant().toString()
else tail = this.getValueText() else
if underlyingElement(this) instanceof @attribute_arg_expr
then tail = this.getValueExpr().toString()
else tail = this.getValueText()
) and ) and
result = prefix + tail result = prefix + tail
) )

View File

@@ -110,8 +110,8 @@ private predicate loopConditionAlwaysUponEntry(ControlFlowNode loop, Expr condit
* should be in this relation. * should be in this relation.
*/ */
pragma[noinline] pragma[noinline]
private predicate isFunction(Element el) { private predicate isFunction(@element el) {
el instanceof Function el instanceof @function
or or
el.(Expr).getParent() = el el.(Expr).getParent() = el
} }
@@ -122,7 +122,7 @@ private predicate isFunction(Element el) {
*/ */
pragma[noopt] pragma[noopt]
private predicate callHasNoTarget(@funbindexpr fc) { private predicate callHasNoTarget(@funbindexpr fc) {
exists(Function f | exists(@function f |
funbind(fc, f) and funbind(fc, f) and
not isFunction(f) not isFunction(f)
) )

View File

@@ -0,0 +1,57 @@
private predicate hasDefinition(@function f) {
exists(@fun_decl fd | fun_decls(fd, f, _, _, _) | fun_def(fd))
}
private predicate onlyOneCompleteFunctionExistsWithMangledName(@mangledname name) {
strictcount(@function f | hasDefinition(f) and mangled_name(f, name)) = 1
}
/** Holds if `f` is a unique function with a definition named `name`. */
private predicate isFunctionWithMangledNameAndWithDefinition(@mangledname name, @function f) {
hasDefinition(f) and
mangled_name(f, name) and
onlyOneCompleteFunctionExistsWithMangledName(name)
}
/** Holds if `f` is a function without a definition named `name`. */
private predicate isFunctionWithMangledNameAndWithoutDefinition(@mangledname name, @function f) {
not hasDefinition(f) and
mangled_name(f, name)
}
/**
* Holds if `incomplete` is a function without a definition, and there exists
* a unique function `complete` with the same name that does have a definition.
*/
private predicate hasTwinWithDefinition(@function incomplete, @function complete) {
not function_instantiation(incomplete, complete) and
(
not compgenerated(incomplete) or
not compgenerated(complete)
) and
exists(@mangledname name |
isFunctionWithMangledNameAndWithoutDefinition(name, incomplete) and
isFunctionWithMangledNameAndWithDefinition(name, complete)
)
}
import Cached
cached
private module Cached {
/**
* If `f` is a function without a definition, and there exists a unique
* function with the same name that does have a definition, then the
* result is that unique function. Otherwise, the result is `f`.
*/
cached
@function resolveFunction(@function f) {
hasTwinWithDefinition(f, result)
or
not hasTwinWithDefinition(f, _) and
result = f
}
cached
predicate isFunction(@function f) { f = resolveFunction(_) }
}

View File

@@ -24,8 +24,8 @@ private predicate isGlobalWithMangledNameAndWithoutDefinition(@mangledname name,
* a unique global variable `complete` with the same name that does have a definition. * a unique global variable `complete` with the same name that does have a definition.
*/ */
private predicate hasTwinWithDefinition(@globalvariable incomplete, @globalvariable complete) { private predicate hasTwinWithDefinition(@globalvariable incomplete, @globalvariable complete) {
not variable_instantiation(incomplete, complete) and
exists(@mangledname name | exists(@mangledname name |
not variable_instantiation(incomplete, complete) and
isGlobalWithMangledNameAndWithoutDefinition(name, incomplete) and isGlobalWithMangledNameAndWithoutDefinition(name, incomplete) and
isGlobalWithMangledNameAndWithDefinition(name, complete) isGlobalWithMangledNameAndWithDefinition(name, complete)
) )

View File

@@ -59,6 +59,41 @@ private module Cached {
import Cached import Cached
private import Nodes0 private import Nodes0
/**
* A module for calculating the number of stars (i.e., `*`s) needed for various
* dataflow node `toString` predicates.
*/
module NodeStars {
private int getNumberOfIndirections(Node n) {
result = n.(RawIndirectOperand).getIndirectionIndex()
or
result = n.(RawIndirectInstruction).getIndirectionIndex()
or
result = n.(VariableNode).getIndirectionIndex()
or
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
or
result = n.(FinalParameterNode).getIndirectionIndex()
}
private int maxNumberOfIndirections() { result = max(getNumberOfIndirections(_)) }
private string repeatStars(int n) {
n = 0 and result = ""
or
n = [1 .. maxNumberOfIndirections()] and
result = "*" + repeatStars(n - 1)
}
/**
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
* output for `n`.
*/
string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
}
import NodeStars
class Node0Impl extends TIRDataFlowNode0 { class Node0Impl extends TIRDataFlowNode0 {
/** /**
* INTERNAL: Do not use. * INTERNAL: Do not use.

View File

@@ -486,47 +486,6 @@ class Node extends TIRDataFlowNode {
} }
} }
private string toExprString(Node n) {
not isDebugMode() and
(
result = n.asExpr(0).toString()
or
not exists(n.asExpr()) and
result = stars(n) + n.asIndirectExpr(0, 1).toString()
)
}
private module NodeStars {
private int getNumberOfIndirections(Node n) {
result = n.(RawIndirectOperand).getIndirectionIndex()
or
result = n.(RawIndirectInstruction).getIndirectionIndex()
or
result = n.(VariableNode).getIndirectionIndex()
or
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
or
result = n.(FinalParameterNode).getIndirectionIndex()
}
private int maxNumberOfIndirections() { result = max(getNumberOfIndirections(_)) }
private string repeatStars(int n) {
n = 0 and result = ""
or
n = [1 .. maxNumberOfIndirections()] and
result = "*" + repeatStars(n - 1)
}
/**
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
* output for `n`.
*/
string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
}
private import NodeStars
/** /**
* A class that lifts pre-SSA dataflow nodes to regular dataflow nodes. * A class that lifts pre-SSA dataflow nodes to regular dataflow nodes.
*/ */
@@ -589,7 +548,10 @@ Type stripPointer(Type t) {
result = t.(FunctionPointerIshType).getBaseType() result = t.(FunctionPointerIshType).getBaseType()
} }
private class PostUpdateNodeImpl extends PartialDefinitionNode, TPostUpdateNodeImpl { /**
* INTERNAL: Do not use.
*/
class PostUpdateNodeImpl extends PartialDefinitionNode, TPostUpdateNodeImpl {
int indirectionIndex; int indirectionIndex;
Operand operand; Operand operand;
@@ -997,7 +959,8 @@ private Type getTypeImpl0(Type t, int indirectionIndex) {
* *
* If `indirectionIndex` cannot be stripped off `t`, an `UnknownType` is returned. * If `indirectionIndex` cannot be stripped off `t`, an `UnknownType` is returned.
*/ */
bindingset[indirectionIndex] bindingset[t, indirectionIndex]
pragma[inline_late]
Type getTypeImpl(Type t, int indirectionIndex) { Type getTypeImpl(Type t, int indirectionIndex) {
result = getTypeImpl0(t, indirectionIndex) result = getTypeImpl0(t, indirectionIndex)
or or

View File

@@ -1,9 +1,24 @@
/** /**
* This file activates debugging mode for dataflow node printing. * This file contains the class that implements the _debug_ version of
* `toString` for `Instruction` and `Operand` dataflow nodes.
*/ */
private import semmle.code.cpp.ir.IR
private import codeql.util.Unit
private import Node0ToString private import Node0ToString
private import DataFlowUtil
private class DebugNode0ToString extends Node0ToString { private class DebugNode0ToString extends Node0ToString {
final override predicate isDebugMode() { any() } DebugNode0ToString() {
// Silence warning about `this` not being bound.
exists(this)
}
override string instructionToString(Instruction i) { result = i.getDumpString() }
override string operandToString(Operand op) {
result = op.getDumpString() + " @ " + op.getUse().getResultId()
}
override string toExprString(Node n) { none() }
} }

View File

@@ -1,75 +1,53 @@
/** /**
* This file contains the abstract class that serves as the base class for * This file imports the class that is used to construct the strings used by
* dataflow node printing. * `Node.ToString`.
* *
* By default, a non-debug string is produced. However, a debug-friendly * Normally, this file should just import `NormalNode0ToString` to compute the
* string can be produced by importing `DebugPrinting.qll`. * efficient `toString`, but for debugging purposes one can import
* `DebugPrinting.qll` to better correlate the dataflow nodes with their
* underlying instructions and operands.
*/ */
private import semmle.code.cpp.ir.IR private import semmle.code.cpp.ir.IR
private import codeql.util.Unit private import codeql.util.Unit
private import DataFlowUtil
import NormalNode0ToString // Change this import to control which version should be used.
/** /** An abstract class to control the behavior of `Node.toString`. */
* A class to control whether a debugging version of instructions and operands abstract class Node0ToString extends Unit {
* should be printed as part of the `toString` output of dataflow nodes. /**
* * Gets the string that should be used by `OperandNode.toString` to print the
* To enable debug printing import the `DebugPrinting.ql` file. By default, * dataflow node whose underlying operand is `op.`
* non-debug output will be used. */
*/ abstract string operandToString(Operand op);
class Node0ToString extends Unit {
abstract predicate isDebugMode();
private string normalInstructionToString(Instruction i) {
not this.isDebugMode() and
if i.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = i.getAst().toString()
}
private string normalOperandToString(Operand op) {
not this.isDebugMode() and
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = op.getDef().getAst().toString()
}
/** /**
* Gets the string that should be used by `InstructionNode.toString` * Gets the string that should be used by `InstructionNode.toString` to print
* the dataflow node whose underlying instruction is `instr`.
*/ */
string instructionToString(Instruction i) { abstract string instructionToString(Instruction i);
if this.isDebugMode()
then result = i.getDumpString()
else result = this.normalInstructionToString(i)
}
/** /**
* Gets the string that should be used by `OperandNode.toString`. * Gets the string representation of the `Expr` associated with `n`, if any.
*/ */
string operandToString(Operand op) { abstract string toExprString(Node n);
if this.isDebugMode()
then result = op.getDumpString() + " @ " + op.getUse().getResultId()
else result = this.normalOperandToString(op)
}
}
private class NoDebugNode0ToString extends Node0ToString {
final override predicate isDebugMode() { none() }
} }
/** /**
* Gets the string that should be used by `OperandNode.toString`. * Gets the string that should be used by `OperandNode.toString` to print the
* dataflow node whose underlying operand is `op.`
*/ */
string operandToString(Operand op) { result = any(Node0ToString nts).operandToString(op) } string operandToString(Operand op) { result = any(Node0ToString s).operandToString(op) }
/** /**
* Gets the string that should be used by `InstructionNode.toString` * Gets the string that should be used by `InstructionNode.toString` to print
* the dataflow node whose underlying instruction is `instr`.
*/ */
string instructionToString(Instruction i) { result = any(Node0ToString nts).instructionToString(i) } string instructionToString(Instruction instr) {
result = any(Node0ToString s).instructionToString(instr)
}
/** /**
* Holds if debugging mode is enabled. * Gets the string representation of the `Expr` associated with `n`, if any.
*
* In debug mode the `toString` on dataflow nodes is more expensive to compute,
* but gives more precise information about the different dataflow nodes.
*/ */
predicate isDebugMode() { any(Node0ToString nts).isDebugMode() } string toExprString(Node n) { result = any(Node0ToString s).toExprString(n) }

View File

@@ -0,0 +1,36 @@
/**
* This file contains the class that implements the non-debug version of
* `toString` for `Instruction` and `Operand` dataflow nodes.
*/
private import semmle.code.cpp.ir.IR
private import codeql.util.Unit
private import Node0ToString
private import DataFlowUtil
private import DataFlowPrivate
private class NormalNode0ToString extends Node0ToString {
NormalNode0ToString() {
// Silence warning about `this` not being bound.
exists(this)
}
override string instructionToString(Instruction i) {
if i.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = i.getAst().toString()
}
override string operandToString(Operand op) {
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
then result = "this"
else result = op.getDef().getAst().toString()
}
override string toExprString(Node n) {
result = n.asExpr(0).toString()
or
not exists(n.asExpr()) and
result = stars(n) + n.asIndirectExpr(0, 1).toString()
}
}

View File

@@ -1,6 +1,7 @@
private import cpp private import cpp
private import semmle.code.cpp.ir.IR private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private import SsaInternals as Ssa private import SsaInternals as Ssa
private import PrintIRUtilities private import PrintIRUtilities
@@ -33,9 +34,9 @@ private string getNodeProperty(Node node, string key) {
key = "flow" and key = "flow" and
result = result =
strictconcat(string flow, boolean to, int order1, int order2 | strictconcat(string flow, boolean to, int order1, int order2 |
flow = getFromFlow(node, order1, order2) + "->" + starsForNode(node) + "@" and to = false flow = getFromFlow(node, order1, order2) + "->" + stars(node) + "@" and to = false
or or
flow = starsForNode(node) + "@->" + getToFlow(node, order1, order2) and to = true flow = stars(node) + "@->" + getToFlow(node, order1, order2) and to = true
| |
flow, ", " order by to, order1, order2, flow flow, ", " order by to, order1, order2, flow
) )

View File

@@ -7,37 +7,14 @@ private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
private string stars(int k) {
k =
[0 .. max([
any(RawIndirectInstruction n).getIndirectionIndex(),
any(RawIndirectOperand n).getIndirectionIndex()
]
)] and
(if k = 0 then result = "" else result = "*" + stars(k - 1))
}
string starsForNode(Node node) {
exists(int indirectionIndex |
node.(IndirectInstruction).hasInstructionAndIndirectionIndex(_, indirectionIndex) or
node.(IndirectOperand).hasOperandAndIndirectionIndex(_, indirectionIndex)
|
result = stars(indirectionIndex)
)
or
not node instanceof IndirectInstruction and
not node instanceof IndirectOperand and
result = ""
}
private Instruction getInstruction(Node n, string stars) { private Instruction getInstruction(Node n, string stars) {
result = [n.asInstruction(), n.(RawIndirectInstruction).getInstruction()] and result = [n.asInstruction(), n.(RawIndirectInstruction).getInstruction()] and
stars = starsForNode(n) stars = stars(n)
} }
private Operand getOperand(Node n, string stars) { private Operand getOperand(Node n, string stars) {
result = [n.asOperand(), n.(RawIndirectOperand).getOperand()] and result = [n.asOperand(), n.(RawIndirectOperand).getOperand()] and
stars = starsForNode(n) stars = stars(n)
} }
/** /**

View File

@@ -16,6 +16,15 @@ private module SourceVariables {
ind = [0 .. countIndirectionsForCppType(base.getLanguageType()) + 1] ind = [0 .. countIndirectionsForCppType(base.getLanguageType()) + 1]
} }
private int maxNumberOfIndirections() { result = max(SourceVariable sv | | sv.getIndirection()) }
private string repeatStars(int n) {
n = 0 and result = ""
or
n = [1 .. maxNumberOfIndirections()] and
result = "*" + repeatStars(n - 1)
}
class SourceVariable extends TSourceVariable { class SourceVariable extends TSourceVariable {
SsaInternals0::SourceVariable base; SsaInternals0::SourceVariable base;
int ind; int ind;
@@ -32,13 +41,7 @@ private module SourceVariables {
SsaInternals0::SourceVariable getBaseVariable() { result = base } SsaInternals0::SourceVariable getBaseVariable() { result = base }
/** Gets a textual representation of this element. */ /** Gets a textual representation of this element. */
string toString() { string toString() { result = repeatStars(this.getIndirection()) + base.toString() }
ind = 0 and
result = this.getBaseVariable().toString()
or
ind > 0 and
result = this.getBaseVariable().toString() + " indirection"
}
/** /**
* Gets the number of loads performed on the base source variable * Gets the number of loads performed on the base source variable

View File

@@ -418,6 +418,11 @@ class BaseCallVariable extends AbstractBaseSourceVariable, TBaseCallVariable {
} }
private module IsModifiableAtImpl { private module IsModifiableAtImpl {
pragma[nomagic]
private predicate isUnderlyingIndirectionType(Type t) {
t = any(Indirection ind).getUnderlyingType()
}
/** /**
* Holds if the `indirectionIndex`'th dereference of a value of type * Holds if the `indirectionIndex`'th dereference of a value of type
* `cppType` is a type that can be modified (either by modifying the value * `cppType` is a type that can be modified (either by modifying the value
@@ -445,10 +450,9 @@ private module IsModifiableAtImpl {
bindingset[cppType, indirectionIndex] bindingset[cppType, indirectionIndex]
pragma[inline_late] pragma[inline_late]
private predicate impl(CppType cppType, int indirectionIndex) { private predicate impl(CppType cppType, int indirectionIndex) {
exists(Type pointerType, Type base, Type t | exists(Type pointerType, Type base |
pointerType = t.getUnderlyingType() and isUnderlyingIndirectionType(pointerType) and
pointerType = any(Indirection ind).getUnderlyingType() and cppType.hasUnderlyingType(pointerType, _) and
cppType.hasType(t, _) and
base = getTypeImpl(pointerType, indirectionIndex) base = getTypeImpl(pointerType, indirectionIndex)
| |
// The value cannot be modified if it has a const specifier, // The value cannot be modified if it has a const specifier,

View File

@@ -227,7 +227,7 @@ class CppType extends TCppType {
predicate hasType(Type type, boolean isGLValue) { none() } predicate hasType(Type type, boolean isGLValue) { none() }
/** /**
* Holds if this type represents the C++ type `type`. If `isGLValue` is `true`, then this type * Holds if this type represents the C++ unspecified type `type`. If `isGLValue` is `true`, then this type
* represents a glvalue of type `type`. Otherwise, it represents a prvalue of type `type`. * represents a glvalue of type `type`. Otherwise, it represents a prvalue of type `type`.
*/ */
final predicate hasUnspecifiedType(Type type, boolean isGLValue) { final predicate hasUnspecifiedType(Type type, boolean isGLValue) {
@@ -236,6 +236,18 @@ class CppType extends TCppType {
type = specifiedType.getUnspecifiedType() type = specifiedType.getUnspecifiedType()
) )
} }
/**
* Holds if this type represents the C++ type `type` (after resolving
* typedefs). If `isGLValue` is `true`, then this type represents a glvalue
* of type `type`. Otherwise, it represents a prvalue of type `type`.
*/
final predicate hasUnderlyingType(Type type, boolean isGLValue) {
exists(Type typedefType |
this.hasType(typedefType, isGLValue) and
type = typedefType.getUnderlyingType()
)
}
} }
/** /**

View File

@@ -9,8 +9,9 @@
import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.ArrayFunction
import semmle.code.cpp.models.interfaces.Taint import semmle.code.cpp.models.interfaces.Taint
pragma[nomagic]
private Type stripTopLevelSpecifiersOnly(Type t) { private Type stripTopLevelSpecifiersOnly(Type t) {
result = stripTopLevelSpecifiersOnly(t.(SpecifiedType).getBaseType()) result = stripTopLevelSpecifiersOnly(pragma[only_bind_out](t.(SpecifiedType).getBaseType()))
or or
result = t and result = t and
not t instanceof SpecifiedType not t instanceof SpecifiedType

View File

@@ -937,6 +937,7 @@ case @attribute_arg.kind of
| 2 = @attribute_arg_constant | 2 = @attribute_arg_constant
| 3 = @attribute_arg_type | 3 = @attribute_arg_type
| 4 = @attribute_arg_constant_expr | 4 = @attribute_arg_constant_expr
| 5 = @attribute_arg_expr
; ;
attribute_arg_value( attribute_arg_value(
@@ -951,6 +952,10 @@ attribute_arg_constant(
unique int arg: @attribute_arg ref, unique int arg: @attribute_arg ref,
int constant: @expr ref int constant: @expr ref
) )
attribute_arg_expr(
unique int arg: @attribute_arg ref,
int expr: @expr ref
)
attribute_arg_name( attribute_arg_name(
unique int arg: @attribute_arg ref, unique int arg: @attribute_arg ref,
string name: string ref string name: string ref

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Support expression attribute arguments
compatibility: backwards

View File

@@ -1,3 +1,7 @@
## 0.9.1
No user-facing changes.
## 0.9.0 ## 0.9.0
### Breaking Changes ### Breaking Changes

View File

@@ -87,6 +87,8 @@ module FlowFromFree<isSinkSig/2 isASink, isExcludedSig/2 isExcluded> {
| |
e = any(StoreInstruction store).getDestinationAddress().getUnconvertedResultExpression() e = any(StoreInstruction store).getDestinationAddress().getUnconvertedResultExpression()
) )
or
n.asExpr() instanceof ArrayExpr
} }
} }

View File

@@ -101,35 +101,43 @@ module ParameterSinks {
) )
} }
private CallInstruction getAnAlwaysReachedCallInstruction(IRFunction f) { private CallInstruction getAnAlwaysReachedCallInstruction() {
result.getBlock().postDominates(f.getEntryBlock()) exists(IRFunction f | result.getBlock().postDominates(f.getEntryBlock()))
} }
pragma[nomagic] pragma[nomagic]
predicate callHasTargetAndArgument(Function f, int i, CallInstruction call, Instruction argument) { private predicate callHasTargetAndArgument(Function f, int i, Instruction argument) {
call.getStaticCallTarget() = f and exists(CallInstruction call |
call.getArgument(i) = argument call.getStaticCallTarget() = f and
call.getArgument(i) = argument and
call = getAnAlwaysReachedCallInstruction()
)
} }
pragma[nomagic] pragma[nomagic]
predicate initializeParameterInFunction(Function f, int i, InitializeParameterInstruction init) { private predicate initializeParameterInFunction(Function f, int i) {
pragma[only_bind_out](init.getEnclosingFunction()) = f and exists(InitializeParameterInstruction init |
init.hasIndex(i) pragma[only_bind_out](init.getEnclosingFunction()) = f and
init.hasIndex(i) and
init = getAnAlwaysDereferencedParameter()
)
}
pragma[nomagic]
private predicate alwaysDereferencedArgumentHasValueNumber(ValueNumber vn) {
exists(int i, Function f, Instruction argument |
callHasTargetAndArgument(f, i, argument) and
initializeParameterInFunction(pragma[only_bind_into](f), pragma[only_bind_into](i)) and
vn.getAnInstruction() = argument
)
} }
InitializeParameterInstruction getAnAlwaysDereferencedParameter() { InitializeParameterInstruction getAnAlwaysDereferencedParameter() {
result = getAnAlwaysDereferencedParameter0() result = getAnAlwaysDereferencedParameter0()
or or
exists( exists(ValueNumber vn |
CallInstruction call, int i, InitializeParameterInstruction p, Instruction argument, alwaysDereferencedArgumentHasValueNumber(vn) and
Function f vn.getAnInstruction() = result
|
callHasTargetAndArgument(f, i, call, argument) and
initializeParameterInFunction(f, i, p) and
p = getAnAlwaysDereferencedParameter() and
result =
pragma[only_bind_out](pragma[only_bind_into](valueNumber(argument)).getAnInstruction()) and
call = getAnAlwaysReachedCallInstruction(_)
) )
} }
} }

View File

@@ -0,0 +1,98 @@
import cpp
import semmle.code.cpp.models.implementations.StdContainer
/**
* Holds if `e` will be consumed by its parent as a glvalue and does not have
* an lvalue-to-rvalue conversion. This means that it will be materialized into
* a temporary object.
*/
predicate isTemporary(Expr e) {
e instanceof TemporaryObjectExpr
or
e.isPRValueCategory() and
e.getUnspecifiedType() instanceof Class and
not e.hasLValueToRValueConversion()
}
/** Holds if `e` is written to a container. */
predicate isStoredInContainer(Expr e) {
exists(StdSequenceContainerInsert insert, Call call, int index |
call = insert.getACallToThisFunction() and
index = insert.getAValueTypeParameterIndex() and
call.getArgument(index) = e
)
or
exists(StdSequenceContainerPush push, Call call, int index |
call = push.getACallToThisFunction() and
index = push.getAValueTypeParameterIndex() and
call.getArgument(index) = e
)
or
exists(StdSequenceEmplace emplace, Call call, int index |
call = emplace.getACallToThisFunction() and
index = emplace.getAValueTypeParameterIndex() and
call.getArgument(index) = e
)
or
exists(StdSequenceEmplaceBack emplaceBack, Call call, int index |
call = emplaceBack.getACallToThisFunction() and
index = emplaceBack.getAValueTypeParameterIndex() and
call.getArgument(index) = e
)
}
/**
* Holds if `e` or a conversion of `e` has an lvalue-to-rvalue conversion.
*/
private predicate hasLValueToRValueConversion(Expr e) {
e.getConversion*().hasLValueToRValueConversion() and
not e instanceof ConditionalExpr // ConditionalExpr may be spuriously reported as having an lvalue-to-rvalue conversion
}
/**
* Holds if the value of `e` outlives the enclosing full expression. For
* example, because the value is stored in a local variable.
*/
predicate outlivesFullExpr(Expr e) {
not hasLValueToRValueConversion(e) and
(
any(Assignment assign).getRValue() = e
or
any(Variable v).getInitializer().getExpr() = e
or
any(ReturnStmt ret).getExpr() = e
or
exists(ConditionalExpr cond |
outlivesFullExpr(cond) and
[cond.getThen(), cond.getElse()] = e
)
or
exists(BinaryOperation bin |
outlivesFullExpr(bin) and
bin.getAnOperand() = e and
not bin instanceof ComparisonOperation
)
or
exists(PointerFieldAccess fa |
outlivesFullExpr(fa) and
fa.getQualifier() = e
)
or
exists(AddressOfExpr ao |
outlivesFullExpr(ao) and
ao.getOperand() = e
)
or
exists(ClassAggregateLiteral aggr |
outlivesFullExpr(aggr) and
aggr.getAFieldExpr(_) = e
)
or
exists(ArrayAggregateLiteral aggr |
outlivesFullExpr(aggr) and
aggr.getAnElementExpr(_) = e
)
or
isStoredInContainer(e)
)
}

View File

@@ -14,81 +14,7 @@
import cpp import cpp
import semmle.code.cpp.models.implementations.StdString import semmle.code.cpp.models.implementations.StdString
import semmle.code.cpp.models.implementations.StdContainer import Temporaries
/**
* Holds if `e` will be consumed by its parent as a glvalue and does not have
* an lvalue-to-rvalue conversion. This means that it will be materialized into
* a temporary object.
*/
predicate isTemporary(Expr e) {
e instanceof TemporaryObjectExpr
or
e.isPRValueCategory() and
e.getUnspecifiedType() instanceof Class and
not e.hasLValueToRValueConversion()
}
/** Holds if `e` is written to a container. */
predicate isStoredInContainer(Expr e) {
exists(StdSequenceContainerInsert insert, Call call, int index |
call = insert.getACallToThisFunction() and
index = insert.getAValueTypeParameterIndex() and
call.getArgument(index) = e
)
or
exists(StdSequenceContainerPush push, Call call, int index |
call = push.getACallToThisFunction() and
index = push.getAValueTypeParameterIndex() and
call.getArgument(index) = e
)
or
exists(StdSequenceEmplace emplace, Call call, int index |
call = emplace.getACallToThisFunction() and
index = emplace.getAValueTypeParameterIndex() and
call.getArgument(index) = e
)
or
exists(StdSequenceEmplaceBack emplaceBack, Call call, int index |
call = emplaceBack.getACallToThisFunction() and
index = emplaceBack.getAValueTypeParameterIndex() and
call.getArgument(index) = e
)
}
/**
* Holds if the value of `e` outlives the enclosing full expression. For
* example, because the value is stored in a local variable.
*/
predicate outlivesFullExpr(Expr e) {
any(Assignment assign).getRValue() = e
or
any(Variable v).getInitializer().getExpr() = e
or
any(ReturnStmt ret).getExpr() = e
or
exists(ConditionalExpr cond |
outlivesFullExpr(cond) and
[cond.getThen(), cond.getElse()] = e
)
or
exists(BinaryOperation bin |
outlivesFullExpr(bin) and
bin.getAnOperand() = e
)
or
exists(ClassAggregateLiteral aggr |
outlivesFullExpr(aggr) and
aggr.getAFieldExpr(_) = e
)
or
exists(ArrayAggregateLiteral aggr |
outlivesFullExpr(aggr) and
aggr.getAnElementExpr(_) = e
)
or
isStoredInContainer(e)
}
from Call c from Call c
where where

View File

@@ -0,0 +1,44 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Calling <code>get</code> on a <code>std::unique_ptr</code> object returns a pointer to the underlying allocations.
When the <code>std::unique_ptr</code> object is destroyed, the pointer returned by <code>get</code> is no
longer valid. If the pointer is used after the <code>std::unique_ptr</code> object is destroyed, then the behavior is undefined.
</p>
</overview>
<recommendation>
<p>
Ensure that the pointer returned by <code>get</code> does not outlive the underlying <code>std::unique_ptr</code> object.
</p>
</recommendation>
<example>
<p>
The following example gets a <code>std::unique_ptr</code> object, and then converts the resulting unique pointer to a
pointer using <code>get</code> so that it can be passed to the <code>work</code> function.
However, the <code>std::unique_ptr</code> object is destroyed as soon as the call
to <code>get</code> returns. This means that <code>work</code> is given a pointer to invalid memory.
</p>
<sample src="UseOfUniquePointerAfterLifetimeEndsBad.cpp" />
<p>
The following example fixes the above code by ensuring that the pointer returned by the call to <code>get</code> does
not outlive the underlying <code>std::unique_ptr</code> objects. This ensures that the pointer passed to <code>work</code>
points to valid memory.
</p>
<sample src="UseOfUniquePointerAfterLifetimeEndsGood.cpp" />
</example>
<references>
<li><a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM50-CPP.+Do+not+access+freed+memory">MEM50-CPP. Do not access freed memory</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,36 @@
/**
* @name Use of unique pointer after lifetime ends
* @description Referencing the contents of a unique pointer after the underlying object has expired may lead to unexpected behavior.
* @kind problem
* @precision high
* @id cpp/use-of-unique-pointer-after-lifetime-ends
* @problem.severity warning
* @security-severity 8.8
* @tags reliability
* security
* external/cwe/cwe-416
* external/cwe/cwe-664
*/
import cpp
import semmle.code.cpp.models.interfaces.PointerWrapper
import Temporaries
predicate isUniquePointerDerefFunction(Function f) {
exists(PointerWrapper wrapper |
f = wrapper.getAnUnwrapperFunction() and
// We only want unique pointers as the memory behind share pointers may still be
// alive after the shared pointer is destroyed.
wrapper.(Class).hasQualifiedName(["std", "bsl"], "unique_ptr")
)
}
from Call c
where
outlivesFullExpr(c) and
not c.isFromUninstantiatedTemplate(_) and
isUniquePointerDerefFunction(c.getTarget()) and
isTemporary(c.getQualifier().getFullyConverted())
select c,
"The underlying unique pointer object is destroyed after the call to '" + c.getTarget() +
"' returns."

View File

@@ -0,0 +1,10 @@
#include <memory>
std::unique_ptr<T> getUniquePointer();
void work(const T*);
// BAD: the unique pointer is deallocated when `get` returns. So `work`
// is given a pointer to invalid memory.
void work_with_unique_ptr_bad() {
const T* combined_string = getUniquePointer().get();
work(combined_string);
}

View File

@@ -0,0 +1,10 @@
#include <memory>
std::unique_ptr<T> getUniquePointer();
void work(const T*);
// GOOD: the unique pointer outlives the call to `work`. So the pointer
// obtainted from `get` is valid.
void work_with_unique_ptr_good() {
auto combined_string = getUniquePointer();
work(combined_string.get());
}

View File

@@ -0,0 +1,4 @@
---
category: newQuery
---
* Added a new query, `cpp/use-of-unique-pointer-after-lifetime-ends`, to detect uses of the contents unique pointers that will be destroyed immediately.

View File

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

View File

@@ -1,2 +1,2 @@
--- ---
lastReleaseVersion: 0.9.0 lastReleaseVersion: 0.9.1

View File

@@ -32,18 +32,41 @@ predicate hasReferenceInitializer(EnumConstant c) {
) )
} }
/**
* Gets the `rnk`'th (1-based) enumeration constant in `e` that does not have a
* reference initializer (i.e., an initializer that refers to an enumeration
* constant from the same enumeration).
*/
EnumConstant getNonReferenceInitializedEnumConstantByRank(Enum e, int rnk) {
result =
rank[rnk](EnumConstant cand, int pos, string filepath, int startline, int startcolumn |
e.getEnumConstant(pos) = cand and
not hasReferenceInitializer(cand) and
cand.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _)
|
cand order by pos, filepath, startline, startcolumn
)
}
/**
* Holds if `ec` is not the last enumeration constant in `e` that has a non-
* reference initializer.
*/
predicate hasNextWithoutReferenceInitializer(Enum e, EnumConstant ec) {
exists(int rnk |
ec = getNonReferenceInitializedEnumConstantByRank(e, rnk) and
exists(getNonReferenceInitializedEnumConstantByRank(e, rnk + 1))
)
}
// There exists another constant whose value is implicit, but it's // There exists another constant whose value is implicit, but it's
// not the last one: the last value is okay to use to get the highest // not the last one: the last value is okay to use to get the highest
// enum value automatically. It can be followed by aliases though. // enum value automatically. It can be followed by aliases though.
predicate enumThatHasConstantWithImplicitValue(Enum e) { predicate enumThatHasConstantWithImplicitValue(Enum e) {
exists(EnumConstant ec, int pos | exists(EnumConstant ec |
ec = e.getEnumConstant(pos) and ec = e.getAnEnumConstant() and
not hasInitializer(ec) and not hasInitializer(ec) and
exists(EnumConstant ec2, int pos2 | hasNextWithoutReferenceInitializer(e, ec)
ec2 = e.getEnumConstant(pos2) and
pos2 > pos and
not hasReferenceInitializer(ec2)
)
) )
} }

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries name: codeql/cpp-queries
version: 0.9.1-dev version: 0.9.2-dev
groups: groups:
- cpp - cpp
- queries - queries

View File

@@ -1,6 +1,7 @@
| b.c:5:3:5:34 | return ... | 10 | | b.c:5:3:5:34 | return ... | 10 |
| c.c:2:3:2:20 | return ... | 5 | | c.c:2:3:2:20 | return ... | 5 |
| e.c:2:3:2:19 | return ... | 17 | | e.c:2:3:2:19 | return ... | 17 |
| g.c:3:3:3:12 | return ... | 20 |
| i.c:3:3:3:12 | return ... | 30 | | i.c:3:3:3:12 | return ... | 30 |
| i.c:8:3:8:12 | return ... | 31 | | i.c:8:3:8:12 | return ... | 31 |
| i.c:13:3:13:12 | return ... | 32 | | i.c:13:3:13:12 | return ... | 32 |

View File

@@ -3,4 +3,4 @@ static int g() {
return 20; return 20;
} }
#endif #endif
// semmle-extractor-options: --clang -include-pch ${testdir}/clang-pch.testproj/f.pch --expect_errors // semmle-extractor-options: --clang -include-pch ${testdir}/clang-pch.testproj/f.pch

View File

@@ -1,6 +1,6 @@
#ifdef SEEN_H #ifdef SEEN_H
static int h() { static int h() {
return 30; // [FALSE POSITIVE] (#pragma hdrstop bug, SEEN_H should not be defined in the precompiled header) return 30;
} }
#endif #endif
#ifdef H1 #ifdef H1
@@ -10,7 +10,7 @@ static int h1() {
#endif #endif
#ifdef H2 #ifdef H2
static int h2() { static int h2() {
return 32; // [FALSE POSITIVE] (#pragma hdrstop bug, H2 should not be defined in the precompiled header) return 32;
} }
#endif #endif
// semmle-extractor-options: --clang -include-pch ${testdir}/clang-pch.testproj/h.pch // semmle-extractor-options: --clang -include-pch ${testdir}/clang-pch.testproj/h.pch

View File

@@ -9,7 +9,6 @@ edges
| test_free.cpp:83:12:83:12 | pointer to operator delete output argument | test_free.cpp:85:12:85:12 | a | | test_free.cpp:83:12:83:12 | pointer to operator delete output argument | test_free.cpp:85:12:85:12 | a |
| test_free.cpp:101:10:101:10 | pointer to free output argument | test_free.cpp:103:10:103:10 | a | | test_free.cpp:101:10:101:10 | pointer to free output argument | test_free.cpp:103:10:103:10 | a |
| test_free.cpp:128:10:128:11 | pointer to free output argument | test_free.cpp:129:10:129:11 | * ... | | test_free.cpp:128:10:128:11 | pointer to free output argument | test_free.cpp:129:10:129:11 | * ... |
| test_free.cpp:131:10:131:13 | pointer to free output argument | test_free.cpp:132:10:132:13 | access to array |
| test_free.cpp:152:27:152:27 | pointer to free output argument | test_free.cpp:154:10:154:10 | a | | test_free.cpp:152:27:152:27 | pointer to free output argument | test_free.cpp:154:10:154:10 | a |
| test_free.cpp:207:10:207:10 | pointer to free output argument | test_free.cpp:209:10:209:10 | a | | test_free.cpp:207:10:207:10 | pointer to free output argument | test_free.cpp:209:10:209:10 | a |
nodes nodes
@@ -33,8 +32,6 @@ nodes
| test_free.cpp:103:10:103:10 | a | semmle.label | a | | test_free.cpp:103:10:103:10 | a | semmle.label | a |
| test_free.cpp:128:10:128:11 | pointer to free output argument | semmle.label | pointer to free output argument | | test_free.cpp:128:10:128:11 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:129:10:129:11 | * ... | semmle.label | * ... | | test_free.cpp:129:10:129:11 | * ... | semmle.label | * ... |
| test_free.cpp:131:10:131:13 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:132:10:132:13 | access to array | semmle.label | access to array |
| test_free.cpp:152:27:152:27 | pointer to free output argument | semmle.label | pointer to free output argument | | test_free.cpp:152:27:152:27 | pointer to free output argument | semmle.label | pointer to free output argument |
| test_free.cpp:154:10:154:10 | a | semmle.label | a | | test_free.cpp:154:10:154:10 | a | semmle.label | a |
| test_free.cpp:207:10:207:10 | pointer to free output argument | semmle.label | pointer to free output argument | | test_free.cpp:207:10:207:10 | pointer to free output argument | semmle.label | pointer to free output argument |
@@ -51,6 +48,5 @@ subpaths
| test_free.cpp:85:12:85:12 | a | test_free.cpp:83:12:83:12 | pointer to operator delete output argument | test_free.cpp:85:12:85:12 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:83:5:83:13 | delete | delete | | test_free.cpp:85:12:85:12 | a | test_free.cpp:83:12:83:12 | pointer to operator delete output argument | test_free.cpp:85:12:85:12 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:83:5:83:13 | delete | delete |
| test_free.cpp:103:10:103:10 | a | test_free.cpp:101:10:101:10 | pointer to free output argument | test_free.cpp:103:10:103:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:101:5:101:8 | call to free | call to free | | test_free.cpp:103:10:103:10 | a | test_free.cpp:101:10:101:10 | pointer to free output argument | test_free.cpp:103:10:103:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:101:5:101:8 | call to free | call to free |
| test_free.cpp:129:10:129:11 | * ... | test_free.cpp:128:10:128:11 | pointer to free output argument | test_free.cpp:129:10:129:11 | * ... | Memory pointed to by '* ...' may already have been freed by $@. | test_free.cpp:128:5:128:8 | call to free | call to free | | test_free.cpp:129:10:129:11 | * ... | test_free.cpp:128:10:128:11 | pointer to free output argument | test_free.cpp:129:10:129:11 | * ... | Memory pointed to by '* ...' may already have been freed by $@. | test_free.cpp:128:5:128:8 | call to free | call to free |
| test_free.cpp:132:10:132:13 | access to array | test_free.cpp:131:10:131:13 | pointer to free output argument | test_free.cpp:132:10:132:13 | access to array | Memory pointed to by 'access to array' may already have been freed by $@. | test_free.cpp:131:5:131:8 | call to free | call to free |
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | pointer to free output argument | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free | | test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | pointer to free output argument | test_free.cpp:154:10:154:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:152:22:152:25 | call to free | call to free |
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | pointer to free output argument | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free | | test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | pointer to free output argument | test_free.cpp:209:10:209:10 | a | Memory pointed to by 'a' may already have been freed by $@. | test_free.cpp:207:5:207:8 | call to free | call to free |

View File

@@ -129,7 +129,7 @@ void test_ptr_deref(void ** a) {
free(*a); // BAD free(*a); // BAD
*a = malloc(10); *a = malloc(10);
free(a[0]); // GOOD free(a[0]); // GOOD
free(a[1]); // GOOD [FALSE POSITIVE] free(a[1]); // GOOD
} }
struct list { struct list {

View File

@@ -9,4 +9,5 @@
| test.cpp:188:39:188:42 | call to data | The underlying string object is destroyed after the call to 'data' returns. | | test.cpp:188:39:188:42 | call to data | The underlying string object is destroyed after the call to 'data' returns. |
| test.cpp:189:44:189:47 | call to data | The underlying string object is destroyed after the call to 'data' returns. | | test.cpp:189:44:189:47 | call to data | The underlying string object is destroyed after the call to 'data' returns. |
| test.cpp:191:29:191:32 | call to data | The underlying string object is destroyed after the call to 'data' returns. | | test.cpp:191:29:191:32 | call to data | The underlying string object is destroyed after the call to 'data' returns. |
| test.cpp:193:31:193:35 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. | | test.cpp:193:47:193:51 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
| test.cpp:195:31:195:35 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |

View File

@@ -190,6 +190,8 @@ const char* test1(bool b1, bool b2) {
char* s9; char* s9;
s9 = std::string("hello").data(); // BAD s9 = std::string("hello").data(); // BAD
const char* s13 = b1 ? std::string("hello").c_str() : s1; // BAD
return std::string("hello").c_str(); // BAD return std::string("hello").c_str(); // BAD
} }

View File

@@ -0,0 +1,11 @@
| test.cpp:156:15:156:15 | call to operator* | The underlying unique pointer object is destroyed after the call to 'operator*' returns. |
| test.cpp:157:31:157:33 | call to get | The underlying unique pointer object is destroyed after the call to 'get' returns. |
| test.cpp:159:32:159:32 | call to operator-> | The underlying unique pointer object is destroyed after the call to 'operator->' returns. |
| test.cpp:160:35:160:37 | call to get | The underlying unique pointer object is destroyed after the call to 'get' returns. |
| test.cpp:161:44:161:46 | call to get | The underlying unique pointer object is destroyed after the call to 'get' returns. |
| test.cpp:163:25:163:27 | call to get | The underlying unique pointer object is destroyed after the call to 'get' returns. |
| test.cpp:172:33:172:35 | call to get | The underlying unique pointer object is destroyed after the call to 'get' returns. |
| test.cpp:174:32:174:34 | call to get | The underlying unique pointer object is destroyed after the call to 'get' returns. |
| test.cpp:177:16:177:16 | call to operator* | The underlying unique pointer object is destroyed after the call to 'operator*' returns. |
| test.cpp:177:36:177:36 | call to operator* | The underlying unique pointer object is destroyed after the call to 'operator*' returns. |
| test.cpp:179:11:179:11 | call to operator* | The underlying unique pointer object is destroyed after the call to 'operator*' returns. |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-416/UseOfUniquePointerAfterLifetimeEnds.ql

View File

@@ -0,0 +1,206 @@
typedef unsigned long size_t;
namespace std {
template<class T> struct remove_reference { typedef T type; };
template<class T> struct remove_reference<T &> { typedef T type; };
template<class T> struct remove_reference<T &&> { typedef T type; };
template<class T> using remove_reference_t = typename remove_reference<T>::type;
template< class T > std::remove_reference_t<T>&& move( T&& t );
template< class T > struct default_delete;
template<class T> struct add_lvalue_reference { typedef T& type; };
}
// --- iterator ---
namespace std {
template<class T> struct remove_const { typedef T type; };
template<class T> struct remove_const<const T> { typedef T type; };
// `remove_const_t<T>` removes any `const` specifier from `T`
template<class T> using remove_const_t = typename remove_const<T>::type;
struct ptrdiff_t;
template<class I> struct iterator_traits;
template <class Category,
class value_type,
class difference_type = ptrdiff_t,
class pointer_type = value_type*,
class reference_type = value_type&>
struct iterator {
typedef Category iterator_category;
iterator();
iterator(iterator<Category, remove_const_t<value_type> > const &other); // non-const -> const conversion constructor
iterator &operator++();
iterator operator++(int);
iterator &operator--();
iterator operator--(int);
bool operator==(iterator other) const;
bool operator!=(iterator other) const;
reference_type operator*() const;
pointer_type operator->() const;
iterator operator+(int);
iterator operator-(int);
iterator &operator+=(int);
iterator &operator-=(int);
int operator-(iterator);
reference_type operator[](int);
};
struct input_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
}
// --- string ---
namespace std
{
using nullptr_t = decltype(nullptr);
template<class T, class Deleter = std::default_delete<T>> class unique_ptr {
public:
using pointer = T*;
using element_type = T;
using deleter_type = Deleter;
constexpr unique_ptr() noexcept;
constexpr unique_ptr(nullptr_t) noexcept;
explicit unique_ptr(pointer p) noexcept;
unique_ptr(unique_ptr&& u) noexcept;
template<class U, class E> unique_ptr(unique_ptr<U, E>&& u) noexcept;
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(unique_ptr&& u) noexcept;
unique_ptr& operator=(std::nullptr_t) noexcept;
template<class U, class E> unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept;
~unique_ptr();
pointer get() const noexcept;
deleter_type& get_deleter() noexcept;
const deleter_type& get_deleter() const noexcept;
explicit operator bool() const noexcept;
typename std::add_lvalue_reference<T>::type operator*() const;
pointer operator->() const noexcept;
pointer release() noexcept;
void reset(pointer p = pointer()) noexcept;
void swap(unique_ptr& u) noexcept;
};
}
// --- vector ---
namespace std {
template <class T> class allocator {
public:
allocator() throw();
typedef size_t size_type;
};
template<class T, class Allocator = allocator<T>>
class vector {
public:
using value_type = T;
using reference = value_type&;
using const_reference = const value_type&;
using size_type = unsigned int;
using iterator = std::iterator<random_access_iterator_tag, T>;
using const_iterator = std::iterator<random_access_iterator_tag, const T>;
vector() noexcept(noexcept(Allocator()));
explicit vector(const Allocator&) noexcept;
explicit vector(size_type n, const Allocator& = Allocator());
vector(size_type n, const T& value, const Allocator& = Allocator());
template<class InputIterator, class IteratorCategory = typename InputIterator::iterator_category> vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
~vector();
void push_back(const T& x);
void push_back(T&& x);
iterator insert(const_iterator position, const T& x);
iterator insert(const_iterator position, T&& x);
iterator insert(const_iterator position, size_type n, const T& x);
template<class InputIterator> iterator insert(const_iterator position, InputIterator first, InputIterator last);
template <class... Args> iterator emplace (const_iterator position, Args&&... args);
template <class... Args> void emplace_back (Args&&... args);
};
}
struct S {
const char* s;
};
void call(S*);
void call_by_value(S);
void call_by_ref(S&);
std::unique_ptr<S> get_unique_ptr();
const S* test1(bool b1, bool b2) {
auto s1 = *get_unique_ptr(); // GOOD
auto s1a = &*get_unique_ptr(); // BAD
auto s1b = get_unique_ptr().get(); // BAD
auto s1c = get_unique_ptr()->s; // GOOD
auto s1d = &(get_unique_ptr()->s); // BAD
auto s2 = b1 ? get_unique_ptr().get() : nullptr; // BAD
auto s3 = b2 ? nullptr :get_unique_ptr().get(); // BAD
const S* s4;
s4 = get_unique_ptr().get(); // BAD
call(get_unique_ptr().get()); // GOOD
call(b1 ? get_unique_ptr().get() : nullptr); // GOOD
call(b1 ? (b2 ? nullptr : get_unique_ptr().get()) : nullptr); // GOOD
call_by_value(*get_unique_ptr()); // GOOD
call_by_ref(*get_unique_ptr()); // GOOD
std::vector<S*> v1;
v1.push_back(get_unique_ptr().get()); // BAD
S* s5[] = { get_unique_ptr().get() }; // BAD
S s6 = b1 ? *get_unique_ptr() : *get_unique_ptr(); // GOOD
S& s7 = b1 ? *get_unique_ptr() : *get_unique_ptr(); // BAD
return &*get_unique_ptr(); // BAD
}
void test2(bool b1, bool b2) {
std::unique_ptr<S> s = get_unique_ptr();
auto s1 = s.get(); // GOOD
auto s2 = b1 ? s.get() : nullptr; // GOOD
auto s3 = b2 ? nullptr : s.get(); // GOOD
const S* s4;
s4 = s.get(); // GOOD
std::unique_ptr<S>& sRef = s;
auto s5 = sRef.get(); // GOOD
auto s6 = b1 ? sRef.get() : nullptr; // GOOD
auto s7 = b2 ? nullptr : sRef.get(); // GOOD
const S* s8;
s8 = sRef.get(); // GOOD
std::unique_ptr<S>&& sRefRef = get_unique_ptr();
auto s9 = sRefRef.get(); // GOOD
auto s10 = b1 ? sRefRef.get() : nullptr; // GOOD
auto s11 = b2 ? nullptr : sRefRef.get(); // GOOD
const S* s12;
s12 = sRefRef.get(); // GOOD
}

View File

@@ -936,9 +936,8 @@ namespace Semmle.Autobuild.CSharp.Tests
{ {
actions.RunProcess["dotnet --list-sdks"] = 0; actions.RunProcess["dotnet --list-sdks"] = 0;
actions.RunProcessOut["dotnet --list-sdks"] = "2.1.2 [C:\\Program Files\\dotnet\\sdks]\n2.1.4 [C:\\Program Files\\dotnet\\sdks]"; actions.RunProcessOut["dotnet --list-sdks"] = "2.1.2 [C:\\Program Files\\dotnet\\sdks]\n2.1.4 [C:\\Program Files\\dotnet\\sdks]";
actions.RunProcess[@"chmod u+x dotnet-install.sh"] = 0; actions.RunProcess[@"chmod u+x scratch/.dotnet/dotnet-install.sh"] = 0;
actions.RunProcess[@"./dotnet-install.sh --channel release --version 2.1.3 --install-dir scratch/.dotnet"] = 0; actions.RunProcess[@"scratch/.dotnet/dotnet-install.sh --channel release --version 2.1.3 --install-dir scratch/.dotnet"] = 0;
actions.RunProcess[@"rm dotnet-install.sh"] = 0;
actions.RunProcess[@"scratch/.dotnet/dotnet --info"] = 0; actions.RunProcess[@"scratch/.dotnet/dotnet --info"] = 0;
actions.RunProcess[@"scratch/.dotnet/dotnet clean C:\Project/test.csproj"] = 0; actions.RunProcess[@"scratch/.dotnet/dotnet clean C:\Project/test.csproj"] = 0;
actions.RunProcess[@"scratch/.dotnet/dotnet restore C:\Project/test.csproj"] = 0; actions.RunProcess[@"scratch/.dotnet/dotnet restore C:\Project/test.csproj"] = 0;
@@ -960,10 +959,11 @@ namespace Semmle.Autobuild.CSharp.Tests
</Project>"); </Project>");
actions.LoadXml[@"C:\Project/test.csproj"] = xml; actions.LoadXml[@"C:\Project/test.csproj"] = xml;
actions.DownloadFiles.Add(("https://dot.net/v1/dotnet-install.sh", "dotnet-install.sh")); actions.DownloadFiles.Add(("https://dot.net/v1/dotnet-install.sh", "scratch/.dotnet/dotnet-install.sh"));
actions.CreateDirectories.Add(@"scratch/.dotnet");
var autobuilder = CreateAutoBuilder(false, dotnetVersion: "2.1.3"); var autobuilder = CreateAutoBuilder(false, dotnetVersion: "2.1.3");
TestAutobuilderScript(autobuilder, 0, 8); TestAutobuilderScript(autobuilder, 0, 7);
} }
[Fact] [Fact]
@@ -972,9 +972,8 @@ namespace Semmle.Autobuild.CSharp.Tests
actions.RunProcess["dotnet --list-sdks"] = 0; actions.RunProcess["dotnet --list-sdks"] = 0;
actions.RunProcessOut["dotnet --list-sdks"] = @"2.1.3 [C:\Program Files\dotnet\sdks] actions.RunProcessOut["dotnet --list-sdks"] = @"2.1.3 [C:\Program Files\dotnet\sdks]
2.1.4 [C:\Program Files\dotnet\sdks]"; 2.1.4 [C:\Program Files\dotnet\sdks]";
actions.RunProcess[@"chmod u+x dotnet-install.sh"] = 0; actions.RunProcess[@"chmod u+x scratch/.dotnet/dotnet-install.sh"] = 0;
actions.RunProcess[@"./dotnet-install.sh --channel release --version 2.1.3 --install-dir scratch/.dotnet"] = 0; actions.RunProcess[@"scratch/.dotnet/dotnet-install.sh --channel release --version 2.1.3 --install-dir scratch/.dotnet"] = 0;
actions.RunProcess[@"rm dotnet-install.sh"] = 0;
actions.RunProcess[@"scratch/.dotnet/dotnet --info"] = 0; actions.RunProcess[@"scratch/.dotnet/dotnet --info"] = 0;
actions.RunProcess[@"scratch/.dotnet/dotnet clean C:\Project/test.csproj"] = 0; actions.RunProcess[@"scratch/.dotnet/dotnet clean C:\Project/test.csproj"] = 0;
actions.RunProcess[@"scratch/.dotnet/dotnet restore C:\Project/test.csproj"] = 0; actions.RunProcess[@"scratch/.dotnet/dotnet restore C:\Project/test.csproj"] = 0;
@@ -996,10 +995,11 @@ namespace Semmle.Autobuild.CSharp.Tests
</Project>"); </Project>");
actions.LoadXml[@"C:\Project/test.csproj"] = xml; actions.LoadXml[@"C:\Project/test.csproj"] = xml;
actions.DownloadFiles.Add(("https://dot.net/v1/dotnet-install.sh", "dotnet-install.sh")); actions.DownloadFiles.Add(("https://dot.net/v1/dotnet-install.sh", "scratch/.dotnet/dotnet-install.sh"));
actions.CreateDirectories.Add(@"scratch/.dotnet");
var autobuilder = CreateAutoBuilder(false, dotnetVersion: "2.1.3"); var autobuilder = CreateAutoBuilder(false, dotnetVersion: "2.1.3");
TestAutobuilderScript(autobuilder, 0, 8); TestAutobuilderScript(autobuilder, 0, 7);
} }
private void TestDotnetVersionWindows(Action action, int commandsRun) private void TestDotnetVersionWindows(Action action, int commandsRun)

View File

@@ -190,18 +190,23 @@ namespace Semmle.Autobuild.CSharp
} }
else else
{ {
var dotnetInstallPath = builder.Actions.PathCombine(FileUtils.GetTemporaryWorkingDirectory(
builder.Actions.GetEnvironmentVariable,
builder.Options.Language.UpperCaseName,
out var shouldCleanUp), ".dotnet", "dotnet-install.sh");
var downloadDotNetInstallSh = BuildScript.DownloadFile( var downloadDotNetInstallSh = BuildScript.DownloadFile(
"https://dot.net/v1/dotnet-install.sh", "https://dot.net/v1/dotnet-install.sh",
"dotnet-install.sh", dotnetInstallPath,
e => builder.Log(Severity.Warning, $"Failed to download 'dotnet-install.sh': {e.Message}")); e => builder.Log(Severity.Warning, $"Failed to download 'dotnet-install.sh': {e.Message}"));
var chmod = new CommandBuilder(builder.Actions). var chmod = new CommandBuilder(builder.Actions).
RunCommand("chmod"). RunCommand("chmod").
Argument("u+x"). Argument("u+x").
Argument("dotnet-install.sh"); Argument(dotnetInstallPath);
var install = new CommandBuilder(builder.Actions). var install = new CommandBuilder(builder.Actions).
RunCommand("./dotnet-install.sh"). RunCommand(dotnetInstallPath).
Argument("--channel"). Argument("--channel").
Argument("release"). Argument("release").
Argument("--version"). Argument("--version").
@@ -209,11 +214,17 @@ namespace Semmle.Autobuild.CSharp
Argument("--install-dir"). Argument("--install-dir").
Argument(path); Argument(path);
var removeScript = new CommandBuilder(builder.Actions). var buildScript = downloadDotNetInstallSh & chmod.Script & install.Script;
RunCommand("rm").
Argument("dotnet-install.sh");
return downloadDotNetInstallSh & chmod.Script & install.Script & BuildScript.Try(removeScript.Script); if (shouldCleanUp)
{
var removeScript = new CommandBuilder(builder.Actions).
RunCommand("rm").
Argument(dotnetInstallPath);
buildScript &= removeScript.Script;
}
return buildScript;
} }
}); });
} }

View File

@@ -52,7 +52,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
this.progressMonitor = new ProgressMonitor(logger); this.progressMonitor = new ProgressMonitor(logger);
this.sourceDir = new DirectoryInfo(srcDir); this.sourceDir = new DirectoryInfo(srcDir);
packageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName)); packageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName, "packages"));
legacyPackageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName, "legacypackages")); legacyPackageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName, "legacypackages"));
missingPackageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName, "missingpackages")); missingPackageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName, "missingpackages"));
@@ -72,7 +72,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
this.progressMonitor.FindingFiles(srcDir); this.progressMonitor.FindingFiles(srcDir);
var allFiles = GetAllFiles(); var allFiles = GetAllFiles().ToList();
var binaryFileExtensions = new HashSet<string>(new[] { ".dll", ".exe" }); // TODO: add more binary file extensions. var binaryFileExtensions = new HashSet<string>(new[] { ".dll", ".exe" }); // TODO: add more binary file extensions.
var allNonBinaryFiles = allFiles.Where(f => !binaryFileExtensions.Contains(f.Extension.ToLowerInvariant())).ToList(); var allNonBinaryFiles = allFiles.Where(f => !binaryFileExtensions.Contains(f.Extension.ToLowerInvariant())).ToList();
var smallNonBinaryFiles = allNonBinaryFiles.SelectSmallFiles(progressMonitor).SelectFileNames(); var smallNonBinaryFiles = allNonBinaryFiles.SelectSmallFiles(progressMonitor).SelectFileNames();
@@ -439,6 +439,25 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
files = files.Where(f => !f.FullName.StartsWith(options.DotNetPath, StringComparison.OrdinalIgnoreCase)); files = files.Where(f => !f.FullName.StartsWith(options.DotNetPath, StringComparison.OrdinalIgnoreCase));
} }
files = files.Where(f =>
{
try
{
if (f.Exists)
{
return true;
}
progressMonitor.Log(Severity.Warning, $"File {f.FullName} could not be processed.");
return false;
}
catch (Exception ex)
{
progressMonitor.Log(Severity.Warning, $"File {f.FullName} could not be processed: {ex.Message}");
return false;
}
});
files = new FilePathFilter(sourceDir, progressMonitor).Filter(files); files = new FilePathFilter(sourceDir, progressMonitor).Filter(files);
return files; return files;
} }
@@ -448,7 +467,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
/// with this source tree. Use a SHA1 of the directory name. /// with this source tree. Use a SHA1 of the directory name.
/// </summary> /// </summary>
/// <returns>The full path of the temp directory.</returns> /// <returns>The full path of the temp directory.</returns>
private static string ComputeTempDirectory(string srcDir, string packages = "packages") private static string ComputeTempDirectory(string srcDir, string subfolderName)
{ {
var bytes = Encoding.Unicode.GetBytes(srcDir); var bytes = Encoding.Unicode.GetBytes(srcDir);
var sha = SHA1.HashData(bytes); var sha = SHA1.HashData(bytes);
@@ -456,7 +475,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
foreach (var b in sha.Take(8)) foreach (var b in sha.Take(8))
sb.AppendFormat("{0:x2}", b); sb.AppendFormat("{0:x2}", b);
return Path.Combine(FileUtils.GetTemporaryWorkingDirectory(out var _), "GitHub", packages, sb.ToString()); return Path.Combine(FileUtils.GetTemporaryWorkingDirectory(out var _), sb.ToString(), subfolderName);
} }
/// <summary> /// <summary>
@@ -704,7 +723,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
Parallel.ForEach(notYetDownloadedPackages, new ParallelOptions { MaxDegreeOfParallelism = options.Threads }, package => Parallel.ForEach(notYetDownloadedPackages, new ParallelOptions { MaxDegreeOfParallelism = options.Threads }, package =>
{ {
progressMonitor.NugetInstall(package); progressMonitor.NugetInstall(package);
using var tempDir = new TemporaryDirectory(ComputeTempDirectory(package)); using var tempDir = new TemporaryDirectory(ComputeTempDirectory(package, "missingpackages_workingdir"));
var success = dotnet.New(tempDir.DirInfo.FullName); var success = dotnet.New(tempDir.DirInfo.FullName);
if (!success) if (!success)
{ {

View File

@@ -80,11 +80,11 @@ internal sealed class StubVisitor : SymbolVisitor
stubWriter.Write(explicitInterfaceType.GetQualifiedName()); stubWriter.Write(explicitInterfaceType.GetQualifiedName());
stubWriter.Write('.'); stubWriter.Write('.');
if (writeName) if (writeName)
stubWriter.Write(explicitInterfaceSymbol.GetName()); stubWriter.Write(EscapeIdentifier(explicitInterfaceSymbol.GetName()));
} }
else if (writeName) else if (writeName)
{ {
stubWriter.Write(symbol.GetName()); stubWriter.Write(EscapeIdentifier(symbol.GetName()));
} }
} }
@@ -557,6 +557,9 @@ internal sealed class StubVisitor : SymbolVisitor
}); });
} }
private static bool ExcludeMethod(IMethodSymbol symbol) =>
symbol.Name == "<Clone>$";
private void StubMethod(IMethodSymbol symbol, IMethodSymbol? explicitInterfaceSymbol, IMethodSymbol? baseCtor) private void StubMethod(IMethodSymbol symbol, IMethodSymbol? explicitInterfaceSymbol, IMethodSymbol? baseCtor)
{ {
var methodKind = explicitInterfaceSymbol is null ? symbol.MethodKind : explicitInterfaceSymbol.MethodKind; var methodKind = explicitInterfaceSymbol is null ? symbol.MethodKind : explicitInterfaceSymbol.MethodKind;
@@ -568,7 +571,7 @@ internal sealed class StubVisitor : SymbolVisitor
MethodKind.Ordinary MethodKind.Ordinary
}; };
if (!relevantMethods.Contains(methodKind)) if (!relevantMethods.Contains(methodKind) || ExcludeMethod(symbol))
return; return;
StubAttributes(symbol.GetAttributes()); StubAttributes(symbol.GetAttributes());

View File

@@ -76,6 +76,26 @@ public int M1(ref readonly Guid guid) => throw null;
Assert.Equal(expected, stub); Assert.Equal(expected, stub);
} }
[Fact]
public void StubGeneratorEscapeMethodName()
{
// Setup
const string source = @"
public class MyTest {
public int @default() { return 0; }
}";
// Execute
var stub = GenerateStub(source);
// Verify
const string expected = @"public class MyTest {
public int @default() => throw null;
}
";
Assert.Equal(expected, stub);
}
private static string GenerateStub(string source) private static string GenerateStub(string source)
{ {
var st = CSharpSyntaxTree.ParseText(source); var st = CSharpSyntaxTree.ParseText(source);

View File

@@ -144,20 +144,26 @@ namespace Semmle.Util
return nested; return nested;
} }
private static readonly Lazy<string> tempFolderPath = new Lazy<string>(() =>
{
var tempPath = Path.GetTempPath();
var name = Guid.NewGuid().ToString("N").ToUpper();
var tempFolder = Path.Combine(tempPath, "GitHub", name);
Directory.CreateDirectory(tempFolder);
return tempFolder;
});
public static string GetTemporaryWorkingDirectory(Func<string, string?> getEnvironmentVariable, string lang, out bool shouldCleanUp) public static string GetTemporaryWorkingDirectory(Func<string, string?> getEnvironmentVariable, string lang, out bool shouldCleanUp)
{ {
shouldCleanUp = false;
var tempFolder = getEnvironmentVariable($"CODEQL_EXTRACTOR_{lang}_SCRATCH_DIR"); var tempFolder = getEnvironmentVariable($"CODEQL_EXTRACTOR_{lang}_SCRATCH_DIR");
if (!string.IsNullOrEmpty(tempFolder))
if (string.IsNullOrEmpty(tempFolder))
{ {
var tempPath = Path.GetTempPath(); shouldCleanUp = false;
var name = Guid.NewGuid().ToString("N").ToUpper(); return tempFolder;
tempFolder = Path.Combine(tempPath, "GitHub", name);
shouldCleanUp = true;
} }
return tempFolder; shouldCleanUp = true;
return tempFolderPath.Value;
} }
public static string GetTemporaryWorkingDirectory(out bool shouldCleanUp) => public static string GetTemporaryWorkingDirectory(out bool shouldCleanUp) =>

View File

@@ -1,3 +1,7 @@
## 1.7.5
No user-facing changes.
## 1.7.4 ## 1.7.4
No user-facing changes. No user-facing changes.

View File

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

View File

@@ -1,2 +1,2 @@
--- ---
lastReleaseVersion: 1.7.4 lastReleaseVersion: 1.7.5

View File

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

View File

@@ -1,3 +1,7 @@
## 1.7.5
No user-facing changes.
## 1.7.4 ## 1.7.4
No user-facing changes. No user-facing changes.

View File

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

View File

@@ -1,2 +1,2 @@
--- ---
lastReleaseVersion: 1.7.4 lastReleaseVersion: 1.7.5

View File

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

View File

@@ -4,10 +4,11 @@ private string getPath(Assembly a) {
not a.getCompilation().getOutputAssembly() = a and not a.getCompilation().getOutputAssembly() = a and
exists(string s | s = a.getFile().getAbsolutePath() | exists(string s | s = a.getFile().getAbsolutePath() |
result = result =
s.substring(s.indexOf("GitHub/packages/") + "GitHub/packages/".length() + 16, s.length()) s.substring(s.indexOf("test-db/working/") + "test-db/working/".length() + 16 +
"/packages".length(), s.length())
or or
result = s and result = s and
not exists(s.indexOf("GitHub/packages/")) not exists(s.indexOf("test-db/working/"))
) )
} }

View File

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

View File

@@ -0,0 +1,5 @@
{
"sdk": {
"version": "8.0.100"
}
}

View File

@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,8 @@
from create_database_utils import *
path = b'\xd2abcd.cs'
with open(path, 'w') as file:
file.write('class X { }\n')
run_codeql_database_create([], lang="csharp", extra_args=["--extractor-option=buildless=true", "--extractor-option=cil=false"])

View File

@@ -4,10 +4,11 @@ private string getPath(Assembly a) {
not a.getCompilation().getOutputAssembly() = a and not a.getCompilation().getOutputAssembly() = a and
exists(string s | s = a.getFile().getAbsolutePath() | exists(string s | s = a.getFile().getAbsolutePath() |
result = result =
s.substring(s.indexOf("GitHub/packages/") + "GitHub/packages/".length() + 16, s.length()) s.substring(s.indexOf("test-db/working/") + "test-db/working/".length() + 16 +
"/packages".length(), s.length())
or or
result = s and result = s and
not exists(s.indexOf("GitHub/packages/")) not exists(s.indexOf("test-db/working/"))
) )
} }

View File

@@ -4,10 +4,11 @@ private string getPath(Assembly a) {
not a.getCompilation().getOutputAssembly() = a and not a.getCompilation().getOutputAssembly() = a and
exists(string s | s = a.getFile().getAbsolutePath() | exists(string s | s = a.getFile().getAbsolutePath() |
result = result =
s.substring(s.indexOf("GitHub/packages/") + "GitHub/packages/".length() + 16, s.length()) s.substring(s.indexOf("test-db/working/") + "test-db/working/".length() + 16 +
"/packages".length(), s.length())
or or
result = s and result = s and
not exists(s.indexOf("GitHub/packages/")) not exists(s.indexOf("test-db/working/"))
) )
} }

View File

@@ -4,19 +4,9 @@ private string getPath(Assembly a) {
not a.getCompilation().getOutputAssembly() = a and not a.getCompilation().getOutputAssembly() = a and
exists(string s | s = a.getFile().getAbsolutePath() | exists(string s | s = a.getFile().getAbsolutePath() |
result = result =
s.substring(s.indexOf("GitHub/packages/") + "GitHub/packages/".length() + 16, s.length()) s.substring(s.indexOf("test-db/working/") + "test-db/working/".length() + 16 +
or "/legacypackages".length(), s.length())
result = // TODO: include all other assemblies from the test results. Initially disable because mono installations were problematic on ARM runners.
s.substring(s.indexOf("GitHub/legacypackages/") + "GitHub/legacypackages/".length() + 16,
s.length())
// TODO: excluding all other assemblies from the test result as mono installations seem problematic on ARM runners.
// or
// result = s.substring(s.indexOf("lib/mono/") + "lib/mono/".length(), s.length())
// or
// result = s and
// not exists(s.indexOf("GitHub/packages/")) and
// not exists(s.indexOf("GitHub/legacypackages/")) and
// not exists(s.indexOf("lib/mono/"))
) )
} }

View File

@@ -4,10 +4,11 @@ private string getPath(Assembly a) {
not a.getCompilation().getOutputAssembly() = a and not a.getCompilation().getOutputAssembly() = a and
exists(string s | s = a.getFile().getAbsolutePath() | exists(string s | s = a.getFile().getAbsolutePath() |
result = result =
s.substring(s.indexOf("GitHub/packages/") + "GitHub/packages/".length() + 16, s.length()) s.substring(s.indexOf("test-db/working/") + "test-db/working/".length() + 16 +
"/packages".length(), s.length())
or or
result = s and result = s and
not exists(s.indexOf("GitHub/packages/")) not exists(s.indexOf("test-db/working/"))
) )
} }

View File

@@ -1,3 +1,7 @@
## 0.8.5
No user-facing changes.
## 0.8.4 ## 0.8.4
No user-facing changes. No user-facing changes.

View File

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

View File

@@ -1,2 +1,2 @@
--- ---
lastReleaseVersion: 0.8.4 lastReleaseVersion: 0.8.5

View File

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

View File

@@ -1,3 +1,7 @@
## 0.8.5
No user-facing changes.
## 0.8.4 ## 0.8.4
### Minor Analysis Improvements ### Minor Analysis Improvements

View File

@@ -11,17 +11,24 @@ without properly sanitizing the input first, allows for a cross-site scripting v
</overview> </overview>
<recommendation> <recommendation>
<p>To guard against cross-site scripting, consider using contextual output encoding/escaping before <p>
writing user input to the page, or one of the other solutions that are mentioned in the To guard against cross-site scripting, consider using a library that provides suitable encoding
references.</p> functionality, such as the <code>System.Net.WebUtility</code> class, to sanitize the untrusted input before writing it to the page.
For other possible solutions, see the references.
</p>
</recommendation> </recommendation>
<example> <example>
<p>The following example shows the page parameter being written directly to the server error page, <p>
leaving the website vulnerable to cross-site scripting.</p> The following example shows the page parameter being written directly to the server error page,
leaving the website vulnerable to cross-site scripting.
<sample src="XSS.cs" /> </p>
<sample src="XSSBad.cs" />
<p>
Sanitizing the user-controlled data using the <code>WebUtility.HtmlEncode</code> method prevents the vulnerability:
</p>
<sample src="XSSGood.cs" />
</example> </example>
<references> <references>
@@ -36,6 +43,5 @@ OWASP:
Wikipedia: <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">Cross-site scripting</a>. Wikipedia: <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">Cross-site scripting</a>.
</li> </li>
</references> </references>
</qhelp> </qhelp>

View File

@@ -0,0 +1,13 @@
using System;
using System.Web;
using System.Net;
public class XSSHandler : IHttpHandler
{
public void ProcessRequest(HttpContext ctx)
{
string page = WebUtility.HtmlEncode(ctx.Request.QueryString["page"]);
ctx.Response.Write(
"The page \"" + page + "\" was not found.");
}
}

View File

@@ -0,0 +1,195 @@
/**
* @name C# extraction information
* @description Information about the extraction for a C# database
* @kind metric
* @tags summary telemetry
* @id cs/telemetry/extraction-information
*/
import csharp
import semmle.code.csharp.commons.Diagnostics
predicate fileCount(string key, int value) {
key = "Number of files" and
value = strictcount(File f)
}
predicate fileCountByExtension(string key, int value) {
exists(string extension |
key = "Number of files with extension " + extension and
value = strictcount(File f | f.getExtension() = extension)
)
}
predicate totalNumberOfLines(string key, int value) {
key = "Total number of lines" and
value = strictsum(File f | any() | f.getNumberOfLines())
}
predicate numberOfLinesOfCode(string key, int value) {
key = "Number of lines of code" and
value = strictsum(File f | any() | f.getNumberOfLinesOfCode())
}
predicate totalNumberOfLinesByExtension(string key, int value) {
exists(string extension |
key = "Total number of lines with extension " + extension and
value = strictsum(File f | f.getExtension() = extension | f.getNumberOfLines())
)
}
predicate numberOfLinesOfCodeByExtension(string key, int value) {
exists(string extension |
key = "Number of lines of code with extension " + extension and
value = strictsum(File f | f.getExtension() = extension | f.getNumberOfLinesOfCode())
)
}
predicate extractorDiagnostics(string key, int value) {
exists(int severity |
key = "Number of diagnostics with severity " + severity.toString() and
value = strictcount(Diagnostic d | d.getSeverity() = severity)
)
}
CompilerError getAmbiguityCompilerError() {
result.getSeverity() >= 3 and
result.getTag() = ["CS0101", "CS0104", "CS0111", "CS0121", "CS0229"]
}
predicate numberOfAmbiguityCompilerErrors(string key, int value) {
value = count(getAmbiguityCompilerError()) and
key = "Number of compiler reported ambiguity errors"
}
predicate numberOfDistinctAmbiguityCompilerErrorMessages(string key, int value) {
value = count(getAmbiguityCompilerError().getFullMessage()) and
key = "Number of compiler reported ambiguity error messages"
}
predicate extractionIsStandalone(string key, int value) {
(
value = 1 and
extractionIsStandalone()
or
value = 0 and
not extractionIsStandalone()
) and
key = "Is buildless extraction"
}
signature module StatsSig {
int getNumberOfOk();
int getNumberOfNotOk();
string getOkText();
string getNotOkText();
}
module ReportStats<StatsSig Stats> {
predicate numberOfOk(string key, int value) {
value = Stats::getNumberOfOk() and
key = "Number of " + Stats::getOkText()
}
predicate numberOfNotOk(string key, int value) {
value = Stats::getNumberOfNotOk() and
key = "Number of " + Stats::getNotOkText()
}
predicate percentageOfOk(string key, float value) {
value = Stats::getNumberOfOk() * 100.0 / (Stats::getNumberOfOk() + Stats::getNumberOfNotOk()) and
key = "Percentage of " + Stats::getOkText()
}
}
module CallTargetStats implements StatsSig {
int getNumberOfOk() { result = count(Call c | exists(c.getTarget())) }
int getNumberOfNotOk() { result = count(Call c | not exists(c.getTarget())) }
string getOkText() { result = "calls with call target" }
string getNotOkText() { result = "calls with missing call target" }
}
module ExprTypeStats implements StatsSig {
int getNumberOfOk() { result = count(Expr e | not e.getType() instanceof UnknownType) }
int getNumberOfNotOk() { result = count(Expr e | e.getType() instanceof UnknownType) }
string getOkText() { result = "expressions with known type" }
string getNotOkText() { result = "expressions with unknown type" }
}
module TypeMentionTypeStats implements StatsSig {
int getNumberOfOk() { result = count(TypeMention t | not t.getType() instanceof UnknownType) }
int getNumberOfNotOk() { result = count(TypeMention t | t.getType() instanceof UnknownType) }
string getOkText() { result = "type mentions with known type" }
string getNotOkText() { result = "type mentions with unknown type" }
}
module AccessTargetStats implements StatsSig {
int getNumberOfOk() { result = count(Access a | exists(a.getTarget())) }
int getNumberOfNotOk() { result = count(Access a | not exists(a.getTarget())) }
string getOkText() { result = "access with target" }
string getNotOkText() { result = "access with missing target" }
}
module ExprStats implements StatsSig {
int getNumberOfOk() { result = count(Expr e | not e instanceof @unknown_expr) }
int getNumberOfNotOk() { result = count(Expr e | e instanceof @unknown_expr) }
string getOkText() { result = "expressions with known kind" }
string getNotOkText() { result = "expressions with unknown kind" }
}
module CallTargetStatsReport = ReportStats<CallTargetStats>;
module ExprTypeStatsReport = ReportStats<ExprTypeStats>;
module TypeMentionTypeStatsReport = ReportStats<TypeMentionTypeStats>;
module AccessTargetStatsReport = ReportStats<AccessTargetStats>;
module ExprStatsReport = ReportStats<ExprStats>;
from string key, float value
where
fileCount(key, value) or
fileCountByExtension(key, value) or
totalNumberOfLines(key, value) or
numberOfLinesOfCode(key, value) or
totalNumberOfLinesByExtension(key, value) or
numberOfLinesOfCodeByExtension(key, value) or
extractorDiagnostics(key, value) or
numberOfAmbiguityCompilerErrors(key, value) or
numberOfDistinctAmbiguityCompilerErrorMessages(key, value) or
extractionIsStandalone(key, value) or
CallTargetStatsReport::numberOfOk(key, value) or
CallTargetStatsReport::numberOfNotOk(key, value) or
CallTargetStatsReport::percentageOfOk(key, value) or
ExprTypeStatsReport::numberOfOk(key, value) or
ExprTypeStatsReport::numberOfNotOk(key, value) or
ExprTypeStatsReport::percentageOfOk(key, value) or
TypeMentionTypeStatsReport::numberOfOk(key, value) or
TypeMentionTypeStatsReport::numberOfNotOk(key, value) or
TypeMentionTypeStatsReport::percentageOfOk(key, value) or
AccessTargetStatsReport::numberOfOk(key, value) or
AccessTargetStatsReport::numberOfNotOk(key, value) or
AccessTargetStatsReport::percentageOfOk(key, value) or
ExprStatsReport::numberOfOk(key, value) or
ExprStatsReport::numberOfNotOk(key, value) or
ExprStatsReport::percentageOfOk(key, value)
select key, value

View File

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

View File

@@ -1,2 +1,2 @@
--- ---
lastReleaseVersion: 0.8.4 lastReleaseVersion: 0.8.5

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-queries name: codeql/csharp-queries
version: 0.8.5-dev version: 0.8.6-dev
groups: groups:
- csharp - csharp
- queries - queries

View File

@@ -7,7 +7,7 @@ private import ModelEditor
* A class of effectively public callables from source code. * A class of effectively public callables from source code.
*/ */
class PublicEndpointFromSource extends Endpoint { class PublicEndpointFromSource extends Endpoint {
PublicEndpointFromSource() { this.fromSource() and not this.getFile() instanceof TestFile } PublicEndpointFromSource() { this.fromSource() and not this.getFile() instanceof TestRelatedFile }
override predicate isSource() { this instanceof SourceCallable } override predicate isSource() { this instanceof SourceCallable }

View File

@@ -110,9 +110,9 @@ string supportedType(Endpoint endpoint) {
} }
string methodClassification(Call method) { string methodClassification(Call method) {
method.getFile() instanceof TestFile and result = "test" method.getFile() instanceof TestRelatedFile and result = "test"
or or
not method.getFile() instanceof TestFile and not method.getFile() instanceof TestRelatedFile and
result = "source" result = "source"
} }
@@ -129,3 +129,13 @@ private string qualifiedTypeName(string namespace, Type t) {
private string qualifiedCallableName(string namespace, string type, Callable c) { private string qualifiedCallableName(string namespace, string type, Callable c) {
exists(string name | hasQualifiedMethodName(c, namespace, type, name) | result = name) exists(string name | hasQualifiedMethodName(c, namespace, type, name) | result = name)
} }
/** A file that is either a test file or is only used in tests. */
class TestRelatedFile extends File {
TestRelatedFile() {
this instanceof TestFile
or
this.getAbsolutePath().matches(["%/test/%", "%/tests/%"]) and
not this.getAbsolutePath().matches("%/ql/test/%") // allows our test cases to work
}
}

View File

@@ -4,5 +4,6 @@ semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resour
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/Dapper/2.1.24/Dapper.csproj semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/Dapper/2.1.24/Dapper.csproj
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/ServiceStack/8.0.0/ServiceStack.csproj semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/ServiceStack/8.0.0/ServiceStack.csproj
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/ServiceStack.OrmLite.SqlServer/8.0.0/ServiceStack.OrmLite.SqlServer.csproj semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/ServiceStack.OrmLite.SqlServer/8.0.0/ServiceStack.OrmLite.SqlServer.csproj
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/EntityFramework/6.4.4/EntityFramework.csproj
semmle-extractor-options: ${testdir}/../../../resources/stubs/System.Web.cs semmle-extractor-options: ${testdir}/../../../resources/stubs/System.Web.cs
semmle-extractor-options: ${testdir}/../../../resources/stubs/EntityFramework.cs semmle-extractor-options: ${testdir}/../../../resources/stubs/EntityFrameworkCore.cs

View File

@@ -141,6 +141,35 @@ summary
| System.Data.Entity;DbContext;false;SaveChangesAsync;();;Argument[this].Property[EFTests.MyContext.Persons].Element.Property[EFTests.Person.Id];SyntheticGlobal[EFTests.MyContext.Persons#ReturnValue.Element.Property[EFTests.Person.Id]];value;manual | | System.Data.Entity;DbContext;false;SaveChangesAsync;();;Argument[this].Property[EFTests.MyContext.Persons].Element.Property[EFTests.Person.Id];SyntheticGlobal[EFTests.MyContext.Persons#ReturnValue.Element.Property[EFTests.Person.Id]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;();;Argument[this].Property[EFTests.MyContext.Persons].Element.Property[EFTests.Person.Name];SyntheticGlobal[EFTests.MyContext.PersonAddresses#ReturnValue.Element.Property[EFTests.PersonAddressMap.Person].Property[EFTests.Person.Name]];value;manual | | System.Data.Entity;DbContext;false;SaveChangesAsync;();;Argument[this].Property[EFTests.MyContext.Persons].Element.Property[EFTests.Person.Name];SyntheticGlobal[EFTests.MyContext.PersonAddresses#ReturnValue.Element.Property[EFTests.PersonAddressMap.Person].Property[EFTests.Person.Name]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;();;Argument[this].Property[EFTests.MyContext.Persons].Element.Property[EFTests.Person.Name];SyntheticGlobal[EFTests.MyContext.Persons#ReturnValue.Element.Property[EFTests.Person.Name]];value;manual | | System.Data.Entity;DbContext;false;SaveChangesAsync;();;Argument[this].Property[EFTests.MyContext.Persons].Element.Property[EFTests.Person.Name];SyntheticGlobal[EFTests.MyContext.Persons#ReturnValue.Element.Property[EFTests.Person.Name]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.Addresses].Element.Property[EFTests.Address.Id];SyntheticGlobal[EFTests.MyContext.Addresses#ReturnValue.Element.Property[EFTests.Address.Id]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.Addresses].Element.Property[EFTests.Address.Id];SyntheticGlobal[EFTests.MyContext.PersonAddresses#ReturnValue.Element.Property[EFTests.PersonAddressMap.Address].Property[EFTests.Address.Id]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.Addresses].Element.Property[EFTests.Address.Id];SyntheticGlobal[EFTests.MyContext.Persons#ReturnValue.Element.Property[EFTests.Person.Addresses].Element.Property[EFTests.Address.Id]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.Addresses].Element.Property[EFTests.Address.Street];SyntheticGlobal[EFTests.MyContext.Addresses#ReturnValue.Element.Property[EFTests.Address.Street]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.Addresses].Element.Property[EFTests.Address.Street];SyntheticGlobal[EFTests.MyContext.PersonAddresses#ReturnValue.Element.Property[EFTests.PersonAddressMap.Address].Property[EFTests.Address.Street]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.Addresses].Element.Property[EFTests.Address.Street];SyntheticGlobal[EFTests.MyContext.Persons#ReturnValue.Element.Property[EFTests.Person.Addresses].Element.Property[EFTests.Address.Street]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.PersonAddresses].Element.Property[EFTests.PersonAddressMap.AddressId];SyntheticGlobal[EFTests.MyContext.PersonAddresses#ReturnValue.Element.Property[EFTests.PersonAddressMap.AddressId]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.PersonAddresses].Element.Property[EFTests.PersonAddressMap.Address].Property[EFTests.Address.Id];SyntheticGlobal[EFTests.MyContext.Addresses#ReturnValue.Element.Property[EFTests.Address.Id]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.PersonAddresses].Element.Property[EFTests.PersonAddressMap.Address].Property[EFTests.Address.Id];SyntheticGlobal[EFTests.MyContext.PersonAddresses#ReturnValue.Element.Property[EFTests.PersonAddressMap.Address].Property[EFTests.Address.Id]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.PersonAddresses].Element.Property[EFTests.PersonAddressMap.Address].Property[EFTests.Address.Id];SyntheticGlobal[EFTests.MyContext.Persons#ReturnValue.Element.Property[EFTests.Person.Addresses].Element.Property[EFTests.Address.Id]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.PersonAddresses].Element.Property[EFTests.PersonAddressMap.Address].Property[EFTests.Address.Street];SyntheticGlobal[EFTests.MyContext.Addresses#ReturnValue.Element.Property[EFTests.Address.Street]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.PersonAddresses].Element.Property[EFTests.PersonAddressMap.Address].Property[EFTests.Address.Street];SyntheticGlobal[EFTests.MyContext.PersonAddresses#ReturnValue.Element.Property[EFTests.PersonAddressMap.Address].Property[EFTests.Address.Street]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.PersonAddresses].Element.Property[EFTests.PersonAddressMap.Address].Property[EFTests.Address.Street];SyntheticGlobal[EFTests.MyContext.Persons#ReturnValue.Element.Property[EFTests.Person.Addresses].Element.Property[EFTests.Address.Street]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.PersonAddresses].Element.Property[EFTests.PersonAddressMap.Id];SyntheticGlobal[EFTests.MyContext.PersonAddresses#ReturnValue.Element.Property[EFTests.PersonAddressMap.Id]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.PersonAddresses].Element.Property[EFTests.PersonAddressMap.PersonId];SyntheticGlobal[EFTests.MyContext.PersonAddresses#ReturnValue.Element.Property[EFTests.PersonAddressMap.PersonId]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.PersonAddresses].Element.Property[EFTests.PersonAddressMap.Person].Property[EFTests.Person.Id];SyntheticGlobal[EFTests.MyContext.PersonAddresses#ReturnValue.Element.Property[EFTests.PersonAddressMap.Person].Property[EFTests.Person.Id]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.PersonAddresses].Element.Property[EFTests.PersonAddressMap.Person].Property[EFTests.Person.Id];SyntheticGlobal[EFTests.MyContext.Persons#ReturnValue.Element.Property[EFTests.Person.Id]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.PersonAddresses].Element.Property[EFTests.PersonAddressMap.Person].Property[EFTests.Person.Name];SyntheticGlobal[EFTests.MyContext.PersonAddresses#ReturnValue.Element.Property[EFTests.PersonAddressMap.Person].Property[EFTests.Person.Name]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.PersonAddresses].Element.Property[EFTests.PersonAddressMap.Person].Property[EFTests.Person.Name];SyntheticGlobal[EFTests.MyContext.Persons#ReturnValue.Element.Property[EFTests.Person.Name]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.Persons].Element.Property[EFTests.Person.Addresses].Element.Property[EFTests.Address.Id];SyntheticGlobal[EFTests.MyContext.Addresses#ReturnValue.Element.Property[EFTests.Address.Id]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.Persons].Element.Property[EFTests.Person.Addresses].Element.Property[EFTests.Address.Id];SyntheticGlobal[EFTests.MyContext.PersonAddresses#ReturnValue.Element.Property[EFTests.PersonAddressMap.Address].Property[EFTests.Address.Id]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.Persons].Element.Property[EFTests.Person.Addresses].Element.Property[EFTests.Address.Id];SyntheticGlobal[EFTests.MyContext.Persons#ReturnValue.Element.Property[EFTests.Person.Addresses].Element.Property[EFTests.Address.Id]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.Persons].Element.Property[EFTests.Person.Addresses].Element.Property[EFTests.Address.Street];SyntheticGlobal[EFTests.MyContext.Addresses#ReturnValue.Element.Property[EFTests.Address.Street]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.Persons].Element.Property[EFTests.Person.Addresses].Element.Property[EFTests.Address.Street];SyntheticGlobal[EFTests.MyContext.PersonAddresses#ReturnValue.Element.Property[EFTests.PersonAddressMap.Address].Property[EFTests.Address.Street]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.Persons].Element.Property[EFTests.Person.Addresses].Element.Property[EFTests.Address.Street];SyntheticGlobal[EFTests.MyContext.Persons#ReturnValue.Element.Property[EFTests.Person.Addresses].Element.Property[EFTests.Address.Street]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.Persons].Element.Property[EFTests.Person.Id];SyntheticGlobal[EFTests.MyContext.PersonAddresses#ReturnValue.Element.Property[EFTests.PersonAddressMap.Person].Property[EFTests.Person.Id]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.Persons].Element.Property[EFTests.Person.Id];SyntheticGlobal[EFTests.MyContext.Persons#ReturnValue.Element.Property[EFTests.Person.Id]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.Persons].Element.Property[EFTests.Person.Name];SyntheticGlobal[EFTests.MyContext.PersonAddresses#ReturnValue.Element.Property[EFTests.PersonAddressMap.Person].Property[EFTests.Person.Name]];value;manual |
| System.Data.Entity;DbContext;false;SaveChangesAsync;(System.Threading.CancellationToken);;Argument[this].Property[EFTests.MyContext.Persons].Element.Property[EFTests.Person.Name];SyntheticGlobal[EFTests.MyContext.Persons#ReturnValue.Element.Property[EFTests.Person.Name]];value;manual |
neutral neutral
sourceNode sourceNode
sinkNode sinkNode

View File

@@ -1,2 +1,4 @@
semmle-extractor-options: /r:System.Data.dll /r:System.ComponentModel.Primitives.dll /r:System.ComponentModel.TypeConverter.dll ${testdir}/../../../resources/stubs/EntityFramework.cs ${testdir}/../../../resources/stubs/System.Data.cs /r:System.ComponentModel.TypeConverter.dll /r:System.Data.Common.dll /r:System.Linq.dll semmle-extractor-options: /nostdlib /noconfig
semmle-extractor-options: ${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/System.ComponentModel.Annotations.cs ${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/System.ComponentModel.cs semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/EntityFramework/6.4.4/EntityFramework.csproj
semmle-extractor-options: ${testdir}/../../../resources/stubs/EntityFrameworkCore.cs

View File

@@ -1,10 +1,10 @@
sqlExpressions sqlExpressions
| sql.cs:44:23:44:44 | object creation of type MySqlCommand | sql.cs:44:40:44:43 | access to parameter text | | sql.cs:54:23:54:44 | object creation of type MySqlCommand | sql.cs:54:40:54:43 | access to parameter text |
| sql.cs:45:13:45:38 | ... = ... | sql.cs:45:35:45:38 | access to parameter text | | sql.cs:55:13:55:38 | ... = ... | sql.cs:55:35:55:38 | access to parameter text |
| sql.cs:46:13:46:34 | object creation of type MySqlCommand | sql.cs:46:30:46:33 | access to parameter text | | sql.cs:56:13:56:34 | object creation of type MySqlCommand | sql.cs:56:30:56:33 | access to parameter text |
| sql.cs:46:13:46:53 | ... = ... | sql.cs:46:50:46:53 | access to parameter text | | sql.cs:56:13:56:53 | ... = ... | sql.cs:56:50:56:53 | access to parameter text |
sqlCsvSinks sqlCsvSinks
| sql.cs:43:46:43:65 | object creation of type SqlCommand | sql.cs:43:61:43:64 | access to parameter text | | sql.cs:53:46:53:65 | object creation of type SqlCommand | sql.cs:53:61:53:64 | access to parameter text |
| sql.cs:47:13:47:42 | object creation of type SqlDataAdapter | sql.cs:47:32:47:35 | access to parameter text | | sql.cs:57:13:57:50 | object creation of type SqlDataAdapter | sql.cs:57:32:57:35 | access to parameter text |
| sql.cs:48:13:48:47 | call to method ExecuteScalar | sql.cs:48:43:48:46 | access to parameter text | | sql.cs:58:13:58:47 | call to method ExecuteScalar | sql.cs:58:43:58:46 | access to parameter text |
| sql.cs:49:13:49:75 | call to method ExecuteScalar | sql.cs:49:71:49:74 | access to parameter text | | sql.cs:59:13:59:75 | call to method ExecuteScalar | sql.cs:59:71:59:74 | access to parameter text |

View File

@@ -1,3 +1,3 @@
semmle-extractor-options: ${testdir}/../../../resources/stubs/System.Data.cs semmle-extractor-options: /nostdlib /noconfig
semmle-extractor-options: ${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/System.ComponentModel.cs semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj
semmle-extractor-options: /r:System.ComponentModel.TypeConverter.dll /r:System.Data.Common.dll semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/System.Data.SqlClient/4.8.5/System.Data.SqlClient.csproj

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