From a4a877019cc8e0f57999fb344eb5a506ba3afa58 Mon Sep 17 00:00:00 2001 From: BP Cheng Date: Mon, 26 Jan 2026 20:58:54 -0800 Subject: [PATCH 1/4] config_format: cf_yaml: fix Windows crash when libyaml is loaded as DLL On Windows, passing FILE* across DLL boundaries can cause crashes due to different C runtime libraries having incompatible internal FILE structures. When libyaml is built as a dynamic library (DLL), using yaml_parser_set_input_file() causes the FILE* pointer to cross the DLL boundary, leading to memory corruption or crashes. This fix reads the YAML config file into a memory buffer and uses yaml_parser_set_input_string() instead of yaml_parser_set_input_file(), avoiding the cross-DLL FILE* issue. The implementation opens the file in binary mode ("rb") for consistent behavior, reads the entire file content into a buffer, uses yaml_parser_set_input_string() with the buffer, and properly frees the buffer after parsing. Signed-off-by: BP Cheng Signed-off-by: BP Cheng --- src/config_format/flb_cf_yaml.c | 48 ++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/src/config_format/flb_cf_yaml.c b/src/config_format/flb_cf_yaml.c index 916093368d9..3b473409b34 100644 --- a/src/config_format/flb_cf_yaml.c +++ b/src/config_format/flb_cf_yaml.c @@ -2905,7 +2905,7 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, } flb_debug("============ %s ============", cfg_file); - fh = fopen(include_file, "r"); + fh = fopen(include_file, "rb"); if (!fh) { flb_errno(); @@ -2926,8 +2926,47 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, } ctx->level++; + /* + * On Windows, passing FILE* across DLL boundaries can cause crashes due to + * different C runtime libraries. Read the file into a buffer and use + * yaml_parser_set_input_string() instead of yaml_parser_set_input_file(). + */ + { + long file_size; + unsigned char *file_buffer = NULL; + size_t bytes_read; + + /* Get file size */ + fseek(fh, 0, SEEK_END); + file_size = ftell(fh); + fseek(fh, 0, SEEK_SET); + + if (file_size < 0) { + flb_error("[config] could not determine file size for %s", cfg_file); + fclose(fh); + flb_sds_destroy(include_dir); + flb_sds_destroy(include_file); + return -1; + } + + /* Allocate buffer */ + file_buffer = flb_malloc(file_size + 1); + if (!file_buffer) { + flb_error("[config] could not allocate memory for config file %s", cfg_file); + fclose(fh); + flb_sds_destroy(include_dir); + flb_sds_destroy(include_file); + return -1; + } + + /* Read file content */ + bytes_read = fread(file_buffer, 1, file_size, fh); + fclose(fh); + fh = NULL; /* Mark as closed */ + file_buffer[bytes_read] = '\0'; + yaml_parser_initialize(&parser); - yaml_parser_set_input_file(&parser, fh); + yaml_parser_set_input_string(&parser, file_buffer, bytes_read); do { status = yaml_parser_parse(&parser, &event); @@ -2990,7 +3029,10 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, state = state_pop(ctx); } - fclose(fh); + /* Free the file buffer that was allocated for yaml_parser_set_input_string */ + flb_free(file_buffer); + } /* End of block that declared file_buffer */ + ctx->level--; flb_sds_destroy(include_file); From aab04d0221f2bbbfc1b45a9bc6df0d115a22b167 Mon Sep 17 00:00:00 2001 From: BP Cheng Date: Mon, 26 Jan 2026 21:21:27 -0800 Subject: [PATCH 2/4] config_format: cf_yaml: fix Windows crash when libyaml is loaded as DLL On Windows, passing FILE* across DLL boundaries can cause crashes due to different C runtime libraries having incompatible internal FILE structures. When libyaml is built as a dynamic library (DLL), using yaml_parser_set_input_file() causes the FILE* pointer to cross the DLL boundary, leading to memory corruption or crashes. This fix reads the YAML config file into a memory buffer and uses yaml_parser_set_input_string() instead of yaml_parser_set_input_file(), avoiding the cross-DLL FILE* issue. The implementation opens the file in binary mode ("rb") for consistent behavior, reads the entire file content into a buffer, uses yaml_parser_set_input_string() with the buffer, and properly frees the buffer after parsing. Error paths now use goto to ensure proper cleanup of parser state and ctx->level. Signed-off-by: BP Cheng Signed-off-by: BP Cheng --- src/config_format/flb_cf_yaml.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/config_format/flb_cf_yaml.c b/src/config_format/flb_cf_yaml.c index 3b473409b34..6cf0991f996 100644 --- a/src/config_format/flb_cf_yaml.c +++ b/src/config_format/flb_cf_yaml.c @@ -2935,6 +2935,7 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, long file_size; unsigned char *file_buffer = NULL; size_t bytes_read; + int parser_initialized = 0; /* Get file size */ fseek(fh, 0, SEEK_END); @@ -2944,9 +2945,9 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, if (file_size < 0) { flb_error("[config] could not determine file size for %s", cfg_file); fclose(fh); - flb_sds_destroy(include_dir); - flb_sds_destroy(include_file); - return -1; + fh = NULL; + code = -1; + goto done; } /* Allocate buffer */ @@ -2954,9 +2955,9 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, if (!file_buffer) { flb_error("[config] could not allocate memory for config file %s", cfg_file); fclose(fh); - flb_sds_destroy(include_dir); - flb_sds_destroy(include_file); - return -1; + fh = NULL; + code = -1; + goto done; } /* Read file content */ @@ -2966,6 +2967,7 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, file_buffer[bytes_read] = '\0'; yaml_parser_initialize(&parser); + parser_initialized = 1; yaml_parser_set_input_string(&parser, file_buffer, bytes_read); do { @@ -3019,7 +3021,9 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, yaml_event_delete(&event); } - yaml_parser_delete(&parser); + if (parser_initialized) { + yaml_parser_delete(&parser); + } /* free all remaining states */ if (code == -1) { @@ -3030,7 +3034,10 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, } /* Free the file buffer that was allocated for yaml_parser_set_input_string */ - flb_free(file_buffer); + if (file_buffer) { + flb_free(file_buffer); + } + } /* End of block that declared file_buffer */ ctx->level--; From a4627d30eee45610ad821eb26d0b3a254b18786f Mon Sep 17 00:00:00 2001 From: BP Cheng Date: Mon, 26 Jan 2026 21:31:42 -0800 Subject: [PATCH 3/4] config_format: cf_yaml: fix Windows crash when libyaml is loaded as DLL On Windows, passing FILE* across DLL boundaries can cause crashes due to different C runtime libraries having incompatible internal FILE structures. When libyaml is built as a dynamic library (DLL), using yaml_parser_set_input_file() causes the FILE* pointer to cross the DLL boundary, leading to memory corruption or crashes. This fix reads the YAML config file into a memory buffer and uses yaml_parser_set_input_string() instead of yaml_parser_set_input_file(), avoiding the cross-DLL FILE* issue. The implementation opens the file in binary mode ("rb") for consistent behavior, reads the entire file content into a buffer, uses yaml_parser_set_input_string() with the buffer, and properly frees the buffer after parsing. Error paths now use goto to ensure proper cleanup of parser state and ctx->level. Added error checks for fread (via ferror) and yaml_parser_initialize return values. Signed-off-by: BP Cheng Signed-off-by: BP Cheng --- src/config_format/flb_cf_yaml.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/config_format/flb_cf_yaml.c b/src/config_format/flb_cf_yaml.c index 6cf0991f996..42736c242fc 100644 --- a/src/config_format/flb_cf_yaml.c +++ b/src/config_format/flb_cf_yaml.c @@ -2962,11 +2962,25 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, /* Read file content */ bytes_read = fread(file_buffer, 1, file_size, fh); + if (bytes_read != (size_t)file_size && ferror(fh)) { + flb_error("[config] error reading file %s", cfg_file); + fclose(fh); + fh = NULL; + flb_free(file_buffer); + file_buffer = NULL; + code = -1; + goto done; + } fclose(fh); fh = NULL; /* Mark as closed */ file_buffer[bytes_read] = '\0'; - yaml_parser_initialize(&parser); + if (!yaml_parser_initialize(&parser)) { + flb_error("[config] failed to initialize YAML parser"); + code = -1; + goto done; + } + parser_initialized = 1; yaml_parser_set_input_string(&parser, file_buffer, bytes_read); From 32627021df7be810f5dcb022e7d72a0f9a883ede Mon Sep 17 00:00:00 2001 From: BP Cheng Date: Tue, 27 Jan 2026 01:36:09 -0800 Subject: [PATCH 4/4] config_format: cf_yaml: fix Windows crash when libyaml is loaded as DLL On Windows, passing FILE* across DLL boundaries can cause crashes due to different C runtime libraries having incompatible internal FILE structures. When libyaml is built as a dynamic library (DLL), using yaml_parser_set_input_file() causes the FILE* pointer to cross the DLL boundary, leading to memory corruption or crashes. This fix reads the YAML config file into a memory buffer and uses yaml_parser_set_input_string() instead of yaml_parser_set_input_file(), avoiding the cross-DLL FILE* issue. The implementation opens the file in binary mode ("rb") for consistent behavior, reads the entire file content into a buffer, uses yaml_parser_set_input_string() with the buffer, and properly frees the buffer after parsing. Signed-off-by: BP Cheng Signed-off-by: BP Cheng --- src/config_format/flb_cf_yaml.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/config_format/flb_cf_yaml.c b/src/config_format/flb_cf_yaml.c index 42736c242fc..ebfef2eb9d4 100644 --- a/src/config_format/flb_cf_yaml.c +++ b/src/config_format/flb_cf_yaml.c @@ -2936,6 +2936,7 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, unsigned char *file_buffer = NULL; size_t bytes_read; int parser_initialized = 0; + int event_needs_delete = 0; /* Get file size */ fseek(fh, 0, SEEK_END); @@ -2986,6 +2987,7 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, do { status = yaml_parser_parse(&parser, &event); + event_needs_delete = 1; /* Mark that event needs cleanup on error */ if (status == YAML_FAILURE) { if (parser.problem) { @@ -3024,6 +3026,7 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, } yaml_event_delete(&event); + event_needs_delete = 0; /* Event has been deleted, reset flag */ state = cfl_list_entry_last(&ctx->states, struct parser_state, _head); } while (state->state != STATE_STOP); @@ -3031,7 +3034,7 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, flb_debug("=============================="); done: - if (code == -1) { + if (code == -1 && event_needs_delete) { yaml_event_delete(&event); }