Browse Source

[Fix] Finally get rid of RSPAMD_USE_47BIT_LIGHTUSERDATA_HACK

tags/3.5
Vsevolod Stakhov 1 year ago
parent
commit
6a7407939e
No account linked to committer's email address
3 changed files with 83 additions and 99 deletions
  1. 1
    1
      src/libserver/cfg_utils.c
  2. 76
    82
      src/lua/lua_common.c
  3. 6
    16
      src/lua/lua_common.h

+ 1
- 1
src/libserver/cfg_utils.c View File



if (cfg->lua_state && cfg->own_lua_state) { if (cfg->lua_state && cfg->own_lua_state) {
lua_thread_pool_free (cfg->lua_thread_pool); lua_thread_pool_free (cfg->lua_thread_pool);
lua_close (cfg->lua_state);
rspamd_lua_close (cfg->lua_state);
} }


if (cfg->redis_pool) { if (cfg->redis_pool) {

+ 76
- 82
src/lua/lua_common.c View File

return g_quark_from_static_string ("lua-routines"); return g_quark_from_static_string ("lua-routines");
} }


/* idea from daurnimator */
#if defined(WITH_LUAJIT) && (defined(_LP64) || defined(_LLP64) || defined(__arch64__) || defined (__arm64__) || defined (__aarch64__) || defined(_WIN64))
#define RSPAMD_USE_47BIT_LIGHTUSERDATA_HACK 1
#else
#define RSPAMD_USE_47BIT_LIGHTUSERDATA_HACK 0
#endif

#if RSPAMD_USE_47BIT_LIGHTUSERDATA_HACK
#define RSPAMD_LIGHTUSERDATA_MASK(p) ((void *)((uintptr_t)(p) & ((1UL<<47)-1)))
#else
#define RSPAMD_LIGHTUSERDATA_MASK(p) ((void *)(p))
#endif

/* /*
* Used to map string to a pointer * Used to map string to a pointer
*/ */
KHASH_INIT (lua_class_set, const gchar *, bool, 0, rspamd_str_hash, rspamd_str_equal);
khash_t (lua_class_set) *lua_classes = NULL;

RSPAMD_CONSTRUCTOR (lua_classes_ctor)
KHASH_INIT (lua_class_set, const char*, int, 1, rspamd_str_hash, rspamd_str_equal);
struct rspamd_lua_context {
lua_State *L;
khash_t(lua_class_set) *classes;
struct rspamd_lua_context *prev, *next; /* Expensive but we usually have exactly one lua state */
};
struct rspamd_lua_context *rspamd_lua_global_ctx = NULL;
#define RSPAMD_LUA_NCLASSES 64
static inline struct rspamd_lua_context*
rspamd_lua_ctx_by_state (lua_State *L)
{ {
lua_classes = kh_init (lua_class_set);
}
struct rspamd_lua_context *cur;


RSPAMD_DESTRUCTOR (lua_classes_dtor)
{
kh_destroy (lua_class_set, lua_classes);
DL_FOREACH(rspamd_lua_global_ctx, cur) {
if (cur->L == L) {
return cur;
}
}

/* When we are using thread pool, this is the case... */
return rspamd_lua_global_ctx;
} }


/* Util functions */ /* Util functions */
const gchar *classname, const gchar *classname,
const struct luaL_reg *methods) const struct luaL_reg *methods)
{ {
void *class_ptr;
khiter_t k; khiter_t k;
gint r, nmethods = 0; gint r, nmethods = 0;
gboolean seen_index = false; gboolean seen_index = false;

k = kh_put (lua_class_set, lua_classes, classname, &r);
class_ptr = RSPAMD_LIGHTUSERDATA_MASK (kh_key (lua_classes, k));
struct rspamd_lua_context *ctx = rspamd_lua_ctx_by_state(L);


if (methods) { if (methods) {
for (;;) { for (;;) {
lua_pushstring (L, classname); lua_pushstring (L, classname);
lua_rawset (L, -3); lua_rawset (L, -3);


lua_pushstring (L, "class_ptr");
lua_pushlightuserdata (L, class_ptr);
lua_rawset (L, -3);

if (methods) { if (methods) {
luaL_register (L, NULL, methods); /* pushes all methods as MT fields */ luaL_register (L, NULL, methods); /* pushes all methods as MT fields */
} }


lua_pushvalue (L, -1); /* Preserves metatable */ lua_pushvalue (L, -1); /* Preserves metatable */
lua_rawsetp (L, LUA_REGISTRYINDEX, class_ptr);
int offset = luaL_ref (L, LUA_REGISTRYINDEX);
k = kh_put (lua_class_set, ctx->classes, classname, &r);
kh_value(ctx->classes, k) = offset;
/* MT is left on stack ! */ /* MT is left on stack ! */
} }


rspamd_lua_setclass (lua_State * L, const gchar *classname, gint objidx) rspamd_lua_setclass (lua_State * L, const gchar *classname, gint objidx)
{ {
khiter_t k; khiter_t k;
struct rspamd_lua_context *ctx = rspamd_lua_ctx_by_state(L);


k = kh_get (lua_class_set, lua_classes, classname);
k = kh_get (lua_class_set, ctx->classes, classname);


g_assert (k != kh_end (lua_classes));
lua_rawgetp (L, LUA_REGISTRYINDEX,
RSPAMD_LIGHTUSERDATA_MASK (kh_key (lua_classes, k)));
g_assert (k != kh_end (ctx->classes));
lua_rawgeti (L, LUA_REGISTRYINDEX, kh_value(ctx->classes, k));


if (objidx < 0) { if (objidx < 0) {
objidx--; objidx--;
rspamd_lua_class_metatable (lua_State *L, const gchar *classname) rspamd_lua_class_metatable (lua_State *L, const gchar *classname)
{ {
khiter_t k; khiter_t k;
struct rspamd_lua_context *ctx = rspamd_lua_ctx_by_state(L);


k = kh_get (lua_class_set, lua_classes, classname);
k = kh_get (lua_class_set, ctx->classes, classname);


g_assert (k != kh_end (lua_classes));
lua_rawgetp (L, LUA_REGISTRYINDEX,
RSPAMD_LIGHTUSERDATA_MASK (kh_key (lua_classes, k)));
g_assert (k != kh_end (ctx->classes));
lua_rawgeti (L, LUA_REGISTRYINDEX, kh_value(ctx->classes, k));
} }


void void
luaL_Reg *meth) luaL_Reg *meth)
{ {
khiter_t k; khiter_t k;
struct rspamd_lua_context *ctx = rspamd_lua_ctx_by_state(L);


k = kh_get (lua_class_set, lua_classes, classname);
k = kh_get (lua_class_set, ctx->classes, classname);


g_assert (k != kh_end (lua_classes));
/* get metatable identified by pointer */
lua_rawgetp (L, LUA_REGISTRYINDEX,
RSPAMD_LIGHTUSERDATA_MASK (kh_key (lua_classes, k)));
g_assert (k != kh_end (ctx->classes));
lua_rawgeti (L, LUA_REGISTRYINDEX, kh_value(ctx->classes, k));


lua_pushcfunction (L, meth->func); lua_pushcfunction (L, meth->func);
lua_setfield (L, -2, meth->name); lua_setfield (L, -2, meth->name);
L = luaL_newstate (); L = luaL_newstate ();
} }


struct rspamd_lua_context *ctx;

ctx = (struct rspamd_lua_context *)g_malloc0 (sizeof (*ctx));
ctx->L = L;
ctx->classes = kh_init(lua_class_set);
kh_resize(lua_class_set, ctx->classes, RSPAMD_LUA_NCLASSES);
DL_APPEND(rspamd_lua_global_ctx, ctx);

lua_gc (L, LUA_GCSTOP, 0); lua_gc (L, LUA_GCSTOP, 0);
luaL_openlibs (L); luaL_openlibs (L);
luaopen_logger (L); luaopen_logger (L);
return L; return L;
} }


void
rspamd_lua_close (lua_State *L)
{
struct rspamd_lua_context *ctx = rspamd_lua_ctx_by_state(L);

/* TODO: we will leak this memory, but I don't know how to resolve
* the chicked-egg problem when lua_close calls GC for many
* userdata that requires classes metatables to be represented
* For now, it is safe to leave it as is, I'm afraid
*/
#if 0
int ref;
kh_foreach_value(ctx->classes, ref, {
luaL_unref(L, LUA_REGISTRYINDEX, ref);
});
#endif

lua_close(L);
DL_DELETE(rspamd_lua_global_ctx, ctx);
kh_destroy(lua_class_set, ctx->classes);
g_free(ctx);
}

void void
rspamd_lua_start_gc (struct rspamd_config *cfg) rspamd_lua_start_gc (struct rspamd_config *cfg)
{ {
lua_gc (L, LUA_GCRESTART, 0); lua_gc (L, LUA_GCRESTART, 0);
} }


/**
* Initialize new locked lua_State structure
*/
struct lua_locked_state *
rspamd_init_lua_locked (struct rspamd_config *cfg)
{
struct lua_locked_state *new;

new = g_malloc0 (sizeof (struct lua_locked_state));
new->L = rspamd_lua_init (false);
new->m = rspamd_mutex_new ();

return new;
}

/**
* Free locked state structure
*/
void
rspamd_free_lua_locked (struct lua_locked_state *st)
{
g_assert (st != NULL);

lua_close (st->L);

rspamd_mutex_free (st->m);

g_free (st);
}



void void
rspamd_plugins_table_push_elt (lua_State *L, const gchar *field_name, rspamd_plugins_table_push_elt (lua_State *L, const gchar *field_name,
p = lua_touserdata (L, index); p = lua_touserdata (L, index);
if (p) { if (p) {
if (lua_getmetatable (L, index)) { if (lua_getmetatable (L, index)) {
k = kh_get (lua_class_set, lua_classes, name);
struct rspamd_lua_context *ctx = rspamd_lua_ctx_by_state(L);


if (k == kh_end (lua_classes)) {
k = kh_get (lua_class_set, ctx->classes, name);

if (k == kh_end (ctx->classes)) {
lua_pop (L, 1); lua_pop (L, 1);


return NULL; return NULL;
} }


lua_rawgetp (L, LUA_REGISTRYINDEX,
RSPAMD_LIGHTUSERDATA_MASK (kh_key (lua_classes, k)));
lua_rawgeti (L, LUA_REGISTRYINDEX, kh_value(ctx->classes, k));


if (lua_rawequal (L, -1, -2)) { /* does it have the correct mt? */ if (lua_rawequal (L, -1, -2)) { /* does it have the correct mt? */
lua_pop (L, 2); /* remove both metatables */ lua_pop (L, 2); /* remove both metatables */
else { else {
/* Match class */ /* Match class */
if (lua_getmetatable (L, pos)) { if (lua_getmetatable (L, pos)) {
k = kh_get (lua_class_set, lua_classes, (gchar *)classname);
struct rspamd_lua_context *ctx = rspamd_lua_ctx_by_state(L);

k = kh_get (lua_class_set, ctx->classes, classname);


if (k == kh_end (lua_classes)) {
if (k == kh_end (ctx->classes)) {
goto err; goto err;
} }


lua_rawgetp (L, LUA_REGISTRYINDEX,
RSPAMD_LIGHTUSERDATA_MASK (kh_key (lua_classes, k)));
lua_rawgeti (L, LUA_REGISTRYINDEX, kh_value(ctx->classes, k));


if (!lua_rawequal (L, -1, -2)) { if (!lua_rawequal (L, -1, -2)) {
goto err; goto err;

+ 6
- 16
src/lua/lua_common.h View File

extern const luaL_reg null_reg[]; extern const luaL_reg null_reg[];


#define RSPAMD_LUA_API_VERSION 12 #define RSPAMD_LUA_API_VERSION 12

/* Locked lua state with mutex */
struct lua_locked_state {
lua_State *L;
rspamd_mutex_t *m;
};

/** /**
* Lua IP address structure * Lua IP address structure
*/ */
*/ */
lua_State *rspamd_lua_init (bool wipe_mem); lua_State *rspamd_lua_init (bool wipe_mem);


/**
* Close lua_state and free remainders
* @param L
*/
void rspamd_lua_close (lua_State *L);

void rspamd_lua_start_gc (struct rspamd_config *cfg); void rspamd_lua_start_gc (struct rspamd_config *cfg);


/** /**
gboolean gboolean
rspamd_init_lua_filters (struct rspamd_config *cfg, bool force_load, bool strict); rspamd_init_lua_filters (struct rspamd_config *cfg, bool force_load, bool strict);


/**
* Initialize new locked lua_State structure
*/
struct lua_locked_state *rspamd_init_lua_locked (struct rspamd_config *cfg);

/**
* Free locked state structure
*/
void rspamd_free_lua_locked (struct lua_locked_state *st);


/** /**
* Push lua ip address * Push lua ip address

Loading…
Cancel
Save