From 6f387631433299361aca4d94500009df6813b825 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Fri, 24 Jul 2026 05:04:42 +0900 Subject: [PATCH 1/3] add size-bounded string copying and concatenation functions * include/mruby/common.h (MRB_STRLCPY, MRB_STRLCAT): Add a macros. --- include/mruby/common.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/mruby/common.h b/include/mruby/common.h index 9faf4a0c72..eb9fdbac98 100644 --- a/include/mruby/common.h +++ b/include/mruby/common.h @@ -122,6 +122,24 @@ MRB_BEGIN_DECL # endif #endif +/** Declare size-bounded string copying and concatenation functions. */ +// The `__POSIX_VISIBLE` and `__BSD_VISIBLE` conditionals are from +// OpenBSD's . The former refers to the POSIX.1-2024. +#if ((defined(__POSIX_VISIBLE) && __POSIX_VISIBLE >= 202405) ||\ + (defined(__BSD_VISIBLE) && __BSD_VISIBLE)) ||\ + (defined(__GLIBC__) &&\ + ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 38) || __GLIBC__ > 2)) +#define MRB_STRLCPY(dst, src, dstsize) strlcpy((dst), (src), (dstsize)) +#define MRB_STRLCAT(dst, src, dstsize) strlcat((dst), (src), (dstsize)) +#else +#define MRB_STRLCPY(dst, src, dstsize) snprintf((dst), (dstsize), "%s", (src)) +#define MRB_STRLCAT(dst, src, dstsize) do {\ + size_t tmp_len = strlen(dst);\ + if (tmp_len < (dstsize))\ + snprintf((dst) + tmp_len, (dstsize) - tmp_len, "%s", (src));\ + } while (0) +#endif + MRB_END_DECL #endif /* MRUBY_COMMON_H */ From 12f42c757a0885f951de62f32c3258e739f03b33 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Thu, 23 Jul 2026 13:19:45 +0900 Subject: [PATCH 2/3] use strlcpy instead of strcpy --- mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c | 4 +++- mrbgems/mruby-bin-mirb/tools/mirb/mirb.c | 9 ++++++--- mrbgems/mruby-bin-mirb/tools/mirb/mirb_completion.c | 7 +++++-- mrbgems/mruby-compiler/src/diagnostic.c | 4 +++- mrbgems/mruby-dir/ports/win/dir_hal.c | 7 +++++-- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c index 42fa2fa621..2de242c3c3 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,7 @@ #include "mrdb.h" #include "apibreak.h" #include "apilist.h" +#include "mrdbconf.h" void mrdb_state_free(mrb_state*); @@ -274,7 +276,7 @@ get_command(mrb_state *mrb, mrdb_state *mrdb) if (i == 0 && feof(stdin)) { clearerr(stdin); - strcpy(mrdb->command, "quit"); + MRB_STRLCPY(mrdb->command, "quit", MAX_COMMAND_LINE + 1); i += sizeof("quit") - 1; } diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c index 0f943ce4aa..6de1d26847 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -44,6 +45,8 @@ extern mrb_state *global_mrb; /* defined in mruby-compiler (ccontext.c) */ # define MRB_NO_MIRB_UNDERSCORE #endif +#define MAX_RUBY_CODE 4096 + static void p(mrb_state *mrb, mrb_value obj, mirb_highlighter *hl) { @@ -461,7 +464,7 @@ decl_lv_underscore(mrb_state *mrb, mrb_ccontext *cxt) int main(int argc, char **argv) { - char ruby_code[4096] = { 0 }; + char ruby_code[MAX_RUBY_CODE] = { 0 }; char last_code_line[1024] = { 0 }; int last_char; size_t char_index; @@ -596,7 +599,7 @@ main(int argc, char **argv) free(input); continue; } - strcpy(ruby_code, input); + MRB_STRLCPY(ruby_code, input, MAX_RUBY_CODE); free(input); /* Count lines for line number update */ @@ -662,7 +665,7 @@ main(int argc, char **argv) if (check_keyword(last_code_line, "quit") || check_keyword(last_code_line, "exit")) { break; } - strcpy(ruby_code, last_code_line); + MRB_STRLCPY(ruby_code, last_code_line, MAX_RUBY_CODE); } evaluate: diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb_completion.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb_completion.c index cc82ddd2c1..2cefd4fd22 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb_completion.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb_completion.c @@ -8,6 +8,7 @@ #include "mirb_highlight.h" #include #include +#include #include #include #include @@ -24,6 +25,8 @@ #define strdup _strdup #endif +#define MAX_COMPLETION_LINE 1024 + /* strndup is not available on Windows (MSVC and MinGW) */ #ifdef _WIN32 static char* @@ -660,7 +663,7 @@ mirb_linenoise_completion(const char *buf, linenoiseCompletions *lc) { int cursor_pos = (int)strlen(buf); /* linenoise completes at end */ int i, prefix_start; - char completion_line[1024]; + char completion_line[MAX_COMPLETION_LINE]; /* Clear previous completions */ mirb_completion_free(g_ctx); @@ -679,7 +682,7 @@ mirb_linenoise_completion(const char *buf, linenoiseCompletions *lc) } /* Add completion */ - strcpy(completion_line + prefix_start, g_ctx->completions[i]); + MRB_STRLCPY(completion_line + prefix_start, g_ctx->completions[i], MAX_COMPLETION_LINE); linenoiseAddCompletion(lc, completion_line); } diff --git a/mrbgems/mruby-compiler/src/diagnostic.c b/mrbgems/mruby-compiler/src/diagnostic.c index d9c79039dc..d3b9637976 100644 --- a/mrbgems/mruby-compiler/src/diagnostic.c +++ b/mrbgems/mruby-compiler/src/diagnostic.c @@ -1,4 +1,6 @@ #include "../include/mrc_diagnostic.h" +#include +#include static void line_and_column_by_start_and_offset(const uint8_t *source_start, const uint8_t *location_start, uint32_t *line, uint32_t *column) @@ -82,7 +84,7 @@ mrc_diagnostic_list_append(mrc_ccontext *c, const uint8_t * location_start, cons snprintf(buf, sizeof(buf), "%s, %s", diagnostic_code_str, message); size_t len = strlen(buf); list->message = (char *)mrc_malloc(c, len + 1); - strcpy(list->message, buf); + MRB_STRLCPY(list->message, buf, len + 1); list->message[len] = '\0'; list->code = code; diff --git a/mrbgems/mruby-dir/ports/win/dir_hal.c b/mrbgems/mruby-dir/ports/win/dir_hal.c index 8bc3b1be26..9eb13de781 100644 --- a/mrbgems/mruby-dir/ports/win/dir_hal.c +++ b/mrbgems/mruby-dir/ports/win/dir_hal.c @@ -12,8 +12,10 @@ */ #include +#include #include "dir_hal.h" +#include #include #include #include @@ -46,8 +48,9 @@ mrb_hal_dir_open(mrb_state *mrb, const char *path) suffix = (len > 0 && (path[len-1] == '/' || path[len-1] == '\\')) ? "*" : "/*"; handle = (mrb_dir_handle*)mrb_malloc(mrb, sizeof(mrb_dir_handle)); - handle->pattern = (char*)mrb_malloc(mrb, len + strlen(suffix) + 1); - strcpy(handle->pattern, path); + size_t plen = len + strlen(suffix) + 1; + handle->pattern = (char*)mrb_malloc(mrb, plen); + MRB_STRLCPY(handle->pattern, path, plen); strcat(handle->pattern, suffix); handle->handle = _findfirst(handle->pattern, &handle->info); From 106eecc387a6906edc2ff17ba7d3f46ef1206a66 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Fri, 24 Jul 2026 05:54:23 +0900 Subject: [PATCH 3/3] use strlcat instead of strcat --- mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c | 7 ++++--- mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c | 7 +++++-- mrbgems/mruby-bin-mirb/tools/mirb/mirb.c | 2 +- mrbgems/mruby-dir/ports/win/dir_hal.c | 2 +- src/numeric.c | 7 +++++-- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c b/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c index 0fc087bdf9..6e6ed6e930 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c @@ -10,6 +10,7 @@ #include "apilist.h" #include "apistring.h" #include +#include #include #include @@ -52,10 +53,10 @@ build_path(mrb_state *mrb, const char *dir, const char *base) memset(path, 0, len); if (strcmp(dir, ".")) { - strcat(path, dir); - strcat(path, "/"); + MRB_STRLCAT(path, dir, len); + MRB_STRLCAT(path, "/", len); } - strcat(path, base); + MRB_STRLCAT(path, base, len); return path; } diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c index 6beed461da..12ed93e32f 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c @@ -4,11 +4,13 @@ */ #include +#include #include #include #include "apilist.h" #include "apistring.h" +#include #include typedef struct help_msg { @@ -262,10 +264,11 @@ replace_ext(mrb_state *mrb, const char *filename, const char *ext) len = strlen(filename); } - s = (char*)mrb_malloc(mrb, len + strlen(ext) + 1); + size_t slen = len + strlen(ext) + 1; + s = (char*)mrb_malloc(mrb, slen); memset(s, '\0', len + strlen(ext) + 1); strncpy(s, filename, len); - strcat(s, ext); + MRB_STRLCAT(s, ext, slen); return s; } diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c index 6de1d26847..49fae12e65 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -659,7 +659,7 @@ main(int argc, char **argv) fputs("concatenated input string too long\n", stderr); continue; } - strcat(ruby_code, last_code_line); + MRB_STRLCAT(ruby_code, last_code_line, MAX_RUBY_CODE); } else { if (check_keyword(last_code_line, "quit") || check_keyword(last_code_line, "exit")) { diff --git a/mrbgems/mruby-dir/ports/win/dir_hal.c b/mrbgems/mruby-dir/ports/win/dir_hal.c index 9eb13de781..917ae3d0e5 100644 --- a/mrbgems/mruby-dir/ports/win/dir_hal.c +++ b/mrbgems/mruby-dir/ports/win/dir_hal.c @@ -51,7 +51,7 @@ mrb_hal_dir_open(mrb_state *mrb, const char *path) size_t plen = len + strlen(suffix) + 1; handle->pattern = (char*)mrb_malloc(mrb, plen); MRB_STRLCPY(handle->pattern, path, plen); - strcat(handle->pattern, suffix); + MRB_STRLCAT(handle->pattern, suffix, plen); handle->handle = _findfirst(handle->pattern, &handle->info); if (handle->handle == -1) { diff --git a/src/numeric.c b/src/numeric.c index a6a59e96bd..bdf3c54dec 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -410,6 +411,8 @@ num_fdiv(mrb_state *mrb, mrb_value x) return flo_div(mrb, mrb_ensure_float_type(mrb, x)); } +#define BUFFER_MAX 25 + /** * Converts an mrb_value float to a new mrb_value string. * It handles formatting to ensure the string representation includes a @@ -425,7 +428,7 @@ num_fdiv(mrb_state *mrb, mrb_value x) mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) { - char buf[25]; + char buf[BUFFER_MAX]; mrb_format_float(mrb_float(flo), buf, sizeof(buf), 'g', -2, '\0'); for (char *p = buf; *p; p++) { @@ -437,7 +440,7 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) goto exit; } } - strcat(buf, ".0"); + MRB_STRLCAT(buf, ".0", BUFFER_MAX); exit: return mrb_str_new_cstr(mrb, buf); }