ZEND_API void ZEND_FASTCALL zend_objects_store_del(zend_object *object) /* {{{ */ { ZEND_ASSERT(GC_REFCOUNT(object) == 0); /* GC might have released this object already. */ if (UNEXPECTED(GC_TYPE(object) == IS_NULL)) { return; } /* Make sure we hold a reference count during the destructor call otherwise, when the destructor ends the storage might be freed when the refcount reaches 0 a second time */ if (!(OBJ_FLAGS(object) & IS_OBJ_DESTRUCTOR_CALLED)) { GC_ADD_FLAGS(object, IS_OBJ_DESTRUCTOR_CALLED); if (object->handlers->dtor_obj != zend_objects_destroy_object || object->ce->destructor) { GC_SET_REFCOUNT(object, 1); object->handlers->dtor_obj(object); GC_DELREF(object); } } if (GC_REFCOUNT(object) == 0) { uint32_t handle = object->handle; void *ptr; ZEND_ASSERT(EG(objects_store).object_buckets != NULL); ZEND_ASSERT(IS_OBJ_VALID(EG(objects_store).object_buckets[handle])); EG(objects_store).object_buckets[handle] = SET_OBJ_INVALID(object); if (!(OBJ_FLAGS(object) & IS_OBJ_FREE_CALLED)) { GC_ADD_FLAGS(object, IS_OBJ_FREE_CALLED); GC_SET_REFCOUNT(object, 1); object->handlers->free_obj(object); } ptr = ((char*)object) - object->handlers->offset; GC_REMOVE_FROM_BUFFER(object); efree(ptr); ZEND_OBJECTS_STORE_ADD_TO_FREE_LIST(handle); } }
/* This function might be not thread safe at least because it would update the hash val in the passed string. Be sure it is called in the appropriate context. */ static zend_always_inline zend_string *zend_add_interned_string(zend_string *str, HashTable *interned_strings, uint32_t flags) { zval val; GC_SET_REFCOUNT(str, 1); GC_FLAGS(str) |= IS_STR_INTERNED | flags; ZVAL_INTERNED_STR(&val, str); zend_hash_add_new(interned_strings, str, &val); return str; }
static int do_callback(struct pdo_sqlite_fci *fc, zval *cb, int argc, sqlite3_value **argv, sqlite3_context *context, int is_agg) { zval *zargs = NULL; zval retval; int i; int ret; int fake_argc; zend_reference *agg_context = NULL; if (is_agg) { is_agg = 2; } fake_argc = argc + is_agg; fc->fci.size = sizeof(fc->fci); ZVAL_COPY_VALUE(&fc->fci.function_name, cb); fc->fci.object = NULL; fc->fci.retval = &retval; fc->fci.param_count = fake_argc; /* build up the params */ if (fake_argc) { zargs = safe_emalloc(fake_argc, sizeof(zval), 0); } if (is_agg) { agg_context = (zend_reference*)sqlite3_aggregate_context(context, sizeof(zend_reference)); if (!agg_context) { ZVAL_NULL(&zargs[0]); } else { if (Z_ISUNDEF(agg_context->val)) { GC_SET_REFCOUNT(agg_context, 1); GC_TYPE_INFO(agg_context) = IS_REFERENCE; ZVAL_NULL(&agg_context->val); } ZVAL_REF(&zargs[0], agg_context); } ZVAL_LONG(&zargs[1], sqlite3_aggregate_count(context)); } for (i = 0; i < argc; i++) { /* get the value */ switch (sqlite3_value_type(argv[i])) { case SQLITE_INTEGER: ZVAL_LONG(&zargs[i + is_agg], sqlite3_value_int(argv[i])); break; case SQLITE_FLOAT: ZVAL_DOUBLE(&zargs[i + is_agg], sqlite3_value_double(argv[i])); break; case SQLITE_NULL: ZVAL_NULL(&zargs[i + is_agg]); break; case SQLITE_BLOB: case SQLITE3_TEXT: default: ZVAL_STRINGL(&zargs[i + is_agg], (char*)sqlite3_value_text(argv[i]), sqlite3_value_bytes(argv[i])); break; } } fc->fci.params = zargs; if ((ret = zend_call_function(&fc->fci, &fc->fcc)) == FAILURE) { php_error_docref(NULL, E_WARNING, "An error occurred while invoking the callback"); } /* clean up the params */ if (zargs) { for (i = is_agg; i < fake_argc; i++) { zval_ptr_dtor(&zargs[i]); } if (is_agg) { zval_ptr_dtor(&zargs[1]); } efree(zargs); } if (!is_agg || !argv) { /* only set the sqlite return value if we are a scalar function, * or if we are finalizing an aggregate */ if (!Z_ISUNDEF(retval)) { switch (Z_TYPE(retval)) { case IS_LONG: sqlite3_result_int(context, Z_LVAL(retval)); break; case IS_NULL: sqlite3_result_null(context); break; case IS_DOUBLE: sqlite3_result_double(context, Z_DVAL(retval)); break; default: convert_to_string_ex(&retval); sqlite3_result_text(context, Z_STRVAL(retval), Z_STRLEN(retval), SQLITE_TRANSIENT); break; } } else { sqlite3_result_error(context, "failed to invoke callback", 0); } if (agg_context) { zval_ptr_dtor(&agg_context->val); } } else { /* we're stepping in an aggregate; the return value goes into * the context */ if (agg_context) { zval_ptr_dtor(&agg_context->val); } if (!Z_ISUNDEF(retval)) { ZVAL_COPY_VALUE(&agg_context->val, &retval); ZVAL_UNDEF(&retval); } else { ZVAL_UNDEF(&agg_context->val); } } if (!Z_ISUNDEF(retval)) { zval_ptr_dtor(&retval); } return ret; }