zend_objects.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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. /* $Id$ */
  20. #include "zend.h"
  21. #include "zend_globals.h"
  22. #include "zend_variables.h"
  23. #include "zend_API.h"
  24. #include "zend_interfaces.h"
  25. #include "zend_exceptions.h"
  26. ZEND_API void zend_object_std_init(zend_object *object, zend_class_entry *ce TSRMLS_DC)
  27. {
  28. object->ce = ce;
  29. object->properties = NULL;
  30. object->properties_table = NULL;
  31. object->guards = NULL;
  32. }
  33. ZEND_API void zend_object_std_dtor(zend_object *object TSRMLS_DC)
  34. {
  35. if (object->guards) {
  36. zend_hash_destroy(object->guards);
  37. FREE_HASHTABLE(object->guards);
  38. }
  39. if (object->properties) {
  40. zend_hash_destroy(object->properties);
  41. FREE_HASHTABLE(object->properties);
  42. if (object->properties_table) {
  43. efree(object->properties_table);
  44. }
  45. } else if (object->properties_table) {
  46. int i;
  47. for (i = 0; i < object->ce->default_properties_count; i++) {
  48. if (object->properties_table[i]) {
  49. zval_ptr_dtor(&object->properties_table[i]);
  50. }
  51. }
  52. efree(object->properties_table);
  53. }
  54. }
  55. ZEND_API void zend_objects_destroy_object(zend_object *object, zend_object_handle handle TSRMLS_DC)
  56. {
  57. zend_function *destructor = object ? object->ce->destructor : NULL;
  58. if (destructor) {
  59. zval *old_exception;
  60. zval *obj;
  61. zend_object_store_bucket *obj_bucket;
  62. if (destructor->op_array.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) {
  63. if (destructor->op_array.fn_flags & ZEND_ACC_PRIVATE) {
  64. /* Ensure that if we're calling a private function, we're allowed to do so.
  65. */
  66. if (object->ce != EG(scope)) {
  67. zend_class_entry *ce = object->ce;
  68. zend_error(EG(in_execution) ? E_ERROR : E_WARNING,
  69. "Call to private %s::__destruct() from context '%s'%s",
  70. ce->name,
  71. EG(scope) ? EG(scope)->name : "",
  72. EG(in_execution) ? "" : " during shutdown ignored");
  73. return;
  74. }
  75. } else {
  76. /* Ensure that if we're calling a protected function, we're allowed to do so.
  77. */
  78. if (!zend_check_protected(zend_get_function_root_class(destructor), EG(scope))) {
  79. zend_class_entry *ce = object->ce;
  80. zend_error(EG(in_execution) ? E_ERROR : E_WARNING,
  81. "Call to protected %s::__destruct() from context '%s'%s",
  82. ce->name,
  83. EG(scope) ? EG(scope)->name : "",
  84. EG(in_execution) ? "" : " during shutdown ignored");
  85. return;
  86. }
  87. }
  88. }
  89. MAKE_STD_ZVAL(obj);
  90. Z_TYPE_P(obj) = IS_OBJECT;
  91. Z_OBJ_HANDLE_P(obj) = handle;
  92. obj_bucket = &EG(objects_store).object_buckets[handle];
  93. if (!obj_bucket->bucket.obj.handlers) {
  94. obj_bucket->bucket.obj.handlers = &std_object_handlers;
  95. }
  96. Z_OBJ_HT_P(obj) = obj_bucket->bucket.obj.handlers;
  97. zval_copy_ctor(obj);
  98. /* Make sure that destructors are protected from previously thrown exceptions.
  99. * For example, if an exception was thrown in a function and when the function's
  100. * local variable destruction results in a destructor being called.
  101. */
  102. old_exception = NULL;
  103. if (EG(exception)) {
  104. if (Z_OBJ_HANDLE_P(EG(exception)) == handle) {
  105. zend_error(E_ERROR, "Attempt to destruct pending exception");
  106. } else {
  107. old_exception = EG(exception);
  108. EG(exception) = NULL;
  109. }
  110. }
  111. zend_call_method_with_0_params(&obj, object->ce, &destructor, ZEND_DESTRUCTOR_FUNC_NAME, NULL);
  112. if (old_exception) {
  113. if (EG(exception)) {
  114. zend_exception_set_previous(EG(exception), old_exception TSRMLS_CC);
  115. } else {
  116. EG(exception) = old_exception;
  117. }
  118. }
  119. zval_ptr_dtor(&obj);
  120. }
  121. }
  122. ZEND_API void zend_objects_free_object_storage(zend_object *object TSRMLS_DC)
  123. {
  124. zend_object_std_dtor(object TSRMLS_CC);
  125. efree(object);
  126. }
  127. ZEND_API zend_object_value zend_objects_new(zend_object **object, zend_class_entry *class_type TSRMLS_DC)
  128. {
  129. zend_object_value retval;
  130. *object = emalloc(sizeof(zend_object));
  131. (*object)->ce = class_type;
  132. (*object)->properties = NULL;
  133. (*object)->properties_table = NULL;
  134. (*object)->guards = NULL;
  135. retval.handle = zend_objects_store_put(*object, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) zend_objects_free_object_storage, NULL TSRMLS_CC);
  136. retval.handlers = &std_object_handlers;
  137. return retval;
  138. }
  139. ZEND_API zend_object *zend_objects_get_address(const zval *zobject TSRMLS_DC)
  140. {
  141. return (zend_object *)zend_object_store_get_object(zobject TSRMLS_CC);
  142. }
  143. ZEND_API void zend_objects_clone_members(zend_object *new_object, zend_object_value new_obj_val, zend_object *old_object, zend_object_handle handle TSRMLS_DC)
  144. {
  145. int i;
  146. if (old_object->properties_table) {
  147. if (!new_object->properties_table) {
  148. new_object->properties_table = emalloc(sizeof(zval*) * old_object->ce->default_properties_count);
  149. memset(new_object->properties_table, 0, sizeof(zval*) * old_object->ce->default_properties_count);
  150. }
  151. for (i = 0; i < old_object->ce->default_properties_count; i++) {
  152. if (!new_object->properties) {
  153. if (new_object->properties_table[i]) {
  154. zval_ptr_dtor(&new_object->properties_table[i]);
  155. }
  156. }
  157. if (!old_object->properties) {
  158. new_object->properties_table[i] = old_object->properties_table[i];
  159. if (new_object->properties_table[i]) {
  160. Z_ADDREF_P(new_object->properties_table[i]);
  161. }
  162. }
  163. }
  164. }
  165. if (old_object->properties) {
  166. if (!new_object->properties) {
  167. ALLOC_HASHTABLE(new_object->properties);
  168. zend_hash_init(new_object->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
  169. }
  170. zend_hash_copy(new_object->properties, old_object->properties, (copy_ctor_func_t) zval_add_ref, (void *) NULL /* Not used anymore */, sizeof(zval *));
  171. if (old_object->properties_table) {
  172. HashPosition pos;
  173. zend_property_info *prop_info;
  174. for (zend_hash_internal_pointer_reset_ex(&old_object->ce->properties_info, &pos);
  175. zend_hash_get_current_data_ex(&old_object->ce->properties_info, (void**)&prop_info, &pos) == SUCCESS;
  176. zend_hash_move_forward_ex(&old_object->ce->properties_info, &pos)) {
  177. if ((prop_info->flags & ZEND_ACC_STATIC) == 0) {
  178. if (zend_hash_quick_find(new_object->properties, prop_info->name, prop_info->name_length+1, prop_info->h, (void**)&new_object->properties_table[prop_info->offset]) == FAILURE) {
  179. new_object->properties_table[prop_info->offset] = NULL;
  180. }
  181. }
  182. }
  183. }
  184. }
  185. if (old_object->ce->clone) {
  186. zval *new_obj;
  187. MAKE_STD_ZVAL(new_obj);
  188. new_obj->type = IS_OBJECT;
  189. new_obj->value.obj = new_obj_val;
  190. zval_copy_ctor(new_obj);
  191. zend_call_method_with_0_params(&new_obj, old_object->ce, &old_object->ce->clone, ZEND_CLONE_FUNC_NAME, NULL);
  192. zval_ptr_dtor(&new_obj);
  193. }
  194. }
  195. ZEND_API zend_object_value zend_objects_clone_obj(zval *zobject TSRMLS_DC)
  196. {
  197. zend_object_value new_obj_val;
  198. zend_object *old_object;
  199. zend_object *new_object;
  200. zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
  201. /* assume that create isn't overwritten, so when clone depends on the
  202. * overwritten one then it must itself be overwritten */
  203. old_object = zend_objects_get_address(zobject TSRMLS_CC);
  204. new_obj_val = zend_objects_new(&new_object, old_object->ce TSRMLS_CC);
  205. zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
  206. return new_obj_val;
  207. }
  208. /*
  209. * Local variables:
  210. * tab-width: 4
  211. * c-basic-offset: 4
  212. * indent-tabs-mode: t
  213. * End:
  214. */