summaryrefslogtreecommitdiff
path: root/object.c
diff options
context:
space:
mode:
authorNobuyoshi Nakada <[email protected]>2025-03-04 10:22:17 +0900
committerNobuyoshi Nakada <[email protected]>2025-03-07 12:14:48 +0900
commit8841f885bde7bbe571d2043830799059870dc70c (patch)
treea6cac4130484ba1c7b55434710c249b99210d50d /object.c
parent6bad47ac6d62b54fe30e3f161c2a9d8f5fa4800c (diff)
[Bug #21163] Fix hexadecimal float conversion
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/12878
Diffstat (limited to 'object.c')
-rw-r--r--object.c33
1 files changed, 29 insertions, 4 deletions
diff --git a/object.c b/object.c
index 248a65a64b..74f58a15bd 100644
--- a/object.c
+++ b/object.c
@@ -3405,6 +3405,13 @@ rb_f_integer(rb_execution_context_t *ec, VALUE obj, VALUE arg, VALUE base, VALUE
return rb_convert_to_integer(arg, NUM2INT(base), exc);
}
+static bool
+is_digit_char(unsigned char c, int base)
+{
+ int i = ruby_digit36_to_number_table[c];
+ return (i >= 0 && i < base);
+}
+
static double
rb_cstr_to_dbl_raise(const char *p, rb_encoding *enc, int badcheck, int raise, int *error)
{
@@ -3446,23 +3453,37 @@ rb_cstr_to_dbl_raise(const char *p, rb_encoding *enc, int badcheck, int raise, i
char *e = init_e;
char prev = 0;
int dot_seen = FALSE;
+ int base = 10;
+ char exp_letter = 'e';
switch (*p) {case '+': case '-': prev = *n++ = *p++;}
if (*p == '0') {
prev = *n++ = '0';
- while (*++p == '0');
+ switch (*++p) {
+ case 'x': case 'X':
+ prev = *n++ = 'x';
+ base = 16;
+ exp_letter = 'p';
+ if (*++p != '0') break;
+ /* fallthrough */
+ case '0': /* squeeze successive zeros */
+ while (*++p == '0');
+ break;
+ }
}
while (p < end && n < e) prev = *n++ = *p++;
while (*p) {
if (*p == '_') {
/* remove an underscore between digits */
- if (n == buf || !ISDIGIT(prev) || (++p, !ISDIGIT(*p))) {
+ if (n == buf ||
+ !is_digit_char(prev, base) ||
+ !is_digit_char(*++p, base)) {
if (badcheck) goto bad;
break;
}
}
prev = *p++;
- if (e == init_e && (prev == 'e' || prev == 'E' || prev == 'p' || prev == 'P')) {
+ if (e == init_e && (rb_tolower(prev) == exp_letter)) {
e = buf + sizeof(buf) - 1;
*n++ = prev;
switch (*p) {case '+': case '-': prev = *n++ = *p++;}
@@ -3470,6 +3491,10 @@ rb_cstr_to_dbl_raise(const char *p, rb_encoding *enc, int badcheck, int raise, i
prev = *n++ = '0';
while (*++p == '0');
}
+
+ /* reset base to decimal for underscore check of
+ * binary exponent part */
+ base = 10;
continue;
}
else if (ISSPACE(prev)) {
@@ -3479,7 +3504,7 @@ rb_cstr_to_dbl_raise(const char *p, rb_encoding *enc, int badcheck, int raise, i
break;
}
}
- else if (prev == '.' ? dot_seen++ : !ISDIGIT(prev)) {
+ else if (prev == '.' ? dot_seen++ : !is_digit_char(prev, base)) {
if (badcheck) goto bad;
break;
}