Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Brodes/seh flow phase3.2 add load store seh exceptions #18260

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
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
Loading