Beispiel #1
0
		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('/', '.'));
		}
Beispiel #2
0
	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;
//		}
	}