1 17 package org.apache.bcel.verifier.statics; 18 19 20 import java.util.HashMap ; 21 import java.util.HashSet ; 22 import java.util.Locale ; 23 import java.util.Map ; 24 import java.util.Set ; 25 import org.apache.bcel.Constants; 26 import org.apache.bcel.Repository; 27 import org.apache.bcel.classfile.Attribute; 28 import org.apache.bcel.classfile.ClassFormatException; 29 import org.apache.bcel.classfile.Code; 30 import org.apache.bcel.classfile.CodeException; 31 import org.apache.bcel.classfile.Constant; 32 import org.apache.bcel.classfile.ConstantClass; 33 import org.apache.bcel.classfile.ConstantDouble; 34 import org.apache.bcel.classfile.ConstantFieldref; 35 import org.apache.bcel.classfile.ConstantFloat; 36 import org.apache.bcel.classfile.ConstantInteger; 37 import org.apache.bcel.classfile.ConstantInterfaceMethodref; 38 import org.apache.bcel.classfile.ConstantLong; 39 import org.apache.bcel.classfile.ConstantMethodref; 40 import org.apache.bcel.classfile.ConstantNameAndType; 41 import org.apache.bcel.classfile.ConstantPool; 42 import org.apache.bcel.classfile.ConstantString; 43 import org.apache.bcel.classfile.ConstantUtf8; 44 import org.apache.bcel.classfile.ConstantValue; 45 import org.apache.bcel.classfile.Deprecated; 46 import org.apache.bcel.classfile.DescendingVisitor; 47 import org.apache.bcel.classfile.EmptyVisitor; 48 import org.apache.bcel.classfile.ExceptionTable; 49 import org.apache.bcel.classfile.Field; 50 import org.apache.bcel.classfile.InnerClass; 51 import org.apache.bcel.classfile.InnerClasses; 52 import org.apache.bcel.classfile.JavaClass; 53 import org.apache.bcel.classfile.LineNumber; 54 import org.apache.bcel.classfile.LineNumberTable; 55 import org.apache.bcel.classfile.LocalVariable; 56 import org.apache.bcel.classfile.LocalVariableTable; 57 import org.apache.bcel.classfile.Method; 58 import org.apache.bcel.classfile.Node; 59 import org.apache.bcel.classfile.SourceFile; 60 import org.apache.bcel.classfile.Synthetic; 61 import org.apache.bcel.classfile.Unknown; 62 import org.apache.bcel.classfile.Visitor; 63 import org.apache.bcel.generic.ArrayType; 64 import org.apache.bcel.generic.ObjectType; 65 import org.apache.bcel.generic.Type; 66 import org.apache.bcel.verifier.PassVerifier; 67 import org.apache.bcel.verifier.VerificationResult; 68 import org.apache.bcel.verifier.Verifier; 69 import org.apache.bcel.verifier.VerifierFactory; 70 import org.apache.bcel.verifier.exc.AssertionViolatedException; 71 import org.apache.bcel.verifier.exc.ClassConstraintException; 72 import org.apache.bcel.verifier.exc.LocalVariableInfoInconsistentException; 73 74 85 public final class Pass2Verifier extends PassVerifier implements Constants{ 86 87 93 private LocalVariablesInfo[] localVariablesInfos; 94 95 96 private Verifier myOwner; 97 98 103 public Pass2Verifier(Verifier owner){ 104 myOwner = owner; 105 } 106 107 116 public LocalVariablesInfo getLocalVariablesInfo(int method_nr){ 117 if (this.verify() != VerificationResult.VR_OK) { 118 return null; } 120 if (method_nr < 0 || method_nr >= localVariablesInfos.length){ 121 throw new AssertionViolatedException("Method number out of range."); 122 } 123 return localVariablesInfos[method_nr]; 124 } 125 126 148 public VerificationResult do_verify(){ 149 try { 150 VerificationResult vr1 = myOwner.doPass1(); 151 if (vr1.equals(VerificationResult.VR_OK)){ 152 153 localVariablesInfos = new LocalVariablesInfo[Repository.lookupClass(myOwner.getClassName()).getMethods().length]; 156 157 VerificationResult vr = VerificationResult.VR_OK; try{ 159 constant_pool_entries_satisfy_static_constraints(); 160 field_and_method_refs_are_valid(); 161 every_class_has_an_accessible_superclass(); 162 final_methods_are_not_overridden(); 163 } 164 catch (ClassConstraintException cce){ 165 vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, cce.getMessage()); 166 } 167 return vr; 168 } else { 169 return VerificationResult.VR_NOTYET; 170 } 171 172 } catch (ClassNotFoundException e) { 173 throw new AssertionViolatedException("Missing class: " + e.toString()); 175 } 176 } 177 178 191 private void every_class_has_an_accessible_superclass(){ 192 try { 193 Set hs = new HashSet (); JavaClass jc = Repository.lookupClass(myOwner.getClassName()); 195 int supidx = -1; 196 197 while (supidx != 0){ 198 supidx = jc.getSuperclassNameIndex(); 199 200 if (supidx == 0){ 201 if (jc != Repository.lookupClass(Type.OBJECT.getClassName())){ 202 throw new ClassConstraintException("Superclass of '"+jc.getClassName()+"' missing but not "+Type.OBJECT.getClassName()+" itself!"); 203 } 204 } 205 else{ 206 String supername = jc.getSuperclassName(); 207 if (! hs.add(supername)){ throw new ClassConstraintException("Circular superclass hierarchy detected."); 209 } 210 Verifier v = VerifierFactory.getVerifier(supername); 211 VerificationResult vr = v.doPass1(); 212 213 if (vr != VerificationResult.VR_OK){ 214 throw new ClassConstraintException("Could not load in ancestor class '"+supername+"'."); 215 } 216 jc = Repository.lookupClass(supername); 217 218 if (jc.isFinal()){ 219 throw new ClassConstraintException("Ancestor class '"+supername+"' has the FINAL access modifier and must therefore not be subclassed."); 220 } 221 } 222 } 223 224 } catch (ClassNotFoundException e) { 225 throw new AssertionViolatedException("Missing class: " + e.toString()); 227 } 228 } 229 230 241 private void final_methods_are_not_overridden(){ 242 try { 243 Map hashmap = new HashMap (); 244 JavaClass jc = Repository.lookupClass(myOwner.getClassName()); 245 246 int supidx = -1; 247 while (supidx != 0){ 248 supidx = jc.getSuperclassNameIndex(); 249 250 Method[] methods = jc.getMethods(); 251 for (int i=0; i<methods.length; i++){ 252 String name_and_sig = (methods[i].getName()+methods[i].getSignature()); 253 254 if (hashmap.containsKey(name_and_sig)){ 255 if ( methods[i].isFinal() ){ 256 if (!(methods[i].isPrivate())) { 257 throw new ClassConstraintException("Method '"+name_and_sig+"' in class '"+hashmap.get(name_and_sig)+"' overrides the final (not-overridable) definition in class '"+jc.getClassName()+"'."); 258 } 259 else{ 260 addMessage("Method '"+name_and_sig+"' in class '"+hashmap.get(name_and_sig)+"' overrides the final (not-overridable) definition in class '"+jc.getClassName()+"'. This is okay, as the original definition was private; however this constraint leverage was introduced by JLS 8.4.6 (not vmspec2) and the behaviour of the Sun verifiers."); 261 } 262 } 263 else{ 264 if (!methods[i].isStatic()){ hashmap.put(name_and_sig, jc.getClassName()); 266 } 267 } 268 } 269 else{ 270 if (!methods[i].isStatic()){ hashmap.put(name_and_sig, jc.getClassName()); 272 } 273 } 274 } 275 276 jc = Repository.lookupClass(jc.getSuperclassName()); } 278 279 } catch (ClassNotFoundException e) { 280 throw new AssertionViolatedException("Missing class: " + e.toString()); 282 } 283 284 } 285 286 292 private void constant_pool_entries_satisfy_static_constraints(){ 293 try { 294 JavaClass jc = Repository.lookupClass(myOwner.getClassName()); 298 new CPESSC_Visitor(jc); 300 } catch (ClassNotFoundException e) { 301 throw new AssertionViolatedException("Missing class: " + e.toString()); 303 } 304 } 305 306 313 private class CPESSC_Visitor extends org.apache.bcel.classfile.EmptyVisitor implements Visitor{ 314 private Class CONST_Class; 315 320 private Class CONST_String; 321 private Class CONST_Integer; 322 private Class CONST_Float; 323 private Class CONST_Long; 324 private Class CONST_Double; 325 private Class CONST_NameAndType; 326 private Class CONST_Utf8; 327 328 private final JavaClass jc; 329 private final ConstantPool cp; private final int cplen; private DescendingVisitor carrier; 332 333 private Set field_names = new HashSet (); 334 private Set field_names_and_desc = new HashSet (); 335 private Set method_names_and_desc = new HashSet (); 336 337 private CPESSC_Visitor(JavaClass _jc){ 338 jc = _jc; 339 cp = _jc.getConstantPool(); 340 cplen = cp.getLength(); 341 342 CONST_Class = org.apache.bcel.classfile.ConstantClass.class; 343 348 CONST_String = org.apache.bcel.classfile.ConstantString.class; 349 CONST_Integer = org.apache.bcel.classfile.ConstantInteger.class; 350 CONST_Float = org.apache.bcel.classfile.ConstantFloat.class; 351 CONST_Long = org.apache.bcel.classfile.ConstantLong.class; 352 CONST_Double = org.apache.bcel.classfile.ConstantDouble.class; 353 CONST_NameAndType = org.apache.bcel.classfile.ConstantNameAndType.class; 354 CONST_Utf8 = org.apache.bcel.classfile.ConstantUtf8.class; 355 356 carrier = new DescendingVisitor(_jc, this); 357 carrier.visit(); 358 } 359 360 private void checkIndex(Node referrer, int index, Class shouldbe){ 361 if ((index < 0) || (index >= cplen)){ 362 throw new ClassConstraintException("Invalid index '"+index+"' used by '"+tostring(referrer)+"'."); 363 } 364 Constant c = cp.getConstant(index); 365 if (! shouldbe.isInstance(c)){ 366 367 throw new ClassCastException ("Illegal constant '"+tostring(c)+"' at index '"+index+"'. '"+tostring(referrer)+"' expects a '"+shouldbe+"'."); 368 } 369 } 370 public void visitJavaClass(JavaClass obj){ 374 Attribute[] atts = obj.getAttributes(); 375 boolean foundSourceFile = false; 376 boolean foundInnerClasses = false; 377 378 boolean hasInnerClass = new InnerClassDetector(jc).innerClassReferenced(); 381 382 for (int i=0; i<atts.length; i++){ 383 if ((! (atts[i] instanceof SourceFile)) && 384 (! (atts[i] instanceof Deprecated )) && 385 (! (atts[i] instanceof InnerClasses)) && 386 (! (atts[i] instanceof Synthetic))){ 387 addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of the ClassFile structure '"+tostring(obj)+"' is unknown and will therefore be ignored."); 388 } 389 390 if (atts[i] instanceof SourceFile){ 391 if (foundSourceFile == false) { 392 foundSourceFile = true; 393 } else { 394 throw new ClassConstraintException("A ClassFile structure (like '"+tostring(obj)+"') may have no more than one SourceFile attribute."); } 396 } 397 398 if (atts[i] instanceof InnerClasses){ 399 if (foundInnerClasses == false) { 400 foundInnerClasses = true; 401 } else{ 402 if (hasInnerClass){ 403 throw new ClassConstraintException("A Classfile structure (like '"+tostring(obj)+"') must have exactly one InnerClasses attribute if at least one Inner Class is referenced (which is the case). More than one InnerClasses attribute was found."); 404 } 405 } 406 if (!hasInnerClass){ 407 addMessage("No referenced Inner Class found, but InnerClasses attribute '"+tostring(atts[i])+"' found. Strongly suggest removal of that attribute."); 408 } 409 } 410 411 } 412 if (hasInnerClass && !foundInnerClasses){ 413 addMessage("A Classfile structure (like '"+tostring(obj)+"') must have exactly one InnerClasses attribute if at least one Inner Class is referenced (which is the case). No InnerClasses attribute was found."); 418 } 419 } 420 public void visitConstantClass(ConstantClass obj){ 424 if (obj.getTag() != Constants.CONSTANT_Class){ 425 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 426 } 427 checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 428 429 } 430 public void visitConstantFieldref(ConstantFieldref obj){ 431 if (obj.getTag() != Constants.CONSTANT_Fieldref){ 432 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 433 } 434 checkIndex(obj, obj.getClassIndex(), CONST_Class); 435 checkIndex(obj, obj.getNameAndTypeIndex(), CONST_NameAndType); 436 } 437 public void visitConstantMethodref(ConstantMethodref obj){ 438 if (obj.getTag() != Constants.CONSTANT_Methodref){ 439 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 440 } 441 checkIndex(obj, obj.getClassIndex(), CONST_Class); 442 checkIndex(obj, obj.getNameAndTypeIndex(), CONST_NameAndType); 443 } 444 public void visitConstantInterfaceMethodref(ConstantInterfaceMethodref obj){ 445 if (obj.getTag() != Constants.CONSTANT_InterfaceMethodref){ 446 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 447 } 448 checkIndex(obj, obj.getClassIndex(), CONST_Class); 449 checkIndex(obj, obj.getNameAndTypeIndex(), CONST_NameAndType); 450 } 451 public void visitConstantString(ConstantString obj){ 452 if (obj.getTag() != Constants.CONSTANT_String){ 453 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 454 } 455 checkIndex(obj, obj.getStringIndex(), CONST_Utf8); 456 } 457 public void visitConstantInteger(ConstantInteger obj){ 458 if (obj.getTag() != Constants.CONSTANT_Integer){ 459 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 460 } 461 } 463 public void visitConstantFloat(ConstantFloat obj){ 464 if (obj.getTag() != Constants.CONSTANT_Float){ 465 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 466 } 467 } 469 public void visitConstantLong(ConstantLong obj){ 470 if (obj.getTag() != Constants.CONSTANT_Long){ 471 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 472 } 473 } 475 public void visitConstantDouble(ConstantDouble obj){ 476 if (obj.getTag() != Constants.CONSTANT_Double){ 477 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 478 } 479 } 481 public void visitConstantNameAndType(ConstantNameAndType obj){ 482 if (obj.getTag() != Constants.CONSTANT_NameAndType){ 483 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 484 } 485 checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 486 checkIndex(obj, obj.getSignatureIndex(), CONST_Utf8); 488 } 489 public void visitConstantUtf8(ConstantUtf8 obj){ 490 if (obj.getTag() != Constants.CONSTANT_Utf8){ 491 throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); 492 } 493 } 495 public void visitField(Field obj){ 499 500 if (jc.isClass()){ 501 int maxone=0; 502 if (obj.isPrivate()) { 503 maxone++; 504 } 505 if (obj.isProtected()) { 506 maxone++; 507 } 508 if (obj.isPublic()) { 509 maxone++; 510 } 511 if (maxone > 1){ 512 throw new ClassConstraintException("Field '"+tostring(obj)+"' must only have at most one of its ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC modifiers set."); 513 } 514 515 if (obj.isFinal() && obj.isVolatile()){ 516 throw new ClassConstraintException("Field '"+tostring(obj)+"' must only have at most one of its ACC_FINAL, ACC_VOLATILE modifiers set."); 517 } 518 } 519 else{ if (!obj.isPublic()){ 521 throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_PUBLIC modifier set but hasn't!"); 522 } 523 if (!obj.isStatic()){ 524 throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_STATIC modifier set but hasn't!"); 525 } 526 if (!obj.isFinal()){ 527 throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_FINAL modifier set but hasn't!"); 528 } 529 } 530 531 if ((obj.getAccessFlags() & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_VOLATILE|ACC_TRANSIENT)) > 0){ 532 addMessage("Field '"+tostring(obj)+"' has access flag(s) other than ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_VOLATILE, ACC_TRANSIENT set (ignored)."); 533 } 534 535 checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 536 537 String name = obj.getName(); 538 if (! validFieldName(name)){ 539 throw new ClassConstraintException("Field '"+tostring(obj)+"' has illegal name '"+obj.getName()+"'."); 540 } 541 542 checkIndex(obj, obj.getSignatureIndex(), CONST_Utf8); 544 545 String sig = ((ConstantUtf8) (cp.getConstant(obj.getSignatureIndex()))).getBytes(); 547 try{ 548 Type.getType(sig); 549 } 550 catch (ClassFormatException cfe){ 551 throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'."); 552 } 553 554 String nameanddesc = (name+sig); 555 if (field_names_and_desc.contains(nameanddesc)){ 556 throw new ClassConstraintException("No two fields (like '"+tostring(obj)+"') are allowed have same names and descriptors!"); 557 } 558 if (field_names.contains(name)){ 559 addMessage("More than one field of name '"+name+"' detected (but with different type descriptors). This is very unusual."); 560 } 561 field_names_and_desc.add(nameanddesc); 562 field_names.add(name); 563 564 Attribute[] atts = obj.getAttributes(); 565 for (int i=0; i<atts.length; i++){ 566 if ((! (atts[i] instanceof ConstantValue)) && 567 (! (atts[i] instanceof Synthetic)) && 568 (! (atts[i] instanceof Deprecated ))){ 569 addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Field '"+tostring(obj)+"' is unknown and will therefore be ignored."); 570 } 571 if (! (atts[i] instanceof ConstantValue)){ 572 addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Field '"+tostring(obj)+"' is not a ConstantValue and is therefore only of use for debuggers and such."); 573 } 574 } 575 } 576 public void visitMethod(Method obj){ 580 581 checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 582 583 String name = obj.getName(); 584 if (! validMethodName(name, true)){ 585 throw new ClassConstraintException("Method '"+tostring(obj)+"' has illegal name '"+name+"'."); 586 } 587 588 checkIndex(obj, obj.getSignatureIndex(), CONST_Utf8); 590 591 String sig = ((ConstantUtf8) (cp.getConstant(obj.getSignatureIndex()))).getBytes(); 593 Type t; 594 Type[] ts; try{ 596 t = Type.getReturnType(sig); 597 ts = Type.getArgumentTypes(sig); 598 } 599 catch (ClassFormatException cfe){ 600 throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by Method '"+tostring(obj)+"'."); 601 } 602 603 Type act = t; 605 if (act instanceof ArrayType) { 606 act = ((ArrayType) act).getBasicType(); 607 } 608 if (act instanceof ObjectType){ 609 Verifier v = VerifierFactory.getVerifier( ((ObjectType) act).getClassName() ); 610 VerificationResult vr = v.doPass1(); 611 if (vr != VerificationResult.VR_OK) { 612 throw new ClassConstraintException("Method '"+tostring(obj)+"' has a return type that does not pass verification pass 1: '"+vr+"'."); 613 } 614 } 615 616 for (int i=0; i<ts.length; i++){ 617 act = ts[i]; 618 if (act instanceof ArrayType) { 619 act = ((ArrayType) act).getBasicType(); 620 } 621 if (act instanceof ObjectType){ 622 Verifier v = VerifierFactory.getVerifier( ((ObjectType) act).getClassName() ); 623 VerificationResult vr = v.doPass1(); 624 if (vr != VerificationResult.VR_OK) { 625 throw new ClassConstraintException("Method '"+tostring(obj)+"' has an argument type that does not pass verification pass 1: '"+vr+"'."); 626 } 627 } 628 } 629 630 if (name.equals(STATIC_INITIALIZER_NAME) && (ts.length != 0)){ 632 throw new ClassConstraintException("Method '"+tostring(obj)+"' has illegal name '"+name+"'. It's name resembles the class or interface initialization method which it isn't because of its arguments (==descriptor)."); 633 } 634 635 if (jc.isClass()){ 636 int maxone=0; 637 if (obj.isPrivate()) { 638 maxone++; 639 } 640 if (obj.isProtected()) { 641 maxone++; 642 } 643 if (obj.isPublic()) { 644 maxone++; 645 } 646 if (maxone > 1){ 647 throw new ClassConstraintException("Method '"+tostring(obj)+"' must only have at most one of its ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC modifiers set."); 648 } 649 650 if (obj.isAbstract()){ 651 if (obj.isFinal()) { 652 throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_FINAL modifier set."); 653 } 654 if (obj.isNative()) { 655 throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_NATIVE modifier set."); 656 } 657 if (obj.isPrivate()) { 658 throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_PRIVATE modifier set."); 659 } 660 if (obj.isStatic()) { 661 throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_STATIC modifier set."); 662 } 663 if (obj.isStrictfp()) { 664 throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_STRICT modifier set."); 665 } 666 if (obj.isSynchronized()) { 667 throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_SYNCHRONIZED modifier set."); 668 } 669 } 670 } 671 else{ if (!name.equals(STATIC_INITIALIZER_NAME)){ if (!obj.isPublic()){ 674 throw new ClassConstraintException("Interface method '"+tostring(obj)+"' must have the ACC_PUBLIC modifier set but hasn't!"); 675 } 676 if (!obj.isAbstract()){ 677 throw new ClassConstraintException("Interface method '"+tostring(obj)+"' must have the ACC_STATIC modifier set but hasn't!"); 678 } 679 if ( obj.isPrivate() || 680 obj.isProtected() || 681 obj.isStatic() || 682 obj.isFinal() || 683 obj.isSynchronized() || 684 obj.isNative() || 685 obj.isStrictfp() ){ 686 throw new ClassConstraintException("Interface method '"+tostring(obj)+"' must not have any of the ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT, ACC_STRICT modifiers set."); 687 } 688 } 689 } 690 691 if (name.equals(CONSTRUCTOR_NAME)){ 693 if ( obj.isStatic() || 696 obj.isFinal() || 697 obj.isSynchronized() || 698 obj.isNative() || 699 obj.isAbstract() ){ 700 throw new ClassConstraintException("Instance initialization method '"+tostring(obj)+"' must not have any of the ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT modifiers set."); 701 } 702 } 703 704 if (name.equals(STATIC_INITIALIZER_NAME)){ 706 if ((obj.getAccessFlags() & (~ACC_STRICT)) > 0){ 707 addMessage("Class or interface initialization method '"+tostring(obj)+"' has superfluous access modifier(s) set: everything but ACC_STRICT is ignored."); 708 } 709 if (obj.isAbstract()){ 710 throw new ClassConstraintException("Class or interface initialization method '"+tostring(obj)+"' must not be abstract. This contradicts the Java Language Specification, Second Edition (which omits this constraint) but is common practice of existing verifiers."); 711 } 712 } 713 714 if ((obj.getAccessFlags() & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_SYNCHRONIZED|ACC_NATIVE|ACC_ABSTRACT|ACC_STRICT)) > 0){ 715 addMessage("Method '"+tostring(obj)+"' has access flag(s) other than ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT, ACC_STRICT set (ignored)."); 716 } 717 718 String nameanddesc = (name+sig); 719 if (method_names_and_desc.contains(nameanddesc)){ 720 throw new ClassConstraintException("No two methods (like '"+tostring(obj)+"') are allowed have same names and desciptors!"); 721 } 722 method_names_and_desc.add(nameanddesc); 723 724 Attribute[] atts = obj.getAttributes(); 725 int num_code_atts = 0; 726 for (int i=0; i<atts.length; i++){ 727 if ((! (atts[i] instanceof Code)) && 728 (! (atts[i] instanceof ExceptionTable)) && 729 (! (atts[i] instanceof Synthetic)) && 730 (! (atts[i] instanceof Deprecated ))){ 731 addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Method '"+tostring(obj)+"' is unknown and will therefore be ignored."); 732 } 733 if ((! (atts[i] instanceof Code)) && 734 (! (atts[i] instanceof ExceptionTable))){ 735 addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Method '"+tostring(obj)+"' is neither Code nor Exceptions and is therefore only of use for debuggers and such."); 736 } 737 if ((atts[i] instanceof Code) && (obj.isNative() || obj.isAbstract())){ 738 throw new ClassConstraintException("Native or abstract methods like '"+tostring(obj)+"' must not have a Code attribute like '"+tostring(atts[i])+"'."); } 740 if (atts[i] instanceof Code) { 741 num_code_atts++; 742 } 743 } 744 if ( !obj.isNative() && !obj.isAbstract() && num_code_atts != 1){ 745 throw new ClassConstraintException("Non-native, non-abstract methods like '"+tostring(obj)+"' must have exactly one Code attribute (found: "+num_code_atts+")."); 746 } 747 } 748 public void visitSourceFile(SourceFile obj){ 753 755 checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 756 757 String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); 758 if (! name.equals("SourceFile")){ 759 throw new ClassConstraintException("The SourceFile attribute '"+tostring(obj)+"' is not correctly named 'SourceFile' but '"+name+"'."); 760 } 761 762 checkIndex(obj, obj.getSourceFileIndex(), CONST_Utf8); 763 764 String sourcefilename = ((ConstantUtf8) cp.getConstant(obj.getSourceFileIndex())).getBytes(); String sourcefilenamelc = sourcefilename.toLowerCase(Locale.ENGLISH); 766 767 if ( (sourcefilename.indexOf('/') != -1) || 768 (sourcefilename.indexOf('\\') != -1) || 769 (sourcefilename.indexOf(':') != -1) || 770 (sourcefilenamelc.lastIndexOf(".java") == -1) ){ 771 addMessage("SourceFile attribute '"+tostring(obj)+"' has a funny name: remember not to confuse certain parsers working on javap's output. Also, this name ('"+sourcefilename+"') is considered an unqualified (simple) file name only."); 772 } 773 } 774 public void visitDeprecated(Deprecated obj){ checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 776 777 String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); 778 if (! name.equals("Deprecated")){ 779 throw new ClassConstraintException("The Deprecated attribute '"+tostring(obj)+"' is not correctly named 'Deprecated' but '"+name+"'."); 780 } 781 } 782 public void visitSynthetic(Synthetic obj){ checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 784 String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); 785 if (! name.equals("Synthetic")){ 786 throw new ClassConstraintException("The Synthetic attribute '"+tostring(obj)+"' is not correctly named 'Synthetic' but '"+name+"'."); 787 } 788 } 789 public void visitInnerClasses(InnerClasses obj){ 791 793 checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 794 795 String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); 796 if (! name.equals("InnerClasses")){ 797 throw new ClassConstraintException("The InnerClasses attribute '"+tostring(obj)+"' is not correctly named 'InnerClasses' but '"+name+"'."); 798 } 799 800 InnerClass[] ics = obj.getInnerClasses(); 801 802 for (int i=0; i<ics.length; i++){ 803 checkIndex(obj, ics[i].getInnerClassIndex(), CONST_Class); 804 int outer_idx = ics[i].getOuterClassIndex(); 805 if (outer_idx != 0){ 806 checkIndex(obj, outer_idx, CONST_Class); 807 } 808 int innername_idx = ics[i].getInnerNameIndex(); 809 if (innername_idx != 0){ 810 checkIndex(obj, innername_idx, CONST_Utf8); 811 } 812 int acc = ics[i].getInnerAccessFlags(); 813 acc = acc & (~ (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT)); 814 if (acc != 0){ 815 addMessage("Unknown access flag for inner class '"+tostring(ics[i])+"' set (InnerClasses attribute '"+tostring(obj)+"')."); 816 } 817 } 818 } 821 public void visitConstantValue(ConstantValue obj){ checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 828 829 String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); 830 if (! name.equals("ConstantValue")){ 831 throw new ClassConstraintException("The ConstantValue attribute '"+tostring(obj)+"' is not correctly named 'ConstantValue' but '"+name+"'."); 832 } 833 834 Object pred = carrier.predecessor(); 835 if (pred instanceof Field){ Field f = (Field) pred; 837 Type field_type = Type.getType(((ConstantUtf8) (cp.getConstant(f.getSignatureIndex()))).getBytes()); 839 840 int index = obj.getConstantValueIndex(); 841 if ((index < 0) || (index >= cplen)){ 842 throw new ClassConstraintException("Invalid index '"+index+"' used by '"+tostring(obj)+"'."); 843 } 844 Constant c = cp.getConstant(index); 845 846 if (CONST_Long.isInstance(c) && field_type.equals(Type.LONG)){ 847 return; 848 } 849 if (CONST_Float.isInstance(c) && field_type.equals(Type.FLOAT)){ 850 return; 851 } 852 if (CONST_Double.isInstance(c) && field_type.equals(Type.DOUBLE)){ 853 return; 854 } 855 if (CONST_Integer.isInstance(c) && (field_type.equals(Type.INT) || field_type.equals(Type.SHORT) || field_type.equals(Type.CHAR) || field_type.equals(Type.BYTE) || field_type.equals(Type.BOOLEAN))){ 856 return; 857 } 858 if (CONST_String.isInstance(c) && field_type.equals(Type.STRING)){ 859 return; 860 } 861 862 throw new ClassConstraintException("Illegal type of ConstantValue '"+obj+"' embedding Constant '"+c+"'. It is referenced by field '"+tostring(f)+"' expecting a different type: '"+field_type+"'."); 863 } 864 } 865 public void visitCode(Code obj){ try { 872 875 checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 876 877 String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); 878 if (! name.equals("Code")){ 879 throw new ClassConstraintException("The Code attribute '"+tostring(obj)+"' is not correctly named 'Code' but '"+name+"'."); 880 } 881 882 Method m = null; if (!(carrier.predecessor() instanceof Method)){ 884 addMessage("Code attribute '"+tostring(obj)+"' is not declared in a method_info structure but in '"+carrier.predecessor()+"'. Ignored."); 885 return; 886 } 887 else{ 888 m = (Method) carrier.predecessor(); } 891 892 if (obj.getCode().length == 0){ 893 throw new ClassConstraintException("Code array of Code attribute '"+tostring(obj)+"' (method '"+m+"') must not be empty."); 894 } 895 896 CodeException[] exc_table = obj.getExceptionTable(); 898 for (int i=0; i<exc_table.length; i++){ 899 int exc_index = exc_table[i].getCatchType(); 900 if (exc_index != 0){ checkIndex(obj, exc_index, CONST_Class); 902 ConstantClass cc = (ConstantClass) (cp.getConstant(exc_index)); 903 checkIndex(cc, cc.getNameIndex(), CONST_Utf8); String cname = ((ConstantUtf8) cp.getConstant(cc.getNameIndex())).getBytes().replace('/','.'); 905 906 Verifier v = VerifierFactory.getVerifier(cname); 907 VerificationResult vr = v.doPass1(); 908 909 if (vr != VerificationResult.VR_OK){ 910 throw new ClassConstraintException("Code attribute '"+tostring(obj)+"' (method '"+m+"') has an exception_table entry '"+tostring(exc_table[i])+"' that references '"+cname+"' as an Exception but it does not pass verification pass 1: "+vr); 911 } 912 else{ 913 JavaClass e = Repository.lookupClass(cname); 916 JavaClass t = Repository.lookupClass(Type.THROWABLE.getClassName()); 917 JavaClass o = Repository.lookupClass(Type.OBJECT.getClassName()); 918 while (e != o){ 919 if (e == t) { 920 break; } 922 923 v = VerifierFactory.getVerifier(e.getSuperclassName()); 924 vr = v.doPass1(); 925 if (vr != VerificationResult.VR_OK){ 926 throw new ClassConstraintException("Code attribute '"+tostring(obj)+"' (method '"+m+"') has an exception_table entry '"+tostring(exc_table[i])+"' that references '"+cname+"' as an Exception but '"+e.getSuperclassName()+"' in the ancestor hierachy does not pass verification pass 1: "+vr); 927 } 928 else{ 929 e = Repository.lookupClass(e.getSuperclassName()); 930 } 931 } 932 if (e != t) { 933 throw new ClassConstraintException("Code attribute '"+tostring(obj)+"' (method '"+m+"') has an exception_table entry '"+tostring(exc_table[i])+"' that references '"+cname+"' as an Exception but it is not a subclass of '"+t.getClassName()+"'."); 934 } 935 } 936 } 937 } 938 939 int method_number = -1; 943 Method[] ms = Repository.lookupClass(myOwner.getClassName()).getMethods(); 944 for (int mn=0; mn<ms.length; mn++){ 945 if (m == ms[mn]){ 946 method_number = mn; 947 break; 948 } 949 } 950 if (method_number < 0){ throw new AssertionViolatedException("Could not find a known BCEL Method object in the corresponding BCEL JavaClass object."); 952 } 953 localVariablesInfos[method_number] = new LocalVariablesInfo(obj.getMaxLocals()); 954 955 int num_of_lvt_attribs = 0; 956 Attribute[] atts = obj.getAttributes(); 958 for (int a=0; a<atts.length; a++){ 959 if ((! (atts[a] instanceof LineNumberTable)) && 960 (! (atts[a] instanceof LocalVariableTable))){ 961 addMessage("Attribute '"+tostring(atts[a])+"' as an attribute of Code attribute '"+tostring(obj)+"' (method '"+m+"') is unknown and will therefore be ignored."); 962 } 963 else{ addMessage("Attribute '"+tostring(atts[a])+"' as an attribute of Code attribute '"+tostring(obj)+"' (method '"+m+"') will effectively be ignored and is only useful for debuggers and such."); 965 } 966 967 if (atts[a] instanceof LocalVariableTable){ 973 LocalVariableTable lvt = (LocalVariableTable) atts[a]; 974 975 checkIndex(lvt, lvt.getNameIndex(), CONST_Utf8); 976 977 String lvtname = ((ConstantUtf8) cp.getConstant(lvt.getNameIndex())).getBytes(); 978 if (! lvtname.equals("LocalVariableTable")){ 979 throw new ClassConstraintException("The LocalVariableTable attribute '"+tostring(lvt)+"' is not correctly named 'LocalVariableTable' but '"+lvtname+"'."); 980 } 981 982 Code code = obj; 983 984 LocalVariable[] localvariables = lvt.getLocalVariableTable(); 986 987 for (int i=0; i<localvariables.length; i++){ 988 checkIndex(lvt, localvariables[i].getNameIndex(), CONST_Utf8); 989 String localname = ((ConstantUtf8) cp.getConstant(localvariables[i].getNameIndex())).getBytes(); 990 if (!validJavaIdentifier(localname)){ 991 throw new ClassConstraintException("LocalVariableTable '"+tostring(lvt)+"' references a local variable by the name '"+localname+"' which is not a legal Java simple name."); 992 } 993 994 checkIndex(lvt, localvariables[i].getSignatureIndex(), CONST_Utf8); 995 String localsig = ((ConstantUtf8) (cp.getConstant(localvariables[i].getSignatureIndex()))).getBytes(); Type t; 997 try{ 998 t = Type.getType(localsig); 999 } 1000 catch (ClassFormatException cfe){ 1001 throw new ClassConstraintException("Illegal descriptor (==signature) '"+localsig+"' used by LocalVariable '"+tostring(localvariables[i])+"' referenced by '"+tostring(lvt)+"'."); 1002 } 1003 int localindex = localvariables[i].getIndex(); 1004 if ( ( (t==Type.LONG || t==Type.DOUBLE)? localindex+1:localindex) >= code.getMaxLocals()){ 1005 throw new ClassConstraintException("LocalVariableTable attribute '"+tostring(lvt)+"' references a LocalVariable '"+tostring(localvariables[i])+"' with an index that exceeds the surrounding Code attribute's max_locals value of '"+code.getMaxLocals()+"'."); 1006 } 1007 1008 try{ 1009 localVariablesInfos[method_number].add(localindex, localname, localvariables[i].getStartPC(), localvariables[i].getLength(), t); 1010 } 1011 catch(LocalVariableInfoInconsistentException lviie){ 1012 throw new ClassConstraintException("Conflicting information in LocalVariableTable '"+tostring(lvt)+"' found in Code attribute '"+tostring(obj)+"' (method '"+tostring(m)+"'). "+lviie.getMessage()); 1013 } 1014 } 1016 num_of_lvt_attribs++; 1017 if (num_of_lvt_attribs > obj.getMaxLocals()){ 1018 throw new ClassConstraintException("Number of LocalVariableTable attributes of Code attribute '"+tostring(obj)+"' (method '"+tostring(m)+"') exceeds number of local variable slots '"+obj.getMaxLocals()+"' ('There may be no more than one LocalVariableTable attribute per local variable in the Code attribute.')."); 1019 } 1020 } } 1023 } catch (ClassNotFoundException e) { 1024 throw new AssertionViolatedException("Missing class: " + e.toString()); 1026 } 1027 1028 } 1030 public void visitExceptionTable(ExceptionTable obj){ try { 1032 checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 1034 1035 String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); 1036 if (! name.equals("Exceptions")){ 1037 throw new ClassConstraintException("The Exceptions attribute '"+tostring(obj)+"' is not correctly named 'Exceptions' but '"+name+"'."); 1038 } 1039 1040 int[] exc_indices = obj.getExceptionIndexTable(); 1041 1042 for (int i=0; i<exc_indices.length; i++){ 1043 checkIndex(obj, exc_indices[i], CONST_Class); 1044 1045 ConstantClass cc = (ConstantClass) (cp.getConstant(exc_indices[i])); 1046 checkIndex(cc, cc.getNameIndex(), CONST_Utf8); String cname = ((ConstantUtf8) cp.getConstant(cc.getNameIndex())).getBytes().replace('/','.'); 1049 Verifier v = VerifierFactory.getVerifier(cname); 1050 VerificationResult vr = v.doPass1(); 1051 1052 if (vr != VerificationResult.VR_OK){ 1053 throw new ClassConstraintException("Exceptions attribute '"+tostring(obj)+"' references '"+cname+"' as an Exception but it does not pass verification pass 1: "+vr); 1054 } 1055 else{ 1056 JavaClass e = Repository.lookupClass(cname); 1059 JavaClass t = Repository.lookupClass(Type.THROWABLE.getClassName()); 1060 JavaClass o = Repository.lookupClass(Type.OBJECT.getClassName()); 1061 while (e != o){ 1062 if (e == t) { 1063 break; } 1065 1066 v = VerifierFactory.getVerifier(e.getSuperclassName()); 1067 vr = v.doPass1(); 1068 if (vr != VerificationResult.VR_OK){ 1069 throw new ClassConstraintException("Exceptions attribute '"+tostring(obj)+"' references '"+cname+"' as an Exception but '"+e.getSuperclassName()+"' in the ancestor hierachy does not pass verification pass 1: "+vr); 1070 } 1071 else{ 1072 e = Repository.lookupClass(e.getSuperclassName()); 1073 } 1074 } 1075 if (e != t) { 1076 throw new ClassConstraintException("Exceptions attribute '"+tostring(obj)+"' references '"+cname+"' as an Exception but it is not a subclass of '"+t.getClassName()+"'."); 1077 } 1078 } 1079 } 1080 1081 } catch (ClassNotFoundException e) { 1082 throw new AssertionViolatedException("Missing class: " + e.toString()); 1084 } 1085 } 1086 public void visitLineNumberTable(LineNumberTable obj){ checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 1093 1094 String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); 1095 if (! name.equals("LineNumberTable")){ 1096 throw new ClassConstraintException("The LineNumberTable attribute '"+tostring(obj)+"' is not correctly named 'LineNumberTable' but '"+name+"'."); 1097 } 1098 1099 1103 } 1104 public void visitLocalVariableTable(LocalVariableTable obj){ } 1108 public void visitUnknown(Unknown obj){ checkIndex(obj, obj.getNameIndex(), CONST_Utf8); 1114 1115 addMessage("Unknown attribute '"+tostring(obj)+"'. This attribute is not known in any context!"); 1117 } 1118 public void visitLocalVariable(LocalVariable obj){ 1122 1125 } 1127 public void visitCodeException(CodeException obj){ 1128 1132 } 1134 public void visitConstantPool(ConstantPool obj){ 1135 } 1139 public void visitInnerClass(InnerClass obj){ 1140 } 1143 public void visitLineNumber(LineNumber obj){ 1144 1147 } 1149 } 1150 1151 1165 private void field_and_method_refs_are_valid(){ 1166 try { 1167 JavaClass jc = Repository.lookupClass(myOwner.getClassName()); 1168 DescendingVisitor v = new DescendingVisitor(jc, new FAMRAV_Visitor(jc)); 1169 v.visit(); 1170 1171 } catch (ClassNotFoundException e) { 1172 throw new AssertionViolatedException("Missing class: " + e.toString()); 1174 } 1175 } 1176 1177 1186 private class FAMRAV_Visitor extends EmptyVisitor implements Visitor{ 1187 private final ConstantPool cp; private FAMRAV_Visitor(JavaClass _jc){ 1189 cp = _jc.getConstantPool(); 1190 } 1191 1192 public void visitConstantFieldref(ConstantFieldref obj){ 1193 if (obj.getTag() != Constants.CONSTANT_Fieldref){ 1194 throw new ClassConstraintException("ConstantFieldref '"+tostring(obj)+"' has wrong tag!"); 1195 } 1196 int name_and_type_index = obj.getNameAndTypeIndex(); 1197 ConstantNameAndType cnat = (ConstantNameAndType) (cp.getConstant(name_and_type_index)); 1198 String name = ((ConstantUtf8) (cp.getConstant(cnat.getNameIndex()))).getBytes(); if (!validFieldName(name)){ 1200 throw new ClassConstraintException("Invalid field name '"+name+"' referenced by '"+tostring(obj)+"'."); 1201 } 1202 1203 int class_index = obj.getClassIndex(); 1204 ConstantClass cc = (ConstantClass) (cp.getConstant(class_index)); 1205 String className = ((ConstantUtf8) (cp.getConstant(cc.getNameIndex()))).getBytes(); if (! validClassName(className)){ 1207 throw new ClassConstraintException("Illegal class name '"+className+"' used by '"+tostring(obj)+"'."); 1208 } 1209 1210 String sig = ((ConstantUtf8) (cp.getConstant(cnat.getSignatureIndex()))).getBytes(); 1212 try{ 1213 Type.getType(sig); 1214 } 1215 catch (ClassFormatException cfe){ 1216 throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'."); 1217 } 1218 } 1219 1220 public void visitConstantMethodref(ConstantMethodref obj){ 1221 if (obj.getTag() != Constants.CONSTANT_Methodref){ 1222 throw new ClassConstraintException("ConstantMethodref '"+tostring(obj)+"' has wrong tag!"); 1223 } 1224 int name_and_type_index = obj.getNameAndTypeIndex(); 1225 ConstantNameAndType cnat = (ConstantNameAndType) (cp.getConstant(name_and_type_index)); 1226 String name = ((ConstantUtf8) (cp.getConstant(cnat.getNameIndex()))).getBytes(); if (!validClassMethodName(name)){ 1228 throw new ClassConstraintException("Invalid (non-interface) method name '"+name+"' referenced by '"+tostring(obj)+"'."); 1229 } 1230 1231 int class_index = obj.getClassIndex(); 1232 ConstantClass cc = (ConstantClass) (cp.getConstant(class_index)); 1233 String className = ((ConstantUtf8) (cp.getConstant(cc.getNameIndex()))).getBytes(); if (! validClassName(className)){ 1235 throw new ClassConstraintException("Illegal class name '"+className+"' used by '"+tostring(obj)+"'."); 1236 } 1237 1238 String sig = ((ConstantUtf8) (cp.getConstant(cnat.getSignatureIndex()))).getBytes(); 1240 try{ 1241 Type t = Type.getReturnType(sig); 1242 if ( name.equals(CONSTRUCTOR_NAME) && (t != Type.VOID) ){ 1243 throw new ClassConstraintException("Instance initialization method must have VOID return type."); 1244 } 1245 } 1246 catch (ClassFormatException cfe){ 1247 throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'."); 1248 } 1249 } 1250 1251 public void visitConstantInterfaceMethodref(ConstantInterfaceMethodref obj){ 1252 if (obj.getTag() != Constants.CONSTANT_InterfaceMethodref){ 1253 throw new ClassConstraintException("ConstantInterfaceMethodref '"+tostring(obj)+"' has wrong tag!"); 1254 } 1255 int name_and_type_index = obj.getNameAndTypeIndex(); 1256 ConstantNameAndType cnat = (ConstantNameAndType) (cp.getConstant(name_and_type_index)); 1257 String name = ((ConstantUtf8) (cp.getConstant(cnat.getNameIndex()))).getBytes(); if (!validInterfaceMethodName(name)){ 1259 throw new ClassConstraintException("Invalid (interface) method name '"+name+"' referenced by '"+tostring(obj)+"'."); 1260 } 1261 1262 int class_index = obj.getClassIndex(); 1263 ConstantClass cc = (ConstantClass) (cp.getConstant(class_index)); 1264 String className = ((ConstantUtf8) (cp.getConstant(cc.getNameIndex()))).getBytes(); if (! validClassName(className)){ 1266 throw new ClassConstraintException("Illegal class name '"+className+"' used by '"+tostring(obj)+"'."); 1267 } 1268 1269 String sig = ((ConstantUtf8) (cp.getConstant(cnat.getSignatureIndex()))).getBytes(); 1271 try{ 1272 Type t = Type.getReturnType(sig); 1273 if ( name.equals(STATIC_INITIALIZER_NAME) && (t != Type.VOID) ){ 1274 addMessage("Class or interface initialization method '"+STATIC_INITIALIZER_NAME+"' usually has VOID return type instead of '"+t+"'. Note this is really not a requirement of The Java Virtual Machine Specification, Second Edition."); 1275 } 1276 } 1277 catch (ClassFormatException cfe){ 1278 throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'."); 1279 } 1280 1281 } 1282 1283 } 1284 1285 1289 private static final boolean validClassName(String name){ 1290 1294 return true; 1295 } 1296 1304 private static boolean validMethodName(String name, boolean allowStaticInit){ 1305 if (validJavaLangMethodName(name)) { 1306 return true; 1307 } 1308 1309 if (allowStaticInit){ 1310 return (name.equals(CONSTRUCTOR_NAME) || name.equals(STATIC_INITIALIZER_NAME)); 1311 } 1312 else{ 1313 return name.equals(CONSTRUCTOR_NAME); 1314 } 1315 } 1316 1317 1322 private static boolean validClassMethodName(String name){ 1323 return validMethodName(name, false); 1324 } 1325 1326 1332 private static boolean validJavaLangMethodName(String name){ 1333 if (!Character.isJavaIdentifierStart(name.charAt(0))) { 1334 return false; 1335 } 1336 1337 for (int i=1; i<name.length(); i++){ 1338 if (!Character.isJavaIdentifierPart(name.charAt(i))) { 1339 return false; 1340 } 1341 } 1342 return true; 1343 } 1344 1345 1350 private static boolean validInterfaceMethodName(String name){ 1351 if (name.startsWith("<")) { 1353 return false; 1354 } 1355 return validJavaLangMethodName(name); 1356 } 1357 1358 1362 private static boolean validJavaIdentifier(String name){ 1363 if (name.length() == 0) { 1364 return false; } 1366 1367 if (!Character.isJavaIdentifierStart(name.charAt(0))) { 1369 return false; 1370 } 1371 1372 for (int i=1; i<name.length(); i++){ 1373 if (!Character.isJavaIdentifierPart(name.charAt(i))) { 1374 return false; 1375 } 1376 } 1377 return true; 1378 } 1379 1380 1384 private static boolean validFieldName(String name){ 1385 return validJavaIdentifier(name); 1387 } 1388 1389 1408 private static class InnerClassDetector extends EmptyVisitor{ 1409 private boolean hasInnerClass = false; 1410 private JavaClass jc; 1411 private ConstantPool cp; 1412 1413 1414 public InnerClassDetector(JavaClass _jc){ 1415 jc = _jc; 1416 cp = jc.getConstantPool(); 1417 (new DescendingVisitor(jc, this)).visit(); 1418 } 1419 1423 public boolean innerClassReferenced(){ 1424 return hasInnerClass; 1425 } 1426 1427 public void visitConstantClass(ConstantClass obj){ 1428 Constant c = cp.getConstant(obj.getNameIndex()); 1429 if (c instanceof ConstantUtf8){ String classname = ((ConstantUtf8) c).getBytes(); 1431 if (classname.startsWith(jc.getClassName().replace('.','/')+"$")){ 1432 hasInnerClass = true; 1433 } 1434 } 1435 } 1436 } 1437 1438 1441 private static String tostring(Node n){ 1442 return new StringRepresentation(n).toString(); 1443 } 1444} 1445 | Popular Tags |