Skip to content

Commit cc4bbc2

Browse files
committed
Binary: Generate IR for CIL's newobject instruction.
1 parent 88a3f09 commit cc4bbc2

5 files changed

Lines changed: 139 additions & 6 deletions

File tree

binary/ql/lib/semmle/code/binary/ast/internal/CilInstructions.qll

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,9 +362,13 @@ class CilDup extends @il_dup, CilInstruction { }
362362

363363
class CilIl_pop extends @il_il_pop, CilInstruction { }
364364

365-
abstract class CilCall extends CilInstruction {
365+
abstract class CilCallOrNewObject extends CilInstruction {
366366
final int getNumberOfArguments() { il_number_of_arguments(this, result) }
367367

368+
final string getExternalName() { il_call_target_unresolved(this, result) }
369+
}
370+
371+
abstract class CilCall extends CilCallOrNewObject {
368372
final predicate hasReturnValue() { il_call_has_return_value(this) }
369373

370374
CilMethod getTarget() { result.getFullyQualifiedName() = this.getExternalName() }
@@ -591,7 +595,10 @@ class CilLdstr extends @il_ldstr, CilInstruction {
591595
string getValue() { il_operand_string(this, result) }
592596
}
593597

594-
class CilNewobj extends @il_newobj, CilInstruction { }
598+
class CilNewobj extends @il_newobj, CilCallOrNewObject {
599+
/** ... If it exists. */
600+
CilMethod getConstructor() { result.getFullyQualifiedName() = this.getExternalName() }
601+
}
595602

596603
class CilCastclass extends @il_castclass, CilInstruction { }
597604

binary/ql/lib/semmle/code/binary/ast/ir/internal/Instruction0/InstructionTag.qll

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@ newtype TInstructionTag =
5353
CilCallTag() or
5454
CilCallTargetTag() or
5555
CilLdindLoadTag() or
56-
CilStindStoreTag()
56+
CilStindStoreTag() or
57+
CilNewObjInitTag() or
58+
CilNewObjCallTag() or
59+
CilNewObjExternalRefTag()
5760

5861
class InstructionTag extends TInstructionTag {
5962
final string toString() {
@@ -196,6 +199,15 @@ class InstructionTag extends TInstructionTag {
196199
or
197200
this = CilStindStoreTag() and
198201
result = "CilStindStore"
202+
or
203+
this = CilNewObjInitTag() and
204+
result = "CilNewObjInit"
205+
or
206+
this = CilNewObjCallTag() and
207+
result = "CilNewObjCall"
208+
or
209+
this = CilNewObjExternalRefTag() and
210+
result = "CilNewObjExternalRef"
199211
}
200212
}
201213

@@ -211,7 +223,7 @@ private newtype TOperandTag =
211223
TCondJumpTargetTag() or
212224
TJumpTargetTag() or
213225
TCilOperandTag(int i) {
214-
i = [0 .. max(CilCall call, int k | k = call.getNumberOfArguments() - 1 | k)]
226+
i = [0 .. max(CilCallOrNewObject call, int k | k = call.getNumberOfArguments() | k)]
215227
}
216228

217229
abstract class OperandTag extends TOperandTag {

binary/ql/lib/semmle/code/binary/ast/ir/internal/Instruction0/TempVariableTag.qll

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ newtype TTempVariableTag =
2929
CilCallTargetVarTag() or
3030
CilLoadStringVarTag() or
3131
CilLoadArgVarTag() or
32-
CilLdindVarTag()
32+
CilLdindVarTag() or
33+
CilNewObjInitVarTag() or
34+
CilNewObjCallExternalVarTag()
3335

3436
class TempVariableTag extends TTempVariableTag {
3537
string toString() {
@@ -125,5 +127,11 @@ class TempVariableTag extends TTempVariableTag {
125127
or
126128
this = CilLdindVarTag() and
127129
result = "ldind"
130+
or
131+
this = CilNewObjInitVarTag() and
132+
result = "newobj"
133+
or
134+
this = CilNewObjCallExternalVarTag() and
135+
result = "newobj_ext"
128136
}
129137
}

binary/ql/lib/semmle/code/binary/ast/ir/internal/Instruction0/TranslatedElement.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ newtype TTranslatedElement =
132132
TTranslatedCilStoreIndirect(Raw::CilStoreIndirectInstruction stind) {
133133
shouldTranslateCilInstr(stind)
134134
} or
135-
TTranslatedCilType(Raw::CilType type) { shouldTranslatedCilType(type) }
135+
TTranslatedCilType(Raw::CilType type) { shouldTranslatedCilType(type) } or
136+
TTranslatedNewObject(Raw::CilNewobj newObj) { shouldTranslateCilInstr(newObj) }
136137

137138
TranslatedElement getTranslatedElement(Raw::Element raw) {
138139
result.getRawElement() = raw and

binary/ql/lib/semmle/code/binary/ast/ir/internal/Instruction0/TranslatedInstruction.qll

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2400,3 +2400,108 @@ class TranslatedCilStoreIndirect extends TranslatedCilInstruction, TTranslatedCi
24002400
result = getTranslatedCilInstruction(instr.getABackwardPredecessor()).getStackElement(i + 2)
24012401
}
24022402
}
2403+
2404+
// Translate a `nobjc<constructor>` CIL instruction to:
2405+
// 1. x = init
2406+
// 2. call co constructor(x, args...)
2407+
class TranslatedNewObject extends TranslatedCilInstruction, TTranslatedNewObject {
2408+
override Raw::CilNewobj instr;
2409+
2410+
TranslatedNewObject() { this = TTranslatedNewObject(instr) }
2411+
2412+
final override predicate hasInstruction(
2413+
Opcode opcode, InstructionTag tag, Option<Variable>::Option v
2414+
) {
2415+
not exists(instr.getConstructor()) and
2416+
opcode instanceof Opcode::ExternalRef and
2417+
tag = CilNewObjExternalRefTag() and
2418+
v.asSome() = this.getTempVariable(CilNewObjCallExternalVarTag())
2419+
or
2420+
opcode instanceof Opcode::Init and
2421+
tag = CilNewObjInitTag() and
2422+
v.asSome() = this.getTempVariable(CilNewObjInitVarTag())
2423+
or
2424+
opcode instanceof Opcode::Call and
2425+
tag = CilNewObjCallTag() and
2426+
v.isNone()
2427+
}
2428+
2429+
override string getExternalName(InstructionTag tag) {
2430+
not exists(instr.getConstructor()) and
2431+
tag = CilCallTargetTag() and
2432+
result = instr.getExternalName()
2433+
}
2434+
2435+
override predicate hasTempVariable(TempVariableTag tag) {
2436+
tag = CilNewObjInitVarTag()
2437+
or
2438+
not exists(instr.getConstructor()) and tag = CilNewObjCallExternalVarTag()
2439+
}
2440+
2441+
override predicate producesResult() { any() }
2442+
2443+
override Variable getVariableOperand(InstructionTag tag, OperandTag operandTag) {
2444+
tag = CilNewObjCallTag() and
2445+
(
2446+
not exists(instr.getConstructor()) and
2447+
operandTag instanceof CallTargetTag and
2448+
result = this.getInstruction(CilNewObjExternalRefTag()).getResultVariable()
2449+
or
2450+
exists(int i | i = operandTag.(CilOperandTag).getCilIndex() |
2451+
// The 0'th argument to the constructor is the just-zero-initialized new object
2452+
if i = 0
2453+
then result = this.getInstruction(CilNewObjInitTag()).getResultVariable()
2454+
else
2455+
// And the other arguments are the constructor arguments
2456+
result =
2457+
getTranslatedCilInstruction(instr.getABackwardPredecessor()).getStackElement(i - 1)
2458+
)
2459+
)
2460+
}
2461+
2462+
override Instruction getChildSuccessor(TranslatedElement child, SuccessorType succType) { none() }
2463+
2464+
override Instruction getSuccessor(InstructionTag tag, SuccessorType succType) {
2465+
tag = CilNewObjInitTag() and
2466+
succType instanceof DirectSuccessor and
2467+
(
2468+
if exists(instr.getConstructor())
2469+
then result = this.getInstruction(CilNewObjCallTag())
2470+
else result = this.getInstruction(CilNewObjExternalRefTag())
2471+
)
2472+
or
2473+
not exists(instr.getConstructor()) and
2474+
(
2475+
tag = CilNewObjExternalRefTag() and
2476+
succType instanceof DirectSuccessor and
2477+
result = this.getInstruction(CilNewObjCallTag())
2478+
)
2479+
or
2480+
tag = CilNewObjCallTag() and
2481+
succType instanceof DirectSuccessor and
2482+
result = getTranslatedInstruction(instr.getASuccessor()).getEntry()
2483+
}
2484+
2485+
override Instruction getEntry() { result = this.getInstruction(CilNewObjInitTag()) }
2486+
2487+
override Variable getResultVariable() { result = this.getTempVariable(CilNewObjInitVarTag()) }
2488+
2489+
final override TranslatedCilMethod getStaticCallTarget(InstructionTag tag) {
2490+
tag = CilNewObjCallTag() and
2491+
result = getTranslatedFunction(instr.getConstructor())
2492+
}
2493+
2494+
final override Variable getStackElement(int i) {
2495+
// The new top element is the constructed object
2496+
if i = 0
2497+
then result = this.getTempVariable(CilNewObjInitVarTag())
2498+
else
2499+
// And the other arguments have been popped off the stack.
2500+
// Note: We don't subtract 1 because the number of arguments is actually
2501+
// one more than `instr.getNumberOfArguments()` since we the 0'th
2502+
// argument is the newly-constructed object.
2503+
result =
2504+
getTranslatedCilInstruction(instr.getABackwardPredecessor())
2505+
.getStackElement(i + instr.getNumberOfArguments())
2506+
}
2507+
}

0 commit comments

Comments
 (0)