zend_objects.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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. | Dmitry Stogov <dmitry@php.net> |
  18. +----------------------------------------------------------------------+
  19. */
  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. #include "zend_weakrefs.h"
  27. static zend_always_inline void _zend_object_std_init(zend_object *object, zend_class_entry *ce)
  28. {
  29. GC_SET_REFCOUNT(object, 1);
  30. GC_TYPE_INFO(object) = GC_OBJECT;
  31. object->ce = ce;
  32. object->properties = NULL;
  33. zend_objects_store_put(object);
  34. if (UNEXPECTED(ce->ce_flags & ZEND_ACC_USE_GUARDS)) {
  35. ZVAL_UNDEF(object->properties_table + object->ce->default_properties_count);
  36. }
  37. }
  38. ZEND_API void ZEND_FASTCALL zend_object_std_init(zend_object *object, zend_class_entry *ce)
  39. {
  40. _zend_object_std_init(object, ce);
  41. }
  42. ZEND_API void zend_object_std_dtor(zend_object *object)
  43. {
  44. zval *p, *end;
  45. if (object->properties) {
  46. if (EXPECTED(!(GC_FLAGS(object->properties) & IS_ARRAY_IMMUTABLE))) {
  47. if (EXPECTED(GC_DELREF(object->properties) == 0)
  48. && EXPECTED(GC_TYPE(object->properties) != IS_NULL)) {
  49. zend_array_destroy(object->properties);
  50. }
  51. }
  52. }
  53. p = object->properties_table;
  54. if (EXPECTED(object->ce->default_properties_count)) {
  55. end = p + object->ce->default_properties_count;
  56. do {
  57. if (Z_REFCOUNTED_P(p)) {
  58. if (UNEXPECTED(Z_ISREF_P(p)) &&
  59. (ZEND_DEBUG || ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(p)))) {
  60. zend_property_info *prop_info = zend_get_property_info_for_slot(object, p);
  61. if (ZEND_TYPE_IS_SET(prop_info->type)) {
  62. ZEND_REF_DEL_TYPE_SOURCE(Z_REF_P(p), prop_info);
  63. }
  64. }
  65. i_zval_ptr_dtor(p);
  66. }
  67. p++;
  68. } while (p != end);
  69. }
  70. if (UNEXPECTED(object->ce->ce_flags & ZEND_ACC_USE_GUARDS)) {
  71. if (EXPECTED(Z_TYPE_P(p) == IS_STRING)) {
  72. zval_ptr_dtor_str(p);
  73. } else if (Z_TYPE_P(p) == IS_ARRAY) {
  74. HashTable *guards;
  75. guards = Z_ARRVAL_P(p);
  76. ZEND_ASSERT(guards != NULL);
  77. zend_hash_destroy(guards);
  78. FREE_HASHTABLE(guards);
  79. }
  80. }
  81. if (UNEXPECTED(GC_FLAGS(object) & IS_OBJ_WEAKLY_REFERENCED)) {
  82. zend_weakrefs_notify(object);
  83. }
  84. }
  85. ZEND_API void zend_objects_destroy_object(zend_object *object)
  86. {
  87. zend_function *destructor = object->ce->destructor;
  88. if (destructor) {
  89. zend_object *old_exception;
  90. const zend_op *old_opline_before_exception;
  91. if (destructor->op_array.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) {
  92. if (destructor->op_array.fn_flags & ZEND_ACC_PRIVATE) {
  93. /* Ensure that if we're calling a private function, we're allowed to do so.
  94. */
  95. if (EG(current_execute_data)) {
  96. zend_class_entry *scope = zend_get_executed_scope();
  97. if (object->ce != scope) {
  98. zend_throw_error(NULL,
  99. "Call to private %s::__destruct() from %s%s",
  100. ZSTR_VAL(object->ce->name),
  101. scope ? "scope " : "global scope",
  102. scope ? ZSTR_VAL(scope->name) : ""
  103. );
  104. return;
  105. }
  106. } else {
  107. zend_error(E_WARNING,
  108. "Call to private %s::__destruct() from global scope during shutdown ignored",
  109. ZSTR_VAL(object->ce->name));
  110. return;
  111. }
  112. } else {
  113. /* Ensure that if we're calling a protected function, we're allowed to do so.
  114. */
  115. if (EG(current_execute_data)) {
  116. zend_class_entry *scope = zend_get_executed_scope();
  117. if (!zend_check_protected(zend_get_function_root_class(destructor), scope)) {
  118. zend_throw_error(NULL,
  119. "Call to protected %s::__destruct() from %s%s",
  120. ZSTR_VAL(object->ce->name),
  121. scope ? "scope " : "global scope",
  122. scope ? ZSTR_VAL(scope->name) : ""
  123. );
  124. return;
  125. }
  126. } else {
  127. zend_error(E_WARNING,
  128. "Call to protected %s::__destruct() from global scope during shutdown ignored",
  129. ZSTR_VAL(object->ce->name));
  130. return;
  131. }
  132. }
  133. }
  134. GC_ADDREF(object);
  135. /* Make sure that destructors are protected from previously thrown exceptions.
  136. * For example, if an exception was thrown in a function and when the function's
  137. * local variable destruction results in a destructor being called.
  138. */
  139. old_exception = NULL;
  140. if (EG(exception)) {
  141. if (EG(exception) == object) {
  142. zend_error_noreturn(E_CORE_ERROR, "Attempt to destruct pending exception");
  143. } else {
  144. if (EG(current_execute_data)
  145. && EG(current_execute_data)->func
  146. && ZEND_USER_CODE(EG(current_execute_data)->func->common.type)) {
  147. zend_rethrow_exception(EG(current_execute_data));
  148. }
  149. old_exception = EG(exception);
  150. old_opline_before_exception = EG(opline_before_exception);
  151. EG(exception) = NULL;
  152. }
  153. }
  154. zend_call_known_instance_method_with_0_params(destructor, object, NULL);
  155. if (old_exception) {
  156. EG(opline_before_exception) = old_opline_before_exception;
  157. if (EG(exception)) {
  158. zend_exception_set_previous(EG(exception), old_exception);
  159. } else {
  160. EG(exception) = old_exception;
  161. }
  162. }
  163. OBJ_RELEASE(object);
  164. }
  165. }
  166. ZEND_API zend_object* ZEND_FASTCALL zend_objects_new(zend_class_entry *ce)
  167. {
  168. zend_object *object = emalloc(sizeof(zend_object) + zend_object_properties_size(ce));
  169. _zend_object_std_init(object, ce);
  170. object->handlers = &std_object_handlers;
  171. return object;
  172. }
  173. ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, zend_object *old_object)
  174. {
  175. if (old_object->ce->default_properties_count) {
  176. zval *src = old_object->properties_table;
  177. zval *dst = new_object->properties_table;
  178. zval *end = src + old_object->ce->default_properties_count;
  179. do {
  180. i_zval_ptr_dtor(dst);
  181. ZVAL_COPY_VALUE_PROP(dst, src);
  182. zval_add_ref(dst);
  183. if (UNEXPECTED(Z_ISREF_P(dst)) &&
  184. (ZEND_DEBUG || ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(dst)))) {
  185. zend_property_info *prop_info = zend_get_property_info_for_slot(new_object, dst);
  186. if (ZEND_TYPE_IS_SET(prop_info->type)) {
  187. ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(dst), prop_info);
  188. }
  189. }
  190. src++;
  191. dst++;
  192. } while (src != end);
  193. } else if (old_object->properties && !old_object->ce->clone) {
  194. /* fast copy */
  195. if (EXPECTED(old_object->handlers == &std_object_handlers)) {
  196. if (EXPECTED(!(GC_FLAGS(old_object->properties) & IS_ARRAY_IMMUTABLE))) {
  197. GC_ADDREF(old_object->properties);
  198. }
  199. new_object->properties = old_object->properties;
  200. return;
  201. }
  202. }
  203. if (old_object->properties &&
  204. EXPECTED(zend_hash_num_elements(old_object->properties))) {
  205. zval *prop, new_prop;
  206. zend_ulong num_key;
  207. zend_string *key;
  208. if (!new_object->properties) {
  209. new_object->properties = zend_new_array(zend_hash_num_elements(old_object->properties));
  210. zend_hash_real_init_mixed(new_object->properties);
  211. } else {
  212. zend_hash_extend(new_object->properties, new_object->properties->nNumUsed + zend_hash_num_elements(old_object->properties), 0);
  213. }
  214. HT_FLAGS(new_object->properties) |=
  215. HT_FLAGS(old_object->properties) & HASH_FLAG_HAS_EMPTY_IND;
  216. ZEND_HASH_FOREACH_KEY_VAL(old_object->properties, num_key, key, prop) {
  217. if (Z_TYPE_P(prop) == IS_INDIRECT) {
  218. ZVAL_INDIRECT(&new_prop, new_object->properties_table + (Z_INDIRECT_P(prop) - old_object->properties_table));
  219. } else {
  220. ZVAL_COPY_VALUE(&new_prop, prop);
  221. zval_add_ref(&new_prop);
  222. }
  223. if (EXPECTED(key)) {
  224. _zend_hash_append(new_object->properties, key, &new_prop);
  225. } else {
  226. zend_hash_index_add_new(new_object->properties, num_key, &new_prop);
  227. }
  228. } ZEND_HASH_FOREACH_END();
  229. }
  230. if (old_object->ce->clone) {
  231. GC_ADDREF(new_object);
  232. zend_call_known_instance_method_with_0_params(new_object->ce->clone, new_object, NULL);
  233. OBJ_RELEASE(new_object);
  234. }
  235. }
  236. ZEND_API zend_object *zend_objects_clone_obj(zend_object *old_object)
  237. {
  238. zend_object *new_object;
  239. /* assume that create isn't overwritten, so when clone depends on the
  240. * overwritten one then it must itself be overwritten */
  241. new_object = zend_objects_new(old_object->ce);
  242. /* zend_objects_clone_members() expect the properties to be initialized. */
  243. if (new_object->ce->default_properties_count) {
  244. zval *p = new_object->properties_table;
  245. zval *end = p + new_object->ce->default_properties_count;
  246. do {
  247. ZVAL_UNDEF(p);
  248. p++;
  249. } while (p != end);
  250. }
  251. zend_objects_clone_members(new_object, old_object);
  252. return new_object;
  253. }