add some missing checks on bytecode parsing

The `tests/racket/stress/fuzz' test fails much less frequently,
though problems certainly remain.
This commit is contained in:
Matthew Flatt 2011-12-08 13:34:20 -07:00
parent 657be87c66
commit 4a387c5b6a
10 changed files with 137 additions and 41 deletions

View File

@ -8,8 +8,15 @@
(bytes-set! bs byte (bitwise-xor (expt 2 bit) val)))
(define (run-file bs)
(eval (parameterize ([read-accept-compiled #t])
(with-input-from-bytes bs read))))
(sync
(parameterize ([current-custodian (make-custodian)])
(thread
(lambda ()
(custodian-limit-memory (current-custodian)
(* 512 (expt 2 20)))
(with-handlers ([void void])
(eval (parameterize ([read-accept-compiled #t])
(with-input-from-bytes bs read)))))))))
(define (run fname seed0)
(define seed (or seed0 (+ 1 (random (expt 2 30)))))
@ -21,17 +28,20 @@
(for ([i (in-range (quotient len 10000))]) (flip-bit bs (random len)))
(with-handlers ([void void]) (run-file bs)))
(let ([seed #f] [file #f] [dir #f])
(let ([seed0 #f] [file #f] [dir #f] [forever? #f])
(command-line
#:once-each
["-s" seed "random seed" (set! seed (string->number seed))]
["-s" seed "random seed" (set! seed0 (string->number seed))]
["--oo" "forever" (set! forever? #t)]
#:once-any
["-f" file "filename to run" (set! file file)]
["-d" dir* "dir to run" (set! dir dir*)]
["-c" "run over all collections" (set! dir (find-collects-dir))]
#:args () (void))
(cond [file (run file seed)]
[dir (for ([p (in-directory dir)]
#:when (regexp-match #rx"\\.zo" p))
(run p seed))]
[else (printf "Nothing to do.\n")]))
(let loop ()
(cond [file (run file seed0)]
[dir (for ([p (in-directory dir)]
#:when (regexp-match #rx"\\.zo" p))
(run p seed0))]
[else (printf "Nothing to do.\n")])
(when forever? (loop))))

View File

@ -4127,12 +4127,24 @@ Scheme_Object *scheme_make_application(Scheme_Object *v)
Scheme_App_Rec *scheme_malloc_application(int n)
{
Scheme_App_Rec *app;
int size;
intptr_t size;
size = (sizeof(Scheme_App_Rec)
+ ((n - mzFLEX_DELTA) * sizeof(Scheme_Object *))
+ n * sizeof(char));
app = (Scheme_App_Rec *)scheme_malloc_tagged(size);
if (n < 0) {
scheme_signal_error("bad application count");
app = NULL;
} else if (n > 4096) {
size = scheme_check_overflow(n,
sizeof(char),
(sizeof(Scheme_App_Rec)
+ ((n - mzFLEX_DELTA) * sizeof(Scheme_Object *))));
app = (Scheme_App_Rec *)scheme_malloc_fail_ok(scheme_malloc_tagged, size);
if (!app) scheme_signal_error("out of memory allocating application bytecode");
} else {
size = (sizeof(Scheme_App_Rec)
+ ((n - mzFLEX_DELTA) * sizeof(Scheme_Object *))
+ n * sizeof(char));
app = (Scheme_App_Rec *)scheme_malloc_tagged(size);
}
app->so.type = scheme_application_type;

View File

@ -1352,6 +1352,10 @@ Scheme_Object **scheme_make_builtin_references_table(void)
scheme_misc_count += sizeof(Scheme_Object *) * (builtin_ref_counter + 1);
#endif
for (j = builtin_ref_counter + 1; j--; ) {
t[j] = scheme_false;
}
for (j = 0; j < 4; j++) {
if (!j)
kenv = kernel_env;

View File

@ -275,7 +275,13 @@ static Scheme_Object *read_letrec(Scheme_Object *obj)
lr->body = SCHEME_CAR(obj);
obj = SCHEME_CDR(obj);
sa = MALLOC_N(Scheme_Object*, c);
if (c < 0) return NULL;
if (c < 4096)
sa = MALLOC_N(Scheme_Object*, c);
else {
sa = scheme_malloc_fail_ok(scheme_malloc, scheme_check_overflow(c, sizeof(Scheme_Object *), 0));
if (!sa) scheme_signal_error("out of memory allocating letrec bytecode");
}
lr->procs = sa;
for (i = 0; i < c; i++) {
if (!SCHEME_PAIRP(obj)) return NULL;
@ -312,6 +318,8 @@ static Scheme_Object *read_top(Scheme_Object *obj)
if (!SCHEME_PAIRP(obj)) return NULL;
top->prefix = (Resolve_Prefix *)SCHEME_CAR(obj);
top->code = SCHEME_CDR(obj);
if (!SAME_TYPE(SCHEME_TYPE(top->prefix), scheme_resolve_prefix_type))
return NULL;
return (Scheme_Object *)top;
}
@ -585,6 +593,8 @@ static Scheme_Object *read_sequence_save_first(Scheme_Object *obj)
static Scheme_Object *read_sequence_splice(Scheme_Object *obj)
{
obj = scheme_make_sequence_compilation(obj, 1);
if (!obj) return NULL;
if (SAME_TYPE(SCHEME_TYPE(obj), scheme_sequence_type))
obj->type = scheme_splice_sequence_type;
return obj;
@ -958,6 +968,9 @@ static Scheme_Object *read_toplevel(Scheme_Object *obj)
flags = 0;
}
if (depth < 0) return NULL;
if (pos < 0) return NULL;
return scheme_make_toplevel(depth, pos, 1, flags);
}
@ -1029,6 +1042,7 @@ static Scheme_Object *do_read_local(Scheme_Type t, Scheme_Object *obj)
flags = 0;
n = (int)SCHEME_INT_VAL(obj);
if (n < 0) return NULL;
return scheme_make_local(t, n, flags);
}
@ -1086,7 +1100,7 @@ static Scheme_Object *write_resolve_prefix(Scheme_Object *obj)
static Scheme_Object *read_resolve_prefix(Scheme_Object *obj)
{
Resolve_Prefix *rp;
Scheme_Object *tv, *sv, **a, *stx;
Scheme_Object *tv, *sv, **a, *stx, *tl;
intptr_t i;
if (!SCHEME_PAIRP(obj)) return NULL;
@ -1119,7 +1133,15 @@ static Scheme_Object *read_resolve_prefix(Scheme_Object *obj)
i = rp->num_toplevels;
a = MALLOC_N(Scheme_Object *, i);
while (i--) {
a[i] = SCHEME_VEC_ELS(tv)[i];
tl = SCHEME_VEC_ELS(tv)[i];
if (!SCHEME_FALSEP(tl)
&& !SCHEME_SYMBOLP(tl)
&& (!SCHEME_PAIRP(tl)
|| !SCHEME_SYMBOLP(SCHEME_CAR(tl)))
&& !SAME_TYPE(SCHEME_TYPE(tl), scheme_variable_type)
&& !SAME_TYPE(SCHEME_TYPE(tl), scheme_module_variable_type))
return NULL;
a[i] = tl;
}
rp->toplevels = a;

View File

@ -4066,6 +4066,7 @@ typedef struct Scheme_Load_Delay {
#define ZO_CHECK(x) if (!(x)) scheme_ill_formed_code(port);
#define RANGE_CHECK(x, y) ZO_CHECK (x y)
#define RANGE_POS_CHECK(x, y) ZO_CHECK ((x > 0) && (x y))
#define RANGE_CHECK_GETS(x) RANGE_CHECK(x, <= port->size - port->pos)
typedef struct CPort {
@ -4179,13 +4180,22 @@ static Scheme_Object *read_compact_svector(CPort *port, int l)
o->type = scheme_svector_type;
SCHEME_SVEC_LEN(o) = l;
if (l > 0)
v = MALLOC_N_ATOMIC(mzshort, l);
else
if (l > 0) {
if (l > 4096) {
v = (mzshort *)scheme_malloc_fail_ok(scheme_malloc_atomic,
scheme_check_overflow(l, sizeof(mzshort), 0));
if (!v)
scheme_signal_error("out of memory allocating vector");
} else {
v = MALLOC_N_ATOMIC(mzshort, l);
}
} else {
v = NULL;
l = 0; /* in case it was negative */
}
SCHEME_SVEC_VEC(o) = v;
while (l--) {
while (l-- > 0) {
mzshort cn;
cn = read_compact_number(port);
v[l] = cn;
@ -4295,7 +4305,7 @@ static Scheme_Object *read_compact(CPort *port, int use_stack)
break;
case CPT_SYMREF:
l = read_compact_number(port);
RANGE_CHECK(l, < port->symtab_size);
RANGE_POS_CHECK(l, < port->symtab_size);
v = port->symtab[l];
if (v == SYMTAB_IN_PROGRESS) {
/* there is a cycle */
@ -4351,8 +4361,12 @@ static Scheme_Object *read_compact(CPort *port, int use_stack)
l = read_compact_number(port);
RANGE_CHECK_GETS(el);
s = read_compact_chars(port, buffer, BLK_BUF_SIZE, el);
us = (mzchar *)scheme_malloc_atomic((l + 1) * sizeof(mzchar));
scheme_utf8_decode_all((const unsigned char *)s, el, us, 0);
if (l < 4096)
us = (mzchar *)scheme_malloc_atomic((l + 1) * sizeof(mzchar));
else
us = (mzchar *)scheme_malloc_fail_ok(scheme_malloc_atomic, (l + 1) * sizeof(mzchar));
if (scheme_utf8_decode((const unsigned char *)s, 0, el, us, 0, l, NULL, 0, 0) != l)
scheme_ill_formed_code(port);
us[l] = 0;
v = scheme_make_immutable_sized_char_string(us, l, 0);
v = scheme_intern_literal_string(v);
@ -4648,6 +4662,7 @@ static Scheme_Object *read_compact(CPort *port, int use_stack)
port->symtab[l] = (Scheme_Object *)cl;
v = read_compact(port, 0);
if (!SAME_TYPE(SCHEME_TYPE(v), scheme_closure_type)
|| !((Scheme_Closure *)v)->code
|| ((Scheme_Closure *)v)->code->closure_size) {
scheme_ill_formed_code(port);
return NULL;
@ -4659,7 +4674,7 @@ static Scheme_Object *read_compact(CPort *port, int use_stack)
case CPT_DELAY_REF:
{
l = read_compact_number(port);
RANGE_CHECK(l, < port->symtab_size);
RANGE_POS_CHECK(l, < port->symtab_size);
v = port->symtab[l];
if (!v) {
if (port->delay_info) {
@ -4675,6 +4690,9 @@ static Scheme_Object *read_compact(CPort *port, int use_stack)
port->pos = save_pos;
port->symtab[l] = v;
}
} else if (v == SYMTAB_IN_PROGRESS) {
/* there is a cycle */
scheme_ill_formed_code(port);
}
return v;
break;
@ -4983,11 +5001,19 @@ static Scheme_Object *read_compiled(Scheme_Object *port,
/* Load table mapping symtab indices to stream positions: */
all_short = scheme_get_byte(port);
so = (intptr_t *)scheme_malloc_fail_ok(scheme_malloc_atomic, sizeof(intptr_t) * symtabsize);
if (symtabsize < 0)
so = NULL;
else
so = (intptr_t *)scheme_malloc_fail_ok(scheme_malloc_atomic,
scheme_check_overflow(symtabsize, sizeof(intptr_t), 0));
if (!so)
scheme_read_err(port, NULL, -1, -1, -1, -1, 0, NULL,
"read (compiled): could not allocate symbol table of size %" PRIdPTR,
symtabsize);
if ((got = scheme_get_bytes(port, (all_short ? 2 : 4) * (symtabsize - 1), (char *)so, 0))
!= ((all_short ? 2 : 4) * (symtabsize - 1)))
scheme_read_err(port, NULL, -1, -1, -1, -1, 0, NULL,
"read (compiled): ill-formed code (bad table count: %ld != %ld)",
"read (compiled): ill-formed code (bad table count: %" PRIdPTR " != %" PRIdPTR ")",
got, (all_short ? 2 : 4) * (symtabsize - 1));
offset += got;
@ -5328,6 +5354,8 @@ Scheme_Object *scheme_unmarshal_wrap_get(Scheme_Unmarshal_Tables *ut,
if ((l < 0) || ((uintptr_t)l >= ut->rp->symtab_size))
scheme_ill_formed_code(ut->rp);
if (SAME_OBJ(ut->rp->symtab[l], SYMTAB_IN_PROGRESS))
scheme_ill_formed_code(ut->rp);
if (!ut->rp->symtab[l]) {
Scheme_Object *v;

View File

@ -632,6 +632,17 @@ static void raise_out_of_memory(void)
scheme_raise_out_of_memory(NULL, NULL);
}
intptr_t scheme_check_overflow(intptr_t n, intptr_t m, intptr_t a)
{
intptr_t v;
v = (n * m) + a;
if ((v < n) || (v < m) || (v < a) || (((v - a) / n) != m))
scheme_signal_error("allocation size overflow");
return v;
}
void *scheme_malloc_fail_ok(void *(*f)(size_t), size_t s)
{
void *v;

View File

@ -3663,6 +3663,8 @@ int scheme_can_inline_fp_comp();
void scheme_unused_object(Scheme_Object*);
void scheme_unused_intptr(intptr_t);
intptr_t scheme_check_overflow(intptr_t n, intptr_t m, intptr_t a);
/*========================================================================*/
/* places */
/*========================================================================*/

View File

@ -4723,10 +4723,10 @@ byte_converter_p(int argc, Scheme_Object *argv[])
/**********************************************************************/
static intptr_t utf8_decode_x(const unsigned char *s, intptr_t start, intptr_t end,
unsigned int *us, intptr_t dstart, intptr_t dend,
intptr_t *ipos, intptr_t *jpos,
char compact, char utf16, int *_state,
int might_continue, int permissive)
unsigned int *us, intptr_t dstart, intptr_t dend,
intptr_t *ipos, intptr_t *jpos,
char compact, char utf16, int *_state,
int might_continue, int permissive)
/* Results:
non-negative => translation complete, = number of produced chars
-1 => input ended in middle of encoding (only if might_continue)
@ -5079,16 +5079,16 @@ static intptr_t utf8_decode_x(const unsigned char *s, intptr_t start, intptr_t e
}
intptr_t scheme_utf8_decode(const unsigned char *s, intptr_t start, intptr_t end,
unsigned int *us, intptr_t dstart, intptr_t dend,
intptr_t *ipos, char utf16, int permissive)
unsigned int *us, intptr_t dstart, intptr_t dend,
intptr_t *ipos, char utf16, int permissive)
{
return utf8_decode_x(s, start, end, us, dstart, dend,
ipos, NULL, utf16, utf16, NULL, 0, permissive);
}
intptr_t scheme_utf8_decode_as_prefix(const unsigned char *s, intptr_t start, intptr_t end,
unsigned int *us, intptr_t dstart, intptr_t dend,
intptr_t *ipos, char utf16, int permissive)
unsigned int *us, intptr_t dstart, intptr_t dend,
intptr_t *ipos, char utf16, int permissive)
/* Always returns number of read characters, not error codes. */
{
intptr_t opos;

View File

@ -7279,6 +7279,7 @@ static Scheme_Object *datum_to_syntax_inner(Scheme_Object *o,
--cnt;
}
if (!first) return_NULL;
if (!SCHEME_NULLP(o)) {
o = datum_to_syntax_inner(o, ut, stx_src, sub_stx_wraps, ht, tainted);
if (!o) return_NULL;

View File

@ -793,7 +793,7 @@ static void validate_unclosed_procedure(Mz_CPort *port, Scheme_Object *expr,
if (q == self_pos)
self_pos_in_closure = i;
p = q + delta;
if ((q < 0) || (p >= depth) || (stack[p] <= VALID_UNINIT))
if ((q < 0) || (p < 0) || (p >= depth) || (stack[p] <= VALID_UNINIT))
scheme_ill_formed_code(port);
vld = stack[p];
if (vld == VALID_VAL_NOCLEAR)
@ -884,6 +884,10 @@ static void module_validate(Scheme_Object *data, Mz_CPort *port,
if (!SCHEME_MODNAMEP(m->modname))
scheme_ill_formed_code(port);
validate_toplevel(m->dummy, port, stack, tls, depth, delta,
num_toplevels, num_stxes, num_lifts, tl_use_map,
0);
scheme_validate_code(port, m->bodies[0], m->max_let_depth,
m->prefix->num_toplevels, m->prefix->num_stxes, m->prefix->num_lifts,
NULL,
@ -1012,7 +1016,7 @@ void scheme_validate_expr(Mz_CPort *port, Scheme_Object *expr,
no_flo(need_flonum, port);
if ((c < 0) || (p < 0) || (d >= depth)
if ((c < 0) || (p < 0) || (d < 0) || (d >= depth)
|| (stack[d] != VALID_TOPLEVELS)
|| (p >= (num_toplevels + num_lifts + num_stxes + (num_stxes ? 1 : 0)))
|| ((p >= num_toplevels) && (p < num_toplevels + num_stxes + (num_stxes ? 1 : 0))))
@ -1071,7 +1075,7 @@ void scheme_validate_expr(Mz_CPort *port, Scheme_Object *expr,
int q = SCHEME_LOCAL_POS(expr);
int p = q + delta;
if ((q < 0) || (p >= depth))
if ((q < 0) || (p >= depth) || (p < 0))
scheme_ill_formed_code(port);
if (SCHEME_GET_LOCAL_FLAGS(expr) != SCHEME_LOCAL_FLONUM)
@ -1128,8 +1132,9 @@ void scheme_validate_expr(Mz_CPort *port, Scheme_Object *expr,
no_flo(need_flonum, port);
if ((q < 0) || (p >= depth) || ((stack[p] != VALID_BOX)
&& (stack[p] != VALID_BOX_NOCLEAR)))
if ((q < 0) || (p >= depth) || (p < 0)
|| ((stack[p] != VALID_BOX)
&& (stack[p] != VALID_BOX_NOCLEAR)))
scheme_ill_formed_code(port);
if (SCHEME_GET_LOCAL_FLAGS(expr) == SCHEME_LOCAL_CLEAR_ON_READ) {
@ -1315,7 +1320,7 @@ void scheme_validate_expr(Mz_CPort *port, Scheme_Object *expr,
no_flo(need_flonum, port);
if ((c < 0) || (p < 0) || (d >= depth)
if ((c < 0) || (p < 0) || (d < 0) || (d >= depth)
|| (stack[d] != VALID_TOPLEVELS)
|| (p != num_toplevels)
|| (i >= num_stxes))
@ -1346,6 +1351,7 @@ void scheme_validate_expr(Mz_CPort *port, Scheme_Object *expr,
for (i = 0; i < c; i++, p++) {
if ((q < 0)
|| (p < 0)
|| (SCHEME_LET_AUTOBOX(lv) && ((p >= depth)
|| ((stack[p] != VALID_BOX)
&& (stack[p] != VALID_BOX_NOCLEAR))))