Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 20 additions & 33 deletions src/prism.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading