@@ -147,14 +147,31 @@ php_stream_filter_status_t userfilter_filter(
147147 uint32_t orig_no_fclose = stream -> flags & PHP_STREAM_FLAG_NO_FCLOSE ;
148148 stream -> flags |= PHP_STREAM_FLAG_NO_FCLOSE ;
149149
150- zval * stream_prop = zend_hash_str_find_ind (Z_OBJPROP_P (obj ), "stream" , sizeof ("stream" )- 1 );
151- if (stream_prop ) {
152- /* Give the userfilter class a hook back to the stream */
153- zval_ptr_dtor (stream_prop );
154- php_stream_to_zval (stream , stream_prop );
155- Z_ADDREF_P (stream_prop );
150+ /* Give the userfilter class a hook back to the stream */
151+ zend_class_entry * old_scope = EG (fake_scope );
152+ EG (fake_scope ) = Z_OBJCE_P (obj );
153+
154+ zend_string * stream_name = ZSTR_INIT_LITERAL ("stream" , 0 );
155+ bool stream_property_exists = Z_OBJ_HT_P (obj )-> has_property (Z_OBJ_P (obj ), stream_name , ZEND_PROPERTY_EXISTS , NULL );
156+ if (stream_property_exists ) {
157+ zval stream_zval ;
158+ php_stream_to_zval (stream , & stream_zval );
159+ zend_update_property_ex (Z_OBJCE_P (obj ), Z_OBJ_P (obj ), stream_name , & stream_zval );
160+ /* If property update threw an exception, skip filter execution */
161+ if (EG (exception )) {
162+ EG (fake_scope ) = old_scope ;
163+ if (buckets_in -> head ) {
164+ php_error_docref (NULL , E_WARNING , "Unprocessed filter buckets remaining on input brigade" );
165+ }
166+ zend_string_release (stream_name );
167+ stream -> flags &= ~PHP_STREAM_FLAG_NO_FCLOSE ;
168+ stream -> flags |= orig_no_fclose ;
169+ return PSFS_ERR_FATAL ;
170+ }
156171 }
157172
173+ EG (fake_scope ) = old_scope ;
174+
158175 ZVAL_STRINGL (& func_name , "filter" , sizeof ("filter" )- 1 );
159176
160177 /* Setup calling arguments */
@@ -195,11 +212,16 @@ php_stream_filter_status_t userfilter_filter(
195212
196213 /* filter resources are cleaned up by the stream destructor,
197214 * keeping a reference to the stream resource here would prevent it
198- * from being destroyed properly */
199- if (stream_prop ) {
200- convert_to_null (stream_prop );
215+ * from being destroyed properly.
216+ * Since the property accepted a resource assignment above, it must have
217+ * no type hint or be typed as mixed, so we can safely assign null.
218+ */
219+ if (stream_property_exists ) {
220+ zend_update_property_null (Z_OBJCE_P (obj ), Z_OBJ_P (obj ), ZSTR_VAL (stream_name ), ZSTR_LEN (stream_name ));
201221 }
202222
223+ zend_string_release (stream_name );
224+
203225 zval_ptr_dtor (& args [3 ]);
204226 zval_ptr_dtor (& args [2 ]);
205227 zval_ptr_dtor (& args [1 ]);
0 commit comments