From 0a866420563094129f0b63d7b0cddad227b520f6 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 9 Apr 2021 16:14:03 -0400 Subject: [PATCH 1/4] C++: Refactor some side effect generation code This change was necessary for my upcoming changes to introduce side effect instructions for indirections of smart pointers. The code to decide which parameters have which side effects appeared in both the IPA constructor for `TTranslatedSideEffect` and in `TranslatedCall`. These two versions didn't quite agree, especially once the `SideEffectFunction` model provides its own side effects instead of the defaults. The relevant code has now been factored out into `SideEffects.qll`. This queries the model if one exists, and provides default side effects if no model exists. This fixes at least one existing issue, where we were emitting a buffer read side effect for `*this` instead of an indirect read side effect. This accounts for all of the IR diffs in the tests. --- .../raw/internal/SideEffects.qll | 109 ++++++ .../raw/internal/TranslatedCall.qll | 114 ++---- .../raw/internal/TranslatedElement.qll | 44 +-- .../test/library-tests/ir/ir/raw_ir.expected | 337 +++++++++--------- .../ir/ssa/aliased_ssa_ir.expected | 6 +- .../ir/ssa/aliased_ssa_ir_unsound.expected | 6 +- .../ir/ssa/unaliased_ssa_ir.expected | 6 +- .../ir/ssa/unaliased_ssa_ir_unsound.expected | 6 +- 8 files changed, 332 insertions(+), 296 deletions(-) create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/SideEffects.qll diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/SideEffects.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/SideEffects.qll new file mode 100644 index 000000000000..350127a58d17 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/SideEffects.qll @@ -0,0 +1,109 @@ +/** + * Predicates to compute the modeled side effects of calls during IR construction. + * + * These are used in `TranslatedElement.qll` to generate the `TTranslatedSideEffect` instances, and + * also in `TranslatedCall.qll` to inject the actual side effect instructions. + */ + +private import cpp +private import semmle.code.cpp.ir.implementation.Opcode +private import semmle.code.cpp.models.interfaces.SideEffect + +/** + * Holds if the specified call has a side effect that does not come from a `SideEffectFunction` + * model. + */ +private predicate hasDefaultSideEffect(Call call, ParameterIndex i, boolean buffer, boolean isWrite) { + not call.getTarget() instanceof SideEffectFunction and + ( + exists(MemberFunction mfunc | + // A non-static member function, including a constructor or destructor, may write to `*this`, + // and may also read from `*this` if it is not a constructor. + i = -1 and + mfunc = call.getTarget() and + not mfunc.isStatic() and + buffer = false and + ( + isWrite = false and not mfunc instanceof Constructor + or + isWrite = true and not mfunc instanceof ConstMemberFunction + ) + ) + or + exists(Expr expr | + // A pointer-like argument is assumed to read from the pointed-to buffer, and may write to the + // buffer as well unless the pointer points to a `const` value. + i >= 0 and + buffer = true and + expr = call.getArgument(i).getFullyConverted() and + exists(Type t | t = expr.getUnspecifiedType() | + t instanceof ArrayType or + t instanceof PointerType or + t instanceof ReferenceType + ) and + ( + isWrite = true and + not call.getTarget().getParameter(i).getType().isDeeplyConstBelow() + or + isWrite = false + ) + ) + ) +} + +/** + * Returns a side effect opcode for parameter index `i` of the specified call. + * + * This predicate will return at most two results: one read side effect, and one write side effect. + */ +Opcode getASideEffectOpcode(Call call, ParameterIndex i) { + exists(boolean buffer | + ( + call.getTarget().(SideEffectFunction).hasSpecificReadSideEffect(i, buffer) + or + not call.getTarget() instanceof SideEffectFunction and + hasDefaultSideEffect(call, i, buffer, false) + ) and + if exists(call.getTarget().(SideEffectFunction).getParameterSizeIndex(i)) + then ( + buffer = true and + result instanceof Opcode::SizedBufferReadSideEffect + ) else ( + buffer = false and result instanceof Opcode::IndirectReadSideEffect + or + buffer = true and result instanceof Opcode::BufferReadSideEffect + ) + ) + or + exists(boolean buffer, boolean mustWrite | + ( + call.getTarget().(SideEffectFunction).hasSpecificWriteSideEffect(i, buffer, mustWrite) + or + not call.getTarget() instanceof SideEffectFunction and + hasDefaultSideEffect(call, i, buffer, true) and + mustWrite = false + ) and + if exists(call.getTarget().(SideEffectFunction).getParameterSizeIndex(i)) + then ( + buffer = true and + mustWrite = false and + result instanceof Opcode::SizedBufferMayWriteSideEffect + or + buffer = true and + mustWrite = true and + result instanceof Opcode::SizedBufferMustWriteSideEffect + ) else ( + buffer = false and + mustWrite = false and + result instanceof Opcode::IndirectMayWriteSideEffect + or + buffer = false and + mustWrite = true and + result instanceof Opcode::IndirectMustWriteSideEffect + or + buffer = true and mustWrite = false and result instanceof Opcode::BufferMayWriteSideEffect + or + buffer = true and mustWrite = true and result instanceof Opcode::BufferMustWriteSideEffect + ) + ) +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index 7ad1dd2c01e5..0b52937f1cb7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -4,6 +4,7 @@ private import semmle.code.cpp.ir.implementation.internal.OperandTag private import semmle.code.cpp.ir.internal.CppType private import semmle.code.cpp.models.interfaces.SideEffect private import InstructionTag +private import SideEffects private import TranslatedElement private import TranslatedExpr private import TranslatedFunction @@ -424,12 +425,15 @@ class TranslatedCallSideEffects extends TranslatedSideEffects, TTranslatedCallSi } class TranslatedStructorCallSideEffects extends TranslatedCallSideEffects { - TranslatedStructorCallSideEffects() { getParent().(TranslatedStructorCall).hasQualifier() } + TranslatedStructorCallSideEffects() { + getParent().(TranslatedStructorCall).hasQualifier() and + getASideEffectOpcode(expr, -1) instanceof WriteSideEffectOpcode + } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType t) { - opcode instanceof Opcode::IndirectMayWriteSideEffect and tag instanceof OnlyInstructionTag and - t = getTypeForPRValue(expr.getTarget().getDeclaringType()) + t = getTypeForPRValue(expr.getTarget().getDeclaringType()) and + opcode = getASideEffectOpcode(expr, -1).(WriteSideEffectOpcode) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -460,9 +464,11 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff Call call; Expr arg; int index; - boolean write; + SideEffectOpcode sideEffectOpcode; - TranslatedSideEffect() { this = TTranslatedArgumentSideEffect(call, arg, index, write) } + TranslatedSideEffect() { + this = TTranslatedArgumentSideEffect(call, arg, index, sideEffectOpcode) + } override Locatable getAST() { result = arg } @@ -472,13 +478,13 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff int getArgumentIndex() { result = index } - predicate isWrite() { write = true } + predicate isWrite() { sideEffectOpcode instanceof WriteSideEffectOpcode } override string toString() { - write = true and + isWrite() and result = "(write side effect for " + arg.toString() + ")" or - write = false and + not isWrite() and result = "(read side effect for " + arg.toString() + ")" } @@ -489,29 +495,31 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) { - isWrite() and - hasSpecificWriteSideEffect(opcode) and - tag = OnlyInstructionTag() and ( - opcode instanceof BufferAccessOpcode and - type = getUnknownType() - or - not opcode instanceof BufferAccessOpcode and - exists(Type baseType | baseType = arg.getUnspecifiedType().(DerivedType).getBaseType() | - if baseType instanceof VoidType - then type = getUnknownType() - else type = getTypeForPRValueOrUnknown(baseType) + tag = OnlyInstructionTag() and + opcode = sideEffectOpcode + ) and + ( + isWrite() and + ( + opcode instanceof BufferAccessOpcode and + type = getUnknownType() + or + not opcode instanceof BufferAccessOpcode and + exists(Type baseType | baseType = arg.getUnspecifiedType().(DerivedType).getBaseType() | + if baseType instanceof VoidType + then type = getUnknownType() + else type = getTypeForPRValueOrUnknown(baseType) + ) + or + index = -1 and + not arg.getUnspecifiedType() instanceof DerivedType and + type = getTypeForPRValueOrUnknown(arg.getUnspecifiedType()) ) or - index = -1 and - not arg.getUnspecifiedType() instanceof DerivedType and - type = getTypeForPRValueOrUnknown(arg.getUnspecifiedType()) + not isWrite() and + type = getVoidType() ) - or - not isWrite() and - hasSpecificReadSideEffect(opcode) and - tag = OnlyInstructionTag() and - type = getVoidType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -535,7 +543,7 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff override CppType getInstructionMemoryOperandType(InstructionTag tag, TypedOperandTag operandTag) { not isWrite() and - if hasSpecificReadSideEffect(any(BufferAccessOpcode op)) + if sideEffectOpcode instanceof BufferAccessOpcode then result = getUnknownType() and tag instanceof OnlyInstructionTag and @@ -557,56 +565,6 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff ) } - predicate hasSpecificWriteSideEffect(Opcode op) { - exists(boolean buffer, boolean mustWrite | - if exists(call.getTarget().(SideEffectFunction).getParameterSizeIndex(index)) - then - call.getTarget().(SideEffectFunction).hasSpecificWriteSideEffect(index, true, mustWrite) and - buffer = true and - ( - mustWrite = false and op instanceof Opcode::SizedBufferMayWriteSideEffect - or - mustWrite = true and op instanceof Opcode::SizedBufferMustWriteSideEffect - ) - else ( - call.getTarget().(SideEffectFunction).hasSpecificWriteSideEffect(index, buffer, mustWrite) and - ( - buffer = true and mustWrite = false and op instanceof Opcode::BufferMayWriteSideEffect - or - buffer = false and mustWrite = false and op instanceof Opcode::IndirectMayWriteSideEffect - or - buffer = true and mustWrite = true and op instanceof Opcode::BufferMustWriteSideEffect - or - buffer = false and mustWrite = true and op instanceof Opcode::IndirectMustWriteSideEffect - ) - ) - ) - or - not call.getTarget() instanceof SideEffectFunction and - getArgumentIndex() != -1 and - op instanceof Opcode::BufferMayWriteSideEffect - or - not call.getTarget() instanceof SideEffectFunction and - getArgumentIndex() = -1 and - op instanceof Opcode::IndirectMayWriteSideEffect - } - - predicate hasSpecificReadSideEffect(Opcode op) { - exists(boolean buffer | - call.getTarget().(SideEffectFunction).hasSpecificReadSideEffect(index, buffer) and - if exists(call.getTarget().(SideEffectFunction).getParameterSizeIndex(index)) - then buffer = true and op instanceof Opcode::SizedBufferReadSideEffect - else ( - buffer = true and op instanceof Opcode::BufferReadSideEffect - or - buffer = false and op instanceof Opcode::IndirectReadSideEffect - ) - ) - or - not call.getTarget() instanceof SideEffectFunction and - op instanceof Opcode::BufferReadSideEffect - } - override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) { tag = OnlyInstructionTag() and result = getTranslatedCallInstruction(call) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index 1de9936ae1fb..eca659914b02 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -12,6 +12,7 @@ private import TranslatedStmt private import TranslatedExpr private import IRConstruction private import semmle.code.cpp.models.interfaces.SideEffect +private import SideEffects /** * Gets the "real" parent of `expr`. This predicate treats conversions as if @@ -635,46 +636,15 @@ newtype TTranslatedElement = // The side effects of an allocation, i.e. `new`, `new[]` or `malloc` TTranslatedAllocationSideEffects(AllocationExpr expr) { not ignoreExpr(expr) } or // A precise side effect of an argument to a `Call` - TTranslatedArgumentSideEffect(Call call, Expr expr, int n, boolean isWrite) { - ( - expr = call.getArgument(n).getFullyConverted() - or - expr = call.getQualifier().getFullyConverted() and - n = -1 and - // Exclude calls to static member functions. They don't modify the qualifier - not exists(MemberFunction func | func = call.getTarget() and func.isStatic()) - ) and + TTranslatedArgumentSideEffect(Call call, Expr expr, int n, SideEffectOpcode opcode) { + not ignoreExpr(expr) and + not ignoreExpr(call) and ( - call.getTarget().(SideEffectFunction).hasSpecificReadSideEffect(n, _) and - isWrite = false - or - call.getTarget().(SideEffectFunction).hasSpecificWriteSideEffect(n, _, _) and - isWrite = true - or - not call.getTarget() instanceof SideEffectFunction and - exists(Type t | t = expr.getUnspecifiedType() | - t instanceof ArrayType or - t instanceof PointerType or - t instanceof ReferenceType - ) and - ( - isWrite = true and - not call.getTarget().getParameter(n).getType().isDeeplyConstBelow() - or - isWrite = false - ) + n >= 0 and expr = call.getArgument(n).getFullyConverted() or - not call.getTarget() instanceof SideEffectFunction and - n = -1 and - ( - isWrite = true and - not call.getTarget() instanceof ConstMemberFunction - or - isWrite = false - ) + n = -1 and expr = call.getQualifier().getFullyConverted() ) and - not ignoreExpr(expr) and - not ignoreExpr(call) + opcode = getASideEffectOpcode(call, n) } /** diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index a7dac56cc96a..e008e2de6596 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -42,7 +42,7 @@ bad_asts.cpp: # 16| r16_3(int) = Constant[1] : # 16| r16_4(int) = Call[MemberFunction] : func:r16_2, this:r16_1, 0:r16_3 # 16| mu16_5(unknown) = ^CallSideEffect : ~m? -# 16| v16_6(void) = ^BufferReadSideEffect[-1] : &:r16_1, ~m? +# 16| v16_6(void) = ^IndirectReadSideEffect[-1] : &:r16_1, ~m? # 16| mu16_7(S) = ^IndirectMayWriteSideEffect[-1] : &:r16_1 # 17| v17_1(void) = NoOp : # 14| v14_4(void) = ReturnVoid : @@ -3385,47 +3385,46 @@ ir.cpp: # 622| void CallMethods(String&, String*, String) # 622| Block 0 -# 622| v622_1(void) = EnterFunction : -# 622| mu622_2(unknown) = AliasedDefinition : -# 622| mu622_3(unknown) = InitializeNonLocal : -# 622| r622_4(glval) = VariableAddress[r] : -# 622| mu622_5(String &) = InitializeParameter[r] : &:r622_4 -# 622| r622_6(String &) = Load[r] : &:r622_4, ~m? -# 622| mu622_7(unknown) = InitializeIndirection[r] : &:r622_6 -# 622| r622_8(glval) = VariableAddress[p] : -# 622| mu622_9(String *) = InitializeParameter[p] : &:r622_8 -# 622| r622_10(String *) = Load[p] : &:r622_8, ~m? -# 622| mu622_11(unknown) = InitializeIndirection[p] : &:r622_10 -# 622| r622_12(glval) = VariableAddress[s] : -# 622| mu622_13(String) = InitializeParameter[s] : &:r622_12 -# 623| r623_1(glval) = VariableAddress[r] : -# 623| r623_2(String &) = Load[r] : &:r623_1, ~m? -# 623| r623_3(glval) = CopyValue : r623_2 -# 623| r623_4(glval) = Convert : r623_3 -# 623| r623_5(glval) = FunctionAddress[c_str] : -# 623| r623_6(char *) = Call[c_str] : func:r623_5, this:r623_4 -# 623| mu623_7(unknown) = ^CallSideEffect : ~m? -# 623| v623_8(void) = ^BufferReadSideEffect[-1] : &:r623_4, ~m? -# 624| r624_1(glval) = VariableAddress[p] : -# 624| r624_2(String *) = Load[p] : &:r624_1, ~m? -# 624| r624_3(String *) = Convert : r624_2 -# 624| r624_4(glval) = FunctionAddress[c_str] : -# 624| r624_5(char *) = Call[c_str] : func:r624_4, this:r624_3 -# 624| mu624_6(unknown) = ^CallSideEffect : ~m? -# 624| v624_7(void) = ^BufferReadSideEffect[-1] : &:r624_3, ~m? -# 624| mu624_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r624_3 -# 625| r625_1(glval) = VariableAddress[s] : -# 625| r625_2(glval) = Convert : r625_1 -# 625| r625_3(glval) = FunctionAddress[c_str] : -# 625| r625_4(char *) = Call[c_str] : func:r625_3, this:r625_2 -# 625| mu625_5(unknown) = ^CallSideEffect : ~m? -# 625| v625_6(void) = ^BufferReadSideEffect[-1] : &:r625_2, ~m? -# 626| v626_1(void) = NoOp : -# 622| v622_14(void) = ReturnIndirection[r] : &:r622_6, ~m? -# 622| v622_15(void) = ReturnIndirection[p] : &:r622_10, ~m? -# 622| v622_16(void) = ReturnVoid : -# 622| v622_17(void) = AliasedUse : ~m? -# 622| v622_18(void) = ExitFunction : +# 622| v622_1(void) = EnterFunction : +# 622| mu622_2(unknown) = AliasedDefinition : +# 622| mu622_3(unknown) = InitializeNonLocal : +# 622| r622_4(glval) = VariableAddress[r] : +# 622| mu622_5(String &) = InitializeParameter[r] : &:r622_4 +# 622| r622_6(String &) = Load[r] : &:r622_4, ~m? +# 622| mu622_7(unknown) = InitializeIndirection[r] : &:r622_6 +# 622| r622_8(glval) = VariableAddress[p] : +# 622| mu622_9(String *) = InitializeParameter[p] : &:r622_8 +# 622| r622_10(String *) = Load[p] : &:r622_8, ~m? +# 622| mu622_11(unknown) = InitializeIndirection[p] : &:r622_10 +# 622| r622_12(glval) = VariableAddress[s] : +# 622| mu622_13(String) = InitializeParameter[s] : &:r622_12 +# 623| r623_1(glval) = VariableAddress[r] : +# 623| r623_2(String &) = Load[r] : &:r623_1, ~m? +# 623| r623_3(glval) = CopyValue : r623_2 +# 623| r623_4(glval) = Convert : r623_3 +# 623| r623_5(glval) = FunctionAddress[c_str] : +# 623| r623_6(char *) = Call[c_str] : func:r623_5, this:r623_4 +# 623| mu623_7(unknown) = ^CallSideEffect : ~m? +# 623| v623_8(void) = ^IndirectReadSideEffect[-1] : &:r623_4, ~m? +# 624| r624_1(glval) = VariableAddress[p] : +# 624| r624_2(String *) = Load[p] : &:r624_1, ~m? +# 624| r624_3(String *) = Convert : r624_2 +# 624| r624_4(glval) = FunctionAddress[c_str] : +# 624| r624_5(char *) = Call[c_str] : func:r624_4, this:r624_3 +# 624| mu624_6(unknown) = ^CallSideEffect : ~m? +# 624| v624_7(void) = ^IndirectReadSideEffect[-1] : &:r624_3, ~m? +# 625| r625_1(glval) = VariableAddress[s] : +# 625| r625_2(glval) = Convert : r625_1 +# 625| r625_3(glval) = FunctionAddress[c_str] : +# 625| r625_4(char *) = Call[c_str] : func:r625_3, this:r625_2 +# 625| mu625_5(unknown) = ^CallSideEffect : ~m? +# 625| v625_6(void) = ^IndirectReadSideEffect[-1] : &:r625_2, ~m? +# 626| v626_1(void) = NoOp : +# 622| v622_14(void) = ReturnIndirection[r] : &:r622_6, ~m? +# 622| v622_15(void) = ReturnIndirection[p] : &:r622_10, ~m? +# 622| v622_16(void) = ReturnVoid : +# 622| v622_17(void) = AliasedUse : ~m? +# 622| v622_18(void) = ExitFunction : # 628| void C::~C() # 628| Block 0 @@ -3575,7 +3574,7 @@ ir.cpp: # 653| r653_4(int) = Constant[0] : # 653| r653_5(int) = Call[InstanceMemberFunction] : func:r653_3, this:r653_2, 0:r653_4 # 653| mu653_6(unknown) = ^CallSideEffect : ~m? -# 653| v653_7(void) = ^BufferReadSideEffect[-1] : &:r653_2, ~m? +# 653| v653_7(void) = ^IndirectReadSideEffect[-1] : &:r653_2, ~m? # 653| mu653_8(C) = ^IndirectMayWriteSideEffect[-1] : &:r653_2 # 654| r654_1(glval) = VariableAddress[#this] : # 654| r654_2(C *) = Load[#this] : &:r654_1, ~m? @@ -3584,7 +3583,7 @@ ir.cpp: # 654| r654_5(int) = Constant[1] : # 654| r654_6(int) = Call[InstanceMemberFunction] : func:r654_4, this:r654_3, 0:r654_5 # 654| mu654_7(unknown) = ^CallSideEffect : ~m? -# 654| v654_8(void) = ^BufferReadSideEffect[-1] : &:r654_3, ~m? +# 654| v654_8(void) = ^IndirectReadSideEffect[-1] : &:r654_3, ~m? # 654| mu654_9(C) = ^IndirectMayWriteSideEffect[-1] : &:r654_3 # 655| r655_1(glval) = VariableAddress[#this] : # 655| r655_2(C *) = Load[#this] : &:r655_1, ~m? @@ -3592,7 +3591,7 @@ ir.cpp: # 655| r655_4(int) = Constant[2] : # 655| r655_5(int) = Call[InstanceMemberFunction] : func:r655_3, this:r655_2, 0:r655_4 # 655| mu655_6(unknown) = ^CallSideEffect : ~m? -# 655| v655_7(void) = ^BufferReadSideEffect[-1] : &:r655_2, ~m? +# 655| v655_7(void) = ^IndirectReadSideEffect[-1] : &:r655_2, ~m? # 655| mu655_8(C) = ^IndirectMayWriteSideEffect[-1] : &:r655_2 # 656| v656_1(void) = NoOp : # 652| v652_8(void) = ReturnIndirection[#this] : &:r652_6, ~m? @@ -4006,7 +4005,7 @@ ir.cpp: #-----| r0_6(String &) = CopyValue : r745_15 # 745| r745_16(String &) = Call[operator=] : func:r745_12, this:r745_11, 0:r0_6 # 745| mu745_17(unknown) = ^CallSideEffect : ~m? -# 745| v745_18(void) = ^BufferReadSideEffect[-1] : &:r745_11, ~m? +# 745| v745_18(void) = ^IndirectReadSideEffect[-1] : &:r745_11, ~m? #-----| v0_7(void) = ^BufferReadSideEffect[0] : &:r0_6, ~m? # 745| mu745_19(String) = ^IndirectMayWriteSideEffect[-1] : &:r745_11 #-----| r0_8(glval) = CopyValue : r745_16 @@ -4113,7 +4112,7 @@ ir.cpp: #-----| r0_8(Base &) = CopyValue : r754_14 # 754| r754_15(Base &) = Call[operator=] : func:r754_10, this:r0_5, 0:r0_8 # 754| mu754_16(unknown) = ^CallSideEffect : ~m? -#-----| v0_9(void) = ^BufferReadSideEffect[-1] : &:r0_5, ~m? +#-----| v0_9(void) = ^IndirectReadSideEffect[-1] : &:r0_5, ~m? #-----| v0_10(void) = ^BufferReadSideEffect[0] : &:r0_8, ~m? #-----| mu0_11(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_5 #-----| r0_12(glval) = CopyValue : r754_15 @@ -4129,7 +4128,7 @@ ir.cpp: #-----| r0_14(String &) = CopyValue : r754_24 # 754| r754_25(String &) = Call[operator=] : func:r754_21, this:r754_20, 0:r0_14 # 754| mu754_26(unknown) = ^CallSideEffect : ~m? -# 754| v754_27(void) = ^BufferReadSideEffect[-1] : &:r754_20, ~m? +# 754| v754_27(void) = ^IndirectReadSideEffect[-1] : &:r754_20, ~m? #-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_14, ~m? # 754| mu754_28(String) = ^IndirectMayWriteSideEffect[-1] : &:r754_20 #-----| r0_16(glval) = CopyValue : r754_25 @@ -4220,7 +4219,7 @@ ir.cpp: #-----| r0_8(Middle &) = CopyValue : r763_14 # 763| r763_15(Middle &) = Call[operator=] : func:r763_10, this:r0_5, 0:r0_8 # 763| mu763_16(unknown) = ^CallSideEffect : ~m? -#-----| v0_9(void) = ^BufferReadSideEffect[-1] : &:r0_5, ~m? +#-----| v0_9(void) = ^IndirectReadSideEffect[-1] : &:r0_5, ~m? #-----| v0_10(void) = ^BufferReadSideEffect[0] : &:r0_8, ~m? #-----| mu0_11(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_5 #-----| r0_12(glval) = CopyValue : r763_15 @@ -4236,7 +4235,7 @@ ir.cpp: #-----| r0_14(String &) = CopyValue : r763_24 # 763| r763_25(String &) = Call[operator=] : func:r763_21, this:r763_20, 0:r0_14 # 763| mu763_26(unknown) = ^CallSideEffect : ~m? -# 763| v763_27(void) = ^BufferReadSideEffect[-1] : &:r763_20, ~m? +# 763| v763_27(void) = ^IndirectReadSideEffect[-1] : &:r763_20, ~m? #-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_14, ~m? # 763| mu763_28(String) = ^IndirectMayWriteSideEffect[-1] : &:r763_20 #-----| r0_16(glval) = CopyValue : r763_25 @@ -4505,7 +4504,7 @@ ir.cpp: # 808| r808_5(Base &) = CopyValue : r808_4 # 808| r808_6(Base &) = Call[operator=] : func:r808_2, this:r808_1, 0:r808_5 # 808| mu808_7(unknown) = ^CallSideEffect : ~m? -# 808| v808_8(void) = ^BufferReadSideEffect[-1] : &:r808_1, ~m? +# 808| v808_8(void) = ^IndirectReadSideEffect[-1] : &:r808_1, ~m? # 808| v808_9(void) = ^BufferReadSideEffect[0] : &:r808_5, ~m? # 808| mu808_10(Base) = ^IndirectMayWriteSideEffect[-1] : &:r808_1 # 808| r808_11(glval) = CopyValue : r808_6 @@ -4525,7 +4524,7 @@ ir.cpp: # 809| r809_14(Base &) = CopyValue : r809_13 # 809| r809_15(Base &) = Call[operator=] : func:r809_2, this:r809_1, 0:r809_14 # 809| mu809_16(unknown) = ^CallSideEffect : ~m? -# 809| v809_17(void) = ^BufferReadSideEffect[-1] : &:r809_1, ~m? +# 809| v809_17(void) = ^IndirectReadSideEffect[-1] : &:r809_1, ~m? # 809| v809_18(void) = ^BufferReadSideEffect[0] : &:r809_14, ~m? # 809| mu809_19(Base) = ^IndirectMayWriteSideEffect[-1] : &:r809_1 # 809| r809_20(glval) = CopyValue : r809_15 @@ -4545,7 +4544,7 @@ ir.cpp: # 810| r810_14(Base &) = CopyValue : r810_13 # 810| r810_15(Base &) = Call[operator=] : func:r810_2, this:r810_1, 0:r810_14 # 810| mu810_16(unknown) = ^CallSideEffect : ~m? -# 810| v810_17(void) = ^BufferReadSideEffect[-1] : &:r810_1, ~m? +# 810| v810_17(void) = ^IndirectReadSideEffect[-1] : &:r810_1, ~m? # 810| v810_18(void) = ^BufferReadSideEffect[0] : &:r810_14, ~m? # 810| mu810_19(Base) = ^IndirectMayWriteSideEffect[-1] : &:r810_1 # 810| r810_20(glval) = CopyValue : r810_15 @@ -4577,7 +4576,7 @@ ir.cpp: # 816| r816_6(Middle &) = CopyValue : r816_5 # 816| r816_7(Middle &) = Call[operator=] : func:r816_2, this:r816_1, 0:r816_6 # 816| mu816_8(unknown) = ^CallSideEffect : ~m? -# 816| v816_9(void) = ^BufferReadSideEffect[-1] : &:r816_1, ~m? +# 816| v816_9(void) = ^IndirectReadSideEffect[-1] : &:r816_1, ~m? # 816| v816_10(void) = ^BufferReadSideEffect[0] : &:r816_6, ~m? # 816| mu816_11(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r816_1 # 816| r816_12(glval) = CopyValue : r816_7 @@ -4589,7 +4588,7 @@ ir.cpp: # 817| r817_6(Middle &) = CopyValue : r817_5 # 817| r817_7(Middle &) = Call[operator=] : func:r817_2, this:r817_1, 0:r817_6 # 817| mu817_8(unknown) = ^CallSideEffect : ~m? -# 817| v817_9(void) = ^BufferReadSideEffect[-1] : &:r817_1, ~m? +# 817| v817_9(void) = ^IndirectReadSideEffect[-1] : &:r817_1, ~m? # 817| v817_10(void) = ^BufferReadSideEffect[0] : &:r817_6, ~m? # 817| mu817_11(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r817_1 # 817| r817_12(glval) = CopyValue : r817_7 @@ -4616,7 +4615,7 @@ ir.cpp: # 822| r822_6(Base &) = CopyValue : r822_5 # 822| r822_7(Base &) = Call[operator=] : func:r822_2, this:r822_1, 0:r822_6 # 822| mu822_8(unknown) = ^CallSideEffect : ~m? -# 822| v822_9(void) = ^BufferReadSideEffect[-1] : &:r822_1, ~m? +# 822| v822_9(void) = ^IndirectReadSideEffect[-1] : &:r822_1, ~m? # 822| v822_10(void) = ^BufferReadSideEffect[0] : &:r822_6, ~m? # 822| mu822_11(Base) = ^IndirectMayWriteSideEffect[-1] : &:r822_1 # 822| r822_12(glval) = CopyValue : r822_7 @@ -4637,7 +4636,7 @@ ir.cpp: # 823| r823_15(Base &) = CopyValue : r823_14 # 823| r823_16(Base &) = Call[operator=] : func:r823_2, this:r823_1, 0:r823_15 # 823| mu823_17(unknown) = ^CallSideEffect : ~m? -# 823| v823_18(void) = ^BufferReadSideEffect[-1] : &:r823_1, ~m? +# 823| v823_18(void) = ^IndirectReadSideEffect[-1] : &:r823_1, ~m? # 823| v823_19(void) = ^BufferReadSideEffect[0] : &:r823_15, ~m? # 823| mu823_20(Base) = ^IndirectMayWriteSideEffect[-1] : &:r823_1 # 823| r823_21(glval) = CopyValue : r823_16 @@ -4658,7 +4657,7 @@ ir.cpp: # 824| r824_15(Base &) = CopyValue : r824_14 # 824| r824_16(Base &) = Call[operator=] : func:r824_2, this:r824_1, 0:r824_15 # 824| mu824_17(unknown) = ^CallSideEffect : ~m? -# 824| v824_18(void) = ^BufferReadSideEffect[-1] : &:r824_1, ~m? +# 824| v824_18(void) = ^IndirectReadSideEffect[-1] : &:r824_1, ~m? # 824| v824_19(void) = ^BufferReadSideEffect[0] : &:r824_15, ~m? # 824| mu824_20(Base) = ^IndirectMayWriteSideEffect[-1] : &:r824_1 # 824| r824_21(glval) = CopyValue : r824_16 @@ -4694,7 +4693,7 @@ ir.cpp: # 830| r830_7(Derived &) = CopyValue : r830_6 # 830| r830_8(Derived &) = Call[operator=] : func:r830_2, this:r830_1, 0:r830_7 # 830| mu830_9(unknown) = ^CallSideEffect : ~m? -# 830| v830_10(void) = ^BufferReadSideEffect[-1] : &:r830_1, ~m? +# 830| v830_10(void) = ^IndirectReadSideEffect[-1] : &:r830_1, ~m? # 830| v830_11(void) = ^BufferReadSideEffect[0] : &:r830_7, ~m? # 830| mu830_12(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r830_1 # 830| r830_13(glval) = CopyValue : r830_8 @@ -4707,7 +4706,7 @@ ir.cpp: # 831| r831_7(Derived &) = CopyValue : r831_6 # 831| r831_8(Derived &) = Call[operator=] : func:r831_2, this:r831_1, 0:r831_7 # 831| mu831_9(unknown) = ^CallSideEffect : ~m? -# 831| v831_10(void) = ^BufferReadSideEffect[-1] : &:r831_1, ~m? +# 831| v831_10(void) = ^IndirectReadSideEffect[-1] : &:r831_1, ~m? # 831| v831_11(void) = ^BufferReadSideEffect[0] : &:r831_7, ~m? # 831| mu831_12(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r831_1 # 831| r831_13(glval) = CopyValue : r831_8 @@ -5688,7 +5687,7 @@ ir.cpp: # 1044| r1044_4(float) = Constant[1.0] : # 1044| r1044_5(char) = Call[operator()] : func:r1044_3, this:r1044_2, 0:r1044_4 # 1044| mu1044_6(unknown) = ^CallSideEffect : ~m? -# 1044| v1044_7(void) = ^BufferReadSideEffect[-1] : &:r1044_2, ~m? +# 1044| v1044_7(void) = ^IndirectReadSideEffect[-1] : &:r1044_2, ~m? # 1045| r1045_1(glval) = VariableAddress[lambda_val] : # 1045| r1045_2(glval) = VariableAddress[#temp1045:20] : # 1045| mu1045_3(decltype([...](...){...})) = Uninitialized[#temp1045:20] : &:r1045_2 @@ -5709,7 +5708,7 @@ ir.cpp: # 1046| r1046_4(float) = Constant[2.0] : # 1046| r1046_5(char) = Call[operator()] : func:r1046_3, this:r1046_2, 0:r1046_4 # 1046| mu1046_6(unknown) = ^CallSideEffect : ~m? -# 1046| v1046_7(void) = ^BufferReadSideEffect[-1] : &:r1046_2, ~m? +# 1046| v1046_7(void) = ^IndirectReadSideEffect[-1] : &:r1046_2, ~m? # 1047| r1047_1(glval) = VariableAddress[lambda_ref_explicit] : # 1047| r1047_2(glval) = VariableAddress[#temp1047:29] : # 1047| mu1047_3(decltype([...](...){...})) = Uninitialized[#temp1047:29] : &:r1047_2 @@ -5727,7 +5726,7 @@ ir.cpp: # 1048| r1048_4(float) = Constant[3.0] : # 1048| r1048_5(char) = Call[operator()] : func:r1048_3, this:r1048_2, 0:r1048_4 # 1048| mu1048_6(unknown) = ^CallSideEffect : ~m? -# 1048| v1048_7(void) = ^BufferReadSideEffect[-1] : &:r1048_2, ~m? +# 1048| v1048_7(void) = ^IndirectReadSideEffect[-1] : &:r1048_2, ~m? # 1049| r1049_1(glval) = VariableAddress[lambda_val_explicit] : # 1049| r1049_2(glval) = VariableAddress[#temp1049:29] : # 1049| mu1049_3(decltype([...](...){...})) = Uninitialized[#temp1049:29] : &:r1049_2 @@ -5744,7 +5743,7 @@ ir.cpp: # 1050| r1050_4(float) = Constant[4.0] : # 1050| r1050_5(char) = Call[operator()] : func:r1050_3, this:r1050_2, 0:r1050_4 # 1050| mu1050_6(unknown) = ^CallSideEffect : ~m? -# 1050| v1050_7(void) = ^BufferReadSideEffect[-1] : &:r1050_2, ~m? +# 1050| v1050_7(void) = ^IndirectReadSideEffect[-1] : &:r1050_2, ~m? # 1051| r1051_1(glval) = VariableAddress[lambda_mixed_explicit] : # 1051| r1051_2(glval) = VariableAddress[#temp1051:31] : # 1051| mu1051_3(decltype([...](...){...})) = Uninitialized[#temp1051:31] : &:r1051_2 @@ -5766,7 +5765,7 @@ ir.cpp: # 1052| r1052_4(float) = Constant[5.0] : # 1052| r1052_5(char) = Call[operator()] : func:r1052_3, this:r1052_2, 0:r1052_4 # 1052| mu1052_6(unknown) = ^CallSideEffect : ~m? -# 1052| v1052_7(void) = ^BufferReadSideEffect[-1] : &:r1052_2, ~m? +# 1052| v1052_7(void) = ^IndirectReadSideEffect[-1] : &:r1052_2, ~m? # 1053| r1053_1(glval) = VariableAddress[r] : # 1053| r1053_2(glval) = VariableAddress[x] : # 1053| r1053_3(int) = Load[x] : &:r1053_2, ~m? @@ -5804,7 +5803,7 @@ ir.cpp: # 1055| r1055_4(float) = Constant[6.0] : # 1055| r1055_5(char) = Call[operator()] : func:r1055_3, this:r1055_2, 0:r1055_4 # 1055| mu1055_6(unknown) = ^CallSideEffect : ~m? -# 1055| v1055_7(void) = ^BufferReadSideEffect[-1] : &:r1055_2, ~m? +# 1055| v1055_7(void) = ^IndirectReadSideEffect[-1] : &:r1055_2, ~m? # 1056| v1056_1(void) = NoOp : # 1040| v1040_10(void) = ReturnIndirection[s] : &:r1040_8, ~m? # 1040| v1040_11(void) = ReturnVoid : @@ -5869,7 +5868,7 @@ ir.cpp: # 1043| r1043_16(glval) = FunctionAddress[c_str] : # 1043| r1043_17(char *) = Call[c_str] : func:r1043_16, this:r1043_15 # 1043| mu1043_18(unknown) = ^CallSideEffect : ~m? -# 1043| v1043_19(void) = ^BufferReadSideEffect[-1] : &:r1043_15, ~m? +# 1043| v1043_19(void) = ^IndirectReadSideEffect[-1] : &:r1043_15, ~m? # 1043| r1043_20(glval) = VariableAddress[#this] : # 1043| r1043_21(lambda [] type at line 1043, col. 21 *) = Load[#this] : &:r1043_20, ~m? # 1043| r1043_22(glval) = FieldAddress[x] : r1043_21 @@ -5921,7 +5920,7 @@ ir.cpp: # 1045| r1045_14(glval) = FunctionAddress[c_str] : # 1045| r1045_15(char *) = Call[c_str] : func:r1045_14, this:r1045_13 # 1045| mu1045_16(unknown) = ^CallSideEffect : ~m? -# 1045| v1045_17(void) = ^BufferReadSideEffect[-1] : &:r1045_13, ~m? +# 1045| v1045_17(void) = ^IndirectReadSideEffect[-1] : &:r1045_13, ~m? # 1045| r1045_18(glval) = VariableAddress[#this] : # 1045| r1045_19(lambda [] type at line 1045, col. 21 *) = Load[#this] : &:r1045_18, ~m? # 1045| r1045_20(glval) = FieldAddress[x] : r1045_19 @@ -5955,7 +5954,7 @@ ir.cpp: # 1047| r1047_16(glval) = FunctionAddress[c_str] : # 1047| r1047_17(char *) = Call[c_str] : func:r1047_16, this:r1047_15 # 1047| mu1047_18(unknown) = ^CallSideEffect : ~m? -# 1047| v1047_19(void) = ^BufferReadSideEffect[-1] : &:r1047_15, ~m? +# 1047| v1047_19(void) = ^IndirectReadSideEffect[-1] : &:r1047_15, ~m? # 1047| r1047_20(int) = Constant[0] : # 1047| r1047_21(glval) = PointerAdd[1] : r1047_17, r1047_20 # 1047| r1047_22(char) = Load[?] : &:r1047_21, ~m? @@ -6003,7 +6002,7 @@ ir.cpp: # 1049| r1049_14(glval) = FunctionAddress[c_str] : # 1049| r1049_15(char *) = Call[c_str] : func:r1049_14, this:r1049_13 # 1049| mu1049_16(unknown) = ^CallSideEffect : ~m? -# 1049| v1049_17(void) = ^BufferReadSideEffect[-1] : &:r1049_13, ~m? +# 1049| v1049_17(void) = ^IndirectReadSideEffect[-1] : &:r1049_13, ~m? # 1049| r1049_18(int) = Constant[0] : # 1049| r1049_19(glval) = PointerAdd[1] : r1049_15, r1049_18 # 1049| r1049_20(char) = Load[?] : &:r1049_19, ~m? @@ -6034,7 +6033,7 @@ ir.cpp: # 1051| r1051_16(glval) = FunctionAddress[c_str] : # 1051| r1051_17(char *) = Call[c_str] : func:r1051_16, this:r1051_15 # 1051| mu1051_18(unknown) = ^CallSideEffect : ~m? -# 1051| v1051_19(void) = ^BufferReadSideEffect[-1] : &:r1051_15, ~m? +# 1051| v1051_19(void) = ^IndirectReadSideEffect[-1] : &:r1051_15, ~m? # 1051| r1051_20(glval) = VariableAddress[#this] : # 1051| r1051_21(lambda [] type at line 1051, col. 32 *) = Load[#this] : &:r1051_20, ~m? # 1051| r1051_22(glval) = FieldAddress[x] : r1051_21 @@ -6068,7 +6067,7 @@ ir.cpp: # 1054| r1054_16(glval) = FunctionAddress[c_str] : # 1054| r1054_17(char *) = Call[c_str] : func:r1054_16, this:r1054_15 # 1054| mu1054_18(unknown) = ^CallSideEffect : ~m? -# 1054| v1054_19(void) = ^BufferReadSideEffect[-1] : &:r1054_15, ~m? +# 1054| v1054_19(void) = ^IndirectReadSideEffect[-1] : &:r1054_15, ~m? # 1054| r1054_20(glval) = VariableAddress[#this] : # 1054| r1054_21(lambda [] type at line 1054, col. 23 *) = Load[#this] : &:r1054_20, ~m? # 1054| r1054_22(glval) = FieldAddress[x] : r1054_21 @@ -6095,37 +6094,37 @@ ir.cpp: # 1077| void RangeBasedFor(vector const&) # 1077| Block 0 -# 1077| v1077_1(void) = EnterFunction : -# 1077| mu1077_2(unknown) = AliasedDefinition : -# 1077| mu1077_3(unknown) = InitializeNonLocal : -# 1077| r1077_4(glval &>) = VariableAddress[v] : -# 1077| mu1077_5(vector &) = InitializeParameter[v] : &:r1077_4 -# 1077| r1077_6(vector &) = Load[v] : &:r1077_4, ~m? -# 1077| mu1077_7(unknown) = InitializeIndirection[v] : &:r1077_6 -# 1078| r1078_1(glval &>) = VariableAddress[(__range)] : -# 1078| r1078_2(glval &>) = VariableAddress[v] : -# 1078| r1078_3(vector &) = Load[v] : &:r1078_2, ~m? -# 1078| r1078_4(glval>) = CopyValue : r1078_3 -# 1078| r1078_5(vector &) = CopyValue : r1078_4 -# 1078| mu1078_6(vector &) = Store[(__range)] : &:r1078_1, r1078_5 -# 1078| r1078_7(glval) = VariableAddress[(__begin)] : -# 1078| r1078_8(glval &>) = VariableAddress[(__range)] : -# 1078| r1078_9(vector &) = Load[(__range)] : &:r1078_8, ~m? -#-----| r0_1(glval>) = CopyValue : r1078_9 -# 1078| r1078_10(glval) = FunctionAddress[begin] : -# 1078| r1078_11(iterator) = Call[begin] : func:r1078_10, this:r0_1 -# 1078| mu1078_12(unknown) = ^CallSideEffect : ~m? -#-----| v0_2(void) = ^BufferReadSideEffect[-1] : &:r0_1, ~m? -# 1078| mu1078_13(iterator) = Store[(__begin)] : &:r1078_7, r1078_11 -# 1078| r1078_14(glval) = VariableAddress[(__end)] : -# 1078| r1078_15(glval &>) = VariableAddress[(__range)] : -# 1078| r1078_16(vector &) = Load[(__range)] : &:r1078_15, ~m? -#-----| r0_3(glval>) = CopyValue : r1078_16 -# 1078| r1078_17(glval) = FunctionAddress[end] : -# 1078| r1078_18(iterator) = Call[end] : func:r1078_17, this:r0_3 -# 1078| mu1078_19(unknown) = ^CallSideEffect : ~m? -#-----| v0_4(void) = ^BufferReadSideEffect[-1] : &:r0_3, ~m? -# 1078| mu1078_20(iterator) = Store[(__end)] : &:r1078_14, r1078_18 +# 1077| v1077_1(void) = EnterFunction : +# 1077| mu1077_2(unknown) = AliasedDefinition : +# 1077| mu1077_3(unknown) = InitializeNonLocal : +# 1077| r1077_4(glval &>) = VariableAddress[v] : +# 1077| mu1077_5(vector &) = InitializeParameter[v] : &:r1077_4 +# 1077| r1077_6(vector &) = Load[v] : &:r1077_4, ~m? +# 1077| mu1077_7(unknown) = InitializeIndirection[v] : &:r1077_6 +# 1078| r1078_1(glval &>) = VariableAddress[(__range)] : +# 1078| r1078_2(glval &>) = VariableAddress[v] : +# 1078| r1078_3(vector &) = Load[v] : &:r1078_2, ~m? +# 1078| r1078_4(glval>) = CopyValue : r1078_3 +# 1078| r1078_5(vector &) = CopyValue : r1078_4 +# 1078| mu1078_6(vector &) = Store[(__range)] : &:r1078_1, r1078_5 +# 1078| r1078_7(glval) = VariableAddress[(__begin)] : +# 1078| r1078_8(glval &>) = VariableAddress[(__range)] : +# 1078| r1078_9(vector &) = Load[(__range)] : &:r1078_8, ~m? +#-----| r0_1(glval>) = CopyValue : r1078_9 +# 1078| r1078_10(glval) = FunctionAddress[begin] : +# 1078| r1078_11(iterator) = Call[begin] : func:r1078_10, this:r0_1 +# 1078| mu1078_12(unknown) = ^CallSideEffect : ~m? +#-----| v0_2(void) = ^IndirectReadSideEffect[-1] : &:r0_1, ~m? +# 1078| mu1078_13(iterator) = Store[(__begin)] : &:r1078_7, r1078_11 +# 1078| r1078_14(glval) = VariableAddress[(__end)] : +# 1078| r1078_15(glval &>) = VariableAddress[(__range)] : +# 1078| r1078_16(vector &) = Load[(__range)] : &:r1078_15, ~m? +#-----| r0_3(glval>) = CopyValue : r1078_16 +# 1078| r1078_17(glval) = FunctionAddress[end] : +# 1078| r1078_18(iterator) = Call[end] : func:r1078_17, this:r0_3 +# 1078| mu1078_19(unknown) = ^CallSideEffect : ~m? +#-----| v0_4(void) = ^IndirectReadSideEffect[-1] : &:r0_3, ~m? +# 1078| mu1078_20(iterator) = Store[(__end)] : &:r1078_14, r1078_18 #-----| Goto -> Block 1 # 1078| Block 1 @@ -6136,26 +6135,26 @@ ir.cpp: # 1078| r1078_24(iterator) = Load[(__end)] : &:r1078_23, ~m? # 1078| r1078_25(bool) = Call[operator!=] : func:r1078_22, this:r0_5, 0:r1078_24 # 1078| mu1078_26(unknown) = ^CallSideEffect : ~m? -#-----| v0_6(void) = ^BufferReadSideEffect[-1] : &:r0_5, ~m? +#-----| v0_6(void) = ^IndirectReadSideEffect[-1] : &:r0_5, ~m? # 1078| v1078_27(void) = ConditionalBranch : r1078_25 #-----| False -> Block 5 #-----| True -> Block 2 # 1078| Block 2 -# 1078| r1078_28(glval) = VariableAddress[e] : -# 1078| r1078_29(glval) = VariableAddress[(__begin)] : -#-----| r0_7(glval) = Convert : r1078_29 -# 1078| r1078_30(glval) = FunctionAddress[operator*] : -# 1078| r1078_31(int &) = Call[operator*] : func:r1078_30, this:r0_7 -# 1078| mu1078_32(unknown) = ^CallSideEffect : ~m? -#-----| v0_8(void) = ^BufferReadSideEffect[-1] : &:r0_7, ~m? -# 1078| r1078_33(int) = Load[?] : &:r1078_31, ~m? -# 1078| mu1078_34(int) = Store[e] : &:r1078_28, r1078_33 -# 1079| r1079_1(glval) = VariableAddress[e] : -# 1079| r1079_2(int) = Load[e] : &:r1079_1, ~m? -# 1079| r1079_3(int) = Constant[0] : -# 1079| r1079_4(bool) = CompareGT : r1079_2, r1079_3 -# 1079| v1079_5(void) = ConditionalBranch : r1079_4 +# 1078| r1078_28(glval) = VariableAddress[e] : +# 1078| r1078_29(glval) = VariableAddress[(__begin)] : +#-----| r0_7(glval) = Convert : r1078_29 +# 1078| r1078_30(glval) = FunctionAddress[operator*] : +# 1078| r1078_31(int &) = Call[operator*] : func:r1078_30, this:r0_7 +# 1078| mu1078_32(unknown) = ^CallSideEffect : ~m? +#-----| v0_8(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~m? +# 1078| r1078_33(int) = Load[?] : &:r1078_31, ~m? +# 1078| mu1078_34(int) = Store[e] : &:r1078_28, r1078_33 +# 1079| r1079_1(glval) = VariableAddress[e] : +# 1079| r1079_2(int) = Load[e] : &:r1079_1, ~m? +# 1079| r1079_3(int) = Constant[0] : +# 1079| r1079_4(bool) = CompareGT : r1079_2, r1079_3 +# 1079| v1079_5(void) = ConditionalBranch : r1079_4 #-----| False -> Block 4 #-----| True -> Block 3 @@ -6169,36 +6168,36 @@ ir.cpp: # 1078| r1078_37(glval) = FunctionAddress[operator++] : # 1078| r1078_38(iterator &) = Call[operator++] : func:r1078_37, this:r1078_36 # 1078| mu1078_39(unknown) = ^CallSideEffect : ~m? -# 1078| v1078_40(void) = ^BufferReadSideEffect[-1] : &:r1078_36, ~m? +# 1078| v1078_40(void) = ^IndirectReadSideEffect[-1] : &:r1078_36, ~m? # 1078| mu1078_41(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r1078_36 # 1078| r1078_42(glval) = CopyValue : r1078_38 #-----| Goto (back edge) -> Block 1 # 1084| Block 5 -# 1084| r1084_1(glval &>) = VariableAddress[(__range)] : -# 1084| r1084_2(glval &>) = VariableAddress[v] : -# 1084| r1084_3(vector &) = Load[v] : &:r1084_2, ~m? -# 1084| r1084_4(glval>) = CopyValue : r1084_3 -# 1084| r1084_5(vector &) = CopyValue : r1084_4 -# 1084| mu1084_6(vector &) = Store[(__range)] : &:r1084_1, r1084_5 -# 1084| r1084_7(glval) = VariableAddress[(__begin)] : -# 1084| r1084_8(glval &>) = VariableAddress[(__range)] : -# 1084| r1084_9(vector &) = Load[(__range)] : &:r1084_8, ~m? -#-----| r0_9(glval>) = CopyValue : r1084_9 -# 1084| r1084_10(glval) = FunctionAddress[begin] : -# 1084| r1084_11(iterator) = Call[begin] : func:r1084_10, this:r0_9 -# 1084| mu1084_12(unknown) = ^CallSideEffect : ~m? -#-----| v0_10(void) = ^BufferReadSideEffect[-1] : &:r0_9, ~m? -# 1084| mu1084_13(iterator) = Store[(__begin)] : &:r1084_7, r1084_11 -# 1084| r1084_14(glval) = VariableAddress[(__end)] : -# 1084| r1084_15(glval &>) = VariableAddress[(__range)] : -# 1084| r1084_16(vector &) = Load[(__range)] : &:r1084_15, ~m? -#-----| r0_11(glval>) = CopyValue : r1084_16 -# 1084| r1084_17(glval) = FunctionAddress[end] : -# 1084| r1084_18(iterator) = Call[end] : func:r1084_17, this:r0_11 -# 1084| mu1084_19(unknown) = ^CallSideEffect : ~m? -#-----| v0_12(void) = ^BufferReadSideEffect[-1] : &:r0_11, ~m? -# 1084| mu1084_20(iterator) = Store[(__end)] : &:r1084_14, r1084_18 +# 1084| r1084_1(glval &>) = VariableAddress[(__range)] : +# 1084| r1084_2(glval &>) = VariableAddress[v] : +# 1084| r1084_3(vector &) = Load[v] : &:r1084_2, ~m? +# 1084| r1084_4(glval>) = CopyValue : r1084_3 +# 1084| r1084_5(vector &) = CopyValue : r1084_4 +# 1084| mu1084_6(vector &) = Store[(__range)] : &:r1084_1, r1084_5 +# 1084| r1084_7(glval) = VariableAddress[(__begin)] : +# 1084| r1084_8(glval &>) = VariableAddress[(__range)] : +# 1084| r1084_9(vector &) = Load[(__range)] : &:r1084_8, ~m? +#-----| r0_9(glval>) = CopyValue : r1084_9 +# 1084| r1084_10(glval) = FunctionAddress[begin] : +# 1084| r1084_11(iterator) = Call[begin] : func:r1084_10, this:r0_9 +# 1084| mu1084_12(unknown) = ^CallSideEffect : ~m? +#-----| v0_10(void) = ^IndirectReadSideEffect[-1] : &:r0_9, ~m? +# 1084| mu1084_13(iterator) = Store[(__begin)] : &:r1084_7, r1084_11 +# 1084| r1084_14(glval) = VariableAddress[(__end)] : +# 1084| r1084_15(glval &>) = VariableAddress[(__range)] : +# 1084| r1084_16(vector &) = Load[(__range)] : &:r1084_15, ~m? +#-----| r0_11(glval>) = CopyValue : r1084_16 +# 1084| r1084_17(glval) = FunctionAddress[end] : +# 1084| r1084_18(iterator) = Call[end] : func:r1084_17, this:r0_11 +# 1084| mu1084_19(unknown) = ^CallSideEffect : ~m? +#-----| v0_12(void) = ^IndirectReadSideEffect[-1] : &:r0_11, ~m? +# 1084| mu1084_20(iterator) = Store[(__end)] : &:r1084_14, r1084_18 #-----| Goto -> Block 6 # 1084| Block 6 @@ -6209,7 +6208,7 @@ ir.cpp: # 1084| r1084_24(iterator) = Load[(__end)] : &:r1084_23, ~m? # 1084| r1084_25(bool) = Call[operator!=] : func:r1084_22, this:r0_13, 0:r1084_24 # 1084| mu1084_26(unknown) = ^CallSideEffect : ~m? -#-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_13, ~m? +#-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_13, ~m? # 1084| v1084_27(void) = ConditionalBranch : r1084_25 #-----| False -> Block 10 #-----| True -> Block 8 @@ -6219,29 +6218,29 @@ ir.cpp: # 1084| r1084_29(glval) = FunctionAddress[operator++] : # 1084| r1084_30(iterator &) = Call[operator++] : func:r1084_29, this:r1084_28 # 1084| mu1084_31(unknown) = ^CallSideEffect : ~m? -# 1084| v1084_32(void) = ^BufferReadSideEffect[-1] : &:r1084_28, ~m? +# 1084| v1084_32(void) = ^IndirectReadSideEffect[-1] : &:r1084_28, ~m? # 1084| mu1084_33(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r1084_28 # 1084| r1084_34(glval) = CopyValue : r1084_30 #-----| Goto (back edge) -> Block 6 # 1084| Block 8 -# 1084| r1084_35(glval) = VariableAddress[e] : -# 1084| r1084_36(glval) = VariableAddress[(__begin)] : -#-----| r0_15(glval) = Convert : r1084_36 -# 1084| r1084_37(glval) = FunctionAddress[operator*] : -# 1084| r1084_38(int &) = Call[operator*] : func:r1084_37, this:r0_15 -# 1084| mu1084_39(unknown) = ^CallSideEffect : ~m? -#-----| v0_16(void) = ^BufferReadSideEffect[-1] : &:r0_15, ~m? -# 1084| r1084_40(glval) = CopyValue : r1084_38 -# 1084| r1084_41(glval) = Convert : r1084_40 -# 1084| r1084_42(int &) = CopyValue : r1084_41 -# 1084| mu1084_43(int &) = Store[e] : &:r1084_35, r1084_42 -# 1085| r1085_1(glval) = VariableAddress[e] : -# 1085| r1085_2(int &) = Load[e] : &:r1085_1, ~m? -# 1085| r1085_3(int) = Load[?] : &:r1085_2, ~m? -# 1085| r1085_4(int) = Constant[5] : -# 1085| r1085_5(bool) = CompareLT : r1085_3, r1085_4 -# 1085| v1085_6(void) = ConditionalBranch : r1085_5 +# 1084| r1084_35(glval) = VariableAddress[e] : +# 1084| r1084_36(glval) = VariableAddress[(__begin)] : +#-----| r0_15(glval) = Convert : r1084_36 +# 1084| r1084_37(glval) = FunctionAddress[operator*] : +# 1084| r1084_38(int &) = Call[operator*] : func:r1084_37, this:r0_15 +# 1084| mu1084_39(unknown) = ^CallSideEffect : ~m? +#-----| v0_16(void) = ^IndirectReadSideEffect[-1] : &:r0_15, ~m? +# 1084| r1084_40(glval) = CopyValue : r1084_38 +# 1084| r1084_41(glval) = Convert : r1084_40 +# 1084| r1084_42(int &) = CopyValue : r1084_41 +# 1084| mu1084_43(int &) = Store[e] : &:r1084_35, r1084_42 +# 1085| r1085_1(glval) = VariableAddress[e] : +# 1085| r1085_2(int &) = Load[e] : &:r1085_1, ~m? +# 1085| r1085_3(int) = Load[?] : &:r1085_2, ~m? +# 1085| r1085_4(int) = Constant[5] : +# 1085| r1085_5(bool) = CompareLT : r1085_3, r1085_4 +# 1085| v1085_6(void) = ConditionalBranch : r1085_5 #-----| False -> Block 7 #-----| True -> Block 9 @@ -7525,7 +7524,7 @@ ir.cpp: # 1373| r1373_8(glval) = FunctionAddress[c_str] : # 1373| r1373_9(char *) = Call[c_str] : func:r1373_8, this:r1373_7 # 1373| mu1373_10(unknown) = ^CallSideEffect : ~m? -# 1373| v1373_11(void) = ^BufferReadSideEffect[-1] : &:r1373_7, ~m? +# 1373| v1373_11(void) = ^IndirectReadSideEffect[-1] : &:r1373_7, ~m? # 1374| r1374_1(glval) = VariableAddress[#temp1374:5] : # 1374| r1374_2(glval) = FunctionAddress[returnValue] : # 1374| r1374_3(String) = Call[returnValue] : func:r1374_2 @@ -7535,7 +7534,7 @@ ir.cpp: # 1374| r1374_7(glval) = FunctionAddress[c_str] : # 1374| r1374_8(char *) = Call[c_str] : func:r1374_7, this:r1374_6 # 1374| mu1374_9(unknown) = ^CallSideEffect : ~m? -# 1374| v1374_10(void) = ^BufferReadSideEffect[-1] : &:r1374_6, ~m? +# 1374| v1374_10(void) = ^IndirectReadSideEffect[-1] : &:r1374_6, ~m? # 1376| r1376_1(glval) = VariableAddress[#temp1376:5] : # 1376| r1376_2(glval) = FunctionAddress[defaultConstruct] : # 1376| r1376_3(String) = Call[defaultConstruct] : func:r1376_2 @@ -7589,7 +7588,7 @@ ir.cpp: # 1385| r1385_4(glval) = FunctionAddress[method] : # 1385| v1385_5(void) = Call[method] : func:r1385_4, this:r1385_1 # 1385| mu1385_6(unknown) = ^CallSideEffect : ~m? -# 1385| v1385_7(void) = ^BufferReadSideEffect[-1] : &:r1385_1, ~m? +# 1385| v1385_7(void) = ^IndirectReadSideEffect[-1] : &:r1385_1, ~m? # 1385| mu1385_8(destructor_only) = ^IndirectMayWriteSideEffect[-1] : &:r1385_1 # 1386| r1386_1(glval) = VariableAddress[#temp1386:5] : # 1386| r1386_2(glval) = FunctionAddress[returnValue] : @@ -7599,7 +7598,7 @@ ir.cpp: # 1386| r1386_6(glval) = FunctionAddress[method] : # 1386| v1386_7(void) = Call[method] : func:r1386_6, this:r1386_1 # 1386| mu1386_8(unknown) = ^CallSideEffect : ~m? -# 1386| v1386_9(void) = ^BufferReadSideEffect[-1] : &:r1386_1, ~m? +# 1386| v1386_9(void) = ^IndirectReadSideEffect[-1] : &:r1386_1, ~m? # 1386| mu1386_10(destructor_only) = ^IndirectMayWriteSideEffect[-1] : &:r1386_1 # 1388| r1388_1(glval) = VariableAddress[#temp1388:5] : # 1388| r1388_2(glval) = FunctionAddress[defaultConstruct] : @@ -7667,7 +7666,7 @@ ir.cpp: # 1397| r1397_7(glval) = FunctionAddress[method] : # 1397| v1397_8(void) = Call[method] : func:r1397_7, this:r1397_1 # 1397| mu1397_9(unknown) = ^CallSideEffect : ~m? -# 1397| v1397_10(void) = ^BufferReadSideEffect[-1] : &:r1397_1, ~m? +# 1397| v1397_10(void) = ^IndirectReadSideEffect[-1] : &:r1397_1, ~m? # 1397| mu1397_11(copy_constructor) = ^IndirectMayWriteSideEffect[-1] : &:r1397_1 # 1398| r1398_1(glval) = VariableAddress[#temp1398:5] : # 1398| r1398_2(glval) = FunctionAddress[returnValue] : @@ -7677,7 +7676,7 @@ ir.cpp: # 1398| r1398_6(glval) = FunctionAddress[method] : # 1398| v1398_7(void) = Call[method] : func:r1398_6, this:r1398_1 # 1398| mu1398_8(unknown) = ^CallSideEffect : ~m? -# 1398| v1398_9(void) = ^BufferReadSideEffect[-1] : &:r1398_1, ~m? +# 1398| v1398_9(void) = ^IndirectReadSideEffect[-1] : &:r1398_1, ~m? # 1398| mu1398_10(copy_constructor) = ^IndirectMayWriteSideEffect[-1] : &:r1398_1 # 1399| r1399_1(glval) = VariableAddress[#temp1399:5] : # 1399| r1399_2(glval) = FunctionAddress[defaultConstruct] : @@ -7851,7 +7850,7 @@ ir.cpp: # 1447| r1447_9(glval) = FunctionAddress[f] : # 1447| r1447_10(float) = Call[f] : func:r1447_9, this:r1447_8 # 1447| mu1447_11(unknown) = ^CallSideEffect : ~m? -# 1447| v1447_12(void) = ^BufferReadSideEffect[-1] : &:r1447_8, ~m? +# 1447| v1447_12(void) = ^IndirectReadSideEffect[-1] : &:r1447_8, ~m? # 1447| mu1447_13(float) = Store[f] : &:r1447_1, r1447_10 # 1448| v1448_1(void) = NoOp : # 1443| v1443_4(void) = ReturnVoid : diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected index c4019a38251e..76de50dd792b 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected @@ -1059,7 +1059,7 @@ ssa.cpp: # 241| v241_3(void) = Call[g] : func:r241_2, this:r241_1 # 241| m241_4(unknown) = ^CallSideEffect : ~m240_7 # 241| m241_5(unknown) = Chi : total:m240_7, partial:m241_4 -# 241| v241_6(void) = ^BufferReadSideEffect[-1] : &:r241_1, ~m240_9 +# 241| v241_6(void) = ^IndirectReadSideEffect[-1] : &:r241_1, m240_9 # 241| m241_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r241_1 # 241| m241_8(Constructible) = Chi : total:m240_9, partial:m241_7 # 242| r242_1(glval) = VariableAddress[c] : @@ -1067,7 +1067,7 @@ ssa.cpp: # 242| v242_3(void) = Call[g] : func:r242_2, this:r242_1 # 242| m242_4(unknown) = ^CallSideEffect : ~m241_5 # 242| m242_5(unknown) = Chi : total:m241_5, partial:m242_4 -# 242| v242_6(void) = ^BufferReadSideEffect[-1] : &:r242_1, ~m241_8 +# 242| v242_6(void) = ^IndirectReadSideEffect[-1] : &:r242_1, m241_8 # 242| m242_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r242_1 # 242| m242_8(Constructible) = Chi : total:m241_8, partial:m242_7 # 243| r243_1(glval) = VariableAddress[c2] : @@ -1084,7 +1084,7 @@ ssa.cpp: # 244| v244_3(void) = Call[g] : func:r244_2, this:r244_1 # 244| m244_4(unknown) = ^CallSideEffect : ~m243_7 # 244| m244_5(unknown) = Chi : total:m243_7, partial:m244_4 -# 244| v244_6(void) = ^BufferReadSideEffect[-1] : &:r244_1, ~m243_9 +# 244| v244_6(void) = ^IndirectReadSideEffect[-1] : &:r244_1, m243_9 # 244| m244_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1 # 244| m244_8(Constructible) = Chi : total:m243_9, partial:m244_7 # 245| v245_1(void) = NoOp : diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected index a101e638cd08..ab79d20214a8 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected @@ -1054,7 +1054,7 @@ ssa.cpp: # 241| v241_3(void) = Call[g] : func:r241_2, this:r241_1 # 241| m241_4(unknown) = ^CallSideEffect : ~m240_7 # 241| m241_5(unknown) = Chi : total:m240_7, partial:m241_4 -# 241| v241_6(void) = ^BufferReadSideEffect[-1] : &:r241_1, ~m240_9 +# 241| v241_6(void) = ^IndirectReadSideEffect[-1] : &:r241_1, m240_9 # 241| m241_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r241_1 # 241| m241_8(Constructible) = Chi : total:m240_9, partial:m241_7 # 242| r242_1(glval) = VariableAddress[c] : @@ -1062,7 +1062,7 @@ ssa.cpp: # 242| v242_3(void) = Call[g] : func:r242_2, this:r242_1 # 242| m242_4(unknown) = ^CallSideEffect : ~m241_5 # 242| m242_5(unknown) = Chi : total:m241_5, partial:m242_4 -# 242| v242_6(void) = ^BufferReadSideEffect[-1] : &:r242_1, ~m241_8 +# 242| v242_6(void) = ^IndirectReadSideEffect[-1] : &:r242_1, m241_8 # 242| m242_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r242_1 # 242| m242_8(Constructible) = Chi : total:m241_8, partial:m242_7 # 243| r243_1(glval) = VariableAddress[c2] : @@ -1079,7 +1079,7 @@ ssa.cpp: # 244| v244_3(void) = Call[g] : func:r244_2, this:r244_1 # 244| m244_4(unknown) = ^CallSideEffect : ~m243_7 # 244| m244_5(unknown) = Chi : total:m243_7, partial:m244_4 -# 244| v244_6(void) = ^BufferReadSideEffect[-1] : &:r244_1, ~m243_9 +# 244| v244_6(void) = ^IndirectReadSideEffect[-1] : &:r244_1, m243_9 # 244| m244_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1 # 244| m244_8(Constructible) = Chi : total:m243_9, partial:m244_7 # 245| v245_1(void) = NoOp : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index 8b6cf17dbbbb..0b257db98a43 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -983,13 +983,13 @@ ssa.cpp: # 241| r241_2(glval) = FunctionAddress[g] : # 241| v241_3(void) = Call[g] : func:r241_2, this:r241_1 # 241| mu241_4(unknown) = ^CallSideEffect : ~m? -# 241| v241_5(void) = ^BufferReadSideEffect[-1] : &:r241_1, ~m? +# 241| v241_5(void) = ^IndirectReadSideEffect[-1] : &:r241_1, ~m? # 241| mu241_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r241_1 # 242| r242_1(glval) = VariableAddress[c] : # 242| r242_2(glval) = FunctionAddress[g] : # 242| v242_3(void) = Call[g] : func:r242_2, this:r242_1 # 242| mu242_4(unknown) = ^CallSideEffect : ~m? -# 242| v242_5(void) = ^BufferReadSideEffect[-1] : &:r242_1, ~m? +# 242| v242_5(void) = ^IndirectReadSideEffect[-1] : &:r242_1, ~m? # 242| mu242_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r242_1 # 243| r243_1(glval) = VariableAddress[c2] : # 243| mu243_2(Constructible) = Uninitialized[c2] : &:r243_1 @@ -1002,7 +1002,7 @@ ssa.cpp: # 244| r244_2(glval) = FunctionAddress[g] : # 244| v244_3(void) = Call[g] : func:r244_2, this:r244_1 # 244| mu244_4(unknown) = ^CallSideEffect : ~m? -# 244| v244_5(void) = ^BufferReadSideEffect[-1] : &:r244_1, ~m? +# 244| v244_5(void) = ^IndirectReadSideEffect[-1] : &:r244_1, ~m? # 244| mu244_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1 # 245| v245_1(void) = NoOp : # 239| v239_4(void) = ReturnVoid : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected index 8b6cf17dbbbb..0b257db98a43 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected @@ -983,13 +983,13 @@ ssa.cpp: # 241| r241_2(glval) = FunctionAddress[g] : # 241| v241_3(void) = Call[g] : func:r241_2, this:r241_1 # 241| mu241_4(unknown) = ^CallSideEffect : ~m? -# 241| v241_5(void) = ^BufferReadSideEffect[-1] : &:r241_1, ~m? +# 241| v241_5(void) = ^IndirectReadSideEffect[-1] : &:r241_1, ~m? # 241| mu241_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r241_1 # 242| r242_1(glval) = VariableAddress[c] : # 242| r242_2(glval) = FunctionAddress[g] : # 242| v242_3(void) = Call[g] : func:r242_2, this:r242_1 # 242| mu242_4(unknown) = ^CallSideEffect : ~m? -# 242| v242_5(void) = ^BufferReadSideEffect[-1] : &:r242_1, ~m? +# 242| v242_5(void) = ^IndirectReadSideEffect[-1] : &:r242_1, ~m? # 242| mu242_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r242_1 # 243| r243_1(glval) = VariableAddress[c2] : # 243| mu243_2(Constructible) = Uninitialized[c2] : &:r243_1 @@ -1002,7 +1002,7 @@ ssa.cpp: # 244| r244_2(glval) = FunctionAddress[g] : # 244| v244_3(void) = Call[g] : func:r244_2, this:r244_1 # 244| mu244_4(unknown) = ^CallSideEffect : ~m? -# 244| v244_5(void) = ^BufferReadSideEffect[-1] : &:r244_1, ~m? +# 244| v244_5(void) = ^IndirectReadSideEffect[-1] : &:r244_1, ~m? # 244| mu244_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1 # 245| v245_1(void) = NoOp : # 239| v239_4(void) = ReturnVoid : From 697b2dcde8faafcc585c41a08dd1036f2ab53e09 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 12 Apr 2021 18:11:10 -0400 Subject: [PATCH 2/4] C++: Add missing store step for single-field struct use We have special code to handle field flow for single-field structs, but that special case was too specific. Some `Store`s to single-field structs have no `Chi` instruction, which is the case that we handled already. However, it is possible for the `Store` to have a `Chi` instruction (e.g. for `{AllAliased}`), but still have a use of the result of the `Store` directly. We now add a `PostUpdateNode` for the result of the `Store` itself in those cases, just like we already did if the `Store` had no `Chi`. --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 15 +++++-- .../ir/dataflow/internal/PrintIRLocalFlow.qll | 29 +------------- .../dataflow/internal/PrintIRStoreSteps.qll | 33 ++++++++++++++++ .../ir/dataflow/internal/PrintIRUtilities.qll | 39 +++++++++++++++++++ .../dataflow-ir-consistency.expected | 2 + .../fields/dataflow-ir-consistency.expected | 4 ++ .../dataflow/fields/ir-path-flow.expected | 6 +-- 7 files changed, 93 insertions(+), 35 deletions(-) create mode 100644 cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/PrintIRStoreSteps.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/PrintIRUtilities.qll diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 76ca7b215dce..81a07ad9d04a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -362,15 +362,22 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { /** * Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to. - * For instance, an update to a field of a struct containing only one field. For these cases we - * attach the PostUpdateNode to the store instruction. There's no obvious pre update node for this case - * (as the entire memory is updated), so `getPreUpdateNode` is implemented as `none()`. + * For instance, an update to a field of a struct containing only one field. Even if the store does + * have a chi instruction, a subsequent use of the result of the store may be linked directly to the + * result of the store as an inexact definition if the store totally overlaps the use. For these + * cases we attach the PostUpdateNode to the store instruction. There's no obvious pre update node + * for this case (as the entire memory is updated), so `getPreUpdateNode` is implemented as + * `none()`. */ private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode { override StoreInstruction instr; ExplicitSingleFieldStoreQualifierNode() { - not exists(ChiInstruction chi | chi.getPartial() = instr) and + ( + instr.getAUse().isDefinitionInexact() + or + not exists(ChiInstruction chi | chi.getPartial() = instr) + ) and // Without this condition any store would create a `PostUpdateNode`. instr.getDestinationAddress() instanceof FieldAddressInstruction } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/PrintIRLocalFlow.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/PrintIRLocalFlow.qll index 337dc71a3caa..16182296e400 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/PrintIRLocalFlow.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/PrintIRLocalFlow.qll @@ -6,34 +6,7 @@ private import semmle.code.cpp.ir.ValueNumbering private import semmle.code.cpp.ir.IR private import semmle.code.cpp.ir.dataflow.DataFlow private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil - -/** - * Gets a short ID for an IR dataflow node. - * - For `Instruction`s, this is just the result ID of the instruction (e.g. `m128`). - * - For `Operand`s, this is the label of the operand, prefixed with the result ID of the - * instruction and a dot (e.g. `m128.left`). - * - For `Variable`s, this is the qualified name of the variable. - */ -private string nodeId(DataFlow::Node node, int order1, int order2) { - exists(Instruction instruction | instruction = node.asInstruction() | - result = instruction.getResultId() and - order1 = instruction.getBlock().getDisplayIndex() and - order2 = instruction.getDisplayIndexInBlock() - ) - or - exists(Operand operand, Instruction instruction | - operand = node.asOperand() and - instruction = operand.getUse() - | - result = instruction.getResultId() + "." + operand.getDumpId() and - order1 = instruction.getBlock().getDisplayIndex() and - order2 = instruction.getDisplayIndexInBlock() - ) - or - result = "var(" + node.asVariable().getQualifiedName() + ")" and - order1 = 1000000 and - order2 = 0 -} +private import PrintIRUtilities /** * Gets the local dataflow from other nodes in the same function to this node. diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/PrintIRStoreSteps.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/PrintIRStoreSteps.qll new file mode 100644 index 000000000000..8c3182162170 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/PrintIRStoreSteps.qll @@ -0,0 +1,33 @@ +/** + * Print the dataflow local store steps in IR dumps. + */ + +private import cpp +// The `ValueNumbering` library has to be imported right after `cpp` to ensure +// that the cached IR gets the same checksum here as it does in queries that use +// `ValueNumbering` without `DataFlow`. +private import semmle.code.cpp.ir.ValueNumbering +private import semmle.code.cpp.ir.IR +private import semmle.code.cpp.ir.dataflow.DataFlow +private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil +private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate +private import PrintIRUtilities + +/** + * Property provider for local IR dataflow store steps. + */ +class LocalFlowPropertyProvider extends IRPropertyProvider { + override string getInstructionProperty(Instruction instruction, string key) { + exists(DataFlow::Node objectNode, Content content | + key = "content[" + content.toString() + "]" and + instruction = objectNode.asInstruction() and + result = + strictconcat(string element, DataFlow::Node fieldNode | + storeStep(fieldNode, content, objectNode) and + element = nodeId(fieldNode, _, _) + | + element, ", " + ) + ) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/PrintIRUtilities.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/PrintIRUtilities.qll new file mode 100644 index 000000000000..5fc15cf986c7 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/PrintIRUtilities.qll @@ -0,0 +1,39 @@ +/** + * Shared utilities used when printing dataflow annotations in IR dumps. + */ + +private import cpp +// The `ValueNumbering` library has to be imported right after `cpp` to ensure +// that the cached IR gets the same checksum here as it does in queries that use +// `ValueNumbering` without `DataFlow`. +private import semmle.code.cpp.ir.ValueNumbering +private import semmle.code.cpp.ir.IR +private import semmle.code.cpp.ir.dataflow.DataFlow + +/** + * Gets a short ID for an IR dataflow node. + * - For `Instruction`s, this is just the result ID of the instruction (e.g. `m128`). + * - For `Operand`s, this is the label of the operand, prefixed with the result ID of the + * instruction and a dot (e.g. `m128.left`). + * - For `Variable`s, this is the qualified name of the variable. + */ +string nodeId(DataFlow::Node node, int order1, int order2) { + exists(Instruction instruction | instruction = node.asInstruction() | + result = instruction.getResultId() and + order1 = instruction.getBlock().getDisplayIndex() and + order2 = instruction.getDisplayIndexInBlock() + ) + or + exists(Operand operand, Instruction instruction | + operand = node.asOperand() and + instruction = operand.getUse() + | + result = instruction.getResultId() + "." + operand.getDumpId() and + order1 = instruction.getBlock().getDisplayIndex() and + order2 = instruction.getDisplayIndexInBlock() + ) + or + result = "var(" + node.asVariable().getQualifiedName() + ")" and + order1 = 1000000 and + order2 = 0 +} diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected index fc6c97aa2a63..db9a86fbb570 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected @@ -26,6 +26,7 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre +| test.cpp:373:5:373:20 | Store | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead @@ -82,4 +83,5 @@ postWithInFlow | test.cpp:125:3:125:11 | Chi | PostUpdateNode should not be the target of local flow. | | test.cpp:359:5:359:20 | Chi | PostUpdateNode should not be the target of local flow. | | test.cpp:373:5:373:20 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:373:5:373:20 | Store | PostUpdateNode should not be the target of local flow. | | test.cpp:465:3:465:15 | Chi | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected index 63d3b2c0f48f..fe7d8360403c 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected @@ -20,7 +20,9 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre +| D.cpp:57:5:57:42 | Store | PostUpdateNode should have one pre-update node but has 0. | | simple.cpp:65:5:65:22 | Store | PostUpdateNode should have one pre-update node but has 0. | +| simple.cpp:83:9:83:28 | Store | PostUpdateNode should have one pre-update node but has 0. | | simple.cpp:92:5:92:22 | Store | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable @@ -54,6 +56,7 @@ postWithInFlow | D.cpp:49:15:49:24 | Chi | PostUpdateNode should not be the target of local flow. | | D.cpp:56:15:56:24 | Chi | PostUpdateNode should not be the target of local flow. | | D.cpp:57:5:57:42 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:57:5:57:42 | Store | PostUpdateNode should not be the target of local flow. | | aliasing.cpp:9:3:9:22 | Chi | PostUpdateNode should not be the target of local flow. | | aliasing.cpp:13:3:13:21 | Chi | PostUpdateNode should not be the target of local flow. | | aliasing.cpp:17:3:17:21 | Chi | PostUpdateNode should not be the target of local flow. | @@ -150,6 +153,7 @@ postWithInFlow | simple.cpp:23:35:23:35 | Chi | PostUpdateNode should not be the target of local flow. | | simple.cpp:65:5:65:22 | Store | PostUpdateNode should not be the target of local flow. | | simple.cpp:83:9:83:28 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:83:9:83:28 | Store | PostUpdateNode should not be the target of local flow. | | simple.cpp:92:5:92:22 | Store | PostUpdateNode should not be the target of local flow. | | struct_init.c:20:20:20:29 | Chi | PostUpdateNode should not be the target of local flow. | | struct_init.c:20:34:20:34 | Chi | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index 37a0dc3832a2..e6234ca17f77 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -228,8 +228,8 @@ edges | simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | | simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | -| simple.cpp:83:9:83:28 | Chi [f1] | simple.cpp:84:14:84:20 | this indirection [f1] | -| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Chi [f1] | +| simple.cpp:83:9:83:28 | Store [f1] | simple.cpp:84:14:84:20 | this indirection [f1] | +| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Store [f1] | | simple.cpp:84:14:84:20 | this indirection [f1] | simple.cpp:84:14:84:20 | call to getf2f1 | | simple.cpp:92:5:92:22 | Store [i] | simple.cpp:93:20:93:20 | Store [i] | | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | Store [i] | @@ -494,7 +494,7 @@ nodes | simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | | simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | | simple.cpp:67:13:67:13 | i | semmle.label | i | -| simple.cpp:83:9:83:28 | Chi [f1] | semmle.label | Chi [f1] | +| simple.cpp:83:9:83:28 | Store [f1] | semmle.label | Store [f1] | | simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | | simple.cpp:84:14:84:20 | this indirection [f1] | semmle.label | this indirection [f1] | From afd2f58f9fa6a75a390b818a5ea33cc1ae2b63fb Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 12 Apr 2021 18:21:05 -0400 Subject: [PATCH 3/4] C++: Fix PR feedback --- .../cpp/ir/implementation/raw/internal/TranslatedCall.qll | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index 0b52937f1cb7..56d4c807ac85 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -495,10 +495,8 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) { - ( - tag = OnlyInstructionTag() and - opcode = sideEffectOpcode - ) and + tag = OnlyInstructionTag() and + opcode = sideEffectOpcode and ( isWrite() and ( From b29f35f564f7f657a6f1fed4e63b5396d3d64220 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 14 Apr 2021 11:15:16 -0400 Subject: [PATCH 4/4] Fix formatting --- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 81a07ad9d04a..f5fb7309cff6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -362,7 +362,7 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { /** * Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to. - * For instance, an update to a field of a struct containing only one field. Even if the store does + * For instance, an update to a field of a struct containing only one field. Even if the store does * have a chi instruction, a subsequent use of the result of the store may be linked directly to the * result of the store as an inexact definition if the store totally overlaps the use. For these * cases we attach the PostUpdateNode to the store instruction. There's no obvious pre update node