From a496ad2c8bb103d179cfc90a82e824a18fbd0801 Mon Sep 17 00:00:00 2001 From: Jonghyeon Park Date: Wed, 10 Jun 2026 10:16:28 +0900 Subject: [PATCH] fix: segfault on api test ApiTest.RendersHtmlThroughPublicApi (SEGFAULT) ApiTest.RendersAstJsonThroughPublicApi (SEGFAULT) --- lib/namumark.c | 58 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/lib/namumark.c b/lib/namumark.c index ed0c845..a233c94 100644 --- a/lib/namumark.c +++ b/lib/namumark.c @@ -27,8 +27,8 @@ const char *namumark_status_message(namumark_status status) { } static namumark_status render_document_to_stream(namumark_node *document, - namumark_output_format format, - FILE *stream) { + namumark_output_format format, + FILE *stream) { int ok = 0; switch (format) { case NAMUMARK_OUTPUT_HTML: @@ -43,6 +43,37 @@ static namumark_status render_document_to_stream(namumark_node *document, return ok ? NAMUMARK_OK : NAMUMARK_ERROR_RENDER; } +static namumark_status read_stream_to_buffer(FILE *stream, + namumark_buffer *output) { + long file_size; + char *data; + + if (fflush(stream) != 0 || fseek(stream, 0, SEEK_END) != 0) { + return NAMUMARK_ERROR_RENDER; + } + + file_size = ftell(stream); + if (file_size < 0 || fseek(stream, 0, SEEK_SET) != 0) { + return NAMUMARK_ERROR_RENDER; + } + + data = (char *)malloc((size_t)file_size + 1); + if (data == NULL) { + return NAMUMARK_ERROR_ALLOCATION; + } + + if (file_size > 0 && + fread(data, 1, (size_t)file_size, stream) != (size_t)file_size) { + free(data); + return NAMUMARK_ERROR_RENDER; + } + + data[file_size] = '\0'; + output->data = data; + output->size = (size_t)file_size; + return NAMUMARK_OK; +} + namumark_status namumark_render(const char *input, size_t input_size, namumark_output_format format, namumark_buffer *output) { @@ -70,33 +101,20 @@ namumark_status namumark_render(const char *input, size_t input_size, return NAMUMARK_ERROR_PARSE; } - char *data = NULL; - size_t size = 0; - /* - * open_memstream gives the renderers a FILE* without exposing FILE ownership - * to embedders. The resulting heap buffer becomes namumark_buffer::data on - * success and is freed locally on render failure. - */ - FILE *stream = open_memstream(&data, &size); + FILE *stream = tmpfile(); if (stream == NULL) { namumark_node_free(document); return NAMUMARK_ERROR_ALLOCATION; } namumark_status status = render_document_to_stream(document, format, stream); - if (fclose(stream) != 0 && status == NAMUMARK_OK) { - status = NAMUMARK_ERROR_RENDER; + if (status == NAMUMARK_OK) { + status = read_stream_to_buffer(stream, output); } + fclose(stream); namumark_node_free(document); - if (status != NAMUMARK_OK) { - free(data); - return status; - } - - output->data = data; - output->size = size; - return NAMUMARK_OK; + return status; } namumark_status namumark_render_html(const char *input, size_t input_size,