Merge branch 'main' into henti/update_dotnet

This commit is contained in:
Henti Smith
2024-01-31 11:06:23 +00:00
committed by GitHub
78 changed files with 14499 additions and 4804 deletions

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* Added a new `ThrowingFunction` abstract class that can be used to model an external function that may throw an exception.

View File

@@ -285,7 +285,7 @@ private predicate backEdgeCandidate(
// is a back edge. This includes edges from `continue` and the fall-through
// edge(s) after the last instruction(s) in the body.
exists(TranslatedWhileStmt s |
targetInstruction = s.getFirstConditionInstruction() and
targetInstruction = s.getFirstConditionInstruction(_) and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
requiredAncestor = s.getBody()
)
@@ -296,7 +296,7 @@ private predicate backEdgeCandidate(
// { ... } while (0)` statement. Note that all `continue` statements in a
// do-while loop produce forward edges.
exists(TranslatedDoStmt s |
targetInstruction = s.getBody().getFirstInstruction() and
targetInstruction = s.getBody().getFirstInstruction(_) and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
requiredAncestor = s.getCondition()
)
@@ -308,7 +308,7 @@ private predicate backEdgeCandidate(
// last instruction(s) in the body. A for loop may not have a condition, in
// which case `getFirstConditionInstruction` returns the body instead.
exists(TranslatedForStmt s |
targetInstruction = s.getFirstConditionInstruction() and
targetInstruction = s.getFirstConditionInstruction(_) and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
(
requiredAncestor = s.getUpdate()
@@ -322,7 +322,7 @@ private predicate backEdgeCandidate(
// Any edge from within the update of the loop to the condition of
// the loop is a back edge.
exists(TranslatedRangeBasedForStmt s |
targetInstruction = s.getCondition().getFirstInstruction() and
targetInstruction = s.getCondition().getFirstInstruction(_) and
targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and
requiredAncestor = s.getUpdate()
)

View File

@@ -3,6 +3,7 @@ private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.CppType
private import semmle.code.cpp.models.interfaces.SideEffect
private import semmle.code.cpp.models.interfaces.Throwing
private import InstructionTag
private import SideEffects
private import TranslatedElement
@@ -40,10 +41,10 @@ abstract class TranslatedCall extends TranslatedExpr {
id = this.getNumberOfArguments() and result = this.getSideEffects()
}
final override Instruction getFirstInstruction() {
final override Instruction getFirstInstruction(EdgeKind kind) {
if exists(this.getQualifier())
then result = this.getQualifier().getFirstInstruction()
else result = this.getFirstCallTargetInstruction()
then result = this.getQualifier().getFirstInstruction(kind)
else result = this.getFirstCallTargetInstruction(kind)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -52,34 +53,43 @@ abstract class TranslatedCall extends TranslatedExpr {
resultType = getTypeForPRValue(this.getCallResultType())
}
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getQualifier() and
result = this.getFirstCallTargetInstruction()
result = this.getFirstCallTargetInstruction(kind)
or
child = this.getCallTarget() and
result = this.getFirstArgumentOrCallInstruction()
result = this.getFirstArgumentOrCallInstruction(kind)
or
exists(int argIndex |
child = this.getArgument(argIndex) and
if exists(this.getArgument(argIndex + 1))
then result = this.getArgument(argIndex + 1).getFirstInstruction()
else result = this.getInstruction(CallTag())
then result = this.getArgument(argIndex + 1).getFirstInstruction(kind)
else (
result = this.getInstruction(CallTag()) and kind instanceof GotoEdge
)
)
or
child = this.getSideEffects() and
if this.isNoReturn()
then
kind instanceof GotoEdge and
result =
any(UnreachedInstruction instr |
this.getEnclosingFunction().getFunction() = instr.getEnclosingFunction()
)
else result = this.getParent().getChildSuccessor(this)
else (
not this.mustThrowException() and
result = this.getParent().getChildSuccessor(this, kind)
or
this.mayThrowException() and
kind instanceof ExceptionEdge and
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
)
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
kind instanceof GotoEdge and
tag = CallTag() and
result = this.getSideEffects().getFirstInstruction()
result = this.getSideEffects().getFirstInstruction(kind)
}
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
@@ -100,6 +110,16 @@ abstract class TranslatedCall extends TranslatedExpr {
final override Instruction getResult() { result = this.getInstruction(CallTag()) }
/**
* Holds if the evaluation of this call may throw an exception.
*/
abstract predicate mayThrowException();
/**
* Holds if the evaluation of this call always throws an exception.
*/
abstract predicate mustThrowException();
/**
* Gets the result type of the call.
*/
@@ -121,8 +141,8 @@ abstract class TranslatedCall extends TranslatedExpr {
* it can be overridden by a subclass for cases where there is a call target
* that is not computed from an expression (e.g. a direct call).
*/
Instruction getFirstCallTargetInstruction() {
result = this.getCallTarget().getFirstInstruction()
Instruction getFirstCallTargetInstruction(EdgeKind kind) {
result = this.getCallTarget().getFirstInstruction(kind)
}
/**
@@ -159,10 +179,12 @@ abstract class TranslatedCall extends TranslatedExpr {
* If there are any arguments, gets the first instruction of the first
* argument. Otherwise, returns the call instruction.
*/
final Instruction getFirstArgumentOrCallInstruction() {
final Instruction getFirstArgumentOrCallInstruction(EdgeKind kind) {
if this.hasArguments()
then result = this.getArgument(0).getFirstInstruction()
else result = this.getInstruction(CallTag())
then result = this.getArgument(0).getFirstInstruction(kind)
else (
kind instanceof GotoEdge and result = this.getInstruction(CallTag())
)
}
/**
@@ -203,12 +225,12 @@ abstract class TranslatedSideEffects extends TranslatedElement {
)
}
final override Instruction getChildSuccessor(TranslatedElement te) {
final override Instruction getChildSuccessor(TranslatedElement te, EdgeKind kind) {
exists(int i |
this.getChild(i) = te and
if exists(this.getChild(i + 1))
then result = this.getChild(i + 1).getFirstInstruction()
else result = this.getParent().getChildSuccessor(this)
then result = this.getChild(i + 1).getFirstInstruction(kind)
else result = this.getParent().getChildSuccessor(this, kind)
)
}
@@ -216,11 +238,12 @@ abstract class TranslatedSideEffects extends TranslatedElement {
none()
}
final override Instruction getFirstInstruction() {
result = this.getChild(0).getFirstInstruction()
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getChild(0).getFirstInstruction(kind)
or
// Some functions, like `std::move()`, have no side effects whatsoever.
not exists(this.getChild(0)) and result = this.getParent().getChildSuccessor(this)
not exists(this.getChild(0)) and
result = this.getParent().getChildSuccessor(this, kind)
}
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
@@ -235,8 +258,9 @@ abstract class TranslatedSideEffects extends TranslatedElement {
* (`TranslatedAllocatorCall`).
*/
abstract class TranslatedDirectCall extends TranslatedCall {
final override Instruction getFirstCallTargetInstruction() {
result = this.getInstruction(CallTargetTag())
final override Instruction getFirstCallTargetInstruction(EdgeKind kind) {
result = this.getInstruction(CallTargetTag()) and
kind instanceof GotoEdge
}
final override Instruction getCallTargetResult() { result = this.getInstruction(CallTargetTag()) }
@@ -253,8 +277,7 @@ abstract class TranslatedDirectCall extends TranslatedCall {
result = TranslatedCall.super.getInstructionSuccessor(tag, kind)
or
tag = CallTargetTag() and
kind instanceof GotoEdge and
result = this.getFirstArgumentOrCallInstruction()
result = this.getFirstArgumentOrCallInstruction(kind)
}
}
@@ -290,6 +313,15 @@ class TranslatedExprCall extends TranslatedCallExpr {
override TranslatedExpr getCallTarget() {
result = getTranslatedExpr(expr.getExpr().getFullyConverted())
}
final override predicate mayThrowException() {
// We assume that a call to a function pointer will not throw an exception.
// This is not sound in general, but this will greatly reduce the number of
// exceptional edges.
none()
}
final override predicate mustThrowException() { none() }
}
/**
@@ -311,6 +343,14 @@ class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
exists(this.getQualifier()) and
not exists(MemberFunction func | expr.getTarget() = func and func.isStatic())
}
final override predicate mayThrowException() {
expr.getTarget().(ThrowingFunction).mayThrowException(_)
}
final override predicate mustThrowException() {
expr.getTarget().(ThrowingFunction).mayThrowException(true)
}
}
/**
@@ -376,10 +416,11 @@ private int initializeAllocationGroup() { result = 3 }
abstract class TranslatedSideEffect extends TranslatedElement {
final override TranslatedElement getChild(int n) { none() }
final override Instruction getChildSuccessor(TranslatedElement child) { none() }
final override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) { none() }
final override Instruction getFirstInstruction() {
result = this.getInstruction(OnlyInstructionTag())
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(OnlyInstructionTag()) and
kind instanceof GotoEdge
}
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) {
@@ -388,9 +429,8 @@ abstract class TranslatedSideEffect extends TranslatedElement {
}
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
result = this.getParent().getChildSuccessor(this) and
tag = OnlyInstructionTag() and
kind instanceof GotoEdge
result = this.getParent().getChildSuccessor(this, kind) and
tag = OnlyInstructionTag()
}
final override Declaration getFunction() { result = this.getParent().getFunction() }

View File

@@ -7,9 +7,17 @@ private import TranslatedElement
private import TranslatedExpr
abstract class ConditionContext extends TranslatedElement {
abstract Instruction getChildTrueSuccessor(TranslatedCondition child);
/**
* Gets the instruction to be executed when `child` evaluates to `true`. The
* successor edge kind is specified by `kind`.
*/
abstract Instruction getChildTrueSuccessor(TranslatedCondition child, EdgeKind kind);
abstract Instruction getChildFalseSuccessor(TranslatedCondition child);
/**
* Gets the instruction to be executed when `child` evaluates to `false`. The
* successor edge kind is specified by `kind`.
*/
abstract Instruction getChildFalseSuccessor(TranslatedCondition child, EdgeKind kind);
}
TranslatedCondition getTranslatedCondition(Expr expr) { result.getExpr() = expr }
@@ -44,8 +52,8 @@ abstract class TranslatedFlexibleCondition extends TranslatedCondition, Conditio
final override TranslatedElement getChild(int id) { id = 0 and result = this.getOperand() }
final override Instruction getFirstInstruction() {
result = this.getOperand().getFirstInstruction()
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getOperand().getFirstInstruction(kind)
}
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -54,7 +62,7 @@ abstract class TranslatedFlexibleCondition extends TranslatedCondition, Conditio
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
final override Instruction getChildSuccessor(TranslatedElement child) { none() }
final override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) { none() }
abstract TranslatedCondition getOperand();
}
@@ -62,14 +70,14 @@ abstract class TranslatedFlexibleCondition extends TranslatedCondition, Conditio
class TranslatedParenthesisCondition extends TranslatedFlexibleCondition {
override ParenthesisExpr expr;
final override Instruction getChildTrueSuccessor(TranslatedCondition child) {
final override Instruction getChildTrueSuccessor(TranslatedCondition child, EdgeKind kind) {
child = this.getOperand() and
result = this.getConditionContext().getChildTrueSuccessor(this)
result = this.getConditionContext().getChildTrueSuccessor(this, kind)
}
final override Instruction getChildFalseSuccessor(TranslatedCondition child) {
final override Instruction getChildFalseSuccessor(TranslatedCondition child, EdgeKind kind) {
child = this.getOperand() and
result = this.getConditionContext().getChildFalseSuccessor(this)
result = this.getConditionContext().getChildFalseSuccessor(this, kind)
}
final override TranslatedCondition getOperand() {
@@ -80,7 +88,7 @@ class TranslatedParenthesisCondition extends TranslatedFlexibleCondition {
abstract class TranslatedNativeCondition extends TranslatedCondition, TTranslatedNativeCondition {
TranslatedNativeCondition() { this = TTranslatedNativeCondition(expr) }
final override Instruction getChildSuccessor(TranslatedElement child) { none() }
final override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) { none() }
}
abstract class TranslatedBinaryLogicalOperation extends TranslatedNativeCondition, ConditionContext {
@@ -92,8 +100,8 @@ abstract class TranslatedBinaryLogicalOperation extends TranslatedNativeConditio
id = 1 and result = this.getRightOperand()
}
final override Instruction getFirstInstruction() {
result = this.getLeftOperand().getFirstInstruction()
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getLeftOperand().getFirstInstruction(kind)
}
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -114,34 +122,34 @@ abstract class TranslatedBinaryLogicalOperation extends TranslatedNativeConditio
class TranslatedLogicalAndExpr extends TranslatedBinaryLogicalOperation {
TranslatedLogicalAndExpr() { expr instanceof LogicalAndExpr }
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
override Instruction getChildTrueSuccessor(TranslatedCondition child, EdgeKind kind) {
child = this.getLeftOperand() and
result = this.getRightOperand().getFirstInstruction()
result = this.getRightOperand().getFirstInstruction(kind)
or
child = this.getRightOperand() and
result = this.getConditionContext().getChildTrueSuccessor(this)
result = this.getConditionContext().getChildTrueSuccessor(this, kind)
}
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
override Instruction getChildFalseSuccessor(TranslatedCondition child, EdgeKind kind) {
(child = this.getLeftOperand() or child = this.getRightOperand()) and
result = this.getConditionContext().getChildFalseSuccessor(this)
result = this.getConditionContext().getChildFalseSuccessor(this, kind)
}
}
class TranslatedLogicalOrExpr extends TranslatedBinaryLogicalOperation {
override LogicalOrExpr expr;
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
override Instruction getChildTrueSuccessor(TranslatedCondition child, EdgeKind kind) {
(child = this.getLeftOperand() or child = this.getRightOperand()) and
result = this.getConditionContext().getChildTrueSuccessor(this)
result = this.getConditionContext().getChildTrueSuccessor(this, kind)
}
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
override Instruction getChildFalseSuccessor(TranslatedCondition child, EdgeKind kind) {
child = this.getLeftOperand() and
result = this.getRightOperand().getFirstInstruction()
result = this.getRightOperand().getFirstInstruction(kind)
or
child = this.getRightOperand() and
result = this.getConditionContext().getChildFalseSuccessor(this)
result = this.getConditionContext().getChildFalseSuccessor(this, kind)
}
}
@@ -150,7 +158,9 @@ class TranslatedValueCondition extends TranslatedCondition, TTranslatedValueCond
override TranslatedElement getChild(int id) { id = 0 and result = this.getValueExpr() }
override Instruction getFirstInstruction() { result = this.getValueExpr().getFirstInstruction() }
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getValueExpr().getFirstInstruction(kind)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
tag = ValueConditionConditionalBranchTag() and
@@ -158,19 +168,20 @@ class TranslatedValueCondition extends TranslatedCondition, TTranslatedValueCond
resultType = getVoidType()
}
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getValueExpr() and
result = this.getInstruction(ValueConditionConditionalBranchTag())
result = this.getInstruction(ValueConditionConditionalBranchTag()) and
kind instanceof GotoEdge
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = ValueConditionConditionalBranchTag() and
(
kind instanceof TrueEdge and
result = this.getConditionContext().getChildTrueSuccessor(this)
result = this.getConditionContext().getChildTrueSuccessor(this, any(GotoEdge edge))
or
kind instanceof FalseEdge and
result = this.getConditionContext().getChildFalseSuccessor(this)
result = this.getConditionContext().getChildFalseSuccessor(this, any(GotoEdge edge))
)
}

View File

@@ -67,8 +67,8 @@ abstract class TranslatedLocalVariableDeclaration extends TranslatedVariableInit
getTranslatedInitialization(this.getVariable().getInitializer().getExpr().getFullyConverted())
}
final override Instruction getInitializationSuccessor() {
result = this.getParent().getChildSuccessor(this)
final override Instruction getInitializationSuccessor(EdgeKind kind) {
result = this.getParent().getChildSuccessor(this, kind)
}
final override IRVariable getIRVariable() {
@@ -147,8 +147,9 @@ class TranslatedStaticLocalVariableDeclarationEntry extends TranslatedDeclaratio
type = getBoolType()
}
final override Instruction getFirstInstruction() {
result = this.getInstruction(DynamicInitializationFlagAddressTag())
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(DynamicInitializationFlagAddressTag()) and
kind instanceof GotoEdge
}
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -163,10 +164,10 @@ class TranslatedStaticLocalVariableDeclarationEntry extends TranslatedDeclaratio
tag = DynamicInitializationConditionalBranchTag() and
(
kind instanceof TrueEdge and
result = this.getParent().getChildSuccessor(this)
result = this.getParent().getChildSuccessor(this, any(GotoEdge edge))
or
kind instanceof FalseEdge and
result = this.getInitialization().getFirstInstruction()
result = this.getInitialization().getFirstInstruction(any(GotoEdge edge))
)
or
tag = DynamicInitializationFlagConstantTag() and
@@ -174,13 +175,13 @@ class TranslatedStaticLocalVariableDeclarationEntry extends TranslatedDeclaratio
result = this.getInstruction(DynamicInitializationFlagStoreTag())
or
tag = DynamicInitializationFlagStoreTag() and
kind instanceof GotoEdge and
result = this.getParent().getChildSuccessor(this)
result = this.getParent().getChildSuccessor(this, kind)
}
final override Instruction getChildSuccessor(TranslatedElement child) {
final override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getInitialization() and
result = this.getInstruction(DynamicInitializationFlagConstantTag())
result = this.getInstruction(DynamicInitializationFlagConstantTag()) and
kind instanceof GotoEdge
}
final override IRDynamicInitializationFlag getInstructionVariable(InstructionTag tag) {

View File

@@ -827,9 +827,10 @@ abstract class TranslatedElement extends TTranslatedElement {
Location getLocation() { result = this.getAst().getLocation() }
/**
* Get the first instruction to be executed in the evaluation of this element.
* Get the first instruction to be executed in the evaluation of this
* element when the edge kind is `kind`.
*/
abstract Instruction getFirstInstruction();
abstract Instruction getFirstInstruction(EdgeKind kind);
/**
* Get the immediate child elements of this element.
@@ -904,18 +905,19 @@ abstract class TranslatedElement extends TTranslatedElement {
/**
* Gets the successor instruction to which control should flow after the
* child element specified by `child` has finished execution.
* child element specified by `child` has finished execution. The successor
* edge kind is specified by `kind`.
*/
abstract Instruction getChildSuccessor(TranslatedElement child);
abstract Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind);
/**
* Gets the instruction to which control should flow if an exception is thrown
* within this element. This will generally return first `catch` block of the
* nearest enclosing `try`, or the `Unwind` instruction for the function if
* there is no enclosing `try`.
* there is no enclosing `try`. The successor edge kind is specified by `kind`.
*/
Instruction getExceptionSuccessorInstruction() {
result = this.getParent().getExceptionSuccessorInstruction()
Instruction getExceptionSuccessorInstruction(EdgeKind kind) {
result = this.getParent().getExceptionSuccessorInstruction(kind)
}
/**

View File

@@ -109,8 +109,9 @@ class TranslatedFunction extends TranslatedRootElement, TTranslatedFunction {
result = getTranslatedEllipsisParameter(func)
}
final override Instruction getFirstInstruction() {
result = this.getInstruction(EnterFunctionTag())
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(EnterFunctionTag()) and
kind instanceof GotoEdge
}
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -121,17 +122,20 @@ class TranslatedFunction extends TranslatedRootElement, TTranslatedFunction {
or
tag = AliasedDefinitionTag() and
result = this.getInstruction(InitializeNonLocalTag())
or
(
tag = InitializeNonLocalTag() and
if exists(this.getThisType())
then result = this.getParameter(-1).getFirstInstruction()
else
if exists(this.getParameter(0))
then result = this.getParameter(0).getFirstInstruction()
else result = this.getBody().getFirstInstruction()
)
or
)
or
(
tag = InitializeNonLocalTag() and
if exists(this.getThisType())
then result = this.getParameter(-1).getFirstInstruction(kind)
else
if exists(this.getParameter(0))
then result = this.getParameter(0).getFirstInstruction(kind)
else result = this.getBody().getFirstInstruction(kind)
)
or
kind instanceof GotoEdge and
(
tag = ReturnValueAddressTag() and
result = this.getInstruction(ReturnTag())
or
@@ -146,25 +150,25 @@ class TranslatedFunction extends TranslatedRootElement, TTranslatedFunction {
)
}
final override Instruction getChildSuccessor(TranslatedElement child) {
exists(int paramIndex |
child = this.getParameter(paramIndex) and
final override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
exists(int paramIndex | child = this.getParameter(paramIndex) |
if
exists(func.getParameter(paramIndex + 1)) or
getEllipsisParameterIndexForFunction(func) = paramIndex + 1
then result = this.getParameter(paramIndex + 1).getFirstInstruction()
else result = this.getConstructorInitList().getFirstInstruction()
then result = this.getParameter(paramIndex + 1).getFirstInstruction(kind)
else result = this.getConstructorInitList().getFirstInstruction(kind)
)
or
child = this.getConstructorInitList() and
result = this.getBody().getFirstInstruction()
result = this.getBody().getFirstInstruction(kind)
or
child = this.getBody() and
result = this.getReturnSuccessorInstruction()
result = this.getReturnSuccessorInstruction(kind)
or
child = this.getDestructorDestructionList() and
result = this.getReadEffects().getFirstInstruction()
result = this.getReadEffects().getFirstInstruction(kind)
or
kind instanceof GotoEdge and
child = this.getReadEffects() and
if this.hasReturnValue()
then result = this.getInstruction(ReturnValueAddressTag())
@@ -218,8 +222,9 @@ class TranslatedFunction extends TranslatedRootElement, TTranslatedFunction {
)
}
final override Instruction getExceptionSuccessorInstruction() {
result = this.getInstruction(UnwindTag())
final override Instruction getExceptionSuccessorInstruction(EdgeKind kind) {
result = this.getInstruction(UnwindTag()) and
kind instanceof GotoEdge
}
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
@@ -268,8 +273,8 @@ class TranslatedFunction extends TranslatedRootElement, TTranslatedFunction {
* Gets the instruction to which control should flow after a `return`
* statement.
*/
final Instruction getReturnSuccessorInstruction() {
result = this.getDestructorDestructionList().getFirstInstruction()
final Instruction getReturnSuccessorInstruction(EdgeKind kind) {
result = this.getDestructorDestructionList().getFirstInstruction(kind)
}
/**
@@ -369,30 +374,30 @@ TranslatedEllipsisParameter getTranslatedEllipsisParameter(Function func) {
abstract class TranslatedParameter extends TranslatedElement {
final override TranslatedElement getChild(int id) { none() }
final override Instruction getFirstInstruction() {
result = this.getInstruction(InitializerVariableAddressTag())
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(InitializerVariableAddressTag()) and
kind instanceof GotoEdge
}
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
kind instanceof GotoEdge and
(
tag = InitializerVariableAddressTag() and
result = this.getInstruction(InitializerStoreTag())
or
tag = InitializerStoreTag() and
if this.hasIndirection()
then result = this.getInstruction(InitializerIndirectAddressTag())
else result = this.getParent().getChildSuccessor(this)
or
tag = InitializerIndirectAddressTag() and
result = this.getInstruction(InitializerIndirectStoreTag())
or
tag = InitializerIndirectStoreTag() and
result = this.getParent().getChildSuccessor(this)
)
tag = InitializerVariableAddressTag() and
result = this.getInstruction(InitializerStoreTag())
or
tag = InitializerStoreTag() and
if this.hasIndirection()
then kind instanceof GotoEdge and result = this.getInstruction(InitializerIndirectAddressTag())
else result = this.getParent().getChildSuccessor(this, kind)
or
kind instanceof GotoEdge and
tag = InitializerIndirectAddressTag() and
result = this.getInstruction(InitializerIndirectStoreTag())
or
tag = InitializerIndirectStoreTag() and
result = this.getParent().getChildSuccessor(this, kind)
}
final override Instruction getChildSuccessor(TranslatedElement child) { none() }
final override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) { none() }
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
tag = InitializerVariableAddressTag() and
@@ -600,10 +605,10 @@ class TranslatedConstructorInitList extends TranslatedElement, InitializationCon
)
}
override Instruction getFirstInstruction() {
override Instruction getFirstInstruction(EdgeKind kind) {
if exists(this.getChild(0))
then result = this.getChild(0).getFirstInstruction()
else result = this.getParent().getChildSuccessor(this)
then result = this.getChild(0).getFirstInstruction(kind)
else result = this.getParent().getChildSuccessor(this, kind)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -614,12 +619,12 @@ class TranslatedConstructorInitList extends TranslatedElement, InitializationCon
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
exists(int id |
child = this.getChild(id) and
if exists(this.getChild(id + 1))
then result = this.getChild(id + 1).getFirstInstruction()
else result = this.getParent().getChildSuccessor(this)
then result = this.getChild(id + 1).getFirstInstruction(kind)
else result = this.getParent().getChildSuccessor(this, kind)
)
}
@@ -667,10 +672,10 @@ class TranslatedDestructorDestructionList extends TranslatedElement,
)
}
override Instruction getFirstInstruction() {
override Instruction getFirstInstruction(EdgeKind kind) {
if exists(this.getChild(0))
then result = this.getChild(0).getFirstInstruction()
else result = this.getParent().getChildSuccessor(this)
then result = this.getChild(0).getFirstInstruction(kind)
else result = this.getParent().getChildSuccessor(this, kind)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -681,12 +686,12 @@ class TranslatedDestructorDestructionList extends TranslatedElement,
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
exists(int id |
child = this.getChild(id) and
if exists(this.getChild(id + 1))
then result = this.getChild(id + 1).getFirstInstruction()
else result = this.getParent().getChildSuccessor(this)
then result = this.getChild(id + 1).getFirstInstruction(kind)
else result = this.getParent().getChildSuccessor(this, kind)
)
}
}
@@ -714,16 +719,16 @@ class TranslatedReadEffects extends TranslatedElement, TTranslatedReadEffects {
result = getTranslatedParameterReadEffect(func.getParameter(id))
}
override Instruction getFirstInstruction() {
override Instruction getFirstInstruction(EdgeKind kind) {
if exists(this.getAChild())
then
result =
min(TranslatedElement child, int id | child = this.getChild(id) | child order by id)
.getFirstInstruction()
else result = this.getParent().getChildSuccessor(this)
.getFirstInstruction(kind)
else result = this.getParent().getChildSuccessor(this, kind)
}
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
exists(int id | child = this.getChild(id) |
if exists(TranslatedReadEffect child2, int id2 | id2 > id and child2 = this.getChild(id2))
then
@@ -732,8 +737,8 @@ class TranslatedReadEffects extends TranslatedElement, TTranslatedReadEffects {
child2 = this.getChild(id2) and id2 > id
|
child2 order by id2
).getFirstInstruction()
else result = this.getParent().getChildSuccessor(this)
).getFirstInstruction(kind)
else result = this.getParent().getChildSuccessor(this, kind)
)
}
@@ -755,15 +760,17 @@ private TranslatedParameterReadEffect getTranslatedParameterReadEffect(Parameter
abstract class TranslatedReadEffect extends TranslatedElement {
override TranslatedElement getChild(int id) { none() }
override Instruction getChildSuccessor(TranslatedElement child) { none() }
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) { none() }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
kind = EdgeKind::gotoEdge() and
result = this.getParent().getChildSuccessor(this)
result = this.getParent().getChildSuccessor(this, kind)
}
override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) }
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(OnlyInstructionTag()) and
kind instanceof GotoEdge
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
opcode instanceof Opcode::ReturnIndirection and

View File

@@ -22,7 +22,10 @@ class TranslatedStaticStorageDurationVarInit extends TranslatedRootElement,
final override Declaration getFunction() { result = var }
override Instruction getFirstInstruction() { result = this.getInstruction(EnterFunctionTag()) }
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(EnterFunctionTag()) and
kind instanceof GotoEdge
}
override TranslatedElement getChild(int n) {
n = 1 and
@@ -63,10 +66,13 @@ class TranslatedStaticStorageDurationVarInit extends TranslatedRootElement,
or
tag = AliasedDefinitionTag() and
result = this.getInstruction(InitializerVariableAddressTag())
or
tag = InitializerVariableAddressTag() and
result = this.getChild(1).getFirstInstruction()
or
)
or
tag = InitializerVariableAddressTag() and
result = this.getChild(1).getFirstInstruction(kind)
or
kind instanceof GotoEdge and
(
tag = ReturnTag() and
result = this.getInstruction(AliasedUseTag())
or
@@ -75,9 +81,10 @@ class TranslatedStaticStorageDurationVarInit extends TranslatedRootElement,
)
}
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getChild(1) and
result = this.getInstruction(ReturnTag())
result = this.getInstruction(ReturnTag()) and
kind instanceof GotoEdge
}
final override CppType getInstructionMemoryOperandType(

View File

@@ -37,8 +37,9 @@ abstract class InitializationContext extends TranslatedElement {
abstract class TranslatedVariableInitialization extends TranslatedElement, InitializationContext {
final override TranslatedElement getChild(int id) { id = 0 and result = this.getInitialization() }
final override Instruction getFirstInstruction() {
result = this.getInstruction(InitializerVariableAddressTag())
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(InitializerVariableAddressTag()) and
kind instanceof GotoEdge
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -55,24 +56,24 @@ abstract class TranslatedVariableInitialization extends TranslatedElement, Initi
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
(
tag = InitializerVariableAddressTag() and
kind instanceof GotoEdge and
if this.hasUninitializedInstruction()
then result = this.getInstruction(InitializerStoreTag())
else result = this.getInitialization().getFirstInstruction()
then kind instanceof GotoEdge and result = this.getInstruction(InitializerStoreTag())
else result = this.getInitialization().getFirstInstruction(kind)
)
or
this.hasUninitializedInstruction() and
kind instanceof GotoEdge and
tag = InitializerStoreTag() and
(
result = this.getInitialization().getFirstInstruction()
result = this.getInitialization().getFirstInstruction(kind)
or
not exists(this.getInitialization()) and result = this.getInitializationSuccessor()
not exists(this.getInitialization()) and
result = this.getInitializationSuccessor(kind)
)
}
final override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getInitialization() and result = this.getInitializationSuccessor()
final override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getInitialization() and
result = this.getInitializationSuccessor(kind)
}
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
@@ -107,8 +108,9 @@ abstract class TranslatedVariableInitialization extends TranslatedElement, Initi
/**
* Gets the `Instruction` to be executed immediately after the initialization.
* The successor edge kind is specified by `kind`.
*/
abstract Instruction getInitializationSuccessor();
abstract Instruction getInitializationSuccessor(EdgeKind kind);
/**
* Holds if this initialization requires an `Uninitialized` instruction to be emitted before
@@ -168,18 +170,19 @@ abstract class TranslatedInitialization extends TranslatedElement, TTranslatedIn
* Represents the IR translation of an initialization from an initializer list.
*/
abstract class TranslatedListInitialization extends TranslatedInitialization, InitializationContext {
override Instruction getFirstInstruction() {
result = this.getChild(0).getFirstInstruction()
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getChild(0).getFirstInstruction(kind)
or
not exists(this.getChild(0)) and result = this.getParent().getChildSuccessor(this)
not exists(this.getChild(0)) and
result = this.getParent().getChildSuccessor(this, kind)
}
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
exists(int index |
child = this.getChild(index) and
if exists(this.getChild(index + 1))
then result = this.getChild(index + 1).getFirstInstruction()
else result = this.getParent().getChildSuccessor(this)
then result = this.getChild(index + 1).getFirstInstruction(kind)
else result = this.getParent().getChildSuccessor(this, kind)
)
}
@@ -239,8 +242,8 @@ abstract class TranslatedDirectInitialization extends TranslatedInitialization {
override TranslatedElement getChild(int id) { id = 0 and result = this.getInitializer() }
override Instruction getFirstInstruction() {
result = this.getInitializer().getFirstInstruction()
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInitializer().getFirstInstruction(kind)
}
final TranslatedExpr getInitializer() { result = getTranslatedExpr(expr) }
@@ -265,12 +268,13 @@ class TranslatedSimpleDirectInitialization extends TranslatedDirectInitializatio
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = InitializerStoreTag() and
result = this.getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
result = this.getParent().getChildSuccessor(this, kind)
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getInitializer() and result = this.getInstruction(InitializerStoreTag())
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getInitializer() and
result = this.getInstruction(InitializerStoreTag()) and
kind instanceof GotoEdge
}
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
@@ -335,12 +339,13 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
kind instanceof GotoEdge and
(
tag = InitializerLoadStringTag() and
result = this.getInstruction(InitializerStoreTag())
or
if this.zeroInitRange(_, _)
then (
tag = InitializerLoadStringTag() and
result = this.getInstruction(InitializerStoreTag())
or
if this.zeroInitRange(_, _)
then (
kind instanceof GotoEdge and
(
tag = InitializerStoreTag() and
result = this.getInstruction(ZeroPadStringConstantTag())
or
@@ -352,18 +357,20 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
or
tag = ZeroPadStringElementAddressTag() and
result = this.getInstruction(ZeroPadStringStoreTag())
or
tag = ZeroPadStringStoreTag() and
result = this.getParent().getChildSuccessor(this)
) else (
tag = InitializerStoreTag() and
result = this.getParent().getChildSuccessor(this)
)
or
tag = ZeroPadStringStoreTag() and
result = this.getParent().getChildSuccessor(this, kind)
) else (
tag = InitializerStoreTag() and
result = this.getParent().getChildSuccessor(this, kind)
)
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getInitializer() and result = this.getInstruction(InitializerLoadStringTag())
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getInitializer() and
result = this.getInstruction(InitializerLoadStringTag()) and
kind instanceof GotoEdge
}
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
@@ -456,8 +463,8 @@ class TranslatedConstructorInitialization extends TranslatedDirectInitialization
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getInitializer() and result = this.getParent().getChildSuccessor(this)
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getInitializer() and result = this.getParent().getChildSuccessor(this, kind)
}
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
@@ -502,8 +509,9 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
result = getEnclosingVariable(ast).(StaticInitializedStaticLocalVariable)
}
final override Instruction getFirstInstruction() {
result = this.getInstruction(this.getFieldAddressTag())
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(this.getFieldAddressTag()) and
kind instanceof GotoEdge
}
/**
@@ -558,12 +566,11 @@ class TranslatedExplicitFieldInitialization extends TranslatedFieldInitializatio
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = this.getFieldAddressTag() and
result = this.getInitialization().getFirstInstruction() and
kind instanceof GotoEdge
result = this.getInitialization().getFirstInstruction(kind)
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getInitialization() and result = this.getParent().getChildSuccessor(this)
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getInitialization() and result = this.getParent().getChildSuccessor(this, kind)
}
override TranslatedElement getChild(int id) { id = 0 and result = this.getInitialization() }
@@ -608,10 +615,10 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
or
tag = this.getFieldDefaultValueTag() and
result = this.getInstruction(this.getFieldDefaultValueStoreTag())
or
tag = this.getFieldDefaultValueStoreTag() and
result = this.getParent().getChildSuccessor(this)
)
or
tag = this.getFieldDefaultValueStoreTag() and
result = this.getParent().getChildSuccessor(this, kind)
}
override string getInstructionConstantValue(InstructionTag tag) {
@@ -632,7 +639,7 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
)
}
override Instruction getChildSuccessor(TranslatedElement child) { none() }
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) { none() }
override TranslatedElement getChild(int id) { none() }
@@ -667,8 +674,9 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
result = getEnclosingVariable(initList).(StaticInitializedStaticLocalVariable)
}
final override Instruction getFirstInstruction() {
result = this.getInstruction(this.getElementIndexTag())
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(this.getElementIndexTag()) and
kind instanceof GotoEdge
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -745,12 +753,11 @@ class TranslatedExplicitElementInitialization extends TranslatedElementInitializ
result = TranslatedElementInitialization.super.getInstructionSuccessor(tag, kind)
or
tag = this.getElementAddressTag() and
result = this.getInitialization().getFirstInstruction() and
kind instanceof GotoEdge
result = this.getInitialization().getFirstInstruction(kind)
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getInitialization() and result = this.getParent().getChildSuccessor(this)
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getInitialization() and result = this.getParent().getChildSuccessor(this, kind)
}
override TranslatedElement getChild(int id) { id = 0 and result = this.getInitialization() }
@@ -803,10 +810,10 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
or
tag = this.getElementDefaultValueTag() and
result = this.getInstruction(this.getElementDefaultValueStoreTag())
or
tag = this.getElementDefaultValueStoreTag() and
result = this.getParent().getChildSuccessor(this)
)
or
tag = this.getElementDefaultValueStoreTag() and
result = this.getParent().getChildSuccessor(this, kind)
}
override string getInstructionConstantValue(InstructionTag tag) {
@@ -829,7 +836,7 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
)
}
override Instruction getChildSuccessor(TranslatedElement child) { none() }
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) { none() }
override TranslatedElement getChild(int id) { none() }
@@ -869,9 +876,9 @@ abstract class TranslatedStructorCallFromStructor extends TranslatedElement, Str
final override Function getFunction() { result = getEnclosingFunction(call) }
final override Instruction getChildSuccessor(TranslatedElement child) {
final override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getStructorCall() and
result = this.getParent().getChildSuccessor(this)
result = this.getParent().getChildSuccessor(this, kind)
}
final TranslatedExpr getStructorCall() { result = getTranslatedExpr(call) }
@@ -882,8 +889,9 @@ abstract class TranslatedStructorCallFromStructor extends TranslatedElement, Str
* destructor from within a derived class constructor or destructor.
*/
abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStructor {
final override Instruction getFirstInstruction() {
result = this.getInstruction(OnlyInstructionTag())
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(OnlyInstructionTag()) and
kind instanceof GotoEdge
}
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -894,8 +902,7 @@ abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStru
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
kind instanceof GotoEdge and
result = this.getStructorCall().getFirstInstruction()
result = this.getStructorCall().getFirstInstruction(kind)
}
final override Instruction getReceiver() { result = this.getInstruction(OnlyInstructionTag()) }
@@ -936,8 +943,8 @@ class TranslatedConstructorDelegationInit extends TranslatedConstructorCallFromC
final override string toString() { result = "delegation construct: " + call.toString() }
final override Instruction getFirstInstruction() {
result = this.getStructorCall().getFirstInstruction()
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getStructorCall().getFirstInstruction(kind)
}
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -998,7 +1005,9 @@ class TranslatedConstructorBareInit extends TranslatedElement, TTranslatedConstr
final override string toString() { result = "construct base (no constructor)" }
override Instruction getFirstInstruction() { result = this.getParent().getChildSuccessor(this) }
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getParent().getChildSuccessor(this, kind)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
none()
@@ -1010,7 +1019,7 @@ class TranslatedConstructorBareInit extends TranslatedElement, TTranslatedConstr
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getChildSuccessor(TranslatedElement child) { none() }
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) { none() }
}
TranslatedConstructorBareInit getTranslatedConstructorBareInit(ConstructorInit init) {

View File

@@ -30,7 +30,9 @@ class TranslatedMicrosoftTryExceptHandler extends TranslatedElement,
final override Locatable getAst() { result = tryExcept.getExcept() }
override Instruction getFirstInstruction() { result = this.getChild(0).getFirstInstruction() }
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getChild(0).getFirstInstruction(kind)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
// t1 = -1
@@ -192,23 +194,21 @@ class TranslatedMicrosoftTryExceptHandler extends TranslatedElement,
or
// Branch -> Handler (the condition value is always 0, -1 or 1, and we've checked for 0 or -1 already.)
tag = TryExceptCompareOneBranch() and
(
kind instanceof TrueEdge and
result = this.getTranslatedHandler().getFirstInstruction()
)
kind instanceof TrueEdge and
result = this.getTranslatedHandler().getFirstInstruction(any(GotoEdge edge))
or
// Unwind -> Parent
tag = UnwindTag() and
kind instanceof GotoEdge and
result = this.getParent().getChildSuccessor(this)
result = this.getParent().getChildSuccessor(this, kind)
}
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
kind instanceof GotoEdge and
child = this.getTranslatedCondition() and
result = this.getInstruction(TryExceptGenerateNegativeOne())
or
child = this.getTranslatedHandler() and
result = this.getParent().getChildSuccessor(this)
result = this.getParent().getChildSuccessor(this, kind)
}
private TranslatedExpr getTranslatedCondition() {
@@ -254,7 +254,10 @@ class TranslatedEmptyStmt extends TranslatedStmt {
override TranslatedElement getChild(int id) { none() }
override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) }
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(OnlyInstructionTag()) and
kind instanceof GotoEdge
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
tag = OnlyInstructionTag() and
@@ -264,11 +267,10 @@ class TranslatedEmptyStmt extends TranslatedStmt {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
result = this.getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
result = this.getParent().getChildSuccessor(this, kind)
}
override Instruction getChildSuccessor(TranslatedElement child) { none() }
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) { none() }
}
/**
@@ -285,10 +287,11 @@ class TranslatedDeclStmt extends TranslatedStmt {
none()
}
override Instruction getFirstInstruction() {
result = this.getDeclarationEntry(0).getFirstInstruction()
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getDeclarationEntry(0).getFirstInstruction(kind)
or
not exists(this.getDeclarationEntry(0)) and result = this.getParent().getChildSuccessor(this)
not exists(this.getDeclarationEntry(0)) and
result = this.getParent().getChildSuccessor(this, kind)
}
private int getChildCount() { result = count(this.getDeclarationEntry(_)) }
@@ -317,12 +320,12 @@ class TranslatedDeclStmt extends TranslatedStmt {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
exists(int index |
child = this.getDeclarationEntry(index) and
if index = (this.getChildCount() - 1)
then result = this.getParent().getChildSuccessor(this)
else result = this.getDeclarationEntry(index + 1).getFirstInstruction()
then result = this.getParent().getChildSuccessor(this, kind)
else result = this.getDeclarationEntry(index + 1).getFirstInstruction(kind)
)
}
}
@@ -338,13 +341,15 @@ class TranslatedExprStmt extends TranslatedStmt {
none()
}
override Instruction getFirstInstruction() { result = this.getExpr().getFirstInstruction() }
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getExpr().getFirstInstruction(kind)
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getExpr() and
result = this.getParent().getChildSuccessor(this)
result = this.getParent().getChildSuccessor(this, kind)
}
}
@@ -362,8 +367,8 @@ abstract class TranslatedReturnStmt extends TranslatedStmt {
class TranslatedReturnValueStmt extends TranslatedReturnStmt, TranslatedVariableInitialization {
TranslatedReturnValueStmt() { stmt.hasExpr() and hasReturnValue(stmt.getEnclosingFunction()) }
final override Instruction getInitializationSuccessor() {
result = this.getEnclosingFunction().getReturnSuccessorInstruction()
final override Instruction getInitializationSuccessor(EdgeKind kind) {
result = this.getEnclosingFunction().getReturnSuccessorInstruction(kind)
}
final override Type getTargetType() { result = this.getEnclosingFunction().getReturnType() }
@@ -390,7 +395,9 @@ class TranslatedReturnVoidExpressionStmt extends TranslatedReturnStmt {
result = this.getExpr()
}
override Instruction getFirstInstruction() { result = this.getExpr().getFirstInstruction() }
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getExpr().getFirstInstruction(kind)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
tag = OnlyInstructionTag() and
@@ -400,13 +407,13 @@ class TranslatedReturnVoidExpressionStmt extends TranslatedReturnStmt {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
result = this.getEnclosingFunction().getReturnSuccessorInstruction() and
kind instanceof GotoEdge
result = this.getEnclosingFunction().getReturnSuccessorInstruction(kind)
}
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getExpr() and
result = this.getInstruction(OnlyInstructionTag())
result = this.getInstruction(OnlyInstructionTag()) and
kind instanceof GotoEdge
}
private TranslatedExpr getExpr() { result = getTranslatedExpr(stmt.getExpr()) }
@@ -423,7 +430,10 @@ class TranslatedReturnVoidStmt extends TranslatedReturnStmt {
override TranslatedElement getChild(int id) { none() }
override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) }
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(OnlyInstructionTag()) and
kind instanceof GotoEdge
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
tag = OnlyInstructionTag() and
@@ -433,11 +443,10 @@ class TranslatedReturnVoidStmt extends TranslatedReturnStmt {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
result = this.getEnclosingFunction().getReturnSuccessorInstruction() and
kind instanceof GotoEdge
result = this.getEnclosingFunction().getReturnSuccessorInstruction(kind)
}
override Instruction getChildSuccessor(TranslatedElement child) { none() }
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) { none() }
}
/**
@@ -451,8 +460,8 @@ class TranslatedNoValueReturnStmt extends TranslatedReturnStmt, TranslatedVariab
not stmt.hasExpr() and hasReturnValue(stmt.getEnclosingFunction())
}
final override Instruction getInitializationSuccessor() {
result = this.getEnclosingFunction().getReturnSuccessorInstruction()
final override Instruction getInitializationSuccessor(EdgeKind kind) {
result = this.getEnclosingFunction().getReturnSuccessorInstruction(kind)
}
final override Type getTargetType() { result = this.getEnclosingFunction().getReturnType() }
@@ -524,40 +533,42 @@ class TranslatedTryStmt extends TranslatedStmt {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getFirstInstruction() { result = this.getBody().getFirstInstruction() }
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getBody().getFirstInstruction(kind)
}
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
// All non-finally children go to the successor of the `try` if
// there is no finally block, but if there is a finally block
// then we go to that one.
child = [this.getBody(), this.getHandler(_)] and
(
not exists(this.getFinally()) and
result = this.getParent().getChildSuccessor(this)
result = this.getParent().getChildSuccessor(this, kind)
or
result = this.getFinally().getFirstInstruction()
result = this.getFinally().getFirstInstruction(kind)
)
or
// And after the finally block we go to the successor of the `try`.
child = this.getFinally() and
result = this.getParent().getChildSuccessor(this)
result = this.getParent().getChildSuccessor(this, kind)
}
final Instruction getNextHandler(TranslatedHandler handler) {
final Instruction getNextHandler(TranslatedHandler handler, EdgeKind kind) {
exists(int index |
handler = this.getHandler(index) and
result = this.getHandler(index + 1).getFirstInstruction()
result = this.getHandler(index + 1).getFirstInstruction(kind)
)
or
// The last catch clause flows to the exception successor of the parent
// of the `try`, because the exception successor of the `try` itself is
// the first catch clause.
handler = this.getHandler(stmt.getNumberOfCatchClauses() - 1) and
result = this.getParent().getExceptionSuccessorInstruction()
result = this.getParent().getExceptionSuccessorInstruction(kind)
}
final override Instruction getExceptionSuccessorInstruction() {
result = this.getHandler(0).getFirstInstruction()
final override Instruction getExceptionSuccessorInstruction(EdgeKind kind) {
result = this.getHandler(0).getFirstInstruction(kind)
}
private TranslatedElement getHandler(int index) { result = stmt.getTranslatedHandler(index) }
@@ -579,10 +590,10 @@ class TranslatedBlock extends TranslatedStmt {
resultType = getVoidType()
}
override Instruction getFirstInstruction() {
override Instruction getFirstInstruction(EdgeKind kind) {
if this.isEmpty()
then result = this.getInstruction(OnlyInstructionTag())
else result = this.getStmt(0).getFirstInstruction()
then kind instanceof GotoEdge and result = this.getInstruction(OnlyInstructionTag())
else result = this.getStmt(0).getFirstInstruction(kind)
}
private predicate isEmpty() { not exists(stmt.getStmt(0)) }
@@ -593,16 +604,15 @@ class TranslatedBlock extends TranslatedStmt {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
result = this.getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
result = this.getParent().getChildSuccessor(this, kind)
}
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
exists(int index |
child = this.getStmt(index) and
if index = (this.getStmtCount() - 1)
then result = this.getParent().getChildSuccessor(this)
else result = this.getStmt(index + 1).getFirstInstruction()
then result = this.getParent().getChildSuccessor(this, kind)
else result = this.getStmt(index + 1).getFirstInstruction(kind)
)
}
}
@@ -615,16 +625,19 @@ abstract class TranslatedHandler extends TranslatedStmt {
override TranslatedElement getChild(int id) { id = 1 and result = this.getBlock() }
override Instruction getFirstInstruction() { result = this.getInstruction(CatchTag()) }
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getBlock() and result = this.getParent().getChildSuccessor(this)
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(CatchTag()) and
kind instanceof GotoEdge
}
override Instruction getExceptionSuccessorInstruction() {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getBlock() and result = this.getParent().getChildSuccessor(this, kind)
}
override Instruction getExceptionSuccessorInstruction(EdgeKind kind) {
// A throw from within a `catch` block flows to the handler for the parent of
// the `try`.
result = this.getParent().getParent().getExceptionSuccessorInstruction()
result = this.getParent().getParent().getExceptionSuccessorInstruction(kind)
}
TranslatedStmt getBlock() { result = getTranslatedStmt(stmt.getBlock()) }
@@ -649,20 +662,21 @@ class TranslatedCatchByTypeHandler extends TranslatedHandler {
id = 0 and result = this.getParameter()
}
override Instruction getChildSuccessor(TranslatedElement child) {
result = super.getChildSuccessor(child)
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
result = super.getChildSuccessor(child, kind)
or
child = this.getParameter() and result = this.getBlock().getFirstInstruction()
child = this.getParameter() and
result = this.getBlock().getFirstInstruction(kind)
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = CatchTag() and
(
kind instanceof GotoEdge and
result = this.getParameter().getFirstInstruction()
result = this.getParameter().getFirstInstruction(kind)
or
kind instanceof ExceptionEdge and
result = this.getParent().(TranslatedTryStmt).getNextHandler(this)
result = this.getParent().(TranslatedTryStmt).getNextHandler(this, any(GotoEdge edge))
)
}
@@ -690,18 +704,17 @@ class TranslatedCatchAnyHandler extends TranslatedHandler {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = CatchTag() and
kind instanceof GotoEdge and
result = this.getBlock().getFirstInstruction()
result = this.getBlock().getFirstInstruction(kind)
}
}
class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
override IfStmt stmt;
override Instruction getFirstInstruction() {
override Instruction getFirstInstruction(EdgeKind kind) {
if this.hasInitialization()
then result = this.getInitialization().getFirstInstruction()
else result = this.getFirstConditionInstruction()
then result = this.getInitialization().getFirstInstruction(kind)
else result = this.getFirstConditionInstruction(kind)
}
override TranslatedElement getChild(int id) {
@@ -724,8 +737,8 @@ class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
result = getTranslatedCondition(stmt.getCondition().getFullyConverted())
}
private Instruction getFirstConditionInstruction() {
result = this.getCondition().getFirstInstruction()
private Instruction getFirstConditionInstruction(EdgeKind kind) {
result = this.getCondition().getFirstInstruction(kind)
}
private TranslatedStmt getThen() { result = getTranslatedStmt(stmt.getThen()) }
@@ -736,24 +749,24 @@ class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
override Instruction getChildTrueSuccessor(TranslatedCondition child, EdgeKind kind) {
child = this.getCondition() and
result = this.getThen().getFirstInstruction()
result = this.getThen().getFirstInstruction(kind)
}
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
override Instruction getChildFalseSuccessor(TranslatedCondition child, EdgeKind kind) {
child = this.getCondition() and
if this.hasElse()
then result = this.getElse().getFirstInstruction()
else result = this.getParent().getChildSuccessor(this)
then result = this.getElse().getFirstInstruction(kind)
else result = this.getParent().getChildSuccessor(this, kind)
}
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getInitialization() and
result = this.getFirstConditionInstruction()
result = this.getFirstConditionInstruction(kind)
or
(child = this.getThen() or child = this.getElse()) and
result = this.getParent().getChildSuccessor(this)
result = this.getParent().getChildSuccessor(this, kind)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -770,10 +783,10 @@ abstract class TranslatedLoop extends TranslatedStmt, ConditionContext {
final TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getStmt()) }
final Instruction getFirstConditionInstruction() {
final Instruction getFirstConditionInstruction(EdgeKind kind) {
if this.hasCondition()
then result = this.getCondition().getFirstInstruction()
else result = this.getBody().getFirstInstruction()
then result = this.getCondition().getFirstInstruction(kind)
else result = this.getBody().getFirstInstruction(kind)
}
final predicate hasCondition() { exists(stmt.getCondition()) }
@@ -790,32 +803,39 @@ abstract class TranslatedLoop extends TranslatedStmt, ConditionContext {
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
final override Instruction getChildTrueSuccessor(TranslatedCondition child) {
child = this.getCondition() and result = this.getBody().getFirstInstruction()
final override Instruction getChildTrueSuccessor(TranslatedCondition child, EdgeKind kind) {
child = this.getCondition() and result = this.getBody().getFirstInstruction(kind)
}
final override Instruction getChildFalseSuccessor(TranslatedCondition child) {
child = this.getCondition() and result = this.getParent().getChildSuccessor(this)
final override Instruction getChildFalseSuccessor(TranslatedCondition child, EdgeKind kind) {
child = this.getCondition() and
result = this.getParent().getChildSuccessor(this, kind)
}
}
class TranslatedWhileStmt extends TranslatedLoop {
TranslatedWhileStmt() { stmt instanceof WhileStmt }
override Instruction getFirstInstruction() { result = this.getFirstConditionInstruction() }
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getFirstConditionInstruction(kind)
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getBody() and result = this.getFirstConditionInstruction()
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getBody() and
result = this.getFirstConditionInstruction(kind)
}
}
class TranslatedDoStmt extends TranslatedLoop {
TranslatedDoStmt() { stmt instanceof DoStmt }
override Instruction getFirstInstruction() { result = this.getBody().getFirstInstruction() }
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getBody().getFirstInstruction(kind)
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getBody() and result = this.getFirstConditionInstruction()
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getBody() and
result = this.getFirstConditionInstruction(kind)
}
}
@@ -842,24 +862,24 @@ class TranslatedForStmt extends TranslatedLoop {
private predicate hasUpdate() { exists(stmt.getUpdate()) }
override Instruction getFirstInstruction() {
override Instruction getFirstInstruction(EdgeKind kind) {
if this.hasInitialization()
then result = this.getInitialization().getFirstInstruction()
else result = this.getFirstConditionInstruction()
then result = this.getInitialization().getFirstInstruction(kind)
else result = this.getFirstConditionInstruction(kind)
}
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getInitialization() and
result = this.getFirstConditionInstruction()
result = this.getFirstConditionInstruction(kind)
or
(
child = this.getBody() and
if this.hasUpdate()
then result = this.getUpdate().getFirstInstruction()
else result = this.getFirstConditionInstruction()
then result = this.getUpdate().getFirstInstruction(kind)
else result = this.getFirstConditionInstruction(kind)
)
or
child = this.getUpdate() and result = this.getFirstConditionInstruction()
child = this.getUpdate() and result = this.getFirstConditionInstruction(kind)
}
}
@@ -888,25 +908,25 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
id = 5 and result = this.getBody()
}
override Instruction getFirstInstruction() {
result = this.getRangeVariableDeclStmt().getFirstInstruction()
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getRangeVariableDeclStmt().getFirstInstruction(kind)
}
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getRangeVariableDeclStmt() and
result = this.getBeginEndVariableDeclStmt().getFirstInstruction()
result = this.getBeginEndVariableDeclStmt().getFirstInstruction(kind)
or
child = this.getBeginEndVariableDeclStmt() and
result = this.getCondition().getFirstInstruction()
result = this.getCondition().getFirstInstruction(kind)
or
child = this.getVariableDeclStmt() and
result = this.getBody().getFirstInstruction()
result = this.getBody().getFirstInstruction(kind)
or
child = this.getBody() and
result = this.getUpdate().getFirstInstruction()
result = this.getUpdate().getFirstInstruction(kind)
or
child = this.getUpdate() and
result = this.getCondition().getFirstInstruction()
result = this.getCondition().getFirstInstruction(kind)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -915,12 +935,14 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
child = this.getCondition() and result = this.getVariableDeclStmt().getFirstInstruction()
override Instruction getChildTrueSuccessor(TranslatedCondition child, EdgeKind kind) {
child = this.getCondition() and
result = this.getVariableDeclStmt().getFirstInstruction(kind)
}
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
child = this.getCondition() and result = this.getParent().getChildSuccessor(this)
override Instruction getChildFalseSuccessor(TranslatedCondition child, EdgeKind kind) {
child = this.getCondition() and
result = this.getParent().getChildSuccessor(this, kind)
}
private TranslatedDeclStmt getRangeVariableDeclStmt() {
@@ -960,7 +982,10 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
class TranslatedJumpStmt extends TranslatedStmt {
override JumpStmt stmt;
override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) }
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(OnlyInstructionTag()) and
kind instanceof GotoEdge
}
override TranslatedElement getChild(int id) { none() }
@@ -972,11 +997,10 @@ class TranslatedJumpStmt extends TranslatedStmt {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
kind instanceof GotoEdge and
result = getTranslatedStmt(stmt.getTarget()).getFirstInstruction()
result = getTranslatedStmt(stmt.getTarget()).getFirstInstruction(kind)
}
override Instruction getChildSuccessor(TranslatedElement child) { none() }
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) { none() }
}
private EdgeKind getCaseEdge(SwitchCase switchCase) {
@@ -995,14 +1019,16 @@ class TranslatedSwitchStmt extends TranslatedStmt {
result = getTranslatedExpr(stmt.getExpr().getFullyConverted())
}
private Instruction getFirstExprInstruction() { result = this.getExpr().getFirstInstruction() }
private Instruction getFirstExprInstruction(EdgeKind kind) {
result = this.getExpr().getFirstInstruction(kind)
}
private TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getStmt()) }
override Instruction getFirstInstruction() {
override Instruction getFirstInstruction(EdgeKind kind) {
if this.hasInitialization()
then result = this.getInitialization().getFirstInstruction()
else result = this.getFirstExprInstruction()
then result = this.getInitialization().getFirstInstruction(kind)
else result = this.getFirstExprInstruction(kind)
}
override TranslatedElement getChild(int id) {
@@ -1036,21 +1062,24 @@ class TranslatedSwitchStmt extends TranslatedStmt {
exists(SwitchCase switchCase |
switchCase = stmt.getASwitchCase() and
kind = getCaseEdge(switchCase) and
result = getTranslatedStmt(switchCase).getFirstInstruction()
result = getTranslatedStmt(switchCase).getFirstInstruction(any(GotoEdge edge))
)
or
not stmt.hasDefaultCase() and
tag = SwitchBranchTag() and
kind instanceof DefaultEdge and
result = this.getParent().getChildSuccessor(this)
result = this.getParent().getChildSuccessor(this, any(GotoEdge edge))
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getInitialization() and result = this.getFirstExprInstruction()
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getInitialization() and
result = this.getFirstExprInstruction(kind)
or
child = this.getExpr() and result = this.getInstruction(SwitchBranchTag())
kind instanceof GotoEdge and
child = this.getExpr() and
result = this.getInstruction(SwitchBranchTag())
or
child = this.getBody() and result = this.getParent().getChildSuccessor(this)
child = this.getBody() and result = this.getParent().getChildSuccessor(this, kind)
}
}
@@ -1061,10 +1090,12 @@ class TranslatedAsmStmt extends TranslatedStmt {
result = getTranslatedExpr(stmt.getChild(id).(Expr).getFullyConverted())
}
override Instruction getFirstInstruction() {
override Instruction getFirstInstruction(EdgeKind kind) {
if exists(this.getChild(0))
then result = this.getChild(0).getFirstInstruction()
else result = this.getInstruction(AsmTag())
then result = this.getChild(0).getFirstInstruction(kind)
else (
kind instanceof GotoEdge and result = this.getInstruction(AsmTag())
)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -1091,16 +1122,17 @@ class TranslatedAsmStmt extends TranslatedStmt {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = AsmTag() and
result = this.getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
result = this.getParent().getChildSuccessor(this, kind)
}
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
exists(int index |
child = this.getChild(index) and
if exists(this.getChild(index + 1))
then result = this.getChild(index + 1).getFirstInstruction()
else result = this.getInstruction(AsmTag())
then result = this.getChild(index + 1).getFirstInstruction(kind)
else (
kind instanceof GotoEdge and result = this.getInstruction(AsmTag())
)
)
}
}
@@ -1113,7 +1145,9 @@ class TranslatedVlaDimensionStmt extends TranslatedStmt {
result = getTranslatedExpr(stmt.getDimensionExpr().getFullyConverted())
}
override Instruction getFirstInstruction() { result = this.getChild(0).getFirstInstruction() }
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getChild(0).getFirstInstruction(kind)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
none()
@@ -1121,9 +1155,9 @@ class TranslatedVlaDimensionStmt extends TranslatedStmt {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getChildSuccessor(TranslatedElement child) {
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) {
child = this.getChild(0) and
result = this.getParent().getChildSuccessor(this)
result = this.getParent().getChildSuccessor(this, kind)
}
}
@@ -1132,7 +1166,10 @@ class TranslatedVlaDeclarationStmt extends TranslatedStmt {
override TranslatedExpr getChild(int id) { none() }
override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) }
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(OnlyInstructionTag()) and
kind instanceof GotoEdge
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
// TODO: This needs a new kind of instruction that represents initialization of a VLA.
@@ -1144,9 +1181,8 @@ class TranslatedVlaDeclarationStmt extends TranslatedStmt {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
result = this.getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
result = this.getParent().getChildSuccessor(this, kind)
}
override Instruction getChildSuccessor(TranslatedElement child) { none() }
override Instruction getChildSuccessor(TranslatedElement child, EdgeKind kind) { none() }
}

View File

@@ -39,3 +39,4 @@ private import implementations.ODBC
private import implementations.SqLite3
private import implementations.PostgreSql
private import implementations.System
private import implementations.StructuredExceptionHandling

View File

@@ -0,0 +1,9 @@
import semmle.code.cpp.models.interfaces.Throwing
class WindowsDriverFunction extends ThrowingFunction {
WindowsDriverFunction() {
this.hasGlobalName(["RaiseException", "ExRaiseAccessViolation", "ExRaiseDatatypeMisalignment"])
}
final override predicate mayThrowException(boolean unconditional) { unconditional = true }
}

View File

@@ -0,0 +1,22 @@
/**
* Provides an abstract class for modeling whether a function may throw an
* exception.
* To use this QL library, create a QL class extending `ThrowingFunction` with
* a characteristic predicate that selects the function or set of functions you
* are modeling the exceptional flow of.
*/
import semmle.code.cpp.Function
import semmle.code.cpp.models.Models
import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
/**
* A class that models the exceptional behavior of a function.
*/
abstract class ThrowingFunction extends Function {
/**
* Holds if this function may throw an exception during evaluation.
* If `unconditional` is `true` the function always throws an exception.
*/
abstract predicate mayThrowException(boolean unconditional);
}

View File

@@ -56,6 +56,8 @@ VariableAccess commonException() {
// Finally, exclude functions that contain assembly blocks. It's
// anyone's guess what happens in those.
containsInlineAssembly(result.getEnclosingFunction())
or
exists(Call c | c.getQualifier() = result | c.getTarget().isStatic())
}
predicate isSinkImpl(Instruction sink, VariableAccess va) {

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* The "Potentially uninitialized local variable" query (`cpp/uninitialized-local`) no longer reports an alert when the local variable is used as a qualifier to a static member function call.
* ```

View File

@@ -1815,6 +1815,42 @@ ir.c:
# 15| Type = [CharPointerType] char *
# 15| ValueCategory = prvalue
# 16| getStmt(1): [ReturnStmt] return ...
# 18| [TopLevelFunction] void ExRaiseAccessViolation(int)
# 18| <params>:
# 18| getParameter(0): [Parameter] (unnamed parameter 0)
# 18| Type = [IntType] int
# 21| [TopLevelFunction] int TryExceptTest(int)
# 21| <params>:
# 21| getParameter(0): [Parameter] x
# 21| Type = [IntType] int
# 21| getEntryPoint(): [BlockStmt] { ... }
# 22| getStmt(0): [DeclStmt] declaration
# 22| getDeclarationEntry(0): [VariableDeclarationEntry] definition of localPtr
# 22| Type = [IntPointerType] int *
# 24| getStmt(1): [MicrosoftTryExceptStmt] __try { ... } __except( ... ) { ... }
# 24| getStmt(): [BlockStmt] { ... }
# 25| getStmt(0): [ExprStmt] ExprStmt
# 25| getExpr(): [FunctionCall] call to ExRaiseAccessViolation
# 25| Type = [VoidType] void
# 25| ValueCategory = prvalue
# 25| getArgument(0): [VariableAccess] x
# 25| Type = [IntType] int
# 25| ValueCategory = prvalue(load)
# 26| getCondition(): [Literal] 1
# 26| Type = [IntType] int
# 26| Value = [Literal] 1
# 26| ValueCategory = prvalue
# 26| getExcept(): [BlockStmt] { ... }
# 27| getStmt(0): [ReturnStmt] return ...
# 27| getExpr(): [Literal] 1
# 27| Type = [IntType] int
# 27| Value = [Literal] 1
# 27| ValueCategory = prvalue
# 29| getStmt(2): [ReturnStmt] return ...
# 29| getExpr(): [Literal] 0
# 29| Type = [IntType] int
# 29| Value = [Literal] 0
# 29| ValueCategory = prvalue
ir.cpp:
# 1| [TopLevelFunction] void Constants()
# 1| <params>:

View File

@@ -809,6 +809,58 @@ ir.c:
# 13| v13_11(void) = AliasedUse : m13_3
# 13| v13_12(void) = ExitFunction :
# 21| int TryExceptTest(int)
# 21| Block 0
# 21| v21_1(void) = EnterFunction :
# 21| m21_2(unknown) = AliasedDefinition :
# 21| m21_3(unknown) = InitializeNonLocal :
# 21| m21_4(unknown) = Chi : total:m21_2, partial:m21_3
# 21| r21_5(glval<int>) = VariableAddress[x] :
# 21| m21_6(int) = InitializeParameter[x] : &:r21_5
# 22| r22_1(glval<int *>) = VariableAddress[localPtr] :
# 22| m22_2(int *) = Uninitialized[localPtr] : &:r22_1
# 25| r25_1(glval<unknown>) = FunctionAddress[ExRaiseAccessViolation] :
# 25| r25_2(glval<int>) = VariableAddress[x] :
# 25| r25_3(int) = Load[x] : &:r25_2, m21_6
# 25| v25_4(void) = Call[ExRaiseAccessViolation] : func:r25_1, 0:r25_3
# 25| m25_5(unknown) = ^CallSideEffect : ~m21_4
# 25| m25_6(unknown) = Chi : total:m21_4, partial:m25_5
#-----| Exception -> Block 3
# 26| Block 1
# 26| r26_1(int) = Constant[0] :
# 26| r26_2(bool) = CompareEQ : r26_7, r26_1
# 26| v26_3(void) = ConditionalBranch : r26_2
#-----| False -> Block 2
#-----| True -> Block 5
# 26| Block 2
# 26| r26_4(int) = Constant[1] :
# 26| r26_5(bool) = CompareEQ : r26_7, r26_4
# 26| v26_6(void) = ConditionalBranch : r26_5
#-----| False -> Block 5
#-----| True -> Block 4
# 26| Block 3
# 26| r26_7(int) = Constant[1] :
# 26| r26_8(int) = Constant[-1] :
# 26| r26_9(bool) = CompareEQ : r26_7, r26_8
# 26| v26_10(void) = ConditionalBranch : r26_9
#-----| False -> Block 1
#-----| True -> Block 5
# 27| Block 4
# 27| r27_1(glval<int>) = VariableAddress[#return] :
# 27| r27_2(int) = Constant[1] :
# 27| m27_3(int) = Store[#return] : &:r27_1, r27_2
# 21| r21_7(glval<int>) = VariableAddress[#return] :
# 21| v21_8(void) = ReturnValue : &:r21_7, m27_3
# 21| v21_9(void) = AliasedUse : ~m25_6
# 21| v21_10(void) = ExitFunction :
# 21| Block 5
# 21| v21_11(void) = Unreached :
ir.cpp:
# 1| void Constants()
# 1| Block 0

View File

@@ -15,4 +15,18 @@ void CStyleCast(void *src)
char *dst = (char*)src;
}
void ExRaiseAccessViolation(int);
#define EXCEPTION_EXECUTE_HANDLER 1
int TryExceptTest(int x) {
int *localPtr;
__try {
ExRaiseAccessViolation(x);
} __except(EXCEPTION_EXECUTE_HANDLER) {
return 1;
}
return 0;
}
// semmle-extractor-options: --microsoft

View File

@@ -1005,6 +1005,31 @@
| ir.c:15:24:15:26 | Address | &:r15_2 |
| ir.c:15:24:15:26 | Load | m13_6 |
| ir.c:15:24:15:26 | Unary | r15_3 |
| ir.c:21:5:21:17 | Address | &:r21_7 |
| ir.c:21:5:21:17 | ChiPartial | partial:m21_3 |
| ir.c:21:5:21:17 | ChiTotal | total:m21_2 |
| ir.c:21:5:21:17 | Load | m27_3 |
| ir.c:21:5:21:17 | SideEffect | ~m25_6 |
| ir.c:21:23:21:23 | Address | &:r21_5 |
| ir.c:22:8:22:15 | Address | &:r22_1 |
| ir.c:25:5:25:26 | CallTarget | func:r25_1 |
| ir.c:25:5:25:26 | ChiPartial | partial:m25_5 |
| ir.c:25:5:25:26 | ChiTotal | total:m21_4 |
| ir.c:25:5:25:26 | SideEffect | ~m21_4 |
| ir.c:25:28:25:28 | Address | &:r25_2 |
| ir.c:25:28:25:28 | Arg(0) | 0:r25_3 |
| ir.c:25:28:25:28 | Load | m21_6 |
| ir.c:26:14:26:38 | Left | r26_7 |
| ir.c:26:14:26:38 | Left | r26_7 |
| ir.c:26:14:26:38 | Left | r26_7 |
| ir.c:26:41:28:3 | Condition | r26_2 |
| ir.c:26:41:28:3 | Condition | r26_5 |
| ir.c:26:41:28:3 | Condition | r26_9 |
| ir.c:26:41:28:3 | Right | r26_1 |
| ir.c:26:41:28:3 | Right | r26_4 |
| ir.c:26:41:28:3 | Right | r26_8 |
| ir.c:27:5:27:13 | Address | &:r27_1 |
| ir.c:27:12:27:12 | StoreValue | r27_2 |
| ir.cpp:1:6:1:14 | ChiPartial | partial:m1_3 |
| ir.cpp:1:6:1:14 | ChiTotal | total:m1_2 |
| ir.cpp:1:6:1:14 | SideEffect | m1_3 |

View File

@@ -786,6 +786,62 @@ ir.c:
# 13| v13_10(void) = AliasedUse : ~m?
# 13| v13_11(void) = ExitFunction :
# 21| int TryExceptTest(int)
# 21| Block 0
# 21| v21_1(void) = EnterFunction :
# 21| mu21_2(unknown) = AliasedDefinition :
# 21| mu21_3(unknown) = InitializeNonLocal :
# 21| r21_4(glval<int>) = VariableAddress[x] :
# 21| mu21_5(int) = InitializeParameter[x] : &:r21_4
# 22| r22_1(glval<int *>) = VariableAddress[localPtr] :
# 22| mu22_2(int *) = Uninitialized[localPtr] : &:r22_1
# 25| r25_1(glval<unknown>) = FunctionAddress[ExRaiseAccessViolation] :
# 25| r25_2(glval<int>) = VariableAddress[x] :
# 25| r25_3(int) = Load[x] : &:r25_2, ~m?
# 25| v25_4(void) = Call[ExRaiseAccessViolation] : func:r25_1, 0:r25_3
# 25| mu25_5(unknown) = ^CallSideEffect : ~m?
#-----| Exception -> Block 5
# 21| Block 1
# 21| r21_6(glval<int>) = VariableAddress[#return] :
# 21| v21_7(void) = ReturnValue : &:r21_6, ~m?
# 21| v21_8(void) = AliasedUse : ~m?
# 21| v21_9(void) = ExitFunction :
# 26| Block 2
# 26| r26_1(int) = Constant[0] :
# 26| r26_2(bool) = CompareEQ : r26_8, r26_1
# 26| v26_3(void) = ConditionalBranch : r26_2
#-----| False -> Block 3
#-----| True -> Block 4
# 26| Block 3
# 26| r26_4(int) = Constant[1] :
# 26| r26_5(bool) = CompareEQ : r26_8, r26_4
# 26| v26_6(void) = ConditionalBranch : r26_5
#-----| True -> Block 6
# 26| Block 4
# 26| v26_7(void) = Unwind :
# 29| r29_1(glval<int>) = VariableAddress[#return] :
# 29| r29_2(int) = Constant[0] :
# 29| mu29_3(int) = Store[#return] : &:r29_1, r29_2
#-----| Goto -> Block 1
# 26| Block 5
# 26| r26_8(int) = Constant[1] :
# 26| r26_9(int) = Constant[-1] :
# 26| r26_10(bool) = CompareEQ : r26_8, r26_9
# 26| v26_11(void) = ConditionalBranch : r26_10
#-----| False -> Block 2
#-----| True -> Block 4
# 27| Block 6
# 27| r27_1(glval<int>) = VariableAddress[#return] :
# 27| r27_2(int) = Constant[1] :
# 27| mu27_3(int) = Store[#return] : &:r27_1, r27_2
#-----| Goto -> Block 1
ir.cpp:
# 1| void Constants()
# 1| Block 0

View File

@@ -532,4 +532,16 @@ int non_exhaustive_switch_2(State s) {
return y; // GOOD (y is not initialized when s = StateC, but if s = StateC we won't reach this point)
}
return 0;
}
class StaticMethodClass{
public:
static int get(){
return 1;
}
};
int static_method_false_positive(){
StaticMethodClass *t;
int i = t->get(); // GOOD: the `get` method is static and this is equivalent to StaticMethodClass::get()
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
description: Remove `compilation_expanded_args`.
compatibility: backwards
compilation_expanded_args.rel: delete

View File

@@ -39,7 +39,33 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.compilation_assembly(this, assembly);
// Arguments
Compilation.Settings.Args.ForEach((arg, index) => trapFile.compilation_args(this, index, arg));
var expandedIndex = 0;
for (var i = 0; i < Compilation.Settings.Args.Length; i++)
{
var arg = Compilation.Settings.Args[i];
trapFile.compilation_args(this, i, arg);
if (CommandLineExtensions.IsFileArgument(arg))
{
try
{
var rspFileContent = System.IO.File.ReadAllText(arg[1..]);
var rspArgs = CommandLineParser.SplitCommandLineIntoArguments(rspFileContent, removeHashComments: true);
foreach (var rspArg in rspArgs)
{
trapFile.compilation_expanded_args(this, expandedIndex++, rspArg);
}
}
catch (Exception exc)
{
Context.ExtractionError($"Couldn't read compiler argument file: {arg}. {exc.Message}", null, null, exc.StackTrace);
}
}
else
{
trapFile.compilation_expanded_args(this, expandedIndex++, arg);
}
}
// Files
Context.Compilation.SyntaxTrees.Select(tree => File.Create(Context, tree.FilePath)).ForEach((file, index) => trapFile.compilation_compiling_files(this, index, file));

View File

@@ -67,8 +67,8 @@ namespace Semmle.Extraction.CSharp
bool argsWritten;
using (var streamWriter = new StreamWriter(new FileStream(tempFile, FileMode.Append, FileAccess.Write)))
{
streamWriter.WriteLine($"# Arguments to Roslyn: {string.Join(' ', roslynArgs.Where(arg => !arg.StartsWith('@')))}");
argsWritten = roslynArgs.WriteCommandLine(streamWriter);
streamWriter.WriteLine($"# Arguments to Roslyn: {string.Join(' ', roslynArgs.Where(arg => !CommandLineExtensions.IsFileArgument(arg)))}");
argsWritten = streamWriter.WriteContentFromArgumentFile(roslynArgs);
}
var hash = FileUtils.ComputeFileHash(tempFile);

View File

@@ -68,6 +68,9 @@ namespace Semmle.Extraction.CSharp
internal static void compilation_args(this TextWriter trapFile, Compilation compilation, int index, string arg) =>
trapFile.WriteTuple("compilation_args", compilation, index, arg);
internal static void compilation_expanded_args(this TextWriter trapFile, Compilation compilation, int index, string arg) =>
trapFile.WriteTuple("compilation_expanded_args", compilation, index, arg);
internal static void compilation_compiling_files(this TextWriter trapFile, Compilation compilation, int index, Extraction.Entities.File file) =>
trapFile.WriteTuple("compilation_compiling_files", compilation, index, file);

View File

@@ -210,7 +210,7 @@ namespace Semmle.Extraction.Tests
try
{
File.AppendAllText(file, "Test");
new string[] { "/noconfig", "@" + file }.WriteCommandLine(sw);
sw.WriteContentFromArgumentFile(new string[] { "/noconfig", "@" + file });
Assert.Equal("Test", Regex.Replace(sw.ToString(), @"\t|\n|\r", ""));
}
finally

View File

@@ -6,22 +6,25 @@ namespace Semmle.Util
{
public static class CommandLineExtensions
{
public static bool IsFileArgument(string arg) => arg.StartsWith('@');
/// <summary>
/// Archives the first "@" argument in a list of command line arguments.
/// Subsequent "@" arguments are ignored.
/// Archives the content of all the "@" arguments in a list of command line arguments.
/// </summary>
/// <param name="commandLineArguments">The raw command line arguments.</param>
/// <param name="textWriter">The writer to archive to.</param>
/// <param name="commandLineArguments">The raw command line arguments.</param>
/// <returns>True iff the file was written.</returns>
public static bool WriteCommandLine(this IEnumerable<string> commandLineArguments, TextWriter textWriter)
public static bool WriteContentFromArgumentFile(this TextWriter textWriter, IEnumerable<string> commandLineArguments)
{
var found = false;
foreach (var arg in commandLineArguments.Where(arg => arg.StartsWith('@')).Select(arg => arg.Substring(1)))
foreach (var arg in commandLineArguments.Where(IsFileArgument).Select(arg => arg[1..]))
{
string? line;
using var file = new StreamReader(arg);
while ((line = file.ReadLine()) is not null)
{
textWriter.WriteLine(line);
}
found = true;
}
return found;

View File

@@ -0,0 +1,187 @@
| 0 | /noconfig |
| 1 | /unsafe- |
| 2 | /checked- |
| 4 | /fullpaths |
| 5 | /nostdlib+ |
| 9 | /highentropyva+ |
| 11 | /reference:[...]/8.0.0/ref/net8.0/Microsoft.CSharp.dll |
| 12 | /reference:[...]/8.0.0/ref/net8.0/Microsoft.VisualBasic.Core.dll |
| 13 | /reference:[...]/8.0.0/ref/net8.0/Microsoft.VisualBasic.dll |
| 14 | /reference:[...]/8.0.0/ref/net8.0/Microsoft.Win32.Primitives.dll |
| 15 | /reference:[...]/8.0.0/ref/net8.0/Microsoft.Win32.Registry.dll |
| 16 | /reference:[...]/8.0.0/ref/net8.0/mscorlib.dll |
| 17 | /reference:[...]/8.0.0/ref/net8.0/netstandard.dll |
| 18 | /reference:[...]/8.0.0/ref/net8.0/System.AppContext.dll |
| 19 | /reference:[...]/8.0.0/ref/net8.0/System.Buffers.dll |
| 20 | /reference:[...]/8.0.0/ref/net8.0/System.Collections.Concurrent.dll |
| 21 | /reference:[...]/8.0.0/ref/net8.0/System.Collections.dll |
| 22 | /reference:[...]/8.0.0/ref/net8.0/System.Collections.Immutable.dll |
| 23 | /reference:[...]/8.0.0/ref/net8.0/System.Collections.NonGeneric.dll |
| 24 | /reference:[...]/8.0.0/ref/net8.0/System.Collections.Specialized.dll |
| 25 | /reference:[...]/8.0.0/ref/net8.0/System.ComponentModel.Annotations.dll |
| 26 | /reference:[...]/8.0.0/ref/net8.0/System.ComponentModel.DataAnnotations.dll |
| 27 | /reference:[...]/8.0.0/ref/net8.0/System.ComponentModel.dll |
| 28 | /reference:[...]/8.0.0/ref/net8.0/System.ComponentModel.EventBasedAsync.dll |
| 29 | /reference:[...]/8.0.0/ref/net8.0/System.ComponentModel.Primitives.dll |
| 30 | /reference:[...]/8.0.0/ref/net8.0/System.ComponentModel.TypeConverter.dll |
| 31 | /reference:[...]/8.0.0/ref/net8.0/System.Configuration.dll |
| 32 | /reference:[...]/8.0.0/ref/net8.0/System.Console.dll |
| 33 | /reference:[...]/8.0.0/ref/net8.0/System.Core.dll |
| 34 | /reference:[...]/8.0.0/ref/net8.0/System.Data.Common.dll |
| 35 | /reference:[...]/8.0.0/ref/net8.0/System.Data.DataSetExtensions.dll |
| 36 | /reference:[...]/8.0.0/ref/net8.0/System.Data.dll |
| 37 | /reference:[...]/8.0.0/ref/net8.0/System.Diagnostics.Contracts.dll |
| 38 | /reference:[...]/8.0.0/ref/net8.0/System.Diagnostics.Debug.dll |
| 39 | /reference:[...]/8.0.0/ref/net8.0/System.Diagnostics.DiagnosticSource.dll |
| 40 | /reference:[...]/8.0.0/ref/net8.0/System.Diagnostics.FileVersionInfo.dll |
| 41 | /reference:[...]/8.0.0/ref/net8.0/System.Diagnostics.Process.dll |
| 42 | /reference:[...]/8.0.0/ref/net8.0/System.Diagnostics.StackTrace.dll |
| 43 | /reference:[...]/8.0.0/ref/net8.0/System.Diagnostics.TextWriterTraceListener.dll |
| 44 | /reference:[...]/8.0.0/ref/net8.0/System.Diagnostics.Tools.dll |
| 45 | /reference:[...]/8.0.0/ref/net8.0/System.Diagnostics.TraceSource.dll |
| 46 | /reference:[...]/8.0.0/ref/net8.0/System.Diagnostics.Tracing.dll |
| 47 | /reference:[...]/8.0.0/ref/net8.0/System.dll |
| 48 | /reference:[...]/8.0.0/ref/net8.0/System.Drawing.dll |
| 49 | /reference:[...]/8.0.0/ref/net8.0/System.Drawing.Primitives.dll |
| 50 | /reference:[...]/8.0.0/ref/net8.0/System.Dynamic.Runtime.dll |
| 51 | /reference:[...]/8.0.0/ref/net8.0/System.Formats.Asn1.dll |
| 52 | /reference:[...]/8.0.0/ref/net8.0/System.Formats.Tar.dll |
| 53 | /reference:[...]/8.0.0/ref/net8.0/System.Globalization.Calendars.dll |
| 54 | /reference:[...]/8.0.0/ref/net8.0/System.Globalization.dll |
| 55 | /reference:[...]/8.0.0/ref/net8.0/System.Globalization.Extensions.dll |
| 56 | /reference:[...]/8.0.0/ref/net8.0/System.IO.Compression.Brotli.dll |
| 57 | /reference:[...]/8.0.0/ref/net8.0/System.IO.Compression.dll |
| 58 | /reference:[...]/8.0.0/ref/net8.0/System.IO.Compression.FileSystem.dll |
| 59 | /reference:[...]/8.0.0/ref/net8.0/System.IO.Compression.ZipFile.dll |
| 60 | /reference:[...]/8.0.0/ref/net8.0/System.IO.dll |
| 61 | /reference:[...]/8.0.0/ref/net8.0/System.IO.FileSystem.AccessControl.dll |
| 62 | /reference:[...]/8.0.0/ref/net8.0/System.IO.FileSystem.dll |
| 63 | /reference:[...]/8.0.0/ref/net8.0/System.IO.FileSystem.DriveInfo.dll |
| 64 | /reference:[...]/8.0.0/ref/net8.0/System.IO.FileSystem.Primitives.dll |
| 65 | /reference:[...]/8.0.0/ref/net8.0/System.IO.FileSystem.Watcher.dll |
| 66 | /reference:[...]/8.0.0/ref/net8.0/System.IO.IsolatedStorage.dll |
| 67 | /reference:[...]/8.0.0/ref/net8.0/System.IO.MemoryMappedFiles.dll |
| 68 | /reference:[...]/8.0.0/ref/net8.0/System.IO.Pipes.AccessControl.dll |
| 69 | /reference:[...]/8.0.0/ref/net8.0/System.IO.Pipes.dll |
| 70 | /reference:[...]/8.0.0/ref/net8.0/System.IO.UnmanagedMemoryStream.dll |
| 71 | /reference:[...]/8.0.0/ref/net8.0/System.Linq.dll |
| 72 | /reference:[...]/8.0.0/ref/net8.0/System.Linq.Expressions.dll |
| 73 | /reference:[...]/8.0.0/ref/net8.0/System.Linq.Parallel.dll |
| 74 | /reference:[...]/8.0.0/ref/net8.0/System.Linq.Queryable.dll |
| 75 | /reference:[...]/8.0.0/ref/net8.0/System.Memory.dll |
| 76 | /reference:[...]/8.0.0/ref/net8.0/System.Net.dll |
| 77 | /reference:[...]/8.0.0/ref/net8.0/System.Net.Http.dll |
| 78 | /reference:[...]/8.0.0/ref/net8.0/System.Net.Http.Json.dll |
| 79 | /reference:[...]/8.0.0/ref/net8.0/System.Net.HttpListener.dll |
| 80 | /reference:[...]/8.0.0/ref/net8.0/System.Net.Mail.dll |
| 81 | /reference:[...]/8.0.0/ref/net8.0/System.Net.NameResolution.dll |
| 82 | /reference:[...]/8.0.0/ref/net8.0/System.Net.NetworkInformation.dll |
| 83 | /reference:[...]/8.0.0/ref/net8.0/System.Net.Ping.dll |
| 84 | /reference:[...]/8.0.0/ref/net8.0/System.Net.Primitives.dll |
| 85 | /reference:[...]/8.0.0/ref/net8.0/System.Net.Quic.dll |
| 86 | /reference:[...]/8.0.0/ref/net8.0/System.Net.Requests.dll |
| 87 | /reference:[...]/8.0.0/ref/net8.0/System.Net.Security.dll |
| 88 | /reference:[...]/8.0.0/ref/net8.0/System.Net.ServicePoint.dll |
| 89 | /reference:[...]/8.0.0/ref/net8.0/System.Net.Sockets.dll |
| 90 | /reference:[...]/8.0.0/ref/net8.0/System.Net.WebClient.dll |
| 91 | /reference:[...]/8.0.0/ref/net8.0/System.Net.WebHeaderCollection.dll |
| 92 | /reference:[...]/8.0.0/ref/net8.0/System.Net.WebProxy.dll |
| 93 | /reference:[...]/8.0.0/ref/net8.0/System.Net.WebSockets.Client.dll |
| 94 | /reference:[...]/8.0.0/ref/net8.0/System.Net.WebSockets.dll |
| 95 | /reference:[...]/8.0.0/ref/net8.0/System.Numerics.dll |
| 96 | /reference:[...]/8.0.0/ref/net8.0/System.Numerics.Vectors.dll |
| 97 | /reference:[...]/8.0.0/ref/net8.0/System.ObjectModel.dll |
| 98 | /reference:[...]/8.0.0/ref/net8.0/System.Reflection.DispatchProxy.dll |
| 99 | /reference:[...]/8.0.0/ref/net8.0/System.Reflection.dll |
| 100 | /reference:[...]/8.0.0/ref/net8.0/System.Reflection.Emit.dll |
| 101 | /reference:[...]/8.0.0/ref/net8.0/System.Reflection.Emit.ILGeneration.dll |
| 102 | /reference:[...]/8.0.0/ref/net8.0/System.Reflection.Emit.Lightweight.dll |
| 103 | /reference:[...]/8.0.0/ref/net8.0/System.Reflection.Extensions.dll |
| 104 | /reference:[...]/8.0.0/ref/net8.0/System.Reflection.Metadata.dll |
| 105 | /reference:[...]/8.0.0/ref/net8.0/System.Reflection.Primitives.dll |
| 106 | /reference:[...]/8.0.0/ref/net8.0/System.Reflection.TypeExtensions.dll |
| 107 | /reference:[...]/8.0.0/ref/net8.0/System.Resources.Reader.dll |
| 108 | /reference:[...]/8.0.0/ref/net8.0/System.Resources.ResourceManager.dll |
| 109 | /reference:[...]/8.0.0/ref/net8.0/System.Resources.Writer.dll |
| 110 | /reference:[...]/8.0.0/ref/net8.0/System.Runtime.CompilerServices.Unsafe.dll |
| 111 | /reference:[...]/8.0.0/ref/net8.0/System.Runtime.CompilerServices.VisualC.dll |
| 112 | /reference:[...]/8.0.0/ref/net8.0/System.Runtime.dll |
| 113 | /reference:[...]/8.0.0/ref/net8.0/System.Runtime.Extensions.dll |
| 114 | /reference:[...]/8.0.0/ref/net8.0/System.Runtime.Handles.dll |
| 115 | /reference:[...]/8.0.0/ref/net8.0/System.Runtime.InteropServices.dll |
| 116 | /reference:[...]/8.0.0/ref/net8.0/System.Runtime.InteropServices.JavaScript.dll |
| 117 | /reference:[...]/8.0.0/ref/net8.0/System.Runtime.InteropServices.RuntimeInformation.dll |
| 118 | /reference:[...]/8.0.0/ref/net8.0/System.Runtime.Intrinsics.dll |
| 119 | /reference:[...]/8.0.0/ref/net8.0/System.Runtime.Loader.dll |
| 120 | /reference:[...]/8.0.0/ref/net8.0/System.Runtime.Numerics.dll |
| 121 | /reference:[...]/8.0.0/ref/net8.0/System.Runtime.Serialization.dll |
| 122 | /reference:[...]/8.0.0/ref/net8.0/System.Runtime.Serialization.Formatters.dll |
| 123 | /reference:[...]/8.0.0/ref/net8.0/System.Runtime.Serialization.Json.dll |
| 124 | /reference:[...]/8.0.0/ref/net8.0/System.Runtime.Serialization.Primitives.dll |
| 125 | /reference:[...]/8.0.0/ref/net8.0/System.Runtime.Serialization.Xml.dll |
| 126 | /reference:[...]/8.0.0/ref/net8.0/System.Security.AccessControl.dll |
| 127 | /reference:[...]/8.0.0/ref/net8.0/System.Security.Claims.dll |
| 128 | /reference:[...]/8.0.0/ref/net8.0/System.Security.Cryptography.Algorithms.dll |
| 129 | /reference:[...]/8.0.0/ref/net8.0/System.Security.Cryptography.Cng.dll |
| 130 | /reference:[...]/8.0.0/ref/net8.0/System.Security.Cryptography.Csp.dll |
| 131 | /reference:[...]/8.0.0/ref/net8.0/System.Security.Cryptography.dll |
| 132 | /reference:[...]/8.0.0/ref/net8.0/System.Security.Cryptography.Encoding.dll |
| 133 | /reference:[...]/8.0.0/ref/net8.0/System.Security.Cryptography.OpenSsl.dll |
| 134 | /reference:[...]/8.0.0/ref/net8.0/System.Security.Cryptography.Primitives.dll |
| 135 | /reference:[...]/8.0.0/ref/net8.0/System.Security.Cryptography.X509Certificates.dll |
| 136 | /reference:[...]/8.0.0/ref/net8.0/System.Security.dll |
| 137 | /reference:[...]/8.0.0/ref/net8.0/System.Security.Principal.dll |
| 138 | /reference:[...]/8.0.0/ref/net8.0/System.Security.Principal.Windows.dll |
| 139 | /reference:[...]/8.0.0/ref/net8.0/System.Security.SecureString.dll |
| 140 | /reference:[...]/8.0.0/ref/net8.0/System.ServiceModel.Web.dll |
| 141 | /reference:[...]/8.0.0/ref/net8.0/System.ServiceProcess.dll |
| 142 | /reference:[...]/8.0.0/ref/net8.0/System.Text.Encoding.CodePages.dll |
| 143 | /reference:[...]/8.0.0/ref/net8.0/System.Text.Encoding.dll |
| 144 | /reference:[...]/8.0.0/ref/net8.0/System.Text.Encoding.Extensions.dll |
| 145 | /reference:[...]/8.0.0/ref/net8.0/System.Text.Encodings.Web.dll |
| 146 | /reference:[...]/8.0.0/ref/net8.0/System.Text.Json.dll |
| 147 | /reference:[...]/8.0.0/ref/net8.0/System.Text.RegularExpressions.dll |
| 148 | /reference:[...]/8.0.0/ref/net8.0/System.Threading.Channels.dll |
| 149 | /reference:[...]/8.0.0/ref/net8.0/System.Threading.dll |
| 150 | /reference:[...]/8.0.0/ref/net8.0/System.Threading.Overlapped.dll |
| 151 | /reference:[...]/8.0.0/ref/net8.0/System.Threading.Tasks.Dataflow.dll |
| 152 | /reference:[...]/8.0.0/ref/net8.0/System.Threading.Tasks.dll |
| 153 | /reference:[...]/8.0.0/ref/net8.0/System.Threading.Tasks.Extensions.dll |
| 154 | /reference:[...]/8.0.0/ref/net8.0/System.Threading.Tasks.Parallel.dll |
| 155 | /reference:[...]/8.0.0/ref/net8.0/System.Threading.Thread.dll |
| 156 | /reference:[...]/8.0.0/ref/net8.0/System.Threading.ThreadPool.dll |
| 157 | /reference:[...]/8.0.0/ref/net8.0/System.Threading.Timer.dll |
| 158 | /reference:[...]/8.0.0/ref/net8.0/System.Transactions.dll |
| 159 | /reference:[...]/8.0.0/ref/net8.0/System.Transactions.Local.dll |
| 160 | /reference:[...]/8.0.0/ref/net8.0/System.ValueTuple.dll |
| 161 | /reference:[...]/8.0.0/ref/net8.0/System.Web.dll |
| 162 | /reference:[...]/8.0.0/ref/net8.0/System.Web.HttpUtility.dll |
| 163 | /reference:[...]/8.0.0/ref/net8.0/System.Windows.dll |
| 164 | /reference:[...]/8.0.0/ref/net8.0/System.Xml.dll |
| 165 | /reference:[...]/8.0.0/ref/net8.0/System.Xml.Linq.dll |
| 166 | /reference:[...]/8.0.0/ref/net8.0/System.Xml.ReaderWriter.dll |
| 167 | /reference:[...]/8.0.0/ref/net8.0/System.Xml.Serialization.dll |
| 168 | /reference:[...]/8.0.0/ref/net8.0/System.Xml.XDocument.dll |
| 169 | /reference:[...]/8.0.0/ref/net8.0/System.Xml.XmlDocument.dll |
| 170 | /reference:[...]/8.0.0/ref/net8.0/System.Xml.XmlSerializer.dll |
| 171 | /reference:[...]/8.0.0/ref/net8.0/System.Xml.XPath.dll |
| 172 | /reference:[...]/8.0.0/ref/net8.0/System.Xml.XPath.XDocument.dll |
| 173 | /reference:[...]/8.0.0/ref/net8.0/WindowsBase.dll |
| 174 | /debug+ |
| 178 | /optimize- |
| 182 | /warnaserror- |
| 183 | /utf8output |
| 184 | /deterministic+ |
| 193 | /analyzerconfig:[...]/8.0.100/Sdks/Microsoft.NET.Sdk/analyzers/build/config/analysislevel_8_default.globalconfig |
| 194 | /analyzer:[...]/8.0.100/Sdks/Microsoft.NET.Sdk/targets/../analyzers/Microsoft.CodeAnalysis.CSharp.NetAnalyzers.dll |
| 195 | /analyzer:[...]/8.0.100/Sdks/Microsoft.NET.Sdk/targets/../analyzers/Microsoft.CodeAnalysis.NetAnalyzers.dll |
| 196 | /analyzer:[...]/8.0.0/analyzers/dotnet/cs/Microsoft.Interop.ComInterfaceGenerator.dll |
| 197 | /analyzer:[...]/8.0.0/analyzers/dotnet/cs/Microsoft.Interop.JavaScript.JSImportGenerator.dll |
| 198 | /analyzer:[...]/8.0.0/analyzers/dotnet/cs/Microsoft.Interop.LibraryImportGenerator.dll |
| 199 | /analyzer:[...]/8.0.0/analyzers/dotnet/cs/Microsoft.Interop.SourceGeneration.dll |
| 200 | /analyzer:[...]/8.0.0/analyzers/dotnet/cs/System.Text.Json.SourceGeneration.dll |
| 201 | /analyzer:[...]/8.0.0/analyzers/dotnet/cs/System.Text.RegularExpressions.Generator.dll |
| 202 | Program.cs |
| 203 | obj/Debug/net8.0/test.GlobalUsings.g.cs |
| 204 | obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs |
| 205 | obj/Debug/net8.0/test.AssemblyInfo.cs |

View File

@@ -0,0 +1,17 @@
import csharp
import semmle.code.csharp.commons.Compilation
bindingset[arg]
private string normalize(string arg) {
not exists(arg.indexOf(":")) and result = arg
or
exists(int i, int j |
i = arg.indexOf(":") and
j = arg.indexOf("/8.0") and
result = arg.substring(0, i + 1) + "[...]" + arg.substring(j, arg.length())
)
}
from Compilation c, int i, string s
where s = normalize(c.getExpandedArgument(i))
select i, s

View File

@@ -0,0 +1 @@
var dummy = "dummy";

View File

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

View File

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<Target Name="DeleteBinObjFolders" BeforeTargets="Clean">
<RemoveDir Directories=".\bin" />
<RemoveDir Directories=".\obj" />
</Target>
</Project>

View File

@@ -0,0 +1,3 @@
from create_database_utils import *
run_codeql_database_create([], lang="csharp", extra_args=["--extractor-option=cil=false"])

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* Added a new database relation to store compiler arguments specified inside `@[...].rsp` file arguments. The arguments
are returned by `Compilation::getExpandedArgument/1` and `Compilation::getExpandedArguments/0`.

View File

@@ -23,6 +23,22 @@ class Compilation extends @compilation {
result = concat(int i | exists(this.getArgument(i)) | this.getArgument(i), " ")
}
/**
* Gets the `i`th expanded command line argument. This is similar to
* `getArgument`, but for a `@someFile.rsp` argument, it includes the arguments
* from that file, rather than just taking the argument literally.
*/
string getExpandedArgument(int i) { compilation_expanded_args(this, i, result) }
/**
* Gets the expanded arguments as a concatenated string. This is similar to
* `getArguments`, but for a `@someFile.rsp` argument, it includes the arguments
* from that file, rather than just taking the argument literally.
*/
string getExpandedArguments() {
result = concat(int i | exists(this.getExpandedArgument(i)) | this.getExpandedArgument(i), " ")
}
/** Gets the 'i'th source file in this compilation. */
File getFileCompiled(int i) { compilation_compiling_files(this, i, result) }

View File

@@ -47,6 +47,19 @@ compilation_args(
string arg : string ref
);
/**
* The expanded arguments that were passed to the extractor for a
* compiler invocation. This is similar to `compilation_args`, but
* for a `@someFile.rsp` argument, it includes the arguments from that
* file, rather than just taking the argument literally.
*/
#keyset[id, num]
compilation_expanded_args(
int id : @compilation ref,
int num : int ref,
string arg : string ref
);
/**
* The source files that are compiled by a compiler invocation.
* If `id` is for the compiler invocation

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: Add `compilation_expanded_args`.
compatibility: backwards

View File

@@ -165,6 +165,15 @@ module AccessTargetStatsReport = ReportStats<AccessTargetStats>;
module ExprStatsReport = ReportStats<ExprStats>;
predicate analyzerAssemblies(string key, float value) {
exists(Compilation c, string arg |
c.getExpandedArgument(_) = arg and
arg.indexOf("/analyzer:") = 0 and
key = "CSC analyzer: " + arg.substring(10, arg.length())
) and
value = 1.0
}
from string key, float value
where
(
@@ -192,7 +201,8 @@ where
AccessTargetStatsReport::percentageOfOk(key, value) or
ExprStatsReport::numberOfOk(key, value) or
ExprStatsReport::numberOfNotOk(key, value) or
ExprStatsReport::percentageOfOk(key, value)
ExprStatsReport::percentageOfOk(key, value) or
analyzerAssemblies(key, value)
) and
/* Infinity */
value != 1.0 / 0.0 and

View File

@@ -0,0 +1 @@
Diagnostics/ExtractedFiles.ql

View File

@@ -1 +0,0 @@
Diagnostics/SuccessfullyExtractedFiles.ql

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added `html.escape` as a sanitizer for HTML.

View File

@@ -4830,6 +4830,35 @@ module StdlibPrivate {
override predicate isShellInterpreted(DataFlow::Node arg) { arg = this.getCommand() }
}
}
// ---------------------------------------------------------------------------
// html
// ---------------------------------------------------------------------------
/**
* A call to 'html.escape'.
* See https://docs.python.org/3/library/html.html#html.escape
*/
private class HtmlEscapeCall extends Escaping::Range, API::CallNode {
HtmlEscapeCall() {
this = API::moduleImport("html").getMember("escape").getACall() and
// if quote escaping is disabled, that might lead to XSS if the result is inserted
// in the attribute value of a tag, such as `<foo bar="escape_result">`. Since we
// don't know how values are being inserted, and we don't want to lose these
// results (FNs), we require quote escaping to be enabled. This might lead to some
// FPs, so we might need to revisit this in the future.
not this.getParameter(1, "quote")
.getAValueReachingSink()
.asExpr()
.(ImmutableLiteral)
.booleanValue() = false
}
override DataFlow::Node getAnInput() { result = this.getParameter(0, "s").asSink() }
override DataFlow::Node getOutput() { result = this }
override string getKind() { result = Escaping::getHtmlKind() }
}
}
// ---------------------------------------------------------------------------

View File

@@ -0,0 +1,9 @@
import html
s = "tainted"
html.escape(s) # $ escapeInput=s escapeKind=html escapeOutput=html.escape(..)
html.escape(s, True) # $ escapeInput=s escapeKind=html escapeOutput=html.escape(..)
# not considered html escapes, since they don't escape all relevant characters
html.escape(s, False)
html.escape(s, quote=False)

View File

@@ -0,0 +1 @@
Diagnostics/ExtractedFiles.ql

View File

@@ -1 +0,0 @@
Diagnostics/SuccessfullyExtractedFiles.ql

View File

@@ -58,7 +58,7 @@ class Call extends Expr instanceof CallImpl {
TCfgScope(result) = viableCallableLambda(c, _)
)
or
result = getTarget(this.getAControlFlowNode())
result = getTarget(TNormalCall(this.getAControlFlowNode()))
}
override AstNode getAChild(string pred) {

View File

@@ -70,7 +70,7 @@ deprecated class RequiredSummaryComponentStack = Impl::Private::RequiredSummaryC
*/
private module LibraryCallbackSummaries {
private predicate libraryCall(CfgNodes::ExprNodes::CallCfgNode call) {
not exists(getTarget(call))
not exists(getTarget(TNormalCall(call)))
}
private DataFlow::LocalSourceNode trackLambdaCreation(TypeTracker t) {

View File

@@ -87,18 +87,22 @@ abstract class LibraryCallable extends string {
* defined in library code.
*/
class DataFlowCallable extends TDataFlowCallable {
/** Gets the underlying source code callable, if any. */
Callable asCallable() { this = TCfgScope(result) }
/**
* Gets the underlying CFG scope, if any.
*
* This is usually a `Callable`, but can also be a `Toplevel` file.
*/
CfgScope asCfgScope() { this = TCfgScope(result) }
/** Gets the underlying library callable, if any. */
LibraryCallable asLibraryCallable() { this = TLibraryCallable(result) }
/** Gets a textual representation of this callable. */
string toString() { result = [this.asCallable().toString(), this.asLibraryCallable()] }
string toString() { result = [this.asCfgScope().toString(), this.asLibraryCallable()] }
/** Gets the location of this callable. */
Location getLocation() {
result = this.asCallable().getLocation()
result = this.asCfgScope().getLocation()
or
this instanceof TLibraryCallable and
result instanceof EmptyLocation
@@ -109,18 +113,18 @@ class DataFlowCallable extends TDataFlowCallable {
* A call. This includes calls from source code, as well as call(back)s
* inside library callables with a flow summary.
*/
class DataFlowCall extends TDataFlowCall {
abstract class DataFlowCall extends TDataFlowCall {
/** Gets the enclosing callable. */
DataFlowCallable getEnclosingCallable() { none() }
abstract DataFlowCallable getEnclosingCallable();
/** Gets the underlying source code call, if any. */
CfgNodes::ExprNodes::CallCfgNode asCall() { none() }
abstract CfgNodes::ExprNodes::CallCfgNode asCall();
/** Gets a textual representation of this call. */
string toString() { none() }
abstract string toString();
/** Gets the location of this call. */
Location getLocation() { none() }
abstract Location getLocation();
/**
* Holds if this element is at the specified location.
@@ -159,12 +163,14 @@ class SummaryCall extends DataFlowCall, TSummaryCall {
override DataFlowCallable getEnclosingCallable() { result.asLibraryCallable() = c }
override CfgNodes::ExprNodes::CallCfgNode asCall() { none() }
override string toString() { result = "[summary] call to " + receiver + " in " + c }
override EmptyLocation getLocation() { any() }
}
private class NormalCall extends DataFlowCall, TNormalCall {
class NormalCall extends DataFlowCall, TNormalCall {
private CfgNodes::ExprNodes::CallCfgNode c;
NormalCall() { this = TNormalCall(c) }
@@ -188,14 +194,17 @@ private class RelevantCall extends CfgNodes::ExprNodes::CallCfgNode {
}
pragma[nomagic]
private predicate methodCall(RelevantCall call, DataFlow::Node receiver, string method) {
method = call.getExpr().(MethodCall).getMethodName() and
receiver.asExpr() = call.getReceiver()
private predicate methodCall(DataFlowCall call, DataFlow::Node receiver, string method) {
call.asCall() =
any(RelevantCall rc |
method = rc.getExpr().(MethodCall).getMethodName() and
receiver.asExpr() = rc.getReceiver()
)
}
pragma[nomagic]
private predicate flowsToMethodCallReceiver(
RelevantCall call, DataFlow::LocalSourceNode sourceNode, string method
DataFlowCall call, DataFlow::LocalSourceNode sourceNode, string method
) {
exists(DataFlow::Node receiver |
methodCall(call, receiver, method) and
@@ -204,7 +213,7 @@ private predicate flowsToMethodCallReceiver(
}
pragma[nomagic]
private predicate moduleFlowsToMethodCallReceiver(RelevantCall call, Module m, string method) {
private predicate moduleFlowsToMethodCallReceiver(DataFlowCall call, Module m, string method) {
flowsToMethodCallReceiver(call, trackModuleAccess(m), method)
}
@@ -308,23 +317,23 @@ predicate isUserDefinedNew(SingletonMethod new) {
)
}
private Callable viableSourceCallableNonInit(RelevantCall call) {
result = getTargetInstance(call, _)
private DataFlowCallable viableSourceCallableNonInit(DataFlowCall call) {
result.asCfgScope() = getTargetInstance(call, _)
or
result = getTargetSingleton(call, _)
result.asCfgScope() = getTargetSingleton(call, _)
or
exists(Module cls, string method |
superCall(call, cls, method) and
result = lookupMethod(cls.getAnImmediateAncestor(), method)
superCall(call.asCall(), cls, method) and
result.asCfgScope() = lookupMethod(cls.getAnImmediateAncestor(), method)
)
}
private Callable viableSourceCallableInit(RelevantCall call) { result = getInitializeTarget(call) }
/** Holds if `call` may resolve to the returned source-code method. */
private Callable viableSourceCallable(RelevantCall call) {
private DataFlowCallable viableSourceCallable(DataFlowCall call) {
result = viableSourceCallableNonInit(call) or
result = viableSourceCallableInit(call)
result.asCfgScope() = viableSourceCallableInit(call.asCall())
}
/** Holds if `call` may resolve to the returned summarized library method. */
@@ -364,7 +373,7 @@ private predicate extendCallModule(Module m, Module n) {
* sub classes when `exact = false`.
*/
pragma[nomagic]
private Method lookupMethod(Module m, string name, boolean exact) {
private CfgScope lookupMethod(Module m, string name, boolean exact) {
result = lookupMethod(m, name) and
exact in [false, true]
or
@@ -405,16 +414,16 @@ private module Cached {
}
cached
CfgScope getTarget(RelevantCall call) {
result = viableSourceCallableNonInit(call)
CfgScope getTarget(DataFlowCall call) {
result = viableSourceCallableNonInit(call).asCfgScope()
or
result = blockCall(call)
result = blockCall(call.asCall())
}
/** Gets a viable run-time target for the call `call`. */
cached
DataFlowCallable viableCallable(DataFlowCall call) {
result.asCallable() = viableSourceCallable(call.asCall())
result = viableSourceCallable(call)
or
result = viableLibraryCallable(call)
}
@@ -477,9 +486,6 @@ private module Cached {
import Cached
pragma[nomagic]
private predicate isNotSelf(DataFlow::Node n) { not n instanceof SelfParameterNodeImpl }
private module TrackModuleInput implements CallGraphConstruction::Simple::InputSig {
class State = Module;
@@ -511,7 +517,7 @@ private predicate hasUserDefinedNew(Module m) {
pragma[nomagic]
private predicate isStandardNewCall(RelevantCall new, Module m, boolean exact) {
exists(DataFlow::LocalSourceNode sourceNode |
flowsToMethodCallReceiver(new, sourceNode, "new") and
flowsToMethodCallReceiver(TNormalCall(new), sourceNode, "new") and
// `m` should not have a user-defined `self.new` method
not hasUserDefinedNew(m)
|
@@ -657,10 +663,7 @@ private module TrackInstanceInput implements CallGraphConstruction::InputSig {
pragma[nomagic]
predicate stepNoCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
// We exclude steps into `self` parameters. For those, we instead rely on the type of
// the enclosing module
smallStepNoCall(nodeFrom, nodeTo, summary) and
isNotSelf(nodeTo)
smallStepNoCall(nodeFrom, nodeTo, summary)
or
// We exclude steps into type checked variables. For those, we instead rely on the
// type being checked against
@@ -692,7 +695,7 @@ private DataFlow::Node trackInstance(Module tp, boolean exact) {
}
pragma[nomagic]
private Method lookupInstanceMethodCall(RelevantCall call, string method, boolean exact) {
private CfgScope lookupInstanceMethodCall(DataFlowCall call, string method, boolean exact) {
exists(Module tp, DataFlow::Node receiver |
methodCall(call, pragma[only_bind_into](receiver), pragma[only_bind_into](method)) and
receiver = trackInstance(tp, exact) and
@@ -707,24 +710,25 @@ private predicate isToplevelMethodInFile(Method m, File f) {
}
pragma[nomagic]
private CfgScope getTargetInstance(RelevantCall call, string method) {
private CfgScope getTargetInstance(DataFlowCall call, string method) {
exists(boolean exact |
result = lookupInstanceMethodCall(call, method, exact) and
(
if result.(Method).isPrivate()
then
call.getReceiver().getExpr() instanceof SelfVariableAccess and
call.asCall().getReceiver().getExpr() instanceof SelfVariableAccess and
// For now, we restrict the scope of top-level declarations to their file.
// This may remove some plausible targets, but also removes a lot of
// implausible targets
(
isToplevelMethodInFile(result, call.getFile()) or
isToplevelMethodInFile(result, call.asCall().getFile()) or
not isToplevelMethodInFile(result, _)
)
else any()
) and
if result.(Method).isProtected()
then result = lookupMethod(call.getExpr().getEnclosingModule().getModule(), method, exact)
then
result = lookupMethod(call.asCall().getExpr().getEnclosingModule().getModule(), method, exact)
else any()
)
}
@@ -1006,7 +1010,7 @@ private DataFlow::Node trackSingletonMethodOnInstance(MethodBase method, string
/** Holds if a `self` access may be the receiver of `call` directly inside module `m`. */
pragma[nomagic]
private predicate selfInModuleFlowsToMethodCallReceiver(RelevantCall call, Module m, string method) {
private predicate selfInModuleFlowsToMethodCallReceiver(DataFlowCall call, Module m, string method) {
exists(SelfLocalSourceNode self |
flowsToMethodCallReceiver(call, self, method) and
selfInModule(self.getVariable(), m)
@@ -1019,7 +1023,7 @@ private predicate selfInModuleFlowsToMethodCallReceiver(RelevantCall call, Modul
*/
pragma[nomagic]
private predicate selfInSingletonMethodFlowsToMethodCallReceiver(
RelevantCall call, Module m, string method
DataFlowCall call, Module m, string method
) {
exists(SelfLocalSourceNode self, MethodBase caller |
flowsToMethodCallReceiver(call, self, method) and
@@ -1029,7 +1033,7 @@ private predicate selfInSingletonMethodFlowsToMethodCallReceiver(
}
pragma[nomagic]
private CfgScope getTargetSingleton(RelevantCall call, string method) {
private CfgScope getTargetSingleton(DataFlowCall call, string method) {
// singleton method defined on an instance, e.g.
// ```rb
// c = C.new
@@ -1089,41 +1093,60 @@ private CfgScope getTargetSingleton(RelevantCall call, string method) {
)
}
/**
* Holds if the parameter at position `pos` inside `encl` must flow to the receiver
* of `call`, which targets a method named `name`.
*/
pragma[nomagic]
private predicate paramMustFlowToReceiver(
ParameterPosition pos, DataFlowCall call, DataFlowCallable encl, string name
) {
exists(ParameterNodeImpl p |
// `p` is a parameter of `encl`,
p.isParameterOf(encl, pos) and
// the receiver of `call` references `p`
exists(DataFlow::Node receiver |
methodCall(pragma[only_bind_into](call), pragma[only_bind_into](receiver), name) and
LocalFlow::localMustFlowStep*(p, receiver)
)
)
}
pragma[nomagic]
private predicate mayBenefitFromCallContext(
DataFlowCall call, ParameterPosition pos, DataFlowCall ctx
) {
paramMustFlowToReceiver(pos, call, viableCallable(ctx), _)
}
/**
* Holds if the set of viable implementations that can be called by `call`
* might be improved by knowing the call context.
*/
predicate mayBenefitFromCallContext(DataFlowCall call) { mayBenefitFromCallContext(call, _, _) }
/**
* Holds if `ctx` targets the enclosing callable of `call`, the receiver of `call` is a
* parameter access, where the corresponding argument of `ctx` is `arg`.
* parameter access (at position `ppos`), where the corresponding argument of `ctx`
* is `arg`.
*
* `name` is the name of the method being called by `call`, `source` is a
* `LocalSourceNode` that flows to `arg`, and `paramDef` is the SSA definition for the
* parameter that is the receiver of `call`.
* `name` is the name of the method being called by `call` and `source` is a
* `LocalSourceNode` that flows to `arg`.
*/
pragma[nomagic]
private predicate argMustFlowToReceiver(
RelevantCall ctx, DataFlow::LocalSourceNode source, DataFlow::Node arg, RelevantCall call,
string name
RelevantCall ctx, DataFlow::LocalSourceNode source, DataFlow::Node arg, ParameterPosition ppos,
DataFlowCall call, string name
) {
exists(
ParameterNodeImpl p, SsaDefinitionExtNode paramDef, ParameterPosition ppos,
ArgumentPosition apos, Callable encl
|
// the receiver of `call` references `p`
exists(DataFlow::Node receiver |
LocalFlow::localFlowSsaParamInput(p, paramDef) and
methodCall(pragma[only_bind_into](call), pragma[only_bind_into](receiver),
pragma[only_bind_into](name)) and
receiver.asExpr() = paramDef.getDefinitionExt().(Ssa::Definition).getARead()
) and
// `p` is a parameter of `encl`,
encl = call.getScope() and
p.isParameterOf(TCfgScope(encl), ppos) and
// `arg` is the argument for `p` in the call `ctx`
exists(ArgumentPosition apos, DataFlowCallable encl |
paramMustFlowToReceiver(ppos, call, encl, name) and
parameterMatch(ppos, apos) and
source.flowsTo(arg)
|
encl = viableSourceCallableNonInit(ctx) and
encl = viableSourceCallableNonInit(TNormalCall(ctx)) and
arg.(ArgumentNode).sourceArgumentOf(ctx, apos)
or
encl = viableSourceCallableInit(ctx) and
encl.asCfgScope() = viableSourceCallableInit(ctx) and
if apos.isSelf()
then
// when we are targeting an initializer, the type of `self` inside the
@@ -1131,74 +1154,52 @@ private predicate argMustFlowToReceiver(
// of the `new` call
arg.asExpr() = ctx
else arg.(ArgumentNode).sourceArgumentOf(ctx, apos)
or
ctx.getAstNode() = encl.asLibraryCallable().getACallSimple() and
arg.(ArgumentNode).sourceArgumentOf(ctx, apos)
)
}
/**
* Holds if `ctx` targets the enclosing callable of `new`, and
* the receiver of `new` is a parameter access, where the corresponding argument
* `arg` of `ctx` has type `tp`.
*
* `new` calls the object creation `new` method.
*/
pragma[nomagic]
private predicate mayBenefitFromCallContextInitialize(
RelevantCall ctx, RelevantCall new, DataFlow::Node arg, Module tp, string name
) {
exists(DataFlow::LocalSourceNode source |
argMustFlowToReceiver(ctx, pragma[only_bind_into](source), arg, new, "new") and
source = trackModuleAccess(tp) and
name = "initialize" and
exists(lookupMethod(tp, name))
private CfgScope viableImplInCallContextInitialize(RelevantCall call, RelevantCall ctx) {
exists(Module m, DataFlow::LocalSourceNode source |
argMustFlowToReceiver(ctx, pragma[only_bind_into](source), _, _, TNormalCall(call), "new") and
source = trackModuleAccess(m) and
result = getInitializeTarget(call) and
result = lookupMethod(m, "initialize")
)
}
/**
* Holds if `ctx` targets the enclosing callable of `call`, and
* the receiver of `call` is a parameter access, where the corresponding argument
* `arg` of `ctx` has type `tp`.
*
* `name` is the name of the method being called by `call`, and `exact` is pertaining
* to the type of the argument.
*/
pragma[nomagic]
private predicate mayBenefitFromCallContextInstance(
RelevantCall ctx, RelevantCall call, DataFlow::Node arg, Module tp, boolean exact, string name
) {
exists(DataFlow::LocalSourceNode source |
argMustFlowToReceiver(ctx, pragma[only_bind_into](source), arg, call,
private CfgScope viableImplInCallContextInstance(DataFlowCall call, RelevantCall ctx) {
exists(Module m, DataFlow::LocalSourceNode source, string name, boolean exact |
argMustFlowToReceiver(ctx, pragma[only_bind_into](source), _, _, pragma[only_bind_into](call),
pragma[only_bind_into](name)) and
source = trackInstance(tp, exact) and
exists(lookupMethod(tp, pragma[only_bind_into](name)))
source = trackInstance(m, exact) and
result = getTargetInstance(call, pragma[only_bind_into](name)) and
result = lookupMethod(m, pragma[only_bind_into](name), exact)
)
}
/**
* Holds if `ctx` targets the enclosing callable of `call`, and
* the receiver of `call` is a parameter access, where the corresponding argument
* `arg` of `ctx` is a module access targeting a module of type `tp`.
*
* `name` is the name of the method being called by `call`, and `exact` is pertaining
* to the type of the argument.
*/
pragma[nomagic]
private predicate mayBenefitFromCallContextSingleton(
RelevantCall ctx, RelevantCall call, DataFlow::Node arg, Module tp, boolean exact, string name
) {
exists(DataFlow::LocalSourceNode source |
argMustFlowToReceiver(ctx, pragma[only_bind_into](source), pragma[only_bind_into](arg), call,
pragma[only_bind_into](name)) and
exists(lookupSingletonMethod(tp, pragma[only_bind_into](name), exact))
private CfgScope viableImplInCallContextSingleton(DataFlowCall call, RelevantCall ctx) {
exists(
Module m, DataFlow::LocalSourceNode source, DataFlow::Node arg, string name, boolean exact
|
source = trackModuleAccess(tp) and
argMustFlowToReceiver(ctx, pragma[only_bind_into](source), arg, _, pragma[only_bind_into](call),
pragma[only_bind_into](name)) and
result = getTargetSingleton(call, pragma[only_bind_into](name)) and
result = lookupSingletonMethod(m, pragma[only_bind_into](name), exact)
|
source = trackModuleAccess(m) and
exact = true
or
exists(SelfVariable self | arg.asExpr().getExpr() = self.getAnAccess() |
selfInModule(self, tp) and
selfInModule(self, m) and
exact = true
or
exists(MethodBase caller |
selfInMethod(self, caller, tp) and
selfInMethod(self, caller, m) and
singletonMethod(caller, _, _) and
exact = false
)
@@ -1206,64 +1207,33 @@ private predicate mayBenefitFromCallContextSingleton(
)
}
/**
* Holds if the set of viable implementations that can be called by `call`
* might be improved by knowing the call context.
*/
predicate mayBenefitFromCallContext(DataFlowCall call) {
mayBenefitFromCallContextInitialize(_, call.asCall(), _, _, _)
or
mayBenefitFromCallContextInstance(_, call.asCall(), _, _, _, _)
or
mayBenefitFromCallContextSingleton(_, call.asCall(), _, _, _, _)
}
/**
* Gets a viable dispatch target of `call` in the context `ctx`. This is
* restricted to those `call`s for which a context might make a difference.
*/
pragma[nomagic]
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
mayBenefitFromCallContext(call) and
(
// `ctx` can provide a potentially better type bound
exists(RelevantCall call0, Callable res |
call0 = call.asCall() and
res = result.asCallable() and
exists(Module m, string name |
mayBenefitFromCallContextInitialize(ctx.asCall(), pragma[only_bind_into](call0), _,
pragma[only_bind_into](m), pragma[only_bind_into](name)) and
res = getInitializeTarget(call0) and
res = lookupMethod(m, name)
or
exists(boolean exact |
mayBenefitFromCallContextInstance(ctx.asCall(), pragma[only_bind_into](call0), _,
pragma[only_bind_into](m), pragma[only_bind_into](exact), pragma[only_bind_into](name)) and
res = getTargetInstance(call0, name) and
res = lookupMethod(m, name, exact)
or
mayBenefitFromCallContextSingleton(ctx.asCall(), pragma[only_bind_into](call0), _,
pragma[only_bind_into](m), pragma[only_bind_into](exact), pragma[only_bind_into](name)) and
res = getTargetSingleton(call0, name) and
res = lookupSingletonMethod(m, name, exact)
)
)
)
// `ctx` can provide a potentially better type bound
exists(CfgScope res | res = result.asCfgScope() |
res = viableImplInCallContextInitialize(call.asCall(), ctx.asCall())
or
res = viableImplInCallContextInstance(call, ctx.asCall())
or
res = viableImplInCallContextSingleton(call, ctx.asCall())
)
or
exists(ParameterPosition pos | mayBenefitFromCallContext(call, pos, ctx) |
// `ctx` cannot provide a type bound, and the receiver of the call is `self`;
// in this case, still apply an open-world assumption
exists(RelevantCall call0, RelevantCall ctx0, DataFlow::Node arg, string name |
call0 = call.asCall() and
ctx0 = ctx.asCall() and
argMustFlowToReceiver(ctx0, _, arg, call0, name) and
not mayBenefitFromCallContextInitialize(ctx0, call0, arg, _, _) and
not mayBenefitFromCallContextInstance(ctx0, call0, arg, _, _, name) and
not mayBenefitFromCallContextSingleton(ctx0, call0, arg, _, _, name) and
result.asCallable() = viableSourceCallable(call0)
pos.isSelf() and
result = viableSourceCallable(call) and
not exists(RelevantCall ctx0 | ctx0 = ctx.asCall() |
exists(viableImplInCallContextInitialize(call.asCall(), ctx0)) or
exists(viableImplInCallContextInstance(call, ctx0)) or
exists(viableImplInCallContextSingleton(call, ctx0))
)
or
// library calls should always be able to resolve
argMustFlowToReceiver(ctx.asCall(), _, _, call.asCall(), _) and
result = viableLibraryCallable(call)
)
}

View File

@@ -235,6 +235,30 @@ module LocalFlow {
or
nodeTo.(BlockArgumentNode).getParameterNode(true) = nodeFrom
}
predicate localMustFlowStep(Node node1, Node node2) {
LocalFlow::localFlowSsaParamInput(node1, node2)
or
exists(SsaImpl::Definition def |
def.(Ssa::WriteDefinition).assigns(node1.asExpr()) and
node2.(SsaDefinitionExtNode).getDefinitionExt() = def
or
def = node1.(SsaDefinitionExtNode).getDefinitionExt() and
node2.asExpr() = SsaImpl::getARead(def)
)
or
node1.asExpr() = node2.asExpr().(CfgNodes::ExprNodes::AssignExprCfgNode).getRhs()
or
node1.asExpr() = node2.asExpr().(CfgNodes::ExprNodes::BlockArgumentCfgNode).getValue()
or
node1 = node2.(BlockArgumentNode).getParameterNode(true)
or
node1 =
unique(FlowSummaryNode n1 |
FlowSummaryImpl::Private::Steps::summaryLocalStep(n1.getSummaryNode(),
node2.(FlowSummaryNode).getSummaryNode(), true)
)
}
}
/** An argument of a call (including qualifier arguments and block arguments). */
@@ -508,11 +532,11 @@ private module Cached {
isParameterNode(_, c, any(ParameterPosition p | p.isKeyword(_)))
} or
TSynthSplatParameterNode(DataFlowCallable c) {
exists(c.asCallable()) and // exclude library callables (for now)
exists(c.asCfgScope()) and // exclude library callables (for now)
isParameterNode(_, c, any(ParameterPosition p | p.isPositional(_)))
} or
TSynthSplatParameterShiftNode(DataFlowCallable c, int splatPos, int n) {
splatPos = unique(int i | splatParameterAt(c.asCallable(), i) and i > 0) and
splatPos = unique(int i | splatParameterAt(c.asCfgScope(), i) and i > 0) and
n in [0 .. 10]
} or
TExprPostUpdateNode(CfgNodes::ExprCfgNode n) {
@@ -715,7 +739,7 @@ private module Cached {
cached
predicate exprNodeReturnedFromCached(ExprNode e, Callable c) {
exists(ReturnNode r |
nodeGetEnclosingCallable(r).asCallable() = c and
nodeGetEnclosingCallable(r).asCfgScope() = c and
(
r.(ExplicitReturnNode).getReturningNode().getReturnedValueNode() = e.asExpr() or
r.(ExprReturnNode) = e
@@ -881,10 +905,10 @@ private module ParameterNodes {
abstract predicate isParameterOf(DataFlowCallable c, ParameterPosition pos);
final predicate isSourceParameterOf(Callable c, ParameterPosition pos) {
final predicate isSourceParameterOf(CfgScope c, ParameterPosition pos) {
exists(DataFlowCallable callable |
this.isParameterOf(callable, pos) and
c = callable.asCallable()
c = callable.asCfgScope()
)
}
}
@@ -901,7 +925,7 @@ private module ParameterNodes {
override Parameter getParameter() { result = parameter }
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
exists(Callable callable | callable = c.asCallable() |
exists(Callable callable | callable = c.asCfgScope() |
exists(int i | pos.isPositional(i) and callable.getParameter(i) = parameter |
parameter instanceof SimpleParameter
or
@@ -955,7 +979,7 @@ private module ParameterNodes {
override Parameter getParameter() { none() }
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
method = c.asCallable() and pos.isSelf()
method = c.asCfgScope() and pos.isSelf()
}
override CfgScope getCfgScope() { result = method }
@@ -984,7 +1008,7 @@ private module ParameterNodes {
override Parameter getParameter() { none() }
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
callable = c.asCallable() and pos.isLambdaSelf()
callable = c.asCfgScope() and pos.isLambdaSelf()
}
override CfgScope getCfgScope() { result = callable }
@@ -1010,7 +1034,7 @@ private module ParameterNodes {
}
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
c.asCallable() = method and pos.isBlock()
c.asCfgScope() = method and pos.isBlock()
}
CfgNodes::ExprNodes::CallCfgNode getAYieldCall() {
@@ -1088,7 +1112,7 @@ private module ParameterNodes {
c = callable and pos.isSynthHashSplat()
}
final override CfgScope getCfgScope() { result = callable.asCallable() }
final override CfgScope getCfgScope() { result = callable.asCfgScope() }
final override DataFlowCallable getEnclosingCallable() { result = callable }
@@ -1144,7 +1168,7 @@ private module ParameterNodes {
predicate readInto(ParameterNode p, ContentSet c) {
exists(int n |
isParameterNode(p, callable, any(ParameterPosition pos | pos.isPositional(n))) and
not exists(int i | splatParameterAt(callable.asCallable(), i) and i < n)
not exists(int i | splatParameterAt(callable.asCfgScope(), i) and i < n)
|
// Important: do not include `TSplatContent(_, false)` here, as normal parameter matching is possible
c = getSplatContent(n, true)
@@ -1161,7 +1185,7 @@ private module ParameterNodes {
c = callable and pos.isSynthSplat()
}
final override CfgScope getCfgScope() { result = callable.asCallable() }
final override CfgScope getCfgScope() { result = callable.asCfgScope() }
final override DataFlowCallable getEnclosingCallable() { result = callable }
@@ -1212,7 +1236,7 @@ private module ParameterNodes {
cs = getArrayContent(pos)
}
final override CfgScope getCfgScope() { result = callable.asCallable() }
final override CfgScope getCfgScope() { result = callable.asCfgScope() }
final override DataFlowCallable getEnclosingCallable() { result = callable }
@@ -1321,11 +1345,11 @@ module ArgumentNodes {
}
private class SummaryArgumentNode extends FlowSummaryNode, ArgumentNode {
private SummaryCall call_;
private FlowSummaryImpl::Private::SummaryNode receiver;
private ArgumentPosition pos_;
SummaryArgumentNode() {
FlowSummaryImpl::Private::summaryArgumentNode(call_.getReceiver(), this.getSummaryNode(), pos_)
FlowSummaryImpl::Private::summaryArgumentNode(receiver, this.getSummaryNode(), pos_)
}
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition pos) {
@@ -1333,7 +1357,7 @@ module ArgumentNodes {
}
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
call = call_ and pos = pos_
call.(SummaryCall).getReceiver() = receiver and pos = pos_
}
}
@@ -1543,7 +1567,7 @@ module ArgumentNodes {
import ArgumentNodes
/** A call to `new`. */
private class NewCall extends DataFlowCall {
private class NewCall extends NormalCall {
NewCall() { this.asCall().getExpr().(MethodCall).getMethodName() = "new" }
}
@@ -1856,7 +1880,7 @@ predicate clearsContent(Node n, ContentSet c) {
ParameterPosition keywordPos, ConstantValue::ConstantSymbolValue cv, string name
|
n = TNormalParameterNode(hashSplatParam) and
callable.asCallable() = hashSplatParam.getCallable() and
callable.asCfgScope() = hashSplatParam.getCallable() and
keywordParam.isParameterOf(callable, keywordPos) and
keywordPos.isKeyword(name) and
c.isKnownOrUnknownElement(TKnownElementContent(cv)) and
@@ -2042,7 +2066,7 @@ private predicate lambdaCreationExpr(CfgNodes::ExprCfgNode creation, LambdaCallK
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) {
lambdaCreationExpr(creation.asExpr(), kind, c.asCallable())
lambdaCreationExpr(creation.asExpr(), kind, c.asCfgScope())
}
/** Holds if `call` is a call to `lambda`, `proc`, or `Proc.new` */

View File

@@ -77,7 +77,7 @@ class Node extends TNode {
or
exists(DataFlowCallable c |
lambdaCreation(this, _, c) and
result.asCallableAstNode() = c.asCallable()
result.asCallableAstNode() = c.asCfgScope()
)
}

View File

@@ -126,13 +126,10 @@ module UnsafeDeserialization {
}
}
private string getAKnownOjModeName(boolean isSafe) {
result = ["compat", "custom", "json", "null", "rails", "strict", "wab"] and isSafe = true
or
result = "object" and isSafe = false
}
private predicate isOjModePair(CfgNodes::ExprNodes::PairCfgNode p, string modeValue) {
/**
* Oj/Ox common code to establish whether a deserialization mode is defined.
*/
private predicate isModePair(CfgNodes::ExprNodes::PairCfgNode p, string modeValue) {
p.getKey().getConstantValue().isStringlikeValue("mode") and
DataFlow::exprNode(p.getValue()).getALocalSource().getConstantValue().isSymbol(modeValue)
}
@@ -140,28 +137,31 @@ module UnsafeDeserialization {
/**
* A node representing a hash that contains the key `:mode`.
*/
private class OjOptionsHashWithModeKey extends DataFlow::Node {
private class OptionsHashWithModeKey extends DataFlow::Node {
private string modeValue;
OjOptionsHashWithModeKey() {
OptionsHashWithModeKey() {
exists(DataFlow::LocalSourceNode options |
options.flowsTo(this) and
isOjModePair(options.asExpr().(CfgNodes::ExprNodes::HashLiteralCfgNode).getAKeyValuePair(),
isModePair(options.asExpr().(CfgNodes::ExprNodes::HashLiteralCfgNode).getAKeyValuePair(),
modeValue)
)
}
/**
* Holds if this hash node contains a `:mode` key whose value is one known
* to be `isSafe` with untrusted data.
* Holds if this hash node contains the `:mode`
*/
predicate hasKnownMode(boolean isSafe) { modeValue = getAKnownOjModeName(isSafe) }
predicate hasKnownMode(string mode) { modeValue = mode }
}
/**
* Holds if this hash node contains a `:mode` key whose value is one of the
* `Oj` modes known to be safe to use with untrusted data.
*/
predicate hasSafeMode() { this.hasKnownMode(true) }
/**
* Unsafe deserialization utilizing the Oj gem
* See: https://github.com/ohler55/oj
*/
private string getAKnownOjModeName(boolean isSafe) {
result = ["compat", "custom", "json", "null", "rails", "strict", "wab"] and isSafe = true
or
result = "object" and isSafe = false
}
/**
@@ -179,10 +179,7 @@ module UnsafeDeserialization {
/**
* Gets the value being assigned to `Oj.default_options`.
*/
DataFlow::Node getValue() {
result.asExpr() =
this.getArgument(0).asExpr().(CfgNodes::ExprNodes::AssignExprCfgNode).getRhs()
}
DataFlow::Node getValue() { result = this.getArgument(0) }
}
/**
@@ -197,9 +194,9 @@ module UnsafeDeserialization {
*/
predicate hasExplicitKnownMode(boolean isSafe) {
exists(DataFlow::Node arg, int i | i >= 1 and arg = this.getArgument(i) |
arg.(OjOptionsHashWithModeKey).hasKnownMode(isSafe)
arg.(OptionsHashWithModeKey).hasKnownMode(getAKnownOjModeName(isSafe))
or
isOjModePair(arg.asExpr(), getAKnownOjModeName(isSafe))
isModePair(arg.asExpr(), getAKnownOjModeName(isSafe))
)
}
}
@@ -223,13 +220,106 @@ module UnsafeDeserialization {
// anywhere to set the default options to a known safe mode.
not ojLoad.hasExplicitKnownMode(_) and
not exists(SetOjDefaultOptionsCall setOpts |
setOpts.getValue().(OjOptionsHashWithModeKey).hasSafeMode()
setOpts.getValue().(OptionsHashWithModeKey).hasKnownMode(getAKnownOjModeName(true))
)
)
)
}
}
/**
* The first argument in a call to `Oj.object_load`, always considered as a
* sink for unsafe deserialization. (global and local mode options are ignored)
*/
private class OjObjectLoadArgument extends Sink {
OjObjectLoadArgument() {
this = API::getTopLevelMember("Oj").getAMethodCall("object_load").getArgument(0)
}
}
/**
* Unsafe deserialization utilizing the Ox gem
* See: https://github.com/ohler55/ox
*/
private string getAKnownOxModeName(boolean isSafe) {
result = ["generic", "limited", "hash", "hash_no_attrs"] and isSafe = true
or
result = "object" and isSafe = false
}
/**
* A call node that sets `Ox.default_options`.
*
* ```rb
* Ox.default_options = { mode: :limited, effort: :tolerant }
* ```
*/
private class SetOxDefaultOptionsCall extends DataFlow::CallNode {
SetOxDefaultOptionsCall() {
this = API::getTopLevelMember("Ox").getAMethodCall("default_options=")
}
/**
* Gets the value being assigned to `Ox.default_options`.
*/
DataFlow::Node getValue() { result = this.getArgument(0) }
}
/**
* A call to `Ox.load`.
*/
private class OxLoadCall extends DataFlow::CallNode {
OxLoadCall() { this = API::getTopLevelMember("Ox").getAMethodCall("load") }
/**
* Holds if this call to `Ox.load` includes an explicit options hash
* argument that sets the mode to one that is known to be `isSafe`.
*/
predicate hasExplicitKnownMode(boolean isSafe) {
exists(DataFlow::Node arg, int i | i >= 1 and arg = this.getArgument(i) |
arg.(OptionsHashWithModeKey).hasKnownMode(getAKnownOxModeName(isSafe))
or
isModePair(arg.asExpr(), getAKnownOxModeName(isSafe))
)
}
}
/**
* An argument in a call to `Ox.load` where the mode is `:object` (not the default),
* considered a sink for unsafe deserialization.
*/
class UnsafeOxLoadArgument extends Sink {
UnsafeOxLoadArgument() {
exists(OxLoadCall oxLoad |
this = oxLoad.getArgument(0) and
// Exclude calls that explicitly pass a safe mode option.
not oxLoad.hasExplicitKnownMode(true) and
(
// Sinks to include:
// - Calls with an explicit, unsafe mode option.
oxLoad.hasExplicitKnownMode(false)
or
// - Calls with no explicit mode option and there exists a call
// anywhere to set the default options to an unsafe mode (object).
not oxLoad.hasExplicitKnownMode(_) and
exists(SetOxDefaultOptionsCall setOpts |
setOpts.getValue().(OptionsHashWithModeKey).hasKnownMode(getAKnownOxModeName(false))
)
)
)
}
}
/**
* The first argument in a call to `Ox.parse_obj`, always considered as a
* sink for unsafe deserialization.
*/
class OxParseObjArgument extends Sink {
OxParseObjArgument() {
this = API::getTopLevelMember("Ox").getAMethodCall("parse_obj").getArgument(0)
}
}
/**
* An argument in a call to `Plist.parse_xml` where `marshal` is `true` (which is
* the default), considered a sink for unsafe deserialization.

View File

@@ -32,7 +32,7 @@ private predicate callStepNoInitialize(
) {
exists(DataFlowDispatch::ParameterPosition pos |
argumentPositionMatch(call, arg, pos) and
p.isSourceParameterOf(DataFlowDispatch::getTarget(call), pos)
p.isSourceParameterOf(DataFlowDispatch::getTarget(DataFlowDispatch::TNormalCall(call)), pos)
)
}
@@ -110,7 +110,7 @@ private predicate viableParam(
DataFlowDispatch::ParameterPosition ppos
) {
exists(Cfg::CfgScope callable |
DataFlowDispatch::getTarget(call) = callable or
DataFlowDispatch::getTarget(DataFlowDispatch::TNormalCall(call)) = callable or
DataFlowDispatch::getInitializeTarget(call) = callable
|
p.isSourceParameterOf(callable, ppos)
@@ -296,7 +296,8 @@ module TypeTrackingInput implements Shared::TypeTrackingInput {
exists(ExprNodes::CallCfgNode call |
nodeFrom instanceof DataFlowPrivate::ReturnNode and
not nodeFrom instanceof DataFlowPrivate::InitializeReturnNode and
nodeFrom.(DataFlowPrivate::NodeImpl).getCfgScope() = DataFlowDispatch::getTarget(call) and
nodeFrom.(DataFlowPrivate::NodeImpl).getCfgScope() =
DataFlowDispatch::getTarget(DataFlowDispatch::TNormalCall(call)) and
// deliberately do not include `getInitializeTarget`, since calls to `new` should not
// get the return value from `initialize`. Any fields being set in the initializer
// will reach all reads via `callStep` and `localFieldStep`.

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* Added new unsafe deserialization sinks for the ox gem.
* Added an additional unsafe deserialization sink for the oj gem.

View File

@@ -43,6 +43,7 @@ string getArgumentPath(DataFlow::ParameterNode paramNode) {
*/
predicate pathToMethod(DataFlow::MethodNode method, string type, string path) {
method.getLocation().getFile() instanceof RelevantFile and
method.isPublic() and // only public methods are modeled
exists(DataFlow::ModuleNode mod, string methodName |
method = mod.getOwnInstanceMethod(methodName) and
if methodName = "initialize"

View File

@@ -27,6 +27,13 @@ method. In <code>psych</code> version 4.0.0 and above, the <code>load</code> met
safely be used.
</p>
<p>
If deserializing an untrusted XML document using the <code>ox</code> gem,
do not use <code>parse_obj</code> and <code>load</code> using the non-default :object mode.
Instead use the <code>load</code> method in the default mode or better explicitly set a safe
mode such as :hash.
</p>
<p>
To safely deserialize <a href="https://en.wikipedia.org/wiki/Property_list">Property List</a>
files using the <code>plist</code> gem, ensure that you pass <code>marshal: false</code>
@@ -37,8 +44,8 @@ when calling <code>Plist.parse_xml</code>.
<example>
<p>
The following example calls the <code>Marshal.load</code>,
<code>JSON.load</code>, <code>YAML.load</code>, and <code>Oj.load</code> methods
on data from an HTTP request. Since these methods are capable of deserializing
<code>JSON.load</code>, <code>YAML.load</code>, <code>Oj.load</code> and <code>Ox.parse_obj</code>
methods on data from an HTTP request. Since these methods are capable of deserializing
to arbitrary objects, this is inherently unsafe.
</p>
<sample src="examples/UnsafeDeserializationBad.rb"/>

View File

@@ -23,4 +23,9 @@ class UserController < ActionController::Base
object = Oj.load params[:json]
# ...
end
def ox_example
object = Ox.parse_obj params[:xml]
# ...
end
end

View File

@@ -104,7 +104,7 @@ class MethodEndpoint extends Endpoint instanceof DataFlow::MethodNode {
/** Holds if this API has a supported summary. */
pragma[nomagic]
predicate hasSummary() { none() }
predicate hasSummary() { this.getNode() instanceof SummaryCallable }
/** Holds if this API is a known source. */
pragma[nomagic]
@@ -116,7 +116,7 @@ class MethodEndpoint extends Endpoint instanceof DataFlow::MethodNode {
/** Holds if this API is a known neutral. */
pragma[nomagic]
predicate isNeutral() { none() }
predicate isNeutral() { this.getNode() instanceof NeutralCallable }
/**
* Holds if this API is supported by existing CodeQL libraries, that is, it is either a
@@ -183,6 +183,30 @@ class SourceCallable extends DataFlow::CallableNode {
}
}
/**
* A callable where there exists a MaD summary model that applies to it.
*/
class SummaryCallable extends DataFlow::CallableNode {
SummaryCallable() {
exists(string type, string path |
Util::pathToMethod(this, type, path) and
summaryModel(type, path, _, _, _)
)
}
}
/**
* A callable where there exists a MaD neutral model that applies to it.
*/
class NeutralCallable extends DataFlow::CallableNode {
NeutralCallable() {
exists(string type, string path |
Util::pathToMethod(this, type, path) and
neutralModel(type, path, _)
)
}
}
/**
* A module defined in source code
*/

View File

@@ -219,11 +219,14 @@ subpaths
| call_sensitivity.rb:200:8:200:8 | x | call_sensitivity.rb:199:16:199:23 | call to taint | call_sensitivity.rb:200:8:200:8 | x | $@ | call_sensitivity.rb:199:16:199:23 | call to taint | call to taint |
| call_sensitivity.rb:204:8:204:8 | x | call_sensitivity.rb:199:16:199:23 | call to taint | call_sensitivity.rb:204:8:204:8 | x | $@ | call_sensitivity.rb:199:16:199:23 | call to taint | call to taint |
mayBenefitFromCallContext
| call_sensitivity.rb:6:5:6:21 | call to puts |
| call_sensitivity.rb:22:5:22:18 | call to call |
| call_sensitivity.rb:51:5:51:10 | call to sink |
| call_sensitivity.rb:55:5:55:13 | call to method1 |
| call_sensitivity.rb:59:5:59:18 | call to method2 |
| call_sensitivity.rb:63:5:63:16 | call to method1 |
| call_sensitivity.rb:67:5:67:25 | call to method3 |
| call_sensitivity.rb:71:5:71:10 | call to sink |
| call_sensitivity.rb:81:5:81:18 | call to method1 |
| call_sensitivity.rb:89:5:89:23 | call to singleton_method1 |
| call_sensitivity.rb:93:5:93:28 | call to singleton_method2 |
@@ -232,11 +235,15 @@ mayBenefitFromCallContext
| call_sensitivity.rb:105:5:105:10 | call to sink |
| call_sensitivity.rb:106:5:106:13 | call to method1 |
| call_sensitivity.rb:110:5:110:9 | call to new |
| call_sensitivity.rb:129:5:129:25 | call to puts |
| call_sensitivity.rb:133:5:133:25 | call to puts |
| call_sensitivity.rb:137:5:137:18 | call to method2 |
| call_sensitivity.rb:141:5:141:25 | call to method3 |
| call_sensitivity.rb:149:5:149:28 | call to singleton_method2 |
| call_sensitivity.rb:153:5:153:35 | call to singleton_method3 |
| call_sensitivity.rb:157:5:157:25 | call to puts |
| call_sensitivity.rb:175:3:175:12 | call to new |
| call_sensitivity.rb:183:5:183:25 | call to puts |
| call_sensitivity.rb:194:3:196:5 | call to invoke_block1 |
viableImplInCallContext
| call_sensitivity.rb:51:5:51:10 | call to sink | call_sensitivity.rb:55:5:55:13 | call to method1 | call_sensitivity.rb:5:1:7:3 | sink |

View File

@@ -0,0 +1 @@
queries/diagnostics/ExtractedFiles.ql

View File

@@ -1 +0,0 @@
queries/diagnostics/SuccessfullyExtractedFiles.ql

View File

@@ -0,0 +1,16 @@
require "ox"
class UsersController < ActionController::Base
# BAD - Ox.load is unsafe when the mode :object is set globally
def route0
xml_data = params[:key]
object = Ox.load xml_data
end
# GOOD - the unsafe mode set globally is overridden with an insecure mode passed as
# a call argument
def route1
xml_data = params[:key]
object = Ox.load xml_data, mode: :generic
end
end

View File

@@ -0,0 +1,5 @@
require "ox"
# Set the default mode for the Ox library to use the :object mode, which makes
# Ox.load unsafe for untrusted data.
Ox.default_options = { :mode => :object }

View File

@@ -0,0 +1,12 @@
edges
| OxGlobalOptions.rb:6:5:6:12 | xml_data | OxGlobalOptions.rb:7:22:7:29 | xml_data |
| OxGlobalOptions.rb:6:16:6:21 | call to params | OxGlobalOptions.rb:6:16:6:27 | ...[...] |
| OxGlobalOptions.rb:6:16:6:27 | ...[...] | OxGlobalOptions.rb:6:5:6:12 | xml_data |
nodes
| OxGlobalOptions.rb:6:5:6:12 | xml_data | semmle.label | xml_data |
| OxGlobalOptions.rb:6:16:6:21 | call to params | semmle.label | call to params |
| OxGlobalOptions.rb:6:16:6:27 | ...[...] | semmle.label | ...[...] |
| OxGlobalOptions.rb:7:22:7:29 | xml_data | semmle.label | xml_data |
subpaths
#select
| OxGlobalOptions.rb:7:22:7:29 | xml_data | OxGlobalOptions.rb:6:16:6:21 | call to params | OxGlobalOptions.rb:7:22:7:29 | xml_data | Unsafe deserialization depends on a $@. | OxGlobalOptions.rb:6:16:6:21 | call to params | user-provided value |

View File

@@ -0,0 +1 @@
queries/security/cwe-502/UnsafeDeserialization.ql

View File

@@ -1,36 +1,45 @@
edges
| PlistUnsafeDeserialization.rb:5:30:5:35 | call to params | PlistUnsafeDeserialization.rb:5:30:5:49 | ...[...] |
| PlistUnsafeDeserialization.rb:6:30:6:35 | call to params | PlistUnsafeDeserialization.rb:6:30:6:49 | ...[...] |
| UnsafeDeserialization.rb:10:5:10:19 | serialized_data | UnsafeDeserialization.rb:11:27:11:41 | serialized_data |
| UnsafeDeserialization.rb:10:23:10:50 | call to decode64 | UnsafeDeserialization.rb:10:5:10:19 | serialized_data |
| UnsafeDeserialization.rb:10:39:10:44 | call to params | UnsafeDeserialization.rb:10:39:10:50 | ...[...] |
| UnsafeDeserialization.rb:10:39:10:50 | ...[...] | UnsafeDeserialization.rb:10:23:10:50 | call to decode64 |
| UnsafeDeserialization.rb:16:5:16:19 | serialized_data | UnsafeDeserialization.rb:17:30:17:44 | serialized_data |
| UnsafeDeserialization.rb:16:23:16:50 | call to decode64 | UnsafeDeserialization.rb:16:5:16:19 | serialized_data |
| UnsafeDeserialization.rb:16:39:16:44 | call to params | UnsafeDeserialization.rb:16:39:16:50 | ...[...] |
| UnsafeDeserialization.rb:16:39:16:50 | ...[...] | UnsafeDeserialization.rb:16:23:16:50 | call to decode64 |
| UnsafeDeserialization.rb:22:5:22:13 | json_data | UnsafeDeserialization.rb:23:24:23:32 | json_data |
| UnsafeDeserialization.rb:22:17:22:22 | call to params | UnsafeDeserialization.rb:22:17:22:28 | ...[...] |
| UnsafeDeserialization.rb:22:17:22:28 | ...[...] | UnsafeDeserialization.rb:22:5:22:13 | json_data |
| UnsafeDeserialization.rb:28:5:28:13 | json_data | UnsafeDeserialization.rb:29:27:29:35 | json_data |
| UnsafeDeserialization.rb:28:17:28:22 | call to params | UnsafeDeserialization.rb:28:17:28:28 | ...[...] |
| UnsafeDeserialization.rb:28:17:28:28 | ...[...] | UnsafeDeserialization.rb:28:5:28:13 | json_data |
| UnsafeDeserialization.rb:40:5:40:13 | yaml_data | UnsafeDeserialization.rb:41:24:41:32 | yaml_data |
| UnsafeDeserialization.rb:40:17:40:22 | call to params | UnsafeDeserialization.rb:40:17:40:28 | ...[...] |
| UnsafeDeserialization.rb:40:17:40:28 | ...[...] | UnsafeDeserialization.rb:40:5:40:13 | yaml_data |
| UnsafeDeserialization.rb:52:5:52:13 | json_data | UnsafeDeserialization.rb:53:22:53:30 | json_data |
| UnsafeDeserialization.rb:52:5:52:13 | json_data | UnsafeDeserialization.rb:54:22:54:30 | json_data |
| UnsafeDeserialization.rb:52:17:52:22 | call to params | UnsafeDeserialization.rb:52:17:52:28 | ...[...] |
| UnsafeDeserialization.rb:52:17:52:28 | ...[...] | UnsafeDeserialization.rb:52:5:52:13 | json_data |
| UnsafeDeserialization.rb:59:5:59:13 | json_data | UnsafeDeserialization.rb:69:23:69:31 | json_data |
| UnsafeDeserialization.rb:59:17:59:22 | call to params | UnsafeDeserialization.rb:59:17:59:28 | ...[...] |
| UnsafeDeserialization.rb:59:17:59:28 | ...[...] | UnsafeDeserialization.rb:59:5:59:13 | json_data |
| UnsafeDeserialization.rb:81:5:81:7 | xml | UnsafeDeserialization.rb:82:34:82:36 | xml |
| UnsafeDeserialization.rb:81:11:81:16 | call to params | UnsafeDeserialization.rb:81:11:81:22 | ...[...] |
| UnsafeDeserialization.rb:81:11:81:22 | ...[...] | UnsafeDeserialization.rb:81:5:81:7 | xml |
| UnsafeDeserialization.rb:87:5:87:13 | yaml_data | UnsafeDeserialization.rb:88:25:88:33 | yaml_data |
| UnsafeDeserialization.rb:87:17:87:22 | call to params | UnsafeDeserialization.rb:87:17:87:28 | ...[...] |
| UnsafeDeserialization.rb:87:17:87:28 | ...[...] | UnsafeDeserialization.rb:87:5:87:13 | yaml_data |
| UnsafeDeserialization.rb:11:5:11:19 | serialized_data | UnsafeDeserialization.rb:12:27:12:41 | serialized_data |
| UnsafeDeserialization.rb:11:23:11:50 | call to decode64 | UnsafeDeserialization.rb:11:5:11:19 | serialized_data |
| UnsafeDeserialization.rb:11:39:11:44 | call to params | UnsafeDeserialization.rb:11:39:11:50 | ...[...] |
| UnsafeDeserialization.rb:11:39:11:50 | ...[...] | UnsafeDeserialization.rb:11:23:11:50 | call to decode64 |
| UnsafeDeserialization.rb:17:5:17:19 | serialized_data | UnsafeDeserialization.rb:18:30:18:44 | serialized_data |
| UnsafeDeserialization.rb:17:23:17:50 | call to decode64 | UnsafeDeserialization.rb:17:5:17:19 | serialized_data |
| UnsafeDeserialization.rb:17:39:17:44 | call to params | UnsafeDeserialization.rb:17:39:17:50 | ...[...] |
| UnsafeDeserialization.rb:17:39:17:50 | ...[...] | UnsafeDeserialization.rb:17:23:17:50 | call to decode64 |
| UnsafeDeserialization.rb:23:5:23:13 | json_data | UnsafeDeserialization.rb:24:24:24:32 | json_data |
| UnsafeDeserialization.rb:23:17:23:22 | call to params | UnsafeDeserialization.rb:23:17:23:28 | ...[...] |
| UnsafeDeserialization.rb:23:17:23:28 | ...[...] | UnsafeDeserialization.rb:23:5:23:13 | json_data |
| UnsafeDeserialization.rb:29:5:29:13 | json_data | UnsafeDeserialization.rb:30:27:30:35 | json_data |
| UnsafeDeserialization.rb:29:17:29:22 | call to params | UnsafeDeserialization.rb:29:17:29:28 | ...[...] |
| UnsafeDeserialization.rb:29:17:29:28 | ...[...] | UnsafeDeserialization.rb:29:5:29:13 | json_data |
| UnsafeDeserialization.rb:41:5:41:13 | yaml_data | UnsafeDeserialization.rb:42:24:42:32 | yaml_data |
| UnsafeDeserialization.rb:41:17:41:22 | call to params | UnsafeDeserialization.rb:41:17:41:28 | ...[...] |
| UnsafeDeserialization.rb:41:17:41:28 | ...[...] | UnsafeDeserialization.rb:41:5:41:13 | yaml_data |
| UnsafeDeserialization.rb:53:5:53:13 | json_data | UnsafeDeserialization.rb:54:22:54:30 | json_data |
| UnsafeDeserialization.rb:53:5:53:13 | json_data | UnsafeDeserialization.rb:55:22:55:30 | json_data |
| UnsafeDeserialization.rb:53:17:53:22 | call to params | UnsafeDeserialization.rb:53:17:53:28 | ...[...] |
| UnsafeDeserialization.rb:53:17:53:28 | ...[...] | UnsafeDeserialization.rb:53:5:53:13 | json_data |
| UnsafeDeserialization.rb:60:5:60:13 | json_data | UnsafeDeserialization.rb:70:23:70:31 | json_data |
| UnsafeDeserialization.rb:60:17:60:22 | call to params | UnsafeDeserialization.rb:60:17:60:28 | ...[...] |
| UnsafeDeserialization.rb:60:17:60:28 | ...[...] | UnsafeDeserialization.rb:60:5:60:13 | json_data |
| UnsafeDeserialization.rb:81:4:81:12 | json_data | UnsafeDeserialization.rb:82:28:82:36 | json_data |
| UnsafeDeserialization.rb:81:16:81:21 | call to params | UnsafeDeserialization.rb:81:16:81:27 | ...[...] |
| UnsafeDeserialization.rb:81:16:81:27 | ...[...] | UnsafeDeserialization.rb:81:4:81:12 | json_data |
| UnsafeDeserialization.rb:87:4:87:11 | xml_data | UnsafeDeserialization.rb:88:26:88:33 | xml_data |
| UnsafeDeserialization.rb:87:15:87:20 | call to params | UnsafeDeserialization.rb:87:15:87:26 | ...[...] |
| UnsafeDeserialization.rb:87:15:87:26 | ...[...] | UnsafeDeserialization.rb:87:4:87:11 | xml_data |
| UnsafeDeserialization.rb:93:5:93:12 | xml_data | UnsafeDeserialization.rb:94:22:94:29 | xml_data |
| UnsafeDeserialization.rb:93:16:93:21 | call to params | UnsafeDeserialization.rb:93:16:93:27 | ...[...] |
| UnsafeDeserialization.rb:93:16:93:27 | ...[...] | UnsafeDeserialization.rb:93:5:93:12 | xml_data |
| UnsafeDeserialization.rb:109:5:109:7 | xml | UnsafeDeserialization.rb:110:34:110:36 | xml |
| UnsafeDeserialization.rb:109:11:109:16 | call to params | UnsafeDeserialization.rb:109:11:109:22 | ...[...] |
| UnsafeDeserialization.rb:109:11:109:22 | ...[...] | UnsafeDeserialization.rb:109:5:109:7 | xml |
| UnsafeDeserialization.rb:115:5:115:13 | yaml_data | UnsafeDeserialization.rb:116:25:116:33 | yaml_data |
| UnsafeDeserialization.rb:115:17:115:22 | call to params | UnsafeDeserialization.rb:115:17:115:28 | ...[...] |
| UnsafeDeserialization.rb:115:17:115:28 | ...[...] | UnsafeDeserialization.rb:115:5:115:13 | yaml_data |
| YAMLUnsafeDeserialization.rb:5:16:5:21 | call to params | YAMLUnsafeDeserialization.rb:5:16:5:35 | ...[...] |
| YAMLUnsafeDeserialization.rb:11:23:11:28 | call to params | YAMLUnsafeDeserialization.rb:11:23:11:42 | ...[...] |
| YAMLUnsafeDeserialization.rb:12:28:12:33 | call to params | YAMLUnsafeDeserialization.rb:12:28:12:45 | ...[...] |
@@ -46,50 +55,62 @@ nodes
| PlistUnsafeDeserialization.rb:5:30:5:49 | ...[...] | semmle.label | ...[...] |
| PlistUnsafeDeserialization.rb:6:30:6:35 | call to params | semmle.label | call to params |
| PlistUnsafeDeserialization.rb:6:30:6:49 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:10:5:10:19 | serialized_data | semmle.label | serialized_data |
| UnsafeDeserialization.rb:10:23:10:50 | call to decode64 | semmle.label | call to decode64 |
| UnsafeDeserialization.rb:10:39:10:44 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:10:39:10:50 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:11:27:11:41 | serialized_data | semmle.label | serialized_data |
| UnsafeDeserialization.rb:16:5:16:19 | serialized_data | semmle.label | serialized_data |
| UnsafeDeserialization.rb:16:23:16:50 | call to decode64 | semmle.label | call to decode64 |
| UnsafeDeserialization.rb:16:39:16:44 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:16:39:16:50 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:17:30:17:44 | serialized_data | semmle.label | serialized_data |
| UnsafeDeserialization.rb:22:5:22:13 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:22:17:22:22 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:22:17:22:28 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:23:24:23:32 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:28:5:28:13 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:28:17:28:22 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:28:17:28:28 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:29:27:29:35 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:40:5:40:13 | yaml_data | semmle.label | yaml_data |
| UnsafeDeserialization.rb:40:17:40:22 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:40:17:40:28 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:41:24:41:32 | yaml_data | semmle.label | yaml_data |
| UnsafeDeserialization.rb:52:5:52:13 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:52:17:52:22 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:52:17:52:28 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:53:22:53:30 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:11:5:11:19 | serialized_data | semmle.label | serialized_data |
| UnsafeDeserialization.rb:11:23:11:50 | call to decode64 | semmle.label | call to decode64 |
| UnsafeDeserialization.rb:11:39:11:44 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:11:39:11:50 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:12:27:12:41 | serialized_data | semmle.label | serialized_data |
| UnsafeDeserialization.rb:17:5:17:19 | serialized_data | semmle.label | serialized_data |
| UnsafeDeserialization.rb:17:23:17:50 | call to decode64 | semmle.label | call to decode64 |
| UnsafeDeserialization.rb:17:39:17:44 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:17:39:17:50 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:18:30:18:44 | serialized_data | semmle.label | serialized_data |
| UnsafeDeserialization.rb:23:5:23:13 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:23:17:23:22 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:23:17:23:28 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:24:24:24:32 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:29:5:29:13 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:29:17:29:22 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:29:17:29:28 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:30:27:30:35 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:41:5:41:13 | yaml_data | semmle.label | yaml_data |
| UnsafeDeserialization.rb:41:17:41:22 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:41:17:41:28 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:42:24:42:32 | yaml_data | semmle.label | yaml_data |
| UnsafeDeserialization.rb:53:5:53:13 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:53:17:53:22 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:53:17:53:28 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:54:22:54:30 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:59:5:59:13 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:59:17:59:22 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:59:17:59:28 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:69:23:69:31 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:81:5:81:7 | xml | semmle.label | xml |
| UnsafeDeserialization.rb:81:11:81:16 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:81:11:81:22 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:82:34:82:36 | xml | semmle.label | xml |
| UnsafeDeserialization.rb:87:5:87:13 | yaml_data | semmle.label | yaml_data |
| UnsafeDeserialization.rb:87:17:87:22 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:87:17:87:28 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:88:25:88:33 | yaml_data | semmle.label | yaml_data |
| UnsafeDeserialization.rb:92:24:92:34 | call to read | semmle.label | call to read |
| UnsafeDeserialization.rb:95:24:95:33 | call to gets | semmle.label | call to gets |
| UnsafeDeserialization.rb:98:24:98:32 | call to read | semmle.label | call to read |
| UnsafeDeserialization.rb:101:24:101:27 | call to gets | semmle.label | call to gets |
| UnsafeDeserialization.rb:104:24:104:32 | call to readlines | semmle.label | call to readlines |
| UnsafeDeserialization.rb:55:22:55:30 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:60:5:60:13 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:60:17:60:22 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:60:17:60:28 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:70:23:70:31 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:81:4:81:12 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:81:16:81:21 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:81:16:81:27 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:82:28:82:36 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:87:4:87:11 | xml_data | semmle.label | xml_data |
| UnsafeDeserialization.rb:87:15:87:20 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:87:15:87:26 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:88:26:88:33 | xml_data | semmle.label | xml_data |
| UnsafeDeserialization.rb:93:5:93:12 | xml_data | semmle.label | xml_data |
| UnsafeDeserialization.rb:93:16:93:21 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:93:16:93:27 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:94:22:94:29 | xml_data | semmle.label | xml_data |
| UnsafeDeserialization.rb:109:5:109:7 | xml | semmle.label | xml |
| UnsafeDeserialization.rb:109:11:109:16 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:109:11:109:22 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:110:34:110:36 | xml | semmle.label | xml |
| UnsafeDeserialization.rb:115:5:115:13 | yaml_data | semmle.label | yaml_data |
| UnsafeDeserialization.rb:115:17:115:22 | call to params | semmle.label | call to params |
| UnsafeDeserialization.rb:115:17:115:28 | ...[...] | semmle.label | ...[...] |
| UnsafeDeserialization.rb:116:25:116:33 | yaml_data | semmle.label | yaml_data |
| UnsafeDeserialization.rb:120:24:120:34 | call to read | semmle.label | call to read |
| UnsafeDeserialization.rb:123:24:123:33 | call to gets | semmle.label | call to gets |
| UnsafeDeserialization.rb:126:24:126:32 | call to read | semmle.label | call to read |
| UnsafeDeserialization.rb:129:24:129:27 | call to gets | semmle.label | call to gets |
| UnsafeDeserialization.rb:132:24:132:32 | call to readlines | semmle.label | call to readlines |
| YAMLUnsafeDeserialization.rb:5:16:5:21 | call to params | semmle.label | call to params |
| YAMLUnsafeDeserialization.rb:5:16:5:35 | ...[...] | semmle.label | ...[...] |
| YAMLUnsafeDeserialization.rb:11:23:11:28 | call to params | semmle.label | call to params |
@@ -111,21 +132,24 @@ subpaths
#select
| PlistUnsafeDeserialization.rb:5:30:5:49 | ...[...] | PlistUnsafeDeserialization.rb:5:30:5:35 | call to params | PlistUnsafeDeserialization.rb:5:30:5:49 | ...[...] | Unsafe deserialization depends on a $@. | PlistUnsafeDeserialization.rb:5:30:5:35 | call to params | user-provided value |
| PlistUnsafeDeserialization.rb:6:30:6:49 | ...[...] | PlistUnsafeDeserialization.rb:6:30:6:35 | call to params | PlistUnsafeDeserialization.rb:6:30:6:49 | ...[...] | Unsafe deserialization depends on a $@. | PlistUnsafeDeserialization.rb:6:30:6:35 | call to params | user-provided value |
| UnsafeDeserialization.rb:11:27:11:41 | serialized_data | UnsafeDeserialization.rb:10:39:10:44 | call to params | UnsafeDeserialization.rb:11:27:11:41 | serialized_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:10:39:10:44 | call to params | user-provided value |
| UnsafeDeserialization.rb:17:30:17:44 | serialized_data | UnsafeDeserialization.rb:16:39:16:44 | call to params | UnsafeDeserialization.rb:17:30:17:44 | serialized_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:16:39:16:44 | call to params | user-provided value |
| UnsafeDeserialization.rb:23:24:23:32 | json_data | UnsafeDeserialization.rb:22:17:22:22 | call to params | UnsafeDeserialization.rb:23:24:23:32 | json_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:22:17:22:22 | call to params | user-provided value |
| UnsafeDeserialization.rb:29:27:29:35 | json_data | UnsafeDeserialization.rb:28:17:28:22 | call to params | UnsafeDeserialization.rb:29:27:29:35 | json_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:28:17:28:22 | call to params | user-provided value |
| UnsafeDeserialization.rb:41:24:41:32 | yaml_data | UnsafeDeserialization.rb:40:17:40:22 | call to params | UnsafeDeserialization.rb:41:24:41:32 | yaml_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:40:17:40:22 | call to params | user-provided value |
| UnsafeDeserialization.rb:53:22:53:30 | json_data | UnsafeDeserialization.rb:52:17:52:22 | call to params | UnsafeDeserialization.rb:53:22:53:30 | json_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:52:17:52:22 | call to params | user-provided value |
| UnsafeDeserialization.rb:54:22:54:30 | json_data | UnsafeDeserialization.rb:52:17:52:22 | call to params | UnsafeDeserialization.rb:54:22:54:30 | json_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:52:17:52:22 | call to params | user-provided value |
| UnsafeDeserialization.rb:69:23:69:31 | json_data | UnsafeDeserialization.rb:59:17:59:22 | call to params | UnsafeDeserialization.rb:69:23:69:31 | json_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:59:17:59:22 | call to params | user-provided value |
| UnsafeDeserialization.rb:82:34:82:36 | xml | UnsafeDeserialization.rb:81:11:81:16 | call to params | UnsafeDeserialization.rb:82:34:82:36 | xml | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:81:11:81:16 | call to params | user-provided value |
| UnsafeDeserialization.rb:88:25:88:33 | yaml_data | UnsafeDeserialization.rb:87:17:87:22 | call to params | UnsafeDeserialization.rb:88:25:88:33 | yaml_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:87:17:87:22 | call to params | user-provided value |
| UnsafeDeserialization.rb:92:24:92:34 | call to read | UnsafeDeserialization.rb:92:24:92:34 | call to read | UnsafeDeserialization.rb:92:24:92:34 | call to read | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:92:24:92:34 | call to read | value from stdin |
| UnsafeDeserialization.rb:95:24:95:33 | call to gets | UnsafeDeserialization.rb:95:24:95:33 | call to gets | UnsafeDeserialization.rb:95:24:95:33 | call to gets | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:95:24:95:33 | call to gets | value from stdin |
| UnsafeDeserialization.rb:98:24:98:32 | call to read | UnsafeDeserialization.rb:98:24:98:32 | call to read | UnsafeDeserialization.rb:98:24:98:32 | call to read | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:98:24:98:32 | call to read | value from stdin |
| UnsafeDeserialization.rb:101:24:101:27 | call to gets | UnsafeDeserialization.rb:101:24:101:27 | call to gets | UnsafeDeserialization.rb:101:24:101:27 | call to gets | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:101:24:101:27 | call to gets | value from stdin |
| UnsafeDeserialization.rb:104:24:104:32 | call to readlines | UnsafeDeserialization.rb:104:24:104:32 | call to readlines | UnsafeDeserialization.rb:104:24:104:32 | call to readlines | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:104:24:104:32 | call to readlines | value from stdin |
| UnsafeDeserialization.rb:12:27:12:41 | serialized_data | UnsafeDeserialization.rb:11:39:11:44 | call to params | UnsafeDeserialization.rb:12:27:12:41 | serialized_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:11:39:11:44 | call to params | user-provided value |
| UnsafeDeserialization.rb:18:30:18:44 | serialized_data | UnsafeDeserialization.rb:17:39:17:44 | call to params | UnsafeDeserialization.rb:18:30:18:44 | serialized_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:17:39:17:44 | call to params | user-provided value |
| UnsafeDeserialization.rb:24:24:24:32 | json_data | UnsafeDeserialization.rb:23:17:23:22 | call to params | UnsafeDeserialization.rb:24:24:24:32 | json_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:23:17:23:22 | call to params | user-provided value |
| UnsafeDeserialization.rb:30:27:30:35 | json_data | UnsafeDeserialization.rb:29:17:29:22 | call to params | UnsafeDeserialization.rb:30:27:30:35 | json_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:29:17:29:22 | call to params | user-provided value |
| UnsafeDeserialization.rb:42:24:42:32 | yaml_data | UnsafeDeserialization.rb:41:17:41:22 | call to params | UnsafeDeserialization.rb:42:24:42:32 | yaml_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:41:17:41:22 | call to params | user-provided value |
| UnsafeDeserialization.rb:54:22:54:30 | json_data | UnsafeDeserialization.rb:53:17:53:22 | call to params | UnsafeDeserialization.rb:54:22:54:30 | json_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:53:17:53:22 | call to params | user-provided value |
| UnsafeDeserialization.rb:55:22:55:30 | json_data | UnsafeDeserialization.rb:53:17:53:22 | call to params | UnsafeDeserialization.rb:55:22:55:30 | json_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:53:17:53:22 | call to params | user-provided value |
| UnsafeDeserialization.rb:70:23:70:31 | json_data | UnsafeDeserialization.rb:60:17:60:22 | call to params | UnsafeDeserialization.rb:70:23:70:31 | json_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:60:17:60:22 | call to params | user-provided value |
| UnsafeDeserialization.rb:82:28:82:36 | json_data | UnsafeDeserialization.rb:81:16:81:21 | call to params | UnsafeDeserialization.rb:82:28:82:36 | json_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:81:16:81:21 | call to params | user-provided value |
| UnsafeDeserialization.rb:88:26:88:33 | xml_data | UnsafeDeserialization.rb:87:15:87:20 | call to params | UnsafeDeserialization.rb:88:26:88:33 | xml_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:87:15:87:20 | call to params | user-provided value |
| UnsafeDeserialization.rb:94:22:94:29 | xml_data | UnsafeDeserialization.rb:93:16:93:21 | call to params | UnsafeDeserialization.rb:94:22:94:29 | xml_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:93:16:93:21 | call to params | user-provided value |
| UnsafeDeserialization.rb:110:34:110:36 | xml | UnsafeDeserialization.rb:109:11:109:16 | call to params | UnsafeDeserialization.rb:110:34:110:36 | xml | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:109:11:109:16 | call to params | user-provided value |
| UnsafeDeserialization.rb:116:25:116:33 | yaml_data | UnsafeDeserialization.rb:115:17:115:22 | call to params | UnsafeDeserialization.rb:116:25:116:33 | yaml_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:115:17:115:22 | call to params | user-provided value |
| UnsafeDeserialization.rb:120:24:120:34 | call to read | UnsafeDeserialization.rb:120:24:120:34 | call to read | UnsafeDeserialization.rb:120:24:120:34 | call to read | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:120:24:120:34 | call to read | value from stdin |
| UnsafeDeserialization.rb:123:24:123:33 | call to gets | UnsafeDeserialization.rb:123:24:123:33 | call to gets | UnsafeDeserialization.rb:123:24:123:33 | call to gets | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:123:24:123:33 | call to gets | value from stdin |
| UnsafeDeserialization.rb:126:24:126:32 | call to read | UnsafeDeserialization.rb:126:24:126:32 | call to read | UnsafeDeserialization.rb:126:24:126:32 | call to read | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:126:24:126:32 | call to read | value from stdin |
| UnsafeDeserialization.rb:129:24:129:27 | call to gets | UnsafeDeserialization.rb:129:24:129:27 | call to gets | UnsafeDeserialization.rb:129:24:129:27 | call to gets | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:129:24:129:27 | call to gets | value from stdin |
| UnsafeDeserialization.rb:132:24:132:32 | call to readlines | UnsafeDeserialization.rb:132:24:132:32 | call to readlines | UnsafeDeserialization.rb:132:24:132:32 | call to readlines | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:132:24:132:32 | call to readlines | value from stdin |
| YAMLUnsafeDeserialization.rb:5:16:5:35 | ...[...] | YAMLUnsafeDeserialization.rb:5:16:5:21 | call to params | YAMLUnsafeDeserialization.rb:5:16:5:35 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:5:16:5:21 | call to params | user-provided value |
| YAMLUnsafeDeserialization.rb:11:23:11:42 | ...[...] | YAMLUnsafeDeserialization.rb:11:23:11:28 | call to params | YAMLUnsafeDeserialization.rb:11:23:11:42 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:11:23:11:28 | call to params | user-provided value |
| YAMLUnsafeDeserialization.rb:12:28:12:45 | ...[...] | YAMLUnsafeDeserialization.rb:12:28:12:33 | call to params | YAMLUnsafeDeserialization.rb:12:28:12:45 | ...[...] | Unsafe deserialization depends on a $@. | YAMLUnsafeDeserialization.rb:12:28:12:33 | call to params | user-provided value |

View File

@@ -2,6 +2,7 @@ require "active_job"
require "base64"
require "json"
require "oj"
require "ox"
require "yaml"
class UsersController < ActionController::Base
@@ -75,15 +76,42 @@ class UsersController < ActionController::Base
object = Oj.safe_load json_data
end
# BAD - Oj.object_load is always unsafe
def route10
json_data = params[:key]
object = Oj.object_load json_data
end
# BAD - Ox.parse_obj is always unsafe
def route11
xml_data = params[:key]
object = Ox.parse_obj xml_data
end
# BAD - Ox.load with :object mode is always unsafe
def route12
xml_data = params[:key]
object = Ox.load xml_data, mode: :object
end
# GOOD - Ox.load is safe in the default mode (which is :generic) and in any other mode than :object
def route13
xml_data = params[:key]
object1 = Ox.load xml_data
object2 = Ox.load xml_data, mode: :limited
object3 = Ox.load xml_data, mode: :hash
object4 = Ox.load xml_data, mode: :generic
end
# BAD - `Hash.from_trusted_xml` will deserialize elements with the
# `type="yaml"` attribute as YAML.
def route10
def route14
xml = params[:key]
hash = Hash.from_trusted_xml(xml)
end
# BAD
def route11
def route15
yaml_data = params[:key]
object = Psych.load yaml_data
end