{"record":{"id":"fbbcbc1aa8e765fc","repo":"QL-Win/QuickLook","slug":"data-directories-incomplete","errorCode":null,"errorMessage":"Data directories incomplete.","messagePattern":"Data directories incomplete\\.","errorType":"exception","errorClass":"PEImageParseException","httpStatus":null,"severity":"error","filePath":"QuickLook.Plugin/QuickLook.Plugin.PEViewer/PEImageParser/PEImage.cs","lineNumber":198,"sourceCode":"                SizeOfStackReserve = reader.ReadUInt64(),\n                SizeOfStackCommit = reader.ReadUInt64(),\n                SizeOfHeapReserve = reader.ReadUInt64(),\n                SizeOfHeapCommit = reader.ReadUInt64(),\n                LoaderFlags = reader.ReadUInt32(),\n                NumberOfRvaAndSizes = reader.ReadUInt32()\n            };\n        }\n        else if (magic == 0x107)\n        {\n            throw new PEImageParseException((int)reader.BaseStream.Position - 2, \"Optional header for ROM's is not supported.\");\n        }\n        else\n        {\n            throw new PEImageParseException((int)reader.BaseStream.Position - 2, \"Optional header magic value of '0x\" + magic.ToString(\"x4\") + \"' unknown.\");\n        }\n\n        // Data Directories\n        if (reader.BaseStream.Length - reader.BaseStream.Position < OptionalHeader.NumberOfRvaAndSizes * 8) throw new PEImageParseException((int)reader.BaseStream.Position, \"Data directories incomplete.\");\n\n        OptionalHeader.DataDirectories = Create.Array((int)OptionalHeader.NumberOfRvaAndSizes, i => new ImageDataDirectory((ImageDataDirectoryName)i, reader.ReadUInt32(), reader.ReadUInt32()));\n\n        // Section Headers\n        if (reader.BaseStream.Length - reader.BaseStream.Position < CoffHeader.NumberOfSections * 40) throw new PEImageParseException((int)reader.BaseStream.Position, \"Section headers incomplete.\");\n\n        Sections = Create\n            .Enumerable(CoffHeader.NumberOfSections, i => new ImageSectionHeader\n            {\n                Name = reader.ReadBytes(8).TakeWhile(c => c != 0).ToArray().ToUTF8String(),\n                VirtualSize = reader.ReadUInt32(),\n                VirtualAddress = reader.ReadUInt32(),\n                SizeOfRawData = reader.ReadUInt32(),\n                PointerToRawData = reader.ReadUInt32(),\n                PointerToRelocations = reader.ReadUInt32(),\n                PointerToLineNumbers = reader.ReadUInt32(),\n                NumberOfRelocations = reader.ReadUInt16(),\n                NumberOfLineNumbers = reader.ReadUInt16(),","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/QL-Win/QuickLook/blob/cb5d9c429c81d9796fac469da2a68efb5626946d/QuickLook.Plugin/QuickLook.Plugin.PEViewer/PEImageParser/PEImage.cs#L180-L216","documentation":"After the optional header, the PE format stores a data directory table consisting of NumberOfRvaAndSizes entries, each 8 bytes (a 4-byte RVA + 4-byte Size). The parser computes NumberOfRvaAndSizes * 8 and checks that many bytes remain; if not, the data directory table is truncated. The standard value for NumberOfRvaAndSizes is 16 (0x10) in modern PE images.","triggerScenarios":"OptionalHeader.NumberOfRvaAndSizes multiplied by 8 exceeds the remaining bytes in the stream. This can happen because the NumberOfRvaAndSizes field is corrupted to an abnormally large value, or because the file is physically truncated after the optional header.","commonSituations":"A corrupted NumberOfRvaAndSizes field (e.g. garbage data making it millions instead of 16); a file truncated after the optional header but before the data directory table; a malformed PE produced by a buggy or obfuscating toolchain.","solutions":["Inspect the file with a PE viewer to check whether NumberOfRvaAndSizes is a sane value (standard is 16)","Re-acquire the file if it appears to be truncated","Pre-validate by reading NumberOfRvaAndSizes from the optional header and sanity-checking it is <= 16 before full parsing","Catch PEImageParseException for robust handling of malformed PE inputs"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Sanity-check NumberOfRvaAndSizes (standard value is 16, max 16 per spec)\nstatic bool HasValidRvaCount(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 magicOff = peOff + 4 + 20;\n    if (magicOff + 2 > b.Length) return false;\n    ushort magic = BitConverter.ToUInt16(b, magicOff);\n    // NumberOfRvaAndSizes is the last 4 bytes of the fixed optional header\n    int rvaOff = magic == 0x20b ? magicOff + 108 : magicOff + 92;\n    if (rvaOff + 4 > b.Length) return false;\n    uint rvaCount = BitConverter.ToUInt32(b, rvaOff);\n    return rvaCount <= 16 && (long)b.Length - (rvaOff + 4) >= rvaCount * 8;\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    var image = PEImage.FromFile(path);\n}\ncatch (PEImageParseException ex) when (ex.Message.Contains(\"Data directories\"))\n{\n    // NumberOfRvaAndSizes is corrupt or file is truncated after optional header\n    logger.Warn($\"Corrupt data directory table: {ex.Message} at offset {ex.Offset}\");\n}","preventionTips":["Sanity-check NumberOfRvaAndSizes before full parsing — the standard value is 16 and should never exceed 16","Verify file integrity when processing untrusted PE files","Treat an abnormally large NumberOfRvaAndSizes as evidence of corruption"],"tags":["pe-format","binary-parsing","truncated-file","corrupted-file","data-directories"],"backgroundTag":null,"analyzedSha":"cb5d9c429c81d9796fac469da2a68efb5626946d","analyzedAt":"2026-08-13T11:51:01.370Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}