001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.bcel.classfile; 020 021import java.io.DataInput; 022import java.io.DataInputStream; 023import java.io.DataOutputStream; 024import java.io.IOException; 025import java.util.HashMap; 026import java.util.Map; 027 028import org.apache.bcel.Const; 029import org.apache.bcel.util.Args; 030 031/** 032 * Abstract superclass for <em>Attribute</em> objects. Currently the <em>ConstantValue</em>, <em>SourceFile</em>, <em>Code</em>, <em>Exceptiontable</em>, 033 * <em>LineNumberTable</em>, <em>LocalVariableTable</em>, <em>InnerClasses</em> and <em>Synthetic</em> attributes are supported. The <em>Unknown</em> attribute 034 * stands for non-standard-attributes. 035 * 036 * <pre> 037 * attribute_info { 038 * u2 attribute_name_index; 039 * u4 attribute_length; 040 * u1 info[attribute_length]; 041 * } 042 * </pre> 043 * <p> 044 * The default maximum number of attribute nesting levels in {@link #readAttribute(DataInput, ConstantPool)} is {@code 64} before throwing a 045 * {@link ClassFormatException}. This is configurable through the system property {@code org.apache.bcel.classfile.Attribute.maxNestingDepth}. Attributes may 046 * legitimately nest (for example, a <em>Code</em> attribute carries its own attribute table, and <em>Record</em> components carry theirs), but a malicious 047 * class file can nest such attributes deeply enough to overflow the parser's stack. 048 * </p> 049 * 050 * @see ConstantValue 051 * @see SourceFile 052 * @see Code 053 * @see Unknown 054 * @see ExceptionTable 055 * @see LineNumberTable 056 * @see LocalVariableTable 057 * @see InnerClasses 058 * @see Synthetic 059 * @see Deprecated 060 * @see Signature 061 */ 062public abstract class Attribute implements Cloneable, Node { 063 064 private static final boolean debug = Boolean.getBoolean(Attribute.class.getCanonicalName() + ".debug"); // Debugging on/off 065 066 /** 067 * Maximum number of attribute nesting levels {@link #readAttribute(DataInput, ConstantPool)} accepts before throwing a {@link ClassFormatException}, 068 * configurable through the system property {@code org.apache.bcel.classfile.Attribute.maxNestingDepth}. Attributes may legitimately nest (for example, a 069 * <em>Code</em> attribute carries its own attribute table, and <em>Record</em> components carry theirs), but a malicious class file can nest such 070 * attributes deeply enough to overflow the parser's stack. 071 */ 072 private static final int MAX_NESTING_DEPTH = Integer.getInteger(Attribute.class.getCanonicalName() + ".maxNestingDepth", 64).intValue(); 073 074 /** 075 * The per-thread attribute nesting depth of {@link #readAttribute(DataInput, ConstantPool)}. 076 */ 077 private static final ThreadLocal<Integer> NESTING_DEPTH = ThreadLocal.withInitial(() -> Integer.valueOf(0)); 078 079 private static final Map<String, Object> READERS = new HashMap<>(); 080 081 /** 082 * Empty array. 083 * 084 * @since 6.6.0 085 */ 086 public static final Attribute[] EMPTY_ARRAY = {}; 087 088 /** 089 * Add an Attribute reader capable of parsing (user-defined) attributes named "name". You should not add readers for the 090 * standard attributes such as "LineNumberTable", because those are handled internally. 091 * 092 * @param name The name of the attribute as stored in the class file. 093 * @param attributeReader The reader object. 094 * @deprecated (6.0) Use {@link #addAttributeReader(String, UnknownAttributeReader)} instead. 095 */ 096 @java.lang.Deprecated 097 public static void addAttributeReader(final String name, final AttributeReader attributeReader) { 098 READERS.put(name, attributeReader); 099 } 100 101 /** 102 * Add an Attribute reader capable of parsing (user-defined) attributes named "name". You should not add readers for the 103 * standard attributes such as "LineNumberTable", because those are handled internally. 104 * 105 * @param name The name of the attribute as stored in the class file. 106 * @param unknownAttributeReader The reader object. 107 */ 108 public static void addAttributeReader(final String name, final UnknownAttributeReader unknownAttributeReader) { 109 READERS.put(name, unknownAttributeReader); 110 } 111 112 /** 113 * Prints a message to stderr if debug mode is enabled. 114 * 115 * @param msg The message to print. 116 */ 117 protected static void println(final String msg) { 118 if (debug) { 119 System.err.println(msg); 120 } 121 } 122 123 /** 124 * Reads one attribute using standard eight-byte Code headers. 125 * 126 * @param dataInput Input stream. 127 * @param constantPool Array of constants. 128 * @return Attribute. 129 * @throws IOException Thrown if an I/O error occurs. 130 * @since 6.0 131 * @see #readAttribute(DataInput, ConstantPool, boolean) 132 */ 133 public static Attribute readAttribute(final DataInput dataInput, final ConstantPool constantPool) throws IOException { 134 return readAttribute(dataInput, constantPool, false); 135 } 136 137 /** 138 * Reads one attribute using the selected Code header layout. 139 * 140 * <p> 141 * The compact layout uses {@code u1}, {@code u1}, and {@code u2} for {@code max_stack}, {@code max_locals}, and {@code code_length}, respectively. These 142 * fields occupy 4 bytes instead of the standard 8 bytes; the rest of the Code attribute layout is unchanged. This layout is intended for historical class 143 * files with version 45.0 through 45.2. This method has no enclosing class version to check, so the caller must select the layout. The selection also 144 * applies to Code attributes encountered while reading nested attributes. 145 * </p> 146 * 147 * @param dataInput Input stream. 148 * @param constantPool Constant pool. 149 * @param compactCodeHeader Whether to read compact four-byte Code headers ({@code true}) or standard eight-byte headers ({@code false}). 150 * @return The attribute. 151 * @throws IOException Thrown if an I/O error occurs. 152 * @throws ClassFormatException Thrown if the attribute is malformed or exceeds the nesting limit. 153 * @since 6.14.0 154 * @see Code#isCompactCodeHeader() 155 */ 156 public static Attribute readAttribute(final DataInput dataInput, final ConstantPool constantPool, final boolean compactCodeHeader) throws IOException { 157 // Track the nesting depth to guard against malicious class files that nest attributes (for example, a Code attribute inside a Code attribute, or 158 // mutually recursive Record component attributes) deeply enough to overflow the parser's stack (CWE-674). 159 final int depth = NESTING_DEPTH.get().intValue() + 1; 160 if (depth > MAX_NESTING_DEPTH) { 161 throw new ClassFormatException( 162 "Attributes are nested more than %,d levels deep; if this is a valid class file, raise the limit with the system property %s.maxNestingDepth.", 163 MAX_NESTING_DEPTH, Attribute.class.getCanonicalName()); 164 } 165 NESTING_DEPTH.set(Integer.valueOf(depth)); 166 try { 167 return readAttribute0(dataInput, constantPool, compactCodeHeader); 168 } finally { 169 if (depth == 1) { 170 NESTING_DEPTH.remove(); 171 } else { 172 NESTING_DEPTH.set(Integer.valueOf(depth - 1)); 173 } 174 } 175 } 176 177 /** 178 * Reads one attribute using standard eight-byte Code headers. 179 * 180 * @param dataInputStream Input stream. 181 * @param constantPool Array of constants. 182 * @return Attribute. 183 * @throws IOException Thrown if an I/O error occurs. 184 * @see #readAttribute(DataInput, ConstantPool, boolean) 185 */ 186 public static Attribute readAttribute(final DataInputStream dataInputStream, final ConstantPool constantPool) throws IOException { 187 return readAttribute((DataInput) dataInputStream, constantPool); 188 } 189 190 /** 191 * Reads one attribute without tracking the nesting depth; only to be called by {@link #readAttribute(DataInput, ConstantPool, boolean)}. 192 */ 193 private static Attribute readAttribute0(final DataInput dataInput, final ConstantPool constantPool, final boolean compactCodeHeader) throws IOException { 194 byte tag = Const.ATTR_UNKNOWN; // Unknown attribute 195 // Get class name from constant pool via 'name_index' indirection 196 final int nameIndex = dataInput.readUnsignedShort(); 197 final String name = constantPool.getConstantUtf8(nameIndex).getBytes(); 198 199 // Length of data in bytes 200 final int length = dataInput.readInt(); 201 202 // Compare strings to find known attribute 203 for (byte i = 0; i < Const.KNOWN_ATTRIBUTES; i++) { 204 if (name.equals(Const.getAttributeName(i))) { 205 tag = i; // found! 206 break; 207 } 208 } 209 210 // Call proper constructor, depending on 'tag' 211 switch (tag) { 212 case Const.ATTR_UNKNOWN: 213 final Object r = READERS.get(name); 214 if (r instanceof UnknownAttributeReader) { 215 return ((UnknownAttributeReader) r).createAttribute(nameIndex, length, dataInput, constantPool); 216 } 217 return new Unknown(nameIndex, length, dataInput, constantPool); 218 case Const.ATTR_CONSTANT_VALUE: 219 return new ConstantValue(nameIndex, length, dataInput, constantPool); 220 case Const.ATTR_SOURCE_FILE: 221 return new SourceFile(nameIndex, length, dataInput, constantPool); 222 case Const.ATTR_CODE: 223 return new Code(nameIndex, length, dataInput, constantPool, compactCodeHeader); 224 case Const.ATTR_EXCEPTIONS: 225 return new ExceptionTable(nameIndex, length, dataInput, constantPool); 226 case Const.ATTR_LINE_NUMBER_TABLE: 227 return new LineNumberTable(nameIndex, length, dataInput, constantPool); 228 case Const.ATTR_LOCAL_VARIABLE_TABLE: 229 return new LocalVariableTable(nameIndex, length, dataInput, constantPool); 230 case Const.ATTR_INNER_CLASSES: 231 return new InnerClasses(nameIndex, length, dataInput, constantPool); 232 case Const.ATTR_SYNTHETIC: 233 return new Synthetic(nameIndex, length, dataInput, constantPool); 234 case Const.ATTR_DEPRECATED: 235 return new Deprecated(nameIndex, length, dataInput, constantPool); 236 case Const.ATTR_PMG: 237 return new PMGClass(nameIndex, length, dataInput, constantPool); 238 case Const.ATTR_SIGNATURE: 239 return new Signature(nameIndex, length, dataInput, constantPool); 240 case Const.ATTR_STACK_MAP: 241 // old style stack map: unneeded for JDK5 and below; 242 // illegal(?) for JDK6 and above. So just delete with a warning. 243 println("Warning: Obsolete StackMap attribute ignored."); 244 return new Unknown(nameIndex, length, dataInput, constantPool); 245 case Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS: 246 return new RuntimeVisibleAnnotations(nameIndex, length, dataInput, constantPool); 247 case Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS: 248 return new RuntimeInvisibleAnnotations(nameIndex, length, dataInput, constantPool); 249 case Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS: 250 return new RuntimeVisibleParameterAnnotations(nameIndex, length, dataInput, constantPool); 251 case Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS: 252 return new RuntimeInvisibleParameterAnnotations(nameIndex, length, dataInput, constantPool); 253 case Const.ATTR_ANNOTATION_DEFAULT: 254 return new AnnotationDefault(nameIndex, length, dataInput, constantPool); 255 case Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE: 256 return new LocalVariableTypeTable(nameIndex, length, dataInput, constantPool); 257 case Const.ATTR_ENCLOSING_METHOD: 258 return new EnclosingMethod(nameIndex, length, dataInput, constantPool); 259 case Const.ATTR_STACK_MAP_TABLE: 260 // read new style stack map: StackMapTable. The rest of the code 261 // calls this a StackMap for historical reasons. 262 return new StackMap(nameIndex, length, dataInput, constantPool); 263 case Const.ATTR_BOOTSTRAP_METHODS: 264 return new BootstrapMethods(nameIndex, length, dataInput, constantPool); 265 case Const.ATTR_METHOD_PARAMETERS: 266 return new MethodParameters(nameIndex, length, dataInput, constantPool); 267 case Const.ATTR_MODULE: 268 return new Module(nameIndex, length, dataInput, constantPool); 269 case Const.ATTR_MODULE_PACKAGES: 270 return new ModulePackages(nameIndex, length, dataInput, constantPool); 271 case Const.ATTR_MODULE_MAIN_CLASS: 272 return new ModuleMainClass(nameIndex, length, dataInput, constantPool); 273 case Const.ATTR_NEST_HOST: 274 return new NestHost(nameIndex, length, dataInput, constantPool); 275 case Const.ATTR_NEST_MEMBERS: 276 return new NestMembers(nameIndex, length, dataInput, constantPool); 277 case Const.ATTR_RECORD: 278 return new Record(nameIndex, length, dataInput, constantPool, compactCodeHeader); 279 case Const.ATTR_PERMITTED_SUBCLASSES: 280 return new PermittedSubclasses(nameIndex, length, dataInput, constantPool); 281 case Const.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS: 282 return new RuntimeVisibleTypeAnnotations(nameIndex, length, dataInput, constantPool); 283 case Const.ATTR_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS: 284 return new RuntimeInvisibleTypeAnnotations(nameIndex, length, dataInput, constantPool); 285 default: 286 // Never reached 287 throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag); 288 } 289 } 290 291 /** 292 * Remove attribute reader 293 * 294 * @param name The name of the attribute as stored in the class file. 295 */ 296 public static void removeAttributeReader(final String name) { 297 READERS.remove(name); 298 } 299 300 /** 301 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter. 302 */ 303 @java.lang.Deprecated 304 protected int name_index; // Points to attribute name in constant pool TODO make private (has getter & setter) 305 306 /** 307 * @deprecated (since 6.0) (since 6.0) will be made private; do not access directly, use getter/setter. 308 */ 309 @java.lang.Deprecated 310 protected int length; // Content length of attribute field TODO make private (has getter & setter). 311 312 /** 313 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter. 314 */ 315 @java.lang.Deprecated 316 protected byte tag; // Tag to distinguish subclasses TODO make private & final; supposed to be immutable. 317 318 /** 319 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter. 320 */ 321 @java.lang.Deprecated 322 protected ConstantPool constant_pool; // TODO make private (has getter & setter). 323 324 /** 325 * Constructs an instance. 326 * 327 * <pre> 328 * attribute_info { 329 * u2 attribute_name_index; 330 * u4 attribute_length; 331 * u1 info[attribute_length]; 332 * } 333 * </pre> 334 * 335 * @param tag tag. 336 * @param nameIndex u2 name index. 337 * @param length u4 length. 338 * @param constantPool constant pool. 339 */ 340 protected Attribute(final byte tag, final int nameIndex, final int length, final ConstantPool constantPool) { 341 this.tag = tag; 342 this.name_index = Args.requireU2(nameIndex, 0, constantPool.getLength(), getClass().getSimpleName() + " name index"); 343 this.length = Args.requireU4(length, getClass().getSimpleName() + " attribute length"); 344 this.constant_pool = constantPool; 345 } 346 347 /** 348 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 349 * That is, the hierarchy of methods, fields, attributes, and other elements forms a tree of objects. 350 * 351 * @param v Visitor object. 352 */ 353 @Override 354 public abstract void accept(Visitor v); 355 356 /** 357 * Use copy() if you want to have a deep copy(), that is, with all references copied correctly. 358 * 359 * @return shallow copy of this attribute. 360 */ 361 @Override 362 public Object clone() { 363 Attribute attr = null; 364 try { 365 attr = (Attribute) super.clone(); 366 } catch (final CloneNotSupportedException e) { 367 throw new UnsupportedOperationException("Clone Not Supported", e); // never happens 368 } 369 return attr; 370 } 371 372 /** 373 * Creates a deep copy of this attribute. 374 * 375 * @param constantPool constant pool to save. 376 * @return deep copy of this attribute. 377 */ 378 public abstract Attribute copy(ConstantPool constantPool); 379 380 /** 381 * Dumps attribute to file stream in binary format. 382 * 383 * @param file Output file stream. 384 * @throws IOException Thrown if an I/O error occurs. 385 */ 386 public void dump(final DataOutputStream file) throws IOException { 387 file.writeShort(name_index); 388 file.writeInt(length); 389 } 390 391 /** 392 * Gets the constant pool used by this object. 393 * 394 * @return Constant pool used by this object. 395 * @see ConstantPool 396 */ 397 public final ConstantPool getConstantPool() { 398 return constant_pool; 399 } 400 401 /** 402 * Gets the length of attribute field in bytes. 403 * 404 * @return Length of attribute field in bytes. 405 */ 406 public final int getLength() { 407 return length; 408 } 409 410 /** 411 * Gets the name of the attribute. 412 * 413 * @return Name of attribute. 414 * @since 6.0 415 */ 416 public String getName() { 417 return constant_pool.getConstantUtf8(name_index).getBytes(); 418 } 419 420 /** 421 * Gets the name index in constant pool of attribute name. 422 * 423 * @return Name index in constant pool of attribute name. 424 */ 425 public final int getNameIndex() { 426 return name_index; 427 } 428 429 /** 430 * Gets the tag of attribute, that is, its type. 431 * 432 * @return Tag of attribute, that is, its type. Value may not be altered, thus there is no setTag() method. 433 */ 434 public final byte getTag() { 435 return tag; 436 } 437 438 /** 439 * Sets the constant pool to be used for this object. 440 * 441 * @param constantPool Constant pool to be used for this object. 442 * @see ConstantPool 443 */ 444 public final void setConstantPool(final ConstantPool constantPool) { 445 this.constant_pool = constantPool; 446 } 447 448 /** 449 * Sets the length in bytes. 450 * 451 * @param length length in bytes. 452 */ 453 public final void setLength(final int length) { 454 this.length = length; 455 } 456 457 /** 458 * Sets the name index of attribute. 459 * 460 * @param nameIndex of attribute. 461 */ 462 public final void setNameIndex(final int nameIndex) { 463 this.name_index = nameIndex; 464 } 465 466 /** 467 * @return attribute name. 468 */ 469 @Override 470 public String toString() { 471 return Const.getAttributeName(tag); 472 } 473}