From 1d3fe10d3dd6b688ccf39c18e7f330c172799faf Mon Sep 17 00:00:00 2001 From: Sam Tobin-Hochstadt Date: Wed, 28 Oct 2015 11:31:32 -0400 Subject: [PATCH] Ensure that the closure_map is big enough when deserializing. Also document more invariants about the closure representation, and avoid some code duplication. Fixes #1108 (caught by fuzz testing). --- racket/src/racket/src/marshal.c | 7 ++++++- racket/src/racket/src/resolve.c | 2 +- racket/src/racket/src/schpriv.h | 12 +++++++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/racket/src/racket/src/marshal.c b/racket/src/racket/src/marshal.c index 44e7b7573d..a7ae4cddcb 100644 --- a/racket/src/racket/src/marshal.c +++ b/racket/src/racket/src/marshal.c @@ -792,7 +792,7 @@ static Scheme_Object *write_compiled_closure(Scheme_Object *obj) svec_size = data->closure_size; if (SCHEME_CLOSURE_DATA_FLAGS(data) & CLOS_HAS_TYPED_ARGS) { - svec_size += ((CLOS_TYPE_BITS_PER_ARG * (data->num_params + data->closure_size)) + BITS_PER_MZSHORT - 1) / BITS_PER_MZSHORT; + svec_size += boxmap_size(data->num_params + data->closure_size); { int k, mv; for (k = data->num_params + data->closure_size; --k; ) { @@ -1014,6 +1014,11 @@ static Scheme_Object *read_compiled_closure(Scheme_Object *obj) if (!(SCHEME_CLOSURE_DATA_FLAGS(data) & CLOS_HAS_TYPED_ARGS)) data->closure_size = SCHEME_SVEC_LEN(v); + + if ((SCHEME_CLOSURE_DATA_FLAGS(data) & CLOS_HAS_TYPED_ARGS)) + if (data->closure_size + boxmap_size(data->closure_size + data->num_params) != SCHEME_SVEC_LEN(v)) + return NULL; + data->closure_map = SCHEME_SVEC_VEC(v); /* If the closure is empty, create the closure now */ diff --git a/racket/src/racket/src/resolve.c b/racket/src/racket/src/resolve.c index 45b6031e3a..f1bd0fea3b 100644 --- a/racket/src/racket/src/resolve.c +++ b/racket/src/racket/src/resolve.c @@ -1683,7 +1683,7 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) /* closures */ /*========================================================================*/ -XFORM_NONGCING static int boxmap_size(int n) +XFORM_NONGCING int boxmap_size(int n) { return ((CLOS_TYPE_BITS_PER_ARG * n) + (BITS_PER_MZSHORT - 1)) / BITS_PER_MZSHORT; } diff --git a/racket/src/racket/src/schpriv.h b/racket/src/racket/src/schpriv.h index a4a2fcd96f..8da3285bec 100644 --- a/racket/src/racket/src/schpriv.h +++ b/racket/src/racket/src/schpriv.h @@ -2709,9 +2709,14 @@ typedef struct Scheme_Closure_Data Scheme_Inclhash_Object iso; /* keyex used for flags */ mzshort num_params; /* includes collecting arg if has_rest */ mzshort max_let_depth; - mzshort closure_size; - mzshort *closure_map; /* actually a Closure_Info* until resolved; if CLOS_HAS_TYPED_ARGS, - followed by bit array with CLOS_TYPE_BITS_PER_ARG bits per args then per closed-over */ + mzshort closure_size; /* the number of closed-over variables */ + mzshort *closure_map; /* actually a Closure_Info* until resolved; + contains closure_size elements mapping closed-over var to stack positions. + + If CLOS_HAS_TYPED_ARGS, that array is followed by bit array with + CLOS_TYPE_BITS_PER_ARG bits per args then per closed-over + + total size = closure_size + (closure_size + num_params) * CLOS_TYPE_BITS_PER_ARG */ Scheme_Object *code; Scheme_Object *name; /* name or (vector name src line col pos span generated?) */ void *tl_map; /* fixnum or bit array (as array of `int's) indicating which globals+lifts in prefix are used */ @@ -2732,6 +2737,7 @@ typedef struct Scheme_Closure_Data XFORM_NONGCING void scheme_boxmap_set(mzshort *boxmap, int j, int bit, int delta); XFORM_NONGCING int scheme_boxmap_get(mzshort *boxmap, int j, int delta); +XFORM_NONGCING int boxmap_size(int n); int scheme_has_method_property(Scheme_Object *code);