/* php_spintf_appendstring() {{{ */ inline static void php_sprintf_appendstring(char **buffer, int *pos, int *size, char *add, int min_width, int max_width, char padding, int alignment, int len, int neg, int expprec, int always_sign) { register int npad; int req_size; int copy_len; int m_width; copy_len = (expprec ? MIN(max_width, len) : len); npad = min_width - copy_len; if (npad < 0) { npad = 0; } PRINTF_DEBUG(("sprintf: appendstring(%x, %d, %d, \"%s\", %d, '%c', %d)\n", *buffer, *pos, *size, add, min_width, padding, alignment)); m_width = MAX(min_width, copy_len); if(m_width > INT_MAX - *pos - 1) { zend_error_noreturn(E_ERROR, "Field width %d is too long", m_width); } req_size = *pos + m_width + 1; if (req_size > *size) { while (req_size > *size) { if(*size > INT_MAX/2) { zend_error_noreturn(E_ERROR, "Field width %d is too long", req_size); } *size <<= 1; } PRINTF_DEBUG(("sprintf ereallocing buffer to %d bytes\n", *size)); *buffer = erealloc(*buffer, *size); } if (alignment == ALIGN_RIGHT) { if ((neg || always_sign) && padding=='0') { (*buffer)[(*pos)++] = (neg) ? '-' : '+'; add++; len--; copy_len--; } while (npad-- > 0) { (*buffer)[(*pos)++] = padding; } } PRINTF_DEBUG(("sprintf: appending \"%s\"\n", add)); memcpy(&(*buffer)[*pos], add, copy_len + 1); *pos += copy_len; if (alignment == ALIGN_LEFT) { while (npad--) { (*buffer)[(*pos)++] = padding; } } }
/* {{{ zend_signal_register * Set a handler for a signal we want to defer. * Previously set handler must have been saved before. */ static int zend_signal_register(int signo, void (*handler)(int, siginfo_t*, void*)) { struct sigaction sa = {{0}}; if (sigaction(signo, NULL, &sa) == 0) { if ((sa.sa_flags & SA_SIGINFO) && sa.sa_sigaction == handler) { return FAILURE; } SIGG(handlers)[signo-1].flags = sa.sa_flags; if (sa.sa_flags & SA_SIGINFO) { SIGG(handlers)[signo-1].handler = (void *)sa.sa_sigaction; } else { SIGG(handlers)[signo-1].handler = (void *)sa.sa_handler; } sa.sa_flags = SA_SIGINFO; /* we'll use a siginfo handler */ sa.sa_sigaction = handler; sa.sa_mask = global_sigmask; if (sigaction(signo, &sa, NULL) < 0) { zend_error_noreturn(E_ERROR, "Error installing signal handler for %d", signo); } return SUCCESS; } return FAILURE; } /* }}} */
/* {{{ zend_implement_aggregate */ static int zend_implement_aggregate(zend_class_entry *interface, zend_class_entry *class_type) { uint32_t i; int t = -1; if (class_type->get_iterator) { if (class_type->type == ZEND_INTERNAL_CLASS) { /* inheritance ensures the class has necessary userland methods */ return SUCCESS; } else if (class_type->get_iterator != zend_user_it_get_new_iterator) { /* c-level get_iterator cannot be changed (exception being only Traversable is implmented) */ if (class_type->num_interfaces) { for (i = 0; i < class_type->num_interfaces; i++) { if (class_type->interfaces[i] == zend_ce_iterator) { zend_error_noreturn(E_ERROR, "Class %s cannot implement both %s and %s at the same time", class_type->name->val, interface->name->val, zend_ce_iterator->name->val); return FAILURE; } if (class_type->interfaces[i] == zend_ce_traversable) { t = i; } } } if (t == -1) { return FAILURE; } } } class_type->iterator_funcs.zf_new_iterator = NULL; class_type->get_iterator = zend_user_it_get_new_iterator; return SUCCESS; }
/* {{{ zend_implement_iterator */ static int zend_implement_iterator(zend_class_entry *interface, zend_class_entry *class_type) { if (class_type->get_iterator && class_type->get_iterator != zend_user_it_get_iterator) { if (class_type->type == ZEND_INTERNAL_CLASS) { /* inheritance ensures the class has the necessary userland methods */ return SUCCESS; } else { /* c-level get_iterator cannot be changed */ if (class_type->get_iterator == zend_user_it_get_new_iterator) { zend_error_noreturn(E_ERROR, "Class %s cannot implement both %s and %s at the same time", class_type->name->val, interface->name->val, zend_ce_aggregate->name->val); } return FAILURE; } } class_type->get_iterator = zend_user_it_get_iterator; class_type->iterator_funcs.zf_valid = NULL; class_type->iterator_funcs.zf_current = NULL; class_type->iterator_funcs.zf_key = NULL; class_type->iterator_funcs.zf_next = NULL; class_type->iterator_funcs.zf_rewind = NULL; if (!class_type->iterator_funcs.funcs) { class_type->iterator_funcs.funcs = &zend_interface_iterator_funcs_iterator; } return SUCCESS; }
void zend_exception_set_previous(zend_object *exception, zend_object *add_previous) /* {{{ */ { zval *previous, *ancestor, *ex; zval pv, zv, rv; zend_class_entry *base_ce; if (exception == add_previous || !add_previous || !exception) { return; } ZVAL_OBJ(&pv, add_previous); if (!instanceof_function(Z_OBJCE(pv), zend_ce_throwable)) { zend_error_noreturn(E_CORE_ERROR, "Previous exception must implement Throwable"); return; } ZVAL_OBJ(&zv, exception); ex = &zv; do { ancestor = zend_read_property_ex(i_get_exception_base(&pv), &pv, ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv); while (Z_TYPE_P(ancestor) == IS_OBJECT) { if (Z_OBJ_P(ancestor) == Z_OBJ_P(ex)) { OBJ_RELEASE(add_previous); return; } ancestor = zend_read_property_ex(i_get_exception_base(ancestor), ancestor, ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv); } base_ce = i_get_exception_base(ex); previous = zend_read_property_ex(base_ce, ex, ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv); if (Z_TYPE_P(previous) == IS_NULL) { zend_update_property_ex(base_ce, ex, ZSTR_KNOWN(ZEND_STR_PREVIOUS), &pv); GC_DELREF(add_previous); return; } ex = previous; } while (Z_OBJ_P(ex) != add_previous); }
/* {{{ zend_sigaction * Register a signal handler that will be deferred in critical sections */ ZEND_API int zend_sigaction(int signo, const struct sigaction *act, struct sigaction *oldact) { struct sigaction sa = {{0}}; sigset_t sigset; if (oldact != NULL) { oldact->sa_flags = SIGG(handlers)[signo-1].flags; oldact->sa_handler = (void *) SIGG(handlers)[signo-1].handler; oldact->sa_mask = global_sigmask; } if (act != NULL) { SIGG(handlers)[signo-1].flags = act->sa_flags; if (act->sa_flags & SA_SIGINFO) { SIGG(handlers)[signo-1].handler = (void *) act->sa_sigaction; } else { SIGG(handlers)[signo-1].handler = (void *) act->sa_handler; } sa.sa_flags = SA_SIGINFO | (act->sa_flags & SA_FLAGS_MASK); sa.sa_sigaction = zend_signal_handler_defer; sa.sa_mask = global_sigmask; if (sigaction(signo, &sa, NULL) < 0) { zend_error_noreturn(E_ERROR, "Error installing signal handler for %d", signo); } /* unsure this signal is not blocked */ sigemptyset(&sigset); sigaddset(&sigset, signo); zend_sigprocmask(SIG_UNBLOCK, &sigset, NULL); } return SUCCESS; }
/* {{{ zend_implement_aggregate */ static int zend_implement_aggregate(zend_class_entry *interface, zend_class_entry *class_type) { uint32_t i; int t = -1; zend_class_iterator_funcs *funcs_ptr; if (class_type->get_iterator) { if (class_type->type == ZEND_INTERNAL_CLASS) { /* inheritance ensures the class has necessary userland methods */ return SUCCESS; } else if (class_type->get_iterator != zend_user_it_get_new_iterator) { /* c-level get_iterator cannot be changed (exception being only Traversable is implemented) */ if (class_type->num_interfaces) { ZEND_ASSERT(class_type->ce_flags & (ZEND_ACC_LINKED|ZEND_ACC_LINKING_IN_PROGRESS)); for (i = 0; i < class_type->num_interfaces; i++) { if (class_type->interfaces[i] == zend_ce_iterator) { zend_error_noreturn(E_ERROR, "Class %s cannot implement both %s and %s at the same time", ZSTR_VAL(class_type->name), ZSTR_VAL(interface->name), ZSTR_VAL(zend_ce_iterator->name)); return FAILURE; } if (class_type->interfaces[i] == zend_ce_traversable) { t = i; } } } if (t == -1) { return FAILURE; } } } if (class_type->parent && (class_type->parent->ce_flags & ZEND_ACC_REUSE_GET_ITERATOR)) { class_type->get_iterator = class_type->parent->get_iterator; class_type->ce_flags |= ZEND_ACC_REUSE_GET_ITERATOR; } else { class_type->get_iterator = zend_user_it_get_new_iterator; } funcs_ptr = class_type->iterator_funcs_ptr; if (class_type->type == ZEND_INTERNAL_CLASS) { if (!funcs_ptr) { funcs_ptr = calloc(1, sizeof(zend_class_iterator_funcs)); class_type->iterator_funcs_ptr = funcs_ptr; } funcs_ptr->zf_new_iterator = zend_hash_str_find_ptr(&class_type->function_table, "getiterator", sizeof("getiterator") - 1); } else { if (!funcs_ptr) { funcs_ptr = zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs)); class_type->iterator_funcs_ptr = funcs_ptr; memset(funcs_ptr, 0, sizeof(zend_class_iterator_funcs)); } else { funcs_ptr->zf_new_iterator = NULL; } } return SUCCESS; }
/* {{{ unset an object property */ void pthreads_unset_property(PTHREADS_UNSET_PROPERTY_PASSTHRU_D) { PTHREAD pthreads = PTHREADS_FETCH_FROM(object); if (pthreads_store_delete(pthreads->store, Z_STRVAL_P(member), Z_STRLEN_P(member) TSRMLS_CC)!=SUCCESS){ zend_error_noreturn( E_WARNING, "pthreads has experienced an internal error while deleting %s::$%s", Z_OBJCE_P(object)->name, Z_STRVAL_P(member) ); } zend_handlers->unset_property(PTHREADS_UNSET_PROPERTY_PASSTHRU_C); }
/* {{{ zend_implement_iterator */ static int zend_implement_iterator(zend_class_entry *interface, zend_class_entry *class_type) { zend_class_iterator_funcs *funcs_ptr; if (class_type->get_iterator && class_type->get_iterator != zend_user_it_get_iterator) { if (class_type->type == ZEND_INTERNAL_CLASS) { /* inheritance ensures the class has the necessary userland methods */ return SUCCESS; } else { /* c-level get_iterator cannot be changed */ if (class_type->get_iterator == zend_user_it_get_new_iterator) { zend_error_noreturn(E_ERROR, "Class %s cannot implement both %s and %s at the same time", ZSTR_VAL(class_type->name), ZSTR_VAL(interface->name), ZSTR_VAL(zend_ce_aggregate->name)); } return FAILURE; } } if (class_type->parent && (class_type->parent->ce_flags & ZEND_ACC_REUSE_GET_ITERATOR)) { class_type->get_iterator = class_type->parent->get_iterator; class_type->ce_flags |= ZEND_ACC_REUSE_GET_ITERATOR; } else { class_type->get_iterator = zend_user_it_get_iterator; } funcs_ptr = class_type->iterator_funcs_ptr; if (class_type->type == ZEND_INTERNAL_CLASS) { if (!funcs_ptr) { funcs_ptr = calloc(1, sizeof(zend_class_iterator_funcs)); class_type->iterator_funcs_ptr = funcs_ptr; } else { funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1); funcs_ptr->zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1); funcs_ptr->zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1); funcs_ptr->zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1); funcs_ptr->zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1); } } else { if (!funcs_ptr) { funcs_ptr = zend_arena_alloc(&CG(arena), sizeof(zend_class_iterator_funcs)); class_type->iterator_funcs_ptr = funcs_ptr; memset(funcs_ptr, 0, sizeof(zend_class_iterator_funcs)); } else { funcs_ptr->zf_valid = NULL; funcs_ptr->zf_current = NULL; funcs_ptr->zf_key = NULL; funcs_ptr->zf_next = NULL; funcs_ptr->zf_rewind = NULL; } } return SUCCESS; }
/* {{{ zend_implement_throwable */ static int zend_implement_throwable(zend_class_entry *interface, zend_class_entry *class_type) { if (instanceof_function(class_type, zend_ce_exception) || instanceof_function(class_type, zend_ce_error)) { return SUCCESS; } zend_error_noreturn(E_ERROR, "Class %s cannot implement interface %s, extend %s or %s instead", ZSTR_VAL(class_type->name), ZSTR_VAL(interface->name), ZSTR_VAL(zend_ce_exception->name), ZSTR_VAL(zend_ce_error->name)); return FAILURE; }
ZEND_API ZEND_COLD void zend_throw_exception_internal(zval *exception) /* {{{ */ { #ifdef HAVE_DTRACE if (DTRACE_EXCEPTION_THROWN_ENABLED()) { if (exception != NULL) { DTRACE_EXCEPTION_THROWN(ZSTR_VAL(Z_OBJ_P(exception)->ce->name)); } else { DTRACE_EXCEPTION_THROWN(NULL); } } #endif /* HAVE_DTRACE */ if (exception != NULL) { zend_object *previous = EG(exception); zend_exception_set_previous(Z_OBJ_P(exception), EG(exception)); EG(exception) = Z_OBJ_P(exception); if (previous) { return; } } if (!EG(current_execute_data)) { if (exception && Z_OBJCE_P(exception) == zend_ce_parse_error) { return; } if(EG(exception)) { zend_exception_error(EG(exception), E_ERROR); } zend_error_noreturn(E_CORE_ERROR, "Exception thrown without a stack frame"); } if (zend_throw_exception_hook) { zend_throw_exception_hook(exception); } if (!EG(current_execute_data)->func || !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) || EG(current_execute_data)->opline->opcode == ZEND_HANDLE_EXCEPTION) { /* no need to rethrow the exception */ return; } EG(opline_before_exception) = EG(current_execute_data)->opline; EG(current_execute_data)->opline = EG(exception_op); }
ZEND_API void zval_internal_ptr_dtor(zval *zval_ptr) /* {{{ */ { if (Z_REFCOUNTED_P(zval_ptr)) { zend_refcounted *ref = Z_COUNTED_P(zval_ptr); if (GC_DELREF(ref) == 0) { if (Z_TYPE_P(zval_ptr) == IS_STRING) { zend_string *str = (zend_string*)ref; CHECK_ZVAL_STRING(str); ZEND_ASSERT(!ZSTR_IS_INTERNED(str)); ZEND_ASSERT((GC_FLAGS(str) & IS_STR_PERSISTENT)); free(str); } else { zend_error_noreturn(E_CORE_ERROR, "Internal zval's can't be arrays, objects, resources or reference"); } } } }
/* {{{ zend_implement_traversable */ static int zend_implement_traversable(zend_class_entry *interface, zend_class_entry *class_type) { /* check that class_type is traversable at c-level or implements at least one of 'aggregate' and 'Iterator' */ uint32_t i; if (class_type->get_iterator || (class_type->parent && class_type->parent->get_iterator)) { return SUCCESS; } for (i = 0; i < class_type->num_interfaces; i++) { if (class_type->interfaces[i] == zend_ce_aggregate || class_type->interfaces[i] == zend_ce_iterator) { return SUCCESS; } } zend_error_noreturn(E_CORE_ERROR, "Class %s must implement interface %s as part of either %s or %s", class_type->name->val, zend_ce_traversable->name->val, zend_ce_iterator->name->val, zend_ce_aggregate->name->val); return FAILURE; }
/* {{{ zend_implement_traversable */ static int zend_implement_traversable(zend_class_entry *interface, zend_class_entry *class_type) { /* check that class_type is traversable at c-level or implements at least one of 'aggregate' and 'Iterator' */ uint32_t i; if (class_type->get_iterator || (class_type->parent && class_type->parent->get_iterator)) { return SUCCESS; } if (class_type->num_interfaces) { ZEND_ASSERT(class_type->ce_flags & (ZEND_ACC_LINKED|ZEND_ACC_LINKING_IN_PROGRESS)); for (i = 0; i < class_type->num_interfaces; i++) { if (class_type->interfaces[i] == zend_ce_aggregate || class_type->interfaces[i] == zend_ce_iterator) { return SUCCESS; } } } zend_error_noreturn(E_CORE_ERROR, "Class %s must implement interface %s as part of either %s or %s", ZSTR_VAL(class_type->name), ZSTR_VAL(zend_ce_traversable->name), ZSTR_VAL(zend_ce_iterator->name), ZSTR_VAL(zend_ce_aggregate->name)); return FAILURE; }
/* {{{ writes a property to a thread in the appropriate way */ void pthreads_write_property(PTHREADS_WRITE_PROPERTY_PASSTHRU_D) { PTHREAD pthreads = PTHREADS_FETCH_FROM(object); if (Z_TYPE_P(member)==IS_STRING) { switch(Z_TYPE_P(value)){ case IS_STRING: case IS_LONG: case IS_ARRAY: case IS_OBJECT: case IS_NULL: case IS_DOUBLE: case IS_BOOL: { if (pthreads_store_write(pthreads->store, Z_STRVAL_P(member), Z_STRLEN_P(member), &value TSRMLS_CC)!=SUCCESS){ zend_error_noreturn( E_WARNING, "pthreads failed to write member %s::$%s", Z_OBJCE_P(object)->name, Z_STRVAL_P(member) ); } else zend_handlers->write_property(PTHREADS_WRITE_PROPERTY_PASSTHRU_C); } break; default: zend_handlers->write_property(PTHREADS_WRITE_PROPERTY_PASSTHRU_C); } } else zend_handlers->write_property(PTHREADS_WRITE_PROPERTY_PASSTHRU_C); }
ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope, zend_ulong flags) { zend_constant *c; const char *colon; zend_class_entry *ce = NULL; zend_string *class_name; const char *name = cname->val; size_t name_len = cname->len; /* Skip leading \\ */ if (name[0] == '\\') { name += 1; name_len -= 1; cname = NULL; } if ((colon = zend_memrchr(name, ':', name_len)) && colon > name && (*(colon - 1) == ':')) { int class_name_len = colon - name - 1; size_t const_name_len = name_len - class_name_len - 2; zend_string *constant_name = zend_string_init(colon + 1, const_name_len, 0); char *lcname; zval *ret_constant = NULL; ALLOCA_FLAG(use_heap) class_name = zend_string_init(name, class_name_len, 0); lcname = do_alloca(class_name_len + 1, use_heap); zend_str_tolower_copy(lcname, name, class_name_len); if (!scope) { if (EG(current_execute_data)) { scope = EG(scope); } else { scope = CG(active_class_entry); } } if (class_name_len == sizeof("self")-1 && !memcmp(lcname, "self", sizeof("self")-1)) { if (scope) { ce = scope; } else { zend_error_noreturn(E_ERROR, "Cannot access self:: when no class scope is active"); } } else if (class_name_len == sizeof("parent")-1 && !memcmp(lcname, "parent", sizeof("parent")-1)) { if (!scope) { zend_error_noreturn(E_ERROR, "Cannot access parent:: when no class scope is active"); } else if (!scope->parent) { zend_error_noreturn(E_ERROR, "Cannot access parent:: when current class scope has no parent"); } else { ce = scope->parent; } } else if (class_name_len == sizeof("static")-1 && !memcmp(lcname, "static", sizeof("static")-1)) { if (EG(current_execute_data) && EG(current_execute_data)->called_scope) { ce = EG(current_execute_data)->called_scope; } else { zend_error_noreturn(E_ERROR, "Cannot access static:: when no class scope is active"); } } else { ce = zend_fetch_class(class_name, flags); } free_alloca(lcname, use_heap); if (ce) { ret_constant = zend_hash_find(&ce->constants_table, constant_name); if (ret_constant == NULL) { if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) { zend_error_noreturn(E_ERROR, "Undefined class constant '%s::%s'", class_name->val, constant_name->val); } } else if (Z_ISREF_P(ret_constant)) { ret_constant = Z_REFVAL_P(ret_constant); } } zend_string_release(class_name); zend_string_free(constant_name); if (ret_constant && Z_CONSTANT_P(ret_constant)) { zval_update_constant_ex(ret_constant, 1, ce); } return ret_constant; } /* non-class constant */ if ((colon = zend_memrchr(name, '\\', name_len)) != NULL) { /* compound constant name */ int prefix_len = colon - name; size_t const_name_len = name_len - prefix_len - 1; const char *constant_name = colon + 1; char *lcname; size_t lcname_len; ALLOCA_FLAG(use_heap) lcname_len = prefix_len + 1 + const_name_len; lcname = do_alloca(lcname_len + 1, use_heap); zend_str_tolower_copy(lcname, name, prefix_len); /* Check for namespace constant */ lcname[prefix_len] = '\\'; memcpy(lcname + prefix_len + 1, constant_name, const_name_len + 1); if ((c = zend_hash_str_find_ptr(EG(zend_constants), lcname, lcname_len)) == NULL) { /* try lowercase */ zend_str_tolower(lcname + prefix_len + 1, const_name_len); if ((c = zend_hash_str_find_ptr(EG(zend_constants), lcname, lcname_len)) != NULL) { if ((c->flags & CONST_CS) != 0) { c = NULL; } } } free_alloca(lcname, use_heap); if (c) { return &c->value; } /* name requires runtime resolution, need to check non-namespaced name */ if ((flags & IS_CONSTANT_UNQUALIFIED) != 0) { return zend_get_constant_str(constant_name, const_name_len); } return NULL; } if (cname) { return zend_get_constant(cname); } else { return zend_get_constant_str(name, name_len); } }
/* {{{ zend_call_method Only returns the returned zval if retval_ptr != NULL */ ZEND_API zval* zend_call_method(zend_object *object, zend_class_entry *obj_ce, zend_function **fn_proxy, const char *function_name, size_t function_name_len, zval *retval_ptr, int param_count, zval* arg1, zval* arg2) { int result; zend_fcall_info fci; zval retval; zval params[2]; if (param_count > 0) { ZVAL_COPY_VALUE(¶ms[0], arg1); } if (param_count > 1) { ZVAL_COPY_VALUE(¶ms[1], arg2); } fci.size = sizeof(fci); fci.object = object; fci.retval = retval_ptr ? retval_ptr : &retval; fci.param_count = param_count; fci.params = params; fci.no_separation = 1; if (!fn_proxy && !obj_ce) { /* no interest in caching and no information already present that is * needed later inside zend_call_function. */ ZVAL_STRINGL(&fci.function_name, function_name, function_name_len); result = zend_call_function(&fci, NULL); zval_ptr_dtor(&fci.function_name); } else { zend_fcall_info_cache fcic; ZVAL_UNDEF(&fci.function_name); /* Unused */ if (!obj_ce) { obj_ce = object ? object->ce : NULL; } if (!fn_proxy || !*fn_proxy) { if (EXPECTED(obj_ce)) { fcic.function_handler = zend_hash_str_find_ptr( &obj_ce->function_table, function_name, function_name_len); if (UNEXPECTED(fcic.function_handler == NULL)) { /* error at c-level */ zend_error_noreturn(E_CORE_ERROR, "Couldn't find implementation for method %s::%s", ZSTR_VAL(obj_ce->name), function_name); } } else { fcic.function_handler = zend_fetch_function_str(function_name, function_name_len); if (UNEXPECTED(fcic.function_handler == NULL)) { /* error at c-level */ zend_error_noreturn(E_CORE_ERROR, "Couldn't find implementation for function %s", function_name); } } if (fn_proxy) { *fn_proxy = fcic.function_handler; } } else { fcic.function_handler = *fn_proxy; } if (object) { fcic.called_scope = object->ce; } else { zend_class_entry *called_scope = zend_get_called_scope(EG(current_execute_data)); if (obj_ce && (!called_scope || !instanceof_function(called_scope, obj_ce))) { fcic.called_scope = obj_ce; } else { fcic.called_scope = called_scope; } } fcic.object = object; result = zend_call_function(&fci, &fcic); } if (result == FAILURE) { /* error at c-level */ if (!obj_ce) { obj_ce = object ? object->ce : NULL; } if (!EG(exception)) { zend_error_noreturn(E_CORE_ERROR, "Couldn't execute method %s%s%s", obj_ce ? ZSTR_VAL(obj_ce->name) : "", obj_ce ? "::" : "", function_name); } } if (!retval_ptr) { zval_ptr_dtor(&retval); return NULL; } return retval_ptr; }
/* {{{ zend_call_method Only returns the returned zval if retval_ptr != NULL */ ZEND_API zval* zend_call_method(zval *object, zend_class_entry *obj_ce, zend_function **fn_proxy, const char *function_name, size_t function_name_len, zval *retval_ptr, int param_count, zval* arg1, zval* arg2) { int result; zend_fcall_info fci; zval retval; HashTable *function_table; zval params[2]; if (param_count > 0) { ZVAL_COPY_VALUE(¶ms[0], arg1); } if (param_count > 1) { ZVAL_COPY_VALUE(¶ms[1], arg2); } fci.size = sizeof(fci); /*fci.function_table = NULL; will be read form zend_class_entry of object if needed */ fci.object = (object && Z_TYPE_P(object) == IS_OBJECT) ? Z_OBJ_P(object) : NULL; ZVAL_STRINGL(&fci.function_name, function_name, function_name_len); fci.retval = retval_ptr ? retval_ptr : &retval; fci.param_count = param_count; fci.params = params; fci.no_separation = 1; fci.symbol_table = NULL; if (!fn_proxy && !obj_ce) { /* no interest in caching and no information already present that is * needed later inside zend_call_function. */ fci.function_table = !object ? EG(function_table) : NULL; result = zend_call_function(&fci, NULL); zval_ptr_dtor(&fci.function_name); } else { zend_fcall_info_cache fcic; fcic.initialized = 1; if (!obj_ce) { obj_ce = object ? Z_OBJCE_P(object) : NULL; } if (obj_ce) { function_table = &obj_ce->function_table; } else { function_table = EG(function_table); } if (!fn_proxy || !*fn_proxy) { if ((fcic.function_handler = zend_hash_find_ptr(function_table, Z_STR(fci.function_name))) == NULL) { /* error at c-level */ zend_error_noreturn(E_CORE_ERROR, "Couldn't find implementation for method %s%s%s", obj_ce ? obj_ce->name->val : "", obj_ce ? "::" : "", function_name); } if (fn_proxy) { *fn_proxy = fcic.function_handler; } } else { fcic.function_handler = *fn_proxy; } fcic.calling_scope = obj_ce; if (object) { fcic.called_scope = Z_OBJCE_P(object); } else { zend_class_entry *called_scope = zend_get_called_scope(EG(current_execute_data)); if (obj_ce && (!called_scope || !instanceof_function(called_scope, obj_ce))) { fcic.called_scope = obj_ce; } else { fcic.called_scope = called_scope; } } fcic.object = object ? Z_OBJ_P(object) : NULL; result = zend_call_function(&fci, &fcic); zval_ptr_dtor(&fci.function_name); } if (result == FAILURE) { /* error at c-level */ if (!obj_ce) { obj_ce = object ? Z_OBJCE_P(object) : NULL; } if (!EG(exception)) { zend_error_noreturn(E_CORE_ERROR, "Couldn't execute method %s%s%s", obj_ce ? obj_ce->name->val : "", obj_ce ? "::" : "", function_name); } } /* copy arguments back, they might be changed by references */ if (param_count > 0 && Z_ISREF(params[0]) && !Z_ISREF_P(arg1)) { ZVAL_COPY_VALUE(arg1, ¶ms[0]); } if (param_count > 1 && Z_ISREF(params[1]) && !Z_ISREF_P(arg2)) { ZVAL_COPY_VALUE(arg2, ¶ms[1]); } if (!retval_ptr) { zval_ptr_dtor(&retval); return NULL; } return retval_ptr; }
/* {{{ pthreads_call_method */ int pthreads_call_method(PTHREADS_CALL_METHOD_PASSTHRU_D) { zval ***argv = NULL, zmethod, *zresult; zend_function *call = NULL; zend_fcall_info info; zend_fcall_info_cache cache; zend_class_entry *scope; int called = -1, argc = ZEND_NUM_ARGS(), access = ZEND_ACC_PUBLIC, mlength = 0; char *lcname; zend_bool unprotect; if (getThis()) { PTHREAD thread = PTHREADS_FETCH; if (thread) { switch((access=pthreads_modifiers_get(thread->modifiers, method TSRMLS_CC))){ case ZEND_ACC_PRIVATE: case ZEND_ACC_PROTECTED: { scope = Z_OBJCE_P(getThis()); /* * Stop invalid private method calls */ if (access == ZEND_ACC_PRIVATE && !PTHREADS_IN_THREAD(thread)) { zend_error_noreturn( E_ERROR, "pthreads detected an attempt to call private method %s::%s from outside the threading context", scope->name, method ); return FAILURE; } /* * Get arguments from stack */ if (ZEND_NUM_ARGS()) { argv = safe_emalloc(sizeof(zval **), argc, 0); if (argv) { zend_get_parameters_array_ex(argc, argv); } } mlength = strlen(method); lcname = calloc(1, mlength+1); zend_str_tolower_copy(lcname, method, mlength); if (zend_hash_find(&scope->function_table, lcname, mlength+1, (void**)&call)==SUCCESS) { if (call) { /* * Make protected method call */ { if (access != ZEND_ACC_PROTECTED || pthreads_modifiers_protect(thread->modifiers, method, &unprotect TSRMLS_CC)) { ZVAL_STRINGL(&zmethod, method, strlen(method), 0); info.size = sizeof(info); info.object_ptr = getThis(); info.function_name = &zmethod; info.retval_ptr_ptr = &zresult; info.no_separation = 1; info.symbol_table = NULL; info.param_count = argc; info.params = argv; cache.initialized = 1; cache.function_handler = call; cache.calling_scope = EG(called_scope); cache.called_scope = scope; cache.object_ptr = getThis(); if ((called=zend_call_function(&info, &cache TSRMLS_CC))!=SUCCESS) { zend_error_noreturn( E_ERROR, "pthreads has experienced an internal error while calling %s method %s::%s and cannot continue", (access == ZEND_ACC_PROTECTED) ? "protected" : "private", scope->name, method ); } else { #if PHP_VERSION_ID > 50399 { zend_op_array *ops = (zend_op_array*) call; if (ops) { if (ops->run_time_cache) { efree(ops->run_time_cache); ops->run_time_cache = NULL; } } } #endif if (!return_value_used) { zval_ptr_dtor(&zresult); } else { ZVAL_ZVAL(return_value, zresult, 1, 1); } } if (access == ZEND_ACC_PROTECTED) { pthreads_modifiers_unprotect(thread->modifiers, method, unprotect TSRMLS_CC); } } else { zend_error_noreturn( E_ERROR, "pthreads has experienced an internal error while calling %s method %s::%s and cannot continue", (access == ZEND_ACC_PROTECTED) ? "protected" : "private", scope->name, method ); called = FAILURE; } } } else { zend_error_noreturn( E_ERROR, "pthreads has experienced an internal error while finding %s method %s::%s and cannot continue", (access == ZEND_ACC_PROTECTED) ? "protected" : "private", scope->name, method ); called = FAILURE; } } /* * Free unstacked arguments */ if (argc) { efree(argv); } free(lcname); return called; } break; } } } switch (called) { case -1: return zend_handlers->call_method(PTHREADS_CALL_METHOD_PASSTHRU_C); default: return called; } } /* }}} */
static void dic_optimizer_get_handler(INTERNAL_FUNCTION_PARAMETERS) { char *id, should_free = 1; zend_ulong id_hash; int id_len, i; long oninvalid, exception_on_invalid_reference_const; zval **found_service, **alias, **method_in_map = NULL, *this_services, *this_aliases, *this_methodMap, *this_loading; zend_function *method = NULL; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &id, &id_len, &oninvalid) == FAILURE) { return; } if (strcasecmp(id, "service_container") == 0) { RETURN_THIS; } this_services = zend_read_property(Z_OBJCE_P(getThis()), getThis(), SYMFONY_DIC_TOKEN_SERVICES_KEY, sizeof(SYMFONY_DIC_TOKEN_SERVICES_KEY) - 1, 0 TSRMLS_CC); this_aliases = zend_read_property(Z_OBJCE_P(getThis()), getThis(), SYMFONY_DIC_TOKEN_ALIASES_KEY, sizeof(SYMFONY_DIC_TOKEN_ALIASES_KEY) - 1, 0 TSRMLS_CC); this_loading = zend_read_property(Z_OBJCE_P(getThis()), getThis(), SYMFONY_DIC_TOKEN_LOADING_KEY, sizeof(SYMFONY_DIC_TOKEN_LOADING_KEY) - 1, 0 TSRMLS_CC); this_methodMap = zend_read_property(Z_OBJCE_P(getThis()), getThis(), SYMFONY_DIC_TOKEN_METHODMAP_KEY, sizeof(SYMFONY_DIC_TOKEN_METHODMAP_KEY) - 1, 0 TSRMLS_CC); if (!SYMFONY_DIC_G(cache_done)) { zval invalidBehavior; zend_class_entry **exception_ce; zend_get_constant_ex("self::EXCEPTION_ON_INVALID_REFERENCE", sizeof("self::EXCEPTION_ON_INVALID_REFERENCE") - 1, &invalidBehavior, Z_OBJCE_P(getThis()), 0 TSRMLS_CC); SYMFONY_DIC_G(invalid_behavior) = Z_LVAL(invalidBehavior); if (FAILURE == zend_lookup_class(SYMFONY_DIC_TOKEN_SERVICE_CIRCULAR_REFERENCE_EXCEPTION_KEY_UP, sizeof(SYMFONY_DIC_TOKEN_SERVICE_CIRCULAR_REFERENCE_EXCEPTION_KEY_UP) - 1, &exception_ce TSRMLS_CC)) { zend_error_noreturn(E_ERROR, "Class %s not found", SYMFONY_DIC_TOKEN_SERVICE_CIRCULAR_REFERENCE_EXCEPTION_KEY_UP); } SYMFONY_DIC_G(ServiceCircularReferenceException) = *exception_ce; if (FAILURE == zend_lookup_class(SYMFONY_DIC_TOKEN_SERVICE_NOT_FOUND_EXCEPTION_KEY_UP, sizeof(SYMFONY_DIC_TOKEN_SERVICE_NOT_FOUND_EXCEPTION_KEY_UP) - 1, &exception_ce TSRMLS_CC)) { zend_error_noreturn(E_ERROR, "Class %s not found", SYMFONY_DIC_TOKEN_SERVICE_NOT_FOUND_EXCEPTION_KEY_UP); } SYMFONY_DIC_G(ServiceNotFoundException) = *exception_ce; if (FAILURE == zend_lookup_class(SYMFONY_DIC_TOKEN_INACTIVE_SCOPE_EXCEPTION_KEY_UP, sizeof(SYMFONY_DIC_TOKEN_INACTIVE_SCOPE_EXCEPTION_KEY_UP) - 1, &exception_ce TSRMLS_CC)) { zend_error_noreturn(E_ERROR, "Class %s not found", SYMFONY_DIC_TOKEN_INACTIVE_SCOPE_EXCEPTION_KEY_UP); } SYMFONY_DIC_G(InactiveScopeException) = *exception_ce; SYMFONY_DIC_G(cache_done) = 1; } exception_on_invalid_reference_const = SYMFONY_DIC_G(invalid_behavior); if (ZEND_NUM_ARGS() <= 1) { oninvalid = exception_on_invalid_reference_const; } if (IS_INTERNED(id)) { id_hash = INTERNED_HASH(id); } else { id_hash = zend_inline_hash_func(id, id_len + 1); } id = estrndup(id, id_len); /* zend_str_tolower will change it otherwise */ for (i = 0; i <= 1; i++, zend_str_tolower(id, id_len), id_hash = zend_inline_hash_func(id, id_len + 1)) { if (zend_hash_quick_find(Z_ARRVAL_P(this_aliases), id, id_len + 1, id_hash, (void **)&alias) == SUCCESS) { should_free = 0; efree(id); id = Z_STRVAL_PP(alias); id_len = Z_STRLEN_PP(alias); id_hash = zend_inline_hash_func(id, id_len + 1); } if (zend_hash_quick_find(Z_ARRVAL_P(this_services), id, id_len + 1, id_hash, (void **)&found_service) == SUCCESS) { RETVAL_ZVAL_FAST(*found_service); goto free_and_return; } } if (zend_hash_quick_exists(Z_ARRVAL_P(this_loading), id, id_len + 1, id_hash)) { zval *ServiceCircularReferenceException; ALLOC_INIT_ZVAL(ServiceCircularReferenceException); /* ctor_args */ object_init_ex(ServiceCircularReferenceException, SYMFONY_DIC_G(ServiceCircularReferenceException)); zend_throw_exception_object(ServiceCircularReferenceException TSRMLS_CC); goto free_and_return; } zend_hash_quick_find(Z_ARRVAL_P(this_methodMap), id, id_len + 1, id_hash, (void **)&method_in_map); if (!method_in_map) { char *new_id; for (i=0; i < id_len; i++) { if (id[i] == '_') { memmove(&id[i], &id[i + 1], --id_len); } } php_strtr(id, id_len, ".\\", "__", 2); id_len = spprintf(&new_id, 0, "get%sservice", id); efree(id); id = new_id; id_hash = zend_inline_hash_func(id, id_len + 1); zend_hash_quick_find(&Z_OBJCE_P(getThis())->function_table, id, id_len + 1, id_hash, (void **)&method); if (!method) { if (oninvalid == exception_on_invalid_reference_const) { zval *ServiceNotFoundException; ALLOC_INIT_ZVAL(ServiceNotFoundException); object_init_ex(ServiceNotFoundException, SYMFONY_DIC_G(ServiceNotFoundException)); zend_throw_exception_object(ServiceNotFoundException TSRMLS_CC); /* ctor_args */ } goto free_and_return; } } else { char *method_name_lc; method_name_lc = zend_str_tolower_dup(Z_STRVAL_PP(method_in_map), Z_STRLEN_PP(method_in_map)); zend_hash_find(&Z_OBJCE_P(getThis())->function_table, method_name_lc, Z_STRLEN_PP(method_in_map) + 1, (void **)&method); efree(method_name_lc); } zend_fcall_info fci = {0}; zend_fcall_info_cache fcic = {0}; zval *loading, *result; ALLOC_INIT_ZVAL(loading); ZVAL_BOOL(loading, 1); zend_hash_quick_add(Z_ARRVAL_P(this_loading), id, id_len + 1, id_hash, &loading, sizeof(zval *), NULL); fcic.called_scope = Z_OBJCE_P(getThis()); fcic.calling_scope = Z_OBJCE_P(getThis()); fcic.function_handler = method; fcic.initialized = 1; fcic.object_ptr = getThis(); fci.retval_ptr_ptr = &result; fci.size = sizeof(zend_fcall_info); zend_call_function(&fci, &fcic TSRMLS_CC); zend_hash_quick_del(Z_ARRVAL_P(this_loading), id, id_len + 1, id_hash); if (!EG(exception)) { RETVAL_ZVAL_FAST(result); } else { zend_hash_quick_del(Z_ARRVAL_P(this_services), id, id_len, id_hash); if (instanceof_function(Z_OBJCE_P(EG(exception)), SYMFONY_DIC_G(InactiveScopeException) TSRMLS_CC) && oninvalid == exception_on_invalid_reference_const) { EG(exception) = NULL; } } zval_ptr_dtor(&result); free_and_return: if (should_free) { efree(id); } return; }
apc_segment_t apc_mmap(char *file_mask, size_t size) { apc_segment_t segment; int fd = -1; int flags = MAP_SHARED | MAP_NOSYNC; #ifdef APC_MEMPROTECT int remap = 1; #endif /* If no filename was provided, do an anonymous mmap */ if(!file_mask || (file_mask && !strlen(file_mask))) { #if !defined(MAP_ANON) zend_error_noreturn(E_CORE_ERROR, "Anonymous mmap does not appear to be available on this system (MAP_ANON/MAP_ANONYMOUS). Please see the apc.mmap_file_mask INI option."); #else fd = -1; flags = MAP_SHARED | MAP_ANON; #ifdef APC_MEMPROTECT remap = 0; #endif #endif } else if(!strcmp(file_mask,"/dev/zero")) { fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR); if(fd == -1) { zend_error_noreturn(E_CORE_ERROR, "apc_mmap: open on /dev/zero failed"); } #ifdef APC_MEMPROTECT remap = 0; /* cannot remap */ #endif } else { /* * Otherwise we do a normal filesystem mmap */ fd = mkstemp(file_mask); if(fd == -1) { zend_error_noreturn(E_CORE_ERROR, "apc_mmap: mkstemp on %s failed", file_mask); } if (ftruncate(fd, size) < 0) { close(fd); unlink(file_mask); zend_error_noreturn(E_CORE_ERROR, "apc_mmap: ftruncate failed"); } unlink(file_mask); } segment.shmaddr = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE, flags, fd, 0); segment.size = size; #ifdef APC_MEMPROTECT if(remap) { segment.roaddr = (void *)mmap(NULL, size, PROT_READ, flags, fd, 0); } else { segment.roaddr = NULL; } #endif if ((long)segment.shmaddr == -1) { zend_error_noreturn(E_CORE_ERROR, "apc_mmap: Failed to mmap %zu bytes. Is your apc.shm_size too large?", size); } if (fd != -1) close(fd); return segment; }