zend_extensions.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend Engine |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 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@php.net> |
  16. | Zeev Suraski <zeev@php.net> |
  17. +----------------------------------------------------------------------+
  18. */
  19. #include "zend_extensions.h"
  20. #include "zend_system_id.h"
  21. ZEND_API zend_llist zend_extensions;
  22. ZEND_API uint32_t zend_extension_flags = 0;
  23. ZEND_API int zend_op_array_extension_handles = 0;
  24. static int last_resource_number;
  25. zend_result zend_load_extension(const char *path)
  26. {
  27. #if ZEND_EXTENSIONS_SUPPORT
  28. DL_HANDLE handle;
  29. handle = DL_LOAD(path);
  30. if (!handle) {
  31. #ifndef ZEND_WIN32
  32. fprintf(stderr, "Failed loading %s: %s\n", path, DL_ERROR());
  33. #else
  34. fprintf(stderr, "Failed loading %s\n", path);
  35. /* See http://support.microsoft.com/kb/190351 */
  36. fflush(stderr);
  37. #endif
  38. return FAILURE;
  39. }
  40. #ifdef ZEND_WIN32
  41. char *err;
  42. if (!php_win32_image_compatible(handle, &err)) {
  43. zend_error(E_CORE_WARNING, err);
  44. return FAILURE;
  45. }
  46. #endif
  47. return zend_load_extension_handle(handle, path);
  48. #else
  49. fprintf(stderr, "Extensions are not supported on this platform.\n");
  50. /* See http://support.microsoft.com/kb/190351 */
  51. #ifdef ZEND_WIN32
  52. fflush(stderr);
  53. #endif
  54. return FAILURE;
  55. #endif
  56. }
  57. zend_result zend_load_extension_handle(DL_HANDLE handle, const char *path)
  58. {
  59. #if ZEND_EXTENSIONS_SUPPORT
  60. zend_extension *new_extension;
  61. zend_extension_version_info *extension_version_info;
  62. extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "extension_version_info");
  63. if (!extension_version_info) {
  64. extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "_extension_version_info");
  65. }
  66. new_extension = (zend_extension *) DL_FETCH_SYMBOL(handle, "zend_extension_entry");
  67. if (!new_extension) {
  68. new_extension = (zend_extension *) DL_FETCH_SYMBOL(handle, "_zend_extension_entry");
  69. }
  70. if (!extension_version_info || !new_extension) {
  71. fprintf(stderr, "%s doesn't appear to be a valid Zend extension\n", path);
  72. /* See http://support.microsoft.com/kb/190351 */
  73. #ifdef ZEND_WIN32
  74. fflush(stderr);
  75. #endif
  76. DL_UNLOAD(handle);
  77. return FAILURE;
  78. }
  79. /* allow extension to proclaim compatibility with any Zend version */
  80. if (extension_version_info->zend_extension_api_no != ZEND_EXTENSION_API_NO &&(!new_extension->api_no_check || new_extension->api_no_check(ZEND_EXTENSION_API_NO) != SUCCESS)) {
  81. if (extension_version_info->zend_extension_api_no > ZEND_EXTENSION_API_NO) {
  82. fprintf(stderr, "%s requires Zend Engine API version %d.\n"
  83. "The Zend Engine API version %d which is installed, is outdated.\n\n",
  84. new_extension->name,
  85. extension_version_info->zend_extension_api_no,
  86. ZEND_EXTENSION_API_NO);
  87. /* See http://support.microsoft.com/kb/190351 */
  88. #ifdef ZEND_WIN32
  89. fflush(stderr);
  90. #endif
  91. DL_UNLOAD(handle);
  92. return FAILURE;
  93. } else if (extension_version_info->zend_extension_api_no < ZEND_EXTENSION_API_NO) {
  94. fprintf(stderr, "%s requires Zend Engine API version %d.\n"
  95. "The Zend Engine API version %d which is installed, is newer.\n"
  96. "Contact %s at %s for a later version of %s.\n\n",
  97. new_extension->name,
  98. extension_version_info->zend_extension_api_no,
  99. ZEND_EXTENSION_API_NO,
  100. new_extension->author,
  101. new_extension->URL,
  102. new_extension->name);
  103. /* See http://support.microsoft.com/kb/190351 */
  104. #ifdef ZEND_WIN32
  105. fflush(stderr);
  106. #endif
  107. DL_UNLOAD(handle);
  108. return FAILURE;
  109. }
  110. } else if (strcmp(ZEND_EXTENSION_BUILD_ID, extension_version_info->build_id) &&
  111. (!new_extension->build_id_check || new_extension->build_id_check(ZEND_EXTENSION_BUILD_ID) != SUCCESS)) {
  112. fprintf(stderr, "Cannot load %s - it was built with configuration %s, whereas running engine is %s\n",
  113. new_extension->name, extension_version_info->build_id, ZEND_EXTENSION_BUILD_ID);
  114. /* See http://support.microsoft.com/kb/190351 */
  115. #ifdef ZEND_WIN32
  116. fflush(stderr);
  117. #endif
  118. DL_UNLOAD(handle);
  119. return FAILURE;
  120. } else if (zend_get_extension(new_extension->name)) {
  121. fprintf(stderr, "Cannot load %s - it was already loaded\n", new_extension->name);
  122. /* See http://support.microsoft.com/kb/190351 */
  123. #ifdef ZEND_WIN32
  124. fflush(stderr);
  125. #endif
  126. DL_UNLOAD(handle);
  127. return FAILURE;
  128. }
  129. zend_register_extension(new_extension, handle);
  130. return SUCCESS;
  131. #else
  132. fprintf(stderr, "Extensions are not supported on this platform.\n");
  133. /* See http://support.microsoft.com/kb/190351 */
  134. #ifdef ZEND_WIN32
  135. fflush(stderr);
  136. #endif
  137. return FAILURE;
  138. #endif
  139. }
  140. void zend_register_extension(zend_extension *new_extension, DL_HANDLE handle)
  141. {
  142. #if ZEND_EXTENSIONS_SUPPORT
  143. zend_extension extension;
  144. extension = *new_extension;
  145. extension.handle = handle;
  146. zend_extension_dispatch_message(ZEND_EXTMSG_NEW_EXTENSION, &extension);
  147. zend_llist_add_element(&zend_extensions, &extension);
  148. if (extension.op_array_ctor) {
  149. zend_extension_flags |= ZEND_EXTENSIONS_HAVE_OP_ARRAY_CTOR;
  150. }
  151. if (extension.op_array_dtor) {
  152. zend_extension_flags |= ZEND_EXTENSIONS_HAVE_OP_ARRAY_DTOR;
  153. }
  154. if (extension.op_array_handler) {
  155. zend_extension_flags |= ZEND_EXTENSIONS_HAVE_OP_ARRAY_HANDLER;
  156. }
  157. if (extension.op_array_persist_calc) {
  158. zend_extension_flags |= ZEND_EXTENSIONS_HAVE_OP_ARRAY_PERSIST_CALC;
  159. }
  160. if (extension.op_array_persist) {
  161. zend_extension_flags |= ZEND_EXTENSIONS_HAVE_OP_ARRAY_PERSIST;
  162. }
  163. /*fprintf(stderr, "Loaded %s, version %s\n", extension.name, extension.version);*/
  164. #endif
  165. }
  166. static void zend_extension_shutdown(zend_extension *extension)
  167. {
  168. #if ZEND_EXTENSIONS_SUPPORT
  169. if (extension->shutdown) {
  170. extension->shutdown(extension);
  171. }
  172. #endif
  173. }
  174. /* int return due to zend linked list API */
  175. static int zend_extension_startup(zend_extension *extension)
  176. {
  177. #if ZEND_EXTENSIONS_SUPPORT
  178. if (extension->startup) {
  179. if (extension->startup(extension)!=SUCCESS) {
  180. return 1;
  181. }
  182. zend_append_version_info(extension);
  183. }
  184. #endif
  185. return 0;
  186. }
  187. void zend_startup_extensions_mechanism()
  188. {
  189. /* Startup extensions mechanism */
  190. zend_llist_init(&zend_extensions, sizeof(zend_extension), (void (*)(void *)) zend_extension_dtor, 1);
  191. zend_op_array_extension_handles = 0;
  192. last_resource_number = 0;
  193. }
  194. void zend_startup_extensions()
  195. {
  196. zend_llist_apply_with_del(&zend_extensions, (int (*)(void *)) zend_extension_startup);
  197. }
  198. void zend_shutdown_extensions(void)
  199. {
  200. zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_shutdown);
  201. zend_llist_destroy(&zend_extensions);
  202. }
  203. void zend_extension_dtor(zend_extension *extension)
  204. {
  205. #if ZEND_EXTENSIONS_SUPPORT && !ZEND_DEBUG
  206. if (extension->handle && !getenv("ZEND_DONT_UNLOAD_MODULES")) {
  207. DL_UNLOAD(extension->handle);
  208. }
  209. #endif
  210. }
  211. static void zend_extension_message_dispatcher(const zend_extension *extension, int num_args, va_list args)
  212. {
  213. int message;
  214. void *arg;
  215. if (!extension->message_handler || num_args!=2) {
  216. return;
  217. }
  218. message = va_arg(args, int);
  219. arg = va_arg(args, void *);
  220. extension->message_handler(message, arg);
  221. }
  222. ZEND_API void zend_extension_dispatch_message(int message, void *arg)
  223. {
  224. zend_llist_apply_with_arguments(&zend_extensions, (llist_apply_with_args_func_t) zend_extension_message_dispatcher, 2, message, arg);
  225. }
  226. ZEND_API int zend_get_resource_handle(const char *module_name)
  227. {
  228. if (last_resource_number<ZEND_MAX_RESERVED_RESOURCES) {
  229. zend_add_system_entropy(module_name, "zend_get_resource_handle", &last_resource_number, sizeof(int));
  230. return last_resource_number++;
  231. } else {
  232. return -1;
  233. }
  234. }
  235. ZEND_API int zend_get_op_array_extension_handle(const char *module_name)
  236. {
  237. int handle = zend_op_array_extension_handles++;
  238. zend_add_system_entropy(module_name, "zend_get_op_array_extension_handle", &zend_op_array_extension_handles, sizeof(int));
  239. return handle;
  240. }
  241. ZEND_API int zend_get_op_array_extension_handles(const char *module_name, int handles)
  242. {
  243. int handle = zend_op_array_extension_handles;
  244. zend_op_array_extension_handles += handles;
  245. zend_add_system_entropy(module_name, "zend_get_op_array_extension_handle", &zend_op_array_extension_handles, sizeof(int));
  246. return handle;
  247. }
  248. ZEND_API zend_extension *zend_get_extension(const char *extension_name)
  249. {
  250. zend_llist_element *element;
  251. for (element = zend_extensions.head; element; element = element->next) {
  252. zend_extension *extension = (zend_extension *) element->data;
  253. if (!strcmp(extension->name, extension_name)) {
  254. return extension;
  255. }
  256. }
  257. return NULL;
  258. }
  259. typedef struct _zend_extension_persist_data {
  260. zend_op_array *op_array;
  261. size_t size;
  262. char *mem;
  263. } zend_extension_persist_data;
  264. static void zend_extension_op_array_persist_calc_handler(zend_extension *extension, zend_extension_persist_data *data)
  265. {
  266. if (extension->op_array_persist_calc) {
  267. data->size += extension->op_array_persist_calc(data->op_array);
  268. }
  269. }
  270. static void zend_extension_op_array_persist_handler(zend_extension *extension, zend_extension_persist_data *data)
  271. {
  272. if (extension->op_array_persist) {
  273. size_t size = extension->op_array_persist(data->op_array, data->mem);
  274. if (size) {
  275. data->mem = (void*)((char*)data->mem + size);
  276. data->size += size;
  277. }
  278. }
  279. }
  280. ZEND_API size_t zend_extensions_op_array_persist_calc(zend_op_array *op_array)
  281. {
  282. if (zend_extension_flags & ZEND_EXTENSIONS_HAVE_OP_ARRAY_PERSIST_CALC) {
  283. zend_extension_persist_data data;
  284. data.op_array = op_array;
  285. data.size = 0;
  286. data.mem = NULL;
  287. zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_persist_calc_handler, &data);
  288. return data.size;
  289. }
  290. return 0;
  291. }
  292. ZEND_API size_t zend_extensions_op_array_persist(zend_op_array *op_array, void *mem)
  293. {
  294. if (zend_extension_flags & ZEND_EXTENSIONS_HAVE_OP_ARRAY_PERSIST) {
  295. zend_extension_persist_data data;
  296. data.op_array = op_array;
  297. data.size = 0;
  298. data.mem = mem;
  299. zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_persist_handler, &data);
  300. return data.size;
  301. }
  302. return 0;
  303. }