zend_objects.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend Engine |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1998-2018 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. ZEND_API void ZEND_FASTCALL zend_object_std_init(zend_object *object, zend_class_entry *ce)
  27. {
  28. GC_SET_REFCOUNT(object, 1);
  29. GC_TYPE_INFO(object) = IS_OBJECT | (GC_COLLECTABLE << GC_FLAGS_SHIFT);
  30. object->ce = ce;
  31. object->properties = NULL;
  32. zend_objects_store_put(object);
  33. if (UNEXPECTED(ce->ce_flags & ZEND_ACC_USE_GUARDS)) {
  34. ZVAL_UNDEF(object->properties_table + object->ce->default_properties_count);
  35. }
  36. }
  37. ZEND_API void zend_object_std_dtor(zend_object *object)
  38. {
  39. zval *p, *end;
  40. if (object->properties) {
  41. if (EXPECTED(!(GC_FLAGS(object->properties) & IS_ARRAY_IMMUTABLE))) {
  42. if (EXPECTED(GC_DELREF(object->properties) == 0)
  43. && EXPECTED(GC_TYPE(object->properties) != IS_NULL)) {
  44. zend_array_destroy(object->properties);
  45. }
  46. }
  47. }
  48. p = object->properties_table;
  49. if (EXPECTED(object->ce->default_properties_count)) {
  50. end = p + object->ce->default_properties_count;
  51. do {
  52. i_zval_ptr_dtor(p ZEND_FILE_LINE_CC);
  53. p++;
  54. } while (p != end);
  55. }
  56. if (UNEXPECTED(object->ce->ce_flags & ZEND_ACC_USE_GUARDS)) {
  57. if (EXPECTED(Z_TYPE_P(p) == IS_STRING)) {
  58. zval_ptr_dtor_str(p);
  59. } else if (Z_TYPE_P(p) == IS_ARRAY) {
  60. HashTable *guards;
  61. guards = Z_ARRVAL_P(p);
  62. ZEND_ASSERT(guards != NULL);
  63. zend_hash_destroy(guards);
  64. FREE_HASHTABLE(guards);
  65. }
  66. }
  67. }
  68. ZEND_API void zend_objects_destroy_object(zend_object *object)
  69. {
  70. zend_function *destructor = object->ce->destructor;
  71. if (destructor) {
  72. zend_object *old_exception;
  73. zend_class_entry *orig_fake_scope;
  74. zend_fcall_info fci;
  75. zend_fcall_info_cache fcic;
  76. zval ret;
  77. if (destructor->op_array.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) {
  78. if (destructor->op_array.fn_flags & ZEND_ACC_PRIVATE) {
  79. /* Ensure that if we're calling a private function, we're allowed to do so.
  80. */
  81. if (EG(current_execute_data)) {
  82. zend_class_entry *scope = zend_get_executed_scope();
  83. if (object->ce != scope) {
  84. zend_throw_error(NULL,
  85. "Call to private %s::__destruct() from context '%s'",
  86. ZSTR_VAL(object->ce->name),
  87. scope ? ZSTR_VAL(scope->name) : "");
  88. return;
  89. }
  90. } else {
  91. zend_error(E_WARNING,
  92. "Call to private %s::__destruct() from context '' during shutdown ignored",
  93. ZSTR_VAL(object->ce->name));
  94. return;
  95. }
  96. } else {
  97. /* Ensure that if we're calling a protected function, we're allowed to do so.
  98. */
  99. if (EG(current_execute_data)) {
  100. zend_class_entry *scope = zend_get_executed_scope();
  101. if (!zend_check_protected(zend_get_function_root_class(destructor), scope)) {
  102. zend_throw_error(NULL,
  103. "Call to protected %s::__destruct() from context '%s'",
  104. ZSTR_VAL(object->ce->name),
  105. scope ? ZSTR_VAL(scope->name) : "");
  106. return;
  107. }
  108. } else {
  109. zend_error(E_WARNING,
  110. "Call to protected %s::__destruct() from context '' during shutdown ignored",
  111. ZSTR_VAL(object->ce->name));
  112. return;
  113. }
  114. }
  115. }
  116. GC_ADDREF(object);
  117. /* Make sure that destructors are protected from previously thrown exceptions.
  118. * For example, if an exception was thrown in a function and when the function's
  119. * local variable destruction results in a destructor being called.
  120. */
  121. old_exception = NULL;
  122. if (EG(exception)) {
  123. if (EG(exception) == object) {
  124. zend_error_noreturn(E_CORE_ERROR, "Attempt to destruct pending exception");
  125. } else {
  126. old_exception = EG(exception);
  127. EG(exception) = NULL;
  128. }
  129. }
  130. orig_fake_scope = EG(fake_scope);
  131. EG(fake_scope) = NULL;
  132. ZVAL_UNDEF(&ret);
  133. fci.size = sizeof(fci);
  134. fci.object = object;
  135. fci.retval = &ret;
  136. fci.param_count = 0;
  137. fci.params = NULL;
  138. fci.no_separation = 1;
  139. ZVAL_UNDEF(&fci.function_name); /* Unused */
  140. fcic.function_handler = destructor;
  141. fcic.called_scope = object->ce;
  142. fcic.object = object;
  143. zend_call_function(&fci, &fcic);
  144. zval_ptr_dtor(&ret);
  145. if (old_exception) {
  146. if (EG(exception)) {
  147. zend_exception_set_previous(EG(exception), old_exception);
  148. } else {
  149. EG(exception) = old_exception;
  150. }
  151. }
  152. OBJ_RELEASE(object);
  153. EG(fake_scope) = orig_fake_scope;
  154. }
  155. }
  156. ZEND_API zend_object* ZEND_FASTCALL zend_objects_new(zend_class_entry *ce)
  157. {
  158. zend_object *object = emalloc(sizeof(zend_object) + zend_object_properties_size(ce));
  159. zend_object_std_init(object, ce);
  160. object->handlers = &std_object_handlers;
  161. return object;
  162. }
  163. ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, zend_object *old_object)
  164. {
  165. if (old_object->ce->default_properties_count) {
  166. zval *src = old_object->properties_table;
  167. zval *dst = new_object->properties_table;
  168. zval *end = src + old_object->ce->default_properties_count;
  169. do {
  170. i_zval_ptr_dtor(dst ZEND_FILE_LINE_CC);
  171. ZVAL_COPY_VALUE(dst, src);
  172. zval_add_ref(dst);
  173. src++;
  174. dst++;
  175. } while (src != end);
  176. } else if (old_object->properties && !old_object->ce->clone) {
  177. /* fast copy */
  178. if (EXPECTED(old_object->handlers == &std_object_handlers)) {
  179. if (EXPECTED(!(GC_FLAGS(old_object->properties) & IS_ARRAY_IMMUTABLE))) {
  180. GC_ADDREF(old_object->properties);
  181. }
  182. new_object->properties = old_object->properties;
  183. return;
  184. }
  185. }
  186. if (old_object->properties &&
  187. EXPECTED(zend_hash_num_elements(old_object->properties))) {
  188. zval *prop, new_prop;
  189. zend_ulong num_key;
  190. zend_string *key;
  191. if (!new_object->properties) {
  192. new_object->properties = zend_new_array(zend_hash_num_elements(old_object->properties));
  193. zend_hash_real_init_mixed(new_object->properties);
  194. } else {
  195. zend_hash_extend(new_object->properties, new_object->properties->nNumUsed + zend_hash_num_elements(old_object->properties), 0);
  196. }
  197. HT_FLAGS(new_object->properties) |=
  198. HT_FLAGS(old_object->properties) & HASH_FLAG_HAS_EMPTY_IND;
  199. ZEND_HASH_FOREACH_KEY_VAL(old_object->properties, num_key, key, prop) {
  200. if (Z_TYPE_P(prop) == IS_INDIRECT) {
  201. ZVAL_INDIRECT(&new_prop, new_object->properties_table + (Z_INDIRECT_P(prop) - old_object->properties_table));
  202. } else {
  203. ZVAL_COPY_VALUE(&new_prop, prop);
  204. zval_add_ref(&new_prop);
  205. }
  206. if (EXPECTED(key)) {
  207. _zend_hash_append(new_object->properties, key, &new_prop);
  208. } else {
  209. zend_hash_index_add_new(new_object->properties, num_key, &new_prop);
  210. }
  211. } ZEND_HASH_FOREACH_END();
  212. }
  213. if (old_object->ce->clone) {
  214. zend_fcall_info fci;
  215. zend_fcall_info_cache fcic;
  216. zval ret;
  217. GC_ADDREF(new_object);
  218. ZVAL_UNDEF(&ret);
  219. fci.size = sizeof(fci);
  220. fci.object = new_object;
  221. fci.retval = &ret;
  222. fci.param_count = 0;
  223. fci.params = NULL;
  224. fci.no_separation = 1;
  225. ZVAL_UNDEF(&fci.function_name); /* Unused */
  226. fcic.function_handler = new_object->ce->clone;
  227. fcic.called_scope = new_object->ce;
  228. fcic.object = new_object;
  229. zend_call_function(&fci, &fcic);
  230. zval_ptr_dtor(&ret);
  231. OBJ_RELEASE(new_object);
  232. }
  233. }
  234. ZEND_API zend_object *zend_objects_clone_obj(zval *zobject)
  235. {
  236. zend_object *old_object;
  237. zend_object *new_object;
  238. /* assume that create isn't overwritten, so when clone depends on the
  239. * overwritten one then it must itself be overwritten */
  240. old_object = Z_OBJ_P(zobject);
  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. }
  254. /*
  255. * Local variables:
  256. * tab-width: 4
  257. * c-basic-offset: 4
  258. * indent-tabs-mode: t
  259. * End:
  260. * vim600: sw=4 ts=4 fdm=marker
  261. * vim<600: sw=4 ts=4
  262. */