Avoid using `snprintf` when `MRB_DISABLE_STDIO` is set; fix
MODIFY
mrbgems/mruby-compiler/core/parse.y
mrbgems/mruby-compiler/core/parse.y
@@ -220,6 +220,25 @@ parser_strdup(parser_state *p, const char *s)
#undef strdup
#define strdup(s) parser_strdup(p, s)
+static void
+itoa(short i, char *s)
+{
+ char *p = s;
+ char *t = s;
+
+ while (i > 0) {
+ *p++ = (i % 10)+'0';
+ i /= 10;
+ }
+ if (p == s) *p++ = '0';
+ *p = 0;
+ p--; /* point the last char */
+ while (t < p) {
+ char c = *t;
+ *t++ = *p;
+ *p-- = c;
+ }
+}
/* xxx ----------------------------- */
static node*
@@ -3172,7 +3191,7 @@ var_ref : variable
{
char buf[16];
- snprintf(buf, sizeof(buf), "%d", p->lineno);
+ itoa(p->lineno, buf);
$$ = new_int(p, buf, 10);
}
| keyword__ENCODING__
@@ -3692,11 +3711,12 @@ yyerror(parser_state *p, const char *s)
}
static void
-yyerror_i(parser_state *p, const char *fmt, int i)
+yyerror_c(parser_state *p, const char *msg, char c)
{
char buf[256];
- snprintf(buf, sizeof(buf), fmt, i);
+ strcpy(buf, msg);
+ strcat(buf, &c);
yyerror(p, buf);
}
@@ -3735,11 +3755,13 @@ yywarning(parser_state *p, const char *s)
}
static void
-yywarning_s(parser_state *p, const char *fmt, const char *s)
+yywarning_s(parser_state *p, const char *msg, const char *s)
{
char buf[256];
- snprintf(buf, sizeof(buf), fmt, s);
+ strcpy(buf, msg);
+ strcat(buf, ": ");
+ strcat(buf, s);
yywarning(p, buf);
}
@@ -3751,10 +3773,10 @@ backref_error(parser_state *p, node *n)
c = intn(n->car);
if (c == NODE_NTH_REF) {
- yyerror_i(p, "can't set variable $%" MRB_PRId, intn(n->cdr));
+ yyerror_c(p, "can't set variable $", (char)intn(n->cdr)+'0');
}
else if (c == NODE_BACK_REF) {
- yyerror_i(p, "can't set variable $%c", intn(n->cdr));
+ yyerror_c(p, "can't set variable $", (char)intn(n->cdr));
}
else {
mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c));
@@ -4298,7 +4320,15 @@ parse_string(parser_state *p)
}
if (c < 0) {
char buf[256];
- snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term);
+ const char s1[] = "can't find heredoc delimiter \"";
+ const char s2[] = "\" anywhere before EOF";
+
+ if (sizeof(s1)+sizeof(s2)+strlen(hinf->term)+1 >= sizeof(buf)) {
+ yyerror(p, "can't find heredoc delimiter anywhere before EOF");
+ }
+ strcpy(buf, s1);
+ strcat(buf, hinf->term);
+ strcat(buf, s2);
yyerror(p, buf);
return 0;
}
@@ -4449,9 +4479,14 @@ parse_string(parser_state *p)
pushback(p, re_opt);
if (toklen(p)) {
char msg[128];
+
+ strcpy(msg, "unknown regexp option");
tokfix(p);
- snprintf(msg, sizeof(msg), "unknown regexp option%s - %s",
- toklen(p) > 1 ? "s" : "", tok(p));
+ if (toklen(p) > 1) {
+ strcat(msg, "s");
+ }
+ strcat(msg, " - ");
+ strcat(msg, tok(p));
yyerror(p, msg);
}
if (f != 0) {
@@ -4879,7 +4914,10 @@ parser_yylex(parser_state *p)
}
if (c2) {
char buf[256];
- snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2);
+ char cc = (char)c2;
+
+ strcpy(buf, "invalid character syntax; use ?\\");
+ strcat(buf, &cc);
yyerror(p, buf);
}
}
@@ -5252,7 +5290,7 @@ parser_yylex(parser_state *p)
pushback(p, c);
if (nondigit) {
trailing_uc:
- yyerror_i(p, "trailing '%c' in number", nondigit);
+ yyerror_c(p, "trailing non digit in number: ", (char)nondigit);
}
tokfix(p);
if (is_float) {
@@ -5267,10 +5305,10 @@ parser_yylex(parser_state *p)
errno = 0;
d = mrb_float_read(tok(p), &endp);
if (d == 0 && endp == tok(p)) {
- yywarning_s(p, "corrupted float value %s", tok(p));
+ yywarning_s(p, "corrupted float value", tok(p));
}
else if (errno == ERANGE) {
- yywarning_s(p, "float %s out of range", tok(p));
+ yywarning_s(p, "float out of range", tok(p));
errno = 0;
}
pylval.nd = new_float(p, tok(p));
@@ -5612,7 +5650,7 @@ parser_yylex(parser_state *p)
{
unsigned long n = strtoul(tok(p), NULL, 10);
if (n > INT_MAX) {
- yyerror_i(p, "capture group index must be <= %d", INT_MAX);
+ yyerror(p, "capture group index must be <= " MRB_STRINGIZE(INT_MAX));
return 0;
}
pylval.nd = new_nth_ref(p, (int)n);
@@ -5649,10 +5687,10 @@ parser_yylex(parser_state *p)
}
else if (ISDIGIT(c)) {
if (p->tidx == 1) {
- yyerror_i(p, "'@%c' is not allowed as an instance variable name", c);
+ yyerror_c(p, "wrong instance variable name: @", c);
}
else {
- yyerror_i(p, "'@@%c' is not allowed as a class variable name", c);
+ yyerror_c(p, "wrong class variable name: @@", c);
}
return 0;
}
@@ -5668,7 +5706,14 @@ parser_yylex(parser_state *p)
default:
if (!identchar(c)) {
- yyerror_i(p, "Invalid char '\\x%02X' in expression", c);
+ char buf[36];
+ const char s[] = "Invalid char in expression: 0x";
+
+ strcpy(buf, s);
+ buf[sizeof(s)] = (c & 0xff00) >> 8;
+ buf[sizeof(s)+1] = (c & 0xff);
+ buf[sizeof(s)+2] = 0;
+ yyerror(p, buf);
goto retry;
}
@@ -6097,11 +6142,12 @@ mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c)
if (c) c->parser_nerr = p->nerr;
if (p->capture_errors) {
char buf[256];
- int n;
- n = snprintf(buf, sizeof(buf), "line %d: %s\n",
- p->error_buffer[0].lineno, p->error_buffer[0].message);
- mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n));
+ strcpy(buf, "line ");
+ itoa(p->error_buffer[0].lineno, buf+5);
+ strcat(buf, ": ");
+ strcat(buf, p->error_buffer[0].message);
+ mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, strlen(buf)));
mrb_parser_free(p);
return mrb_undef_value();
}

Avoid using `snprintf` when `MRB_DISABLE_STDIO` is set; fix #4173