Hello Stephen, Thursday, June 12, 2003, 1:06:25 PM, you wrote:
So... Can you change code in CVS to fix this? SK> I found the problem (again:)), and posting this so anybody interested SK> can read from one place. SK> Last time I did not noticed the setSize() invokation from within SK> initFromFile. SK> What happens: SK> setSize() makes the proper length and changes the opcode (hmm, I am not SK> sure I want BCEL to change compiled code without my confirmation, but SK> who cares!). The next line in the initFromFile _restores_ the old opcode SK> (LDC_W), thus making opcode and length inconsistent. The problem shows SK> only when compiled code contains LDC_W with index less than MAX_BYTE SK> (when LDC suffice), and, therefore, shows up very rarely. SK> Konstantin Scheglov wrote: >>Hello Stephen, >> >>Thursday, June 12, 2003, 11:56:21 AM, you wrote: >> >>SK> Kosja, we are strange guys. >>SK> Who checked the bug reports? >>SK> Nobody... >>SK> But should: >>SK> http://nagoya.apache.org/bugzilla/show_bug.cgi?id=18323 >> Ok, thanks. But to find this bug I should already to know, what to >>search. :-) >> >>SK> (I investigated the code. Actually nobody invokes setSize(), when >>SK> reading from file; and NOONE sets proper length of LDC_W, when reading >>SK> from file (i think), and it stays 0 all the time. The fix you made in >>SK> dump() forces dumping with proper length for the proper instruction). >> LDC_W.initFromFile calls LDC.setIndex, which call LDC.setSize() >> Well, may be my fix is not enough, it just dumps right bytes, but >>length is still wrong. >> As I can see, there was version 1.2 of LDC_W with: >> opcode = org.apache.bcel.Constants.LDC_W; >> length = 3; >> but in 1.3 there was "bug fix" and length change was removed. >> >>SK> Strange, I have passed near a MB bytecode through BCEL, and had never >>SK> seen this bug in action. >> Yes, I and users of my tool also process many MB of code, but >>as you can see, sometimes this happens. I have sample class (about 500 >>bytes length). Most probably this class also was automatically >>generated, and generator is not smart enough to use LDC when index is >>small, so it uses LDC_W and this causes problem. I think javac/jikes >>use LDC where this is possible, so you just never see such cases. >> >>SK> About method copy: >>SK> class Class1 { >>SK> void method1() { >>SK> // getstatic <System.out> >>SK> // ldc #3 <String "Hello world">!!!!! >>SK> // invokevirtual <PrintStream::println(String)> >>SK> // return >>SK> } >>SK> } >> >>SK> if you want to copy method1 to _another_ class, you have to make sure >>SK> that ldc "Hello world" points somewhere in the new constantpool where >>SK> you have "Hello world". Complications are pouring in when you want the >>SK> copied method to reference methods of its containing class; or to >>SK> checkcast if a reference points to instance of the enclosing class. >> Thank you. >> I just replace methods in each class with a little changed methods, >>so I think, that changing of constant pool is not required. >> >>SK> Konstantin Scheglov wrote: >> >> >> >>>>Hello Stephen, >>>> >>>>Wednesday, June 11, 2003, 7:11:16 PM, you wrote: >>>> >>>> Ok, now I am sure, that this is bug in BCEL. >>>> >>>> Here is code from LDC_W: >>>> protected void initFromFile(ByteSequence bytes, boolean wide) >>>> throws IOException >>>> { >>>> setIndex(bytes.readUnsignedShort()); >>>> // Override just in case it has been changed >>>> opcode = org.apache.bcel.Constants.LDC_W; >>>> } >>>> As you can see, it forces instruction code to LDC_W. >>>> >>>> And here is code from LDC: >>>> public final void setIndex(int index) { >>>> super.setIndex(index); >>>> setSize(); >>>> } >>>> protected final void setSize() { >>>> if(index <= org.apache.bcel.Constants.MAX_BYTE) { // Fits in one byte? >>>> opcode = org.apache.bcel.Constants.LDC; >>>> length = 2; >>>> } else { >>>> opcode = org.apache.bcel.Constants.LDC_W; >>>> length = 3; >>>> } >>>> } >>>> >>>> I.e. setSize() changes inscruction code and length. Then, length >>>>used in dump() to detect, that byte or short argument is needed: >>>> public void dump(DataOutputStream out) throws IOException { >>>> out.writeByte(opcode); >>>> if(length == 2) >>>> out.writeByte(index); >>>> else // Applies for LDC_W >>>> out.writeShort(index); >>>> } >>>> >>>> But we have (in my case) length == 2, i.e. one byte and LDC_W >>>>instruction! So, when it tryies to create String for this instruction, >>>>it reads one random byte (in reallity next instruction)! >>>> >>>> When I change dump() to this code, I receive no exceptions. >>>> >>>> public void dump(DataOutputStream out) throws IOException { >>>> out.writeByte(opcode); >>>> if(opcode == org.apache.bcel.Constants.LDC) >>>> out.writeByte(index); >>>> else // Applies for LDC_W >>>> out.writeShort(index); >>>> } >>>> >>>> >>>> >>>>SK> The code you sent is OK, at least for BCEL 5.0 and 5.1 (I have >>>>SK> experience with those). The problem is elsewere. >>>>SK> Btw, did you checked if your original (not instrumented) classes are >>>>SK> acceptible? It is so stupid mistake, that you have to be genious to >>>>SK> avoid it, at least I can not :))). >>>>SK> Beside this: if you copy method from one class to another (i do not what >>>>SK> are your real application), you must change the constant pool indices of >>>>SK> the instructions. >>>> >>>>SK> Konstantin Scheglov wrote: >>>> >>>> >>>> >>>> >>>> >>>>>>I use following code to instrument one class. >>>>>>But when I instrument some classes and try to print debug >>>>>>information, I receive following exception. >>>>>> >>>>>>org.apache.bcel.classfile.ClassFormatException: Invalid constant pool reference: >>>>>>28088. Constant pool size is: 1024 >>>>>> at >>>>>> org.apache.bcel.classfile.ConstantPool.getConstant(ConstantPool.java:242) >>>>>> at org.apache.bcel.classfile.Utility.codeToString(Utility.java:369) >>>>>> at org.apache.bcel.classfile.Utility.codeToString(Utility.java:166) >>>>>> at org.apache.bcel.classfile.Code.toString(Code.java:326) >>>>>> at org.apache.bcel.classfile.Code.toString(Code.java:352) >>>>>> at java.lang.String.valueOf(String.java:2131) >>>>>> at java.io.PrintStream.print(PrintStream.java:462) >>>>>> at java.io.PrintStream.println(PrintStream.java:599) >>>>>> at >>>>>> ru.nlmk.eclipse.plugins.profiler.trace.Trace.instrumentClass(Trace.java:1190) >>>>>> at >>>>>> ru.nlmk.eclipse.plugins.profiler.trace.test.TestBCEL.main(TestBCEL.java:23) >>>>>> >>>>>> >>>>>>As you can see, I just copy code from one method to another (in real application >>>>>>I change code a little). And when I try to load this class in real application >>>>>>I receive exception like this from JVM: "VerifyError: Illegal constant pool >>>>>>index". >>>>>> >>>>>> >>>>>> public static JavaClass instrumentClass(JavaClass clazz) throws Exception { >>>>>> ClassGen classGen = new ClassGen(clazz); >>>>>> ConstantPoolGen cp = new ConstantPoolGen(clazz.getConstantPool()); >>>>>> classGen.setConstantPool(cp); >>>>>> // >>>>>> for (int i = 0; i < clazz.getMethods().length; i++) { >>>>>> Method method = clazz.getMethods()[i]; >>>>>> if (method.isAbstract() || method.isNative()) >>>>>> continue; >>>>>> if (method.getName().equals("finalize")) >>>>>> continue; >>>>>> MethodGen mg = new MethodGen(method, clazz.getClassName(), >>>>>> cp); >>>>>> mg.setConstantPool(cp); >>>>>> Method newMethod = mg.getMethod(); >>>>>> if (m_Debug) { >>>>>> System.out.println(method.getCode()); >>>>>> System.out.println(newMethod.getCode()); >>>>>> } >>>>>> classGen.replaceMethod(method, newMethod); >>>>>> } >>>>>> // >>>>>> JavaClass newClazz = classGen.getJavaClass(); >>>>>> newClazz.setConstantPool(cp.getFinalConstantPool()); >>>>>> return newClazz; >>>>>> } >>>>>> >>>>>>What I do wrong? >>>>>>I see such exception only on few classes (methods). >>>>>>I have example of such class. >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> >>>> >>>>SK> --------------------------------------------------------------------- >>>>SK> To unsubscribe, e-mail: [EMAIL PROTECTED] >>>>SK> For additional commands, e-mail: [EMAIL PROTECTED] >>>> >>>> >>>> >>>> >>>> >>>> >>>> >> >> >> >> >> >> -- Best regards, Konstantin mailto:[EMAIL PROTECTED] --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
