You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Pass3aVerifier.java 48KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188
  1. package org.aspectj.apache.bcel.verifier.statics;
  2. /* ====================================================================
  3. * The Apache Software License, Version 1.1
  4. *
  5. * Copyright (c) 2001 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (https://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Apache" and "Apache Software Foundation" and
  28. * "Apache BCEL" must not be used to endorse or promote products
  29. * derived from this software without prior written permission. For
  30. * written permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * "Apache BCEL", nor may "Apache" appear in their name, without
  34. * prior written permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation. For more
  52. * information on the Apache Software Foundation, please see
  53. * <https://www.apache.org/>.
  54. */
  55. import org.aspectj.apache.bcel.Constants;
  56. import org.aspectj.apache.bcel.Repository;
  57. import org.aspectj.apache.bcel.classfile.Attribute;
  58. import org.aspectj.apache.bcel.classfile.Code;
  59. import org.aspectj.apache.bcel.classfile.CodeException;
  60. import org.aspectj.apache.bcel.classfile.Constant;
  61. import org.aspectj.apache.bcel.classfile.ConstantClass;
  62. import org.aspectj.apache.bcel.classfile.ConstantDouble;
  63. import org.aspectj.apache.bcel.classfile.ConstantFieldref;
  64. import org.aspectj.apache.bcel.classfile.ConstantFloat;
  65. import org.aspectj.apache.bcel.classfile.ConstantInteger;
  66. import org.aspectj.apache.bcel.classfile.ConstantInterfaceMethodref;
  67. import org.aspectj.apache.bcel.classfile.ConstantLong;
  68. import org.aspectj.apache.bcel.classfile.ConstantMethodref;
  69. import org.aspectj.apache.bcel.classfile.ConstantNameAndType;
  70. import org.aspectj.apache.bcel.classfile.ConstantPool;
  71. import org.aspectj.apache.bcel.classfile.ConstantString;
  72. import org.aspectj.apache.bcel.classfile.ConstantUtf8;
  73. import org.aspectj.apache.bcel.classfile.Field;
  74. import org.aspectj.apache.bcel.classfile.JavaClass;
  75. import org.aspectj.apache.bcel.classfile.LineNumber;
  76. import org.aspectj.apache.bcel.classfile.LineNumberTable;
  77. import org.aspectj.apache.bcel.classfile.LocalVariable;
  78. import org.aspectj.apache.bcel.classfile.LocalVariableTable;
  79. import org.aspectj.apache.bcel.classfile.Method;
  80. import org.aspectj.apache.bcel.generic.ArrayType;
  81. import org.aspectj.apache.bcel.generic.FieldInstruction;
  82. import org.aspectj.apache.bcel.generic.IINC;
  83. import org.aspectj.apache.bcel.generic.INVOKEINTERFACE;
  84. import org.aspectj.apache.bcel.generic.Instruction;
  85. import org.aspectj.apache.bcel.generic.InstructionBranch;
  86. import org.aspectj.apache.bcel.generic.InstructionByte;
  87. import org.aspectj.apache.bcel.generic.InstructionHandle;
  88. import org.aspectj.apache.bcel.generic.InstructionList;
  89. import org.aspectj.apache.bcel.generic.InvokeInstruction;
  90. import org.aspectj.apache.bcel.generic.LOOKUPSWITCH;
  91. import org.aspectj.apache.bcel.generic.MULTIANEWARRAY;
  92. import org.aspectj.apache.bcel.generic.ObjectType;
  93. import org.aspectj.apache.bcel.generic.RET;
  94. import org.aspectj.apache.bcel.generic.TABLESWITCH;
  95. import org.aspectj.apache.bcel.generic.Type;
  96. import org.aspectj.apache.bcel.verifier.InstructionWalker;
  97. import org.aspectj.apache.bcel.verifier.PassVerifier;
  98. import org.aspectj.apache.bcel.verifier.VerificationResult;
  99. import org.aspectj.apache.bcel.verifier.Verifier;
  100. import org.aspectj.apache.bcel.verifier.VerifierFactory;
  101. import org.aspectj.apache.bcel.verifier.exc.AssertionViolatedException;
  102. import org.aspectj.apache.bcel.verifier.exc.ClassConstraintException;
  103. import org.aspectj.apache.bcel.verifier.exc.InvalidMethodException;
  104. import org.aspectj.apache.bcel.verifier.exc.StaticCodeConstraintException;
  105. import org.aspectj.apache.bcel.verifier.exc.StaticCodeInstructionConstraintException;
  106. import org.aspectj.apache.bcel.verifier.exc.StaticCodeInstructionOperandConstraintException;
  107. /**
  108. * This PassVerifier verifies a class file according to pass 3, static part as described in The Java Virtual Machine Specification,
  109. * 2nd edition. More detailed information is to be found at the do_verify() method's documentation.
  110. *
  111. * @version $Id: Pass3aVerifier.java,v 1.5 2009/09/10 15:35:06 aclement Exp $
  112. * @author <A HREF="https://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
  113. * @see #do_verify()
  114. */
  115. public final class Pass3aVerifier extends PassVerifier {
  116. /** The Verifier that created this. */
  117. private final Verifier myOwner;
  118. /**
  119. * The method number to verify. This is the index in the array returned by JavaClass.getMethods().
  120. */
  121. private final int method_no;
  122. /**
  123. * The one and only InstructionList object used by an instance of this class. It's here for performance reasons by do_verify()
  124. * and its callees.
  125. */
  126. InstructionList instructionList;
  127. /**
  128. * The one and only Code object used by an instance of this class. It's here for performance reasons by do_verify() and its
  129. * callees.
  130. */
  131. Code code;
  132. /** Should only be instantiated by a Verifier. */
  133. public Pass3aVerifier(Verifier owner, int method_no) {
  134. myOwner = owner;
  135. this.method_no = method_no;
  136. }
  137. /**
  138. * Pass 3a is the verification of static constraints of JVM code (such as legal targets of branch instructions). This is the
  139. * part of pass 3 where you do not need data flow analysis. JustIce also delays the checks for a correct exception table of a
  140. * Code attribute and correct line number entries in a LineNumberTable attribute of a Code attribute (which conceptually belong
  141. * to pass 2) to this pass. Also, most of the check for valid local variable entries in a LocalVariableTable attribute of a Code
  142. * attribute is delayed until this pass. All these checks need access to the code array of the Code attribute.
  143. *
  144. * @throws InvalidMethodException if the method to verify does not exist.
  145. */
  146. @Override
  147. public VerificationResult do_verify() {
  148. if (myOwner.doPass2().equals(VerificationResult.VR_OK)) {
  149. // Okay, class file was loaded correctly by Pass 1
  150. // and satisfies static constraints of Pass 2.
  151. JavaClass jc = Repository.lookupClass(myOwner.getClassName());
  152. Method[] methods = jc.getMethods();
  153. if (method_no >= methods.length) {
  154. throw new InvalidMethodException("METHOD DOES NOT EXIST!");
  155. }
  156. Method method = methods[method_no];
  157. code = method.getCode();
  158. // No Code? Nothing to verify!
  159. if (method.isAbstract() || method.isNative()) { // IF mg HAS NO CODE (static constraint of Pass 2)
  160. return VerificationResult.VR_OK;
  161. }
  162. // TODO:
  163. // We want a very sophisticated code examination here with good explanations
  164. // on where to look for an illegal instruction or such.
  165. // Only after that we should try to build an InstructionList and throw an
  166. // AssertionViolatedException if after our examination InstructionList building
  167. // still fails.
  168. // That examination should be implemented in a byte-oriented way, i.e. look for
  169. // an instruction, make sure its validity, count its length, find the next
  170. // instruction and so on.
  171. try {
  172. instructionList = new InstructionList(method.getCode().getCode());
  173. } catch (RuntimeException re) {
  174. return new VerificationResult(VerificationResult.VERIFIED_REJECTED,
  175. "Bad bytecode in the code array of the Code attribute of method '" + method + "'.");
  176. }
  177. instructionList.setPositions(true);
  178. // Start verification.
  179. VerificationResult vr = VerificationResult.VR_OK; // default
  180. try {
  181. delayedPass2Checks();
  182. } catch (ClassConstraintException cce) {
  183. vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, cce.getMessage());
  184. return vr;
  185. }
  186. try {
  187. pass3StaticInstructionChecks();
  188. pass3StaticInstructionOperandsChecks();
  189. } catch (StaticCodeConstraintException scce) {
  190. vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, scce.getMessage());
  191. }
  192. return vr;
  193. } else { // did not pass Pass 2.
  194. return VerificationResult.VR_NOTYET;
  195. }
  196. }
  197. /**
  198. * These are the checks that could be done in pass 2 but are delayed to pass 3 for performance reasons. Also, these checks need
  199. * access to the code array of the Code attribute of a Method so it's okay to perform them here. Also see the description of the
  200. * do_verify() method.
  201. *
  202. * @throws ClassConstraintException if the verification fails.
  203. * @see #do_verify()
  204. */
  205. private void delayedPass2Checks() {
  206. int[] instructionPositions = instructionList.getInstructionPositions();
  207. int codeLength = code.getCode().length;
  208. // ///////////////////
  209. // LineNumberTable //
  210. // ///////////////////
  211. LineNumberTable lnt = code.getLineNumberTable();
  212. if (lnt != null) {
  213. LineNumber[] lineNumbers = lnt.getLineNumberTable();
  214. IntList offsets = new IntList();
  215. lineNumber_loop: for (int i = 0; i < lineNumbers.length; i++) { // may appear in any order.
  216. for (int j = 0; j < instructionPositions.length; j++) {
  217. // TODO: Make this a binary search! The instructionPositions array is naturally ordered!
  218. int offset = lineNumbers[i].getStartPC();
  219. if (instructionPositions[j] == offset) {
  220. if (offsets.contains(offset)) {
  221. addMessage("LineNumberTable attribute '"
  222. + code.getLineNumberTable()
  223. + "' refers to the same code offset ('"
  224. + offset
  225. + "') more than once which is violating the semantics [but is sometimes produced by IBM's 'jikes' compiler].");
  226. } else {
  227. offsets.add(offset);
  228. }
  229. continue lineNumber_loop;
  230. }
  231. }
  232. throw new ClassConstraintException("Code attribute '" + code + "' has a LineNumberTable attribute '"
  233. + code.getLineNumberTable() + "' referring to a code offset ('" + lineNumbers[i].getStartPC()
  234. + "') that does not exist.");
  235. }
  236. }
  237. // /////////////////////////
  238. // LocalVariableTable(s) //
  239. // /////////////////////////
  240. /*
  241. * We cannot use code.getLocalVariableTable() because there could be more than only one. This is a bug in BCEL.
  242. */
  243. Attribute[] atts = code.getAttributes();
  244. for (int a = 0; a < atts.length; a++) {
  245. if (atts[a] instanceof LocalVariableTable) {
  246. LocalVariableTable lvt = (LocalVariableTable) atts[a];
  247. if (lvt != null) {
  248. LocalVariable[] localVariables = lvt.getLocalVariableTable();
  249. for (int i = 0; i < localVariables.length; i++) {
  250. int startpc = localVariables[i].getStartPC();
  251. int length = localVariables[i].getLength();
  252. if (!contains(instructionPositions, startpc)) {
  253. throw new ClassConstraintException("Code attribute '" + code + "' has a LocalVariableTable attribute '"
  254. + code.getLocalVariableTable() + "' referring to a code offset ('" + startpc
  255. + "') that does not exist.");
  256. }
  257. if (!contains(instructionPositions, startpc + length) && startpc + length != codeLength) {
  258. throw new ClassConstraintException("Code attribute '" + code + "' has a LocalVariableTable attribute '"
  259. + code.getLocalVariableTable() + "' referring to a code offset start_pc+length ('"
  260. + (startpc + length) + "') that does not exist.");
  261. }
  262. }
  263. }
  264. }
  265. }
  266. // //////////////////
  267. // ExceptionTable //
  268. // //////////////////
  269. // In BCEL's "classfile" API, the startPC/endPC-notation is
  270. // inclusive/exclusive as in the Java Virtual Machine Specification.
  271. // WARNING: This is not true for BCEL's "generic" API.
  272. CodeException[] exceptionTable = code.getExceptionTable();
  273. for (int i = 0; i < exceptionTable.length; i++) {
  274. int startpc = exceptionTable[i].getStartPC();
  275. int endpc = exceptionTable[i].getEndPC();
  276. int handlerpc = exceptionTable[i].getHandlerPC();
  277. if (startpc >= endpc) {
  278. throw new ClassConstraintException("Code attribute '" + code + "' has an exception_table entry '"
  279. + exceptionTable[i] + "' that has its start_pc ('" + startpc + "') not smaller than its end_pc ('" + endpc
  280. + "').");
  281. }
  282. if (!contains(instructionPositions, startpc)) {
  283. throw new ClassConstraintException("Code attribute '" + code + "' has an exception_table entry '"
  284. + exceptionTable[i] + "' that has a non-existant bytecode offset as its start_pc ('" + startpc + "').");
  285. }
  286. if (!contains(instructionPositions, endpc) && endpc != codeLength) {
  287. throw new ClassConstraintException("Code attribute '" + code + "' has an exception_table entry '"
  288. + exceptionTable[i] + "' that has a non-existant bytecode offset as its end_pc ('" + startpc
  289. + "') [that is also not equal to code_length ('" + codeLength + "')].");
  290. }
  291. if (!contains(instructionPositions, handlerpc)) {
  292. throw new ClassConstraintException("Code attribute '" + code + "' has an exception_table entry '"
  293. + exceptionTable[i] + "' that has a non-existant bytecode offset as its handler_pc ('" + handlerpc + "').");
  294. }
  295. }
  296. }
  297. /**
  298. * These are the checks if constraints are satisfied which are described in the Java Virtual Machine Specification, Second
  299. * Edition as Static Constraints on the instructions of Java Virtual Machine Code (chapter 4.8.1).
  300. *
  301. * @throws StaticCodeConstraintException if the verification fails.
  302. */
  303. private void pass3StaticInstructionChecks() {
  304. // Code array must not be empty:
  305. // Enforced in pass 2 (also stated in the static constraints of the Code
  306. // array in vmspec2), together with pass 1 (reading code_length bytes and
  307. // interpreting them as code[]). So this must not be checked again here.
  308. if (!(code.getCode().length < 65536)) {// contradicts vmspec2 page 152 ("Limitations"), but is on page 134.
  309. throw new StaticCodeInstructionConstraintException("Code array in code attribute '" + code
  310. + "' too big: must be smaller than 65536 bytes.");
  311. }
  312. // First opcode at offset 0: okay, that's clear. Nothing to do.
  313. // Only instances of the instructions documented in Section 6.4 may appear in
  314. // the code array.
  315. // For BCEL's sake, we cannot handle WIDE stuff, but hopefully BCEL does its job right :)
  316. // The last byte of the last instruction in the code array must be the byte at index
  317. // code_length-1 : See the do_verify() comments. We actually don't iterate through the
  318. // byte array, but use an InstructionList so we cannot check for this. But BCEL does
  319. // things right, so it's implicitly okay.
  320. // TODO: Check how BCEL handles (and will handle) instructions like IMPDEP1, IMPDEP2,
  321. // BREAKPOINT... that BCEL knows about but which are illegal anyway.
  322. // We currently go the safe way here.
  323. InstructionHandle ih = instructionList.getStart();
  324. while (ih != null) {
  325. Instruction i = ih.getInstruction();
  326. if (i.getOpcode() == Constants.IMPDEP1) {
  327. throw new StaticCodeInstructionConstraintException(
  328. "IMPDEP1 must not be in the code, it is an illegal instruction for _internal_ JVM use!");
  329. }
  330. if (i.getOpcode() == Constants.IMPDEP2) {
  331. throw new StaticCodeInstructionConstraintException(
  332. "IMPDEP2 must not be in the code, it is an illegal instruction for _internal_ JVM use!");
  333. }
  334. if (i.getOpcode() == Constants.BREAKPOINT) {
  335. throw new StaticCodeInstructionConstraintException(
  336. "BREAKPOINT must not be in the code, it is an illegal instruction for _internal_ JVM use!");
  337. }
  338. ih = ih.getNext();
  339. }
  340. // The original verifier seems to do this check here, too.
  341. // An unreachable last instruction may also not fall through the
  342. // end of the code, which is stupid -- but with the original
  343. // verifier's subroutine semantics one cannot predict reachability.
  344. Instruction last = instructionList.getEnd().getInstruction();
  345. if (!(last.isReturnInstruction() || last instanceof RET || last.getOpcode() == Constants.GOTO
  346. || last.getOpcode() == Constants.GOTO_W || last.getOpcode() == Constants.ATHROW)) {
  347. throw new StaticCodeInstructionConstraintException(
  348. "Execution must not fall off the bottom of the code array. This constraint is enforced statically as some existing verifiers do - so it may be a false alarm if the last instruction is not reachable.");
  349. }
  350. }
  351. /**
  352. * These are the checks for the satisfaction of constraints which are described in the Java Virtual Machine Specification,
  353. * Second Edition as Static Constraints on the operands of instructions of Java Virtual Machine Code (chapter 4.8.1). BCEL
  354. * parses the code array to create an InstructionList and therefore has to check some of these constraints. Additional checks
  355. * are also implemented here.
  356. *
  357. * @throws StaticCodeConstraintException if the verification fails.
  358. */
  359. private void pass3StaticInstructionOperandsChecks() {
  360. // When building up the InstructionList, BCEL has already done all those checks
  361. // mentioned in The Java Virtual Machine Specification, Second Edition, as
  362. // "static constraints on the operands of instructions in the code array".
  363. // TODO: see the do_verify() comments. Maybe we should really work on the
  364. // byte array first to give more comprehensive messages.
  365. // TODO: Review Exception API, possibly build in some "offending instruction" thing
  366. // when we're ready to insulate the offending instruction by doing the
  367. // above thing.
  368. // TODO: Implement as much as possible here. BCEL does _not_ check everything.
  369. ConstantPool cpg = new ConstantPool(Repository.lookupClass(myOwner.getClassName()).getConstantPool().getConstantPool());
  370. InstOperandConstraintVisitor v = new InstOperandConstraintVisitor(cpg);
  371. // Checks for the things BCEL does _not_ handle itself.
  372. InstructionHandle ih = instructionList.getStart();
  373. while (ih != null) {
  374. Instruction i = ih.getInstruction();
  375. // An "own" constraint, due to JustIce's new definition of what "subroutine" means.
  376. if (i.isJsrInstruction()) {
  377. InstructionHandle target = ((InstructionBranch) i).getTarget();
  378. if (target == instructionList.getStart()) {
  379. throw new StaticCodeInstructionOperandConstraintException(
  380. "Due to JustIce's clear definition of subroutines, no JSR or JSR_W may have a top-level instruction (such as the very first instruction, which is targeted by instruction '"
  381. + ih + "' as its target.");
  382. }
  383. if (!target.getInstruction().isASTORE()) {
  384. throw new StaticCodeInstructionOperandConstraintException(
  385. "Due to JustIce's clear definition of subroutines, no JSR or JSR_W may target anything else than an ASTORE instruction. Instruction '"
  386. + ih + "' targets '" + target + "'.");
  387. }
  388. }
  389. // vmspec2, page 134-137
  390. InstructionWalker.accept(ih.getInstruction(), v);
  391. ih = ih.getNext();
  392. }
  393. }
  394. /** A small utility method returning if a given int i is in the given int[] ints. */
  395. private static boolean contains(int[] ints, int i) {
  396. for (int j = 0; j < ints.length; j++) {
  397. if (ints[j] == i) {
  398. return true;
  399. }
  400. }
  401. return false;
  402. }
  403. /** Returns the method number as supplied when instantiating. */
  404. public int getMethodNo() {
  405. return method_no;
  406. }
  407. /**
  408. * This visitor class does the actual checking for the instruction operand's constraints.
  409. */
  410. private class InstOperandConstraintVisitor extends org.aspectj.apache.bcel.verifier.EmptyInstVisitor {
  411. /** The ConstantPoolGen instance this Visitor operates on. */
  412. private final ConstantPool cpg;
  413. /** The only Constructor. */
  414. InstOperandConstraintVisitor(ConstantPool cpg) {
  415. this.cpg = cpg;
  416. }
  417. /**
  418. * Utility method to return the max_locals value of the method verified by the surrounding Pass3aVerifier instance.
  419. */
  420. private int max_locals() {
  421. return Repository.lookupClass(myOwner.getClassName()).getMethods()[method_no].getCode().getMaxLocals();
  422. }
  423. /**
  424. * A utility method to always raise an exeption.
  425. */
  426. private void constraintViolated(Instruction i, String message) {
  427. throw new StaticCodeInstructionOperandConstraintException("Instruction " + i + " constraint violated: " + message);
  428. }
  429. /**
  430. * A utility method to raise an exception if the index is not a valid constant pool index.
  431. */
  432. private void indexValid(Instruction i, int idx) {
  433. if (idx < 0 || idx >= cpg.getSize()) {
  434. constraintViolated(i, "Illegal constant pool index '" + idx + "'.");
  435. }
  436. }
  437. // /////////////////////////////////////////////////////////
  438. // The Java Virtual Machine Specification, pages 134-137 //
  439. // /////////////////////////////////////////////////////////
  440. /**
  441. * Assures the generic preconditions of a LoadClass instance. The referenced class is loaded and pass2-verified.
  442. */
  443. @Override
  444. public void visitLoadClass(Instruction o) {
  445. ObjectType t = o.getLoadClassType(cpg);
  446. if (t != null) {// null means "no class is loaded"
  447. Verifier v = VerifierFactory.getVerifier(t.getClassName());
  448. VerificationResult vr = v.doPass1();
  449. if (vr.getStatus() != VerificationResult.VERIFIED_OK) {
  450. constraintViolated(o, "Class '" + o.getLoadClassType(cpg).getClassName()
  451. + "' is referenced, but cannot be loaded: '" + vr + "'.");
  452. }
  453. }
  454. }
  455. // The target of each jump and branch instruction [...] must be the opcode [...]
  456. // BCEL _DOES_ handle this.
  457. // tableswitch: BCEL will do it, supposedly.
  458. // lookupswitch: BCEL will do it, supposedly.
  459. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  460. // LDC and LDC_W (LDC_W is a subclass of LDC in BCEL's model)
  461. @Override
  462. public void visitLDC(Instruction o) {
  463. indexValid(o, o.getIndex());
  464. Constant c = cpg.getConstant(o.getIndex());
  465. if (!(c instanceof ConstantInteger || c instanceof ConstantFloat || c instanceof ConstantString)) {
  466. constraintViolated(o,
  467. "Operand of LDC or LDC_W must be one of CONSTANT_Integer, CONSTANT_Float or CONSTANT_String, but is '" + c
  468. + "'.");
  469. }
  470. }
  471. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  472. // LDC2_W
  473. @Override
  474. public void visitLDC2_W(Instruction o) {
  475. indexValid(o, o.getIndex());
  476. Constant c = cpg.getConstant(o.getIndex());
  477. if (!(c instanceof ConstantLong || c instanceof ConstantDouble)) {
  478. constraintViolated(o, "Operand of LDC2_W must be CONSTANT_Long or CONSTANT_Double, but is '" + c + "'.");
  479. }
  480. try {
  481. indexValid(o, o.getIndex() + 1);
  482. } catch (StaticCodeInstructionOperandConstraintException e) {
  483. throw new AssertionViolatedException("OOPS: Does not BCEL handle that? LDC2_W operand has a problem.");
  484. }
  485. }
  486. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  487. // getfield, putfield, getstatic, putstatic
  488. public void visitFieldInstruction(FieldInstruction o) {
  489. indexValid(o, o.getIndex());
  490. Constant c = cpg.getConstant(o.getIndex());
  491. if (!(c instanceof ConstantFieldref)) {
  492. constraintViolated(o, "Indexing a constant that's not a CONSTANT_Fieldref but a '" + c + "'.");
  493. }
  494. String field_name = o.getFieldName(cpg);
  495. JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
  496. Field[] fields = jc.getFields();
  497. Field f = null;
  498. for (int i = 0; i < fields.length; i++) {
  499. if (fields[i].getName().equals(field_name)) {
  500. f = fields[i];
  501. break;
  502. }
  503. }
  504. if (f == null) {
  505. /* TODO: also look up if the field is inherited! */
  506. constraintViolated(o, "Referenced field '" + field_name + "' does not exist in class '" + jc.getClassName() + "'.");
  507. } else {
  508. /*
  509. * TODO: Check if assignment compatibility is sufficient. What does Sun do?
  510. */
  511. Type f_type = Type.getType(f.getSignature());
  512. Type o_type = o.getType(cpg);
  513. /*
  514. * TODO: Is there a way to make BCEL tell us if a field has a void method's signature, i.e. "()I" instead of "I"?
  515. */
  516. if (!f_type.equals(o_type)) {
  517. constraintViolated(o, "Referenced field '" + field_name + "' has type '" + f_type + "' instead of '" + o_type
  518. + "' as expected.");
  519. }
  520. /* TODO: Check for access modifiers here. */
  521. }
  522. }
  523. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  524. @Override
  525. public void visitInvokeInstruction(InvokeInstruction o) {
  526. indexValid(o, o.getIndex());
  527. if (o.getOpcode() == Constants.INVOKEVIRTUAL || o.getOpcode() == Constants.INVOKESPECIAL
  528. || o.getOpcode() == Constants.INVOKESTATIC) {
  529. Constant c = cpg.getConstant(o.getIndex());
  530. if (!(c instanceof ConstantMethodref)) {
  531. constraintViolated(o, "Indexing a constant that's not a CONSTANT_Methodref but a '" + c + "'.");
  532. } else {
  533. // Constants are okay due to pass2.
  534. ConstantNameAndType cnat = (ConstantNameAndType) cpg.getConstant(((ConstantMethodref) c).getNameAndTypeIndex());
  535. ConstantUtf8 cutf8 = (ConstantUtf8) cpg.getConstant(cnat.getNameIndex());
  536. if (cutf8.getValue().equals(Constants.CONSTRUCTOR_NAME) && !(o.getOpcode() == Constants.INVOKESPECIAL)) {
  537. constraintViolated(o, "Only INVOKESPECIAL is allowed to invoke instance initialization methods.");
  538. }
  539. if (!cutf8.getValue().equals(Constants.CONSTRUCTOR_NAME) && cutf8.getValue().startsWith("<")) {
  540. constraintViolated(
  541. o,
  542. "No method with a name beginning with '<' other than the instance initialization methods may be called by the method invocation instructions.");
  543. }
  544. }
  545. } else { // if (o instanceof INVOKEINTERFACE){
  546. Constant c = cpg.getConstant(o.getIndex());
  547. if (!(c instanceof ConstantInterfaceMethodref)) {
  548. constraintViolated(o, "Indexing a constant that's not a CONSTANT_InterfaceMethodref but a '" + c + "'.");
  549. }
  550. // TODO: From time to time check if BCEL allows to detect if the
  551. // 'count' operand is consistent with the information in the
  552. // CONSTANT_InterfaceMethodref and if the last operand is zero.
  553. // By now, BCEL hides those two operands because they're superfluous.
  554. // Invoked method must not be <init> or <clinit>
  555. ConstantNameAndType cnat = (ConstantNameAndType) cpg.getConstant(((ConstantInterfaceMethodref) c)
  556. .getNameAndTypeIndex());
  557. String name = ((ConstantUtf8) cpg.getConstant(cnat.getNameIndex())).getValue();
  558. if (name.equals(Constants.CONSTRUCTOR_NAME)) {
  559. constraintViolated(o, "Method to invoke must not be '" + Constants.CONSTRUCTOR_NAME + "'.");
  560. }
  561. if (name.equals(Constants.STATIC_INITIALIZER_NAME)) {
  562. constraintViolated(o, "Method to invoke must not be '" + Constants.STATIC_INITIALIZER_NAME + "'.");
  563. }
  564. }
  565. // The LoadClassType is the method-declaring class, so we have to check the other types.
  566. Type t = o.getReturnType(cpg);
  567. if (t instanceof ArrayType) {
  568. t = ((ArrayType) t).getBasicType();
  569. }
  570. if (t instanceof ObjectType) {
  571. Verifier v = VerifierFactory.getVerifier(((ObjectType) t).getClassName());
  572. VerificationResult vr = v.doPass2();
  573. if (vr.getStatus() != VerificationResult.VERIFIED_OK) {
  574. constraintViolated(o, "Return type class/interface could not be verified successfully: '" + vr.getMessage()
  575. + "'.");
  576. }
  577. }
  578. Type[] ts = o.getArgumentTypes(cpg);
  579. for (int i = 0; i < ts.length; i++) {
  580. t = ts[i];
  581. if (t instanceof ArrayType) {
  582. t = ((ArrayType) t).getBasicType();
  583. }
  584. if (t instanceof ObjectType) {
  585. Verifier v = VerifierFactory.getVerifier(((ObjectType) t).getClassName());
  586. VerificationResult vr = v.doPass2();
  587. if (vr.getStatus() != VerificationResult.VERIFIED_OK) {
  588. constraintViolated(o, "Argument type class/interface could not be verified successfully: '"
  589. + vr.getMessage() + "'.");
  590. }
  591. }
  592. }
  593. }
  594. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  595. @Override
  596. public void visitINSTANCEOF(Instruction o) {
  597. indexValid(o, o.getIndex());
  598. Constant c = cpg.getConstant(o.getIndex());
  599. if (!(c instanceof ConstantClass)) {
  600. constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '" + c + "'.");
  601. }
  602. }
  603. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  604. @Override
  605. public void visitCHECKCAST(Instruction o) {
  606. indexValid(o, o.getIndex());
  607. Constant c = cpg.getConstant(o.getIndex());
  608. if (!(c instanceof ConstantClass)) {
  609. constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '" + c + "'.");
  610. }
  611. }
  612. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  613. @Override
  614. public void visitNEW(Instruction o) {
  615. indexValid(o, o.getIndex());
  616. Constant c = cpg.getConstant(o.getIndex());
  617. if (!(c instanceof ConstantClass)) {
  618. constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '" + c + "'.");
  619. } else {
  620. ConstantUtf8 cutf8 = (ConstantUtf8) cpg.getConstant(((ConstantClass) c).getNameIndex());
  621. Type t = Type.getType("L" + cutf8.getValue() + ";");
  622. if (t instanceof ArrayType) {
  623. constraintViolated(o, "NEW must not be used to create an array.");
  624. }
  625. }
  626. }
  627. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  628. public void visitMULTIANEWARRAY(MULTIANEWARRAY o) {
  629. indexValid(o, o.getIndex());
  630. Constant c = cpg.getConstant(o.getIndex());
  631. if (!(c instanceof ConstantClass)) {
  632. constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '" + c + "'.");
  633. }
  634. int dimensions2create = o.getDimensions();
  635. if (dimensions2create < 1) {
  636. constraintViolated(o, "Number of dimensions to create must be greater than zero.");
  637. }
  638. Type t = o.getType(cpg);
  639. if (t instanceof ArrayType) {
  640. int dimensions = ((ArrayType) t).getDimensions();
  641. if (dimensions < dimensions2create) {
  642. constraintViolated(o,
  643. "Not allowed to create array with more dimensions ('+dimensions2create+') than the one referenced by the CONSTANT_Class '"
  644. + t + "'.");
  645. }
  646. } else {
  647. constraintViolated(
  648. o,
  649. "Expecting a CONSTANT_Class referencing an array type. [Constraint not found in The Java Virtual Machine Specification, Second Edition, 4.8.1]");
  650. }
  651. }
  652. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  653. public void visitANEWARRAY(Instruction o) {
  654. indexValid(o, o.getIndex());
  655. Constant c = cpg.getConstant(o.getIndex());
  656. if (!(c instanceof ConstantClass)) {
  657. constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '" + c + "'.");
  658. }
  659. Type t = o.getType(cpg);
  660. if (t instanceof ArrayType) {
  661. int dimensions = ((ArrayType) t).getDimensions();
  662. if (dimensions >= 255) {
  663. constraintViolated(o, "Not allowed to create an array with more than 255 dimensions.");
  664. }
  665. }
  666. }
  667. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  668. public void visitNEWARRAY(Instruction o) {
  669. byte t = ((InstructionByte) o).getTypecode();
  670. if (!(t == Constants.T_BOOLEAN || t == Constants.T_CHAR || t == Constants.T_FLOAT || t == Constants.T_DOUBLE
  671. || t == Constants.T_BYTE || t == Constants.T_SHORT || t == Constants.T_INT || t == Constants.T_LONG)) {
  672. constraintViolated(o, "Illegal type code '+t+' for 'atype' operand.");
  673. }
  674. }
  675. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  676. public void visitILOAD(Instruction o) {
  677. int idx = o.getIndex();
  678. if (idx < 0) {
  679. constraintViolated(o, "Index '" + idx + "' must be non-negative.");
  680. } else {
  681. int maxminus1 = max_locals() - 1;
  682. if (idx > maxminus1) {
  683. constraintViolated(o, "Index '" + idx + "' must not be greater than max_locals-1 '" + maxminus1 + "'.");
  684. }
  685. }
  686. }
  687. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  688. public void visitFLOAD(Instruction o) {
  689. int idx = o.getIndex();
  690. if (idx < 0) {
  691. constraintViolated(o, "Index '" + idx + "' must be non-negative.");
  692. } else {
  693. int maxminus1 = max_locals() - 1;
  694. if (idx > maxminus1) {
  695. constraintViolated(o, "Index '" + idx + "' must not be greater than max_locals-1 '" + maxminus1 + "'.");
  696. }
  697. }
  698. }
  699. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  700. public void visitALOAD(Instruction o) {
  701. int idx = o.getIndex();
  702. if (idx < 0) {
  703. constraintViolated(o, "Index '" + idx + "' must be non-negative.");
  704. } else {
  705. int maxminus1 = max_locals() - 1;
  706. if (idx > maxminus1) {
  707. constraintViolated(o, "Index '" + idx + "' must not be greater than max_locals-1 '" + maxminus1 + "'.");
  708. }
  709. }
  710. }
  711. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  712. public void visitISTORE(Instruction o) {
  713. int idx = o.getIndex();
  714. if (idx < 0) {
  715. constraintViolated(o, "Index '" + idx + "' must be non-negative.");
  716. } else {
  717. int maxminus1 = max_locals() - 1;
  718. if (idx > maxminus1) {
  719. constraintViolated(o, "Index '" + idx + "' must not be greater than max_locals-1 '" + maxminus1 + "'.");
  720. }
  721. }
  722. }
  723. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  724. public void visitFSTORE(Instruction o) {
  725. int idx = o.getIndex();
  726. if (idx < 0) {
  727. constraintViolated(o, "Index '" + idx + "' must be non-negative.");
  728. } else {
  729. int maxminus1 = max_locals() - 1;
  730. if (idx > maxminus1) {
  731. constraintViolated(o, "Index '" + idx + "' must not be greater than max_locals-1 '" + maxminus1 + "'.");
  732. }
  733. }
  734. }
  735. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  736. public void visitASTORE(Instruction o) {
  737. int idx = o.getIndex();
  738. if (idx < 0) {
  739. constraintViolated(o, "Index '" + idx + "' must be non-negative.");
  740. } else {
  741. int maxminus1 = max_locals() - 1;
  742. if (idx > maxminus1) {
  743. constraintViolated(o, "Index '" + idx + "' must not be greater than max_locals-1 '" + maxminus1 + "'.");
  744. }
  745. }
  746. }
  747. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  748. public void visitIINC(IINC o) {
  749. int idx = o.getIndex();
  750. if (idx < 0) {
  751. constraintViolated(o, "Index '" + idx + "' must be non-negative.");
  752. } else {
  753. int maxminus1 = max_locals() - 1;
  754. if (idx > maxminus1) {
  755. constraintViolated(o, "Index '" + idx + "' must not be greater than max_locals-1 '" + maxminus1 + "'.");
  756. }
  757. }
  758. }
  759. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  760. public void visitRET(RET o) {
  761. int idx = o.getIndex();
  762. if (idx < 0) {
  763. constraintViolated(o, "Index '" + idx + "' must be non-negative.");
  764. } else {
  765. int maxminus1 = max_locals() - 1;
  766. if (idx > maxminus1) {
  767. constraintViolated(o, "Index '" + idx + "' must not be greater than max_locals-1 '" + maxminus1 + "'.");
  768. }
  769. }
  770. }
  771. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  772. public void visitLLOAD(Instruction o) {
  773. int idx = o.getIndex();
  774. if (idx < 0) {
  775. constraintViolated(
  776. o,
  777. "Index '"
  778. + idx
  779. + "' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
  780. } else {
  781. int maxminus2 = max_locals() - 2;
  782. if (idx > maxminus2) {
  783. constraintViolated(o, "Index '" + idx + "' must not be greater than max_locals-2 '" + maxminus2 + "'.");
  784. }
  785. }
  786. }
  787. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  788. public void visitDLOAD(Instruction o) {
  789. int idx = o.getIndex();
  790. if (idx < 0) {
  791. constraintViolated(
  792. o,
  793. "Index '"
  794. + idx
  795. + "' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
  796. } else {
  797. int maxminus2 = max_locals() - 2;
  798. if (idx > maxminus2) {
  799. constraintViolated(o, "Index '" + idx + "' must not be greater than max_locals-2 '" + maxminus2 + "'.");
  800. }
  801. }
  802. }
  803. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  804. public void visitLSTORE(Instruction o) {
  805. int idx = o.getIndex();
  806. if (idx < 0) {
  807. constraintViolated(
  808. o,
  809. "Index '"
  810. + idx
  811. + "' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
  812. } else {
  813. int maxminus2 = max_locals() - 2;
  814. if (idx > maxminus2) {
  815. constraintViolated(o, "Index '" + idx + "' must not be greater than max_locals-2 '" + maxminus2 + "'.");
  816. }
  817. }
  818. }
  819. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  820. public void visitDSTORE(Instruction o) {
  821. int idx = o.getIndex();
  822. if (idx < 0) {
  823. constraintViolated(
  824. o,
  825. "Index '"
  826. + idx
  827. + "' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
  828. } else {
  829. int maxminus2 = max_locals() - 2;
  830. if (idx > maxminus2) {
  831. constraintViolated(o, "Index '" + idx + "' must not be greater than max_locals-2 '" + maxminus2 + "'.");
  832. }
  833. }
  834. }
  835. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  836. public void visitLOOKUPSWITCH(LOOKUPSWITCH o) {
  837. int[] matchs = o.getMatchs();
  838. int max = Integer.MIN_VALUE;
  839. for (int i = 0; i < matchs.length; i++) {
  840. if (matchs[i] == max && i != 0) {
  841. constraintViolated(o, "Match '" + matchs[i] + "' occurs more than once.");
  842. }
  843. if (matchs[i] < max) {
  844. constraintViolated(o, "Lookup table must be sorted but isn't.");
  845. } else {
  846. max = matchs[i];
  847. }
  848. }
  849. }
  850. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  851. public void visitTABLESWITCH(TABLESWITCH o) {
  852. // "high" must be >= "low". We cannot check this, as BCEL hides
  853. // it from us.
  854. }
  855. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  856. public void visitPUTSTATIC(FieldInstruction o) {
  857. String field_name = o.getFieldName(cpg);
  858. JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
  859. Field[] fields = jc.getFields();
  860. Field f = null;
  861. for (int i = 0; i < fields.length; i++) {
  862. if (fields[i].getName().equals(field_name)) {
  863. f = fields[i];
  864. break;
  865. }
  866. }
  867. if (f == null) {
  868. throw new AssertionViolatedException("Field not found?!?");
  869. }
  870. if (f.isFinal()) {
  871. if (!myOwner.getClassName().equals(o.getClassType(cpg).getClassName())) {
  872. constraintViolated(o, "Referenced field '" + f
  873. + "' is final and must therefore be declared in the current class '" + myOwner.getClassName()
  874. + "' which is not the case: it is declared in '" + o.getClassType(cpg).getClassName() + "'.");
  875. }
  876. }
  877. if (!f.isStatic()) {
  878. constraintViolated(o, "Referenced field '" + f + "' is not static which it should be.");
  879. }
  880. String meth_name = Repository.lookupClass(myOwner.getClassName()).getMethods()[method_no].getName();
  881. // If it's an interface, it can be set only in <clinit>.
  882. if (!jc.isClass() && !meth_name.equals(Constants.STATIC_INITIALIZER_NAME)) {
  883. constraintViolated(o, "Interface field '" + f + "' must be set in a '" + Constants.STATIC_INITIALIZER_NAME
  884. + "' method.");
  885. }
  886. }
  887. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  888. public void visitGETSTATIC(FieldInstruction o) {
  889. String field_name = o.getFieldName(cpg);
  890. JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
  891. Field[] fields = jc.getFields();
  892. Field f = null;
  893. for (int i = 0; i < fields.length; i++) {
  894. if (fields[i].getName().equals(field_name)) {
  895. f = fields[i];
  896. break;
  897. }
  898. }
  899. if (f == null) {
  900. throw new AssertionViolatedException("Field not found?!?");
  901. }
  902. if (!f.isStatic()) {
  903. constraintViolated(o, "Referenced field '" + f + "' is not static which it should be.");
  904. }
  905. }
  906. /* Checks if the constraints of operands of the said instruction(s) are satisfied. */
  907. // public void visitPUTFIELD(PUTFIELD o){
  908. // for performance reasons done in Pass 3b
  909. // }
  910. /* Checks if the constraints of operands of the said instruction(s) are satisfied. */
  911. // public void visitGETFIELD(GETFIELD o){
  912. // for performance reasons done in Pass 3b
  913. // }
  914. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  915. public void visitINVOKEINTERFACE(INVOKEINTERFACE o) {
  916. // INVOKEINTERFACE is a LoadClass; the Class where the referenced method is declared in,
  917. // is therefore resolved/verified.
  918. // INVOKEINTERFACE is an InvokeInstruction, the argument and return types are resolved/verified,
  919. // too. So are the allowed method names.
  920. String classname = o.getClassName(cpg);
  921. JavaClass jc = Repository.lookupClass(classname);
  922. Method[] ms = jc.getMethods();
  923. Method m = null;
  924. for (int i = 0; i < ms.length; i++) {
  925. if (ms[i].getName().equals(o.getMethodName(cpg))
  926. && Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))
  927. && objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) {
  928. m = ms[i];
  929. break;
  930. }
  931. }
  932. if (m == null) {
  933. constraintViolated(
  934. o,
  935. "Referenced method '"
  936. + o.getMethodName(cpg)
  937. + "' with expected signature not found in class '"
  938. + jc.getClassName()
  939. + "'. The native verfier does allow the method to be declared in some superinterface, which the Java Virtual Machine Specification, Second Edition does not.");
  940. }
  941. if (jc.isClass()) {
  942. constraintViolated(o, "Referenced class '" + jc.getClassName() + "' is a class, but not an interface as expected.");
  943. }
  944. }
  945. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  946. public void visitINVOKESPECIAL(InvokeInstruction o) {
  947. // INVOKESPECIAL is a LoadClass; the Class where the referenced method is declared in,
  948. // is therefore resolved/verified.
  949. // INVOKESPECIAL is an InvokeInstruction, the argument and return types are resolved/verified,
  950. // too. So are the allowed method names.
  951. String classname = o.getClassName(cpg);
  952. JavaClass jc = Repository.lookupClass(classname);
  953. Method[] ms = jc.getMethods();
  954. Method m = null;
  955. for (int i = 0; i < ms.length; i++) {
  956. if (ms[i].getName().equals(o.getMethodName(cpg))
  957. && Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))
  958. && objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) {
  959. m = ms[i];
  960. break;
  961. }
  962. }
  963. if (m == null) {
  964. constraintViolated(
  965. o,
  966. "Referenced method '"
  967. + o.getMethodName(cpg)
  968. + "' with expected signature not found in class '"
  969. + jc.getClassName()
  970. + "'. The native verfier does allow the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not.");
  971. }
  972. JavaClass current = Repository.lookupClass(myOwner.getClassName());
  973. if (current.isSuper()) {
  974. if (Repository.instanceOf(current, jc) && !current.equals(jc)) {
  975. if (!o.getMethodName(cpg).equals(Constants.CONSTRUCTOR_NAME)) {
  976. // Special lookup procedure for ACC_SUPER classes.
  977. int supidx = -1;
  978. Method meth = null;
  979. while (supidx != 0) {
  980. supidx = current.getSuperclassNameIndex();
  981. current = Repository.lookupClass(current.getSuperclassName());
  982. Method[] meths = current.getMethods();
  983. for (int i = 0; i < meths.length; i++) {
  984. if (meths[i].getName().equals(o.getMethodName(cpg))
  985. && Type.getReturnType(meths[i].getSignature()).equals(o.getReturnType(cpg))
  986. && objarrayequals(Type.getArgumentTypes(meths[i].getSignature()), o.getArgumentTypes(cpg))) {
  987. meth = meths[i];
  988. break;
  989. }
  990. }
  991. if (meth != null) {
  992. break;
  993. }
  994. }
  995. if (meth == null) {
  996. constraintViolated(o, "ACC_SUPER special lookup procedure not successful: method '"
  997. + o.getMethodName(cpg) + "' with proper signature not declared in superclass hierarchy.");
  998. }
  999. }
  1000. }
  1001. }
  1002. }
  1003. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  1004. public void visitINVOKESTATIC(InvokeInstruction o) {
  1005. // INVOKESTATIC is a LoadClass; the Class where the referenced method is declared in,
  1006. // is therefore resolved/verified.
  1007. // INVOKESTATIC is an InvokeInstruction, the argument and return types are resolved/verified,
  1008. // too. So are the allowed method names.
  1009. String classname = o.getClassName(cpg);
  1010. JavaClass jc = Repository.lookupClass(classname);
  1011. Method[] ms = jc.getMethods();
  1012. Method m = null;
  1013. for (int i = 0; i < ms.length; i++) {
  1014. if (ms[i].getName().equals(o.getMethodName(cpg))
  1015. && Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))
  1016. && objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) {
  1017. m = ms[i];
  1018. break;
  1019. }
  1020. }
  1021. if (m == null) {
  1022. constraintViolated(
  1023. o,
  1024. "Referenced method '"
  1025. + o.getMethodName(cpg)
  1026. + "' with expected signature not found in class '"
  1027. + jc.getClassName()
  1028. + "'. The native verifier possibly allows the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not.");
  1029. }
  1030. if (!m.isStatic()) { // implies it's not abstract, verified in pass 2.
  1031. constraintViolated(o, "Referenced method '" + o.getMethodName(cpg) + "' has ACC_STATIC unset.");
  1032. }
  1033. }
  1034. /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
  1035. public void visitINVOKEVIRTUAL(InvokeInstruction o) {
  1036. // INVOKEVIRTUAL is a LoadClass; the Class where the referenced method is declared in,
  1037. // is therefore resolved/verified.
  1038. // INVOKEVIRTUAL is an InvokeInstruction, the argument and return types are resolved/verified,
  1039. // too. So are the allowed method names.
  1040. String classname = o.getClassName(cpg);
  1041. JavaClass jc = Repository.lookupClass(classname);
  1042. Method[] ms = jc.getMethods();
  1043. Method m = null;
  1044. for (int i = 0; i < ms.length; i++) {
  1045. if (ms[i].getName().equals(o.getMethodName(cpg))
  1046. && Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))
  1047. && objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) {
  1048. m = ms[i];
  1049. break;
  1050. }
  1051. }
  1052. if (m == null) {
  1053. constraintViolated(
  1054. o,
  1055. "Referenced method '"
  1056. + o.getMethodName(cpg)
  1057. + "' with expected signature not found in class '"
  1058. + jc.getClassName()
  1059. + "'. The native verfier does allow the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not.");
  1060. }
  1061. if (!jc.isClass()) {
  1062. constraintViolated(o, "Referenced class '" + jc.getClassName() + "' is an interface, but not a class as expected.");
  1063. }
  1064. }
  1065. // WIDE stuff is BCEL-internal and cannot be checked here.
  1066. /**
  1067. * A utility method like equals(Object) for arrays. The equality of the elements is based on their equals(Object) method
  1068. * instead of their object identity.
  1069. */
  1070. private boolean objarrayequals(Object[] o, Object[] p) {
  1071. if (o.length != p.length) {
  1072. return false;
  1073. }
  1074. for (int i = 0; i < o.length; i++) {
  1075. if (!o[i].equals(p[i])) {
  1076. return false;
  1077. }
  1078. }
  1079. return true;
  1080. }
  1081. }
  1082. }