From 0e4431ff4a24575c8718b32d3e72024bf5cb942d Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Tue, 27 Oct 2026 11:17:11 -0400 Subject: [PATCH] Avoid strtoul for numbered references --- src/prism.c | 53 ++++++++++++++++++++--------------------------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/src/prism.c b/src/prism.c index 01b91fee91..da849e0839 100644 --- a/src/prism.c +++ b/src/prism.c @@ -5852,54 +5852,41 @@ pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_token_t *openin ); } -/** - * The maximum numbered reference value is defined as the maximum value that an - * integer can hold minus 1 bit for CRuby instruction sequence operand tagging. - */ -#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1)) - /** * Parse the decimal number represented by the range of bytes. Returns - * 0 if the number fails to parse or if the number is greater than the maximum - * value representable by a numbered reference. This function assumes that the - * range of bytes has already been validated to contain only decimal digits. + * 0 if the number is greater than the maximum value representable by a numbered + * reference. This function assumes that the range of bytes has already been + * validated to contain only decimal digits. */ static uint32_t pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) { - const uint8_t *start = token->start + 1; - const uint8_t *end = token->end; +/** + * The maximum numbered reference value is defined as the maximum value that an + * integer can hold minus 1 bit for CRuby instruction sequence operand tagging. + */ +#define NTH_REF_MAX ((uint64_t) (uint32_t) (INT_MAX >> 1)) - ptrdiff_t diff = end - start; + const uint8_t *start = token->start + 1; + ptrdiff_t diff = token->end - start; assert(diff > 0); -#if PTRDIFF_MAX > SIZE_MAX - assert(diff < (ptrdiff_t) SIZE_MAX); -#endif - size_t length = (size_t) diff; - - char *digits = xcalloc(length + 1, sizeof(char)); - memcpy(digits, start, length); - digits[length] = '\0'; - char *endptr; - errno = 0; - unsigned long value = strtoul(digits, &endptr, 10); - - if ((digits == endptr) || (*endptr != '\0')) { - pm_parser_err(parser, U32(start - parser->start), U32(length), PM_ERR_INVALID_NUMBER_DECIMAL); - value = 0; - } + size_t length = (size_t) diff; + uint64_t value = 0; - xfree_sized(digits, sizeof(char) * (length + 1)); + for (size_t idx = 0; idx < length; ++idx) { + value = value * 10 + (uint64_t) (start[idx] - '0'); - if ((errno == ERANGE) || (value > NTH_REF_MAX)) { - PM_PARSER_WARN_FORMAT(parser, U32(start - parser->start), U32(length), PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start); - value = 0; + if (value > NTH_REF_MAX) { + PM_PARSER_WARN_FORMAT(parser, U32(start - parser->start), U32(length), PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start); + value = 0; + break; + } } return (uint32_t) value; -} #undef NTH_REF_MAX +} /** * Allocate and initialize a new NthReferenceReadNode node.