Files
codeql/csharp/ql/lib/semmle/code/cil/Handler.qll
Andrew Eisenberg c9f1c98390 Packaging: C# refactoring
Split c# pack into `codeql/csharp-all` and `codeql/csharp-queries`.
2021-08-19 14:09:35 -07:00

84 lines
3.1 KiB
Plaintext

/**
* Provides classes for different types of handler.
*/
private import CIL
/**
* A handler is a piece of code that can be executed out of sequence, for example
* when an instruction generates an exception or leaves a `finally` block.
*
* Each handler has a scope representing the block of instructions guarded by
* this handler (corresponding to a C# `try { ... }` block), and a block of instructions
* to execute when the handler is triggered (corresponding to a `catch` or `finally` block).
*
* Handlers are entry points (`EntryPoint`) so that they can
* provide values on the stack, for example the value of the current exception. This is why
* some handlers have a push count of 1.
*
* Either a finally handler (`FinallyHandler`), filter handler (`FilterHandler`),
* catch handler (`CatchHandler`), or a fault handler (`FaultHandler`).
*/
class Handler extends Element, EntryPoint, @cil_handler {
override MethodImplementation getImplementation() { cil_handler(this, result, _, _, _, _, _) }
/** Gets the 0-based index of this handler. Handlers are evaluated in this sequence. */
int getIndex() { cil_handler(this, _, result, _, _, _, _) }
/** Gets the first instruction in the `try` block of this handler. */
Instruction getTryStart() { cil_handler(this, _, _, _, result, _, _) }
/** Gets the last instruction in the `try` block of this handler. */
Instruction getTryEnd() { cil_handler(this, _, _, _, _, result, _) }
/** Gets the first instruction in the `catch`/`finally` block. */
Instruction getHandlerStart() { cil_handler(this, _, _, _, _, _, result) }
/**
* Holds if the instruction `i` is in the scope of this handler.
*/
predicate isInScope(Instruction i) {
i.getImplementation() = getImplementation() and
i.getIndex() in [getTryStart().getIndex() .. getTryEnd().getIndex()]
}
override string toString() { none() }
override Instruction getASuccessorType(FlowType t) {
result = getHandlerStart() and
t instanceof NormalFlow
}
/** Gets the type of the caught exception, if any. */
Type getCaughtType() { cil_handler_type(this, result) }
override Location getLocation() { result = getTryStart().getLocation() }
}
/** A handler corresponding to a `finally` block. */
class FinallyHandler extends Handler, @cil_finally_handler {
override string toString() { result = "finally {...}" }
}
/** A handler corresponding to a `where()` clause. */
class FilterHandler extends Handler, @cil_filter_handler {
override string toString() { result = "where (...)" }
/** Gets the filter clause - the start of a sequence of instructions to evaluate the filter function. */
Instruction getFilterClause() { cil_handler_filter(this, result) }
override int getPushCount() { result = 1 }
}
/** A handler corresponding to a `catch` clause. */
class CatchHandler extends Handler, @cil_catch_handler {
override string toString() { result = "catch(" + getCaughtType().getName() + ") {...}" }
override int getPushCount() { result = 1 }
}
/** A handler for memory faults. */
class FaultHandler extends Handler, @cil_fault_handler {
override string toString() { result = "fault {...}" }
}