From 5ae93b2284bcd1bc657e5190940dbc6fdfc61c7e Mon Sep 17 00:00:00 2001 From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> Date: Wed, 14 Jun 2017 20:05:02 +0300 Subject: [PATCH] schema: make func_def be pointer in struct func Need for #944 --- src/box/alter.cc | 72 ++++++++++++++++++++++++++-------------- src/box/box.cc | 10 +++--- src/box/func.cc | 16 +++++---- src/box/func.h | 2 +- src/box/key_def.h | 14 +++++++- src/box/schema.cc | 14 ++++---- src/box/schema.h | 7 ++++ src/box/sysview_index.cc | 2 +- src/box/tuple.h | 31 ++++++++++++++--- 9 files changed, 119 insertions(+), 49 deletions(-) diff --git a/src/box/alter.cc b/src/box/alter.cc index 9b29fac379..95027043e8 100644 --- a/src/box/alter.cc +++ b/src/box/alter.cc @@ -1687,19 +1687,37 @@ on_replace_dd_user(struct trigger * /* trigger */, void *event) } } +/** + * Get function identifiers from a tuple. + * + * @param tuple Tuple to get ids from. + * @param[out] fid Function identifier. + * @param[out] uid Owner identifier. + */ +static inline void +func_def_get_ids_from_tuple(const struct tuple *tuple, uint32_t *fid, + uint32_t *uid) +{ + *fid = tuple_field_u32_xc(tuple, BOX_FUNC_FIELD_ID); + *uid = tuple_field_u32_xc(tuple, BOX_FUNC_FIELD_UID); +} + /** Create a function definition from tuple. */ -static void -func_def_create_from_tuple(struct func_def *def, struct tuple *tuple) +static struct func_def * +func_def_new_from_tuple(const struct tuple *tuple) { - def->fid = tuple_field_u32_xc(tuple, BOX_FUNC_FIELD_ID); - def->uid = tuple_field_u32_xc(tuple, BOX_FUNC_FIELD_UID); - const char *name = tuple_field_cstr_xc(tuple, BOX_FUNC_FIELD_NAME); - uint32_t len = strlen(name); - if (len >= sizeof(def->name)) { + uint32_t len; + const char *name = tuple_field_str_xc(tuple, BOX_FUNC_FIELD_NAME, + &len); + if (len > BOX_NAME_MAX) tnt_raise(ClientError, ER_CREATE_FUNCTION, - name, "function name is too long"); - } - snprintf(def->name, sizeof(def->name), "%s", name); + tt_cstr(name, len), "function name is too long"); + struct func_def *def = (struct func_def *) malloc(func_def_sizeof(len)); + if (def == NULL) + tnt_raise(OutOfMemory, func_def_sizeof(len), "malloc", "def"); + auto def_guard = make_scoped_guard([=] { free(def); }); + func_def_get_ids_from_tuple(tuple, &def->fid, &def->uid); + snprintf(def->name, len + 1, "%s", name); if (tuple_field_count(tuple) > BOX_FUNC_FIELD_SETUID) def->setuid = tuple_field_u32_xc(tuple, BOX_FUNC_FIELD_SETUID); else @@ -1710,12 +1728,14 @@ func_def_create_from_tuple(struct func_def *def, struct tuple *tuple) def->language = STR2ENUM(func_language, language); if (def->language == func_language_MAX) { tnt_raise(ClientError, ER_FUNCTION_LANGUAGE, - language, name); + language, def->name); } } else { /* Lua is the default. */ def->language = FUNC_LANGUAGE_LUA; } + def_guard.is_active = false; + return def; } /** Remove a function from function cache */ @@ -1734,9 +1754,10 @@ static void func_cache_replace_func(struct trigger * /* trigger */, void *event) { struct txn_stmt *stmt = txn_last_stmt((struct txn*) event); - struct func_def def; - func_def_create_from_tuple(&def, stmt->new_tuple); - func_cache_replace(&def); + struct func_def *def = func_def_new_from_tuple(stmt->new_tuple); + auto def_guard = make_scoped_guard([=] { free(def); }); + func_cache_replace(def); + def_guard.is_active = false; } /** @@ -1751,36 +1772,39 @@ on_replace_dd_func(struct trigger * /* trigger */, void *event) struct txn_stmt *stmt = txn_current_stmt(txn); struct tuple *old_tuple = stmt->old_tuple; struct tuple *new_tuple = stmt->new_tuple; - struct func_def def; uint32_t fid = tuple_field_u32_xc(old_tuple ? old_tuple : new_tuple, BOX_FUNC_FIELD_ID); struct func *old_func = func_by_id(fid); if (new_tuple != NULL && old_func == NULL) { /* INSERT */ - func_def_create_from_tuple(&def, new_tuple); - func_cache_replace(&def); + struct func_def *def = func_def_new_from_tuple(new_tuple); + auto def_guard = make_scoped_guard([=] { free(def); }); + func_cache_replace(def); + def_guard.is_active = false; struct trigger *on_rollback = txn_alter_trigger_new(func_cache_remove_func, NULL); txn_on_rollback(txn, on_rollback); } else if (new_tuple == NULL) { /* DELETE */ - func_def_create_from_tuple(&def, old_tuple); + uint32_t uid; + func_def_get_ids_from_tuple(old_tuple, &fid, &uid); /* * Can only delete func if you're the one * who created it or a superuser. */ - access_check_ddl(def.uid, SC_FUNCTION); + access_check_ddl(uid, SC_FUNCTION); /* Can only delete func if it has no grants. */ - if (schema_find_grants("function", old_func->def.fid)) { + if (schema_find_grants("function", old_func->def->fid)) { tnt_raise(ClientError, ER_DROP_FUNCTION, - (unsigned) old_func->def.uid, + (unsigned) old_func->def->uid, "function has grants"); } struct trigger *on_commit = txn_alter_trigger_new(func_cache_remove_func, NULL); txn_on_commit(txn, on_commit); } else { /* UPDATE, REPLACE */ - func_def_create_from_tuple(&def, new_tuple); - access_check_ddl(def.uid, SC_FUNCTION); + struct func_def *def = func_def_new_from_tuple(new_tuple); + auto def_guard = make_scoped_guard([=] { free(def); }); + access_check_ddl(def->uid, SC_FUNCTION); struct trigger *on_commit = txn_alter_trigger_new(func_cache_replace_func, NULL); txn_on_commit(txn, on_commit); @@ -1849,7 +1873,7 @@ priv_def_check(struct priv_def *priv) case SC_FUNCTION: { struct func *func = func_cache_find(priv->object_id); - if (func->def.uid != grantor->def.uid && + if (func->def->uid != grantor->def.uid && grantor->def.uid != ADMIN) { tnt_raise(ClientError, ER_ACCESS_DENIED, "Grant", schema_object_name(priv->object_type), diff --git a/src/box/box.cc b/src/box/box.cc index 70ecf2db82..a29436d463 100644 --- a/src/box/box.cc +++ b/src/box/box.cc @@ -927,7 +927,7 @@ access_check_func(const char *name, uint32_t name_len) if ((credentials->universal_access & PRIV_ALL) == PRIV_ALL) return func; uint8_t access = PRIV_X & ~credentials->universal_access; - if (func == NULL || (func->def.uid != credentials->uid && + if (func == NULL || (func->def->uid != credentials->uid && access & ~func->access[credentials->auth_token].effective)) { /* Access violation, report error. */ char name_buf[BOX_NAME_MAX + 1]; @@ -943,7 +943,7 @@ access_check_func(const char *name, uint32_t name_len) int func_call(struct func *func, struct request *request, struct obuf *out) { - assert(func != NULL && func->def.language == FUNC_LANGUAGE_C); + assert(func != NULL && func->def->language == FUNC_LANGUAGE_C); if (func->func == NULL) func_load(func); @@ -1030,7 +1030,7 @@ box_process_call(struct request *request, struct obuf *out) * defined, it's obviously not a setuid one. */ struct credentials *orig_credentials = NULL; - if (func && func->def.setuid) { + if (func && func->def->setuid) { orig_credentials = current_user(); /* Remember and change the current user id. */ if (func->owner_credentials.auth_token >= BOX_USER_MAX) { @@ -1040,7 +1040,7 @@ box_process_call(struct request *request, struct obuf *out) * be around to fill it (recovery of * system spaces from a snapshot). */ - struct user *owner = user_find_xc(func->def.uid); + struct user *owner = user_find_xc(func->def->uid); credentials_init(&func->owner_credentials, owner->auth_token, owner->def.uid); @@ -1049,7 +1049,7 @@ box_process_call(struct request *request, struct obuf *out) } int rc; - if (func && func->def.language == FUNC_LANGUAGE_C) { + if (func && func->def->language == FUNC_LANGUAGE_C) { rc = func_call(func, request, out); } else { rc = box_lua_call(request, out); diff --git a/src/box/func.cc b/src/box/func.cc index 29feba695c..93390b8128 100644 --- a/src/box/func.cc +++ b/src/box/func.cc @@ -43,7 +43,7 @@ func_new(struct func_def *def) diag_set(OutOfMemory, sizeof(*func), "malloc", "func"); return NULL; } - func->def = *def; + func->def = def; /** Nobody has access to the function but the owner. */ memset(func->access, 0, sizeof(func->access)); /* @@ -95,7 +95,7 @@ func_load(struct func *func) * E.g. name = foo.bar.baz, function = baz, package = foo.bar */ const char *sym; - const char *package = func->def.name; + const char *package = func->def->name; const char *package_end = strrchr(package, '.'); if (package_end != NULL) { /* module.submodule.function => module.submodule, function */ @@ -112,21 +112,21 @@ func_load(struct func *func) lua_getfield(L, -3, "cpath"); if (lua_pcall(L, 2, 1, 0)) { - tnt_raise(ClientError, ER_LOAD_FUNCTION, func->def.name, + tnt_raise(ClientError, ER_LOAD_FUNCTION, func->def->name, lua_tostring(L, -1)); } if (lua_isnil(L, -1)) { - tnt_raise(ClientError, ER_LOAD_FUNCTION, func->def.name, + tnt_raise(ClientError, ER_LOAD_FUNCTION, func->def->name, "shared library not found in the search path"); } func->dlhandle = dlopen(lua_tostring(L, -1), RTLD_NOW | RTLD_LOCAL); if (func->dlhandle == NULL) { - tnt_raise(LoggedError, ER_LOAD_FUNCTION, func->def.name, + tnt_raise(LoggedError, ER_LOAD_FUNCTION, func->def->name, dlerror()); } func->func = (box_function_f) dlsym(func->dlhandle, sym); if (func->func == NULL) { - tnt_raise(LoggedError, ER_LOAD_FUNCTION, func->def.name, + tnt_raise(LoggedError, ER_LOAD_FUNCTION, func->def->name, dlerror()); } } @@ -135,12 +135,14 @@ void func_update(struct func *func, struct func_def *def) { func_unload(func); - func->def = *def; + free(func->def); + func->def = def; } void func_delete(struct func *func) { func_unload(func); + free(func->def); free(func); } diff --git a/src/box/func.h b/src/box/func.h index f590e353ef..c29b964ea5 100644 --- a/src/box/func.h +++ b/src/box/func.h @@ -40,7 +40,7 @@ extern "C" { * Stored function. */ struct func { - struct func_def def; + struct func_def *def; /** * For C functions, the body of the function. */ diff --git a/src/box/key_def.h b/src/box/key_def.h index 54815d2d74..39707b0bbe 100644 --- a/src/box/key_def.h +++ b/src/box/key_def.h @@ -421,9 +421,21 @@ struct func_def { */ enum func_language language; /** Function name. */ - char name[BOX_NAME_MAX + 1]; + char name[0]; }; +/** + * @param name_length length of func_def->name + * @returns size in bytes needed to allocate for struct func_def + * for a function of length @a a name_length. + */ +static inline size_t +func_def_sizeof(uint32_t name_length) +{ + /* +1 for '\0' name terminating. */ + return sizeof(struct func_def) + name_length + 1; +} + /** * Definition of a privilege */ diff --git a/src/box/schema.cc b/src/box/schema.cc index 7feb18653d..555fb36f6e 100644 --- a/src/box/schema.cc +++ b/src/box/schema.cc @@ -353,7 +353,7 @@ schema_free(void) struct func *func = ((struct func *) mh_i32ptr_node(funcs, i)->val); - func_cache_delete(func->def.fid); + func_cache_delete(func->def->fid); } mh_i32ptr_delete(funcs); } @@ -377,17 +377,19 @@ func_cache_replace(struct func_def *def) const struct mh_i32ptr_node_t node = { def->fid, func }; mh_int_t k1 = mh_i32ptr_put(funcs, &node, NULL, NULL); if (k1 == mh_end(funcs)) { + func->def = NULL; func_delete(func); goto error; } - size_t def_name_len = strlen(func->def.name); - uint32_t name_hash = mh_strn_hash(func->def.name, def_name_len); + size_t def_name_len = strlen(func->def->name); + uint32_t name_hash = mh_strn_hash(func->def->name, def_name_len); const struct mh_strnptr_node_t strnode = { - func->def.name, def_name_len, name_hash, func }; + func->def->name, def_name_len, name_hash, func }; mh_int_t k2 = mh_strnptr_put(funcs_by_name, &strnode, NULL, NULL); if (k2 == mh_end(funcs_by_name)) { mh_i32ptr_del(funcs, k1, NULL); + func->def = NULL; func_delete(func); goto error; } @@ -402,8 +404,8 @@ func_cache_delete(uint32_t fid) struct func *func = (struct func *) mh_i32ptr_node(funcs, k)->val; mh_i32ptr_del(funcs, k, NULL); - k = mh_strnptr_find_inp(funcs_by_name, func->def.name, - strlen(func->def.name)); + k = mh_strnptr_find_inp(funcs_by_name, func->def->name, + strlen(func->def->name)); if (k != mh_end(funcs)) mh_strnptr_del(funcs_by_name, k, NULL); func_delete(func); diff --git a/src/box/schema.h b/src/box/schema.h index 61bced142e..7832f132c7 100644 --- a/src/box/schema.h +++ b/src/box/schema.h @@ -214,6 +214,13 @@ uint32_t schema_find_id(uint32_t system_space_id, uint32_t index_id, const char *name, uint32_t len); +/** + * Insert a new function or update the old one. + * + * @param def Function definition. In a case of success the ownership + * of @a def is transfered to the data dictionary, thus the caller + * must not delete it. + */ void func_cache_replace(struct func_def *def); diff --git a/src/box/sysview_index.cc b/src/box/sysview_index.cc index 1b3ad170ed..33f5f9f1df 100644 --- a/src/box/sysview_index.cc +++ b/src/box/sysview_index.cc @@ -221,7 +221,7 @@ vfunc_filter(struct space *source, struct tuple *tuple) struct func *func = func_by_name(name, name_len); assert(func != NULL); uint8_t effective = func->access[cr->auth_token].effective; - if (func->def.uid == cr->uid || (PRIV_X & effective)) + if (func->def->uid == cr->uid || (PRIV_X & effective)) return true; return false; } diff --git a/src/box/tuple.h b/src/box/tuple.h index 2a8fdc3462..e842d5885d 100644 --- a/src/box/tuple.h +++ b/src/box/tuple.h @@ -604,16 +604,28 @@ tuple_field_u32(const struct tuple *tuple, uint32_t fieldno, uint32_t *out) /** * A convenience shortcut for data dictionary - get a tuple field - * as a NUL-terminated string - returns a string of up to 256 bytes. + * as a string. */ static inline const char * -tuple_field_cstr(const struct tuple *tuple, uint32_t fieldno) +tuple_field_str(const struct tuple *tuple, uint32_t fieldno, uint32_t *len) { const char *field = tuple_field_with_type(tuple, fieldno, MP_STR); if (field == NULL) return NULL; - uint32_t len = 0; - const char *str = mp_decode_str(&field, &len); + return mp_decode_str(&field, len); +} + +/** + * A convenience shortcut for data dictionary - get a tuple field + * as a NUL-terminated string - returns a string of up to 256 bytes. + */ +static inline const char * +tuple_field_cstr(const struct tuple *tuple, uint32_t fieldno) +{ + uint32_t len; + const char *str = tuple_field_str(tuple, fieldno, &len); + if (str == NULL) + return NULL; return tt_cstr(str, len); } @@ -771,6 +783,17 @@ tuple_field_u32_xc(const struct tuple *tuple, uint32_t fieldno) return out; } +/** @copydoc tuple_field_str() */ +static inline const char * +tuple_field_str_xc(const struct tuple *tuple, uint32_t fieldno, + uint32_t *len) +{ + const char *ret = tuple_field_str(tuple, fieldno, len); + if (ret == NULL) + diag_raise(); + return ret; +} + /** @copydoc tuple_field_cstr() */ static inline const char * tuple_field_cstr_xc(const struct tuple *tuple, uint32_t fieldno) -- GitLab