Skip to content

Commit 38302fa

Browse files
committed
Call callbacks from a pcall
Lua errors (including allocation failures) would `longjmp` out of the callbacks, bypassing cleanup in libmosquitto. This commit changes errors from undefined behaviour (that luckily used to get reported) to silently discarding errors. Closes #23
1 parent 2633d51 commit 38302fa

1 file changed

Lines changed: 122 additions & 46 deletions

File tree

lua-mosquitto.c

Lines changed: 122 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -522,12 +522,9 @@ static int ctx_want_write(lua_State *L)
522522
return 1;
523523
}
524524

525-
static void ctx_on_connect(
526-
struct mosquitto *mosq,
527-
void *obj,
528-
int rc)
529-
{
530-
ctx_t *ctx = obj;
525+
static int ctx_on_connect_safe(lua_State *L) {
526+
int ref = lua_tointeger(L, 1);
527+
int rc = lua_tointeger(L, 2);
531528
bool success = false;
532529
char *str = "reserved for future use";
533530

@@ -562,22 +559,37 @@ static void ctx_on_connect(
562559
break;
563560
}
564561

565-
lua_rawgeti(ctx->L, LUA_REGISTRYINDEX, ctx->on_connect);
562+
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
566563

567-
lua_pushboolean(ctx->L, success);
568-
lua_pushinteger(ctx->L, rc);
569-
lua_pushstring(ctx->L, str);
564+
lua_pushboolean(L, success);
565+
lua_pushinteger(L, rc);
566+
lua_pushstring(L, str);
570567

571-
lua_call(ctx->L, 3, 0);
572-
}
568+
lua_call(L, 3, 0);
573569

570+
return 0;
571+
}
574572

575-
static void ctx_on_disconnect(
573+
static void ctx_on_connect(
576574
struct mosquitto *mosq,
577575
void *obj,
578576
int rc)
579577
{
580578
ctx_t *ctx = obj;
579+
lua_State *L = ctx->L;
580+
lua_pushcfunction(L, ctx_on_connect_safe);
581+
lua_pushinteger(L, ctx->on_connect);
582+
lua_pushinteger(L, rc);
583+
if (LUA_OK != lua_pcall(L, 2, 0, 0)) {
584+
/* pop error message */
585+
lua_pop(L, 1);
586+
}
587+
}
588+
589+
590+
static int ctx_on_disconnect_safe(lua_State *L) {
591+
int ref = lua_tointeger(L, 1);
592+
int rc = lua_tointeger(L, 2);
581593
bool success = true;
582594
char *str = "client-initiated disconnect";
583595

@@ -586,13 +598,31 @@ static void ctx_on_disconnect(
586598
str = "unexpected disconnect";
587599
}
588600

589-
lua_rawgeti(ctx->L, LUA_REGISTRYINDEX, ctx->on_disconnect);
601+
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
590602

591-
lua_pushboolean(ctx->L, success);
592-
lua_pushinteger(ctx->L, rc);
593-
lua_pushstring(ctx->L, str);
603+
lua_pushboolean(L, success);
604+
lua_pushinteger(L, rc);
605+
lua_pushstring(L, str);
594606

595-
lua_call(ctx->L, 3, 0);
607+
lua_call(L, 3, 0);
608+
609+
return 0;
610+
}
611+
612+
static void ctx_on_disconnect(
613+
struct mosquitto *mosq,
614+
void *obj,
615+
int rc)
616+
{
617+
ctx_t *ctx = obj;
618+
lua_State *L = ctx->L;
619+
lua_pushcfunction(L, ctx_on_disconnect_safe);
620+
lua_pushinteger(L, ctx->on_disconnect);
621+
lua_pushinteger(L, rc);
622+
if (LUA_OK != lua_pcall(L, 2, 0, 0)) {
623+
/* pop error message */
624+
lua_pop(L, 1);
625+
}
596626
}
597627

598628
static void ctx_on_publish(
@@ -601,10 +631,31 @@ static void ctx_on_publish(
601631
int mid)
602632
{
603633
ctx_t *ctx = obj;
634+
lua_State *L = ctx->L;
635+
lua_rawgeti(L, LUA_REGISTRYINDEX, ctx->on_publish);
636+
lua_pushinteger(L, mid);
637+
if (LUA_OK != lua_pcall(L, 1, 0, 0)) {
638+
/* pop error message */
639+
lua_pop(L, 1);
640+
}
641+
}
642+
643+
static int ctx_on_message_safe(lua_State *L) {
644+
int ref = lua_tointeger(L, 1);
645+
const struct mosquitto_message *msg = lua_touserdata(L, 2);
646+
647+
/* push registered Lua callback function onto the stack */
648+
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
649+
/* push function args */
650+
lua_pushinteger(L, msg->mid);
651+
lua_pushstring(L, msg->topic);
652+
lua_pushlstring(L, msg->payload, msg->payloadlen);
653+
lua_pushinteger(L, msg->qos);
654+
lua_pushboolean(L, msg->retain);
655+
656+
lua_call(L, 5, 0); /* args: mid, topic, payload, qos, retain */
604657

605-
lua_rawgeti(ctx->L, LUA_REGISTRYINDEX, ctx->on_publish);
606-
lua_pushinteger(ctx->L, mid);
607-
lua_call(ctx->L, 1, 0);
658+
return 0;
608659
}
609660

610661
static void ctx_on_message(
@@ -613,17 +664,14 @@ static void ctx_on_message(
613664
const struct mosquitto_message *msg)
614665
{
615666
ctx_t *ctx = obj;
616-
617-
/* push registered Lua callback function onto the stack */
618-
lua_rawgeti(ctx->L, LUA_REGISTRYINDEX, ctx->on_message);
619-
/* push function args */
620-
lua_pushinteger(ctx->L, msg->mid);
621-
lua_pushstring(ctx->L, msg->topic);
622-
lua_pushlstring(ctx->L, msg->payload, msg->payloadlen);
623-
lua_pushinteger(ctx->L, msg->qos);
624-
lua_pushboolean(ctx->L, msg->retain);
625-
626-
lua_call(ctx->L, 5, 0); /* args: mid, topic, payload, qos, retain */
667+
lua_State *L = ctx->L;
668+
lua_pushcfunction(L, ctx_on_message_safe);
669+
lua_pushinteger(L, ctx->on_message);
670+
lua_pushlightuserdata(L, (void*)msg);
671+
if (LUA_OK != lua_pcall(L, 2, 0, 0)) {
672+
/* pop error message */
673+
lua_pop(L, 1);
674+
}
627675
}
628676

629677
static void ctx_on_subscribe(
@@ -634,16 +682,24 @@ static void ctx_on_subscribe(
634682
const int *granted_qos)
635683
{
636684
ctx_t *ctx = obj;
685+
lua_State *L = ctx->L;
637686
int i;
638687

639-
lua_rawgeti(ctx->L, LUA_REGISTRYINDEX, ctx->on_subscribe);
640-
lua_pushinteger(ctx->L, mid);
688+
if (!lua_checkstack(L, qos_count + 2)) {
689+
/* can't allocate enough stack space */
690+
return;
691+
}
641692

693+
lua_rawgeti(L, LUA_REGISTRYINDEX, ctx->on_subscribe);
694+
lua_pushinteger(L, mid);
642695
for (i = 0; i < qos_count; i++) {
643-
lua_pushinteger(ctx->L, granted_qos[i]);
696+
lua_pushinteger(L, granted_qos[i]);
644697
}
645698

646-
lua_call(ctx->L, qos_count + 1, 0);
699+
if (LUA_OK != lua_pcall(L, qos_count + 1, 0, 0)) {
700+
/* pop error message */
701+
lua_pop(L, 1);
702+
}
647703
}
648704

649705
static void ctx_on_unsubscribe(
@@ -652,10 +708,28 @@ static void ctx_on_unsubscribe(
652708
int mid)
653709
{
654710
ctx_t *ctx = obj;
711+
lua_State *L = ctx->L;
712+
lua_rawgeti(L, LUA_REGISTRYINDEX, ctx->on_unsubscribe);
713+
lua_pushinteger(L, mid);
714+
if (LUA_OK != lua_pcall(L, 1, 0, 0)) {
715+
/* pop error message */
716+
lua_pop(L, 1);
717+
}
718+
}
719+
720+
static int ctx_on_log_safe(lua_State *L) {
721+
int ref = lua_tointeger(L, 1);
722+
int level = lua_tointeger(L, 2);
723+
const char *str = lua_touserdata(L, 3);
724+
725+
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
726+
727+
lua_pushinteger(L, level);
728+
lua_pushstring(L, str);
655729

656-
lua_rawgeti(ctx->L, LUA_REGISTRYINDEX, ctx->on_unsubscribe);
657-
lua_pushinteger(ctx->L, mid);
658-
lua_call(ctx->L, 1, 0);
730+
lua_call(L, 2, 0);
731+
732+
return 0;
659733
}
660734

661735
static void ctx_on_log(
@@ -665,13 +739,15 @@ static void ctx_on_log(
665739
const char *str)
666740
{
667741
ctx_t *ctx = obj;
668-
669-
lua_rawgeti(ctx->L, LUA_REGISTRYINDEX, ctx->on_log);
670-
671-
lua_pushinteger(ctx->L, level);
672-
lua_pushstring(ctx->L, str);
673-
674-
lua_call(ctx->L, 2, 0);
742+
lua_State *L = ctx->L;
743+
lua_pushcfunction(L, ctx_on_log_safe);
744+
lua_pushinteger(L, ctx->on_log);
745+
lua_pushinteger(L, level);
746+
lua_pushlightuserdata(L, (void*)str);
747+
if (LUA_OK != lua_pcall(L, 3, 0, 0)) {
748+
/* pop error message */
749+
lua_pop(L, 1);
750+
}
675751
}
676752

677753
static int callback_type_from_string(const char *);

0 commit comments

Comments
 (0)