Tested with commit cc63806 (v2.28e), Apple clang 21, macOS arm64.
kbts_LoadFont returns KBTS_LOAD_FONT_ERROR_NONE when the data does not start with a header it knows (0x00010000, OTTO, ttcf). It does not set Font->Error. So kbts_FontFromMemory returns a font with Blob == NULL, and kbts_FontIsValid says the font is valid. The next call that uses the font dereferences the NULL blob.
The docs for kbts_LoadFont say: "If we could not find any useful font data, the [return value] is KBTS_LOAD_FONT_ERROR_INVALID_FONT."
Two real files hit this as well as junk data:
- An Apple TrueType font with the
trueheader: Zycon.ttf from HarfBuzz's tests - A Mac resource-fork font: DFONT.dfont
Direct API
// cc -g invalid_font.c -o invalid_font && ./invalid_font [font file]
#define KB_TEXT_SHAPE_IMPLEMENTATION
#include "kb_text_shape.h"
#include "common.h"
int main(int argc, char **argv)
{
static char junk[64] = "not a font";
int size = sizeof(junk);
void *data = argc > 1 ? read_file(argv[1], &size) : junk;
kbts_font font = kbts_FontFromMemory(data, size, 0, 0, 0);
printf("kbts_FontIsValid: %d, font.Blob: %p\n", kbts_FontIsValid(&font), (void *)font.Blob);
fflush(stdout);
kbts_shape_config *config = kbts_CreateShapeConfig(&font, KBTS_SCRIPT_LATIN, KBTS_LANGUAGE_DONT_KNOW, 0, 0);
printf("kbts_CreateShapeConfig: %p\n", (void *)config);
return 0;
}common.h only has a read_file helper. Output with -fsanitize=address, the same for no argument, Zycon.ttf and DFONT.dfont:
kbts_FontIsValid: 1, font.Blob: 0x0
==ERROR: AddressSanitizer: SEGV on unknown address 0x00000000004c
#0 kbts__BlobTableData kb_text_shape.h:17817
#1 kbts__PlaceShapeConfig kb_text_shape.h:24320
#2 kbts_CreateShapeConfig2 kb_text_shape.h:24896
#3 kbts_CreateShapeConfig kb_text_shape.h:24909Context API
// cc -g invalid_font_context.c -o invalid_font_context && ./invalid_font_context
#define KB_TEXT_SHAPE_IMPLEMENTATION
#include "kb_text_shape.h"
#include <stdio.h>
int main(void)
{
static char junk[64] = "not a font";
kbts_shape_context *context = kbts_CreateShapeContext(0, 0);
kbts_font *font = kbts_ShapePushFontFromMemory(context, junk, sizeof(junk), 0);
printf("kbts_ShapePushFontFromMemory: %p\n", (void *)font);
fflush(stdout);
kbts_ShapeBegin(context, KBTS_DIRECTION_DONT_KNOW, KBTS_LANGUAGE_DONT_KNOW);
kbts_ShapeUtf8(context, "abc", 3, KBTS_USER_ID_GENERATION_MODE_CODEPOINT_INDEX);
kbts_ShapeEnd(context);
printf("kbts_ShapeError: %d\n", (int)kbts_ShapeError(context));
kbts_run run;
while (kbts_ShapeRun(context, &run)) {
kbts_glyph *glyph;
while (kbts_GlyphIteratorNext(&run.Glyphs, &glyph)) { printf("glyph id %d\n", glyph->Id); }
}
return 0;
}Without ASan, kbts_ShapePushFontFromMemory returns a non-NULL font and the program crashes later in kbts_ShapeRun. With -fsanitize=address it crashes inside the push, on a wild address, so the blob pointer may not be initialized on this path:
==ERROR: AddressSanitizer: SEGV on unknown address 0x5847d7d9d7ea
#0 kbts__BlobTableData kb_text_shape.h:17817
#1 kbts_GetVariationInfo kb_text_shape.h:25099
#2 kbts__InitializeContextFont kb_text_shape.h:25489
#3 kbts_ShapePushFontFromMemory2 kb_text_shape.h:25623Expected: kbts_LoadFont returns KBTS_LOAD_FONT_ERROR_INVALID_FONT and sets Font->Error, so kbts_FontIsValid returns 0 and kbts_ShapePushFontFromMemory returns 0.
(I found this with help from Claude, with a harness that runs HarfBuzz's shaping test suite through kb and through HarfBuzz and compares them. I checked each repro by hand.)
Activity
0No activity yet.