зеркало из https://github.com/github/ruby.git
Make expandarray compaction safe
The expandarray instruction can allocate an array, which can trigger a GC compaction. However, since it does not increment the sp until the end of the instruction, the objects it places on the stack are not marked or reference updated by the GC, which can cause the objects to move which leaves broken or incorrect objects on the stack. This commit changes the instruction to be handles_sp so the sp is incremented inside of the instruction right after the object is written on the stack.
This commit is contained in:
Родитель
492c82cb41
Коммит
0aed37b973
|
@ -498,10 +498,11 @@ expandarray
|
||||||
(rb_num_t num, rb_num_t flag)
|
(rb_num_t num, rb_num_t flag)
|
||||||
(..., VALUE ary)
|
(..., VALUE ary)
|
||||||
(...)
|
(...)
|
||||||
|
// attr bool handles_sp = true;
|
||||||
// attr bool leaf = false; /* has rb_check_array_type() */
|
// attr bool leaf = false; /* has rb_check_array_type() */
|
||||||
// attr rb_snum_t sp_inc = (rb_snum_t)num - 1 + (flag & 1 ? 1 : 0);
|
// attr rb_snum_t sp_inc = (rb_snum_t)num - 1 + (flag & 1 ? 1 : 0);
|
||||||
{
|
{
|
||||||
vm_expandarray(GET_SP(), ary, num, (int)flag);
|
vm_expandarray(GET_CFP(), ary, num, (int)flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* concat two arrays */
|
/* concat two arrays */
|
||||||
|
|
|
@ -1866,11 +1866,9 @@ rb_vm_throw(const rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, rb_nu
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
vm_expandarray(VALUE *sp, VALUE ary, rb_num_t num, int flag)
|
vm_expandarray(struct rb_control_frame_struct *cfp, VALUE ary, rb_num_t num, int flag)
|
||||||
{
|
{
|
||||||
int is_splat = flag & 0x01;
|
int is_splat = flag & 0x01;
|
||||||
rb_num_t space_size = num + is_splat;
|
|
||||||
VALUE *base = sp - 1;
|
|
||||||
const VALUE *ptr;
|
const VALUE *ptr;
|
||||||
rb_num_t len;
|
rb_num_t len;
|
||||||
const VALUE obj = ary;
|
const VALUE obj = ary;
|
||||||
|
@ -1885,7 +1883,7 @@ vm_expandarray(VALUE *sp, VALUE ary, rb_num_t num, int flag)
|
||||||
len = (rb_num_t)RARRAY_LEN(ary);
|
len = (rb_num_t)RARRAY_LEN(ary);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (space_size == 0) {
|
if (num + is_splat == 0) {
|
||||||
/* no space left on stack */
|
/* no space left on stack */
|
||||||
}
|
}
|
||||||
else if (flag & 0x02) {
|
else if (flag & 0x02) {
|
||||||
|
@ -1894,40 +1892,47 @@ vm_expandarray(VALUE *sp, VALUE ary, rb_num_t num, int flag)
|
||||||
|
|
||||||
if (len < num) {
|
if (len < num) {
|
||||||
for (i = 0; i < num - len; i++) {
|
for (i = 0; i < num - len; i++) {
|
||||||
*base++ = Qnil;
|
*cfp->sp++ = Qnil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; i < num; i++, j++) {
|
for (j = 0; i < num; i++, j++) {
|
||||||
VALUE v = ptr[len - j - 1];
|
VALUE v = ptr[len - j - 1];
|
||||||
*base++ = v;
|
*cfp->sp++ = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_splat) {
|
if (is_splat) {
|
||||||
*base = rb_ary_new4(len - j, ptr);
|
*cfp->sp++ = rb_ary_new4(len - j, ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* normal: ary[num..-1], ary[num-2], ary[num-3], ..., ary[0] # top */
|
/* normal: ary[num..-1], ary[num-2], ary[num-3], ..., ary[0] # top */
|
||||||
rb_num_t i;
|
|
||||||
VALUE *bptr = &base[space_size - 1];
|
|
||||||
|
|
||||||
for (i=0; i<num; i++) {
|
|
||||||
if (len <= i) {
|
|
||||||
for (; i<num; i++) {
|
|
||||||
*bptr-- = Qnil;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*bptr-- = ptr[i];
|
|
||||||
}
|
|
||||||
if (is_splat) {
|
if (is_splat) {
|
||||||
if (num > len) {
|
if (num > len) {
|
||||||
*bptr = rb_ary_new();
|
*cfp->sp++ = rb_ary_new();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
*bptr = rb_ary_new4(len - num, ptr + num);
|
*cfp->sp++ = rb_ary_new4(len - num, ptr + num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num > len) {
|
||||||
|
rb_num_t i = 0;
|
||||||
|
for (; i < num - len; i++) {
|
||||||
|
*cfp->sp++ = Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (rb_num_t j = 0; i < num; i++, j++) {
|
||||||
|
*cfp->sp++ = ptr[len - j - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (rb_num_t j = 0; j < num; j++) {
|
||||||
|
*cfp->sp++ = ptr[num - j - 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RB_GC_GUARD(ary);
|
RB_GC_GUARD(ary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче