Skip to content
Closed
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ 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 semmle.code.cpp.models.interfaces.NonThrowing
private import InstructionTag
private import SideEffects
private import TranslatedElement
Expand Down Expand Up @@ -84,12 +85,14 @@ abstract class TranslatedCall extends TranslatedExpr {
this.getEnclosingFunction().getFunction() = instr.getEnclosingFunction()
)
else (
not this.mustThrowException() and
not this.mustThrowException(_) and
result = this.getParent().getChildSuccessor(this, kind)
or
this.mayThrowException() and
kind instanceof CppExceptionEdge and
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
exists(ExceptionEdge e | this.hasExceptionBehavior(e) |
this.mayThrowException(e) and
kind = e and
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
)
)
}

Expand Down Expand Up @@ -118,13 +121,42 @@ abstract class TranslatedCall extends TranslatedExpr {

/**
* Holds if the evaluation of this call may throw an exception.
* The edge `e` determines what type of exception is being considered,
* `CppExceptionEdge` or `SehExceptionEdge`.
*/
abstract predicate mayThrowException();
abstract predicate mayThrowException(ExceptionEdge e);

/**
* Holds if the evaluation of this call always throws an exception.
* The edge `e` determines what type of exception is being considered,
* `CppExceptionEdge` or `SehExceptionEdge`.
*/
abstract predicate mustThrowException(ExceptionEdge e);

/**
* Holds when the call target is known to never raise an exception.
* The edge `e` determines what type of exception is being considered,
* `CppExceptionEdge` or `SehExceptionEdge`.
*
* Note that `alwaysRaiseException`, `mayRaiseException`,
* and `neverRaiseException` may conflict (e.g., all hold for a given target).
* Conflicting results are resolved during IR generation.
*/
abstract predicate mustThrowException();
abstract predicate neverThrowException(ExceptionEdge e);

/**
* Holds if the call has any exception behavior defined for exception edge type `e`,
* i.e., if the function is known to throw or never throw an exception.
* This handles cases where a function has no annotation to specify
* if a function throws or doesn't throw.
*/
final predicate hasExceptionBehavior(ExceptionEdge e) {
this.mayThrowException(e)
or
this.mustThrowException(e)
or
this.neverThrowException(e)
}

/**
* Gets the result type of the call.
Expand Down Expand Up @@ -320,6 +352,39 @@ abstract class TranslatedCallExpr extends TranslatedNonConstantExpr, TranslatedC
final override int getNumberOfArguments() { result = expr.getNumberOfArguments() }

final override predicate isNoReturn() { any(Options opt).exits(expr.getTarget()) }

override predicate mustThrowException(ExceptionEdge e) {
// Functions that always raise exceptions only occur with Seh exceptions
// Use the `AlwaysSehThrowingFunction` instance unless the function is known to never throw
not this.neverThrowException(e) and
expr.getTarget() instanceof AlwaysSehThrowingFunction and
e instanceof SehExceptionEdge
}

override predicate mayThrowException(ExceptionEdge e) {
// by default, all functions may throw exceptions of any kind
// unless explicitly annotated to never throw
// Only consider a call to "may" throw an Seh exception
// if inside a MicrosoftTryStmt
not this.neverThrowException(e) and
(
this.mustThrowException(e)
or
// for now assuming all calls may throw for Seh only
e instanceof SehExceptionEdge and
exists(MicrosoftTryStmt trystmt | trystmt.getAChild*() = expr)
)
}

override predicate neverThrowException(ExceptionEdge e) {
// currently, only functions can only explicitly stipulate they
// never through a C++ exception
// NOTE: we cannot simply check if not exists may and must throw.
// since an annotation exists to override any other behavior
// i.e., `NonCppThrowingFunction`.
e instanceof CppExceptionEdge and
expr.getTarget() instanceof NonCppThrowingFunction
}
}

/**
Expand All @@ -332,14 +397,16 @@ class TranslatedExprCall extends TranslatedCallExpr {
result = getTranslatedExpr(expr.getExpr().getFullyConverted())
}

final override predicate mayThrowException() {
final override predicate mayThrowException(ExceptionEdge e) { none() }

final override predicate mustThrowException(ExceptionEdge e) { none() }

final override predicate neverThrowException(ExceptionEdge e) {
// 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()
any()
}

final override predicate mustThrowException() { none() }
}

/**
Expand All @@ -361,18 +428,6 @@ 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(_)
or
expr.getTarget() instanceof AlwaysSehThrowingFunction
}

final override predicate mustThrowException() {
expr.getTarget().(ThrowingFunction).mayThrowException(true)
or
expr.getTarget() instanceof AlwaysSehThrowingFunction
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ private import TranslatedInitialization
private import TranslatedStmt
private import TranslatedGlobalVar
private import IRConstruction
private import EdgeKind
import TranslatedCall

/**
Expand Down Expand Up @@ -391,7 +392,15 @@ class TranslatedLoad extends TranslatedValueCategoryAdjustment, TTranslatedLoad

override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
tag = LoadTag() and
result = this.getParent().getChildSuccessor(this, kind)
(
result = this.getParent().getChildSuccessor(this, kind)
or
// All load instructions could throw an Seh exception
// If the load is in a MicrosoftTryStmt, add an exception edge
kind = sehExceptionEdge() and
exists(MicrosoftTryStmt trystmt | trystmt.getAChild*() = expr) and
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge e))
)
}

override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
Expand Down Expand Up @@ -2375,14 +2384,16 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect
result = getTranslatedExpr(expr.getAllocatorCall().getArgument(index).getFullyConverted())
}

final override predicate mayThrowException() {
final override predicate mayThrowException(ExceptionEdge e) { none() }

final override predicate mustThrowException(ExceptionEdge e) { none() }

final override predicate neverThrowException(ExceptionEdge e) {
// We assume that a call to `new` or `new[]` will never throw. This is not
// sound in general, but this will greatly reduce the number of exceptional
// edges.
none()
any()
}

final override predicate mustThrowException() { none() }
}

TranslatedAllocatorCall getTranslatedAllocatorCall(NewOrNewArrayExpr newExpr) {
Expand Down Expand Up @@ -2448,14 +2459,16 @@ class TranslatedDeleteOrDeleteArrayExpr extends TranslatedNonConstantExpr, Trans
result = getTranslatedExpr(expr.getExprWithReuse().getFullyConverted())
}

final override predicate mayThrowException() {
final override predicate mayThrowException(ExceptionEdge e) { none() }

final override predicate mustThrowException(ExceptionEdge e) { none() }

final override predicate neverThrowException(ExceptionEdge e) {
// We assume that a call to `delete` or `delete[]` will never throw. This is not
// sound in general, but this will greatly reduce the number of exceptional
// edges.
none()
any()
}

final override predicate mustThrowException() { none() }
}

TranslatedDeleteOrDeleteArrayExpr getTranslatedDeleteOrDeleteArray(DeleteOrDeleteArrayExpr newExpr) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ class TranslatedFunction extends TranslatedRootElement, TTranslatedFunction {
exists(ThrowExpr throw | throw.getEnclosingFunction() = func)
or
exists(FunctionCall call | call.getEnclosingFunction() = func |
getTranslatedExpr(call).(TranslatedCallExpr).mayThrowException()
getTranslatedExpr(call).(TranslatedCallExpr).mayThrowException(_)
)
)
or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ private import InstructionTag
private import TranslatedElement
private import TranslatedExpr
private import TranslatedFunction
private import EdgeKind

/**
* Gets the `TranslatedInitialization` for the expression `expr`.
Expand Down Expand Up @@ -281,7 +282,15 @@ class TranslatedSimpleDirectInitialization extends TranslatedDirectInitializatio

override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
tag = InitializerStoreTag() and
result = this.getParent().getChildSuccessor(this, kind)
(
result = this.getParent().getChildSuccessor(this, kind)
or
// All store instructions could throw an Seh exception
// If the store is in a MicrosoftTryStmt, add an exception edge
kind = sehExceptionEdge() and
exists(MicrosoftTryStmt trystmt | trystmt.getAChild*() = expr) and
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge e))
)
}

override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
Expand Down Expand Up @@ -359,7 +368,15 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
kind instanceof GotoEdge and
tag = InitializerLoadStringTag() and
result = this.getInstruction(InitializerStoreTag())
(
result = this.getInstruction(InitializerStoreTag())
or
// All load/store instructions could throw an Seh exception
// If the load/store is in a MicrosoftTryStmt, add an exception edge
kind = sehExceptionEdge() and
exists(MicrosoftTryStmt trystmt | trystmt.getAChild*() = expr) and
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge e))
)
or
if this.zeroInitRange(_, _)
then (
Expand Down Expand Up @@ -650,7 +667,15 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
)
or
tag = this.getFieldDefaultValueStoreTag() and
result = this.getParent().getChildSuccessor(this, kind)
(
result = this.getParent().getChildSuccessor(this, kind)
or
// All load/store instructions could throw an Seh exception
// If the load/store is in a MicrosoftTryStmt, add an exception edge
kind = sehExceptionEdge() and
exists(MicrosoftTryStmt trystmt | trystmt.getAChild*() = ast) and
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge e))
)
}

override string getInstructionConstantValue(InstructionTag tag) {
Expand Down Expand Up @@ -850,7 +875,15 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati
)
or
tag = this.getElementDefaultValueStoreTag() and
result = this.getParent().getChildSuccessor(this, kind)
(
result = this.getParent().getChildSuccessor(this, kind)
or
// All load/store instructions could throw an Seh exception
// If the load/store is in a MicrosoftTryStmt, add an exception edge
kind = sehExceptionEdge() and
exists(MicrosoftTryStmt trystmt | trystmt.getAChild*() = initList) and
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge e))
)
}

override string getInstructionConstantValue(InstructionTag tag) {
Expand Down
8 changes: 7 additions & 1 deletion cpp/ql/lib/semmle/code/cpp/models/interfaces/Throwing.qll
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@ import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs

/**
* A function that is known to raise an exception.
*
* DEPRECATED: This was originally used to differentiate Seh and C++ exception use.
* `AlwaysSehThrowingFunction` should be used instead for Seh exceptions that are
* known to always throw and
* `NonCppThrowingFunction` in `semmle.code.cpp.models.interfaces.NonThrowing`
* should be used for C++ exceptions that are known to never throw.
*/
abstract class ThrowingFunction extends Function {
abstract deprecated class ThrowingFunction extends Function {
/**
* Holds if this function may throw an exception during evaluation.
* If `unconditional` is `true` the function always throws an exception.
Expand Down
Loading