1 /*
  2  * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 package jdk.internal.classfile.impl.verifier;
 26 
 27 import java.lang.classfile.*;
 28 import java.lang.classfile.attribute.*;
 29 import java.lang.classfile.constantpool.*;
 30 import java.lang.constant.ClassDesc;
 31 import java.lang.constant.ConstantDescs;
 32 import java.lang.reflect.AccessFlag;
 33 import java.util.ArrayList;
 34 import java.util.Collection;
 35 import java.util.HashSet;
 36 import java.util.List;
 37 import java.util.stream.Collectors;
 38 import java.util.function.Function;
 39 import java.util.function.ToIntFunction;
 40 
 41 import jdk.internal.classfile.impl.BoundAttribute;
 42 import jdk.internal.classfile.impl.Util;
 43 
 44 import static java.lang.constant.ConstantDescs.*;
 45 import static jdk.internal.classfile.impl.StackMapGenerator.*;
 46 
 47 /// ParserVerifier performs selected checks of the class file format according to
 48 /// {@jvms 4.8 Format Checking}.
 49 ///
 50 /// From `classFileParser.cpp`.
 51 ///
 52 public record ParserVerifier(ClassModel classModel) {
 53 
 54     List<VerifyError> verify() {
 55         var errors = new ArrayList<VerifyError>();
 56         verifyConstantPool(errors);
 57         verifyInterfaces(errors);
 58         verifyFields(errors);
 59         verifyMethods(errors);
 60         verifyAttributes(classModel, errors);
 61         return errors;
 62     }
 63 
 64     private void verifyConstantPool(List<VerifyError> errors) {
 65         for (var cpe : classModel.constantPool()) {
 66             try {
 67                 switch (cpe) {
 68                     case DoubleEntry de -> de.doubleValue();
 69                     case FloatEntry fe -> fe.floatValue();
 70                     case IntegerEntry ie -> ie.intValue();
 71                     case LongEntry le -> le.longValue();
 72                     case Utf8Entry ue -> ue.stringValue();
 73                     case ConstantDynamicEntry cde -> cde.asSymbol();
 74                     case InvokeDynamicEntry ide -> ide.asSymbol();
 75                     case ClassEntry ce -> ce.asSymbol();
 76                     case StringEntry se -> se.stringValue();
 77                     case MethodHandleEntry mhe -> mhe.asSymbol();
 78                     case MethodTypeEntry mte -> mte.asSymbol();
 79                     case FieldRefEntry fre -> {
 80                         try {
 81                             fre.owner().asSymbol();
 82                         } catch (VerifyError|Exception e) {
 83                             errors.add(cpeVerifyError(cpe, e));
 84                         }
 85                         try {
 86                             fre.typeSymbol();
 87                         } catch (VerifyError|Exception e) {
 88                             errors.add(cpeVerifyError(cpe, e));
 89                         }
 90                         verifyFieldName(fre.name().stringValue());
 91                     }
 92                     case InterfaceMethodRefEntry imre -> {
 93                         try {
 94                             imre.owner().asSymbol();
 95                         } catch (VerifyError|Exception e) {
 96                             errors.add(cpeVerifyError(cpe, e));
 97                         }
 98                         try {
 99                             imre.typeSymbol();
100                         } catch (VerifyError|Exception e) {
101                             errors.add(cpeVerifyError(cpe, e));
102                         }
103                         verifyMethodName(imre.name().stringValue());
104                     }
105                     case MethodRefEntry mre -> {
106                         try {
107                             mre.owner().asSymbol();
108                         } catch (VerifyError|Exception e) {
109                             errors.add(cpeVerifyError(cpe, e));
110                         }
111                         try {
112                             mre.typeSymbol();
113                         } catch (VerifyError|Exception e) {
114                             errors.add(cpeVerifyError(cpe, e));
115                         }
116                         verifyMethodName(mre.name().stringValue());
117                     }
118                     case ModuleEntry me -> me.asSymbol();
119                     case NameAndTypeEntry nate -> {
120                         try {
121                             nate.name().stringValue();
122                         } catch (VerifyError|Exception e) {
123                             errors.add(cpeVerifyError(cpe, e));
124                         }
125                         nate.type().stringValue();
126                     }
127                     case PackageEntry pe -> pe.asSymbol();
128                 }
129             } catch (VerifyError|Exception e) {
130                 errors.add(cpeVerifyError(cpe, e));
131             }
132         }
133     }
134 
135     private VerifyError cpeVerifyError(final PoolEntry cpe, final Throwable e) {
136         return new VerifyError("%s at constant pool index %d in %s".formatted(e.getMessage(), cpe.index(), toString(classModel)));
137     }
138 
139     private void verifyFieldName(String name) {
140         if (name.length() == 0 || name.chars().anyMatch(ch -> switch(ch) {
141                     case '.', ';', '[', '/' -> true;
142                     default -> false;
143                 })) {
144               throw new VerifyError("Illegal field name %s in %s".formatted(name, toString(classModel)));
145         }
146     }
147 
148     private void verifyMethodName(String name) {
149         if (!name.equals(INIT_NAME)
150             && !name.equals(CLASS_INIT_NAME)
151             && (name.length() == 0 || name.chars().anyMatch(ch -> switch(ch) {
152                     case '.', ';', '[', '/', '<', '>' -> true;
153                     default -> false;
154                 }))) {
155               throw new VerifyError("Illegal method name %s in %s".formatted(name, toString(classModel)));
156         }
157     }
158 
159     private void verifyInterfaces(List<VerifyError> errors) {
160         var intfs = new HashSet<ClassEntry>();
161         for (var intf : classModel.interfaces()) {
162             if (!intfs.add(intf)) {
163                 errors.add(new VerifyError("Duplicate interface %s in %s".formatted(intf.asSymbol().displayName(), toString(classModel))));
164             }
165         }
166     }
167 
168     private void verifyFields(List<VerifyError> errors) {
169         record F(Utf8Entry name, Utf8Entry type) {};
170         var fields = new HashSet<F>();
171         for (var f : classModel.fields()) try {
172             if (!fields.add(new F(f.fieldName(), f.fieldType()))) {
173                 errors.add(new VerifyError("Duplicate field name %s with signature %s in %s".formatted(f.fieldName().stringValue(), f.fieldType().stringValue(), toString(classModel))));
174             }
175             verifyFieldName(f.fieldName().stringValue());
176         } catch (VerifyError ve) {
177             errors.add(ve);
178         }
179     }
180 
181     private void verifyMethods(List<VerifyError> errors) {
182         record M(Utf8Entry name, Utf8Entry type) {};
183         var methods = new HashSet<M>();
184         for (var m : classModel.methods()) try {
185             if (!methods.add(new M(m.methodName(), m.methodType()))) {
186                 errors.add(new VerifyError("Duplicate method name %s with signature %s in %s".formatted(m.methodName().stringValue(), m.methodType().stringValue(), toString(classModel))));
187             }
188             if (m.methodName().equalsString(CLASS_INIT_NAME)
189                     && !m.flags().has(AccessFlag.STATIC)) {
190                 errors.add(new VerifyError("Method <clinit> is not static in %s".formatted(toString(classModel))));
191             }
192             if (classModel.flags().has(AccessFlag.INTERFACE)
193                     && m.methodName().equalsString(INIT_NAME)) {
194                 errors.add(new VerifyError("Interface cannot have a method named <init> in %s".formatted(toString(classModel))));
195             }
196             verifyMethodName(m.methodName().stringValue());
197         } catch (VerifyError ve) {
198             errors.add(ve);
199         }
200     }
201 
202     private void verifyAttributes(ClassFileElement cfe, List<VerifyError> errors) {
203         if (cfe instanceof AttributedElement ae) {
204             var attrNames = new HashSet<String>();
205             for (var a : ae.attributes()) {
206                 if (!a.attributeMapper().allowMultiple() && !attrNames.add(a.attributeName().stringValue())) {
207                     errors.add(new VerifyError("Multiple %s attributes in %s".formatted(a.attributeName().stringValue(), toString(ae))));
208                 }
209                 verifyAttribute(ae, a, errors);
210             }
211         }
212         switch (cfe) {
213             case CompoundElement<?> comp -> {
214                 for (var e : comp) verifyAttributes(e, errors);
215             }
216             case RecordAttribute ra -> {
217                 for(var rc : ra.components()) verifyAttributes(rc, errors);
218             }
219             default -> {}
220         }
221     }
222 
223     private void verifyAttribute(AttributedElement ae, Attribute<?> a, List<VerifyError> errors) {
224         int size = switch (a) {
225             case AnnotationDefaultAttribute aa ->
226                 valueSize(aa.defaultValue());
227             case BootstrapMethodsAttribute bma ->
228                 2 + bma.bootstrapMethods().stream().mapToInt(bm -> 4 + 2 * bm.arguments().size()).sum();
229             case CharacterRangeTableAttribute cra ->
230                 2 + 14 * cra.characterRangeTable().size();
231             case CodeAttribute ca -> {
232                 MethodModel mm = (MethodModel)ae;
233                 if (mm.flags().has(AccessFlag.NATIVE) || mm.flags().has(AccessFlag.ABSTRACT)) {
234                     errors.add(new VerifyError("Code attribute in native or abstract %s".formatted(toString(ae))));
235                 }
236                 if (ca.maxLocals() < Util.maxLocals(mm.flags().flagsMask(), mm.methodTypeSymbol())) {
237                     errors.add(new VerifyError("Arguments can't fit into locals in %s".formatted(toString(ae))));
238                 }
239                 yield 10 + ca.codeLength() + 8 * ca.exceptionHandlers().size() + attributesSize(ca.attributes());
240             }
241             case CompilationIDAttribute cida -> {
242                 cida.compilationId();
243                 yield 2;
244             }
245             case ConstantValueAttribute cva -> {
246                 ClassDesc type = ((FieldModel)ae).fieldTypeSymbol();
247                 ConstantValueEntry cve = cva.constant();
248                 if (!switch (TypeKind.from(type)) {
249                     case BOOLEAN, BYTE, CHAR, INT, SHORT -> cve instanceof IntegerEntry;
250                     case DOUBLE -> cve instanceof DoubleEntry;
251                     case FLOAT -> cve instanceof FloatEntry;
252                     case LONG -> cve instanceof LongEntry;
253                     case REFERENCE -> type.equals(ConstantDescs.CD_String) && cve instanceof StringEntry;
254                     case VOID -> false;
255                 }) {
256                     errors.add(new VerifyError("Bad constant value type in %s".formatted(toString(ae))));
257                 }
258                 yield 2;
259             }
260             case DeprecatedAttribute _ ->
261                 0;
262             case EnclosingMethodAttribute ema -> {
263                 ema.enclosingClass();
264                 ema.enclosingMethod();
265                 yield 4;
266             }
267             case ExceptionsAttribute ea ->
268                 2 + 2 * ea.exceptions().size();
269             case InnerClassesAttribute ica -> {
270                 for (var ici : ica.classes()) {
271                     if (ici.outerClass().isPresent() && ici.outerClass().get().equals(ici.innerClass())) {
272                         errors.add(new VerifyError("Class is both outer and inner class in %s".formatted(toString(ae))));
273                     }
274                 }
275                 yield 2 + 8 * ica.classes().size();
276             }
277             case LineNumberTableAttribute lta ->
278                 2 + 4 * lta.lineNumbers().size();
279             case LoadableDescriptorsAttribute lda -> {
280                 for (var desc : lda.loadableDescriptorSymbols()) {
281                     if (desc.equals(CD_void)) {
282                         errors.add(new VerifyError("illegal signature %s".formatted(desc)));
283                     }
284                 }
285                 yield 2 + 2 * lda.loadableDescriptors().size();
286             }
287             case LocalVariableTableAttribute lvta ->
288                 2 + 10 * lvta.localVariables().size();
289             case LocalVariableTypeTableAttribute lvta ->
290                 2 + 10 * lvta.localVariableTypes().size();
291             case MethodParametersAttribute mpa ->
292                 1 + 4 * mpa.parameters().size();
293             case ModuleAttribute ma ->
294                 16 + subSize(ma.exports(), ModuleExportInfo::exportsTo, 6, 2)
295                    + subSize(ma.opens(), ModuleOpenInfo::opensTo, 6, 2)
296                    + subSize(ma.provides(), ModuleProvideInfo::providesWith, 4, 2)
297                    + 6 * ma.requires().size()
298                    + 2 * ma.uses().size();
299             case ModuleHashesAttribute mha ->
300                 2 + moduleHashesSize(mha.hashes());
301             case ModuleMainClassAttribute mmca -> {
302                 mmca.mainClass();
303                 yield 2;
304             }
305             case ModulePackagesAttribute mpa ->
306                 2 + 2 * mpa.packages().size();
307             case ModuleResolutionAttribute mra ->
308                 2;
309             case ModuleTargetAttribute mta -> {
310                 mta.targetPlatform();
311                 yield 2;
312             }
313             case NestHostAttribute nha -> {
314                 nha.nestHost();
315                 yield 2;
316             }
317             case NestMembersAttribute nma -> {
318                 if (ae.findAttribute(Attributes.nestHost()).isPresent()) {
319                     errors.add(new VerifyError("Conflicting NestHost and NestMembers attributes in %s".formatted(toString(ae))));
320                 }
321                 yield 2 + 2 * nma.nestMembers().size();
322             }
323             case PermittedSubclassesAttribute psa -> {
324                 if (classModel.flags().has(AccessFlag.FINAL)) {
325                     errors.add(new VerifyError("PermittedSubclasses attribute in final %s".formatted(toString(ae))));
326                 }
327                 yield 2 + 2 * psa.permittedSubclasses().size();
328             }
329             case RecordAttribute ra ->
330                 componentsSize(ra.components());
331             case RuntimeVisibleAnnotationsAttribute aa ->
332                 annotationsSize(aa.annotations());
333             case RuntimeInvisibleAnnotationsAttribute aa ->
334                 annotationsSize(aa.annotations());
335             case RuntimeVisibleTypeAnnotationsAttribute aa ->
336                 typeAnnotationsSize(aa.annotations());
337             case RuntimeInvisibleTypeAnnotationsAttribute aa ->
338                 typeAnnotationsSize(aa.annotations());
339             case RuntimeVisibleParameterAnnotationsAttribute aa ->
340                 parameterAnnotationsSize(aa.parameterAnnotations());
341             case RuntimeInvisibleParameterAnnotationsAttribute aa ->
342                 parameterAnnotationsSize(aa.parameterAnnotations());
343             case SignatureAttribute sa -> {
344                 sa.signature();
345                 yield 2;
346             }
347             case SourceDebugExtensionAttribute sda ->
348                 sda.contents().length;
349             case SourceFileAttribute sfa -> {
350                 sfa.sourceFile();
351                 yield 2;
352             }
353             case SourceIDAttribute sida -> {
354                 sida.sourceId();
355                 yield 2;
356             }
357             case StackMapTableAttribute _ ->
358                 -1; // Not sufficient info for assert unset size
359             case SyntheticAttribute _ ->
360                 0;
361             case UnknownAttribute _ ->
362                 -1;
363             case CustomAttribute<?> _ ->
364                 -1;
365             default -> // should not happen if all known attributes are verified
366                 throw new AssertionError(a);
367         };
368         if (size >= 0 && size != ((BoundAttribute)a).payloadLen()) {
369             errors.add(new VerifyError("Wrong %s attribute length in %s".formatted(a.attributeName().stringValue(), toString(ae))));
370         }
371     }
372 
373     private static <T, S extends Collection<?>> int subSize(Collection<T> entries, Function<T, S> subMH, int entrySize, int subSize) {
374         return subSize(entries, (ToIntFunction<T>) t -> entrySize + subSize * subMH.apply(t).size());
375     }
376 
377     private static <T> int subSize(Collection<T> entries, ToIntFunction<T> subMH) {
378         int l = 0;
379         for (T entry : entries) {
380             l += subMH.applyAsInt(entry);
381         }
382         return l;
383     }
384 
385     private static int componentsSize(List<RecordComponentInfo> comps) {
386         int l = 2;
387         for (var rc : comps) {
388             l += 4 + attributesSize(rc.attributes());
389         }
390         return l;
391     }
392 
393     private static int attributesSize(List<Attribute<?>> attrs) {
394         int l = 2;
395         for (var a : attrs) {
396             l += 6 + ((BoundAttribute)a).payloadLen();
397         }
398         return l;
399     }
400 
401     private static int parameterAnnotationsSize(List<List<Annotation>> pans) {
402         int l = 1;
403         for (var ans : pans) {
404             l += annotationsSize(ans);
405         }
406         return l;
407     }
408 
409     private static int annotationsSize(List<Annotation> ans) {
410         int l = 2;
411         for (var an : ans) {
412             l += annotationSize(an);
413         }
414         return l;
415     }
416 
417     private static int typeAnnotationsSize(List<TypeAnnotation> ans) {
418         int l = 2;
419         for (var an : ans) {
420             l += 2 + an.targetInfo().size() + 2 * an.targetPath().size() + annotationSize(an.annotation());
421         }
422         return l;
423     }
424 
425     private static int annotationSize(Annotation an) {
426         int l = 4;
427         for (var el : an.elements()) {
428             l += 2 + valueSize(el.value());
429         }
430         return l;
431     }
432 
433     private static int valueSize(AnnotationValue val) {
434         return 1 + switch (val) {
435             case AnnotationValue.OfAnnotation oan ->
436                 annotationSize(oan.annotation());
437             case AnnotationValue.OfArray oar -> {
438                 int l = 2;
439                 for (var v : oar.values()) {
440                     l += valueSize(v);
441                 }
442                 yield l;
443             }
444             case AnnotationValue.OfConstant _, AnnotationValue.OfClass _ -> 2;
445             case AnnotationValue.OfEnum _ -> 4;
446         };
447     }
448 
449     private static int moduleHashesSize(List<ModuleHashInfo> hashes) {
450         int l = 2;
451         for (var h : hashes) {
452             h.moduleName();
453             l += 4 + h.hash().length;
454         }
455         return l;
456     }
457 
458     private int stackMapFrameSize(StackMapFrameInfo frame) {
459         int ft = frame.frameType();
460         if (ft <= SAME_FRAME_END) return 1;
461         if (ft <= SAME_LOCALS_1_STACK_ITEM_FRAME_END) return 1 + verificationTypeSize(frame.stack().getFirst());
462         if (ft > RESERVED_END) {
463             if (ft == SAME_LOCALS_1_STACK_ITEM_EXTENDED) return 3 + verificationTypeSize(frame.stack().getFirst());
464             if (ft <= SAME_FRAME_EXTENDED) return 3;
465             if (ft <= APPEND_FRAME_END) {
466                 var loc = frame.locals();
467                 int l = 3;
468                 var k = ft - APPEND_FRAME_START + 1;
469                 for (int i = loc.size() - k; i < loc.size(); i++) {
470                     l += verificationTypeSize(loc.get(i));
471                 }
472                 return l;
473             }
474             if (ft == FULL_FRAME) {
475                 int l = 7;
476                 for (var vt : frame.stack()) {
477                     l += verificationTypeSize(vt);
478                 }
479                 for (var vt : frame.locals()) {
480                     l += verificationTypeSize(vt);
481                 }
482                 return l;
483             }
484         }
485         throw new IllegalArgumentException("Invalid stack map frame type " + ft);
486     }
487 
488     private static int verificationTypeSize(StackMapFrameInfo.VerificationTypeInfo vti) {
489         return switch (vti) {
490             case StackMapFrameInfo.SimpleVerificationTypeInfo _ -> 1;
491             case StackMapFrameInfo.ObjectVerificationTypeInfo ovti -> {
492                 ovti.classSymbol();
493                 yield 3;
494             }
495             case StackMapFrameInfo.UninitializedVerificationTypeInfo _ -> 3;
496         };
497     }
498 
499     private String className() {
500         return classModel.thisClass().asSymbol().displayName();
501     }
502 
503     private String toString(AttributedElement ae) {
504         return switch (ae) {
505             case CodeModel m -> "Code attribute for " + toString(m.parent().get());
506             case FieldModel m -> "field %s.%s".formatted(
507                     className(),
508                     m.fieldName().stringValue());
509             case MethodModel m -> "method %s::%s(%s)".formatted(
510                     className(),
511                     m.methodName().stringValue(),
512                     m.methodTypeSymbol().parameterList().stream().map(ClassDesc::displayName).collect(Collectors.joining(",")));
513             case RecordComponentInfo i -> "Record component %s of class %s".formatted(
514                     i.name().stringValue(),
515                     className());
516             default -> "class " + className();
517         };
518     }
519 }