{"record":{"id":"715f8920dfdb7bf7","repo":"QL-Win/QuickLook","slug":"optional-header-not-found","errorCode":null,"errorMessage":"Optional header not found.","messagePattern":"Optional header not found\\.","errorType":"exception","errorClass":"PEImageParseException","httpStatus":null,"severity":"error","filePath":"QuickLook.Plugin/QuickLook.Plugin.PEViewer/PEImageParser/PEImage.cs","lineNumber":112,"sourceCode":"        DosStub = reader.ReadBytes((int)(DosHeader.PEHeaderOffset - reader.BaseStream.Position));\n\n        // COFF Header\n        if (reader.ReadUInt32() != 0x4550) throw new PEImageParseException((int)reader.BaseStream.Position - 4, \"COFF header not found.\");\n        if (reader.BaseStream.Length - reader.BaseStream.Position < 20) throw new PEImageParseException((int)reader.BaseStream.Position, \"COFF header incomplete.\");\n\n        CoffHeader = new()\n        {\n            Machine = (ImageMachineType)reader.ReadUInt16(),\n            NumberOfSections = reader.ReadUInt16(),\n            TimeDateStamp = reader.ReadUInt32(),\n            PointerToSymbolTable = reader.ReadUInt32(),\n            NumberOfSymbols = reader.ReadUInt32(),\n            SizeOfOptionalHeader = reader.ReadUInt16(),\n            Characteristics = (ImageCharacteristics)reader.ReadUInt16()\n        };\n\n        // Optional Header\n        if (reader.BaseStream.Length - reader.BaseStream.Position < 2) throw new PEImageParseException((int)reader.BaseStream.Position, \"Optional header not found.\");\n        ushort magic = reader.ReadUInt16();\n\n        if (magic == 0x10b)\n        {\n            if (reader.BaseStream.Length - reader.BaseStream.Position < 94) throw new PEImageParseException((int)reader.BaseStream.Position, \"Optional header incomplete.\");\n\n            OptionalHeader = new ImageOptionalHeader32\n            {\n                MajorLinkerVersion = reader.ReadByte(),\n                MinorLinkerVersion = reader.ReadByte(),\n                SizeOfCode = reader.ReadUInt32(),\n                SizeOfInitializedData = reader.ReadUInt32(),\n                SizeOfUninitializedData = reader.ReadUInt32(),\n                AddressOfEntryPoint = reader.ReadUInt32(),\n                BaseOfCode = reader.ReadUInt32(),\n                BaseOfData = reader.ReadUInt32(),\n                ImageBase = reader.ReadUInt32(),\n                SectionAlignment = reader.ReadUInt32(),","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/QL-Win/QuickLook/blob/cb5d9c429c81d9796fac469da2a68efb5626946d/QuickLook.Plugin/QuickLook.Plugin.PEViewer/PEImageParser/PEImage.cs#L94-L130","documentation":"Immediately after the 20-byte COFF header, the optional header begins with a 2-byte magic number that identifies the image subtype (PE32, PE32+, or ROM). The parser requires at least 2 bytes remaining to read this magic; if fewer bytes remain the optional header does not exist and parsing aborts. The exception Offset marks where the magic should have been.","triggerScenarios":"The COFF header was parsed successfully but fewer than 2 bytes remain in the stream. This occurs when the file ends immediately after the COFF header, or when the COFF header's SizeOfOptionalHeader field is 0 (typical of COFF object files that are not memory images).","commonSituations":"Passing a COFF object file (.obj) instead of a linked image (.exe/.dll) — object files have SizeOfOptionalHeader = 0 and no optional header; a truncated download where the file ends at the COFF/optional-header boundary; a stripped or malformed image.","solutions":["Confirm you are passing a linked PE image (.exe or .dll), not a COFF object file (.obj)","If the file is an image, re-download and verify its integrity via hash comparison","Guard the call with try-catch(PEImageParseException) when processing untrusted or user-selected files"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Verify SizeOfOptionalHeader > 0 (object files have it set to 0)\nstatic bool HasOptionalHeader(string path)\n{\n    byte[] b = File.ReadAllBytes(path);\n    if (b.Length < 0x40) return false;\n    int peOff = BitConverter.ToInt32(b, 0x3C);\n    int coffOff = peOff + 4; // after PE signature\n    if (coffOff + 20 > b.Length) return false;\n    // SizeOfOptionalHeader is at COFF offset + 16 (2 bytes)\n    ushort sizeOfOptHeader = BitConverter.ToUInt16(b, coffOff + 16);\n    return sizeOfOptHeader > 0;\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    var image = PEImage.FromFile(path);\n}\ncatch (PEImageParseException ex) when (ex.Message.Contains(\"Optional header not found\"))\n{\n    // Likely a .obj object file or truncated image\n    logger.Warn($\"No optional header: {ex.Message}\");\n}","preventionTips":["Do not pass COFF object files (.obj) to this parser — it expects linked PE images only","Check that the file extension and content indicate an image (.exe/.dll), not an object or archive","Verify file completeness before parsing untrusted binaries"],"tags":["pe-format","binary-parsing","truncated-file","object-file"],"backgroundTag":null,"analyzedSha":"cb5d9c429c81d9796fac469da2a68efb5626946d","analyzedAt":"2026-08-13T11:51:01.370Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}