mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
C++: IR translation for NewExpr and NewArrayExpr
These expressions are a little trickier than most because they include an implicit call to an allocator function. The database tells us which function to call, but we have to synthesize the allocation size and alignment arguments ourselves. The alignment argument, if it exists, is always a constant, but the size argument requires multiplication by the element count for most `NewArrayExpr`s. I introduced the new `TranslatedAllocationSize` class to handle this.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,35 +16,59 @@ TranslatedExpr getTranslatedExpr(Expr expr) {
|
||||
result.producesExprResult()
|
||||
}
|
||||
|
||||
abstract class TranslatedExpr extends TranslatedElement {
|
||||
/**
|
||||
* The IR translation of an expression that was either directly present in the
|
||||
* AST as an `Expr` (`TranslatedExpr`) or was synthesized from something other
|
||||
* than an `Expr` .
|
||||
*/
|
||||
abstract class TranslatedOrSynthesizedExpr extends TranslatedElement {
|
||||
/**
|
||||
* Gets the instruction that produces the result of the expression.
|
||||
*/
|
||||
abstract Instruction getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of some part of an expression. This could be the
|
||||
* expression itself (`TranslatedExpr`), or some other construct synthesized
|
||||
* from an `Expr` (e.g. `TranslatedAllocatorCall`).
|
||||
*/
|
||||
abstract class TranslatedFromExpr 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()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `TranslatedFunction` containing this expression.
|
||||
*/
|
||||
final TranslatedFunction getEnclosingFunction() {
|
||||
result = getTranslatedFunction(expr.getEnclosingFunction())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of an expression.
|
||||
*/
|
||||
abstract class TranslatedExpr extends TranslatedOrSynthesizedExpr,
|
||||
TranslatedFromExpr {
|
||||
override final string toString() {
|
||||
result = expr.toString()
|
||||
}
|
||||
|
||||
final Expr getExpr() {
|
||||
result = expr
|
||||
}
|
||||
|
||||
final Type getResultType() {
|
||||
result = expr.getType().getUnspecifiedType()
|
||||
}
|
||||
|
||||
abstract Instruction getResult();
|
||||
|
||||
/**
|
||||
* Holds if this `TranslatedExpr` produces the final result of the original
|
||||
* expression from the AST.
|
||||
@@ -1707,26 +1731,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 TranslatedOrSynthesizedExpr {
|
||||
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 +1746,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 +1779,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 +1805,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 +1852,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 +1868,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 TranslatedOrSynthesizedExpr getArgument(int index);
|
||||
|
||||
/**
|
||||
* If there are any arguments, gets the first instruction of the first
|
||||
@@ -1866,12 +1880,287 @@ 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 TranslatedOrSynthesizedExpr,
|
||||
TranslatedFromExpr, TTranslatedAllocationSize {
|
||||
NewOrNewArrayExpr newExpr;
|
||||
|
||||
TranslatedAllocationSize() {
|
||||
this = TTranslatedAllocationSize(newExpr) and
|
||||
expr = newExpr
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Allocation size for " + newExpr.toString()
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of a call to `operator new` as part of a `new` or `new[]`
|
||||
* expression.
|
||||
*/
|
||||
class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedCall,
|
||||
TranslatedFromExpr {
|
||||
NewOrNewArrayExpr newExpr;
|
||||
|
||||
TranslatedAllocatorCall() {
|
||||
this = TTranslatedAllocatorCall(newExpr) and
|
||||
expr = newExpr
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Allocator call for " + newExpr.toString()
|
||||
}
|
||||
|
||||
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
|
||||
resultType instanceof BoolType and //HACK
|
||||
isGLValue = false
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
result = TranslatedCall.super.getInstructionSuccessor(tag, kind) or
|
||||
(
|
||||
tag = CallTargetTag() and
|
||||
kind instanceof GotoEdge and
|
||||
result = getFirstArgumentOrCallInstruction()
|
||||
)
|
||||
}
|
||||
|
||||
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 TranslatedOrSynthesizedExpr 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 TranslatedOrSynthesizedExpr 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,7 +2175,7 @@ class TranslatedExprCall extends TranslatedCall {
|
||||
/**
|
||||
* Represents the IR translation of a direct function call.
|
||||
*/
|
||||
class TranslatedFunctionCall extends TranslatedCall {
|
||||
class TranslatedFunctionCall extends TranslatedCallExpr {
|
||||
FunctionCall funcCall;
|
||||
|
||||
TranslatedFunctionCall() {
|
||||
@@ -2498,3 +2787,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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,38 @@
|
||||
#-----| params:
|
||||
#-----| __va_list_tag::operator=() -> __va_list_tag &
|
||||
#-----| params:
|
||||
#-----| operator new(unsigned long, align_val_t) -> void *
|
||||
#-----| params:
|
||||
#-----| 0: p#0
|
||||
#-----| Type = unsigned long
|
||||
#-----| 1: p#1
|
||||
#-----| Type = align_val_t
|
||||
#-----| operator new[](unsigned long) -> void *
|
||||
#-----| params:
|
||||
#-----| 0: p#0
|
||||
#-----| Type = unsigned long
|
||||
#-----| operator delete[](void *, unsigned long) -> void
|
||||
#-----| params:
|
||||
#-----| 0: p#0
|
||||
#-----| Type = void *
|
||||
#-----| 1: p#1
|
||||
#-----| Type = unsigned long
|
||||
#-----| operator new[](unsigned long, align_val_t) -> void *
|
||||
#-----| params:
|
||||
#-----| 0: p#0
|
||||
#-----| Type = unsigned long
|
||||
#-----| 1: p#1
|
||||
#-----| Type = align_val_t
|
||||
#-----| operator new(unsigned long) -> void *
|
||||
#-----| params:
|
||||
#-----| 0: p#0
|
||||
#-----| Type = unsigned long
|
||||
#-----| operator delete(void *, unsigned long) -> void
|
||||
#-----| params:
|
||||
#-----| 0: p#0
|
||||
#-----| Type = void *
|
||||
#-----| 1: p#1
|
||||
#-----| Type = unsigned long
|
||||
ir.cpp:
|
||||
# 1| Constants() -> void
|
||||
# 1| params:
|
||||
@@ -5957,3 +5989,317 @@ ir.cpp:
|
||||
# 906| Type = int
|
||||
# 906| ValueCategory = prvalue(load)
|
||||
# 907| 2: return ...
|
||||
# 915| operator new(size_t, float) -> void *
|
||||
# 915| params:
|
||||
# 915| 0: p#0
|
||||
# 915| Type = size_t
|
||||
# 915| 1: p#1
|
||||
# 915| Type = float
|
||||
# 916| operator new[](size_t, float) -> void *
|
||||
# 916| params:
|
||||
# 916| 0: p#0
|
||||
# 916| Type = size_t
|
||||
# 916| 1: p#1
|
||||
# 916| Type = float
|
||||
# 917| operator new(size_t, align_val_t, float) -> void *
|
||||
# 917| params:
|
||||
# 917| 0: p#0
|
||||
# 917| Type = size_t
|
||||
# 917| 1: p#1
|
||||
# 917| Type = align_val_t
|
||||
# 917| 2: p#2
|
||||
# 917| Type = float
|
||||
# 918| operator new[](size_t, align_val_t, float) -> void *
|
||||
# 918| params:
|
||||
# 918| 0: p#0
|
||||
# 918| Type = size_t
|
||||
# 918| 1: p#1
|
||||
# 918| Type = align_val_t
|
||||
# 918| 2: p#2
|
||||
# 918| Type = float
|
||||
# 919| operator delete(void *, float) -> void
|
||||
# 919| params:
|
||||
# 919| 0: p#0
|
||||
# 919| Type = void *
|
||||
# 919| 1: p#1
|
||||
# 919| Type = float
|
||||
# 920| operator delete[](void *, float) -> void
|
||||
# 920| params:
|
||||
# 920| 0: p#0
|
||||
# 920| Type = void *
|
||||
# 920| 1: p#1
|
||||
# 920| Type = float
|
||||
# 921| operator delete(void *, align_val_t, float) -> void
|
||||
# 921| params:
|
||||
# 921| 0: p#0
|
||||
# 921| Type = void *
|
||||
# 921| 1: p#1
|
||||
# 921| Type = align_val_t
|
||||
# 921| 2: p#2
|
||||
# 921| Type = float
|
||||
# 922| operator delete[](void *, align_val_t, float) -> void
|
||||
# 922| params:
|
||||
# 922| 0: p#0
|
||||
# 922| Type = void *
|
||||
# 922| 1: p#1
|
||||
# 922| Type = align_val_t
|
||||
# 922| 2: p#2
|
||||
# 922| Type = float
|
||||
# 924| SizedDealloc::operator=(SizedDealloc &&) -> SizedDealloc &
|
||||
# 924| params:
|
||||
#-----| 0: p#0
|
||||
#-----| Type = SizedDealloc &&
|
||||
# 924| SizedDealloc::operator=(const SizedDealloc &) -> SizedDealloc &
|
||||
# 924| params:
|
||||
#-----| 0: p#0
|
||||
#-----| Type = const SizedDealloc &
|
||||
# 926| SizedDealloc::operator new(size_t) -> void *
|
||||
# 926| params:
|
||||
# 926| 0: p#0
|
||||
# 926| Type = size_t
|
||||
# 927| SizedDealloc::operator new[](size_t) -> void *
|
||||
# 927| params:
|
||||
# 927| 0: p#0
|
||||
# 927| Type = size_t
|
||||
# 928| SizedDealloc::operator delete(void *, size_t) -> void
|
||||
# 928| params:
|
||||
# 928| 0: p#0
|
||||
# 928| Type = void *
|
||||
# 928| 1: p#1
|
||||
# 928| Type = size_t
|
||||
# 929| SizedDealloc::operator delete[](void *, size_t) -> void
|
||||
# 929| params:
|
||||
# 929| 0: p#0
|
||||
# 929| Type = void *
|
||||
# 929| 1: p#1
|
||||
# 929| Type = size_t
|
||||
# 932| Overaligned::operator=(Overaligned &&) -> Overaligned &
|
||||
# 932| params:
|
||||
#-----| 0: p#0
|
||||
#-----| Type = Overaligned &&
|
||||
# 932| Overaligned::operator=(const Overaligned &) -> Overaligned &
|
||||
# 932| params:
|
||||
#-----| 0: p#0
|
||||
#-----| Type = const Overaligned &
|
||||
# 936| DefaultCtorWithDefaultParam::DefaultCtorWithDefaultParam(DefaultCtorWithDefaultParam &&) -> void
|
||||
# 936| params:
|
||||
#-----| 0: p#0
|
||||
#-----| Type = DefaultCtorWithDefaultParam &&
|
||||
# 936| DefaultCtorWithDefaultParam::DefaultCtorWithDefaultParam(const DefaultCtorWithDefaultParam &) -> void
|
||||
# 936| params:
|
||||
#-----| 0: p#0
|
||||
#-----| Type = const DefaultCtorWithDefaultParam &
|
||||
# 936| DefaultCtorWithDefaultParam::operator=(DefaultCtorWithDefaultParam &&) -> DefaultCtorWithDefaultParam &
|
||||
# 936| params:
|
||||
#-----| 0: p#0
|
||||
#-----| Type = DefaultCtorWithDefaultParam &&
|
||||
# 936| DefaultCtorWithDefaultParam::operator=(const DefaultCtorWithDefaultParam &) -> DefaultCtorWithDefaultParam &
|
||||
# 936| params:
|
||||
#-----| 0: p#0
|
||||
#-----| Type = const DefaultCtorWithDefaultParam &
|
||||
# 937| DefaultCtorWithDefaultParam::DefaultCtorWithDefaultParam(double) -> void
|
||||
# 937| params:
|
||||
# 937| 0: d
|
||||
# 937| Type = double
|
||||
# 940| OperatorNew() -> void
|
||||
# 940| params:
|
||||
# 940| body: { ... }
|
||||
# 941| 0: ExprStmt
|
||||
# 941| 0: new
|
||||
# 941| Type = int *
|
||||
# 941| ValueCategory = prvalue
|
||||
# 942| 1: ExprStmt
|
||||
# 942| 0: new
|
||||
# 942| Type = int *
|
||||
# 942| ValueCategory = prvalue
|
||||
# 942| 0: call to operator new
|
||||
# 942| Type = void *
|
||||
# 942| ValueCategory = prvalue
|
||||
# 942| 0: <error expr>
|
||||
# 942| Type = unsigned long
|
||||
# 942| ValueCategory = prvalue
|
||||
# 942| 1: 1.0
|
||||
# 942| Type = float
|
||||
# 942| Value = 1.0
|
||||
# 942| ValueCategory = prvalue
|
||||
# 943| 2: ExprStmt
|
||||
# 943| 0: new
|
||||
# 943| Type = int *
|
||||
# 943| ValueCategory = prvalue
|
||||
# 943| 1: 0
|
||||
# 943| Type = int
|
||||
# 943| Value = 0
|
||||
# 943| ValueCategory = prvalue
|
||||
# 944| 3: ExprStmt
|
||||
# 944| 0: new
|
||||
# 944| Type = String *
|
||||
# 944| ValueCategory = prvalue
|
||||
# 944| 1: call to String
|
||||
# 944| Type = void
|
||||
# 944| ValueCategory = prvalue
|
||||
# 945| 4: ExprStmt
|
||||
# 945| 0: new
|
||||
# 945| Type = String *
|
||||
# 945| ValueCategory = prvalue
|
||||
# 945| 0: call to operator new
|
||||
# 945| Type = void *
|
||||
# 945| ValueCategory = prvalue
|
||||
# 945| 0: <error expr>
|
||||
# 945| Type = unsigned long
|
||||
# 945| ValueCategory = prvalue
|
||||
# 945| 1: 1.0
|
||||
# 945| Type = float
|
||||
# 945| Value = 1.0
|
||||
# 945| ValueCategory = prvalue
|
||||
# 945| 1: call to String
|
||||
# 945| Type = void
|
||||
# 945| ValueCategory = prvalue
|
||||
# 945| 0: array to pointer conversion
|
||||
# 945| Type = const char *
|
||||
# 945| ValueCategory = prvalue
|
||||
# 945| expr: hello
|
||||
# 945| Type = const char[6]
|
||||
# 945| Value = "hello"
|
||||
# 945| ValueCategory = lvalue
|
||||
# 946| 5: ExprStmt
|
||||
# 946| 0: new
|
||||
# 946| Type = Overaligned *
|
||||
# 946| ValueCategory = prvalue
|
||||
# 946| 3: 128
|
||||
# 946| Type = align_val_t
|
||||
# 946| Value = 128
|
||||
# 946| ValueCategory = prvalue
|
||||
# 947| 6: ExprStmt
|
||||
# 947| 0: new
|
||||
# 947| Type = Overaligned *
|
||||
# 947| ValueCategory = prvalue
|
||||
# 947| 0: call to operator new
|
||||
# 947| Type = void *
|
||||
# 947| ValueCategory = prvalue
|
||||
# 947| 0: <error expr>
|
||||
# 947| Type = unsigned long
|
||||
# 947| ValueCategory = prvalue
|
||||
# 947| 1: 128
|
||||
# 947| Type = align_val_t
|
||||
# 947| Value = 128
|
||||
# 947| ValueCategory = prvalue
|
||||
# 947| 2: 1.0
|
||||
# 947| Type = float
|
||||
# 947| Value = 1.0
|
||||
# 947| ValueCategory = prvalue
|
||||
# 947| 1: 0
|
||||
# 947| Type = Overaligned
|
||||
# 947| Value = 0
|
||||
# 947| ValueCategory = prvalue
|
||||
# 948| 7: return ...
|
||||
# 950| OperatorNewArray(int) -> void
|
||||
# 950| params:
|
||||
# 950| 0: n
|
||||
# 950| Type = int
|
||||
# 950| body: { ... }
|
||||
# 951| 0: ExprStmt
|
||||
# 951| 0: new[]
|
||||
# 951| Type = int *
|
||||
# 951| ValueCategory = prvalue
|
||||
# 952| 1: ExprStmt
|
||||
# 952| 0: new[]
|
||||
# 952| Type = int *
|
||||
# 952| ValueCategory = prvalue
|
||||
# 952| 2: n
|
||||
# 952| Type = int
|
||||
# 952| ValueCategory = prvalue(load)
|
||||
# 953| 2: ExprStmt
|
||||
# 953| 0: new[]
|
||||
# 953| Type = int *
|
||||
# 953| ValueCategory = prvalue
|
||||
# 953| 0: call to operator new[]
|
||||
# 953| Type = void *
|
||||
# 953| ValueCategory = prvalue
|
||||
# 953| 0: <error expr>
|
||||
# 953| Type = unsigned long
|
||||
# 953| ValueCategory = prvalue
|
||||
# 953| 1: 1.0
|
||||
# 953| Type = float
|
||||
# 953| Value = 1.0
|
||||
# 953| ValueCategory = prvalue
|
||||
# 953| 2: n
|
||||
# 953| Type = int
|
||||
# 953| ValueCategory = prvalue(load)
|
||||
# 954| 3: ExprStmt
|
||||
# 954| 0: new[]
|
||||
# 954| Type = String *
|
||||
# 954| ValueCategory = prvalue
|
||||
# 954| 1: {...}
|
||||
# 954| Type = String[]
|
||||
# 954| ValueCategory = prvalue
|
||||
# 954| 0: call to String
|
||||
# 954| Type = void
|
||||
# 954| ValueCategory = prvalue
|
||||
# 954| 2: n
|
||||
# 954| Type = int
|
||||
# 954| ValueCategory = prvalue(load)
|
||||
# 955| 4: ExprStmt
|
||||
# 955| 0: new[]
|
||||
# 955| Type = Overaligned *
|
||||
# 955| ValueCategory = prvalue
|
||||
# 955| 2: n
|
||||
# 955| Type = int
|
||||
# 955| ValueCategory = prvalue(load)
|
||||
# 955| 3: 128
|
||||
# 955| Type = align_val_t
|
||||
# 955| Value = 128
|
||||
# 955| ValueCategory = prvalue
|
||||
# 956| 5: ExprStmt
|
||||
# 956| 0: new[]
|
||||
# 956| Type = Overaligned *
|
||||
# 956| ValueCategory = prvalue
|
||||
# 956| 0: call to operator new[]
|
||||
# 956| Type = void *
|
||||
# 956| ValueCategory = prvalue
|
||||
# 956| 0: <error expr>
|
||||
# 956| Type = unsigned long
|
||||
# 956| ValueCategory = prvalue
|
||||
# 956| 1: 128
|
||||
# 956| Type = align_val_t
|
||||
# 956| Value = 128
|
||||
# 956| ValueCategory = prvalue
|
||||
# 956| 2: 1.0
|
||||
# 956| Type = float
|
||||
# 956| Value = 1.0
|
||||
# 956| ValueCategory = prvalue
|
||||
# 957| 6: ExprStmt
|
||||
# 957| 0: new[]
|
||||
# 957| Type = DefaultCtorWithDefaultParam *
|
||||
# 957| ValueCategory = prvalue
|
||||
# 957| 1: {...}
|
||||
# 957| Type = DefaultCtorWithDefaultParam[]
|
||||
# 957| ValueCategory = prvalue
|
||||
# 957| 0: call to DefaultCtorWithDefaultParam
|
||||
# 957| Type = void
|
||||
# 957| ValueCategory = prvalue
|
||||
# 957| 2: n
|
||||
# 957| Type = int
|
||||
# 957| ValueCategory = prvalue(load)
|
||||
# 958| 7: ExprStmt
|
||||
# 958| 0: new[]
|
||||
# 958| Type = int *
|
||||
# 958| ValueCategory = prvalue
|
||||
# 958| 1: {...}
|
||||
# 958| Type = int[3]
|
||||
# 958| ValueCategory = prvalue
|
||||
# 958| 0: 0
|
||||
# 958| Type = int
|
||||
# 958| Value = 0
|
||||
# 958| ValueCategory = prvalue
|
||||
# 958| 1: 1
|
||||
# 958| Type = int
|
||||
# 958| Value = 1
|
||||
# 958| ValueCategory = prvalue
|
||||
# 958| 2: 2
|
||||
# 958| Type = int
|
||||
# 958| Value = 2
|
||||
# 958| ValueCategory = prvalue
|
||||
# 958| 2: n
|
||||
# 958| Type = int
|
||||
# 958| ValueCategory = prvalue(load)
|
||||
# 959| 8: return ...
|
||||
|
||||
@@ -3783,3 +3783,126 @@ ir.cpp:
|
||||
# 906| r3_2(glval<int>) = VariableAddress[#temp906:11] :
|
||||
# 906| m3_3(int) = Store : r3_2, r3_1
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 940| OperatorNew() -> void
|
||||
# 940| Block 0
|
||||
# 940| v0_0(void) = EnterFunction :
|
||||
# 940| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 941| r0_2(bool) = FunctionAddress[operator new] :
|
||||
# 941| r0_3(unsigned long) = Constant[4] :
|
||||
# 941| r0_4(void *) = Invoke : r0_2, r0_3
|
||||
# 941| r0_5(int *) = Convert : r0_4
|
||||
# 942| r0_6(bool) = FunctionAddress[operator new] :
|
||||
# 942| r0_7(unsigned long) = Constant[4] :
|
||||
# 942| r0_8(float) = Constant[1.0] :
|
||||
# 942| r0_9(void *) = Invoke : r0_6, r0_7, r0_8
|
||||
# 942| r0_10(int *) = Convert : r0_9
|
||||
# 943| r0_11(bool) = FunctionAddress[operator new] :
|
||||
# 943| r0_12(unsigned long) = Constant[4] :
|
||||
# 943| r0_13(void *) = Invoke : r0_11, r0_12
|
||||
# 943| r0_14(int *) = Convert : r0_13
|
||||
# 943| r0_15(int) = Constant[0] :
|
||||
# 943| mu0_16(int) = Store : r0_14, r0_15
|
||||
# 944| r0_17(bool) = FunctionAddress[operator new] :
|
||||
# 944| r0_18(unsigned long) = Constant[8] :
|
||||
# 944| r0_19(void *) = Invoke : r0_17, r0_18
|
||||
# 944| r0_20(String *) = Convert : r0_19
|
||||
# 944| r0_21(bool) = FunctionAddress[String] :
|
||||
# 944| v0_22(void) = Invoke : r0_21, this:r0_20
|
||||
# 945| r0_23(bool) = FunctionAddress[operator new] :
|
||||
# 945| r0_24(unsigned long) = Constant[8] :
|
||||
# 945| r0_25(float) = Constant[1.0] :
|
||||
# 945| r0_26(void *) = Invoke : r0_23, r0_24, r0_25
|
||||
# 945| r0_27(String *) = Convert : r0_26
|
||||
# 945| r0_28(bool) = FunctionAddress[String] :
|
||||
# 945| r0_29(glval<char[6]>) = StringConstant["hello"] :
|
||||
# 945| r0_30(char *) = Convert : r0_29
|
||||
# 945| v0_31(void) = Invoke : r0_28, this:r0_27, r0_30
|
||||
# 946| r0_32(bool) = FunctionAddress[operator new] :
|
||||
# 946| r0_33(unsigned long) = Constant[256] :
|
||||
# 946| r0_34(align_val_t) = Constant[128] :
|
||||
# 946| r0_35(void *) = Invoke : r0_32, r0_33, r0_34
|
||||
# 946| r0_36(Overaligned *) = Convert : r0_35
|
||||
# 947| r0_37(bool) = FunctionAddress[operator new] :
|
||||
# 947| r0_38(unsigned long) = Constant[256] :
|
||||
# 947| r0_39(align_val_t) = Constant[128] :
|
||||
# 947| r0_40(float) = Constant[1.0] :
|
||||
# 947| r0_41(void *) = Invoke : r0_37, r0_38, r0_39, r0_40
|
||||
# 947| r0_42(Overaligned *) = Convert : r0_41
|
||||
# 947| r0_43(Overaligned) = Constant[0] :
|
||||
# 947| mu0_44(Overaligned) = Store : r0_42, r0_43
|
||||
# 948| v0_45(void) = NoOp :
|
||||
# 940| v0_46(void) = ReturnVoid :
|
||||
# 940| v0_47(void) = UnmodeledUse : mu*
|
||||
# 940| v0_48(void) = ExitFunction :
|
||||
|
||||
# 950| OperatorNewArray(int) -> void
|
||||
# 950| Block 0
|
||||
# 950| v0_0(void) = EnterFunction :
|
||||
# 950| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 950| r0_2(glval<int>) = VariableAddress[n] :
|
||||
# 950| m0_3(int) = InitializeParameter[n] : r0_2
|
||||
# 951| r0_4(bool) = FunctionAddress[operator new[]] :
|
||||
# 951| r0_5(unsigned long) = Constant[40] :
|
||||
# 951| r0_6(void *) = Invoke : r0_4, r0_5
|
||||
# 951| r0_7(int *) = Convert : r0_6
|
||||
# 952| r0_8(bool) = FunctionAddress[operator new[]] :
|
||||
# 952| r0_9(glval<int>) = VariableAddress[n] :
|
||||
# 952| r0_10(int) = Load : r0_9, m0_3
|
||||
# 952| r0_11(unsigned long) = Convert : r0_10
|
||||
# 952| r0_12(unsigned long) = Constant[4] :
|
||||
# 952| r0_13(unsigned long) = Mul : r0_11, r0_12
|
||||
# 952| r0_14(void *) = Invoke : r0_8, r0_13
|
||||
# 952| r0_15(int *) = Convert : r0_14
|
||||
# 953| r0_16(bool) = FunctionAddress[operator new[]] :
|
||||
# 953| r0_17(glval<int>) = VariableAddress[n] :
|
||||
# 953| r0_18(int) = Load : r0_17, m0_3
|
||||
# 953| r0_19(unsigned long) = Convert : r0_18
|
||||
# 953| r0_20(unsigned long) = Constant[4] :
|
||||
# 953| r0_21(unsigned long) = Mul : r0_19, r0_20
|
||||
# 953| r0_22(float) = Constant[1.0] :
|
||||
# 953| r0_23(void *) = Invoke : r0_16, r0_21, r0_22
|
||||
# 953| r0_24(int *) = Convert : r0_23
|
||||
# 954| r0_25(bool) = FunctionAddress[operator new[]] :
|
||||
# 954| r0_26(glval<int>) = VariableAddress[n] :
|
||||
# 954| r0_27(int) = Load : r0_26, m0_3
|
||||
# 954| r0_28(unsigned long) = Convert : r0_27
|
||||
# 954| r0_29(unsigned long) = Constant[8] :
|
||||
# 954| r0_30(unsigned long) = Mul : r0_28, r0_29
|
||||
# 954| r0_31(void *) = Invoke : r0_25, r0_30
|
||||
# 954| r0_32(String *) = Convert : r0_31
|
||||
# 955| r0_33(bool) = FunctionAddress[operator new[]] :
|
||||
# 955| r0_34(glval<int>) = VariableAddress[n] :
|
||||
# 955| r0_35(int) = Load : r0_34, m0_3
|
||||
# 955| r0_36(unsigned long) = Convert : r0_35
|
||||
# 955| r0_37(unsigned long) = Constant[256] :
|
||||
# 955| r0_38(unsigned long) = Mul : r0_36, r0_37
|
||||
# 955| r0_39(align_val_t) = Constant[128] :
|
||||
# 955| r0_40(void *) = Invoke : r0_33, r0_38, r0_39
|
||||
# 955| r0_41(Overaligned *) = Convert : r0_40
|
||||
# 956| r0_42(bool) = FunctionAddress[operator new[]] :
|
||||
# 956| r0_43(unsigned long) = Constant[2560] :
|
||||
# 956| r0_44(align_val_t) = Constant[128] :
|
||||
# 956| r0_45(float) = Constant[1.0] :
|
||||
# 956| r0_46(void *) = Invoke : r0_42, r0_43, r0_44, r0_45
|
||||
# 956| r0_47(Overaligned *) = Convert : r0_46
|
||||
# 957| r0_48(bool) = FunctionAddress[operator new[]] :
|
||||
# 957| r0_49(glval<int>) = VariableAddress[n] :
|
||||
# 957| r0_50(int) = Load : r0_49, m0_3
|
||||
# 957| r0_51(unsigned long) = Convert : r0_50
|
||||
# 957| r0_52(unsigned long) = Constant[1] :
|
||||
# 957| r0_53(unsigned long) = Mul : r0_51, r0_52
|
||||
# 957| r0_54(void *) = Invoke : r0_48, r0_53
|
||||
# 957| r0_55(DefaultCtorWithDefaultParam *) = Convert : r0_54
|
||||
# 958| r0_56(bool) = FunctionAddress[operator new[]] :
|
||||
# 958| r0_57(glval<int>) = VariableAddress[n] :
|
||||
# 958| r0_58(int) = Load : r0_57, m0_3
|
||||
# 958| r0_59(unsigned long) = Convert : r0_58
|
||||
# 958| r0_60(unsigned long) = Constant[4] :
|
||||
# 958| r0_61(unsigned long) = Mul : r0_59, r0_60
|
||||
# 958| r0_62(void *) = Invoke : r0_56, r0_61
|
||||
# 958| r0_63(int *) = Convert : r0_62
|
||||
# 959| v0_64(void) = NoOp :
|
||||
# 950| v0_65(void) = ReturnVoid :
|
||||
# 950| v0_66(void) = UnmodeledUse : mu*
|
||||
# 950| v0_67(void) = ExitFunction :
|
||||
|
||||
@@ -905,3 +905,75 @@ void ConstantConditions(int x) {
|
||||
bool a = true && true;
|
||||
int b = (true) ? x : x;
|
||||
}
|
||||
|
||||
typedef unsigned long size_t;
|
||||
|
||||
namespace std {
|
||||
enum class align_val_t : size_t {};
|
||||
}
|
||||
|
||||
void* operator new(size_t, float);
|
||||
void* operator new[](size_t, float);
|
||||
void* operator new(size_t, std::align_val_t, float);
|
||||
void* operator new[](size_t, std::align_val_t, float);
|
||||
void operator delete(void*, float);
|
||||
void operator delete[](void*, float);
|
||||
void operator delete(void*, std::align_val_t, float);
|
||||
void operator delete[](void*, std::align_val_t, float);
|
||||
|
||||
struct SizedDealloc {
|
||||
char a[32];
|
||||
void* operator new(size_t);
|
||||
void* operator new[](size_t);
|
||||
void operator delete(void*, size_t);
|
||||
void operator delete[](void*, size_t);
|
||||
};
|
||||
|
||||
struct alignas(128) Overaligned {
|
||||
char a[256];
|
||||
};
|
||||
|
||||
struct DefaultCtorWithDefaultParam {
|
||||
DefaultCtorWithDefaultParam(double d = 1.0);
|
||||
};
|
||||
|
||||
void OperatorNew() {
|
||||
new int; // No constructor
|
||||
new(1.0f) int; // Placement new, no constructor
|
||||
new int(); // Zero-init
|
||||
new String(); // Constructor
|
||||
new(1.0f) String("hello"); // Placement new, constructor with args
|
||||
new Overaligned; // Aligned new
|
||||
new(1.0f) Overaligned(); // Placement aligned new with zero-init
|
||||
}
|
||||
|
||||
void OperatorNewArray(int n) {
|
||||
new int[10]; // Constant size
|
||||
new int[n]; // No constructor
|
||||
new(1.0f) int[n]; // Placement new, no constructor
|
||||
new String[n]; // Constructor
|
||||
new Overaligned[n]; // Aligned new
|
||||
new(1.0f) Overaligned[10]; // Aligned placement new
|
||||
new DefaultCtorWithDefaultParam[n];
|
||||
new int[n] { 0, 1, 2 };
|
||||
}
|
||||
|
||||
#if 0
|
||||
void OperatorDelete() {
|
||||
delete static_cast<int*>(nullptr); // No destructor
|
||||
delete static_cast<String*>(nullptr); // Non-virtual destructor, with size.
|
||||
delete static_cast<SizedDealloc*>(nullptr); // No destructor, with size.
|
||||
delete static_cast<Overaligned*>(nullptr); // No destructor, with size and alignment.
|
||||
delete static_cast<PolymorphicBase*>(nullptr); // Virtual destructor
|
||||
}
|
||||
|
||||
void OperatorDeleteArray() {
|
||||
delete[] static_cast<int*>(nullptr); // No destructor
|
||||
delete[] static_cast<String*>(nullptr); // Non-virtual destructor, with size.
|
||||
delete[] static_cast<SizedDealloc*>(nullptr); // No destructor, with size.
|
||||
delete[] static_cast<Overaligned*>(nullptr); // No destructor, with size and alignment.
|
||||
delete[] static_cast<PolymorphicBase*>(nullptr); // Virtual destructor
|
||||
}
|
||||
#endif
|
||||
|
||||
// semmle-extractor-options: -std=c++17
|
||||
|
||||
@@ -3762,3 +3762,126 @@ ir.cpp:
|
||||
# 906| r3_2(glval<int>) = VariableAddress[#temp906:11] :
|
||||
# 906| mu3_3(int) = Store : r3_2, r3_1
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 940| OperatorNew() -> void
|
||||
# 940| Block 0
|
||||
# 940| v0_0(void) = EnterFunction :
|
||||
# 940| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 941| r0_2(bool) = FunctionAddress[operator new] :
|
||||
# 941| r0_3(unsigned long) = Constant[4] :
|
||||
# 941| r0_4(void *) = Invoke : r0_2, r0_3
|
||||
# 941| r0_5(int *) = Convert : r0_4
|
||||
# 942| r0_6(bool) = FunctionAddress[operator new] :
|
||||
# 942| r0_7(unsigned long) = Constant[4] :
|
||||
# 942| r0_8(float) = Constant[1.0] :
|
||||
# 942| r0_9(void *) = Invoke : r0_6, r0_7, r0_8
|
||||
# 942| r0_10(int *) = Convert : r0_9
|
||||
# 943| r0_11(bool) = FunctionAddress[operator new] :
|
||||
# 943| r0_12(unsigned long) = Constant[4] :
|
||||
# 943| r0_13(void *) = Invoke : r0_11, r0_12
|
||||
# 943| r0_14(int *) = Convert : r0_13
|
||||
# 943| r0_15(int) = Constant[0] :
|
||||
# 943| mu0_16(int) = Store : r0_14, r0_15
|
||||
# 944| r0_17(bool) = FunctionAddress[operator new] :
|
||||
# 944| r0_18(unsigned long) = Constant[8] :
|
||||
# 944| r0_19(void *) = Invoke : r0_17, r0_18
|
||||
# 944| r0_20(String *) = Convert : r0_19
|
||||
# 944| r0_21(bool) = FunctionAddress[String] :
|
||||
# 944| v0_22(void) = Invoke : r0_21, this:r0_20
|
||||
# 945| r0_23(bool) = FunctionAddress[operator new] :
|
||||
# 945| r0_24(unsigned long) = Constant[8] :
|
||||
# 945| r0_25(float) = Constant[1.0] :
|
||||
# 945| r0_26(void *) = Invoke : r0_23, r0_24, r0_25
|
||||
# 945| r0_27(String *) = Convert : r0_26
|
||||
# 945| r0_28(bool) = FunctionAddress[String] :
|
||||
# 945| r0_29(glval<char[6]>) = StringConstant["hello"] :
|
||||
# 945| r0_30(char *) = Convert : r0_29
|
||||
# 945| v0_31(void) = Invoke : r0_28, this:r0_27, r0_30
|
||||
# 946| r0_32(bool) = FunctionAddress[operator new] :
|
||||
# 946| r0_33(unsigned long) = Constant[256] :
|
||||
# 946| r0_34(align_val_t) = Constant[128] :
|
||||
# 946| r0_35(void *) = Invoke : r0_32, r0_33, r0_34
|
||||
# 946| r0_36(Overaligned *) = Convert : r0_35
|
||||
# 947| r0_37(bool) = FunctionAddress[operator new] :
|
||||
# 947| r0_38(unsigned long) = Constant[256] :
|
||||
# 947| r0_39(align_val_t) = Constant[128] :
|
||||
# 947| r0_40(float) = Constant[1.0] :
|
||||
# 947| r0_41(void *) = Invoke : r0_37, r0_38, r0_39, r0_40
|
||||
# 947| r0_42(Overaligned *) = Convert : r0_41
|
||||
# 947| r0_43(Overaligned) = Constant[0] :
|
||||
# 947| mu0_44(Overaligned) = Store : r0_42, r0_43
|
||||
# 948| v0_45(void) = NoOp :
|
||||
# 940| v0_46(void) = ReturnVoid :
|
||||
# 940| v0_47(void) = UnmodeledUse : mu*
|
||||
# 940| v0_48(void) = ExitFunction :
|
||||
|
||||
# 950| OperatorNewArray(int) -> void
|
||||
# 950| Block 0
|
||||
# 950| v0_0(void) = EnterFunction :
|
||||
# 950| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 950| r0_2(glval<int>) = VariableAddress[n] :
|
||||
# 950| mu0_3(int) = InitializeParameter[n] : r0_2
|
||||
# 951| r0_4(bool) = FunctionAddress[operator new[]] :
|
||||
# 951| r0_5(unsigned long) = Constant[40] :
|
||||
# 951| r0_6(void *) = Invoke : r0_4, r0_5
|
||||
# 951| r0_7(int *) = Convert : r0_6
|
||||
# 952| r0_8(bool) = FunctionAddress[operator new[]] :
|
||||
# 952| r0_9(glval<int>) = VariableAddress[n] :
|
||||
# 952| r0_10(int) = Load : r0_9, mu0_1
|
||||
# 952| r0_11(unsigned long) = Convert : r0_10
|
||||
# 952| r0_12(unsigned long) = Constant[4] :
|
||||
# 952| r0_13(unsigned long) = Mul : r0_11, r0_12
|
||||
# 952| r0_14(void *) = Invoke : r0_8, r0_13
|
||||
# 952| r0_15(int *) = Convert : r0_14
|
||||
# 953| r0_16(bool) = FunctionAddress[operator new[]] :
|
||||
# 953| r0_17(glval<int>) = VariableAddress[n] :
|
||||
# 953| r0_18(int) = Load : r0_17, mu0_1
|
||||
# 953| r0_19(unsigned long) = Convert : r0_18
|
||||
# 953| r0_20(unsigned long) = Constant[4] :
|
||||
# 953| r0_21(unsigned long) = Mul : r0_19, r0_20
|
||||
# 953| r0_22(float) = Constant[1.0] :
|
||||
# 953| r0_23(void *) = Invoke : r0_16, r0_21, r0_22
|
||||
# 953| r0_24(int *) = Convert : r0_23
|
||||
# 954| r0_25(bool) = FunctionAddress[operator new[]] :
|
||||
# 954| r0_26(glval<int>) = VariableAddress[n] :
|
||||
# 954| r0_27(int) = Load : r0_26, mu0_1
|
||||
# 954| r0_28(unsigned long) = Convert : r0_27
|
||||
# 954| r0_29(unsigned long) = Constant[8] :
|
||||
# 954| r0_30(unsigned long) = Mul : r0_28, r0_29
|
||||
# 954| r0_31(void *) = Invoke : r0_25, r0_30
|
||||
# 954| r0_32(String *) = Convert : r0_31
|
||||
# 955| r0_33(bool) = FunctionAddress[operator new[]] :
|
||||
# 955| r0_34(glval<int>) = VariableAddress[n] :
|
||||
# 955| r0_35(int) = Load : r0_34, mu0_1
|
||||
# 955| r0_36(unsigned long) = Convert : r0_35
|
||||
# 955| r0_37(unsigned long) = Constant[256] :
|
||||
# 955| r0_38(unsigned long) = Mul : r0_36, r0_37
|
||||
# 955| r0_39(align_val_t) = Constant[128] :
|
||||
# 955| r0_40(void *) = Invoke : r0_33, r0_38, r0_39
|
||||
# 955| r0_41(Overaligned *) = Convert : r0_40
|
||||
# 956| r0_42(bool) = FunctionAddress[operator new[]] :
|
||||
# 956| r0_43(unsigned long) = Constant[2560] :
|
||||
# 956| r0_44(align_val_t) = Constant[128] :
|
||||
# 956| r0_45(float) = Constant[1.0] :
|
||||
# 956| r0_46(void *) = Invoke : r0_42, r0_43, r0_44, r0_45
|
||||
# 956| r0_47(Overaligned *) = Convert : r0_46
|
||||
# 957| r0_48(bool) = FunctionAddress[operator new[]] :
|
||||
# 957| r0_49(glval<int>) = VariableAddress[n] :
|
||||
# 957| r0_50(int) = Load : r0_49, mu0_1
|
||||
# 957| r0_51(unsigned long) = Convert : r0_50
|
||||
# 957| r0_52(unsigned long) = Constant[1] :
|
||||
# 957| r0_53(unsigned long) = Mul : r0_51, r0_52
|
||||
# 957| r0_54(void *) = Invoke : r0_48, r0_53
|
||||
# 957| r0_55(DefaultCtorWithDefaultParam *) = Convert : r0_54
|
||||
# 958| r0_56(bool) = FunctionAddress[operator new[]] :
|
||||
# 958| r0_57(glval<int>) = VariableAddress[n] :
|
||||
# 958| r0_58(int) = Load : r0_57, mu0_1
|
||||
# 958| r0_59(unsigned long) = Convert : r0_58
|
||||
# 958| r0_60(unsigned long) = Constant[4] :
|
||||
# 958| r0_61(unsigned long) = Mul : r0_59, r0_60
|
||||
# 958| r0_62(void *) = Invoke : r0_56, r0_61
|
||||
# 958| r0_63(int *) = Convert : r0_62
|
||||
# 959| v0_64(void) = NoOp :
|
||||
# 950| v0_65(void) = ReturnVoid :
|
||||
# 950| v0_66(void) = UnmodeledUse : mu*
|
||||
# 950| v0_67(void) = ExitFunction :
|
||||
|
||||
@@ -70,6 +70,8 @@
|
||||
| IR: MiddleVB2 | 1 |
|
||||
| IR: NestedInitList | 1 |
|
||||
| IR: Nullptr | 1 |
|
||||
| IR: OperatorNew | 1 |
|
||||
| IR: OperatorNewArray | 1 |
|
||||
| IR: Parameters | 1 |
|
||||
| IR: PointerCompare | 1 |
|
||||
| IR: PointerCrement | 1 |
|
||||
|
||||
@@ -3783,3 +3783,126 @@ ir.cpp:
|
||||
# 906| r3_2(glval<int>) = VariableAddress[#temp906:11] :
|
||||
# 906| m3_3(int) = Store : r3_2, r3_1
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 940| OperatorNew() -> void
|
||||
# 940| Block 0
|
||||
# 940| v0_0(void) = EnterFunction :
|
||||
# 940| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 941| r0_2(bool) = FunctionAddress[operator new] :
|
||||
# 941| r0_3(unsigned long) = Constant[4] :
|
||||
# 941| r0_4(void *) = Invoke : r0_2, r0_3
|
||||
# 941| r0_5(int *) = Convert : r0_4
|
||||
# 942| r0_6(bool) = FunctionAddress[operator new] :
|
||||
# 942| r0_7(unsigned long) = Constant[4] :
|
||||
# 942| r0_8(float) = Constant[1.0] :
|
||||
# 942| r0_9(void *) = Invoke : r0_6, r0_7, r0_8
|
||||
# 942| r0_10(int *) = Convert : r0_9
|
||||
# 943| r0_11(bool) = FunctionAddress[operator new] :
|
||||
# 943| r0_12(unsigned long) = Constant[4] :
|
||||
# 943| r0_13(void *) = Invoke : r0_11, r0_12
|
||||
# 943| r0_14(int *) = Convert : r0_13
|
||||
# 943| r0_15(int) = Constant[0] :
|
||||
# 943| mu0_16(int) = Store : r0_14, r0_15
|
||||
# 944| r0_17(bool) = FunctionAddress[operator new] :
|
||||
# 944| r0_18(unsigned long) = Constant[8] :
|
||||
# 944| r0_19(void *) = Invoke : r0_17, r0_18
|
||||
# 944| r0_20(String *) = Convert : r0_19
|
||||
# 944| r0_21(bool) = FunctionAddress[String] :
|
||||
# 944| v0_22(void) = Invoke : r0_21, this:r0_20
|
||||
# 945| r0_23(bool) = FunctionAddress[operator new] :
|
||||
# 945| r0_24(unsigned long) = Constant[8] :
|
||||
# 945| r0_25(float) = Constant[1.0] :
|
||||
# 945| r0_26(void *) = Invoke : r0_23, r0_24, r0_25
|
||||
# 945| r0_27(String *) = Convert : r0_26
|
||||
# 945| r0_28(bool) = FunctionAddress[String] :
|
||||
# 945| r0_29(glval<char[6]>) = StringConstant["hello"] :
|
||||
# 945| r0_30(char *) = Convert : r0_29
|
||||
# 945| v0_31(void) = Invoke : r0_28, this:r0_27, r0_30
|
||||
# 946| r0_32(bool) = FunctionAddress[operator new] :
|
||||
# 946| r0_33(unsigned long) = Constant[256] :
|
||||
# 946| r0_34(align_val_t) = Constant[128] :
|
||||
# 946| r0_35(void *) = Invoke : r0_32, r0_33, r0_34
|
||||
# 946| r0_36(Overaligned *) = Convert : r0_35
|
||||
# 947| r0_37(bool) = FunctionAddress[operator new] :
|
||||
# 947| r0_38(unsigned long) = Constant[256] :
|
||||
# 947| r0_39(align_val_t) = Constant[128] :
|
||||
# 947| r0_40(float) = Constant[1.0] :
|
||||
# 947| r0_41(void *) = Invoke : r0_37, r0_38, r0_39, r0_40
|
||||
# 947| r0_42(Overaligned *) = Convert : r0_41
|
||||
# 947| r0_43(Overaligned) = Constant[0] :
|
||||
# 947| mu0_44(Overaligned) = Store : r0_42, r0_43
|
||||
# 948| v0_45(void) = NoOp :
|
||||
# 940| v0_46(void) = ReturnVoid :
|
||||
# 940| v0_47(void) = UnmodeledUse : mu*
|
||||
# 940| v0_48(void) = ExitFunction :
|
||||
|
||||
# 950| OperatorNewArray(int) -> void
|
||||
# 950| Block 0
|
||||
# 950| v0_0(void) = EnterFunction :
|
||||
# 950| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 950| r0_2(glval<int>) = VariableAddress[n] :
|
||||
# 950| m0_3(int) = InitializeParameter[n] : r0_2
|
||||
# 951| r0_4(bool) = FunctionAddress[operator new[]] :
|
||||
# 951| r0_5(unsigned long) = Constant[40] :
|
||||
# 951| r0_6(void *) = Invoke : r0_4, r0_5
|
||||
# 951| r0_7(int *) = Convert : r0_6
|
||||
# 952| r0_8(bool) = FunctionAddress[operator new[]] :
|
||||
# 952| r0_9(glval<int>) = VariableAddress[n] :
|
||||
# 952| r0_10(int) = Load : r0_9, m0_3
|
||||
# 952| r0_11(unsigned long) = Convert : r0_10
|
||||
# 952| r0_12(unsigned long) = Constant[4] :
|
||||
# 952| r0_13(unsigned long) = Mul : r0_11, r0_12
|
||||
# 952| r0_14(void *) = Invoke : r0_8, r0_13
|
||||
# 952| r0_15(int *) = Convert : r0_14
|
||||
# 953| r0_16(bool) = FunctionAddress[operator new[]] :
|
||||
# 953| r0_17(glval<int>) = VariableAddress[n] :
|
||||
# 953| r0_18(int) = Load : r0_17, m0_3
|
||||
# 953| r0_19(unsigned long) = Convert : r0_18
|
||||
# 953| r0_20(unsigned long) = Constant[4] :
|
||||
# 953| r0_21(unsigned long) = Mul : r0_19, r0_20
|
||||
# 953| r0_22(float) = Constant[1.0] :
|
||||
# 953| r0_23(void *) = Invoke : r0_16, r0_21, r0_22
|
||||
# 953| r0_24(int *) = Convert : r0_23
|
||||
# 954| r0_25(bool) = FunctionAddress[operator new[]] :
|
||||
# 954| r0_26(glval<int>) = VariableAddress[n] :
|
||||
# 954| r0_27(int) = Load : r0_26, m0_3
|
||||
# 954| r0_28(unsigned long) = Convert : r0_27
|
||||
# 954| r0_29(unsigned long) = Constant[8] :
|
||||
# 954| r0_30(unsigned long) = Mul : r0_28, r0_29
|
||||
# 954| r0_31(void *) = Invoke : r0_25, r0_30
|
||||
# 954| r0_32(String *) = Convert : r0_31
|
||||
# 955| r0_33(bool) = FunctionAddress[operator new[]] :
|
||||
# 955| r0_34(glval<int>) = VariableAddress[n] :
|
||||
# 955| r0_35(int) = Load : r0_34, m0_3
|
||||
# 955| r0_36(unsigned long) = Convert : r0_35
|
||||
# 955| r0_37(unsigned long) = Constant[256] :
|
||||
# 955| r0_38(unsigned long) = Mul : r0_36, r0_37
|
||||
# 955| r0_39(align_val_t) = Constant[128] :
|
||||
# 955| r0_40(void *) = Invoke : r0_33, r0_38, r0_39
|
||||
# 955| r0_41(Overaligned *) = Convert : r0_40
|
||||
# 956| r0_42(bool) = FunctionAddress[operator new[]] :
|
||||
# 956| r0_43(unsigned long) = Constant[2560] :
|
||||
# 956| r0_44(align_val_t) = Constant[128] :
|
||||
# 956| r0_45(float) = Constant[1.0] :
|
||||
# 956| r0_46(void *) = Invoke : r0_42, r0_43, r0_44, r0_45
|
||||
# 956| r0_47(Overaligned *) = Convert : r0_46
|
||||
# 957| r0_48(bool) = FunctionAddress[operator new[]] :
|
||||
# 957| r0_49(glval<int>) = VariableAddress[n] :
|
||||
# 957| r0_50(int) = Load : r0_49, m0_3
|
||||
# 957| r0_51(unsigned long) = Convert : r0_50
|
||||
# 957| r0_52(unsigned long) = Constant[1] :
|
||||
# 957| r0_53(unsigned long) = Mul : r0_51, r0_52
|
||||
# 957| r0_54(void *) = Invoke : r0_48, r0_53
|
||||
# 957| r0_55(DefaultCtorWithDefaultParam *) = Convert : r0_54
|
||||
# 958| r0_56(bool) = FunctionAddress[operator new[]] :
|
||||
# 958| r0_57(glval<int>) = VariableAddress[n] :
|
||||
# 958| r0_58(int) = Load : r0_57, m0_3
|
||||
# 958| r0_59(unsigned long) = Convert : r0_58
|
||||
# 958| r0_60(unsigned long) = Constant[4] :
|
||||
# 958| r0_61(unsigned long) = Mul : r0_59, r0_60
|
||||
# 958| r0_62(void *) = Invoke : r0_56, r0_61
|
||||
# 958| r0_63(int *) = Convert : r0_62
|
||||
# 959| v0_64(void) = NoOp :
|
||||
# 950| v0_65(void) = ReturnVoid :
|
||||
# 950| v0_66(void) = UnmodeledUse : mu*
|
||||
# 950| v0_67(void) = ExitFunction :
|
||||
|
||||
Reference in New Issue
Block a user