From e29c22656458e9252ca0fc32a396d605496b4b4d Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Mon, 5 Aug 2024 13:52:54 -0700 Subject: More error cases, error checking disallow e.g. "struct x { int i; }; x = new x; x.i=3.14;" --- .../main/java/com/seaofnodes/simple/Parser.java | 5 ++- .../java/com/seaofnodes/simple/node/LoadNode.java | 4 +- .../java/com/seaofnodes/simple/node/MemOpNode.java | 10 +++-- .../main/java/com/seaofnodes/simple/node/Node.java | 2 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 14 +++++- .../java/com/seaofnodes/simple/Chapter12Test.java | 50 ++++++++++++++++++++++ 6 files changed, 74 insertions(+), 11 deletions(-) diff --git a/chapter13/src/main/java/com/seaofnodes/simple/Parser.java b/chapter13/src/main/java/com/seaofnodes/simple/Parser.java index bde697d6..fee5215e 100644 --- a/chapter13/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter13/src/main/java/com/seaofnodes/simple/Parser.java @@ -596,7 +596,7 @@ public class Parser { Node n = new NewNode(TypeMemPtr.make(obj), ctrl()).peephole().keep(); int alias = START._aliasStarts.get(obj._name); for( Field field : obj._fields ) { - memAlias(alias, new StoreNode(field._fname, alias, memAlias(alias), n, new ConstantNode(field._type.makeInit()).peephole()).peephole()); + memAlias(alias, new StoreNode(field._fname, alias, field._type, memAlias(alias), n, new ConstantNode(field._type.makeInit()).peephole(),true).peephole()); alias++; } return n.unkeep(); @@ -637,7 +637,8 @@ public class Parser { if( peek('=') ) _lexer._position--; else { Node val = parseExpression(); - memAlias(alias, new StoreNode(name, alias, memAlias(alias), expr, val).peephole()); + Type glb = base._fields[idx]._type; + memAlias(alias, new StoreNode(name, alias,glb, memAlias(alias), expr, val, false).peephole()); return expr; // "obj.a = expr" returns the expression while updating memory } } diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/LoadNode.java index 0c5d72e5..4e1421fa 100644 --- a/chapter13/src/main/java/com/seaofnodes/simple/node/LoadNode.java +++ b/chapter13/src/main/java/com/seaofnodes/simple/node/LoadNode.java @@ -11,7 +11,6 @@ import java.util.BitSet; */ public class LoadNode extends MemOpNode { - Type _declaredType; /** * Load a value from a ptr.field. * @@ -20,8 +19,7 @@ public class LoadNode extends MemOpNode { * @param memPtr The ptr to the struct from where we load a field */ public LoadNode(String name, int alias, Type glb, Node memSlice, Node memPtr) { - super(name, alias, memSlice, memPtr); - _declaredType = glb; + super(name, alias, glb, memSlice, memPtr); } @Override public String label() { return _name; } diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/MemOpNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/MemOpNode.java index 7f8d060a..bc8e46d3 100644 --- a/chapter13/src/main/java/com/seaofnodes/simple/node/MemOpNode.java +++ b/chapter13/src/main/java/com/seaofnodes/simple/node/MemOpNode.java @@ -11,14 +11,18 @@ public abstract class MemOpNode extends Node { public final String _name; public final int _alias; + public final Type _declaredType; - public MemOpNode(String name, int alias, Node memSlice, Node memPtr) { + + public MemOpNode(String name, int alias, Type glb, Node memSlice, Node memPtr) { super(null, memSlice, memPtr); _name = name; _alias = alias; + _declaredType = glb; + } - public MemOpNode(String name, int alias, Node memSlice, Node memPtr, Node value) { - this(name, alias, memSlice, memPtr); + public MemOpNode(String name, int alias, Type glb, Node memSlice, Node memPtr, Node value) { + this(name, alias, glb, memSlice, memPtr); addDef(value); } diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter13/src/main/java/com/seaofnodes/simple/node/Node.java index 52282737..d846fcef 100644 --- a/chapter13/src/main/java/com/seaofnodes/simple/node/Node.java +++ b/chapter13/src/main/java/com/seaofnodes/simple/node/Node.java @@ -137,7 +137,7 @@ public abstract class Node implements OutNode { public boolean isUnused() { return nOuts() == 0; } - public CFGNode cfg0() { return (CFGNode)in(0); } + public CFGNode cfg0() { return (CFGNode)in(0); } /** * Change a def into a Node. Keeps the edges correct, by removing diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/StoreNode.java index 89141892..44a14be1 100644 --- a/chapter13/src/main/java/com/seaofnodes/simple/node/StoreNode.java +++ b/chapter13/src/main/java/com/seaofnodes/simple/node/StoreNode.java @@ -11,14 +11,17 @@ import java.util.BitSet; */ public class StoreNode extends MemOpNode { + private final boolean _init; // Initializing writes are allowed to write null + /** * @param name The struct field we are assigning to * @param memSlice The memory alias node - this is updated after a Store * @param memPtr The ptr to the struct where we will store a value * @param value Value to be stored */ - public StoreNode(String name, int alias, Node memSlice, Node memPtr, Node value) { - super(name, alias, memSlice, memPtr, value); + public StoreNode(String name, int alias, Type glb, Node memSlice, Node memPtr, Node value, boolean init) { + super(name, alias, glb, memSlice, memPtr, value); + _init = init; } @Override public String label() { return "ST"+_name; } @@ -65,4 +68,11 @@ public class StoreNode extends MemOpNode { return false; } + @Override + String err() { + String err = super.err(); + if( err != null ) return err; + Type ptr = val()._type; + return _init || ptr.isa(_declaredType) ? null : "Cannot store "+ptr+" into field "+_declaredType+" "+_name; + } } diff --git a/chapter13/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter13/src/test/java/com/seaofnodes/simple/Chapter12Test.java index e36c7577..8eceb0fa 100644 --- a/chapter13/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/chapter13/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -121,4 +121,54 @@ return f0.i.f.i.i; assertEquals("return 17;", stop.toString()); } + @Test + public void testNullRef0() { + Parser parser = new Parser( +""" +struct N { N next; int i; } +N n = new N; +return n.next; +"""); + StopNode stop = parser.parse(false).iterate(false); + assertEquals("return null;", stop.toString()); + } + + @Test + public void testNullRef1() { + Parser parser = new Parser( +""" +struct N { N next; int i; } +N n = new N; +n.next = new N; +return n.next; +"""); + StopNode stop = parser.parse(false).iterate(false); + assertEquals("return new N;", stop.toString()); + } + + @Test + public void testNullRef2() { + Parser parser = new Parser( +""" +struct N { N next; int i; } +N n = new N; +n.next = null; +return n.next; +"""); + try { parser.parse(true).iterate(true); fail(); } + catch( Exception e ) { assertEquals("Cannot store null into field *N next",e.getMessage()); } + } + + @Test + public void testNullRef3() { + Parser parser = new Parser( +""" +struct N { N next; int i; } +N n = new N; +n.i = 3.14; +return n.i; +"""); + try { parser.parse(true).iterate(true); fail(); } + catch( Exception e ) { assertEquals("Cannot store 3.14 into field IntBot i",e.getMessage()); } + } } -- cgit v1.2.3