Re: Re: NOP ATHROW hack defeated !
Eric Bruneton <[email protected]>
| Newsgroups | gmane.comp.java.objectweb.asm |
|---|---|
| Message-ID | <[email protected]> |
01/05/2011 16:16, Rémi Forax wrote: > On 05/01/2011 11:09 AM, Eric Bruneton wrote: >> 30/04/2011 10:20, Eric Bruneton wrote: >>> 29/04/2011 03:04, Rémi Forax wrote: >>>> Charles Nutter (a JRuby guy) was able to generate a code that defeat >>>> the infamous NOP ... ATHROW hack. >>>> >>>> see http://asm.ow2.org/doc/developer-guide.html#deadcode >>>> for the background. >>>> >>>> Basically, when a code is dead, not reachable, ASM replaces the >>>> offending code by >>>> NOP ... ATHROW and generate a dedicated stackmap: [] >>>> [java/lang/Throwable]. >>>> But if the unreachable code is in a try/catch, we create a path >>>> where no >>>> local variable >>>> are available anymore. So the split verifier will reject the >>>> bytecode if >>>> a local variable is used in the exception handler of the try/catch. >>>> >>>> The program below generates a bytecode which is rejected by the split >>>> verifier. >>>> [forax@localhost asm4-test]$ java deadcode >>>> Exception in thread "main" java.lang.VerifyError: Stack map does not >>>> match the one at exception handler 7 in method >>>> deadcode.foo(Ljava/lang/Object;)V at offset 3 >>>> at java.lang.Class.getDeclaredMethods0(Native Method) >>>> at java.lang.Class.privateGetDeclaredMethods(Class.java:2440) >>>> at java.lang.Class.getMethod0(Class.java:2683) >>>> at java.lang.Class.getMethod(Class.java:1618) >>>> at sun.launcher.LauncherHelper.getMainMethod(LauncherHelper.java:484) >>>> at >>>> sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:476) >>>> >>>> >>>> Eric, do you see a solution for that ? >>> >>> I think we can find which locals to put in the stackmap frame generated >>> for a dead block by using the locals from the first frame of the >>> innermost exception handler for this block(*) (if any). Using the >>> innermost handler is necessary to get the most specific types for these >>> locals (the other handlers will necessarily have these types or super >>> types of these types in their stackmap frames, since they handle more >>> code). Also, since dead blocks are handled after the fix point algorithm >>> is finished, we have the final frames for the exception handlers at this >>> point. >>> >>> The only problem is that exception handlers do not have to be properly >>> nested (nothing enforces this in the specification, although compilers >>> always generate nested handlers because Java try/catch are nested by >>> construction). And in this case the "innermost handler" is not well >>> defined. >> >> there is another solution, which is simpler and works in all cases (I >> think): remove the exception handlers for deadcode (see attached patch). >> >> Eric > > It seems the patch was too shy to show up :) oups! here it is Eric
patch.txt
(text/plain, 2.7 KB)
Index: org/objectweb/asm/Handler.java
===================================================================
--- org/objectweb/asm/Handler.java (revision 1498)
+++ org/objectweb/asm/Handler.java (working copy)
@@ -67,4 +67,52 @@
* Next exception handler block info.
*/
Handler next;
+
+ /**
+ * Removes the range between start and end from the given exception
+ * handlers.
+ *
+ * @param h an exception handler list.
+ * @param start the start of the range to be removed.
+ * @param end the end of the range to be removed. Maybe null.
+ * @return the exception handler list with the start-end range removed.
+ */
+ static Handler remove(Handler h, Label start, Label end) {
+ if (h == null) {
+ return null;
+ } else {
+ h.next = remove(h.next, start, end);
+ }
+ int hstart = h.start.position;
+ int hend = h.end.position;
+ int s = start.position;
+ int e = end == null ? Integer.MAX_VALUE : end.position;
+ // if [hstart,hend[ and [s,e[ intervals intersect...
+ if (s < hend && e > hstart) {
+ boolean i = s <= hstart;
+ boolean j = e >= hend;
+ if (i && j) {
+ // [hstart,hend[ fully included in [s,e[, h removed
+ h = h.next;
+ } else if (i && !j) {
+ // [hstart,hend[ minus [s,e[ = [hstart,e[
+ h.end = end;
+ } else if (!i && j) {
+ // [hstart,hend[ minus [s,e[ = [s,hend[
+ h.start = start;
+ } else { // !i && !j
+ // [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[
+ Handler g = new Handler();
+ g.start = end;
+ g.end = h.end;
+ g.handler = h.handler;
+ g.desc = h.desc;
+ g.type = h.type;
+ g.next = h.next;
+ h.end = start;
+ h.next = g;
+ }
+ }
+ return h;
+ }
}
Index: org/objectweb/asm/MethodWriter.java
===================================================================
--- org/objectweb/asm/MethodWriter.java (revision 1498)
+++ org/objectweb/asm/MethodWriter.java (working copy)
@@ -1366,6 +1366,8 @@
frame[frameIndex++] = Frame.OBJECT
| cw.addType("java/lang/Throwable");
endFrame();
+ // removes the start-end range from the exception handlers
+ firstHandler = Handler.remove(firstHandler, l, k);
}
}
l = l.successor;
message-footer.txt
(text/plain, 238 B)
-- You receive this message as a subscriber of the [email protected] mailing list. To unsubscribe: mailto:[email protected] For general help: mailto:[email protected]?subject=help OW2 mailing lists service home page: http://www.ow2.org/wws