From f4b4ded660cb6901af9c6a6548d8750b9e89982b Mon Sep 17 00:00:00 2001
From: Jo-Philipp Wich <jo@mein.io>
Date: Thu, 29 Sep 2022 13:05:17 +0200
Subject: uloop: task: gracefully handle absent output callback

Both input and output callbacks for uloop tasks are optional, but the
low level io callback implementation did not properly deal with an absent
ucode output callback, triggering an exception in managed code due to
invoking a null value as function.

Fix this issue by checking for the availability of a callable output
function and simply discarding the received task message otherwise.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
---
 lib/uloop.c | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

(limited to 'lib')

diff --git a/lib/uloop.c b/lib/uloop.c
index ef77001..48ff698 100644
--- a/lib/uloop.c
+++ b/lib/uloop.c
@@ -874,7 +874,7 @@ uc_uloop_task_output_cb(struct uloop_fd *fd, unsigned int flags)
 {
 	uc_uloop_task_t *task = container_of(fd, uc_uloop_task_t, output);
 	uc_value_t *obj = ucv_array_get(object_registry, task->registry_index);
-	uc_value_t *msg;
+	uc_value_t *msg = NULL;
 
 	if (flags & ULOOP_READ) {
 		while (true) {
@@ -901,17 +901,22 @@ uc_uloop_task_output_cb(struct uloop_fd *fd, unsigned int flags)
 				break;
 			}
 
-			uc_vm_stack_push(task->vm, ucv_get(obj));
-			uc_vm_stack_push(task->vm, ucv_get(task->output_cb));
-			uc_vm_stack_push(task->vm, msg);
+			if (task->output_cb) {
+				uc_vm_stack_push(task->vm, ucv_get(obj));
+				uc_vm_stack_push(task->vm, ucv_get(task->output_cb));
+				uc_vm_stack_push(task->vm, msg);
 
-			if (uc_vm_call(task->vm, true, 1) == EXCEPTION_NONE) {
-				ucv_put(uc_vm_stack_pop(task->vm));
+				if (uc_vm_call(task->vm, true, 1) == EXCEPTION_NONE) {
+					ucv_put(uc_vm_stack_pop(task->vm));
+				}
+				else {
+					uloop_end();
+
+					return;
+				}
 			}
 			else {
-				uloop_end();
-
-				return;
+				ucv_put(msg);
 			}
 		}
 	}
-- 
cgit v1.2.3