From 8212a66ff27e56531e0b48807088f1c544d75756 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Mon, 28 Sep 2026 09:23:27 -0700 Subject: Check un-init not-null constructor fields Propagate BOT inputs; Arith, Load. CallEnd inlining, the FUnPtr dies early. Load asserts when loading against uninit not-null field. Keep not-nill state for storage class. Clean up Node.peep as constant. --- .../src/main/java/com/seaofnodes/simple/node/LoadNode.java | 1 + .../src/main/java/com/seaofnodes/simple/node/StoreNode.java | 2 ++ .../src/test/java/com/seaofnodes/simple/Chapter10Test.java | 6 +++++- .../src/test/java/com/seaofnodes/simple/Chapter16Test.java | 13 +++++-------- 4 files changed, 13 insertions(+), 9 deletions(-) (limited to 'chapter22/src') diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/LoadNode.java index 4f09400a..e0a6d09a 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/LoadNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/LoadNode.java @@ -145,6 +145,7 @@ public class LoadNode extends MemOpNode { private Node zero(NewNode nnn) { TypeStruct ts = nnn._ptr._obj; Type zero = ts._fields[ts.findAlias(_alias)]._type.makeZero(); + assert zero.isa(_type); // Catch an uninitialized non-null field return castRO(new ConstantNode(zero).peephole()); } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java index ce989826..e151911c 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java @@ -123,6 +123,8 @@ public class StoreNode extends MemOpNode { public Parser.ParseException err() { Parser.ParseException err = super.err(); if( err != null ) return err; + if( ptr()._type == Type.TOP ) + return null; // Dead store TypeMemPtr tmp = (TypeMemPtr)ptr()._type; if( tmp._obj.field(_name)._final && !_init ) return Parser.error("Cannot modify final field '"+_name+"'",_loc); diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/chapter22/src/test/java/com/seaofnodes/simple/Chapter10Test.java index 9b5d5da6..aa2cd941 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/Chapter10Test.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/Chapter10Test.java @@ -47,6 +47,7 @@ public class Chapter10Test { public void testNullGuardErrors() { for( String body : new String[] { "return p.x;", + "if (p == null) return p.x; return -1;", "if (!!points) return p.x; return -1;", "if (!!p) { int x = p.x; } return p.x;" } ) { @@ -54,7 +55,10 @@ public class Chapter10Test { new CodeGen(NULLABLE_POINT_SOURCE+body).parse().opto().typeCheck(); fail(body); } catch( RuntimeException e ) { - assertEquals(body,"Might be null accessing 'x'",e.getMessage()); + // Known null is rejected during parsing in these chapters. + String expected = body.startsWith("if (p == null)") + ? "Accessing unknown field 'x' from 'null'" : "Might be null accessing 'x'"; + assertEquals(body,expected,e.getMessage()); } } } diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Chapter16Test.java b/chapter22/src/test/java/com/seaofnodes/simple/Chapter16Test.java index 58bb4148..e7163075 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/Chapter16Test.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/Chapter16Test.java @@ -145,14 +145,11 @@ return p; @Test public void testStructFinal3() { - CodeGen code = new CodeGen(""" -struct Point { var x; var y; }; -Point p = new Point; -p.x++; -return p; -"""); - try { code.parse().opto(); fail(); } - catch( Exception e ) { assertEquals("'Point' is not fully initialized, field 'x' needs to be set in a constructor",e.getMessage()); } + for( String fields : new String[] { "var x; var y;", "int[] x;", "int[] !x;" } ) { + String src = "struct Point { "+fields+" }; Point p = new Point; p.x++; return p;"; + try { new CodeGen(src).parse().opto(); fail(fields); } + catch( Exception e ) { assertEquals("'Point' is not fully initialized, field 'x' needs to be set in a constructor",e.getMessage()); } + } } @Test -- cgit v1.2.3