зеркало из 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 =
|
private newtype TOpcode =
|
||||||
TNoOp() or
|
TNoOp() or
|
||||||
TUninitialized() or
|
TUninitialized() or
|
||||||
|
TError() or
|
||||||
TInitializeParameter() or
|
TInitializeParameter() or
|
||||||
TInitializeThis() or
|
TInitializeThis() or
|
||||||
TEnterFunction() or
|
TEnterFunction() or
|
||||||
|
@ -147,6 +148,7 @@ abstract class BufferAccessOpcode extends MemoryAccessOpcode {}
|
||||||
module Opcode {
|
module Opcode {
|
||||||
class NoOp extends Opcode, TNoOp { override final string toString() { result = "NoOp" } }
|
class NoOp extends Opcode, TNoOp { override final string toString() { result = "NoOp" } }
|
||||||
class Uninitialized extends MemoryAccessOpcode, TUninitialized { override final string toString() { result = "Uninitialized" } }
|
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 InitializeParameter extends MemoryAccessOpcode, TInitializeParameter { override final string toString() { result = "InitializeParameter" } }
|
||||||
class InitializeThis extends Opcode, TInitializeThis { override final string toString() { result = "InitializeThis" } }
|
class InitializeThis extends Opcode, TInitializeThis { override final string toString() { result = "InitializeThis" } }
|
||||||
class EnterFunction extends Opcode, TEnterFunction { override final string toString() { result = "EnterFunction" } }
|
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 {
|
class UninitializedInstruction extends VariableInstruction {
|
||||||
UninitializedInstruction() {
|
UninitializedInstruction() {
|
||||||
getOpcode() instanceof Opcode::Uninitialized
|
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 {
|
class UninitializedInstruction extends VariableInstruction {
|
||||||
UninitializedInstruction() {
|
UninitializedInstruction() {
|
||||||
getOpcode() instanceof Opcode::Uninitialized
|
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
|
// Ignore the allocator call, because we always synthesize it. Don't ignore
|
||||||
// its arguments, though, because we use them as part of the synthesis.
|
// its arguments, though, because we use them as part of the synthesis.
|
||||||
newExpr.getAllocatorCall() = expr
|
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())
|
not translateFunction(expr.getEnclosingFunction())
|
||||||
or
|
or
|
||||||
// We do not yet translate destructors properly, so for now we ignore the
|
// 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())
|
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 {
|
class UninitializedInstruction extends VariableInstruction {
|
||||||
UninitializedInstruction() {
|
UninitializedInstruction() {
|
||||||
getOpcode() instanceof Opcode::Uninitialized
|
getOpcode() instanceof Opcode::Uninitialized
|
||||||
|
|
|
@ -190,6 +190,34 @@ bad_asts.cpp:
|
||||||
# 27| Type = const Point &
|
# 27| Type = const Point &
|
||||||
# 27| ValueCategory = prvalue(load)
|
# 27| ValueCategory = prvalue(load)
|
||||||
# 28| 1: return ...
|
# 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:
|
clang.cpp:
|
||||||
# 5| int* globalIntAddress()
|
# 5| int* globalIntAddress()
|
||||||
# 5| params:
|
# 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.
|
// Test cases that illustrate known bad ASTs that we have to work around in IR generation.
|
||||||
namespace Bad {
|
namespace Bad {
|
||||||
|
@ -26,4 +26,10 @@ namespace Bad {
|
||||||
void CallCopyConstructor(const Point& a) {
|
void CallCopyConstructor(const Point& a) {
|
||||||
Point b = a; // Copy constructor contains literal expressions with no values.
|
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_13(void) = UnmodeledUse : mu*
|
||||||
# 26| v0_14(void) = ExitFunction :
|
# 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:
|
clang.cpp:
|
||||||
# 5| int* globalIntAddress()
|
# 5| int* globalIntAddress()
|
||||||
# 5| Block 0
|
# 5| Block 0
|
||||||
|
|
Загрузка…
Ссылка в новой задаче