Skip to content

Commit d1e6813

Browse files
author
Dave Bartolomeo
committed
Make side effects for constructor calls use same mechanism as other arguments
This commit is yet another step to fixing the order of IR side effect instructions. Instead of having a special `StructorCallSideEffects` class for the call itself, I've introduced a `TranslatedStructorCallQualifierSideEffect` class that shares a bunch of common code with `TranslatedArgumentExprSideEffect`, but handles the case where there's no `Expr` for the qualifier of the constructor call. Because this class uses the same ordering as regular argument side effects, these side effects now appear in the correct order, reads before writes. The test expectations have changed to reflect the new, correct order.
1 parent ba72a1c commit d1e6813

File tree

7 files changed

+190
-160
lines changed

7 files changed

+190
-160
lines changed

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll

Lines changed: 115 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -406,42 +406,6 @@ class TranslatedCallSideEffects extends TranslatedSideEffects, TTranslatedCallSi
406406
}
407407
}
408408

409-
class TranslatedStructorCallSideEffects extends TranslatedCallSideEffects {
410-
TranslatedStructorCallSideEffects() {
411-
getParent().(TranslatedStructorCall).hasQualifier() and
412-
getASideEffectOpcode(expr, -1) instanceof WriteSideEffectOpcode
413-
}
414-
415-
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType t) {
416-
tag instanceof OnlyInstructionTag and
417-
t = getTypeForPRValue(expr.getTarget().getDeclaringType()) and
418-
opcode = getASideEffectOpcode(expr, -1).(WriteSideEffectOpcode)
419-
}
420-
421-
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
422-
(
423-
if exists(getChild(0))
424-
then result = getChild(0).getFirstInstruction()
425-
else result = getParent().getChildSuccessor(this)
426-
) and
427-
tag = OnlyInstructionTag() and
428-
kind instanceof GotoEdge
429-
}
430-
431-
override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
432-
433-
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
434-
tag instanceof OnlyInstructionTag and
435-
operandTag instanceof AddressOperandTag and
436-
result = getParent().(TranslatedStructorCall).getQualifierResult()
437-
}
438-
439-
final override int getInstructionIndex(InstructionTag tag) {
440-
tag = OnlyInstructionTag() and
441-
result = -1
442-
}
443-
}
444-
445409
/** Returns the sort group index for argument read side effects. */
446410
private int argumentReadGroup() { result = 1 }
447411

@@ -502,19 +466,22 @@ abstract class TranslatedSideEffect extends TranslatedElement {
502466
/**
503467
* The IR translation of a single argument side effect for a call.
504468
*/
505-
class TranslatedArgumentSideEffect extends TranslatedSideEffect, TTranslatedArgumentSideEffect {
469+
abstract class TranslatedArgumentSideEffect extends TranslatedSideEffect {
506470
Call call;
507-
Expr arg;
508471
int index;
509472
SideEffectOpcode sideEffectOpcode;
510473

511-
TranslatedArgumentSideEffect() {
512-
this = TTranslatedArgumentSideEffect(call, arg, index, sideEffectOpcode)
513-
}
514-
515-
override Locatable getAST() { result = arg }
474+
// All subclass charpreds must bind the `index` field.
475+
bindingset[index]
476+
TranslatedArgumentSideEffect() { any() }
516477

517-
Expr getExpr() { result = arg }
478+
override string toString() {
479+
isWrite() and
480+
result = "(write side effect for " + getArgString() + ")"
481+
or
482+
not isWrite() and
483+
result = "(read side effect for " + getArgString() + ")"
484+
}
518485

519486
override Call getPrimaryExpr() { result = call }
520487

@@ -523,17 +490,29 @@ class TranslatedArgumentSideEffect extends TranslatedSideEffect, TTranslatedArgu
523490
if isWrite() then group = argumentWriteGroup() else group = argumentReadGroup()
524491
}
525492

526-
predicate isWrite() { sideEffectOpcode instanceof WriteSideEffectOpcode }
493+
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
494+
tag = OnlyInstructionTag() and
495+
result = getTranslatedCallInstruction(call)
496+
}
527497

528-
override string toString() {
529-
isWrite() and
530-
result = "(write side effect for " + arg.toString() + ")"
531-
or
532-
not isWrite() and
533-
result = "(read side effect for " + arg.toString() + ")"
498+
final override int getInstructionIndex(InstructionTag tag) {
499+
tag = OnlyInstructionTag() and
500+
result = index
534501
}
535502

536-
override predicate sideEffectInstruction(Opcode opcode, CppType type) {
503+
/**
504+
* Gets the `TranslatedFunction` containing this expression.
505+
*/
506+
final TranslatedFunction getEnclosingFunction() {
507+
result = getTranslatedFunction(call.getEnclosingFunction())
508+
}
509+
510+
/**
511+
* Gets the `Function` containing this expression.
512+
*/
513+
final override Function getFunction() { result = call.getEnclosingFunction() }
514+
515+
final override predicate sideEffectInstruction(Opcode opcode, CppType type) {
537516
opcode = sideEffectOpcode and
538517
(
539518
isWrite() and
@@ -542,36 +521,21 @@ class TranslatedArgumentSideEffect extends TranslatedSideEffect, TTranslatedArgu
542521
type = getUnknownType()
543522
or
544523
not opcode instanceof BufferAccessOpcode and
545-
exists(Type baseType | baseType = arg.getUnspecifiedType().(DerivedType).getBaseType() |
546-
if baseType instanceof VoidType
524+
exists(Type indirectionType | indirectionType = getIndirectionType() |
525+
if indirectionType instanceof VoidType
547526
then type = getUnknownType()
548-
else type = getTypeForPRValueOrUnknown(baseType)
527+
else type = getTypeForPRValueOrUnknown(indirectionType)
549528
)
550-
or
551-
index = -1 and
552-
not arg.getUnspecifiedType() instanceof DerivedType and
553-
type = getTypeForPRValueOrUnknown(arg.getUnspecifiedType())
554529
)
555530
or
556531
not isWrite() and
557532
type = getVoidType()
558533
)
559534
}
560535

561-
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
562-
tag instanceof OnlyInstructionTag and
563-
operandTag instanceof AddressOperandTag and
564-
result = getTranslatedExpr(arg).getResult()
565-
or
566-
tag instanceof OnlyInstructionTag and
567-
operandTag instanceof BufferSizeOperandTag and
568-
result =
569-
getTranslatedExpr(call.getArgument(call.getTarget()
570-
.(SideEffectFunction)
571-
.getParameterSizeIndex(index)).getFullyConverted()).getResult()
572-
}
573-
574-
override CppType getInstructionMemoryOperandType(InstructionTag tag, TypedOperandTag operandTag) {
536+
final override CppType getInstructionMemoryOperandType(
537+
InstructionTag tag, TypedOperandTag operandTag
538+
) {
575539
not isWrite() and
576540
if sideEffectOpcode instanceof BufferAccessOpcode
577541
then
@@ -581,12 +545,7 @@ class TranslatedArgumentSideEffect extends TranslatedSideEffect, TTranslatedArgu
581545
else
582546
exists(Type operandType |
583547
tag instanceof OnlyInstructionTag and
584-
operandType = arg.getType().getUnspecifiedType().(DerivedType).getBaseType() and
585-
operandTag instanceof SideEffectOperandTag
586-
or
587-
tag instanceof OnlyInstructionTag and
588-
operandType = arg.getType().getUnspecifiedType() and
589-
not operandType instanceof DerivedType and
548+
operandType = getIndirectionType() and
590549
operandTag instanceof SideEffectOperandTag
591550
|
592551
// If the type we select is an incomplete type (e.g. a forward-declared `struct`), there will
@@ -595,25 +554,87 @@ class TranslatedArgumentSideEffect extends TranslatedSideEffect, TTranslatedArgu
595554
)
596555
}
597556

598-
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
599-
tag = OnlyInstructionTag() and
600-
result = getTranslatedCallInstruction(call)
557+
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
558+
tag instanceof OnlyInstructionTag and
559+
operandTag instanceof AddressOperandTag and
560+
result = getArgInstruction()
561+
or
562+
tag instanceof OnlyInstructionTag and
563+
operandTag instanceof BufferSizeOperandTag and
564+
result =
565+
getTranslatedExpr(call.getArgument(call.getTarget()
566+
.(SideEffectFunction)
567+
.getParameterSizeIndex(index)).getFullyConverted()).getResult()
601568
}
602569

603-
final override int getInstructionIndex(InstructionTag tag) {
604-
tag = OnlyInstructionTag() and
605-
result = index
570+
/** Holds if this side effect is a write side effect, rather than a read side effect. */
571+
final predicate isWrite() { sideEffectOpcode instanceof WriteSideEffectOpcode }
572+
573+
/** Gets a text representation of the argument. */
574+
abstract string getArgString();
575+
576+
/** Gets the `Instruction` whose result is the value of the argument. */
577+
abstract Instruction getArgInstruction();
578+
579+
/** Gets the type pointed to by the argument. */
580+
abstract Type getIndirectionType();
581+
}
582+
583+
/**
584+
* The IR translation of an argument side effect where the argument has an `Expr` object in the AST.
585+
*
586+
* This generally applies to all positional arguments, as well as qualifier (`this`) arguments for
587+
* calls other than constructor calls.
588+
*/
589+
class TranslatedArgumentExprSideEffect extends TranslatedArgumentSideEffect,
590+
TTranslatedArgumentExprSideEffect {
591+
Expr arg;
592+
593+
TranslatedArgumentExprSideEffect() {
594+
this = TTranslatedArgumentExprSideEffect(call, arg, index, sideEffectOpcode)
606595
}
607596

608-
/**
609-
* Gets the `TranslatedFunction` containing this expression.
610-
*/
611-
final TranslatedFunction getEnclosingFunction() {
612-
result = getTranslatedFunction(arg.getEnclosingFunction())
597+
final override Locatable getAST() { result = arg }
598+
599+
final override Type getIndirectionType() {
600+
result = arg.getUnspecifiedType().(DerivedType).getBaseType()
601+
or
602+
// Sometimes the qualifier type gets the type of the class itself, rather than a pointer to the
603+
// class.
604+
index = -1 and
605+
not arg.getUnspecifiedType() instanceof DerivedType and
606+
result = arg.getUnspecifiedType()
613607
}
614608

615-
/**
616-
* Gets the `Function` containing this expression.
617-
*/
618-
override Function getFunction() { result = arg.getEnclosingFunction() }
609+
final override string getArgString() { result = arg.toString() }
610+
611+
final override Instruction getArgInstruction() { result = getTranslatedExpr(arg).getResult() }
612+
}
613+
614+
/**
615+
* The IR translation of an argument side effect for `*this` on a call, where there is no `Expr`
616+
* object that represents the `this` argument.
617+
*
618+
* The applies only to constructor calls, as the AST has explioit qualifier `Expr`s for all other
619+
* calls to non-static member functions.
620+
*/
621+
class TranslatedStructorQualifierSideEffect extends TranslatedArgumentSideEffect,
622+
TTranslatedStructorQualifierSideEffect {
623+
TranslatedStructorQualifierSideEffect() {
624+
this = TTranslatedStructorQualifierSideEffect(call, sideEffectOpcode) and
625+
index = -1
626+
}
627+
628+
final override Locatable getAST() { result = call }
629+
630+
final override Type getIndirectionType() { result = call.getTarget().getDeclaringType() }
631+
632+
final override string getArgString() { result = "this" }
633+
634+
final override Instruction getArgInstruction() {
635+
exists(TranslatedStructorCall structorCall |
636+
structorCall.getExpr() = call and
637+
result = structorCall.getQualifierResult()
638+
)
639+
}
619640
}

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -630,14 +630,14 @@ newtype TTranslatedElement =
630630
// translated elements as no call can be both a `ConstructorCall` and an `AllocationExpr`.
631631
not expr instanceof AllocationExpr and
632632
(
633-
exists(TTranslatedArgumentSideEffect(expr, _, _, _)) or
633+
exists(TTranslatedArgumentExprSideEffect(expr, _, _, _)) or
634634
expr instanceof ConstructorCall
635635
)
636636
} or
637637
// The side effects of an allocation, i.e. `new`, `new[]` or `malloc`
638638
TTranslatedAllocationSideEffects(AllocationExpr expr) { not ignoreExpr(expr) } or
639639
// A precise side effect of an argument to a `Call`
640-
TTranslatedArgumentSideEffect(Call call, Expr expr, int n, SideEffectOpcode opcode) {
640+
TTranslatedArgumentExprSideEffect(Call call, Expr expr, int n, SideEffectOpcode opcode) {
641641
not ignoreExpr(expr) and
642642
not ignoreExpr(call) and
643643
(
@@ -646,6 +646,15 @@ newtype TTranslatedElement =
646646
n = -1 and expr = call.getQualifier().getFullyConverted()
647647
) and
648648
opcode = getASideEffectOpcode(call, n)
649+
} or
650+
// Constructor calls lack a qualifier (`this`) expression, so we need to handle the side effects
651+
// on `*this` without an `Expr`.
652+
TTranslatedStructorQualifierSideEffect(Call call, SideEffectOpcode opcode) {
653+
not ignoreExpr(call) and
654+
// Don't bother with destructor calls for now, since we won't see very many of them in the IR
655+
// until we start injecting implicit destructor calls.
656+
call instanceof ConstructorCall and
657+
opcode = getASideEffectOpcode(call, -1)
649658
}
650659

651660
/**

0 commit comments

Comments
 (0)