dotnet/wpf · error · FileFormatException

FileFormatException(SourceUri)

Error message

FileFormatException(SourceUri)

What it means

SetFace reads the sfnt offset table's numTables field and sanity-checks the file: its size must be at least the offset table plus numTables directory entries. When numTables is absurdly large relative to the file, the font is treated as malformed and FileFormatException(SourceUri) is thrown.

Solutions

  1. Replace the font file with a verified copy and confirm its byte size
  2. Catch FileFormatException around font loading and exclude the bad font
  3. Sanity-check the font before loading (file size > 12 bytes and header plausible)
  4. Scan deployment for partially-written font files

Example fix

// before
var fi = new FileInfo(path);
if (fi.Length == 0) throw ...;
driver.SetFace(0);
// after
var fi = new FileInfo(path);
if (fi.Length < 12) throw new IOException($"Font file too small: {path}");
driver.SetFace(0);
Defensive patterns

Strategy: try-catch

Validate before calling

long minSize = 12; // offset table only; full check needs numTables
if (stream.Length < minSize) throw new IOException("Font file too small");

Try / catch

try { driver.SetFace(0); }
catch (FileFormatException e)
{
    log.Error($"Malformed font header in {e.SourceUri}");
    ExcludeFont(path);
}

Prevention

When it happens

Trigger: Calling SetFace (or ComputeSubset) on a font whose binary header reports a numTables count inconsistent with the actual stream length — typical of corrupt, truncated, or counterfeit font files.

Common situations: Damaged .ttf/.ttc after a bad transfer, fuzzed/hostile font inputs, testing the font pipeline with random bytes, fonts stored inside archives that were extracted incompletely.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/25936db13ca2332f. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/FontFace/FontDriver.cs:188

                    seekPosition += (4 + 4 + 4 * faceIndex);

                    _directoryOffset = ReadOpenTypeLong(seekPosition);

                    seekPosition = _fileStream + (_directoryOffset + 4);
                    // 4 means that we skip the version number
                }

                _faceIndex = faceIndex;

                int numTables = ReadOpenTypeUShort(seekPosition);
                seekPosition += 2;

                // quick check for malformed fonts, see if numTables is too large
                // file size should be >= sizeof(offset table) + numTables * (sizeof(directory entry) + minimum table size (4))
                long minimumFileSize = (4 + 2 + 2 + 2 + 2) + numTables * (4 + 4 + 4 + 4 + 4);
                if (_fileStream.Size < minimumFileSize)
                {
                    throw new FileFormatException(SourceUri);
                }

                _tableDirectory = new DirectoryEntry[numTables];

                // skip searchRange, entrySelector and rangeShift
                seekPosition += 6;

                // I can't use foreach here because C# disallows modifying the current value
                for (int i = 0; i < _tableDirectory.Length; ++i)
                {
                    _tableDirectory[i].tag = (TrueTypeTags)ReadOpenTypeLong(seekPosition);
                    seekPosition += 8; // skip checksum
                    int offset = ReadOpenTypeLong(seekPosition);
                    seekPosition += 4;
                    int length = ReadOpenTypeLong(seekPosition);
                    seekPosition += 4;

                    _tableDirectory[i].pointer = _fileStream.CheckedProbe(offset, length);

View on GitHub (pinned to 81131a70a4)