Fix segfault on accessing non-present impersonator properties of property-only vector chaperones

Additionally this adds macros that distinguish between the chaperone redirects of prop-only vector
chaperones, function chaperones, and structure chaperones since each of these may store a vector
in the redirects field.
This commit is contained in:
Daniel Feltey 2017-06-15 15:05:56 -05:00
parent d3787775f1
commit 87e4bdbec8
7 changed files with 81 additions and 25 deletions

View File

@ -223,6 +223,65 @@
(define-values (a b c) (vector->values b2))
(test '(1 2 3) list a b c)))
(define unsafe-chaperone-vector-name "unsafe-chaperone-vector")
(define unsafe-impersonate-vector-name "unsafe-impersonate-vector")
(define chaperone-vector*-name "chaperone-vector*")
(define impersonate-vector*-name "impersonate-vector*")
(define chaperone-vector-name "chaperone-vector")
(define impersonate-vector-name "impersonate-vector")
;; properties and chaperones
(as-chaperone-or-impersonator
([chaperone-vector impersonate-vector]
[chaperone-vector* impersonate-vector*]
[unsafe-chaperone-vector unsafe-impersonate-vector])
(let ()
(define-values (p1 has1 get1) (make-impersonator-property 'p1))
(define-values (p2 has2 get2) (make-impersonator-property 'p2))
(define v (vector 1 2 3))
(define u (vector 7 8 9))
(define red (lambda (v i x) x))
(define red* (lambda (c v i x) x))
(define v1 (chaperone-vector v #f #f))
(define v2 (chaperone-vector* v #f #f))
(define v3 (unsafe-chaperone-vector v u))
(define v4 (chaperone-vector v #f #f p2 5))
(define v5 (chaperone-vector* v #f #f p2 5))
(define v6 (unsafe-chaperone-vector v u p2 5))
(define v7 (chaperone-vector v red red))
(define v8 (chaperone-vector* v red* red*))
(define v9 (chaperone-vector v red red p2 5))
(define v10 (chaperone-vector* v red* red* p2 5))
(test 5 get2 v4)
(test 5 get2 v5)
(test 5 get2 v6)
(test 5 get2 v9)
(test 5 get2 v10)
(define handler
(lambda (exn)
(test #t
regexp-match?
"p1-accessor: contract violation"
(exn-message exn))))
(err/rt-test (get1 v1) handler)
(err/rt-test (get1 v2) handler)
(err/rt-test (get1 v3) handler)
(err/rt-test (get1 v4) handler)
(err/rt-test (get1 v5) handler)
(err/rt-test (get1 v6) handler)
(err/rt-test (get1 v7) handler)
(err/rt-test (get1 v8) handler)
(err/rt-test (get1 v9) handler)
(err/rt-test (get1 v10) handler)))
;; check property-only chaperones
(as-chaperone-or-impersonator
([chaperone-vector impersonate-vector chaperone-vector* impersonate-vector*]
@ -686,9 +745,6 @@
(test '(set p1-prop p2-prop) unbox b)
(test 17 vector-ref c2 1))
(define unsafe-chaperone-vector-name "unsafe-chaperone-vector")
(define unsafe-impersonate-vector-name "unsafe-impersonate-vector")
(as-chaperone-or-impersonator
([chaperone-vector impersonate-vector]
[chaperone-vector* impersonate-vector*]

View File

@ -3084,8 +3084,7 @@ scheme_do_eval(Scheme_Object *obj, int num_rands, Scheme_Object **rands,
the chaperone may guard access to the function as a field inside
the struct. We'll need to keep track of the original object
as we unwrap to discover procedure chaperones. */
&& (SCHEME_VECTORP(((Scheme_Chaperone *)obj)->redirects))
&& !(SCHEME_VEC_SIZE(((Scheme_Chaperone *)obj)->redirects) & 1))
&& SCHEME_REDIRECTS_STRUCTP(((Scheme_Chaperone *) obj)->redirects))
/* A raw pair is from scheme_apply_chaperone(), propagating the
original object for an applicable structure. */
|| (type == scheme_raw_pair_type)) {
@ -3150,8 +3149,7 @@ scheme_do_eval(Scheme_Object *obj, int num_rands, Scheme_Object **rands,
goto apply_top;
} else {
if (SCHEME_VECTORP(((Scheme_Chaperone *)obj)->redirects)
&& !(SCHEME_VEC_SIZE(((Scheme_Chaperone *)obj)->redirects) & 1))
if (SCHEME_REDIRECTS_STRUCTP(((Scheme_Chaperone *)obj)->redirects))
obj = ((Scheme_Chaperone *)obj)->prev;
else if (SAME_TYPE(SCHEME_TYPE(((Scheme_Chaperone *)obj)->redirects), scheme_nack_guard_evt_type))
/* Chaperone is for evt, not function arguments */

View File

@ -3631,7 +3631,7 @@ static Scheme_Object *do_chaperone_procedure(const char *name, const char *whati
to pass the self proc along. */
for (val = px->prev; SCHEME_P_CHAPERONEP(val); val = ((Scheme_Chaperone *)val)->prev) {
px2 = (Scheme_Chaperone *)val;
if (SCHEME_VECTORP(px2->redirects) && (SCHEME_VEC_SIZE(px2->redirects) & 0x1)) {
if (SCHEME_REDIRECTS_PROCEDUREP(px2->redirects)) {
if ((SCHEME_VEC_SIZE(px2->redirects) > 3)
|| SCHEME_IMMUTABLEP(px2->redirects))
SCHEME_SET_IMMUTABLE(px->redirects);

View File

@ -60,8 +60,7 @@ Scheme_Object *PRIM_APPLY_NAME(Scheme_Object *rator,
t = _SCHEME_TYPE(rator);
if ((t == scheme_proc_chaperone_type)
&& SCHEME_VECTORP(((Scheme_Chaperone *)rator)->redirects)
&& (SCHEME_VEC_SIZE(((Scheme_Chaperone *)rator)->redirects) & 0x1)
&& SCHEME_REDIRECTS_PROCEDUREP((((Scheme_Chaperone *)rator)->redirects))
&& (SCHEME_CHAPERONE_FLAGS((Scheme_Chaperone *)rator) == SCHEME_PROC_CHAPERONE_CALL_DIRECT)) {
if (SCHEME_FALSEP(SCHEME_VEC_ELS(((Scheme_Chaperone *)rator)->redirects)[1])
|| SCHEME_INT_VAL(SCHEME_VEC_ELS(((Scheme_Chaperone *)rator)->redirects)[1]) == argc) {

View File

@ -1170,6 +1170,15 @@ so we can safely reuse the bit.
#define SCHEME_P_CHAPERONEP(obj) (SAME_TYPE(SCHEME_TYPE(obj), scheme_proc_chaperone_type))
#define SCHEME_NP_CHAPERONEP(obj) (SAME_TYPE(SCHEME_TYPE(obj), scheme_chaperone_type))
/* Does the shape of the redirects field match the pattern for particular chaperone types */
#define SCHEME_REDIRECTS_PROCEDUREP(red) (SCHEME_VECTORP(red) \
&& (SCHEME_VEC_SIZE(red) & 1))
#define SCHEME_REDIRECTS_STRUCTP(red) (SCHEME_VECTORP(red) \
&& SCHEME_VEC_SIZE(red) \
&& !(SCHEME_VEC_SIZE(red) & 1))
#define SCHEME_REDIRECTS_PROP_ONLY_VECTORP(red) (SCHEME_VECTORP(red) \
&& !(SCHEME_VEC_SIZE(red)))
#define SCHEME_CHAPERONE_VECTORP(obj) (SCHEME_VECTORP(obj) \
|| (SCHEME_NP_CHAPERONEP(obj) && SCHEME_VECTORP(SCHEME_CHAPERONE_VAL(obj))))
#define SCHEME_CHAPERONE_BOXP(obj) (SCHEME_BOXP(obj) \

View File

@ -1182,9 +1182,8 @@ static Scheme_Object *do_chaperone_prop_accessor(const char *who, Scheme_Object
return v;
}
if (!SCHEME_VECTORP(px->redirects)
|| (SCHEME_VEC_SIZE(px->redirects) & 1)
|| SCHEME_FALSEP(SCHEME_VEC_ELS(px->redirects)[0]))
if (!SCHEME_REDIRECTS_STRUCTP(px->redirects)
|| SCHEME_FALSEP(SCHEME_VEC_ELS(px->redirects)[0]))
arg = px->prev;
else {
ht = (Scheme_Hash_Tree *)SCHEME_VEC_ELS(px->redirects)[0];
@ -2253,8 +2252,7 @@ static Scheme_Object *chaperone_struct_ref(const char *who, Scheme_Object *prim,
Scheme_Chaperone *px = (Scheme_Chaperone *)o;
Scheme_Object *a[2], *red, *orig;
if (SCHEME_VECTORP(px->redirects)
&& !(SCHEME_VEC_SIZE(px->redirects) & 1)
if (SCHEME_REDIRECTS_STRUCTP(px->redirects)
&& SAME_OBJ(SCHEME_VEC_ELS(px->redirects)[1], scheme_undefined)) {
/* chaperone on every field: check that result is not undefined */
o = px->prev;
@ -2269,8 +2267,7 @@ static Scheme_Object *chaperone_struct_ref(const char *who, Scheme_Object *prim,
}
return orig;
} else if (!SCHEME_VECTORP(px->redirects)
|| (SCHEME_VEC_SIZE(px->redirects) & 1)
} else if (!SCHEME_REDIRECTS_STRUCTP(px->redirects)
|| SCHEME_FALSEP(SCHEME_VEC_ELS(px->redirects)[PRE_REDIRECTS + i])) {
o = px->prev;
} else {
@ -2385,8 +2382,7 @@ static void chaperone_struct_set(const char *who, Scheme_Object *prim,
int half;
o = px->prev;
if (SCHEME_VECTORP(px->redirects)
&& !(SCHEME_VEC_SIZE(px->redirects) & 1)
if (SCHEME_REDIRECTS_STRUCTP(px->redirects)
&& !SAME_OBJ(SCHEME_VEC_ELS(px->redirects)[1], scheme_undefined)) {
half = (SCHEME_VEC_SIZE(px->redirects) - PRE_REDIRECTS) >> 1;
red = SCHEME_VEC_ELS(px->redirects)[PRE_REDIRECTS + half + i];
@ -2425,8 +2421,7 @@ static void chaperone_struct_set(const char *who, Scheme_Object *prim,
return;
}
}
} else if (SCHEME_VECTORP(px->redirects)
&& !(SCHEME_VEC_SIZE(px->redirects) & 1)
} else if (SCHEME_REDIRECTS_STRUCTP(px->redirects)
&& SAME_OBJ(SCHEME_VEC_ELS(px->redirects)[1], scheme_undefined)) {
/* chaperone on every field: check that current value is not undefined
--- unless check is disabled by a mark (bit it's faster to check
@ -2996,8 +2991,7 @@ static Scheme_Object *struct_info_chaperone(Scheme_Object *o, Scheme_Object *si,
while (SCHEME_CHAPERONEP(o)) {
px = (Scheme_Chaperone *)o;
if (SCHEME_VECTORP(px->redirects)
&& !(SCHEME_VEC_SIZE(px->redirects) & 1)) {
if (SCHEME_REDIRECTS_STRUCTP(px->redirects)) {
proc = SCHEME_VEC_ELS(px->redirects)[1];
if (SCHEME_TRUEP(proc) && !SAME_OBJ(proc, scheme_undefined)) {
if (SCHEME_CHAPERONE_FLAGS(px) & SCHEME_CHAPERONE_IS_IMPERSONATOR)

View File

@ -499,7 +499,7 @@ Scheme_Object *scheme_chaperone_vector_ref2(Scheme_Object *o, int i, Scheme_Obje
orig = scheme_chaperone_vector_ref2(px->prev, i, outermost);
if (SCHEME_VECTORP(px->redirects)) {
if (SCHEME_REDIRECTS_PROP_ONLY_VECTORP(px->redirects)) {
/* chaperone was on property accessors */
/* or vector chaperone is property only */
return orig;
@ -580,7 +580,7 @@ void scheme_chaperone_vector_set(Scheme_Object *o, int i, Scheme_Object *v)
o = px->prev;
if (!SCHEME_VECTORP(red)) {
if (!SCHEME_REDIRECTS_PROP_ONLY_VECTORP(red)) {
/* not a property only chaperone */
red = SCHEME_CDR(px->redirects);