mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-01 12:20:26 +02:00
Attempt to mutate residualized literal pair throws exception
* libguile/validate.h (SCM_VALIDATE_MUTABLE_PAIR): * libguile/pairs.h (scm_is_mutable_pair): New internal definitions. * libguile/pairs.c (scm_set_car_x, scm_set_cdr_x): Validate mutable pairs. * libguile/alist.c (scm_assq_set_x, scm_assv_set_x, scm_assoc_set_x): * libguile/list.c (scm_reverse_x, scm_list_set_x, scm_list_cdr_set_x): * libguile/srcprop.c (scm_make_srcprops): * libguile/srfi-1.c (scm_srfi1_append_reverse_x) (scm_srfi1_delete_duplicates_x): * libguile/symbols.c (scm_symbol_fset_x, scm_symbol_pset_x): * libguile/sort.c (scm_merge_list_x): Use scm_set_car_x / scm_set_cdr_x instead of the macros, so as to check for mutable pairs. (SCM_VALIDATE_MUTABLE_LIST): New internal helper macro. (scm_sort_x, scm_stable_sort_x, scm_sort_list_x): Use SCM_VALIDATE_MUTABLE_LIST. * libguile/vm-engine.c (VM_VALIDATE_MUTABLE_PAIR): New definition. (set-car!, set-cdr!): Use VM_VALIDATE_MUTABLE_PAIR. Fix error message for set-cdr!.
This commit is contained in:
parent
d7778b3d6a
commit
6e573a0885
11 changed files with 63 additions and 21 deletions
|
@ -290,7 +290,7 @@ SCM_DEFINE (scm_assq_set_x, "assq-set!", 3, 0, 0,
|
||||||
handle = scm_sloppy_assq (key, alist);
|
handle = scm_sloppy_assq (key, alist);
|
||||||
if (scm_is_pair (handle))
|
if (scm_is_pair (handle))
|
||||||
{
|
{
|
||||||
SCM_SETCDR (handle, val);
|
scm_set_cdr_x (handle, val);
|
||||||
return alist;
|
return alist;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -308,7 +308,7 @@ SCM_DEFINE (scm_assv_set_x, "assv-set!", 3, 0, 0,
|
||||||
handle = scm_sloppy_assv (key, alist);
|
handle = scm_sloppy_assv (key, alist);
|
||||||
if (scm_is_pair (handle))
|
if (scm_is_pair (handle))
|
||||||
{
|
{
|
||||||
SCM_SETCDR (handle, val);
|
scm_set_cdr_x (handle, val);
|
||||||
return alist;
|
return alist;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -326,7 +326,7 @@ SCM_DEFINE (scm_assoc_set_x, "assoc-set!", 3, 0, 0,
|
||||||
handle = scm_sloppy_assoc (key, alist);
|
handle = scm_sloppy_assoc (key, alist);
|
||||||
if (scm_is_pair (handle))
|
if (scm_is_pair (handle))
|
||||||
{
|
{
|
||||||
SCM_SETCDR (handle, val);
|
scm_set_cdr_x (handle, val);
|
||||||
return alist;
|
return alist;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -391,14 +391,14 @@ SCM_DEFINE (scm_reverse_x, "reverse!", 1, 1, 0,
|
||||||
while (scm_is_pair (lst))
|
while (scm_is_pair (lst))
|
||||||
{
|
{
|
||||||
SCM old_tail = SCM_CDR (lst);
|
SCM old_tail = SCM_CDR (lst);
|
||||||
SCM_SETCDR (lst, tail);
|
scm_set_cdr_x (lst, tail);
|
||||||
tail = lst;
|
tail = lst;
|
||||||
lst = old_tail;
|
lst = old_tail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SCM_LIKELY (SCM_NULL_OR_NIL_P (lst)))
|
if (SCM_LIKELY (SCM_NULL_OR_NIL_P (lst)))
|
||||||
{
|
{
|
||||||
SCM_SETCDR (old_lst, new_tail);
|
scm_set_cdr_x (old_lst, new_tail);
|
||||||
return tail;
|
return tail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,7 +454,7 @@ SCM_DEFINE (scm_list_set_x, "list-set!", 3, 0, 0,
|
||||||
unsigned long int i = scm_to_ulong (k);
|
unsigned long int i = scm_to_ulong (k);
|
||||||
while (scm_is_pair (lst)) {
|
while (scm_is_pair (lst)) {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
SCM_SETCAR (lst, val);
|
scm_set_car_x (lst, val);
|
||||||
return val;
|
return val;
|
||||||
} else {
|
} else {
|
||||||
--i;
|
--i;
|
||||||
|
@ -500,7 +500,7 @@ SCM_DEFINE (scm_list_cdr_set_x, "list-cdr-set!", 3, 0, 0,
|
||||||
size_t i = scm_to_size_t (k);
|
size_t i = scm_to_size_t (k);
|
||||||
while (scm_is_pair (lst)) {
|
while (scm_is_pair (lst)) {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
SCM_SETCDR (lst, val);
|
scm_set_cdr_x (lst, val);
|
||||||
return val;
|
return val;
|
||||||
} else {
|
} else {
|
||||||
--i;
|
--i;
|
||||||
|
|
|
@ -91,7 +91,7 @@ SCM_DEFINE (scm_set_car_x, "set-car!", 2, 0, 0,
|
||||||
"by @code{set-car!} is unspecified.")
|
"by @code{set-car!} is unspecified.")
|
||||||
#define FUNC_NAME s_scm_set_car_x
|
#define FUNC_NAME s_scm_set_car_x
|
||||||
{
|
{
|
||||||
SCM_VALIDATE_CONS (1, pair);
|
SCM_VALIDATE_MUTABLE_PAIR (1, pair);
|
||||||
SCM_SETCAR (pair, value);
|
SCM_SETCAR (pair, value);
|
||||||
return SCM_UNSPECIFIED;
|
return SCM_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ SCM_DEFINE (scm_set_cdr_x, "set-cdr!", 2, 0, 0,
|
||||||
"by @code{set-cdr!} is unspecified.")
|
"by @code{set-cdr!} is unspecified.")
|
||||||
#define FUNC_NAME s_scm_set_cdr_x
|
#define FUNC_NAME s_scm_set_cdr_x
|
||||||
{
|
{
|
||||||
SCM_VALIDATE_CONS (1, pair);
|
SCM_VALIDATE_MUTABLE_PAIR (1, pair);
|
||||||
SCM_SETCDR (pair, value);
|
SCM_SETCDR (pair, value);
|
||||||
return SCM_UNSPECIFIED;
|
return SCM_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,6 +176,22 @@ scm_cdr (SCM x)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef BUILDING_LIBGUILE
|
||||||
|
static inline int
|
||||||
|
scm_is_mutable_pair (SCM x)
|
||||||
|
{
|
||||||
|
/* Guile embeds literal pairs into compiled object files. It's not
|
||||||
|
valid Scheme to mutate literal values. Two practical reasons to
|
||||||
|
enforce this restriction are to allow literals to share share
|
||||||
|
structure (pairs) with other literals in the compilation unit, and
|
||||||
|
to allow literals containing immediates to be allocated in the
|
||||||
|
read-only, shareable section of the file. Attempting to mutate a
|
||||||
|
pair in the read-only section would cause a segmentation fault, so
|
||||||
|
to avoid that, we really do need to enforce the restriction. */
|
||||||
|
return scm_is_pair (x) && GC_is_heap_ptr (SCM2PTR (x));
|
||||||
|
}
|
||||||
|
#endif /* BUILDING_LIBGUILE */
|
||||||
|
|
||||||
SCM_API SCM scm_cons2 (SCM w, SCM x, SCM y);
|
SCM_API SCM scm_cons2 (SCM w, SCM x, SCM y);
|
||||||
SCM_API SCM scm_pair_p (SCM x);
|
SCM_API SCM scm_pair_p (SCM x);
|
||||||
SCM_API SCM scm_set_car_x (SCM pair, SCM value);
|
SCM_API SCM scm_set_car_x (SCM pair, SCM value);
|
||||||
|
|
|
@ -306,22 +306,22 @@ scm_merge_list_x (SCM alist, SCM blist,
|
||||||
SCM_TICK;
|
SCM_TICK;
|
||||||
if (scm_is_true (scm_call_2 (less, SCM_CAR (blist), SCM_CAR (alist))))
|
if (scm_is_true (scm_call_2 (less, SCM_CAR (blist), SCM_CAR (alist))))
|
||||||
{
|
{
|
||||||
SCM_SETCDR (last, blist);
|
scm_set_cdr_x (last, blist);
|
||||||
blist = SCM_CDR (blist);
|
blist = SCM_CDR (blist);
|
||||||
blen--;
|
blen--;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SCM_SETCDR (last, alist);
|
scm_set_cdr_x (last, alist);
|
||||||
alist = SCM_CDR (alist);
|
alist = SCM_CDR (alist);
|
||||||
alen--;
|
alen--;
|
||||||
}
|
}
|
||||||
last = SCM_CDR (last);
|
last = SCM_CDR (last);
|
||||||
}
|
}
|
||||||
if ((alen > 0) && (blen == 0))
|
if ((alen > 0) && (blen == 0))
|
||||||
SCM_SETCDR (last, alist);
|
scm_set_cdr_x (last, alist);
|
||||||
else if ((alen == 0) && (blen > 0))
|
else if ((alen == 0) && (blen > 0))
|
||||||
SCM_SETCDR (last, blist);
|
scm_set_cdr_x (last, blist);
|
||||||
}
|
}
|
||||||
return build;
|
return build;
|
||||||
} /* scm_merge_list_x */
|
} /* scm_merge_list_x */
|
||||||
|
@ -398,6 +398,14 @@ scm_merge_list_step (SCM * seq, SCM less, long n)
|
||||||
} /* scm_merge_list_step */
|
} /* scm_merge_list_step */
|
||||||
|
|
||||||
|
|
||||||
|
#define SCM_VALIDATE_MUTABLE_LIST(pos, lst) \
|
||||||
|
do { \
|
||||||
|
SCM walk; \
|
||||||
|
for (walk = lst; !scm_is_null_or_nil (walk); walk = SCM_CDR (walk)) \
|
||||||
|
SCM_VALIDATE_MUTABLE_PAIR (pos, walk); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
SCM_DEFINE (scm_sort_x, "sort!", 2, 0, 0,
|
SCM_DEFINE (scm_sort_x, "sort!", 2, 0, 0,
|
||||||
(SCM items, SCM less),
|
(SCM items, SCM less),
|
||||||
"Sort the sequence @var{items}, which may be a list or a\n"
|
"Sort the sequence @var{items}, which may be a list or a\n"
|
||||||
|
@ -414,6 +422,7 @@ SCM_DEFINE (scm_sort_x, "sort!", 2, 0, 0,
|
||||||
if (scm_is_pair (items))
|
if (scm_is_pair (items))
|
||||||
{
|
{
|
||||||
SCM_VALIDATE_LIST_COPYLEN (1, items, len);
|
SCM_VALIDATE_LIST_COPYLEN (1, items, len);
|
||||||
|
SCM_VALIDATE_MUTABLE_LIST (1, items);
|
||||||
return scm_merge_list_step (&items, less, len);
|
return scm_merge_list_step (&items, less, len);
|
||||||
}
|
}
|
||||||
else if (scm_is_array (items) && scm_c_array_rank (items) == 1)
|
else if (scm_is_array (items) && scm_c_array_rank (items) == 1)
|
||||||
|
@ -533,6 +542,7 @@ SCM_DEFINE (scm_stable_sort_x, "stable-sort!", 2, 0, 0,
|
||||||
if (scm_is_pair (items))
|
if (scm_is_pair (items))
|
||||||
{
|
{
|
||||||
SCM_VALIDATE_LIST_COPYLEN (1, items, len);
|
SCM_VALIDATE_LIST_COPYLEN (1, items, len);
|
||||||
|
SCM_VALIDATE_MUTABLE_LIST (1, items);
|
||||||
return scm_merge_list_step (&items, less, len);
|
return scm_merge_list_step (&items, less, len);
|
||||||
}
|
}
|
||||||
else if (scm_is_array (items) && 1 == scm_c_array_rank (items))
|
else if (scm_is_array (items) && 1 == scm_c_array_rank (items))
|
||||||
|
@ -596,6 +606,8 @@ SCM_DEFINE (scm_sort_list_x, "sort-list!", 2, 0, 0,
|
||||||
long len;
|
long len;
|
||||||
|
|
||||||
SCM_VALIDATE_LIST_COPYLEN (1, items, len);
|
SCM_VALIDATE_LIST_COPYLEN (1, items, len);
|
||||||
|
SCM_VALIDATE_MUTABLE_LIST (1, items);
|
||||||
|
|
||||||
return scm_merge_list_step (&items, less, len);
|
return scm_merge_list_step (&items, less, len);
|
||||||
}
|
}
|
||||||
#undef FUNC_NAME
|
#undef FUNC_NAME
|
||||||
|
|
|
@ -143,7 +143,7 @@ scm_make_srcprops (long line, int col, SCM filename, SCM copy, SCM alist)
|
||||||
{
|
{
|
||||||
alist = scm_acons (scm_sym_filename, filename, alist);
|
alist = scm_acons (scm_sym_filename, filename, alist);
|
||||||
if (scm_is_null (old_alist))
|
if (scm_is_null (old_alist))
|
||||||
SCM_SETCDR (scm_last_alist_filename, alist);
|
scm_set_cdr_x (scm_last_alist_filename, alist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,7 @@ SCM_DEFINE (scm_srfi1_append_reverse_x, "append-reverse!", 2, 0, 0,
|
||||||
{
|
{
|
||||||
SCM newtail;
|
SCM newtail;
|
||||||
|
|
||||||
while (scm_is_pair (revhead))
|
while (scm_is_mutable_pair (revhead))
|
||||||
{
|
{
|
||||||
/* take the first cons cell from revhead */
|
/* take the first cons cell from revhead */
|
||||||
newtail = revhead;
|
newtail = revhead;
|
||||||
|
@ -548,7 +548,7 @@ SCM_DEFINE (scm_srfi1_delete_duplicates_x, "delete-duplicates!", 1, 1, 0,
|
||||||
if (scm_is_eq (l, endret))
|
if (scm_is_eq (l, endret))
|
||||||
{
|
{
|
||||||
/* not equal to any, so append this pair */
|
/* not equal to any, so append this pair */
|
||||||
SCM_SETCDR (endret, lst);
|
scm_set_cdr_x (endret, lst);
|
||||||
endret = lst;
|
endret = lst;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -557,7 +557,7 @@ SCM_DEFINE (scm_srfi1_delete_duplicates_x, "delete-duplicates!", 1, 1, 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* terminate, in case last element was deleted */
|
/* terminate, in case last element was deleted */
|
||||||
SCM_SETCDR (endret, SCM_EOL);
|
scm_set_cdr_x (endret, SCM_EOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* demand that lst was a proper list */
|
/* demand that lst was a proper list */
|
||||||
|
|
|
@ -449,7 +449,7 @@ SCM_DEFINE (scm_symbol_fset_x, "symbol-fset!", 2, 0, 0,
|
||||||
#define FUNC_NAME s_scm_symbol_fset_x
|
#define FUNC_NAME s_scm_symbol_fset_x
|
||||||
{
|
{
|
||||||
SCM_VALIDATE_SYMBOL (1, s);
|
SCM_VALIDATE_SYMBOL (1, s);
|
||||||
SCM_SETCAR (SCM_CELL_OBJECT_3 (s), val);
|
scm_set_car_x (SCM_CELL_OBJECT_3 (s), val);
|
||||||
return SCM_UNSPECIFIED;
|
return SCM_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
#undef FUNC_NAME
|
#undef FUNC_NAME
|
||||||
|
@ -461,7 +461,7 @@ SCM_DEFINE (scm_symbol_pset_x, "symbol-pset!", 2, 0, 0,
|
||||||
#define FUNC_NAME s_scm_symbol_pset_x
|
#define FUNC_NAME s_scm_symbol_pset_x
|
||||||
{
|
{
|
||||||
SCM_VALIDATE_SYMBOL (1, s);
|
SCM_VALIDATE_SYMBOL (1, s);
|
||||||
SCM_SETCDR (SCM_CELL_OBJECT_3 (s), val);
|
scm_set_cdr_x (SCM_CELL_OBJECT_3 (s), val);
|
||||||
return SCM_UNSPECIFIED;
|
return SCM_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
#undef FUNC_NAME
|
#undef FUNC_NAME
|
||||||
|
|
|
@ -240,6 +240,11 @@
|
||||||
#define SCM_VALIDATE_CONS(pos, scm) \
|
#define SCM_VALIDATE_CONS(pos, scm) \
|
||||||
SCM_I_MAKE_VALIDATE_MSG2 (pos, scm, scm_is_pair, "pair")
|
SCM_I_MAKE_VALIDATE_MSG2 (pos, scm, scm_is_pair, "pair")
|
||||||
|
|
||||||
|
#ifdef BUILDING_LIBGUILE
|
||||||
|
#define SCM_VALIDATE_MUTABLE_PAIR(pos, scm) \
|
||||||
|
SCM_I_MAKE_VALIDATE_MSG2 (pos, scm, scm_is_mutable_pair, "mutable pair")
|
||||||
|
#endif /* BUILDING_LIBGUILE */
|
||||||
|
|
||||||
#define SCM_VALIDATE_LIST(pos, lst) \
|
#define SCM_VALIDATE_LIST(pos, lst) \
|
||||||
do { \
|
do { \
|
||||||
SCM_ASSERT (scm_ilength (lst) >= 0, lst, pos, FUNC_NAME); \
|
SCM_ASSERT (scm_ilength (lst) >= 0, lst, pos, FUNC_NAME); \
|
||||||
|
|
|
@ -424,6 +424,8 @@
|
||||||
VM_VALIDATE (x, SCM_CHARP, proc, char)
|
VM_VALIDATE (x, SCM_CHARP, proc, char)
|
||||||
#define VM_VALIDATE_PAIR(x, proc) \
|
#define VM_VALIDATE_PAIR(x, proc) \
|
||||||
VM_VALIDATE (x, scm_is_pair, proc, pair)
|
VM_VALIDATE (x, scm_is_pair, proc, pair)
|
||||||
|
#define VM_VALIDATE_MUTABLE_PAIR(x, proc) \
|
||||||
|
VM_VALIDATE (x, scm_is_mutable_pair, proc, mutable_pair)
|
||||||
#define VM_VALIDATE_STRING(obj, proc) \
|
#define VM_VALIDATE_STRING(obj, proc) \
|
||||||
VM_VALIDATE (obj, scm_is_string, proc, string)
|
VM_VALIDATE (obj, scm_is_string, proc, string)
|
||||||
#define VM_VALIDATE_STRUCT(obj, proc) \
|
#define VM_VALIDATE_STRUCT(obj, proc) \
|
||||||
|
@ -2359,7 +2361,7 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
|
||||||
UNPACK_12_12 (op, a, b);
|
UNPACK_12_12 (op, a, b);
|
||||||
x = SP_REF (a);
|
x = SP_REF (a);
|
||||||
y = SP_REF (b);
|
y = SP_REF (b);
|
||||||
VM_VALIDATE_PAIR (x, "set-car!");
|
VM_VALIDATE_MUTABLE_PAIR (x, "set-car!");
|
||||||
SCM_SETCAR (x, y);
|
SCM_SETCAR (x, y);
|
||||||
NEXT (1);
|
NEXT (1);
|
||||||
}
|
}
|
||||||
|
@ -2375,7 +2377,7 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp,
|
||||||
UNPACK_12_12 (op, a, b);
|
UNPACK_12_12 (op, a, b);
|
||||||
x = SP_REF (a);
|
x = SP_REF (a);
|
||||||
y = SP_REF (b);
|
y = SP_REF (b);
|
||||||
VM_VALIDATE_PAIR (x, "set-car!");
|
VM_VALIDATE_MUTABLE_PAIR (x, "set-cdr!");
|
||||||
SCM_SETCDR (x, y);
|
SCM_SETCDR (x, y);
|
||||||
NEXT (1);
|
NEXT (1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -429,6 +429,7 @@ static void vm_error_wrong_num_args (SCM proc) SCM_NORETURN SCM_NOINLINE;
|
||||||
static void vm_error_wrong_type_apply (SCM proc) SCM_NORETURN SCM_NOINLINE;
|
static void vm_error_wrong_type_apply (SCM proc) SCM_NORETURN SCM_NOINLINE;
|
||||||
static void vm_error_not_a_char (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
|
static void vm_error_not_a_char (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
|
||||||
static void vm_error_not_a_pair (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
|
static void vm_error_not_a_pair (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
|
||||||
|
static void vm_error_not_a_mutable_pair (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
|
||||||
static void vm_error_not_a_string (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
|
static void vm_error_not_a_string (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
|
||||||
static void vm_error_not_a_atomic_box (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
|
static void vm_error_not_a_atomic_box (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
|
||||||
static void vm_error_not_a_bytevector (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
|
static void vm_error_not_a_bytevector (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
|
||||||
|
@ -527,6 +528,12 @@ vm_error_not_a_pair (const char *subr, SCM x)
|
||||||
scm_wrong_type_arg_msg (subr, 1, x, "pair");
|
scm_wrong_type_arg_msg (subr, 1, x, "pair");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vm_error_not_a_mutable_pair (const char *subr, SCM x)
|
||||||
|
{
|
||||||
|
scm_wrong_type_arg_msg (subr, 1, x, "mutable pair");
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vm_error_not_a_string (const char *subr, SCM x)
|
vm_error_not_a_string (const char *subr, SCM x)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue