Merge pull request #1554 from jbj/ir-ErrorExpr

C++ IR: support for translating ErrorExpr
This commit is contained in:
Dave Bartolomeo 2019-07-11 13:05:04 -07:00 коммит произвёл GitHub
Родитель 23001d5471 70f81badcb
Коммит 00ff2bb6c4
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 138 добавлений и 2 удалений

Просмотреть файл

@ -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