mrb_str_to_inum(): should treat null byte in strings properly; fix #3040

parent d3a56a69
...@@ -2030,11 +2030,12 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) ...@@ -2030,11 +2030,12 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
} }
MRB_API mrb_value MRB_API mrb_value
mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) mrb_str_len_to_inum(mrb_state *mrb, const char *str, size_t len, int base, int badcheck)
{ {
const char *p; const char *p = str;
const char *pend = str + len;
char sign = 1; char sign = 1;
int c, uscore; int c;
uint64_t n = 0; uint64_t n = 0;
mrb_int val; mrb_int val;
...@@ -2048,7 +2049,8 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) ...@@ -2048,7 +2049,8 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
if (badcheck) goto bad; if (badcheck) goto bad;
return mrb_fixnum_value(0); return mrb_fixnum_value(0);
} }
while (ISSPACE(*str)) str++; while (str<pend && ISSPACE(*str))
str++;
if (str[0] == '+') { if (str[0] == '+') {
str++; str++;
...@@ -2057,10 +2059,6 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) ...@@ -2057,10 +2059,6 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
str++; str++;
sign = 0; sign = 0;
} }
if (str[0] == '+' || str[0] == '-') {
if (badcheck) goto bad;
return mrb_fixnum_value(0);
}
if (base <= 0) { if (base <= 0) {
if (str[0] == '0') { if (str[0] == '0') {
switch (str[1]) { switch (str[1]) {
...@@ -2078,6 +2076,7 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) ...@@ -2078,6 +2076,7 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
break; break;
default: default:
base = 8; base = 8;
break;
} }
} }
else if (base < -1) { else if (base < -1) {
...@@ -2119,35 +2118,37 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) ...@@ -2119,35 +2118,37 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
break; break;
} /* end of switch (base) { */ } /* end of switch (base) { */
if (*str == '0') { /* squeeze preceding 0s */ if (*str == '0') { /* squeeze preceding 0s */
uscore = 0; while (str<pend && ((c = *++str) == '0' || c == '_')) {
while ((c = *++str) == '0' || c == '_') {
if (c == '_') { if (c == '_') {
if (++uscore >= 2) if (*str == '_') {
if (badcheck) goto bad;
break; break;
}
} }
else
uscore = 0;
} }
if (!(c = *str) || ISSPACE(c)) --str; if (!(c = *str) || ISSPACE(c)) --str;
} }
c = *str; c = *str;
if (badcheck && c == '\0') {
goto nullbyte;
}
c = conv_digit(c); c = conv_digit(c);
if (c < 0 || c >= base) { if (c < 0 || c >= base) {
if (badcheck) goto bad; if (badcheck) goto bad;
return mrb_fixnum_value(0); return mrb_fixnum_value(0);
} }
uscore = 0; for (p=str;p<pend;p++) {
for (p=str;*p;p++) {
if (*p == '_') { if (*p == '_') {
if (uscore == 0) { if (p[1] == '_') {
uscore++; if (badcheck) goto bad;
continue; continue;
} }
if (badcheck) goto bad; p++;
break; }
if (badcheck && *p == '\0') {
goto nullbyte;
} }
uscore = 0;
c = conv_digit(*p); c = conv_digit(*p);
if (c < 0 || c >= base) { if (c < 0 || c >= base) {
break; break;
...@@ -2161,17 +2162,26 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) ...@@ -2161,17 +2162,26 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
val = n; val = n;
if (badcheck) { if (badcheck) {
if (p == str) goto bad; /* no number */ if (p == str) goto bad; /* no number */
while (*p && ISSPACE(*p)) p++; while (p<pend && ISSPACE(*p)) p++;
if (*p) goto bad; /* trailing garbage */ if (p<pend) goto bad; /* trailing garbage */
} }
return mrb_fixnum_value(sign ? val : -val); return mrb_fixnum_value(sign ? val : -val);
bad: nullbyte:
mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
/* not reached */
bad:
mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for number(%S)", mrb_str_new_cstr(mrb, str)); mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for number(%S)", mrb_str_new_cstr(mrb, str));
/* not reached */ /* not reached */
return mrb_fixnum_value(0); return mrb_fixnum_value(0);
} }
MRB_API mrb_value
mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
{
return mrb_str_len_to_inum(mrb, str, strlen(str), base, badcheck);
}
MRB_API const char* MRB_API const char*
mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr)
{ {
...@@ -2198,17 +2208,8 @@ mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck) ...@@ -2198,17 +2208,8 @@ mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck)
mrb_int len; mrb_int len;
s = mrb_string_value_ptr(mrb, str); s = mrb_string_value_ptr(mrb, str);
if (s) { len = RSTRING_LEN(str);
len = RSTRING_LEN(str); return mrb_str_len_to_inum(mrb, s, len, base, badcheck);
if (badcheck && strlen(s) != len) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte");
}
if (s[len]) { /* no sentinel somehow */
struct RString *temp_str = str_new(mrb, s, len);
s = RSTR_PTR(temp_str);
}
}
return mrb_cstr_to_inum(mrb, s, base, badcheck);
} }
/* 15.2.10.5.38 */ /* 15.2.10.5.38 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment