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 overhaul2 #17676

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
652b74d
Altering TExceptionEdge to include SEH and regular C++ exceptions, an…
bdrodes Oct 1, 2024
82cdd02
Overhaul of IR exception handling to account for SEH and C++ exceptions.
bdrodes Oct 2, 2024
a818346
Fixing bug in translated call edge generation.
bdrodes Oct 3, 2024
a2ede08
Finalizing a model for throwing and non-throwing functions.
bdrodes Oct 7, 2024
0ed72d1
Propagating the exception kind into getExceptionSuccessorInstruction
bdrodes Oct 7, 2024
e3d0015
updating getNextHandler logic.
bdrodes Oct 7, 2024
7a3ab8c
Review updates to EdgeKind.qll
bdrodes Oct 10, 2024
d0a54a3
Review updates.
bdrodes Oct 10, 2024
fcff607
PR review corrections.
bdrodes Oct 15, 2024
fdf5ac6
Formatting.
bdrodes Oct 23, 2024
a053519
Removing SEH load exceptions for var args and lambda translations
bdrodes Oct 23, 2024
e86c764
Updated comments and formatting.
bdrodes Oct 23, 2024
a40343e
Updating comments.
bdrodes Oct 23, 2024
cc4b280
Comments and changed char pred (moved up to abstract class)
bdrodes Oct 23, 2024
fb16db2
Formatting.
bdrodes Oct 23, 2024
781a9b7
Typo
bdrodes Oct 23, 2024
30810ce
Merge branch 'main' into brodes/seh_flow_overhaul2
bdrodes Oct 23, 2024
a498c87
adding change log
bdrodes Oct 24, 2024
aeeafbc
Merge branch 'brodes/seh_flow_overhaul2' of https://github.com/micros…
bdrodes Oct 24, 2024
61b1fef
Comments
bdrodes Oct 24, 2024
f85ba7a
Updating docs
bdrodes Oct 24, 2024
9dc776e
Type in comments.
bdrodes Oct 24, 2024
3f01e4d
changing isSEH to isSeh to match conventions.
bdrodes Oct 24, 2024
222c9f2
Style changes.
bdrodes Oct 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions cpp/ql/lib/semmle/code/cpp/ir/implementation/EdgeKind.qll
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
TGotoEdge() or // Single successor (including fall-through)
TTrueEdge() or // 'true' edge of conditional branch
TFalseEdge() or // 'false' edge of conditional branch
TExceptionEdge() or // Thrown exception
TExceptionEdge(boolean isSEH){isSEH in [true, false]} or // Thrown exception, true for SEH exceptions, false otherwise

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in isSEH should be PascalCase/camelCase.
MathiasVP marked this conversation as resolved.
Show resolved Hide resolved
TDefaultEdge() or // 'default' label of switch
TCaseEdge(string minValue, string maxValue) {
// Case label of switch
Expand Down Expand Up @@ -54,7 +54,18 @@
* instruction's evaluation throws an exception.
*/
class ExceptionEdge extends EdgeKind, TExceptionEdge {
final override string toString() { result = "Exception" }
boolean isSEH; //true for Structured Exception Handling, false for C++ exceptions

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in isSEH should be PascalCase/camelCase.

ExceptionEdge() { this = TExceptionEdge(isSEH) }

/**
* Holds if the exception is a Structured Exception Handling (SEH) exception.
*/
final predicate isSEH() { isSEH = true }

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in isSEH should be PascalCase/camelCase.

final override string toString() {
result = "Exception"
MathiasVP marked this conversation as resolved.
Show resolved Hide resolved
}
}

/**
Expand Down Expand Up @@ -123,7 +134,7 @@
/**
* Gets the single instance of the `ExceptionEdge` class.
MathiasVP marked this conversation as resolved.
Show resolved Hide resolved
*/
ExceptionEdge exceptionEdge() { result = TExceptionEdge() }
ExceptionEdge exceptionEdge() { result = TExceptionEdge(_) }
MathiasVP marked this conversation as resolved.
Show resolved Hide resolved

/**
* Gets the single instance of the `DefaultEdge` class.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,38 @@
any(UnreachedInstruction instr |
this.getEnclosingFunction().getFunction() = instr.getEnclosingFunction()
)
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))
)
else
exists(boolean isSEH |

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in isSEH should be PascalCase/camelCase.
isSEH = true and kind.(ExceptionEdge).isSEH()
or
isSEH = false and not kind.(ExceptionEdge).isSEH()
MathiasVP marked this conversation as resolved.
Show resolved Hide resolved
|
// Call throw behavior is resolved from most restricted to least restricted in order
// if there are conflicting throwing specificaitons for a function.
// Enumerating all scenarios to be explicit.
(
// If the call is known to never throw, regardless of other defined throwing behavior,
// do not generate any exception edges, only an ordinary successor
if this.(TranslatedCallExpr).neverRaiseException(isSEH)
then result = this.getParent().getChildSuccessor(this, kind)
MathiasVP marked this conversation as resolved.
Show resolved Hide resolved
else
// If the call is known to always throw, regardless of other defined throwing behavior,
// only generate an exception edge.
if this.(TranslatedCallExpr).alwaysRaiseException(isSEH)
then result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge), isSEH)
else
if this.(TranslatedCallExpr).mayRaiseException(isSEH)
then (
// if the call is known to conditionally throw, generate both an exception edge and an
// ordinary successor
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge), isSEH)
or
result = this.getParent().getChildSuccessor(this, kind)
) else
// fallthrough case, no exceptions, just get the ordinary successor
result = this.getParent().getChildSuccessor(this, kind)
)
)
}

override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
Expand All @@ -117,14 +141,28 @@
final override Instruction getResult() { result = this.getInstruction(CallTag()) }

/**
* Holds if the evaluation of this call may throw an exception.
* The call target is known to always raise an exception.
* 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 alwaysRaiseException(boolean isSEH);

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in isSEH should be PascalCase/camelCase.

/**
* The call target is known to conditionally raise an exception.
* Note that `alwaysRaiseException`, `mayRaiseException`,
* and `neverRaiseException` may conflict (e.g., all hold for a given target).
* Conflicting results are resolved during IR generation.
*/

Check warning

Code scanning / CodeQL

Predicate QLDoc style. Warning

The QLDoc for a predicate without a result should start with 'Holds'.
abstract predicate mayThrowException();
abstract predicate mayRaiseException(boolean isSEH);

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in isSEH should be PascalCase/camelCase.

/**
* Holds if the evaluation of this call always throws an exception.
* The call target is known to never raise an exception.
* 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 neverRaiseException(boolean isSEH);

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in isSEH should be PascalCase/camelCase.

/**
* Gets the result type of the call.
Expand Down Expand Up @@ -320,6 +358,34 @@
final override int getNumberOfArguments() { result = expr.getNumberOfArguments() }

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

override Function getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and result = expr.getTarget()
}

override predicate alwaysRaiseException(boolean isSEH) {

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in isSEH should be PascalCase/camelCase.
exists(ThrowingFunction f | f = expr.getTarget() |
f.alwaysRaisesException() and f.isSEH() and isSEH = true
or
f.alwaysRaisesException() and f.isCxx() and isSEH = false
)
}

override predicate mayRaiseException(boolean isSEH) {

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in isSEH should be PascalCase/camelCase.
exists(ThrowingFunction f | f = expr.getTarget() |
f.mayRaiseException() and f.isSEH() and isSEH = true
or
f.mayRaiseException() and f.isCxx() and isSEH = false
)
}

override predicate neverRaiseException(boolean isSEH) {

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in isSEH should be PascalCase/camelCase.
exists(NonThrowingFunction f | f = expr.getTarget() |
f.isSEH() and isSEH = true
or
f.isCxx() and isSEH = false
)
}
}

/**
Expand All @@ -332,14 +398,44 @@
result = getTranslatedExpr(expr.getExpr().getFullyConverted())
}

final override predicate mayThrowException() {
// We assume that a call to a function pointer will not throw an exception.
override predicate alwaysRaiseException(boolean isSEH) {

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in isSEH should be PascalCase/camelCase.
// We assume that a call to a function pointer will not throw a CXX exception.
// This is not sound in general, but this will greatly reduce the number of
// exceptional edges.
none()
// For SEH exceptions, use the defined ThrowingFunction behavior and
// if no throwing function is found, assume a conditional SEH exception
// see `mayRaiseException`
exists(ThrowingFunction f | f = expr.getTarget() |
f.alwaysRaisesException() and f.isSEH() and isSEH = true
)
}

override predicate mayRaiseException(boolean isSEH) {

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in isSEH should be PascalCase/camelCase.
// We assume that a call to a function pointer will not throw a CXX exception.
// This is not sound in general, but this will greatly reduce the number of
// exceptional edges.
// For SEH exceptions, use the defined ThrowingFunction behavior.
// ASSUMPTION: if no ThrowingFunction is found for the given call, assume a conditional SEH exception
// on the call.
exists(ThrowingFunction f | f = expr.getTarget() |
f.mayRaiseException() and f.isSEH() and isSEH = true
)
or
not exists(ThrowingFunction f | f = expr.getTarget() and f.isSEH()) and
isSEH = true
}

final override predicate mustThrowException() { none() }
override predicate neverRaiseException(boolean isSEH) {

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in isSEH should be PascalCase/camelCase.
// We assume that a call to a function pointer will not throw a CXX exception.
// This is not sound in general, but this will greatly reduce the number of
// exceptional edges.
// For SEH exceptions, use the defined ThrowingFunction behavior and
// if no throwing function is found, assume a conditional SEH exception
// see `mayRaiseException`
exists(NonThrowingFunction f | f = expr.getTarget() |
f.isSEH() and isSEH = true
)
}
}

/**
Expand All @@ -348,10 +444,6 @@
class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
override FunctionCall expr;

override Function getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and result = expr.getTarget()
}

override Instruction getQualifierResult() {
this.hasQualifier() and
result = this.getQualifier().getResult()
Expand All @@ -361,14 +453,6 @@
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)
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,14 @@ class TranslatedStaticLocalVariableDeclarationEntry extends TranslatedDeclaratio
result = this.getInstruction(DynamicInitializationFlagLoadTag())
or
tag = DynamicInitializationFlagLoadTag() and
kind instanceof GotoEdge and
result = this.getInstruction(DynamicInitializationConditionalBranchTag())
(
kind instanceof GotoEdge and
result = this.getInstruction(DynamicInitializationConditionalBranchTag())
or
// All load instructions may throw an SEH exception
kind.(ExceptionEdge).isSEH() and
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge e), true)
MathiasVP marked this conversation as resolved.
Show resolved Hide resolved
)
or
tag = DynamicInitializationConditionalBranchTag() and
(
Expand All @@ -182,7 +188,12 @@ class TranslatedStaticLocalVariableDeclarationEntry extends TranslatedDeclaratio
result = this.getInstruction(DynamicInitializationFlagStoreTag())
or
tag = DynamicInitializationFlagStoreTag() and
result = this.getParent().getChildSuccessor(this, kind)
(
result = this.getParent().getChildSuccessor(this, kind)
or
// All store instructions may throw an SEH exception
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge e), true) and kind.(ExceptionEdge).isSEH()
MathiasVP marked this conversation as resolved.
Show resolved Hide resolved
)
}

final override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1104,9 +1104,13 @@
* 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`. The successor edge kind is specified by `kind`.
*
* `isSEH` is true if the exception is a structured exception, false if otherwise.
* The boolean value can be extracted from `ExceptionEdge` from the exception
* edge triggering the call to this function.
*/
Instruction getExceptionSuccessorInstruction(EdgeKind kind) {
result = this.getParent().getExceptionSuccessorInstruction(kind)
Instruction getExceptionSuccessorInstruction(EdgeKind kind, boolean isSEH) {

Check warning

Code scanning / CodeQL

Acronyms should be PascalCase/camelCase. Warning

Acronyms in isSEH should be PascalCase/camelCase.
result = this.getParent().getExceptionSuccessorInstruction(kind, isSEH)
}

/**
Expand Down
Loading
Loading