diff --git a/src/main.c b/src/main.c index 593df6d4..e255f831 100644 --- a/src/main.c +++ b/src/main.c @@ -15,6 +15,7 @@ #include #include +#include #if !defined(_WIN32) && !defined(__MACH__) #include @@ -624,6 +625,11 @@ static int _tf_command_usage(const char* file, int argc, char* argv[]) return 0; } +static void _do_leak_checks(int sig) +{ + VALGRIND_DO_LEAK_CHECK; +} + int main(int argc, char* argv[]) { #if !defined(_WIN32) @@ -639,6 +645,10 @@ int main(int argc, char* argv[]) { perror("signal"); } + if (signal(SIGHUP, _do_leak_checks) == SIG_ERR) + { + perror("signal"); + } #endif if (argc >= 2) diff --git a/src/mem.c b/src/mem.c index a8a757a4..b4be62c3 100644 --- a/src/mem.c +++ b/src/mem.c @@ -38,7 +38,15 @@ static void* _tf_realloc(int64_t* total, void* ptr, size_t size) { memcpy(&old_size, old_ptr, sizeof(size_t)); } - void* new_ptr = realloc(old_ptr, size ? size + sizeof(size_t) : 0); + void* new_ptr = NULL; + if (old_ptr && !size) + { + free(old_ptr); + } + else + { + new_ptr = realloc(old_ptr, size + sizeof(size_t)); + } if (new_ptr) { __atomic_add_fetch(total, (int64_t)size - (int64_t)old_size, __ATOMIC_RELAXED); diff --git a/src/serialize.c b/src/serialize.c index 801840d3..97b0d96f 100644 --- a/src/serialize.c +++ b/src/serialize.c @@ -199,13 +199,6 @@ static bool _serialize_storeInternal(tf_task_t* task, tf_taskstub_t* to, buffer_ if (JS_IsError(context, exception)) { - JSValue m = JS_GetPropertyStr(context, exception, "message"); - if (!JS_IsUndefined(m) && !JS_IsException(m)) - { - const char* ms = JS_ToCString(context, m); - JS_FreeCString(context, ms); - } - JSValue stack = JS_GetPropertyStr(context, exception, "stack"); if (!JS_IsUndefined(stack) && !JS_IsException(stack)) { @@ -253,13 +246,16 @@ static bool _serialize_storeInternal(tf_task_t* task, tf_taskstub_t* to, buffer_ _serialize_writeInt32(buffer, length); for (int i = 0; i < length; ++i) { - _serialize_storeInternal(task, to, buffer, JS_GetPropertyUint32(tf_task_get_context(task), value, i), depth + 1); + JSValue element = JS_GetPropertyUint32(tf_task_get_context(task), value, i); + _serialize_storeInternal(task, to, buffer, element, depth + 1); + JS_FreeValue(context, element); } } else { _serialize_writeInt32(buffer, 0); } + JS_FreeValue(tf_task_get_context(task), length_val); } else if (JS_IsFunction(tf_task_get_context(task), value)) { diff --git a/src/socket.js.c b/src/socket.js.c index 0df4e58f..919a66a0 100644 --- a/src/socket.js.c +++ b/src/socket.js.c @@ -258,6 +258,7 @@ void _socket_close_internal(socket_t* socket) { _sockets[i] = _sockets[_sockets_count - 1]; --_sockets_count; + _sockets = tf_realloc(_sockets, sizeof(socket_t*) * _sockets_count); break; } } @@ -870,10 +871,13 @@ int _socket_writeBytes(socket_t* socket, promiseid_t promise, int (*callback)(so size_t offset; size_t element_size; JSValue buffer = tf_util_try_get_typed_array_buffer(context, value, &offset, &length, &element_size); - size_t size; - if ((array = tf_util_try_get_array_buffer(context, &size, buffer)) != 0) + if (!JS_IsException(buffer)) { - result = callback(socket, promise, (const char*)array, length); + size_t size; + if ((array = tf_util_try_get_array_buffer(context, &size, buffer)) != 0) + { + result = callback(socket, promise, (const char*)array, length); + } } JS_FreeValue(context, buffer); } diff --git a/src/ssb.db.c b/src/ssb.db.c index c5477997..1690ce29 100644 --- a/src/ssb.db.c +++ b/src/ssb.db.c @@ -144,9 +144,13 @@ bool tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, JSValue authorval = JS_GetPropertyStr(context, val, "author"); const char* author = JS_ToCString(context, authorval); int64_t sequence = -1; - JS_ToInt64(context, &sequence, JS_GetPropertyStr(context, val, "sequence")); + JSValue sequenceval = JS_GetPropertyStr(context, val, "sequence"); + JS_ToInt64(context, &sequence, sequenceval); + JS_FreeValue(context, sequenceval); double timestamp = -1.0; - JS_ToFloat64(context, ×tamp, JS_GetPropertyStr(context, val, "timestamp")); + JSValue timestampval = JS_GetPropertyStr(context, val, "timestamp"); + JS_ToFloat64(context, ×tamp, timestampval); + JS_FreeValue(context, timestampval); JSValue contentval = JS_GetPropertyStr(context, val, "content"); JSValue content = JS_JSONStringify(context, contentval, JS_NULL, JS_NULL); diff --git a/src/ssb.import.c b/src/ssb.import.c index 05efd57b..30cdf408 100644 --- a/src/ssb.import.c +++ b/src/ssb.import.c @@ -54,6 +54,7 @@ static void _tf_ssb_import_add_app(tf_ssb_t* ssb, const char* user, const char* int32_t length = 0; JSValue lengthval = JS_GetPropertyStr(context, apps, "length"); JS_ToInt32(context, &length, lengthval); + JS_FreeValue(context, lengthval); JS_SetPropertyUint32(context, apps, length, JS_NewString(context, app)); JSValue json = JS_JSONStringify(context, apps, JS_NULL, JS_NULL); diff --git a/src/ssb.js.c b/src/ssb.js.c index 7644368e..25a6aca0 100644 --- a/src/ssb.js.c +++ b/src/ssb.js.c @@ -491,6 +491,7 @@ static JSValue _tf_ssb_add_rpc(JSContext* context, JSValueConst this_val, int ar JSValue length_val = JS_GetPropertyStr(context, argv[0], "length"); int length = 0; JS_ToInt32(context, &length, length_val); + JS_FreeValue(context, length_val); enum { k_max_name_parts = 16 }; const char* name[k_max_name_parts + 1] = { 0 }; diff --git a/src/task.c b/src/task.c index 3a236f72..6089f7aa 100644 --- a/src/task.c +++ b/src/task.c @@ -598,7 +598,7 @@ static void _tf_task_sendPromiseExportMessage(tf_task_t* from, tf_taskstub_t* to JSValue _tf_task_get_parent(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { tf_task_t* task = JS_GetContextOpaque(context); - return task->_parent ? tf_taskstub_get_task_object(task->_parent) : JS_UNDEFINED; + return task->_parent ? JS_DupValue(context, tf_taskstub_get_task_object(task->_parent)) : JS_UNDEFINED; } static JSValue _tf_task_version(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) @@ -880,6 +880,7 @@ void tf_task_on_receive_packet(int packetType, const char* begin, size_t length, JS_FreeValue(to->_context, value); JSValue utf8 = tf_util_utf8_decode(to->_context, source); + JS_FreeValue(to->_context, source); const char* source_str = JS_ToCString(to->_context, utf8); JS_FreeValue(to->_context, utf8); JSValue result = _tf_task_executeSource(to, source_str, name); @@ -1331,7 +1332,8 @@ void tf_task_activate(tf_task_t* task) JSContext* context = task->_context; JSValue global = JS_GetGlobalObject(context); - JS_SetPropertyStr(context, global, "exports", JS_NewObject(context)); + JSValue e = JS_NewObject(context); + JS_SetPropertyStr(context, global, "exports", e); JSAtom atom = JS_NewAtom(context, "parent"); JS_DefinePropertyGetSet(context, global, atom, JS_NewCFunction(context, _tf_task_get_parent, "parent", 0), JS_UNDEFINED, 0); diff --git a/src/taskstub.js.c b/src/taskstub.js.c index 72356e35..5fe2f08c 100644 --- a/src/taskstub.js.c +++ b/src/taskstub.js.c @@ -25,7 +25,6 @@ static char _executable[1024]; typedef struct _tf_taskstub_t { taskid_t _id; JSValue _object; - JSValue _taskObject; JSValue _on_exit; JSValue _on_error; @@ -78,7 +77,7 @@ static JSValue _taskstub_create(JSContext* context, JSValueConst this_val, int a stub->_on_exit = JS_UNDEFINED; stub->_on_error = JS_UNDEFINED; stub->_on_print = JS_UNDEFINED; - stub->_object = JS_DupValue(context, taskObject); + stub->_object = taskObject; JSAtom atom = JS_NewAtom(context, "onExit"); JS_DefinePropertyGetSet( @@ -157,7 +156,6 @@ static JSValue _taskstub_create(JSContext* context, JSValueConst this_val, int a { tf_packetstream_set_on_receive(stub->_stream, tf_task_on_receive_packet, stub); tf_packetstream_start(stub->_stream); - result = taskObject; } else @@ -200,7 +198,7 @@ taskid_t tf_taskstub_get_id(const tf_taskstub_t* stub) JSValue tf_taskstub_get_task_object(const tf_taskstub_t* stub) { - return stub->_taskObject; + return stub->_object; } tf_packetstream_t* tf_taskstub_get_stream(const tf_taskstub_t* stub) @@ -223,11 +221,10 @@ tf_taskstub_t* tf_taskstub_create_parent(tf_task_t* task, uv_file file) parentStub->_on_error = JS_UNDEFINED; parentStub->_on_print = JS_UNDEFINED; - parentStub->_taskObject = parentObject; JS_SetOpaque(parentObject, parentStub); parentStub->_owner = task; parentStub->_id = k_task_parent_id; - parentStub->_object = JS_DupValue(tf_task_get_context(task), parentObject); + parentStub->_object = parentObject; if (uv_pipe_init(tf_task_get_loop(task), tf_packetstream_get_pipe(parentStub->_stream), 1) != 0) { @@ -300,9 +297,12 @@ static void _taskstub_on_process_exit(uv_process_t* process, int64_t status, int JS_FreeValue(context, argv[0]); JS_FreeValue(context, argv[1]); } - tf_packetstream_close(stub->_stream); + if (stub->_stream) + { + tf_packetstream_close(stub->_stream); + stub->_stream = NULL; + } uv_close((uv_handle_t*)process, _taskstub_on_handle_close); - tf_taskstub_destroy(stub); } static JSValue _taskstub_getExports(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)