public static java.lang.Class defineClass1(java.lang.ClassLoader thisClassLoader, string name, byte[] b, int off, int len, java.security.ProtectionDomain pd, string source) { // it appears the source argument is only used for trace messages in HotSpot. We'll just ignore it for now. Profiler.Enter("ClassLoader.defineClass"); try { try { ClassLoaderWrapper classLoaderWrapper = ClassLoaderWrapper.GetClassLoaderWrapper(thisClassLoader); ClassFileParseOptions cfp = ClassFileParseOptions.LineNumberTable; if (classLoaderWrapper.EmitDebugInfo) { cfp |= ClassFileParseOptions.LocalVariableTable; } if (classLoaderWrapper.RelaxedClassNameValidation) { cfp |= ClassFileParseOptions.RelaxedClassNameValidation; } ClassFile classFile = new ClassFile(b, off, len, name, cfp); if (name != null && classFile.Name != name) { #if !FIRST_PASS throw new java.lang.NoClassDefFoundError(name + " (wrong name: " + classFile.Name + ")"); #endif } TypeWrapper type = classLoaderWrapper.DefineClass(classFile, pd); return(type.ClassObject); } catch (RetargetableJavaException x) { throw x.ToJava(); } } finally { Profiler.Leave("ClassLoader.defineClass"); } }
internal void Read(ClassFile classFile, string[] utf8_cp, Method method, BigEndianBinaryReader br, ClassFileParseOptions options) { max_stack = br.ReadUInt16(); max_locals = br.ReadUInt16(); uint code_length = br.ReadUInt32(); if(code_length > 65535) { throw new ClassFormatError("{0} (Invalid Code length {1})", classFile.Name, code_length); } Instruction[] instructions = new Instruction[code_length + 1]; int basePosition = br.Position; int instructionIndex = 0; try { BigEndianBinaryReader rdr = br.Section(code_length); while(!rdr.IsAtEnd) { instructions[instructionIndex].Read((ushort)(rdr.Position - basePosition), rdr, classFile); hasJsr |= instructions[instructionIndex].NormalizedOpCode == NormalizedByteCode.__jsr; instructionIndex++; } // we add an additional nop instruction to make it easier for consumers of the code array instructions[instructionIndex++].SetTermNop((ushort)(rdr.Position - basePosition)); } catch(ClassFormatError x) { // any class format errors in the code block are actually verify errors verifyError = x.Message; } this.instructions = new Instruction[instructionIndex]; Array.Copy(instructions, 0, this.instructions, 0, instructionIndex); // build the pcIndexMap int[] pcIndexMap = new int[this.instructions[instructionIndex - 1].PC + 1]; for(int i = 0; i < pcIndexMap.Length; i++) { pcIndexMap[i] = -1; } for(int i = 0; i < instructionIndex - 1; i++) { pcIndexMap[this.instructions[i].PC] = i; } // convert branch offsets to indexes for(int i = 0; i < instructionIndex - 1; i++) { switch(this.instructions[i].NormalizedOpCode) { case NormalizedByteCode.__ifeq: case NormalizedByteCode.__ifne: case NormalizedByteCode.__iflt: case NormalizedByteCode.__ifge: case NormalizedByteCode.__ifgt: case NormalizedByteCode.__ifle: case NormalizedByteCode.__if_icmpeq: case NormalizedByteCode.__if_icmpne: case NormalizedByteCode.__if_icmplt: case NormalizedByteCode.__if_icmpge: case NormalizedByteCode.__if_icmpgt: case NormalizedByteCode.__if_icmple: case NormalizedByteCode.__if_acmpeq: case NormalizedByteCode.__if_acmpne: case NormalizedByteCode.__ifnull: case NormalizedByteCode.__ifnonnull: case NormalizedByteCode.__goto: case NormalizedByteCode.__jsr: this.instructions[i].SetTargetIndex(pcIndexMap[this.instructions[i].Arg1 + this.instructions[i].PC]); break; case NormalizedByteCode.__tableswitch: case NormalizedByteCode.__lookupswitch: this.instructions[i].MapSwitchTargets(pcIndexMap); break; } } // read exception table ushort exception_table_length = br.ReadUInt16(); exception_table = new ExceptionTableEntry[exception_table_length]; for(int i = 0; i < exception_table_length; i++) { ushort start_pc = br.ReadUInt16(); ushort end_pc = br.ReadUInt16(); ushort handler_pc = br.ReadUInt16(); ushort catch_type = br.ReadUInt16(); if(start_pc >= end_pc || end_pc > code_length || handler_pc >= code_length || (catch_type != 0 && !classFile.SafeIsConstantPoolClass(catch_type))) { throw new ClassFormatError("Illegal exception table: {0}.{1}{2}", classFile.Name, method.Name, method.Signature); } classFile.MarkLinkRequiredConstantPoolItem(catch_type); // if start_pc, end_pc or handler_pc is invalid (i.e. doesn't point to the start of an instruction), // the index will be -1 and this will be handled by the verifier int startIndex = pcIndexMap[start_pc]; int endIndex; if (end_pc == code_length) { // it is legal for end_pc to point to just after the last instruction, // but since there isn't an entry in our pcIndexMap for that, we have // a special case for this endIndex = instructionIndex - 1; } else { endIndex = pcIndexMap[end_pc]; } int handlerIndex = pcIndexMap[handler_pc]; exception_table[i] = new ExceptionTableEntry(startIndex, endIndex, handlerIndex, catch_type, i); } ushort attributes_count = br.ReadUInt16(); for(int i = 0; i < attributes_count; i++) { switch(classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())) { case "LineNumberTable": if((options & ClassFileParseOptions.LineNumberTable) != 0) { BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); int count = rdr.ReadUInt16(); lineNumberTable = new LineNumberTableEntry[count]; for(int j = 0; j < count; j++) { lineNumberTable[j].start_pc = rdr.ReadUInt16(); lineNumberTable[j].line_number = rdr.ReadUInt16(); if(lineNumberTable[j].start_pc >= code_length) { throw new ClassFormatError("{0} (LineNumberTable has invalid pc)", classFile.Name); } } if(!rdr.IsAtEnd) { throw new ClassFormatError("{0} (LineNumberTable attribute has wrong length)", classFile.Name); } } else { br.Skip(br.ReadUInt32()); } break; case "LocalVariableTable": if((options & ClassFileParseOptions.LocalVariableTable) != 0) { BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); int count = rdr.ReadUInt16(); localVariableTable = new LocalVariableTableEntry[count]; for(int j = 0; j < count; j++) { localVariableTable[j].start_pc = rdr.ReadUInt16(); localVariableTable[j].length = rdr.ReadUInt16(); localVariableTable[j].name = classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()); localVariableTable[j].descriptor = classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()).Replace('/', '.'); localVariableTable[j].index = rdr.ReadUInt16(); } // NOTE we're intentionally not checking that we're at the end of the section // (optional attributes shouldn't cause ClassFormatError) } else { br.Skip(br.ReadUInt32()); } break; default: br.Skip(br.ReadUInt32()); break; } } // build the argmap string sig = method.Signature; List<int> args = new List<int>(); int pos = 0; if(!method.IsStatic) { args.Add(pos++); } for(int i = 1; sig[i] != ')'; i++) { args.Add(pos++); switch(sig[i]) { case 'L': i = sig.IndexOf(';', i); break; case 'D': case 'J': args.Add(-1); break; case '[': { while(sig[i] == '[') { i++; } if(sig[i] == 'L') { i = sig.IndexOf(';', i); } break; } } } argmap = args.ToArray(); if(args.Count > max_locals) { throw new ClassFormatError("{0} (Arguments can't fit into locals)", classFile.Name); } }
internal Method(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options, BigEndianBinaryReader br) : base(classFile, utf8_cp, br) { // vmspec 4.6 says that all flags, except ACC_STRICT are ignored on <clinit> // however, since Java 7 it does need to be marked static if(ReferenceEquals(Name, StringConstants.CLINIT) && ReferenceEquals(Signature, StringConstants.SIG_VOID) && (classFile.MajorVersion < 51 || IsStatic)) { access_flags &= Modifiers.Strictfp; access_flags |= (Modifiers.Static | Modifiers.Private); } else { // LAMESPEC: vmspec 4.6 says that abstract methods can not be strictfp (and this makes sense), but // javac (pre 1.5) is broken and marks abstract methods as strictfp (if you put the strictfp on the class) if((ReferenceEquals(Name, StringConstants.INIT) && (IsStatic || IsSynchronized || IsFinal || IsAbstract || IsNative)) || (IsPrivate && IsPublic) || (IsPrivate && IsProtected) || (IsPublic && IsProtected) || (IsAbstract && (IsFinal || IsNative || IsPrivate || IsStatic || IsSynchronized)) || (classFile.IsInterface && (!IsPublic || !IsAbstract))) { throw new ClassFormatError("{0} (Illegal method modifiers: 0x{1:X})", classFile.Name, access_flags); } } int attributes_count = br.ReadUInt16(); for(int i = 0; i < attributes_count; i++) { switch(classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())) { case "Deprecated": if(br.ReadUInt32() != 0) { throw new ClassFormatError("Invalid Deprecated attribute length"); } flags |= FLAG_MASK_DEPRECATED; break; case "Code": { if(!code.IsEmpty) { throw new ClassFormatError("{0} (Duplicate Code attribute)", classFile.Name); } BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); code.Read(classFile, utf8_cp, this, rdr, options); if(!rdr.IsAtEnd) { throw new ClassFormatError("{0} (Code attribute has wrong length)", classFile.Name); } break; } case "Exceptions": { if(exceptions != null) { throw new ClassFormatError("{0} (Duplicate Exceptions attribute)", classFile.Name); } BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); ushort count = rdr.ReadUInt16(); exceptions = new string[count]; for(int j = 0; j < count; j++) { exceptions[j] = classFile.GetConstantPoolClass(rdr.ReadUInt16()); } if(!rdr.IsAtEnd) { throw new ClassFormatError("{0} (Exceptions attribute has wrong length)", classFile.Name); } break; } case "Signature": if(classFile.MajorVersion < 49) { goto default; } if(br.ReadUInt32() != 2) { throw new ClassFormatError("Signature attribute has incorrect length"); } signature = classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); break; case "RuntimeVisibleAnnotations": if(classFile.MajorVersion < 49) { goto default; } annotations = ReadAnnotations(br, classFile, utf8_cp); break; case "RuntimeVisibleParameterAnnotations": { if(classFile.MajorVersion < 49) { goto default; } if(low == null) { low = new LowFreqData(); } BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); byte num_parameters = rdr.ReadByte(); low.parameterAnnotations = new object[num_parameters][]; for(int j = 0; j < num_parameters; j++) { ushort num_annotations = rdr.ReadUInt16(); low.parameterAnnotations[j] = new object[num_annotations]; for(int k = 0; k < num_annotations; k++) { low.parameterAnnotations[j][k] = ReadAnnotation(rdr, classFile, utf8_cp); } } if(!rdr.IsAtEnd) { throw new ClassFormatError("{0} (RuntimeVisibleParameterAnnotations attribute has wrong length)", classFile.Name); } break; } case "AnnotationDefault": { if(classFile.MajorVersion < 49) { goto default; } if(low == null) { low = new LowFreqData(); } BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); low.annotationDefault = ReadAnnotationElementValue(rdr, classFile, utf8_cp); if(!rdr.IsAtEnd) { throw new ClassFormatError("{0} (AnnotationDefault attribute has wrong length)", classFile.Name); } break; } #if STATIC_COMPILER case "RuntimeInvisibleAnnotations": if(classFile.MajorVersion < 49) { goto default; } foreach(object[] annot in ReadAnnotations(br, classFile, utf8_cp)) { if(annot[1].Equals("Likvm/lang/Internal;")) { if (classFile.IsInterface) { StaticCompiler.IssueMessage(Message.InterfaceMethodCantBeInternal, classFile.Name, this.Name, this.Signature); } else { this.access_flags &= ~Modifiers.AccessMask; flags |= FLAG_MASK_INTERNAL; } } if(annot[1].Equals("Likvm/internal/HasCallerID;")) { flags |= FLAG_HAS_CALLERID; } if(annot[1].Equals("Likvm/lang/DllExport;")) { string name = null; int? ordinal = null; for (int j = 2; j < annot.Length; j += 2) { if (annot[j].Equals("name") && annot[j + 1] is string) { name = (string)annot[j + 1]; } else if (annot[j].Equals("ordinal") && annot[j + 1] is int) { ordinal = (int)annot[j + 1]; } } if (name != null && ordinal != null) { if (!IsStatic) { StaticCompiler.IssueMessage(Message.DllExportMustBeStaticMethod, classFile.Name, this.Name, this.Signature); } else { if (low == null) { low = new LowFreqData(); } low.DllExportName = name; low.DllExportOrdinal = ordinal.Value; } } } } break; #endif default: br.Skip(br.ReadUInt32()); break; } } if(IsAbstract || IsNative) { if(!code.IsEmpty) { throw new ClassFormatError("Abstract or native method cannot have a Code attribute"); } } else { if(code.IsEmpty) { if(ReferenceEquals(this.Name, StringConstants.CLINIT)) { code.verifyError = string.Format("Class {0}, method {1} signature {2}: No Code attribute", classFile.Name, this.Name, this.Signature); return; } throw new ClassFormatError("Method has no Code attribute"); } } }
internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) { s = classFile.GetConstantPoolUtf8String(utf8_cp, string_index); }
internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) { ConstantPoolItemNameAndType name_and_type = (ConstantPoolItemNameAndType)classFile.GetConstantPoolItem(name_and_type_index); // if the constant pool items referred to were strings, GetConstantPoolItem returns null if (name_and_type == null) { throw new ClassFormatError("Bad index in constant pool"); } name = String.Intern(classFile.GetConstantPoolUtf8String(utf8_cp, name_and_type.name_index)); descriptor = String.Intern(classFile.GetConstantPoolUtf8String(utf8_cp, name_and_type.descriptor_index).Replace('/', '.')); }
internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) { string descriptor = classFile.GetConstantPoolUtf8String(utf8_cp, signature_index); if (descriptor == null || !IsValidMethodSig(descriptor)) { throw new ClassFormatError("Invalid MethodType signature"); } this.descriptor = String.Intern(descriptor.Replace('/', '.')); }
internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) { switch ((RefKind)ref_kind) { case RefKind.getField: case RefKind.getStatic: case RefKind.putField: case RefKind.putStatic: cpi = classFile.GetConstantPoolItem(method_index) as ConstantPoolItemFieldref; break; case RefKind.invokeSpecial: case RefKind.invokeVirtual: case RefKind.invokeStatic: case RefKind.newInvokeSpecial: cpi = classFile.GetConstantPoolItem(method_index) as ConstantPoolItemMethodref; break; case RefKind.invokeInterface: cpi = classFile.GetConstantPoolItem(method_index) as ConstantPoolItemInterfaceMethodref; break; } if (cpi == null) { throw new ClassFormatError("Invalid constant pool item MethodHandle"); } if (ReferenceEquals(cpi.Name, StringConstants.INIT) && Kind != RefKind.newInvokeSpecial) { throw new ClassFormatError("Bad method name"); } }
internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) { if(classFile.GetConstantPoolUtf8String(utf8_cp, name_index) == null || classFile.GetConstantPoolUtf8String(utf8_cp, descriptor_index) == null) { throw new ClassFormatError("Illegal constant pool index"); } }
internal ClassFile(byte[] buf, int offset, int length, string inputClassName, ClassFileParseOptions options) { try { BigEndianBinaryReader br = new BigEndianBinaryReader(buf, offset, length); if(br.ReadUInt32() != 0xCAFEBABE) { throw new ClassFormatError("{0} (Bad magic number)", inputClassName); } ushort minorVersion = br.ReadUInt16(); ushort majorVersion = br.ReadUInt16(); if((majorVersion & FLAG_MASK_MAJORVERSION) != majorVersion || majorVersion < SupportedVersions.Minimum || majorVersion > SupportedVersions.Maximum || (majorVersion == SupportedVersions.Minimum && minorVersion < 3) || (majorVersion == SupportedVersions.Maximum && minorVersion != 0)) { throw new UnsupportedClassVersionError(inputClassName + " (" + majorVersion + "." + minorVersion + ")"); } flags = majorVersion; int constantpoolcount = br.ReadUInt16(); constantpool = new ConstantPoolItem[constantpoolcount]; string[] utf8_cp = new string[constantpoolcount]; for(int i = 1; i < constantpoolcount; i++) { Constant tag = (Constant)br.ReadByte(); switch(tag) { case Constant.Class: constantpool[i] = new ConstantPoolItemClass(br); break; case Constant.Double: constantpool[i] = new ConstantPoolItemDouble(br); i++; break; case Constant.Fieldref: constantpool[i] = new ConstantPoolItemFieldref(br); break; case Constant.Float: constantpool[i] = new ConstantPoolItemFloat(br); break; case Constant.Integer: constantpool[i] = new ConstantPoolItemInteger(br); break; case Constant.InterfaceMethodref: constantpool[i] = new ConstantPoolItemInterfaceMethodref(br); break; case Constant.Long: constantpool[i] = new ConstantPoolItemLong(br); i++; break; case Constant.Methodref: constantpool[i] = new ConstantPoolItemMethodref(br); break; case Constant.NameAndType: constantpool[i] = new ConstantPoolItemNameAndType(br); break; case Constant.MethodHandle: if (majorVersion < 51) goto default; constantpool[i] = new ConstantPoolItemMethodHandle(br); break; case Constant.MethodType: if (majorVersion < 51) goto default; constantpool[i] = new ConstantPoolItemMethodType(br); break; case Constant.InvokeDynamic: if (majorVersion < 51) goto default; constantpool[i] = new ConstantPoolItemInvokeDynamic(br); break; case Constant.String: constantpool[i] = new ConstantPoolItemString(br); break; case Constant.Utf8: utf8_cp[i] = br.ReadString(inputClassName); break; default: throw new ClassFormatError("{0} (Illegal constant pool type 0x{1:X})", inputClassName, tag); } } for(int i = 1; i < constantpoolcount; i++) { if(constantpool[i] != null) { try { constantpool[i].Resolve(this, utf8_cp, options); } catch(ClassFormatError x) { // HACK at this point we don't yet have the class name, so any exceptions throw // are missing the class name throw new ClassFormatError("{0} ({1})", inputClassName, x.Message); } catch(IndexOutOfRangeException) { throw new ClassFormatError("{0} (Invalid constant pool item #{1})", inputClassName, i); } catch(InvalidCastException) { throw new ClassFormatError("{0} (Invalid constant pool item #{1})", inputClassName, i); } } } access_flags = (Modifiers)br.ReadUInt16(); // NOTE although the vmspec says (in 4.1) that interfaces must be marked abstract, earlier versions of // javac (JDK 1.1) didn't do this, so the VM doesn't enforce this rule for older class files. // NOTE although the vmspec implies (in 4.1) that ACC_SUPER is illegal on interfaces, it doesn't enforce this // for older class files. // (See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6320322) if((IsInterface && IsFinal) || (IsAbstract && IsFinal) || (majorVersion >= 49 && IsAnnotation && !IsInterface) || (majorVersion >= 49 && IsInterface && (!IsAbstract || IsSuper || IsEnum))) { throw new ClassFormatError("{0} (Illegal class modifiers 0x{1:X})", inputClassName, access_flags); } this_class = br.ReadUInt16(); ValidateConstantPoolItemClass(inputClassName, this_class); super_class = br.ReadUInt16(); ValidateConstantPoolItemClass(inputClassName, super_class); if(IsInterface && (super_class == 0 || this.SuperClass != "java.lang.Object")) { throw new ClassFormatError("{0} (Interfaces must have java.lang.Object as superclass)", Name); } // most checks are already done by ConstantPoolItemClass.Resolve, but since it allows // array types, we do need to check for that if(this.Name[0] == '[') { throw new ClassFormatError("Bad name"); } int interfaces_count = br.ReadUInt16(); interfaces = new ConstantPoolItemClass[interfaces_count]; for(int i = 0; i < interfaces.Length; i++) { int index = br.ReadUInt16(); if(index == 0 || index >= constantpool.Length) { throw new ClassFormatError("{0} (Illegal constant pool index)", Name); } ConstantPoolItemClass cpi = constantpool[index] as ConstantPoolItemClass; if(cpi == null) { throw new ClassFormatError("{0} (Interface name has bad constant type)", Name); } interfaces[i] = cpi; for(int j = 0; j < i; j++) { if(ReferenceEquals(interfaces[j].Name, cpi.Name)) { throw new ClassFormatError("{0} (Repetitive interface name)", Name); } } } int fields_count = br.ReadUInt16(); fields = new Field[fields_count]; for(int i = 0; i < fields_count; i++) { fields[i] = new Field(this, utf8_cp, br); string name = fields[i].Name; if(!IsValidFieldName(name, majorVersion)) { throw new ClassFormatError("{0} (Illegal field name \"{1}\")", Name, name); } for(int j = 0; j < i; j++) { if(ReferenceEquals(fields[j].Name, name) && ReferenceEquals(fields[j].Signature, fields[i].Signature)) { throw new ClassFormatError("{0} (Repetitive field name/signature)", Name); } } } int methods_count = br.ReadUInt16(); methods = new Method[methods_count]; for(int i = 0; i < methods_count; i++) { methods[i] = new Method(this, utf8_cp, options, br); string name = methods[i].Name; string sig = methods[i].Signature; if(!IsValidMethodName(name, majorVersion)) { if(!ReferenceEquals(name, StringConstants.INIT) && !ReferenceEquals(name, StringConstants.CLINIT)) { throw new ClassFormatError("{0} (Illegal method name \"{1}\")", Name, name); } if(!sig.EndsWith("V")) { throw new ClassFormatError("{0} (Method \"{1}\" has illegal signature \"{2}\")", Name, name, sig); } } for(int j = 0; j < i; j++) { if(ReferenceEquals(methods[j].Name, name) && ReferenceEquals(methods[j].Signature, sig)) { throw new ClassFormatError("{0} (Repetitive method name/signature)", Name); } } } int attributes_count = br.ReadUInt16(); for(int i = 0; i < attributes_count; i++) { switch(GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())) { case "Deprecated": if(br.ReadUInt32() != 0) { throw new ClassFormatError("Invalid Deprecated attribute length"); } flags |= FLAG_MASK_DEPRECATED; break; case "SourceFile": if(br.ReadUInt32() != 2) { throw new ClassFormatError("SourceFile attribute has incorrect length"); } sourceFile = GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); break; case "InnerClasses": { BigEndianBinaryReader rdr = br; uint attribute_length = br.ReadUInt32(); ushort count = rdr.ReadUInt16(); if(this.MajorVersion >= 49 && attribute_length != 2 + count * (2 + 2 + 2 + 2)) { throw new ClassFormatError("{0} (InnerClasses attribute has incorrect length)", this.Name); } innerClasses = new InnerClass[count]; for(int j = 0; j < innerClasses.Length; j++) { innerClasses[j].innerClass = rdr.ReadUInt16(); innerClasses[j].outerClass = rdr.ReadUInt16(); innerClasses[j].name = rdr.ReadUInt16(); innerClasses[j].accessFlags = (Modifiers)rdr.ReadUInt16(); if(innerClasses[j].innerClass != 0 && !(GetConstantPoolItem(innerClasses[j].innerClass) is ConstantPoolItemClass)) { throw new ClassFormatError("{0} (inner_class_info_index has bad constant pool index)", this.Name); } if(innerClasses[j].outerClass != 0 && !(GetConstantPoolItem(innerClasses[j].outerClass) is ConstantPoolItemClass)) { throw new ClassFormatError("{0} (outer_class_info_index has bad constant pool index)", this.Name); } if(innerClasses[j].name != 0 && utf8_cp[innerClasses[j].name] == null) { throw new ClassFormatError("{0} (inner class name has bad constant pool index)", this.Name); } if(innerClasses[j].innerClass == innerClasses[j].outerClass) { throw new ClassFormatError("{0} (Class is both inner and outer class)", this.Name); } if(innerClasses[j].innerClass != 0 && innerClasses[j].outerClass != 0) { MarkLinkRequiredConstantPoolItem(innerClasses[j].innerClass); MarkLinkRequiredConstantPoolItem(innerClasses[j].outerClass); } } break; } case "Signature": if(majorVersion < 49) { goto default; } if(br.ReadUInt32() != 2) { throw new ClassFormatError("Signature attribute has incorrect length"); } signature = GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); break; case "EnclosingMethod": if(majorVersion < 49) { goto default; } if(br.ReadUInt32() != 4) { throw new ClassFormatError("EnclosingMethod attribute has incorrect length"); } else { int class_index = br.ReadUInt16(); int method_index = br.ReadUInt16(); if(method_index == 0) { enclosingMethod = new string[] { GetConstantPoolClass(class_index), null, null }; } else { ConstantPoolItemNameAndType m = (ConstantPoolItemNameAndType)GetConstantPoolItem(method_index); enclosingMethod = new string[] { GetConstantPoolClass(class_index), GetConstantPoolUtf8String(utf8_cp, m.name_index), GetConstantPoolUtf8String(utf8_cp, m.descriptor_index).Replace('/', '.') }; } } break; case "RuntimeVisibleAnnotations": if(majorVersion < 49) { goto default; } annotations = ReadAnnotations(br, this, utf8_cp); break; #if STATIC_COMPILER case "RuntimeInvisibleAnnotations": if(majorVersion < 49) { goto default; } foreach(object[] annot in ReadAnnotations(br, this, utf8_cp)) { if(annot[1].Equals("Likvm/lang/Internal;")) { this.access_flags &= ~Modifiers.AccessMask; flags |= FLAG_MASK_INTERNAL; } } break; #endif case "BootstrapMethods": if(majorVersion < 51) { goto default; } bootstrapMethods = ReadBootstrapMethods(br, this); break; case "IKVM.NET.Assembly": if(br.ReadUInt32() != 2) { throw new ClassFormatError("IKVM.NET.Assembly attribute has incorrect length"); } ikvmAssembly = GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); break; default: br.Skip(br.ReadUInt32()); break; } } // validate the invokedynamic entries to point into the bootstrapMethods array for(int i = 1; i < constantpoolcount; i++) { ConstantPoolItemInvokeDynamic cpi; if(constantpool[i] != null && (cpi = constantpool[i] as ConstantPoolItemInvokeDynamic) != null) { if(bootstrapMethods == null || cpi.BootstrapMethod >= bootstrapMethods.Length) { throw new ClassFormatError("Short length on BootstrapMethods in class file"); } } } if(br.Position != offset + length) { throw new ClassFormatError("Extra bytes at the end of the class file"); } } catch(OverflowException) { throw new ClassFormatError("Truncated class file (or section)"); } catch(IndexOutOfRangeException) { // TODO we should throw more specific errors throw new ClassFormatError("Unspecified class file format error"); } // catch(Exception x) // { // Console.WriteLine(x); // FileStream fs = File.Create(inputClassName + ".broken"); // fs.Write(buf, offset, length); // fs.Close(); // throw; // } }
internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) { name = classFile.GetConstantPoolUtf8String(utf8_cp, name_index); if(name.Length > 0) { // We don't enforce the strict class name rules in the static compiler, since HotSpot doesn't enforce *any* rules on // class names for the system (and boot) class loader. We still need to enforce the 1.5 restrictions, because we // rely on those invariants. #if !STATIC_COMPILER if(classFile.MajorVersion < 49 && (options & ClassFileParseOptions.RelaxedClassNameValidation) == 0) { char prev = name[0]; if(Char.IsLetter(prev) || prev == '$' || prev == '_' || prev == '[' || prev == '/') { int skip = 1; int end = name.Length; if(prev == '[') { if(!IsValidFieldSig(name)) { goto barf; } while(name[skip] == '[') { skip++; } if(name.EndsWith(";")) { end--; } } for(int i = skip; i < end; i++) { char c = name[i]; if(!Char.IsLetterOrDigit(c) && c != '$' && c != '_' && (c != '/' || prev == '/')) { goto barf; } prev = c; } name = String.Intern(name.Replace('/', '.')); return; } } else #endif { // since 1.5 the restrictions on class names have been greatly reduced int end = name.Length; if(name[0] == '[') { if(!IsValidFieldSig(name)) { goto barf; } // the semicolon is only allowed at the end and IsValidFieldSig enforces this, // but since invalidJava15Characters contains the semicolon, we decrement end // to make the following check against invalidJava15Characters ignore the // trailing semicolon. if(name[end - 1] == ';') { end--; } } if(name.IndexOfAny(invalidJava15Characters, 0, end) >= 0) { goto barf; } name = String.Intern(name.Replace('/', '.')); return; } } barf: throw new ClassFormatError("Invalid class name \"{0}\"", name); }
internal virtual void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) { }