diff --git a/src/array.c b/src/array.c index 067d5658eb1132b71dd30de673502cb51f8c568e..70da9c02576c2dea7da021a81b7cda004e5fa867 100644 --- a/src/array.c +++ b/src/array.c @@ -448,6 +448,7 @@ void o_append_array(INT32 args) { struct svalue *lval = Pike_sp - args; struct svalue *val = lval + 2; + int lval_type; #ifdef PIKE_DEBUG if (args < 3) { Pike_fatal("Too few arguments to o_append_array(): %d\n", args); @@ -455,7 +456,7 @@ void o_append_array(INT32 args) #endif args -= 3; /* Note: val should always be a zero here! */ - lvalue_to_svalue_no_free(val, lval); + lval_type = lvalue_to_svalue_no_free(val, lval); if (TYPEOF(*val) == T_ARRAY) { struct svalue tmp; @@ -464,10 +465,15 @@ void o_append_array(INT32 args) element and do not do the assign. This can be done because the lvalue already has the array as it's value. */ - if( v->refs == 2 ) - { - if( v->real_item+v->malloced_size >= v->item+v->size+args ) - { + if( (v->refs == 2) && (lval_type != PIKE_T_GET_SET) ) { + if ((TYPEOF(*lval) == T_OBJECT) && + lval->u.object->prog && + ((FIND_LFUN(lval->u.object->prog, LFUN_ASSIGN_INDEX) >= 0) || + (FIND_LFUN(lval->u.object->prog, LFUN_ASSIGN_ARROW) >= 0))) { + /* There's a function controlling assignments in this object, + * so we can't alter the array in place. + */ + } else if( v->real_item+v->malloced_size >= v->item+v->size+args ) { struct svalue *from = val+1; int i; for( i = 0; i<args; i++,from++ ) diff --git a/src/testsuite.in b/src/testsuite.in index 91009427aa3ef54fdb466b9efd909c8f8f40a1d3..e8ac2a877435fa402da2ee55184b14ce985b6454 100644 --- a/src/testsuite.in +++ b/src/testsuite.in @@ -4112,6 +4112,52 @@ test_any([[ return has_index(a->_modified, "foo"); ]], 1) +test_any([[ + // Since the addition of F_APPEND_ARRAY the setter is not being + // called anymore. Instead, the array _data is modified in place. + class A(array _data) { + int counter; + + void `foo=(mixed v) { + counter += !!v; + _data = v; + } + + mixed `foo() { + return _data; + } + }; + + object a = A(({})); + + for (int i = 0; i < 6; i++) { + a->foo += ({ i }); + } + + return a->counter; +]], 6) + +test_any([[ + // Since the addition of F_APPEND_ARRAY the setter is not being + // called anymore. Instead, the array _data is modified in place. + class A(array foo) { + int counter; + + mixed `->=(string sym, mixed v) { + counter += !!v; + return ::`->=(sym, v); + } + }; + + object a = A(({})); + + for (int i = 0; i < 6; i++) { + a->foo += ({ i }); + } + + return a->counter; +]], 6) + test_any([[ // Triggered fatal since object_equal_p did not handle // getter/setter identifier correctly