xref: /PHP-5.6/Zend/zend_list.c (revision 3537e95d)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2016 Zend Technologies Ltd. (http://www.zend.com) |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 2.00 of the Zend license,     |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.zend.com/license/2_00.txt.                                |
11    | If you did not receive a copy of the Zend license and are unable to  |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@zend.com so we can mail you a copy immediately.              |
14    +----------------------------------------------------------------------+
15    | Authors: Andi Gutmans <andi@zend.com>                                |
16    |          Zeev Suraski <zeev@zend.com>                                |
17    +----------------------------------------------------------------------+
18 */
19 
20 /* $Id$ */
21 
22 /* resource lists */
23 
24 #include "zend.h"
25 #include "zend_list.h"
26 #include "zend_API.h"
27 #include "zend_globals.h"
28 
29 ZEND_API int le_index_ptr;
30 
31 /* true global */
32 static HashTable list_destructors;
33 
34 
zend_list_insert(void * ptr,int type TSRMLS_DC)35 ZEND_API int zend_list_insert(void *ptr, int type TSRMLS_DC)
36 {
37 	int index;
38 	zend_rsrc_list_entry le;
39 
40 	le.ptr=ptr;
41 	le.type=type;
42 	le.refcount=1;
43 
44 	index = zend_hash_next_free_element(&EG(regular_list));
45 
46 	zend_hash_index_update(&EG(regular_list), index, (void *) &le, sizeof(zend_rsrc_list_entry), NULL);
47 	return index;
48 }
49 
_zend_list_delete(int id TSRMLS_DC)50 ZEND_API int _zend_list_delete(int id TSRMLS_DC)
51 {
52 	zend_rsrc_list_entry *le;
53 
54 	if (zend_hash_index_find(&EG(regular_list), id, (void **) &le)==SUCCESS) {
55 /*		printf("del(%d): %d->%d\n", id, le->refcount, le->refcount-1); */
56 		if (--le->refcount<=0) {
57 			return zend_hash_index_del(&EG(regular_list), id);
58 		} else {
59 			return SUCCESS;
60 		}
61 	} else {
62 		return FAILURE;
63 	}
64 }
65 
66 
_zend_list_find(int id,int * type TSRMLS_DC)67 ZEND_API void *_zend_list_find(int id, int *type TSRMLS_DC)
68 {
69 	zend_rsrc_list_entry *le;
70 
71 	if (zend_hash_index_find(&EG(regular_list), id, (void **) &le)==SUCCESS) {
72 		*type = le->type;
73 		return le->ptr;
74 	} else {
75 		*type = -1;
76 		return NULL;
77 	}
78 }
79 
_zend_list_addref(int id TSRMLS_DC)80 ZEND_API int _zend_list_addref(int id TSRMLS_DC)
81 {
82 	zend_rsrc_list_entry *le;
83 
84 	if (zend_hash_index_find(&EG(regular_list), id, (void **) &le)==SUCCESS) {
85 /*		printf("add(%d): %d->%d\n", id, le->refcount, le->refcount+1); */
86 		le->refcount++;
87 		return SUCCESS;
88 	} else {
89 		return FAILURE;
90 	}
91 }
92 
93 
zend_register_resource(zval * rsrc_result,void * rsrc_pointer,int rsrc_type TSRMLS_DC)94 ZEND_API int zend_register_resource(zval *rsrc_result, void *rsrc_pointer, int rsrc_type TSRMLS_DC)
95 {
96 	int rsrc_id;
97 
98 	rsrc_id = zend_list_insert(rsrc_pointer, rsrc_type TSRMLS_CC);
99 
100 	if (rsrc_result) {
101 		rsrc_result->value.lval = rsrc_id;
102 		rsrc_result->type = IS_RESOURCE;
103 	}
104 
105 	return rsrc_id;
106 }
107 
108 
zend_fetch_resource(zval ** passed_id TSRMLS_DC,int default_id,const char * resource_type_name,int * found_resource_type,int num_resource_types,...)109 ZEND_API void *zend_fetch_resource(zval **passed_id TSRMLS_DC, int default_id, const char *resource_type_name, int *found_resource_type, int num_resource_types, ...)
110 {
111 	int id;
112 	int actual_resource_type;
113 	void *resource;
114 	va_list resource_types;
115 	int i;
116 	const char *space;
117 	const char *class_name;
118 
119 	if (default_id==-1) { /* use id */
120 		if (!passed_id) {
121 			if (resource_type_name) {
122 				class_name = get_active_class_name(&space TSRMLS_CC);
123 				zend_error(E_WARNING, "%s%s%s(): no %s resource supplied", class_name, space, get_active_function_name(TSRMLS_C), resource_type_name);
124 			}
125 			return NULL;
126 		} else if ((*passed_id)->type != IS_RESOURCE) {
127 			if (resource_type_name) {
128 				class_name = get_active_class_name(&space TSRMLS_CC);
129 				zend_error(E_WARNING, "%s%s%s(): supplied argument is not a valid %s resource", class_name, space, get_active_function_name(TSRMLS_C), resource_type_name);
130 			}
131 			return NULL;
132 		}
133 		id = (*passed_id)->value.lval;
134 	} else {
135 		id = default_id;
136 	}
137 
138 	resource = zend_list_find(id, &actual_resource_type);
139 	if (!resource) {
140 		if (resource_type_name) {
141 			class_name = get_active_class_name(&space TSRMLS_CC);
142 			zend_error(E_WARNING, "%s%s%s(): %d is not a valid %s resource", class_name, space, get_active_function_name(TSRMLS_C), id, resource_type_name);
143 		}
144 		return NULL;
145 	}
146 
147 	va_start(resource_types, num_resource_types);
148 	for (i=0; i<num_resource_types; i++) {
149 		if (actual_resource_type == va_arg(resource_types, int)) {
150 			va_end(resource_types);
151 			if (found_resource_type) {
152 				*found_resource_type = actual_resource_type;
153 			}
154 			return resource;
155 		}
156 	}
157 	va_end(resource_types);
158 
159 	if (resource_type_name) {
160 		class_name = get_active_class_name(&space TSRMLS_CC);
161 		zend_error(E_WARNING, "%s%s%s(): supplied resource is not a valid %s resource", class_name, space, get_active_function_name(TSRMLS_C), resource_type_name);
162 	}
163 
164 	return NULL;
165 }
166 
167 
list_entry_destructor(void * ptr)168 void list_entry_destructor(void *ptr)
169 {
170 	zend_rsrc_list_entry *le = (zend_rsrc_list_entry *) ptr;
171 	zend_rsrc_list_dtors_entry *ld;
172 	TSRMLS_FETCH();
173 
174 	if (zend_hash_index_find(&list_destructors, le->type, (void **) &ld)==SUCCESS) {
175 		switch (ld->type) {
176 			case ZEND_RESOURCE_LIST_TYPE_STD:
177 				if (ld->list_dtor) {
178 					(ld->list_dtor)(le->ptr);
179 				}
180 				break;
181 			case ZEND_RESOURCE_LIST_TYPE_EX:
182 				if (ld->list_dtor_ex) {
183 					ld->list_dtor_ex(le TSRMLS_CC);
184 				}
185 				break;
186 			EMPTY_SWITCH_DEFAULT_CASE()
187 		}
188 	} else {
189 		zend_error(E_WARNING,"Unknown list entry type in request shutdown (%d)", le->type);
190 	}
191 }
192 
193 
plist_entry_destructor(void * ptr)194 void plist_entry_destructor(void *ptr)
195 {
196 	zend_rsrc_list_entry *le = (zend_rsrc_list_entry *) ptr;
197 	zend_rsrc_list_dtors_entry *ld;
198 	TSRMLS_FETCH();
199 
200 	if (zend_hash_index_find(&list_destructors, le->type, (void **) &ld)==SUCCESS) {
201 		switch (ld->type) {
202 			case ZEND_RESOURCE_LIST_TYPE_STD:
203 				if (ld->plist_dtor) {
204 					(ld->plist_dtor)(le->ptr);
205 				}
206 				break;
207 			case ZEND_RESOURCE_LIST_TYPE_EX:
208 				if (ld->plist_dtor_ex) {
209 					ld->plist_dtor_ex(le TSRMLS_CC);
210 				}
211 				break;
212 				EMPTY_SWITCH_DEFAULT_CASE()
213 		}
214 	} else {
215 		zend_error(E_WARNING,"Unknown persistent list entry type in module shutdown (%d)", le->type);
216 	}
217 }
218 
219 
zend_init_rsrc_list(TSRMLS_D)220 int zend_init_rsrc_list(TSRMLS_D)
221 {
222 	if (zend_hash_init(&EG(regular_list), 0, NULL, list_entry_destructor, 0)==SUCCESS) {
223 		EG(regular_list).nNextFreeElement=1;	/* we don't want resource id 0 */
224 		return SUCCESS;
225 	} else {
226 		return FAILURE;
227 	}
228 }
229 
230 
zend_init_rsrc_plist(TSRMLS_D)231 int zend_init_rsrc_plist(TSRMLS_D)
232 {
233 	return zend_hash_init_ex(&EG(persistent_list), 0, NULL, plist_entry_destructor, 1, 0);
234 }
235 
236 
zend_destroy_rsrc_list(HashTable * ht TSRMLS_DC)237 void zend_destroy_rsrc_list(HashTable *ht TSRMLS_DC)
238 {
239 	zend_hash_graceful_reverse_destroy(ht);
240 }
241 
clean_module_resource(zend_rsrc_list_entry * le,int * resource_id TSRMLS_DC)242 static int clean_module_resource(zend_rsrc_list_entry *le, int *resource_id TSRMLS_DC)
243 {
244 	if (le->type == *resource_id) {
245 		return 1;
246 	} else {
247 		return 0;
248 	}
249 }
250 
251 
zend_clean_module_rsrc_dtors_cb(zend_rsrc_list_dtors_entry * ld,int * module_number TSRMLS_DC)252 static int zend_clean_module_rsrc_dtors_cb(zend_rsrc_list_dtors_entry *ld, int *module_number TSRMLS_DC)
253 {
254 	if (ld->module_number == *module_number) {
255 		zend_hash_apply_with_argument(&EG(persistent_list), (apply_func_arg_t) clean_module_resource, (void *) &(ld->resource_id) TSRMLS_CC);
256 		return 1;
257 	} else {
258 		return 0;
259 	}
260 }
261 
262 
zend_clean_module_rsrc_dtors(int module_number TSRMLS_DC)263 void zend_clean_module_rsrc_dtors(int module_number TSRMLS_DC)
264 {
265 	zend_hash_apply_with_argument(&list_destructors, (apply_func_arg_t) zend_clean_module_rsrc_dtors_cb, (void *) &module_number TSRMLS_CC);
266 }
267 
268 
zend_register_list_destructors(void (* ld)(void *),void (* pld)(void *),int module_number)269 ZEND_API int zend_register_list_destructors(void (*ld)(void *), void (*pld)(void *), int module_number)
270 {
271 	zend_rsrc_list_dtors_entry lde;
272 
273 #if 0
274 	printf("Registering destructors %d for module %d\n", list_destructors.nNextFreeElement, module_number);
275 #endif
276 
277 	lde.list_dtor=(void (*)(void *)) ld;
278 	lde.plist_dtor=(void (*)(void *)) pld;
279 	lde.list_dtor_ex = lde.plist_dtor_ex = NULL;
280 	lde.module_number = module_number;
281 	lde.resource_id = list_destructors.nNextFreeElement;
282 	lde.type = ZEND_RESOURCE_LIST_TYPE_STD;
283 	lde.type_name = NULL;
284 
285 	if (zend_hash_next_index_insert(&list_destructors, (void *) &lde, sizeof(zend_rsrc_list_dtors_entry), NULL)==FAILURE) {
286 		return FAILURE;
287 	}
288 	return list_destructors.nNextFreeElement-1;
289 }
290 
291 
zend_register_list_destructors_ex(rsrc_dtor_func_t ld,rsrc_dtor_func_t pld,const char * type_name,int module_number)292 ZEND_API int zend_register_list_destructors_ex(rsrc_dtor_func_t ld, rsrc_dtor_func_t pld, const char *type_name, int module_number)
293 {
294 	zend_rsrc_list_dtors_entry lde;
295 
296 #if 0
297 	printf("Registering destructors %d for module %d\n", list_destructors.nNextFreeElement, module_number);
298 #endif
299 
300 	lde.list_dtor = NULL;
301 	lde.plist_dtor = NULL;
302 	lde.list_dtor_ex = ld;
303 	lde.plist_dtor_ex = pld;
304 	lde.module_number = module_number;
305 	lde.resource_id = list_destructors.nNextFreeElement;
306 	lde.type = ZEND_RESOURCE_LIST_TYPE_EX;
307 	lde.type_name = type_name;
308 
309 	if (zend_hash_next_index_insert(&list_destructors, (void *) &lde, sizeof(zend_rsrc_list_dtors_entry), NULL)==FAILURE) {
310 		return FAILURE;
311 	}
312 	return list_destructors.nNextFreeElement-1;
313 }
314 
zend_fetch_list_dtor_id(char * type_name)315 ZEND_API int zend_fetch_list_dtor_id(char *type_name)
316 {
317 	zend_rsrc_list_dtors_entry *lde;
318 	HashPosition pos;
319 
320 	zend_hash_internal_pointer_reset_ex(&list_destructors, &pos);
321 	while (zend_hash_get_current_data_ex(&list_destructors, (void **)&lde, &pos) == SUCCESS) {
322 		if (lde->type_name && (strcmp(type_name, lde->type_name) == 0)) {
323 #if 0
324 			printf("Found resource id %d for resource type %s\n", (*lde).resource_id, type_name);
325 #endif
326 			return lde->resource_id;
327 		}
328 		zend_hash_move_forward_ex(&list_destructors, &pos);
329 	}
330 
331 	return 0;
332 }
333 
zend_init_rsrc_list_dtors(void)334 int zend_init_rsrc_list_dtors(void)
335 {
336 	int retval;
337 
338 	retval = zend_hash_init(&list_destructors, 50, NULL, NULL, 1);
339 	list_destructors.nNextFreeElement=1;	/* we don't want resource type 0 */
340 
341 	return retval;
342 }
343 
344 
zend_destroy_rsrc_list_dtors(void)345 void zend_destroy_rsrc_list_dtors(void)
346 {
347 	zend_hash_destroy(&list_destructors);
348 }
349 
350 
zend_rsrc_list_get_rsrc_type(int resource TSRMLS_DC)351 const char *zend_rsrc_list_get_rsrc_type(int resource TSRMLS_DC)
352 {
353 	zend_rsrc_list_dtors_entry *lde;
354 	int rsrc_type;
355 
356 	if (!zend_list_find(resource, &rsrc_type))
357 		return NULL;
358 
359 	if (zend_hash_index_find(&list_destructors, rsrc_type, (void **) &lde)==SUCCESS) {
360 		return lde->type_name;
361 	} else {
362 		return NULL;
363 	}
364 }
365 
366 /*
367  * Local variables:
368  * tab-width: 4
369  * c-basic-offset: 4
370  * indent-tabs-mode: t
371  * End:
372  */
373