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}