Browse Source

Don't allow sibling class access to private constructor (#6957)

Ben Morris 7 years ago
parent
commit
44e85a146b

+ 16 - 11
src/context/typecore.ml

@@ -373,17 +373,22 @@ let rec can_access ctx ?(in_overload=false) c cf stat =
 	loop ctx.curclass;
 	loop ctx.curclass;
 	let is_constr = cf.cf_name = "new" in
 	let is_constr = cf.cf_name = "new" in
 	let rec loop c =
 	let rec loop c =
-		(try
-			(* if our common ancestor declare/override the field, then we can access it *)
-			let f = if is_constr then (match c.cl_constructor with None -> raise Not_found | Some c -> c) else PMap.find cf.cf_name (if stat then c.cl_statics else c.cl_fields) in
-			is_parent c ctx.curclass || (List.exists (has Meta.Allow c f) !cur_paths)
-		with Not_found ->
-			false
-		)
-		|| (match c.cl_super with
-		| Some (csup,_) -> loop csup
-		| None -> false)
-		|| has Meta.Access ctx.curclass ctx.curfield (make_path c cf)
+		try
+			has Meta.Access ctx.curclass ctx.curfield (make_path c cf)
+			|| (
+				(* if our common ancestor declare/override the field, then we can access it *)
+				let allowed f = is_parent c ctx.curclass || (List.exists (has Meta.Allow c f) !cur_paths) in
+				if is_constr
+				then (match c.cl_constructor with
+					| Some cf -> if allowed cf then true else raise Not_found
+					| _ -> false
+				)
+				else try allowed (PMap.find cf.cf_name (if stat then c.cl_statics else c.cl_fields)) with Not_found -> false
+			)
+			|| (match c.cl_super with
+			| Some (csup,_) -> loop csup
+			| None -> false)
+		with Not_found -> false
 	in
 	in
 	let b = loop c
 	let b = loop c
 	(* access is also allowed of we access a type parameter which is constrained to our (base) class *)
 	(* access is also allowed of we access a type parameter which is constrained to our (base) class *)

+ 1 - 1
src/typing/typer.ml

@@ -2965,7 +2965,7 @@ and type_new ctx path el with_type p =
 	let build_constructor_call c tl =
 	let build_constructor_call c tl =
 		let ct, f = get_constructor ctx c tl p in
 		let ct, f = get_constructor ctx c tl p in
 		if (Meta.has Meta.CompilerGenerated f.cf_meta) then display_error ctx (error_msg (No_constructor (TClassDecl c))) p;
 		if (Meta.has Meta.CompilerGenerated f.cf_meta) then display_error ctx (error_msg (No_constructor (TClassDecl c))) p;
-		if not (can_access ctx c f true || is_parent c ctx.curclass) && not ctx.untyped then display_error ctx "Cannot access private constructor" p;
+		if not (can_access ctx c f true || is_parent c ctx.curclass) && not ctx.untyped then display_error ctx (Printf.sprintf "Cannot access private constructor of %s" (s_type_path c.cl_path)) p;
 		(match f.cf_kind with
 		(match f.cf_kind with
 		| Var { v_read = AccRequire (r,msg) } -> (match msg with Some msg -> error msg p | None -> error_require r p)
 		| Var { v_read = AccRequire (r,msg) } -> (match msg with Some msg -> error msg p | None -> error_require r p)
 		| _ -> ());
 		| _ -> ());

+ 14 - 0
tests/misc/projects/Issue5871/Main.hx

@@ -0,0 +1,14 @@
+class Base {
+	var v = 0;
+}
+
+class Child extends Base {
+	private function new() {}
+}
+
+class Main extends Base {
+	static function main() {
+		// shouldn't be possible; Child's constructor is private
+		new Child();
+	}
+}

+ 15 - 0
tests/misc/projects/Issue5871/Main2.hx

@@ -0,0 +1,15 @@
+class Base {
+	private function new() {}
+	var v = 0;
+}
+
+class Child extends Base {
+	private function new() super();
+}
+
+class Main2 extends Base {
+	static function main() {
+		// shouldn't be possible; Child's constructor is private
+		new Child();
+	}
+}

+ 2 - 0
tests/misc/projects/Issue5871/parent-constructor-fail.hxml

@@ -0,0 +1,2 @@
+-main Main2
+--interp

+ 1 - 0
tests/misc/projects/Issue5871/parent-constructor-fail.hxml.stderr

@@ -0,0 +1 @@
+Main2.hx:13: characters 3-14 : Cannot access private constructor of Child

+ 2 - 0
tests/misc/projects/Issue5871/parent-no-constructor-fail.hxml

@@ -0,0 +1,2 @@
+-main Main
+--interp

+ 1 - 0
tests/misc/projects/Issue5871/parent-no-constructor-fail.hxml.stderr

@@ -0,0 +1 @@
+Main.hx:12: characters 3-14 : Cannot access private constructor of Child

+ 1 - 1
tests/unit/src/unit/issues/Issue5323.hx

@@ -1,6 +1,6 @@
 package unit.issues;
 package unit.issues;
 class Issue5323 extends Test{
 class Issue5323 extends Test{
-	function new() super();
+	public function new() super();
     function test() {
     function test() {
     	var expected = 1;
     	var expected = 1;
         var actual = new Issue5323().doStuff(function() return 0);
         var actual = new Issue5323().doStuff(function() return 0);