diff --git a/font/sfnt/cmap.go b/font/sfnt/cmap.go index 3adda03..9db98a8 100644 --- a/font/sfnt/cmap.go +++ b/font/sfnt/cmap.go @@ -206,13 +206,13 @@ func (f *Font) makeCachedGlyphIndexFormat12(buf []byte, offset, _ uint32) ([]byt if err != nil { return nil, err } - offset += headerSize - length := u32(buf[4:]) - numGroups := u32(buf[12:]) if f.cmap.length < offset || length > f.cmap.length-offset { return nil, errInvalidCmapTable } + offset += headerSize + + numGroups := u32(buf[12:]) if numGroups > maxCmapSegments { return nil, errUnsupportedNumberOfCmapSegments } diff --git a/font/sfnt/sfnt.go b/font/sfnt/sfnt.go index 8757d7a..61281e7 100644 --- a/font/sfnt/sfnt.go +++ b/font/sfnt/sfnt.go @@ -30,8 +30,17 @@ import ( const ( // This value is arbitrary, but defends against parsing malicious font // files causing excessive memory allocations. For reference, Adobe's - // SourceHanSansSC-Regular.otf has 65535 glyphs and 1581 cmap segments. - maxCmapSegments = 4096 + // SourceHanSansSC-Regular.otf has 65535 glyphs and: + // - its format-4 cmap table has 1581 segments. + // - its format-12 cmap table has 16498 segments. + // + // TODO: eliminate this constraint? If the cmap table is very large, load + // some or all of it lazily (at the time Font.GlyphIndex is called) instead + // of all of it eagerly (at the time Font.initialize is called), while + // keeping an upper bound on the memory used? This will make the code in + // cmap.go more complicated, considering that all of the Font methods are + // safe to call concurrently, as long as each call has a different *Buffer. + maxCmapSegments = 20000 maxGlyphDataLength = 64 * 1024 maxHintBits = 256