Panic: "remapper was overflowed" when composite glyphs reach all 65,536 glyph IDs

Abierto
#35 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
1-2 días
Aptitud para principiantes
56/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
rust
Área
backend

Línea de trabajo

Start by reading subsetter-0.2.6/src/remapper.rs around the overflowing u16 count and trace how glyf::closure remaps composite components. The reproduction in the issue demonstrates the failure when all 65,536 glyph IDs are reached; use it to check a fix. Done means subset returns an error or handles out-of-range component IDs without panicking.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

subset panics on a TrueType font whose glyph closure reaches all 65,536 glyph IDs, in any build:

thread 'main' panicked at subsetter-0.2.6/src/remapper.rs:91:18:
remapper was overflowed

glyf::closure remaps every glyph it reaches through composite components, and Remapper::remap counts them in a u16 with .expect("remapper was overflowed"). Components may name glyph IDs past maxp's glyph count, which Table::glyph_data still reads where loca gives them an entry, so a composite glyph (or several) can reach every ID from 0 to 65535: the 65,536th glyph remapped panics. This happens with 0.2.6 and with main (b0adcc1). (#34 is the same expect reached through the Font DICT remapper of CFF fonts.)

To reproduce with subsetter 0.2.6 (default-features = false). The font is built for this report: three tables, glyf, head and loca, where .notdef is a composite of the empty glyphs 1 to 65535.

fn main() {
    // A TrueType font of three tables, built for this report: glyph 0 is a composite of
    // the empty glyphs 1 to 65535, which `loca` gives entries.
    let mut glyf = vec![0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0]; // numberOfContours -1, bbox
    for glyph in 1..=u16::MAX {
        let flags: u16 = if glyph == u16::MAX { 0x0002 } else { 0x0022 }; // MORE_COMPONENTS
        glyf.extend(flags.to_be_bytes());
        glyf.extend(glyph.to_be_bytes());
        glyf.extend([0, 0]); // byte arguments
    }
    let mut loca = Vec::new();
    loca.extend(0u32.to_be_bytes());
    for _ in 0..=u16::MAX {
        loca.extend((glyf.len() as u32).to_be_bytes()); // glyphs 1.. are empty
    }
    let mut head = vec![0; 54];
    head[51] = 1; // indexToLocFormat: long
    let tables: [(&[u8; 4], Vec<u8>); 3] = [(b"glyf", glyf), (b"head", head), (b"loca", loca)];
    let mut font = vec![0, 1, 0, 0, 0, 3, 0, 32, 0, 1, 0, 16];
    let mut offset = 12 + 16 * tables.len();
    for (tag, table) in &tables {
        font.extend(*tag);
        font.extend([0; 4]); // checksum, not checked
        font.extend((offset as u32).to_be_bytes());
        font.extend((table.len() as u32).to_be_bytes());
        offset += table.len().next_multiple_of(4);
    }
    for (_, table) in &tables {
        font.extend(table);
        font.resize(font.len().next_multiple_of(4), 0);
    }
    let remapper = subsetter::GlyphRemapper::new();
    println!("{:?}", subsetter::subset(&font, 0, &remapper).map(|font| font.len()));
}

cargo run and cargo run --release both panic as above.

It was found by the independent review of a officewright PR that checks glyphs for subsetting; until it is fixed, our call to subset refuses such a subset before the subsetter runs.

A possible fix: return an error from closure (for example MalformedFont) once the remapper holds 65,536 glyphs, or skip components that are not below maxp's glyph count.

Lenguaje dominante
Rust
Estrellas
61
Forks
16
Métricas de merge de PR
Sin PR fusionados en 30 d

Preparar el entorno

Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de typst/subsetter

Todos los issues de typst/subsetter

Issues similares

Más issues de Rust

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.