diff --git a/GNUmakefile b/GNUmakefile index af650279..d1fd0f3e 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -244,7 +244,8 @@ $(APP_OBJS): CFLAGS += \ -Werror ifeq ($(UNAME_M),x86_64) $(filter-out $(BUILD_DIR)/android% $(BUILD_DIR)/macos% $(BUILD_DIR)/ios%,$(APP_OBJS)): CFLAGS += \ - -fanalyzer + -fanalyzer #\ + #-Wno-analyzer-use-of-uninitialized-value endif BLOWFISH_SOURCES := \ diff --git a/src/ssb.rpc.c b/src/ssb.rpc.c index 3406dd87..9ff01256 100644 --- a/src/ssb.rpc.c +++ b/src/ssb.rpc.c @@ -563,72 +563,74 @@ static void _tf_ssb_rpc_connection_blobs_createWants_callback(tf_ssb_connection_ return; } - JSPropertyEnum* ptab; - uint32_t plen; - JS_GetOwnPropertyNames(context, &ptab, &plen, args, JS_GPN_STRING_MASK); - for (uint32_t i = 0; i < plen; ++i) + JSPropertyEnum* ptab = NULL; + uint32_t plen = 0; + if (JS_GetOwnPropertyNames(context, &ptab, &plen, args, JS_GPN_STRING_MASK) == 0) { - JSValue key = JS_AtomToString(context, ptab[i].atom); - JSPropertyDescriptor desc; - JSValue key_value = JS_NULL; - if (JS_GetOwnProperty(context, &desc, args, ptab[i].atom) == 1) + for (uint32_t i = 0; i < plen; ++i) { - key_value = desc.value; - JS_FreeValue(context, desc.setter); - JS_FreeValue(context, desc.getter); - } - const char* blob_id = JS_ToCString(context, key); - int64_t size = 0; - JS_ToInt64(context, &size, key_value); - if (--blob_wants->wants_sent == 0) - { - _tf_ssb_rpc_request_more_blobs(connection); - } - if (size < 0) - { - size_t blob_size = 0; - if (tf_ssb_db_blob_get(ssb, blob_id, NULL, &blob_size)) + JSValue key = JS_AtomToString(context, ptab[i].atom); + JSPropertyDescriptor desc; + JSValue key_value = JS_NULL; + if (JS_GetOwnProperty(context, &desc, args, ptab[i].atom) == 1) { - JSValue message = JS_NewObject(context); - JS_SetPropertyStr(context, message, blob_id, JS_NewInt64(context, blob_size)); - tf_ssb_connection_rpc_send_json( - connection, - k_ssb_rpc_flag_stream, - -blob_wants->request_number, - message, - NULL, - NULL, - NULL); - JS_FreeValue(context, message); + key_value = desc.value; + JS_FreeValue(context, desc.setter); + JS_FreeValue(context, desc.getter); } - else if (size == -1LL) + const char* blob_id = JS_ToCString(context, key); + int64_t size = 0; + JS_ToInt64(context, &size, key_value); + if (--blob_wants->wants_sent == 0) { - JSValue message = JS_NewObject(context); - JS_SetPropertyStr(context, message, blob_id, JS_NewInt64(context, -2)); - tf_ssb_connection_rpc_send_json( - connection, - k_ssb_rpc_flag_stream, - -blob_wants->request_number, - message, - NULL, - NULL, - NULL); - JS_FreeValue(context, message); + _tf_ssb_rpc_request_more_blobs(connection); } + if (size < 0) + { + size_t blob_size = 0; + if (tf_ssb_db_blob_get(ssb, blob_id, NULL, &blob_size)) + { + JSValue message = JS_NewObject(context); + JS_SetPropertyStr(context, message, blob_id, JS_NewInt64(context, blob_size)); + tf_ssb_connection_rpc_send_json( + connection, + k_ssb_rpc_flag_stream, + -blob_wants->request_number, + message, + NULL, + NULL, + NULL); + JS_FreeValue(context, message); + } + else if (size == -1LL) + { + JSValue message = JS_NewObject(context); + JS_SetPropertyStr(context, message, blob_id, JS_NewInt64(context, -2)); + tf_ssb_connection_rpc_send_json( + connection, + k_ssb_rpc_flag_stream, + -blob_wants->request_number, + message, + NULL, + NULL, + NULL); + JS_FreeValue(context, message); + } + } + else + { + _tf_ssb_rpc_connection_blobs_get(connection, blob_id, size); + } + JS_FreeCString(context, blob_id); + JS_FreeValue(context, key); + JS_FreeValue(context, key_value); } - else + for (uint32_t i = 0; i < plen; ++i) { - _tf_ssb_rpc_connection_blobs_get(connection, blob_id, size); + JS_FreeAtom(context, ptab[i].atom); } - JS_FreeCString(context, blob_id); - JS_FreeValue(context, key); - JS_FreeValue(context, key_value); + js_free(context, ptab); } - for (uint32_t i = 0; i < plen; ++i) - { - JS_FreeAtom(context, ptab[i].atom); - } - js_free(context, ptab); } static void _tf_ssb_rpc_connection_room_attendants_callback(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data) @@ -1007,23 +1009,33 @@ static void _tf_ssb_rpc_ebt_replicate_send_clock(tf_ssb_connection_t* connection if (!JS_IsUndefined(message)) { - JSPropertyEnum* ptab; + JSPropertyEnum* ptab = NULL; uint32_t plen = 0; - JS_GetOwnPropertyNames(context, &ptab, &plen, message, JS_GPN_STRING_MASK); - work->clock_count = (int)plen; - work->clock = tf_malloc(sizeof(ebt_clock_row_t) * plen); - for (uint32_t i = 0; i < plen; ++i) + if (JS_GetOwnPropertyNames(context, &ptab, &plen, message, JS_GPN_STRING_MASK) == 0) { - const char* id = JS_AtomToCString(context, ptab[i].atom); - snprintf(work->clock[i].id, sizeof(work->clock[i].id), "%s", id); - JS_FreeCString(context, id); + work->clock_count = (int)plen; + work->clock = tf_malloc(sizeof(ebt_clock_row_t) * plen); + memset(work->clock, 0, sizeof(ebt_clock_row_t) * plen); + for (uint32_t i = 0; i < plen; ++i) + { + const char* id = JS_AtomToCString(context, ptab[i].atom); + snprintf(work->clock[i].id, sizeof(work->clock[i].id), "%s", id); + JS_FreeCString(context, id); - JSValue value = JS_GetProperty(context, message, ptab[i].atom); - JS_ToInt64(context, &work->clock[i].value, value); - JS_FreeValue(context, value); - JS_FreeAtom(context, ptab[i].atom); + JSPropertyDescriptor desc = { 0 }; + JSValue key_value = JS_UNDEFINED; + if (JS_GetOwnProperty(context, &desc, message, ptab[i].atom) == 1) + { + key_value = desc.value; + JS_FreeValue(context, desc.setter); + JS_FreeValue(context, desc.getter); + } + JS_ToInt64(context, &work->clock[i].value, key_value); + JS_FreeValue(context, key_value); + JS_FreeAtom(context, ptab[i].atom); + } + js_free(context, ptab); } - js_free(context, ptab); } tf_ssb_connection_run_work(connection, _tf_ssb_rpc_ebt_replicate_send_clock_work, _tf_ssb_rpc_ebt_replicate_send_clock_after_work, work); @@ -1040,36 +1052,45 @@ static void _tf_ssb_rpc_ebt_replicate_send_messages(tf_ssb_connection_t* connect JSContext* context = tf_ssb_get_context(ssb); JSPropertyEnum* ptab = NULL; uint32_t plen = 0; - JS_GetOwnPropertyNames(context, &ptab, &plen, message, JS_GPN_STRING_MASK); - for (uint32_t i = 0; i < plen; ++i) + if (JS_GetOwnPropertyNames(context, &ptab, &plen, message, JS_GPN_STRING_MASK) == 0) { - JSValue in_clock = JS_GetProperty(context, message, ptab[i].atom); - if (!JS_IsUndefined(in_clock)) + for (uint32_t i = 0; i < plen; ++i) { - JSValue key = JS_AtomToString(context, ptab[i].atom); - int64_t sequence = -1; - JS_ToInt64(context, &sequence, in_clock); - const char* author = JS_ToCString(context, key); - if (sequence >= 0 && (sequence & 1) == 0) + JSValue in_clock = JS_UNDEFINED; + JSPropertyDescriptor desc = { 0 }; + if (JS_GetOwnProperty(context, &desc, message, ptab[i].atom) == 1) { - int32_t request_number = tf_ssb_connection_get_ebt_request_number(connection); - _tf_ssb_connection_send_history_stream(connection, request_number, author, sequence >> 1, false, true); - tf_ssb_connection_add_new_message_request(connection, author, request_number, false); + in_clock = desc.value; + JS_FreeValue(context, desc.setter); + JS_FreeValue(context, desc.getter); } - else + if (!JS_IsUndefined(in_clock)) { - tf_ssb_connection_remove_new_message_request(connection, author); + JSValue key = JS_AtomToString(context, ptab[i].atom); + int64_t sequence = -1; + JS_ToInt64(context, &sequence, in_clock); + const char* author = JS_ToCString(context, key); + if (sequence >= 0 && (sequence & 1) == 0) + { + int32_t request_number = tf_ssb_connection_get_ebt_request_number(connection); + _tf_ssb_connection_send_history_stream(connection, request_number, author, sequence >> 1, false, true); + tf_ssb_connection_add_new_message_request(connection, author, request_number, false); + } + else + { + tf_ssb_connection_remove_new_message_request(connection, author); + } + JS_FreeCString(context, author); + JS_FreeValue(context, key); } - JS_FreeCString(context, author); - JS_FreeValue(context, key); + JS_FreeValue(context, in_clock); } - JS_FreeValue(context, in_clock); + for (uint32_t i = 0; i < plen; ++i) + { + JS_FreeAtom(context, ptab[i].atom); + } + js_free(context, ptab); } - for (uint32_t i = 0; i < plen; ++i) - { - JS_FreeAtom(context, ptab[i].atom); - } - js_free(context, ptab); } static void _tf_ssb_rpc_ebt_replicate(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data) diff --git a/src/tests.c b/src/tests.c index bc9e4063..34320b88 100644 --- a/src/tests.c +++ b/src/tests.c @@ -30,11 +30,22 @@ #endif #if !TARGET_OS_IPHONE -static void _test_nop(const tf_test_options_t* options) +static void _write_file(const char* path, const char* contents) { FILE* file = fopen("out/test.js", "w"); - fprintf(file, "print('hi');"); + if (!file) + { + printf("Unable to write %s: %s.\n", path, strerror(errno)); + fflush(stdout); + abort(); + } + fputs(contents, file); fclose(file); +} + +static void _test_nop(const tf_test_options_t* options) +{ + _write_file("out/test.js", "print('hi');"); char command[256]; snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=:memory: -s out/test.js", options->exe_path); @@ -47,8 +58,8 @@ static void _test_nop(const tf_test_options_t* options) static void _test_child(const tf_test_options_t* options) { - FILE* file = fopen("out/test.js", "w"); - fprintf(file, + _write_file( + "out/test.js", "var task = new Task();\n" "task.onExit = function() {\n" " print('child exited');\n" @@ -59,13 +70,11 @@ static void _test_child(const tf_test_options_t* options) " print('child started');\n" " });\n" "});"); - fclose(file); - file = fopen("out/child.js", "w"); - fprintf(file, + _write_file( + "out/child.js", "print('I am the child process.');\n" "exit(0);\n"); - fclose(file); char command[256]; snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=:memory: -s out/test.js", options->exe_path); @@ -81,8 +90,7 @@ static void _test_child(const tf_test_options_t* options) static void _test_promise(const tf_test_options_t* options) { - FILE* file = fopen("out/test.js", "w"); - fprintf(file, + _write_file("out/test.js", "var task = new Task();\n" "task.activate();\n" "File.readFile('out/child.js').then(function(data) {\n" @@ -98,16 +106,14 @@ static void _test_promise(const tf_test_options_t* options) " });\n" " });\n" "});\n"); - fclose(file); - file = fopen("out/child.js", "w"); - fprintf(file, + _write_file( + "out/child.js", "exports = {\n" " add: function(left, right) {\n" " return left + right;\n" " }\n" "}\n"); - fclose(file); char command[256]; snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=:memory: -s out/test.js", options->exe_path); @@ -123,8 +129,8 @@ static void _test_promise(const tf_test_options_t* options) static void _test_promise_remote_throw(const tf_test_options_t* options) { - FILE* file = fopen("out/test.js", "w"); - fprintf(file, + _write_file( + "out/test.js", "var task = new Task();\n" "task.activate();\n" "File.readFile('out/child.js').then(function(data) {\n" @@ -144,16 +150,14 @@ static void _test_promise_remote_throw(const tf_test_options_t* options) " print('caught', e.message);\n" " });\n" "});\n"); - fclose(file); - file = fopen("out/child.js", "w"); - fprintf(file, + _write_file( + "out/child.js", "exports = {\n" " add: function(left, right) {\n" " throw new Error('fail');\n" " }\n" "}\n"); - fclose(file); char command[256]; snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=:memory: -s out/test.js", options->exe_path); @@ -169,8 +173,8 @@ static void _test_promise_remote_throw(const tf_test_options_t* options) static void _test_promise_remote_reject(const tf_test_options_t* options) { - FILE* file = fopen("out/test.js", "w"); - fprintf(file, + _write_file( + "out/test.js", "var task = new Task();\n" "task.activate();\n" "File.readFile('out/child.js').then(function(data) {\n" @@ -190,10 +194,9 @@ static void _test_promise_remote_reject(const tf_test_options_t* options) " print('caught', e.message);\n" " });\n" "});\n"); - fclose(file); - file = fopen("out/child.js", "w"); - fprintf(file, + _write_file( + "out/child.js", "exports = {\n" " add: function(left, right) {\n" " return new Promise(function(resolve, reject) {\n" @@ -201,7 +204,6 @@ static void _test_promise_remote_reject(const tf_test_options_t* options) " });\n" " }\n" "}\n"); - fclose(file); char command[256]; snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=:memory: -s out/test.js", options->exe_path); @@ -217,8 +219,8 @@ static void _test_promise_remote_reject(const tf_test_options_t* options) static void _test_database(const tf_test_options_t* options) { - FILE* file = fopen("out/test.js", "w"); - fprintf(file, + _write_file( + "out/test.js", "var db = new Database('testdb');\n" "if (db.get('a')) {\n" " exit(1);\n" @@ -245,7 +247,6 @@ static void _test_database(const tf_test_options_t* options) " print('Expected but did not find: ' + JSON.stringify(expected));\n" " exit(4);\n" "}\n"); - fclose(file); char command[256]; unlink("out/test_db0.sqlite"); @@ -262,12 +263,11 @@ static void _test_database(const tf_test_options_t* options) static void _test_this(const tf_test_options_t* options) { - FILE* file = fopen("out/test.js", "w"); - fprintf(file, + _write_file( + "out/test.js", "var task = new Task();\n" "task.activate.bind(null).apply();\n" "exit(0);\n"); - fclose(file); char command[256]; snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=:memory: -s out/test.js", options->exe_path); @@ -282,10 +282,9 @@ static void _test_this(const tf_test_options_t* options) static void _test_await(const tf_test_options_t* options) { - FILE* file = fopen("out/test.js", "w"); - fprintf(file, + _write_file( + "out/test.js", "print('hi');\n" - "function foobar() {\n" " return new Promise(function(resolve, reject) {\n" " resolve(10);\n" @@ -300,7 +299,6 @@ static void _test_await(const tf_test_options_t* options) " }\n" "}\n" "\n"); - fclose(file); char command[256]; snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=:memory: -s out/test.js", options->exe_path); @@ -315,28 +313,25 @@ static void _test_await(const tf_test_options_t* options) static void _test_import(const tf_test_options_t* options) { - FILE* file = fopen("out/test.js", "w"); - fprintf(file, + _write_file( + "out/test.js", "import * as req from './required.js';\n" "if (req.foo() != 12345) {\n" " exit(1);\n" "}\n"); - fclose(file); - file = fopen("out/required.js", "w"); - fprintf(file, + _write_file( + "out/required.js", "export function foo() {\n" " return 12345;\n" "}\n"); - fclose(file); - file = fopen("out/bad.js", "w"); - fprintf(file, + _write_file( + "out/bad.js", "import * as req from './missing.js';\n" "if (req.foo() != 12345) {\n" " exit(1);\n" "}\n"); - fclose(file); char command[256]; snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=:memory: -s out/test.js", options->exe_path); @@ -360,13 +355,8 @@ static void _test_import(const tf_test_options_t* options) static void _test_exit(const tf_test_options_t* options) { - FILE* file = fopen("out/test.js", "w"); - fprintf(file, "import * as blah from './blah.js';\n"); - fclose(file); - - file = fopen("out/blah.js", "w"); - fprintf(file, "\n"); - fclose(file); + _write_file("out/test.js", "import * as blah from './blah.js';\n"); + _write_file("out/blah.js", "\n"); char command[256]; snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=:memory: -s out/test.js", options->exe_path); @@ -382,11 +372,10 @@ static void _test_exit(const tf_test_options_t* options) static void _test_icu(const tf_test_options_t* options) { - FILE* file = fopen("out/test.js", "w"); - fprintf(file, + _write_file( + "out/test.js", "print('Hi');\n" "print(parseInt('3').toLocaleString());\n"); - fclose(file); char command[256]; snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=:memory: -s out/test.js", options->exe_path); @@ -401,8 +390,8 @@ static void _test_icu(const tf_test_options_t* options) static void _test_uint8array(const tf_test_options_t* options) { - FILE* file = fopen("out/test.js", "w"); - fprintf(file, + _write_file( + "out/test.js", "var task = new Task();\n" "task.onExit = function() {\n" " print('child exited');\n" @@ -429,16 +418,14 @@ static void _test_uint8array(const tf_test_options_t* options) " exit(0);\n" " })\n" "})\n"); - fclose(file); - file = fopen("out/child.js", "w"); - fprintf(file, + _write_file( + "out/child.js", "exports = {\n" " test: function(data) {\n" " return data;\n" " }\n" "}\n"); - fclose(file); char command[256]; snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=:memory: -s out/test.js", options->exe_path); @@ -454,8 +441,8 @@ static void _test_uint8array(const tf_test_options_t* options) static void _test_float(const tf_test_options_t* options) { - FILE* file = fopen("out/test.js", "w"); - fprintf(file, + _write_file( + "out/test.js", "var task = new Task();\n" "task.onExit = function() {\n" " print('child exited');\n" @@ -471,10 +458,9 @@ static void _test_float(const tf_test_options_t* options) " exit(result == 1.2 ? 0 : 1);\n" " });\n" "});"); - fclose(file); - file = fopen("out/child.js", "w"); - fprintf(file, + _write_file( + "out/child.js", "print(\"child\");\n" "exports = {\n" " test: function(value) {\n" @@ -484,7 +470,6 @@ static void _test_float(const tf_test_options_t* options) "};\n" "print(\"child ready\");\n" ); - fclose(file); char command[256]; snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=:memory: -s out/test.js", options->exe_path); @@ -500,8 +485,8 @@ static void _test_float(const tf_test_options_t* options) static void _test_socket(const tf_test_options_t* options) { - FILE* file = fopen("out/test.js", "w"); - fprintf(file, + _write_file( + "out/test.js", "'use strict';\n" "\n" "var s = new Socket();\n" @@ -573,7 +558,6 @@ static void _test_socket(const tf_test_options_t* options) " print('caught');\n" " print(e);\n" "});\n"); - fclose(file); char command[256]; snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=:memory: -s out/test.js", options->exe_path); @@ -588,8 +572,8 @@ static void _test_socket(const tf_test_options_t* options) static void _test_file(const tf_test_options_t* options) { - FILE* file = fopen("out/test.js", "w"); - fprintf(file, + _write_file( + "out/test.js", "'use strict';\n" "File.readFile('out/test.js').then(function(data) {\n" "}).catch(function(error) {\n" @@ -602,7 +586,6 @@ static void _test_file(const tf_test_options_t* options) "}).catch(function(error) {\n" " print('expected error', error);\n" "});\n"); - fclose(file); char command[256]; snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=:memory: -s out/test.js", options->exe_path); @@ -617,8 +600,8 @@ static void _test_file(const tf_test_options_t* options) static void _test_sign(const tf_test_options_t* options) { - FILE* file = fopen("out/test.js", "w"); - fprintf(file, + _write_file( + "out/test.js", "'use strict';\n" "let id = ssb.createIdentity('test');\n" "print(id);\n" @@ -634,7 +617,6 @@ static void _test_sign(const tf_test_options_t* options) " exit(1);\n" "}\n" ); - fclose(file); char command[256]; snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=:memory: -s out/test.js", options->exe_path); @@ -649,8 +631,8 @@ static void _test_sign(const tf_test_options_t* options) static void _test_b64(const tf_test_options_t* options) { - FILE* file = fopen("out/test.js", "w"); - fprintf(file, + _write_file( + "out/test.js", "'use strict';\n" "print(base64Encode('hello'));\n" "let x = utf8Decode(base64Decode(base64Encode('hello')));\n" @@ -659,7 +641,6 @@ static void _test_b64(const tf_test_options_t* options) " exit(1);\n" "}\n" ); - fclose(file); char command[256]; snprintf(command, sizeof(command), "%s run --ssb-port=0 --db-path=:memory: -s out/test.js", options->exe_path);