Merge pull request #82 from dave-bartolomeo/dave/NewDelete2

C++: IR generation for `new` and `new[]`
This commit is contained in:
Jonas Jensen
2018-08-23 21:14:07 +02:00
committed by GitHub
13 changed files with 2096 additions and 877 deletions

View File

@@ -581,24 +581,13 @@ class ReferenceDereferenceExpr extends Conversion, @ref_indirect {
}
/**
* A C++ `new` (non-array) expression.
* A C++ `new` or `new[]` expression.
*/
class NewExpr extends Expr, @new_expr {
override string toString() { result = "new" }
class NewOrNewArrayExpr extends Expr, @any_new_expr {
override int getPrecedence() { result = 15 }
/**
* Gets the type that is being allocated.
*
* For example, for `new int` the result is `int`.
*/
Type getAllocatedType() {
new_allocated_type(underlyingElement(this), unresolveElement(result))
}
/**
* Gets the `operator new` that allocates storage.
* Gets the `operator new` or `operator new[]` that allocates storage.
*/
Function getAllocator() {
expr_allocator(underlyingElement(this), unresolveElement(result), _)
@@ -612,6 +601,21 @@ class NewExpr extends Expr, @new_expr {
expr_allocator(underlyingElement(this), _, 1)
}
/**
* Gets the alignment argument passed to the allocation function, if any.
*/
Expr getAlignmentArgument() {
hasAlignedAllocation() and
(
// If we have an allocator call, the alignment is the second argument to
// that call.
result = getAllocatorCall().getArgument(1) or
// Otherwise, the alignment winds up as child number 3 of the `new`
// itself.
result = getChild(3)
)
}
/**
* Gets the call to a non-default `operator new` that allocates storage, if any.
*
@@ -652,6 +656,30 @@ class NewExpr extends Expr, @new_expr {
)
}
/**
* Gets the type that is being allocated.
*
* For example, for `new int` the result is `int`.
* For `new int[5]` the result is `int[5]`.
*/
abstract Type getAllocatedType();
}
/**
* A C++ `new` (non-array) expression.
*/
class NewExpr extends NewOrNewArrayExpr, @new_expr {
override string toString() { result = "new" }
/**
* Gets the type that is being allocated.
*
* For example, for `new int` the result is `int`.
*/
override Type getAllocatedType() {
new_allocated_type(underlyingElement(this), unresolveElement(result))
}
/**
* Gets the call or expression that initializes the allocated object, if any.
*
@@ -664,17 +692,15 @@ class NewExpr extends Expr, @new_expr {
/**
* A C++ `new[]` (array) expression.
*/
class NewArrayExpr extends Expr, @new_array_expr {
class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr {
override string toString() { result = "new[]" }
override int getPrecedence() { result = 15 }
/**
* Gets the type that is being allocated.
*
* For example, for `new int[5]` the result is `int[5]`.
*/
Type getAllocatedType() {
override Type getAllocatedType() {
new_array_allocated_type(underlyingElement(this), unresolveElement(result))
}
@@ -685,56 +711,6 @@ class NewArrayExpr extends Expr, @new_array_expr {
result = getType().getUnderlyingType().(PointerType).getBaseType()
}
/**
* Gets the `operator new[]` that allocates storage.
*/
Function getAllocator() {
expr_allocator(underlyingElement(this), unresolveElement(result), _)
}
/**
* Holds if the allocation function is the version that expects an alignment
* argument of type `std::align_val_t`.
*/
predicate hasAlignedAllocation() {
expr_allocator(underlyingElement(this), _, 1)
}
/**
* Gets the call to a non-default `operator new[]` that allocates storage for the array, if any.
*
* If the default `operator new[]` is used, then there will be no call.
*/
FunctionCall getAllocatorCall() { result = this.getChild(0) }
/**
* Gets the `operator delete` that deallocates storage if the initialization
* throws an exception, if any.
*/
Function getDeallocator() {
expr_deallocator(underlyingElement(this), unresolveElement(result), _)
}
/**
* Holds if the deallocation function expects a size argument.
*/
predicate hasSizedDeallocation() {
exists(int form |
expr_deallocator(underlyingElement(this), _, form) and
form.bitAnd(1) != 0 // Bit zero is the "size" bit
)
}
/**
* Holds if the deallocation function expects an alignment argument.
*/
predicate hasAlignedDeallocation() {
exists(int form |
expr_deallocator(underlyingElement(this), _, form) and
form.bitAnd(2) != 0 // Bit one is the "alignment" bit
)
}
/**
* Gets the call or expression that initializes the first element of the array, if any.
*

View File

@@ -195,8 +195,11 @@ class Instruction extends Construction::TInstruction {
private string getResultTypeString() {
exists(string valcat |
valcat = getValueCategoryString(resultType.toString()) and
if resultType instanceof UnknownType and exists(getResultSize()) then
if (resultType instanceof UnknownType and
not isGLValue() and
exists(getResultSize())) then (
result = valcat + "[" + getResultSize().toString() + "]"
)
else
result = valcat
)

View File

@@ -43,6 +43,9 @@ newtype TInstructionTag =
SwitchBranchTag() or
CallTargetTag() or
CallTag() or
AllocationSizeTag() or
AllocationElementSizeTag() or
AllocationExtentConvertTag() or
ValueConditionConditionalBranchTag() or
ConditionValueTrueTempAddressTag() or
ConditionValueTrueConstantTag() or
@@ -88,11 +91,15 @@ string getInstructionTagId(TInstructionTag tag) {
tag = OnlyInstructionTag() and result = "Only" or // Single instruction (not including implicit Load)
tag = InitializerVariableAddressTag() and result = "InitVarAddr" or
tag = InitializerStoreTag() and result = "InitStore" or
tag = ZeroPadStringConstantTag() and result = "ZeroPadConst" or
tag = ZeroPadStringElementIndexTag() and result = "ZeroPadElemIndex" or
tag = ZeroPadStringElementAddressTag() and result = "ZeroPadElemAddr" or
tag = ZeroPadStringStoreTag() and result = "ZeroPadStore" or
tag = AssignOperationLoadTag() and result = "AssignOpLoad" or
tag = AssignOperationConvertLeftTag() and result = "AssignOpConvLeft" or
tag = AssignOperationOpTag() and result = "AssignOpOp" or
tag = AssignOperationConvertResultTag() and result = "AssignOpConvRes" or
tag = AssignmentStoreTag() and result = "AssigStore" or
tag = AssignmentStoreTag() and result = "AssignStore" or
tag = CrementLoadTag() and result = "CrementLoad" or
tag = CrementConstantTag() and result = "CrementConst" or
tag = CrementOpTag() and result = "CrementOp" or
@@ -106,6 +113,9 @@ string getInstructionTagId(TInstructionTag tag) {
tag = SwitchBranchTag() and result = "SwitchBranch" or
tag = CallTargetTag() and result = "CallTarget" or
tag = CallTag() and result = "Call" or
tag = AllocationSizeTag() and result = "AllocSize" or
tag = AllocationElementSizeTag() and result = "AllocElemSize" or
tag = AllocationExtentConvertTag() and result = "AllocExtConv" or
tag = ValueConditionConditionalBranchTag() and result = "ValCondCondBranch" or
tag = ConditionValueTrueTempAddressTag() and result = "CondValTrueTempAddr" or
tag = ConditionValueTrueConstantTag() and result = "CondValTrueConst" or

View File

@@ -47,12 +47,12 @@ private Element getRealParent(Expr expr) {
}
/**
* Holds if `expr` should be ignored for the purposes of code generation due to
* some property of `expr` itself. Unlike `ignoreExpr()`, this predicate does
* not ignore an expression solely because it is a descendant of an ignored
* element.
* Holds if `expr` and all of its descendants should be ignored for the purposes
* of IR generation due to some property of `expr` itself. Unlike
* `ignoreExpr()`, this predicate does not ignore an expression solely because
* it is a descendant of an ignored element.
*/
private predicate ignoreExprLocal(Expr expr) {
private predicate ignoreExprAndDescendants(Expr expr) {
// Ignore parentless expressions
not exists(getRealParent(expr)) or
// Ignore the constants in SwitchCase, since their values are embedded in the
@@ -65,23 +65,32 @@ private predicate ignoreExprLocal(Expr expr) {
// node as its qualifier, but that `FieldAccess` does not have a child of its own.
// We'll ignore that `FieldAccess`, and supply the receiver as part of the calling
// context, much like we do with constructor calls.
expr.getParent().(DestructorCall).getParent() instanceof DestructorFieldDestruction
expr.getParent().(DestructorCall).getParent() instanceof DestructorFieldDestruction or
exists(NewArrayExpr newExpr |
// REVIEW: Ignore initializers for `NewArrayExpr` until we determine how to
// represent them.
newExpr.getInitializer().getFullyConverted() = expr
)
}
/**
* Holds if `expr` (not including its descendants) should be ignored for the
* purposes of IR generation.
*/
private predicate ignoreExprOnly(Expr expr) {
exists(NewOrNewArrayExpr newExpr |
// 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
)
}
/**
* Holds if `expr` should be ignored for the purposes of IR generation.
*/
private predicate ignoreExpr(Expr expr) {
ignoreExprLocal(expr) or
// Ignore all descendants of ignored elements as well.
ignoreElement(getRealParent(expr))
}
/**
* Holds if `element` should be ignored for the purposes of IR generation.
*/
private predicate ignoreElement(Element element) {
ignoreExpr(element.(Expr))
ignoreExprOnly(expr) or
ignoreExprAndDescendants(getRealParent*(expr))
}
/**
@@ -155,7 +164,7 @@ predicate ignoreLoad(Expr expr) {
newtype TTranslatedElement =
// An expression that is not being consumed as a condition
TTranslatedNonLoadExpr(Expr expr) {
TTranslatedValueExpr(Expr expr) {
not ignoreExpr(expr) and
not isNativeCondition(expr) and
not isFlexibleCondition(expr)
@@ -216,6 +225,9 @@ newtype TTranslatedElement =
exists(ConstructorFieldInit fieldInit |
fieldInit.getExpr().getFullyConverted() = expr
) or
exists(NewExpr newExpr |
newExpr.getInitializer().getFullyConverted() = expr
) or
exists(ThrowExpr throw |
throw.getExpr().getFullyConverted() = expr
)
@@ -298,6 +310,14 @@ newtype TTranslatedElement =
exists(DeclStmt declStmt |
declStmt.getADeclarationEntry() = entry
)
} or
// An allocator call in a `new` or `new[]` expression
TTranslatedAllocatorCall(NewOrNewArrayExpr newExpr) {
not ignoreExpr(newExpr)
} or
// An allocation size for a `new` or `new[]` expression
TTranslatedAllocationSize(NewOrNewArrayExpr newExpr) {
not ignoreExpr(newExpr)
}
/**

View File

@@ -16,33 +16,23 @@ TranslatedExpr getTranslatedExpr(Expr expr) {
result.producesExprResult()
}
/**
* The IR translation of some part of an expression.
* A single `Expr` may consist of multiple `TranslatedExpr` objects. Every
* `Expr` has a single `TranslatedCoreExpr`, which produces the result of the
* expression before any implicit lvalue-to-rvalue conversion. Any expression
* with an lvalue-to-rvalue conversion will also have a `TranslatedLoad` to
* perform that conversion on the original result. A few expressions have
* additional `TranslatedExpr` objects that compute intermediate values, such
* as the `TranslatedAllocatorCall` and `TranslatedAllocationSize` within the
* translation of a `NewExpr`.
*/
abstract class TranslatedExpr extends TranslatedElement {
Expr expr;
override final string toString() {
result = expr.toString()
}
override final Locatable getAST() {
result = expr
}
final Expr getExpr() {
result = expr
}
override final Function getFunction() {
result = expr.getEnclosingFunction()
}
final TranslatedFunction getEnclosingFunction() {
result = getTranslatedFunction(expr.getEnclosingFunction())
}
final Type getResultType() {
result = expr.getType().getUnspecifiedType()
}
/**
* Gets the instruction that produces the result of the expression.
*/
abstract Instruction getResult();
/**
@@ -54,9 +44,50 @@ abstract class TranslatedExpr extends TranslatedElement {
* TranslatedVariableAccess for `x` does not. The TranslatedVariableAccess
* for `y` does produce its result, however, because there is no load on `y`.
*/
final predicate producesExprResult() {
// A load always produces the result of the expression.
this instanceof TranslatedLoad or
abstract predicate producesExprResult();
/**
* Gets the type of the result produced by this expression.
*/
final Type getResultType() {
result = expr.getType().getUnspecifiedType()
}
override final Locatable getAST() {
result = expr
}
override final Function getFunction() {
result = expr.getEnclosingFunction()
}
/**
* Gets the expression from which this `TranslatedExpr` is generated.
*/
final Expr getExpr() {
result = expr
}
/**
* Gets the `TranslatedFunction` containing this expression.
*/
final TranslatedFunction getEnclosingFunction() {
result = getTranslatedFunction(expr.getEnclosingFunction())
}
}
/**
* The IR translation of the "core" part of an expression. This is the part of
* the expression that produces the result value of the expression, before any
* lvalue-to-rvalue conversion on the result. Every expression has a single
* `TranslatedCoreExpr`.
*/
abstract class TranslatedCoreExpr extends TranslatedExpr {
override final string toString() {
result = expr.toString()
}
override final predicate producesExprResult() {
// If there's no load, then this is the only TranslatedExpr for this
// expression.
not expr.hasLValueToRValueConversion() or
@@ -86,7 +117,7 @@ abstract class TranslatedExpr extends TranslatedElement {
}
}
class TranslatedConditionValue extends TranslatedExpr, ConditionContext,
class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
TTranslatedConditionValue {
TranslatedConditionValue() {
this = TTranslatedConditionValue(expr)
@@ -262,11 +293,19 @@ class TranslatedConditionValue extends TranslatedExpr, ConditionContext,
}
}
/**
* IR translation of an implicit lvalue-to-rvalue conversion on the result of
* an expression.
*/
class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
TranslatedLoad() {
this = TTranslatedLoad(expr)
}
override string toString() {
result = "Load of " + expr.toString()
}
override Instruction getFirstInstruction() {
result = getOperand().getFirstInstruction()
}
@@ -279,8 +318,11 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
Type resultType, boolean isGLValue) {
tag = LoadTag() and
opcode instanceof Opcode::Load and
resultType = getResultType() and
isGLValue = isResultGLValue()
resultType = expr.getType().getUnspecifiedType() and
if expr.isGLValueCategory() then
isGLValue = true
else
isGLValue = false
}
override Instruction getInstructionSuccessor(InstructionTag tag,
@@ -313,8 +355,13 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
)
}
private TranslatedExpr getOperand() {
result.getExpr() = expr and not result instanceof TranslatedLoad
override final predicate producesExprResult() {
// A load always produces the result of the expression.
any()
}
private TranslatedCoreExpr getOperand() {
result.getExpr() = expr
}
}
@@ -906,21 +953,24 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
}
}
abstract class TranslatedNonLoadExpr extends TranslatedExpr,
TTranslatedNonLoadExpr {
TranslatedNonLoadExpr() {
this = TTranslatedNonLoadExpr(expr)
}
}
abstract class TranslatedNonConstantExpr extends TranslatedNonLoadExpr {
/**
* IR translation of an expression whose value is not known at compile time.
*/
abstract class TranslatedNonConstantExpr extends TranslatedCoreExpr {
TranslatedNonConstantExpr() {
this = TTranslatedValueExpr(expr) and
not expr.isConstant()
}
}
abstract class TranslatedConstantExpr extends TranslatedNonLoadExpr {
/**
* IR translation of an expression with a compile-time constant value. This
* includes not only literals, but also "integral constant expressions" (e.g.
* `1 + 2`).
*/
abstract class TranslatedConstantExpr extends TranslatedCoreExpr {
TranslatedConstantExpr() {
this = TTranslatedValueExpr(expr) and
expr.isConstant()
}
@@ -998,7 +1048,15 @@ class TranslatedStringLiteral extends TranslatedConstantExpr {
}
}
abstract class TranslatedValueExpr extends TranslatedNonConstantExpr {
/**
* IR translation of an expression that performs a single operation on its
* operands and returns the result.
*/
abstract class TranslatedSingleInstructionExpr extends
TranslatedNonConstantExpr {
/**
* Gets the `Opcode` of the operation to be performed.
*/
abstract Opcode getOpcode();
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
@@ -1014,7 +1072,7 @@ abstract class TranslatedValueExpr extends TranslatedNonConstantExpr {
}
}
class TranslatedUnaryExpr extends TranslatedValueExpr {
class TranslatedUnaryExpr extends TranslatedSingleInstructionExpr {
TranslatedUnaryExpr() {
expr instanceof NotExpr or
expr instanceof ComplementExpr or
@@ -1299,7 +1357,10 @@ private Opcode comparisonOpcode(ComparisonOperation expr) {
expr instanceof GEExpr and result instanceof Opcode::CompareGE
}
class TranslatedBinaryOperation extends TranslatedValueExpr {
/**
* IR translation of a simple binary operation.
*/
class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr {
TranslatedBinaryOperation() {
expr instanceof BinaryArithmeticOperation or
expr instanceof BinaryBitwiseOperation or
@@ -1707,26 +1768,11 @@ class TranslatedAssignOperation extends TranslatedAssignment {
}
/**
* Represents the IR translation of a call to a function.
* The IR translation of a call to a function. The call may be from an actual
* call in the source code, or could be a call that is part of the translation
* of a higher-level constructor (e.g. the allocator call in a `NewExpr`).
*/
abstract class TranslatedCall extends TranslatedNonConstantExpr {
Call call;
TranslatedCall() {
expr = call
}
override final Instruction getFirstInstruction() {
if exists(getQualifier()) then
result = getQualifier().getFirstInstruction()
else
result = getFirstCallTargetInstruction()
}
override final Instruction getResult() {
result = getInstruction(CallTag())
}
abstract class TranslatedCall extends TranslatedExpr {
override final TranslatedElement getChild(int id) {
// We choose the child's id in the order of evaluation.
// The qualifier is evaluated before the call target, because the value of
@@ -1737,6 +1783,21 @@ abstract class TranslatedCall extends TranslatedNonConstantExpr {
result = getArgument(id)
}
override final Instruction getFirstInstruction() {
if exists(getQualifier()) then
result = getQualifier().getFirstInstruction()
else
result = getFirstCallTargetInstruction()
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isGLValue) {
tag = CallTag() and
opcode instanceof Opcode::Invoke and
resultType = getCallResultType() and
isGLValue = false
}
override Instruction getChildSuccessor(TranslatedElement child) {
(
child = getQualifier() and
@@ -1755,14 +1816,6 @@ abstract class TranslatedCall extends TranslatedNonConstantExpr {
)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isGLValue) {
tag = CallTag() and
opcode instanceof Opcode::Invoke and
resultType = call.getType().getUnspecifiedType() and
isGLValue = false
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
kind instanceof GotoEdge and
@@ -1789,13 +1842,15 @@ abstract class TranslatedCall extends TranslatedNonConstantExpr {
)
}
/**
* Holds if the call has any arguments, not counting the `this` argument.
*/
final predicate hasArguments() {
exists(call.getArgument(0))
override final Instruction getResult() {
result = getInstruction(CallTag())
}
/**
* Gets the result type of the call.
*/
abstract Type getCallResultType();
/**
* Holds if the call has a `this` argument.
*/
@@ -1834,9 +1889,7 @@ abstract class TranslatedCall extends TranslatedNonConstantExpr {
* Gets the `TranslatedExpr` for the qualifier of the call (i.e. the value
* that is passed as the `this` argument.
*/
final TranslatedExpr getQualifier() {
result = getTranslatedExpr(call.getQualifier().getFullyConverted())
}
abstract TranslatedExpr getQualifier();
/**
* Gets the instruction whose result value is the `this` argument of the call.
@@ -1852,9 +1905,7 @@ abstract class TranslatedCall extends TranslatedNonConstantExpr {
* Gets the argument with the specified `index`. Does not include the `this`
* argument.
*/
final TranslatedExpr getArgument(int index) {
result = getTranslatedExpr(call.getArgument(index).getFullyConverted())
}
abstract TranslatedExpr getArgument(int index);
/**
* If there are any arguments, gets the first instruction of the first
@@ -1866,12 +1917,305 @@ abstract class TranslatedCall extends TranslatedNonConstantExpr {
else
result = getInstruction(CallTag())
}
/**
* Holds if the call has any arguments, not counting the `this` argument.
*/
abstract predicate hasArguments();
}
/**
* The IR translation of the allocation size argument passed to `operator new`
* in a `new` expression.
*
* We have to synthesize this because not all `NewExpr` nodes have an allocator
* call, and even the ones that do pass an `ErrorExpr` as the argument.
*/
abstract class TranslatedAllocationSize extends TranslatedExpr,
TTranslatedAllocationSize {
NewOrNewArrayExpr newExpr;
TranslatedAllocationSize() {
this = TTranslatedAllocationSize(newExpr) and
expr = newExpr
}
override final string toString() {
result = "Allocation size for " + newExpr.toString()
}
override final predicate producesExprResult() {
none()
}
override final Instruction getResult() {
result = getInstruction(AllocationSizeTag())
}
}
TranslatedAllocationSize getTranslatedAllocationSize(NewOrNewArrayExpr newExpr) {
result.getAST() = newExpr
}
/**
* The IR translation of a constant allocation size.
*
* The allocation size for a `new` expression is always a constant. The
* allocation size for a `new[]` expression is a constant if the array extent
* is a compile-time constant.
*/
class TranslatedConstantAllocationSize extends TranslatedAllocationSize {
TranslatedConstantAllocationSize() {
not exists(newExpr.(NewArrayExpr).getExtent())
}
override final Instruction getFirstInstruction() {
result = getInstruction(AllocationSizeTag())
}
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isGLValue) {
tag = AllocationSizeTag() and
opcode instanceof Opcode::Constant and
resultType = newExpr.getAllocator().getParameter(0).getType().getUnspecifiedType() and
isGLValue = false
}
override final Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
tag = AllocationSizeTag() and
kind instanceof GotoEdge and
result = getParent().getChildSuccessor(this)
}
override final TranslatedElement getChild(int id) {
none()
}
override final Instruction getChildSuccessor(TranslatedElement child) {
none()
}
override final string getInstructionConstantValue(InstructionTag tag) {
tag = AllocationSizeTag() and
result = newExpr.getAllocatedType().getSize().toString()
}
}
/**
* The IR translation of a non-constant allocation size.
*
* This class is used for the allocation size of a `new[]` expression where the
* array extent is not known at compile time. It performs the multiplication of
* the extent by the element size.
*/
class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
NewArrayExpr newArrayExpr;
TranslatedNonConstantAllocationSize() {
newArrayExpr = newExpr and
exists(newArrayExpr.getExtent())
}
override final Instruction getFirstInstruction() {
result = getExtent().getFirstInstruction()
}
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isGLValue) {
isGLValue = false and
resultType = newExpr.getAllocator().getParameter(0).getType().getUnspecifiedType() and
(
// Convert the extent to `size_t`, because the AST doesn't do this already.
tag = AllocationExtentConvertTag() and opcode instanceof Opcode::Convert or
tag = AllocationElementSizeTag() and opcode instanceof Opcode::Constant or
tag = AllocationSizeTag() and opcode instanceof Opcode::Mul // REVIEW: Overflow?
)
}
override final Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
kind instanceof GotoEdge and
(
(
tag = AllocationExtentConvertTag() and
result = getInstruction(AllocationElementSizeTag())
) or
(
tag = AllocationElementSizeTag() and
result = getInstruction(AllocationSizeTag())
) or
(
tag = AllocationSizeTag() and
result = getParent().getChildSuccessor(this)
)
)
}
override final TranslatedElement getChild(int id) {
id = 0 and result = getExtent()
}
override final Instruction getChildSuccessor(TranslatedElement child) {
child = getExtent() and
result = getInstruction(AllocationExtentConvertTag())
}
override final string getInstructionConstantValue(InstructionTag tag) {
tag = AllocationElementSizeTag() and
result = newArrayExpr.getAllocatedElementType().getSize().toString()
}
override final Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
(
tag = AllocationSizeTag() and
(
operandTag instanceof LeftOperand and result = getInstruction(AllocationExtentConvertTag()) or
operandTag instanceof RightOperand and result = getInstruction(AllocationElementSizeTag())
)
) or
(
tag = AllocationExtentConvertTag() and
operandTag instanceof UnaryOperand and
result = getExtent().getResult()
)
}
private TranslatedExpr getExtent() {
result = getTranslatedExpr(newArrayExpr.getExtent().getFullyConverted())
}
}
/**
* IR translation of a direct call to a specific function. Used for both
* explicit calls (`TranslatedFunctionCall`) and implicit calls
* (`TranslatedAllocatorCall`).
*/
abstract class TranslatedDirectCall extends TranslatedCall {
override final Instruction getFirstCallTargetInstruction() {
result = getInstruction(CallTargetTag())
}
override final Instruction getCallTargetResult() {
result = getInstruction(CallTargetTag())
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isGLValue) {
TranslatedCall.super.hasInstruction(opcode, tag, resultType, isGLValue) or
(
tag = CallTargetTag() and
opcode instanceof Opcode::FunctionAddress and
// The database does not contain a `FunctionType` for a function unless
// its address was taken, so we'll just use glval<Unknown> instead of
// glval<FunctionType>.
resultType instanceof UnknownType and
isGLValue = true
)
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
result = TranslatedCall.super.getInstructionSuccessor(tag, kind) or
(
tag = CallTargetTag() and
kind instanceof GotoEdge and
result = getFirstArgumentOrCallInstruction()
)
}
}
/**
* The IR translation of a call to `operator new` as part of a `new` or `new[]`
* expression.
*/
class TranslatedAllocatorCall extends TTranslatedAllocatorCall,
TranslatedDirectCall {
NewOrNewArrayExpr newExpr;
TranslatedAllocatorCall() {
this = TTranslatedAllocatorCall(newExpr) and
expr = newExpr
}
override final string toString() {
result = "Allocator call for " + newExpr.toString()
}
override final predicate producesExprResult() {
none()
}
override Function getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and result = newExpr.getAllocator()
}
override final Type getCallResultType() {
result = newExpr.getAllocator().getType().getUnspecifiedType()
}
override final TranslatedExpr getQualifier() {
none()
}
override final predicate hasArguments() {
// All allocator calls have at least one argument.
any()
}
override final TranslatedExpr getArgument(int index) {
// If the allocator is the default operator new(void*), there will be no
// allocator call in the AST. Otherwise, there will be an allocator call
// that includes all arguments to the allocator, including the size,
// alignment (if any), and placement args. However, the size argument is
// an error node, so we need to provide the correct size argument in any
// case.
if index = 0 then
result = getTranslatedAllocationSize(newExpr)
else if(index = 1 and newExpr.hasAlignedAllocation()) then
result = getTranslatedExpr(newExpr.getAlignmentArgument())
else
result = getTranslatedExpr(newExpr.getAllocatorCall().getArgument(index))
}
}
TranslatedAllocatorCall getTranslatedAllocatorCall(NewOrNewArrayExpr newExpr) {
result.getAST() = newExpr
}
/**
* The IR translation of a call to a function.
*/
abstract class TranslatedCallExpr extends TranslatedNonConstantExpr,
TranslatedCall {
Call call;
TranslatedCallExpr() {
expr = call
}
override final Type getCallResultType() {
result = getResultType()
}
override final predicate hasArguments() {
exists(call.getArgument(0))
}
override final TranslatedExpr getQualifier() {
result = getTranslatedExpr(call.getQualifier().getFullyConverted())
}
override final TranslatedExpr getArgument(int index) {
result = getTranslatedExpr(call.getArgument(index).getFullyConverted())
}
}
/**
* Represents the IR translation of a call through a function pointer.
*/
class TranslatedExprCall extends TranslatedCall {
class TranslatedExprCall extends TranslatedCallExpr {
ExprCall exprCall;
TranslatedExprCall() {
@@ -1886,42 +2230,13 @@ class TranslatedExprCall extends TranslatedCall {
/**
* Represents the IR translation of a direct function call.
*/
class TranslatedFunctionCall extends TranslatedCall {
class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
FunctionCall funcCall;
TranslatedFunctionCall() {
expr = funcCall
}
override final Instruction getFirstCallTargetInstruction() {
result = getInstruction(CallTargetTag())
}
override final Instruction getCallTargetResult() {
result = getInstruction(CallTargetTag())
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isGLValue) {
super.hasInstruction(opcode, tag, resultType, isGLValue) or
(
tag = CallTargetTag() and
opcode instanceof Opcode::FunctionAddress and
resultType instanceof BoolType and //HACK
isGLValue = false
)
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
result = super.getInstructionSuccessor(tag, kind) or
(
tag = CallTargetTag() and
kind instanceof GotoEdge and
result = getFirstArgumentOrCallInstruction()
)
}
override Function getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and result = funcCall.getTarget()
}
@@ -2498,3 +2813,103 @@ class TranslatedVarArgCopy extends TranslatedBuiltInOperation {
result instanceof Opcode::VarArgCopy
}
}
/**
* The IR translation of a `new` or `new[]` expression.
*/
abstract class TranslatedNewOrNewArrayExpr extends TranslatedNonConstantExpr,
InitializationContext {
NewOrNewArrayExpr newExpr;
TranslatedNewOrNewArrayExpr() {
expr = newExpr
}
override final TranslatedElement getChild(int id) {
id = 0 and result = getAllocatorCall() or
id = 1 and result = getInitialization()
}
override final predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isGLValue) {
tag = OnlyInstructionTag() and
opcode instanceof Opcode::Convert and
resultType = getResultType() and
isGLValue = false
}
override final Instruction getFirstInstruction() {
result = getAllocatorCall().getFirstInstruction()
}
override final Instruction getResult() {
result = getInstruction(OnlyInstructionTag())
}
override final Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
kind instanceof GotoEdge and
tag = OnlyInstructionTag() and
if exists(getInitialization()) then
result = getInitialization().getFirstInstruction()
else
result = getParent().getChildSuccessor(this)
}
override final Instruction getChildSuccessor(TranslatedElement child) {
child = getAllocatorCall() and result = getInstruction(OnlyInstructionTag()) or
child = getInitialization() and result = getParent().getChildSuccessor(this)
}
override final Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
tag = OnlyInstructionTag() and
operandTag instanceof UnaryOperand and
result = getAllocatorCall().getResult()
}
override final Instruction getTargetAddress() {
result = getInstruction(OnlyInstructionTag())
}
private TranslatedAllocatorCall getAllocatorCall() {
result = getTranslatedAllocatorCall(newExpr)
}
abstract TranslatedInitialization getInitialization();
}
/**
* The IR translation of a `new` expression.
*/
class TranslatedNewExpr extends TranslatedNewOrNewArrayExpr {
TranslatedNewExpr() {
newExpr instanceof NewExpr
}
override final Type getTargetType() {
result = newExpr.getAllocatedType().getUnspecifiedType()
}
override final TranslatedInitialization getInitialization() {
result = getTranslatedInitialization(newExpr.(NewExpr).getInitializer())
}
}
/**
* The IR translation of a `new[]` expression.
*/
class TranslatedNewArrayExpr extends TranslatedNewOrNewArrayExpr {
TranslatedNewArrayExpr() {
newExpr instanceof NewArrayExpr
}
override final Type getTargetType() {
result = newExpr.getAllocatedType().getUnspecifiedType()
}
override final TranslatedInitialization getInitialization() {
// REVIEW: Figure out how we want to model array initialization in the IR.
none()
}
}

View File

@@ -195,8 +195,11 @@ class Instruction extends Construction::TInstruction {
private string getResultTypeString() {
exists(string valcat |
valcat = getValueCategoryString(resultType.toString()) and
if resultType instanceof UnknownType and exists(getResultSize()) then
if (resultType instanceof UnknownType and
not isGLValue() and
exists(getResultSize())) then (
result = valcat + "[" + getResultSize().toString() + "]"
)
else
result = valcat
)

View File

@@ -195,8 +195,11 @@ class Instruction extends Construction::TInstruction {
private string getResultTypeString() {
exists(string valcat |
valcat = getValueCategoryString(resultType.toString()) and
if resultType instanceof UnknownType and exists(getResultSize()) then
if (resultType instanceof UnknownType and
not isGLValue() and
exists(getResultSize())) then (
result = valcat + "[" + getResultSize().toString() + "]"
)
else
result = valcat
)