From 08e314610230c114dda6bfc1f286bff2fc9abacf Mon Sep 17 00:00:00 2001 From: reuk Date: Tue, 21 Feb 2017 10:56:48 +0000 Subject: [PATCH 01/39] Add nondet methods to CProver class --- .../library/src/org/cprover/CProver.java | 106 +++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/src/java_bytecode/library/src/org/cprover/CProver.java b/src/java_bytecode/library/src/org/cprover/CProver.java index 72c3eeb1d70..46ad7723c9b 100644 --- a/src/java_bytecode/library/src/org/cprover/CProver.java +++ b/src/java_bytecode/library/src/org/cprover/CProver.java @@ -3,9 +3,113 @@ public final class CProver { public static boolean enableAssume=true; + public static boolean enableNondet=true; + + public static boolean nondetBoolean() + { + if (enableNondet) + { + throw new RuntimeException( + "Cannot execute program with CProver.nondetBoolean()"); + } + + return false; + } + + public static byte nondetByte() + { + if (enableNondet) + { + throw new RuntimeException( + "Cannot execute program with CProver.nondetByte()"); + } + + return 0; + } + + public static char nondetChar() + { + if (enableNondet) + { + throw new RuntimeException( + "Cannot execute program with CProver.nondetChar()"); + } + + return '\0'; + } + + public static short nondetShort() + { + if (enableNondet) + { + throw new RuntimeException( + "Cannot execute program with CProver.nondetShort()"); + } + + return 0; + } + + public static int nondetInt() + { + if (enableNondet) + { + throw new RuntimeException( + "Cannot execute program with CProver.nondetInt()"); + } + + return 0; + } + + public static long nondetLong() + { + if (enableNondet) + { + throw new RuntimeException( + "Cannot execute program with CProver.nondetLong()"); + } + + return 0; + } + + public static float nondetFloat() + { + if (enableNondet) + { + throw new RuntimeException( + "Cannot execute program with CProver.nondetFloat()"); + } + + return 0; + } + + public static double nondetDouble() + { + if (enableNondet) + { + throw new RuntimeException( + "Cannot execute program with CProver.nondetDouble()"); + } + + return 0; + } + + public static T nondet() + { + if (enableNondet) + { + throw new RuntimeException( + "Cannot execute program with CProver.nondet()"); + } + + return null; + } + public static void assume(boolean condition) { if(enableAssume) - throw new RuntimeException("Cannot execute program with CProver.assume()"); + { + throw new RuntimeException( + "Cannot execute program with CProver.assume()"); + } } } From 049324907383f4893249f4c12ce46857431beb0c Mon Sep 17 00:00:00 2001 From: reuk Date: Tue, 21 Feb 2017 10:57:29 +0000 Subject: [PATCH 02/39] Add nondet regression test cases --- .../cbmc-java/nondetBoolean/NondetBoolean.class | Bin 0 -> 310 bytes .../cbmc-java/nondetBoolean/NondetBoolean.java | 9 +++++++++ regression/cbmc-java/nondetByte/NondetByte.class | Bin 0 -> 301 bytes regression/cbmc-java/nondetByte/NondetByte.java | 9 +++++++++ regression/cbmc-java/nondetChar/NondetChar.class | Bin 0 -> 301 bytes regression/cbmc-java/nondetChar/NondetChar.java | 9 +++++++++ .../cbmc-java/nondetDouble/NondetDouble.class | Bin 0 -> 307 bytes .../cbmc-java/nondetDouble/NondetDouble.java | 9 +++++++++ .../cbmc-java/nondetFloat/NondetFloat.class | Bin 0 -> 304 bytes regression/cbmc-java/nondetFloat/NondetFloat.java | 9 +++++++++ regression/cbmc-java/nondetInt/NondetInt.class | Bin 0 -> 298 bytes regression/cbmc-java/nondetInt/NondetInt.java | 9 +++++++++ regression/cbmc-java/nondetLong/NondetLong.class | Bin 0 -> 301 bytes regression/cbmc-java/nondetLong/NondetLong.java | 9 +++++++++ .../cbmc-java/nondetShort/NondetShort.class | Bin 0 -> 304 bytes regression/cbmc-java/nondetShort/NondetShort.java | 9 +++++++++ 16 files changed, 72 insertions(+) create mode 100644 regression/cbmc-java/nondetBoolean/NondetBoolean.class create mode 100644 regression/cbmc-java/nondetBoolean/NondetBoolean.java create mode 100644 regression/cbmc-java/nondetByte/NondetByte.class create mode 100644 regression/cbmc-java/nondetByte/NondetByte.java create mode 100644 regression/cbmc-java/nondetChar/NondetChar.class create mode 100644 regression/cbmc-java/nondetChar/NondetChar.java create mode 100644 regression/cbmc-java/nondetDouble/NondetDouble.class create mode 100644 regression/cbmc-java/nondetDouble/NondetDouble.java create mode 100644 regression/cbmc-java/nondetFloat/NondetFloat.class create mode 100644 regression/cbmc-java/nondetFloat/NondetFloat.java create mode 100644 regression/cbmc-java/nondetInt/NondetInt.class create mode 100644 regression/cbmc-java/nondetInt/NondetInt.java create mode 100644 regression/cbmc-java/nondetLong/NondetLong.class create mode 100644 regression/cbmc-java/nondetLong/NondetLong.java create mode 100644 regression/cbmc-java/nondetShort/NondetShort.class create mode 100644 regression/cbmc-java/nondetShort/NondetShort.java diff --git a/regression/cbmc-java/nondetBoolean/NondetBoolean.class b/regression/cbmc-java/nondetBoolean/NondetBoolean.class new file mode 100644 index 0000000000000000000000000000000000000000..415b625be6dbb132549f4a14faebf7593c968fa1 GIT binary patch literal 310 zcmY+8KTpFj5XIjmr4A;grDa8e4H(G624bL6r>aycVqkMpQ>6+%WTpLHOjI5C0DLIK zITHUY*>`&Wy?6KVxqSz4i9?MRQjHGw6}k#NLi@UOWqm`4PtP6*ts&1Xp*t>}ovfa7 z>+eloi4s3C6ZDK%zObV*Nc{=Bxvg)RD{I`v(yUF29kdk=QuHw(bp8>9USP7yxJ7oC zFKtm12J9DE@#1-HeKwpnRgCU$bhF$ejuFfH;Y4y}5C}@TBdHXW^Ec3|G=xOn@C~sf a*!@9IzR?Y$t6x+%iAvHF0kqg6?0o^rqBr3H literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetBoolean/NondetBoolean.java b/regression/cbmc-java/nondetBoolean/NondetBoolean.java new file mode 100644 index 00000000000..925d921da43 --- /dev/null +++ b/regression/cbmc-java/nondetBoolean/NondetBoolean.java @@ -0,0 +1,9 @@ +import org.cprover.CProver; + +class NondetBoolean +{ + static void foo() + { + boolean x = CProver.nondetBoolean(); + } +} diff --git a/regression/cbmc-java/nondetByte/NondetByte.class b/regression/cbmc-java/nondetByte/NondetByte.class new file mode 100644 index 0000000000000000000000000000000000000000..26238494829ab19777adec53a8f69c46c3a91c48 GIT binary patch literal 301 zcmYL@L2JT55QX0)>ZaS+Snai-H`{}`c&qfF;Hju!@t(w0B6e4nDD-FbROz8Vpg*cO z8&DT^XL$3yxAXV^^9!Jl2Z;(oi8}5CB7p{>Hpq2eyb}EG(}GYLnWZ8`Z@E^J{YR?o zdy;Nh@mIzWbHYj-@p`~?VtyGO3%l;>~I7dM1}UpEF@0^D5C W&KW(zd%2>rOcb0RFd*6H;r0YKbTm8w literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetByte/NondetByte.java b/regression/cbmc-java/nondetByte/NondetByte.java new file mode 100644 index 00000000000..9ac1e14c745 --- /dev/null +++ b/regression/cbmc-java/nondetByte/NondetByte.java @@ -0,0 +1,9 @@ +import org.cprover.CProver; + +class NondetByte +{ + static void foo() + { + byte x = CProver.nondetByte(); + } +} diff --git a/regression/cbmc-java/nondetChar/NondetChar.class b/regression/cbmc-java/nondetChar/NondetChar.class new file mode 100644 index 0000000000000000000000000000000000000000..75156101a11d8839098078f3ff38110706125c62 GIT binary patch literal 301 zcmYL@Pfr3d5XIl@B3rtR zseHvs_+c$UPVL$idQf^P8Cf&eRraae^HOb8j0-dc+A%ulGJ75qS{_JO$}G}xzSKoU z=vuc(i*IK)+NIf~uIw_W(0Zo~cL;fFe*(Vz1qgz>9#`_p(+;%dh7j@V$6!l@%M*J4 VkNzNdJ)^Qt6r3J0AlVk+>Ie+4Gy4Dl literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetChar/NondetChar.java b/regression/cbmc-java/nondetChar/NondetChar.java new file mode 100644 index 00000000000..dc0bca2a9bd --- /dev/null +++ b/regression/cbmc-java/nondetChar/NondetChar.java @@ -0,0 +1,9 @@ +import org.cprover.CProver; + +class NondetChar +{ + static void foo() + { + char x = CProver.nondetChar(); + } +} diff --git a/regression/cbmc-java/nondetDouble/NondetDouble.class b/regression/cbmc-java/nondetDouble/NondetDouble.class new file mode 100644 index 0000000000000000000000000000000000000000..ae21153acfeba8457ae26f5418e77676377ad53f GIT binary patch literal 307 zcmYk0ziz@n48}hvlnd7s!k-nXY?Pr{IwBTOyHpgZRre%ZQ4ri!r-b)nqGI3ycqmj~ zh89a_Ti<;@+vm&i1mFohi5fzQJ2VAa0uiA;&UIc)2>$TllTe$Qr6ROmbFJp(HdXc` zNjI$cU&avRyD4p^o^vO)=SDA8F*7AQ9@oh(32}qEKs!VST|#(mAVkg*ZxX$V-_o_p z3PRV|Rh)fWvr{&nE~?6$z8YLzHp4x9zTJh#kJo@8xa)Hzr;HAuJvW4av-<`k0UCeS X0izZC1MlVEDl1X&^nfABn1|b6j~_Ot literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetDouble/NondetDouble.java b/regression/cbmc-java/nondetDouble/NondetDouble.java new file mode 100644 index 00000000000..f0957a4732e --- /dev/null +++ b/regression/cbmc-java/nondetDouble/NondetDouble.java @@ -0,0 +1,9 @@ +import org.cprover.CProver; + +class NondetDouble +{ + static void foo() + { + double x = CProver.nondetDouble(); + } +} diff --git a/regression/cbmc-java/nondetFloat/NondetFloat.class b/regression/cbmc-java/nondetFloat/NondetFloat.class new file mode 100644 index 0000000000000000000000000000000000000000..ec012f53f63434d25c1b83f7d0dfe7d373d82448 GIT binary patch literal 304 zcmYk0Pfx-?5XIlL$kwI&5xkn{O+3(xN5iE_PXtXM+_z;VC3Tl<3g63<#)BWg4`rNf zg0RW%Oy2z7+xhwZ`UdcbYl#+Oi7t8qeSra?{ZyK=o)W_Q@ruw&?OGH1v(o7K{w>#T zsq%`I@YPy^T-d!UbXIz4Ft=u{>#VY>o@~`Y#kfFQ;3~!tBSPnF&a@|zN|{aaoNske z6Gql;l49rVLAxYyDYjWF!!1Hy+@F9ie*%Kw?uILQ<>3SL&J7{r*N?%L2$%op W-4Xpnke*Q4BnnQC7?5lW(D?&jw>5D9 literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetFloat/NondetFloat.java b/regression/cbmc-java/nondetFloat/NondetFloat.java new file mode 100644 index 00000000000..9c0ba0f73e7 --- /dev/null +++ b/regression/cbmc-java/nondetFloat/NondetFloat.java @@ -0,0 +1,9 @@ +import org.cprover.CProver; + +class NondetFloat +{ + static void foo() + { + float x = CProver.nondetFloat(); + } +} diff --git a/regression/cbmc-java/nondetInt/NondetInt.class b/regression/cbmc-java/nondetInt/NondetInt.class new file mode 100644 index 0000000000000000000000000000000000000000..48b42b9b5ef35ca13c10a74b6562a62f7e57935a GIT binary patch literal 298 zcmYLD&1%9x5dJ1nH*Vu!?X}R}st0rNX7M5jg4jZ(_ats5qPwz0-^-KILm!|ICC&!a zft?w?zn%Z{?;n6Zo+L^LC2FV(Gz6N2%6q1>d`R%$I^TrS$Sf40G0n7^?KX+B^Eg>E z;{O;!kY8qJQ#H;URG%5WQ29jXy;Z!ALzGbwXoYx0n^3*6gr?)8b*z`sN3v3BPG}pu zjMA+&du5~1XEE8NuaU(;6THCZlU;fI_yZ6GZ_hl*A>AYBzzZSZ?r5+jK=mely-H8; S26w3}5(TFRERbyT@NfYNvNHt$ literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetInt/NondetInt.java b/regression/cbmc-java/nondetInt/NondetInt.java new file mode 100644 index 00000000000..37f3265a40a --- /dev/null +++ b/regression/cbmc-java/nondetInt/NondetInt.java @@ -0,0 +1,9 @@ +import org.cprover.CProver; + +class NondetInt +{ + static void foo() + { + int x = CProver.nondetInt(); + } +} diff --git a/regression/cbmc-java/nondetLong/NondetLong.class b/regression/cbmc-java/nondetLong/NondetLong.class new file mode 100644 index 0000000000000000000000000000000000000000..9c61a62e4b4b3e90c04910f6f51577a0a9b0fde7 GIT binary patch literal 301 zcmYL@v2MaZ42FLvluM7$Kqx{%Y+p VTEV~YK5kZ7iGrsG3`xd3G%hq6G(G?T literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetLong/NondetLong.java b/regression/cbmc-java/nondetLong/NondetLong.java new file mode 100644 index 00000000000..5165ae60af7 --- /dev/null +++ b/regression/cbmc-java/nondetLong/NondetLong.java @@ -0,0 +1,9 @@ +import org.cprover.CProver; + +class NondetLong +{ + static void foo() + { + long x = CProver.nondetLong(); + } +} diff --git a/regression/cbmc-java/nondetShort/NondetShort.class b/regression/cbmc-java/nondetShort/NondetShort.class new file mode 100644 index 0000000000000000000000000000000000000000..2f7e7b165391f06e72df51ceb6acc0aacc1d1b1c GIT binary patch literal 304 zcmYk0K~KU!5QX2g$kuHI6t5<7QxEjw4dR7_6R9RO-rKT58{9RU!vErg@!${eM;T|E zVBKVQCU3s?cD{c;zX06hQlf)M;tV~3zQBOcotC<+9|-=v5IsvIr;W3YpCBn=|c*c$4W>{Fqm& zs0l-3S8?%f%}&{P_S96i={B}mE5$W@UfdmzFMk4p;O>emIpyvE+H*q)_;q8jCBW$) WIy#~s@Fp!Pn?%9s0Rxh49>QOj%{9aT literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetShort/NondetShort.java b/regression/cbmc-java/nondetShort/NondetShort.java new file mode 100644 index 00000000000..8ed9cce7066 --- /dev/null +++ b/regression/cbmc-java/nondetShort/NondetShort.java @@ -0,0 +1,9 @@ +import org.cprover.CProver; + +class NondetShort +{ + static void foo() + { + short x = CProver.nondetShort(); + } +} From a632f4608e97190147185848a4b0bb428d422fa1 Mon Sep 17 00:00:00 2001 From: reuk Date: Tue, 21 Feb 2017 10:59:47 +0000 Subject: [PATCH 03/39] Add stubs to select nondet methods in java code --- .../java_bytecode_convert_method.cpp | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index 447b5dacb80..7b6cc58555a 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -857,6 +857,15 @@ static unsigned get_bytecode_type_width(const typet &ty) return ty.get_unsigned_int(ID_width); } +static bool statement_is_static_with_name( + const irep_idt& statement, + const exprt& arg0, + const irep_idt& desired_name) +{ + return statement == "invokestatic" && + id2string(arg0.get(ID_identifier)) == desired_name; +} + codet java_bytecode_convert_methodt::convert_instructions( const methodt &method, const code_typet &method_type) @@ -1093,9 +1102,10 @@ codet java_bytecode_convert_methodt::convert_instructions( } } // replace calls to CProver.assume - else if(statement=="invokestatic" && - id2string(arg0.get(ID_identifier))== - "java::org.cprover.CProver.assume:(Z)V") + else if(statement_is_static_with_name( + statement, + arg0, + "java::org.cprover.CProver.assume:(Z)V")) { const code_typet &code_type=to_code_type(arg0.type()); // sanity check: function has the right number of args @@ -1111,6 +1121,30 @@ codet java_bytecode_convert_methodt::convert_instructions( loc.set_function(method_id); c.add_source_location()=loc; } + + // boolean + else if(statement_is_static_with_name( + statement, + arg0, + "java::org.cprover.CProver.nondetBoolean:()Z") + { + // TODO + } + // byte + // char + // short + // int + // long + // float + // double + else if(statement_is_static_with_name( + statement, + arg0, + "java::org.cprover.CProver.nondetBoolean:()I") + { + // TODO + } + else if(statement=="invokeinterface" || statement=="invokespecial" || statement=="invokevirtual" || From 496d0b708dfa345c7228e886e94a1c166aa57fb1 Mon Sep 17 00:00:00 2001 From: reuk Date: Tue, 21 Feb 2017 14:06:09 +0000 Subject: [PATCH 04/39] Add asserts and rebuild java regression classes --- .../cbmc-java/nondetBoolean/NondetBoolean.class | Bin 310 -> 572 bytes .../cbmc-java/nondetBoolean/NondetBoolean.java | 1 + .../cbmc-java/nondetByte/NondetByte.class | Bin 301 -> 569 bytes regression/cbmc-java/nondetByte/NondetByte.java | 1 + .../cbmc-java/nondetChar/NondetChar.class | Bin 301 -> 569 bytes regression/cbmc-java/nondetChar/NondetChar.java | 1 + .../cbmc-java/nondetDouble/NondetDouble.class | Bin 307 -> 577 bytes .../cbmc-java/nondetDouble/NondetDouble.java | 1 + .../cbmc-java/nondetFloat/NondetFloat.class | Bin 304 -> 574 bytes .../cbmc-java/nondetFloat/NondetFloat.java | 1 + regression/cbmc-java/nondetInt/NondetInt.class | Bin 298 -> 566 bytes regression/cbmc-java/nondetInt/NondetInt.java | 1 + .../cbmc-java/nondetLong/NondetLong.class | Bin 301 -> 571 bytes regression/cbmc-java/nondetLong/NondetLong.java | 1 + .../cbmc-java/nondetShort/NondetShort.class | Bin 304 -> 572 bytes .../cbmc-java/nondetShort/NondetShort.java | 1 + 16 files changed, 8 insertions(+) diff --git a/regression/cbmc-java/nondetBoolean/NondetBoolean.class b/regression/cbmc-java/nondetBoolean/NondetBoolean.class index 415b625be6dbb132549f4a14faebf7593c968fa1..f535256ecfd99bb89b87089c97537c70d8d02187 100644 GIT binary patch literal 572 zcmY*WO)mpc6g{sq?X=U;sj9Y06|ulVH+Do&tb8RE3A^dcBg2>{Z>Ii>{sC(w2nlW^XUa`F%UT=wxwE4Chbr<%8@9=O#2#;I-;<o#Wk0W=0O~Z!2c^D_D6Qj0lewa zP8doK4_wKez5ucqb^=V%GSjqSmajx&DO2c>2M{-9HHwU4a^VT=juM6(-Kn^!5Y+6q zHj#*{!L!<9YqeN5lKZKtsF{%vr3729zV7QQa dgw}U z%*ep&m!FrCTH=(SpOc!HH}RXj7=r=>Gf*Q4Faa@8H3K69`{X)CF&7RXAH-t-s^DPY pgvbDSia;@tDC-UeChLtr1|v|Kfq@Hb06Wky4xk7ZP=twr8vtu#6FL9@ diff --git a/regression/cbmc-java/nondetBoolean/NondetBoolean.java b/regression/cbmc-java/nondetBoolean/NondetBoolean.java index 925d921da43..01cbd48d0aa 100644 --- a/regression/cbmc-java/nondetBoolean/NondetBoolean.java +++ b/regression/cbmc-java/nondetBoolean/NondetBoolean.java @@ -5,5 +5,6 @@ class NondetBoolean static void foo() { boolean x = CProver.nondetBoolean(); + assert x == false; } } diff --git a/regression/cbmc-java/nondetByte/NondetByte.class b/regression/cbmc-java/nondetByte/NondetByte.class index 26238494829ab19777adec53a8f69c46c3a91c48..b73d4e57e715e6053fdc3584e88056f34c2010fd 100644 GIT binary patch literal 569 zcmYLGO)mpc6g{^y?bLK=t5nrjeJrrhjU5pbD_;qbu$#_2%~Z{kH`6A53V*;F2|~i& zZxV55&@SfPn|trM=iD=&->>fgmN9E0jUf}mDE1+R5d$R?I))64nkZw;z&N2WX9s~$ zp(p)d%M0v!OSl9&BcxV6-wW3W+Wf)^L9a*--@Ew+MC zbVcAP;dZI{varn!_TdZ_b~4TOQmzz<c|TcD-Y0akuBdK^9KF&8Oe_boQS~#F^9qbE{!6y=6)A`p-5cGcNZ?l>wx@V e>Iudz4E+we_6V)F>R(5+B8h~x9;qFSnF>Fb>S{9p delta 178 zcmdnVvX)8e)W2Q(7#J8#7(}=jSQvP?7U z%*epym!FrCTH;h$k~;B&O#y=f12a$;2rvOLP$>f=13Qo<3#1uAB3j!S7&ihLj0_w= n5+uz4)WX5Q30JBJQ@VqJ$r_=Q3v41g&~y%<0xqC7CI)T*`7aWd diff --git a/regression/cbmc-java/nondetByte/NondetByte.java b/regression/cbmc-java/nondetByte/NondetByte.java index 9ac1e14c745..2eaeaf21042 100644 --- a/regression/cbmc-java/nondetByte/NondetByte.java +++ b/regression/cbmc-java/nondetByte/NondetByte.java @@ -5,5 +5,6 @@ class NondetByte static void foo() { byte x = CProver.nondetByte(); + assert x == 0; } } diff --git a/regression/cbmc-java/nondetChar/NondetChar.class b/regression/cbmc-java/nondetChar/NondetChar.class index 75156101a11d8839098078f3ff38110706125c62..a24b95361ca19adc2f340e5d008a0987a180f540 100644 GIT binary patch literal 569 zcmYLG%TB^j5IsW+#aaag5#RV&s0-P!(-=+Fm9Io&qPx;wv539qw)ijd1FqFXjV8MH zn~ZT<6&AfSnVB=^%<1R%>pOrN=1pW#G%%Gz)|G5mwV3j zUp2etw*K(uk!&kh?D+9?ZeIqTi0lhTtu&n*$3j0W15*~JF=L?*CZQZRsx2pIR5$;{ zZ7U@e!R)~eR4mM5j*#!oAJm(|jrc678ddjN$s3`n_F)nk9dyZ)vuxJW!`dyjf>82A z=qurMsrj;~%?9`V%l1;f9E;^lj~JXvz=H{g!T&Cc60_!i7k;5cTp8*vtR?G!q2bIE cj1CO_4!ZUTt+(o5N4z49l(iA79Zr}EKS3yI@&Et; delta 178 zcmdnVvX)8e)W2Q(7#J8#7(}=jSQvP?7U z%*epym!FrCTH>6MSTym2O#y=f12a$;2rvOLP$>f=13Qo<3#1uAB3j!S7&ihLj0_w= n5+uz4)WX5Q30JBJQ@VqJ$r_=Q3v41g&~y%<0xqC7CI)T*?(Y(S diff --git a/regression/cbmc-java/nondetChar/NondetChar.java b/regression/cbmc-java/nondetChar/NondetChar.java index dc0bca2a9bd..68a724462da 100644 --- a/regression/cbmc-java/nondetChar/NondetChar.java +++ b/regression/cbmc-java/nondetChar/NondetChar.java @@ -5,5 +5,6 @@ class NondetChar static void foo() { char x = CProver.nondetChar(); + assert x == '\0'; } } diff --git a/regression/cbmc-java/nondetDouble/NondetDouble.class b/regression/cbmc-java/nondetDouble/NondetDouble.class index ae21153acfeba8457ae26f5418e77676377ad53f..2a36a78edabd1a68ab0700a79b2912463f6ac199 100644 GIT binary patch literal 577 zcmYjOOHaZ;5dM}H3Z){TBKUsAs0X=tG)4pJMbQLfqPNnnrixv%E&dfFf55YvsL@34 z{w8CbtqL4=XRNp;TUtJ5&?~~_41;@~&ui_g2A4;wnaXEEFbvc~+qvAg zTYs;~b*K4RiWIp{qyqH zzrAfKg=Db$2@K3wn8h4Jwud-qTyQ6((S$rNJ1r@$xhz)>qeyta&pm8R;UD@|Gm zL&4>NC%M~|r}@G*6=)l$n4x_pX~`^GRE8p6cuHzOSu-w h0J(hP2}TEoeg|E9gw~__ccLibh*_J;Z$45Q`T;!;ZCn5V delta 163 zcmX@evYAQh)W2Q(7#J8#7(}=jSQvP?7U z%*epwm!FrCTH=ylnv|0|@r#`pg8~CHP#*{|0WnZ910w_bI6KNO>rKnN$EdQ*! z^|xJ9N+B6C|L{60CKj+rtV6(F=bYOi9VX;i)xMJAn#*cqKaK?Vhw|}dEjnokZg}Jd zL($=ZE4ecer{lsdHOPt+RLIN}Im~jUXkE%w`sfOf4V2ANWE2x?J+KE#7)I$$#zmE& z*}-TNN?a|!KxsTey+eL6b90N#8?@sd5+4yX7PhlZYY##oUbc9gCI5e*o_gY#RUo delta 162 zcmdnTvVlqJ)W2Q(7#J8#7(}=jSQvP?7U z%*ep)m!FrCTH=SldTwo0s}Kp8wfA~F;Fc7BLn;7Iz}-U4j>=IV*sk)VBmzv n0C|c)F_0+h4hAOYjX(w?P?~{(3v2*8&@c|52p3RJW*;g(OLglt!=o)iNvE49-w64)J5hnngnW(=)$$p?nK z%{@nQdqhmK{600vgiDmk#yEM)(uLqu$`txY0muN#N)#Ez=*A1!10|%F-dI>v2$~v= z)({D+Gp~qjJwmxds(6cucc>RHh<*m(NC-}b92)(&IP%1r{#*EsJflixw6Gek12Wmz eGqgKs>OEBD3CeiY@Qz?b6cJ-LxHcOyP5lBC delta 177 zcmdnSvWiLS)W2Q(7#J8#7(}=jSQvP?7i#?Bzf!yv>U z%*ep$m!FrCTH={kGVz^t0fPbqGf)!-ib mB+UTS!ok1^SE>k8x`Tnq8ljX6Y$7|*bPk{bE}%9h25tbhRT3cp diff --git a/regression/cbmc-java/nondetInt/NondetInt.java b/regression/cbmc-java/nondetInt/NondetInt.java index 37f3265a40a..a863b3e8789 100644 --- a/regression/cbmc-java/nondetInt/NondetInt.java +++ b/regression/cbmc-java/nondetInt/NondetInt.java @@ -5,5 +5,6 @@ class NondetInt static void foo() { int x = CProver.nondetInt(); + assert x == 0; } } diff --git a/regression/cbmc-java/nondetLong/NondetLong.class b/regression/cbmc-java/nondetLong/NondetLong.class index 9c61a62e4b4b3e90c04910f6f51577a0a9b0fde7..cc19cdfa9a74631fc447a9b8b502e3fe900105d5 100644 GIT binary patch literal 571 zcmYLG%TB^j5IvU`3Z)8&BEFvsbs-y;#zznr2GK-gqPx;wNfmp|ZQ)DY$Pc(y6ET|T z-fuF-xm97&JCm6?bIzQ8e!sp0C}YV)5~C)@P)H$xaRWsYIz|mln3%+rfoX>PvK<6m zhMw?)T`#a3E$%X~bB4r*=X>EMgSN7I%Ai+-%Na5?&*$~_b%Vl{xplpUBqZnW7fjv;dFidYEDryAH z^hc}oGh)=6ctLFI5n30y+0^YF(r?hudWe50cr1bsM=S;bl2E+a-<4k|s!FcEvK-L> gxsk*(j4llQ9=i4fZLsQJiCPgy%-U9ZMU z%*epym!FrCTH=$Rmp<`>O#y=f12a$;2rvOLP$>f=13Qo<3#1uAB3j!S7&ihLj0_w= p5+uz4)WX5Q30JBJ)C$(TgMrB&p_B_O$PP4}1E`4$sEvt%8vyy05}E)2 diff --git a/regression/cbmc-java/nondetLong/NondetLong.java b/regression/cbmc-java/nondetLong/NondetLong.java index 5165ae60af7..3228a2d3fb3 100644 --- a/regression/cbmc-java/nondetLong/NondetLong.java +++ b/regression/cbmc-java/nondetLong/NondetLong.java @@ -5,5 +5,6 @@ class NondetLong static void foo() { long x = CProver.nondetLong(); + assert x == 0; } } diff --git a/regression/cbmc-java/nondetShort/NondetShort.class b/regression/cbmc-java/nondetShort/NondetShort.class index 2f7e7b165391f06e72df51ceb6acc0aacc1d1b1c..2012b00d57ba6432ab28049ae3b5f966dbf88d9a 100644 GIT binary patch literal 572 zcmYjO%TB^j5IvU`3Z=?J1$?0RSf~rxu#*@K>dIGwF_B$quUN!ha$Ect{Q=i%B1RM4 z`%T6;tq3l9XEHPAoSDv(3f!)*rEV2D*6*YUR)l-0E}2DK(^&X78ATz=HMZgP1V3{(3;2!^q`Z(3J} zW_M7HSFO$fuh&IST72ILrqf5lwYguv6w=>ln>VI`Bn%Bj1M^rgkburm2pZ*%>9)!{ zf7|UzDI`PkA6`Srz#^82bp$wWwz=igVM4abR#%D}F3Yu(FcRDy$%mKK>7)_3)*&|- zayIuI$?c&y9q0F`K~^+SA~WOUFiRJLbtzNmqboo*P*$YKC`Q-&U=NfqjMEzniwZ$g z!_gWdVKx7P$mS!IJEUfAk$i)C-beH!07pXbc&MS#?~5Zxs_9?CFXR|iGDE^jNC#xH fv1e#^(A0aV$`h0k)!!ZgMHCTZJJ>cGDoy+VM-gkg delta 162 zcmdnPvVlqJ)W2Q(7#J8#7(}=jSQvP?7U z%*ep)m!FrCS`wU*UsN*jldTwo0s}Kp8wfA~F;Fc7BLn;7Iz}-U4j>=IV*sk)VBmzv n0C|c)F_0+h4hAOcjX(w?P?~{(3v2*8&@c|52p3R Date: Tue, 21 Feb 2017 14:06:52 +0000 Subject: [PATCH 05/39] Add test descriptors for new tests --- regression/cbmc-java/nondetBoolean/test.desc | 8 ++++++++ regression/cbmc-java/nondetByte/test.desc | 8 ++++++++ regression/cbmc-java/nondetChar/test.desc | 8 ++++++++ regression/cbmc-java/nondetDouble/test.desc | 8 ++++++++ regression/cbmc-java/nondetFloat/test.desc | 8 ++++++++ regression/cbmc-java/nondetInt/test.desc | 8 ++++++++ regression/cbmc-java/nondetLong/test.desc | 8 ++++++++ regression/cbmc-java/nondetShort/test.desc | 8 ++++++++ 8 files changed, 64 insertions(+) create mode 100644 regression/cbmc-java/nondetBoolean/test.desc create mode 100644 regression/cbmc-java/nondetByte/test.desc create mode 100644 regression/cbmc-java/nondetChar/test.desc create mode 100644 regression/cbmc-java/nondetDouble/test.desc create mode 100644 regression/cbmc-java/nondetFloat/test.desc create mode 100644 regression/cbmc-java/nondetInt/test.desc create mode 100644 regression/cbmc-java/nondetLong/test.desc create mode 100644 regression/cbmc-java/nondetShort/test.desc diff --git a/regression/cbmc-java/nondetBoolean/test.desc b/regression/cbmc-java/nondetBoolean/test.desc new file mode 100644 index 00000000000..5d63938cedd --- /dev/null +++ b/regression/cbmc-java/nondetBoolean/test.desc @@ -0,0 +1,8 @@ +CORE +NondetBoolean.class +--function NondetBoolean.foo +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/nondetByte/test.desc b/regression/cbmc-java/nondetByte/test.desc new file mode 100644 index 00000000000..600ea9e4c9d --- /dev/null +++ b/regression/cbmc-java/nondetByte/test.desc @@ -0,0 +1,8 @@ +CORE +NondetByte.class +--function NondetByte.foo +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/nondetChar/test.desc b/regression/cbmc-java/nondetChar/test.desc new file mode 100644 index 00000000000..2c9cd593bc5 --- /dev/null +++ b/regression/cbmc-java/nondetChar/test.desc @@ -0,0 +1,8 @@ +CORE +NondetChar.class +--function NondetChar.foo +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/nondetDouble/test.desc b/regression/cbmc-java/nondetDouble/test.desc new file mode 100644 index 00000000000..16d436501b8 --- /dev/null +++ b/regression/cbmc-java/nondetDouble/test.desc @@ -0,0 +1,8 @@ +CORE +NondetDouble.class +--function NondetDouble.foo +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/nondetFloat/test.desc b/regression/cbmc-java/nondetFloat/test.desc new file mode 100644 index 00000000000..242b1d25199 --- /dev/null +++ b/regression/cbmc-java/nondetFloat/test.desc @@ -0,0 +1,8 @@ +CORE +NondetFloat.class +--function NondetFloat.foo +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/nondetInt/test.desc b/regression/cbmc-java/nondetInt/test.desc new file mode 100644 index 00000000000..0d37a6beb3a --- /dev/null +++ b/regression/cbmc-java/nondetInt/test.desc @@ -0,0 +1,8 @@ +CORE +NondetInt.class +--function NondetInt.foo +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/nondetLong/test.desc b/regression/cbmc-java/nondetLong/test.desc new file mode 100644 index 00000000000..ee5f97327a2 --- /dev/null +++ b/regression/cbmc-java/nondetLong/test.desc @@ -0,0 +1,8 @@ +CORE +NondetLong.class +--function NondetLong.foo +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/nondetShort/test.desc b/regression/cbmc-java/nondetShort/test.desc new file mode 100644 index 00000000000..30f2a446ecd --- /dev/null +++ b/regression/cbmc-java/nondetShort/test.desc @@ -0,0 +1,8 @@ +CORE +NondetShort.class +--function NondetShort.foo +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring From a0b2d04283c8a842b8ecb0b51226161cfa0eec0e Mon Sep 17 00:00:00 2001 From: reuk Date: Tue, 21 Feb 2017 14:07:51 +0000 Subject: [PATCH 06/39] Add support for 'primitive' nondet methods Update test.desc files with correct outcomes Fix formatting issues --- regression/cbmc-java/nondetBoolean/test.desc | 4 +- regression/cbmc-java/nondetByte/test.desc | 4 +- regression/cbmc-java/nondetChar/test.desc | 4 +- regression/cbmc-java/nondetDouble/test.desc | 4 +- regression/cbmc-java/nondetFloat/test.desc | 4 +- regression/cbmc-java/nondetInt/test.desc | 4 +- regression/cbmc-java/nondetLong/test.desc | 4 +- regression/cbmc-java/nondetShort/test.desc | 4 +- .../java_bytecode_convert_method.cpp | 128 ++++++++++++------ 9 files changed, 96 insertions(+), 64 deletions(-) diff --git a/regression/cbmc-java/nondetBoolean/test.desc b/regression/cbmc-java/nondetBoolean/test.desc index 5d63938cedd..9913935eb03 100644 --- a/regression/cbmc-java/nondetBoolean/test.desc +++ b/regression/cbmc-java/nondetBoolean/test.desc @@ -1,8 +1,6 @@ CORE NondetBoolean.class --function NondetBoolean.foo -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ +^VERIFICATION FAILED$ -- ^warning: ignoring diff --git a/regression/cbmc-java/nondetByte/test.desc b/regression/cbmc-java/nondetByte/test.desc index 600ea9e4c9d..c1fbe8bd0fb 100644 --- a/regression/cbmc-java/nondetByte/test.desc +++ b/regression/cbmc-java/nondetByte/test.desc @@ -1,8 +1,6 @@ CORE NondetByte.class --function NondetByte.foo -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ +^VERIFICATION FAILED$ -- ^warning: ignoring diff --git a/regression/cbmc-java/nondetChar/test.desc b/regression/cbmc-java/nondetChar/test.desc index 2c9cd593bc5..306394b706c 100644 --- a/regression/cbmc-java/nondetChar/test.desc +++ b/regression/cbmc-java/nondetChar/test.desc @@ -1,8 +1,6 @@ CORE NondetChar.class --function NondetChar.foo -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ +^VERIFICATION FAILED$ -- ^warning: ignoring diff --git a/regression/cbmc-java/nondetDouble/test.desc b/regression/cbmc-java/nondetDouble/test.desc index 16d436501b8..9c9228fdd24 100644 --- a/regression/cbmc-java/nondetDouble/test.desc +++ b/regression/cbmc-java/nondetDouble/test.desc @@ -1,8 +1,6 @@ CORE NondetDouble.class --function NondetDouble.foo -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ +^VERIFICATION FAILED$ -- ^warning: ignoring diff --git a/regression/cbmc-java/nondetFloat/test.desc b/regression/cbmc-java/nondetFloat/test.desc index 242b1d25199..7370f25ae93 100644 --- a/regression/cbmc-java/nondetFloat/test.desc +++ b/regression/cbmc-java/nondetFloat/test.desc @@ -1,8 +1,6 @@ CORE NondetFloat.class --function NondetFloat.foo -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ +^VERIFICATION FAILED$ -- ^warning: ignoring diff --git a/regression/cbmc-java/nondetInt/test.desc b/regression/cbmc-java/nondetInt/test.desc index 0d37a6beb3a..7669da239ec 100644 --- a/regression/cbmc-java/nondetInt/test.desc +++ b/regression/cbmc-java/nondetInt/test.desc @@ -1,8 +1,6 @@ CORE NondetInt.class --function NondetInt.foo -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ +^VERIFICATION FAILED$ -- ^warning: ignoring diff --git a/regression/cbmc-java/nondetLong/test.desc b/regression/cbmc-java/nondetLong/test.desc index ee5f97327a2..60e03901419 100644 --- a/regression/cbmc-java/nondetLong/test.desc +++ b/regression/cbmc-java/nondetLong/test.desc @@ -1,8 +1,6 @@ CORE NondetLong.class --function NondetLong.foo -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ +^VERIFICATION FAILED$ -- ^warning: ignoring diff --git a/regression/cbmc-java/nondetShort/test.desc b/regression/cbmc-java/nondetShort/test.desc index 30f2a446ecd..882806378b6 100644 --- a/regression/cbmc-java/nondetShort/test.desc +++ b/regression/cbmc-java/nondetShort/test.desc @@ -1,8 +1,6 @@ CORE NondetShort.class --function NondetShort.foo -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ +^VERIFICATION FAILED$ -- ^warning: ignoring diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index 7b6cc58555a..1b82d2f65ac 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -857,13 +857,12 @@ static unsigned get_bytecode_type_width(const typet &ty) return ty.get_unsigned_int(ID_width); } -static bool statement_is_static_with_name( - const irep_idt& statement, - const exprt& arg0, - const irep_idt& desired_name) -{ - return statement == "invokestatic" && - id2string(arg0.get(ID_identifier)) == desired_name; +static bool statement_is_static_with_name(const irep_idt &statement, + const exprt &arg0, + const char *desired_name) +{ + return statement == "invokestatic" && + id2string(arg0.get(ID_identifier)) == desired_name; } codet java_bytecode_convert_methodt::convert_instructions( @@ -1101,48 +1100,97 @@ codet java_bytecode_convert_methodt::convert_instructions( get_message_handler()); } } + // replace calls to CProver.assume - else if(statement_is_static_with_name( - statement, - arg0, - "java::org.cprover.CProver.assume:(Z)V")) + else if (statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.assume:(Z)V")) { - const code_typet &code_type=to_code_type(arg0.type()); + const code_typet &code_type = to_code_type(arg0.type()); // sanity check: function has the right number of args - assert(code_type.parameters().size()==1); + assert(code_type.parameters().size() == 1); exprt operand = pop(1)[0]; // we may need to adjust the type of the argument - if(operand.type()!=bool_typet()) + if (operand.type() != bool_typet()) operand.make_typecast(bool_typet()); - c=code_assumet(operand); - source_locationt loc=i_it->source_location; + c = code_assumet(operand); + source_locationt loc = i_it->source_location; loc.set_function(method_id); - c.add_source_location()=loc; - } - - // boolean - else if(statement_is_static_with_name( - statement, - arg0, - "java::org.cprover.CProver.nondetBoolean:()Z") - { - // TODO - } - // byte - // char - // short - // int - // long - // float - // double - else if(statement_is_static_with_name( - statement, - arg0, - "java::org.cprover.CProver.nondetBoolean:()I") - { - // TODO + c.add_source_location() = loc; + } + + // if the statement is a nondet boolean + else if (statement_is_static_with_name( + statement, arg0, + "java::org.cprover.CProver.nondetBoolean:()Z")) + { + results.resize(1); + results[0] = side_effect_expr_nondett(java_boolean_type()); + results[0].add_source_location() = i_it->source_location; + } + + // if the statement is a nondet byte + else if (statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetByte:()B")) + { + results.resize(1); + results[0] = side_effect_expr_nondett(java_byte_type()); + results[0].add_source_location() = i_it->source_location; + } + + // if the statement is a nondet char + else if (statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetChar:()C")) + { + results.resize(1); + results[0] = side_effect_expr_nondett(java_char_type()); + results[0].add_source_location() = i_it->source_location; + } + + // if the statement is a nondet short + else if (statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetShort:()S")) + { + results.resize(1); + results[0] = side_effect_expr_nondett(java_short_type()); + results[0].add_source_location() = i_it->source_location; + } + + // if the statement is a nondet int + else if (statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetInt:()I")) + { + results.resize(1); + results[0] = side_effect_expr_nondett(java_int_type()); + results[0].add_source_location() = i_it->source_location; + } + + // if the statement is a nondet long + else if (statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetLong:()J")) + { + results.resize(1); + results[0] = side_effect_expr_nondett(java_long_type()); + results[0].add_source_location() = i_it->source_location; + } + + // if the statement is a nondet float + else if (statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetFloat:()F")) + { + results.resize(1); + results[0] = side_effect_expr_nondett(java_float_type()); + results[0].add_source_location() = i_it->source_location; + } + + // if the statement is a nondet double + else if (statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetDouble:()D")) + { + results.resize(1); + results[0] = side_effect_expr_nondett(java_double_type()); + results[0].add_source_location() = i_it->source_location; } else if(statement=="invokeinterface" || From d8f68bb1bb668bf28f896713cc57b6a8140ddffa Mon Sep 17 00:00:00 2001 From: reuk Date: Tue, 21 Feb 2017 17:03:17 +0000 Subject: [PATCH 07/39] Add testcase for generic nondet Update generic testcase --- .../nondetBoolean/NondetBoolean.class | Bin 572 -> 658 bytes .../cbmc-java/nondetByte/NondetByte.class | Bin 569 -> 656 bytes .../cbmc-java/nondetChar/NondetChar.class | Bin 569 -> 656 bytes .../cbmc-java/nondetDouble/NondetDouble.class | Bin 577 -> 666 bytes .../cbmc-java/nondetFloat/NondetFloat.class | Bin 574 -> 662 bytes regression/cbmc-java/nondetGeneric/Bar.class | Bin 0 -> 244 bytes regression/cbmc-java/nondetGeneric/Baz.class | Bin 0 -> 244 bytes regression/cbmc-java/nondetGeneric/Foo.class | Bin 0 -> 244 bytes .../nondetGeneric/NondetGeneric.class | Bin 0 -> 822 bytes .../nondetGeneric/NondetGeneric.java | 18 +++++++ .../cbmc-java/nondetGeneric/dissasembly.txt | 42 +++++++++++++++ .../nondetGeneric/dissasemblyNDebug.txt | 48 ++++++++++++++++++ regression/cbmc-java/nondetGeneric/test.desc | 6 +++ .../cbmc-java/nondetInt/NondetInt.class | Bin 566 -> 652 bytes .../cbmc-java/nondetLong/NondetLong.class | Bin 571 -> 658 bytes .../cbmc-java/nondetShort/NondetShort.class | Bin 572 -> 660 bytes 16 files changed, 114 insertions(+) create mode 100644 regression/cbmc-java/nondetGeneric/Bar.class create mode 100644 regression/cbmc-java/nondetGeneric/Baz.class create mode 100644 regression/cbmc-java/nondetGeneric/Foo.class create mode 100644 regression/cbmc-java/nondetGeneric/NondetGeneric.class create mode 100644 regression/cbmc-java/nondetGeneric/NondetGeneric.java create mode 100644 regression/cbmc-java/nondetGeneric/dissasembly.txt create mode 100644 regression/cbmc-java/nondetGeneric/dissasemblyNDebug.txt create mode 100644 regression/cbmc-java/nondetGeneric/test.desc diff --git a/regression/cbmc-java/nondetBoolean/NondetBoolean.class b/regression/cbmc-java/nondetBoolean/NondetBoolean.class index f535256ecfd99bb89b87089c97537c70d8d02187..ee3af8a020cf9673845b8b0f246efa6a4c984602 100644 GIT binary patch delta 262 zcmdnPGKp2^)W2Q(7#J8#7}U5JI2a_j7$g~_I2qU&q}dr{xENR%B-j~bxftXasht7GcaxhGME_nfFv7OkePuW z$mW44U=Uys1oAi-guo)aKz8WlwTw!P%#$xLiYmfXvM>k(As0|q1c-s={9zDd1nLr< Y{Dsj(1SH1Fz{KMKvQ-SoVPX&m0Mm#k%m4rY delta 193 zcmXAiNeaSH5Jcb4oDky_<2(ffk*p*K5X{PhxXnRa#oWQYD?!8qcpBY{*ijmq>Q{8t z(YzVS<8!?ODY1t`=+Pl^vFO_LJPbmczQ=%}&8SE+L*M6lamuW*&xC35Tw61rIn#2f z4#^lL1Lo?2I*U*QvaKJ~CBKd@x+ZK}zEr%>etv*1#FjRP2$#nH=S`%9G|Qcqh7~i> M{7u!+l0&2Y1t1s|f&c&j diff --git a/regression/cbmc-java/nondetByte/NondetByte.class b/regression/cbmc-java/nondetByte/NondetByte.class index b73d4e57e715e6053fdc3584e88056f34c2010fd..208b0bd3abac7845d0c67e615b91882c64dfc2fb 100644 GIT binary patch delta 279 zcmX|*yGjFL5QV?ldzRm*F-GGx#w!v?6G$P52FqZj_N%TK2rlRr`V!)jx3IGk6?_1n zMtc!wSCHWh=bX8|I1g^?M~~9%+Qmc}TOD6N4yaN3pLCeg esA_Fmp?klnN!~O1l1?@ETr9Jfe=(!NV)hp>k|o># delta 193 zcmXAiNeaSH5Jcb4oDky_<2)s}k${^VK+%OKahscnA%}47N_61?Jd9pI#8zo&s$bDn z2lHa2_xJS%WF#IAp+}3z#iDJ~@h}K&x*k3HHiIJF82T>Hi{r`~`ivMCkA*eynG%LfxD$hLk^m;5Te=!&p)`Bd>t`}qO75L?o)wAl>_sD&)DRKR1|XC=g;=Cc~I#=6f&+C1)*d+}v7 zI*-P~=wj4A&640GgW;`UdMEMCRX^ztqVc|9U&pZ^cZzPB9C>v^gU$4<#+m1F97MCmm)r eDq5RU=-zLtlJ!i!q+Q887t0)GU(BnpSoj4X`X$Ez delta 193 zcmXAiNeaSH5Jcb4oDky_<2)s}k${^VK+%OKahscnA%}47N_61?Jd9pI#8zo&s$bDn z2lHa2_xJS%WF#IAp+}3z#iDJ~@h}K&x*k3HHiIJF82T>Hi{r`~`ivMCkA*eynG%LfxD$hLk^m;5Te=!&p)`Bd>t`}qO75L?+ZN^~8y(n9foM({BV-T4%{5(EXe zK93tg#7P7fGyL<-{KNllKRB(ApO-hF%|?JvBVd}D3NEuAa{)FDkNJQF7Cn~oRLw7l3g=YS`?XHHb zv7Ue4?{6VnN#JZgqn<=qMAF?7YDPtee+P^)E|X8SBqO3vhmWecqf1AG7UD@}pP0(O i)27Y@HQCjrfMT#jIEaG1gB_`nj delta 193 zcmXAiI|{;35Jk_+SHm;@qQ+1BTPSG+7a*t`a1pj{#gNV&SXv1dg00K3u@P~i3=DV9 zaPK|ZcPoB;t~X%8$RkJKQKO#6q2UsGSOhLjj}~p0P7<#zbGP3or_P~&5DJ0_5m(|WYCV;aF!TqTMQ;&<&|9=<6-4*| zJx+^O5uKT!#W{SJ^Buma^<=j`e%_`)n_VA|nopgj0uIYAD?S!AmsOuN)?GHzR`;mf z*H=+|9*sxQWjs8~mcmMINB4?if1vNKheZ?smZ2bo@)beu-OCe8Hyz}X7e zW+(l8JlRKFDPZrtqFw|Tlw>=(Xfh)>_&Z>hIbj~`Duvp7d3w3UkgcL;Q~aobs4rUMMA(e*jfn|F2L0Ywjxd<1H+wj znS0OH!;GKb`vX`paVZeEG-wvFX*q;0CV@lSr9;=Dm&9AsI2@13Wn)JkeFn*EX%9U{ zjMKR~#Suydti=s=6`}BD+c`8Ozl1`ksAPB)R}sL5!I7P-0ppnVB2oTsrQv;w8&>T(KYwiRK*q!Xl(NOmGq z#r%h6eo$wE70kqKOmH{pC5z-jl?$s>$1-0^Ei)AjkK!skn6UT~y9w=r_=(Vae;poW sl%tCZe^vx>vX#5d%I97XYw!TwSybR~wM*!r%G&!GP=m`8p?NTSD=k;ob0YJtNHQkf*rX!ciCmTQ zAKJxHT?kIRFlIvVH|CnBa-ph)mC<`yETxvYN=GMg69H^Ee2LwJuq06?^dVX&Cz%%L qp~jz;L7Z&m?y`!wm&6%9Kz9~3cwF5ITBx%Qeg-t)^F(M?uHXv-n=LT_ literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetGeneric/NondetGeneric.class b/regression/cbmc-java/nondetGeneric/NondetGeneric.class new file mode 100644 index 0000000000000000000000000000000000000000..3e519783af3fea23f1a3cdb4f4198432acec5625 GIT binary patch literal 822 zcmZWmO>fgc5Pcgv*~E35&$dY@P}%}XK;+UBR0tGW4ulrbs)*bidr7w#Z?twQ_$&Pb zoB@d^%9z$kB1~R(KU^JTh3}#1pf+63Pf!H3s>I=OW zCo`0~%60sGN6Yv=c{HN~8OGV$D)2<~Py|9t_YT7%<@(QLbf8Aj=Ify^T^a4Y84`~1 zLMeuHcS|YCo865Z_vK?}m;h1>4E29X?}wor1Tq*r72(K_7_u9#KhbOLs*!fZmQ2*0 z5pe6!IdW{+nB}-;<2o9|ON2Ho%rI2raNBo+L7NE1Q`yv7Y0`5Bhofnug&Pco(~_P3 zp>Rn`S?NLB9cpzXbi4B;u{6#gnFK?n(d?ctqK5OQZyld@!m!|pP-@{#rO-&C5d~-= zJuK5obF^w!sK(;SGwD!gV3;GXO_q^Ow@$#`k&{B6{+aP33gp`pzlajuvM5iBdz2j) z*FPck9mb>gFprUM{lLr@q@SN4^DRa+62v*OAPJmA)Clu0GAFzW<|(#7CkyrqHI7B{ zs#BiZ#1nt>2|g PBW2%<$5W?E3K#wWN;RQ% literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetGeneric/NondetGeneric.java b/regression/cbmc-java/nondetGeneric/NondetGeneric.java new file mode 100644 index 00000000000..0fae8fb674f --- /dev/null +++ b/regression/cbmc-java/nondetGeneric/NondetGeneric.java @@ -0,0 +1,18 @@ +import org.cprover.CProver; + +class Foo { } + +class NondetGeneric +{ + static void callWithoutExplicitType() + { + // User may cast to incompatible type. + Foo foo = CProver.nondet(); + assert foo == null; + } + + static void callWithoutAssigningResult() + { + assert CProver.nondet() == null; + } +} diff --git a/regression/cbmc-java/nondetGeneric/dissasembly.txt b/regression/cbmc-java/nondetGeneric/dissasembly.txt new file mode 100644 index 00000000000..c075155e9fb --- /dev/null +++ b/regression/cbmc-java/nondetGeneric/dissasembly.txt @@ -0,0 +1,42 @@ +Compiled from "NondetGeneric.java" +class NondetGeneric { + static final boolean $assertionsDisabled; + + NondetGeneric(); + Code: + 0: aload_0 + 1: invokespecial #1 // Method java/lang/Object."":()V + 4: return + + static void callWithoutExplicitType(); + Code: + 0: invokestatic #2 // Method org/cprover/CProver.nondet:()Ljava/lang/Object; + 3: checkcast #3 // class Foo + 6: astore_0 + 7: getstatic #4 // Field $assertionsDisabled:Z + 10: ifne 25 + 13: aload_0 + 14: ifnull 25 + 17: new #5 // class java/lang/AssertionError + 20: dup + 21: invokespecial #6 // Method java/lang/AssertionError."":()V + 24: athrow + 25: return + + static void callWithoutAssigningResult(); + Code: + 0: invokestatic #2 // Method org/cprover/CProver.nondet:()Ljava/lang/Object; + 3: pop + 4: return + + static {}; + Code: + 0: ldc #7 // class NondetGeneric + 2: invokevirtual #8 // Method java/lang/Class.desiredAssertionStatus:()Z + 5: ifne 12 + 8: iconst_1 + 9: goto 13 + 12: iconst_0 + 13: putstatic #4 // Field $assertionsDisabled:Z + 16: return +} diff --git a/regression/cbmc-java/nondetGeneric/dissasemblyNDebug.txt b/regression/cbmc-java/nondetGeneric/dissasemblyNDebug.txt new file mode 100644 index 00000000000..1e25c9dac82 --- /dev/null +++ b/regression/cbmc-java/nondetGeneric/dissasemblyNDebug.txt @@ -0,0 +1,48 @@ +Compiled from "NondetGeneric.java" +class NondetGeneric { + static final boolean $assertionsDisabled; + + NondetGeneric(); + Code: + 0: aload_0 + 1: invokespecial #1 // Method java/lang/Object."":()V + 4: return + + static void callWithoutExplicitType(); + Code: + 0: invokestatic #2 // Method org/cprover/CProver.nondet:()Ljava/lang/Object; + 3: checkcast #3 // class Foo + 6: astore_0 + 7: getstatic #4 // Field $assertionsDisabled:Z + 10: ifne 25 + 13: aload_0 + 14: ifnull 25 + 17: new #5 // class java/lang/AssertionError + 20: dup + 21: invokespecial #6 // Method java/lang/AssertionError."":()V + 24: athrow + 25: return + + static void callWithoutAssigningResult(); + Code: + 0: getstatic #4 // Field $assertionsDisabled:Z + 3: ifne 20 + 6: invokestatic #2 // Method org/cprover/CProver.nondet:()Ljava/lang/Object; + 9: ifnull 20 + 12: new #5 // class java/lang/AssertionError + 15: dup + 16: invokespecial #6 // Method java/lang/AssertionError."":()V + 19: athrow + 20: return + + static {}; + Code: + 0: ldc #7 // class NondetGeneric + 2: invokevirtual #8 // Method java/lang/Class.desiredAssertionStatus:()Z + 5: ifne 12 + 8: iconst_1 + 9: goto 13 + 12: iconst_0 + 13: putstatic #4 // Field $assertionsDisabled:Z + 16: return +} diff --git a/regression/cbmc-java/nondetGeneric/test.desc b/regression/cbmc-java/nondetGeneric/test.desc new file mode 100644 index 00000000000..3c655cd1747 --- /dev/null +++ b/regression/cbmc-java/nondetGeneric/test.desc @@ -0,0 +1,6 @@ +CORE +NondetGeneric.class +--function NondetGeneric.foo +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/nondetInt/NondetInt.class b/regression/cbmc-java/nondetInt/NondetInt.class index 41ac3851c34fd552d168edcb9ed114fd119a8fd9..3b244fcdd0c248c57f4acd1aa5ab5650214043a2 100644 GIT binary patch delta 278 zcmdnS(!;8A>ff$?3=9k=3>sVv91N0N3{nizoD6IXGVBbpTnsD>lI#p}TnzFI3hWGu z6Lnn7gnaUo6LZ26i!u|Fa#BM;1S11WNk(QdBLlaOUw&RnYKdoFi8Uhwb6S2rBLiav z5PME6abQ#8VNhmJnYc@jO_hg1jX{0lyIwne2B0j^dRDFN42&Cr3?>FXAjt+6WM<$8 zvUwm17z7vufjkZdA+QK9kR3XCIir#}Ggt>712a&B9q3>V1~CRsxK0)ZVIUL%%83Fo g(A+-^VvHa)lix9#h=9ac8JKt+K&}u6a+nw-0L9=XWdHyG delta 193 zcmXAiOAf(c6otRPkH0ikuc~LMiitEv79i2Jn06x!n(o2egv7uCY=tF=xGFcfIrlrc z=N#;dl|DYVJFsElQX_Eb5!TW49R@BIfy2;c#Mog{q?u*z^Sn51b>uN+R=n0a_L!5D zu{x#^N(SuJ6?GP&@MY@?nv&nd6WtKDE1xP^8kO&33UQ>ZMo693|L0ApgtW`d*aSaj NV|d$NLq`sS?iUVR6pfYi{KAS2JgBpYS#1DOT`V2r>p#7{`+Zh-)0vSvUd_a;7EXd5j z4`lN|6fg)d2m*N=3_@TLULZSs@+w9ZM&`-q8ATOgDp?pr8H5=`fU=@M3^eBtg9Hmu am)PXbj3y!=F;)g99tV)E;y?})g9HF!9VY_- delta 193 zcmXAiOAf(c6otRPPnuu7ih9(mOr(j41&}bY5K}vmR2N}vBq6Z?i(vyIZplq<&izjA zIY;|uC6CYb4lIa03IrYvnnfI1E}@4-;L`T!&~@ph$=Wh^`+a&^IgzH%AbrlAp=QK5 zi`5~CP%>c8E~v8zg)iIrK~wU}XwfBMo9v|~Q{(6Rm_l4>D-cqo^8a}g=A@c!jYW_% N8$&PihMF7(^)DWJ6@>r* diff --git a/regression/cbmc-java/nondetShort/NondetShort.class b/regression/cbmc-java/nondetShort/NondetShort.class index 2012b00d57ba6432ab28049ae3b5f966dbf88d9a..24e76af762bf8a9b407843d66e544c9d9bb84d1b 100644 GIT binary patch delta 264 zcmdnPGKE#=)W2Q(7#J8#7&N#TI2a_k7^E1aIT_d(WY`&Gxfoa&B-t6{xESOa6xbOQ zC+fIZ2>IkEC+37D7G)+T<)nsy2u22$l8nq^Mh0FVzx=$E)RN$g{Gt+TMh51z{Cq|R z#tI+~o>=0S5Mu=D a5}W*m(L@9!#>&9N;{dW%9LQl}kN^PK6(^AZ delta 193 zcmXAiNeaSH5Jcb4sNox@7{@q7bRk)|@BpGNJ%?M5A|W2att&yq19%$2t%x0^p{agF zR~_w}l{`MzJFsBvQ6TVW5EgN0y0knj0++T&hptO6O*WRf+warU%84|62I+I|3^gO- zY^n}PgpvV!c0rv*D16z@51Nu+MvE>9TW2p7PmG`MV+wJltw2bT%Kzt0sDxCrt+5Dl OW@G4O-cXanp#B9UNEM6# From 9a992af011976ff2d2b46316923478e2c4df1f5b Mon Sep 17 00:00:00 2001 From: reuk Date: Wed, 22 Feb 2017 11:27:04 +0000 Subject: [PATCH 08/39] Add support for generic nondet Remove test case with multiple test methods --- regression/cbmc-java/nondetGeneric/Bar.class | Bin 244 -> 0 bytes regression/cbmc-java/nondetGeneric/Baz.class | Bin 244 -> 0 bytes regression/cbmc-java/nondetGeneric/Foo.class | Bin 244 -> 0 bytes .../nondetGeneric/NondetGeneric.class | Bin 822 -> 0 bytes .../nondetGeneric/NondetGeneric.java | 18 ------ .../cbmc-java/nondetGeneric/dissasembly.txt | 42 ------------- .../nondetGeneric/dissasemblyNDebug.txt | 48 -------------- regression/cbmc-java/nondetGeneric/test.desc | 6 -- .../java_bytecode_convert_method.cpp | 59 +++++++++++++++--- 9 files changed, 51 insertions(+), 122 deletions(-) delete mode 100644 regression/cbmc-java/nondetGeneric/Bar.class delete mode 100644 regression/cbmc-java/nondetGeneric/Baz.class delete mode 100644 regression/cbmc-java/nondetGeneric/Foo.class delete mode 100644 regression/cbmc-java/nondetGeneric/NondetGeneric.class delete mode 100644 regression/cbmc-java/nondetGeneric/NondetGeneric.java delete mode 100644 regression/cbmc-java/nondetGeneric/dissasembly.txt delete mode 100644 regression/cbmc-java/nondetGeneric/dissasemblyNDebug.txt delete mode 100644 regression/cbmc-java/nondetGeneric/test.desc diff --git a/regression/cbmc-java/nondetGeneric/Bar.class b/regression/cbmc-java/nondetGeneric/Bar.class deleted file mode 100644 index 7e9d05cd483e75bf4e5ad34a07b09679a256fd02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 244 zcmXYr%?`m(5QWd^A5}l`1eRFn#*SE!uxVHj``h-0D|MS(<-M#V79PMui76(TnKNI` zWajmLJOPZ*_F1`ksAPB)R}sL5!I7P-0ppnVB2oTsrQv;w8&>T(KYwiRK*q!Xl(NOmGq z#r%h6eo$wE70kqKOmH{pC5z-jl?$s>$1-0^Ei)AjkK!skn6UT~y9w=r_=(Vae;poW sl%tCZe^vx>vX#5d%I97XYw!TwSybR~wM*!r%G&!GP=m`8p?NTSD=k;ob0YJtNHQkf*rX!ciCmTQ zAKJxHT?kIRFlIvVH|CnBa-ph)mC<`yETxvYN=GMg69H^Ee2LwJuq06?^dVX&Cz%%L qp~jz;L7Z&m?y`!wm&6%9Kz9~3cwF5ITBx%Qeg-t)^F(M?uHXv-n=LT_ diff --git a/regression/cbmc-java/nondetGeneric/NondetGeneric.class b/regression/cbmc-java/nondetGeneric/NondetGeneric.class deleted file mode 100644 index 3e519783af3fea23f1a3cdb4f4198432acec5625..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 822 zcmZWmO>fgc5Pcgv*~E35&$dY@P}%}XK;+UBR0tGW4ulrbs)*bidr7w#Z?twQ_$&Pb zoB@d^%9z$kB1~R(KU^JTh3}#1pf+63Pf!H3s>I=OW zCo`0~%60sGN6Yv=c{HN~8OGV$D)2<~Py|9t_YT7%<@(QLbf8Aj=Ify^T^a4Y84`~1 zLMeuHcS|YCo865Z_vK?}m;h1>4E29X?}wor1Tq*r72(K_7_u9#KhbOLs*!fZmQ2*0 z5pe6!IdW{+nB}-;<2o9|ON2Ho%rI2raNBo+L7NE1Q`yv7Y0`5Bhofnug&Pco(~_P3 zp>Rn`S?NLB9cpzXbi4B;u{6#gnFK?n(d?ctqK5OQZyld@!m!|pP-@{#rO-&C5d~-= zJuK5obF^w!sK(;SGwD!gV3;GXO_q^Ow@$#`k&{B6{+aP33gp`pzlajuvM5iBdz2j) z*FPck9mb>gFprUM{lLr@q@SN4^DRa+62v*OAPJmA)Clu0GAFzW<|(#7CkyrqHI7B{ zs#BiZ#1nt>2|g PBW2%<$5W?E3K#wWN;RQ% diff --git a/regression/cbmc-java/nondetGeneric/NondetGeneric.java b/regression/cbmc-java/nondetGeneric/NondetGeneric.java deleted file mode 100644 index 0fae8fb674f..00000000000 --- a/regression/cbmc-java/nondetGeneric/NondetGeneric.java +++ /dev/null @@ -1,18 +0,0 @@ -import org.cprover.CProver; - -class Foo { } - -class NondetGeneric -{ - static void callWithoutExplicitType() - { - // User may cast to incompatible type. - Foo foo = CProver.nondet(); - assert foo == null; - } - - static void callWithoutAssigningResult() - { - assert CProver.nondet() == null; - } -} diff --git a/regression/cbmc-java/nondetGeneric/dissasembly.txt b/regression/cbmc-java/nondetGeneric/dissasembly.txt deleted file mode 100644 index c075155e9fb..00000000000 --- a/regression/cbmc-java/nondetGeneric/dissasembly.txt +++ /dev/null @@ -1,42 +0,0 @@ -Compiled from "NondetGeneric.java" -class NondetGeneric { - static final boolean $assertionsDisabled; - - NondetGeneric(); - Code: - 0: aload_0 - 1: invokespecial #1 // Method java/lang/Object."":()V - 4: return - - static void callWithoutExplicitType(); - Code: - 0: invokestatic #2 // Method org/cprover/CProver.nondet:()Ljava/lang/Object; - 3: checkcast #3 // class Foo - 6: astore_0 - 7: getstatic #4 // Field $assertionsDisabled:Z - 10: ifne 25 - 13: aload_0 - 14: ifnull 25 - 17: new #5 // class java/lang/AssertionError - 20: dup - 21: invokespecial #6 // Method java/lang/AssertionError."":()V - 24: athrow - 25: return - - static void callWithoutAssigningResult(); - Code: - 0: invokestatic #2 // Method org/cprover/CProver.nondet:()Ljava/lang/Object; - 3: pop - 4: return - - static {}; - Code: - 0: ldc #7 // class NondetGeneric - 2: invokevirtual #8 // Method java/lang/Class.desiredAssertionStatus:()Z - 5: ifne 12 - 8: iconst_1 - 9: goto 13 - 12: iconst_0 - 13: putstatic #4 // Field $assertionsDisabled:Z - 16: return -} diff --git a/regression/cbmc-java/nondetGeneric/dissasemblyNDebug.txt b/regression/cbmc-java/nondetGeneric/dissasemblyNDebug.txt deleted file mode 100644 index 1e25c9dac82..00000000000 --- a/regression/cbmc-java/nondetGeneric/dissasemblyNDebug.txt +++ /dev/null @@ -1,48 +0,0 @@ -Compiled from "NondetGeneric.java" -class NondetGeneric { - static final boolean $assertionsDisabled; - - NondetGeneric(); - Code: - 0: aload_0 - 1: invokespecial #1 // Method java/lang/Object."":()V - 4: return - - static void callWithoutExplicitType(); - Code: - 0: invokestatic #2 // Method org/cprover/CProver.nondet:()Ljava/lang/Object; - 3: checkcast #3 // class Foo - 6: astore_0 - 7: getstatic #4 // Field $assertionsDisabled:Z - 10: ifne 25 - 13: aload_0 - 14: ifnull 25 - 17: new #5 // class java/lang/AssertionError - 20: dup - 21: invokespecial #6 // Method java/lang/AssertionError."":()V - 24: athrow - 25: return - - static void callWithoutAssigningResult(); - Code: - 0: getstatic #4 // Field $assertionsDisabled:Z - 3: ifne 20 - 6: invokestatic #2 // Method org/cprover/CProver.nondet:()Ljava/lang/Object; - 9: ifnull 20 - 12: new #5 // class java/lang/AssertionError - 15: dup - 16: invokespecial #6 // Method java/lang/AssertionError."":()V - 19: athrow - 20: return - - static {}; - Code: - 0: ldc #7 // class NondetGeneric - 2: invokevirtual #8 // Method java/lang/Class.desiredAssertionStatus:()Z - 5: ifne 12 - 8: iconst_1 - 9: goto 13 - 12: iconst_0 - 13: putstatic #4 // Field $assertionsDisabled:Z - 16: return -} diff --git a/regression/cbmc-java/nondetGeneric/test.desc b/regression/cbmc-java/nondetGeneric/test.desc deleted file mode 100644 index 3c655cd1747..00000000000 --- a/regression/cbmc-java/nondetGeneric/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -NondetGeneric.class ---function NondetGeneric.foo -^VERIFICATION FAILED$ --- -^warning: ignoring diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index 1b82d2f65ac..15cf0bddbec 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -5,6 +5,7 @@ Module: JAVA Bytecode Language Conversion Author: Daniel Kroening, kroening@kroening.com \*******************************************************************/ + #ifdef DEBUG #include #endif @@ -994,15 +995,18 @@ codet java_bytecode_convert_methodt::convert_instructions( while(!working_set.empty()) { - std::set::iterator cur=working_set.begin(); - address_mapt::iterator a_it=address_map.find(*cur); - assert(a_it!=address_map.end()); + std::set::iterator cur = working_set.begin(); + address_mapt::iterator a_it = address_map.find(*cur); + assert(a_it != address_map.end()); working_set.erase(cur); - if(a_it->second.done) + if (a_it->second.done) + { continue; - working_set - .insert(a_it->second.successors.begin(), a_it->second.successors.end()); + } + + working_set.insert(a_it->second.successors.begin(), + a_it->second.successors.end()); instructionst::const_iterator i_it=a_it->second.source; stack.swap(a_it->second.stack); @@ -1017,8 +1021,8 @@ codet java_bytecode_convert_methodt::convert_instructions( "$stack")); irep_idt statement=i_it->statement; - exprt arg0=i_it->args.size()>=1?i_it->args[0]:nil_exprt(); - exprt arg1=i_it->args.size()>=2?i_it->args[1]:nil_exprt(); + exprt arg0 = i_it->args.size() >= 1 ? i_it->args[0] : nil_exprt(); + exprt arg1 = i_it->args.size() >= 2 ? i_it->args[1] : nil_exprt(); const bytecode_infot &bytecode_info=get_bytecode_info(statement); @@ -1193,6 +1197,45 @@ codet java_bytecode_convert_methodt::convert_instructions( results[0].add_source_location() = i_it->source_location; } + // To catch the return type of the nondet call, we have to check the + // next statement for an assignment. + // Check that the statement is static, with the correct signature, and + // that the working set still has remaining items. + else if (statement == "invokestatic" && + has_prefix(id2string(arg0.get(ID_identifier)), + "java::org.cprover.CProver.nondet:()L") && + !working_set.empty()) + { + // For the type search to succeed, the next instruction must be a + // checkcast. + // Find the next item in the working set, and look up that item in the + // address map. + address_mapt::iterator next_it = address_map.find(*working_set.begin()); + assert(next_it != address_map.end()); + + // Create somewhere to store the result, and set the source location. + results.resize(1); + results[0].add_source_location() = i_it->source_location; + + instructionst::const_iterator next_source_it = next_it->second.source; + // If the next item is a checkcast with a 'symbol' argument: + if (next_source_it->statement == "checkcast" && + next_source_it->args.size() >= 1 && + next_source_it->args[0].type().id() == ID_symbol) + { + // We assume that the nondet expression has the symbol type. + results[0] = side_effect_expr_nondett( + java_reference_type(next_source_it->args[0].type())); + } + else + { + // If the next item is not a checkcast, we create a nondet Object + // instead. + results[0] = side_effect_expr_nondett( + java_reference_type(symbol_typet("java::java.lang.Object"))); + } + } + else if(statement=="invokeinterface" || statement=="invokespecial" || statement=="invokevirtual" || From f97cf4faa33aa8ab60476c8a91bf9f7655b57467 Mon Sep 17 00:00:00 2001 From: reuk Date: Wed, 22 Feb 2017 11:36:38 +0000 Subject: [PATCH 09/39] Add 'assignment' test cases for generic nondet --- .../nondetGenericImplicitType/Foo.class | Bin 0 -> 256 bytes .../NondetGenericImplicitType.class | Bin 0 -> 754 bytes .../NondetGenericImplicitType.java | 13 ++ .../nondetGenericImplicitType/test.desc | 6 + .../NondetGenericNoAssignment.class | Bin 0 -> 697 bytes .../NondetGenericNoAssignment.java | 9 ++ .../nondetGenericNoAssignment/goto.txt | 140 ++++++++++++++++++ .../nondetGenericNoAssignment/test.desc | 6 + 8 files changed, 174 insertions(+) create mode 100644 regression/cbmc-java/nondetGenericImplicitType/Foo.class create mode 100644 regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.class create mode 100644 regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.java create mode 100644 regression/cbmc-java/nondetGenericImplicitType/test.desc create mode 100644 regression/cbmc-java/nondetGenericNoAssignment/NondetGenericNoAssignment.class create mode 100644 regression/cbmc-java/nondetGenericNoAssignment/NondetGenericNoAssignment.java create mode 100644 regression/cbmc-java/nondetGenericNoAssignment/goto.txt create mode 100644 regression/cbmc-java/nondetGenericNoAssignment/test.desc diff --git a/regression/cbmc-java/nondetGenericImplicitType/Foo.class b/regression/cbmc-java/nondetGenericImplicitType/Foo.class new file mode 100644 index 0000000000000000000000000000000000000000..fa7a99ecf42e18d91a7f94737c817b49cb0eb9e0 GIT binary patch literal 256 zcmXYr&q@P949357|LMBg;sc0B_26E-DPDvYVQCL7z0XdArfg@*Iu(2@Pl5*@z=sku z)j*OjKfaKB|9pM{xWTAIg5v@w1%`zDPMm~$LUM7rB%}|1#e`uaj;Fg#%l*Q%os!eW zThlE~FLC~dX?T_wLe`AEza^A&zw0fJB`%yzy<2gZu;X6r<7V55m9Ti*^7Y!hnhGg0 zy{empQ6zO|+*3Vk*K7mMG0-n#kfvI-=c;P$kz`jNpm!Am6k78=OmLvO`ZM4VrA~yS Hy{q~K`*1QE literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.class b/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.class new file mode 100644 index 0000000000000000000000000000000000000000..a7e0ce04f43b0dd565f44c0304d094f84fe971ef GIT binary patch literal 754 zcmZ`$O>fgc5Pg$4*~D?1G%Y1*pcE*O1PNbyqe7rS5yBLtRz>9II7_?5^+s!_5`U$C zfHNRb1QKxKz;8l`u}M<|>cO6moq2EG%#UB6z5rOmO&evjY+S%af#os;E(xsID4->9 z*~S%I6<8(AuljK;O`>!Z-&e6e2<4DKeL`_vMJl;N$hSK?1gocql2G+jBsa$g18KI? zVnW^1fgkSpMy2s2X(f9qCbYaw9SvpjP)5?I;L*V-RDnviUytN%!UFe&&sDPbcb@rP zYE3A38(MSG%vRzDub%j$44JhMO6x&5na$qPV-v^?l}@sJCfTih|Il~fU`F7YgX_4# zG>q@SMupHwpWV=pcHMg?+jwA%HiYJxm;!AF9drq`)Apx>eHkRYR&93OU}W^6G;Z%% zW_hJiwhdO^?s)$;vDWHot{3uM2#Z4*D>8keXQ_V%Y1ICHBuq$<@sZk zAk4DovL&{K?lI^sJ2_POU;L9qjeTe0&!Nsy3G>tDK3AvBOCOQ@hWz7qu#Qmeen;gq z3NMaP{F)->GsM}9*yeF6XfoyrvS7Rgoa4I144r78dILNj0Kphiw`IrL0E5K W<=?~lf8Z3PfShwTmDS`Rho#?FjGU_g literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.java b/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.java new file mode 100644 index 00000000000..d7bd77d8cad --- /dev/null +++ b/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.java @@ -0,0 +1,13 @@ +import org.cprover.CProver; + +class Foo { } + +class NondetGenericImplicitType +{ + static void callWithImplicitType() + { + // User may cast to incompatible type. + Foo foo = CProver.nondet(); + assert foo == null; + } +} diff --git a/regression/cbmc-java/nondetGenericImplicitType/test.desc b/regression/cbmc-java/nondetGenericImplicitType/test.desc new file mode 100644 index 00000000000..f8326f141df --- /dev/null +++ b/regression/cbmc-java/nondetGenericImplicitType/test.desc @@ -0,0 +1,6 @@ +CORE +NondetGenericImplicitType.class +--function NondetGenericImplicitType.callWithImplicitType +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/nondetGenericNoAssignment/NondetGenericNoAssignment.class b/regression/cbmc-java/nondetGenericNoAssignment/NondetGenericNoAssignment.class new file mode 100644 index 0000000000000000000000000000000000000000..9fe464b56878def3ac95b641f6c332aed292ea0b GIT binary patch literal 697 zcmZ`$%Wl&^6g}5=;?y4hZ#KnM?DK;BIa26TE>+1)({Vxfo54$3nlhU_xi8 zk~rIswY2xyqh}6fL0B7(RGtd+T;xK_WTYM!g`DKaA~z2RJ?3R^q&ZYmQw0c@_Dr0- zdl8?^#2ULvHmfDrQ&XLYXVPX~zfk<%QG6PQSVS0N0fCQ=5I1m>(6@moi}Oju8UObE zRBNRPs~4*IxD{d(w+XF^{&IXI62k*jdJ-ikTAd0V4PKR&hnJUq6S`a5!~aR#db4^P zWV`{waw-a`MLI8whhU~0;PD?|gSXh=tx~IR8)DDp!~KEB#a_gg*w*fzgFdk1;4=T~ z<)e!x`xeRow9sbTKxa?Kx^cDzTu1`RFoviQz8Dy4|_X lPMHB{cj}+vpTYOu!*f5usWko-Wcf8X;Uimik1r0E{{Zy`l{EkW literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetGenericNoAssignment/NondetGenericNoAssignment.java b/regression/cbmc-java/nondetGenericNoAssignment/NondetGenericNoAssignment.java new file mode 100644 index 00000000000..b004690fb72 --- /dev/null +++ b/regression/cbmc-java/nondetGenericNoAssignment/NondetGenericNoAssignment.java @@ -0,0 +1,9 @@ +import org.cprover.CProver; + +class NondetGenericNoAssignment +{ + static void callWithoutAssignment() + { + assert CProver.nondet() == null; + } +} diff --git a/regression/cbmc-java/nondetGenericNoAssignment/goto.txt b/regression/cbmc-java/nondetGenericNoAssignment/goto.txt new file mode 100644 index 00000000000..10952a9216b --- /dev/null +++ b/regression/cbmc-java/nondetGenericNoAssignment/goto.txt @@ -0,0 +1,140 @@ +CBMC version 5.6 64-bit x86_64 linux +Parsing nondetGenericNoAssignment/NondetGenericNoAssignment.class +Java main class: nondetGenericNoAssignment.NondetGenericNoAssignment +Converting +Generating GOTO Program +Adding goto-destructor code on jump to pc12 +Adding CPROVER library (x86_64) +Removal of function pointers and virtual functions +Partial Inlining +Generic Property Instrumentation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +_start /* _start */ + // 0 no location + __CPROVER_initialize(); + // 1 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V + NondetGenericNoAssignment.callWithoutAssignment:()V(); + // 2 no location + END_FUNCTION +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +java.lang.Object.() /* java::java.lang.Object.:()V */ + // 3 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V + tmp_object_factory$1 = this; + // 4 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V + tmp_object_factory$1->@lock = false; + // 5 no location + END_FUNCTION +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +java.lang.AssertionError.() /* java::java.lang.AssertionError.:()V */ + // 6 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V + tmp_object_factory$2 = this; + // 7 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V + tmp_object_factory$2->@lock = false; + // 8 no location + END_FUNCTION +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +java.lang.Class.desiredAssertionStatus() /* java::java.lang.Class.desiredAssertionStatus:()Z */ + // 9 + tmp_object_factory$3 = NONDET(boolean); + // 10 no location + java.lang.Class.desiredAssertionStatus:()Z#return_value = tmp_object_factory$3; + // 11 no location + GOTO 1 + // 12 no location + java.lang.Class.desiredAssertionStatus:()Z#return_value = tmp_object_factory$3; + // 13 no location + 1: END_FUNCTION +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +NondetGenericNoAssignment.NondetGenericNoAssignment() /* java::NondetGenericNoAssignment.:()V */ + // 14 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 1 + // Labels: pc0 + &this->@java.lang.Object . java.lang.Object.:()V(); + // 15 no location + END_FUNCTION +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +NondetGenericNoAssignment.callWithoutAssignment() /* java::NondetGenericNoAssignment.callWithoutAssignment:()V */ + // 16 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 0 + // Labels: pc0 + $assertionsDisabled = false; + // 17 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 1 + IF (int)$assertionsDisabled != 0 THEN GOTO 1 + // 18 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 3 + // Labels: pc6 + SKIP + // 19 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 3 + IF (void *)NONDET(struct java.lang.Object *) == null THEN GOTO 1 + // 20 no location + // Labels: pc12 + struct java.lang.AssertionError *new_tmp0; + // 21 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 4 + new_tmp0 = MALLOC(struct java.lang.AssertionError, 5L); + // 22 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 4 + *new_tmp0 = { .@class_identifier="java::java.lang.AssertionError", + .@lock=false }; + // 23 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 6 + new_tmp0 . java.lang.AssertionError.:()V(); + // 24 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 6 + ASSERT false // assertion at file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 6 + // 25 no location + dead new_tmp0; + // 26 file NondetGenericNoAssignment.java line 8 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 8 + // Labels: pc20 + 1: GOTO 2 + // 27 no location + 2: END_FUNCTION +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +NondetGenericNoAssignment.() /* java::NondetGenericNoAssignment.:()V */ + // 28 no location + int $stack_tmp1; + // 29 no location + // Labels: pc0 + boolean return_tmp0; + // 30 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 1 + &NondetGenericNoAssignment@class_model . java.lang.Class.desiredAssertionStatus:()Z(); + // 31 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 1 + return_tmp0 = java.lang.Class.desiredAssertionStatus:()Z#return_value; + // 32 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 1 + dead java.lang.Class.desiredAssertionStatus:()Z#return_value; + // 33 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 2 + IF !((int)return_tmp0 != 0) THEN GOTO 1 + // 34 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 2 + dead return_tmp0; + // 35 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 2 + GOTO 2 + // 36 no location + 1: dead return_tmp0; + // 37 no location + // Labels: pc8 + $stack_tmp1 = 1; + // 38 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 4 + GOTO 3 + // 39 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 5 + // Labels: pc12 + 2: SKIP + // 40 no location + $stack_tmp1 = 0; + // 41 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 6 + // Labels: pc13 + 3: $assertionsDisabled = (boolean)$stack_tmp1; + // 42 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 7 + dead $stack_tmp1; + // 43 no location + END_FUNCTION +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +__CPROVER_initialize /* __CPROVER_initialize */ + // 44 no location + __CPROVER_rounding_mode = 0; + // 45 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V + $assertionsDisabled = false; + // 46 no location + NondetGenericNoAssignment.:()V(); + // 47 no location + END_FUNCTION diff --git a/regression/cbmc-java/nondetGenericNoAssignment/test.desc b/regression/cbmc-java/nondetGenericNoAssignment/test.desc new file mode 100644 index 00000000000..86137361e89 --- /dev/null +++ b/regression/cbmc-java/nondetGenericNoAssignment/test.desc @@ -0,0 +1,6 @@ +CORE +NondetGenericNoAssignment.class +--function NondetGenericNoAssignment.callWithoutAssigninment +^VERIFICATION FAILED$ +-- +^warning: ignoring From 943ba3f6cbbe0cba49916c0cd06210f5792ed5ba Mon Sep 17 00:00:00 2001 From: reuk Date: Wed, 22 Feb 2017 15:00:47 +0000 Subject: [PATCH 10/39] Fix object_factory issues with java.lang.Object --- .../java_bytecode_convert_method.cpp | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index 15cf0bddbec..ba7c8d4c118 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -22,9 +22,11 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include "bytecode_info.h" #include "java_bytecode_convert_method.h" #include "java_bytecode_convert_method_class.h" -#include "bytecode_info.h" +#include "java_object_factory.h" +#include "java_opaque_method_stubs.h" #include "java_types.h" #include @@ -1219,21 +1221,29 @@ codet java_bytecode_convert_methodt::convert_instructions( instructionst::const_iterator next_source_it = next_it->second.source; // If the next item is a checkcast with a 'symbol' argument: - if (next_source_it->statement == "checkcast" && - next_source_it->args.size() >= 1 && - next_source_it->args[0].type().id() == ID_symbol) - { - // We assume that the nondet expression has the symbol type. - results[0] = side_effect_expr_nondett( - java_reference_type(next_source_it->args[0].type())); - } - else - { - // If the next item is not a checkcast, we create a nondet Object - // instead. - results[0] = side_effect_expr_nondett( - java_reference_type(symbol_typet("java::java.lang.Object"))); - } + + const auto java_object_type = + (next_source_it->statement == "checkcast" && + next_source_it->args.size() >= 1 && + next_source_it->args[0].type().id() == ID_symbol) + ? next_source_it->args[0].type() + : symbol_typet("java::java.lang.Object"); + +#ifdef DEBUG + std::cerr << java_object_type.pretty() << '\n'; + std::cerr << symbol_table << '\n'; +#endif + + code_blockt init_code; + results[0] = object_factory( + java_reference_type(java_object_type), init_code, true, symbol_table, + max_array_length, i_it->source_location, get_message_handler()); + +#ifdef DEBUG + std::cerr << init_code.pretty() << '\n'; +#endif + + c = init_code; } else if(statement=="invokeinterface" || From caa86226c0930fd8aab04e4629ba1fe7dbeacebe Mon Sep 17 00:00:00 2001 From: reuk Date: Wed, 22 Feb 2017 15:01:23 +0000 Subject: [PATCH 11/39] Update test.desc for no-assignment generic nondet --- regression/cbmc-java/nondetGenericNoAssignment/test.desc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regression/cbmc-java/nondetGenericNoAssignment/test.desc b/regression/cbmc-java/nondetGenericNoAssignment/test.desc index 86137361e89..6d49a1f5a63 100644 --- a/regression/cbmc-java/nondetGenericNoAssignment/test.desc +++ b/regression/cbmc-java/nondetGenericNoAssignment/test.desc @@ -1,6 +1,6 @@ CORE NondetGenericNoAssignment.class ---function NondetGenericNoAssignment.callWithoutAssigninment +--function NondetGenericNoAssignment.callWithoutAssignment ^VERIFICATION FAILED$ -- ^warning: ignoring From 755773f16c7e286e26769b4aabcce4262e661700 Mon Sep 17 00:00:00 2001 From: reuk Date: Wed, 22 Feb 2017 15:49:42 +0000 Subject: [PATCH 12/39] Add generic recursive testcase Remove mistakenly-added txt files Fix formatting issues --- .../cbmc-java/nondetGenericRecursive/A.class | Bin 0 -> 249 bytes .../cbmc-java/nondetGenericRecursive/B.class | Bin 0 -> 267 bytes .../cbmc-java/nondetGenericRecursive/C.class | Bin 0 -> 267 bytes .../NondetGenericRecursive.class | Bin 0 -> 722 bytes .../NondetGenericRecursive.java | 24 ++++++++++++++++ .../nondetGenericRecursive/test.desc | 6 ++++ .../java_bytecode_convert_method.cpp | 26 ++++++++++-------- 7 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 regression/cbmc-java/nondetGenericRecursive/A.class create mode 100644 regression/cbmc-java/nondetGenericRecursive/B.class create mode 100644 regression/cbmc-java/nondetGenericRecursive/C.class create mode 100644 regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.class create mode 100644 regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java create mode 100644 regression/cbmc-java/nondetGenericRecursive/test.desc diff --git a/regression/cbmc-java/nondetGenericRecursive/A.class b/regression/cbmc-java/nondetGenericRecursive/A.class new file mode 100644 index 0000000000000000000000000000000000000000..005c8063d513f9db1756a4f3aae6fcb800c2ebe1 GIT binary patch literal 249 zcmXYrPfNo<5XIj#X=2l8idQcltp{`QRuPI&FQI}hy>GTdyCvPg=Fj)?BzW)x_@Sh; z)q$CL@5dXMpWm-<0FRg?2yhwWDn>?#o{Tl^GatUK43o*xdXS1Cda2{b26 zyw59Tclld+VBO*t19{IENlQ?6Br2Ef$?*OY^dVw^SY~vF0WL(Re*uh;h$D>8sq_Sy CYA+}N literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetGenericRecursive/B.class b/regression/cbmc-java/nondetGenericRecursive/B.class new file mode 100644 index 0000000000000000000000000000000000000000..8a18024f50bec9a3a4833f0bba7ce327a7d3c43f GIT binary patch literal 267 zcmXX=F;2rk5S)!28%)5#Ee$15;3i!V5{U$jWh6l9&zBXPWzN#Y&cCRTD0n~~g|Zi1 z?C#9$>}Yp?KfeHG$PxrdV@zY56G#z);$cpR?u<3vz0j-c6(L-kR$tPu!6u(uC)4VX=e!r^hmg^;3c1EvRH|}K4{CH4jl^{eU zKV*b~=V__zE`2QytZR(Xl1BlO3edSCIS}PWSSr)+IuDY$7s$5jW{ zaGhg~VR22QsWh3=N%}ygVjRnefsGg{n<`P+T?VT^*k!PN9Z80Ipc1(?IUGx~lQ%Q8 z0v(EYR~VJYr%5||rBa4Yu%(koW{+hejS64LaAHz5m3IjBrPf3gk{9?C&u?cUeEn1$ z6$qr6p}HByry87XJu#ttq;kgI`JlHC#8kL&G0$u4AcO+9~WHi%6SI8z*prenlO3zlK=VXmez6E&}eY7AL7Rd9+GP3323D{e5N~qJn zQY4#bknjF!Koc#Bs#u&2kElBzUipa9H&{>J!9GTP_#JbfQQkX2;6^IK3@iNJ2 zql*hOWKMWXSf;*qfzE!S%c)*PXU4NpumH^#|A6W-xcvsU^&a;Bf^(2EO76XUtu6&6 Gto#PhX^-Im literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java b/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java new file mode 100644 index 00000000000..ca0565dea9b --- /dev/null +++ b/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java @@ -0,0 +1,24 @@ +import org.cprover.CProver; + +class A +{ +} + +class B +{ + A a; +} + +class C +{ + B b; +} + +class NondetGenericRecursive +{ + static void foo() + { + C c = CProver.nondet(); + assert c == null; + } +} diff --git a/regression/cbmc-java/nondetGenericRecursive/test.desc b/regression/cbmc-java/nondetGenericRecursive/test.desc new file mode 100644 index 00000000000..33ea1bc39ea --- /dev/null +++ b/regression/cbmc-java/nondetGenericRecursive/test.desc @@ -0,0 +1,6 @@ +CORE +NondetGenericRecursive.class +--function NondetGenericRecursive.foo +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index ba7c8d4c118..1f8e3d42f88 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -1222,25 +1222,27 @@ codet java_bytecode_convert_methodt::convert_instructions( instructionst::const_iterator next_source_it = next_it->second.source; // If the next item is a checkcast with a 'symbol' argument: - const auto java_object_type = - (next_source_it->statement == "checkcast" && - next_source_it->args.size() >= 1 && - next_source_it->args[0].type().id() == ID_symbol) - ? next_source_it->args[0].type() - : symbol_typet("java::java.lang.Object"); + assert(next_source_it->statement == "checkcast"); + assert(next_source_it->args.size() >= 1); + assert(next_source_it->args[0].type().id() == ID_symbol); + const auto java_object_type = next_source_it->args[0].type(); #ifdef DEBUG - std::cerr << java_object_type.pretty() << '\n'; - std::cerr << symbol_table << '\n'; + std::cerr << "java_object_type: " << java_object_type.pretty() << '\n'; + std::cerr << "symbol_table: " << symbol_table << '\n'; #endif code_blockt init_code; - results[0] = object_factory( - java_reference_type(java_object_type), init_code, true, symbol_table, - max_array_length, i_it->source_location, get_message_handler()); + results[0] = object_factory(java_reference_type(java_object_type), + init_code, + true, + symbol_table, + max_array_length, + i_it->source_location, + get_message_handler()); #ifdef DEBUG - std::cerr << init_code.pretty() << '\n'; + std::cerr << "init_code: " << init_code.pretty() << '\n'; #endif c = init_code; From e3e7a91c8fac27e46212d50b81bda628c80fbc15 Mon Sep 17 00:00:00 2001 From: reuk Date: Thu, 23 Feb 2017 09:21:49 +0000 Subject: [PATCH 13/39] Replace object_factory with non-recursive nondet --- .../java_bytecode_convert_method.cpp | 37 +++++-------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index 1f8e3d42f88..a07fdf74aed 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -1203,10 +1203,9 @@ codet java_bytecode_convert_methodt::convert_instructions( // next statement for an assignment. // Check that the statement is static, with the correct signature, and // that the working set still has remaining items. - else if (statement == "invokestatic" && + else if (!working_set.empty() && statement == "invokestatic" && has_prefix(id2string(arg0.get(ID_identifier)), - "java::org.cprover.CProver.nondet:()L") && - !working_set.empty()) + "java::org.cprover.CProver.nondet:()L")) { // For the type search to succeed, the next instruction must be a // checkcast. @@ -1215,37 +1214,21 @@ codet java_bytecode_convert_methodt::convert_instructions( address_mapt::iterator next_it = address_map.find(*working_set.begin()); assert(next_it != address_map.end()); - // Create somewhere to store the result, and set the source location. - results.resize(1); - results[0].add_source_location() = i_it->source_location; - instructionst::const_iterator next_source_it = next_it->second.source; - // If the next item is a checkcast with a 'symbol' argument: + // Check that the statement is a checkcast with an argument of the + // correct type. assert(next_source_it->statement == "checkcast"); assert(next_source_it->args.size() >= 1); assert(next_source_it->args[0].type().id() == ID_symbol); const auto java_object_type = next_source_it->args[0].type(); -#ifdef DEBUG - std::cerr << "java_object_type: " << java_object_type.pretty() << '\n'; - std::cerr << "symbol_table: " << symbol_table << '\n'; -#endif - - code_blockt init_code; - results[0] = object_factory(java_reference_type(java_object_type), - init_code, - true, - symbol_table, - max_array_length, - i_it->source_location, - get_message_handler()); - -#ifdef DEBUG - std::cerr << "init_code: " << init_code.pretty() << '\n'; -#endif - - c = init_code; + // Create somewhere to store the result, and set the source location. + results.resize(1); + results[0].add_source_location() = i_it->source_location; + // Set the result to a nondet of the correct type. + results[0] = + side_effect_expr_nondett(java_reference_type(java_object_type)); } else if(statement=="invokeinterface" || From d53bab8a508067fde7bad61ed0bbdfbe1df389e1 Mon Sep 17 00:00:00 2001 From: reuk Date: Thu, 23 Feb 2017 09:24:26 +0000 Subject: [PATCH 14/39] Remove mistakenly-added txt file --- .../nondetGenericNoAssignment/goto.txt | 140 ------------------ 1 file changed, 140 deletions(-) delete mode 100644 regression/cbmc-java/nondetGenericNoAssignment/goto.txt diff --git a/regression/cbmc-java/nondetGenericNoAssignment/goto.txt b/regression/cbmc-java/nondetGenericNoAssignment/goto.txt deleted file mode 100644 index 10952a9216b..00000000000 --- a/regression/cbmc-java/nondetGenericNoAssignment/goto.txt +++ /dev/null @@ -1,140 +0,0 @@ -CBMC version 5.6 64-bit x86_64 linux -Parsing nondetGenericNoAssignment/NondetGenericNoAssignment.class -Java main class: nondetGenericNoAssignment.NondetGenericNoAssignment -Converting -Generating GOTO Program -Adding goto-destructor code on jump to pc12 -Adding CPROVER library (x86_64) -Removal of function pointers and virtual functions -Partial Inlining -Generic Property Instrumentation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -_start /* _start */ - // 0 no location - __CPROVER_initialize(); - // 1 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V - NondetGenericNoAssignment.callWithoutAssignment:()V(); - // 2 no location - END_FUNCTION -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -java.lang.Object.() /* java::java.lang.Object.:()V */ - // 3 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V - tmp_object_factory$1 = this; - // 4 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V - tmp_object_factory$1->@lock = false; - // 5 no location - END_FUNCTION -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -java.lang.AssertionError.() /* java::java.lang.AssertionError.:()V */ - // 6 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V - tmp_object_factory$2 = this; - // 7 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V - tmp_object_factory$2->@lock = false; - // 8 no location - END_FUNCTION -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -java.lang.Class.desiredAssertionStatus() /* java::java.lang.Class.desiredAssertionStatus:()Z */ - // 9 - tmp_object_factory$3 = NONDET(boolean); - // 10 no location - java.lang.Class.desiredAssertionStatus:()Z#return_value = tmp_object_factory$3; - // 11 no location - GOTO 1 - // 12 no location - java.lang.Class.desiredAssertionStatus:()Z#return_value = tmp_object_factory$3; - // 13 no location - 1: END_FUNCTION -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -NondetGenericNoAssignment.NondetGenericNoAssignment() /* java::NondetGenericNoAssignment.:()V */ - // 14 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 1 - // Labels: pc0 - &this->@java.lang.Object . java.lang.Object.:()V(); - // 15 no location - END_FUNCTION -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -NondetGenericNoAssignment.callWithoutAssignment() /* java::NondetGenericNoAssignment.callWithoutAssignment:()V */ - // 16 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 0 - // Labels: pc0 - $assertionsDisabled = false; - // 17 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 1 - IF (int)$assertionsDisabled != 0 THEN GOTO 1 - // 18 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 3 - // Labels: pc6 - SKIP - // 19 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 3 - IF (void *)NONDET(struct java.lang.Object *) == null THEN GOTO 1 - // 20 no location - // Labels: pc12 - struct java.lang.AssertionError *new_tmp0; - // 21 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 4 - new_tmp0 = MALLOC(struct java.lang.AssertionError, 5L); - // 22 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 4 - *new_tmp0 = { .@class_identifier="java::java.lang.AssertionError", - .@lock=false }; - // 23 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 6 - new_tmp0 . java.lang.AssertionError.:()V(); - // 24 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 6 - ASSERT false // assertion at file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 6 - // 25 no location - dead new_tmp0; - // 26 file NondetGenericNoAssignment.java line 8 function java::NondetGenericNoAssignment.callWithoutAssignment:()V bytecode_index 8 - // Labels: pc20 - 1: GOTO 2 - // 27 no location - 2: END_FUNCTION -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -NondetGenericNoAssignment.() /* java::NondetGenericNoAssignment.:()V */ - // 28 no location - int $stack_tmp1; - // 29 no location - // Labels: pc0 - boolean return_tmp0; - // 30 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 1 - &NondetGenericNoAssignment@class_model . java.lang.Class.desiredAssertionStatus:()Z(); - // 31 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 1 - return_tmp0 = java.lang.Class.desiredAssertionStatus:()Z#return_value; - // 32 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 1 - dead java.lang.Class.desiredAssertionStatus:()Z#return_value; - // 33 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 2 - IF !((int)return_tmp0 != 0) THEN GOTO 1 - // 34 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 2 - dead return_tmp0; - // 35 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 2 - GOTO 2 - // 36 no location - 1: dead return_tmp0; - // 37 no location - // Labels: pc8 - $stack_tmp1 = 1; - // 38 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 4 - GOTO 3 - // 39 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 5 - // Labels: pc12 - 2: SKIP - // 40 no location - $stack_tmp1 = 0; - // 41 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 6 - // Labels: pc13 - 3: $assertionsDisabled = (boolean)$stack_tmp1; - // 42 file NondetGenericNoAssignment.java line 3 function java::NondetGenericNoAssignment.:()V bytecode_index 7 - dead $stack_tmp1; - // 43 no location - END_FUNCTION -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -__CPROVER_initialize /* __CPROVER_initialize */ - // 44 no location - __CPROVER_rounding_mode = 0; - // 45 file NondetGenericNoAssignment.java line 7 function java::NondetGenericNoAssignment.callWithoutAssignment:()V - $assertionsDisabled = false; - // 46 no location - NondetGenericNoAssignment.:()V(); - // 47 no location - END_FUNCTION From fe49f1daa35c78d7428de9062844f8b0db5530e4 Mon Sep 17 00:00:00 2001 From: reuk Date: Thu, 23 Feb 2017 10:21:03 +0000 Subject: [PATCH 15/39] Add nondet recursive expansion to typecheck_expr Add nondet recursive expansion to typecheck_expr --- src/java_bytecode/java_bytecode_typecheck.h | 4 +- .../java_bytecode_typecheck_expr.cpp | 38 +++++++++++++++++-- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/java_bytecode/java_bytecode_typecheck.h b/src/java_bytecode/java_bytecode_typecheck.h index 618b6fce44d..0649eced348 100644 --- a/src/java_bytecode/java_bytecode_typecheck.h +++ b/src/java_bytecode/java_bytecode_typecheck.h @@ -21,8 +21,7 @@ Author: Daniel Kroening, kroening@kroening.com bool java_bytecode_typecheck( symbol_tablet &symbol_table, - message_handlert &message_handler, - bool string_refinement_enabled); + message_handlert &message_handler); bool java_bytecode_typecheck( exprt &expr, @@ -51,7 +50,6 @@ class java_bytecode_typecheckt:public typecheckt protected: symbol_tablet &symbol_table; const namespacet ns; - bool string_refinement_enabled; void typecheck_type_symbol(symbolt &); void typecheck_non_type_symbol(symbolt &); diff --git a/src/java_bytecode/java_bytecode_typecheck_expr.cpp b/src/java_bytecode/java_bytecode_typecheck_expr.cpp index 11e488ff7fe..31d2a3c6b0a 100644 --- a/src/java_bytecode/java_bytecode_typecheck_expr.cpp +++ b/src/java_bytecode/java_bytecode_typecheck_expr.cpp @@ -7,6 +7,9 @@ Author: Daniel Kroening, kroening@kroening.com \*******************************************************************/ #include +#ifdef DEBUG +#include +#endif #include #include @@ -16,9 +19,16 @@ Author: Daniel Kroening, kroening@kroening.com #include #include "java_bytecode_typecheck.h" +#include "java_object_factory.h" #include "java_pointer_casts.h" #include "java_types.h" +java_bytecode_typecheckt::java_bytecode_typecheckt( + symbol_tablet &_symbol_table, message_handlert &_message_handler) + : typecheckt(_message_handler), symbol_table(_symbol_table), ns(symbol_table) +{ +} + /*******************************************************************\ Function: java_bytecode_typecheckt::typecheck_expr @@ -47,11 +57,33 @@ void java_bytecode_typecheckt::typecheck_expr(exprt &expr) typecheck_expr_symbol(to_symbol_expr(expr)); else if(expr.id()==ID_side_effect) { - const irep_idt &statement=to_side_effect_expr(expr).get_statement(); - if(statement==ID_java_new) + const irep_idt &statement = to_side_effect_expr(expr).get_statement(); + if (statement == ID_java_new) + { typecheck_expr_java_new(to_side_effect_expr(expr)); - else if(statement==ID_java_new_array) + } + else if (statement == ID_java_new_array) + { typecheck_expr_java_new_array(to_side_effect_expr(expr)); + } + else if (statement == ID_nondet) + { + // TODO set this properly. + size_t max_nondet_array_length = 100; + + const typet &type = expr.type(); + + code_blockt init_code; + expr = object_factory(type, + init_code, + true, + symbol_table, + max_nondet_array_length, + type.source_location(), + get_message_handler()); + + typecheck_code(init_code); + } } else if(expr.id()==ID_java_string_literal) typecheck_expr_java_string_literal(expr); From ca39c44e679590150bab46b94cab28e0ce73e7f5 Mon Sep 17 00:00:00 2001 From: reuk Date: Thu, 23 Feb 2017 10:34:06 +0000 Subject: [PATCH 16/39] Use correct max_nondet_array_length --- src/java_bytecode/java_bytecode_language.cpp | 4 +--- src/java_bytecode/java_bytecode_typecheck.h | 2 +- src/java_bytecode/java_bytecode_typecheck_expr.cpp | 12 +++++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/java_bytecode/java_bytecode_language.cpp b/src/java_bytecode/java_bytecode_language.cpp index 668960dbe17..16f541c4fcc 100644 --- a/src/java_bytecode/java_bytecode_language.cpp +++ b/src/java_bytecode/java_bytecode_language.cpp @@ -43,7 +43,6 @@ void java_bytecode_languaget::get_language_options(const cmdlinet &cmd) { disable_runtime_checks=cmd.isset("disable-runtime-check"); assume_inputs_non_null=cmd.isset("java-assume-inputs-non-null"); - string_refinement_enabled=cmd.isset("string-refine"); if(cmd.isset("java-max-input-array-length")) max_nondet_array_length= std::stoi(cmd.get_value("java-max-input-array-length")); @@ -495,8 +494,7 @@ bool java_bytecode_languaget::typecheck( disable_runtime_checks, max_user_array_length, lazy_methods, - lazy_methods_mode, - string_refinement_enabled)) + lazy_methods_mode)) return true; } diff --git a/src/java_bytecode/java_bytecode_typecheck.h b/src/java_bytecode/java_bytecode_typecheck.h index 0649eced348..74efbb4cf41 100644 --- a/src/java_bytecode/java_bytecode_typecheck.h +++ b/src/java_bytecode/java_bytecode_typecheck.h @@ -42,7 +42,7 @@ class java_bytecode_typecheckt:public typecheckt { } - virtual ~java_bytecode_typecheckt() { } + virtual ~java_bytecode_typecheckt() = default; virtual void typecheck(); virtual void typecheck_expr(exprt &expr); diff --git a/src/java_bytecode/java_bytecode_typecheck_expr.cpp b/src/java_bytecode/java_bytecode_typecheck_expr.cpp index 31d2a3c6b0a..6c50b612793 100644 --- a/src/java_bytecode/java_bytecode_typecheck_expr.cpp +++ b/src/java_bytecode/java_bytecode_typecheck_expr.cpp @@ -24,8 +24,13 @@ Author: Daniel Kroening, kroening@kroening.com #include "java_types.h" java_bytecode_typecheckt::java_bytecode_typecheckt( - symbol_tablet &_symbol_table, message_handlert &_message_handler) - : typecheckt(_message_handler), symbol_table(_symbol_table), ns(symbol_table) + symbol_tablet &_symbol_table, + message_handlert &_message_handler, + size_t _max_nondet_array_length) + : typecheckt(_message_handler), + symbol_table(_symbol_table), + ns(symbol_table), + max_nondet_array_length(_max_nondet_array_length) { } @@ -68,9 +73,6 @@ void java_bytecode_typecheckt::typecheck_expr(exprt &expr) } else if (statement == ID_nondet) { - // TODO set this properly. - size_t max_nondet_array_length = 100; - const typet &type = expr.type(); code_blockt init_code; From 4aaeea08a99e25d0c2b69afd1e4efe13ee4b5972 Mon Sep 17 00:00:00 2001 From: reuk Date: Thu, 23 Feb 2017 11:04:21 +0000 Subject: [PATCH 17/39] Update cprover class to allow null/non-null nondet Update nondet generic test cases --- .../NondetGenericImplicitType.class | Bin 754 -> 762 bytes .../NondetGenericImplicitType.java | 2 +- .../NondetGenericNoAssignment.class | Bin 697 -> 705 bytes .../NondetGenericNoAssignment.java | 2 +- .../NondetGenericRecursive.class | Bin 722 -> 730 bytes .../NondetGenericRecursive.java | 2 +- .../cbmc-java/nondetGenericWithNull/A.class | Bin 0 -> 248 bytes .../cbmc-java/nondetGenericWithNull/B.class | Bin 0 -> 266 bytes .../NondetGenericWithNull.class | Bin 0 -> 727 bytes .../NondetGenericWithNull.java | 14 ++++++++++++++ .../cbmc-java/nondetGenericWithoutNull/A.class | Bin 0 -> 251 bytes .../cbmc-java/nondetGenericWithoutNull/B.class | Bin 0 -> 269 bytes .../NondetGenericWithoutNull.class | Bin 0 -> 739 bytes .../NondetGenericWithoutNull.java | 14 ++++++++++++++ .../library/src/org/cprover/CProver.java | 2 +- 15 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 regression/cbmc-java/nondetGenericWithNull/A.class create mode 100644 regression/cbmc-java/nondetGenericWithNull/B.class create mode 100644 regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.class create mode 100644 regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java create mode 100644 regression/cbmc-java/nondetGenericWithoutNull/A.class create mode 100644 regression/cbmc-java/nondetGenericWithoutNull/B.class create mode 100644 regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.class create mode 100644 regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java diff --git a/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.class b/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.class index a7e0ce04f43b0dd565f44c0304d094f84fe971ef..6cc50d38fa211b4d08c92f62fbd20b08a65e191c 100644 GIT binary patch delta 28 jcmeyw`iphLJVt)Ly!^bB)ROSbk_^AnoSe-|8GRW6q}B?_ delta 20 bcmeyx`iXVJJVti5y!^bB)RN6>8GRW6R-p%q diff --git a/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.java b/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.java index d7bd77d8cad..f157808974c 100644 --- a/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.java +++ b/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.java @@ -7,7 +7,7 @@ class NondetGenericImplicitType static void callWithImplicitType() { // User may cast to incompatible type. - Foo foo = CProver.nondet(); + Foo foo = CProver.nondetWithNull(); assert foo == null; } } diff --git a/regression/cbmc-java/nondetGenericNoAssignment/NondetGenericNoAssignment.class b/regression/cbmc-java/nondetGenericNoAssignment/NondetGenericNoAssignment.class index 9fe464b56878def3ac95b641f6c332aed292ea0b..6139221c11f9ef8b27a71ec78cd2f3477d729ad0 100644 GIT binary patch delta 28 jcmdnVdXRNPD@X#O7A0^JJ z12gm9#~Yac>*Wu?7~KdSUPHWv=n#UbGRl4uyy0j?@W0B9By>_`WLE#?vRaBd9c9+#!f9%Ck#PHE1(2US^ zKGDK#lX~L~bC7qyD&g%&^Zg7uv1lOV8Qh_V7VG#CKpPP|!pl7s-vBwP BE~Wqg literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetGenericWithNull/B.class b/regression/cbmc-java/nondetGenericWithNull/B.class new file mode 100644 index 0000000000000000000000000000000000000000..43a67432cead9b702e3179ecea4306bfa2c213da GIT binary patch literal 266 zcmXYry>7xl5QJy3u@mzf%2X*63f$0vkRVcMET>3B>a#h8L&sS%XWokniGl~t86L9`Jd zpd&*Ak6eShiHNyfbBoCZ Ib^fQif9@MF0RR91 literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.class b/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.class new file mode 100644 index 0000000000000000000000000000000000000000..4290cfa980aaf8699b5122572314c49ee0355e9a GIT binary patch literal 727 zcmZuu%Wl&^6g@X~GKuRpY5Gc19t8>{LBgBvs1P(f7MM_}sEF(wduXQ^yBa(FnEn83 zK%%IXfE5eA2_ddcl1k9U%zezg=iGDW=kL?605)*PLItZ9F5$Akl?nu|3anWuVpZUp zh3mK>uufQ5_mV{FRK-#9NG0AdlmUSTgwm#pRC=Fav^%>5vlj=FP<2%#`=fV5sb6Nr zgt{C1UbyRNmBr(vneMBEu;TXPD3Iw>8A+}DS1R4_kHYXCgT9Gl<{7f*ZgD)jlY0K! z=iXrsz#|jNn|?SR!P<#O+LupMM%cO#^X`FnD{#}sE!<}KEgKeQ2#xH~3B72~ zc{q{#SnF65mM%mSXxr$ZOQ@Zb$leX)7#E1VJ^z0PBao0+a34c zW>#7~&-FrHK4CeKiPAEdj>fx4NBqE>A7G9DuEKvxwMHg}J%bPH1aq?IuqC#|?g{7v zI|WqvF6Bvq8vFL&0?eb%Q5g%<<^fk{&8;see24MuBg|t|yFV~{+Cy{c%_4}Pmk!6$W@k^!5QX27kd%}b%8t|#7@CExRi#o1mM9&H=r~j){r4IZ6eiZ5% zGWh(xcXv;BI{zI3Ofg6hpckVbF|gap9&Da5bcI|ft?#xDgVCLp8SG-7+UCXjjkpV=5E8c LOg`xDGIjqC3Cl5D literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.class b/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.class new file mode 100644 index 0000000000000000000000000000000000000000..afc7b64b10cbb6ea96dddc7e4d0ca60c56b7d56c GIT binary patch literal 739 zcmZ`$O-~b16g{_{_O-)6KR|4YC?INE6KBItVwC!^uvQWb#_p!mCp;YIkvB8^82*53 zH4&qUx^m%fGR8Y&DMrI$=6;`Z&$~ZCmIW@CA#g=t#YO>30;@LG za8+QPFu(3aku=LY=9!o-{uR=LUUXP@CmNpaW zeeHX}u4hylPm)%=uOdRLKhWV=#*btujq;zXcwZ;+APIuojQdh+rW&!=-{N?7C-(eT zPrSnngSRG>HvM3-g}tK_F7ZEF+ZL*d#-LO-7vx8Y6E5%-hFIY{mifL^ZKRUe%k#%-L6~FDWlL-e-4oDT zc5qY~z)!$a;)hg%3+w|XB1wXp!hXK%x8#m z6Jo*BO{P9Y7L2!m3*5Juq0>(^1uimAW6HCUu>iHY_<+(eg!Kki{ynV!7fwM6$T@dY KSxpXdX#ED8k(Sf| literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java b/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java new file mode 100644 index 00000000000..54fced2dbc5 --- /dev/null +++ b/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java @@ -0,0 +1,14 @@ +import org.cprover.CProver; + +class A { } + +class B { A a; } + +class NondetGenericWithoutNull +{ + static void foo() + { + B b = CProver.nondetWithoutNull(); + assert b == null; + } +} diff --git a/src/java_bytecode/library/src/org/cprover/CProver.java b/src/java_bytecode/library/src/org/cprover/CProver.java index 46ad7723c9b..bf9a2ab515d 100644 --- a/src/java_bytecode/library/src/org/cprover/CProver.java +++ b/src/java_bytecode/library/src/org/cprover/CProver.java @@ -93,7 +93,7 @@ public static double nondetDouble() return 0; } - public static T nondet() + public static T nondet(boolean allowNull) { if (enableNondet) { From 1496ca15321e2235a0b5b506d892f60a084e31db Mon Sep 17 00:00:00 2001 From: reuk Date: Thu, 23 Feb 2017 15:07:58 +0000 Subject: [PATCH 18/39] Support both null and non-null nondet objects --- .../java_bytecode_convert_method.cpp | 18 +- .../java_bytecode_convert_method.cpp.orig | 2403 +++++++++++++++++ .../java_bytecode_typecheck_expr.cpp | 15 +- .../library/src/org/cprover/CProver.java | 15 +- src/util/irep_ids.txt | 3 +- src/util/std_code.h | 24 + 6 files changed, 2465 insertions(+), 13 deletions(-) create mode 100644 src/java_bytecode/java_bytecode_convert_method.cpp.orig diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index a07fdf74aed..0120b28c15b 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -1203,9 +1203,11 @@ codet java_bytecode_convert_methodt::convert_instructions( // next statement for an assignment. // Check that the statement is static, with the correct signature, and // that the working set still has remaining items. + // TODO this will break if the user edits cprover.CProver and adds another + // method that begins with 'nondetWith'. else if (!working_set.empty() && statement == "invokestatic" && has_prefix(id2string(arg0.get(ID_identifier)), - "java::org.cprover.CProver.nondet:()L")) + "java::org.cprover.CProver.nondetWith")) { // For the type search to succeed, the next instruction must be a // checkcast. @@ -1226,9 +1228,16 @@ codet java_bytecode_convert_methodt::convert_instructions( // Create somewhere to store the result, and set the source location. results.resize(1); results[0].add_source_location() = i_it->source_location; - // Set the result to a nondet of the correct type. - results[0] = + + auto nondet_result = side_effect_expr_nondett(java_reference_type(java_object_type)); + // If the function call contains 'nondetWithNull' then allow nulls. + nondet_result.set_allow_null( + has_prefix(id2string(arg0.get(ID_identifier)), + "java::org.cprover.CProver.nondetWithNull")); + + // Set the result to a nondet of the correct type. + results[0] = nondet_result; } else if(statement=="invokeinterface" || @@ -1832,8 +1841,7 @@ codet java_bytecode_convert_methodt::convert_instructions( results[2]=op[1]; results[3]=op[2]; } - // dup2* behaviour depends on the size of the operands on the - // stack + // dup2* behaviour depends on the size of the operands on the stack else if(statement=="dup2") { assert(!stack.empty() && results.empty()); diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp.orig b/src/java_bytecode/java_bytecode_convert_method.cpp.orig new file mode 100644 index 00000000000..a07fdf74aed --- /dev/null +++ b/src/java_bytecode/java_bytecode_convert_method.cpp.orig @@ -0,0 +1,2403 @@ +/*******************************************************************\ + +Module: JAVA Bytecode Language Conversion + +Author: Daniel Kroening, kroening@kroening.com + +\*******************************************************************/ + +#ifdef DEBUG +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "bytecode_info.h" +#include "java_bytecode_convert_method.h" +#include "java_bytecode_convert_method_class.h" +#include "java_object_factory.h" +#include "java_opaque_method_stubs.h" +#include "java_types.h" + +#include +#include +#include +#include + +class patternt +{ +public: + explicit patternt(const char *_p):p(_p) + { + } + + // match with '?' + bool operator==(const irep_idt &what) const + { + for(std::size_t i=0; i or +bool java_bytecode_convert_methodt::is_constructor( + const class_typet::methodt &method) +{ + const std::string &name(id2string(method.get_name())); + const std::string::size_type &npos(std::string::npos); + return npos!=name.find("") || npos!=name.find(""); +} + +exprt::operandst java_bytecode_convert_methodt::pop(std::size_t n) +{ + if(stack.size()") + { + method_symbol.pretty_name= + id2string(class_symbol.pretty_name)+"."+ + id2string(class_symbol.base_name)+"()"; + member_type.set(ID_constructor, true); + } + else + method_symbol.pretty_name= + id2string(class_symbol.pretty_name)+"."+ + id2string(m.base_name)+"()"; + + // do we need to add 'this' as a parameter? + if(!m.is_static) + { + code_typet &code_type=to_code_type(member_type); + code_typet::parameterst ¶meters=code_type.parameters(); + code_typet::parametert this_p; + const reference_typet object_ref_type(symbol_typet(class_symbol.name)); + this_p.type()=object_ref_type; + this_p.set_this(); + parameters.insert(parameters.begin(), this_p); + } + + method_symbol.type=member_type; + symbol_table.add(method_symbol); +} + +/*******************************************************************\ + +Function: java_bytecode_convert_methodt::convert + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void java_bytecode_convert_methodt::convert( + const symbolt &class_symbol, + const methodt &m) +{ + const irep_idt method_identifier= + id2string(class_symbol.name)+"."+id2string(m.name)+":"+m.signature; + method_id=method_identifier; + + const auto &old_sym=symbol_table.lookup(method_identifier); + + typet member_type=old_sym.type; + code_typet &code_type=to_code_type(member_type); + method_return_type=code_type.return_type(); + code_typet::parameterst ¶meters=code_type.parameters(); + + variables.clear(); + + // find parameter names in the local variable table: + for(const auto &v : m.local_variable_table) + { + if(v.start_pc!=0) // Local? + continue; + + typet t=java_type_from_string(v.signature); + std::ostringstream id_oss; + id_oss << method_id << "::" << v.name; + irep_idt identifier(id_oss.str()); + symbol_exprt result(identifier, t); + result.set(ID_C_base_name, v.name); + + variables[v.index].push_back(variablet()); + auto &newv=variables[v.index].back(); + newv.symbol_expr=result; + newv.start_pc=v.start_pc; + newv.length=v.length; + } + + // set up variables array + std::size_t param_index=0; + for(const auto ¶m : parameters) + { + variables[param_index].resize(1); + param_index+=get_variable_slots(param); + } + + // assign names to parameters + param_index=0; + for(auto ¶m : parameters) + { + irep_idt base_name, identifier; + + if(param_index==0 && param.get_this()) + { + base_name="this"; + identifier=id2string(method_identifier)+"::"+id2string(base_name); + param.set_base_name(base_name); + param.set_identifier(identifier); + } + else + { + // in the variable table? + base_name=variables[param_index][0].symbol_expr.get(ID_C_base_name); + identifier=variables[param_index][0].symbol_expr.get(ID_identifier); + + if(base_name.empty()) + { + const typet &type=param.type(); + char suffix=java_char_from_type(type); + base_name="arg"+std::to_string(param_index)+suffix; + identifier=id2string(method_identifier)+"::"+id2string(base_name); + } + + param.set_base_name(base_name); + param.set_identifier(identifier); + } + + // add to symbol table + parameter_symbolt parameter_symbol; + parameter_symbol.base_name=base_name; + parameter_symbol.mode=ID_java; + parameter_symbol.name=identifier; + parameter_symbol.type=param.type(); + symbol_table.add(parameter_symbol); + + // add as a JVM variable + std::size_t slots=get_variable_slots(param); + variables[param_index][0].symbol_expr=parameter_symbol.symbol_expr(); + variables[param_index][0].is_parameter=true; + variables[param_index][0].start_pc=0; + variables[param_index][0].length=std::numeric_limits::max(); + variables[param_index][0].is_parameter=true; + param_index+=slots; + assert(param_index>0); + } + + const bool is_virtual=!m.is_static && !m.is_final; + + #if 0 + class_type.methods().push_back(class_typet::methodt()); + class_typet::methodt &method=class_type.methods().back(); + #else + class_typet::methodt method; + #endif + + method.set_base_name(m.base_name); + method.set_name(method_identifier); + + method.set(ID_abstract, m.is_abstract); + method.set(ID_is_virtual, is_virtual); + + if(is_constructor(method)) + method.set(ID_constructor, true); + + method.type()=member_type; + + // we add the symbol for the method + + symbolt method_symbol; + + method_symbol.name=method.get_name(); + method_symbol.base_name=method.get_base_name(); + method_symbol.mode=ID_java; + method_symbol.location=m.source_location; + method_symbol.location.set_function(method_identifier); + + if(method.get_base_name()=="") + method_symbol.pretty_name=id2string(class_symbol.pretty_name)+"."+ + id2string(class_symbol.base_name)+"()"; + else + method_symbol.pretty_name=id2string(class_symbol.pretty_name)+"."+ + id2string(method.get_base_name())+"()"; + + method_symbol.type=member_type; + if(is_constructor(method)) + method_symbol.type.set(ID_constructor, true); + current_method=method_symbol.name; + method_has_this=code_type.has_this(); + + tmp_vars.clear(); + if((!m.is_abstract) && (!m.is_native)) + method_symbol.value=convert_instructions(m, code_type); + + // Replace the existing stub symbol with the real deal: + const auto s_it=symbol_table.symbols.find(method.get_name()); + assert(s_it!=symbol_table.symbols.end()); + symbol_table.symbols.erase(s_it); + + symbol_table.add(method_symbol); +} + +/*******************************************************************\ + +Function: java_bytecode_convert_methodt::get_bytecode_info + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +const bytecode_infot &java_bytecode_convert_methodt::get_bytecode_info( + const irep_idt &statement) +{ + for(const bytecode_infot *p=bytecode_info; p->mnemonic!=0; p++) + if(statement==p->mnemonic) + return *p; + + error() << "failed to find bytecode mnemonic `" + << statement << '\'' << eom; + throw 0; +} + +static irep_idt get_if_cmp_operator(const irep_idt &stmt) +{ + if(stmt==patternt("if_?cmplt")) + return ID_lt; + if(stmt==patternt("if_?cmple")) + return ID_le; + if(stmt==patternt("if_?cmpgt")) + return ID_gt; + if(stmt==patternt("if_?cmpge")) + return ID_ge; + if(stmt==patternt("if_?cmpeq")) + return ID_equal; + if(stmt==patternt("if_?cmpne")) + return ID_notequal; + + throw "unhandled java comparison instruction"; +} + +static member_exprt to_member(const exprt &pointer, const exprt &fieldref) +{ + symbol_typet class_type(fieldref.get(ID_class)); + + exprt pointer2= + typecast_exprt(pointer, pointer_typet(class_type)); + + const dereference_exprt obj_deref(pointer2, class_type); + + return member_exprt( + obj_deref, + fieldref.get(ID_component_name), + fieldref.type()); +} + +codet java_bytecode_convert_methodt::get_array_bounds_check( + const exprt &arraystruct, + const exprt &idx, + const source_locationt &original_sloc) +{ + constant_exprt intzero=from_integer(0, java_int_type()); + binary_relation_exprt gezero(idx, ID_ge, intzero); + const member_exprt length_field(arraystruct, "length", java_int_type()); + binary_relation_exprt ltlength(idx, ID_lt, length_field); + code_blockt bounds_checks; + + bounds_checks.add(code_assertt(gezero)); + bounds_checks.operands().back().add_source_location()=original_sloc; + bounds_checks.operands().back().add_source_location() + .set_comment("Array index < 0"); + bounds_checks.operands().back().add_source_location() + .set_property_class("array-index-out-of-bounds-low"); + bounds_checks.add(code_assertt(ltlength)); + + bounds_checks.operands().back().add_source_location()=original_sloc; + bounds_checks.operands().back().add_source_location() + .set_comment("Array index >= length"); + bounds_checks.operands().back().add_source_location() + .set_property_class("array-index-out-of-bounds-high"); + + // TODO make this throw ArrayIndexOutOfBoundsException instead of asserting. + return bounds_checks; +} + +/*******************************************************************\ + +Function: replace_goto_target + + Inputs: 'repl', a block of code in which to perform replacement, and + an old_label that should be replaced throughout by new_label. + + Outputs: None (side-effects on repl) + + Purpose: Find all goto statements in 'repl' that target 'old_label' + and redirect them to 'new_label'. + +\*******************************************************************/ + +void java_bytecode_convert_methodt::replace_goto_target( + codet &repl, + const irep_idt &old_label, + const irep_idt &new_label) +{ + const auto &stmt=repl.get_statement(); + if(stmt==ID_goto) + { + auto &g=to_code_goto(repl); + if(g.get_destination()==old_label) + g.set_destination(new_label); + } + else + { + for(auto &op : repl.operands()) + if(op.id()==ID_code) + replace_goto_target(to_code(op), old_label, new_label); + } +} + +/*******************************************************************\ + +Function: java_bytecode_convert_methodt::get_block_for_pcrange + + Inputs: 'tree', a code block descriptor, and 'this_block', the corresponding + actual code_blockt. 'address_start' and 'address_limit', the Java + bytecode offsets searched for. 'next_block_start_address', the + bytecode offset of tree/this_block's successor sibling, or UINT_MAX + if none exists. + + Outputs: Returns the code_blockt most closely enclosing the given address range. + + Purpose: 'tree' describes a tree of code_blockt objects; this_block is the + corresponding block (thus they are both trees with the same shape). + The caller is looking for the single block in the tree that most + closely encloses bytecode address range [address_start,address_limit). + 'next_block_start_address' is the start address of 'tree's successor + sibling and is used to determine when the range spans out of its bounds. + +\*******************************************************************/ + +code_blockt &java_bytecode_convert_methodt::get_block_for_pcrange( + block_tree_nodet &tree, + code_blockt &this_block, + unsigned address_start, + unsigned address_limit, + unsigned next_block_start_address) +{ + address_mapt dummy; + return get_or_create_block_for_pcrange( + tree, + this_block, + address_start, + address_limit, + next_block_start_address, + dummy, + false); +} + +/*******************************************************************\ + +Function: java_bytecode_convert_methodt::get_or_create_block_for_pcrange + + Inputs: See above, plus the bytecode address map 'amap' and 'allow_merge' + which is always true except when called from get_block_for_pcrange + + Outputs: See above, plus potential side-effects on 'tree' and 'this_block' + as descibed in 'Purpose' + + Purpose: As above, but this version can additionally create a new branch + in the block_tree-node and code_blockt trees to envelop the requested + address range. For example, if the tree was initially flat, with + nodes (1-10), (11-20), (21-30) and the caller asked for range 13-28, + this would build a surrounding tree node, leaving the tree of shape + (1-10), ^( (11-20), (21-30) )^, and return a reference to the + new branch highlighted with ^^. + 'tree' and 'this_block' trees are always maintained with equal + shapes. ('this_block' may additionally contain code_declt children + which are ignored for this purpose) + +\*******************************************************************/ + +code_blockt &java_bytecode_convert_methodt::get_or_create_block_for_pcrange( + block_tree_nodet &tree, + code_blockt &this_block, + unsigned address_start, + unsigned address_limit, + unsigned next_block_start_address, + const address_mapt &amap, + bool allow_merge) +{ + // Check the tree shape invariant: + assert(tree.branch.size()==tree.branch_addresses.size()); + + // If there are no child blocks, return this. + if(tree.leaf) + return this_block; + assert(!tree.branch.empty()); + + // Find child block starting > address_start: + const auto afterstart= + std::upper_bound( + tree.branch_addresses.begin(), + tree.branch_addresses.end(), + address_start); + assert(afterstart!=tree.branch_addresses.begin()); + auto findstart=afterstart; + --findstart; + auto child_offset= + std::distance(tree.branch_addresses.begin(), findstart); + + // Find child block starting >= address_limit: + auto findlim= + std::lower_bound( + tree.branch_addresses.begin(), + tree.branch_addresses.end(), + address_limit); + unsigned findlim_block_start_address= + findlim==tree.branch_addresses.end() ? + next_block_start_address : + (*findlim); + + // If all children are in scope, return this. + if(findstart==tree.branch_addresses.begin() && + findlim==tree.branch_addresses.end()) + return this_block; + + // Find the child code_blockt where the queried range begins: + auto child_iter=this_block.operands().begin(); + // Skip any top-of-block declarations; + // all other children are labelled subblocks. + while(child_iter!=this_block.operands().end() && + to_code(*child_iter).get_statement()==ID_decl) + ++child_iter; + assert(child_iter!=this_block.operands().end()); + std::advance(child_iter, child_offset); + assert(child_iter!=this_block.operands().end()); + auto &child_label=to_code_label(to_code(*child_iter)); + auto &child_block=to_code_block(child_label.code()); + + bool single_child(afterstart==findlim); + if(single_child) + { + // Range wholly contained within a child block + return get_or_create_block_for_pcrange( + tree.branch[child_offset], + child_block, + address_start, + address_limit, + findlim_block_start_address, + amap, + allow_merge); + } + + // Otherwise we're being asked for a range of subblocks, but not all of them. + // If it's legal to draw a new lexical scope around the requested subset, + // do so; otherwise just return this block. + + // This can be a new lexical scope if all incoming edges target the + // new block header, or come from within the suggested new block. + + // If modifying the block tree is forbidden, give up and return this: + if(!allow_merge) + return this_block; + + // Check for incoming control-flow edges targeting non-header + // blocks of the new proposed block range: + auto checkit=amap.find(*findstart); + assert(checkit!=amap.end()); + ++checkit; // Skip the header, which can have incoming edges from outside. + for(; + checkit!=amap.end() && (checkit->first)<(findlim_block_start_address); + ++checkit) + { + for(auto p : checkit->second.predecessors) + { + if(p<(*findstart) || p>=findlim_block_start_address) + { + debug() << "Warning: refusing to create lexical block spanning " + << (*findstart) << "-" << findlim_block_start_address + << " due to incoming edge " << p << " -> " + << checkit->first << eom; + return this_block; + } + } + } + + // All incoming edges are acceptable! Create a new block wrapping + // the relevant children. Borrow the header block's label, and redirect + // any block-internal edges to target the inner header block. + + const irep_idt child_label_name=child_label.get_label(); + std::string new_label_str=as_string(child_label_name); + new_label_str+='$'; + irep_idt new_label_irep(new_label_str); + + code_labelt newlabel(child_label_name, code_blockt()); + code_blockt &newblock=to_code_block(newlabel.code()); + auto nblocks=std::distance(findstart, findlim); + assert(nblocks>=2); + debug() << "Combining " << std::distance(findstart, findlim) + << " blocks for addresses " << (*findstart) << "-" + << findlim_block_start_address << eom; + + // Make a new block containing every child of interest: + auto &this_block_children=this_block.operands(); + assert(tree.branch.size()==this_block_children.size()); + for(auto blockidx=child_offset, blocklim=child_offset+nblocks; + blockidx!=blocklim; + ++blockidx) + newblock.move_to_operands(this_block_children[blockidx]); + + // Relabel the inner header: + to_code_label(to_code(newblock.operands()[0])).set_label(new_label_irep); + // Relabel internal gotos: + replace_goto_target(newblock, child_label_name, new_label_irep); + + // Remove the now-empty sibling blocks: + auto delfirst=this_block_children.begin(); + std::advance(delfirst, child_offset+1); + auto dellim=delfirst; + std::advance(dellim, nblocks-1); + this_block_children.erase(delfirst, dellim); + this_block_children[child_offset].swap(newlabel); + + // Perform the same transformation on the index tree: + block_tree_nodet newnode; + auto branchstart=tree.branch.begin(); + std::advance(branchstart, child_offset); + auto branchlim=branchstart; + std::advance(branchlim, nblocks); + for(auto branchiter=branchstart; branchiter!=branchlim; ++branchiter) + newnode.branch.push_back(std::move(*branchiter)); + ++branchstart; + tree.branch.erase(branchstart, branchlim); + + assert(tree.branch.size()==this_block_children.size()); + + auto branchaddriter=tree.branch_addresses.begin(); + std::advance(branchaddriter, child_offset); + auto branchaddrlim=branchaddriter; + std::advance(branchaddrlim, nblocks); + newnode.branch_addresses.insert( + newnode.branch_addresses.begin(), + branchaddriter, + branchaddrlim); + + ++branchaddriter; + tree.branch_addresses.erase(branchaddriter, branchaddrlim); + + tree.branch[child_offset]=std::move(newnode); + + assert(tree.branch.size()==tree.branch_addresses.size()); + + return + to_code_block( + to_code_label( + to_code(this_block_children[child_offset])).code()); +} + +static void gather_symbol_live_ranges( + unsigned pc, + const exprt &e, + std::map &result) +{ + if(e.id()==ID_symbol) + { + const auto &symexpr=to_symbol_expr(e); + auto findit= + result.insert({ // NOLINT(whitespace/braces) + symexpr.get_identifier(), + java_bytecode_convert_methodt::variablet()}); + auto &var=findit.first->second; + if(findit.second) + { + var.symbol_expr=symexpr; + var.start_pc=pc; + var.length=1; + } + else + { + if(pc targets; + + std::vector jsr_ret_targets; + std::vector ret_instructions; + + for(instructionst::const_iterator + i_it=instructions.begin(); + i_it!=instructions.end(); + i_it++) + { + converted_instructiont ins=converted_instructiont(i_it, code_skipt()); + std::pair a_entry= + address_map.insert(std::make_pair(i_it->address, ins)); + assert(a_entry.second); + // addresses are strictly increasing, hence we must have inserted + // a new maximal key + assert(a_entry.first==--address_map.end()); + + if(i_it->statement!="goto" && + i_it->statement!="return" && + !(i_it->statement==patternt("?return")) && + i_it->statement!="athrow" && + i_it->statement!="jsr" && + i_it->statement!="jsr_w" && + i_it->statement!="ret") + { + instructionst::const_iterator next=i_it; + if(++next!=instructions.end()) + a_entry.first->second.successors.push_back(next->address); + } + + if(i_it->statement=="goto" || + i_it->statement==patternt("if_?cmp??") || + i_it->statement==patternt("if??") || + i_it->statement=="ifnonnull" || + i_it->statement=="ifnull" || + i_it->statement=="jsr" || + i_it->statement=="jsr_w") + { + assert(!i_it->args.empty()); + + const unsigned target=safe_string2unsigned( + id2string(to_constant_expr(i_it->args[0]).get_value())); + targets.insert(target); + + a_entry.first->second.successors.push_back(target); + + if(i_it->statement=="jsr" || + i_it->statement=="jsr_w") + { + instructionst::const_iterator next=i_it+1; + assert( + next!=instructions.end() && + "jsr without valid return address?"); + targets.insert(next->address); + jsr_ret_targets.push_back(next->address); + } + } + else if(i_it->statement=="tableswitch" || + i_it->statement=="lookupswitch") + { + bool is_label=true; + for(const auto &arg : i_it->args) + { + if(is_label) + { + const unsigned target=safe_string2unsigned( + id2string(to_constant_expr(arg).get_value())); + targets.insert(target); + a_entry.first->second.successors.push_back(target); + } + is_label=!is_label; + } + } + else if(i_it->statement=="ret") + { + // Finish these later, once we've seen all jsr instructions. + ret_instructions.push_back(i_it); + } + } + + // Draw edges from every `ret` to every `jsr` successor. Could do better with + // flow analysis to distinguish multiple subroutines within the same function. + for(const auto retinst : ret_instructions) + { + auto &a_entry=address_map.at(retinst->address); + a_entry.successors.insert( + a_entry.successors.end(), + jsr_ret_targets.begin(), + jsr_ret_targets.end()); + } + + for(const auto &address : address_map) + { + for(unsigned s : address.second.successors) + { + address_mapt::iterator a_it=address_map.find(s); + assert(a_it!=address_map.end()); + + a_it->second.predecessors.insert(address.first); + } + } + + // Now that the control flow graph is built, set up our local variables + // (these require the graph to determine live ranges) + setup_local_variables(method, address_map); + + std::set working_set; + bool assertion_failure=false; + + if(!instructions.empty()) + working_set.insert(instructions.front().address); + + while(!working_set.empty()) + { + std::set::iterator cur = working_set.begin(); + address_mapt::iterator a_it = address_map.find(*cur); + assert(a_it != address_map.end()); + working_set.erase(cur); + + if (a_it->second.done) + { + continue; + } + + working_set.insert(a_it->second.successors.begin(), + a_it->second.successors.end()); + + instructionst::const_iterator i_it=a_it->second.source; + stack.swap(a_it->second.stack); + a_it->second.stack.clear(); + codet &c=a_it->second.code; + + assert( + stack.empty() || + a_it->second.predecessors.size()<=1 || + has_prefix( + stack.front().get_string(ID_C_base_name), + "$stack")); + + irep_idt statement=i_it->statement; + exprt arg0 = i_it->args.size() >= 1 ? i_it->args[0] : nil_exprt(); + exprt arg1 = i_it->args.size() >= 2 ? i_it->args[1] : nil_exprt(); + + const bytecode_infot &bytecode_info=get_bytecode_info(statement); + + // deal with _idx suffixes + if(statement.size()>=2 && + statement[statement.size()-2]=='_' && + isdigit(statement[statement.size()-1])) + { + arg0=constant_exprt( + std::string(id2string(statement), statement.size()-1, 1), + integer_typet()); + statement=std::string(id2string(statement), 0, statement.size()-2); + } + + exprt::operandst op=pop(bytecode_info.pop); + exprt::operandst results; + results.resize(bytecode_info.push, nil_exprt()); + + if(statement=="aconst_null") + { + assert(results.size()==1); + results[0]=null_pointer_exprt(java_reference_type(void_typet())); + } + else if(statement=="athrow") + { + assert(op.size()==1 && results.size()==1); + if(!assertion_failure) + { + side_effect_expr_throwt throw_expr; + throw_expr.add_source_location()=i_it->source_location; + throw_expr.copy_to_operands(op[0]); + c=code_expressiont(throw_expr); + results[0]=op[0]; + } + else + { + // TODO: this can be removed once we properly handle throw + // if this athrow is generated by an assertion, then skip it + c=code_skipt(); + assertion_failure=false; + } + } + else if(statement=="checkcast") + { + if(!disable_runtime_checks) + { + // checkcast throws an exception in case a cast of object + // on stack to given type fails. + // The stack isn't modified. + // TODO: convert assertions to exceptions. + assert(op.size()==1 && results.size()==1); + binary_predicate_exprt check(op[0], ID_java_instanceof, arg0); + c=code_assertt(check); + c.add_source_location().set_comment("Dynamic cast check"); + c.add_source_location().set_property_class("bad-dynamic-cast"); + results[0]=op[0]; + } + else + c=code_skipt(); + } + else if(statement=="invokedynamic") + { + // not used in Java + code_typet &code_type=to_code_type(arg0.type()); + const code_typet::parameterst ¶meters(code_type.parameters()); + + pop(parameters.size()); + + const typet &return_type=code_type.return_type(); + + if(return_type.id()!=ID_empty) + { + results.resize(1); + results[0]= + zero_initializer( + return_type, + i_it->source_location, + namespacet(symbol_table), + get_message_handler()); + } + } + + // replace calls to CProver.assume + else if (statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.assume:(Z)V")) + { + const code_typet &code_type = to_code_type(arg0.type()); + // sanity check: function has the right number of args + assert(code_type.parameters().size() == 1); + + exprt operand = pop(1)[0]; + // we may need to adjust the type of the argument + if (operand.type() != bool_typet()) + operand.make_typecast(bool_typet()); + + c = code_assumet(operand); + source_locationt loc = i_it->source_location; + loc.set_function(method_id); + c.add_source_location() = loc; + } + + // if the statement is a nondet boolean + else if (statement_is_static_with_name( + statement, arg0, + "java::org.cprover.CProver.nondetBoolean:()Z")) + { + results.resize(1); + results[0] = side_effect_expr_nondett(java_boolean_type()); + results[0].add_source_location() = i_it->source_location; + } + + // if the statement is a nondet byte + else if (statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetByte:()B")) + { + results.resize(1); + results[0] = side_effect_expr_nondett(java_byte_type()); + results[0].add_source_location() = i_it->source_location; + } + + // if the statement is a nondet char + else if (statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetChar:()C")) + { + results.resize(1); + results[0] = side_effect_expr_nondett(java_char_type()); + results[0].add_source_location() = i_it->source_location; + } + + // if the statement is a nondet short + else if (statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetShort:()S")) + { + results.resize(1); + results[0] = side_effect_expr_nondett(java_short_type()); + results[0].add_source_location() = i_it->source_location; + } + + // if the statement is a nondet int + else if (statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetInt:()I")) + { + results.resize(1); + results[0] = side_effect_expr_nondett(java_int_type()); + results[0].add_source_location() = i_it->source_location; + } + + // if the statement is a nondet long + else if (statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetLong:()J")) + { + results.resize(1); + results[0] = side_effect_expr_nondett(java_long_type()); + results[0].add_source_location() = i_it->source_location; + } + + // if the statement is a nondet float + else if (statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetFloat:()F")) + { + results.resize(1); + results[0] = side_effect_expr_nondett(java_float_type()); + results[0].add_source_location() = i_it->source_location; + } + + // if the statement is a nondet double + else if (statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetDouble:()D")) + { + results.resize(1); + results[0] = side_effect_expr_nondett(java_double_type()); + results[0].add_source_location() = i_it->source_location; + } + + // To catch the return type of the nondet call, we have to check the + // next statement for an assignment. + // Check that the statement is static, with the correct signature, and + // that the working set still has remaining items. + else if (!working_set.empty() && statement == "invokestatic" && + has_prefix(id2string(arg0.get(ID_identifier)), + "java::org.cprover.CProver.nondet:()L")) + { + // For the type search to succeed, the next instruction must be a + // checkcast. + // Find the next item in the working set, and look up that item in the + // address map. + address_mapt::iterator next_it = address_map.find(*working_set.begin()); + assert(next_it != address_map.end()); + + instructionst::const_iterator next_source_it = next_it->second.source; + + // Check that the statement is a checkcast with an argument of the + // correct type. + assert(next_source_it->statement == "checkcast"); + assert(next_source_it->args.size() >= 1); + assert(next_source_it->args[0].type().id() == ID_symbol); + const auto java_object_type = next_source_it->args[0].type(); + + // Create somewhere to store the result, and set the source location. + results.resize(1); + results[0].add_source_location() = i_it->source_location; + // Set the result to a nondet of the correct type. + results[0] = + side_effect_expr_nondett(java_reference_type(java_object_type)); + } + + else if(statement=="invokeinterface" || + statement=="invokespecial" || + statement=="invokevirtual" || + statement=="invokestatic") + { + // Remember that this is triggered by an assertion + if(statement=="invokespecial" && + id2string(arg0.get(ID_identifier)) + .find("AssertionError")!=std::string::npos) + { + assertion_failure=true; + } + const bool use_this(statement!="invokestatic"); + const bool is_virtual( + statement=="invokevirtual" || statement=="invokeinterface"); + + code_typet &code_type=to_code_type(arg0.type()); + code_typet::parameterst ¶meters(code_type.parameters()); + + if(use_this) + { + if(parameters.empty() || !parameters[0].get_this()) + { + irep_idt classname=arg0.get(ID_C_class); + typet thistype=symbol_typet(classname); + // Note invokespecial is used for super-method calls as well as + // constructors. + if(statement=="invokespecial") + { + if(as_string(arg0.get(ID_identifier)) + .find("")!=std::string::npos) + { + if(needed_classes) + needed_classes->insert(classname); + code_type.set(ID_constructor, true); + } + else + code_type.set(ID_java_super_method_call, true); + } + pointer_typet object_ref_type(thistype); + code_typet::parametert this_p(object_ref_type); + this_p.set_this(); + this_p.set_base_name("this"); + parameters.insert(parameters.begin(), this_p); + } + } + + code_function_callt call; + source_locationt loc=i_it->source_location; + loc.set_function(method_id); + + call.add_source_location()=loc; + call.arguments()=pop(parameters.size()); + + // double-check a bit + if(use_this) + { + const exprt &this_arg=call.arguments().front(); + assert(this_arg.type().id()==ID_pointer); + } + + // do some type adjustment for the arguments, + // as Java promotes arguments + // Also cast pointers since intermediate locals + // can be void*. + + for(std::size_t i=0; ipush_back(arg0.get(ID_identifier)); + } + + call.function().add_source_location()=loc; + c=call; + } + else if(statement=="return") + { + assert(op.empty() && results.empty()); + c=code_returnt(); + } + else if(statement==patternt("?return")) + { + // Return types are promoted in java, so this might need + // conversion. + assert(op.size()==1 && results.empty()); + exprt r=op[0]; + if(r.type()!=method_return_type) + r=typecast_exprt(r, method_return_type); + c=code_returnt(r); + } + else if(statement==patternt("?astore")) + { + assert(op.size()==3 && results.empty()); + + char type_char=statement[0]; + + exprt pointer= + typecast_exprt(op[0], java_array_type(type_char)); + + const dereference_exprt deref(pointer, pointer.type().subtype()); + + const member_exprt data_ptr( + deref, + "data", + pointer_typet(java_type_from_char(type_char))); + + plus_exprt data_plus_offset(data_ptr, op[1], data_ptr.type()); + typet element_type=data_ptr.type().subtype(); + const dereference_exprt element(data_plus_offset, element_type); + + c=code_blockt(); + if(!disable_runtime_checks) + { + codet bounds_check= + get_array_bounds_check(deref, op[1], i_it->source_location); + bounds_check.add_source_location()=i_it->source_location; + c.move_to_operands(bounds_check); + } + code_assignt array_put(element, op[2]); + array_put.add_source_location()=i_it->source_location; + c.move_to_operands(array_put); + c.add_source_location()=i_it->source_location; + } + else if(statement==patternt("?store")) + { + // store value into some local variable + assert(op.size()==1 && results.empty()); + + exprt var= + variable(arg0, statement[0], i_it->address, NO_CAST); + + exprt toassign=op[0]; + if('a'==statement[0] && toassign.type()!=var.type()) + toassign=typecast_exprt(toassign, var.type()); + + c=code_assignt(var, toassign); + } + else if(statement==patternt("?aload")) + { + assert(op.size()==2 && results.size()==1); + + char type_char=statement[0]; + + exprt pointer= + typecast_exprt(op[0], java_array_type(type_char)); + + const dereference_exprt deref(pointer, pointer.type().subtype()); + + const member_exprt data_ptr( + deref, + "data", + pointer_typet(java_type_from_char(type_char))); + + plus_exprt data_plus_offset(data_ptr, op[1], data_ptr.type()); + typet element_type=data_ptr.type().subtype(); + dereference_exprt element(data_plus_offset, element_type); + + if(!disable_runtime_checks) + { + c=get_array_bounds_check(deref, op[1], i_it->source_location); + c.add_source_location()=i_it->source_location; + } + results[0]=java_bytecode_promotion(element); + } + else if(statement==patternt("?load")) + { + // load a value from a local variable + results[0]= + variable(arg0, statement[0], i_it->address, CAST_AS_NEEDED); + } + else if(statement=="ldc" || statement=="ldc_w" || + statement=="ldc2" || statement=="ldc2_w") + { + assert(op.empty() && results.size()==1); + + // 1) Pushing a String causes a reference to a java.lang.String object + // to be constructed and pushed onto the operand stack. + + // 2) Pushing an int or a float causes a primitive value to be pushed + // onto the stack. + + // 3) Pushing a Class constant causes a reference to a java.lang.Class + // to be pushed onto the operand stack + + if(arg0.id()==ID_java_string_literal) + { + // these need to be references to java.lang.String + results[0]=arg0; + symbol_typet string_type("java::java.lang.String"); + results[0].type()=pointer_typet(string_type); + } + else if(arg0.id()==ID_type) + { + irep_idt class_id=arg0.type().get(ID_identifier); + symbol_typet java_lang_Class("java::java.lang.Class"); + symbol_exprt symbol_expr( + id2string(class_id)+"@class_model", + java_lang_Class); + address_of_exprt address_of_expr(symbol_expr); + results[0]=address_of_expr; + } + else if(arg0.id()==ID_constant) + { + results[0]=arg0; + } + else + { + error() << "unexpected ldc argument" << eom; + throw 0; + } + } + else if(statement=="goto" || statement=="goto_w") + { + assert(op.empty() && results.empty()); + irep_idt number=to_constant_expr(arg0).get_value(); + code_gotot code_goto(label(number)); + c=code_goto; + } + else if(statement=="jsr" || statement=="jsr_w") + { + // As 'goto', except we must also push the subroutine return address: + assert(op.empty() && results.size()==1); + irep_idt number=to_constant_expr(arg0).get_value(); + code_gotot code_goto(label(number)); + c=code_goto; + results[0]= + from_integer( + std::next(i_it)->address, + unsignedbv_typet(64)); + results[0].type()=pointer_typet(void_typet(), 64); + } + else if(statement=="ret") + { + // Since we have a bounded target set, make life easier on our analyses + // and write something like: + // if(retaddr==5) goto 5; else if(retaddr==10) goto 10; ... + assert(op.empty() && results.empty()); + c=code_blockt(); + auto retvar=variable(arg0, 'a', i_it->address, NO_CAST); + assert(!jsr_ret_targets.empty()); + for(size_t idx=0, idxlim=jsr_ret_targets.size(); idx!=idxlim; ++idx) + { + irep_idt number=std::to_string(jsr_ret_targets[idx]); + code_gotot g(label(number)); + g.add_source_location()=i_it->source_location; + if(idx==idxlim-1) + c.move_to_operands(g); + else + { + code_ifthenelset branch; + auto address_ptr= + from_integer( + jsr_ret_targets[idx], + unsignedbv_typet(64)); + address_ptr.type()=pointer_typet(void_typet(), 64); + branch.cond()=equal_exprt(retvar, address_ptr); + branch.cond().add_source_location()=i_it->source_location; + branch.then_case()=g; + branch.add_source_location()=i_it->source_location; + c.move_to_operands(branch); + } + } + } + else if(statement=="iconst_m1") + { + assert(results.size()==1); + results[0]=from_integer(-1, java_int_type()); + } + else if(statement==patternt("?const")) + { + assert(results.size()==1); + + const char type_char=statement[0]; + const bool is_double('d'==type_char); + const bool is_float('f'==type_char); + + if(is_double || is_float) + { + const ieee_float_spect spec( + is_float?ieee_float_spect::single_precision(): + ieee_float_spect::double_precision()); + + ieee_floatt value(spec); + const typet &arg_type(arg0.type()); + if(ID_integer==arg_type.id()) + value.from_integer(arg0.get_int(ID_value)); + else + value.from_expr(to_constant_expr(arg0)); + + results[0]=value.to_expr(); + } + else + { + const unsigned value(arg0.get_unsigned_int(ID_value)); + const typet type=java_type_from_char(statement[0]); + results[0]=from_integer(value, type); + } + } + else if(statement==patternt("?ipush")) + { + assert(results.size()==1); + results[0]=typecast_exprt(arg0, java_int_type()); + } + else if(statement==patternt("if_?cmp??")) + { + irep_idt number=to_constant_expr(arg0).get_value(); + assert(op.size()==2 && results.empty()); + + code_ifthenelset code_branch; + const irep_idt cmp_op=get_if_cmp_operator(statement); + + binary_relation_exprt condition(op[0], cmp_op, op[1]); + + exprt &lhs(condition.lhs()); + exprt &rhs(condition.rhs()); + const typet &lhs_type(lhs.type()); + if(lhs_type!=rhs.type()) + rhs=typecast_exprt(rhs, lhs_type); + + code_branch.cond()=condition; + code_branch.cond().add_source_location()=i_it->source_location; + code_branch.then_case()=code_gotot(label(number)); + code_branch.then_case().add_source_location()=i_it->source_location; + code_branch.add_source_location()=i_it->source_location; + + c=code_branch; + } + else if(statement==patternt("if??")) + { + const irep_idt id= + statement=="ifeq"?ID_equal: + statement=="ifne"?ID_notequal: + statement=="iflt"?ID_lt: + statement=="ifge"?ID_ge: + statement=="ifgt"?ID_gt: + statement=="ifle"?ID_le: + (assert(false), ""); + + irep_idt number=to_constant_expr(arg0).get_value(); + assert(op.size()==1 && results.empty()); + + code_ifthenelset code_branch; + code_branch.cond()= + binary_relation_exprt(op[0], id, from_integer(0, op[0].type())); + code_branch.cond().add_source_location()=i_it->source_location; + code_branch.cond().add_source_location().set_function(method_id); + code_branch.then_case()=code_gotot(label(number)); + code_branch.then_case().add_source_location()=i_it->source_location; + code_branch.then_case().add_source_location().set_function(method_id); + code_branch.add_source_location()=i_it->source_location; + code_branch.add_source_location().set_function(method_id); + + c=code_branch; + } + else if(statement==patternt("ifnonnull")) + { + irep_idt number=to_constant_expr(arg0).get_value(); + assert(op.size()==1 && results.empty()); + code_ifthenelset code_branch; + const typecast_exprt lhs(op[0], pointer_typet(empty_typet())); + const exprt rhs(null_pointer_exprt(to_pointer_type(lhs.type()))); + code_branch.cond()=binary_relation_exprt(lhs, ID_notequal, rhs); + code_branch.then_case()=code_gotot(label(number)); + code_branch.then_case().add_source_location()=i_it->source_location; + code_branch.add_source_location()=i_it->source_location; + + c=code_branch; + } + else if(statement==patternt("ifnull")) + { + assert(op.size()==1 && results.empty()); + irep_idt number=to_constant_expr(arg0).get_value(); + code_ifthenelset code_branch; + const typecast_exprt lhs(op[0], pointer_typet(empty_typet())); + const exprt rhs(null_pointer_exprt(to_pointer_type(lhs.type()))); + code_branch.cond()=binary_relation_exprt(lhs, ID_equal, rhs); + code_branch.then_case()=code_gotot(label(number)); + code_branch.then_case().add_source_location()=i_it->source_location; + code_branch.add_source_location()=i_it->source_location; + + c=code_branch; + } + else if(statement=="iinc") + { + code_assignt code_assign; + code_assign.lhs()= + variable(arg0, 'i', i_it->address, NO_CAST); + code_assign.rhs()=plus_exprt( + variable(arg0, 'i', i_it->address, CAST_AS_NEEDED), + typecast_exprt(arg1, java_int_type())); + c=code_assign; + } + else if(statement==patternt("?xor")) + { + assert(op.size()==2 && results.size()==1); + results[0]=bitxor_exprt(op[0], op[1]); + } + else if(statement==patternt("?or")) + { + assert(op.size()==2 && results.size()==1); + results[0]=bitor_exprt(op[0], op[1]); + } + else if(statement==patternt("?and")) + { + assert(op.size()==2 && results.size()==1); + results[0]=bitand_exprt(op[0], op[1]); + } + else if(statement==patternt("?shl")) + { + assert(op.size()==2 && results.size()==1); + results[0]=shl_exprt(op[0], op[1]); + } + else if(statement==patternt("?shr")) + { + assert(op.size()==2 && results.size()==1); + results[0]=ashr_exprt(op[0], op[1]); + } + else if(statement==patternt("?ushr")) + { + assert(op.size()==2 && results.size()==1); + const typet type=java_type_from_char(statement[0]); + + const std::size_t width=type.get_size_t(ID_width); + typet target=unsignedbv_typet(width); + + const typecast_exprt lhs(op[0], target); + const typecast_exprt rhs(op[1], target); + + results[0]=typecast_exprt(lshr_exprt(lhs, rhs), op[0].type()); + } + else if(statement==patternt("?add")) + { + assert(op.size()==2 && results.size()==1); + results[0]=plus_exprt(op[0], op[1]); + } + else if(statement==patternt("?sub")) + { + assert(op.size()==2 && results.size()==1); + results[0]=minus_exprt(op[0], op[1]); + } + else if(statement==patternt("?div")) + { + assert(op.size()==2 && results.size()==1); + results[0]=div_exprt(op[0], op[1]); + } + else if(statement==patternt("?mul")) + { + assert(op.size()==2 && results.size()==1); + results[0]=mult_exprt(op[0], op[1]); + } + else if(statement==patternt("?neg")) + { + assert(op.size()==1 && results.size()==1); + results[0]=unary_minus_exprt(op[0], op[0].type()); + } + else if(statement==patternt("?rem")) + { + assert(op.size()==2 && results.size()==1); + if(statement=="frem" || statement=="drem") + results[0]=rem_exprt(op[0], op[1]); + else + results[0]=mod_exprt(op[0], op[1]); + } + else if(statement==patternt("?cmp")) + { + assert(op.size()==2 && results.size()==1); + + // The integer result on the stack is: + // 0 if op[0] equals op[1] + // -1 if op[0] is less than op[1] + // 1 if op[0] is greater than op[1] + + const typet t=java_int_type(); + exprt one=from_integer(1, t); + exprt minus_one=from_integer(-1, t); + + if_exprt greater=if_exprt( + binary_relation_exprt(op[0], ID_gt, op[1]), + one, + minus_one); + + results[0]= + if_exprt( + binary_relation_exprt(op[0], ID_equal, op[1]), + from_integer(0, t), + greater); + } + else if(statement==patternt("?cmp?")) + { + assert(op.size()==2 && results.size()==1); + const floatbv_typet type( + to_floatbv_type(java_type_from_char(statement[0]))); + const ieee_float_spect spec(type); + const ieee_floatt nan(ieee_floatt::NaN(spec)); + const constant_exprt nan_expr(nan.to_expr()); + const int nan_value(statement[4]=='l' ? -1 : 1); + const typet result_type(java_int_type()); + const exprt nan_result(from_integer(nan_value, result_type)); + + // (value1 == NaN || value2 == NaN) ? + // nan_value : value1 < value2 ? -1 : value2 < value1 1 ? 1 : 0; + // (value1 == NaN || value2 == NaN) ? + // nan_value : value1 == value2 ? 0 : value1 < value2 -1 ? 1 : 0; + + exprt nan_op0=ieee_float_equal_exprt(nan_expr, op[0]); + exprt nan_op1=ieee_float_equal_exprt(nan_expr, op[1]); + exprt one=from_integer(1, result_type); + exprt minus_one=from_integer(-1, result_type); + results[0]= + if_exprt( + or_exprt(nan_op0, nan_op1), + nan_result, + if_exprt( + ieee_float_equal_exprt(op[0], op[1]), + from_integer(0, result_type), + if_exprt( + binary_relation_exprt(op[0], ID_lt, op[1]), + minus_one, + one))); + } + else if(statement==patternt("?cmpl")) + { + assert(op.size()==2 && results.size()==1); + results[0]=binary_relation_exprt(op[0], ID_lt, op[1]); + } + else if(statement=="dup") + { + assert(op.size()==1 && results.size()==2); + results[0]=results[1]=op[0]; + } + else if(statement=="dup_x1") + { + assert(op.size()==2 && results.size()==3); + results[0]=op[1]; + results[1]=op[0]; + results[2]=op[1]; + } + else if(statement=="dup_x2") + { + assert(op.size()==3 && results.size()==4); + results[0]=op[2]; + results[1]=op[0]; + results[2]=op[1]; + results[3]=op[2]; + } + // dup2* behaviour depends on the size of the operands on the + // stack + else if(statement=="dup2") + { + assert(!stack.empty() && results.empty()); + + if(get_bytecode_type_width(stack.back().type())==32) + op=pop(2); + else + op=pop(1); + + results.insert(results.end(), op.begin(), op.end()); + results.insert(results.end(), op.begin(), op.end()); + } + else if(statement=="dup2_x1") + { + assert(!stack.empty() && results.empty()); + + if(get_bytecode_type_width(stack.back().type())==32) + op=pop(3); + else + op=pop(2); + + results.insert(results.end(), op.begin()+1, op.end()); + results.insert(results.end(), op.begin(), op.end()); + } + else if(statement=="dup2_x2") + { + assert(!stack.empty() && results.empty()); + + if(get_bytecode_type_width(stack.back().type())==32) + op=pop(2); + else + op=pop(1); + + assert(!stack.empty()); + exprt::operandst op2; + + if(get_bytecode_type_width(stack.back().type())==32) + op2=pop(2); + else + op2=pop(1); + + results.insert(results.end(), op.begin(), op.end()); + results.insert(results.end(), op2.begin(), op2.end()); + results.insert(results.end(), op.begin(), op.end()); + } + else if(statement=="dconst") + { + assert(op.empty() && results.size()==1); + } + else if(statement=="fconst") + { + assert(op.empty() && results.size()==1); + } + else if(statement=="getfield") + { + assert(op.size()==1 && results.size()==1); + results[0]=java_bytecode_promotion(to_member(op[0], arg0)); + } + else if(statement=="getstatic") + { + assert(op.empty() && results.size()==1); + symbol_exprt symbol_expr(arg0.type()); + const auto &field_name=arg0.get_string(ID_component_name); + symbol_expr.set_identifier(arg0.get_string(ID_class)+"."+field_name); + if(needed_classes && arg0.type().id()==ID_symbol) + { + needed_classes->insert( + to_symbol_type(arg0.type()).get_identifier()); + } + results[0]=java_bytecode_promotion(symbol_expr); + + // set $assertionDisabled to false + if(field_name.find("$assertionsDisabled")!=std::string::npos) + c=code_assignt(symbol_expr, false_exprt()); + } + else if(statement=="putfield") + { + assert(op.size()==2 && results.size()==0); + c=code_assignt(to_member(op[0], arg0), op[1]); + } + else if(statement=="putstatic") + { + assert(op.size()==1 && results.empty()); + symbol_exprt symbol_expr(arg0.type()); + const auto &field_name=arg0.get_string(ID_component_name); + symbol_expr.set_identifier(arg0.get_string(ID_class)+"."+field_name); + if(needed_classes && arg0.type().id()==ID_symbol) + { + needed_classes->insert( + to_symbol_type(arg0.type()).get_identifier()); + } + c=code_assignt(symbol_expr, op[0]); + } + else if(statement==patternt("?2?")) // i2c etc. + { + assert(op.size()==1 && results.size()==1); + results[0]=typecast_exprt(op[0], java_type_from_char(statement[2])); + } + else if(statement=="new") + { + // use temporary since the stack symbol might get duplicated + assert(op.empty() && results.size()==1); + const pointer_typet ref_type(arg0.type()); + exprt java_new_expr=side_effect_exprt(ID_java_new, ref_type); + + if(!i_it->source_location.get_line().empty()) + java_new_expr.add_source_location()=i_it->source_location; + + const exprt tmp=tmp_variable("new", ref_type); + c=code_assignt(tmp, java_new_expr); + results[0]=tmp; + } + else if(statement=="newarray" || + statement=="anewarray") + { + // the op is the array size + assert(op.size()==1 && results.size()==1); + + char element_type; + + if(statement=="newarray") + { + irep_idt id=arg0.type().id(); + + if(id==ID_bool) + element_type='z'; + else if(id==ID_char) + element_type='c'; + else if(id==ID_float) + element_type='f'; + else if(id==ID_double) + element_type='d'; + else if(id==ID_byte) + element_type='b'; + else if(id==ID_short) + element_type='s'; + else if(id==ID_int) + element_type='i'; + else if(id==ID_long) + element_type='j'; + else + element_type='?'; + } + else + element_type='a'; + + const pointer_typet ref_type=java_array_type(element_type); + + side_effect_exprt java_new_array(ID_java_new_array, ref_type); + java_new_array.copy_to_operands(op[0]); + + if(!i_it->source_location.get_line().empty()) + java_new_array.add_source_location()=i_it->source_location; + + c=code_blockt(); + if(!disable_runtime_checks) + { + // TODO make this throw NegativeArrayIndexException instead. + constant_exprt intzero=from_integer(0, java_int_type()); + binary_relation_exprt gezero(op[0], ID_ge, intzero); + code_assertt check(gezero); + check.add_source_location().set_comment("Array size < 0"); + check.add_source_location() + .set_property_class("array-create-negative-size"); + c.move_to_operands(check); + } + if(max_array_length!=0) + { + constant_exprt size_limit= + from_integer(max_array_length, java_int_type()); + binary_relation_exprt le_max_size(op[0], ID_le, size_limit); + code_assumet assume_le_max_size(le_max_size); + c.move_to_operands(assume_le_max_size); + } + const exprt tmp=tmp_variable("newarray", ref_type); + c.copy_to_operands(code_assignt(tmp, java_new_array)); + results[0]=tmp; + } + else if(statement=="multianewarray") + { + // The first argument is the type, the second argument is the number of + // dimensions. The size of each dimension is on the stack. + irep_idt number=to_constant_expr(arg1).get_value(); + std::size_t dimension=safe_string2size_t(id2string(number)); + + op=pop(dimension); + assert(results.size()==1); + + const pointer_typet ref_type(arg0.type()); + + side_effect_exprt java_new_array(ID_java_new_array, ref_type); + java_new_array.operands()=op; + + if(!i_it->source_location.get_line().empty()) + java_new_array.add_source_location()=i_it->source_location; + + code_blockt checkandcreate; + if(!disable_runtime_checks) + { + // TODO make this throw NegativeArrayIndexException instead. + constant_exprt intzero=from_integer(0, java_int_type()); + binary_relation_exprt gezero(op[0], ID_ge, intzero); + code_assertt check(gezero); + check.add_source_location().set_comment("Array size < 0"); + check.add_source_location() + .set_property_class("array-create-negative-size"); + checkandcreate.move_to_operands(check); + + if(max_array_length!=0) + { + constant_exprt size_limit= + from_integer(max_array_length, java_int_type()); + binary_relation_exprt le_max_size(op[0], ID_le, size_limit); + code_assumet assume_le_max_size(le_max_size); + checkandcreate.move_to_operands(assume_le_max_size); + } + } + const exprt tmp=tmp_variable("newarray", ref_type); + c=code_assignt(tmp, java_new_array); + results[0]=tmp; + } + else if(statement=="arraylength") + { + assert(op.size()==1 && results.size()==1); + + exprt pointer= + typecast_exprt(op[0], java_array_type(statement[0])); + + const dereference_exprt array(pointer, pointer.type().subtype()); + assert(pointer.type().subtype().id()==ID_symbol); + + const member_exprt length(array, "length", java_int_type()); + + results[0]=length; + } + else if(statement=="tableswitch" || + statement=="lookupswitch") + { + assert(op.size()==1 && results.size()==0); + + // we turn into switch-case + code_switcht code_switch; + code_switch.add_source_location()=i_it->source_location; + code_switch.value()=op[0]; + code_blockt code_block; + code_block.add_source_location()=i_it->source_location; + + bool is_label=true; + for(instructiont::argst::const_iterator + a_it=i_it->args.begin(); + a_it!=i_it->args.end(); + a_it++, is_label=!is_label) + { + if(is_label) + { + code_switch_caset code_case; + code_case.add_source_location()=i_it->source_location; + + irep_idt number=to_constant_expr(*a_it).get_value(); + code_case.code()=code_gotot(label(number)); + code_case.code().add_source_location()=i_it->source_location; + + if(a_it==i_it->args.begin()) + code_case.set_default(); + else + { + instructiont::argst::const_iterator prev=a_it; + prev--; + code_case.case_op()=typecast_exprt(*prev, op[0].type()); + code_case.case_op().add_source_location()=i_it->source_location; + } + + code_block.add(code_case); + } + } + + code_switch.body()=code_block; + c=code_switch; + } + else if(statement=="pop" || statement=="pop2") + { + // these are skips + c=code_skipt(); + + // pop2 removes two single-word items from the stack (e.g. two + // integers, or an integer and an object reference) or one + // two-word item (i.e. a double or a long). + // http://cs.au.dk/~mis/dOvs/jvmspec/ref-pop2.html + if(statement=="pop2" && + get_bytecode_type_width(op[0].type())==32) + pop(1); + } + else if(statement=="instanceof") + { + assert(op.size()==1 && results.size()==1); + + results[0]= + binary_predicate_exprt(op[0], ID_java_instanceof, arg0); + } + else if(statement=="monitorenter") + { + // becomes a function call + code_typet type; + type.return_type()=void_typet(); + type.parameters().resize(1); + type.parameters()[0].type()=reference_typet(void_typet()); + code_function_callt call; + call.function()=symbol_exprt("java::monitorenter", type); + call.lhs().make_nil(); + call.arguments().push_back(op[0]); + call.add_source_location()=i_it->source_location; + c=call; + } + else if(statement=="monitorexit") + { + // becomes a function call + code_typet type; + type.return_type()=void_typet(); + type.parameters().resize(1); + type.parameters()[0].type()=reference_typet(void_typet()); + code_function_callt call; + call.function()=symbol_exprt("java::monitorexit", type); + call.lhs().make_nil(); + call.arguments().push_back(op[0]); + call.add_source_location()=i_it->source_location; + c=call; + } + else + { + c=codet(statement); + c.operands()=op; + } + + if(!i_it->source_location.get_line().empty()) + c.add_source_location()=i_it->source_location; + + push(results); + + a_it->second.done=true; + for(const unsigned address : a_it->second.successors) + { + address_mapt::iterator a_it2=address_map.find(address); + assert(a_it2!=address_map.end()); + + if(!stack.empty() && a_it2->second.predecessors.size()>1) + { + // copy into temporaries + code_blockt more_code; + + // introduce temporaries when successor is seen for the first + // time + if(a_it2->second.stack.empty()) + { + for(stackt::iterator s_it=stack.begin(); + s_it!=stack.end(); + ++s_it) + { + symbol_exprt lhs=tmp_variable("$stack", s_it->type()); + code_assignt a(lhs, *s_it); + more_code.copy_to_operands(a); + + s_it->swap(lhs); + } + } + else + { + assert(a_it2->second.stack.size()==stack.size()); + stackt::const_iterator os_it=a_it2->second.stack.begin(); + for(auto &expr : stack) + { + assert(has_prefix(os_it->get_string(ID_C_base_name), "$stack")); + symbol_exprt lhs=to_symbol_expr(*os_it); + code_assignt a(lhs, expr); + more_code.copy_to_operands(a); + + expr.swap(lhs); + ++os_it; + } + } + + if(results.empty()) + { + more_code.copy_to_operands(c); + c.swap(more_code); + } + else + { + c.make_block(); + auto &last_statement=to_code_block(c).find_last_statement(); + if(last_statement.get_statement()==ID_goto) + { + // Insert stack twiddling before branch: + last_statement.make_block(); + last_statement.operands().insert( + last_statement.operands().begin(), + more_code.operands().begin(), + more_code.operands().end()); + } + else + forall_operands(o_it, more_code) + c.copy_to_operands(*o_it); + } + } + + a_it2->second.stack=stack; + } + } + + // TODO: add exception handlers from exception table + // review successor computation of athrow! + code_blockt code; + + // Add anonymous locals to the symtab: + for(const auto &var : used_local_names) + { + symbolt new_symbol; + new_symbol.name=var.get_identifier(); + new_symbol.type=var.type(); + new_symbol.base_name=var.get(ID_C_base_name); + new_symbol.pretty_name=strip_java_namespace_prefix(var.get_identifier()); + new_symbol.mode=ID_java; + new_symbol.is_type=false; + new_symbol.is_file_local=true; + new_symbol.is_thread_local=true; + new_symbol.is_lvalue=true; + symbol_table.add(new_symbol); + } + + // Try to recover block structure as indicated in the local variable table: + + // The block tree node mirrors the block structure of root_block, + // indexing the Java PCs where each subblock starts and ends. + block_tree_nodet root; + code_blockt root_block; + + // First create a simple flat list of basic blocks. We'll add lexical nesting + // constructs as variable live-ranges require next. + bool start_new_block=true; + for(const auto &address_pair : address_map) + { + const unsigned address=address_pair.first; + assert(address_pair.first==address_pair.second.source->address); + const codet &c=address_pair.second.code; + + // Start a new lexical block if this is a branch target: + if(!start_new_block) + start_new_block=targets.find(address)!=targets.end(); + // Start a new lexical block if this is a control flow join + // (e.g. due to exceptional control flow) + if(!start_new_block) + start_new_block=address_pair.second.predecessors.size()>1; + + if(start_new_block) + { + code_labelt newlabel(label(std::to_string(address)), code_blockt()); + root_block.move_to_operands(newlabel); + root.branch.push_back(block_tree_nodet::get_leaf()); + assert((root.branch_addresses.size()==0 || + root.branch_addresses.back()1; + } + + // Find out where temporaries are used: + std::map temporary_variable_live_ranges; + for(const auto &aentry : address_map) + gather_symbol_live_ranges( + aentry.first, + aentry.second.code, + temporary_variable_live_ranges); + + std::vector vars_to_process; + for(const auto &vlist : variables) + for(const auto &v : vlist) + vars_to_process.push_back(&v); + + for(const auto &v : tmp_vars) + vars_to_process.push_back( + &temporary_variable_live_ranges.at(v.get_identifier())); + + for(const auto &v : used_local_names) + vars_to_process.push_back( + &temporary_variable_live_ranges.at(v.get_identifier())); + + for(const auto vp : vars_to_process) + { + const auto &v=*vp; + if(v.is_parameter) + continue; + // Merge lexical scopes as far as possible to allow us to + // declare these variable scopes faithfully. + // Don't insert yet, as for the time being the blocks' only + // operands must be other blocks. + // The declarations will be inserted in the next pass instead. + get_or_create_block_for_pcrange( + root, + root_block, + v.start_pc, + v.start_pc+v.length, + std::numeric_limits::max(), + address_map); + } + for(const auto vp : vars_to_process) + { + const auto &v=*vp; + if(v.is_parameter) + continue; + // Skip anonymous variables: + if(v.symbol_expr.get_identifier()==irep_idt()) + continue; + auto &block=get_block_for_pcrange( + root, + root_block, + v.start_pc, + v.start_pc+v.length, + std::numeric_limits::max()); + code_declt d(v.symbol_expr); + block.operands().insert(block.operands().begin(), d); + } + + for(auto &block : root_block.operands()) + code.move_to_operands(block); + + return code; +} + +/*******************************************************************\ + +Function: java_bytecode_convert_method + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void java_bytecode_convert_method( + const symbolt &class_symbol, + const java_bytecode_parse_treet::methodt &method, + symbol_tablet &symbol_table, + message_handlert &message_handler, + bool disable_runtime_checks, + size_t max_array_length, + safe_pointer > needed_methods, + safe_pointer > needed_classes) +{ + java_bytecode_convert_methodt java_bytecode_convert_method( + symbol_table, + message_handler, + disable_runtime_checks, + max_array_length, + needed_methods, + needed_classes); + + java_bytecode_convert_method(class_symbol, method); +} diff --git a/src/java_bytecode/java_bytecode_typecheck_expr.cpp b/src/java_bytecode/java_bytecode_typecheck_expr.cpp index 6c50b612793..acd61086352 100644 --- a/src/java_bytecode/java_bytecode_typecheck_expr.cpp +++ b/src/java_bytecode/java_bytecode_typecheck_expr.cpp @@ -62,23 +62,28 @@ void java_bytecode_typecheckt::typecheck_expr(exprt &expr) typecheck_expr_symbol(to_symbol_expr(expr)); else if(expr.id()==ID_side_effect) { - const irep_idt &statement = to_side_effect_expr(expr).get_statement(); + auto &side_effect_expr = to_side_effect_expr(expr); + const irep_idt &statement = side_effect_expr.get_statement(); if (statement == ID_java_new) { - typecheck_expr_java_new(to_side_effect_expr(expr)); + typecheck_expr_java_new(side_effect_expr); } else if (statement == ID_java_new_array) { - typecheck_expr_java_new_array(to_side_effect_expr(expr)); + typecheck_expr_java_new_array(side_effect_expr); } else if (statement == ID_nondet) { - const typet &type = expr.type(); + const side_effect_expr_nondett &nondet_expr = + to_side_effect_expr_nondet(side_effect_expr); + + const typet &type = nondet_expr.type(); + const auto allow_null = nondet_expr.get_allow_null(); code_blockt init_code; expr = object_factory(type, init_code, - true, + allow_null, symbol_table, max_nondet_array_length, type.source_location(), diff --git a/src/java_bytecode/library/src/org/cprover/CProver.java b/src/java_bytecode/library/src/org/cprover/CProver.java index bf9a2ab515d..a4879007ed0 100644 --- a/src/java_bytecode/library/src/org/cprover/CProver.java +++ b/src/java_bytecode/library/src/org/cprover/CProver.java @@ -93,12 +93,23 @@ public static double nondetDouble() return 0; } - public static T nondet(boolean allowNull) + public static T nondetWithNull() { if (enableNondet) { throw new RuntimeException( - "Cannot execute program with CProver.nondet()"); + "Cannot execute program with CProver.nondetWithNull()"); + } + + return null; + } + + public static T nondetWithoutNull() + { + if (enableNondet) + { + throw new RuntimeException( + "Cannot execute program with CProver.nondetWithoutNull()"); } return null; diff --git a/src/util/irep_ids.txt b/src/util/irep_ids.txt index 29907f11040..37585ceba96 100644 --- a/src/util/irep_ids.txt +++ b/src/util/irep_ids.txt @@ -802,4 +802,5 @@ cprover_string_to_lower_case_func cprover_string_to_upper_case_func cprover_string_trim_func cprover_string_value_of_func -basic_block_covered_lines \ No newline at end of file +basic_block_covered_lines +nondet_allow_null diff --git a/src/util/std_code.h b/src/util/std_code.h index 08aec694e9e..47c0e94e984 100644 --- a/src/util/std_code.h +++ b/src/util/std_code.h @@ -1042,8 +1042,32 @@ class side_effect_expr_nondett:public side_effect_exprt side_effect_exprt(ID_nondet, _type) { } + + inline void set_allow_null(bool a) + { + set(ID_nondet_allow_null, a); + } + + inline bool get_allow_null() const + { + return get_bool(ID_nondet_allow_null); + } }; +static inline const side_effect_expr_nondett & + to_side_effect_expr_nondet(const side_effect_exprt &expr) +{ + assert(expr.get_statement() == ID_nondet); + return static_cast(expr); +} + +static inline side_effect_expr_nondett & + to_side_effect_expr_nondet(side_effect_exprt &expr) +{ + assert(expr.get_statement() == ID_nondet); + return static_cast(expr); +} + /*! \brief A function call side effect */ class side_effect_expr_function_callt:public side_effect_exprt From 652c204c874231a2103ab5c5875791d80969f196 Mon Sep 17 00:00:00 2001 From: reuk Date: Thu, 23 Feb 2017 16:31:15 +0000 Subject: [PATCH 19/39] Add cerr DEBUG output during typecheck --- .../cbmc-java/nondetGenericRecursive2/A.class | Bin 0 -> 250 bytes .../cbmc-java/nondetGenericRecursive2/B.class | Bin 0 -> 268 bytes .../cbmc-java/nondetGenericRecursive2/C.class | Bin 0 -> 268 bytes .../NondetGenericRecursive2.class | Bin 0 -> 736 bytes .../NondetGenericWithNull.class | Bin 727 -> 727 bytes .../NondetGenericWithoutNull.class | Bin 739 -> 739 bytes .../java_bytecode_typecheck_expr.cpp | 4 ++++ 7 files changed, 4 insertions(+) create mode 100644 regression/cbmc-java/nondetGenericRecursive2/A.class create mode 100644 regression/cbmc-java/nondetGenericRecursive2/B.class create mode 100644 regression/cbmc-java/nondetGenericRecursive2/C.class create mode 100644 regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.class diff --git a/regression/cbmc-java/nondetGenericRecursive2/A.class b/regression/cbmc-java/nondetGenericRecursive2/A.class new file mode 100644 index 0000000000000000000000000000000000000000..5628564f73de76f1351bb4a729940bdd352fce99 GIT binary patch literal 250 zcmXYrPfNo<5XIj#|7?u5c=pg^?ZJR}Qwl}UOQ@iw_sw>&8{!7Gn|?1(LJxibKa@CI z9hjN-e!PMC{yBUBxWza}gtH9i8AgQk-dN-3glKxTCd3cjh6$s}SYGz;HM^CnTOk)! zr&YUF&IJDtW4|>!Ijt6Vg#5MZo#saq;+M)!3mo^P%jwO0jVBm`Oz z#=)1ZvTx;c-LUqUU?Bg6B54WAPDPcn14(9|pbrrPWHQqujBp~l_zPf&TpZ!_m@0k& D)om|Z literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetGenericRecursive2/B.class b/regression/cbmc-java/nondetGenericRecursive2/B.class new file mode 100644 index 0000000000000000000000000000000000000000..606067dcdb8b8be87b1a342f717de25a96a891fc GIT binary patch literal 268 zcmXX=!A`hx61^V)NQhC`(K<)Jn#X2lyMe& zn3?z9ym^_Q-|qu}JB(9wF-$N@a6uqN=;jYILOeIt_ETXsgjvaa3EG<Q|xn4=X~DRcj{nb7OhlYzuZD zswhPn=9O0EN;%{CMGWdMv-3%rB*pJl<228Vx8KbxyXN|hEjy!^tQ)s8dmcY+)LtbB z5y=x7Vc>aMD*Kr(iVf=;BedjGfTRL+E=UeUxe}Jj^t;aE59nJ!3tj2qNlXw6PR<7O L1o@!rlk4UPmB%o_ literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.class b/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.class new file mode 100644 index 0000000000000000000000000000000000000000..a2b0ec053543cbd0c5c4e4551df718f8e958b64c GIT binary patch literal 736 zcmZ`$+fEZv6kWTW_O!!5FF2Wur_F!pUabA*HA9CBu+AHxs$ ztR`YKLElXLCS%+)Vo5YS%j45x8vQ z3a$#Q6Xw_5D3T^tI*jhC$Q=jLC(wvc+*F~8w+Q)mXP030wJ!;kfePg?c{7&gdD={< z547h7yRK1be44c4eH9T}gP{(689$PtG|GD>y~IRnB5&Ve*jHLJlgHkm&++U|?0T=C zxQ7`8FHILuD;F^Q$xWNQ{2R3F1&9vAH+;FdV z@2}(s#%M!WItNdn?Vy7$p?Ws_bbKJam|sqty`Fby^hBCoe><~;T9^rbq2hg=#KR;A z2n+4b;NN)`Tsh121HJ;G;mb%F=}-6LCy5g-@Cim(<0F>&xKwSXirCBZ$6`U4W3R`S z*cQ6Spm*%#P~m?uOV&_j-}%#k8tNRCFh3n0ad$er{0X^l$UlA$>j;(Zcg%c2;pH)k zUsJ?h5!Hn delta 21 ccmcc4dYyGc5)&s613LpRgCqmr Date: Thu, 23 Feb 2017 16:32:22 +0000 Subject: [PATCH 20/39] Add nondetGenericRecursive2 test --- .../NondetGenericRecursive2.java | 24 +++++++++++++++++++ .../nondetGenericRecursive2/test.desc | 6 +++++ 2 files changed, 30 insertions(+) create mode 100644 regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java create mode 100644 regression/cbmc-java/nondetGenericRecursive2/test.desc diff --git a/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java b/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java new file mode 100644 index 00000000000..6362c8f71ca --- /dev/null +++ b/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java @@ -0,0 +1,24 @@ +import org.cprover.CProver; + +class A +{ +} + +class B +{ + A a; +} + +class C +{ + B b; +} + +class NondetGenericRecursive2 +{ + static void foo() + { + C c = CProver.nondetWithoutNull(); + assert c != null; + } +} diff --git a/regression/cbmc-java/nondetGenericRecursive2/test.desc b/regression/cbmc-java/nondetGenericRecursive2/test.desc new file mode 100644 index 00000000000..980b6b20737 --- /dev/null +++ b/regression/cbmc-java/nondetGenericRecursive2/test.desc @@ -0,0 +1,6 @@ +CORE +NondetGenericRecursive2.class +--function NondetGenericRecursive2.foo +^VERIFICATION FAILED$ +-- +^warning: ignoring From c81e06b1f296b5c2117652ff284e090a252ec8c0 Mon Sep 17 00:00:00 2001 From: reuk Date: Fri, 24 Feb 2017 12:13:18 +0000 Subject: [PATCH 21/39] Change generic nondet to init existing variable Removed CProver.class --- .../NondetGenericImplicitType.java | 8 +++---- .../NondetGenericNoAssignment.java | 9 ------- .../nondetGenericNoAssignment/test.desc | 6 ----- .../NondetGenericRecursive.java | 3 ++- .../NondetGenericRecursive2.java | 24 ------------------- .../nondetGenericRecursive2/test.desc | 6 ----- .../NondetGenericWithNull.java | 5 ++-- .../NondetGenericWithoutNull.java | 5 ++-- .../library/src/org/cprover/CProver.java | 15 ++++++------ 9 files changed, 19 insertions(+), 62 deletions(-) delete mode 100644 regression/cbmc-java/nondetGenericNoAssignment/NondetGenericNoAssignment.java delete mode 100644 regression/cbmc-java/nondetGenericNoAssignment/test.desc delete mode 100644 regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java delete mode 100644 regression/cbmc-java/nondetGenericRecursive2/test.desc diff --git a/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.java b/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.java index f157808974c..3ba9a42decf 100644 --- a/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.java +++ b/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.java @@ -4,10 +4,10 @@ class Foo { } class NondetGenericImplicitType { - static void callWithImplicitType() + static void foo() { - // User may cast to incompatible type. - Foo foo = CProver.nondetWithNull(); - assert foo == null; + Foo x = null; + CProver.nondetWithNull(x); + assert x == null; } } diff --git a/regression/cbmc-java/nondetGenericNoAssignment/NondetGenericNoAssignment.java b/regression/cbmc-java/nondetGenericNoAssignment/NondetGenericNoAssignment.java deleted file mode 100644 index a69043bfa6b..00000000000 --- a/regression/cbmc-java/nondetGenericNoAssignment/NondetGenericNoAssignment.java +++ /dev/null @@ -1,9 +0,0 @@ -import org.cprover.CProver; - -class NondetGenericNoAssignment -{ - static void callWithoutAssignment() - { - assert CProver.nondetWithNull() == null; - } -} diff --git a/regression/cbmc-java/nondetGenericNoAssignment/test.desc b/regression/cbmc-java/nondetGenericNoAssignment/test.desc deleted file mode 100644 index 6d49a1f5a63..00000000000 --- a/regression/cbmc-java/nondetGenericNoAssignment/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -NondetGenericNoAssignment.class ---function NondetGenericNoAssignment.callWithoutAssignment -^VERIFICATION FAILED$ --- -^warning: ignoring diff --git a/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java b/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java index 39aab3b241f..2f66827d4d8 100644 --- a/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java +++ b/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java @@ -18,7 +18,8 @@ class NondetGenericRecursive { static void foo() { - C c = CProver.nondetWithNull(); + C c = null; + CProver.nondetWithNull(c); assert c == null; } } diff --git a/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java b/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java deleted file mode 100644 index 6362c8f71ca..00000000000 --- a/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java +++ /dev/null @@ -1,24 +0,0 @@ -import org.cprover.CProver; - -class A -{ -} - -class B -{ - A a; -} - -class C -{ - B b; -} - -class NondetGenericRecursive2 -{ - static void foo() - { - C c = CProver.nondetWithoutNull(); - assert c != null; - } -} diff --git a/regression/cbmc-java/nondetGenericRecursive2/test.desc b/regression/cbmc-java/nondetGenericRecursive2/test.desc deleted file mode 100644 index 980b6b20737..00000000000 --- a/regression/cbmc-java/nondetGenericRecursive2/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -NondetGenericRecursive2.class ---function NondetGenericRecursive2.foo -^VERIFICATION FAILED$ --- -^warning: ignoring diff --git a/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java b/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java index 0474997c407..240fcfa4599 100644 --- a/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java +++ b/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java @@ -8,7 +8,8 @@ class NondetGenericWithNull { static void foo() { - B b = CProver.nondetWithNull(); - assert b == null; + B b = null; + CProver.nondetWithNull(b); + assert b != null; } } diff --git a/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java b/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java index 54fced2dbc5..9c54bb97743 100644 --- a/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java +++ b/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java @@ -8,7 +8,8 @@ class NondetGenericWithoutNull { static void foo() { - B b = CProver.nondetWithoutNull(); - assert b == null; + B b = null; + CProver.nondetWithoutNull(b); + assert b != null; } } diff --git a/src/java_bytecode/library/src/org/cprover/CProver.java b/src/java_bytecode/library/src/org/cprover/CProver.java index a4879007ed0..28690422fa9 100644 --- a/src/java_bytecode/library/src/org/cprover/CProver.java +++ b/src/java_bytecode/library/src/org/cprover/CProver.java @@ -93,26 +93,25 @@ public static double nondetDouble() return 0; } - public static T nondetWithNull() + // Set a variable to a nondeterminate state, which may be null. + public static void nondetWithNull(T t) { if (enableNondet) { throw new RuntimeException( - "Cannot execute program with CProver.nondetWithNull()"); + "Cannot execute program with CProver.nondetWithNull(T)"); } - - return null; } - public static T nondetWithoutNull() + // Set a variable to a nondeterminate state, which must NOT be nullptr, but + // reference fields of the object may be null. + public static void nondetWithoutNull(T t) { if (enableNondet) { throw new RuntimeException( - "Cannot execute program with CProver.nondetWithoutNull()"); + "Cannot execute program with CProver.nondetWithoutNull(T)"); } - - return null; } public static void assume(boolean condition) From 9f0dc21a8e926e3579072c4057b35450fde8d008 Mon Sep 17 00:00:00 2001 From: reuk Date: Fri, 24 Feb 2017 14:34:08 +0000 Subject: [PATCH 22/39] Add another nondet generic recursive test case --- .../NondetGenericImplicitType.java | 13 ------------- .../cbmc-java/nondetGenericImplicitType/test.desc | 6 ------ .../NondetGenericWithoutNull.java | 8 +++++--- .../cbmc-java/nondetGenericWithoutNull/test.desc | 6 ++++++ 4 files changed, 11 insertions(+), 22 deletions(-) delete mode 100644 regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.java delete mode 100644 regression/cbmc-java/nondetGenericImplicitType/test.desc create mode 100644 regression/cbmc-java/nondetGenericWithoutNull/test.desc diff --git a/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.java b/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.java deleted file mode 100644 index 3ba9a42decf..00000000000 --- a/regression/cbmc-java/nondetGenericImplicitType/NondetGenericImplicitType.java +++ /dev/null @@ -1,13 +0,0 @@ -import org.cprover.CProver; - -class Foo { } - -class NondetGenericImplicitType -{ - static void foo() - { - Foo x = null; - CProver.nondetWithNull(x); - assert x == null; - } -} diff --git a/regression/cbmc-java/nondetGenericImplicitType/test.desc b/regression/cbmc-java/nondetGenericImplicitType/test.desc deleted file mode 100644 index f8326f141df..00000000000 --- a/regression/cbmc-java/nondetGenericImplicitType/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -NondetGenericImplicitType.class ---function NondetGenericImplicitType.callWithImplicitType -^VERIFICATION FAILED$ --- -^warning: ignoring diff --git a/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java b/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java index 9c54bb97743..412467eeaab 100644 --- a/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java +++ b/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java @@ -4,12 +4,14 @@ class A { } class B { A a; } +class C { B b; } + class NondetGenericWithoutNull { static void foo() { - B b = null; - CProver.nondetWithoutNull(b); - assert b != null; + C c = null; + CProver.nondetWithoutNull(c); + assert c != null; } } diff --git a/regression/cbmc-java/nondetGenericWithoutNull/test.desc b/regression/cbmc-java/nondetGenericWithoutNull/test.desc new file mode 100644 index 00000000000..446d26face6 --- /dev/null +++ b/regression/cbmc-java/nondetGenericWithoutNull/test.desc @@ -0,0 +1,6 @@ +CORE +NondetGenericWithoutNull.class +--function NondetGenericWithoutNull.foo +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring From 059ce68eaad43d4d27cfb8d8690c86c2f3effca8 Mon Sep 17 00:00:00 2001 From: reuk Date: Fri, 24 Feb 2017 14:35:27 +0000 Subject: [PATCH 23/39] Add new internal 'nondet initializer block' type The new block type is replaced by a nondet initializer during bytecode conversion and typechecking. Add missing test case Make small fixes to test cases Fix formatting issues --- .../NondetGenericRecursive2.java | 25 ++++ .../nondetGenericRecursive2/test.desc | 6 + .../NondetGenericWithNull.java | 5 +- .../cbmc-java/nondetGenericWithNull/test.desc | 6 + .../NondetGenericWithoutNull.java | 4 +- src/goto-programs/goto_convert.cpp | 5 + .../goto_convert_side_effect.cpp | 4 + .../java_bytecode_convert_method.cpp | 132 ++++++++---------- .../java_bytecode_typecheck_code.cpp | 40 +++++- .../java_bytecode_typecheck_expr.cpp | 24 ---- src/util/irep_ids.txt | 1 + src/util/std_code.h | 73 +++++++--- 12 files changed, 203 insertions(+), 122 deletions(-) create mode 100644 regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java create mode 100644 regression/cbmc-java/nondetGenericRecursive2/test.desc create mode 100644 regression/cbmc-java/nondetGenericWithNull/test.desc diff --git a/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java b/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java new file mode 100644 index 00000000000..6588f1f4a4f --- /dev/null +++ b/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java @@ -0,0 +1,25 @@ +import org.cprover.CProver; + +class A +{ +} + +class B +{ + A a; +} + +class C +{ + B b; +} + +class NondetGenericRecursive2 +{ + static void foo() + { + C c = null; + CProver.nondetWithoutNull(c); + assert c.b.a != null; + } +} diff --git a/regression/cbmc-java/nondetGenericRecursive2/test.desc b/regression/cbmc-java/nondetGenericRecursive2/test.desc new file mode 100644 index 00000000000..85c68803951 --- /dev/null +++ b/regression/cbmc-java/nondetGenericRecursive2/test.desc @@ -0,0 +1,6 @@ +CORE +NondetGenericRecursive2.class +--function NondetGenericRecursive2.foo +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java b/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java index 240fcfa4599..ad8bebf349e 100644 --- a/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java +++ b/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java @@ -1,8 +1,6 @@ import org.cprover.CProver; -class A { } - -class B { A a; } +class B { int a; } class NondetGenericWithNull { @@ -11,5 +9,6 @@ static void foo() B b = null; CProver.nondetWithNull(b); assert b != null; + assert b.a != 0; } } diff --git a/regression/cbmc-java/nondetGenericWithNull/test.desc b/regression/cbmc-java/nondetGenericWithNull/test.desc new file mode 100644 index 00000000000..d3c4f793445 --- /dev/null +++ b/regression/cbmc-java/nondetGenericWithNull/test.desc @@ -0,0 +1,6 @@ +CORE +NondetGenericWithNull.class +--function NondetGenericWithNull.foo +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java b/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java index 412467eeaab..cc0207b891b 100644 --- a/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java +++ b/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java @@ -1,8 +1,6 @@ import org.cprover.CProver; -class A { } - -class B { A a; } +class B { int a; } class C { B b; } diff --git a/src/goto-programs/goto_convert.cpp b/src/goto-programs/goto_convert.cpp index a3124f3b898..19add7771c6 100644 --- a/src/goto-programs/goto_convert.cpp +++ b/src/goto-programs/goto_convert.cpp @@ -6,6 +6,10 @@ Author: Daniel Kroening, kroening@kroening.com \*******************************************************************/ +#ifdef DEBUG +#include +#endif + #include #include @@ -905,6 +909,7 @@ void goto_convertt::convert_assign( copy(new_assign, ASSIGN, dest); } + else { clean_expr(rhs, dest); diff --git a/src/goto-programs/goto_convert_side_effect.cpp b/src/goto-programs/goto_convert_side_effect.cpp index f34ee9d03a0..501804e017e 100644 --- a/src/goto-programs/goto_convert_side_effect.cpp +++ b/src/goto-programs/goto_convert_side_effect.cpp @@ -6,6 +6,10 @@ Author: Daniel Kroening, kroening@kroening.com \*******************************************************************/ +#ifdef DEBUG +#include +#endif + #include #include #include diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index 0120b28c15b..95c91c54df6 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -1108,136 +1108,118 @@ codet java_bytecode_convert_methodt::convert_instructions( } // replace calls to CProver.assume - else if (statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.assume:(Z)V")) + else if(statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.assume:(Z)V")) { - const code_typet &code_type = to_code_type(arg0.type()); + const code_typet &code_type=to_code_type(arg0.type()); // sanity check: function has the right number of args - assert(code_type.parameters().size() == 1); + assert(code_type.parameters().size()==1); - exprt operand = pop(1)[0]; + exprt operand=pop(1)[0]; // we may need to adjust the type of the argument - if (operand.type() != bool_typet()) + if(operand.type()!=bool_typet()) operand.make_typecast(bool_typet()); - c = code_assumet(operand); - source_locationt loc = i_it->source_location; + c=code_assumet(operand); + source_locationt loc=i_it->source_location; loc.set_function(method_id); - c.add_source_location() = loc; + c.add_source_location()=loc; } // if the statement is a nondet boolean - else if (statement_is_static_with_name( - statement, arg0, - "java::org.cprover.CProver.nondetBoolean:()Z")) + else if(statement_is_static_with_name( + statement, arg0, + "java::org.cprover.CProver.nondetBoolean:()Z")) { results.resize(1); - results[0] = side_effect_expr_nondett(java_boolean_type()); - results[0].add_source_location() = i_it->source_location; + results[0]=side_effect_expr_nondett(java_boolean_type()); + results[0].add_source_location()=i_it->source_location; } // if the statement is a nondet byte - else if (statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetByte:()B")) + else if(statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetByte:()B")) { results.resize(1); - results[0] = side_effect_expr_nondett(java_byte_type()); - results[0].add_source_location() = i_it->source_location; + results[0]=side_effect_expr_nondett(java_byte_type()); + results[0].add_source_location()=i_it->source_location; } // if the statement is a nondet char - else if (statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetChar:()C")) + else if(statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetChar:()C")) { results.resize(1); - results[0] = side_effect_expr_nondett(java_char_type()); - results[0].add_source_location() = i_it->source_location; + results[0]=side_effect_expr_nondett(java_char_type()); + results[0].add_source_location()=i_it->source_location; } // if the statement is a nondet short - else if (statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetShort:()S")) + else if(statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetShort:()S")) { results.resize(1); - results[0] = side_effect_expr_nondett(java_short_type()); - results[0].add_source_location() = i_it->source_location; + results[0]=side_effect_expr_nondett(java_short_type()); + results[0].add_source_location()=i_it->source_location; } // if the statement is a nondet int - else if (statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetInt:()I")) + else if(statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetInt:()I")) { results.resize(1); - results[0] = side_effect_expr_nondett(java_int_type()); - results[0].add_source_location() = i_it->source_location; + results[0]=side_effect_expr_nondett(java_int_type()); + results[0].add_source_location()=i_it->source_location; } // if the statement is a nondet long - else if (statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetLong:()J")) + else if(statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetLong:()J")) { results.resize(1); - results[0] = side_effect_expr_nondett(java_long_type()); - results[0].add_source_location() = i_it->source_location; + results[0]=side_effect_expr_nondett(java_long_type()); + results[0].add_source_location()=i_it->source_location; } // if the statement is a nondet float - else if (statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetFloat:()F")) + else if(statement_is_static_with_name( + statement, arg0, "java::org.cprover.CProver.nondetFloat:()F")) { results.resize(1); - results[0] = side_effect_expr_nondett(java_float_type()); - results[0].add_source_location() = i_it->source_location; + results[0]=side_effect_expr_nondett(java_float_type()); + results[0].add_source_location()=i_it->source_location; } // if the statement is a nondet double - else if (statement_is_static_with_name( + else if(statement_is_static_with_name( statement, arg0, "java::org.cprover.CProver.nondetDouble:()D")) { results.resize(1); - results[0] = side_effect_expr_nondett(java_double_type()); - results[0].add_source_location() = i_it->source_location; + results[0]=side_effect_expr_nondett(java_double_type()); + results[0].add_source_location()=i_it->source_location; } // To catch the return type of the nondet call, we have to check the // next statement for an assignment. - // Check that the statement is static, with the correct signature, and - // that the working set still has remaining items. - // TODO this will break if the user edits cprover.CProver and adds another - // method that begins with 'nondetWith'. - else if (!working_set.empty() && statement == "invokestatic" && - has_prefix(id2string(arg0.get(ID_identifier)), - "java::org.cprover.CProver.nondetWith")) - { - // For the type search to succeed, the next instruction must be a - // checkcast. - // Find the next item in the working set, and look up that item in the - // address map. - address_mapt::iterator next_it = address_map.find(*working_set.begin()); - assert(next_it != address_map.end()); - - instructionst::const_iterator next_source_it = next_it->second.source; - - // Check that the statement is a checkcast with an argument of the - // correct type. - assert(next_source_it->statement == "checkcast"); - assert(next_source_it->args.size() >= 1); - assert(next_source_it->args[0].type().id() == ID_symbol); - const auto java_object_type = next_source_it->args[0].type(); - - // Create somewhere to store the result, and set the source location. - results.resize(1); - results[0].add_source_location() = i_it->source_location; + // Check that the statement is static, with the correct signature. + else if(statement=="invokestatic" && + has_prefix(id2string(arg0.get(ID_identifier)), + "java::org.cprover.CProver.nondetWith")) + { + const code_typet &code_type=to_code_type(arg0.type()); + // Check function has the right number of args. + assert(code_type.parameters().size()==1); - auto nondet_result = - side_effect_expr_nondett(java_reference_type(java_object_type)); - // If the function call contains 'nondetWithNull' then allow nulls. - nondet_result.set_allow_null( + // Find whether the signature is for the nullable version or not. + const bool allow_null= has_prefix(id2string(arg0.get(ID_identifier)), - "java::org.cprover.CProver.nondetWithNull")); + "java::org.cprover.CProver.nondetWithNull"); - // Set the result to a nondet of the correct type. - results[0] = nondet_result; + c=nondet_initializer_blockt( + to_symbol_expr(to_typecast_expr(pop(1)[0]).op()), allow_null); + source_locationt loc=i_it->source_location; + loc.set_function(method_id); + c.add_source_location()=loc; } else if(statement=="invokeinterface" || diff --git a/src/java_bytecode/java_bytecode_typecheck_code.cpp b/src/java_bytecode/java_bytecode_typecheck_code.cpp index 788f5fa592b..f3d5883a56a 100644 --- a/src/java_bytecode/java_bytecode_typecheck_code.cpp +++ b/src/java_bytecode/java_bytecode_typecheck_code.cpp @@ -6,7 +6,12 @@ Author: Daniel Kroening, kroening@kroening.com \*******************************************************************/ +#ifdef DEBUG +#include +#endif + #include "java_bytecode_typecheck.h" +#include "java_object_factory.h" /*******************************************************************\ @@ -27,16 +32,49 @@ void java_bytecode_typecheckt::typecheck_code(codet &code) if(statement==ID_assign) { code_assignt &code_assign=to_code_assign(code); + + // Now that we've (possibly) converted nondet calls into actual code, + // we can continue typechecking each side. typecheck_expr(code_assign.lhs()); typecheck_expr(code_assign.rhs()); if(code_assign.lhs().type()!=code_assign.rhs().type()) code_assign.rhs().make_typecast(code_assign.lhs().type()); } + else if(statement==ID_nondet_initializer_block) + { + // Cast the expression to a 'nondet initializer block'. + const auto &nondet=to_nondet_initializer_block(code); + // Find the type of the nondet expression. + const auto &nondet_argument=nondet.statement_to_initialize(); + + // Create code to initialize the nondet object. + code_blockt init_code; + const auto output=object_factory( + nondet_argument.type(), + init_code, + nondet.get_allow_null(), + symbol_table, + max_nondet_array_length, + nondet_argument.source_location(), + get_message_handler()); + + // Create a new code block, containing the generated init_code, followed by + // the an assignment setting the passed variable to the newly-initialized + // value. + code_blockt new_code( + std::list{init_code, code_assignt(nondet_argument, output)}); + + // Replace the current code with the newly-created code, and typecheck it. + code=new_code; + typecheck_code(new_code); + } else if(statement==ID_block) { - Forall_operands(it, code) + Forall_operands(it, to_code_block(code)) + { typecheck_code(to_code(*it)); + } } else if(statement==ID_label) { diff --git a/src/java_bytecode/java_bytecode_typecheck_expr.cpp b/src/java_bytecode/java_bytecode_typecheck_expr.cpp index 64584d09681..4e1aa8f6bea 100644 --- a/src/java_bytecode/java_bytecode_typecheck_expr.cpp +++ b/src/java_bytecode/java_bytecode_typecheck_expr.cpp @@ -19,7 +19,6 @@ Author: Daniel Kroening, kroening@kroening.com #include #include "java_bytecode_typecheck.h" -#include "java_object_factory.h" #include "java_pointer_casts.h" #include "java_types.h" @@ -72,29 +71,6 @@ void java_bytecode_typecheckt::typecheck_expr(exprt &expr) { typecheck_expr_java_new_array(side_effect_expr); } - else if (statement == ID_nondet) - { - const side_effect_expr_nondett &nondet_expr = - to_side_effect_expr_nondet(side_effect_expr); - -#ifdef DEBUG - std::cerr << "nondet_expr: " << nondet_expr.pretty() << '\n'; -#endif - - const typet &type = nondet_expr.type(); - const auto allow_null = nondet_expr.get_allow_null(); - - code_blockt init_code; - expr = object_factory(type, - init_code, - allow_null, - symbol_table, - max_nondet_array_length, - type.source_location(), - get_message_handler()); - - typecheck_code(init_code); - } } else if(expr.id()==ID_java_string_literal) typecheck_expr_java_string_literal(expr); diff --git a/src/util/irep_ids.txt b/src/util/irep_ids.txt index 37585ceba96..d46feec5a15 100644 --- a/src/util/irep_ids.txt +++ b/src/util/irep_ids.txt @@ -803,4 +803,5 @@ cprover_string_to_upper_case_func cprover_string_trim_func cprover_string_value_of_func basic_block_covered_lines +nondet_initializer_block nondet_allow_null diff --git a/src/util/std_code.h b/src/util/std_code.h index 47c0e94e984..cdaa5c6cd00 100644 --- a/src/util/std_code.h +++ b/src/util/std_code.h @@ -342,6 +342,55 @@ inline code_assertt &to_code_assert(codet &code) return static_cast(code); } +/*! \brief A block of code which sets its parameter to a nondet value. + */ +class nondet_initializer_blockt:public codet +{ +public: + inline nondet_initializer_blockt( + const exprt &symbol_expr, + bool allow_null): + codet(ID_nondet_initializer_block) + { + copy_to_operands(symbol_expr); + set_allow_null(allow_null); + } + + inline const exprt &statement_to_initialize() const + { + return op0(); + } + + inline exprt &statement_to_initialize() + { + return op0(); + } + + inline void set_allow_null(bool b) + { + set(ID_nondet_allow_null, b); + } + + inline bool get_allow_null() const + { + return get_bool(ID_nondet_allow_null); + } +}; + +static inline const nondet_initializer_blockt & + to_nondet_initializer_block(const codet &code) +{ + assert(code.get_statement()==ID_nondet_initializer_block); + return static_cast(code); +} + +static inline nondet_initializer_blockt & + to_nondet_initializer_block(codet &code) +{ + assert(code.get_statement()==ID_nondet_initializer_block); + return static_cast(code); +} + /*! \brief An if-then-else */ class code_ifthenelset:public codet @@ -1042,30 +1091,22 @@ class side_effect_expr_nondett:public side_effect_exprt side_effect_exprt(ID_nondet, _type) { } - - inline void set_allow_null(bool a) - { - set(ID_nondet_allow_null, a); - } - - inline bool get_allow_null() const - { - return get_bool(ID_nondet_allow_null); - } }; static inline const side_effect_expr_nondett & - to_side_effect_expr_nondet(const side_effect_exprt &expr) + to_side_effect_expr_nondet(const exprt &expr) { - assert(expr.get_statement() == ID_nondet); - return static_cast(expr); + const auto& x = to_side_effect_expr(expr); + assert(x.get_statement() == ID_nondet); + return static_cast(x); } static inline side_effect_expr_nondett & - to_side_effect_expr_nondet(side_effect_exprt &expr) + to_side_effect_expr_nondet(exprt &expr) { - assert(expr.get_statement() == ID_nondet); - return static_cast(expr); + auto& x = to_side_effect_expr(expr); + assert(x.get_statement() == ID_nondet); + return static_cast(x); } /*! \brief A function call side effect From afc28bf21cf17f4d53ab9dfef3ac3f48796c34c1 Mon Sep 17 00:00:00 2001 From: reuk Date: Fri, 24 Feb 2017 15:38:32 +0000 Subject: [PATCH 24/39] Add array test --- .../cbmc-java/nondetGenericArray/A.class | Bin 0 -> 287 bytes .../cbmc-java/nondetGenericArray/B.class | Bin 0 -> 263 bytes .../cbmc-java/nondetGenericArray/C.class | Bin 0 -> 263 bytes .../NondetGenericArray.class | Bin 0 -> 839 bytes .../NondetGenericArray.java | 27 ++++++++++++++++++ .../cbmc-java/nondetGenericArray/test.desc | 6 ++++ 6 files changed, 33 insertions(+) create mode 100644 regression/cbmc-java/nondetGenericArray/A.class create mode 100644 regression/cbmc-java/nondetGenericArray/B.class create mode 100644 regression/cbmc-java/nondetGenericArray/C.class create mode 100644 regression/cbmc-java/nondetGenericArray/NondetGenericArray.class create mode 100644 regression/cbmc-java/nondetGenericArray/NondetGenericArray.java create mode 100644 regression/cbmc-java/nondetGenericArray/test.desc diff --git a/regression/cbmc-java/nondetGenericArray/A.class b/regression/cbmc-java/nondetGenericArray/A.class new file mode 100644 index 0000000000000000000000000000000000000000..1323ce430e51f6749719dce2b36153766f3c292a GIT binary patch literal 287 zcmXX=%}&BV5dLOcsH{aQka+c|9OU8+L(-T)Od32$xOm!@jV`I%WL-#jEDwgn5FfyY zGER}h%zS?{nV;XUZveOGON2;T2yh;u8=*%CjrH#Y@%%t&-WhBBm=IiDFW9=TmYUGX zjMcOCTdv()?z7f(4Fpj${H7&!R%Q;vT@GPOO2# z>zUcv*}eb&{s9=E?W2sqL(@ZxK!Q+?CPRWdQd$*broH}_;LP%!Bm|Mta(ViRrP+u$ zW2GJCiO9CXD9hiXQykRMCQUiXU*{*2$hori&NA0KSuCWMMkNzt#N|5`XHka>kM~ar zP0Pbf=zX|~Q<)U#qQpl6#Lq$Hjd*~SDzlJ(+pB!tKvxDO)VR7&u?nAY{bj%hBOBCs Gx;`J~t}e*{ literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetGenericArray/C.class b/regression/cbmc-java/nondetGenericArray/C.class new file mode 100644 index 0000000000000000000000000000000000000000..27903564a63e3a08c332282492d21f5c9f1fa959 GIT binary patch literal 263 zcmXX=yN<#z5S)dOK!D@X&{6^gY3M*mcaflppa9W3!2+Y;NG2fhSyU%o!3XeBC)PmW z^~~(->^}bg?f^z;`zWH}q3NMTpqNmMe#QiMqO{7VOndze!3ndiBs3zW<>GvdrCEzO zWu+ZuiAXoXD9b;hlke5ZCWV~jud=gACoa+e literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetGenericArray/NondetGenericArray.class b/regression/cbmc-java/nondetGenericArray/NondetGenericArray.class new file mode 100644 index 0000000000000000000000000000000000000000..bbf6914a096c04e4059e4b9327be44ae2de7940c GIT binary patch literal 839 zcmZWn+iuf95It)raqPIXNt;UpEd>gs0ctJ*N>d@ya1kN|q@p6qljAJy7GqZ%rxMTn zMSp;2AfgB)ctqlx5MtJZ6w!y>otd3EGw1C7`1ScKfEwx+GMKS2i{mCt%$YcWlO|4K z-oR-KDa@ESgR=%I78X!7aE@Ve-tG0cj6@jpZi}AV@p+elZ7`%(L?EJ@40>f@ogvW- zyPRRXB?8{=zv^)LL?tuiTA}Cq>#h{a9|jZAmgq4|wc26O<fQ#Giu5056#tmGsu?WY8 zjWL3;aS@jcT()rqHHMN(bbL41bQ*t2-;pwu2Cmw;hU-M;FuZ{!8#l1bFmX`-sI$$z zh&VJ!!ccBH-i{1+xpbP34O!Y#aWID*+4i3VOk#?>H1eb3H8!AQJCLjM5$Ff)acgl6AT{Ew2O;n;7*k)fji literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java b/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java new file mode 100644 index 00000000000..ee31e9a1483 --- /dev/null +++ b/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java @@ -0,0 +1,27 @@ +import org.cprover.CProver; + +class A +{ + int[] ints = new int[10]; +} + +class B +{ + A a; +} + +class C +{ + B b; +} + +class NondetGenericArray +{ + static void foo() + { + C c = null; + CProver.nondetWithoutNull(c); + assert c.b.a != null; + assert c.b.a.ints != null; + } +} diff --git a/regression/cbmc-java/nondetGenericArray/test.desc b/regression/cbmc-java/nondetGenericArray/test.desc new file mode 100644 index 00000000000..25a6155aa3d --- /dev/null +++ b/regression/cbmc-java/nondetGenericArray/test.desc @@ -0,0 +1,6 @@ +CORE +NondetGenericArray.class +--function NondetGenericArray.foo +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring From f9b4448fecfd9c3a4c531c8a6ea167566e75a5da Mon Sep 17 00:00:00 2001 From: reuk Date: Sun, 26 Feb 2017 19:36:27 +0000 Subject: [PATCH 25/39] Apply formatting based on pull-request feedback --- .../java_bytecode_convert_method.cpp | 79 +++++++++------- src/util/std_code.cpp | 90 +++++++++++++++++++ src/util/std_code.h | 33 ++----- 3 files changed, 143 insertions(+), 59 deletions(-) diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index 95c91c54df6..dff6cb5690c 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -860,12 +860,28 @@ static unsigned get_bytecode_type_width(const typet &ty) return ty.get_unsigned_int(ID_width); } -static bool statement_is_static_with_name(const irep_idt &statement, - const exprt &arg0, - const char *desired_name) +/*******************************************************************\ + +Function: statement_is_static_with_name + +Inputs: `statement`: A statement to check. + `arg0`: The first argument of the statement. + `desired_name`: The desired identifier of arg0. + + Outputs: True if statement matches "invokestatic" and arg0's identifier + matches the desired name, false otherwise. + + Purpose: Used to match nondet library methods concisely. + +\*******************************************************************/ + +static bool statement_is_static_with_name( + const irep_idt &statement, + const exprt &arg0, + const std::string &desired_name) { - return statement == "invokestatic" && - id2string(arg0.get(ID_identifier)) == desired_name; + return statement=="invokestatic" && + id2string(arg0.get(ID_identifier))==desired_name; } codet java_bytecode_convert_methodt::convert_instructions( @@ -997,18 +1013,16 @@ codet java_bytecode_convert_methodt::convert_instructions( while(!working_set.empty()) { - std::set::iterator cur = working_set.begin(); - address_mapt::iterator a_it = address_map.find(*cur); - assert(a_it != address_map.end()); + std::set::iterator cur=working_set.begin(); + address_mapt::iterator a_it=address_map.find(*cur); + assert(a_it!=address_map.end()); working_set.erase(cur); if (a_it->second.done) - { continue; - } - working_set.insert(a_it->second.successors.begin(), - a_it->second.successors.end()); + working_set.insert( + a_it->second.successors.begin(), a_it->second.successors.end()); instructionst::const_iterator i_it=a_it->second.source; stack.swap(a_it->second.stack); @@ -1109,7 +1123,7 @@ codet java_bytecode_convert_methodt::convert_instructions( // replace calls to CProver.assume else if(statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.assume:(Z)V")) + statement, arg0, "java::org.cprover.CProver.assume:(Z)V")) { const code_typet &code_type=to_code_type(arg0.type()); // sanity check: function has the right number of args @@ -1126,82 +1140,81 @@ codet java_bytecode_convert_methodt::convert_instructions( c.add_source_location()=loc; } - // if the statement is a nondet boolean + // if the statement is a nondet boolean else if(statement_is_static_with_name( - statement, arg0, - "java::org.cprover.CProver.nondetBoolean:()Z")) + statement, arg0, "java::org.cprover.CProver.nondetBoolean:()Z")) { results.resize(1); results[0]=side_effect_expr_nondett(java_boolean_type()); results[0].add_source_location()=i_it->source_location; } - // if the statement is a nondet byte + // if the statement is a nondet byte else if(statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetByte:()B")) + statement, arg0, "java::org.cprover.CProver.nondetByte:()B")) { results.resize(1); results[0]=side_effect_expr_nondett(java_byte_type()); results[0].add_source_location()=i_it->source_location; } - // if the statement is a nondet char + // if the statement is a nondet char else if(statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetChar:()C")) + statement, arg0, "java::org.cprover.CProver.nondetChar:()C")) { results.resize(1); results[0]=side_effect_expr_nondett(java_char_type()); results[0].add_source_location()=i_it->source_location; } - // if the statement is a nondet short + // if the statement is a nondet short else if(statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetShort:()S")) + statement, arg0, "java::org.cprover.CProver.nondetShort:()S")) { results.resize(1); results[0]=side_effect_expr_nondett(java_short_type()); results[0].add_source_location()=i_it->source_location; } - // if the statement is a nondet int + // if the statement is a nondet int else if(statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetInt:()I")) + statement, arg0, "java::org.cprover.CProver.nondetInt:()I")) { results.resize(1); results[0]=side_effect_expr_nondett(java_int_type()); results[0].add_source_location()=i_it->source_location; } - // if the statement is a nondet long + // if the statement is a nondet long else if(statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetLong:()J")) + statement, arg0, "java::org.cprover.CProver.nondetLong:()J")) { results.resize(1); results[0]=side_effect_expr_nondett(java_long_type()); results[0].add_source_location()=i_it->source_location; } - // if the statement is a nondet float + // if the statement is a nondet float else if(statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetFloat:()F")) + statement, arg0, "java::org.cprover.CProver.nondetFloat:()F")) { results.resize(1); results[0]=side_effect_expr_nondett(java_float_type()); results[0].add_source_location()=i_it->source_location; } - // if the statement is a nondet double + // if the statement is a nondet double else if(statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetDouble:()D")) + statement, arg0, "java::org.cprover.CProver.nondetDouble:()D")) { results.resize(1); results[0]=side_effect_expr_nondett(java_double_type()); results[0].add_source_location()=i_it->source_location; } - // To catch the return type of the nondet call, we have to check the - // next statement for an assignment. - // Check that the statement is static, with the correct signature. + // To catch the return type of the nondet call, we have to check the + // next statement for an assignment. + // Check that the statement is static, with the correct signature. else if(statement=="invokestatic" && has_prefix(id2string(arg0.get(ID_identifier)), "java::org.cprover.CProver.nondetWith")) diff --git a/src/util/std_code.cpp b/src/util/std_code.cpp index 8cc7979c4ac..8593323a85d 100644 --- a/src/util/std_code.cpp +++ b/src/util/std_code.cpp @@ -177,3 +177,93 @@ const codet &codet::last_statement() const return *this; } + +/*******************************************************************\ + +Function: nondet_initializer_blockt::nondet_initializer_blockt + + Inputs: `expr`: An expression to nondet-initialize. + `allow_null`: Whether or not the value may be null post-init. + + Outputs: + + Purpose: + +\*******************************************************************/ + +nondet_initializer_blockt::nondet_initializer_blockt( + const exprt &symbol_expr, + bool allow_null): + codet(ID_nondet_initializer_block) +{ + copy_to_operands(symbol_expr); + set_allow_null(allow_null); +} + +/*******************************************************************\ + +Function: nondet_initializer_blockt::statement_to_initialize + + Inputs: + + Outputs: A reference to the currently-stored expression. + + Purpose: + +\*******************************************************************/ + +const exprt &nondet_initializer_blockt::statement_to_initialize() const +{ + return op0(); +} + +/*******************************************************************\ + +Function: nondet_initializer_blockt::statement_to_initialize + + Inputs: + + Outputs: A reference to the currently-stored expression. + + Purpose: + +\*******************************************************************/ + +exprt &nondet_initializer_blockt::statement_to_initialize() +{ + return op0(); +} + +/*******************************************************************\ + +Function: nondet_initializer_blockt::set_allow_null + + Inputs: `b`: Whether or not the value may be null post-init. + + Outputs: + + Purpose: + +\*******************************************************************/ + +void nondet_initializer_blockt::set_allow_null(bool b) +{ + set(ID_nondet_allow_null, b); +} + +/*******************************************************************\ + +Function: nondet_initializer_blockt::get_allow_null + + Inputs: + + Outputs: Whether or not the value may be null post-init. + + Purpose: + +\*******************************************************************/ + +bool nondet_initializer_blockt::get_allow_null() const +{ + return get_bool(ID_nondet_allow_null); +} diff --git a/src/util/std_code.h b/src/util/std_code.h index cdaa5c6cd00..f1a99120b3f 100644 --- a/src/util/std_code.h +++ b/src/util/std_code.h @@ -347,34 +347,15 @@ inline code_assertt &to_code_assert(codet &code) class nondet_initializer_blockt:public codet { public: - inline nondet_initializer_blockt( - const exprt &symbol_expr, - bool allow_null): - codet(ID_nondet_initializer_block) - { - copy_to_operands(symbol_expr); - set_allow_null(allow_null); - } + nondet_initializer_blockt(const exprt &symbol_expr, bool allow_null); - inline const exprt &statement_to_initialize() const - { - return op0(); - } + const exprt &statement_to_initialize() const; - inline exprt &statement_to_initialize() - { - return op0(); - } + exprt &statement_to_initialize(); - inline void set_allow_null(bool b) - { - set(ID_nondet_allow_null, b); - } + void set_allow_null(bool b); - inline bool get_allow_null() const - { - return get_bool(ID_nondet_allow_null); - } + bool get_allow_null() const; }; static inline const nondet_initializer_blockt & @@ -1096,7 +1077,7 @@ class side_effect_expr_nondett:public side_effect_exprt static inline const side_effect_expr_nondett & to_side_effect_expr_nondet(const exprt &expr) { - const auto& x = to_side_effect_expr(expr); + const auto &x = to_side_effect_expr(expr); assert(x.get_statement() == ID_nondet); return static_cast(x); } @@ -1104,7 +1085,7 @@ static inline const side_effect_expr_nondett & static inline side_effect_expr_nondett & to_side_effect_expr_nondet(exprt &expr) { - auto& x = to_side_effect_expr(expr); + auto &x = to_side_effect_expr(expr); assert(x.get_statement() == ID_nondet); return static_cast(x); } From cc0c081f1c77d1042128c4f52cc8e087c46da230 Mon Sep 17 00:00:00 2001 From: reuk Date: Mon, 27 Feb 2017 09:49:57 +0000 Subject: [PATCH 26/39] Update CProver generic nondet signatures --- .../cbmc-java/nondetGenericArray/NondetGenericArray.java | 3 +-- .../nondetGenericRecursive/NondetGenericRecursive.java | 3 +-- .../nondetGenericRecursive2/NondetGenericRecursive2.java | 3 +-- .../nondetGenericWithNull/NondetGenericWithNull.java | 3 +-- .../NondetGenericWithoutNull.java | 3 +-- src/java_bytecode/library/src/org/cprover/CProver.java | 8 ++++++-- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java b/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java index ee31e9a1483..0b3d9e9d9e1 100644 --- a/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java +++ b/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java @@ -19,8 +19,7 @@ class NondetGenericArray { static void foo() { - C c = null; - CProver.nondetWithoutNull(c); + C c = CProver.nondetWithoutNull(); assert c.b.a != null; assert c.b.a.ints != null; } diff --git a/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java b/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java index 2f66827d4d8..39aab3b241f 100644 --- a/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java +++ b/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java @@ -18,8 +18,7 @@ class NondetGenericRecursive { static void foo() { - C c = null; - CProver.nondetWithNull(c); + C c = CProver.nondetWithNull(); assert c == null; } } diff --git a/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java b/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java index 6588f1f4a4f..f78822c8175 100644 --- a/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java +++ b/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java @@ -18,8 +18,7 @@ class NondetGenericRecursive2 { static void foo() { - C c = null; - CProver.nondetWithoutNull(c); + C c = CProver.nondetWithoutNull(); assert c.b.a != null; } } diff --git a/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java b/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java index ad8bebf349e..d7c4bdb993e 100644 --- a/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java +++ b/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java @@ -6,8 +6,7 @@ class NondetGenericWithNull { static void foo() { - B b = null; - CProver.nondetWithNull(b); + B b = CProver.nondetWithNull(); assert b != null; assert b.a != 0; } diff --git a/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java b/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java index cc0207b891b..99ea429cc4d 100644 --- a/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java +++ b/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java @@ -8,8 +8,7 @@ class NondetGenericWithoutNull { static void foo() { - C c = null; - CProver.nondetWithoutNull(c); + C c = CProver.nondetWithoutNull(); assert c != null; } } diff --git a/src/java_bytecode/library/src/org/cprover/CProver.java b/src/java_bytecode/library/src/org/cprover/CProver.java index 28690422fa9..1ac66f75b3e 100644 --- a/src/java_bytecode/library/src/org/cprover/CProver.java +++ b/src/java_bytecode/library/src/org/cprover/CProver.java @@ -94,24 +94,28 @@ public static double nondetDouble() } // Set a variable to a nondeterminate state, which may be null. - public static void nondetWithNull(T t) + public static T nondetWithNull() { if (enableNondet) { throw new RuntimeException( "Cannot execute program with CProver.nondetWithNull(T)"); } + + return null; } // Set a variable to a nondeterminate state, which must NOT be nullptr, but // reference fields of the object may be null. - public static void nondetWithoutNull(T t) + public static T nondetWithoutNull() { if (enableNondet) { throw new RuntimeException( "Cannot execute program with CProver.nondetWithoutNull(T)"); } + + return null; } public static void assume(boolean condition) From 679538781f520e4225c90820bf9b9bd8e867e11a Mon Sep 17 00:00:00 2001 From: reuk Date: Mon, 27 Feb 2017 16:06:59 +0000 Subject: [PATCH 27/39] Revert to init-in-place for generic nondet --- regression/cbmc-java/nondetBoolean/NondetBoolean.java | 10 +++++----- regression/cbmc-java/nondetByte/NondetByte.java | 10 +++++----- regression/cbmc-java/nondetChar/NondetChar.java | 10 +++++----- regression/cbmc-java/nondetDouble/NondetDouble.java | 10 +++++----- regression/cbmc-java/nondetFloat/NondetFloat.java | 10 +++++----- .../nondetGenericArray/NondetGenericArray.java | 3 ++- .../nondetGenericRecursive/NondetGenericRecursive.java | 3 ++- .../NondetGenericRecursive2.java | 3 ++- .../nondetGenericWithNull/NondetGenericWithNull.java | 3 ++- .../NondetGenericWithoutNull.java | 3 ++- regression/cbmc-java/nondetInt/NondetInt.java | 10 +++++----- regression/cbmc-java/nondetLong/NondetLong.java | 10 +++++----- regression/cbmc-java/nondetShort/NondetShort.java | 10 +++++----- src/java_bytecode/library/src/org/cprover/CProver.java | 8 ++------ 14 files changed, 52 insertions(+), 51 deletions(-) diff --git a/regression/cbmc-java/nondetBoolean/NondetBoolean.java b/regression/cbmc-java/nondetBoolean/NondetBoolean.java index 01cbd48d0aa..34ad5829237 100644 --- a/regression/cbmc-java/nondetBoolean/NondetBoolean.java +++ b/regression/cbmc-java/nondetBoolean/NondetBoolean.java @@ -2,9 +2,9 @@ class NondetBoolean { - static void foo() - { - boolean x = CProver.nondetBoolean(); - assert x == false; - } + static void foo() + { + boolean x = CProver.nondetBoolean(); + assert x == false; + } } diff --git a/regression/cbmc-java/nondetByte/NondetByte.java b/regression/cbmc-java/nondetByte/NondetByte.java index 2eaeaf21042..b300c9c3c5f 100644 --- a/regression/cbmc-java/nondetByte/NondetByte.java +++ b/regression/cbmc-java/nondetByte/NondetByte.java @@ -2,9 +2,9 @@ class NondetByte { - static void foo() - { - byte x = CProver.nondetByte(); - assert x == 0; - } + static void foo() + { + byte x = CProver.nondetByte(); + assert x == 0; + } } diff --git a/regression/cbmc-java/nondetChar/NondetChar.java b/regression/cbmc-java/nondetChar/NondetChar.java index 68a724462da..62de7d3eb66 100644 --- a/regression/cbmc-java/nondetChar/NondetChar.java +++ b/regression/cbmc-java/nondetChar/NondetChar.java @@ -2,9 +2,9 @@ class NondetChar { - static void foo() - { - char x = CProver.nondetChar(); - assert x == '\0'; - } + static void foo() + { + char x = CProver.nondetChar(); + assert x == '\0'; + } } diff --git a/regression/cbmc-java/nondetDouble/NondetDouble.java b/regression/cbmc-java/nondetDouble/NondetDouble.java index 545d8ef88bc..c431d52db1e 100644 --- a/regression/cbmc-java/nondetDouble/NondetDouble.java +++ b/regression/cbmc-java/nondetDouble/NondetDouble.java @@ -2,9 +2,9 @@ class NondetDouble { - static void foo() - { - double x = CProver.nondetDouble(); - assert x == 0; - } + static void foo() + { + double x = CProver.nondetDouble(); + assert x == 0; + } } diff --git a/regression/cbmc-java/nondetFloat/NondetFloat.java b/regression/cbmc-java/nondetFloat/NondetFloat.java index 5a471731a20..31a8241f51b 100644 --- a/regression/cbmc-java/nondetFloat/NondetFloat.java +++ b/regression/cbmc-java/nondetFloat/NondetFloat.java @@ -2,9 +2,9 @@ class NondetFloat { - static void foo() - { - float x = CProver.nondetFloat(); - assert x == 0; - } + static void foo() + { + float x = CProver.nondetFloat(); + assert x == 0; + } } diff --git a/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java b/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java index 0b3d9e9d9e1..ee31e9a1483 100644 --- a/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java +++ b/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java @@ -19,7 +19,8 @@ class NondetGenericArray { static void foo() { - C c = CProver.nondetWithoutNull(); + C c = null; + CProver.nondetWithoutNull(c); assert c.b.a != null; assert c.b.a.ints != null; } diff --git a/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java b/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java index 39aab3b241f..2f66827d4d8 100644 --- a/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java +++ b/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java @@ -18,7 +18,8 @@ class NondetGenericRecursive { static void foo() { - C c = CProver.nondetWithNull(); + C c = null; + CProver.nondetWithNull(c); assert c == null; } } diff --git a/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java b/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java index f78822c8175..6588f1f4a4f 100644 --- a/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java +++ b/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java @@ -18,7 +18,8 @@ class NondetGenericRecursive2 { static void foo() { - C c = CProver.nondetWithoutNull(); + C c = null; + CProver.nondetWithoutNull(c); assert c.b.a != null; } } diff --git a/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java b/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java index d7c4bdb993e..ad8bebf349e 100644 --- a/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java +++ b/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java @@ -6,7 +6,8 @@ class NondetGenericWithNull { static void foo() { - B b = CProver.nondetWithNull(); + B b = null; + CProver.nondetWithNull(b); assert b != null; assert b.a != 0; } diff --git a/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java b/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java index 99ea429cc4d..cc0207b891b 100644 --- a/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java +++ b/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java @@ -8,7 +8,8 @@ class NondetGenericWithoutNull { static void foo() { - C c = CProver.nondetWithoutNull(); + C c = null; + CProver.nondetWithoutNull(c); assert c != null; } } diff --git a/regression/cbmc-java/nondetInt/NondetInt.java b/regression/cbmc-java/nondetInt/NondetInt.java index a863b3e8789..4b2babdc4fa 100644 --- a/regression/cbmc-java/nondetInt/NondetInt.java +++ b/regression/cbmc-java/nondetInt/NondetInt.java @@ -2,9 +2,9 @@ class NondetInt { - static void foo() - { - int x = CProver.nondetInt(); - assert x == 0; - } + static void foo() + { + int x = CProver.nondetInt(); + assert x == 0; + } } diff --git a/regression/cbmc-java/nondetLong/NondetLong.java b/regression/cbmc-java/nondetLong/NondetLong.java index 3228a2d3fb3..1d2ebb98703 100644 --- a/regression/cbmc-java/nondetLong/NondetLong.java +++ b/regression/cbmc-java/nondetLong/NondetLong.java @@ -2,9 +2,9 @@ class NondetLong { - static void foo() - { - long x = CProver.nondetLong(); - assert x == 0; - } + static void foo() + { + long x = CProver.nondetLong(); + assert x == 0; + } } diff --git a/regression/cbmc-java/nondetShort/NondetShort.java b/regression/cbmc-java/nondetShort/NondetShort.java index c5685cc04c8..d54418e263c 100644 --- a/regression/cbmc-java/nondetShort/NondetShort.java +++ b/regression/cbmc-java/nondetShort/NondetShort.java @@ -2,9 +2,9 @@ class NondetShort { - static void foo() - { - short x = CProver.nondetShort(); - assert x == 0; - } + static void foo() + { + short x = CProver.nondetShort(); + assert x == 0; + } } diff --git a/src/java_bytecode/library/src/org/cprover/CProver.java b/src/java_bytecode/library/src/org/cprover/CProver.java index 1ac66f75b3e..28690422fa9 100644 --- a/src/java_bytecode/library/src/org/cprover/CProver.java +++ b/src/java_bytecode/library/src/org/cprover/CProver.java @@ -94,28 +94,24 @@ public static double nondetDouble() } // Set a variable to a nondeterminate state, which may be null. - public static T nondetWithNull() + public static void nondetWithNull(T t) { if (enableNondet) { throw new RuntimeException( "Cannot execute program with CProver.nondetWithNull(T)"); } - - return null; } // Set a variable to a nondeterminate state, which must NOT be nullptr, but // reference fields of the object may be null. - public static T nondetWithoutNull() + public static void nondetWithoutNull(T t) { if (enableNondet) { throw new RuntimeException( "Cannot execute program with CProver.nondetWithoutNull(T)"); } - - return null; } public static void assume(boolean condition) From 4348e9256666526275bd357e4acae1b51e57bc4b Mon Sep 17 00:00:00 2001 From: reuk Date: Mon, 27 Feb 2017 16:13:40 +0000 Subject: [PATCH 28/39] Fix formatting to comply with style guide --- src/java_bytecode/java_bytecode_convert_method.cpp | 2 +- src/java_bytecode/java_bytecode_typecheck_expr.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index dff6cb5690c..17fc9da5861 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -1018,7 +1018,7 @@ codet java_bytecode_convert_methodt::convert_instructions( assert(a_it!=address_map.end()); working_set.erase(cur); - if (a_it->second.done) + if(a_it->second.done) continue; working_set.insert( diff --git a/src/java_bytecode/java_bytecode_typecheck_expr.cpp b/src/java_bytecode/java_bytecode_typecheck_expr.cpp index 4e1aa8f6bea..59e4e96ee33 100644 --- a/src/java_bytecode/java_bytecode_typecheck_expr.cpp +++ b/src/java_bytecode/java_bytecode_typecheck_expr.cpp @@ -63,11 +63,11 @@ void java_bytecode_typecheckt::typecheck_expr(exprt &expr) { auto &side_effect_expr = to_side_effect_expr(expr); const irep_idt &statement = side_effect_expr.get_statement(); - if (statement == ID_java_new) + if(statement==ID_java_new) { typecheck_expr_java_new(side_effect_expr); } - else if (statement == ID_java_new_array) + else if(statement==ID_java_new_array) { typecheck_expr_java_new_array(side_effect_expr); } From a164d48ad6b4d0cd962e468ec43e5cb5f147cf9e Mon Sep 17 00:00:00 2001 From: reuk Date: Mon, 27 Feb 2017 16:42:52 +0000 Subject: [PATCH 29/39] Use classes compiled in debug mode --- src/java_bytecode/java_bytecode_convert_method.cpp | 10 +++++----- src/java_bytecode/java_bytecode_typecheck_code.cpp | 2 -- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index 17fc9da5861..9aec600240e 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -1037,8 +1037,8 @@ codet java_bytecode_convert_methodt::convert_instructions( "$stack")); irep_idt statement=i_it->statement; - exprt arg0 = i_it->args.size() >= 1 ? i_it->args[0] : nil_exprt(); - exprt arg1 = i_it->args.size() >= 2 ? i_it->args[1] : nil_exprt(); + exprt arg0=i_it->args.size()>=1?i_it->args[0]:nil_exprt(); + exprt arg1=i_it->args.size()>=2?i_it->args[1]:nil_exprt(); const bytecode_infot &bytecode_info=get_bytecode_info(statement); @@ -1212,8 +1212,6 @@ codet java_bytecode_convert_methodt::convert_instructions( results[0].add_source_location()=i_it->source_location; } - // To catch the return type of the nondet call, we have to check the - // next statement for an assignment. // Check that the statement is static, with the correct signature. else if(statement=="invokestatic" && has_prefix(id2string(arg0.get(ID_identifier)), @@ -1228,8 +1226,10 @@ codet java_bytecode_convert_methodt::convert_instructions( has_prefix(id2string(arg0.get(ID_identifier)), "java::org.cprover.CProver.nondetWithNull"); + const exprt operand=pop(1)[0]; c=nondet_initializer_blockt( - to_symbol_expr(to_typecast_expr(pop(1)[0]).op()), allow_null); + to_symbol_expr(to_typecast_expr(operand).op()), allow_null); + source_locationt loc=i_it->source_location; loc.set_function(method_id); c.add_source_location()=loc; diff --git a/src/java_bytecode/java_bytecode_typecheck_code.cpp b/src/java_bytecode/java_bytecode_typecheck_code.cpp index f3d5883a56a..1ab9ac4e764 100644 --- a/src/java_bytecode/java_bytecode_typecheck_code.cpp +++ b/src/java_bytecode/java_bytecode_typecheck_code.cpp @@ -33,8 +33,6 @@ void java_bytecode_typecheckt::typecheck_code(codet &code) { code_assignt &code_assign=to_code_assign(code); - // Now that we've (possibly) converted nondet calls into actual code, - // we can continue typechecking each side. typecheck_expr(code_assign.lhs()); typecheck_expr(code_assign.rhs()); From 8d46ad1cf6fac29bb67d2bae7ecfc5c2205ab1c7 Mon Sep 17 00:00:00 2001 From: reuk Date: Mon, 27 Feb 2017 18:01:39 +0000 Subject: [PATCH 30/39] Revert to better generic nodet signature --- .../cbmc-java/nondetAssume1/NondetAssume1.java | 11 +++++++++++ regression/cbmc-java/nondetAssume1/test.desc | 6 ++++++ .../cbmc-java/nondetAssume2/NondetAssume2.java | 17 +++++++++++++++++ regression/cbmc-java/nondetAssume2/test.desc | 6 ++++++ .../nondetGenericArray/NondetGenericArray.java | 3 +-- .../NondetGenericRecursive.java | 3 +-- .../NondetGenericRecursive2.java | 3 +-- .../NondetGenericWithNull.java | 3 +-- .../NondetGenericWithoutNull.java | 3 +-- .../library/src/org/cprover/CProver.java | 8 ++++++-- 10 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 regression/cbmc-java/nondetAssume1/NondetAssume1.java create mode 100644 regression/cbmc-java/nondetAssume1/test.desc create mode 100644 regression/cbmc-java/nondetAssume2/NondetAssume2.java create mode 100644 regression/cbmc-java/nondetAssume2/test.desc diff --git a/regression/cbmc-java/nondetAssume1/NondetAssume1.java b/regression/cbmc-java/nondetAssume1/NondetAssume1.java new file mode 100644 index 00000000000..2883e69dd08 --- /dev/null +++ b/regression/cbmc-java/nondetAssume1/NondetAssume1.java @@ -0,0 +1,11 @@ +import org.cprover.CProver; + +class NondetAssume1 +{ + void foo() + { + int x = CProver.nondetInt(); + CProver.assume(x == 1); + assert x == 1; + } +} diff --git a/regression/cbmc-java/nondetAssume1/test.desc b/regression/cbmc-java/nondetAssume1/test.desc new file mode 100644 index 00000000000..17e769ddad0 --- /dev/null +++ b/regression/cbmc-java/nondetAssume1/test.desc @@ -0,0 +1,6 @@ +CORE +NondetAssume1.class +--function NondetAssume1.foo +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/nondetAssume2/NondetAssume2.java b/regression/cbmc-java/nondetAssume2/NondetAssume2.java new file mode 100644 index 00000000000..ebff45ddd53 --- /dev/null +++ b/regression/cbmc-java/nondetAssume2/NondetAssume2.java @@ -0,0 +1,17 @@ +import org.cprover.CProver; + +class A { int x; } + +class B { A a; } + +class C { B b; } + +class NondetAssume2 +{ + void foo() + { + C c = CProver.nondetWithNull(); + CProver.assume(c != null); + assert c != null; + } +} diff --git a/regression/cbmc-java/nondetAssume2/test.desc b/regression/cbmc-java/nondetAssume2/test.desc new file mode 100644 index 00000000000..4b4f91eadc1 --- /dev/null +++ b/regression/cbmc-java/nondetAssume2/test.desc @@ -0,0 +1,6 @@ +CORE +NondetAssume2.class +--function NondetAssume2.foo +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java b/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java index ee31e9a1483..0b3d9e9d9e1 100644 --- a/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java +++ b/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java @@ -19,8 +19,7 @@ class NondetGenericArray { static void foo() { - C c = null; - CProver.nondetWithoutNull(c); + C c = CProver.nondetWithoutNull(); assert c.b.a != null; assert c.b.a.ints != null; } diff --git a/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java b/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java index 2f66827d4d8..39aab3b241f 100644 --- a/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java +++ b/regression/cbmc-java/nondetGenericRecursive/NondetGenericRecursive.java @@ -18,8 +18,7 @@ class NondetGenericRecursive { static void foo() { - C c = null; - CProver.nondetWithNull(c); + C c = CProver.nondetWithNull(); assert c == null; } } diff --git a/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java b/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java index 6588f1f4a4f..f78822c8175 100644 --- a/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java +++ b/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java @@ -18,8 +18,7 @@ class NondetGenericRecursive2 { static void foo() { - C c = null; - CProver.nondetWithoutNull(c); + C c = CProver.nondetWithoutNull(); assert c.b.a != null; } } diff --git a/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java b/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java index ad8bebf349e..d7c4bdb993e 100644 --- a/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java +++ b/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.java @@ -6,8 +6,7 @@ class NondetGenericWithNull { static void foo() { - B b = null; - CProver.nondetWithNull(b); + B b = CProver.nondetWithNull(); assert b != null; assert b.a != 0; } diff --git a/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java b/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java index cc0207b891b..99ea429cc4d 100644 --- a/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java +++ b/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java @@ -8,8 +8,7 @@ class NondetGenericWithoutNull { static void foo() { - C c = null; - CProver.nondetWithoutNull(c); + C c = CProver.nondetWithoutNull(); assert c != null; } } diff --git a/src/java_bytecode/library/src/org/cprover/CProver.java b/src/java_bytecode/library/src/org/cprover/CProver.java index 28690422fa9..1ac66f75b3e 100644 --- a/src/java_bytecode/library/src/org/cprover/CProver.java +++ b/src/java_bytecode/library/src/org/cprover/CProver.java @@ -94,24 +94,28 @@ public static double nondetDouble() } // Set a variable to a nondeterminate state, which may be null. - public static void nondetWithNull(T t) + public static T nondetWithNull() { if (enableNondet) { throw new RuntimeException( "Cannot execute program with CProver.nondetWithNull(T)"); } + + return null; } // Set a variable to a nondeterminate state, which must NOT be nullptr, but // reference fields of the object may be null. - public static void nondetWithoutNull(T t) + public static T nondetWithoutNull() { if (enableNondet) { throw new RuntimeException( "Cannot execute program with CProver.nondetWithoutNull(T)"); } + + return null; } public static void assume(boolean condition) From 01a575468f769ecb342c387fd3d075350a9afb74 Mon Sep 17 00:00:00 2001 From: reuk Date: Wed, 1 Mar 2017 15:39:48 +0000 Subject: [PATCH 31/39] Remove typechecking following nullable nondet call --- .../NondetGenericArray.java | 4 + .../NondetGenericRecursive2.java | 3 + .../nondetGenericWithoutNull/test.desc | 2 +- .../java_bytecode_convert_method.cpp | 167 +- .../java_bytecode_convert_method.cpp.orig | 2403 ----------------- 5 files changed, 147 insertions(+), 2432 deletions(-) delete mode 100644 src/java_bytecode/java_bytecode_convert_method.cpp.orig diff --git a/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java b/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java index 0b3d9e9d9e1..904027a7767 100644 --- a/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java +++ b/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java @@ -20,6 +20,10 @@ class NondetGenericArray static void foo() { C c = CProver.nondetWithoutNull(); + CProver.assume(c != null); + CProver.assume(c.b != null); + CProver.assume(c.b.a != null); + CProver.assume(c.b.a.ints != null); assert c.b.a != null; assert c.b.a.ints != null; } diff --git a/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java b/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java index f78822c8175..f5eed704366 100644 --- a/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java +++ b/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java @@ -19,6 +19,9 @@ class NondetGenericRecursive2 static void foo() { C c = CProver.nondetWithoutNull(); + CProver.assume(c != null); + CProver.assume(c.b != null); + CProver.assume(c.b.a != null); assert c.b.a != null; } } diff --git a/regression/cbmc-java/nondetGenericWithoutNull/test.desc b/regression/cbmc-java/nondetGenericWithoutNull/test.desc index 446d26face6..cf141f6d4bb 100644 --- a/regression/cbmc-java/nondetGenericWithoutNull/test.desc +++ b/regression/cbmc-java/nondetGenericWithoutNull/test.desc @@ -1,6 +1,6 @@ CORE NondetGenericWithoutNull.class --function NondetGenericWithoutNull.foo -^VERIFICATION SUCCESSFUL$ +^VERIFICATION FAILED$ -- ^warning: ignoring diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index 9aec600240e..0ef3bbe4ae6 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -33,6 +33,91 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include +#include + +/*******************************************************************\ + +Function: traverse_expr_tree + + Inputs: `expr`: an expression tree to traverse + `parents`: will hold previously-visited nodes + `func`: will be called on each node, takes the node and the `parents` + stack as arguments + + Outputs: None + + Purpose: Abstracts the process of calling a function on each node of the + expression tree. + +\*******************************************************************/ + +template +static void traverse_expr_tree( + exprt &expr, + std::vector &parents, + Func func) +{ + const auto& parents_ref=parents; + func(expr, parents_ref); + + parents.push_back(&expr); + for(auto &op : expr.operands()) + { + traverse_expr_tree(op, parents, func); + } + parents.pop_back(); +} + +/*******************************************************************\ + +Function: traverse_expr_tree + + Inputs: `expr`: an expression tree + + Outputs: None + + Purpose: Looks for a symbol node with identifier 'nondetWith(out?)Null'. + Finds the following statement, checks if it is an "assert", and + replaces it with a code_skipt if so. + +\*******************************************************************/ + +static void remove_assert_after_generic_nondet(exprt &expr) +{ + std::vector parents; + traverse_expr_tree( + expr, + parents, + [] (exprt &expr, const std::vector& parents) + { + const std::regex id_regex( + ".*org.cprover.CProver.(nondetWithNull|nondetWithoutNull).*"); + if(expr.id()==ID_symbol && + std::regex_match(as_string(to_symbol_expr(expr).get_identifier()), + id_regex)) + { + assert(2<=parents.size()); + const auto before_1=*(parents.end()-1); + const auto before_2=*(parents.end()-2); + + for(auto it=before_2->operands().begin(), + end=before_2->operands().end(); + it!=end; + ++it) + { + if(&(*it)==before_1) + { + assert(it+1!=end); + if((it+1)->id()==ID_code && + to_code(*(it+1)).get_statement()=="assert") + { + *(it+1)=code_skipt(); + } + } + } + } + }); +} class patternt { @@ -399,7 +484,11 @@ void java_bytecode_convert_methodt::convert( if((!m.is_abstract) && (!m.is_native)) method_symbol.value=convert_instructions(m, code_type); + remove_assert_after_generic_nondet(method_symbol.value); + // Replace the existing stub symbol with the real deal: + + // do we have the method symbol already? const auto s_it=symbol_table.symbols.find(method.get_name()); assert(s_it!=symbol_table.symbols.end()); symbol_table.symbols.erase(s_it); @@ -841,18 +930,6 @@ void java_bytecode_convert_methodt::check_static_field_stub( } } -/*******************************************************************\ - -Function: java_bytecode_convert_methodt::convert_instructions - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - static unsigned get_bytecode_type_width(const typet &ty) { if(ty.id()==ID_pointer) @@ -884,6 +961,18 @@ static bool statement_is_static_with_name( id2string(arg0.get(ID_identifier))==desired_name; } +/*******************************************************************\ + +Function: java_bytecode_convert_methodt::convert_instructions + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + codet java_bytecode_convert_methodt::convert_instructions( const methodt &method, const code_typet &method_type) @@ -1212,27 +1301,41 @@ codet java_bytecode_convert_methodt::convert_instructions( results[0].add_source_location()=i_it->source_location; } - // Check that the statement is static, with the correct signature. else if(statement=="invokestatic" && has_prefix(id2string(arg0.get(ID_identifier)), - "java::org.cprover.CProver.nondetWith")) - { - const code_typet &code_type=to_code_type(arg0.type()); - // Check function has the right number of args. - assert(code_type.parameters().size()==1); - - // Find whether the signature is for the nullable version or not. - const bool allow_null= - has_prefix(id2string(arg0.get(ID_identifier)), - "java::org.cprover.CProver.nondetWithNull"); - - const exprt operand=pop(1)[0]; - c=nondet_initializer_blockt( - to_symbol_expr(to_typecast_expr(operand).op()), allow_null); + "java::org.cprover.CProver.nondetWith") && + !working_set.empty()) + { + // Currently unused. + const auto working_set_begin=working_set.begin(); + const auto next_address=address_map.find(*working_set_begin); + assert(next_address!=address_map.end()); + + // Find the correct return type. + const auto next_source=next_address->second.source; + const auto next_statement=next_source->statement; + assert(next_statement=="checkcast"); + assert(next_source->args.size()>=1); + const auto return_type=pointer_typet(next_source->args[0].type()); + + // Reconstruct a function call with the correct return type. + code_function_callt call; source_locationt loc=i_it->source_location; loc.set_function(method_id); - c.add_source_location()=loc; + call.add_source_location()=loc; + call.function().add_source_location()=loc; + + // Update the pointed-to type. + auto func_type=arg0.type(); + to_code_type(func_type).return_type()=return_type; + + call.function()=symbol_exprt(arg0.get(ID_identifier), func_type); + call.lhs()=tmp_variable("return", return_type); + + results.resize(1); + results[0]=java_bytecode_promotion(call.lhs()); + c=call; } else if(statement=="invokeinterface" || @@ -2394,6 +2497,14 @@ void java_bytecode_convert_method( safe_pointer > needed_methods, safe_pointer > needed_classes) { + if(class_symbol.name=="org.cprover.CProver" && + (method.name=="nondetWithNull" || + method.name=="nondetWithoutNull")) + { + // Ignore these methods, rely on default stubbing behaviour. + return; + } + java_bytecode_convert_methodt java_bytecode_convert_method( symbol_table, message_handler, diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp.orig b/src/java_bytecode/java_bytecode_convert_method.cpp.orig deleted file mode 100644 index a07fdf74aed..00000000000 --- a/src/java_bytecode/java_bytecode_convert_method.cpp.orig +++ /dev/null @@ -1,2403 +0,0 @@ -/*******************************************************************\ - -Module: JAVA Bytecode Language Conversion - -Author: Daniel Kroening, kroening@kroening.com - -\*******************************************************************/ - -#ifdef DEBUG -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "bytecode_info.h" -#include "java_bytecode_convert_method.h" -#include "java_bytecode_convert_method_class.h" -#include "java_object_factory.h" -#include "java_opaque_method_stubs.h" -#include "java_types.h" - -#include -#include -#include -#include - -class patternt -{ -public: - explicit patternt(const char *_p):p(_p) - { - } - - // match with '?' - bool operator==(const irep_idt &what) const - { - for(std::size_t i=0; i or -bool java_bytecode_convert_methodt::is_constructor( - const class_typet::methodt &method) -{ - const std::string &name(id2string(method.get_name())); - const std::string::size_type &npos(std::string::npos); - return npos!=name.find("") || npos!=name.find(""); -} - -exprt::operandst java_bytecode_convert_methodt::pop(std::size_t n) -{ - if(stack.size()") - { - method_symbol.pretty_name= - id2string(class_symbol.pretty_name)+"."+ - id2string(class_symbol.base_name)+"()"; - member_type.set(ID_constructor, true); - } - else - method_symbol.pretty_name= - id2string(class_symbol.pretty_name)+"."+ - id2string(m.base_name)+"()"; - - // do we need to add 'this' as a parameter? - if(!m.is_static) - { - code_typet &code_type=to_code_type(member_type); - code_typet::parameterst ¶meters=code_type.parameters(); - code_typet::parametert this_p; - const reference_typet object_ref_type(symbol_typet(class_symbol.name)); - this_p.type()=object_ref_type; - this_p.set_this(); - parameters.insert(parameters.begin(), this_p); - } - - method_symbol.type=member_type; - symbol_table.add(method_symbol); -} - -/*******************************************************************\ - -Function: java_bytecode_convert_methodt::convert - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -void java_bytecode_convert_methodt::convert( - const symbolt &class_symbol, - const methodt &m) -{ - const irep_idt method_identifier= - id2string(class_symbol.name)+"."+id2string(m.name)+":"+m.signature; - method_id=method_identifier; - - const auto &old_sym=symbol_table.lookup(method_identifier); - - typet member_type=old_sym.type; - code_typet &code_type=to_code_type(member_type); - method_return_type=code_type.return_type(); - code_typet::parameterst ¶meters=code_type.parameters(); - - variables.clear(); - - // find parameter names in the local variable table: - for(const auto &v : m.local_variable_table) - { - if(v.start_pc!=0) // Local? - continue; - - typet t=java_type_from_string(v.signature); - std::ostringstream id_oss; - id_oss << method_id << "::" << v.name; - irep_idt identifier(id_oss.str()); - symbol_exprt result(identifier, t); - result.set(ID_C_base_name, v.name); - - variables[v.index].push_back(variablet()); - auto &newv=variables[v.index].back(); - newv.symbol_expr=result; - newv.start_pc=v.start_pc; - newv.length=v.length; - } - - // set up variables array - std::size_t param_index=0; - for(const auto ¶m : parameters) - { - variables[param_index].resize(1); - param_index+=get_variable_slots(param); - } - - // assign names to parameters - param_index=0; - for(auto ¶m : parameters) - { - irep_idt base_name, identifier; - - if(param_index==0 && param.get_this()) - { - base_name="this"; - identifier=id2string(method_identifier)+"::"+id2string(base_name); - param.set_base_name(base_name); - param.set_identifier(identifier); - } - else - { - // in the variable table? - base_name=variables[param_index][0].symbol_expr.get(ID_C_base_name); - identifier=variables[param_index][0].symbol_expr.get(ID_identifier); - - if(base_name.empty()) - { - const typet &type=param.type(); - char suffix=java_char_from_type(type); - base_name="arg"+std::to_string(param_index)+suffix; - identifier=id2string(method_identifier)+"::"+id2string(base_name); - } - - param.set_base_name(base_name); - param.set_identifier(identifier); - } - - // add to symbol table - parameter_symbolt parameter_symbol; - parameter_symbol.base_name=base_name; - parameter_symbol.mode=ID_java; - parameter_symbol.name=identifier; - parameter_symbol.type=param.type(); - symbol_table.add(parameter_symbol); - - // add as a JVM variable - std::size_t slots=get_variable_slots(param); - variables[param_index][0].symbol_expr=parameter_symbol.symbol_expr(); - variables[param_index][0].is_parameter=true; - variables[param_index][0].start_pc=0; - variables[param_index][0].length=std::numeric_limits::max(); - variables[param_index][0].is_parameter=true; - param_index+=slots; - assert(param_index>0); - } - - const bool is_virtual=!m.is_static && !m.is_final; - - #if 0 - class_type.methods().push_back(class_typet::methodt()); - class_typet::methodt &method=class_type.methods().back(); - #else - class_typet::methodt method; - #endif - - method.set_base_name(m.base_name); - method.set_name(method_identifier); - - method.set(ID_abstract, m.is_abstract); - method.set(ID_is_virtual, is_virtual); - - if(is_constructor(method)) - method.set(ID_constructor, true); - - method.type()=member_type; - - // we add the symbol for the method - - symbolt method_symbol; - - method_symbol.name=method.get_name(); - method_symbol.base_name=method.get_base_name(); - method_symbol.mode=ID_java; - method_symbol.location=m.source_location; - method_symbol.location.set_function(method_identifier); - - if(method.get_base_name()=="") - method_symbol.pretty_name=id2string(class_symbol.pretty_name)+"."+ - id2string(class_symbol.base_name)+"()"; - else - method_symbol.pretty_name=id2string(class_symbol.pretty_name)+"."+ - id2string(method.get_base_name())+"()"; - - method_symbol.type=member_type; - if(is_constructor(method)) - method_symbol.type.set(ID_constructor, true); - current_method=method_symbol.name; - method_has_this=code_type.has_this(); - - tmp_vars.clear(); - if((!m.is_abstract) && (!m.is_native)) - method_symbol.value=convert_instructions(m, code_type); - - // Replace the existing stub symbol with the real deal: - const auto s_it=symbol_table.symbols.find(method.get_name()); - assert(s_it!=symbol_table.symbols.end()); - symbol_table.symbols.erase(s_it); - - symbol_table.add(method_symbol); -} - -/*******************************************************************\ - -Function: java_bytecode_convert_methodt::get_bytecode_info - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -const bytecode_infot &java_bytecode_convert_methodt::get_bytecode_info( - const irep_idt &statement) -{ - for(const bytecode_infot *p=bytecode_info; p->mnemonic!=0; p++) - if(statement==p->mnemonic) - return *p; - - error() << "failed to find bytecode mnemonic `" - << statement << '\'' << eom; - throw 0; -} - -static irep_idt get_if_cmp_operator(const irep_idt &stmt) -{ - if(stmt==patternt("if_?cmplt")) - return ID_lt; - if(stmt==patternt("if_?cmple")) - return ID_le; - if(stmt==patternt("if_?cmpgt")) - return ID_gt; - if(stmt==patternt("if_?cmpge")) - return ID_ge; - if(stmt==patternt("if_?cmpeq")) - return ID_equal; - if(stmt==patternt("if_?cmpne")) - return ID_notequal; - - throw "unhandled java comparison instruction"; -} - -static member_exprt to_member(const exprt &pointer, const exprt &fieldref) -{ - symbol_typet class_type(fieldref.get(ID_class)); - - exprt pointer2= - typecast_exprt(pointer, pointer_typet(class_type)); - - const dereference_exprt obj_deref(pointer2, class_type); - - return member_exprt( - obj_deref, - fieldref.get(ID_component_name), - fieldref.type()); -} - -codet java_bytecode_convert_methodt::get_array_bounds_check( - const exprt &arraystruct, - const exprt &idx, - const source_locationt &original_sloc) -{ - constant_exprt intzero=from_integer(0, java_int_type()); - binary_relation_exprt gezero(idx, ID_ge, intzero); - const member_exprt length_field(arraystruct, "length", java_int_type()); - binary_relation_exprt ltlength(idx, ID_lt, length_field); - code_blockt bounds_checks; - - bounds_checks.add(code_assertt(gezero)); - bounds_checks.operands().back().add_source_location()=original_sloc; - bounds_checks.operands().back().add_source_location() - .set_comment("Array index < 0"); - bounds_checks.operands().back().add_source_location() - .set_property_class("array-index-out-of-bounds-low"); - bounds_checks.add(code_assertt(ltlength)); - - bounds_checks.operands().back().add_source_location()=original_sloc; - bounds_checks.operands().back().add_source_location() - .set_comment("Array index >= length"); - bounds_checks.operands().back().add_source_location() - .set_property_class("array-index-out-of-bounds-high"); - - // TODO make this throw ArrayIndexOutOfBoundsException instead of asserting. - return bounds_checks; -} - -/*******************************************************************\ - -Function: replace_goto_target - - Inputs: 'repl', a block of code in which to perform replacement, and - an old_label that should be replaced throughout by new_label. - - Outputs: None (side-effects on repl) - - Purpose: Find all goto statements in 'repl' that target 'old_label' - and redirect them to 'new_label'. - -\*******************************************************************/ - -void java_bytecode_convert_methodt::replace_goto_target( - codet &repl, - const irep_idt &old_label, - const irep_idt &new_label) -{ - const auto &stmt=repl.get_statement(); - if(stmt==ID_goto) - { - auto &g=to_code_goto(repl); - if(g.get_destination()==old_label) - g.set_destination(new_label); - } - else - { - for(auto &op : repl.operands()) - if(op.id()==ID_code) - replace_goto_target(to_code(op), old_label, new_label); - } -} - -/*******************************************************************\ - -Function: java_bytecode_convert_methodt::get_block_for_pcrange - - Inputs: 'tree', a code block descriptor, and 'this_block', the corresponding - actual code_blockt. 'address_start' and 'address_limit', the Java - bytecode offsets searched for. 'next_block_start_address', the - bytecode offset of tree/this_block's successor sibling, or UINT_MAX - if none exists. - - Outputs: Returns the code_blockt most closely enclosing the given address range. - - Purpose: 'tree' describes a tree of code_blockt objects; this_block is the - corresponding block (thus they are both trees with the same shape). - The caller is looking for the single block in the tree that most - closely encloses bytecode address range [address_start,address_limit). - 'next_block_start_address' is the start address of 'tree's successor - sibling and is used to determine when the range spans out of its bounds. - -\*******************************************************************/ - -code_blockt &java_bytecode_convert_methodt::get_block_for_pcrange( - block_tree_nodet &tree, - code_blockt &this_block, - unsigned address_start, - unsigned address_limit, - unsigned next_block_start_address) -{ - address_mapt dummy; - return get_or_create_block_for_pcrange( - tree, - this_block, - address_start, - address_limit, - next_block_start_address, - dummy, - false); -} - -/*******************************************************************\ - -Function: java_bytecode_convert_methodt::get_or_create_block_for_pcrange - - Inputs: See above, plus the bytecode address map 'amap' and 'allow_merge' - which is always true except when called from get_block_for_pcrange - - Outputs: See above, plus potential side-effects on 'tree' and 'this_block' - as descibed in 'Purpose' - - Purpose: As above, but this version can additionally create a new branch - in the block_tree-node and code_blockt trees to envelop the requested - address range. For example, if the tree was initially flat, with - nodes (1-10), (11-20), (21-30) and the caller asked for range 13-28, - this would build a surrounding tree node, leaving the tree of shape - (1-10), ^( (11-20), (21-30) )^, and return a reference to the - new branch highlighted with ^^. - 'tree' and 'this_block' trees are always maintained with equal - shapes. ('this_block' may additionally contain code_declt children - which are ignored for this purpose) - -\*******************************************************************/ - -code_blockt &java_bytecode_convert_methodt::get_or_create_block_for_pcrange( - block_tree_nodet &tree, - code_blockt &this_block, - unsigned address_start, - unsigned address_limit, - unsigned next_block_start_address, - const address_mapt &amap, - bool allow_merge) -{ - // Check the tree shape invariant: - assert(tree.branch.size()==tree.branch_addresses.size()); - - // If there are no child blocks, return this. - if(tree.leaf) - return this_block; - assert(!tree.branch.empty()); - - // Find child block starting > address_start: - const auto afterstart= - std::upper_bound( - tree.branch_addresses.begin(), - tree.branch_addresses.end(), - address_start); - assert(afterstart!=tree.branch_addresses.begin()); - auto findstart=afterstart; - --findstart; - auto child_offset= - std::distance(tree.branch_addresses.begin(), findstart); - - // Find child block starting >= address_limit: - auto findlim= - std::lower_bound( - tree.branch_addresses.begin(), - tree.branch_addresses.end(), - address_limit); - unsigned findlim_block_start_address= - findlim==tree.branch_addresses.end() ? - next_block_start_address : - (*findlim); - - // If all children are in scope, return this. - if(findstart==tree.branch_addresses.begin() && - findlim==tree.branch_addresses.end()) - return this_block; - - // Find the child code_blockt where the queried range begins: - auto child_iter=this_block.operands().begin(); - // Skip any top-of-block declarations; - // all other children are labelled subblocks. - while(child_iter!=this_block.operands().end() && - to_code(*child_iter).get_statement()==ID_decl) - ++child_iter; - assert(child_iter!=this_block.operands().end()); - std::advance(child_iter, child_offset); - assert(child_iter!=this_block.operands().end()); - auto &child_label=to_code_label(to_code(*child_iter)); - auto &child_block=to_code_block(child_label.code()); - - bool single_child(afterstart==findlim); - if(single_child) - { - // Range wholly contained within a child block - return get_or_create_block_for_pcrange( - tree.branch[child_offset], - child_block, - address_start, - address_limit, - findlim_block_start_address, - amap, - allow_merge); - } - - // Otherwise we're being asked for a range of subblocks, but not all of them. - // If it's legal to draw a new lexical scope around the requested subset, - // do so; otherwise just return this block. - - // This can be a new lexical scope if all incoming edges target the - // new block header, or come from within the suggested new block. - - // If modifying the block tree is forbidden, give up and return this: - if(!allow_merge) - return this_block; - - // Check for incoming control-flow edges targeting non-header - // blocks of the new proposed block range: - auto checkit=amap.find(*findstart); - assert(checkit!=amap.end()); - ++checkit; // Skip the header, which can have incoming edges from outside. - for(; - checkit!=amap.end() && (checkit->first)<(findlim_block_start_address); - ++checkit) - { - for(auto p : checkit->second.predecessors) - { - if(p<(*findstart) || p>=findlim_block_start_address) - { - debug() << "Warning: refusing to create lexical block spanning " - << (*findstart) << "-" << findlim_block_start_address - << " due to incoming edge " << p << " -> " - << checkit->first << eom; - return this_block; - } - } - } - - // All incoming edges are acceptable! Create a new block wrapping - // the relevant children. Borrow the header block's label, and redirect - // any block-internal edges to target the inner header block. - - const irep_idt child_label_name=child_label.get_label(); - std::string new_label_str=as_string(child_label_name); - new_label_str+='$'; - irep_idt new_label_irep(new_label_str); - - code_labelt newlabel(child_label_name, code_blockt()); - code_blockt &newblock=to_code_block(newlabel.code()); - auto nblocks=std::distance(findstart, findlim); - assert(nblocks>=2); - debug() << "Combining " << std::distance(findstart, findlim) - << " blocks for addresses " << (*findstart) << "-" - << findlim_block_start_address << eom; - - // Make a new block containing every child of interest: - auto &this_block_children=this_block.operands(); - assert(tree.branch.size()==this_block_children.size()); - for(auto blockidx=child_offset, blocklim=child_offset+nblocks; - blockidx!=blocklim; - ++blockidx) - newblock.move_to_operands(this_block_children[blockidx]); - - // Relabel the inner header: - to_code_label(to_code(newblock.operands()[0])).set_label(new_label_irep); - // Relabel internal gotos: - replace_goto_target(newblock, child_label_name, new_label_irep); - - // Remove the now-empty sibling blocks: - auto delfirst=this_block_children.begin(); - std::advance(delfirst, child_offset+1); - auto dellim=delfirst; - std::advance(dellim, nblocks-1); - this_block_children.erase(delfirst, dellim); - this_block_children[child_offset].swap(newlabel); - - // Perform the same transformation on the index tree: - block_tree_nodet newnode; - auto branchstart=tree.branch.begin(); - std::advance(branchstart, child_offset); - auto branchlim=branchstart; - std::advance(branchlim, nblocks); - for(auto branchiter=branchstart; branchiter!=branchlim; ++branchiter) - newnode.branch.push_back(std::move(*branchiter)); - ++branchstart; - tree.branch.erase(branchstart, branchlim); - - assert(tree.branch.size()==this_block_children.size()); - - auto branchaddriter=tree.branch_addresses.begin(); - std::advance(branchaddriter, child_offset); - auto branchaddrlim=branchaddriter; - std::advance(branchaddrlim, nblocks); - newnode.branch_addresses.insert( - newnode.branch_addresses.begin(), - branchaddriter, - branchaddrlim); - - ++branchaddriter; - tree.branch_addresses.erase(branchaddriter, branchaddrlim); - - tree.branch[child_offset]=std::move(newnode); - - assert(tree.branch.size()==tree.branch_addresses.size()); - - return - to_code_block( - to_code_label( - to_code(this_block_children[child_offset])).code()); -} - -static void gather_symbol_live_ranges( - unsigned pc, - const exprt &e, - std::map &result) -{ - if(e.id()==ID_symbol) - { - const auto &symexpr=to_symbol_expr(e); - auto findit= - result.insert({ // NOLINT(whitespace/braces) - symexpr.get_identifier(), - java_bytecode_convert_methodt::variablet()}); - auto &var=findit.first->second; - if(findit.second) - { - var.symbol_expr=symexpr; - var.start_pc=pc; - var.length=1; - } - else - { - if(pc targets; - - std::vector jsr_ret_targets; - std::vector ret_instructions; - - for(instructionst::const_iterator - i_it=instructions.begin(); - i_it!=instructions.end(); - i_it++) - { - converted_instructiont ins=converted_instructiont(i_it, code_skipt()); - std::pair a_entry= - address_map.insert(std::make_pair(i_it->address, ins)); - assert(a_entry.second); - // addresses are strictly increasing, hence we must have inserted - // a new maximal key - assert(a_entry.first==--address_map.end()); - - if(i_it->statement!="goto" && - i_it->statement!="return" && - !(i_it->statement==patternt("?return")) && - i_it->statement!="athrow" && - i_it->statement!="jsr" && - i_it->statement!="jsr_w" && - i_it->statement!="ret") - { - instructionst::const_iterator next=i_it; - if(++next!=instructions.end()) - a_entry.first->second.successors.push_back(next->address); - } - - if(i_it->statement=="goto" || - i_it->statement==patternt("if_?cmp??") || - i_it->statement==patternt("if??") || - i_it->statement=="ifnonnull" || - i_it->statement=="ifnull" || - i_it->statement=="jsr" || - i_it->statement=="jsr_w") - { - assert(!i_it->args.empty()); - - const unsigned target=safe_string2unsigned( - id2string(to_constant_expr(i_it->args[0]).get_value())); - targets.insert(target); - - a_entry.first->second.successors.push_back(target); - - if(i_it->statement=="jsr" || - i_it->statement=="jsr_w") - { - instructionst::const_iterator next=i_it+1; - assert( - next!=instructions.end() && - "jsr without valid return address?"); - targets.insert(next->address); - jsr_ret_targets.push_back(next->address); - } - } - else if(i_it->statement=="tableswitch" || - i_it->statement=="lookupswitch") - { - bool is_label=true; - for(const auto &arg : i_it->args) - { - if(is_label) - { - const unsigned target=safe_string2unsigned( - id2string(to_constant_expr(arg).get_value())); - targets.insert(target); - a_entry.first->second.successors.push_back(target); - } - is_label=!is_label; - } - } - else if(i_it->statement=="ret") - { - // Finish these later, once we've seen all jsr instructions. - ret_instructions.push_back(i_it); - } - } - - // Draw edges from every `ret` to every `jsr` successor. Could do better with - // flow analysis to distinguish multiple subroutines within the same function. - for(const auto retinst : ret_instructions) - { - auto &a_entry=address_map.at(retinst->address); - a_entry.successors.insert( - a_entry.successors.end(), - jsr_ret_targets.begin(), - jsr_ret_targets.end()); - } - - for(const auto &address : address_map) - { - for(unsigned s : address.second.successors) - { - address_mapt::iterator a_it=address_map.find(s); - assert(a_it!=address_map.end()); - - a_it->second.predecessors.insert(address.first); - } - } - - // Now that the control flow graph is built, set up our local variables - // (these require the graph to determine live ranges) - setup_local_variables(method, address_map); - - std::set working_set; - bool assertion_failure=false; - - if(!instructions.empty()) - working_set.insert(instructions.front().address); - - while(!working_set.empty()) - { - std::set::iterator cur = working_set.begin(); - address_mapt::iterator a_it = address_map.find(*cur); - assert(a_it != address_map.end()); - working_set.erase(cur); - - if (a_it->second.done) - { - continue; - } - - working_set.insert(a_it->second.successors.begin(), - a_it->second.successors.end()); - - instructionst::const_iterator i_it=a_it->second.source; - stack.swap(a_it->second.stack); - a_it->second.stack.clear(); - codet &c=a_it->second.code; - - assert( - stack.empty() || - a_it->second.predecessors.size()<=1 || - has_prefix( - stack.front().get_string(ID_C_base_name), - "$stack")); - - irep_idt statement=i_it->statement; - exprt arg0 = i_it->args.size() >= 1 ? i_it->args[0] : nil_exprt(); - exprt arg1 = i_it->args.size() >= 2 ? i_it->args[1] : nil_exprt(); - - const bytecode_infot &bytecode_info=get_bytecode_info(statement); - - // deal with _idx suffixes - if(statement.size()>=2 && - statement[statement.size()-2]=='_' && - isdigit(statement[statement.size()-1])) - { - arg0=constant_exprt( - std::string(id2string(statement), statement.size()-1, 1), - integer_typet()); - statement=std::string(id2string(statement), 0, statement.size()-2); - } - - exprt::operandst op=pop(bytecode_info.pop); - exprt::operandst results; - results.resize(bytecode_info.push, nil_exprt()); - - if(statement=="aconst_null") - { - assert(results.size()==1); - results[0]=null_pointer_exprt(java_reference_type(void_typet())); - } - else if(statement=="athrow") - { - assert(op.size()==1 && results.size()==1); - if(!assertion_failure) - { - side_effect_expr_throwt throw_expr; - throw_expr.add_source_location()=i_it->source_location; - throw_expr.copy_to_operands(op[0]); - c=code_expressiont(throw_expr); - results[0]=op[0]; - } - else - { - // TODO: this can be removed once we properly handle throw - // if this athrow is generated by an assertion, then skip it - c=code_skipt(); - assertion_failure=false; - } - } - else if(statement=="checkcast") - { - if(!disable_runtime_checks) - { - // checkcast throws an exception in case a cast of object - // on stack to given type fails. - // The stack isn't modified. - // TODO: convert assertions to exceptions. - assert(op.size()==1 && results.size()==1); - binary_predicate_exprt check(op[0], ID_java_instanceof, arg0); - c=code_assertt(check); - c.add_source_location().set_comment("Dynamic cast check"); - c.add_source_location().set_property_class("bad-dynamic-cast"); - results[0]=op[0]; - } - else - c=code_skipt(); - } - else if(statement=="invokedynamic") - { - // not used in Java - code_typet &code_type=to_code_type(arg0.type()); - const code_typet::parameterst ¶meters(code_type.parameters()); - - pop(parameters.size()); - - const typet &return_type=code_type.return_type(); - - if(return_type.id()!=ID_empty) - { - results.resize(1); - results[0]= - zero_initializer( - return_type, - i_it->source_location, - namespacet(symbol_table), - get_message_handler()); - } - } - - // replace calls to CProver.assume - else if (statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.assume:(Z)V")) - { - const code_typet &code_type = to_code_type(arg0.type()); - // sanity check: function has the right number of args - assert(code_type.parameters().size() == 1); - - exprt operand = pop(1)[0]; - // we may need to adjust the type of the argument - if (operand.type() != bool_typet()) - operand.make_typecast(bool_typet()); - - c = code_assumet(operand); - source_locationt loc = i_it->source_location; - loc.set_function(method_id); - c.add_source_location() = loc; - } - - // if the statement is a nondet boolean - else if (statement_is_static_with_name( - statement, arg0, - "java::org.cprover.CProver.nondetBoolean:()Z")) - { - results.resize(1); - results[0] = side_effect_expr_nondett(java_boolean_type()); - results[0].add_source_location() = i_it->source_location; - } - - // if the statement is a nondet byte - else if (statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetByte:()B")) - { - results.resize(1); - results[0] = side_effect_expr_nondett(java_byte_type()); - results[0].add_source_location() = i_it->source_location; - } - - // if the statement is a nondet char - else if (statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetChar:()C")) - { - results.resize(1); - results[0] = side_effect_expr_nondett(java_char_type()); - results[0].add_source_location() = i_it->source_location; - } - - // if the statement is a nondet short - else if (statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetShort:()S")) - { - results.resize(1); - results[0] = side_effect_expr_nondett(java_short_type()); - results[0].add_source_location() = i_it->source_location; - } - - // if the statement is a nondet int - else if (statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetInt:()I")) - { - results.resize(1); - results[0] = side_effect_expr_nondett(java_int_type()); - results[0].add_source_location() = i_it->source_location; - } - - // if the statement is a nondet long - else if (statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetLong:()J")) - { - results.resize(1); - results[0] = side_effect_expr_nondett(java_long_type()); - results[0].add_source_location() = i_it->source_location; - } - - // if the statement is a nondet float - else if (statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetFloat:()F")) - { - results.resize(1); - results[0] = side_effect_expr_nondett(java_float_type()); - results[0].add_source_location() = i_it->source_location; - } - - // if the statement is a nondet double - else if (statement_is_static_with_name( - statement, arg0, "java::org.cprover.CProver.nondetDouble:()D")) - { - results.resize(1); - results[0] = side_effect_expr_nondett(java_double_type()); - results[0].add_source_location() = i_it->source_location; - } - - // To catch the return type of the nondet call, we have to check the - // next statement for an assignment. - // Check that the statement is static, with the correct signature, and - // that the working set still has remaining items. - else if (!working_set.empty() && statement == "invokestatic" && - has_prefix(id2string(arg0.get(ID_identifier)), - "java::org.cprover.CProver.nondet:()L")) - { - // For the type search to succeed, the next instruction must be a - // checkcast. - // Find the next item in the working set, and look up that item in the - // address map. - address_mapt::iterator next_it = address_map.find(*working_set.begin()); - assert(next_it != address_map.end()); - - instructionst::const_iterator next_source_it = next_it->second.source; - - // Check that the statement is a checkcast with an argument of the - // correct type. - assert(next_source_it->statement == "checkcast"); - assert(next_source_it->args.size() >= 1); - assert(next_source_it->args[0].type().id() == ID_symbol); - const auto java_object_type = next_source_it->args[0].type(); - - // Create somewhere to store the result, and set the source location. - results.resize(1); - results[0].add_source_location() = i_it->source_location; - // Set the result to a nondet of the correct type. - results[0] = - side_effect_expr_nondett(java_reference_type(java_object_type)); - } - - else if(statement=="invokeinterface" || - statement=="invokespecial" || - statement=="invokevirtual" || - statement=="invokestatic") - { - // Remember that this is triggered by an assertion - if(statement=="invokespecial" && - id2string(arg0.get(ID_identifier)) - .find("AssertionError")!=std::string::npos) - { - assertion_failure=true; - } - const bool use_this(statement!="invokestatic"); - const bool is_virtual( - statement=="invokevirtual" || statement=="invokeinterface"); - - code_typet &code_type=to_code_type(arg0.type()); - code_typet::parameterst ¶meters(code_type.parameters()); - - if(use_this) - { - if(parameters.empty() || !parameters[0].get_this()) - { - irep_idt classname=arg0.get(ID_C_class); - typet thistype=symbol_typet(classname); - // Note invokespecial is used for super-method calls as well as - // constructors. - if(statement=="invokespecial") - { - if(as_string(arg0.get(ID_identifier)) - .find("")!=std::string::npos) - { - if(needed_classes) - needed_classes->insert(classname); - code_type.set(ID_constructor, true); - } - else - code_type.set(ID_java_super_method_call, true); - } - pointer_typet object_ref_type(thistype); - code_typet::parametert this_p(object_ref_type); - this_p.set_this(); - this_p.set_base_name("this"); - parameters.insert(parameters.begin(), this_p); - } - } - - code_function_callt call; - source_locationt loc=i_it->source_location; - loc.set_function(method_id); - - call.add_source_location()=loc; - call.arguments()=pop(parameters.size()); - - // double-check a bit - if(use_this) - { - const exprt &this_arg=call.arguments().front(); - assert(this_arg.type().id()==ID_pointer); - } - - // do some type adjustment for the arguments, - // as Java promotes arguments - // Also cast pointers since intermediate locals - // can be void*. - - for(std::size_t i=0; ipush_back(arg0.get(ID_identifier)); - } - - call.function().add_source_location()=loc; - c=call; - } - else if(statement=="return") - { - assert(op.empty() && results.empty()); - c=code_returnt(); - } - else if(statement==patternt("?return")) - { - // Return types are promoted in java, so this might need - // conversion. - assert(op.size()==1 && results.empty()); - exprt r=op[0]; - if(r.type()!=method_return_type) - r=typecast_exprt(r, method_return_type); - c=code_returnt(r); - } - else if(statement==patternt("?astore")) - { - assert(op.size()==3 && results.empty()); - - char type_char=statement[0]; - - exprt pointer= - typecast_exprt(op[0], java_array_type(type_char)); - - const dereference_exprt deref(pointer, pointer.type().subtype()); - - const member_exprt data_ptr( - deref, - "data", - pointer_typet(java_type_from_char(type_char))); - - plus_exprt data_plus_offset(data_ptr, op[1], data_ptr.type()); - typet element_type=data_ptr.type().subtype(); - const dereference_exprt element(data_plus_offset, element_type); - - c=code_blockt(); - if(!disable_runtime_checks) - { - codet bounds_check= - get_array_bounds_check(deref, op[1], i_it->source_location); - bounds_check.add_source_location()=i_it->source_location; - c.move_to_operands(bounds_check); - } - code_assignt array_put(element, op[2]); - array_put.add_source_location()=i_it->source_location; - c.move_to_operands(array_put); - c.add_source_location()=i_it->source_location; - } - else if(statement==patternt("?store")) - { - // store value into some local variable - assert(op.size()==1 && results.empty()); - - exprt var= - variable(arg0, statement[0], i_it->address, NO_CAST); - - exprt toassign=op[0]; - if('a'==statement[0] && toassign.type()!=var.type()) - toassign=typecast_exprt(toassign, var.type()); - - c=code_assignt(var, toassign); - } - else if(statement==patternt("?aload")) - { - assert(op.size()==2 && results.size()==1); - - char type_char=statement[0]; - - exprt pointer= - typecast_exprt(op[0], java_array_type(type_char)); - - const dereference_exprt deref(pointer, pointer.type().subtype()); - - const member_exprt data_ptr( - deref, - "data", - pointer_typet(java_type_from_char(type_char))); - - plus_exprt data_plus_offset(data_ptr, op[1], data_ptr.type()); - typet element_type=data_ptr.type().subtype(); - dereference_exprt element(data_plus_offset, element_type); - - if(!disable_runtime_checks) - { - c=get_array_bounds_check(deref, op[1], i_it->source_location); - c.add_source_location()=i_it->source_location; - } - results[0]=java_bytecode_promotion(element); - } - else if(statement==patternt("?load")) - { - // load a value from a local variable - results[0]= - variable(arg0, statement[0], i_it->address, CAST_AS_NEEDED); - } - else if(statement=="ldc" || statement=="ldc_w" || - statement=="ldc2" || statement=="ldc2_w") - { - assert(op.empty() && results.size()==1); - - // 1) Pushing a String causes a reference to a java.lang.String object - // to be constructed and pushed onto the operand stack. - - // 2) Pushing an int or a float causes a primitive value to be pushed - // onto the stack. - - // 3) Pushing a Class constant causes a reference to a java.lang.Class - // to be pushed onto the operand stack - - if(arg0.id()==ID_java_string_literal) - { - // these need to be references to java.lang.String - results[0]=arg0; - symbol_typet string_type("java::java.lang.String"); - results[0].type()=pointer_typet(string_type); - } - else if(arg0.id()==ID_type) - { - irep_idt class_id=arg0.type().get(ID_identifier); - symbol_typet java_lang_Class("java::java.lang.Class"); - symbol_exprt symbol_expr( - id2string(class_id)+"@class_model", - java_lang_Class); - address_of_exprt address_of_expr(symbol_expr); - results[0]=address_of_expr; - } - else if(arg0.id()==ID_constant) - { - results[0]=arg0; - } - else - { - error() << "unexpected ldc argument" << eom; - throw 0; - } - } - else if(statement=="goto" || statement=="goto_w") - { - assert(op.empty() && results.empty()); - irep_idt number=to_constant_expr(arg0).get_value(); - code_gotot code_goto(label(number)); - c=code_goto; - } - else if(statement=="jsr" || statement=="jsr_w") - { - // As 'goto', except we must also push the subroutine return address: - assert(op.empty() && results.size()==1); - irep_idt number=to_constant_expr(arg0).get_value(); - code_gotot code_goto(label(number)); - c=code_goto; - results[0]= - from_integer( - std::next(i_it)->address, - unsignedbv_typet(64)); - results[0].type()=pointer_typet(void_typet(), 64); - } - else if(statement=="ret") - { - // Since we have a bounded target set, make life easier on our analyses - // and write something like: - // if(retaddr==5) goto 5; else if(retaddr==10) goto 10; ... - assert(op.empty() && results.empty()); - c=code_blockt(); - auto retvar=variable(arg0, 'a', i_it->address, NO_CAST); - assert(!jsr_ret_targets.empty()); - for(size_t idx=0, idxlim=jsr_ret_targets.size(); idx!=idxlim; ++idx) - { - irep_idt number=std::to_string(jsr_ret_targets[idx]); - code_gotot g(label(number)); - g.add_source_location()=i_it->source_location; - if(idx==idxlim-1) - c.move_to_operands(g); - else - { - code_ifthenelset branch; - auto address_ptr= - from_integer( - jsr_ret_targets[idx], - unsignedbv_typet(64)); - address_ptr.type()=pointer_typet(void_typet(), 64); - branch.cond()=equal_exprt(retvar, address_ptr); - branch.cond().add_source_location()=i_it->source_location; - branch.then_case()=g; - branch.add_source_location()=i_it->source_location; - c.move_to_operands(branch); - } - } - } - else if(statement=="iconst_m1") - { - assert(results.size()==1); - results[0]=from_integer(-1, java_int_type()); - } - else if(statement==patternt("?const")) - { - assert(results.size()==1); - - const char type_char=statement[0]; - const bool is_double('d'==type_char); - const bool is_float('f'==type_char); - - if(is_double || is_float) - { - const ieee_float_spect spec( - is_float?ieee_float_spect::single_precision(): - ieee_float_spect::double_precision()); - - ieee_floatt value(spec); - const typet &arg_type(arg0.type()); - if(ID_integer==arg_type.id()) - value.from_integer(arg0.get_int(ID_value)); - else - value.from_expr(to_constant_expr(arg0)); - - results[0]=value.to_expr(); - } - else - { - const unsigned value(arg0.get_unsigned_int(ID_value)); - const typet type=java_type_from_char(statement[0]); - results[0]=from_integer(value, type); - } - } - else if(statement==patternt("?ipush")) - { - assert(results.size()==1); - results[0]=typecast_exprt(arg0, java_int_type()); - } - else if(statement==patternt("if_?cmp??")) - { - irep_idt number=to_constant_expr(arg0).get_value(); - assert(op.size()==2 && results.empty()); - - code_ifthenelset code_branch; - const irep_idt cmp_op=get_if_cmp_operator(statement); - - binary_relation_exprt condition(op[0], cmp_op, op[1]); - - exprt &lhs(condition.lhs()); - exprt &rhs(condition.rhs()); - const typet &lhs_type(lhs.type()); - if(lhs_type!=rhs.type()) - rhs=typecast_exprt(rhs, lhs_type); - - code_branch.cond()=condition; - code_branch.cond().add_source_location()=i_it->source_location; - code_branch.then_case()=code_gotot(label(number)); - code_branch.then_case().add_source_location()=i_it->source_location; - code_branch.add_source_location()=i_it->source_location; - - c=code_branch; - } - else if(statement==patternt("if??")) - { - const irep_idt id= - statement=="ifeq"?ID_equal: - statement=="ifne"?ID_notequal: - statement=="iflt"?ID_lt: - statement=="ifge"?ID_ge: - statement=="ifgt"?ID_gt: - statement=="ifle"?ID_le: - (assert(false), ""); - - irep_idt number=to_constant_expr(arg0).get_value(); - assert(op.size()==1 && results.empty()); - - code_ifthenelset code_branch; - code_branch.cond()= - binary_relation_exprt(op[0], id, from_integer(0, op[0].type())); - code_branch.cond().add_source_location()=i_it->source_location; - code_branch.cond().add_source_location().set_function(method_id); - code_branch.then_case()=code_gotot(label(number)); - code_branch.then_case().add_source_location()=i_it->source_location; - code_branch.then_case().add_source_location().set_function(method_id); - code_branch.add_source_location()=i_it->source_location; - code_branch.add_source_location().set_function(method_id); - - c=code_branch; - } - else if(statement==patternt("ifnonnull")) - { - irep_idt number=to_constant_expr(arg0).get_value(); - assert(op.size()==1 && results.empty()); - code_ifthenelset code_branch; - const typecast_exprt lhs(op[0], pointer_typet(empty_typet())); - const exprt rhs(null_pointer_exprt(to_pointer_type(lhs.type()))); - code_branch.cond()=binary_relation_exprt(lhs, ID_notequal, rhs); - code_branch.then_case()=code_gotot(label(number)); - code_branch.then_case().add_source_location()=i_it->source_location; - code_branch.add_source_location()=i_it->source_location; - - c=code_branch; - } - else if(statement==patternt("ifnull")) - { - assert(op.size()==1 && results.empty()); - irep_idt number=to_constant_expr(arg0).get_value(); - code_ifthenelset code_branch; - const typecast_exprt lhs(op[0], pointer_typet(empty_typet())); - const exprt rhs(null_pointer_exprt(to_pointer_type(lhs.type()))); - code_branch.cond()=binary_relation_exprt(lhs, ID_equal, rhs); - code_branch.then_case()=code_gotot(label(number)); - code_branch.then_case().add_source_location()=i_it->source_location; - code_branch.add_source_location()=i_it->source_location; - - c=code_branch; - } - else if(statement=="iinc") - { - code_assignt code_assign; - code_assign.lhs()= - variable(arg0, 'i', i_it->address, NO_CAST); - code_assign.rhs()=plus_exprt( - variable(arg0, 'i', i_it->address, CAST_AS_NEEDED), - typecast_exprt(arg1, java_int_type())); - c=code_assign; - } - else if(statement==patternt("?xor")) - { - assert(op.size()==2 && results.size()==1); - results[0]=bitxor_exprt(op[0], op[1]); - } - else if(statement==patternt("?or")) - { - assert(op.size()==2 && results.size()==1); - results[0]=bitor_exprt(op[0], op[1]); - } - else if(statement==patternt("?and")) - { - assert(op.size()==2 && results.size()==1); - results[0]=bitand_exprt(op[0], op[1]); - } - else if(statement==patternt("?shl")) - { - assert(op.size()==2 && results.size()==1); - results[0]=shl_exprt(op[0], op[1]); - } - else if(statement==patternt("?shr")) - { - assert(op.size()==2 && results.size()==1); - results[0]=ashr_exprt(op[0], op[1]); - } - else if(statement==patternt("?ushr")) - { - assert(op.size()==2 && results.size()==1); - const typet type=java_type_from_char(statement[0]); - - const std::size_t width=type.get_size_t(ID_width); - typet target=unsignedbv_typet(width); - - const typecast_exprt lhs(op[0], target); - const typecast_exprt rhs(op[1], target); - - results[0]=typecast_exprt(lshr_exprt(lhs, rhs), op[0].type()); - } - else if(statement==patternt("?add")) - { - assert(op.size()==2 && results.size()==1); - results[0]=plus_exprt(op[0], op[1]); - } - else if(statement==patternt("?sub")) - { - assert(op.size()==2 && results.size()==1); - results[0]=minus_exprt(op[0], op[1]); - } - else if(statement==patternt("?div")) - { - assert(op.size()==2 && results.size()==1); - results[0]=div_exprt(op[0], op[1]); - } - else if(statement==patternt("?mul")) - { - assert(op.size()==2 && results.size()==1); - results[0]=mult_exprt(op[0], op[1]); - } - else if(statement==patternt("?neg")) - { - assert(op.size()==1 && results.size()==1); - results[0]=unary_minus_exprt(op[0], op[0].type()); - } - else if(statement==patternt("?rem")) - { - assert(op.size()==2 && results.size()==1); - if(statement=="frem" || statement=="drem") - results[0]=rem_exprt(op[0], op[1]); - else - results[0]=mod_exprt(op[0], op[1]); - } - else if(statement==patternt("?cmp")) - { - assert(op.size()==2 && results.size()==1); - - // The integer result on the stack is: - // 0 if op[0] equals op[1] - // -1 if op[0] is less than op[1] - // 1 if op[0] is greater than op[1] - - const typet t=java_int_type(); - exprt one=from_integer(1, t); - exprt minus_one=from_integer(-1, t); - - if_exprt greater=if_exprt( - binary_relation_exprt(op[0], ID_gt, op[1]), - one, - minus_one); - - results[0]= - if_exprt( - binary_relation_exprt(op[0], ID_equal, op[1]), - from_integer(0, t), - greater); - } - else if(statement==patternt("?cmp?")) - { - assert(op.size()==2 && results.size()==1); - const floatbv_typet type( - to_floatbv_type(java_type_from_char(statement[0]))); - const ieee_float_spect spec(type); - const ieee_floatt nan(ieee_floatt::NaN(spec)); - const constant_exprt nan_expr(nan.to_expr()); - const int nan_value(statement[4]=='l' ? -1 : 1); - const typet result_type(java_int_type()); - const exprt nan_result(from_integer(nan_value, result_type)); - - // (value1 == NaN || value2 == NaN) ? - // nan_value : value1 < value2 ? -1 : value2 < value1 1 ? 1 : 0; - // (value1 == NaN || value2 == NaN) ? - // nan_value : value1 == value2 ? 0 : value1 < value2 -1 ? 1 : 0; - - exprt nan_op0=ieee_float_equal_exprt(nan_expr, op[0]); - exprt nan_op1=ieee_float_equal_exprt(nan_expr, op[1]); - exprt one=from_integer(1, result_type); - exprt minus_one=from_integer(-1, result_type); - results[0]= - if_exprt( - or_exprt(nan_op0, nan_op1), - nan_result, - if_exprt( - ieee_float_equal_exprt(op[0], op[1]), - from_integer(0, result_type), - if_exprt( - binary_relation_exprt(op[0], ID_lt, op[1]), - minus_one, - one))); - } - else if(statement==patternt("?cmpl")) - { - assert(op.size()==2 && results.size()==1); - results[0]=binary_relation_exprt(op[0], ID_lt, op[1]); - } - else if(statement=="dup") - { - assert(op.size()==1 && results.size()==2); - results[0]=results[1]=op[0]; - } - else if(statement=="dup_x1") - { - assert(op.size()==2 && results.size()==3); - results[0]=op[1]; - results[1]=op[0]; - results[2]=op[1]; - } - else if(statement=="dup_x2") - { - assert(op.size()==3 && results.size()==4); - results[0]=op[2]; - results[1]=op[0]; - results[2]=op[1]; - results[3]=op[2]; - } - // dup2* behaviour depends on the size of the operands on the - // stack - else if(statement=="dup2") - { - assert(!stack.empty() && results.empty()); - - if(get_bytecode_type_width(stack.back().type())==32) - op=pop(2); - else - op=pop(1); - - results.insert(results.end(), op.begin(), op.end()); - results.insert(results.end(), op.begin(), op.end()); - } - else if(statement=="dup2_x1") - { - assert(!stack.empty() && results.empty()); - - if(get_bytecode_type_width(stack.back().type())==32) - op=pop(3); - else - op=pop(2); - - results.insert(results.end(), op.begin()+1, op.end()); - results.insert(results.end(), op.begin(), op.end()); - } - else if(statement=="dup2_x2") - { - assert(!stack.empty() && results.empty()); - - if(get_bytecode_type_width(stack.back().type())==32) - op=pop(2); - else - op=pop(1); - - assert(!stack.empty()); - exprt::operandst op2; - - if(get_bytecode_type_width(stack.back().type())==32) - op2=pop(2); - else - op2=pop(1); - - results.insert(results.end(), op.begin(), op.end()); - results.insert(results.end(), op2.begin(), op2.end()); - results.insert(results.end(), op.begin(), op.end()); - } - else if(statement=="dconst") - { - assert(op.empty() && results.size()==1); - } - else if(statement=="fconst") - { - assert(op.empty() && results.size()==1); - } - else if(statement=="getfield") - { - assert(op.size()==1 && results.size()==1); - results[0]=java_bytecode_promotion(to_member(op[0], arg0)); - } - else if(statement=="getstatic") - { - assert(op.empty() && results.size()==1); - symbol_exprt symbol_expr(arg0.type()); - const auto &field_name=arg0.get_string(ID_component_name); - symbol_expr.set_identifier(arg0.get_string(ID_class)+"."+field_name); - if(needed_classes && arg0.type().id()==ID_symbol) - { - needed_classes->insert( - to_symbol_type(arg0.type()).get_identifier()); - } - results[0]=java_bytecode_promotion(symbol_expr); - - // set $assertionDisabled to false - if(field_name.find("$assertionsDisabled")!=std::string::npos) - c=code_assignt(symbol_expr, false_exprt()); - } - else if(statement=="putfield") - { - assert(op.size()==2 && results.size()==0); - c=code_assignt(to_member(op[0], arg0), op[1]); - } - else if(statement=="putstatic") - { - assert(op.size()==1 && results.empty()); - symbol_exprt symbol_expr(arg0.type()); - const auto &field_name=arg0.get_string(ID_component_name); - symbol_expr.set_identifier(arg0.get_string(ID_class)+"."+field_name); - if(needed_classes && arg0.type().id()==ID_symbol) - { - needed_classes->insert( - to_symbol_type(arg0.type()).get_identifier()); - } - c=code_assignt(symbol_expr, op[0]); - } - else if(statement==patternt("?2?")) // i2c etc. - { - assert(op.size()==1 && results.size()==1); - results[0]=typecast_exprt(op[0], java_type_from_char(statement[2])); - } - else if(statement=="new") - { - // use temporary since the stack symbol might get duplicated - assert(op.empty() && results.size()==1); - const pointer_typet ref_type(arg0.type()); - exprt java_new_expr=side_effect_exprt(ID_java_new, ref_type); - - if(!i_it->source_location.get_line().empty()) - java_new_expr.add_source_location()=i_it->source_location; - - const exprt tmp=tmp_variable("new", ref_type); - c=code_assignt(tmp, java_new_expr); - results[0]=tmp; - } - else if(statement=="newarray" || - statement=="anewarray") - { - // the op is the array size - assert(op.size()==1 && results.size()==1); - - char element_type; - - if(statement=="newarray") - { - irep_idt id=arg0.type().id(); - - if(id==ID_bool) - element_type='z'; - else if(id==ID_char) - element_type='c'; - else if(id==ID_float) - element_type='f'; - else if(id==ID_double) - element_type='d'; - else if(id==ID_byte) - element_type='b'; - else if(id==ID_short) - element_type='s'; - else if(id==ID_int) - element_type='i'; - else if(id==ID_long) - element_type='j'; - else - element_type='?'; - } - else - element_type='a'; - - const pointer_typet ref_type=java_array_type(element_type); - - side_effect_exprt java_new_array(ID_java_new_array, ref_type); - java_new_array.copy_to_operands(op[0]); - - if(!i_it->source_location.get_line().empty()) - java_new_array.add_source_location()=i_it->source_location; - - c=code_blockt(); - if(!disable_runtime_checks) - { - // TODO make this throw NegativeArrayIndexException instead. - constant_exprt intzero=from_integer(0, java_int_type()); - binary_relation_exprt gezero(op[0], ID_ge, intzero); - code_assertt check(gezero); - check.add_source_location().set_comment("Array size < 0"); - check.add_source_location() - .set_property_class("array-create-negative-size"); - c.move_to_operands(check); - } - if(max_array_length!=0) - { - constant_exprt size_limit= - from_integer(max_array_length, java_int_type()); - binary_relation_exprt le_max_size(op[0], ID_le, size_limit); - code_assumet assume_le_max_size(le_max_size); - c.move_to_operands(assume_le_max_size); - } - const exprt tmp=tmp_variable("newarray", ref_type); - c.copy_to_operands(code_assignt(tmp, java_new_array)); - results[0]=tmp; - } - else if(statement=="multianewarray") - { - // The first argument is the type, the second argument is the number of - // dimensions. The size of each dimension is on the stack. - irep_idt number=to_constant_expr(arg1).get_value(); - std::size_t dimension=safe_string2size_t(id2string(number)); - - op=pop(dimension); - assert(results.size()==1); - - const pointer_typet ref_type(arg0.type()); - - side_effect_exprt java_new_array(ID_java_new_array, ref_type); - java_new_array.operands()=op; - - if(!i_it->source_location.get_line().empty()) - java_new_array.add_source_location()=i_it->source_location; - - code_blockt checkandcreate; - if(!disable_runtime_checks) - { - // TODO make this throw NegativeArrayIndexException instead. - constant_exprt intzero=from_integer(0, java_int_type()); - binary_relation_exprt gezero(op[0], ID_ge, intzero); - code_assertt check(gezero); - check.add_source_location().set_comment("Array size < 0"); - check.add_source_location() - .set_property_class("array-create-negative-size"); - checkandcreate.move_to_operands(check); - - if(max_array_length!=0) - { - constant_exprt size_limit= - from_integer(max_array_length, java_int_type()); - binary_relation_exprt le_max_size(op[0], ID_le, size_limit); - code_assumet assume_le_max_size(le_max_size); - checkandcreate.move_to_operands(assume_le_max_size); - } - } - const exprt tmp=tmp_variable("newarray", ref_type); - c=code_assignt(tmp, java_new_array); - results[0]=tmp; - } - else if(statement=="arraylength") - { - assert(op.size()==1 && results.size()==1); - - exprt pointer= - typecast_exprt(op[0], java_array_type(statement[0])); - - const dereference_exprt array(pointer, pointer.type().subtype()); - assert(pointer.type().subtype().id()==ID_symbol); - - const member_exprt length(array, "length", java_int_type()); - - results[0]=length; - } - else if(statement=="tableswitch" || - statement=="lookupswitch") - { - assert(op.size()==1 && results.size()==0); - - // we turn into switch-case - code_switcht code_switch; - code_switch.add_source_location()=i_it->source_location; - code_switch.value()=op[0]; - code_blockt code_block; - code_block.add_source_location()=i_it->source_location; - - bool is_label=true; - for(instructiont::argst::const_iterator - a_it=i_it->args.begin(); - a_it!=i_it->args.end(); - a_it++, is_label=!is_label) - { - if(is_label) - { - code_switch_caset code_case; - code_case.add_source_location()=i_it->source_location; - - irep_idt number=to_constant_expr(*a_it).get_value(); - code_case.code()=code_gotot(label(number)); - code_case.code().add_source_location()=i_it->source_location; - - if(a_it==i_it->args.begin()) - code_case.set_default(); - else - { - instructiont::argst::const_iterator prev=a_it; - prev--; - code_case.case_op()=typecast_exprt(*prev, op[0].type()); - code_case.case_op().add_source_location()=i_it->source_location; - } - - code_block.add(code_case); - } - } - - code_switch.body()=code_block; - c=code_switch; - } - else if(statement=="pop" || statement=="pop2") - { - // these are skips - c=code_skipt(); - - // pop2 removes two single-word items from the stack (e.g. two - // integers, or an integer and an object reference) or one - // two-word item (i.e. a double or a long). - // http://cs.au.dk/~mis/dOvs/jvmspec/ref-pop2.html - if(statement=="pop2" && - get_bytecode_type_width(op[0].type())==32) - pop(1); - } - else if(statement=="instanceof") - { - assert(op.size()==1 && results.size()==1); - - results[0]= - binary_predicate_exprt(op[0], ID_java_instanceof, arg0); - } - else if(statement=="monitorenter") - { - // becomes a function call - code_typet type; - type.return_type()=void_typet(); - type.parameters().resize(1); - type.parameters()[0].type()=reference_typet(void_typet()); - code_function_callt call; - call.function()=symbol_exprt("java::monitorenter", type); - call.lhs().make_nil(); - call.arguments().push_back(op[0]); - call.add_source_location()=i_it->source_location; - c=call; - } - else if(statement=="monitorexit") - { - // becomes a function call - code_typet type; - type.return_type()=void_typet(); - type.parameters().resize(1); - type.parameters()[0].type()=reference_typet(void_typet()); - code_function_callt call; - call.function()=symbol_exprt("java::monitorexit", type); - call.lhs().make_nil(); - call.arguments().push_back(op[0]); - call.add_source_location()=i_it->source_location; - c=call; - } - else - { - c=codet(statement); - c.operands()=op; - } - - if(!i_it->source_location.get_line().empty()) - c.add_source_location()=i_it->source_location; - - push(results); - - a_it->second.done=true; - for(const unsigned address : a_it->second.successors) - { - address_mapt::iterator a_it2=address_map.find(address); - assert(a_it2!=address_map.end()); - - if(!stack.empty() && a_it2->second.predecessors.size()>1) - { - // copy into temporaries - code_blockt more_code; - - // introduce temporaries when successor is seen for the first - // time - if(a_it2->second.stack.empty()) - { - for(stackt::iterator s_it=stack.begin(); - s_it!=stack.end(); - ++s_it) - { - symbol_exprt lhs=tmp_variable("$stack", s_it->type()); - code_assignt a(lhs, *s_it); - more_code.copy_to_operands(a); - - s_it->swap(lhs); - } - } - else - { - assert(a_it2->second.stack.size()==stack.size()); - stackt::const_iterator os_it=a_it2->second.stack.begin(); - for(auto &expr : stack) - { - assert(has_prefix(os_it->get_string(ID_C_base_name), "$stack")); - symbol_exprt lhs=to_symbol_expr(*os_it); - code_assignt a(lhs, expr); - more_code.copy_to_operands(a); - - expr.swap(lhs); - ++os_it; - } - } - - if(results.empty()) - { - more_code.copy_to_operands(c); - c.swap(more_code); - } - else - { - c.make_block(); - auto &last_statement=to_code_block(c).find_last_statement(); - if(last_statement.get_statement()==ID_goto) - { - // Insert stack twiddling before branch: - last_statement.make_block(); - last_statement.operands().insert( - last_statement.operands().begin(), - more_code.operands().begin(), - more_code.operands().end()); - } - else - forall_operands(o_it, more_code) - c.copy_to_operands(*o_it); - } - } - - a_it2->second.stack=stack; - } - } - - // TODO: add exception handlers from exception table - // review successor computation of athrow! - code_blockt code; - - // Add anonymous locals to the symtab: - for(const auto &var : used_local_names) - { - symbolt new_symbol; - new_symbol.name=var.get_identifier(); - new_symbol.type=var.type(); - new_symbol.base_name=var.get(ID_C_base_name); - new_symbol.pretty_name=strip_java_namespace_prefix(var.get_identifier()); - new_symbol.mode=ID_java; - new_symbol.is_type=false; - new_symbol.is_file_local=true; - new_symbol.is_thread_local=true; - new_symbol.is_lvalue=true; - symbol_table.add(new_symbol); - } - - // Try to recover block structure as indicated in the local variable table: - - // The block tree node mirrors the block structure of root_block, - // indexing the Java PCs where each subblock starts and ends. - block_tree_nodet root; - code_blockt root_block; - - // First create a simple flat list of basic blocks. We'll add lexical nesting - // constructs as variable live-ranges require next. - bool start_new_block=true; - for(const auto &address_pair : address_map) - { - const unsigned address=address_pair.first; - assert(address_pair.first==address_pair.second.source->address); - const codet &c=address_pair.second.code; - - // Start a new lexical block if this is a branch target: - if(!start_new_block) - start_new_block=targets.find(address)!=targets.end(); - // Start a new lexical block if this is a control flow join - // (e.g. due to exceptional control flow) - if(!start_new_block) - start_new_block=address_pair.second.predecessors.size()>1; - - if(start_new_block) - { - code_labelt newlabel(label(std::to_string(address)), code_blockt()); - root_block.move_to_operands(newlabel); - root.branch.push_back(block_tree_nodet::get_leaf()); - assert((root.branch_addresses.size()==0 || - root.branch_addresses.back()1; - } - - // Find out where temporaries are used: - std::map temporary_variable_live_ranges; - for(const auto &aentry : address_map) - gather_symbol_live_ranges( - aentry.first, - aentry.second.code, - temporary_variable_live_ranges); - - std::vector vars_to_process; - for(const auto &vlist : variables) - for(const auto &v : vlist) - vars_to_process.push_back(&v); - - for(const auto &v : tmp_vars) - vars_to_process.push_back( - &temporary_variable_live_ranges.at(v.get_identifier())); - - for(const auto &v : used_local_names) - vars_to_process.push_back( - &temporary_variable_live_ranges.at(v.get_identifier())); - - for(const auto vp : vars_to_process) - { - const auto &v=*vp; - if(v.is_parameter) - continue; - // Merge lexical scopes as far as possible to allow us to - // declare these variable scopes faithfully. - // Don't insert yet, as for the time being the blocks' only - // operands must be other blocks. - // The declarations will be inserted in the next pass instead. - get_or_create_block_for_pcrange( - root, - root_block, - v.start_pc, - v.start_pc+v.length, - std::numeric_limits::max(), - address_map); - } - for(const auto vp : vars_to_process) - { - const auto &v=*vp; - if(v.is_parameter) - continue; - // Skip anonymous variables: - if(v.symbol_expr.get_identifier()==irep_idt()) - continue; - auto &block=get_block_for_pcrange( - root, - root_block, - v.start_pc, - v.start_pc+v.length, - std::numeric_limits::max()); - code_declt d(v.symbol_expr); - block.operands().insert(block.operands().begin(), d); - } - - for(auto &block : root_block.operands()) - code.move_to_operands(block); - - return code; -} - -/*******************************************************************\ - -Function: java_bytecode_convert_method - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -void java_bytecode_convert_method( - const symbolt &class_symbol, - const java_bytecode_parse_treet::methodt &method, - symbol_tablet &symbol_table, - message_handlert &message_handler, - bool disable_runtime_checks, - size_t max_array_length, - safe_pointer > needed_methods, - safe_pointer > needed_classes) -{ - java_bytecode_convert_methodt java_bytecode_convert_method( - symbol_table, - message_handler, - disable_runtime_checks, - max_array_length, - needed_methods, - needed_classes); - - java_bytecode_convert_method(class_symbol, method); -} From 2b6197d36edd27d8731869317fda34f49735d959 Mon Sep 17 00:00:00 2001 From: reuk Date: Wed, 1 Mar 2017 15:44:11 +0000 Subject: [PATCH 32/39] Remove tests using nondetWithoutNull These tests don't work as expected at the moment, because nondetWithoutNull has not been implemented yet. --- .../nondetGenericArray/NondetGenericArray.java | 2 +- .../NondetGenericRecursive2.java | 2 +- .../NondetGenericWithoutNull.java | 14 -------------- .../cbmc-java/nondetGenericWithoutNull/test.desc | 6 ------ .../library/src/org/cprover/CProver.java | 14 -------------- 5 files changed, 2 insertions(+), 36 deletions(-) delete mode 100644 regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java delete mode 100644 regression/cbmc-java/nondetGenericWithoutNull/test.desc diff --git a/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java b/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java index 904027a7767..d481494fe8b 100644 --- a/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java +++ b/regression/cbmc-java/nondetGenericArray/NondetGenericArray.java @@ -19,7 +19,7 @@ class NondetGenericArray { static void foo() { - C c = CProver.nondetWithoutNull(); + C c = CProver.nondetWithNull(); CProver.assume(c != null); CProver.assume(c.b != null); CProver.assume(c.b.a != null); diff --git a/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java b/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java index f5eed704366..4cb14e5945b 100644 --- a/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java +++ b/regression/cbmc-java/nondetGenericRecursive2/NondetGenericRecursive2.java @@ -18,7 +18,7 @@ class NondetGenericRecursive2 { static void foo() { - C c = CProver.nondetWithoutNull(); + C c = CProver.nondetWithNull(); CProver.assume(c != null); CProver.assume(c.b != null); CProver.assume(c.b.a != null); diff --git a/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java b/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java deleted file mode 100644 index 99ea429cc4d..00000000000 --- a/regression/cbmc-java/nondetGenericWithoutNull/NondetGenericWithoutNull.java +++ /dev/null @@ -1,14 +0,0 @@ -import org.cprover.CProver; - -class B { int a; } - -class C { B b; } - -class NondetGenericWithoutNull -{ - static void foo() - { - C c = CProver.nondetWithoutNull(); - assert c != null; - } -} diff --git a/regression/cbmc-java/nondetGenericWithoutNull/test.desc b/regression/cbmc-java/nondetGenericWithoutNull/test.desc deleted file mode 100644 index cf141f6d4bb..00000000000 --- a/regression/cbmc-java/nondetGenericWithoutNull/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -NondetGenericWithoutNull.class ---function NondetGenericWithoutNull.foo -^VERIFICATION FAILED$ --- -^warning: ignoring diff --git a/src/java_bytecode/library/src/org/cprover/CProver.java b/src/java_bytecode/library/src/org/cprover/CProver.java index 1ac66f75b3e..3780450a37d 100644 --- a/src/java_bytecode/library/src/org/cprover/CProver.java +++ b/src/java_bytecode/library/src/org/cprover/CProver.java @@ -93,7 +93,6 @@ public static double nondetDouble() return 0; } - // Set a variable to a nondeterminate state, which may be null. public static T nondetWithNull() { if (enableNondet) @@ -105,19 +104,6 @@ public static T nondetWithNull() return null; } - // Set a variable to a nondeterminate state, which must NOT be nullptr, but - // reference fields of the object may be null. - public static T nondetWithoutNull() - { - if (enableNondet) - { - throw new RuntimeException( - "Cannot execute program with CProver.nondetWithoutNull(T)"); - } - - return null; - } - public static void assume(boolean condition) { if(enableAssume) From 1d307e9f34657428ff74292d3680063a80daca0b Mon Sep 17 00:00:00 2001 From: reuk Date: Wed, 1 Mar 2017 16:40:37 +0000 Subject: [PATCH 33/39] Remove old, unused 'nondet block' code --- .../java_bytecode_typecheck_code.cpp | 28 ------ src/util/irep_ids.txt | 1 - src/util/std_code.cpp | 89 ------------------- src/util/std_code.h | 30 ------- 4 files changed, 148 deletions(-) diff --git a/src/java_bytecode/java_bytecode_typecheck_code.cpp b/src/java_bytecode/java_bytecode_typecheck_code.cpp index 1ab9ac4e764..7cc93a991a6 100644 --- a/src/java_bytecode/java_bytecode_typecheck_code.cpp +++ b/src/java_bytecode/java_bytecode_typecheck_code.cpp @@ -39,34 +39,6 @@ void java_bytecode_typecheckt::typecheck_code(codet &code) if(code_assign.lhs().type()!=code_assign.rhs().type()) code_assign.rhs().make_typecast(code_assign.lhs().type()); } - else if(statement==ID_nondet_initializer_block) - { - // Cast the expression to a 'nondet initializer block'. - const auto &nondet=to_nondet_initializer_block(code); - // Find the type of the nondet expression. - const auto &nondet_argument=nondet.statement_to_initialize(); - - // Create code to initialize the nondet object. - code_blockt init_code; - const auto output=object_factory( - nondet_argument.type(), - init_code, - nondet.get_allow_null(), - symbol_table, - max_nondet_array_length, - nondet_argument.source_location(), - get_message_handler()); - - // Create a new code block, containing the generated init_code, followed by - // the an assignment setting the passed variable to the newly-initialized - // value. - code_blockt new_code( - std::list{init_code, code_assignt(nondet_argument, output)}); - - // Replace the current code with the newly-created code, and typecheck it. - code=new_code; - typecheck_code(new_code); - } else if(statement==ID_block) { Forall_operands(it, to_code_block(code)) diff --git a/src/util/irep_ids.txt b/src/util/irep_ids.txt index d46feec5a15..37585ceba96 100644 --- a/src/util/irep_ids.txt +++ b/src/util/irep_ids.txt @@ -803,5 +803,4 @@ cprover_string_to_upper_case_func cprover_string_trim_func cprover_string_value_of_func basic_block_covered_lines -nondet_initializer_block nondet_allow_null diff --git a/src/util/std_code.cpp b/src/util/std_code.cpp index 8593323a85d..8bdf4521228 100644 --- a/src/util/std_code.cpp +++ b/src/util/std_code.cpp @@ -178,92 +178,3 @@ const codet &codet::last_statement() const return *this; } -/*******************************************************************\ - -Function: nondet_initializer_blockt::nondet_initializer_blockt - - Inputs: `expr`: An expression to nondet-initialize. - `allow_null`: Whether or not the value may be null post-init. - - Outputs: - - Purpose: - -\*******************************************************************/ - -nondet_initializer_blockt::nondet_initializer_blockt( - const exprt &symbol_expr, - bool allow_null): - codet(ID_nondet_initializer_block) -{ - copy_to_operands(symbol_expr); - set_allow_null(allow_null); -} - -/*******************************************************************\ - -Function: nondet_initializer_blockt::statement_to_initialize - - Inputs: - - Outputs: A reference to the currently-stored expression. - - Purpose: - -\*******************************************************************/ - -const exprt &nondet_initializer_blockt::statement_to_initialize() const -{ - return op0(); -} - -/*******************************************************************\ - -Function: nondet_initializer_blockt::statement_to_initialize - - Inputs: - - Outputs: A reference to the currently-stored expression. - - Purpose: - -\*******************************************************************/ - -exprt &nondet_initializer_blockt::statement_to_initialize() -{ - return op0(); -} - -/*******************************************************************\ - -Function: nondet_initializer_blockt::set_allow_null - - Inputs: `b`: Whether or not the value may be null post-init. - - Outputs: - - Purpose: - -\*******************************************************************/ - -void nondet_initializer_blockt::set_allow_null(bool b) -{ - set(ID_nondet_allow_null, b); -} - -/*******************************************************************\ - -Function: nondet_initializer_blockt::get_allow_null - - Inputs: - - Outputs: Whether or not the value may be null post-init. - - Purpose: - -\*******************************************************************/ - -bool nondet_initializer_blockt::get_allow_null() const -{ - return get_bool(ID_nondet_allow_null); -} diff --git a/src/util/std_code.h b/src/util/std_code.h index f1a99120b3f..cc98d57f641 100644 --- a/src/util/std_code.h +++ b/src/util/std_code.h @@ -342,36 +342,6 @@ inline code_assertt &to_code_assert(codet &code) return static_cast(code); } -/*! \brief A block of code which sets its parameter to a nondet value. - */ -class nondet_initializer_blockt:public codet -{ -public: - nondet_initializer_blockt(const exprt &symbol_expr, bool allow_null); - - const exprt &statement_to_initialize() const; - - exprt &statement_to_initialize(); - - void set_allow_null(bool b); - - bool get_allow_null() const; -}; - -static inline const nondet_initializer_blockt & - to_nondet_initializer_block(const codet &code) -{ - assert(code.get_statement()==ID_nondet_initializer_block); - return static_cast(code); -} - -static inline nondet_initializer_blockt & - to_nondet_initializer_block(codet &code) -{ - assert(code.get_statement()==ID_nondet_initializer_block); - return static_cast(code); -} - /*! \brief An if-then-else */ class code_ifthenelset:public codet From 96060b1ece123835cd64a955d8b3684752c9298b Mon Sep 17 00:00:00 2001 From: reuk Date: Thu, 2 Mar 2017 18:19:02 +0000 Subject: [PATCH 34/39] Fix build after patching --- .../cbmc-java/nondetAssume1/NondetAssume1.class | Bin 0 -> 721 bytes regression/cbmc-java/nondetAssume2/A.class | Bin 0 -> 256 bytes regression/cbmc-java/nondetAssume2/B.class | Bin 0 -> 258 bytes regression/cbmc-java/nondetAssume2/C.class | Bin 0 -> 258 bytes .../cbmc-java/nondetAssume2/NondetAssume2.class | Bin 0 -> 758 bytes .../nondetGenericArray/NondetGenericArray.class | Bin 839 -> 952 bytes .../NondetGenericRecursive2.class | Bin 736 -> 878 bytes .../cbmc-java/nondetGenericWithNull/B.class | Bin 266 -> 264 bytes .../NondetGenericWithNull.class | Bin 727 -> 771 bytes .../java_bytecode_convert_method.cpp | 1 - 10 files changed, 1 deletion(-) create mode 100644 regression/cbmc-java/nondetAssume1/NondetAssume1.class create mode 100644 regression/cbmc-java/nondetAssume2/A.class create mode 100644 regression/cbmc-java/nondetAssume2/B.class create mode 100644 regression/cbmc-java/nondetAssume2/C.class create mode 100644 regression/cbmc-java/nondetAssume2/NondetAssume2.class diff --git a/regression/cbmc-java/nondetAssume1/NondetAssume1.class b/regression/cbmc-java/nondetAssume1/NondetAssume1.class new file mode 100644 index 0000000000000000000000000000000000000000..e05127a4413390c0a7819b653a769525ff090d73 GIT binary patch literal 721 zcmZWnO>fgc5PfTJ;@EXan$i#&J_@9e7KDY=8xblBAXO>_si+dUZS1AExZY~*RQ#4+ z;Kmt{Xay47`ArBh>sYBO4m&%$GxOfO+5P?Z`%eJtxaYyel7}v?7<1KygKG}1d#GT^ z!Lo-Nxar^)!$MDFnbdi#((Fl`iE$z$1~y`-4&pSSGOe8JcG$FUI>a%xNx4?*-wZR!33?!^< zsc{B1Oen_Cj${^V8O@p@&H01^1Texfy^Kq5#+n_|K6y4Rk_Ltg&kaE^Rc)_ooS%M~hCt!mK!_Y>RGIPGJqY{39Ix3EVz~{RR9O%`X3dxgV&!K0)=D z0k;eA7C8A1*&2bm=uu~es67QMi8%eCi&!M`HpN`ne^6%|Y>|pC%{o{wdIRQL&NtMK X%LcxJ|1ZU$RABiVMsSA?7B2q-3xR|f literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetAssume2/A.class b/regression/cbmc-java/nondetAssume2/A.class new file mode 100644 index 0000000000000000000000000000000000000000..66636e271af6e2bf9d5f74a1c6b54f950067c43a GIT binary patch literal 256 zcmXX=I|{;35S%qJ(fIcSmTF-@>=Ypgf)KP&>|f$TpTq?65wB$>Sa<*rC2pd{?#|54 ze%_zw3%~?j3mRG`+9o;#x^b)s#!Q7OofEYFU{BB&(LoYgt_tNkyLd9*2`^x!>qfo^ z_99j}|BHHhQVEZ`&Xiznqb&C2QWf@f6dq*iBuRFW!~?8UnAu$OUU~Qc-5HcnFTI#2G0!u735j!G5V%4x9_S2d$Qf<;7?`0*i@Bki4+@XuP^PMyI zo;&Z)^95jnu8lGr3vCM>0trIdTTBV&Ohqc2v+NHJ1Y;E+CBgAjBsclhm&soEAv;|! z4n%kmiPE|-jqI#aowVd6dl%tAG$p@$Ox40oT3;?EETsSd literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetAssume2/C.class b/regression/cbmc-java/nondetAssume2/C.class new file mode 100644 index 0000000000000000000000000000000000000000..bbf6b9b7eaefdf0ebb7df435b7e489815784f53e GIT binary patch literal 258 zcmXX=%MQU%5IsY+)Y}(WVxfuH5eZGK8WzOoBZm_WH0=Xm7W&| zB0PvhY5o_D?5t9q3zf&aPc<%lu#V5BRJm zZqY=2(!{^X7{6Nx%k-f=Kkj$FbG~za{rUVAzy=%(78WgB#WfSxwOuNrfEy-mTF7J3 z#4QWUSTV6GP+xZASgOR2!uXLNyTd?^1jIlfzv+j5@<1TlYVQab-Do5QDm_1x{qez2 zsuvn8Q0qmW8|=8s*YPxIBzu0W(fueK$>d=ij}PR%`y_iEMdbJB^}3A9+llMFdFmdf zg`8KQu;~TU*4B13R-Sy~r;W~Wt?#=>u8lJ0Ox(87LYuT*8*Av;D8UwJYJ?NG;jY8} z6OE6RiWIw^qcU;F#$BunRL@GD4fmy&a6ysUb-Y6r9ZBVMpQlz}E=+a3^pm~*I0yt9 zt#>NyHw8gwFY{Nl`~8?;G4k0NXEXBquGdDNHXRF*FL}!4`=bJqT1A==wHI|L3-Yf{V1Co=*_6EogMJw%nd%&4g<0KcVZt`;#9QJ5a{?FnRzmhSDkhp+ nqCriUWkinI|N3xG& literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetGenericArray/NondetGenericArray.class b/regression/cbmc-java/nondetGenericArray/NondetGenericArray.class index bbf6914a096c04e4059e4b9327be44ae2de7940c..d0aa1cbfaeffb9b557561359e9cbae334c41d6b4 100644 GIT binary patch literal 952 zcmZWn?M@Rx6g|_HPP<*8w0x8Tq7}8RO8vl3sN_e;K-=+WE4Tn zMR5wJqd0?X6fxvD@*1L;ZMda-HTKt7+72(O_Wf4B?{XSl(@h zU^chL5URKh!7yC498qg+*M)qdk{J?J*EH-kLt4u321DMa)npj0)?B9{y!*lt(lX0Z z8m|_q;tSWMCMH?c3i*Spo?*UxXzciC;=m9ons&Fpw(7Q|DehUS+eClC`7NVu=!j#4 zqoCsgE>i7^j!U?#lR8&8uIjjk>l`<9+{B`eAq+F56s%wy&PJj9UxK?*x{@gMH{mGi zxCN3Uet>&a-x8)rBD!*;VD3n_Eo7nc*gqMD9H0AB%iFBAY@5``=Bh`*#6CQ1Cq>yBJegO8$Y^XGEXvLHp{*Q{6a0 z4qd6CgZ|JN8V)ohrxBA#A%jW!3Tdoh3I?X}8Z$jY9Bs;&r2I6kF=)Rr%rRABgC!O( rv1Ey*(^PJ{$92JH3XCLTAEEDdiGDz&Uo=&500F(Eq@5urfMb6Fr7yQL delta 543 zcmZXRO-~b16o#KW)AlmMRcN75%BSK76mS%Z0*wi#3lVjWD zSeWn!T&oQbOk_#oA8^56A%rudb|H&%&wK8BKHhWhnZ8UEe%+k^1o9MI+8J~iV%Wi9 z#Nh!C9Y%SidF+y4(BTPBHDfO0*-$q`MtVW&Ix9cBkyYvs`mHt_j;si(GZU&5 zWQ&P-WUL@hyb>SJoua-9ut>_8h%Qs41e-qzbkQwQ8|hZ@fn2mm~^g5 ztV#Tm_8%lRP8;Zph{*gUnza4ngbGL6(a0X+f_tQ8uZ+*gpY+M=WLpv}=7jB)oQ#-* tb1weY0tE$LtEFj?sw`^_e&&FBsOYG*bx#ISYYiZh;%1bHe%@#gaj)R z@gw{Kzd*z{C5^=5o9}(+yz|X-<~{J?PP~5IJphA@c^GOv>ZsQ=*xnezp(#W&Eg?Kw zHEkY2YBlX19i%j!hv{S0aQHUX8X>CbGIZ0UP}7Dqy@o#eH3LSb4;hLm&Lz}{J8T$X zG&iq0!^K}{?o{OwB}^D<~f;bf=AMNLU9TQ`|IQ$za} z7F0BD$BJ^KgaJiNR9d={9!TAw&PDhrk=4y_#wZnSegc$HE-pw#;qZy1?cupwd`~#D zsb{qR6u)zeKXpaG+WkNN3inUq0)0fe&B^`?;d_FMH-sK7g_Ea93I}qlmOD$Sq>;Eh zP=YMU0-0t;zQiS$kcy!{iD;4;Rg_WDj7nyOxT-)rnCF#TiFZx-=oj}A{r}hPxBxzr Lu@6)&#z)OJqsKov delta 362 zcmX|-yGjE=6o$Xq+iW)L=3=tuViNC{q!1(^TBu-YXCqoGXp=M%OP?WZ7woMpR8Ub+ zJHc15@d+%fMLfG=io=|r^UwF6nNR1#UV8g^cmmqAJW^CW#;IxQDKrhugojO4GwCtK zv}UHiey-~M_tk>Wh-TJjj(LUJ^6^MVYih+=@L8l8ovK!l>vTH@hrQk7-ck3Y7hS4a z^re;smy$%4EyZ`FGo=KFB8WDO@GK+R5d}H2$t><|QF%FCM*qCh?_(ss%00#l=Jqw# zfK2n1^dt7(9nSNWxJ+VVkmMBQT_I)0hGZ?g0!49zQZ8!eo3a*zOKBL?PGV%CyuQU9 cpsfom^9C#C8wvk^R_56&BW+AQT`kw^Tc;D04k*gD*ylh delta 19 acmeBR>SCH8&BE;CXgyK(93$(*H!=V-qXn!0 diff --git a/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.class b/regression/cbmc-java/nondetGenericWithNull/NondetGenericWithNull.class index 7b9929260ea83e8ce6e3aa61dd5c47c3bfbf2301..7f80aedd94127faba480ce67542da6c70aa5561f 100644 GIT binary patch delta 413 zcmYL_xk>|36o$V$Gnt!AMza`WHjVodHDfVgtAd5t2v(LUM3j&~5^ODef{-qqm9+~h z3Th|h1$+%3K*W>LXmJl`|G#tJL+7^N`+9r^d^`t-g2Olynqq`7lbR`q5QPXP)0!EF zS>`nJZLh0}?cTaS#IR<;WsxO?+H#5FDl#XP(~4KE)Q-H(X7jMoINk$|J zlltiuzl9Ohya$X|%-w6OF0s-Z(I-L&_t-B%CRw^gcmI=DGHTM7Nn(kOpam%_IAsy5 z4m7nKJW5&`#)2l}ldL9_5`^p@f*$}tA{o9T(nVXBSmq5@U&IJR2DkLLgfQF<`3Z7C GIsXm&WHQtM delta 365 zcmZXPyH3ME5Jk`WwTZptMS$3b@P3&h60(Fug=i_M$j_wU3nF*^0qPJz5J*5pK|{&U zAjGT@X()E*?&{9DGuOeVKY0Isdf5E2!MN{dsK1P6vgvSO$%i#v5Z(n1E+>RFR0SB~_fXowm}RZ{(I zhMI_QXv!T_pPH6v^J}0@M_x4+=gmWL+vel}=N0$j7O$k4y%9a(U(ENU&NXf3F^&*@+t<}9eq!&M0+=Q?iBC;#1`V?m@~Uq44%xG F`~V)ZBD??q diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index 0ef3bbe4ae6..0a2db850a42 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -26,7 +26,6 @@ Author: Daniel Kroening, kroening@kroening.com #include "java_bytecode_convert_method.h" #include "java_bytecode_convert_method_class.h" #include "java_object_factory.h" -#include "java_opaque_method_stubs.h" #include "java_types.h" #include From 8dd731b52f1cbf8f1ab64b1fa123dc43578b689b Mon Sep 17 00:00:00 2001 From: reuk Date: Thu, 2 Mar 2017 21:06:27 +0000 Subject: [PATCH 35/39] Use regex to test nondet method name --- .../java_bytecode_convert_method.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index 0a2db850a42..6293a8cac87 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -483,6 +483,10 @@ void java_bytecode_convert_methodt::convert( if((!m.is_abstract) && (!m.is_native)) method_symbol.value=convert_instructions(m, code_type); +#ifdef DEBUG + std::cerr << method_symbol.value.pretty() << '\n'; +#endif + remove_assert_after_generic_nondet(method_symbol.value); // Replace the existing stub symbol with the real deal: @@ -1300,12 +1304,14 @@ codet java_bytecode_convert_methodt::convert_instructions( results[0].add_source_location()=i_it->source_location; } - else if(statement=="invokestatic" && - has_prefix(id2string(arg0.get(ID_identifier)), - "java::org.cprover.CProver.nondetWith") && - !working_set.empty()) + else if( + statement=="invokestatic" && + std::regex_match( + id2string(arg0.get(ID_identifier)), + std::regex( + ".*org.cprover.CProver.(nondetWithNull|nondetWithoutNull).*")) && + !working_set.empty()) { - // Currently unused. const auto working_set_begin=working_set.begin(); const auto next_address=address_map.find(*working_set_begin); assert(next_address!=address_map.end()); From 2fe55a38a50baff1684a745472e23da65833adfd Mon Sep 17 00:00:00 2001 From: reuk Date: Mon, 6 Mar 2017 09:47:00 +0000 Subject: [PATCH 36/39] Fix breakage introduced during rebase --- src/java_bytecode/java_bytecode_convert_method.cpp | 4 ---- src/java_bytecode/java_bytecode_language.cpp | 3 ++- src/java_bytecode/java_bytecode_typecheck.h | 4 +++- src/java_bytecode/java_bytecode_typecheck_expr.cpp | 11 ----------- 4 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index 6293a8cac87..6bce7bd4792 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -483,10 +483,6 @@ void java_bytecode_convert_methodt::convert( if((!m.is_abstract) && (!m.is_native)) method_symbol.value=convert_instructions(m, code_type); -#ifdef DEBUG - std::cerr << method_symbol.value.pretty() << '\n'; -#endif - remove_assert_after_generic_nondet(method_symbol.value); // Replace the existing stub symbol with the real deal: diff --git a/src/java_bytecode/java_bytecode_language.cpp b/src/java_bytecode/java_bytecode_language.cpp index 16f541c4fcc..eb6d81c42a9 100644 --- a/src/java_bytecode/java_bytecode_language.cpp +++ b/src/java_bytecode/java_bytecode_language.cpp @@ -494,7 +494,8 @@ bool java_bytecode_languaget::typecheck( disable_runtime_checks, max_user_array_length, lazy_methods, - lazy_methods_mode)) + lazy_methods_mode, + string_refinement_enabled)) return true; } diff --git a/src/java_bytecode/java_bytecode_typecheck.h b/src/java_bytecode/java_bytecode_typecheck.h index 74efbb4cf41..ce5c8b4fabe 100644 --- a/src/java_bytecode/java_bytecode_typecheck.h +++ b/src/java_bytecode/java_bytecode_typecheck.h @@ -21,7 +21,8 @@ Author: Daniel Kroening, kroening@kroening.com bool java_bytecode_typecheck( symbol_tablet &symbol_table, - message_handlert &message_handler); + message_handlert &message_handler, + bool string_refinement_enabled); bool java_bytecode_typecheck( exprt &expr, @@ -50,6 +51,7 @@ class java_bytecode_typecheckt:public typecheckt protected: symbol_tablet &symbol_table; const namespacet ns; + bool string_refinement_enabled; void typecheck_type_symbol(symbolt &); void typecheck_non_type_symbol(symbolt &); diff --git a/src/java_bytecode/java_bytecode_typecheck_expr.cpp b/src/java_bytecode/java_bytecode_typecheck_expr.cpp index 59e4e96ee33..49345b6d680 100644 --- a/src/java_bytecode/java_bytecode_typecheck_expr.cpp +++ b/src/java_bytecode/java_bytecode_typecheck_expr.cpp @@ -22,17 +22,6 @@ Author: Daniel Kroening, kroening@kroening.com #include "java_pointer_casts.h" #include "java_types.h" -java_bytecode_typecheckt::java_bytecode_typecheckt( - symbol_tablet &_symbol_table, - message_handlert &_message_handler, - size_t _max_nondet_array_length) - : typecheckt(_message_handler), - symbol_table(_symbol_table), - ns(symbol_table), - max_nondet_array_length(_max_nondet_array_length) -{ -} - /*******************************************************************\ Function: java_bytecode_typecheckt::typecheck_expr From 67697aaaad2a15b4a096f2952009ecf18e0890a8 Mon Sep 17 00:00:00 2001 From: reuk Date: Wed, 8 Mar 2017 14:04:06 +0000 Subject: [PATCH 37/39] Implement style fixes based on feedback --- .../java_bytecode_convert_method.cpp | 72 +++++++----------- src/java_bytecode/java_bytecode_typecheck.h | 2 +- .../java_bytecode_typecheck_expr.cpp | 4 +- .../library/target/org/cprover/CProver.class | Bin 0 -> 1957 bytes src/util/expr_util.h | 59 +++++++++++++- src/util/std_code.cpp | 1 - src/util/std_code.h | 12 +-- 7 files changed, 93 insertions(+), 57 deletions(-) create mode 100644 src/java_bytecode/library/target/org/cprover/CProver.class diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index 6bce7bd4792..4d815555436 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -16,6 +16,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include +#include #include @@ -33,39 +34,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include - -/*******************************************************************\ - -Function: traverse_expr_tree - - Inputs: `expr`: an expression tree to traverse - `parents`: will hold previously-visited nodes - `func`: will be called on each node, takes the node and the `parents` - stack as arguments - - Outputs: None - - Purpose: Abstracts the process of calling a function on each node of the - expression tree. - -\*******************************************************************/ - -template -static void traverse_expr_tree( - exprt &expr, - std::vector &parents, - Func func) -{ - const auto& parents_ref=parents; - func(expr, parents_ref); - - parents.push_back(&expr); - for(auto &op : expr.operands()) - { - traverse_expr_tree(op, parents, func); - } - parents.pop_back(); -} +#include /*******************************************************************\ @@ -83,21 +52,19 @@ Function: traverse_expr_tree static void remove_assert_after_generic_nondet(exprt &expr) { - std::vector parents; traverse_expr_tree( expr, - parents, - [] (exprt &expr, const std::vector& parents) + [] (exprt &expr, const std::vector &parents) { const std::regex id_regex( ".*org.cprover.CProver.(nondetWithNull|nondetWithoutNull).*"); if(expr.id()==ID_symbol && - std::regex_match(as_string(to_symbol_expr(expr).get_identifier()), + std::regex_match(id2string(to_symbol_expr(expr).get_identifier()), id_regex)) { assert(2<=parents.size()); - const auto before_1=*(parents.end()-1); - const auto before_2=*(parents.end()-2); + const auto before_1=*std::prev(parents.end(), 1); + const auto before_2=*std::prev(parents.end(), 2); for(auto it=before_2->operands().begin(), end=before_2->operands().end(); @@ -106,11 +73,12 @@ static void remove_assert_after_generic_nondet(exprt &expr) { if(&(*it)==before_1) { - assert(it+1!=end); - if((it+1)->id()==ID_code && - to_code(*(it+1)).get_statement()=="assert") + const auto next_it=std::next(it); + assert(next_it!=end); + if(next_it->id()==ID_code && + to_code(*next_it).get_statement()=="assert") { - *(it+1)=code_skipt(); + *next_it=code_skipt(); } } } @@ -929,11 +897,23 @@ void java_bytecode_convert_methodt::check_static_field_stub( } } -static unsigned get_bytecode_type_width(const typet &ty) +/*******************************************************************\ + +Function: get_bytecode_type_width + + Inputs: `type`: A bytecode type. + + Outputs: The width of the type, in bits. + + Purpose: Used to check the size of the item on the top of the stack. + +\*******************************************************************/ + +static unsigned get_bytecode_type_width(const typet &type) { - if(ty.id()==ID_pointer) + if(type.id()==ID_pointer) return 32; - return ty.get_unsigned_int(ID_width); + return type.get_unsigned_int(ID_width); } /*******************************************************************\ diff --git a/src/java_bytecode/java_bytecode_typecheck.h b/src/java_bytecode/java_bytecode_typecheck.h index ce5c8b4fabe..618b6fce44d 100644 --- a/src/java_bytecode/java_bytecode_typecheck.h +++ b/src/java_bytecode/java_bytecode_typecheck.h @@ -43,7 +43,7 @@ class java_bytecode_typecheckt:public typecheckt { } - virtual ~java_bytecode_typecheckt() = default; + virtual ~java_bytecode_typecheckt() { } virtual void typecheck(); virtual void typecheck_expr(exprt &expr); diff --git a/src/java_bytecode/java_bytecode_typecheck_expr.cpp b/src/java_bytecode/java_bytecode_typecheck_expr.cpp index 49345b6d680..d49e017b37e 100644 --- a/src/java_bytecode/java_bytecode_typecheck_expr.cpp +++ b/src/java_bytecode/java_bytecode_typecheck_expr.cpp @@ -50,8 +50,8 @@ void java_bytecode_typecheckt::typecheck_expr(exprt &expr) typecheck_expr_symbol(to_symbol_expr(expr)); else if(expr.id()==ID_side_effect) { - auto &side_effect_expr = to_side_effect_expr(expr); - const irep_idt &statement = side_effect_expr.get_statement(); + auto &side_effect_expr=to_side_effect_expr(expr); + const irep_idt &statement=side_effect_expr.get_statement(); if(statement==ID_java_new) { typecheck_expr_java_new(side_effect_expr); diff --git a/src/java_bytecode/library/target/org/cprover/CProver.class b/src/java_bytecode/library/target/org/cprover/CProver.class new file mode 100644 index 0000000000000000000000000000000000000000..02f1504b61611b7ef5493aea24941b405f72f4c6 GIT binary patch literal 1957 zcmb7^ZEw<07>4fyI0^&C<~H9I--~;}>C`!Jx}h_giAIP<6F(HzKo#1hwo`wK|G{@Z zm}sKk{ZYpIv}`np1e(wuo<8?=o^zhN=l7rQKLIS_RvhEF7(*J1QCw1RIgT){C|FW( zRl%}?yn=#)YYJ8rT$gz_6s$(E7DZ7Yp_^K@sjt3#>9%wM@pLy-vdm505f~{Lrs1pz zgw^aLfk@HXWa8L{Vd^EfRn_f^1PCNePq1cLO+yv*E!V4) zw3`AcKls>i8YQ>c6qr=A8_%_EE!Wh{dhUMpxn6VfoV9G!P0ev_mV2mBS^hU?Ma@H|*U>XuwpF*aR^}BKkl7*nYif5u%}O|zdVUBg+oEQN zlE}76$->~Xcx{!M+~69veaOP3Eru-2vyIeT7`!mwR#LPyxM;_Ah02OrVV@>s|7Qo$ z`zDjq?X~QBu0|iwOS!fK1kxQ7`5qRSQUj(fJGNog^VvsO;7Ksf6C{L~oS&nZ^dX-K zP=smT_wnBmJ_Vn9&V7UU%z?mu-bcJ(n4$wX$gxb#^W>4Û#BKZU1Clirx*z+s= zj?s{(OL;kQ>Juy=jYE7BhDZ~1*qiHrppl-SDT4NSm;mS~j`gW1+7px^=mbG$f)!^0&NgfBIscdq$1k~l#rm*$1c!gf}RlcEC@P>8G7V@?N3UO_|yfe60}KBqXU}t zQs(HVdF0xaElZ0rKK=!%9b=A3p!9Rlmo4%v^6U;z!TH^9LGHc0Vv(;%@fYfR4{>t% Oksv|>PeYDFxbPRKBa}@5 literal 0 HcmV?d00001 diff --git a/src/util/expr_util.h b/src/util/expr_util.h index f5d33b95cad..819db8838f9 100644 --- a/src/util/expr_util.h +++ b/src/util/expr_util.h @@ -17,8 +17,10 @@ Author: Daniel Kroening, kroening@kroening.com */ #include "irep.h" +#include "expr.h" + +#include -class exprt; class symbol_exprt; class update_exprt; class with_exprt; @@ -51,4 +53,59 @@ bool has_subexpr(const exprt &, const irep_idt &); /*! lift up an if_exprt one level */ if_exprt lift_if(const exprt &, std::size_t operand_number); +/*******************************************************************\ + +Function: traverse_expr_tree + + Inputs: `expr`: an expression tree to traverse + `parents`: will hold previously-visited nodes + `func`: will be called on each node, takes the node and the `parents` + stack as arguments + + Outputs: None + + Purpose: Abstracts the process of calling a function on each node of the + expression tree. + +\*******************************************************************/ + +template +inline void traverse_expr_tree( + exprt &expr, + std::vector &parents, + Func func) +{ + const auto &parents_ref=parents; + func(expr, parents_ref); + + parents.push_back(&expr); + for(auto &op : expr.operands()) + { + traverse_expr_tree(op, parents, func); + } + parents.pop_back(); +} + +/*******************************************************************\ + +Function: traverse_expr_tree + + Inputs: `expr`: an expression tree to traverse + `func`: will be called on each node, takes the node and the `parents` + stack as arguments + + Outputs: None + + Purpose: Behaves exactly like traverse_expr_tree with three arguments, but + sets up the `parents` vector internally. + +\*******************************************************************/ + +template +inline void traverse_expr_tree(exprt &expr, Func &&func) +{ + std::vector parents; + traverse_expr_tree(expr, parents, std::forward(func)); +} + #endif // CPROVER_UTIL_EXPR_UTIL_H diff --git a/src/util/std_code.cpp b/src/util/std_code.cpp index 8bdf4521228..8cc7979c4ac 100644 --- a/src/util/std_code.cpp +++ b/src/util/std_code.cpp @@ -177,4 +177,3 @@ const codet &codet::last_statement() const return *this; } - diff --git a/src/util/std_code.h b/src/util/std_code.h index cc98d57f641..1ab10a01450 100644 --- a/src/util/std_code.h +++ b/src/util/std_code.h @@ -1047,17 +1047,17 @@ class side_effect_expr_nondett:public side_effect_exprt static inline const side_effect_expr_nondett & to_side_effect_expr_nondet(const exprt &expr) { - const auto &x = to_side_effect_expr(expr); - assert(x.get_statement() == ID_nondet); - return static_cast(x); + const auto &side_effect_expr=to_side_effect_expr(expr); + assert(side_effect_expr.get_statement() == ID_nondet); + return static_cast(side_effect_expr); } static inline side_effect_expr_nondett & to_side_effect_expr_nondet(exprt &expr) { - auto &x = to_side_effect_expr(expr); - assert(x.get_statement() == ID_nondet); - return static_cast(x); + auto &side_effect_expr=to_side_effect_expr(expr); + assert(side_effect_expr.get_statement() == ID_nondet); + return static_cast(side_effect_expr); } /*! \brief A function call side effect From 101a65d87973fdc386c68089a3eb099382b2358b Mon Sep 17 00:00:00 2001 From: reuk Date: Fri, 10 Mar 2017 09:17:51 +0000 Subject: [PATCH 38/39] Mark known failing tests as KNOWNBUG --- regression/cbmc-java/nondetGenericArray/test.desc | 2 +- regression/cbmc-java/nondetGenericRecursive2/test.desc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/regression/cbmc-java/nondetGenericArray/test.desc b/regression/cbmc-java/nondetGenericArray/test.desc index 25a6155aa3d..c91a230aa69 100644 --- a/regression/cbmc-java/nondetGenericArray/test.desc +++ b/regression/cbmc-java/nondetGenericArray/test.desc @@ -1,4 +1,4 @@ -CORE +KNOWNBUG NondetGenericArray.class --function NondetGenericArray.foo ^VERIFICATION SUCCESSFUL$ diff --git a/regression/cbmc-java/nondetGenericRecursive2/test.desc b/regression/cbmc-java/nondetGenericRecursive2/test.desc index 85c68803951..821072235a2 100644 --- a/regression/cbmc-java/nondetGenericRecursive2/test.desc +++ b/regression/cbmc-java/nondetGenericRecursive2/test.desc @@ -1,4 +1,4 @@ -CORE +KNOWNBUG NondetGenericRecursive2.class --function NondetGenericRecursive2.foo ^VERIFICATION SUCCESSFUL$ From 8321fa833f1adb8da5291d4eedbf26c461a9fa1c Mon Sep 17 00:00:00 2001 From: reuk Date: Fri, 10 Mar 2017 15:28:19 +0000 Subject: [PATCH 39/39] Fix bug assigning nondetWithNull to Object In the case where we really want to create a nondet java.lang.Object, the java compiler does not emit a checkcast instruction, which means that our attempt to divine the nondet type using checkcast fails. This commit changes the behaviour of nondetWithNull so that it will create an Object if the following instruction is not a checkcast. The test nondetCastToObject tests this behaviour. --- regression/cbmc-java/Makefile | 13 ++++++++++ .../NondetCastToObject.class | Bin 0 -> 778 bytes .../NondetCastToObject.java | 11 +++++++++ .../cbmc-java/nondetCastToObject/test.desc | 6 +++++ .../java_bytecode_convert_method.cpp | 23 ++++++++++-------- 5 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 regression/cbmc-java/nondetCastToObject/NondetCastToObject.class create mode 100644 regression/cbmc-java/nondetCastToObject/NondetCastToObject.java create mode 100644 regression/cbmc-java/nondetCastToObject/test.desc diff --git a/regression/cbmc-java/Makefile b/regression/cbmc-java/Makefile index cee83cba67a..89c7c9da139 100644 --- a/regression/cbmc-java/Makefile +++ b/regression/cbmc-java/Makefile @@ -18,3 +18,16 @@ show: vim -o "$$dir/*.java" "$$dir/*.out"; \ fi; \ done; + +%.class: %.java ../../src/org.cprover.jar + javac -g -cp ../../src/org.cprover.jar:. $< + +nondet_java_files := $(shell find . -name "Nondet*.java") +nondet_class_files := $(patsubst %.java, %.class, $(nondet_java_files)) + +.PHONY: nondet-class-files +nondet-class-files: $(nondet_class_files) + +.PHONY: clean-nondet-class-files +clean-nondet-class-files: + -rm $(nondet_class_files) diff --git a/regression/cbmc-java/nondetCastToObject/NondetCastToObject.class b/regression/cbmc-java/nondetCastToObject/NondetCastToObject.class new file mode 100644 index 0000000000000000000000000000000000000000..2b767b750bdd4705a88988840c9114e6150f390b GIT binary patch literal 778 zcmZuvPjAyO6#qF%n>Nj8mzAzCV1o^4S0I<&n9xvxQz%HAHql#}n9U=LCnwp5*%#mp zNNfTLZXofQ5aJ~*?V%iOKilv9{yh8FpD*74Y~i7WDpoAqz|DNRRfUOF6KfVqSTS+i z!X2!e*kD-N@RNkARLD4aCK7)X@sNQH8Oqxt7U>fPz0=)iF#0m&40TV$e2|@txZ2B; z85~arezfl^k?$vmMtUR?hNd@=amdrYpQL;8)##W9>0?5CDmNqZIK2V^cPII|9)X|{W9w%TC4())YX>m%~8l9|PLi2h*U>fgX=$Ftx!Z=60 z_Y<|RD80Er`Fjqn7tjt2icOj;1Ye~uW)(E8G1P>{z$%)!O4KdNu0j6|+r;t?Yf@Qz is$i?o1}r+}XH?E73O>P@x02(OpxHaQ;cK+faQ!cJU74K# literal 0 HcmV?d00001 diff --git a/regression/cbmc-java/nondetCastToObject/NondetCastToObject.java b/regression/cbmc-java/nondetCastToObject/NondetCastToObject.java new file mode 100644 index 00000000000..2d698439f74 --- /dev/null +++ b/regression/cbmc-java/nondetCastToObject/NondetCastToObject.java @@ -0,0 +1,11 @@ +import org.cprover.CProver; + +class NondetCastToObject +{ + void foo() + { + Object o = CProver.nondetWithNull(); + CProver.assume(o != null); + assert o != null; + } +} diff --git a/regression/cbmc-java/nondetCastToObject/test.desc b/regression/cbmc-java/nondetCastToObject/test.desc new file mode 100644 index 00000000000..c59f81d644f --- /dev/null +++ b/regression/cbmc-java/nondetCastToObject/test.desc @@ -0,0 +1,6 @@ +CORE +NondetCastToObject.class +--function NondetCastToObject.foo +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index 4d815555436..98d95046cfe 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -74,8 +74,8 @@ static void remove_assert_after_generic_nondet(exprt &expr) if(&(*it)==before_1) { const auto next_it=std::next(it); - assert(next_it!=end); - if(next_it->id()==ID_code && + if(next_it!=end && + next_it->id()==ID_code && to_code(*next_it).get_statement()=="assert") { *next_it=code_skipt(); @@ -1288,6 +1288,10 @@ codet java_bytecode_convert_methodt::convert_instructions( ".*org.cprover.CProver.(nondetWithNull|nondetWithoutNull).*")) && !working_set.empty()) { + // Get the nondet function code type. + auto func_type=to_code_type(arg0.type()); + + // Find the next instruction. const auto working_set_begin=working_set.begin(); const auto next_address=address_map.find(*working_set_begin); assert(next_address!=address_map.end()); @@ -1295,9 +1299,12 @@ codet java_bytecode_convert_methodt::convert_instructions( // Find the correct return type. const auto next_source=next_address->second.source; const auto next_statement=next_source->statement; - assert(next_statement=="checkcast"); - assert(next_source->args.size()>=1); - const auto return_type=pointer_typet(next_source->args[0].type()); + // The next return type is the casted-to type *if* the next statement is + // a checkcast. Otherwise, we leave it as-is. + const auto return_type= + (next_statement=="checkcast" && next_source->args.size()>=1) ? + pointer_typet(next_source->args[0].type()) : + func_type.return_type(); // Reconstruct a function call with the correct return type. code_function_callt call; @@ -1306,11 +1313,7 @@ codet java_bytecode_convert_methodt::convert_instructions( loc.set_function(method_id); call.add_source_location()=loc; call.function().add_source_location()=loc; - - // Update the pointed-to type. - auto func_type=arg0.type(); - to_code_type(func_type).return_type()=return_type; - + func_type.return_type()=return_type; call.function()=symbol_exprt(arg0.get(ID_identifier), func_type); call.lhs()=tmp_variable("return", return_type);