Skip to content

Commit 1dfd32e

Browse files
committed
C++: Model function calls throwing exceptions.
1 parent eb94203 commit 1dfd32e

File tree

5 files changed

+86
-1
lines changed

5 files changed

+86
-1
lines changed

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ private import semmle.code.cpp.ir.implementation.Opcode
33
private import semmle.code.cpp.ir.implementation.internal.OperandTag
44
private import semmle.code.cpp.ir.internal.CppType
55
private import semmle.code.cpp.models.interfaces.SideEffect
6+
private import semmle.code.cpp.models.interfaces.Throwing
67
private import InstructionTag
78
private import SideEffects
89
private import TranslatedElement
@@ -76,7 +77,14 @@ abstract class TranslatedCall extends TranslatedExpr {
7677
any(UnreachedInstruction instr |
7778
this.getEnclosingFunction().getFunction() = instr.getEnclosingFunction()
7879
)
79-
else result = this.getParent().getChildSuccessor(this, kind)
80+
else (
81+
not this.mustThrowException() and
82+
result = this.getParent().getChildSuccessor(this, kind)
83+
or
84+
this.mayThrowException() and
85+
kind instanceof ExceptionEdge and
86+
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
87+
)
8088
}
8189

8290
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -102,6 +110,16 @@ abstract class TranslatedCall extends TranslatedExpr {
102110

103111
final override Instruction getResult() { result = this.getInstruction(CallTag()) }
104112

113+
/**
114+
* Holds if the evaluation of this call may throw an exception.
115+
*/
116+
abstract predicate mayThrowException();
117+
118+
/**
119+
* Holds if the evaluation of this call always throws an exception.
120+
*/
121+
abstract predicate mustThrowException();
122+
105123
/**
106124
* Gets the result type of the call.
107125
*/
@@ -295,6 +313,15 @@ class TranslatedExprCall extends TranslatedCallExpr {
295313
override TranslatedExpr getCallTarget() {
296314
result = getTranslatedExpr(expr.getExpr().getFullyConverted())
297315
}
316+
317+
final override predicate mayThrowException() {
318+
// We assume that a call to a function pointer will not throw an exception.
319+
// This is not sound in general, but this will greatly reduce the number of
320+
// exceptional edges.
321+
none()
322+
}
323+
324+
final override predicate mustThrowException() { none() }
298325
}
299326

300327
/**
@@ -316,6 +343,14 @@ class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
316343
exists(this.getQualifier()) and
317344
not exists(MemberFunction func | expr.getTarget() = func and func.isStatic())
318345
}
346+
347+
final override predicate mayThrowException() {
348+
expr.getTarget().(ThrowingFunction).mayThrowException(_)
349+
}
350+
351+
final override predicate mustThrowException() {
352+
expr.getTarget().(ThrowingFunction).mayThrowException(true)
353+
}
319354
}
320355

321356
/**

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2063,6 +2063,15 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect
20632063
else
20642064
result = getTranslatedExpr(expr.getAllocatorCall().getArgument(index).getFullyConverted())
20652065
}
2066+
2067+
final override predicate mayThrowException() {
2068+
// We assume that a call to `new` or `new[]` will never throw. This is not
2069+
// sound in general, but this will greatly reduce the number of exceptional
2070+
// edges.
2071+
none()
2072+
}
2073+
2074+
final override predicate mustThrowException() { none() }
20662075
}
20672076

20682077
TranslatedAllocatorCall getTranslatedAllocatorCall(NewOrNewArrayExpr newExpr) {
@@ -2123,6 +2132,15 @@ class TranslatedDeleteOrDeleteArrayExpr extends TranslatedNonConstantExpr, Trans
21232132
index = 0 and
21242133
result = getTranslatedExpr(expr.getExpr().getFullyConverted())
21252134
}
2135+
2136+
final override predicate mayThrowException() {
2137+
// We assume that a call to `delete` or `delete[]` will never throw. This is not
2138+
// sound in general, but this will greatly reduce the number of exceptional
2139+
// edges.
2140+
none()
2141+
}
2142+
2143+
final override predicate mustThrowException() { none() }
21262144
}
21272145

21282146
TranslatedDeleteOrDeleteArrayExpr getTranslatedDeleteOrDeleteArray(DeleteOrDeleteArrayExpr newExpr) {

cpp/ql/lib/semmle/code/cpp/models/Models.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,4 @@ private import implementations.ODBC
3939
private import implementations.SqLite3
4040
private import implementations.PostgreSql
4141
private import implementations.System
42+
private import implementations.StructuredExceptionHandling
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import semmle.code.cpp.models.interfaces.Throwing
2+
3+
class WindowsDriverFunction extends ThrowingFunction {
4+
WindowsDriverFunction() {
5+
this.hasGlobalName(["RaiseException", "ExRaiseAccessViolation", "ExRaiseDatatypeMisalignment"])
6+
}
7+
8+
final override predicate mayThrowException(boolean unconditional) { unconditional = true }
9+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Provides an abstract class for modeling whether a function may throw an
3+
* exception.
4+
* To use this QL library, create a QL class extending `ThrowingFunction` with
5+
* a characteristic predicate that selects the function or set of functions you
6+
* are modeling the exceptional flow of.
7+
*/
8+
9+
import semmle.code.cpp.Function
10+
import semmle.code.cpp.models.Models
11+
import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
12+
13+
/**
14+
* A class that models the exceptional behavior of a function.
15+
*/
16+
abstract class ThrowingFunction extends Function {
17+
/**
18+
* Holds if this function may throw an exception during evaluation.
19+
* If `unconditional` is `true` the function always throws an exception.
20+
*/
21+
abstract predicate mayThrowException(boolean unconditional);
22+
}

0 commit comments

Comments
 (0)