internal FieldOrMethod(ClassFile classFile, BigEndianBinaryReader br) { access_flags = (__Modifiers) br.ReadUInt16(); name = String.Intern(classFile.GetConstantPoolUtf8String(br.ReadUInt16())); descriptor = classFile.GetConstantPoolUtf8String(br.ReadUInt16()); ValidateSig(classFile, descriptor); descriptor = String.Intern(descriptor.Replace('/', '.')); }
internal ClassFile(byte[] buf, int offset, int length, string inputClassName, bool allowJavaLangObject) { try { BigEndianBinaryReader br = new BigEndianBinaryReader(buf, offset, length); if (br.ReadUInt32() != 0xCAFEBABE) { throw new ClassFormatError("{0} (Bad magic number)", inputClassName); } int minorVersion = br.ReadUInt16(); majorVersion = br.ReadUInt16(); if (majorVersion < SupportedVersions.Minimum || majorVersion > SupportedVersions.Maximum) { throw new UnsupportedClassVersionError(inputClassName + " (" + majorVersion + "." + minorVersion + ")"); } int constantpoolcount = br.ReadUInt16(); constantpool = new ConstantPoolItem[constantpoolcount]; 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.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); } 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 // NOTE although the vmspec implies (in 4.1) that ACC_SUPER is illegal on interfaces, it doesn't enforce this if ((IsInterface && IsFinal) || (IsAbstract && IsFinal)) { 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(); // NOTE for convenience we allow parsing java/lang/Object (which has no super class), so // we check for super_class != 0 if (super_class != 0) { ValidateConstantPoolItemClass(inputClassName, super_class); } else { if (this.Name != "java.lang.Object" || !allowJavaLangObject) { throw new ClassFormatError("{0} (Bad superclass index)", Name); } } 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 (interfaces[j].Name == cpi.Name) { throw new ClassFormatError("{0} (Repetitive interface name)", Name); } } } int fields_count = br.ReadUInt16(); fields = new Field[fields_count]; Hashtable fieldNameSigs = new Hashtable(); for (int i = 0; i < fields_count; i++) { fields[i] = new Field(this, br); string name = fields[i].Name; if (!IsValidIdentifier(name)) { throw new ClassFormatError("{0} (Illegal field name \"{1}\")", Name, name); } try { fieldNameSigs.Add(name + fields[i].Signature, null); } catch (ArgumentException) { throw new ClassFormatError("{0} (Repetitive field name/signature)", Name); } } int methods_count = br.ReadUInt16(); methods = new Method[methods_count]; Hashtable methodNameSigs = new Hashtable(); for (int i = 0; i < methods_count; i++) { methods[i] = new Method(this, br); string name = methods[i].Name; string sig = methods[i].Signature; if (!IsValidIdentifier(name) && name != "<init>" && name != "<clinit>") { throw new ClassFormatError("{0} (Illegal method name \"{1}\")", Name, name); } if ((name == "<init>" || name == "<clinit>") && !sig.EndsWith("V")) { throw new ClassFormatError("{0} (Method \"{1}\" has illegal signature \"{2}\")", Name, name, sig); } try { methodNameSigs.Add(name + sig, null); } catch (ArgumentException) { throw new ClassFormatError("{0} (Repetitive method name/signature)", Name); } } int attributes_count = br.ReadUInt16(); for (int i = 0; i < attributes_count; i++) { switch (GetConstantPoolUtf8String(br.ReadUInt16())) { case "Deprecated": deprecated = true; #if FUZZ_HACK br.Skip(br.ReadUInt32()); #else if(br.ReadUInt32() != 0) { throw new ClassFormatError("Deprecated attribute has non-zero length"); } #endif break; case "SourceFile": if (br.ReadUInt32() != 2) { throw new ClassFormatError("SourceFile attribute has incorrect length"); } sourceFile = GetConstantPoolUtf8String(br.ReadUInt16()); break; case "InnerClasses": #if FUZZ_HACK // Sun totally ignores the length of InnerClasses attribute, // so when we're running Fuzz this shows up as lots of differences. // To get rid off these differences define the FUZZ_HACK symbol. BigEndianBinaryReader rdr = br; br.ReadUInt32(); #else BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); #endif ushort count = rdr.ReadUInt16(); 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 !FUZZ_HACK if(!rdr.IsAtEnd) { throw new ClassFormatError("{0} (InnerClasses attribute has wrong length)", this.Name); } #endif break; case "IKVM.NET.Assembly": if (br.ReadUInt32() != 2) { throw new ClassFormatError("IKVM.NET.Assembly attribute has incorrect length"); } ikvmAssembly = GetConstantPoolUtf8String(br.ReadUInt16()); break; default: br.Skip(br.ReadUInt32()); break; } } 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; // } }