@@ -260,6 +260,70 @@ static const char *hlua_tostring_safe(lua_State *L, int index)
260260 return str ;
261261}
262262
263+ /* below is an helper function similar to lua_pushvfstring() to push a
264+ * formatted string on Lua stack but in a safe way (function may not LJMP).
265+ * It can be useful to push allocated strings (ie: error messages) on the
266+ * stack and ensure proper cleanup.
267+ *
268+ * Returns a pointer to the internal copy of the string on success and NULL
269+ * on error.
270+ *
271+ * It is assumed that the calling function is allowed to manipulate <L>
272+ */
273+ __LJMP static int _hlua_pushvfstring_safe (lua_State * L )
274+ {
275+ const char * * dst = lua_touserdata (L , 1 );
276+ const char * fmt = lua_touserdata (L , 2 );
277+ va_list * argp = lua_touserdata (L , 3 );
278+
279+ * dst = lua_pushvfstring (L , fmt , * argp );
280+ return 1 ;
281+ }
282+ static const char * hlua_pushvfstring_safe (lua_State * L , const char * fmt , va_list argp )
283+ {
284+ const char * dst = NULL ;
285+ va_list cpy_argp ; /* required if argp is implemented as array type */
286+
287+ if (!lua_checkstack (L , 4 ))
288+ return NULL ;
289+
290+ va_copy (cpy_argp , argp );
291+
292+ /* push our custom _hlua_pushvfstring_safe() function on the stack, then
293+ * push our destination string pointer, fmt and arg list
294+ */
295+ lua_pushcfunction (L , _hlua_pushvfstring_safe );
296+ lua_pushlightuserdata (L , & dst ); // 1st func argument = dst string pointer
297+ lua_pushlightuserdata (L , (void * )fmt ); // 2nd func argument = fmt
298+ lua_pushlightuserdata (L , & cpy_argp ); // 3rd func argument = arg list
299+
300+ /* call our custom function with proper arguments using pcall() to catch
301+ * exceptions (if any)
302+ */
303+ switch (lua_pcall (L , 3 , 1 , 0 )) {
304+ case LUA_OK :
305+ break ;
306+ default :
307+ /* error was caught */
308+ dst = NULL ;
309+ }
310+ va_end (cpy_argp );
311+
312+ return dst ;
313+ }
314+
315+ static const char * hlua_pushfstring_safe (lua_State * L , const char * fmt , ...)
316+ {
317+ va_list argp ;
318+ const char * dst ;
319+
320+ va_start (argp , fmt );
321+ dst = hlua_pushvfstring_safe (L , fmt , argp );
322+ va_end (argp );
323+
324+ return dst ;
325+ }
326+
263327#define SET_SAFE_LJMP_L (__L , __HLUA ) \
264328 ({ \
265329 int ret; \
@@ -1367,8 +1431,8 @@ __LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
13671431 }
13681432 reg = regex_comp (argp [idx ].data .str .area , !(argp [idx ].type_flags & ARGF_REG_ICASE ), 1 , & err );
13691433 if (!reg ) {
1370- msg = lua_pushfstring (L , "error compiling regex '%s' : '%s'" ,
1371- argp [idx ].data .str .area , err );
1434+ msg = hlua_pushfstring_safe (L , "error compiling regex '%s' : '%s'" ,
1435+ argp [idx ].data .str .area , err );
13721436 free (err );
13731437 goto error ;
13741438 }
@@ -1388,7 +1452,8 @@ __LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
13881452 ul = auth_find_userlist (argp [idx ].data .str .area );
13891453
13901454 if (!ul ) {
1391- msg = lua_pushfstring (L , "unable to find userlist '%s'" , argp [idx ].data .str .area );
1455+ msg = hlua_pushfstring_safe (L , "unable to find userlist '%s'" ,
1456+ argp [idx ].data .str .area );
13921457 goto error ;
13931458 }
13941459 argp [idx ].type = ARGT_USR ;
@@ -1412,9 +1477,9 @@ __LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
14121477
14131478 /* Check for type of argument. */
14141479 if ((mask & ARGT_MASK ) != argp [idx ].type ) {
1415- msg = lua_pushfstring (L , "'%s' expected, got '%s'" ,
1416- arg_type_names [(mask & ARGT_MASK )],
1417- arg_type_names [argp [idx ].type & ARGT_MASK ]);
1480+ msg = hlua_pushfstring_safe (L , "'%s' expected, got '%s'" ,
1481+ arg_type_names [(mask & ARGT_MASK )],
1482+ arg_type_names [argp [idx ].type & ARGT_MASK ]);
14181483 goto error ;
14191484 }
14201485
@@ -1960,9 +2025,11 @@ static enum hlua_exec hlua_ctx_resume(struct hlua *lua, int yield_allowed)
19602025 msg = hlua_tostring_safe (lua -> T , -1 );
19612026 trace = hlua_traceback (lua -> T , ", " );
19622027 if (msg )
1963- lua_pushfstring (lua -> T , "[state-id %d] runtime error: %s from %s" , lua -> state_id , msg , trace );
2028+ hlua_pushfstring_safe (lua -> T , "[state-id %d] runtime error: %s from %s" ,
2029+ lua -> state_id , msg , trace );
19642030 else
1965- lua_pushfstring (lua -> T , "[state-id %d] unknown runtime error from %s" , lua -> state_id , trace );
2031+ hlua_pushfstring_safe (lua -> T , "[state-id %d] unknown runtime error from %s" ,
2032+ lua -> state_id , trace );
19662033
19672034 /* Move the error msg at the top and then empty the stack except last msg */
19682035 lua_insert (lua -> T , - lua_gettop (lua -> T ));
@@ -1984,9 +2051,11 @@ static enum hlua_exec hlua_ctx_resume(struct hlua *lua, int yield_allowed)
19842051 }
19852052 msg = hlua_tostring_safe (lua -> T , -1 );
19862053 if (msg )
1987- lua_pushfstring (lua -> T , "[state-id %d] message handler error: %s" , lua -> state_id , msg );
2054+ hlua_pushfstring_safe (lua -> T , "[state-id %d] message handler error: %s" ,
2055+ lua -> state_id , msg );
19882056 else
1989- lua_pushfstring (lua -> T , "[state-id %d] message handler error" , lua -> state_id );
2057+ hlua_pushfstring_safe (lua -> T , "[state-id %d] message handler error" ,
2058+ lua -> state_id );
19902059
19912060 /* Move the error msg at the top and then empty the stack except last msg */
19922061 lua_insert (lua -> T , - lua_gettop (lua -> T ));
@@ -4700,7 +4769,7 @@ __LJMP static int hlua_run_sample_fetch(lua_State *L)
47004769
47014770 /* Run the special args checker. */
47024771 if (f -> val_args && !f -> val_args (args , NULL )) {
4703- lua_pushfstring (L , "error in arguments" );
4772+ hlua_pushfstring_safe (L , "error in arguments" );
47044773 goto error ;
47054774 }
47064775
0 commit comments