@@ -112,14 +112,27 @@ MYSQLND_METHOD(mysqlnd_vio, network_write)(MYSQLND_VIO * const vio, const zend_u
112
112
}
113
113
/* }}} */
114
114
115
+ static void mysqlnd_fixup_regular_list (php_stream * net_stream )
116
+ {
117
+ /*
118
+ Streams are not meant for C extensions! Thus we need a hack. Every connected stream will
119
+ be registered as resource (in EG(regular_list). So far, so good. However, it won't be
120
+ unregistered until the script ends. So, we need to take care of that.
121
+ */
122
+ dtor_func_t origin_dtor = EG (regular_list ).pDestructor ;
123
+ EG (regular_list ).pDestructor = NULL ;
124
+ zend_hash_index_del (& EG (regular_list ), net_stream -> res -> handle );
125
+ EG (regular_list ).pDestructor = origin_dtor ;
126
+ efree (net_stream -> res );
127
+ net_stream -> res = NULL ;
128
+ }
115
129
116
130
/* {{{ mysqlnd_vio::open_pipe */
117
131
static php_stream *
118
132
MYSQLND_METHOD (mysqlnd_vio , open_pipe )(MYSQLND_VIO * const vio , const MYSQLND_CSTRING scheme , const bool persistent ,
119
133
MYSQLND_STATS * const conn_stats , MYSQLND_ERROR_INFO * const error_info )
120
134
{
121
135
unsigned int streams_options = 0 ;
122
- dtor_func_t origin_dtor ;
123
136
php_stream * net_stream = NULL ;
124
137
125
138
DBG_ENTER ("mysqlnd_vio::open_pipe" );
@@ -132,16 +145,34 @@ MYSQLND_METHOD(mysqlnd_vio, open_pipe)(MYSQLND_VIO * const vio, const MYSQLND_CS
132
145
SET_CLIENT_ERROR (error_info , CR_CONNECTION_ERROR , UNKNOWN_SQLSTATE , "Unknown error while connecting" );
133
146
DBG_RETURN (NULL );
134
147
}
135
- /*
136
- Streams are not meant for C extensions! Thus we need a hack. Every connected stream will
137
- be registered as resource (in EG(regular_list). So far, so good. However, it won't be
138
- unregistered until the script ends. So, we need to take care of that.
139
- */
140
- origin_dtor = EG (regular_list ).pDestructor ;
141
- EG (regular_list ).pDestructor = NULL ;
142
- zend_hash_index_del (& EG (regular_list ), net_stream -> res -> handle ); /* ToDO: should it be res->handle, do streams register with addref ?*/
143
- EG (regular_list ).pDestructor = origin_dtor ;
144
- net_stream -> res = NULL ;
148
+
149
+ if (persistent ) {
150
+ /* This is a similar hack as for mysqlnd_vio::open_tcp_or_unix.
151
+ * The main difference here is that we have no access to the hashed key.
152
+ * We can however perform a loop over the persistent resource list to find
153
+ * which one corresponds to our newly allocated stream.
154
+ * This loop is pretty cheap because it will normally either be the last entry or second to last entry
155
+ * in the list, depending on whether the socket connection itself is persistent or not.
156
+ * That's why we use a reverse loop. */
157
+ Bucket * bucket ;
158
+ /* Use a bucket loop to make deletion cheap. */
159
+ ZEND_HASH_MAP_REVERSE_FOREACH_BUCKET (& EG (persistent_list ), bucket ) {
160
+ zend_resource * current_res = Z_RES (bucket -> val );
161
+ if (current_res -> ptr == net_stream ) {
162
+ dtor_func_t origin_dtor = EG (persistent_list ).pDestructor ;
163
+ EG (persistent_list ).pDestructor = NULL ;
164
+ zend_hash_del_bucket (& EG (persistent_list ), bucket );
165
+ EG (persistent_list ).pDestructor = origin_dtor ;
166
+ pefree (current_res , 1 );
167
+ break ;
168
+ }
169
+ } ZEND_HASH_FOREACH_END ();
170
+ #if ZEND_DEBUG
171
+ php_stream_auto_cleanup (net_stream );
172
+ #endif
173
+ }
174
+
175
+ mysqlnd_fixup_regular_list (net_stream );
145
176
146
177
DBG_RETURN (net_stream );
147
178
}
@@ -205,6 +236,7 @@ MYSQLND_METHOD(mysqlnd_vio, open_tcp_or_unix)(MYSQLND_VIO * const vio, const MYS
205
236
zend_resource * le ;
206
237
207
238
if ((le = zend_hash_str_find_ptr (& EG (persistent_list ), hashed_details , hashed_details_len ))) {
239
+ ZEND_ASSERT (le -> ptr == net_stream );
208
240
origin_dtor = EG (persistent_list ).pDestructor ;
209
241
/*
210
242
in_free will let streams code skip destructing - big HACK,
@@ -218,22 +250,12 @@ MYSQLND_METHOD(mysqlnd_vio, open_tcp_or_unix)(MYSQLND_VIO * const vio, const MYS
218
250
}
219
251
#if ZEND_DEBUG
220
252
/* Shut-up the streams, they don't know what they are doing */
221
- net_stream -> __exposed = 1 ;
253
+ php_stream_auto_cleanup ( net_stream ) ;
222
254
#endif
223
255
mnd_sprintf_free (hashed_details );
224
256
}
225
257
226
- /*
227
- Streams are not meant for C extensions! Thus we need a hack. Every connected stream will
228
- be registered as resource (in EG(regular_list). So far, so good. However, it won't be
229
- unregistered until the script ends. So, we need to take care of that.
230
- */
231
- origin_dtor = EG (regular_list ).pDestructor ;
232
- EG (regular_list ).pDestructor = NULL ;
233
- zend_hash_index_del (& EG (regular_list ), net_stream -> res -> handle ); /* ToDO: should it be res->handle, do streams register with addref ?*/
234
- efree (net_stream -> res );
235
- net_stream -> res = NULL ;
236
- EG (regular_list ).pDestructor = origin_dtor ;
258
+ mysqlnd_fixup_regular_list (net_stream );
237
259
DBG_RETURN (net_stream );
238
260
}
239
261
/* }}} */
0 commit comments