mirror of
https://github.com/github/codeql.git
synced 2026-04-28 02:05:14 +02:00
Merge branch 'main' into henti/update_dotnet
This commit is contained in:
4
cpp/ql/lib/change-notes/2024-01-30-throwing-model.md
Normal file
4
cpp/ql/lib/change-notes/2024-01-30-throwing-model.md
Normal 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.
|
||||
@@ -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()
|
||||
)
|
||||
|
||||
@@ -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() }
|
||||
|
||||
@@ -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))
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -39,3 +39,4 @@ private import implementations.ODBC
|
||||
private import implementations.SqLite3
|
||||
private import implementations.PostgreSql
|
||||
private import implementations.System
|
||||
private import implementations.StructuredExceptionHandling
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
22
cpp/ql/lib/semmle/code/cpp/models/interfaces/Throwing.qll
Normal file
22
cpp/ql/lib/semmle/code/cpp/models/interfaces/Throwing.qll
Normal 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);
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
* ```
|
||||
@@ -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>:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Remove `compilation_expanded_args`.
|
||||
compatibility: backwards
|
||||
compilation_expanded_args.rel: delete
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 |
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
var dummy = "dummy";
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "8.0.100"
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -0,0 +1,3 @@
|
||||
from create_database_utils import *
|
||||
|
||||
run_codeql_database_create([], lang="csharp", extra_args=["--extractor-option=cil=false"])
|
||||
@@ -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`.
|
||||
@@ -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) }
|
||||
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Add `compilation_expanded_args`.
|
||||
compatibility: backwards
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Diagnostics/ExtractedFiles.ql
|
||||
@@ -1 +0,0 @@
|
||||
Diagnostics/SuccessfullyExtractedFiles.ql
|
||||
4
python/ql/lib/change-notes/2024-01-22-html-escape.md
Normal file
4
python/ql/lib/change-notes/2024-01-22-html-escape.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added `html.escape` as a sanitizer for HTML.
|
||||
@@ -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() }
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -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)
|
||||
@@ -0,0 +1 @@
|
||||
Diagnostics/ExtractedFiles.ql
|
||||
@@ -1 +0,0 @@
|
||||
Diagnostics/SuccessfullyExtractedFiles.ql
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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` */
|
||||
|
||||
@@ -77,7 +77,7 @@ class Node extends TNode {
|
||||
or
|
||||
exists(DataFlowCallable c |
|
||||
lambdaCreation(this, _, c) and
|
||||
result.asCallableAstNode() = c.asCallable()
|
||||
result.asCallableAstNode() = c.asCfgScope()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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.
|
||||
@@ -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"
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
queries/diagnostics/ExtractedFiles.ql
|
||||
@@ -1 +0,0 @@
|
||||
queries/diagnostics/SuccessfullyExtractedFiles.ql
|
||||
@@ -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
|
||||
@@ -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 }
|
||||
@@ -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 |
|
||||
@@ -0,0 +1 @@
|
||||
queries/security/cwe-502/UnsafeDeserialization.ql
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user