BUG/MINOR: lua: Duplicate lua strings in sample fetches/converters arg array
Strings in the argument array used by sample fetches and converters must be
duplicated. This is mandatory because, during the arguments validations, these
strings may be converted and released. It works this way during the
configuration parsing and there is no reason to adapt this behavior during the
runtime when a sample fetch or a sample converter is called from the lua. In
fact, there is a reason to not change the behavior. It must reamain simple for
everyone to add new fetches or converters.
Thus, lua strings are duplicated. It is only performed at the end of the
hlua_lua2arg_check() function, if the argument is still a ARGT_STR. Of course,
it requires a cleanup loop after the call or when an error is triggered.
This patch depends on following commits:
* 959171376 "BUG/MINOR: arg: Fix leaks during arguments validation for fetches/converters"
* fdea1b631 "MINOR: hlua: Don't needlessly copy lua strings in trash during args validation"
It may be backported to all supported versions, most probably as far as 2.1
only.
diff --git a/src/hlua.c b/src/hlua.c
index efbc90a..30b7b8a 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -591,8 +591,9 @@
uint64_t mask, struct proxy *p)
{
int min_arg;
- int idx;
+ int i, idx;
struct proxy *px;
+ const char *msg = NULL;
char *sname, *pname;
idx = 0;
@@ -600,10 +601,12 @@
mask >>= ARGM_BITS;
while (1) {
+ struct buffer tmp = BUF_NULL;
/* Check oversize. */
if (idx >= ARGM_NBARGS && argp[idx].type != ARGT_STOP) {
- WILL_LJMP(luaL_argerror(L, first + idx, "Malformed argument mask"));
+ msg = "Malformed argument mask";
+ goto error;
}
/* Check for mandatory arguments. */
@@ -611,8 +614,10 @@
if (idx < min_arg) {
/* If miss other argument than the first one, we return an error. */
- if (idx > 0)
- WILL_LJMP(luaL_argerror(L, first + idx, "Mandatory argument expected"));
+ if (idx > 0) {
+ msg = "Mandatory argument expected";
+ goto error;
+ }
/* If first argument have a certain type, some default values
* may be used. See the function smp_resolve_args().
@@ -620,16 +625,20 @@
switch (mask & ARGT_MASK) {
case ARGT_FE:
- if (!(p->cap & PR_CAP_FE))
- WILL_LJMP(luaL_argerror(L, first + idx, "Mandatory argument expected"));
+ if (!(p->cap & PR_CAP_FE)) {
+ msg = "Mandatory argument expected";
+ goto error;
+ }
argp[idx].data.prx = p;
argp[idx].type = ARGT_FE;
argp[idx+1].type = ARGT_STOP;
break;
case ARGT_BE:
- if (!(p->cap & PR_CAP_BE))
- WILL_LJMP(luaL_argerror(L, first + idx, "Mandatory argument expected"));
+ if (!(p->cap & PR_CAP_BE)) {
+ msg = "Mandatory argument expected";
+ goto error;
+ }
argp[idx].data.prx = p;
argp[idx].type = ARGT_BE;
argp[idx+1].type = ARGT_STOP;
@@ -642,97 +651,129 @@
break;
default:
- WILL_LJMP(luaL_argerror(L, first + idx, "Mandatory argument expected"));
+ msg = "Mandatory argument expected";
+ goto error;
break;
}
}
- return 0;
+ break;
}
/* Check for exceed the number of required argument. */
if ((mask & ARGT_MASK) == ARGT_STOP &&
argp[idx].type != ARGT_STOP) {
- WILL_LJMP(luaL_argerror(L, first + idx, "Last argument expected"));
+ msg = "Last argument expected";
+ goto error;
}
if ((mask & ARGT_MASK) == ARGT_STOP &&
argp[idx].type == ARGT_STOP) {
- return 0;
+ break;
}
- /* Convert some argument types. */
+ /* Convert some argument types. All string in argp[] are for not
+ * duplicated yet.
+ */
switch (mask & ARGT_MASK) {
case ARGT_SINT:
- if (argp[idx].type != ARGT_SINT)
- WILL_LJMP(luaL_argerror(L, first + idx, "integer expected"));
+ if (argp[idx].type != ARGT_SINT) {
+ msg = "integer expected";
+ goto error;
+ }
argp[idx].type = ARGT_SINT;
break;
case ARGT_TIME:
- if (argp[idx].type != ARGT_SINT)
- WILL_LJMP(luaL_argerror(L, first + idx, "integer expected"));
+ if (argp[idx].type != ARGT_SINT) {
+ msg = "integer expected";
+ goto error;
+ }
argp[idx].type = ARGT_TIME;
break;
case ARGT_SIZE:
- if (argp[idx].type != ARGT_SINT)
- WILL_LJMP(luaL_argerror(L, first + idx, "integer expected"));
+ if (argp[idx].type != ARGT_SINT) {
+ msg = "integer expected";
+ goto error;
+ }
argp[idx].type = ARGT_SIZE;
break;
case ARGT_FE:
- if (argp[idx].type != ARGT_STR)
- WILL_LJMP(luaL_argerror(L, first + idx, "string expected"));
+ if (argp[idx].type != ARGT_STR) {
+ msg = "string expected";
+ goto error;
+ }
argp[idx].data.prx = proxy_fe_by_name(argp[idx].data.str.area);
- if (!argp[idx].data.prx)
- WILL_LJMP(luaL_argerror(L, first + idx, "frontend doesn't exist"));
+ if (!argp[idx].data.prx) {
+ msg = "frontend doesn't exist";
+ goto error;
+ }
argp[idx].type = ARGT_FE;
break;
case ARGT_BE:
- if (argp[idx].type != ARGT_STR)
- WILL_LJMP(luaL_argerror(L, first + idx, "string expected"));
+ if (argp[idx].type != ARGT_STR) {
+ msg = "string expected";
+ goto error;
+ }
argp[idx].data.prx = proxy_be_by_name(argp[idx].data.str.area);
- if (!argp[idx].data.prx)
- WILL_LJMP(luaL_argerror(L, first + idx, "backend doesn't exist"));
+ if (!argp[idx].data.prx) {
+ msg = "backend doesn't exist";
+ goto error;
+ }
argp[idx].type = ARGT_BE;
break;
case ARGT_TAB:
- if (argp[idx].type != ARGT_STR)
- WILL_LJMP(luaL_argerror(L, first + idx, "string expected"));
+ if (argp[idx].type != ARGT_STR) {
+ msg = "string expected";
+ goto error;
+ }
argp[idx].data.t = stktable_find_by_name(argp[idx].data.str.area);
- if (!argp[idx].data.t)
- WILL_LJMP(luaL_argerror(L, first + idx, "table doesn't exist"));
+ if (!argp[idx].data.t) {
+ msg = "table doesn't exist";
+ goto error;
+ }
argp[idx].type = ARGT_TAB;
break;
case ARGT_SRV:
- if (argp[idx].type != ARGT_STR)
- WILL_LJMP(luaL_argerror(L, first + idx, "string expected"));
+ if (argp[idx].type != ARGT_STR) {
+ msg = "string expected";
+ goto error;
+ }
sname = strrchr(argp[idx].data.str.area, '/');
if (sname) {
*sname++ = '\0';
pname = argp[idx].data.str.area;
px = proxy_be_by_name(pname);
- if (!px)
- WILL_LJMP(luaL_argerror(L, first + idx, "backend doesn't exist"));
+ if (!px) {
+ msg = "backend doesn't exist";
+ goto error;
+ }
}
else {
sname = argp[idx].data.str.area;
px = p;
}
argp[idx].data.srv = findserver(px, sname);
- if (!argp[idx].data.srv)
- WILL_LJMP(luaL_argerror(L, first + idx, "server doesn't exist"));
+ if (!argp[idx].data.srv) {
+ msg = "server doesn't exist";
+ goto error;
+ }
argp[idx].type = ARGT_SRV;
break;
case ARGT_IPV4:
- if (argp[idx].type != ARGT_STR)
- WILL_LJMP(luaL_argerror(L, first + idx, "string expected"));
- if (inet_pton(AF_INET, argp[idx].data.str.area, &argp[idx].data.ipv4))
- WILL_LJMP(luaL_argerror(L, first + idx, "invalid IPv4 address"));
+ if (argp[idx].type != ARGT_STR) {
+ msg = "string expected";
+ goto error;
+ }
+ if (inet_pton(AF_INET, argp[idx].data.str.area, &argp[idx].data.ipv4)) {
+ msg = "invalid IPv4 address";
+ goto error;
+ }
argp[idx].type = ARGT_IPV4;
break;
@@ -740,19 +781,27 @@
if (argp[idx].type == ARGT_SINT)
len2mask4(argp[idx].data.sint, &argp[idx].data.ipv4);
else if (argp[idx].type == ARGT_STR) {
- if (!str2mask(argp[idx].data.str.area, &argp[idx].data.ipv4))
- WILL_LJMP(luaL_argerror(L, first + idx, "invalid IPv4 mask"));
+ if (!str2mask(argp[idx].data.str.area, &argp[idx].data.ipv4)) {
+ msg = "invalid IPv4 mask";
+ goto error;
+ }
+ }
+ else {
+ msg = "integer or string expected";
+ goto error;
}
- else
- WILL_LJMP(luaL_argerror(L, first + idx, "integer or string expected"));
argp[idx].type = ARGT_MSK4;
break;
case ARGT_IPV6:
- if (argp[idx].type != ARGT_STR)
- WILL_LJMP(luaL_argerror(L, first + idx, "string expected"));
- if (inet_pton(AF_INET6, argp[idx].data.str.area, &argp[idx].data.ipv6))
- WILL_LJMP(luaL_argerror(L, first + idx, "invalid IPv6 address"));
+ if (argp[idx].type != ARGT_STR) {
+ msg = "string expected";
+ goto error;
+ }
+ if (inet_pton(AF_INET6, argp[idx].data.str.area, &argp[idx].data.ipv6)) {
+ msg = "invalid IPv6 address";
+ goto error;
+ }
argp[idx].type = ARGT_IPV6;
break;
@@ -760,33 +809,56 @@
if (argp[idx].type == ARGT_SINT)
len2mask6(argp[idx].data.sint, &argp[idx].data.ipv6);
else if (argp[idx].type == ARGT_STR) {
- if (!str2mask6(argp[idx].data.str.area, &argp[idx].data.ipv6))
- WILL_LJMP(luaL_argerror(L, first + idx, "invalid IPv6 mask"));
+ if (!str2mask6(argp[idx].data.str.area, &argp[idx].data.ipv6)) {
+ msg = "invalid IPv6 mask";
+ goto error;
+ }
+ }
+ else {
+ msg = "integer or string expected";
+ goto error;
}
- else
- WILL_LJMP(luaL_argerror(L, first + idx, "integer or string expected"));
argp[idx].type = ARGT_MSK6;
break;
case ARGT_MAP:
case ARGT_REG:
case ARGT_USR:
- WILL_LJMP(luaL_argerror(L, first + idx, "type not yet supported"));
+ msg = "type not yet supported";
+ goto error;
+ break;
+
+ case ARGT_STR:
+ if (!chunk_dup(&tmp, &argp[idx].data.str)) {
+ msg = "unable to duplicate string arg";
+ goto error;
+ }
+ argp[idx].data.str = tmp;
break;
+
}
/* Check for type of argument. */
if ((mask & ARGT_MASK) != argp[idx].type) {
- const char *msg = lua_pushfstring(L, "'%s' expected, got '%s'",
- arg_type_names[(mask & ARGT_MASK)],
- arg_type_names[argp[idx].type & ARGT_MASK]);
- WILL_LJMP(luaL_argerror(L, first + idx, msg));
+ msg = lua_pushfstring(L, "'%s' expected, got '%s'",
+ arg_type_names[(mask & ARGT_MASK)],
+ arg_type_names[argp[idx].type & ARGT_MASK]);
+ goto error;
}
/* Next argument. */
mask >>= ARGT_BITS;
idx++;
}
+ return 0;
+
+ error:
+ for (i = 0; i < idx; i++) {
+ if (argp[i].type == ARGT_STR)
+ chunk_destroy(&argp[i].data.str);
+ }
+ WILL_LJMP(luaL_argerror(L, first + idx, msg));
+ return 0; /* Never reached */
}
/*
@@ -3255,7 +3327,7 @@
/* Run the special args checker. */
if (f->val_args && !f->val_args(args, NULL)) {
lua_pushfstring(L, "error in arguments");
- WILL_LJMP(lua_error(L));
+ goto error;
}
/* Initialise the sample. */
@@ -3268,7 +3340,7 @@
lua_pushstring(L, "");
else
lua_pushnil(L);
- return 1;
+ goto end;
}
/* Convert the returned sample in lua value. */
@@ -3276,7 +3348,21 @@
hlua_smp2lua_str(L, &smp);
else
hlua_smp2lua(L, &smp);
+
+ end:
+ for (i = 0; args[i].type != ARGT_STOP; i++) {
+ if (args[i].type == ARGT_STR)
+ chunk_destroy(&args[i].data.str);
+ }
return 1;
+
+ error:
+ for (i = 0; args[i].type != ARGT_STOP; i++) {
+ if (args[i].type == ARGT_STR)
+ chunk_destroy(&args[i].data.str);
+ }
+ WILL_LJMP(lua_error(L));
+ return 0; /* Never reached */
}
/*
@@ -3361,13 +3447,13 @@
/* Run the special args checker. */
if (conv->val_args && !conv->val_args(args, conv, "", 0, NULL)) {
hlua_pusherror(L, "error in arguments");
- WILL_LJMP(lua_error(L));
+ goto error;
}
/* Initialise the sample. */
if (!hlua_lua2smp(L, 2, &smp)) {
hlua_pusherror(L, "error in the input argument");
- WILL_LJMP(lua_error(L));
+ goto error;
}
smp_set_owner(&smp, hsmp->p, hsmp->s->sess, hsmp->s, hsmp->dir & SMP_OPT_DIR);
@@ -3376,12 +3462,12 @@
if (!sample_casts[smp.data.type][conv->in_type]) {
hlua_pusherror(L, "invalid input argument: cannot cast '%s' to '%s'",
smp_to_type[smp.data.type], smp_to_type[conv->in_type]);
- WILL_LJMP(lua_error(L));
+ goto error;
}
if (sample_casts[smp.data.type][conv->in_type] != c_none &&
!sample_casts[smp.data.type][conv->in_type](&smp)) {
hlua_pusherror(L, "error during the input argument casting");
- WILL_LJMP(lua_error(L));
+ goto error;
}
/* Run the sample conversion process. */
@@ -3390,7 +3476,7 @@
lua_pushstring(L, "");
else
lua_pushnil(L);
- return 1;
+ goto end;
}
/* Convert the returned sample in lua value. */
@@ -3398,7 +3484,20 @@
hlua_smp2lua_str(L, &smp);
else
hlua_smp2lua(L, &smp);
+ end:
+ for (i = 0; args[i].type != ARGT_STOP; i++) {
+ if (args[i].type == ARGT_STR)
+ chunk_destroy(&args[i].data.str);
+ }
return 1;
+
+ error:
+ for (i = 0; args[i].type != ARGT_STOP; i++) {
+ if (args[i].type == ARGT_STR)
+ chunk_destroy(&args[i].data.str);
+ }
+ WILL_LJMP(lua_error(L));
+ return 0; /* Never reached */
}
/*