Use bounded comparisons for compiler attributes

Compare compiler attribute names using Ruby string lengths.  Share
attribute handling between the compiler paths to keep their behavior
aligned.
This commit is contained in:
Nobuyoshi Nakada 2026-07-15 03:34:40 +09:00 committed by Nobuyoshi Nakada
parent 878d20ef1b
commit 21b7c7257f
Notes: git 2026-07-15 04:29:38 +00:00
4 changed files with 39 additions and 44 deletions

View File

@ -9273,12 +9273,37 @@ delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *arg
}
}
static int
compile_builtin_attr_symbol(rb_iseq_t *iseq, VALUE symbol)
{
VALUE string = rb_sym2str(symbol);
if (rb_streql_lit(string, "leaf")) {
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
}
else if (rb_streql_lit(string, "inline_block")) {
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
}
else if (rb_streql_lit(string, "use_block")) {
iseq_set_use_block(iseq);
}
else if (rb_streql_lit(string, "c_trace")) {
// Let the iseq act like a C method in backtraces
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
}
else if (rb_streql_lit(string, "without_interrupts")) {
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_WITHOUT_INTERRUPTS;
}
else {
return COMPILE_NG;
}
return COMPILE_OK;
}
// Compile Primitive.attr! :leaf, ...
static int
compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
{
VALUE symbol;
VALUE string;
if (!node) goto no_arg;
while (node) {
if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
@ -9295,27 +9320,7 @@ compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
}
if (!SYMBOL_P(symbol)) goto non_symbol_arg;
string = rb_sym2str(symbol);
if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
}
else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
}
else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
iseq_set_use_block(iseq);
}
else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
// Let the iseq act like a C method in backtraces
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
}
else if (strcmp(RSTRING_PTR(string), "without_interrupts") == 0) {
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_WITHOUT_INTERRUPTS;
}
else {
goto unknown_arg;
}
if (compile_builtin_attr_symbol(iseq, symbol) != COMPILE_OK) goto unknown_arg;
node = next;
}
return COMPILE_OK;
@ -9326,7 +9331,7 @@ compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
return COMPILE_NG;
unknown_arg:
COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %" PRIsVALUE, symbol);
return COMPILE_NG;
bad_arg:
UNKNOWN_NODE("attr!", node, COMPILE_NG);

View File

@ -220,6 +220,14 @@ rb_str_eql_internal(const VALUE str1, const VALUE str2)
return Qfalse;
}
static inline bool
rb_streql_cstr(VALUE str, const char *lit, size_t len)
{
if ((size_t)RSTRING_LEN(str) != len) return false;
return memcmp(RSTRING_PTR(str), lit, len) == 0;
}
#define rb_streql_lit(str, lit) rb_streql_cstr(str, lit, rb_strlen_lit(lit))
#if __has_builtin(__builtin_constant_p)
# define rb_fstring_cstr(str) \
(__builtin_constant_p(str) ? \

2
iseq.c
View File

@ -616,7 +616,7 @@ iseq_location_setup(rb_iseq_t *iseq, VALUE name, VALUE path, VALUE realpath, int
RB_OBJ_WRITE(iseq, &loc->base_label, name);
loc->first_lineno = first_lineno;
if (ISEQ_BODY(iseq)->local_iseq == iseq && strcmp(RSTRING_PTR(name), "initialize") == 0) {
if (ISEQ_BODY(iseq)->local_iseq == iseq && rb_streql_lit(name, "initialize")) {
ISEQ_BODY(iseq)->param.flags.use_block = 1;
}

View File

@ -3534,26 +3534,8 @@ pm_compile_builtin_attr(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_a
}
VALUE symbol = pm_static_literal_value(iseq, argument, scope_node);
VALUE string = rb_sym2str(symbol);
if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
}
else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
}
else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
iseq_set_use_block(iseq);
}
else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
// Let the iseq act like a C method in backtraces
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
}
else if (strcmp(RSTRING_PTR(string), "without_interrupts") == 0) {
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_WITHOUT_INTERRUPTS;
}
else {
COMPILE_ERROR(iseq, node_location->line, "unknown argument to attr!: %s", RSTRING_PTR(string));
if (compile_builtin_attr_symbol(iseq, symbol) != COMPILE_OK) {
COMPILE_ERROR(iseq, node_location->line, "unknown argument to attr!: %" PRIsVALUE, symbol);
return COMPILE_NG;
}
}