1 /*
2   +----------------------------------------------------------------------+
3   | Compatibility macros for different PHP versions                      |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 2016 The PHP Group                                     |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt.                                 |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Author: Adam Harvey <aharvey@php.net>                                |
16   +----------------------------------------------------------------------+
17 */
18 
19 #ifndef _COMPAT_ZEND_RESOURCE_H
20 #define _COMPAT_ZEND_RESOURCE_H
21 
22 /*
23  * The PHP 5 and PHP 7 resource APIs use the same function names for mutually
24  * incompatible functions, which is unfortunate. A simple version of the PHP 5
25  * macro API can be implemented on top of the PHP 7 API, but not vice versa
26  * (since, for example, zend_register_resource() in PHP 5 also sets the zval,
27  * which is a separate action in PHP 7).
28  *
29  * Instead of using preprocessor trickery to try to mangle things into a sane
30  * API, I've implemented a minimal API that supports basic resource handling
31  * and delegates appropriately on both versions.
32  *
33  * Destructors should be registered using the normal
34  * zend_register_list_destructors() or zend_register_list_destructors_ex()
35  * functions. The destructor function should take a "zend_resource *" (there is
36  * an appropriate typedef in the PHP 5 section to make this work); as only a
37  * subset of fields are available across PHP versions, this should be treated
38  * as this struct in effect:
39  *
40  * typedef struct {
41  *   void *ptr;
42  *   int   type;
43  * } zend_resource;
44  *
45  * Accessing other fields will likely result in compilation errors and/or
46  * segfaults.
47  */
48 
49 /**
50  * Deletes the resource.
51  *
52  * On PHP 5, this is equivalent to zend_list_delete(Z_LVAL_P(zv)).
53  * On PHP 7, this is equivalent to zend_list_close(Z_RES_P(zv)).
54  *
55  * @param zv The IS_RESOURCE zval to delete.
56  */
57 static void compat_zend_delete_resource(const zval *zv);
58 
59 /**
60  * Fetches the resource.
61  *
62  * This API does not support the default ID that's possible with the PHP 5
63  * zend_fetch_resource() API, and will always set that value to -1.
64  *
65  * @param zv             The IS_RESOURCE zval to fetch.
66  * @param rsrc_type_name The type name to use in error messages.
67  * @param rsrc_type      The resource type ID.
68  * @return A void pointer to the resource, which needs to be typecast, or NULL
69  *         on error.
70  */
71 static void *compat_zend_fetch_resource(zval *zv, const char *rsrc_type_name, int rsrc_type);
72 
73 /**
74  * Registers a new resource.
75  *
76  * @param zv        The zval to set to IS_RESOURCE with the new resource value.
77  * @param ptr       A void pointer to the resource.
78  * @param rsrc_type The resource type ID.
79  */
80 static void compat_zend_register_resource(zval *zv, void *ptr, int rsrc_type);
81 
82 #ifdef PHP_7
83 /*============================================================================*/
84 
compat_zend_delete_resource(const zval * zv)85 static void compat_zend_delete_resource(const zval *zv)
86 {
87 	if (IS_RESOURCE != Z_TYPE_P(zv)) {
88 		return;
89 	}
90 
91 	zend_list_close(Z_RES_P(zv));
92 }
93 
compat_zend_fetch_resource(zval * zv,const char * rsrc_type_name,int rsrc_type)94 static void *compat_zend_fetch_resource(zval *zv, const char *rsrc_type_name, int rsrc_type)
95 {
96 	if (IS_RESOURCE != Z_TYPE_P(zv)) {
97 		return NULL;
98 	}
99 
100 	return zend_fetch_resource(Z_RES_P(zv), rsrc_type_name, rsrc_type);
101 }
102 
compat_zend_register_resource(zval * zv,void * ptr,int rsrc_type)103 static void compat_zend_register_resource(zval *zv, void *ptr, int rsrc_type)
104 {
105 	ZVAL_RES(zv, zend_register_resource(ptr, rsrc_type));
106 }
107 
108 #else
109 /*== PHP 5 ===================================================================*/
110 
111 /* Used for destructors. */
112 typedef zend_rsrc_list_entry zend_resource;
113 
compat_zend_delete_resource(const zval * zv)114 static void compat_zend_delete_resource(const zval *zv)
115 {
116 	if (IS_RESOURCE != Z_TYPE_P(zv)) {
117 		return;
118 	}
119 
120 	zend_list_delete(Z_LVAL_P(zv));
121 }
122 
compat_zend_fetch_resource(zval * zv,const char * rsrc_type_name,int rsrc_type)123 static void *compat_zend_fetch_resource(zval *zv, const char *rsrc_type_name, int rsrc_type)
124 {
125 #if ZEND_MODULE_API_NO >= 20100412
126 	return zend_fetch_resource(&zv, -1, rsrc_type_name, NULL, 1, rsrc_type);
127 #else
128 	return zend_fetch_resource(&zv, -1, (char *)rsrc_type_name, NULL, 1, rsrc_type);
129 #endif
130 }
131 
compat_zend_register_resource(zval * zv,void * ptr,int rsrc_type)132 static void compat_zend_register_resource(zval *zv, void *ptr, int rsrc_type)
133 {
134 	ZEND_REGISTER_RESOURCE(zv, ptr, rsrc_type);
135 }
136 
137 #endif /* PHP_7 */
138 /*============================================================================*/
139 
140 #endif /* _COMPAT_ZEND_RESOURCE_H */
141