From 19c857a77324e54609e5800aebaa580e788de9d1 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 25 May 2026 06:09:11 +0900 Subject: [PATCH] mruby-regexp: prefix exposed engine entry points with `mrb_re_` The Pike VM and pattern compiler were exporting bare names like `re_compile`, `re_exec`, `re_free`, `re_is_word_char`, `re_utf8_charlen`, `re_utf8_decode`. `re_exec` in particular collides with the obsolete BSD libc function of the same name (still present on FreeBSD/NetBSD base), so embedding mruby alongside platform regex could surface a link-time symbol clash. Rename all six entry points to `mrb_re_*` to keep the gem's external symbols inside mruby's namespace. Source file names and the public header path are unchanged. Refs #6858. Co-authored-by: Claude --- mrbgems/mruby-regexp/include/re_internal.h | 14 +++++------ mrbgems/mruby-regexp/src/re_compile.c | 6 ++--- mrbgems/mruby-regexp/src/re_exec.c | 28 +++++++++++----------- mrbgems/mruby-regexp/src/re_utf8.c | 6 ++--- mrbgems/mruby-regexp/src/regexp.c | 18 +++++++------- mrbgems/mruby-regexp/test/regexp.rb | 2 +- 6 files changed, 37 insertions(+), 37 deletions(-) diff --git a/mrbgems/mruby-regexp/include/re_internal.h b/mrbgems/mruby-regexp/include/re_internal.h index a03752b67..5a60696af 100644 --- a/mrbgems/mruby-regexp/include/re_internal.h +++ b/mrbgems/mruby-regexp/include/re_internal.h @@ -76,7 +76,7 @@ typedef struct mrb_regexp_pattern { uint8_t first_bytes[16]; /* bitmap of possible first bytes (128-bit, ASCII) */ mrb_bool has_first_bytes; /* true if first_bytes is usable for skipping */ mrb_bool is_literal; /* true if pattern is pure literal (no metacharacters) */ - /* Cached VM state for pike_vm (avoids malloc per re_exec call) */ + /* Cached VM state for pike_vm (avoids malloc per mrb_re_exec call) */ uint32_t *cached_visited; /* generation-based visited array */ void *cached_threads[2]; /* curr/next thread lists */ int cached_list_capa; /* capacity of cached thread lists */ @@ -113,21 +113,21 @@ typedef struct { } re_thread_cache; /* Compile a pattern string into bytecode */ -mrb_regexp_pattern* re_compile(mrb_state *mrb, const char *pattern, mrb_int len, uint32_t flags); +mrb_regexp_pattern* mrb_re_compile(mrb_state *mrb, const char *pattern, mrb_int len, uint32_t flags); /* Free a compiled pattern */ -void re_free(mrb_state *mrb, mrb_regexp_pattern *pat); +void mrb_re_free(mrb_state *mrb, mrb_regexp_pattern *pat); /* Execute a match. Returns number of captures filled (0 = no match). captures[2*n] = start, captures[2*n+1] = end for group n. */ -int re_exec(mrb_state *mrb, const mrb_regexp_pattern *pat, +int mrb_re_exec(mrb_state *mrb, const mrb_regexp_pattern *pat, const char *str, mrb_int len, mrb_int start, int *captures, int captures_size); /* UTF-8 helpers */ -int re_utf8_charlen(const char *s, const char *end); -uint32_t re_utf8_decode(const char *s, int *len); -mrb_bool re_is_word_char(uint32_t c); +int mrb_re_utf8_charlen(const char *s, const char *end); +uint32_t mrb_re_utf8_decode(const char *s, int *len); +mrb_bool mrb_re_is_word_char(uint32_t c); #endif /* MRB_RE_INTERNAL_H */ diff --git a/mrbgems/mruby-regexp/src/re_compile.c b/mrbgems/mruby-regexp/src/re_compile.c index 79bb9109d..edbb96890 100644 --- a/mrbgems/mruby-regexp/src/re_compile.c +++ b/mrbgems/mruby-regexp/src/re_compile.c @@ -183,7 +183,7 @@ class_add_shorthand(re_charclass *cc, int ch) break; case 'W': for (int i = 0; i < 128; i++) { - if (!re_is_word_char(i)) class_set_bit(cc, (uint8_t)i); + if (!mrb_re_is_word_char(i)) class_set_bit(cc, (uint8_t)i); } cc->utf8_any = TRUE; break; @@ -857,7 +857,7 @@ compute_first_set(const re_inst *code, uint32_t code_len, } mrb_regexp_pattern* -re_compile(mrb_state *mrb, const char *pattern, mrb_int len, uint32_t flags) +mrb_re_compile(mrb_state *mrb, const char *pattern, mrb_int len, uint32_t flags) { re_compiler c; memset(&c, 0, sizeof(c)); @@ -984,7 +984,7 @@ re_compile(mrb_state *mrb, const char *pattern, mrb_int len, uint32_t flags) } void -re_free(mrb_state *mrb, mrb_regexp_pattern *pat) +mrb_re_free(mrb_state *mrb, mrb_regexp_pattern *pat) { if (pat) { mrb_free(mrb, pat->code); diff --git a/mrbgems/mruby-regexp/src/re_exec.c b/mrbgems/mruby-regexp/src/re_exec.c index 246398219..8f6e04731 100644 --- a/mrbgems/mruby-regexp/src/re_exec.c +++ b/mrbgems/mruby-regexp/src/re_exec.c @@ -170,16 +170,16 @@ add_thread(pike_state *s, re_threadlist *list, case RE_WBOUND: { - mrb_bool before = (sp > s->str) && re_is_word_char((uint8_t)sp[-1]); - mrb_bool after = (sp < s->str_end) && re_is_word_char((uint8_t)*sp); + mrb_bool before = (sp > s->str) && mrb_re_is_word_char((uint8_t)sp[-1]); + mrb_bool after = (sp < s->str_end) && mrb_re_is_word_char((uint8_t)*sp); if (before != after) { pc++; continue; } } return; case RE_NWBOUND: { - mrb_bool before = (sp > s->str) && re_is_word_char((uint8_t)sp[-1]); - mrb_bool after = (sp < s->str_end) && re_is_word_char((uint8_t)*sp); + mrb_bool before = (sp > s->str) && mrb_re_is_word_char((uint8_t)sp[-1]); + mrb_bool after = (sp < s->str_end) && mrb_re_is_word_char((uint8_t)*sp); if (before == after) { pc++; continue; } } return; @@ -301,7 +301,7 @@ pike_vm(mrb_state *mrb, const mrb_regexp_pattern *pat, next.count = 0; int ch = (uint8_t)*sp; - int advance = re_utf8_charlen(sp, str_end); + int advance = mrb_re_utf8_charlen(sp, str_end); for (int i = 0; i < curr.count; i++) { re_thread *th = &curr.threads[i]; @@ -404,22 +404,22 @@ bt_match(const mrb_regexp_pattern *pat, const char *str, const char *str_end, case RE_ANY: if (sp >= str_end || *sp == '\n') return FALSE; - sp += re_utf8_charlen(sp, str_end); pc++; + sp += mrb_re_utf8_charlen(sp, str_end); pc++; break; case RE_ANY_NL: if (sp >= str_end) return FALSE; - sp += re_utf8_charlen(sp, str_end); pc++; + sp += mrb_re_utf8_charlen(sp, str_end); pc++; break; case RE_CLASS: if (sp >= str_end || !class_match(&pat->classes[inst.a], (uint8_t)*sp)) return FALSE; - sp += re_utf8_charlen(sp, str_end); pc++; + sp += mrb_re_utf8_charlen(sp, str_end); pc++; break; case RE_NCLASS: if (sp >= str_end || class_match(&pat->classes[inst.a], (uint8_t)*sp)) return FALSE; - sp += re_utf8_charlen(sp, str_end); pc++; + sp += mrb_re_utf8_charlen(sp, str_end); pc++; break; case RE_MATCH: @@ -473,8 +473,8 @@ bt_match(const mrb_regexp_pattern *pat, const char *str, const char *str_end, case RE_WBOUND: { - mrb_bool before = (sp > str) && re_is_word_char((uint8_t)sp[-1]); - mrb_bool after = (sp < str_end) && re_is_word_char((uint8_t)*sp); + mrb_bool before = (sp > str) && mrb_re_is_word_char((uint8_t)sp[-1]); + mrb_bool after = (sp < str_end) && mrb_re_is_word_char((uint8_t)*sp); if (before == after) return FALSE; } pc++; @@ -482,8 +482,8 @@ bt_match(const mrb_regexp_pattern *pat, const char *str, const char *str_end, case RE_NWBOUND: { - mrb_bool before = (sp > str) && re_is_word_char((uint8_t)sp[-1]); - mrb_bool after = (sp < str_end) && re_is_word_char((uint8_t)*sp); + mrb_bool before = (sp > str) && mrb_re_is_word_char((uint8_t)sp[-1]); + mrb_bool after = (sp < str_end) && mrb_re_is_word_char((uint8_t)*sp); if (before != after) return FALSE; } pc++; @@ -611,7 +611,7 @@ literal_exec(const mrb_regexp_pattern *pat, /* Public entry point */ int -re_exec(mrb_state *mrb, const mrb_regexp_pattern *pat, +mrb_re_exec(mrb_state *mrb, const mrb_regexp_pattern *pat, const char *str, mrb_int len, mrb_int start, int *captures, int captures_size) { diff --git a/mrbgems/mruby-regexp/src/re_utf8.c b/mrbgems/mruby-regexp/src/re_utf8.c index 82f22b1bb..148d59858 100644 --- a/mrbgems/mruby-regexp/src/re_utf8.c +++ b/mrbgems/mruby-regexp/src/re_utf8.c @@ -9,7 +9,7 @@ /* Return byte length of UTF-8 character at s. Returns 1 for invalid sequences (treat as single byte). */ int -re_utf8_charlen(const char *s, const char *end) +mrb_re_utf8_charlen(const char *s, const char *end) { uint8_t c = (uint8_t)*s; int len; @@ -28,7 +28,7 @@ re_utf8_charlen(const char *s, const char *end) /* Decode a UTF-8 character and return its codepoint. *len is set to the byte length consumed. */ uint32_t -re_utf8_decode(const char *s, int *len) +mrb_re_utf8_decode(const char *s, int *len) { uint8_t c = (uint8_t)s[0]; uint32_t cp; @@ -66,7 +66,7 @@ re_utf8_decode(const char *s, int *len) /* Check if character is a "word" character (\w): [a-zA-Z0-9_] */ mrb_bool -re_is_word_char(uint32_t c) +mrb_re_is_word_char(uint32_t c) { if (c >= 'a' && c <= 'z') return TRUE; if (c >= 'A' && c <= 'Z') return TRUE; diff --git a/mrbgems/mruby-regexp/src/regexp.c b/mrbgems/mruby-regexp/src/regexp.c index 325fd553f..fa06557f5 100644 --- a/mrbgems/mruby-regexp/src/regexp.c +++ b/mrbgems/mruby-regexp/src/regexp.c @@ -19,7 +19,7 @@ /* Regexp data type */ static void regexp_free(mrb_state *mrb, void *ptr) { - re_free(mrb, (mrb_regexp_pattern*)ptr); + mrb_re_free(mrb, (mrb_regexp_pattern*)ptr); } static const struct mrb_data_type regexp_type = { "Regexp", regexp_free }; @@ -107,13 +107,13 @@ regexp_init(mrb_state *mrb, mrb_value self) flags = parse_flags(mrb, flags_val); } - /* Set @source and @flags before re_compile() so a Regexp that survives + /* Set @source and @flags before mrb_re_compile() so a Regexp that survives a compile-time exception (e.g. picked up by ObjectSpace.each_object) still has usable IVs for hash/eql?/inspect. */ mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "@source"), pattern); mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "@flags"), mrb_int_value(mrb, (mrb_int)flags)); - pat = re_compile(mrb, RSTRING_PTR(pattern), RSTRING_LEN(pattern), flags); + pat = mrb_re_compile(mrb, RSTRING_PTR(pattern), RSTRING_LEN(pattern), flags); DATA_TYPE(self) = ®exp_type; DATA_PTR(self) = pat; @@ -206,7 +206,7 @@ exec_match(mrb_state *mrb, mrb_value self, mrb_value str, mrb_int pos) int cap_size = pat->num_captures * 2; int *captures = (int*)mrb_malloc(mrb, sizeof(int) * cap_size); memset(captures, -1, sizeof(int) * cap_size); - int ncap = re_exec(mrb, pat, RSTRING_PTR(str), RSTRING_LEN(str), pos, + int ncap = mrb_re_exec(mrb, pat, RSTRING_PTR(str), RSTRING_LEN(str), pos, captures, cap_size); if (ncap == 0) { @@ -244,7 +244,7 @@ regexp_match_p(mrb_state *mrb, mrb_value self) mrb_regexp_pattern *pat = DATA_GET_PTR(mrb, self, ®exp_type, mrb_regexp_pattern); if (!pat) mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized Regexp"); - int ncap = re_exec(mrb, pat, RSTRING_PTR(str), RSTRING_LEN(str), pos, NULL, 0); + int ncap = mrb_re_exec(mrb, pat, RSTRING_PTR(str), RSTRING_LEN(str), pos, NULL, 0); return mrb_bool_value(ncap > 0); } @@ -281,7 +281,7 @@ regexp_case_match(mrb_state *mrb, mrb_value self) pat = DATA_GET_PTR(mrb, self, ®exp_type, mrb_regexp_pattern); if (!pat) return mrb_false_value(); - int ncap = re_exec(mrb, pat, RSTRING_PTR(str), RSTRING_LEN(str), 0, NULL, 0); + int ncap = mrb_re_exec(mrb, pat, RSTRING_PTR(str), RSTRING_LEN(str), 0, NULL, 0); return mrb_bool_value(ncap > 0); } @@ -726,7 +726,7 @@ regexp_gsub_str(mrb_state *mrb, mrb_value self) while (pos <= slen) { memset(captures, -1, sizeof(int) * cap_size); - int n = re_exec(mrb, pat, s, slen, pos, captures, cap_size); + int n = mrb_re_exec(mrb, pat, s, slen, pos, captures, cap_size); if (n == 0) break; /* save last match for $~ */ @@ -800,7 +800,7 @@ regexp_sub_str(mrb_state *mrb, mrb_value self) int *captures = (int*)mrb_malloc(mrb, sizeof(int) * cap_size); memset(captures, -1, sizeof(int) * cap_size); - int n = re_exec(mrb, pat, s, slen, 0, captures, cap_size); + int n = mrb_re_exec(mrb, pat, s, slen, 0, captures, cap_size); if (n == 0) { mrb_free(mrb, captures); clear_match_globals(mrb); @@ -858,7 +858,7 @@ regexp_scan(mrb_state *mrb, mrb_value self) while (pos <= slen) { memset(captures, -1, sizeof(int) * cap_size); - int n = re_exec(mrb, pat, s, slen, pos, captures, cap_size); + int n = mrb_re_exec(mrb, pat, s, slen, pos, captures, cap_size); if (n == 0) break; last_ncap = cap_size; diff --git a/mrbgems/mruby-regexp/test/regexp.rb b/mrbgems/mruby-regexp/test/regexp.rb index d3e24d25a..787c6898d 100644 --- a/mrbgems/mruby-regexp/test/regexp.rb +++ b/mrbgems/mruby-regexp/test/regexp.rb @@ -381,7 +381,7 @@ assert("MatchData#named_captures") do end assert("Regexp - named captures survive /x preprocessing") do - # Regression: with /x, re_compile freed the stripped buffer that + # Regression: with /x, mrb_re_compile freed the stripped buffer that # named_captures[i].name pointed into. re = /(?\d+) # comment \s* (?\w+) /x