public class B { private boolean maybe; public final boolean flag; public B(boolean b, boolean f) { this.maybe = b; this.flag = f; } public void caller() { callee1(new Object()); callee1(null); callee2(new Object()); } public void callee1(Object param) { param.toString(); // NPE } public void callee2(Object param) { if (param != null) { param.toString(); // OK } param.toString(); // NPE } private static boolean customIsNull(Object x) { if (x instanceof String) return false; if (x == null) return true; return x == null; } public void nullGuards() { Object o1 = maybe ? null : new Object(); if (o1 != null) o1.hashCode(); // OK Object o2 = maybe ? null : ""; if (o2 instanceof String) o2.hashCode(); // OK Object o3 = null; if ((o3 = maybe ? null : "") != null) o3.hashCode(); // OK Object o4 = maybe ? null : ""; if ((2 > 1 && o4 != null) != false) o4.hashCode(); // OK Object o5 = (o4 != null) ? "" : null; if (o5 != null) o4.hashCode(); // OK if (o4 != null) o5.hashCode(); // OK Object o6 = maybe ? null : ""; if (!customIsNull(o6)) o6.hashCode(); // OK Object o7 = maybe ? null : ""; boolean ok = o7 != null && 2 > 1; if (ok) o7.hashCode(); // OK else o7.hashCode(); // NPE Object o8 = maybe ? null : ""; int track = o8 == null ? 42 : 1+1; if (track == 2) o8.hashCode(); // OK if (track != 42) o8.hashCode(); // OK if (track < 42) o8.hashCode(); // OK if (track <= 41) o8.hashCode(); // OK } public void deref() { int[] xs = maybe ? null : new int[2]; if (2 > 1) xs[0] = 5; // NPE if (2 > 1) maybe = xs[1] > 5; // NPE if (2 > 1) { int l = xs.length; // NPE } if (2 > 1) { for (int i : xs) { } // NPE } if (2 > 1) { synchronized(xs) { // NPE xs.hashCode(); // Not reported - same basic block } } if (4 > 3) { assert xs != null; xs[0] = xs[1]; // OK } } public void f(boolean b) { String x = b ? null : "abc"; x = x == null ? "" : x; if (x == null) x.hashCode(); // OK - dead else x.hashCode(); // OK } public void lengthGuard(int[] a, int[] b) { int alen = a == null ? 0 : a.length; // OK int blen = b == null ? 0 : b.length; // OK int sum = 0; if (alen == blen) { for(int i = 0; i < alen; i++) { sum += a[i]; // OK sum += b[i]; // OK } } int alen2; if (a != null) alen2 = a.length; // OK else alen2 = 0; for(int i = 1; i <= alen2; ++i) { sum += a[i-1]; // OK } } public void missedGuard(Object obj) { obj.hashCode(); // NPE int x = obj != null ? 1 : 0; } private Object mkMaybe() { if (maybe) throw new RuntimeException(); return new Object(); } public void exceptions() { Object obj = null; try { obj = mkMaybe(); } catch(Exception e) { } obj.hashCode(); // NPE Object obj2 = null; try { obj2 = mkMaybe(); } catch(Exception e) { assert false; } obj2.hashCode(); // OK Object obj3 = null; try { obj3 = mkMaybe(); } finally { //cleanup } obj3.hashCode(); // OK } public void clearNotNull() { Object o = new Object(); if (o == null) o.hashCode(); // OK o.hashCode(); // OK try { mkMaybe(); } catch(Exception e) { if (e == null) e.hashCode(); // OK e.hashCode(); // OK } Object n = null; Object o2 = n == null ? new Object() : n; o2.hashCode(); // OK Object o3 = "abc"; if (o3 == null) o3.hashCode(); // OK o3.hashCode(); // OK Object o4 = "" + null; if (o4 == null) o4.hashCode(); // OK o4.hashCode(); // OK } public void correlatedConditions(boolean cond, int num) { Object o = null; if (cond) o = new Object(); if (cond) o.hashCode(); // OK o = null; if (flag) o = ""; if (flag) o.hashCode(); // OK o = null; Object other = maybe ? null : ""; if (other == null) o = ""; if (other != null) o.hashCode(); // NPE else o.hashCode(); // OK Object o2 = (num < 0) ? null : ""; if (num < 0) o2 = ""; else o2.hashCode(); // OK } public void trackingVariable(int[] a) { Object o = null; Object other = null; if (maybe) { o = "abc"; other = "def"; } if (other instanceof String) o.hashCode(); // OK o = null; int count = 0; boolean found = false; for (int i = 0; i < a.length; i++) { if (a[i] == 42) { o = ((Integer)a[i]).toString(); count++; if (2 > 1) { } found = true; } if (a[i] > 10000) { o = null; count = 0; if (2 > 1) { } found = false; } } if (count > 3) o.hashCode(); // OK if (found) o.hashCode(); // OK Object prev = null; for (int i = 0; i < a.length; ++i) { if (i != 0) prev.hashCode(); // OK prev = a[i]; } String s = null; if (2 > 1) { boolean s_null = true; for (int i : a) { s_null = false; s = "" + a; } if (!s_null) s.hashCode(); // OK } Object r = null; MyStatus stat = MyStatus.INIT; while (stat == MyStatus.INIT && stat != MyStatus.READY) { r = mkMaybe(); if (2 > 1) stat = MyStatus.READY; } r.hashCode(); // OK } public enum MyStatus { READY, INIT } public void g(Object obj) { String msg = null; if(obj == null) msg = "foo"; else if(obj.hashCode() > 7) { // OK msg = "bar"; } if(msg != null) { msg += "foobar"; throw new RuntimeException(msg); } obj.hashCode(); // OK } public void loopCorr(int iters) { int[] a = null; if (iters > 0) a = new int[iters]; for (int i = 0; i < iters; ++i) a[i] = 0; // OK if (iters > 0) { String last = null; for (int i = 0; i < iters; i++) last = "abc"; last.hashCode(); // OK } int[] b = maybe ? null : new int[iters]; if (iters > 0 && (b == null || b.length < iters)) { throw new RuntimeException(); } for (int i = 0; i < iters; ++i) { b[i] = 0; // OK } } void test(Exception e, boolean b) { Exception ioe = null; if (b) { ioe = new Exception(""); } if (ioe != null) { ioe = e; } else { ioe.getMessage(); // NPE; always } } public void lengthGuard2(int[] a, int[] b) { int alen = a == null ? 0 : a.length; // OK int sum = 0; int i; for(i = 0; i < alen; i++) { sum += a[i]; // OK } int blen = b == null ? 0 : b.length; // OK for(i = 0; i < blen; i++) { sum += b[i]; // OK } i = -3; } public void corrConds2(Object x, Object y) { if ((x != null && y == null) || (x == null && y != null)) return; if (x != null) y.hashCode(); // OK if (y != null) x.hashCode(); // OK } public void corrConds3(Object y) { Object x = null; if(y instanceof String) { x = new Object(); } if(y instanceof String) { x.hashCode(); // Spurious NPE - false positive } } public void corrConds4(Object y) { Object x = null; if(!(y instanceof String)) { x = new Object(); } if(!(y instanceof String)) { x.hashCode(); // Spurious NPE - false positive } } public void corrConds5(Object y, Object z) { Object x = null; if(y == z) { x = new Object(); } if(y == z) { x.hashCode(); // Spurious NPE - false positive } Object x2 = null; if(y != z) { x2 = new Object(); } if(y != z) { x2.hashCode(); // Spurious NPE - false positive } Object x3 = null; if(y != z) { x3 = new Object(); } if(!(y == z)) { x3.hashCode(); // Spurious NPE - false positive } } public void bitwise(Object x, boolean b) { boolean notnull = x != null; boolean g1 = notnull; g1 &= b; if (g1) { x.hashCode(); // OK } boolean g2 = b; g2 &= notnull; if (g2) { x.hashCode(); // OK } boolean g3 = !notnull; g3 |= b; if (!g3) { x.hashCode(); // OK } boolean g4 = b; g4 |= !notnull; if (!g4) { x.hashCode(); // OK } boolean g5 = g1 = b & notnull; if (g5) { x.hashCode(); // OK } g5 |= b; if (g5) { x.hashCode(); // NPE } } public void corrCondLoop1(boolean a[]) { Object x = new Object(); for (int i = 0; i < a.length; i++) { boolean b = a[i]; if (b) { x = null; } if (!b) { x.hashCode(); // NPE } // flow can loop around from one iteration to the next } } public void corrCondLoop2(boolean a[]) { for (int i = 0; i < a.length; i++) { // x is local to the loop iteration and thus cannot loop around and reach the sink Object x = new Object(); boolean b = a[i]; if (b) { x = null; } if (!b) { x.hashCode(); // OK } } } public void loopCorrTest1(int[] a) { boolean ready = a.length > 7; Object x = new Object(); for (int i = 0; i < a.length; i++) { // condition correlates with itself through iterations when ready isn't updated if (!ready) { x = null; } else { x.hashCode(); // OK } if ((a[i] & 1) != 0) { ready = (a[i] & 2) != 0; x = new Object(); } } } public void loopCorrTest2(boolean[] a) { Object x = new Object(); boolean cur = a[0]; for (int i = 1; i < a.length; i++) { boolean prev = cur; cur = a[i]; if (!prev) { // correctly guarded by !cur from the _previous_ iteration x.hashCode(); // Spurious NPE - false positive } else { x = new Object(); } if (cur) { x = null; } } } public void loopCorrTest3(String[] ss) { Object x = null; Object t = null; for (String s : ss) { if (t == null) { t = s; } else { if (t instanceof String) { x = new Object(); t = new Object(); } // correctly guarded by t: null -> String -> Object x.hashCode(); // Spurious NPE - false positive } } } public void initCorr(boolean b) { Object o2 = b ? null : ""; if (b) o2 = ""; else o2.hashCode(); // OK } public void complexLoopTest(int[] xs, int[] ys) { int len = ys != null ? ys.length : 0; for (int i = 0, j = 0; i < xs.length; i++) { if (j < len && ys[j] == 42) { // OK j++; } else if (j > 0) { ys[0]++; // OK } } } public void trackTest(Object o, int n) { boolean isnull = o == null; int c = -1; if (maybe) { } if (c == 100) { return; } o.hashCode(); // NPE } public void testFinally(int[] xs, int[] ys) { if (xs.length == 0) return; if (ys.length == 0) return; String s1 = null; String s2 = null; for (int x : xs) { try { if (x == 0) { break; } s1 = "1"; for (int y : ys) { if (y == 0) { break; } s2 = "2"; } } finally { } s1.hashCode(); // OK s2.hashCode(); // NPE } s1.hashCode(); // NPE - false negative, Java CFG lacks proper edge label } public void lenCheck(int[] xs, int n, int t) { if (n > 42) return; if (maybe) {} if (n > 0 && (xs == null || xs.length < n)) { return; } if (maybe) {} if (n > 21) return; if (maybe) {} for (int i = 0; i < n; ++i) { xs[i]++; // OK } } public void rangetest(int n) { String s = null; if (n < 0 || n > 10) s = "A"; if (n > 100) s.hashCode(); // OK if (n == 42) s.hashCode(); // OK } }