Browse Source

[cpp] Forbid questionable value type heap construction (#12457)

* Forbid questionable value type heap construction

* Add tests to ensure compilation fails

* Shuffle tests into cpp folder

* Tweak error message
Aidan Lee 1 week ago
parent
commit
8aa38a1b98

+ 2 - 0
src/generators/cpp/cppError.ml

@@ -13,6 +13,7 @@ type cppError =
     | ExtendingManagedType
     | ExtendingManagedType
     | UnresolvedTypeParameter of string
     | UnresolvedTypeParameter of string
     | PromotedStackOnlyValueType
     | PromotedStackOnlyValueType
+    | HeapAllocationOfValueType
 
 
 let cpp_abort error pos =
 let cpp_abort error pos =
     let print = Printf.sprintf "CPP%0*i: %s" 4 in
     let print = Printf.sprintf "CPP%0*i: %s" 4 in
@@ -30,6 +31,7 @@ let cpp_abort error pos =
         | ExtendingManagedType -> print 9 "Class cannot extend a managed type extern"
         | ExtendingManagedType -> print 9 "Class cannot extend a managed type extern"
         | UnresolvedTypeParameter s -> print 10 (Printf.sprintf "Unable to resolve parameter %s, consider adding a type hint" s)
         | UnresolvedTypeParameter s -> print 10 (Printf.sprintf "Unable to resolve parameter %s, consider adding a type hint" s)
         | PromotedStackOnlyValueType -> print 11 "Marshalling value type with the StackOnly flag cannot be promoted to the heap"
         | PromotedStackOnlyValueType -> print 11 "Marshalling value type with the StackOnly flag cannot be promoted to the heap"
+        | HeapAllocationOfValueType -> print 12 "Value type cannot be allocated directly to a pointer"
     in
     in
 
 
     abort str pos
     abort str pos

+ 6 - 0
src/generators/cpp/filters/cppFilterValueType.ml

@@ -1,5 +1,6 @@
 open CppAst
 open CppAst
 open CppAstTools
 open CppAstTools
+open CppError
 
 
 (* If we are constructing a value type of reference state, inspect the surrounding context and choose a more appropriate construction *)
 (* If we are constructing a value type of reference state, inspect the surrounding context and choose a more appropriate construction *)
 let filter_determine_construction return_type cppexpr =
 let filter_determine_construction return_type cppexpr =
@@ -8,6 +9,11 @@ let filter_determine_construction return_type cppexpr =
   in
   in
 
 
   match cppexpr.cpptype, return_type, cppexpr.cppexpr with
   match cppexpr.cpptype, return_type, cppexpr.cppexpr with
+  (* Allocating a value type directly into a pointer type is ambiguous at best and UB C++ at worse, so forbid it entirely *)
+  | _, TCppStar (TCppMarshalNativeType ((ValueClass _ | ValueEnum _), _), _), CppCall ((FuncNew _), _)
+  | _, TCppPointer (_, TCppMarshalNativeType ((ValueClass _ | ValueEnum _), _)), CppCall ((FuncNew _), _)
+  | _, TCppRawPointer (_, TCppMarshalNativeType ((ValueClass _ | ValueEnum _), _)), CppCall ((FuncNew _), _) ->
+    cpp_abort HeapAllocationOfValueType cppexpr.cpppos
   | TCppMarshalNativeType (value_type, Reference), TCppMarshalNativeType (_, Stack), CppCall ((FuncNew _), args) ->
   | TCppMarshalNativeType (value_type, Reference), TCppMarshalNativeType (_, Stack), CppCall ((FuncNew _), args) ->
     let stack = TCppMarshalNativeType (value_type, Stack) in
     let stack = TCppMarshalNativeType (value_type, Stack) in
     { cppexpr with cpptype = stack; cppexpr = CppCall ((FuncNew stack), args) }
     { cppexpr with cpptype = stack; cppexpr = CppCall ((FuncNew stack), args) }

+ 13 - 0
tests/misc/cpp/projects/Issue12457/Compile1.hx

@@ -0,0 +1,13 @@
+@:semantics(value)
+@:cpp.ValueType
+extern class Struct {
+    function new();
+    var a:Int;
+}
+
+@:headerCode("struct Struct { int a; Struct() {} };")
+class Compile1 {
+    static function main() {
+        final struct : cpp.Star<Struct> = cast new Struct();
+    }
+}

+ 13 - 0
tests/misc/cpp/projects/Issue12457/Compile2.hx

@@ -0,0 +1,13 @@
+@:semantics(value)
+@:cpp.ValueType
+extern class Struct {
+    function new();
+    var a:Int;
+}
+
+@:headerCode("struct Struct { int a; Struct() {} };")
+class Compile2 {
+    static function main() {
+        final struct : cpp.RawPointer<Struct> = cast new Struct();
+    }
+}

+ 13 - 0
tests/misc/cpp/projects/Issue12457/Compile3.hx

@@ -0,0 +1,13 @@
+@:semantics(value)
+@:cpp.ValueType
+extern class Struct {
+    function new();
+    var a:Int;
+}
+
+@:headerCode("struct Struct { int a; Struct() {} };")
+class Compile3 {
+    static function main() {
+        final struct : cpp.Pointer<Struct> = cast new Struct();
+    }
+}

+ 3 - 0
tests/misc/cpp/projects/Issue12457/compile1-fail.hxml

@@ -0,0 +1,3 @@
+-m Compile1
+--cpp bin
+--debug

+ 1 - 0
tests/misc/cpp/projects/Issue12457/compile1-fail.hxml.stderr

@@ -0,0 +1 @@
+Compile1.hx:11: characters 48-60 : CPP0012: Value type cannot be allocated directly to a pointer

+ 3 - 0
tests/misc/cpp/projects/Issue12457/compile2-fail.hxml

@@ -0,0 +1,3 @@
+-m Compile2
+--cpp bin
+--debug

+ 1 - 0
tests/misc/cpp/projects/Issue12457/compile2-fail.hxml.stderr

@@ -0,0 +1 @@
+Compile2.hx:11: characters 54-66 : CPP0012: Value type cannot be allocated directly to a pointer

+ 3 - 0
tests/misc/cpp/projects/Issue12457/compile3-fail.hxml

@@ -0,0 +1,3 @@
+-m Compile3
+--cpp bin
+--debug

+ 1 - 0
tests/misc/cpp/projects/Issue12457/compile3-fail.hxml.stderr

@@ -0,0 +1 @@
+Compile3.hx:11: characters 51-63 : CPP0012: Value type cannot be allocated directly to a pointer