diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll index bd1ffcd5ce15..90afabca30de 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll @@ -92,7 +92,9 @@ private newtype TOpcode = TUninitializedGroup() or TInlineAsm() or TUnreached() or - TNewObj() + TNewObj() or + TTypeidExpr() or + TTypeidType() /** * An opcode that specifies the operation performed by an `Instruction`. @@ -1281,4 +1283,29 @@ module Opcode { class NewObj extends Opcode, TNewObj { final override string toString() { result = "NewObj" } } + + /** + * The `Opcode` for a `TypeidInstruction`. + * + * See the `TypeidInstruction` documentation for more details. + */ + abstract class Typeid extends Opcode { } + + /** + * The `Opcode` for a `TypeidExprInstruction`. + * + * See the `TypeidExprInstruction` documentation for more details. + */ + class TypeidExpr extends Typeid, UnaryOpcode, TTypeidExpr { + final override string toString() { result = "TypeidExpr" } + } + + /** + * The `Opcode` for a `TypeidTypeInstruction`. + * + * See the `TypeidTypeInstruction` documentation for more details. + */ + class TypeidType extends Typeid, TTypeidType { + final override string toString() { result = "TypeidType" } + } } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 96c18a04ff7b..d5332cecf85a 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -2293,3 +2293,26 @@ class NextVarArgInstruction extends UnaryInstruction { class NewObjInstruction extends Instruction { NewObjInstruction() { this.getOpcode() instanceof Opcode::NewObj } } + +/** + * An instruction that returns the type info for its operand. + */ +class TypeidInstruction extends Instruction { + TypeidInstruction() { this.getOpcode() instanceof Opcode::Typeid } +} + +/** + * An instruction that returns the type info for its operand, where the + * operand occurs as an expression in the AST. + */ +class TypeidExprInstruction extends TypeidInstruction, UnaryInstruction { + TypeidExprInstruction() { this.getOpcode() instanceof Opcode::TypeidExpr } +} + +/** + * An instruction that returns the type info for its operand, where the + * operand occurs as a type in the AST. + */ +class TypeidTypeInstruction extends TypeidInstruction { + TypeidTypeInstruction() { this.getOpcode() instanceof Opcode::TypeidType } +} diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 96c18a04ff7b..d5332cecf85a 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -2293,3 +2293,26 @@ class NextVarArgInstruction extends UnaryInstruction { class NewObjInstruction extends Instruction { NewObjInstruction() { this.getOpcode() instanceof Opcode::NewObj } } + +/** + * An instruction that returns the type info for its operand. + */ +class TypeidInstruction extends Instruction { + TypeidInstruction() { this.getOpcode() instanceof Opcode::Typeid } +} + +/** + * An instruction that returns the type info for its operand, where the + * operand occurs as an expression in the AST. + */ +class TypeidExprInstruction extends TypeidInstruction, UnaryInstruction { + TypeidExprInstruction() { this.getOpcode() instanceof Opcode::TypeidExpr } +} + +/** + * An instruction that returns the type info for its operand, where the + * operand occurs as a type in the AST. + */ +class TypeidTypeInstruction extends TypeidInstruction { + TypeidTypeInstruction() { this.getOpcode() instanceof Opcode::TypeidType } +} diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index dea86499e7ca..2aa5eeebb6b7 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -4185,3 +4185,52 @@ class TranslatedAssumeExpr extends TranslatedSingleInstructionExpr { none() } } + +class TranslatedTypeidExpr extends TranslatedSingleInstructionExpr { + override TypeidOperator expr; + + final override Opcode getOpcode() { + exists(this.getOperand()) and + result instanceof Opcode::TypeidExpr + or + not exists(this.getOperand()) and + result instanceof Opcode::TypeidType + } + + final override Instruction getFirstInstruction(EdgeKind kind) { + result = this.getOperand().getFirstInstruction(kind) + or + not exists(this.getOperand()) and + result = this.getInstruction(OnlyInstructionTag()) and + kind instanceof GotoEdge + } + + override Instruction getALastInstructionInternal() { + result = this.getInstruction(OnlyInstructionTag()) + } + + final override TranslatedElement getChildInternal(int id) { + id = 0 and result = this.getOperand() + } + + final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) { + tag = OnlyInstructionTag() and + result = this.getParent().getChildSuccessor(this, kind) + } + + final override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) { + child = this.getOperand() and + result = this.getInstruction(OnlyInstructionTag()) and + kind instanceof GotoEdge + } + + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + tag = OnlyInstructionTag() and + result = this.getOperand().getResult() and + operandTag instanceof UnaryOperandTag + } + + private TranslatedExpr getOperand() { + result = getTranslatedExpr(expr.getExpr().getFullyConverted()) + } +} diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 96c18a04ff7b..d5332cecf85a 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -2293,3 +2293,26 @@ class NextVarArgInstruction extends UnaryInstruction { class NewObjInstruction extends Instruction { NewObjInstruction() { this.getOpcode() instanceof Opcode::NewObj } } + +/** + * An instruction that returns the type info for its operand. + */ +class TypeidInstruction extends Instruction { + TypeidInstruction() { this.getOpcode() instanceof Opcode::Typeid } +} + +/** + * An instruction that returns the type info for its operand, where the + * operand occurs as an expression in the AST. + */ +class TypeidExprInstruction extends TypeidInstruction, UnaryInstruction { + TypeidExprInstruction() { this.getOpcode() instanceof Opcode::TypeidExpr } +} + +/** + * An instruction that returns the type info for its operand, where the + * operand occurs as a type in the AST. + */ +class TypeidTypeInstruction extends TypeidInstruction { + TypeidTypeInstruction() { this.getOpcode() instanceof Opcode::TypeidType } +} diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected index 38f0a0a4f4f7..78f0bbd1e0c8 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected @@ -39983,4 +39983,17 @@ type_info_test.cpp: # 3| m3_4(unknown) = Chi : total:m3_2, partial:m3_3 # 3| r3_5(glval) = VariableAddress[x] : # 3| m3_6(int) = InitializeParameter[x] : &:r3_5 +# 3| m3_7(unknown) = Chi : total:m3_4, partial:m3_6 # 4| r4_1(glval) = VariableAddress[t1] : +# 4| r4_2(glval) = VariableAddress[x] : +# 4| r4_3(glval) = TypeidExpr : r4_2 +# 4| r4_4(type_info &) = CopyValue : r4_3 +# 4| m4_5(type_info &) = Store[t1] : &:r4_1, r4_4 +# 5| r5_1(glval) = VariableAddress[t2] : +# 5| r5_2(glval) = TypeidType : +# 5| r5_3(type_info &) = CopyValue : r5_2 +# 5| m5_4(type_info &) = Store[t2] : &:r5_1, r5_3 +# 6| v6_1(void) = NoOp : +# 3| v3_8(void) = ReturnVoid : +# 3| v3_9(void) = AliasedUse : m3_3 +# 3| v3_10(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected index 137b2aee2665..b83d9ea47e38 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected @@ -6,7 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| type_info_test.cpp:4:25:4:26 | VariableAddress: definition of t1 | Instruction 'VariableAddress: definition of t1' has no successors in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected index 137b2aee2665..b83d9ea47e38 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected @@ -6,7 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| type_info_test.cpp:4:25:4:26 | VariableAddress: definition of t1 | Instruction 'VariableAddress: definition of t1' has no successors in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction diff --git a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected index 9cdfdd2dcd5e..e30106d35204 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected @@ -1,6 +1,4 @@ missingOperand -| type_info_test.cpp:4:30:4:38 | CopyValue: (reference to) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | -| type_info_test.cpp:5:30:5:40 | CopyValue: (reference to) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | unexpectedOperand duplicateOperand missingPhiOperand @@ -8,9 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| type_info_test.cpp:4:25:4:26 | VariableAddress: definition of t1 | Instruction 'VariableAddress: definition of t1' has no successors in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | -| type_info_test.cpp:4:37:4:37 | VariableAddress: x | Instruction 'VariableAddress: x' has no successors in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | -| type_info_test.cpp:5:25:5:26 | VariableAddress: definition of t2 | Instruction 'VariableAddress: definition of t2' has no successors in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction @@ -26,8 +21,6 @@ lostReachability backEdgeCountMismatch useNotDominatedByDefinition | ir.cpp:1535:8:1535:8 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1535:8:1535:8 | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() | -| type_info_test.cpp:4:25:4:26 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | -| type_info_test.cpp:5:25:5:26 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated 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 c9158233914d..68c2f3602983 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -38112,19 +38112,15 @@ type_info_test.cpp: # 3| r3_4(glval) = VariableAddress[x] : # 3| mu3_5(int) = InitializeParameter[x] : &:r3_4 # 4| r4_1(glval) = VariableAddress[t1] : - -# 4| Block 1 -# 4| r4_2(glval) = VariableAddress[x] : - -# 4| Block 2 -# 4| r4_3(type_info &) = CopyValue : -# 4| mu4_4(type_info &) = Store[t1] : &:r4_1, r4_3 -# 5| r5_1(glval) = VariableAddress[t2] : - -# 5| Block 3 -# 5| r5_2(type_info &) = CopyValue : -# 5| mu5_3(type_info &) = Store[t2] : &:r5_1, r5_2 -# 6| v6_1(void) = NoOp : -# 3| v3_6(void) = ReturnVoid : -# 3| v3_7(void) = AliasedUse : ~m? -# 3| v3_8(void) = ExitFunction : +# 4| r4_2(glval) = VariableAddress[x] : +# 4| r4_3(glval) = TypeidExpr : r4_2 +# 4| r4_4(type_info &) = CopyValue : r4_3 +# 4| mu4_5(type_info &) = Store[t1] : &:r4_1, r4_4 +# 5| r5_1(glval) = VariableAddress[t2] : +# 5| r5_2(glval) = TypeidType : +# 5| r5_3(type_info &) = CopyValue : r5_2 +# 5| mu5_4(type_info &) = Store[t2] : &:r5_1, r5_3 +# 6| v6_1(void) = NoOp : +# 3| v3_6(void) = ReturnVoid : +# 3| v3_7(void) = AliasedUse : ~m? +# 3| v3_8(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected index 137b2aee2665..b83d9ea47e38 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected @@ -6,7 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| type_info_test.cpp:4:25:4:26 | VariableAddress: definition of t1 | Instruction 'VariableAddress: definition of t1' has no successors in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected index 137b2aee2665..b83d9ea47e38 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected @@ -6,7 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| type_info_test.cpp:4:25:4:26 | VariableAddress: definition of t1 | Instruction 'VariableAddress: definition of t1' has no successors in function '$@'. | type_info_test.cpp:3:6:3:19 | void type_info_test(int) | void type_info_test(int) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction