Skip to content

Commit 20c6212

Browse files
committed
Improve ref counting.
Passing arrays back and forth between PHP and JavaScript means we need to get a handle on pass-by-value and references. Unfortunately we can't get compile-time-pass-by-reference to work with magic methods, so tweak so that we always separate the zvals we get to ensure they are pass-by-value (and don't corrupt copy-on-write aliases). We'll need to use an explicit wrapper class to pass arrays by reference to JS.
1 parent c6a5d7d commit 20c6212

File tree

2 files changed

+18
-2
lines changed

2 files changed

+18
-2
lines changed

src/asyncmapperchannel.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,19 @@ objid_t AsyncMapperChannel::IdForPhpObj(zval *z) {
113113

114114
objid_t id = NewId();
115115
if (id >= php_obj_list_.size()) { php_obj_list_.resize(id + 1); }
116-
// XXX Should we clone/separate z?
116+
// Pass by value. Note that we seem to be very rarely (never?)
117+
// given refs.
117118
Z_ADDREF_P(z);
118-
php_obj_list_[id] = z;
119119
if (Z_TYPE_P(z) == IS_OBJECT) {
120120
php_obj_to_id_[handle] = id;
121121
} else {
122+
// We're going to modify this from JS side, so make sure we have
123+
// a unique copy (otherwise other copy-on-write references on the
124+
// PHP side could be unexpectedly altered).
125+
z = ZVal::Separate(z);
122126
php_arr_to_id_[z] = id;
123127
}
128+
php_obj_list_[id] = z;
124129
return id;
125130
}
126131

src/values.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,17 @@ class ZVal {
9090
inline zval ** PtrPtr() { return &zvalp; }
9191
inline zval * Escape() { Z_ADDREF_P(zvalp); return zvalp; }
9292

93+
// Ensure an unshared copy of this value.
94+
inline void Separate() {
95+
assert(!transferred_);
96+
SEPARATE_ZVAL_IF_NOT_REF(&zvalp);
97+
}
98+
// A static version that will work on unwrapped zval*
99+
static inline zval *Separate(zval *z) {
100+
SEPARATE_ZVAL_IF_NOT_REF(&z);
101+
return z;
102+
}
103+
93104
// Support a PHP calling convention where the actual zval object
94105
// is owned by the caller, but the contents are transferred to the
95106
// callee.

0 commit comments

Comments
 (0)