QL-Win/QuickLook · error · PEImageParseException

Data directories incomplete.

Error message

Data directories incomplete.

What it means

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.

Source

Thrown at QuickLook.Plugin/QuickLook.Plugin.PEViewer/PEImageParser/PEImage.cs:198

                SizeOfStackReserve = reader.ReadUInt64(),
                SizeOfStackCommit = reader.ReadUInt64(),
                SizeOfHeapReserve = reader.ReadUInt64(),
                SizeOfHeapCommit = reader.ReadUInt64(),
                LoaderFlags = reader.ReadUInt32(),
                NumberOfRvaAndSizes = reader.ReadUInt32()
            };
        }
        else if (magic == 0x107)
        {
            throw new PEImageParseException((int)reader.BaseStream.Position - 2, "Optional header for ROM's is not supported.");
        }
        else
        {
            throw new PEImageParseException((int)reader.BaseStream.Position - 2, "Optional header magic value of '0x" + magic.ToString("x4") + "' unknown.");
        }

        // Data Directories
        if (reader.BaseStream.Length - reader.BaseStream.Position < OptionalHeader.NumberOfRvaAndSizes * 8) throw new PEImageParseException((int)reader.BaseStream.Position, "Data directories incomplete.");

        OptionalHeader.DataDirectories = Create.Array((int)OptionalHeader.NumberOfRvaAndSizes, i => new ImageDataDirectory((ImageDataDirectoryName)i, reader.ReadUInt32(), reader.ReadUInt32()));

        // Section Headers
        if (reader.BaseStream.Length - reader.BaseStream.Position < CoffHeader.NumberOfSections * 40) throw new PEImageParseException((int)reader.BaseStream.Position, "Section headers incomplete.");

        Sections = Create
            .Enumerable(CoffHeader.NumberOfSections, i => new ImageSectionHeader
            {
                Name = reader.ReadBytes(8).TakeWhile(c => c != 0).ToArray().ToUTF8String(),
                VirtualSize = reader.ReadUInt32(),
                VirtualAddress = reader.ReadUInt32(),
                SizeOfRawData = reader.ReadUInt32(),
                PointerToRawData = reader.ReadUInt32(),
                PointerToRelocations = reader.ReadUInt32(),
                PointerToLineNumbers = reader.ReadUInt32(),
                NumberOfRelocations = reader.ReadUInt16(),
                NumberOfLineNumbers = reader.ReadUInt16(),

View on GitHub (pinned to cb5d9c429c)

Solutions

  1. Inspect the file with a PE viewer to check whether NumberOfRvaAndSizes is a sane value (standard is 16)
  2. Re-acquire the file if it appears to be truncated
  3. Pre-validate by reading NumberOfRvaAndSizes from the optional header and sanity-checking it is <= 16 before full parsing
  4. Catch PEImageParseException for robust handling of malformed PE inputs
Defensive patterns

Strategy: validation

Validate before calling

// Sanity-check NumberOfRvaAndSizes (standard value is 16, max 16 per spec)
static bool HasValidRvaCount(string path)
{
    byte[] b = File.ReadAllBytes(path);
    if (b.Length < 0x40) return false;
    int peOff = BitConverter.ToInt32(b, 0x3C);
    int magicOff = peOff + 4 + 20;
    if (magicOff + 2 > b.Length) return false;
    ushort magic = BitConverter.ToUInt16(b, magicOff);
    // NumberOfRvaAndSizes is the last 4 bytes of the fixed optional header
    int rvaOff = magic == 0x20b ? magicOff + 108 : magicOff + 92;
    if (rvaOff + 4 > b.Length) return false;
    uint rvaCount = BitConverter.ToUInt32(b, rvaOff);
    return rvaCount <= 16 && (long)b.Length - (rvaOff + 4) >= rvaCount * 8;
}

Try / catch

try
{
    var image = PEImage.FromFile(path);
}
catch (PEImageParseException ex) when (ex.Message.Contains("Data directories"))
{
    // NumberOfRvaAndSizes is corrupt or file is truncated after optional header
    logger.Warn($"Corrupt data directory table: {ex.Message} at offset {ex.Offset}");
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of QL-Win/QuickLook@cb5d9c429c (2026-08-13). Data as JSON: /api/errors/fbbcbc1aa8e765fc. Report an issue: GitHub.