0 Replies Latest reply on Aug 21, 2009 2:27 AM by dschulten

    Pop from empty stack after MethodCall.replace

    dschulten

      Hi,

      I need to replace the following call in legacy bytecode:

      dataInputStream.read(buf, 0, len);

      by

      dataInputStream.readFully(buf, 0, len);

      The original read() has the obvious flaw that it does not check for the return value of dataInputStream.read, which leads to problems if the implementation chooses to fill the buffer only partially. I want to solve this bug using Javassist.

      I do the following:

      ExprEditor exprEditor = new ExprEditor() {

      @Override
      public void edit(MethodCall methodCall)
      throws CannotCompileException {
      String methodName = methodCall.getMethodName();
      if (methodName.equals("read")) {
      methodCall.replace("$_ = $0.readFully($$);");
      didChangesToClassfile = true;
      }
      }
      };

      But the created class is broken, it is rejected by the classloader and jode says "Pop from empty stack".

      Obviously I want to replace a method call with a return value which is being ignored by a void method call. I guess this is what causes the problem, but maybe I am wrong.

      The offending bytecode is below, look around readFully in line 114:

      public void (String arg1)
      Code(max_stack = 4, max_locals = 9, code_length = 139)
      0: aload_0
      1: invokespecial java.lang.Object. ()V (23)
      4: new <java.io.DataInputStream> (2)
      7: dup
      8: aload_0
      9: invokevirtual java.lang.Object.getClass ()Ljava/lang/Class; (24)
      12: aload_1
      13: invokevirtual java.lang.Class.getResourceAsStream (Ljava/lang/String;)Ljava/io/InputStream; (22)
      16: invokespecial java.io.DataInputStream. (Ljava/io/InputStream;)V (16)
      19: dup
      20: astore_1
      21: invokevirtual java.io.DataInputStream.readUnsignedByte ()I (21)
      24: i2c
      25: bipush 70
      27: if_icmpeq #31
      30: return
      31: aload_1
      32: invokevirtual java.io.DataInputStream.readUnsignedByte ()I (21)
      35: i2c
      36: bipush 49
      38: if_icmpeq #42
      41: return
      42: aload_0
      43: aload_1
      44: invokevirtual java.io.DataInputStream.readByte ()B (19)
      47: putfield ak.h I (15)
      50: aload_0
      51: aload_1
      52: invokevirtual java.io.DataInputStream.readByte ()B (19)
      55: putfield ak.d I (11)
      58: aload_0
      59: aload_1
      60: invokevirtual java.io.DataInputStream.readByte ()B (19)
      63: putfield ak.e I (12)
      66: aload_0
      67: aload_1
      68: invokevirtual java.io.DataInputStream.readByte ()B (19)
      71: putfield ak.f I (13)
      74: aload_0
      75: aload_1
      76: invokevirtual java.io.DataInputStream.readByte ()B (19)
      79: putfield ak.g I (14)
      82: aload_1
      83: invokevirtual java.io.DataInputStream.readShort ()S (20)
      86: dup
      87: istore_2
      88: newarray
      90: astore_3
      91: aload_1
      92: aload_3
      93: iconst_0
      94: iload_2
      95: istore %7
      97: istore %6
      99: astore %5
      101: astore %4
      103: iconst_0
      104: istore %8
      106: aload %4
      108: aload %5
      110: iload %6
      112: iload %7
      114: invokevirtual java.io.DataInputStream.readFully ([BII)V (116)
      117: istore %8
      119: iload %8
      121: pop
      122: aload_0
      123: aload_3
      124: iconst_0
      125: iload_2
      126: invokestatic javax.microedition.lcdui.Image.createImage ([BII)Ljavax/microedition/lcdui/Image; (34)
      129: putfield ak.G Ljavax/microedition/lcdui/Image; (10)
      132: aload_1
      133: invokevirtual java.io.DataInputStream.close ()V (17)
      136: return
      137: pop
      138: return

      The original bytecode looks like this:

      public void (String arg1)
      Code(max_stack = 4, max_locals = 4, code_length = 116)
      0: aload_0
      1: invokespecial java.lang.Object. ()V (23)
      4: new <java.io.DataInputStream> (2)
      7: dup
      8: aload_0
      9: invokevirtual java.lang.Object.getClass ()Ljava/lang/Class; (24)
      12: aload_1
      13: invokevirtual java.lang.Class.getResourceAsStream (Ljava/lang/String;)Ljava/io/InputStream; (22)
      16: invokespecial java.io.DataInputStream. (Ljava/io/InputStream;)V (16)
      19: dup
      20: astore_1
      21: invokevirtual java.io.DataInputStream.readUnsignedByte ()I (21)
      24: i2c
      25: bipush 70
      27: if_icmpeq #31
      30: return
      31: aload_1
      32: invokevirtual java.io.DataInputStream.readUnsignedByte ()I (21)
      35: i2c
      36: bipush 49
      38: if_icmpeq #42
      41: return
      42: aload_0
      43: aload_1
      44: invokevirtual java.io.DataInputStream.readByte ()B (19)
      47: putfield ak.h I (15)
      50: aload_0
      51: aload_1
      52: invokevirtual java.io.DataInputStream.readByte ()B (19)
      55: putfield ak.d I (11)
      58: aload_0
      59: aload_1
      60: invokevirtual java.io.DataInputStream.readByte ()B (19)
      63: putfield ak.e I (12)
      66: aload_0
      67: aload_1
      68: invokevirtual java.io.DataInputStream.readByte ()B (19)
      71: putfield ak.f I (13)
      74: aload_0
      75: aload_1
      76: invokevirtual java.io.DataInputStream.readByte ()B (19)
      79: putfield ak.g I (14)
      82: aload_1
      83: invokevirtual java.io.DataInputStream.readShort ()S (20)
      86: dup
      87: istore_2
      88: newarray
      90: astore_3
      91: aload_1
      92: aload_3
      93: iconst_0
      94: iload_2
      95: invokevirtual java.io.DataInputStream.read ([BII)I (18)
      98: pop
      99: aload_0
      100: aload_3
      101: iconst_0
      102: iload_2
      103: invokestatic javax.microedition.lcdui.Image.createImage ([BII)Ljavax/microedition/lcdui/Image; (34)
      106: putfield ak.G Ljavax/microedition/lcdui/Image; (10)
      109: aload_1
      110: invokevirtual java.io.DataInputStream.close ()V (17)
      113: return
      114: pop
      115: return