зеркало из https://github.com/github/codeql.git
Merge pull request #1554 from jbj/ir-ErrorExpr
C++ IR: support for translating ErrorExpr
This commit is contained in:
Коммит
00ff2bb6c4
|
@ -1,6 +1,7 @@
|
|||
private newtype TOpcode =
|
||||
TNoOp() or
|
||||
TUninitialized() or
|
||||
TError() or
|
||||
TInitializeParameter() or
|
||||
TInitializeThis() or
|
||||
TEnterFunction() or
|
||||
|
@ -147,6 +148,7 @@ abstract class BufferAccessOpcode extends MemoryAccessOpcode {}
|
|||
module Opcode {
|
||||
class NoOp extends Opcode, TNoOp { override final string toString() { result = "NoOp" } }
|
||||
class Uninitialized extends MemoryAccessOpcode, TUninitialized { override final string toString() { result = "Uninitialized" } }
|
||||
class Error extends Opcode, TError { override final string toString() { result = "Error" } }
|
||||
class InitializeParameter extends MemoryAccessOpcode, TInitializeParameter { override final string toString() { result = "InitializeParameter" } }
|
||||
class InitializeThis extends Opcode, TInitializeThis { override final string toString() { result = "InitializeThis" } }
|
||||
class EnterFunction extends Opcode, TEnterFunction { override final string toString() { result = "EnterFunction" } }
|
||||
|
|
|
@ -702,6 +702,22 @@ class FieldAddressInstruction extends FieldInstruction {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that produces a well-defined but unknown result and has
|
||||
* unknown side effects, including side effects that are not conservatively
|
||||
* modeled in the SSA graph.
|
||||
*
|
||||
* This type of instruction appears when there is an `ErrorExpr` in the AST,
|
||||
* meaning that the extractor could not understand the expression and therefore
|
||||
* produced a partial AST. Queries that give alerts when some action is _not_
|
||||
* taken may want to ignore any function that contains an `ErrorInstruction`.
|
||||
*/
|
||||
class ErrorInstruction extends Instruction {
|
||||
ErrorInstruction() {
|
||||
getOpcode() instanceof Opcode::Error
|
||||
}
|
||||
}
|
||||
|
||||
class UninitializedInstruction extends VariableInstruction {
|
||||
UninitializedInstruction() {
|
||||
getOpcode() instanceof Opcode::Uninitialized
|
||||
|
|
|
@ -702,6 +702,22 @@ class FieldAddressInstruction extends FieldInstruction {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that produces a well-defined but unknown result and has
|
||||
* unknown side effects, including side effects that are not conservatively
|
||||
* modeled in the SSA graph.
|
||||
*
|
||||
* This type of instruction appears when there is an `ErrorExpr` in the AST,
|
||||
* meaning that the extractor could not understand the expression and therefore
|
||||
* produced a partial AST. Queries that give alerts when some action is _not_
|
||||
* taken may want to ignore any function that contains an `ErrorInstruction`.
|
||||
*/
|
||||
class ErrorInstruction extends Instruction {
|
||||
ErrorInstruction() {
|
||||
getOpcode() instanceof Opcode::Error
|
||||
}
|
||||
}
|
||||
|
||||
class UninitializedInstruction extends VariableInstruction {
|
||||
UninitializedInstruction() {
|
||||
getOpcode() instanceof Opcode::Uninitialized
|
||||
|
|
|
@ -84,7 +84,13 @@ private predicate ignoreExprOnly(Expr expr) {
|
|||
// Ignore the allocator call, because we always synthesize it. Don't ignore
|
||||
// its arguments, though, because we use them as part of the synthesis.
|
||||
newExpr.getAllocatorCall() = expr
|
||||
) or
|
||||
)
|
||||
or
|
||||
// The extractor deliberately emits an `ErrorExpr` as the first argument to
|
||||
// the allocator call, if any, of a `NewOrNewArrayExpr`. That `ErrorExpr`
|
||||
// should not be translated.
|
||||
exists(NewOrNewArrayExpr new | expr = new.getAllocatorCall().getArgument(0))
|
||||
or
|
||||
not translateFunction(expr.getEnclosingFunction())
|
||||
or
|
||||
// We do not yet translate destructors properly, so for now we ignore the
|
||||
|
|
|
@ -2862,3 +2862,29 @@ class TranslatedStmtExpr extends TranslatedNonConstantExpr {
|
|||
result = getTranslatedStmt(expr.getStmt())
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedErrorExpr extends TranslatedSingleInstructionExpr {
|
||||
override ErrorExpr expr;
|
||||
|
||||
override final Instruction getFirstInstruction() {
|
||||
result = getInstruction(OnlyInstructionTag())
|
||||
}
|
||||
|
||||
override final TranslatedElement getChild(int id) { none() }
|
||||
|
||||
override final Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = getParent().getChildSuccessor(this) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override final Instruction getChildSuccessor(TranslatedElement child) { none() }
|
||||
|
||||
override final Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
none()
|
||||
}
|
||||
|
||||
override final Opcode getOpcode() {
|
||||
result instanceof Opcode::Error
|
||||
}
|
||||
}
|
||||
|
|
|
@ -702,6 +702,22 @@ class FieldAddressInstruction extends FieldInstruction {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that produces a well-defined but unknown result and has
|
||||
* unknown side effects, including side effects that are not conservatively
|
||||
* modeled in the SSA graph.
|
||||
*
|
||||
* This type of instruction appears when there is an `ErrorExpr` in the AST,
|
||||
* meaning that the extractor could not understand the expression and therefore
|
||||
* produced a partial AST. Queries that give alerts when some action is _not_
|
||||
* taken may want to ignore any function that contains an `ErrorInstruction`.
|
||||
*/
|
||||
class ErrorInstruction extends Instruction {
|
||||
ErrorInstruction() {
|
||||
getOpcode() instanceof Opcode::Error
|
||||
}
|
||||
}
|
||||
|
||||
class UninitializedInstruction extends VariableInstruction {
|
||||
UninitializedInstruction() {
|
||||
getOpcode() instanceof Opcode::Uninitialized
|
||||
|
|
|
@ -190,6 +190,34 @@ bad_asts.cpp:
|
|||
# 27| Type = const Point &
|
||||
# 27| ValueCategory = prvalue(load)
|
||||
# 28| 1: return ...
|
||||
# 30| void Bad::errorExpr()
|
||||
# 30| params:
|
||||
# 30| body: { ... }
|
||||
# 31| 0: declaration
|
||||
# 31| 0: definition of intref
|
||||
# 31| Type = int &
|
||||
# 31| init: initializer for intref
|
||||
# 31| expr: <error expr>
|
||||
# 31| Type = error
|
||||
# 31| ValueCategory = prvalue
|
||||
# 32| 1: declaration
|
||||
# 32| 0: definition of x
|
||||
# 32| Type = int
|
||||
# 32| init: initializer for x
|
||||
# 32| expr: <error expr>
|
||||
# 32| Type = error
|
||||
# 32| ValueCategory = prvalue
|
||||
# 33| 2: ExprStmt
|
||||
# 33| 0: ... = ...
|
||||
# 33| Type = int
|
||||
# 33| ValueCategory = lvalue
|
||||
# 33| 0: x
|
||||
# 33| Type = int
|
||||
# 33| ValueCategory = lvalue
|
||||
#-----| 1: <error expr>
|
||||
#-----| Type = error
|
||||
#-----| ValueCategory = prvalue(load)
|
||||
# 34| 3: return ...
|
||||
clang.cpp:
|
||||
# 5| int* globalIntAddress()
|
||||
# 5| params:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// semmle-extractor-options: -std=c++17
|
||||
// semmle-extractor-options: -std=c++17 --expect_errors
|
||||
|
||||
// Test cases that illustrate known bad ASTs that we have to work around in IR generation.
|
||||
namespace Bad {
|
||||
|
@ -26,4 +26,10 @@ namespace Bad {
|
|||
void CallCopyConstructor(const Point& a) {
|
||||
Point b = a; // Copy constructor contains literal expressions with no values.
|
||||
}
|
||||
|
||||
void errorExpr() {
|
||||
int &intref = 0;
|
||||
int x = 0[0];
|
||||
x = 1[1];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,26 @@ bad_asts.cpp:
|
|||
# 26| v0_13(void) = UnmodeledUse : mu*
|
||||
# 26| v0_14(void) = ExitFunction :
|
||||
|
||||
# 30| void Bad::errorExpr()
|
||||
# 30| Block 0
|
||||
# 30| v0_0(void) = EnterFunction :
|
||||
# 30| mu0_1(unknown) = AliasedDefinition :
|
||||
# 30| mu0_2(unknown) = UnmodeledDefinition :
|
||||
# 31| r0_3(glval<int &>) = VariableAddress[intref] :
|
||||
# 31| r0_4(error) = Error :
|
||||
# 31| mu0_5(int &) = Store : &:r0_3, r0_4
|
||||
# 32| r0_6(glval<int>) = VariableAddress[x] :
|
||||
# 32| r0_7(error) = Error :
|
||||
# 32| mu0_8(int) = Store : &:r0_6, r0_7
|
||||
#-----| r0_9(glval<error>) = Error :
|
||||
#-----| r0_10(error) = Load : &:r0_9, ~mu0_2
|
||||
# 33| r0_11(glval<int>) = VariableAddress[x] :
|
||||
# 33| mu0_12(int) = Store : &:r0_11, r0_10
|
||||
# 34| v0_13(void) = NoOp :
|
||||
# 30| v0_14(void) = ReturnVoid :
|
||||
# 30| v0_15(void) = UnmodeledUse : mu*
|
||||
# 30| v0_16(void) = ExitFunction :
|
||||
|
||||
clang.cpp:
|
||||
# 5| int* globalIntAddress()
|
||||
# 5| Block 0
|
||||
|
|
Загрузка…
Ссылка в новой задаче