浏览代码

[hl] allow assign struct to packed (#12043)

* [hl] allow assign struct to packed

* Fix assign null cause access violation

* Move is_packed check to only where it's needed

* Add a space in args while we are here
Yuxiao Mao 7 月之前
父节点
当前提交
7726475e66
共有 4 个文件被更改,包括 101 次插入11 次删除
  1. 12 9
      src/generators/genhl.ml
  2. 7 2
      src/generators/hl2c.ml
  3. 2 0
      src/generators/hlcode.ml
  4. 80 0
      tests/unit/src/unit/issues/Issue12043.hx

+ 12 - 9
src/generators/genhl.ml

@@ -130,7 +130,7 @@ type access =
 	| AStaticFun of fundecl index
 	| AInstanceFun of texpr * fundecl index
 	| AInstanceProto of texpr * field index
-	| AInstanceField of texpr * field index
+	| AInstanceField of texpr * field index * bool
 	| AArray of reg * (ttype * ttype) * reg
 	| ACArray of reg * ttype * reg
 	| AVirtualMethod of texpr * field index
@@ -1326,11 +1326,12 @@ and object_access ctx eobj t f =
 	match t with
 	| HObj p | HStruct p ->
 		(try
-			let fid = fst (get_index f.cf_name p) in
+			let fid, t = get_index f.cf_name p in
 			if f.cf_kind = Method MethNormal then
 				AInstanceProto (eobj, -fid-1)
 			else
-				AInstanceField (eobj, fid)
+				let is_packed = match t with | HPacked _ -> true | _ -> false in
+				AInstanceField (eobj, fid, is_packed)
 		with Not_found ->
 			ADynamic (eobj, alloc_string ctx f.cf_name))
 	| HVirtual v ->
@@ -1339,7 +1340,7 @@ and object_access ctx eobj t f =
 			if f.cf_kind = Method MethNormal then
 				AVirtualMethod (eobj, fid)
 			else
-				AInstanceField (eobj, fid)
+				AInstanceField (eobj, fid, false)
 		with Not_found ->
 			ADynamic (eobj, alloc_string ctx f.cf_name))
 	| HDyn ->
@@ -2175,7 +2176,7 @@ and eval_expr ctx e =
 				| _ -> abort "Constant mode required" e.epos
 			) in
 			(match get_access ctx value with
-			| AInstanceField (f, index) -> op ctx (OPrefetch (eval_expr ctx f, index + 1, mode))
+			| AInstanceField (f, index, _) -> op ctx (OPrefetch (eval_expr ctx f, index + 1, mode))
 			| _ -> op ctx (OPrefetch (eval_expr ctx value, 0, mode)));
 			alloc_tmp ctx HVoid
         | "$unsafecast", [value] ->
@@ -2323,7 +2324,7 @@ and eval_expr ctx e =
 			op ctx (OStaticClosure (r,f));
 		| AInstanceFun (ethis, f) ->
 			op ctx (OInstanceClosure (r, f, eval_null_check ctx ethis))
-		| AInstanceField (ethis,fid) ->
+		| AInstanceField (ethis, fid, _) ->
 			let robj = eval_null_check ctx ethis in
 			op ctx (match ethis.eexpr with TConst TThis -> OGetThis (r,fid) | _ -> OField (r,robj,fid));
 		| AInstanceProto (ethis,fid) | AVirtualMethod (ethis, fid) ->
@@ -2521,15 +2522,17 @@ and eval_expr ctx e =
 				op ctx (OGetGlobal (o, g));
 				op ctx (OSetField (o, fid, r));
 				r
-			| AInstanceField ({ eexpr = TConst TThis }, fid) ->
+			| AInstanceField ({ eexpr = TConst TThis }, fid, is_packed) ->
 				let r = value() in
+				if is_packed then op ctx (ONullCheck r);
 				op ctx (OSetThis (fid,r));
 				r
-			| AInstanceField (ethis, fid) ->
+			| AInstanceField (ethis, fid, is_packed) ->
 				let rthis = eval_null_check ctx ethis in
 				hold ctx rthis;
 				let r = value() in
 				free ctx rthis;
+				if is_packed then op ctx (ONullCheck r);
 				op ctx (OSetField (rthis, fid, r));
 				r
 			| ALocal (v,l) ->
@@ -3087,7 +3090,7 @@ and gen_assign_op ctx acc e1 f =
 			f r
 	in
 	match acc with
-	| AInstanceField (eobj, findex) ->
+	| AInstanceField (eobj, findex, _) ->
 		let robj = eval_null_check ctx eobj in
 		hold ctx robj;
 		let t = real_type ctx e1 in

+ 7 - 2
src/generators/hl2c.ml

@@ -542,8 +542,13 @@ let generate_function ctx f =
 	let funname fid = define_function ctx fid in
 
 	let rcast r t =
-		if tsame (rtype r) t then (reg r)
-		else Printf.sprintf "((%s)%s)" (ctype t) (reg r)
+		let rt = (rtype r) in
+		if tsame rt t then (reg r)
+		else match t, rt with
+		| HPacked _, HStruct _ ->
+			Printf.sprintf "(*(%s*)%s)" (ctype t) (reg r)
+		| _ ->
+			Printf.sprintf "((%s)%s)" (ctype t) (reg r)
 	in
 
 	let rfun r args t =

+ 2 - 0
src/generators/hlcode.ml

@@ -355,6 +355,8 @@ let rec safe_cast t1 t2 =
 		loop p1
 	| HPacked t1, HStruct _ ->
 		safe_cast t1 t2
+	| HStruct _, HPacked t2 ->
+		safe_cast t1 t2
 	| HFun (args1,t1), HFun (args2,t2) when List.length args1 = List.length args2 ->
 		List.for_all2 (fun t1 t2 -> safe_cast t2 t1 || (t1 = HDyn && is_dynamic t2)) args1 args2 && safe_cast t1 t2
 	| HArray t1,HArray t2 ->

+ 80 - 0
tests/unit/src/unit/issues/Issue12043.hx

@@ -0,0 +1,80 @@
+package unit.issues;
+
+#if hl
+private class Parent {
+	@:packed public var st : St;
+	@:packed public var st1 : St;
+	public function new() {
+	}
+}
+
+@:struct private class St {
+	public var x : Single;
+	public var y : Single;
+	public var z : Single;
+	public function new( x : Single, y : Single, z : Single ) {
+		this.x = x;
+		this.y = y;
+		this.z = z;
+	}
+}
+#end
+
+class Issue12043 extends Test {
+	#if hl
+	var p : Parent;
+	@:packed var st2 : St;
+	var st3 : St;
+	function test() {
+		// assign @:struct to @:packed
+		st3 = new St(16.3, 17.3, 18.3);
+		st2 = new St(13.3, 14.3, 15.3);
+		p = new Parent();
+		p.st1 = st2;
+		p.st = new St(10.3, 11.3, 12.3);
+		feq(10.3, p.st.x);
+		feq(11.3, p.st.y);
+		feq(12.3, p.st.z);
+		feq(13.3, p.st1.x);
+		feq(14.3, p.st1.y);
+		feq(15.3, p.st1.z);
+		feq(13.3, st2.x);
+		feq(14.3, st2.y);
+		feq(15.3, st2.z);
+		feq(16.3, st3.x);
+		feq(17.3, st3.y);
+		feq(18.3, st3.z);
+
+		// assign inside @:packed
+		p.st.y = 7.7;
+		st2.y = 8.8;
+		st3.y = 9.9;
+		feq(10.3, p.st.x);
+		feq(7.7, p.st.y);
+		feq(12.3, p.st.z);
+		feq(13.3, p.st1.x);
+		feq(14.3, p.st1.y); // p.st1 is a copy and is not impacted
+		feq(15.3, p.st1.z);
+		feq(13.3, st2.x);
+		feq(8.8, st2.y);
+		feq(15.3, st2.z);
+		feq(16.3, st3.x);
+		feq(9.9, st3.y);
+		feq(18.3, st3.z);
+
+		// assign null to @:packed
+		try {
+			p.st = null;
+			assert("Assign null to @:packed is currently not allowed");
+		} catch (e) {
+			eq("Null access", e.message);
+		}
+		try {
+			st2 = null;
+			assert("Assign null to @:packed is currently not allowed");
+		} catch (e) {
+			eq("Null access", e.message);
+		}
+	}
+	#end
+}