summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2015-12-01 16:11:47 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2015-12-01 16:11:47 +0900
commit0701236dacd1c108d79f9cc90665fb4069d43c55 (patch)
tree476adac1ff9ac34ab504c49fd0e01d8ad2c888e7 /src
parentd3a56a694935202efa16f752e092f965abfca5aa (diff)
downloadmruby-0701236dacd1c108d79f9cc90665fb4069d43c55.tar.gz
mruby-0701236dacd1c108d79f9cc90665fb4069d43c55.zip
mrb_str_to_inum(): should treat null byte in strings properly; fix #3040
Diffstat (limited to 'src')
-rw-r--r--src/string.c69
1 files changed, 35 insertions, 34 deletions
diff --git a/src/string.c b/src/string.c
index 6ea139c90..329010e59 100644
--- a/src/string.c
+++ b/src/string.c
@@ -2030,11 +2030,12 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
}
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;
- int c, uscore;
+ int c;
uint64_t n = 0;
mrb_int val;
@@ -2048,7 +2049,8 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
if (badcheck) goto bad;
return mrb_fixnum_value(0);
}
- while (ISSPACE(*str)) str++;
+ while (str<pend && ISSPACE(*str))
+ str++;
if (str[0] == '+') {
str++;
@@ -2057,10 +2059,6 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
str++;
sign = 0;
}
- if (str[0] == '+' || str[0] == '-') {
- if (badcheck) goto bad;
- return mrb_fixnum_value(0);
- }
if (base <= 0) {
if (str[0] == '0') {
switch (str[1]) {
@@ -2078,6 +2076,7 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
break;
default:
base = 8;
+ break;
}
}
else if (base < -1) {
@@ -2119,35 +2118,37 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
break;
} /* end of switch (base) { */
if (*str == '0') { /* squeeze preceding 0s */
- uscore = 0;
- while ((c = *++str) == '0' || c == '_') {
+ while (str<pend && ((c = *++str) == '0' || c == '_')) {
if (c == '_') {
- if (++uscore >= 2)
+ if (*str == '_') {
+ if (badcheck) goto bad;
break;
+ }
}
- else
- uscore = 0;
}
if (!(c = *str) || ISSPACE(c)) --str;
}
c = *str;
+ if (badcheck && c == '\0') {
+ goto nullbyte;
+ }
c = conv_digit(c);
if (c < 0 || c >= base) {
if (badcheck) goto bad;
return mrb_fixnum_value(0);
}
- uscore = 0;
- for (p=str;*p;p++) {
+ for (p=str;p<pend;p++) {
if (*p == '_') {
- if (uscore == 0) {
- uscore++;
+ if (p[1] == '_') {
+ if (badcheck) goto bad;
continue;
}
- if (badcheck) goto bad;
- break;
+ p++;
+ }
+ if (badcheck && *p == '\0') {
+ goto nullbyte;
}
- uscore = 0;
c = conv_digit(*p);
if (c < 0 || c >= base) {
break;
@@ -2161,17 +2162,26 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck)
val = n;
if (badcheck) {
if (p == str) goto bad; /* no number */
- while (*p && ISSPACE(*p)) p++;
- if (*p) goto bad; /* trailing garbage */
+ while (p<pend && ISSPACE(*p)) p++;
+ if (p<pend) goto bad; /* trailing garbage */
}
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));
/* not reached */
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_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)
mrb_int len;
s = mrb_string_value_ptr(mrb, str);
- if (s) {
- len = RSTRING_LEN(str);
- 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);
+ len = RSTRING_LEN(str);
+ return mrb_str_len_to_inum(mrb, s, len, base, badcheck);
}
/* 15.2.10.5.38 */