From 60845001dd22dd5c35849597b424c08bd160774e Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Fri, 29 Aug 2025 17:46:19 +0200 Subject: [PATCH 01/16] C++: Add `sizeof` VLA IR test cases --- .../library-tests/ir/ir/PrintAST.expected | 180 ++++++++++++++++++ .../library-tests/ir/ir/aliased_ir.expected | 19 ++ .../ir/ir/aliased_ssa_consistency.expected | 1 + .../aliased_ssa_consistency_unsound.expected | 1 + cpp/ql/test/library-tests/ir/ir/ir.cpp | 14 ++ .../ir/ir/raw_consistency.expected | 24 +++ .../test/library-tests/ir/ir/raw_ir.expected | 90 +++++++++ .../ir/ir/unaliased_ssa_consistency.expected | 1 + ...unaliased_ssa_consistency_unsound.expected | 1 + 9 files changed, 331 insertions(+) diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index c3085da03ab5..b03bd3266044 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -24581,6 +24581,186 @@ ir.cpp: # 2776| Value = [CStyleCast] 42 # 2776| ValueCategory = prvalue # 2777| getStmt(2): [ReturnStmt] return ... +# 2779| [TopLevelFunction] void vla_sizeof_test(int, size_t, char) +# 2779| : +# 2779| getParameter(0): [Parameter] len1 +# 2779| Type = [IntType] int +# 2779| getParameter(1): [Parameter] len2 +# 2779| Type = [CTypedefType,Size_t] size_t +# 2779| getParameter(2): [Parameter] len3 +# 2779| Type = [PlainCharType] char +# 2780| getEntryPoint(): [BlockStmt] { ... } +# 2781| getStmt(0): [DeclStmt] declaration +# 2781| getDeclarationEntry(0): [VariableDeclarationEntry] definition of tmp1 +# 2781| Type = [ArrayType] char[] +# 2781| getStmt(1): [VlaDimensionStmt] VLA dimension size +# 2781| getDimensionExpr(): [VariableAccess] len1 +# 2781| Type = [IntType] int +# 2781| ValueCategory = prvalue(load) +# 2781| getStmt(2): [VlaDeclStmt] VLA declaration +# 2782| getStmt(3): [DeclStmt] declaration +# 2782| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x +# 2782| Type = [CTypedefType,Size_t] size_t +# 2782| getVariable().getInitializer(): [Initializer] initializer for x +# 2782| getExpr(): [SizeofExprOperator] sizeof() +# 2782| Type = [LongType] unsigned long +# 2782| ValueCategory = prvalue +# 2782| getExprOperand(): [VariableAccess] tmp1 +# 2782| Type = [ArrayType] char[] +# 2782| ValueCategory = lvalue +# 2782| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) +# 2782| Type = [ArrayType] char[] +# 2782| ValueCategory = lvalue +# 2783| getStmt(4): [DeclStmt] declaration +# 2783| getDeclarationEntry(0): [VariableDeclarationEntry] definition of tmp2 +# 2783| Type = [ArrayType] int[][] +# 2783| getStmt(5): [VlaDimensionStmt] VLA dimension size +# 2783| getDimensionExpr(): [VariableAccess] len1 +# 2783| Type = [IntType] int +# 2783| ValueCategory = prvalue(load) +# 2783| getStmt(6): [VlaDimensionStmt] VLA dimension size +# 2783| getDimensionExpr(): [VariableAccess] len2 +# 2783| Type = [CTypedefType,Size_t] size_t +# 2783| ValueCategory = prvalue(load) +# 2783| getStmt(7): [VlaDeclStmt] VLA declaration +# 2784| getStmt(8): [DeclStmt] declaration +# 2784| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y +# 2784| Type = [CTypedefType,Size_t] size_t +# 2784| getVariable().getInitializer(): [Initializer] initializer for y +# 2784| getExpr(): [SizeofExprOperator] sizeof() +# 2784| Type = [LongType] unsigned long +# 2784| ValueCategory = prvalue +# 2784| getExprOperand(): [VariableAccess] tmp2 +# 2784| Type = [ArrayType] int[][] +# 2784| ValueCategory = lvalue +# 2784| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) +# 2784| Type = [ArrayType] int[][] +# 2784| ValueCategory = lvalue +# 2785| getStmt(9): [DeclStmt] declaration +# 2785| getDeclarationEntry(0): [VariableDeclarationEntry] definition of z +# 2785| Type = [CTypedefType,Size_t] size_t +# 2785| getVariable().getInitializer(): [Initializer] initializer for z +# 2785| getExpr(): [SizeofExprOperator] sizeof() +# 2785| Type = [LongType] unsigned long +# 2785| ValueCategory = prvalue +# 2785| getExprOperand(): [PointerDereferenceExpr] * ... +# 2785| Type = [ArrayType] int[] +# 2785| ValueCategory = lvalue +# 2785| getOperand(): [VariableAccess] tmp2 +# 2785| Type = [ArrayType] int[][] +# 2785| ValueCategory = lvalue +# 2785| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2785| Type = [PointerType] int(*)[] +# 2785| ValueCategory = prvalue +# 2785| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) +# 2785| Type = [ArrayType] int[] +# 2785| ValueCategory = lvalue +# 2786| getStmt(10): [DeclStmt] declaration +# 2786| getDeclarationEntry(0): [VariableDeclarationEntry] definition of tmp3 +# 2786| Type = [ArrayType] int[][][] +# 2786| getStmt(11): [VlaDimensionStmt] VLA dimension size +# 2786| getDimensionExpr(): [VariableAccess] len1 +# 2786| Type = [IntType] int +# 2786| ValueCategory = prvalue(load) +# 2786| getStmt(12): [VlaDimensionStmt] VLA dimension size +# 2786| getDimensionExpr(): [VariableAccess] len2 +# 2786| Type = [CTypedefType,Size_t] size_t +# 2786| ValueCategory = prvalue(load) +# 2786| getStmt(13): [VlaDimensionStmt] VLA dimension size +# 2786| getDimensionExpr(): [VariableAccess] len3 +# 2786| Type = [PlainCharType] char +# 2786| ValueCategory = prvalue(load) +# 2786| getStmt(14): [VlaDeclStmt] VLA declaration +# 2787| getStmt(15): [DeclStmt] declaration +# 2787| getDeclarationEntry(0): [VariableDeclarationEntry] definition of w +# 2787| Type = [CTypedefType,Size_t] size_t +# 2787| getVariable().getInitializer(): [Initializer] initializer for w +# 2787| getExpr(): [SizeofExprOperator] sizeof() +# 2787| Type = [LongType] unsigned long +# 2787| ValueCategory = prvalue +# 2787| getExprOperand(): [VariableAccess] tmp3 +# 2787| Type = [ArrayType] int[][][] +# 2787| ValueCategory = lvalue +# 2787| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) +# 2787| Type = [ArrayType] int[][][] +# 2787| ValueCategory = lvalue +# 2788| getStmt(16): [DeclStmt] declaration +# 2788| getDeclarationEntry(0): [VariableDeclarationEntry] definition of v +# 2788| Type = [CTypedefType,Size_t] size_t +# 2788| getVariable().getInitializer(): [Initializer] initializer for v +# 2788| getExpr(): [SizeofExprOperator] sizeof() +# 2788| Type = [LongType] unsigned long +# 2788| ValueCategory = prvalue +# 2788| getExprOperand(): [PointerDereferenceExpr] * ... +# 2788| Type = [ArrayType] int[][] +# 2788| ValueCategory = lvalue +# 2788| getOperand(): [VariableAccess] tmp3 +# 2788| Type = [ArrayType] int[][][] +# 2788| ValueCategory = lvalue +# 2788| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2788| Type = [PointerType] int(*)[][] +# 2788| ValueCategory = prvalue +# 2788| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) +# 2788| Type = [ArrayType] int[][] +# 2788| ValueCategory = lvalue +# 2789| getStmt(17): [DeclStmt] declaration +# 2789| getDeclarationEntry(0): [VariableDeclarationEntry] definition of u +# 2789| Type = [CTypedefType,Size_t] size_t +# 2789| getVariable().getInitializer(): [Initializer] initializer for u +# 2789| getExpr(): [SizeofExprOperator] sizeof() +# 2789| Type = [LongType] unsigned long +# 2789| ValueCategory = prvalue +# 2789| getExprOperand(): [PointerDereferenceExpr] * ... +# 2789| Type = [ArrayType] int[] +# 2789| ValueCategory = lvalue +# 2789| getOperand(): [PointerDereferenceExpr] * ... +# 2789| Type = [ArrayType] int[][] +# 2789| ValueCategory = lvalue +# 2789| getOperand(): [VariableAccess] tmp3 +# 2789| Type = [ArrayType] int[][][] +# 2789| ValueCategory = lvalue +# 2789| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2789| Type = [PointerType] int(*)[][] +# 2789| ValueCategory = prvalue +# 2789| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2789| Type = [PointerType] int(*)[] +# 2789| ValueCategory = prvalue +# 2789| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) +# 2789| Type = [ArrayType] int[] +# 2789| ValueCategory = lvalue +# 2790| getStmt(18): [DeclStmt] declaration +# 2790| getDeclarationEntry(0): [VariableDeclarationEntry] definition of t +# 2790| Type = [CTypedefType,Size_t] size_t +# 2790| getVariable().getInitializer(): [Initializer] initializer for t +# 2790| getExpr(): [SizeofExprOperator] sizeof() +# 2790| Type = [LongType] unsigned long +# 2790| Value = [SizeofExprOperator] 4 +# 2790| ValueCategory = prvalue +# 2790| getExprOperand(): [PointerDereferenceExpr] * ... +# 2790| Type = [IntType] int +# 2790| ValueCategory = lvalue +# 2790| getOperand(): [PointerDereferenceExpr] * ... +# 2790| Type = [ArrayType] int[] +# 2790| ValueCategory = lvalue +# 2790| getOperand(): [PointerDereferenceExpr] * ... +# 2790| Type = [ArrayType] int[][] +# 2790| ValueCategory = lvalue +# 2790| getOperand(): [VariableAccess] tmp3 +# 2790| Type = [ArrayType] int[][][] +# 2790| ValueCategory = lvalue +# 2790| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2790| Type = [PointerType] int(*)[][] +# 2790| ValueCategory = prvalue +# 2790| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2790| Type = [PointerType] int(*)[] +# 2790| ValueCategory = prvalue +# 2790| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2790| Type = [IntPointerType] int * +# 2790| ValueCategory = prvalue +# 2790| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) +# 2790| Type = [IntType] int +# 2790| ValueCategory = lvalue +# 2791| getStmt(19): [ReturnStmt] return ... ir23.cpp: # 1| [TopLevelFunction] bool consteval_1() # 1| : 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 d8babdb54e20..bedfe5dd1c12 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected @@ -20430,6 +20430,25 @@ ir.cpp: # 2774| v2774_6(void) = AliasedUse : ~m2776_6 # 2774| v2774_7(void) = ExitFunction : +# 2779| void vla_sizeof_test(int, size_t, char) +# 2779| Block 0 +# 2779| v2779_1(void) = EnterFunction : +# 2779| m2779_2(unknown) = AliasedDefinition : +# 2779| m2779_3(unknown) = InitializeNonLocal : +# 2779| m2779_4(unknown) = Chi : total:m2779_2, partial:m2779_3 +# 2779| r2779_5(glval) = VariableAddress[len1] : +# 2779| m2779_6(int) = InitializeParameter[len1] : &:r2779_5 +# 2779| r2779_7(glval) = VariableAddress[len2] : +# 2779| m2779_8(unsigned long) = InitializeParameter[len2] : &:r2779_7 +# 2779| r2779_9(glval) = VariableAddress[len3] : +# 2779| m2779_10(char) = InitializeParameter[len3] : &:r2779_9 +# 2781| r2781_1(glval) = VariableAddress[tmp1] : +# 2781| m2781_2(char[]) = Uninitialized[tmp1] : &:r2781_1 +# 2781| r2781_3(glval) = VariableAddress[len1] : +# 2781| r2781_4(int) = Load[len1] : &:r2781_3, m2779_6 +# 2781| v2781_5(void) = NoOp : +# 2782| r2782_1(glval) = VariableAddress[x] : + ir23.cpp: # 1| bool consteval_1() # 1| Block 0 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 b83d9ea47e38..e748890d80d6 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,6 +6,7 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2782:10:2782:10 | VariableAddress: definition of x | Instruction 'VariableAddress: definition of x' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | 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 b83d9ea47e38..e748890d80d6 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,6 +6,7 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2782:10:2782:10 | VariableAddress: definition of x | Instruction 'VariableAddress: definition of x' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp index 66af788db12d..b4fb243ecdfc 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -2776,4 +2776,18 @@ void test_allocation_with_initializer() { long* p2 = new long(42); } +void vla_sizeof_test(int len1, size_t len2, char len3) +{ + char tmp1[len1]; + size_t x = sizeof(tmp1); + int tmp2[len1][len2]; + size_t y = sizeof(tmp2); + size_t z = sizeof(*tmp2); + int tmp3[len1][len2][len3]; + size_t w = sizeof(tmp3); + size_t v = sizeof(*tmp3); + size_t u = sizeof(**tmp3); + size_t t = sizeof(***tmp3); +} + // semmle-extractor-options: -std=c++20 --clang 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 e30106d35204..be7e3801c665 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected @@ -1,4 +1,10 @@ missingOperand +| ir.cpp:2782:14:2782:25 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2784:14:2784:25 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2785:14:2785:26 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2787:14:2787:25 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2788:14:2788:26 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2789:14:2789:27 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | unexpectedOperand duplicateOperand missingPhiOperand @@ -6,6 +12,18 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2782:10:2782:10 | VariableAddress: definition of x | Instruction 'VariableAddress: definition of x' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2782:21:2782:24 | VariableAddress: tmp1 | Instruction 'VariableAddress: tmp1' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2784:10:2784:10 | VariableAddress: definition of y | Instruction 'VariableAddress: definition of y' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2784:21:2784:24 | VariableAddress: tmp2 | Instruction 'VariableAddress: tmp2' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2785:10:2785:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2785:21:2785:25 | CopyValue: * ... | Instruction 'CopyValue: * ...' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2787:10:2787:10 | VariableAddress: definition of w | Instruction 'VariableAddress: definition of w' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2787:21:2787:24 | VariableAddress: tmp3 | Instruction 'VariableAddress: tmp3' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2788:10:2788:10 | VariableAddress: definition of v | Instruction 'VariableAddress: definition of v' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2788:21:2788:25 | CopyValue: * ... | Instruction 'CopyValue: * ...' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2789:10:2789:10 | VariableAddress: definition of u | Instruction 'VariableAddress: definition of u' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2789:21:2789:26 | CopyValue: * ... | Instruction 'CopyValue: * ...' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction @@ -21,6 +39,12 @@ 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() | +| ir.cpp:2782:10:2782:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2784:10:2784:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2785:10:2785:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2787:10:2787:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2788:10:2788:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | +| ir.cpp:2789:10:2789:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | 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 a567c651ca24..d7269265fa88 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -18577,6 +18577,96 @@ ir.cpp: # 2774| v2774_5(void) = AliasedUse : ~m? # 2774| v2774_6(void) = ExitFunction : +# 2779| void vla_sizeof_test(int, size_t, char) +# 2779| Block 0 +# 2779| v2779_1(void) = EnterFunction : +# 2779| mu2779_2(unknown) = AliasedDefinition : +# 2779| mu2779_3(unknown) = InitializeNonLocal : +# 2779| r2779_4(glval) = VariableAddress[len1] : +# 2779| mu2779_5(int) = InitializeParameter[len1] : &:r2779_4 +# 2779| r2779_6(glval) = VariableAddress[len2] : +# 2779| mu2779_7(unsigned long) = InitializeParameter[len2] : &:r2779_6 +# 2779| r2779_8(glval) = VariableAddress[len3] : +# 2779| mu2779_9(char) = InitializeParameter[len3] : &:r2779_8 +# 2781| r2781_1(glval) = VariableAddress[tmp1] : +# 2781| mu2781_2(char[]) = Uninitialized[tmp1] : &:r2781_1 +# 2781| r2781_3(glval) = VariableAddress[len1] : +# 2781| r2781_4(int) = Load[len1] : &:r2781_3, ~m? +# 2781| v2781_5(void) = NoOp : +# 2782| r2782_1(glval) = VariableAddress[x] : + +# 2782| Block 1 +# 2782| r2782_2(glval) = VariableAddress[tmp1] : + +# 2784| Block 1 +# 2784| r2784_1(glval) = VariableAddress[tmp2] : + +# 2787| Block 1 +# 2787| r2787_1(glval) = VariableAddress[tmp3] : + +# 2785| Block 4 +# 2785| r2785_1(glval) = VariableAddress[tmp2] : +# 2785| r2785_2(int(*)[]) = Convert : r2785_1 +# 2785| r2785_3(glval) = CopyValue : r2785_2 + +# 2788| Block 4 +# 2788| r2788_1(glval) = VariableAddress[tmp3] : +# 2788| r2788_2(int(*)[][]) = Convert : r2788_1 +# 2788| r2788_3(glval) = CopyValue : r2788_2 + +# 2789| Block 6 +# 2789| r2789_1(glval) = VariableAddress[tmp3] : +# 2789| r2789_2(int(*)[][]) = Convert : r2789_1 +# 2789| r2789_3(glval) = CopyValue : r2789_2 +# 2789| r2789_4(int(*)[]) = Convert : r2789_3 +# 2789| r2789_5(glval) = CopyValue : r2789_4 + +# 2782| Block 7 +# 2782| mu2782_3(unsigned long) = Store[x] : &:r2782_1 +# 2783| r2783_1(glval) = VariableAddress[tmp2] : +# 2783| mu2783_2(int[][]) = Uninitialized[tmp2] : &:r2783_1 +# 2783| r2783_3(glval) = VariableAddress[len1] : +# 2783| r2783_4(int) = Load[len1] : &:r2783_3, ~m? +# 2783| r2783_5(glval) = VariableAddress[len2] : +# 2783| r2783_6(unsigned long) = Load[len2] : &:r2783_5, ~m? +# 2783| v2783_7(void) = NoOp : +# 2784| r2784_2(glval) = VariableAddress[y] : + +# 2784| Block 8 +# 2784| mu2784_3(unsigned long) = Store[y] : &:r2784_2 +# 2785| r2785_4(glval) = VariableAddress[z] : + +# 2785| Block 9 +# 2785| mu2785_5(unsigned long) = Store[z] : &:r2785_4 +# 2786| r2786_1(glval) = VariableAddress[tmp3] : +# 2786| mu2786_2(int[][][]) = Uninitialized[tmp3] : &:r2786_1 +# 2786| r2786_3(glval) = VariableAddress[len1] : +# 2786| r2786_4(int) = Load[len1] : &:r2786_3, ~m? +# 2786| r2786_5(glval) = VariableAddress[len2] : +# 2786| r2786_6(unsigned long) = Load[len2] : &:r2786_5, ~m? +# 2786| r2786_7(glval) = VariableAddress[len3] : +# 2786| r2786_8(char) = Load[len3] : &:r2786_7, ~m? +# 2786| v2786_9(void) = NoOp : +# 2787| r2787_2(glval) = VariableAddress[w] : + +# 2787| Block 10 +# 2787| mu2787_3(unsigned long) = Store[w] : &:r2787_2 +# 2788| r2788_4(glval) = VariableAddress[v] : + +# 2788| Block 11 +# 2788| mu2788_5(unsigned long) = Store[v] : &:r2788_4 +# 2789| r2789_6(glval) = VariableAddress[u] : + +# 2789| Block 12 +# 2789| mu2789_7(unsigned long) = Store[u] : &:r2789_6 +# 2790| r2790_1(glval) = VariableAddress[t] : +# 2790| r2790_2(unsigned long) = Constant[4] : +# 2790| mu2790_3(unsigned long) = Store[t] : &:r2790_1, r2790_2 +# 2791| v2791_1(void) = NoOp : +# 2779| v2779_10(void) = ReturnVoid : +# 2779| v2779_11(void) = AliasedUse : ~m? +# 2779| v2779_12(void) = ExitFunction : + ir23.cpp: # 1| bool consteval_1() # 1| Block 0 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 b83d9ea47e38..e748890d80d6 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,6 +6,7 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2782:10:2782:10 | VariableAddress: definition of x | Instruction 'VariableAddress: definition of x' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | 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 b83d9ea47e38..e748890d80d6 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,6 +6,7 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2782:10:2782:10 | VariableAddress: definition of x | Instruction 'VariableAddress: definition of x' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction From d9320b3c16b08818e8a189bacaa1dee8cc3ae2ae Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Fri, 29 Aug 2025 17:51:51 +0200 Subject: [PATCH 02/16] C++: Support `sizeof` VLAs in the IR --- .../raw/internal/InstructionTag.qll | 7 +- .../raw/internal/TranslatedElement.qll | 7 +- .../raw/internal/TranslatedExpr.qll | 99 ++++++++++++++++++- 3 files changed, 109 insertions(+), 4 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll index d864e86aa040..da93976c4e26 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll @@ -97,7 +97,12 @@ newtype TInstructionTag = exists(Stmt s | exists(s.getImplicitDestructorCall(index))) } or CoAwaitBranchTag() or - BoolToIntConversionTag() + BoolToIntConversionTag() or + SizeofVlaDimensionTag(int index) { + index = -1 + or + exists(VlaDeclStmt v | exists(v.getVlaDimensionStmt(index))) + } class InstructionTag extends TInstructionTag { final string toString() { result = getInstructionTagId(this) } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index e1314035437e..330362f55603 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -123,13 +123,16 @@ private predicate ignoreExprAndDescendants(Expr expr) { // or ignoreExprAndDescendants(getRealParent(expr)) // recursive case or - // va_start doesn't evaluate its argument, so we don't need to translate it. + // va_start does not evaluate its argument, so we do not need to translate it. exists(BuiltInVarArgsStart vaStartExpr | vaStartExpr.getLastNamedParameter().getFullyConverted() = expr ) or + // sizeof does not evaluate its argument, so we do not need to translate it. + exists(SizeofExprOperator sizeofExpr | sizeofExpr.getExprOperand().getFullyConverted() = expr) + or // The children of C11 _Generic expressions are just surface syntax. - exists(C11GenericExpr generic | generic.getAChild() = expr) + exists(C11GenericExpr generic | generic.getAChild().getFullyConverted() = expr) or // Do not translate implicit destructor calls for unnamed temporary variables that are // conditionally constructed (until we have a mechanism for calling these only when the 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 f749f8b7502c..463f13f1aee7 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 @@ -187,7 +187,7 @@ Variable getEnclosingVariable(Expr e) { } /** - * The IR translation of the "core" part of an expression. This is the part of + * The IR translation of the "core" part of an expression. This is the part of * the expression that produces the result value of the expression, before any * lvalue-to-rvalue conversion on the result. Every expression has a single * `TranslatedCoreExpr`. @@ -4094,6 +4094,103 @@ class TranslatedStmtExpr extends TranslatedNonConstantExpr { TranslatedStmt getStmt() { result = getTranslatedStmt(expr.getStmt()) } } +private VlaDeclStmt getVlaDeclStmt(Expr expr, int pointerDerefCount) { + expr.(VariableAccess).getTarget() = result.getVariable() and + pointerDerefCount = 0 + or + result = getVlaDeclStmt(expr.(PointerDereferenceExpr).getOperand(), pointerDerefCount - 1) +} + +class TranslatedSizeofExpr extends TranslatedNonConstantExpr { + override SizeofExprOperator expr; + VlaDeclStmt vlaDeclStmt; + int pointerDerefCount; + + TranslatedSizeofExpr() { + vlaDeclStmt = getVlaDeclStmt(expr.getExprOperand(), pointerDerefCount) and + pointerDerefCount < vlaDeclStmt.getNumberOfVlaDimensionStmts() + } + + final override Instruction getFirstInstruction(EdgeKind kind) { + result = this.getInstruction(SizeofVlaDimensionTag(-1)) and + kind instanceof GotoEdge + } + + override Instruction getALastInstructionInternal() { + result = + this.getInstruction(SizeofVlaDimensionTag(vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1)) + } + + final override TranslatedElement getChildInternal(int id) { none() } + + final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { + opcode instanceof Opcode::Constant and + tag = SizeofVlaDimensionTag(-1) and + resultType = this.getResultType() + or + opcode instanceof Opcode::Mul and + exists(int n | pointerDerefCount <= n and n < vlaDeclStmt.getNumberOfVlaDimensionStmts() | + tag = SizeofVlaDimensionTag(n) + ) and + resultType = this.getResultType() + } + + final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) { + tag = SizeofVlaDimensionTag(-1) and + result = this.getInstruction(SizeofVlaDimensionTag(pointerDerefCount)) and + kind instanceof GotoEdge + or + exists(int n | pointerDerefCount <= n and n < vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1 | + tag = SizeofVlaDimensionTag(n) and + result = this.getInstruction(SizeofVlaDimensionTag(n + 1)) + ) and + kind instanceof GotoEdge + or + tag = SizeofVlaDimensionTag(vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1) and + result = this.getParent().getChildSuccessor(this, kind) + } + + override string getInstructionConstantValue(InstructionTag tag) { + tag = SizeofVlaDimensionTag(-1) and + result = + this.getBaseSize(vlaDeclStmt.getVariable().getType(), + vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1).toString() + } + + private int getBaseSize(DerivedType type, int n) { + n = 0 and + result = type.getBaseType().getSize() + or + n = [1 .. vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1] and + result = this.getBaseSize(type.getBaseType(), n - 1) + } + + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + exists(int n | pointerDerefCount <= n and n < vlaDeclStmt.getNumberOfVlaDimensionStmts() | + tag = SizeofVlaDimensionTag(n) and + ( + operandTag instanceof LeftOperandTag and + ( + n - 1 >= pointerDerefCount and + result = this.getInstruction(SizeofVlaDimensionTag(n - 1)) + or + n - 1 < pointerDerefCount and + result = this.getInstruction(SizeofVlaDimensionTag(-1)) + ) + or + operandTag instanceof RightOperandTag and + result = + getTranslatedExpr(vlaDeclStmt.getVlaDimensionStmt(n).getDimensionExpr()).getResult() + ) + ) + } + + final override Instruction getResult() { + result = + this.getInstruction(SizeofVlaDimensionTag(vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1)) + } +} + class TranslatedErrorExpr extends TranslatedSingleInstructionExpr { override ErrorExpr expr; From dc7833052964fbab41425a9e4148a1fc3393e448 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Fri, 29 Aug 2025 17:58:00 +0200 Subject: [PATCH 03/16] C++: Update expected test results --- .../library-tests/ir/ir/aliased_ir.expected | 50 +++++++ .../ir/ir/aliased_ssa_consistency.expected | 1 - .../aliased_ssa_consistency_unsound.expected | 1 - .../ir/ir/raw_consistency.expected | 24 ---- .../test/library-tests/ir/ir/raw_ir.expected | 122 +++++++----------- .../ir/ir/unaliased_ssa_consistency.expected | 1 - ...unaliased_ssa_consistency_unsound.expected | 1 - 7 files changed, 100 insertions(+), 100 deletions(-) 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 bedfe5dd1c12..a9896a1b3d8d 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected @@ -20448,6 +20448,56 @@ ir.cpp: # 2781| r2781_4(int) = Load[len1] : &:r2781_3, m2779_6 # 2781| v2781_5(void) = NoOp : # 2782| r2782_1(glval) = VariableAddress[x] : +# 2782| r2782_2(unsigned long) = Constant[1] : +# 2782| r2782_3(unsigned long) = Mul : r2782_2, r2781_4 +# 2782| m2782_4(unsigned long) = Store[x] : &:r2782_1, r2782_3 +# 2783| r2783_1(glval) = VariableAddress[tmp2] : +# 2783| m2783_2(int[][]) = Uninitialized[tmp2] : &:r2783_1 +# 2783| r2783_3(glval) = VariableAddress[len1] : +# 2783| r2783_4(int) = Load[len1] : &:r2783_3, m2779_6 +# 2783| r2783_5(glval) = VariableAddress[len2] : +# 2783| r2783_6(unsigned long) = Load[len2] : &:r2783_5, m2779_8 +# 2783| v2783_7(void) = NoOp : +# 2784| r2784_1(glval) = VariableAddress[y] : +# 2784| r2784_2(unsigned long) = Constant[4] : +# 2784| r2784_3(unsigned long) = Mul : r2784_2, r2783_4 +# 2784| r2784_4(unsigned long) = Mul : r2784_3, r2783_6 +# 2784| m2784_5(unsigned long) = Store[y] : &:r2784_1, r2784_4 +# 2785| r2785_1(glval) = VariableAddress[z] : +# 2785| r2785_2(unsigned long) = Constant[4] : +# 2785| r2785_3(unsigned long) = Mul : r2785_2, r2783_6 +# 2785| m2785_4(unsigned long) = Store[z] : &:r2785_1, r2785_3 +# 2786| r2786_1(glval) = VariableAddress[tmp3] : +# 2786| m2786_2(int[][][]) = Uninitialized[tmp3] : &:r2786_1 +# 2786| r2786_3(glval) = VariableAddress[len1] : +# 2786| r2786_4(int) = Load[len1] : &:r2786_3, m2779_6 +# 2786| r2786_5(glval) = VariableAddress[len2] : +# 2786| r2786_6(unsigned long) = Load[len2] : &:r2786_5, m2779_8 +# 2786| r2786_7(glval) = VariableAddress[len3] : +# 2786| r2786_8(char) = Load[len3] : &:r2786_7, m2779_10 +# 2786| v2786_9(void) = NoOp : +# 2787| r2787_1(glval) = VariableAddress[w] : +# 2787| r2787_2(unsigned long) = Constant[4] : +# 2787| r2787_3(unsigned long) = Mul : r2787_2, r2786_4 +# 2787| r2787_4(unsigned long) = Mul : r2787_3, r2786_6 +# 2787| r2787_5(unsigned long) = Mul : r2787_4, r2786_8 +# 2787| m2787_6(unsigned long) = Store[w] : &:r2787_1, r2787_5 +# 2788| r2788_1(glval) = VariableAddress[v] : +# 2788| r2788_2(unsigned long) = Constant[4] : +# 2788| r2788_3(unsigned long) = Mul : r2788_2, r2786_6 +# 2788| r2788_4(unsigned long) = Mul : r2788_3, r2786_8 +# 2788| m2788_5(unsigned long) = Store[v] : &:r2788_1, r2788_4 +# 2789| r2789_1(glval) = VariableAddress[u] : +# 2789| r2789_2(unsigned long) = Constant[4] : +# 2789| r2789_3(unsigned long) = Mul : r2789_2, r2786_8 +# 2789| m2789_4(unsigned long) = Store[u] : &:r2789_1, r2789_3 +# 2790| r2790_1(glval) = VariableAddress[t] : +# 2790| r2790_2(unsigned long) = Constant[4] : +# 2790| m2790_3(unsigned long) = Store[t] : &:r2790_1, r2790_2 +# 2791| v2791_1(void) = NoOp : +# 2779| v2779_11(void) = ReturnVoid : +# 2779| v2779_12(void) = AliasedUse : m2779_3 +# 2779| v2779_13(void) = ExitFunction : ir23.cpp: # 1| bool consteval_1() 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 e748890d80d6..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 -| ir.cpp:2782:10:2782:10 | VariableAddress: definition of x | Instruction 'VariableAddress: definition of x' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | 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 e748890d80d6..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 -| ir.cpp:2782:10:2782:10 | VariableAddress: definition of x | Instruction 'VariableAddress: definition of x' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | 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 be7e3801c665..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,10 +1,4 @@ missingOperand -| ir.cpp:2782:14:2782:25 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2784:14:2784:25 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2785:14:2785:26 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2787:14:2787:25 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2788:14:2788:26 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2789:14:2789:27 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | unexpectedOperand duplicateOperand missingPhiOperand @@ -12,18 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| ir.cpp:2782:10:2782:10 | VariableAddress: definition of x | Instruction 'VariableAddress: definition of x' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2782:21:2782:24 | VariableAddress: tmp1 | Instruction 'VariableAddress: tmp1' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2784:10:2784:10 | VariableAddress: definition of y | Instruction 'VariableAddress: definition of y' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2784:21:2784:24 | VariableAddress: tmp2 | Instruction 'VariableAddress: tmp2' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2785:10:2785:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2785:21:2785:25 | CopyValue: * ... | Instruction 'CopyValue: * ...' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2787:10:2787:10 | VariableAddress: definition of w | Instruction 'VariableAddress: definition of w' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2787:21:2787:24 | VariableAddress: tmp3 | Instruction 'VariableAddress: tmp3' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2788:10:2788:10 | VariableAddress: definition of v | Instruction 'VariableAddress: definition of v' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2788:21:2788:25 | CopyValue: * ... | Instruction 'CopyValue: * ...' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2789:10:2789:10 | VariableAddress: definition of u | Instruction 'VariableAddress: definition of u' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2789:21:2789:26 | CopyValue: * ... | Instruction 'CopyValue: * ...' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction @@ -39,12 +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() | -| ir.cpp:2782:10:2782:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2784:10:2784:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2785:10:2785:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2787:10:2787:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2788:10:2788:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | -| ir.cpp:2789:10:2789:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | 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 d7269265fa88..5b696e8460f6 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -18594,78 +18594,56 @@ ir.cpp: # 2781| r2781_4(int) = Load[len1] : &:r2781_3, ~m? # 2781| v2781_5(void) = NoOp : # 2782| r2782_1(glval) = VariableAddress[x] : - -# 2782| Block 1 -# 2782| r2782_2(glval) = VariableAddress[tmp1] : - -# 2784| Block 1 -# 2784| r2784_1(glval) = VariableAddress[tmp2] : - -# 2787| Block 1 -# 2787| r2787_1(glval) = VariableAddress[tmp3] : - -# 2785| Block 4 -# 2785| r2785_1(glval) = VariableAddress[tmp2] : -# 2785| r2785_2(int(*)[]) = Convert : r2785_1 -# 2785| r2785_3(glval) = CopyValue : r2785_2 - -# 2788| Block 4 -# 2788| r2788_1(glval) = VariableAddress[tmp3] : -# 2788| r2788_2(int(*)[][]) = Convert : r2788_1 -# 2788| r2788_3(glval) = CopyValue : r2788_2 - -# 2789| Block 6 -# 2789| r2789_1(glval) = VariableAddress[tmp3] : -# 2789| r2789_2(int(*)[][]) = Convert : r2789_1 -# 2789| r2789_3(glval) = CopyValue : r2789_2 -# 2789| r2789_4(int(*)[]) = Convert : r2789_3 -# 2789| r2789_5(glval) = CopyValue : r2789_4 - -# 2782| Block 7 -# 2782| mu2782_3(unsigned long) = Store[x] : &:r2782_1 -# 2783| r2783_1(glval) = VariableAddress[tmp2] : -# 2783| mu2783_2(int[][]) = Uninitialized[tmp2] : &:r2783_1 -# 2783| r2783_3(glval) = VariableAddress[len1] : -# 2783| r2783_4(int) = Load[len1] : &:r2783_3, ~m? -# 2783| r2783_5(glval) = VariableAddress[len2] : -# 2783| r2783_6(unsigned long) = Load[len2] : &:r2783_5, ~m? -# 2783| v2783_7(void) = NoOp : -# 2784| r2784_2(glval) = VariableAddress[y] : - -# 2784| Block 8 -# 2784| mu2784_3(unsigned long) = Store[y] : &:r2784_2 -# 2785| r2785_4(glval) = VariableAddress[z] : - -# 2785| Block 9 -# 2785| mu2785_5(unsigned long) = Store[z] : &:r2785_4 -# 2786| r2786_1(glval) = VariableAddress[tmp3] : -# 2786| mu2786_2(int[][][]) = Uninitialized[tmp3] : &:r2786_1 -# 2786| r2786_3(glval) = VariableAddress[len1] : -# 2786| r2786_4(int) = Load[len1] : &:r2786_3, ~m? -# 2786| r2786_5(glval) = VariableAddress[len2] : -# 2786| r2786_6(unsigned long) = Load[len2] : &:r2786_5, ~m? -# 2786| r2786_7(glval) = VariableAddress[len3] : -# 2786| r2786_8(char) = Load[len3] : &:r2786_7, ~m? -# 2786| v2786_9(void) = NoOp : -# 2787| r2787_2(glval) = VariableAddress[w] : - -# 2787| Block 10 -# 2787| mu2787_3(unsigned long) = Store[w] : &:r2787_2 -# 2788| r2788_4(glval) = VariableAddress[v] : - -# 2788| Block 11 -# 2788| mu2788_5(unsigned long) = Store[v] : &:r2788_4 -# 2789| r2789_6(glval) = VariableAddress[u] : - -# 2789| Block 12 -# 2789| mu2789_7(unsigned long) = Store[u] : &:r2789_6 -# 2790| r2790_1(glval) = VariableAddress[t] : -# 2790| r2790_2(unsigned long) = Constant[4] : -# 2790| mu2790_3(unsigned long) = Store[t] : &:r2790_1, r2790_2 -# 2791| v2791_1(void) = NoOp : -# 2779| v2779_10(void) = ReturnVoid : -# 2779| v2779_11(void) = AliasedUse : ~m? -# 2779| v2779_12(void) = ExitFunction : +# 2782| r2782_2(unsigned long) = Constant[1] : +# 2782| r2782_3(unsigned long) = Mul : r2782_2, r2781_4 +# 2782| mu2782_4(unsigned long) = Store[x] : &:r2782_1, r2782_3 +# 2783| r2783_1(glval) = VariableAddress[tmp2] : +# 2783| mu2783_2(int[][]) = Uninitialized[tmp2] : &:r2783_1 +# 2783| r2783_3(glval) = VariableAddress[len1] : +# 2783| r2783_4(int) = Load[len1] : &:r2783_3, ~m? +# 2783| r2783_5(glval) = VariableAddress[len2] : +# 2783| r2783_6(unsigned long) = Load[len2] : &:r2783_5, ~m? +# 2783| v2783_7(void) = NoOp : +# 2784| r2784_1(glval) = VariableAddress[y] : +# 2784| r2784_2(unsigned long) = Constant[4] : +# 2784| r2784_3(unsigned long) = Mul : r2784_2, r2783_4 +# 2784| r2784_4(unsigned long) = Mul : r2784_3, r2783_6 +# 2784| mu2784_5(unsigned long) = Store[y] : &:r2784_1, r2784_4 +# 2785| r2785_1(glval) = VariableAddress[z] : +# 2785| r2785_2(unsigned long) = Constant[4] : +# 2785| r2785_3(unsigned long) = Mul : r2785_2, r2783_6 +# 2785| mu2785_4(unsigned long) = Store[z] : &:r2785_1, r2785_3 +# 2786| r2786_1(glval) = VariableAddress[tmp3] : +# 2786| mu2786_2(int[][][]) = Uninitialized[tmp3] : &:r2786_1 +# 2786| r2786_3(glval) = VariableAddress[len1] : +# 2786| r2786_4(int) = Load[len1] : &:r2786_3, ~m? +# 2786| r2786_5(glval) = VariableAddress[len2] : +# 2786| r2786_6(unsigned long) = Load[len2] : &:r2786_5, ~m? +# 2786| r2786_7(glval) = VariableAddress[len3] : +# 2786| r2786_8(char) = Load[len3] : &:r2786_7, ~m? +# 2786| v2786_9(void) = NoOp : +# 2787| r2787_1(glval) = VariableAddress[w] : +# 2787| r2787_2(unsigned long) = Constant[4] : +# 2787| r2787_3(unsigned long) = Mul : r2787_2, r2786_4 +# 2787| r2787_4(unsigned long) = Mul : r2787_3, r2786_6 +# 2787| r2787_5(unsigned long) = Mul : r2787_4, r2786_8 +# 2787| mu2787_6(unsigned long) = Store[w] : &:r2787_1, r2787_5 +# 2788| r2788_1(glval) = VariableAddress[v] : +# 2788| r2788_2(unsigned long) = Constant[4] : +# 2788| r2788_3(unsigned long) = Mul : r2788_2, r2786_6 +# 2788| r2788_4(unsigned long) = Mul : r2788_3, r2786_8 +# 2788| mu2788_5(unsigned long) = Store[v] : &:r2788_1, r2788_4 +# 2789| r2789_1(glval) = VariableAddress[u] : +# 2789| r2789_2(unsigned long) = Constant[4] : +# 2789| r2789_3(unsigned long) = Mul : r2789_2, r2786_8 +# 2789| mu2789_4(unsigned long) = Store[u] : &:r2789_1, r2789_3 +# 2790| r2790_1(glval) = VariableAddress[t] : +# 2790| r2790_2(unsigned long) = Constant[4] : +# 2790| mu2790_3(unsigned long) = Store[t] : &:r2790_1, r2790_2 +# 2791| v2791_1(void) = NoOp : +# 2779| v2779_10(void) = ReturnVoid : +# 2779| v2779_11(void) = AliasedUse : ~m? +# 2779| v2779_12(void) = ExitFunction : ir23.cpp: # 1| bool consteval_1() 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 e748890d80d6..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 -| ir.cpp:2782:10:2782:10 | VariableAddress: definition of x | Instruction 'VariableAddress: definition of x' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | 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 e748890d80d6..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 -| ir.cpp:2782:10:2782:10 | VariableAddress: definition of x | Instruction 'VariableAddress: definition of x' has no successors in function '$@'. | ir.cpp:2779:6:2779:20 | void vla_sizeof_test(int, size_t, char) | void vla_sizeof_test(int, size_t, char) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction From 5bd08e817444b909b8b541d2f23a68e61f58beab Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 1 Sep 2025 10:59:17 +0200 Subject: [PATCH 04/16] C++: Add more `sizeof` VLA tests --- .../library-tests/ir/ir/PrintAST.expected | 491 +++++++++++++----- .../library-tests/ir/ir/aliased_ir.expected | 163 ++++-- .../ir/ir/aliased_ssa_consistency.expected | 2 + .../aliased_ssa_consistency_unsound.expected | 2 + cpp/ql/test/library-tests/ir/ir/ir.cpp | 25 +- .../ir/ir/raw_consistency.expected | 12 + .../test/library-tests/ir/ir/raw_ir.expected | 195 +++++-- .../ir/ir/unaliased_ssa_consistency.expected | 2 + ...unaliased_ssa_consistency_unsound.expected | 2 + 9 files changed, 666 insertions(+), 228 deletions(-) diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index b03bd3266044..34d231f8ebd4 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -24589,178 +24589,413 @@ ir.cpp: # 2779| Type = [CTypedefType,Size_t] size_t # 2779| getParameter(2): [Parameter] len3 # 2779| Type = [PlainCharType] char -# 2780| getEntryPoint(): [BlockStmt] { ... } -# 2781| getStmt(0): [DeclStmt] declaration -# 2781| getDeclarationEntry(0): [VariableDeclarationEntry] definition of tmp1 -# 2781| Type = [ArrayType] char[] -# 2781| getStmt(1): [VlaDimensionStmt] VLA dimension size -# 2781| getDimensionExpr(): [VariableAccess] len1 -# 2781| Type = [IntType] int -# 2781| ValueCategory = prvalue(load) -# 2781| getStmt(2): [VlaDeclStmt] VLA declaration -# 2782| getStmt(3): [DeclStmt] declaration -# 2782| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x +# 2779| getEntryPoint(): [BlockStmt] { ... } +# 2780| getStmt(0): [DeclStmt] declaration +# 2780| getDeclarationEntry(0): [VariableDeclarationEntry] definition of tmp1 +# 2780| Type = [ArrayType] char[] +# 2780| getStmt(1): [VlaDimensionStmt] VLA dimension size +# 2780| getDimensionExpr(): [VariableAccess] len1 +# 2780| Type = [IntType] int +# 2780| ValueCategory = prvalue(load) +# 2780| getStmt(2): [VlaDeclStmt] VLA declaration +# 2781| getStmt(3): [DeclStmt] declaration +# 2781| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x +# 2781| Type = [CTypedefType,Size_t] size_t +# 2781| getVariable().getInitializer(): [Initializer] initializer for x +# 2781| getExpr(): [SizeofExprOperator] sizeof() +# 2781| Type = [LongType] unsigned long +# 2781| ValueCategory = prvalue +# 2781| getExprOperand(): [VariableAccess] tmp1 +# 2781| Type = [ArrayType] char[] +# 2781| ValueCategory = lvalue +# 2781| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) +# 2781| Type = [ArrayType] char[] +# 2781| ValueCategory = lvalue +# 2782| getStmt(4): [DeclStmt] declaration +# 2782| getDeclarationEntry(0): [VariableDeclarationEntry] definition of tmp2 +# 2782| Type = [ArrayType] int[][] +# 2782| getStmt(5): [VlaDimensionStmt] VLA dimension size +# 2782| getDimensionExpr(): [VariableAccess] len1 +# 2782| Type = [IntType] int +# 2782| ValueCategory = prvalue(load) +# 2782| getStmt(6): [VlaDimensionStmt] VLA dimension size +# 2782| getDimensionExpr(): [VariableAccess] len2 # 2782| Type = [CTypedefType,Size_t] size_t -# 2782| getVariable().getInitializer(): [Initializer] initializer for x -# 2782| getExpr(): [SizeofExprOperator] sizeof() -# 2782| Type = [LongType] unsigned long -# 2782| ValueCategory = prvalue -# 2782| getExprOperand(): [VariableAccess] tmp1 -# 2782| Type = [ArrayType] char[] -# 2782| ValueCategory = lvalue -# 2782| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) -# 2782| Type = [ArrayType] char[] -# 2782| ValueCategory = lvalue -# 2783| getStmt(4): [DeclStmt] declaration -# 2783| getDeclarationEntry(0): [VariableDeclarationEntry] definition of tmp2 -# 2783| Type = [ArrayType] int[][] -# 2783| getStmt(5): [VlaDimensionStmt] VLA dimension size -# 2783| getDimensionExpr(): [VariableAccess] len1 -# 2783| Type = [IntType] int -# 2783| ValueCategory = prvalue(load) -# 2783| getStmt(6): [VlaDimensionStmt] VLA dimension size -# 2783| getDimensionExpr(): [VariableAccess] len2 +# 2782| ValueCategory = prvalue(load) +# 2782| getStmt(7): [VlaDeclStmt] VLA declaration +# 2783| getStmt(8): [DeclStmt] declaration +# 2783| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y # 2783| Type = [CTypedefType,Size_t] size_t -# 2783| ValueCategory = prvalue(load) -# 2783| getStmt(7): [VlaDeclStmt] VLA declaration -# 2784| getStmt(8): [DeclStmt] declaration -# 2784| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y +# 2783| getVariable().getInitializer(): [Initializer] initializer for y +# 2783| getExpr(): [SizeofExprOperator] sizeof() +# 2783| Type = [LongType] unsigned long +# 2783| ValueCategory = prvalue +# 2783| getExprOperand(): [VariableAccess] tmp2 +# 2783| Type = [ArrayType] int[][] +# 2783| ValueCategory = lvalue +# 2783| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) +# 2783| Type = [ArrayType] int[][] +# 2783| ValueCategory = lvalue +# 2784| getStmt(9): [DeclStmt] declaration +# 2784| getDeclarationEntry(0): [VariableDeclarationEntry] definition of z # 2784| Type = [CTypedefType,Size_t] size_t -# 2784| getVariable().getInitializer(): [Initializer] initializer for y +# 2784| getVariable().getInitializer(): [Initializer] initializer for z # 2784| getExpr(): [SizeofExprOperator] sizeof() # 2784| Type = [LongType] unsigned long # 2784| ValueCategory = prvalue -# 2784| getExprOperand(): [VariableAccess] tmp2 -# 2784| Type = [ArrayType] int[][] +# 2784| getExprOperand(): [PointerDereferenceExpr] * ... +# 2784| Type = [ArrayType] int[] # 2784| ValueCategory = lvalue +# 2784| getOperand(): [VariableAccess] tmp2 +# 2784| Type = [ArrayType] int[][] +# 2784| ValueCategory = lvalue +# 2784| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2784| Type = [PointerType] int(*)[] +# 2784| ValueCategory = prvalue # 2784| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) -# 2784| Type = [ArrayType] int[][] +# 2784| Type = [ArrayType] int[] # 2784| ValueCategory = lvalue -# 2785| getStmt(9): [DeclStmt] declaration -# 2785| getDeclarationEntry(0): [VariableDeclarationEntry] definition of z +# 2785| getStmt(10): [DeclStmt] declaration +# 2785| getDeclarationEntry(0): [VariableDeclarationEntry] definition of tmp3 +# 2785| Type = [ArrayType] int[][][] +# 2785| getStmt(11): [VlaDimensionStmt] VLA dimension size +# 2785| getDimensionExpr(): [VariableAccess] len1 +# 2785| Type = [IntType] int +# 2785| ValueCategory = prvalue(load) +# 2785| getStmt(12): [VlaDimensionStmt] VLA dimension size +# 2785| getDimensionExpr(): [VariableAccess] len2 # 2785| Type = [CTypedefType,Size_t] size_t -# 2785| getVariable().getInitializer(): [Initializer] initializer for z -# 2785| getExpr(): [SizeofExprOperator] sizeof() -# 2785| Type = [LongType] unsigned long -# 2785| ValueCategory = prvalue -# 2785| getExprOperand(): [PointerDereferenceExpr] * ... -# 2785| Type = [ArrayType] int[] -# 2785| ValueCategory = lvalue -# 2785| getOperand(): [VariableAccess] tmp2 -# 2785| Type = [ArrayType] int[][] -# 2785| ValueCategory = lvalue -# 2785| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion -# 2785| Type = [PointerType] int(*)[] -# 2785| ValueCategory = prvalue -# 2785| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) -# 2785| Type = [ArrayType] int[] -# 2785| ValueCategory = lvalue -# 2786| getStmt(10): [DeclStmt] declaration -# 2786| getDeclarationEntry(0): [VariableDeclarationEntry] definition of tmp3 -# 2786| Type = [ArrayType] int[][][] -# 2786| getStmt(11): [VlaDimensionStmt] VLA dimension size -# 2786| getDimensionExpr(): [VariableAccess] len1 -# 2786| Type = [IntType] int -# 2786| ValueCategory = prvalue(load) -# 2786| getStmt(12): [VlaDimensionStmt] VLA dimension size -# 2786| getDimensionExpr(): [VariableAccess] len2 +# 2785| ValueCategory = prvalue(load) +# 2785| getStmt(13): [VlaDimensionStmt] VLA dimension size +# 2785| getDimensionExpr(): [VariableAccess] len3 +# 2785| Type = [PlainCharType] char +# 2785| ValueCategory = prvalue(load) +# 2785| getStmt(14): [VlaDeclStmt] VLA declaration +# 2786| getStmt(15): [DeclStmt] declaration +# 2786| getDeclarationEntry(0): [VariableDeclarationEntry] definition of w # 2786| Type = [CTypedefType,Size_t] size_t -# 2786| ValueCategory = prvalue(load) -# 2786| getStmt(13): [VlaDimensionStmt] VLA dimension size -# 2786| getDimensionExpr(): [VariableAccess] len3 -# 2786| Type = [PlainCharType] char -# 2786| ValueCategory = prvalue(load) -# 2786| getStmt(14): [VlaDeclStmt] VLA declaration -# 2787| getStmt(15): [DeclStmt] declaration -# 2787| getDeclarationEntry(0): [VariableDeclarationEntry] definition of w +# 2786| getVariable().getInitializer(): [Initializer] initializer for w +# 2786| getExpr(): [SizeofExprOperator] sizeof() +# 2786| Type = [LongType] unsigned long +# 2786| ValueCategory = prvalue +# 2786| getExprOperand(): [VariableAccess] tmp3 +# 2786| Type = [ArrayType] int[][][] +# 2786| ValueCategory = lvalue +# 2786| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) +# 2786| Type = [ArrayType] int[][][] +# 2786| ValueCategory = lvalue +# 2787| getStmt(16): [DeclStmt] declaration +# 2787| getDeclarationEntry(0): [VariableDeclarationEntry] definition of v # 2787| Type = [CTypedefType,Size_t] size_t -# 2787| getVariable().getInitializer(): [Initializer] initializer for w +# 2787| getVariable().getInitializer(): [Initializer] initializer for v # 2787| getExpr(): [SizeofExprOperator] sizeof() # 2787| Type = [LongType] unsigned long # 2787| ValueCategory = prvalue -# 2787| getExprOperand(): [VariableAccess] tmp3 -# 2787| Type = [ArrayType] int[][][] +# 2787| getExprOperand(): [PointerDereferenceExpr] * ... +# 2787| Type = [ArrayType] int[][] # 2787| ValueCategory = lvalue +# 2787| getOperand(): [VariableAccess] tmp3 +# 2787| Type = [ArrayType] int[][][] +# 2787| ValueCategory = lvalue +# 2787| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2787| Type = [PointerType] int(*)[][] +# 2787| ValueCategory = prvalue # 2787| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) -# 2787| Type = [ArrayType] int[][][] +# 2787| Type = [ArrayType] int[][] # 2787| ValueCategory = lvalue -# 2788| getStmt(16): [DeclStmt] declaration -# 2788| getDeclarationEntry(0): [VariableDeclarationEntry] definition of v +# 2788| getStmt(17): [DeclStmt] declaration +# 2788| getDeclarationEntry(0): [VariableDeclarationEntry] definition of u # 2788| Type = [CTypedefType,Size_t] size_t -# 2788| getVariable().getInitializer(): [Initializer] initializer for v +# 2788| getVariable().getInitializer(): [Initializer] initializer for u # 2788| getExpr(): [SizeofExprOperator] sizeof() # 2788| Type = [LongType] unsigned long # 2788| ValueCategory = prvalue # 2788| getExprOperand(): [PointerDereferenceExpr] * ... -# 2788| Type = [ArrayType] int[][] +# 2788| Type = [ArrayType] int[] # 2788| ValueCategory = lvalue -# 2788| getOperand(): [VariableAccess] tmp3 -# 2788| Type = [ArrayType] int[][][] +# 2788| getOperand(): [PointerDereferenceExpr] * ... +# 2788| Type = [ArrayType] int[][] # 2788| ValueCategory = lvalue +# 2788| getOperand(): [VariableAccess] tmp3 +# 2788| Type = [ArrayType] int[][][] +# 2788| ValueCategory = lvalue +# 2788| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2788| Type = [PointerType] int(*)[][] +# 2788| ValueCategory = prvalue # 2788| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion -# 2788| Type = [PointerType] int(*)[][] +# 2788| Type = [PointerType] int(*)[] # 2788| ValueCategory = prvalue # 2788| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) -# 2788| Type = [ArrayType] int[][] +# 2788| Type = [ArrayType] int[] # 2788| ValueCategory = lvalue -# 2789| getStmt(17): [DeclStmt] declaration -# 2789| getDeclarationEntry(0): [VariableDeclarationEntry] definition of u +# 2789| getStmt(18): [DeclStmt] declaration +# 2789| getDeclarationEntry(0): [VariableDeclarationEntry] definition of t # 2789| Type = [CTypedefType,Size_t] size_t -# 2789| getVariable().getInitializer(): [Initializer] initializer for u +# 2789| getVariable().getInitializer(): [Initializer] initializer for t # 2789| getExpr(): [SizeofExprOperator] sizeof() # 2789| Type = [LongType] unsigned long +# 2789| Value = [SizeofExprOperator] 4 # 2789| ValueCategory = prvalue # 2789| getExprOperand(): [PointerDereferenceExpr] * ... -# 2789| Type = [ArrayType] int[] +# 2789| Type = [IntType] int # 2789| ValueCategory = lvalue # 2789| getOperand(): [PointerDereferenceExpr] * ... -# 2789| Type = [ArrayType] int[][] +# 2789| Type = [ArrayType] int[] # 2789| ValueCategory = lvalue -# 2789| getOperand(): [VariableAccess] tmp3 -# 2789| Type = [ArrayType] int[][][] +# 2789| getOperand(): [PointerDereferenceExpr] * ... +# 2789| Type = [ArrayType] int[][] # 2789| ValueCategory = lvalue +# 2789| getOperand(): [VariableAccess] tmp3 +# 2789| Type = [ArrayType] int[][][] +# 2789| ValueCategory = lvalue +# 2789| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2789| Type = [PointerType] int(*)[][] +# 2789| ValueCategory = prvalue # 2789| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion -# 2789| Type = [PointerType] int(*)[][] +# 2789| Type = [PointerType] int(*)[] # 2789| ValueCategory = prvalue # 2789| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion -# 2789| Type = [PointerType] int(*)[] +# 2789| Type = [IntPointerType] int * # 2789| ValueCategory = prvalue # 2789| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) -# 2789| Type = [ArrayType] int[] +# 2789| Type = [IntType] int # 2789| ValueCategory = lvalue -# 2790| getStmt(18): [DeclStmt] declaration -# 2790| getDeclarationEntry(0): [VariableDeclarationEntry] definition of t -# 2790| Type = [CTypedefType,Size_t] size_t -# 2790| getVariable().getInitializer(): [Initializer] initializer for t -# 2790| getExpr(): [SizeofExprOperator] sizeof() -# 2790| Type = [LongType] unsigned long -# 2790| Value = [SizeofExprOperator] 4 -# 2790| ValueCategory = prvalue -# 2790| getExprOperand(): [PointerDereferenceExpr] * ... -# 2790| Type = [IntType] int -# 2790| ValueCategory = lvalue -# 2790| getOperand(): [PointerDereferenceExpr] * ... -# 2790| Type = [ArrayType] int[] -# 2790| ValueCategory = lvalue -# 2790| getOperand(): [PointerDereferenceExpr] * ... -# 2790| Type = [ArrayType] int[][] -# 2790| ValueCategory = lvalue -# 2790| getOperand(): [VariableAccess] tmp3 -# 2790| Type = [ArrayType] int[][][] -# 2790| ValueCategory = lvalue -# 2790| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion -# 2790| Type = [PointerType] int(*)[][] -# 2790| ValueCategory = prvalue -# 2790| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion -# 2790| Type = [PointerType] int(*)[] -# 2790| ValueCategory = prvalue -# 2790| getOperand().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion -# 2790| Type = [IntPointerType] int * -# 2790| ValueCategory = prvalue -# 2790| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) -# 2790| Type = [IntType] int -# 2790| ValueCategory = lvalue -# 2791| getStmt(19): [ReturnStmt] return ... +# 2790| getStmt(19): [ReturnStmt] return ... +# 2792| [TopLevelFunction] void vla_sizeof_test2(int, size_t, char) +# 2792| : +# 2792| getParameter(0): [Parameter] len1 +# 2792| Type = [IntType] int +# 2792| getParameter(1): [Parameter] len2 +# 2792| Type = [CTypedefType,Size_t] size_t +# 2792| getParameter(2): [Parameter] len3 +# 2792| Type = [PlainCharType] char +# 2792| getEntryPoint(): [BlockStmt] { ... } +# 2793| getStmt(0): [DeclStmt] declaration +# 2793| getDeclarationEntry(0): [VariableDeclarationEntry] definition of tmp1 +# 2793| Type = [ArrayType] int[][] +# 2793| getStmt(1): [VlaDimensionStmt] VLA dimension size +# 2793| getDimensionExpr(): [VariableAccess] len1 +# 2793| Type = [IntType] int +# 2793| ValueCategory = prvalue(load) +# 2793| getStmt(2): [VlaDimensionStmt] VLA dimension size +# 2793| getDimensionExpr(): [VariableAccess] len2 +# 2793| Type = [CTypedefType,Size_t] size_t +# 2793| ValueCategory = prvalue(load) +# 2793| getStmt(3): [VlaDeclStmt] VLA declaration +# 2794| getStmt(4): [DeclStmt] declaration +# 2794| getDeclarationEntry(0): [VariableDeclarationEntry] definition of z +# 2794| Type = [CTypedefType,Size_t] size_t +# 2794| getVariable().getInitializer(): [Initializer] initializer for z +# 2794| getExpr(): [SizeofExprOperator] sizeof() +# 2794| Type = [LongType] unsigned long +# 2794| ValueCategory = prvalue +# 2794| getExprOperand(): [ArrayExpr] access to array +# 2794| Type = [ArrayType] int[] +# 2794| ValueCategory = lvalue +# 2794| getArrayBase(): [VariableAccess] tmp1 +# 2794| Type = [ArrayType] int[][] +# 2794| ValueCategory = lvalue +# 2794| getArrayOffset(): [Literal] 1 +# 2794| Type = [IntType] int +# 2794| Value = [Literal] 1 +# 2794| ValueCategory = prvalue +# 2794| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2794| Type = [PointerType] int(*)[] +# 2794| ValueCategory = prvalue +# 2794| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) +# 2794| Type = [ArrayType] int[] +# 2794| ValueCategory = lvalue +# 2795| getStmt(5): [DeclStmt] declaration +# 2795| getDeclarationEntry(0): [VariableDeclarationEntry] definition of tmp2 +# 2795| Type = [ArrayType] int[][][] +# 2795| getStmt(6): [VlaDimensionStmt] VLA dimension size +# 2795| getDimensionExpr(): [VariableAccess] len1 +# 2795| Type = [IntType] int +# 2795| ValueCategory = prvalue(load) +# 2795| getStmt(7): [VlaDimensionStmt] VLA dimension size +# 2795| getDimensionExpr(): [VariableAccess] len2 +# 2795| Type = [CTypedefType,Size_t] size_t +# 2795| ValueCategory = prvalue(load) +# 2795| getStmt(8): [VlaDimensionStmt] VLA dimension size +# 2795| getDimensionExpr(): [VariableAccess] len3 +# 2795| Type = [PlainCharType] char +# 2795| ValueCategory = prvalue(load) +# 2795| getStmt(9): [VlaDeclStmt] VLA declaration +# 2796| getStmt(10): [DeclStmt] declaration +# 2796| getDeclarationEntry(0): [VariableDeclarationEntry] definition of v +# 2796| Type = [CTypedefType,Size_t] size_t +# 2796| getVariable().getInitializer(): [Initializer] initializer for v +# 2796| getExpr(): [SizeofExprOperator] sizeof() +# 2796| Type = [LongType] unsigned long +# 2796| ValueCategory = prvalue +# 2796| getExprOperand(): [ArrayExpr] access to array +# 2796| Type = [ArrayType] int[][] +# 2796| ValueCategory = lvalue +# 2796| getArrayBase(): [VariableAccess] tmp2 +# 2796| Type = [ArrayType] int[][][] +# 2796| ValueCategory = lvalue +# 2796| getArrayOffset(): [Literal] 1 +# 2796| Type = [IntType] int +# 2796| Value = [Literal] 1 +# 2796| ValueCategory = prvalue +# 2796| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2796| Type = [PointerType] int(*)[][] +# 2796| ValueCategory = prvalue +# 2796| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) +# 2796| Type = [ArrayType] int[][] +# 2796| ValueCategory = lvalue +# 2797| getStmt(11): [DeclStmt] declaration +# 2797| getDeclarationEntry(0): [VariableDeclarationEntry] definition of u +# 2797| Type = [CTypedefType,Size_t] size_t +# 2797| getVariable().getInitializer(): [Initializer] initializer for u +# 2797| getExpr(): [SizeofExprOperator] sizeof() +# 2797| Type = [LongType] unsigned long +# 2797| ValueCategory = prvalue +# 2797| getExprOperand(): [ArrayExpr] access to array +# 2797| Type = [ArrayType] int[] +# 2797| ValueCategory = lvalue +# 2797| getArrayBase(): [ArrayExpr] access to array +# 2797| Type = [ArrayType] int[][] +# 2797| ValueCategory = lvalue +# 2797| getArrayBase(): [VariableAccess] tmp2 +# 2797| Type = [ArrayType] int[][][] +# 2797| ValueCategory = lvalue +# 2797| getArrayOffset(): [Literal] 1 +# 2797| Type = [IntType] int +# 2797| Value = [Literal] 1 +# 2797| ValueCategory = prvalue +# 2797| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2797| Type = [PointerType] int(*)[][] +# 2797| ValueCategory = prvalue +# 2797| getArrayOffset(): [Literal] 2 +# 2797| Type = [IntType] int +# 2797| Value = [Literal] 2 +# 2797| ValueCategory = prvalue +# 2797| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2797| Type = [PointerType] int(*)[] +# 2797| ValueCategory = prvalue +# 2797| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) +# 2797| Type = [ArrayType] int[] +# 2797| ValueCategory = lvalue +# 2798| getStmt(12): [DeclStmt] declaration +# 2798| getDeclarationEntry(0): [VariableDeclarationEntry] definition of t +# 2798| Type = [CTypedefType,Size_t] size_t +# 2798| getVariable().getInitializer(): [Initializer] initializer for t +# 2798| getExpr(): [SizeofExprOperator] sizeof() +# 2798| Type = [LongType] unsigned long +# 2798| Value = [SizeofExprOperator] 4 +# 2798| ValueCategory = prvalue +# 2798| getExprOperand(): [ArrayExpr] access to array +# 2798| Type = [IntType] int +# 2798| ValueCategory = lvalue +# 2798| getArrayBase(): [ArrayExpr] access to array +# 2798| Type = [ArrayType] int[] +# 2798| ValueCategory = lvalue +# 2798| getArrayBase(): [ArrayExpr] access to array +# 2798| Type = [ArrayType] int[][] +# 2798| ValueCategory = lvalue +# 2798| getArrayBase(): [VariableAccess] tmp2 +# 2798| Type = [ArrayType] int[][][] +# 2798| ValueCategory = lvalue +# 2798| getArrayOffset(): [Literal] 1 +# 2798| Type = [IntType] int +# 2798| Value = [Literal] 1 +# 2798| ValueCategory = prvalue +# 2798| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2798| Type = [PointerType] int(*)[][] +# 2798| ValueCategory = prvalue +# 2798| getArrayOffset(): [Literal] 2 +# 2798| Type = [IntType] int +# 2798| Value = [Literal] 2 +# 2798| ValueCategory = prvalue +# 2798| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2798| Type = [PointerType] int(*)[] +# 2798| ValueCategory = prvalue +# 2798| getArrayOffset(): [Literal] 3 +# 2798| Type = [IntType] int +# 2798| Value = [Literal] 3 +# 2798| ValueCategory = prvalue +# 2798| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2798| Type = [IntPointerType] int * +# 2798| ValueCategory = prvalue +# 2798| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) +# 2798| Type = [IntType] int +# 2798| ValueCategory = lvalue +# 2799| getStmt(13): [ReturnStmt] return ... +# 2801| [TopLevelFunction] size_t vla_sizeof_test3(int, size_t, char, bool) +# 2801| : +# 2801| getParameter(0): [Parameter] len1 +# 2801| Type = [IntType] int +# 2801| getParameter(1): [Parameter] len2 +# 2801| Type = [CTypedefType,Size_t] size_t +# 2801| getParameter(2): [Parameter] len3 +# 2801| Type = [PlainCharType] char +# 2801| getParameter(3): [Parameter] b +# 2801| Type = [BoolType] bool +# 2801| getEntryPoint(): [BlockStmt] { ... } +# 2802| getStmt(0): [DeclStmt] declaration +# 2802| getDeclarationEntry(0): [TypeDeclarationEntry] declaration of arr +# 2802| Type = [CTypedefType,LocalTypedefType] arr +# 2802| getStmt(1): [VlaDimensionStmt] VLA dimension size +# 2802| getDimensionExpr(): [VariableAccess] len1 +# 2802| Type = [IntType] int +# 2802| ValueCategory = prvalue(load) +# 2802| getStmt(2): [VlaDimensionStmt] VLA dimension size +# 2802| getDimensionExpr(): [VariableAccess] len2 +# 2802| Type = [CTypedefType,Size_t] size_t +# 2802| ValueCategory = prvalue(load) +# 2802| getStmt(3): [VlaDeclStmt] VLA declaration +# 2803| getStmt(4): [DeclStmt] declaration +# 2803| getDeclarationEntry(0): [TypeDeclarationEntry] declaration of arr2 +# 2803| Type = [CTypedefType,LocalTypedefType] arr2 +# 2803| getStmt(5): [VlaDeclStmt] VLA declaration +# 2804| getStmt(6): [DeclStmt] declaration +# 2804| getDeclarationEntry(0): [TypeDeclarationEntry] declaration of arr3 +# 2804| Type = [CTypedefType,LocalTypedefType] arr3 +# 2804| getStmt(7): [VlaDimensionStmt] VLA dimension size +# 2804| getDimensionExpr(): [VariableAccess] len3 +# 2804| Type = [PlainCharType] char +# 2804| ValueCategory = prvalue(load) +# 2804| getStmt(8): [VlaDeclStmt] VLA declaration +# 2806| getStmt(9): [IfStmt] if (...) ... +# 2806| getCondition(): [VariableAccess] b +# 2806| Type = [BoolType] bool +# 2806| ValueCategory = prvalue(load) +# 2806| getThen(): [BlockStmt] { ... } +# 2807| getStmt(0): [DeclStmt] declaration +# 2807| getDeclarationEntry(0): [VariableDeclarationEntry] definition of tmp +# 2807| Type = [CTypedefType,LocalTypedefType] arr3 +# 2807| getStmt(1): [VlaDeclStmt] VLA declaration +# 2808| getStmt(2): [ReturnStmt] return ... +# 2808| getExpr(): [SizeofExprOperator] sizeof() +# 2808| Type = [LongType] unsigned long +# 2808| ValueCategory = prvalue +# 2808| getExprOperand(): [ArrayExpr] access to array +# 2808| Type = [CTypedefType,LocalTypedefType] arr2 +# 2808| ValueCategory = lvalue +# 2808| getArrayBase(): [VariableAccess] tmp +# 2808| Type = [CTypedefType,LocalTypedefType] arr3 +# 2808| ValueCategory = lvalue +# 2808| getArrayOffset(): [Literal] 1 +# 2808| Type = [IntType] int +# 2808| Value = [Literal] 1 +# 2808| ValueCategory = prvalue +# 2808| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2808| Type = [PointerType] arr2 * +# 2808| ValueCategory = prvalue +# 2808| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) +# 2808| Type = [CTypedefType,LocalTypedefType] arr2 +# 2808| ValueCategory = lvalue +# 2811| getStmt(10): [ReturnStmt] return ... +# 2811| getExpr(): [Literal] 0 +# 2811| Type = [IntType] int +# 2811| Value = [Literal] 0 +# 2811| ValueCategory = prvalue +# 2811| getExpr().getFullyConverted(): [CStyleCast] (size_t)... +# 2811| Conversion = [IntegralConversion] integral conversion +# 2811| Type = [CTypedefType,Size_t] size_t +# 2811| Value = [CStyleCast] 0 +# 2811| ValueCategory = prvalue ir23.cpp: # 1| [TopLevelFunction] bool consteval_1() # 1| : 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 a9896a1b3d8d..218df42da10f 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected @@ -20442,63 +20442,128 @@ ir.cpp: # 2779| m2779_8(unsigned long) = InitializeParameter[len2] : &:r2779_7 # 2779| r2779_9(glval) = VariableAddress[len3] : # 2779| m2779_10(char) = InitializeParameter[len3] : &:r2779_9 -# 2781| r2781_1(glval) = VariableAddress[tmp1] : -# 2781| m2781_2(char[]) = Uninitialized[tmp1] : &:r2781_1 -# 2781| r2781_3(glval) = VariableAddress[len1] : -# 2781| r2781_4(int) = Load[len1] : &:r2781_3, m2779_6 -# 2781| v2781_5(void) = NoOp : -# 2782| r2782_1(glval) = VariableAddress[x] : -# 2782| r2782_2(unsigned long) = Constant[1] : -# 2782| r2782_3(unsigned long) = Mul : r2782_2, r2781_4 -# 2782| m2782_4(unsigned long) = Store[x] : &:r2782_1, r2782_3 -# 2783| r2783_1(glval) = VariableAddress[tmp2] : -# 2783| m2783_2(int[][]) = Uninitialized[tmp2] : &:r2783_1 -# 2783| r2783_3(glval) = VariableAddress[len1] : -# 2783| r2783_4(int) = Load[len1] : &:r2783_3, m2779_6 -# 2783| r2783_5(glval) = VariableAddress[len2] : -# 2783| r2783_6(unsigned long) = Load[len2] : &:r2783_5, m2779_8 -# 2783| v2783_7(void) = NoOp : -# 2784| r2784_1(glval) = VariableAddress[y] : +# 2780| r2780_1(glval) = VariableAddress[tmp1] : +# 2780| m2780_2(char[]) = Uninitialized[tmp1] : &:r2780_1 +# 2780| r2780_3(glval) = VariableAddress[len1] : +# 2780| r2780_4(int) = Load[len1] : &:r2780_3, m2779_6 +# 2780| v2780_5(void) = NoOp : +# 2781| r2781_1(glval) = VariableAddress[x] : +# 2781| r2781_2(unsigned long) = Constant[1] : +# 2781| r2781_3(unsigned long) = Mul : r2781_2, r2780_4 +# 2781| m2781_4(unsigned long) = Store[x] : &:r2781_1, r2781_3 +# 2782| r2782_1(glval) = VariableAddress[tmp2] : +# 2782| m2782_2(int[][]) = Uninitialized[tmp2] : &:r2782_1 +# 2782| r2782_3(glval) = VariableAddress[len1] : +# 2782| r2782_4(int) = Load[len1] : &:r2782_3, m2779_6 +# 2782| r2782_5(glval) = VariableAddress[len2] : +# 2782| r2782_6(unsigned long) = Load[len2] : &:r2782_5, m2779_8 +# 2782| v2782_7(void) = NoOp : +# 2783| r2783_1(glval) = VariableAddress[y] : +# 2783| r2783_2(unsigned long) = Constant[4] : +# 2783| r2783_3(unsigned long) = Mul : r2783_2, r2782_4 +# 2783| r2783_4(unsigned long) = Mul : r2783_3, r2782_6 +# 2783| m2783_5(unsigned long) = Store[y] : &:r2783_1, r2783_4 +# 2784| r2784_1(glval) = VariableAddress[z] : # 2784| r2784_2(unsigned long) = Constant[4] : -# 2784| r2784_3(unsigned long) = Mul : r2784_2, r2783_4 -# 2784| r2784_4(unsigned long) = Mul : r2784_3, r2783_6 -# 2784| m2784_5(unsigned long) = Store[y] : &:r2784_1, r2784_4 -# 2785| r2785_1(glval) = VariableAddress[z] : -# 2785| r2785_2(unsigned long) = Constant[4] : -# 2785| r2785_3(unsigned long) = Mul : r2785_2, r2783_6 -# 2785| m2785_4(unsigned long) = Store[z] : &:r2785_1, r2785_3 -# 2786| r2786_1(glval) = VariableAddress[tmp3] : -# 2786| m2786_2(int[][][]) = Uninitialized[tmp3] : &:r2786_1 -# 2786| r2786_3(glval) = VariableAddress[len1] : -# 2786| r2786_4(int) = Load[len1] : &:r2786_3, m2779_6 -# 2786| r2786_5(glval) = VariableAddress[len2] : -# 2786| r2786_6(unsigned long) = Load[len2] : &:r2786_5, m2779_8 -# 2786| r2786_7(glval) = VariableAddress[len3] : -# 2786| r2786_8(char) = Load[len3] : &:r2786_7, m2779_10 -# 2786| v2786_9(void) = NoOp : -# 2787| r2787_1(glval) = VariableAddress[w] : +# 2784| r2784_3(unsigned long) = Mul : r2784_2, r2782_6 +# 2784| m2784_4(unsigned long) = Store[z] : &:r2784_1, r2784_3 +# 2785| r2785_1(glval) = VariableAddress[tmp3] : +# 2785| m2785_2(int[][][]) = Uninitialized[tmp3] : &:r2785_1 +# 2785| r2785_3(glval) = VariableAddress[len1] : +# 2785| r2785_4(int) = Load[len1] : &:r2785_3, m2779_6 +# 2785| r2785_5(glval) = VariableAddress[len2] : +# 2785| r2785_6(unsigned long) = Load[len2] : &:r2785_5, m2779_8 +# 2785| r2785_7(glval) = VariableAddress[len3] : +# 2785| r2785_8(char) = Load[len3] : &:r2785_7, m2779_10 +# 2785| v2785_9(void) = NoOp : +# 2786| r2786_1(glval) = VariableAddress[w] : +# 2786| r2786_2(unsigned long) = Constant[4] : +# 2786| r2786_3(unsigned long) = Mul : r2786_2, r2785_4 +# 2786| r2786_4(unsigned long) = Mul : r2786_3, r2785_6 +# 2786| r2786_5(unsigned long) = Mul : r2786_4, r2785_8 +# 2786| m2786_6(unsigned long) = Store[w] : &:r2786_1, r2786_5 +# 2787| r2787_1(glval) = VariableAddress[v] : # 2787| r2787_2(unsigned long) = Constant[4] : -# 2787| r2787_3(unsigned long) = Mul : r2787_2, r2786_4 -# 2787| r2787_4(unsigned long) = Mul : r2787_3, r2786_6 -# 2787| r2787_5(unsigned long) = Mul : r2787_4, r2786_8 -# 2787| m2787_6(unsigned long) = Store[w] : &:r2787_1, r2787_5 -# 2788| r2788_1(glval) = VariableAddress[v] : +# 2787| r2787_3(unsigned long) = Mul : r2787_2, r2785_6 +# 2787| r2787_4(unsigned long) = Mul : r2787_3, r2785_8 +# 2787| m2787_5(unsigned long) = Store[v] : &:r2787_1, r2787_4 +# 2788| r2788_1(glval) = VariableAddress[u] : # 2788| r2788_2(unsigned long) = Constant[4] : -# 2788| r2788_3(unsigned long) = Mul : r2788_2, r2786_6 -# 2788| r2788_4(unsigned long) = Mul : r2788_3, r2786_8 -# 2788| m2788_5(unsigned long) = Store[v] : &:r2788_1, r2788_4 -# 2789| r2789_1(glval) = VariableAddress[u] : +# 2788| r2788_3(unsigned long) = Mul : r2788_2, r2785_8 +# 2788| m2788_4(unsigned long) = Store[u] : &:r2788_1, r2788_3 +# 2789| r2789_1(glval) = VariableAddress[t] : # 2789| r2789_2(unsigned long) = Constant[4] : -# 2789| r2789_3(unsigned long) = Mul : r2789_2, r2786_8 -# 2789| m2789_4(unsigned long) = Store[u] : &:r2789_1, r2789_3 -# 2790| r2790_1(glval) = VariableAddress[t] : -# 2790| r2790_2(unsigned long) = Constant[4] : -# 2790| m2790_3(unsigned long) = Store[t] : &:r2790_1, r2790_2 -# 2791| v2791_1(void) = NoOp : +# 2789| m2789_3(unsigned long) = Store[t] : &:r2789_1, r2789_2 +# 2790| v2790_1(void) = NoOp : # 2779| v2779_11(void) = ReturnVoid : # 2779| v2779_12(void) = AliasedUse : m2779_3 # 2779| v2779_13(void) = ExitFunction : +# 2792| void vla_sizeof_test2(int, size_t, char) +# 2792| Block 0 +# 2792| v2792_1(void) = EnterFunction : +# 2792| m2792_2(unknown) = AliasedDefinition : +# 2792| m2792_3(unknown) = InitializeNonLocal : +# 2792| m2792_4(unknown) = Chi : total:m2792_2, partial:m2792_3 +# 2792| r2792_5(glval) = VariableAddress[len1] : +# 2792| m2792_6(int) = InitializeParameter[len1] : &:r2792_5 +# 2792| r2792_7(glval) = VariableAddress[len2] : +# 2792| m2792_8(unsigned long) = InitializeParameter[len2] : &:r2792_7 +# 2792| r2792_9(glval) = VariableAddress[len3] : +# 2792| m2792_10(char) = InitializeParameter[len3] : &:r2792_9 +# 2793| r2793_1(glval) = VariableAddress[tmp1] : +# 2793| m2793_2(int[][]) = Uninitialized[tmp1] : &:r2793_1 +# 2793| r2793_3(glval) = VariableAddress[len1] : +# 2793| r2793_4(int) = Load[len1] : &:r2793_3, m2792_6 +# 2793| r2793_5(glval) = VariableAddress[len2] : +# 2793| r2793_6(unsigned long) = Load[len2] : &:r2793_5, m2792_8 +# 2793| v2793_7(void) = NoOp : +# 2794| r2794_1(glval) = VariableAddress[z] : + +# 2801| size_t vla_sizeof_test3(int, size_t, char, bool) +# 2801| Block 0 +# 2801| v2801_1(void) = EnterFunction : +# 2801| m2801_2(unknown) = AliasedDefinition : +# 2801| m2801_3(unknown) = InitializeNonLocal : +# 2801| m2801_4(unknown) = Chi : total:m2801_2, partial:m2801_3 +# 2801| r2801_5(glval) = VariableAddress[len1] : +# 2801| m2801_6(int) = InitializeParameter[len1] : &:r2801_5 +# 2801| r2801_7(glval) = VariableAddress[len2] : +# 2801| m2801_8(unsigned long) = InitializeParameter[len2] : &:r2801_7 +# 2801| r2801_9(glval) = VariableAddress[len3] : +# 2801| m2801_10(char) = InitializeParameter[len3] : &:r2801_9 +# 2801| r2801_11(glval) = VariableAddress[b] : +# 2801| m2801_12(bool) = InitializeParameter[b] : &:r2801_11 +# 2802| r2802_1(glval) = VariableAddress[len1] : +# 2802| r2802_2(int) = Load[len1] : &:r2802_1, m2801_6 +# 2802| r2802_3(glval) = VariableAddress[len2] : +# 2802| r2802_4(unsigned long) = Load[len2] : &:r2802_3, m2801_8 +# 2802| v2802_5(void) = NoOp : +# 2803| v2803_1(void) = NoOp : +# 2804| r2804_1(glval) = VariableAddress[len3] : +# 2804| r2804_2(char) = Load[len3] : &:r2804_1, m2801_10 +# 2804| v2804_3(void) = NoOp : +# 2806| r2806_1(glval) = VariableAddress[b] : +# 2806| r2806_2(bool) = Load[b] : &:r2806_1, m2801_12 +# 2806| v2806_3(void) = ConditionalBranch : r2806_2 +#-----| False -> Block 2 +#-----| True -> Block 1 + +# 2807| Block 1 +# 2807| r2807_1(glval) = VariableAddress[tmp] : +# 2807| m2807_2(long[][][]) = Uninitialized[tmp] : &:r2807_1 +# 2807| v2807_3(void) = NoOp : +# 2808| r2808_1(glval) = VariableAddress[#return] : + +# 2811| Block 2 +# 2811| r2811_1(glval) = VariableAddress[#return] : +# 2811| r2811_2(unsigned long) = Constant[0] : +# 2811| m2811_3(unsigned long) = Store[#return] : &:r2811_1, r2811_2 +# 2801| r2801_13(glval) = VariableAddress[#return] : +# 2801| v2801_14(void) = ReturnValue : &:r2801_13, m2811_3 +# 2801| v2801_15(void) = AliasedUse : m2801_3 +# 2801| v2801_16(void) = ExitFunction : + ir23.cpp: # 1| bool consteval_1() # 1| Block 0 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 b83d9ea47e38..12feac2ecd25 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,6 +6,8 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2794:10:2794:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | +| ir.cpp:2808:5:2808:26 | VariableAddress: return ... | Instruction 'VariableAddress: return ...' has no successors in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | 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 b83d9ea47e38..12feac2ecd25 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,6 +6,8 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2794:10:2794:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | +| ir.cpp:2808:5:2808:26 | VariableAddress: return ... | Instruction 'VariableAddress: return ...' has no successors in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp index b4fb243ecdfc..be0e1904374c 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -2776,8 +2776,7 @@ void test_allocation_with_initializer() { long* p2 = new long(42); } -void vla_sizeof_test(int len1, size_t len2, char len3) -{ +void vla_sizeof_test(int len1, size_t len2, char len3) { char tmp1[len1]; size_t x = sizeof(tmp1); int tmp2[len1][len2]; @@ -2790,4 +2789,26 @@ void vla_sizeof_test(int len1, size_t len2, char len3) size_t t = sizeof(***tmp3); } +void vla_sizeof_test2(int len1, size_t len2, char len3) { + int tmp1[len1][len2]; + size_t z = sizeof(tmp1[1]); + int tmp2[len1][len2][len3]; + size_t v = sizeof(tmp2[1]); + size_t u = sizeof(tmp2[1][2]); + size_t t = sizeof(tmp2[1][2][3]); +} + +size_t vla_sizeof_test3(int len1, size_t len2, char len3, bool b) { + typedef long arr[len1][len2]; + typedef arr arr2; + typedef arr2 arr3[len3]; + + if (b) { + arr3 tmp; + return sizeof(tmp[1]); + } + + return 0; +} + // semmle-extractor-options: -std=c++20 --clang 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 e30106d35204..e47bac20c76f 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected @@ -1,4 +1,8 @@ missingOperand +| ir.cpp:2794:14:2794:28 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | +| ir.cpp:2796:14:2796:28 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | +| ir.cpp:2797:14:2797:31 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | +| ir.cpp:2808:12:2808:25 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | unexpectedOperand duplicateOperand missingPhiOperand @@ -6,6 +10,10 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2794:10:2794:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | +| ir.cpp:2796:10:2796:10 | VariableAddress: definition of v | Instruction 'VariableAddress: definition of v' has no successors in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | +| ir.cpp:2797:10:2797:10 | VariableAddress: definition of u | Instruction 'VariableAddress: definition of u' has no successors in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | +| ir.cpp:2808:5:2808:26 | VariableAddress: return ... | Instruction 'VariableAddress: return ...' has no successors in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction @@ -21,6 +29,10 @@ 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() | +| ir.cpp:2794:10:2794:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | +| ir.cpp:2796:10:2796:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | +| ir.cpp:2797:10:2797:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | +| ir.cpp:2808:5:2808:26 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | 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 5b696e8460f6..e312083ab559 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -18588,63 +18588,160 @@ ir.cpp: # 2779| mu2779_7(unsigned long) = InitializeParameter[len2] : &:r2779_6 # 2779| r2779_8(glval) = VariableAddress[len3] : # 2779| mu2779_9(char) = InitializeParameter[len3] : &:r2779_8 -# 2781| r2781_1(glval) = VariableAddress[tmp1] : -# 2781| mu2781_2(char[]) = Uninitialized[tmp1] : &:r2781_1 -# 2781| r2781_3(glval) = VariableAddress[len1] : -# 2781| r2781_4(int) = Load[len1] : &:r2781_3, ~m? -# 2781| v2781_5(void) = NoOp : -# 2782| r2782_1(glval) = VariableAddress[x] : -# 2782| r2782_2(unsigned long) = Constant[1] : -# 2782| r2782_3(unsigned long) = Mul : r2782_2, r2781_4 -# 2782| mu2782_4(unsigned long) = Store[x] : &:r2782_1, r2782_3 -# 2783| r2783_1(glval) = VariableAddress[tmp2] : -# 2783| mu2783_2(int[][]) = Uninitialized[tmp2] : &:r2783_1 -# 2783| r2783_3(glval) = VariableAddress[len1] : -# 2783| r2783_4(int) = Load[len1] : &:r2783_3, ~m? -# 2783| r2783_5(glval) = VariableAddress[len2] : -# 2783| r2783_6(unsigned long) = Load[len2] : &:r2783_5, ~m? -# 2783| v2783_7(void) = NoOp : -# 2784| r2784_1(glval) = VariableAddress[y] : +# 2780| r2780_1(glval) = VariableAddress[tmp1] : +# 2780| mu2780_2(char[]) = Uninitialized[tmp1] : &:r2780_1 +# 2780| r2780_3(glval) = VariableAddress[len1] : +# 2780| r2780_4(int) = Load[len1] : &:r2780_3, ~m? +# 2780| v2780_5(void) = NoOp : +# 2781| r2781_1(glval) = VariableAddress[x] : +# 2781| r2781_2(unsigned long) = Constant[1] : +# 2781| r2781_3(unsigned long) = Mul : r2781_2, r2780_4 +# 2781| mu2781_4(unsigned long) = Store[x] : &:r2781_1, r2781_3 +# 2782| r2782_1(glval) = VariableAddress[tmp2] : +# 2782| mu2782_2(int[][]) = Uninitialized[tmp2] : &:r2782_1 +# 2782| r2782_3(glval) = VariableAddress[len1] : +# 2782| r2782_4(int) = Load[len1] : &:r2782_3, ~m? +# 2782| r2782_5(glval) = VariableAddress[len2] : +# 2782| r2782_6(unsigned long) = Load[len2] : &:r2782_5, ~m? +# 2782| v2782_7(void) = NoOp : +# 2783| r2783_1(glval) = VariableAddress[y] : +# 2783| r2783_2(unsigned long) = Constant[4] : +# 2783| r2783_3(unsigned long) = Mul : r2783_2, r2782_4 +# 2783| r2783_4(unsigned long) = Mul : r2783_3, r2782_6 +# 2783| mu2783_5(unsigned long) = Store[y] : &:r2783_1, r2783_4 +# 2784| r2784_1(glval) = VariableAddress[z] : # 2784| r2784_2(unsigned long) = Constant[4] : -# 2784| r2784_3(unsigned long) = Mul : r2784_2, r2783_4 -# 2784| r2784_4(unsigned long) = Mul : r2784_3, r2783_6 -# 2784| mu2784_5(unsigned long) = Store[y] : &:r2784_1, r2784_4 -# 2785| r2785_1(glval) = VariableAddress[z] : -# 2785| r2785_2(unsigned long) = Constant[4] : -# 2785| r2785_3(unsigned long) = Mul : r2785_2, r2783_6 -# 2785| mu2785_4(unsigned long) = Store[z] : &:r2785_1, r2785_3 -# 2786| r2786_1(glval) = VariableAddress[tmp3] : -# 2786| mu2786_2(int[][][]) = Uninitialized[tmp3] : &:r2786_1 -# 2786| r2786_3(glval) = VariableAddress[len1] : -# 2786| r2786_4(int) = Load[len1] : &:r2786_3, ~m? -# 2786| r2786_5(glval) = VariableAddress[len2] : -# 2786| r2786_6(unsigned long) = Load[len2] : &:r2786_5, ~m? -# 2786| r2786_7(glval) = VariableAddress[len3] : -# 2786| r2786_8(char) = Load[len3] : &:r2786_7, ~m? -# 2786| v2786_9(void) = NoOp : -# 2787| r2787_1(glval) = VariableAddress[w] : +# 2784| r2784_3(unsigned long) = Mul : r2784_2, r2782_6 +# 2784| mu2784_4(unsigned long) = Store[z] : &:r2784_1, r2784_3 +# 2785| r2785_1(glval) = VariableAddress[tmp3] : +# 2785| mu2785_2(int[][][]) = Uninitialized[tmp3] : &:r2785_1 +# 2785| r2785_3(glval) = VariableAddress[len1] : +# 2785| r2785_4(int) = Load[len1] : &:r2785_3, ~m? +# 2785| r2785_5(glval) = VariableAddress[len2] : +# 2785| r2785_6(unsigned long) = Load[len2] : &:r2785_5, ~m? +# 2785| r2785_7(glval) = VariableAddress[len3] : +# 2785| r2785_8(char) = Load[len3] : &:r2785_7, ~m? +# 2785| v2785_9(void) = NoOp : +# 2786| r2786_1(glval) = VariableAddress[w] : +# 2786| r2786_2(unsigned long) = Constant[4] : +# 2786| r2786_3(unsigned long) = Mul : r2786_2, r2785_4 +# 2786| r2786_4(unsigned long) = Mul : r2786_3, r2785_6 +# 2786| r2786_5(unsigned long) = Mul : r2786_4, r2785_8 +# 2786| mu2786_6(unsigned long) = Store[w] : &:r2786_1, r2786_5 +# 2787| r2787_1(glval) = VariableAddress[v] : # 2787| r2787_2(unsigned long) = Constant[4] : -# 2787| r2787_3(unsigned long) = Mul : r2787_2, r2786_4 -# 2787| r2787_4(unsigned long) = Mul : r2787_3, r2786_6 -# 2787| r2787_5(unsigned long) = Mul : r2787_4, r2786_8 -# 2787| mu2787_6(unsigned long) = Store[w] : &:r2787_1, r2787_5 -# 2788| r2788_1(glval) = VariableAddress[v] : +# 2787| r2787_3(unsigned long) = Mul : r2787_2, r2785_6 +# 2787| r2787_4(unsigned long) = Mul : r2787_3, r2785_8 +# 2787| mu2787_5(unsigned long) = Store[v] : &:r2787_1, r2787_4 +# 2788| r2788_1(glval) = VariableAddress[u] : # 2788| r2788_2(unsigned long) = Constant[4] : -# 2788| r2788_3(unsigned long) = Mul : r2788_2, r2786_6 -# 2788| r2788_4(unsigned long) = Mul : r2788_3, r2786_8 -# 2788| mu2788_5(unsigned long) = Store[v] : &:r2788_1, r2788_4 -# 2789| r2789_1(glval) = VariableAddress[u] : +# 2788| r2788_3(unsigned long) = Mul : r2788_2, r2785_8 +# 2788| mu2788_4(unsigned long) = Store[u] : &:r2788_1, r2788_3 +# 2789| r2789_1(glval) = VariableAddress[t] : # 2789| r2789_2(unsigned long) = Constant[4] : -# 2789| r2789_3(unsigned long) = Mul : r2789_2, r2786_8 -# 2789| mu2789_4(unsigned long) = Store[u] : &:r2789_1, r2789_3 -# 2790| r2790_1(glval) = VariableAddress[t] : -# 2790| r2790_2(unsigned long) = Constant[4] : -# 2790| mu2790_3(unsigned long) = Store[t] : &:r2790_1, r2790_2 -# 2791| v2791_1(void) = NoOp : +# 2789| mu2789_3(unsigned long) = Store[t] : &:r2789_1, r2789_2 +# 2790| v2790_1(void) = NoOp : # 2779| v2779_10(void) = ReturnVoid : # 2779| v2779_11(void) = AliasedUse : ~m? # 2779| v2779_12(void) = ExitFunction : +# 2792| void vla_sizeof_test2(int, size_t, char) +# 2792| Block 0 +# 2792| v2792_1(void) = EnterFunction : +# 2792| mu2792_2(unknown) = AliasedDefinition : +# 2792| mu2792_3(unknown) = InitializeNonLocal : +# 2792| r2792_4(glval) = VariableAddress[len1] : +# 2792| mu2792_5(int) = InitializeParameter[len1] : &:r2792_4 +# 2792| r2792_6(glval) = VariableAddress[len2] : +# 2792| mu2792_7(unsigned long) = InitializeParameter[len2] : &:r2792_6 +# 2792| r2792_8(glval) = VariableAddress[len3] : +# 2792| mu2792_9(char) = InitializeParameter[len3] : &:r2792_8 +# 2793| r2793_1(glval) = VariableAddress[tmp1] : +# 2793| mu2793_2(int[][]) = Uninitialized[tmp1] : &:r2793_1 +# 2793| r2793_3(glval) = VariableAddress[len1] : +# 2793| r2793_4(int) = Load[len1] : &:r2793_3, ~m? +# 2793| r2793_5(glval) = VariableAddress[len2] : +# 2793| r2793_6(unsigned long) = Load[len2] : &:r2793_5, ~m? +# 2793| v2793_7(void) = NoOp : +# 2794| r2794_1(glval) = VariableAddress[z] : + +# 2794| Block 1 +# 2794| mu2794_2(unsigned long) = Store[z] : &:r2794_1 +# 2795| r2795_1(glval) = VariableAddress[tmp2] : +# 2795| mu2795_2(int[][][]) = Uninitialized[tmp2] : &:r2795_1 +# 2795| r2795_3(glval) = VariableAddress[len1] : +# 2795| r2795_4(int) = Load[len1] : &:r2795_3, ~m? +# 2795| r2795_5(glval) = VariableAddress[len2] : +# 2795| r2795_6(unsigned long) = Load[len2] : &:r2795_5, ~m? +# 2795| r2795_7(glval) = VariableAddress[len3] : +# 2795| r2795_8(char) = Load[len3] : &:r2795_7, ~m? +# 2795| v2795_9(void) = NoOp : +# 2796| r2796_1(glval) = VariableAddress[v] : + +# 2796| Block 2 +# 2796| mu2796_2(unsigned long) = Store[v] : &:r2796_1 +# 2797| r2797_1(glval) = VariableAddress[u] : + +# 2797| Block 3 +# 2797| mu2797_2(unsigned long) = Store[u] : &:r2797_1 +# 2798| r2798_1(glval) = VariableAddress[t] : +# 2798| r2798_2(unsigned long) = Constant[4] : +# 2798| mu2798_3(unsigned long) = Store[t] : &:r2798_1, r2798_2 +# 2799| v2799_1(void) = NoOp : +# 2792| v2792_10(void) = ReturnVoid : +# 2792| v2792_11(void) = AliasedUse : ~m? +# 2792| v2792_12(void) = ExitFunction : + +# 2801| size_t vla_sizeof_test3(int, size_t, char, bool) +# 2801| Block 0 +# 2801| v2801_1(void) = EnterFunction : +# 2801| mu2801_2(unknown) = AliasedDefinition : +# 2801| mu2801_3(unknown) = InitializeNonLocal : +# 2801| r2801_4(glval) = VariableAddress[len1] : +# 2801| mu2801_5(int) = InitializeParameter[len1] : &:r2801_4 +# 2801| r2801_6(glval) = VariableAddress[len2] : +# 2801| mu2801_7(unsigned long) = InitializeParameter[len2] : &:r2801_6 +# 2801| r2801_8(glval) = VariableAddress[len3] : +# 2801| mu2801_9(char) = InitializeParameter[len3] : &:r2801_8 +# 2801| r2801_10(glval) = VariableAddress[b] : +# 2801| mu2801_11(bool) = InitializeParameter[b] : &:r2801_10 +# 2802| r2802_1(glval) = VariableAddress[len1] : +# 2802| r2802_2(int) = Load[len1] : &:r2802_1, ~m? +# 2802| r2802_3(glval) = VariableAddress[len2] : +# 2802| r2802_4(unsigned long) = Load[len2] : &:r2802_3, ~m? +# 2802| v2802_5(void) = NoOp : +# 2803| v2803_1(void) = NoOp : +# 2804| r2804_1(glval) = VariableAddress[len3] : +# 2804| r2804_2(char) = Load[len3] : &:r2804_1, ~m? +# 2804| v2804_3(void) = NoOp : +# 2806| r2806_1(glval) = VariableAddress[b] : +# 2806| r2806_2(bool) = Load[b] : &:r2806_1, ~m? +# 2806| v2806_3(void) = ConditionalBranch : r2806_2 +#-----| False -> Block 4 +#-----| True -> Block 2 + +# 2801| Block 1 +# 2801| r2801_12(glval) = VariableAddress[#return] : +# 2801| v2801_13(void) = ReturnValue : &:r2801_12, ~m? +# 2801| v2801_14(void) = AliasedUse : ~m? +# 2801| v2801_15(void) = ExitFunction : + +# 2807| Block 2 +# 2807| r2807_1(glval) = VariableAddress[tmp] : +# 2807| mu2807_2(long[][][]) = Uninitialized[tmp] : &:r2807_1 +# 2807| v2807_3(void) = NoOp : +# 2808| r2808_1(glval) = VariableAddress[#return] : + +# 2808| Block 3 +# 2808| mu2808_2(unsigned long) = Store[#return] : &:r2808_1 +#-----| Goto -> Block 1 + +# 2811| Block 4 +# 2811| r2811_1(glval) = VariableAddress[#return] : +# 2811| r2811_2(unsigned long) = Constant[0] : +# 2811| mu2811_3(unsigned long) = Store[#return] : &:r2811_1, r2811_2 +#-----| Goto -> Block 1 + ir23.cpp: # 1| bool consteval_1() # 1| Block 0 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 b83d9ea47e38..12feac2ecd25 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,6 +6,8 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2794:10:2794:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | +| ir.cpp:2808:5:2808:26 | VariableAddress: return ... | Instruction 'VariableAddress: return ...' has no successors in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | 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 b83d9ea47e38..12feac2ecd25 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,6 +6,8 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2794:10:2794:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | +| ir.cpp:2808:5:2808:26 | VariableAddress: return ... | Instruction 'VariableAddress: return ...' has no successors in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction From fdab63fd5fb92b5f56a3da4b206eeb8c68c2a499 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 1 Sep 2025 16:10:32 +0200 Subject: [PATCH 05/16] C++: Handle `ArrayExpr`s in `sizeof` VLAs --- .../code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll | 2 ++ 1 file changed, 2 insertions(+) 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 463f13f1aee7..913774953070 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 @@ -4099,6 +4099,8 @@ private VlaDeclStmt getVlaDeclStmt(Expr expr, int pointerDerefCount) { pointerDerefCount = 0 or result = getVlaDeclStmt(expr.(PointerDereferenceExpr).getOperand(), pointerDerefCount - 1) + or + result = getVlaDeclStmt(expr.(ArrayExpr).getArrayBase(), pointerDerefCount - 1) } class TranslatedSizeofExpr extends TranslatedNonConstantExpr { From 74f5687660c680b3eeb2c2e86106d9aec97233b4 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 1 Sep 2025 16:12:30 +0200 Subject: [PATCH 06/16] C++: Update expected test results --- .../library-tests/ir/ir/aliased_ir.expected | 28 ++++++++++ .../ir/ir/aliased_ssa_consistency.expected | 1 - .../aliased_ssa_consistency_unsound.expected | 1 - .../ir/ir/raw_consistency.expected | 9 --- .../test/library-tests/ir/ir/raw_ir.expected | 55 ++++++++++--------- .../ir/ir/unaliased_ssa_consistency.expected | 1 - ...unaliased_ssa_consistency_unsound.expected | 1 - 7 files changed, 56 insertions(+), 40 deletions(-) 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 218df42da10f..022b373ed6bc 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected @@ -20519,6 +20519,34 @@ ir.cpp: # 2793| r2793_6(unsigned long) = Load[len2] : &:r2793_5, m2792_8 # 2793| v2793_7(void) = NoOp : # 2794| r2794_1(glval) = VariableAddress[z] : +# 2794| r2794_2(unsigned long) = Constant[4] : +# 2794| r2794_3(unsigned long) = Mul : r2794_2, r2793_6 +# 2794| m2794_4(unsigned long) = Store[z] : &:r2794_1, r2794_3 +# 2795| r2795_1(glval) = VariableAddress[tmp2] : +# 2795| m2795_2(int[][][]) = Uninitialized[tmp2] : &:r2795_1 +# 2795| r2795_3(glval) = VariableAddress[len1] : +# 2795| r2795_4(int) = Load[len1] : &:r2795_3, m2792_6 +# 2795| r2795_5(glval) = VariableAddress[len2] : +# 2795| r2795_6(unsigned long) = Load[len2] : &:r2795_5, m2792_8 +# 2795| r2795_7(glval) = VariableAddress[len3] : +# 2795| r2795_8(char) = Load[len3] : &:r2795_7, m2792_10 +# 2795| v2795_9(void) = NoOp : +# 2796| r2796_1(glval) = VariableAddress[v] : +# 2796| r2796_2(unsigned long) = Constant[4] : +# 2796| r2796_3(unsigned long) = Mul : r2796_2, r2795_6 +# 2796| r2796_4(unsigned long) = Mul : r2796_3, r2795_8 +# 2796| m2796_5(unsigned long) = Store[v] : &:r2796_1, r2796_4 +# 2797| r2797_1(glval) = VariableAddress[u] : +# 2797| r2797_2(unsigned long) = Constant[4] : +# 2797| r2797_3(unsigned long) = Mul : r2797_2, r2795_8 +# 2797| m2797_4(unsigned long) = Store[u] : &:r2797_1, r2797_3 +# 2798| r2798_1(glval) = VariableAddress[t] : +# 2798| r2798_2(unsigned long) = Constant[4] : +# 2798| m2798_3(unsigned long) = Store[t] : &:r2798_1, r2798_2 +# 2799| v2799_1(void) = NoOp : +# 2792| v2792_11(void) = ReturnVoid : +# 2792| v2792_12(void) = AliasedUse : m2792_3 +# 2792| v2792_13(void) = ExitFunction : # 2801| size_t vla_sizeof_test3(int, size_t, char, bool) # 2801| Block 0 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 12feac2ecd25..f44d68efc86c 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 -| ir.cpp:2794:10:2794:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | | ir.cpp:2808:5:2808:26 | VariableAddress: return ... | Instruction 'VariableAddress: return ...' has no successors in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | ambiguousSuccessors unexplainedLoop 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 12feac2ecd25..f44d68efc86c 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 -| ir.cpp:2794:10:2794:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | | ir.cpp:2808:5:2808:26 | VariableAddress: return ... | Instruction 'VariableAddress: return ...' has no successors in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | ambiguousSuccessors unexplainedLoop 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 e47bac20c76f..b7361a165a53 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected @@ -1,7 +1,4 @@ missingOperand -| ir.cpp:2794:14:2794:28 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | -| ir.cpp:2796:14:2796:28 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | -| ir.cpp:2797:14:2797:31 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | | ir.cpp:2808:12:2808:25 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | unexpectedOperand duplicateOperand @@ -10,9 +7,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| ir.cpp:2794:10:2794:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | -| ir.cpp:2796:10:2796:10 | VariableAddress: definition of v | Instruction 'VariableAddress: definition of v' has no successors in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | -| ir.cpp:2797:10:2797:10 | VariableAddress: definition of u | Instruction 'VariableAddress: definition of u' has no successors in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | | ir.cpp:2808:5:2808:26 | VariableAddress: return ... | Instruction 'VariableAddress: return ...' has no successors in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | ambiguousSuccessors unexplainedLoop @@ -29,9 +23,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() | -| ir.cpp:2794:10:2794:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | -| ir.cpp:2796:10:2796:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | -| ir.cpp:2797:10:2797:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | | ir.cpp:2808:5:2808:26 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | switchInstructionWithoutDefaultEdge notMarkedAsConflated 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 e312083ab559..1b923a0662b0 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -18664,33 +18664,34 @@ ir.cpp: # 2793| r2793_6(unsigned long) = Load[len2] : &:r2793_5, ~m? # 2793| v2793_7(void) = NoOp : # 2794| r2794_1(glval) = VariableAddress[z] : - -# 2794| Block 1 -# 2794| mu2794_2(unsigned long) = Store[z] : &:r2794_1 -# 2795| r2795_1(glval) = VariableAddress[tmp2] : -# 2795| mu2795_2(int[][][]) = Uninitialized[tmp2] : &:r2795_1 -# 2795| r2795_3(glval) = VariableAddress[len1] : -# 2795| r2795_4(int) = Load[len1] : &:r2795_3, ~m? -# 2795| r2795_5(glval) = VariableAddress[len2] : -# 2795| r2795_6(unsigned long) = Load[len2] : &:r2795_5, ~m? -# 2795| r2795_7(glval) = VariableAddress[len3] : -# 2795| r2795_8(char) = Load[len3] : &:r2795_7, ~m? -# 2795| v2795_9(void) = NoOp : -# 2796| r2796_1(glval) = VariableAddress[v] : - -# 2796| Block 2 -# 2796| mu2796_2(unsigned long) = Store[v] : &:r2796_1 -# 2797| r2797_1(glval) = VariableAddress[u] : - -# 2797| Block 3 -# 2797| mu2797_2(unsigned long) = Store[u] : &:r2797_1 -# 2798| r2798_1(glval) = VariableAddress[t] : -# 2798| r2798_2(unsigned long) = Constant[4] : -# 2798| mu2798_3(unsigned long) = Store[t] : &:r2798_1, r2798_2 -# 2799| v2799_1(void) = NoOp : -# 2792| v2792_10(void) = ReturnVoid : -# 2792| v2792_11(void) = AliasedUse : ~m? -# 2792| v2792_12(void) = ExitFunction : +# 2794| r2794_2(unsigned long) = Constant[4] : +# 2794| r2794_3(unsigned long) = Mul : r2794_2, r2793_6 +# 2794| mu2794_4(unsigned long) = Store[z] : &:r2794_1, r2794_3 +# 2795| r2795_1(glval) = VariableAddress[tmp2] : +# 2795| mu2795_2(int[][][]) = Uninitialized[tmp2] : &:r2795_1 +# 2795| r2795_3(glval) = VariableAddress[len1] : +# 2795| r2795_4(int) = Load[len1] : &:r2795_3, ~m? +# 2795| r2795_5(glval) = VariableAddress[len2] : +# 2795| r2795_6(unsigned long) = Load[len2] : &:r2795_5, ~m? +# 2795| r2795_7(glval) = VariableAddress[len3] : +# 2795| r2795_8(char) = Load[len3] : &:r2795_7, ~m? +# 2795| v2795_9(void) = NoOp : +# 2796| r2796_1(glval) = VariableAddress[v] : +# 2796| r2796_2(unsigned long) = Constant[4] : +# 2796| r2796_3(unsigned long) = Mul : r2796_2, r2795_6 +# 2796| r2796_4(unsigned long) = Mul : r2796_3, r2795_8 +# 2796| mu2796_5(unsigned long) = Store[v] : &:r2796_1, r2796_4 +# 2797| r2797_1(glval) = VariableAddress[u] : +# 2797| r2797_2(unsigned long) = Constant[4] : +# 2797| r2797_3(unsigned long) = Mul : r2797_2, r2795_8 +# 2797| mu2797_4(unsigned long) = Store[u] : &:r2797_1, r2797_3 +# 2798| r2798_1(glval) = VariableAddress[t] : +# 2798| r2798_2(unsigned long) = Constant[4] : +# 2798| mu2798_3(unsigned long) = Store[t] : &:r2798_1, r2798_2 +# 2799| v2799_1(void) = NoOp : +# 2792| v2792_10(void) = ReturnVoid : +# 2792| v2792_11(void) = AliasedUse : ~m? +# 2792| v2792_12(void) = ExitFunction : # 2801| size_t vla_sizeof_test3(int, size_t, char, bool) # 2801| Block 0 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 12feac2ecd25..f44d68efc86c 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 -| ir.cpp:2794:10:2794:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | | ir.cpp:2808:5:2808:26 | VariableAddress: return ... | Instruction 'VariableAddress: return ...' has no successors in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | ambiguousSuccessors unexplainedLoop 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 12feac2ecd25..f44d68efc86c 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 -| ir.cpp:2794:10:2794:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2792:6:2792:21 | void vla_sizeof_test2(int, size_t, char) | void vla_sizeof_test2(int, size_t, char) | | ir.cpp:2808:5:2808:26 | VariableAddress: return ... | Instruction 'VariableAddress: return ...' has no successors in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | ambiguousSuccessors unexplainedLoop From 6e8f44da42103da4b86b531df389d63789a041ed Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 1 Sep 2025 16:17:54 +0200 Subject: [PATCH 07/16] C++: Handle `sizeof` VLAs with typedefs --- .../raw/internal/TranslatedExpr.qll | 72 +++++++++++++------ 1 file changed, 50 insertions(+), 22 deletions(-) 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 913774953070..21ac5ec7c133 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 @@ -4103,14 +4103,48 @@ private VlaDeclStmt getVlaDeclStmt(Expr expr, int pointerDerefCount) { result = getVlaDeclStmt(expr.(ArrayExpr).getArrayBase(), pointerDerefCount - 1) } +private int getNumberOfVlaDimensions(VlaDeclStmt vlaDeclStmt) { + not exists(getParentVlaDecl(vlaDeclStmt)) and + result = vlaDeclStmt.getNumberOfVlaDimensionStmts() + or + result = + vlaDeclStmt.getNumberOfVlaDimensionStmts() + + getNumberOfVlaDimensions(getParentVlaDecl(vlaDeclStmt)) +} + +private VlaDeclStmt getParentVlaDecl(VlaDeclStmt vlaDeclStmt) { + exists(Variable v, Type baseType | + v = vlaDeclStmt.getVariable() and + baseType = getBaseType(v.getType(), vlaDeclStmt.getNumberOfVlaDimensionStmts()) + | + result.getType() = baseType + ) + or + exists(Type t, Type baseType | + t = vlaDeclStmt.getType().(TypedefType).getBaseType() and + baseType = getBaseType(t, vlaDeclStmt.getNumberOfVlaDimensionStmts()) + | + result.getType() = baseType + ) +} + +private Type getBaseType(Type type, int n) { + n = 0 and + result = type + or + result = getBaseType(type.(DerivedType).getBaseType(), n - 1) +} + class TranslatedSizeofExpr extends TranslatedNonConstantExpr { override SizeofExprOperator expr; VlaDeclStmt vlaDeclStmt; + int vlaDimensions; int pointerDerefCount; TranslatedSizeofExpr() { vlaDeclStmt = getVlaDeclStmt(expr.getExprOperand(), pointerDerefCount) and - pointerDerefCount < vlaDeclStmt.getNumberOfVlaDimensionStmts() + vlaDimensions = getNumberOfVlaDimensions(vlaDeclStmt) and + pointerDerefCount < vlaDimensions } final override Instruction getFirstInstruction(EdgeKind kind) { @@ -4119,8 +4153,7 @@ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { } override Instruction getALastInstructionInternal() { - result = - this.getInstruction(SizeofVlaDimensionTag(vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1)) + result = this.getInstruction(SizeofVlaDimensionTag(vlaDimensions - 1)) } final override TranslatedElement getChildInternal(int id) { none() } @@ -4131,9 +4164,7 @@ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { resultType = this.getResultType() or opcode instanceof Opcode::Mul and - exists(int n | pointerDerefCount <= n and n < vlaDeclStmt.getNumberOfVlaDimensionStmts() | - tag = SizeofVlaDimensionTag(n) - ) and + exists(int n | pointerDerefCount <= n and n < vlaDimensions | tag = SizeofVlaDimensionTag(n)) and resultType = this.getResultType() } @@ -4142,33 +4173,24 @@ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { result = this.getInstruction(SizeofVlaDimensionTag(pointerDerefCount)) and kind instanceof GotoEdge or - exists(int n | pointerDerefCount <= n and n < vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1 | + exists(int n | pointerDerefCount <= n and n < vlaDimensions - 1 | tag = SizeofVlaDimensionTag(n) and result = this.getInstruction(SizeofVlaDimensionTag(n + 1)) ) and kind instanceof GotoEdge or - tag = SizeofVlaDimensionTag(vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1) and + tag = SizeofVlaDimensionTag(vlaDimensions - 1) and result = this.getParent().getChildSuccessor(this, kind) } override string getInstructionConstantValue(InstructionTag tag) { tag = SizeofVlaDimensionTag(-1) and result = - this.getBaseSize(vlaDeclStmt.getVariable().getType(), - vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1).toString() - } - - private int getBaseSize(DerivedType type, int n) { - n = 0 and - result = type.getBaseType().getSize() - or - n = [1 .. vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1] and - result = this.getBaseSize(type.getBaseType(), n - 1) + getBaseType(vlaDeclStmt.getVariable().getUnderlyingType(), vlaDimensions).getSize().toString() } override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { - exists(int n | pointerDerefCount <= n and n < vlaDeclStmt.getNumberOfVlaDimensionStmts() | + exists(int n | pointerDerefCount <= n and n < vlaDimensions | tag = SizeofVlaDimensionTag(n) and ( operandTag instanceof LeftOperandTag and @@ -4182,14 +4204,20 @@ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { or operandTag instanceof RightOperandTag and result = - getTranslatedExpr(vlaDeclStmt.getVlaDimensionStmt(n).getDimensionExpr()).getResult() + getTranslatedExpr(this.getVlaDimension(vlaDeclStmt, n).getDimensionExpr()).getResult() ) ) } + private VlaDimensionStmt getVlaDimension(VlaDeclStmt v, int n) { + n < v.getNumberOfVlaDimensionStmts() and + result = v.getVlaDimensionStmt(n) + or + result = this.getVlaDimension(getParentVlaDecl(v), n - v.getNumberOfVlaDimensionStmts()) + } + final override Instruction getResult() { - result = - this.getInstruction(SizeofVlaDimensionTag(vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1)) + result = this.getInstruction(SizeofVlaDimensionTag(vlaDimensions - 1)) } } From ffbc83deebf30a5c20a32f9be3d51f00586245fc Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 1 Sep 2025 16:18:21 +0200 Subject: [PATCH 08/16] C++: Update expected test results --- .../library-tests/ir/ir/aliased_ir.expected | 31 ++++++++++++------- .../ir/ir/aliased_ssa_consistency.expected | 1 - .../aliased_ssa_consistency_unsound.expected | 1 - .../ir/ir/raw_consistency.expected | 3 -- .../test/library-tests/ir/ir/raw_ir.expected | 11 ++++--- .../ir/ir/unaliased_ssa_consistency.expected | 1 - ...unaliased_ssa_consistency_unsound.expected | 1 - 7 files changed, 26 insertions(+), 23 deletions(-) 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 022b373ed6bc..279abae70a5e 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected @@ -20574,23 +20574,32 @@ ir.cpp: # 2806| r2806_1(glval) = VariableAddress[b] : # 2806| r2806_2(bool) = Load[b] : &:r2806_1, m2801_12 # 2806| v2806_3(void) = ConditionalBranch : r2806_2 -#-----| False -> Block 2 -#-----| True -> Block 1 +#-----| False -> Block 3 +#-----| True -> Block 2 -# 2807| Block 1 +# 2801| Block 1 +# 2801| m2801_13(unsigned long) = Phi : from 2:m2808_5, from 3:m2811_3 +# 2801| r2801_14(glval) = VariableAddress[#return] : +# 2801| v2801_15(void) = ReturnValue : &:r2801_14, m2801_13 +# 2801| v2801_16(void) = AliasedUse : m2801_3 +# 2801| v2801_17(void) = ExitFunction : + +# 2807| Block 2 # 2807| r2807_1(glval) = VariableAddress[tmp] : # 2807| m2807_2(long[][][]) = Uninitialized[tmp] : &:r2807_1 # 2807| v2807_3(void) = NoOp : # 2808| r2808_1(glval) = VariableAddress[#return] : +# 2808| r2808_2(unsigned long) = Constant : +# 2808| r2808_3(unsigned long) = Mul : r2808_2, r2802_2 +# 2808| r2808_4(unsigned long) = Mul : r2808_3, r2802_4 +# 2808| m2808_5(unsigned long) = Store[#return] : &:r2808_1, r2808_4 +#-----| Goto -> Block 1 -# 2811| Block 2 -# 2811| r2811_1(glval) = VariableAddress[#return] : -# 2811| r2811_2(unsigned long) = Constant[0] : -# 2811| m2811_3(unsigned long) = Store[#return] : &:r2811_1, r2811_2 -# 2801| r2801_13(glval) = VariableAddress[#return] : -# 2801| v2801_14(void) = ReturnValue : &:r2801_13, m2811_3 -# 2801| v2801_15(void) = AliasedUse : m2801_3 -# 2801| v2801_16(void) = ExitFunction : +# 2811| Block 3 +# 2811| r2811_1(glval) = VariableAddress[#return] : +# 2811| r2811_2(unsigned long) = Constant[0] : +# 2811| m2811_3(unsigned long) = Store[#return] : &:r2811_1, r2811_2 +#-----| Goto -> Block 1 ir23.cpp: # 1| bool consteval_1() 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 f44d68efc86c..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 -| ir.cpp:2808:5:2808:26 | VariableAddress: return ... | Instruction 'VariableAddress: return ...' has no successors in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | 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 f44d68efc86c..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 -| ir.cpp:2808:5:2808:26 | VariableAddress: return ... | Instruction 'VariableAddress: return ...' has no successors in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | 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 b7361a165a53..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,5 +1,4 @@ missingOperand -| ir.cpp:2808:12:2808:25 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | unexpectedOperand duplicateOperand missingPhiOperand @@ -7,7 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| ir.cpp:2808:5:2808:26 | VariableAddress: return ... | Instruction 'VariableAddress: return ...' has no successors in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction @@ -23,7 +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() | -| ir.cpp:2808:5:2808:26 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | 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 1b923a0662b0..662d45acaa54 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -18718,7 +18718,7 @@ ir.cpp: # 2806| r2806_1(glval) = VariableAddress[b] : # 2806| r2806_2(bool) = Load[b] : &:r2806_1, ~m? # 2806| v2806_3(void) = ConditionalBranch : r2806_2 -#-----| False -> Block 4 +#-----| False -> Block 3 #-----| True -> Block 2 # 2801| Block 1 @@ -18732,12 +18732,13 @@ ir.cpp: # 2807| mu2807_2(long[][][]) = Uninitialized[tmp] : &:r2807_1 # 2807| v2807_3(void) = NoOp : # 2808| r2808_1(glval) = VariableAddress[#return] : - -# 2808| Block 3 -# 2808| mu2808_2(unsigned long) = Store[#return] : &:r2808_1 +# 2808| r2808_2(unsigned long) = Constant : +# 2808| r2808_3(unsigned long) = Mul : r2808_2, r2802_2 +# 2808| r2808_4(unsigned long) = Mul : r2808_3, r2802_4 +# 2808| mu2808_5(unsigned long) = Store[#return] : &:r2808_1, r2808_4 #-----| Goto -> Block 1 -# 2811| Block 4 +# 2811| Block 3 # 2811| r2811_1(glval) = VariableAddress[#return] : # 2811| r2811_2(unsigned long) = Constant[0] : # 2811| mu2811_3(unsigned long) = Store[#return] : &:r2811_1, r2811_2 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 f44d68efc86c..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 -| ir.cpp:2808:5:2808:26 | VariableAddress: return ... | Instruction 'VariableAddress: return ...' has no successors in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | 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 f44d68efc86c..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 -| ir.cpp:2808:5:2808:26 | VariableAddress: return ... | Instruction 'VariableAddress: return ...' has no successors in function '$@'. | ir.cpp:2801:8:2801:23 | size_t vla_sizeof_test3(int, size_t, char, bool) | size_t vla_sizeof_test3(int, size_t, char, bool) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction From 6a9324fab033c596892a6be91ee848eb7ab94b10 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 1 Sep 2025 16:46:59 +0200 Subject: [PATCH 09/16] C++: Fix obtaining the base type of a VLA --- .../implementation/raw/internal/TranslatedExpr.qll | 14 ++++++++++++-- .../test/library-tests/ir/ir/aliased_ir.expected | 2 +- cpp/ql/test/library-tests/ir/ir/raw_ir.expected | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) 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 21ac5ec7c133..fa5bc731c8e1 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,8 +4185,18 @@ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { override string getInstructionConstantValue(InstructionTag tag) { tag = SizeofVlaDimensionTag(-1) and - result = - getBaseType(vlaDeclStmt.getVariable().getUnderlyingType(), vlaDimensions).getSize().toString() + result = this.getVlaBaseType(vlaDeclStmt).getSize().toString() + } + + private Type getVlaBaseType(VlaDeclStmt v) { + not exists(getParentVlaDecl(v)) and + ( + result = getBaseType(v.getVariable().getUnderlyingType(), v.getNumberOfVlaDimensionStmts()) + or + result = getBaseType(v.getType().getUnderlyingType(), v.getNumberOfVlaDimensionStmts()) + ) + or + result = this.getVlaBaseType(getParentVlaDecl(v)) } override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { 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 279abae70a5e..afa2b781480d 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected @@ -20589,7 +20589,7 @@ ir.cpp: # 2807| m2807_2(long[][][]) = Uninitialized[tmp] : &:r2807_1 # 2807| v2807_3(void) = NoOp : # 2808| r2808_1(glval) = VariableAddress[#return] : -# 2808| r2808_2(unsigned long) = Constant : +# 2808| r2808_2(unsigned long) = Constant[8] : # 2808| r2808_3(unsigned long) = Mul : r2808_2, r2802_2 # 2808| r2808_4(unsigned long) = Mul : r2808_3, r2802_4 # 2808| m2808_5(unsigned long) = Store[#return] : &:r2808_1, r2808_4 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 662d45acaa54..a14e59b32130 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -18732,7 +18732,7 @@ ir.cpp: # 2807| mu2807_2(long[][][]) = Uninitialized[tmp] : &:r2807_1 # 2807| v2807_3(void) = NoOp : # 2808| r2808_1(glval) = VariableAddress[#return] : -# 2808| r2808_2(unsigned long) = Constant : +# 2808| r2808_2(unsigned long) = Constant[8] : # 2808| r2808_3(unsigned long) = Mul : r2808_2, r2802_2 # 2808| r2808_4(unsigned long) = Mul : r2808_3, r2802_4 # 2808| mu2808_5(unsigned long) = Store[#return] : &:r2808_1, r2808_4 From f0f66c6d5880054c240726b458fbd6696171099b Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 1 Sep 2025 17:45:14 +0200 Subject: [PATCH 10/16] C++: Minor refactor * Introduce new instruction tag for the base size * Introduce some convenience predicates on `VlaDeclStmt` --- .../raw/internal/InstructionTag.qll | 5 +- .../raw/internal/TranslatedExpr.qll | 74 ++++++------------- cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll | 54 ++++++++++++++ 3 files changed, 78 insertions(+), 55 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll index da93976c4e26..90af7d54fbb5 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll @@ -98,10 +98,9 @@ newtype TInstructionTag = } or CoAwaitBranchTag() or BoolToIntConversionTag() or + SizeofVlaBaseSizeTag() or SizeofVlaDimensionTag(int index) { - index = -1 - or - exists(VlaDeclStmt v | exists(v.getVlaDimensionStmt(index))) + exists(VlaDeclStmt v | exists(v.getTransitiveVlaDimensionStmt(index))) } class InstructionTag extends TInstructionTag { 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 fa5bc731c8e1..c3aecd8d9409 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 @@ -4103,38 +4103,6 @@ private VlaDeclStmt getVlaDeclStmt(Expr expr, int pointerDerefCount) { result = getVlaDeclStmt(expr.(ArrayExpr).getArrayBase(), pointerDerefCount - 1) } -private int getNumberOfVlaDimensions(VlaDeclStmt vlaDeclStmt) { - not exists(getParentVlaDecl(vlaDeclStmt)) and - result = vlaDeclStmt.getNumberOfVlaDimensionStmts() - or - result = - vlaDeclStmt.getNumberOfVlaDimensionStmts() + - getNumberOfVlaDimensions(getParentVlaDecl(vlaDeclStmt)) -} - -private VlaDeclStmt getParentVlaDecl(VlaDeclStmt vlaDeclStmt) { - exists(Variable v, Type baseType | - v = vlaDeclStmt.getVariable() and - baseType = getBaseType(v.getType(), vlaDeclStmt.getNumberOfVlaDimensionStmts()) - | - result.getType() = baseType - ) - or - exists(Type t, Type baseType | - t = vlaDeclStmt.getType().(TypedefType).getBaseType() and - baseType = getBaseType(t, vlaDeclStmt.getNumberOfVlaDimensionStmts()) - | - result.getType() = baseType - ) -} - -private Type getBaseType(Type type, int n) { - n = 0 and - result = type - or - result = getBaseType(type.(DerivedType).getBaseType(), n - 1) -} - class TranslatedSizeofExpr extends TranslatedNonConstantExpr { override SizeofExprOperator expr; VlaDeclStmt vlaDeclStmt; @@ -4143,12 +4111,12 @@ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { TranslatedSizeofExpr() { vlaDeclStmt = getVlaDeclStmt(expr.getExprOperand(), pointerDerefCount) and - vlaDimensions = getNumberOfVlaDimensions(vlaDeclStmt) and + vlaDimensions = vlaDeclStmt.getTransitiveNumberOfVlaDimensionStmts() and pointerDerefCount < vlaDimensions } final override Instruction getFirstInstruction(EdgeKind kind) { - result = this.getInstruction(SizeofVlaDimensionTag(-1)) and + result = this.getInstruction(SizeofVlaBaseSizeTag()) and kind instanceof GotoEdge } @@ -4160,7 +4128,7 @@ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { opcode instanceof Opcode::Constant and - tag = SizeofVlaDimensionTag(-1) and + tag = SizeofVlaBaseSizeTag() and resultType = this.getResultType() or opcode instanceof Opcode::Mul and @@ -4169,7 +4137,7 @@ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { } final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) { - tag = SizeofVlaDimensionTag(-1) and + tag = SizeofVlaBaseSizeTag() and result = this.getInstruction(SizeofVlaDimensionTag(pointerDerefCount)) and kind instanceof GotoEdge or @@ -4184,19 +4152,27 @@ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { } override string getInstructionConstantValue(InstructionTag tag) { - tag = SizeofVlaDimensionTag(-1) and - result = this.getVlaBaseType(vlaDeclStmt).getSize().toString() + tag = SizeofVlaBaseSizeTag() and + result = this.getBaseType(vlaDeclStmt).getSize().toString() } - private Type getVlaBaseType(VlaDeclStmt v) { - not exists(getParentVlaDecl(v)) and + private Type getBaseType(VlaDeclStmt v) { + not exists(v.getParentVlaDecl()) and ( - result = getBaseType(v.getVariable().getUnderlyingType(), v.getNumberOfVlaDimensionStmts()) + result = + this.getBaseType(v.getVariable().getUnderlyingType(), v.getNumberOfVlaDimensionStmts()) or - result = getBaseType(v.getType().getUnderlyingType(), v.getNumberOfVlaDimensionStmts()) + result = this.getBaseType(v.getType().getUnderlyingType(), v.getNumberOfVlaDimensionStmts()) ) or - result = this.getVlaBaseType(getParentVlaDecl(v)) + result = this.getBaseType(v.getParentVlaDecl()) + } + + private Type getBaseType(Type type, int n) { + n = 0 and + result = type + or + result = this.getBaseType(type.(DerivedType).getBaseType(), n - 1) } override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { @@ -4209,23 +4185,17 @@ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { result = this.getInstruction(SizeofVlaDimensionTag(n - 1)) or n - 1 < pointerDerefCount and - result = this.getInstruction(SizeofVlaDimensionTag(-1)) + result = this.getInstruction(SizeofVlaBaseSizeTag()) ) or operandTag instanceof RightOperandTag and result = - getTranslatedExpr(this.getVlaDimension(vlaDeclStmt, n).getDimensionExpr()).getResult() + getTranslatedExpr(vlaDeclStmt.getTransitiveVlaDimensionStmt(n).getDimensionExpr()) + .getResult() ) ) } - private VlaDimensionStmt getVlaDimension(VlaDeclStmt v, int n) { - n < v.getNumberOfVlaDimensionStmts() and - result = v.getVlaDimensionStmt(n) - or - result = this.getVlaDimension(getParentVlaDecl(v), n - v.getNumberOfVlaDimensionStmts()) - } - final override Instruction getResult() { result = this.getInstruction(SizeofVlaDimensionTag(vlaDimensions - 1)) } diff --git a/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll b/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll index 5305c8ca58f6..bd3a54c61594 100644 --- a/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll +++ b/cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll @@ -2355,6 +2355,20 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl { ) } + /** + * Gets the number of VLA dimension statements in this VLA declaration + * statement and transitively of the VLA declaration used to define its + * base type. if any. + */ + int getTransitiveNumberOfVlaDimensionStmts() { + not exists(this.getParentVlaDecl()) and + result = this.getNumberOfVlaDimensionStmts() + or + result = + this.getNumberOfVlaDimensionStmts() + + this.getParentVlaDecl().getTransitiveNumberOfVlaDimensionStmts() + } + /** * Gets the `i`th VLA dimension statement in this VLA * declaration statement. @@ -2367,6 +2381,19 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl { ) } + /** + * Gets the `i`th VLA dimension statement in this VLA declaration + * statement or transitively of the VLA declaration used to define + * its base type. + */ + VlaDimensionStmt getTransitiveVlaDimensionStmt(int i) { + i < this.getNumberOfVlaDimensionStmts() and + result = this.getVlaDimensionStmt(i) + or + result = + this.getParentVlaDecl().getTransitiveVlaDimensionStmt(i - this.getNumberOfVlaDimensionStmts()) + } + /** * Gets the type that this VLA declaration statement relates to, * if any. @@ -2378,4 +2405,31 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl { * if any. */ Variable getVariable() { variable_vla(unresolveElement(result), underlyingElement(this)) } + + /** + * Get the VLA declaration used to define the base type of + * this VLA declaration, if any. + */ + VlaDeclStmt getParentVlaDecl() { + exists(Variable v, Type baseType | + v = this.getVariable() and + baseType = this.getBaseType(v.getType(), this.getNumberOfVlaDimensionStmts()) + | + result.getType() = baseType + ) + or + exists(Type t, Type baseType | + t = this.getType().(TypedefType).getBaseType() and + baseType = this.getBaseType(t, this.getNumberOfVlaDimensionStmts()) + | + result.getType() = baseType + ) + } + + private Type getBaseType(Type type, int n) { + n = 0 and + result = type + or + result = this.getBaseType(type.(DerivedType).getBaseType(), n - 1) + } } From f68d3477d4be389ae9b9ec5b0c11921996419a76 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 1 Sep 2025 19:24:34 +0200 Subject: [PATCH 11/16] C++: Output necessary conversions in the `sizeof` VLA IR --- .../raw/internal/InstructionTag.qll | 3 + .../raw/internal/TranslatedExpr.qll | 41 +++++++++-- .../library-tests/ir/ir/aliased_ir.expected | 70 ++++++++++++------- .../test/library-tests/ir/ir/raw_ir.expected | 68 +++++++++++------- 4 files changed, 124 insertions(+), 58 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll index 90af7d54fbb5..be3f680aa16d 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll @@ -99,6 +99,9 @@ newtype TInstructionTag = CoAwaitBranchTag() or BoolToIntConversionTag() or SizeofVlaBaseSizeTag() or + SizeofVlaConversionTag(int index) { + exists(VlaDeclStmt v | exists(v.getTransitiveVlaDimensionStmt(index))) + } or SizeofVlaDimensionTag(int index) { exists(VlaDeclStmt v | exists(v.getTransitiveVlaDimensionStmt(index))) } 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 c3aecd8d9409..b7ffffea3337 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 @@ -4131,6 +4131,23 @@ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { tag = SizeofVlaBaseSizeTag() and resultType = this.getResultType() or + exists(int n, Type dimType | + pointerDerefCount <= n and + n < vlaDimensions and + dimType = vlaDeclStmt.getTransitiveVlaDimensionStmt(n).getDimensionExpr().getUnderlyingType() + | + ( + expr.getUnderlyingType() = dimType and + opcode instanceof Opcode::CopyValue and + tag = SizeofVlaConversionTag(n) + or + not expr.getUnderlyingType() = dimType and + opcode instanceof Opcode::Convert and + tag = SizeofVlaConversionTag(n) + ) + ) and + resultType = this.getResultType() + or opcode instanceof Opcode::Mul and exists(int n | pointerDerefCount <= n and n < vlaDimensions | tag = SizeofVlaDimensionTag(n)) and resultType = this.getResultType() @@ -4138,12 +4155,18 @@ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) { tag = SizeofVlaBaseSizeTag() and - result = this.getInstruction(SizeofVlaDimensionTag(pointerDerefCount)) and + result = this.getInstruction(SizeofVlaConversionTag(pointerDerefCount)) and + kind instanceof GotoEdge + or + exists(int n | pointerDerefCount <= n and n < vlaDimensions | + tag = SizeofVlaConversionTag(n) and + result = this.getInstruction(SizeofVlaDimensionTag(n)) + ) and kind instanceof GotoEdge or exists(int n | pointerDerefCount <= n and n < vlaDimensions - 1 | tag = SizeofVlaDimensionTag(n) and - result = this.getInstruction(SizeofVlaDimensionTag(n + 1)) + result = this.getInstruction(SizeofVlaConversionTag(n + 1)) ) and kind instanceof GotoEdge or @@ -4176,6 +4199,16 @@ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { } override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + exists(int n | pointerDerefCount <= n and n < vlaDimensions | + tag = SizeofVlaConversionTag(n) and + ( + operandTag instanceof UnaryOperandTag and + result = + getTranslatedExpr(vlaDeclStmt.getTransitiveVlaDimensionStmt(n).getDimensionExpr()) + .getResult() + ) + ) + or exists(int n | pointerDerefCount <= n and n < vlaDimensions | tag = SizeofVlaDimensionTag(n) and ( @@ -4189,9 +4222,7 @@ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { ) or operandTag instanceof RightOperandTag and - result = - getTranslatedExpr(vlaDeclStmt.getTransitiveVlaDimensionStmt(n).getDimensionExpr()) - .getResult() + result = this.getInstruction(SizeofVlaConversionTag(n)) ) ) } 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 afa2b781480d..df46de0f4892 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected @@ -20449,8 +20449,9 @@ ir.cpp: # 2780| v2780_5(void) = NoOp : # 2781| r2781_1(glval) = VariableAddress[x] : # 2781| r2781_2(unsigned long) = Constant[1] : -# 2781| r2781_3(unsigned long) = Mul : r2781_2, r2780_4 -# 2781| m2781_4(unsigned long) = Store[x] : &:r2781_1, r2781_3 +# 2781| r2781_3(unsigned long) = Convert : r2780_4 +# 2781| r2781_4(unsigned long) = Mul : r2781_2, r2781_3 +# 2781| m2781_5(unsigned long) = Store[x] : &:r2781_1, r2781_4 # 2782| r2782_1(glval) = VariableAddress[tmp2] : # 2782| m2782_2(int[][]) = Uninitialized[tmp2] : &:r2782_1 # 2782| r2782_3(glval) = VariableAddress[len1] : @@ -20460,13 +20461,16 @@ ir.cpp: # 2782| v2782_7(void) = NoOp : # 2783| r2783_1(glval) = VariableAddress[y] : # 2783| r2783_2(unsigned long) = Constant[4] : -# 2783| r2783_3(unsigned long) = Mul : r2783_2, r2782_4 -# 2783| r2783_4(unsigned long) = Mul : r2783_3, r2782_6 -# 2783| m2783_5(unsigned long) = Store[y] : &:r2783_1, r2783_4 +# 2783| r2783_3(unsigned long) = Convert : r2782_4 +# 2783| r2783_4(unsigned long) = Mul : r2783_2, r2783_3 +# 2783| r2783_5(unsigned long) = CopyValue : r2782_6 +# 2783| r2783_6(unsigned long) = Mul : r2783_4, r2783_5 +# 2783| m2783_7(unsigned long) = Store[y] : &:r2783_1, r2783_6 # 2784| r2784_1(glval) = VariableAddress[z] : # 2784| r2784_2(unsigned long) = Constant[4] : -# 2784| r2784_3(unsigned long) = Mul : r2784_2, r2782_6 -# 2784| m2784_4(unsigned long) = Store[z] : &:r2784_1, r2784_3 +# 2784| r2784_3(unsigned long) = CopyValue : r2782_6 +# 2784| r2784_4(unsigned long) = Mul : r2784_2, r2784_3 +# 2784| m2784_5(unsigned long) = Store[z] : &:r2784_1, r2784_4 # 2785| r2785_1(glval) = VariableAddress[tmp3] : # 2785| m2785_2(int[][][]) = Uninitialized[tmp3] : &:r2785_1 # 2785| r2785_3(glval) = VariableAddress[len1] : @@ -20478,19 +20482,25 @@ ir.cpp: # 2785| v2785_9(void) = NoOp : # 2786| r2786_1(glval) = VariableAddress[w] : # 2786| r2786_2(unsigned long) = Constant[4] : -# 2786| r2786_3(unsigned long) = Mul : r2786_2, r2785_4 -# 2786| r2786_4(unsigned long) = Mul : r2786_3, r2785_6 -# 2786| r2786_5(unsigned long) = Mul : r2786_4, r2785_8 -# 2786| m2786_6(unsigned long) = Store[w] : &:r2786_1, r2786_5 +# 2786| r2786_3(unsigned long) = Convert : r2785_4 +# 2786| r2786_4(unsigned long) = Mul : r2786_2, r2786_3 +# 2786| r2786_5(unsigned long) = CopyValue : r2785_6 +# 2786| r2786_6(unsigned long) = Mul : r2786_4, r2786_5 +# 2786| r2786_7(unsigned long) = Convert : r2785_8 +# 2786| r2786_8(unsigned long) = Mul : r2786_6, r2786_7 +# 2786| m2786_9(unsigned long) = Store[w] : &:r2786_1, r2786_8 # 2787| r2787_1(glval) = VariableAddress[v] : # 2787| r2787_2(unsigned long) = Constant[4] : -# 2787| r2787_3(unsigned long) = Mul : r2787_2, r2785_6 -# 2787| r2787_4(unsigned long) = Mul : r2787_3, r2785_8 -# 2787| m2787_5(unsigned long) = Store[v] : &:r2787_1, r2787_4 +# 2787| r2787_3(unsigned long) = CopyValue : r2785_6 +# 2787| r2787_4(unsigned long) = Mul : r2787_2, r2787_3 +# 2787| r2787_5(unsigned long) = Convert : r2785_8 +# 2787| r2787_6(unsigned long) = Mul : r2787_4, r2787_5 +# 2787| m2787_7(unsigned long) = Store[v] : &:r2787_1, r2787_6 # 2788| r2788_1(glval) = VariableAddress[u] : # 2788| r2788_2(unsigned long) = Constant[4] : -# 2788| r2788_3(unsigned long) = Mul : r2788_2, r2785_8 -# 2788| m2788_4(unsigned long) = Store[u] : &:r2788_1, r2788_3 +# 2788| r2788_3(unsigned long) = Convert : r2785_8 +# 2788| r2788_4(unsigned long) = Mul : r2788_2, r2788_3 +# 2788| m2788_5(unsigned long) = Store[u] : &:r2788_1, r2788_4 # 2789| r2789_1(glval) = VariableAddress[t] : # 2789| r2789_2(unsigned long) = Constant[4] : # 2789| m2789_3(unsigned long) = Store[t] : &:r2789_1, r2789_2 @@ -20520,8 +20530,9 @@ ir.cpp: # 2793| v2793_7(void) = NoOp : # 2794| r2794_1(glval) = VariableAddress[z] : # 2794| r2794_2(unsigned long) = Constant[4] : -# 2794| r2794_3(unsigned long) = Mul : r2794_2, r2793_6 -# 2794| m2794_4(unsigned long) = Store[z] : &:r2794_1, r2794_3 +# 2794| r2794_3(unsigned long) = CopyValue : r2793_6 +# 2794| r2794_4(unsigned long) = Mul : r2794_2, r2794_3 +# 2794| m2794_5(unsigned long) = Store[z] : &:r2794_1, r2794_4 # 2795| r2795_1(glval) = VariableAddress[tmp2] : # 2795| m2795_2(int[][][]) = Uninitialized[tmp2] : &:r2795_1 # 2795| r2795_3(glval) = VariableAddress[len1] : @@ -20533,13 +20544,16 @@ ir.cpp: # 2795| v2795_9(void) = NoOp : # 2796| r2796_1(glval) = VariableAddress[v] : # 2796| r2796_2(unsigned long) = Constant[4] : -# 2796| r2796_3(unsigned long) = Mul : r2796_2, r2795_6 -# 2796| r2796_4(unsigned long) = Mul : r2796_3, r2795_8 -# 2796| m2796_5(unsigned long) = Store[v] : &:r2796_1, r2796_4 +# 2796| r2796_3(unsigned long) = CopyValue : r2795_6 +# 2796| r2796_4(unsigned long) = Mul : r2796_2, r2796_3 +# 2796| r2796_5(unsigned long) = Convert : r2795_8 +# 2796| r2796_6(unsigned long) = Mul : r2796_4, r2796_5 +# 2796| m2796_7(unsigned long) = Store[v] : &:r2796_1, r2796_6 # 2797| r2797_1(glval) = VariableAddress[u] : # 2797| r2797_2(unsigned long) = Constant[4] : -# 2797| r2797_3(unsigned long) = Mul : r2797_2, r2795_8 -# 2797| m2797_4(unsigned long) = Store[u] : &:r2797_1, r2797_3 +# 2797| r2797_3(unsigned long) = Convert : r2795_8 +# 2797| r2797_4(unsigned long) = Mul : r2797_2, r2797_3 +# 2797| m2797_5(unsigned long) = Store[u] : &:r2797_1, r2797_4 # 2798| r2798_1(glval) = VariableAddress[t] : # 2798| r2798_2(unsigned long) = Constant[4] : # 2798| m2798_3(unsigned long) = Store[t] : &:r2798_1, r2798_2 @@ -20578,7 +20592,7 @@ ir.cpp: #-----| True -> Block 2 # 2801| Block 1 -# 2801| m2801_13(unsigned long) = Phi : from 2:m2808_5, from 3:m2811_3 +# 2801| m2801_13(unsigned long) = Phi : from 2:m2808_7, from 3:m2811_3 # 2801| r2801_14(glval) = VariableAddress[#return] : # 2801| v2801_15(void) = ReturnValue : &:r2801_14, m2801_13 # 2801| v2801_16(void) = AliasedUse : m2801_3 @@ -20590,9 +20604,11 @@ ir.cpp: # 2807| v2807_3(void) = NoOp : # 2808| r2808_1(glval) = VariableAddress[#return] : # 2808| r2808_2(unsigned long) = Constant[8] : -# 2808| r2808_3(unsigned long) = Mul : r2808_2, r2802_2 -# 2808| r2808_4(unsigned long) = Mul : r2808_3, r2802_4 -# 2808| m2808_5(unsigned long) = Store[#return] : &:r2808_1, r2808_4 +# 2808| r2808_3(unsigned long) = Convert : r2802_2 +# 2808| r2808_4(unsigned long) = Mul : r2808_2, r2808_3 +# 2808| r2808_5(unsigned long) = CopyValue : r2802_4 +# 2808| r2808_6(unsigned long) = Mul : r2808_4, r2808_5 +# 2808| m2808_7(unsigned long) = Store[#return] : &:r2808_1, r2808_6 #-----| Goto -> Block 1 # 2811| Block 3 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 a14e59b32130..5a65885edee2 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -18595,8 +18595,9 @@ ir.cpp: # 2780| v2780_5(void) = NoOp : # 2781| r2781_1(glval) = VariableAddress[x] : # 2781| r2781_2(unsigned long) = Constant[1] : -# 2781| r2781_3(unsigned long) = Mul : r2781_2, r2780_4 -# 2781| mu2781_4(unsigned long) = Store[x] : &:r2781_1, r2781_3 +# 2781| r2781_3(unsigned long) = Convert : r2780_4 +# 2781| r2781_4(unsigned long) = Mul : r2781_2, r2781_3 +# 2781| mu2781_5(unsigned long) = Store[x] : &:r2781_1, r2781_4 # 2782| r2782_1(glval) = VariableAddress[tmp2] : # 2782| mu2782_2(int[][]) = Uninitialized[tmp2] : &:r2782_1 # 2782| r2782_3(glval) = VariableAddress[len1] : @@ -18606,13 +18607,16 @@ ir.cpp: # 2782| v2782_7(void) = NoOp : # 2783| r2783_1(glval) = VariableAddress[y] : # 2783| r2783_2(unsigned long) = Constant[4] : -# 2783| r2783_3(unsigned long) = Mul : r2783_2, r2782_4 -# 2783| r2783_4(unsigned long) = Mul : r2783_3, r2782_6 -# 2783| mu2783_5(unsigned long) = Store[y] : &:r2783_1, r2783_4 +# 2783| r2783_3(unsigned long) = Convert : r2782_4 +# 2783| r2783_4(unsigned long) = Mul : r2783_2, r2783_3 +# 2783| r2783_5(unsigned long) = CopyValue : r2782_6 +# 2783| r2783_6(unsigned long) = Mul : r2783_4, r2783_5 +# 2783| mu2783_7(unsigned long) = Store[y] : &:r2783_1, r2783_6 # 2784| r2784_1(glval) = VariableAddress[z] : # 2784| r2784_2(unsigned long) = Constant[4] : -# 2784| r2784_3(unsigned long) = Mul : r2784_2, r2782_6 -# 2784| mu2784_4(unsigned long) = Store[z] : &:r2784_1, r2784_3 +# 2784| r2784_3(unsigned long) = CopyValue : r2782_6 +# 2784| r2784_4(unsigned long) = Mul : r2784_2, r2784_3 +# 2784| mu2784_5(unsigned long) = Store[z] : &:r2784_1, r2784_4 # 2785| r2785_1(glval) = VariableAddress[tmp3] : # 2785| mu2785_2(int[][][]) = Uninitialized[tmp3] : &:r2785_1 # 2785| r2785_3(glval) = VariableAddress[len1] : @@ -18624,19 +18628,25 @@ ir.cpp: # 2785| v2785_9(void) = NoOp : # 2786| r2786_1(glval) = VariableAddress[w] : # 2786| r2786_2(unsigned long) = Constant[4] : -# 2786| r2786_3(unsigned long) = Mul : r2786_2, r2785_4 -# 2786| r2786_4(unsigned long) = Mul : r2786_3, r2785_6 -# 2786| r2786_5(unsigned long) = Mul : r2786_4, r2785_8 -# 2786| mu2786_6(unsigned long) = Store[w] : &:r2786_1, r2786_5 +# 2786| r2786_3(unsigned long) = Convert : r2785_4 +# 2786| r2786_4(unsigned long) = Mul : r2786_2, r2786_3 +# 2786| r2786_5(unsigned long) = CopyValue : r2785_6 +# 2786| r2786_6(unsigned long) = Mul : r2786_4, r2786_5 +# 2786| r2786_7(unsigned long) = Convert : r2785_8 +# 2786| r2786_8(unsigned long) = Mul : r2786_6, r2786_7 +# 2786| mu2786_9(unsigned long) = Store[w] : &:r2786_1, r2786_8 # 2787| r2787_1(glval) = VariableAddress[v] : # 2787| r2787_2(unsigned long) = Constant[4] : -# 2787| r2787_3(unsigned long) = Mul : r2787_2, r2785_6 -# 2787| r2787_4(unsigned long) = Mul : r2787_3, r2785_8 -# 2787| mu2787_5(unsigned long) = Store[v] : &:r2787_1, r2787_4 +# 2787| r2787_3(unsigned long) = CopyValue : r2785_6 +# 2787| r2787_4(unsigned long) = Mul : r2787_2, r2787_3 +# 2787| r2787_5(unsigned long) = Convert : r2785_8 +# 2787| r2787_6(unsigned long) = Mul : r2787_4, r2787_5 +# 2787| mu2787_7(unsigned long) = Store[v] : &:r2787_1, r2787_6 # 2788| r2788_1(glval) = VariableAddress[u] : # 2788| r2788_2(unsigned long) = Constant[4] : -# 2788| r2788_3(unsigned long) = Mul : r2788_2, r2785_8 -# 2788| mu2788_4(unsigned long) = Store[u] : &:r2788_1, r2788_3 +# 2788| r2788_3(unsigned long) = Convert : r2785_8 +# 2788| r2788_4(unsigned long) = Mul : r2788_2, r2788_3 +# 2788| mu2788_5(unsigned long) = Store[u] : &:r2788_1, r2788_4 # 2789| r2789_1(glval) = VariableAddress[t] : # 2789| r2789_2(unsigned long) = Constant[4] : # 2789| mu2789_3(unsigned long) = Store[t] : &:r2789_1, r2789_2 @@ -18665,8 +18675,9 @@ ir.cpp: # 2793| v2793_7(void) = NoOp : # 2794| r2794_1(glval) = VariableAddress[z] : # 2794| r2794_2(unsigned long) = Constant[4] : -# 2794| r2794_3(unsigned long) = Mul : r2794_2, r2793_6 -# 2794| mu2794_4(unsigned long) = Store[z] : &:r2794_1, r2794_3 +# 2794| r2794_3(unsigned long) = CopyValue : r2793_6 +# 2794| r2794_4(unsigned long) = Mul : r2794_2, r2794_3 +# 2794| mu2794_5(unsigned long) = Store[z] : &:r2794_1, r2794_4 # 2795| r2795_1(glval) = VariableAddress[tmp2] : # 2795| mu2795_2(int[][][]) = Uninitialized[tmp2] : &:r2795_1 # 2795| r2795_3(glval) = VariableAddress[len1] : @@ -18678,13 +18689,16 @@ ir.cpp: # 2795| v2795_9(void) = NoOp : # 2796| r2796_1(glval) = VariableAddress[v] : # 2796| r2796_2(unsigned long) = Constant[4] : -# 2796| r2796_3(unsigned long) = Mul : r2796_2, r2795_6 -# 2796| r2796_4(unsigned long) = Mul : r2796_3, r2795_8 -# 2796| mu2796_5(unsigned long) = Store[v] : &:r2796_1, r2796_4 +# 2796| r2796_3(unsigned long) = CopyValue : r2795_6 +# 2796| r2796_4(unsigned long) = Mul : r2796_2, r2796_3 +# 2796| r2796_5(unsigned long) = Convert : r2795_8 +# 2796| r2796_6(unsigned long) = Mul : r2796_4, r2796_5 +# 2796| mu2796_7(unsigned long) = Store[v] : &:r2796_1, r2796_6 # 2797| r2797_1(glval) = VariableAddress[u] : # 2797| r2797_2(unsigned long) = Constant[4] : -# 2797| r2797_3(unsigned long) = Mul : r2797_2, r2795_8 -# 2797| mu2797_4(unsigned long) = Store[u] : &:r2797_1, r2797_3 +# 2797| r2797_3(unsigned long) = Convert : r2795_8 +# 2797| r2797_4(unsigned long) = Mul : r2797_2, r2797_3 +# 2797| mu2797_5(unsigned long) = Store[u] : &:r2797_1, r2797_4 # 2798| r2798_1(glval) = VariableAddress[t] : # 2798| r2798_2(unsigned long) = Constant[4] : # 2798| mu2798_3(unsigned long) = Store[t] : &:r2798_1, r2798_2 @@ -18733,9 +18747,11 @@ ir.cpp: # 2807| v2807_3(void) = NoOp : # 2808| r2808_1(glval) = VariableAddress[#return] : # 2808| r2808_2(unsigned long) = Constant[8] : -# 2808| r2808_3(unsigned long) = Mul : r2808_2, r2802_2 -# 2808| r2808_4(unsigned long) = Mul : r2808_3, r2802_4 -# 2808| mu2808_5(unsigned long) = Store[#return] : &:r2808_1, r2808_4 +# 2808| r2808_3(unsigned long) = Convert : r2802_2 +# 2808| r2808_4(unsigned long) = Mul : r2808_2, r2808_3 +# 2808| r2808_5(unsigned long) = CopyValue : r2802_4 +# 2808| r2808_6(unsigned long) = Mul : r2808_4, r2808_5 +# 2808| mu2808_7(unsigned long) = Store[#return] : &:r2808_1, r2808_6 #-----| Goto -> Block 1 # 2811| Block 3 From 8a7553232f0d0f96a364e34c05df94927ded98a6 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 2 Sep 2025 10:48:12 +0200 Subject: [PATCH 12/16] C++: Add more `sizeof` VLA tests --- .../library-tests/ir/ir/PrintAST.expected | 95 +++++++++++++++++++ .../library-tests/ir/ir/aliased_ir.expected | 46 +++++++++ .../ir/ir/aliased_ssa_consistency.expected | 1 + .../aliased_ssa_consistency_unsound.expected | 1 + cpp/ql/test/library-tests/ir/ir/ir.cpp | 10 ++ .../ir/ir/raw_consistency.expected | 3 + .../test/library-tests/ir/ir/raw_ir.expected | 51 ++++++++++ .../ir/ir/unaliased_ssa_consistency.expected | 1 + ...unaliased_ssa_consistency_unsound.expected | 1 + 9 files changed, 209 insertions(+) diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index 34d231f8ebd4..630a4ca5ceba 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -24996,6 +24996,101 @@ ir.cpp: # 2811| Type = [CTypedefType,Size_t] size_t # 2811| Value = [CStyleCast] 0 # 2811| ValueCategory = prvalue +# 2814| [TopLevelFunction] void vla_sizeof_test4(int, size_t) +# 2814| : +# 2814| getParameter(0): [Parameter] len1 +# 2814| Type = [IntType] int +# 2814| getParameter(1): [Parameter] len2 +# 2814| Type = [CTypedefType,Size_t] size_t +# 2814| getEntryPoint(): [BlockStmt] { ... } +# 2815| getStmt(0): [DeclStmt] declaration +# 2815| getDeclarationEntry(0): [VariableDeclarationEntry] definition of tmp1 +# 2815| Type = [ArrayType] int[][] +# 2815| getStmt(1): [VlaDimensionStmt] VLA dimension size +# 2815| getDimensionExpr(): [VariableAccess] len1 +# 2815| Type = [IntType] int +# 2815| ValueCategory = prvalue(load) +# 2815| getStmt(2): [VlaDimensionStmt] VLA dimension size +# 2815| getDimensionExpr(): [VariableAccess] len2 +# 2815| Type = [CTypedefType,Size_t] size_t +# 2815| ValueCategory = prvalue(load) +# 2815| getStmt(3): [VlaDeclStmt] VLA declaration +# 2816| getStmt(4): [DeclStmt] declaration +# 2816| getDeclarationEntry(0): [VariableDeclarationEntry] definition of z +# 2816| Type = [CTypedefType,Size_t] size_t +# 2816| getVariable().getInitializer(): [Initializer] initializer for z +# 2816| getExpr(): [SizeofExprOperator] sizeof() +# 2816| Type = [LongType] unsigned long +# 2816| ValueCategory = prvalue +# 2816| getExprOperand(): [ArrayExpr] access to array +# 2816| Type = [ArrayType] int[] +# 2816| ValueCategory = lvalue +# 2816| getArrayBase(): [VariableAccess] tmp1 +# 2816| Type = [ArrayType] int[][] +# 2816| ValueCategory = lvalue +# 2816| getArrayOffset(): [Literal] 1 +# 2816| Type = [IntType] int +# 2816| Value = [Literal] 1 +# 2816| ValueCategory = prvalue +# 2816| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion +# 2816| Type = [PointerType] int(*)[] +# 2816| ValueCategory = prvalue +# 2816| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) +# 2816| Type = [ArrayType] int[] +# 2816| ValueCategory = lvalue +# 2817| getStmt(5): [ReturnStmt] return ... +# 2819| [TopLevelFunction] void vla_sizeof_test5(int, size_t) +# 2819| : +# 2819| getParameter(0): [Parameter] len1 +# 2819| Type = [IntType] int +# 2819| getParameter(1): [Parameter] len2 +# 2819| Type = [CTypedefType,Size_t] size_t +# 2819| getEntryPoint(): [BlockStmt] { ... } +# 2820| getStmt(0): [DeclStmt] declaration +# 2820| getDeclarationEntry(0): [VariableDeclarationEntry] definition of tmp1 +# 2820| Type = [ArrayType] int[][] +# 2820| getStmt(1): [VlaDimensionStmt] VLA dimension size +# 2820| getDimensionExpr(): [VariableAccess] len1 +# 2820| Type = [IntType] int +# 2820| ValueCategory = prvalue(load) +# 2820| getStmt(2): [VlaDimensionStmt] VLA dimension size +# 2820| getDimensionExpr(): [VariableAccess] len2 +# 2820| Type = [CTypedefType,Size_t] size_t +# 2820| ValueCategory = prvalue(load) +# 2820| getStmt(3): [VlaDeclStmt] VLA declaration +# 2821| getStmt(4): [DeclStmt] declaration +# 2821| getDeclarationEntry(0): [VariableDeclarationEntry] definition of z +# 2821| Type = [CTypedefType,Size_t] size_t +# 2821| getVariable().getInitializer(): [Initializer] initializer for z +# 2821| getExpr(): [SizeofExprOperator] sizeof() +# 2821| Type = [LongType] unsigned long +# 2821| ValueCategory = prvalue +# 2821| getExprOperand(): [ArrayExpr] access to array +# 2821| Type = [ArrayType] int[] +# 2821| ValueCategory = lvalue +# 2821| getArrayBase(): [PointerDereferenceExpr] * ... +# 2821| Type = [ArrayType] int[][] +# 2821| ValueCategory = lvalue +# 2821| getOperand(): [AddressOfExpr] & ... +# 2821| Type = [PointerType] int(*)[][] +# 2821| ValueCategory = prvalue +# 2821| getOperand(): [VariableAccess] tmp1 +# 2821| Type = [ArrayType] int[][] +# 2821| ValueCategory = lvalue +# 2821| getArrayOffset(): [Literal] 1 +# 2821| Type = [IntType] int +# 2821| Value = [Literal] 1 +# 2821| ValueCategory = prvalue +# 2821| getArrayBase().getFullyConverted(): [ParenthesisExpr] (...) +# 2821| Type = [PointerType] int(*)[] +# 2821| ValueCategory = prvalue +# 2821| getExpr(): [ArrayToPointerConversion] array to pointer conversion +# 2821| Type = [PointerType] int(*)[] +# 2821| ValueCategory = prvalue +# 2821| getExprOperand().getFullyConverted(): [ParenthesisExpr] (...) +# 2821| Type = [ArrayType] int[] +# 2821| ValueCategory = lvalue +# 2822| getStmt(5): [ReturnStmt] return ... ir23.cpp: # 1| [TopLevelFunction] bool consteval_1() # 1| : 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 df46de0f4892..73da36142599 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected @@ -20617,6 +20617,52 @@ ir.cpp: # 2811| m2811_3(unsigned long) = Store[#return] : &:r2811_1, r2811_2 #-----| Goto -> Block 1 +# 2814| void vla_sizeof_test4(int, size_t) +# 2814| Block 0 +# 2814| v2814_1(void) = EnterFunction : +# 2814| m2814_2(unknown) = AliasedDefinition : +# 2814| m2814_3(unknown) = InitializeNonLocal : +# 2814| m2814_4(unknown) = Chi : total:m2814_2, partial:m2814_3 +# 2814| r2814_5(glval) = VariableAddress[len1] : +# 2814| m2814_6(int) = InitializeParameter[len1] : &:r2814_5 +# 2814| r2814_7(glval) = VariableAddress[len2] : +# 2814| m2814_8(unsigned long) = InitializeParameter[len2] : &:r2814_7 +# 2815| r2815_1(glval) = VariableAddress[tmp1] : +# 2815| m2815_2(int[][]) = Uninitialized[tmp1] : &:r2815_1 +# 2815| r2815_3(glval) = VariableAddress[len1] : +# 2815| r2815_4(int) = Load[len1] : &:r2815_3, m2814_6 +# 2815| r2815_5(glval) = VariableAddress[len2] : +# 2815| r2815_6(unsigned long) = Load[len2] : &:r2815_5, m2814_8 +# 2815| v2815_7(void) = NoOp : +# 2816| r2816_1(glval) = VariableAddress[z] : +# 2816| r2816_2(unsigned long) = Constant[4] : +# 2816| r2816_3(unsigned long) = CopyValue : r2815_6 +# 2816| r2816_4(unsigned long) = Mul : r2816_2, r2816_3 +# 2816| m2816_5(unsigned long) = Store[z] : &:r2816_1, r2816_4 +# 2817| v2817_1(void) = NoOp : +# 2814| v2814_9(void) = ReturnVoid : +# 2814| v2814_10(void) = AliasedUse : m2814_3 +# 2814| v2814_11(void) = ExitFunction : + +# 2819| void vla_sizeof_test5(int, size_t) +# 2819| Block 0 +# 2819| v2819_1(void) = EnterFunction : +# 2819| m2819_2(unknown) = AliasedDefinition : +# 2819| m2819_3(unknown) = InitializeNonLocal : +# 2819| m2819_4(unknown) = Chi : total:m2819_2, partial:m2819_3 +# 2819| r2819_5(glval) = VariableAddress[len1] : +# 2819| m2819_6(int) = InitializeParameter[len1] : &:r2819_5 +# 2819| r2819_7(glval) = VariableAddress[len2] : +# 2819| m2819_8(unsigned long) = InitializeParameter[len2] : &:r2819_7 +# 2820| r2820_1(glval) = VariableAddress[tmp1] : +# 2820| m2820_2(int[][]) = Uninitialized[tmp1] : &:r2820_1 +# 2820| r2820_3(glval) = VariableAddress[len1] : +# 2820| r2820_4(int) = Load[len1] : &:r2820_3, m2819_6 +# 2820| r2820_5(glval) = VariableAddress[len2] : +# 2820| r2820_6(unsigned long) = Load[len2] : &:r2820_5, m2819_8 +# 2820| v2820_7(void) = NoOp : +# 2821| r2821_1(glval) = VariableAddress[z] : + ir23.cpp: # 1| bool consteval_1() # 1| Block 0 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 b83d9ea47e38..45b26f56bd79 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,6 +6,7 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2821:10:2821:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2819:6:2819:21 | void vla_sizeof_test5(int, size_t) | void vla_sizeof_test5(int, size_t) | 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 b83d9ea47e38..45b26f56bd79 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,6 +6,7 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2821:10:2821:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2819:6:2819:21 | void vla_sizeof_test5(int, size_t) | void vla_sizeof_test5(int, size_t) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp index be0e1904374c..3dce0a0e1ea9 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -2811,4 +2811,14 @@ size_t vla_sizeof_test3(int len1, size_t len2, char len3, bool b) { return 0; } +void vla_sizeof_test4(int len1, size_t len2) { + int tmp1[len1][len2]; + size_t z = sizeof(1[tmp1]); +} + +void vla_sizeof_test5(int len1, size_t len2) { + int tmp1[len1][len2]; + size_t z = sizeof((*&tmp1)[1]); +} + // semmle-extractor-options: -std=c++20 --clang 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 e30106d35204..fb13b34cf552 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected @@ -1,4 +1,5 @@ missingOperand +| ir.cpp:2821:14:2821:32 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2819:6:2819:21 | void vla_sizeof_test5(int, size_t) | void vla_sizeof_test5(int, size_t) | unexpectedOperand duplicateOperand missingPhiOperand @@ -6,6 +7,7 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2821:10:2821:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2819:6:2819:21 | void vla_sizeof_test5(int, size_t) | void vla_sizeof_test5(int, size_t) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction @@ -21,6 +23,7 @@ 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() | +| ir.cpp:2821:10:2821:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2819:6:2819:21 | void vla_sizeof_test5(int, size_t) | void vla_sizeof_test5(int, size_t) | 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 5a65885edee2..aa65bb705b02 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -18760,6 +18760,57 @@ ir.cpp: # 2811| mu2811_3(unsigned long) = Store[#return] : &:r2811_1, r2811_2 #-----| Goto -> Block 1 +# 2814| void vla_sizeof_test4(int, size_t) +# 2814| Block 0 +# 2814| v2814_1(void) = EnterFunction : +# 2814| mu2814_2(unknown) = AliasedDefinition : +# 2814| mu2814_3(unknown) = InitializeNonLocal : +# 2814| r2814_4(glval) = VariableAddress[len1] : +# 2814| mu2814_5(int) = InitializeParameter[len1] : &:r2814_4 +# 2814| r2814_6(glval) = VariableAddress[len2] : +# 2814| mu2814_7(unsigned long) = InitializeParameter[len2] : &:r2814_6 +# 2815| r2815_1(glval) = VariableAddress[tmp1] : +# 2815| mu2815_2(int[][]) = Uninitialized[tmp1] : &:r2815_1 +# 2815| r2815_3(glval) = VariableAddress[len1] : +# 2815| r2815_4(int) = Load[len1] : &:r2815_3, ~m? +# 2815| r2815_5(glval) = VariableAddress[len2] : +# 2815| r2815_6(unsigned long) = Load[len2] : &:r2815_5, ~m? +# 2815| v2815_7(void) = NoOp : +# 2816| r2816_1(glval) = VariableAddress[z] : +# 2816| r2816_2(unsigned long) = Constant[4] : +# 2816| r2816_3(unsigned long) = CopyValue : r2815_6 +# 2816| r2816_4(unsigned long) = Mul : r2816_2, r2816_3 +# 2816| mu2816_5(unsigned long) = Store[z] : &:r2816_1, r2816_4 +# 2817| v2817_1(void) = NoOp : +# 2814| v2814_8(void) = ReturnVoid : +# 2814| v2814_9(void) = AliasedUse : ~m? +# 2814| v2814_10(void) = ExitFunction : + +# 2819| void vla_sizeof_test5(int, size_t) +# 2819| Block 0 +# 2819| v2819_1(void) = EnterFunction : +# 2819| mu2819_2(unknown) = AliasedDefinition : +# 2819| mu2819_3(unknown) = InitializeNonLocal : +# 2819| r2819_4(glval) = VariableAddress[len1] : +# 2819| mu2819_5(int) = InitializeParameter[len1] : &:r2819_4 +# 2819| r2819_6(glval) = VariableAddress[len2] : +# 2819| mu2819_7(unsigned long) = InitializeParameter[len2] : &:r2819_6 +# 2820| r2820_1(glval) = VariableAddress[tmp1] : +# 2820| mu2820_2(int[][]) = Uninitialized[tmp1] : &:r2820_1 +# 2820| r2820_3(glval) = VariableAddress[len1] : +# 2820| r2820_4(int) = Load[len1] : &:r2820_3, ~m? +# 2820| r2820_5(glval) = VariableAddress[len2] : +# 2820| r2820_6(unsigned long) = Load[len2] : &:r2820_5, ~m? +# 2820| v2820_7(void) = NoOp : +# 2821| r2821_1(glval) = VariableAddress[z] : + +# 2821| Block 1 +# 2821| mu2821_2(unsigned long) = Store[z] : &:r2821_1 +# 2822| v2822_1(void) = NoOp : +# 2819| v2819_8(void) = ReturnVoid : +# 2819| v2819_9(void) = AliasedUse : ~m? +# 2819| v2819_10(void) = ExitFunction : + ir23.cpp: # 1| bool consteval_1() # 1| Block 0 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 b83d9ea47e38..45b26f56bd79 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,6 +6,7 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2821:10:2821:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2819:6:2819:21 | void vla_sizeof_test5(int, size_t) | void vla_sizeof_test5(int, size_t) | 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 b83d9ea47e38..45b26f56bd79 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,6 +6,7 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:2821:10:2821:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2819:6:2819:21 | void vla_sizeof_test5(int, size_t) | void vla_sizeof_test5(int, size_t) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction From 438cc961da4629f2aedef0ae4acc5f893988a92c Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 2 Sep 2025 11:05:07 +0200 Subject: [PATCH 13/16] C++: Document `TranslatedSizeofExpr` --- .../cpp/ir/implementation/raw/internal/TranslatedExpr.qll | 4 ++++ 1 file changed, 4 insertions(+) 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 b7ffffea3337..367d6f652e09 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 @@ -4103,6 +4103,10 @@ private VlaDeclStmt getVlaDeclStmt(Expr expr, int pointerDerefCount) { result = getVlaDeclStmt(expr.(ArrayExpr).getArrayBase(), pointerDerefCount - 1) } +/** + * The IR translation of `SizeofExprOperator` when its result is non-constant, i.e., + * when the operand expression refers to a variable length array. + */ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { override SizeofExprOperator expr; VlaDeclStmt vlaDeclStmt; From f4df3881f8f3d7151d947e44e2861de5f27fb90c Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 2 Sep 2025 11:05:47 +0200 Subject: [PATCH 14/16] C++: Handle `*&` sequences in `sizeof` VLA expressions --- .../raw/internal/TranslatedExpr.qll | 6 ++++++ .../test/library-tests/ir/ir/aliased_ir.expected | 8 ++++++++ .../ir/ir/aliased_ssa_consistency.expected | 1 - .../ir/aliased_ssa_consistency_unsound.expected | 1 - .../library-tests/ir/ir/raw_consistency.expected | 3 --- cpp/ql/test/library-tests/ir/ir/raw_ir.expected | 15 ++++++++------- .../ir/ir/unaliased_ssa_consistency.expected | 1 - .../ir/unaliased_ssa_consistency_unsound.expected | 1 - 8 files changed, 22 insertions(+), 14 deletions(-) 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 367d6f652e09..3db6a1dc7a8d 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 @@ -4098,8 +4098,14 @@ private VlaDeclStmt getVlaDeclStmt(Expr expr, int pointerDerefCount) { expr.(VariableAccess).getTarget() = result.getVariable() and pointerDerefCount = 0 or + not expr.(PointerDereferenceExpr).getOperand() instanceof AddressOfExpr and result = getVlaDeclStmt(expr.(PointerDereferenceExpr).getOperand(), pointerDerefCount - 1) or + // Skip sequences of the form `*&...` + result = + getVlaDeclStmt(expr.(PointerDereferenceExpr).getOperand().(AddressOfExpr).getOperand(), + pointerDerefCount) + or result = getVlaDeclStmt(expr.(ArrayExpr).getArrayBase(), pointerDerefCount - 1) } 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 73da36142599..566cf07423b8 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected @@ -20662,6 +20662,14 @@ ir.cpp: # 2820| r2820_6(unsigned long) = Load[len2] : &:r2820_5, m2819_8 # 2820| v2820_7(void) = NoOp : # 2821| r2821_1(glval) = VariableAddress[z] : +# 2821| r2821_2(unsigned long) = Constant[4] : +# 2821| r2821_3(unsigned long) = CopyValue : r2820_6 +# 2821| r2821_4(unsigned long) = Mul : r2821_2, r2821_3 +# 2821| m2821_5(unsigned long) = Store[z] : &:r2821_1, r2821_4 +# 2822| v2822_1(void) = NoOp : +# 2819| v2819_9(void) = ReturnVoid : +# 2819| v2819_10(void) = AliasedUse : m2819_3 +# 2819| v2819_11(void) = ExitFunction : ir23.cpp: # 1| bool consteval_1() 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 45b26f56bd79..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 -| ir.cpp:2821:10:2821:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2819:6:2819:21 | void vla_sizeof_test5(int, size_t) | void vla_sizeof_test5(int, size_t) | 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 45b26f56bd79..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 -| ir.cpp:2821:10:2821:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2819:6:2819:21 | void vla_sizeof_test5(int, size_t) | void vla_sizeof_test5(int, size_t) | 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 fb13b34cf552..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,5 +1,4 @@ missingOperand -| ir.cpp:2821:14:2821:32 | Store: sizeof() | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:2819:6:2819:21 | void vla_sizeof_test5(int, size_t) | void vla_sizeof_test5(int, size_t) | unexpectedOperand duplicateOperand missingPhiOperand @@ -7,7 +6,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| ir.cpp:2821:10:2821:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2819:6:2819:21 | void vla_sizeof_test5(int, size_t) | void vla_sizeof_test5(int, size_t) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction @@ -23,7 +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() | -| ir.cpp:2821:10:2821:10 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:2819:6:2819:21 | void vla_sizeof_test5(int, size_t) | void vla_sizeof_test5(int, size_t) | 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 aa65bb705b02..1d8f885cd15b 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -18803,13 +18803,14 @@ ir.cpp: # 2820| r2820_6(unsigned long) = Load[len2] : &:r2820_5, ~m? # 2820| v2820_7(void) = NoOp : # 2821| r2821_1(glval) = VariableAddress[z] : - -# 2821| Block 1 -# 2821| mu2821_2(unsigned long) = Store[z] : &:r2821_1 -# 2822| v2822_1(void) = NoOp : -# 2819| v2819_8(void) = ReturnVoid : -# 2819| v2819_9(void) = AliasedUse : ~m? -# 2819| v2819_10(void) = ExitFunction : +# 2821| r2821_2(unsigned long) = Constant[4] : +# 2821| r2821_3(unsigned long) = CopyValue : r2820_6 +# 2821| r2821_4(unsigned long) = Mul : r2821_2, r2821_3 +# 2821| mu2821_5(unsigned long) = Store[z] : &:r2821_1, r2821_4 +# 2822| v2822_1(void) = NoOp : +# 2819| v2819_8(void) = ReturnVoid : +# 2819| v2819_9(void) = AliasedUse : ~m? +# 2819| v2819_10(void) = ExitFunction : ir23.cpp: # 1| bool consteval_1() 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 45b26f56bd79..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 -| ir.cpp:2821:10:2821:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2819:6:2819:21 | void vla_sizeof_test5(int, size_t) | void vla_sizeof_test5(int, size_t) | 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 45b26f56bd79..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 -| ir.cpp:2821:10:2821:10 | VariableAddress: definition of z | Instruction 'VariableAddress: definition of z' has no successors in function '$@'. | ir.cpp:2819:6:2819:21 | void vla_sizeof_test5(int, size_t) | void vla_sizeof_test5(int, size_t) | ambiguousSuccessors unexplainedLoop unnecessaryPhiInstruction From 9431b0c754f6e0d21a1655be2bd7a87d6d9495d5 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 2 Sep 2025 11:26:19 +0200 Subject: [PATCH 15/16] C++: Add change note for new `VlaDeclStmt` predicates --- cpp/ql/lib/change-notes/2025-09-02-vla.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 cpp/ql/lib/change-notes/2025-09-02-vla.md diff --git a/cpp/ql/lib/change-notes/2025-09-02-vla.md b/cpp/ql/lib/change-notes/2025-09-02-vla.md new file mode 100644 index 000000000000..e59e3ef5ffe0 --- /dev/null +++ b/cpp/ql/lib/change-notes/2025-09-02-vla.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* Added predicates `getTransitiveNumberOfVlaDimensionStmts`, `getTransitiveVlaDimensionStmt`, and `getParentVlaDecl` to `VlaDeclStmt` for handling `VlaDeclStmt`s whose base type defined in terms of an other `VlaDeclStmt` via a `typedef`. From 8de1ed0d851594c3a350f58af4ec60d867f08322 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 2 Sep 2025 17:03:48 +0200 Subject: [PATCH 16/16] C++: Address review comments --- .../raw/internal/TranslatedExpr.qll | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) 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 3db6a1dc7a8d..6024a881c5fc 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 @@ -4144,16 +4144,15 @@ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { exists(int n, Type dimType | pointerDerefCount <= n and n < vlaDimensions and - dimType = vlaDeclStmt.getTransitiveVlaDimensionStmt(n).getDimensionExpr().getUnderlyingType() + dimType = this.getDimensionExpr(n).getUnderlyingType() and + tag = SizeofVlaConversionTag(n) | ( expr.getUnderlyingType() = dimType and - opcode instanceof Opcode::CopyValue and - tag = SizeofVlaConversionTag(n) + opcode instanceof Opcode::CopyValue or not expr.getUnderlyingType() = dimType and - opcode instanceof Opcode::Convert and - tag = SizeofVlaConversionTag(n) + opcode instanceof Opcode::Convert ) ) and resultType = this.getResultType() @@ -4213,9 +4212,7 @@ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { tag = SizeofVlaConversionTag(n) and ( operandTag instanceof UnaryOperandTag and - result = - getTranslatedExpr(vlaDeclStmt.getTransitiveVlaDimensionStmt(n).getDimensionExpr()) - .getResult() + result = getTranslatedExpr(this.getDimensionExpr(n)).getResult() ) ) or @@ -4237,6 +4234,10 @@ class TranslatedSizeofExpr extends TranslatedNonConstantExpr { ) } + private Expr getDimensionExpr(int n) { + result = vlaDeclStmt.getTransitiveVlaDimensionStmt(n).getDimensionExpr().getFullyConverted() + } + final override Instruction getResult() { result = this.getInstruction(SizeofVlaDimensionTag(vlaDimensions - 1)) }