diff --git a/.cirrus.yml b/.cirrus.yml index 36d584eb77..dd4fa39560 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,6 +1,6 @@ --- bazel-opt_task: - timeout_in: 5m + timeout_in: 10m container: image: toxchat/toktok-stack:latest-release cpu: 2 @@ -18,7 +18,7 @@ bazel-opt_task: -//c-toxcore/auto_tests:tcp_relay_test # Cirrus doesn't allow external network connections. bazel-dbg_task: - timeout_in: 5m + timeout_in: 10m container: image: toxchat/toktok-stack:latest-debug cpu: 2 diff --git a/auto_tests/file_saving_test.c b/auto_tests/file_saving_test.c index 9198920400..1dcabc3031 100644 --- a/auto_tests/file_saving_test.c +++ b/auto_tests/file_saving_test.c @@ -13,8 +13,8 @@ #include #include -#include "../testing/misc_tools.h" #include "../toxcore/ccompat.h" +#include "../toxcore/tox.h" #include "auto_test_support.h" #include "check_compat.h" @@ -70,7 +70,8 @@ static void load_data_decrypted(void) uint8_t *cipher = (uint8_t *)malloc(size); ck_assert(cipher != nullptr); - uint8_t *clear = (uint8_t *)malloc(size - TOX_PASS_ENCRYPTION_EXTRA_LENGTH); + const size_t clear_size = size - TOX_PASS_ENCRYPTION_EXTRA_LENGTH; + uint8_t *clear = (uint8_t *)malloc(clear_size); ck_assert(clear != nullptr); size_t read_value = fread(cipher, sizeof(*cipher), size, f); printf("Read read_value = %u of %u\n", (unsigned)read_value, (unsigned)size); @@ -83,9 +84,10 @@ static void load_data_decrypted(void) struct Tox_Options *options = tox_options_new(nullptr); ck_assert(options != nullptr); + tox_options_set_experimental_owned_data(options, true); tox_options_set_savedata_type(options, TOX_SAVEDATA_TYPE_TOX_SAVE); - - tox_options_set_savedata_data(options, clear, size); + tox_options_set_savedata_data(options, clear, clear_size); + free(clear); Tox_Err_New err; @@ -103,7 +105,6 @@ static void load_data_decrypted(void) "name returned by tox_self_get_name does not match expected result"); tox_kill(t); - free(clear); free(cipher); free(readname); fclose(f); diff --git a/toxcore/tox.h b/toxcore/tox.h index dddaf16fee..4d3bd4805b 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h @@ -574,7 +574,7 @@ struct Tox_Options { * TOX_PROXY_TYPE_NONE. * * The data pointed at by this member is owned by the user, so must - * outlive the options object. + * outlive the options object (unless experimental_owned_data is set). */ const char *proxy_host; @@ -629,10 +629,10 @@ struct Tox_Options { Tox_Savedata_Type savedata_type; /** - * The savedata. + * The savedata (either a Tox save or a secret key) to load from. * - * The data pointed at by this member is owned by the user, so must outlive - * the options object. + * The data pointed at by this member is owned by the user, so must + * outlive the options object (unless experimental_owned_data is set). */ const uint8_t *savedata_data; @@ -694,6 +694,34 @@ struct Tox_Options { * Default: false. May become true in the future (0.3.0). */ bool experimental_disable_dns; + + /** + * @brief Whether the savedata data is owned by the Tox_Options object. + * + * If true, the setters for savedata and proxy_host try to copy the string. + * If that fails, the value is not copied and the member is set to the + * user-provided pointer. In that case, the user must not free the string + * until the Tox_Options object is freed. Client code can check whether + * allocation succeeded by checking the returned bool. If + * experimental_owned_data is false, it will always return true. If set to + * true, the return value will be false on allocation failure. + * + * If set to true, this must be set before any other member that allocates + * memory is set. + */ + bool experimental_owned_data; + + /** + * @brief Owned pointer to the savedata data. + * @private + */ + uint8_t *owned_savedata_data; + + /** + * @brief Owned pointer to the proxy host. + * @private + */ + char *owned_proxy_host; }; #endif /* TOX_HIDE_DEPRECATED */ @@ -719,7 +747,7 @@ void tox_options_set_proxy_type(Tox_Options *options, Tox_Proxy_Type proxy_type) const char *tox_options_get_proxy_host(const Tox_Options *options); -void tox_options_set_proxy_host(Tox_Options *options, const char *proxy_host); +bool tox_options_set_proxy_host(Tox_Options *options, const char *proxy_host); uint16_t tox_options_get_proxy_port(const Tox_Options *options); @@ -747,7 +775,7 @@ void tox_options_set_savedata_type(Tox_Options *options, Tox_Savedata_Type saved const uint8_t *tox_options_get_savedata_data(const Tox_Options *options); -void tox_options_set_savedata_data(Tox_Options *options, const uint8_t savedata_data[], size_t length); +bool tox_options_set_savedata_data(Tox_Options *options, const uint8_t savedata_data[], size_t length); size_t tox_options_get_savedata_length(const Tox_Options *options); @@ -761,6 +789,10 @@ void *tox_options_get_log_user_data(const Tox_Options *options); void tox_options_set_log_user_data(Tox_Options *options, void *log_user_data); +bool tox_options_get_experimental_owned_data(const Tox_Options *options); + +void tox_options_set_experimental_owned_data(Tox_Options *options, bool experimental_owned_data); + bool tox_options_get_experimental_thread_safety(const Tox_Options *options); void tox_options_set_experimental_thread_safety(Tox_Options *options, bool experimental_thread_safety); diff --git a/toxcore/tox_api.c b/toxcore/tox_api.c index d6996de7c8..ca790748be 100644 --- a/toxcore/tox_api.c +++ b/toxcore/tox_api.c @@ -3,7 +3,8 @@ */ #include "tox.h" -#include +#include // free, malloc +#include // memcpy, strlen #include "ccompat.h" #include "tox_private.h" @@ -164,9 +165,34 @@ const char *tox_options_get_proxy_host(const Tox_Options *options) { return options->proxy_host; } -void tox_options_set_proxy_host(Tox_Options *options, const char *proxy_host) +bool tox_options_set_proxy_host(Tox_Options *options, const char *proxy_host) { - options->proxy_host = proxy_host; + if (!options->experimental_owned_data) { + options->proxy_host = proxy_host; + return true; + } + + if (options->owned_proxy_host != nullptr) { + free(options->owned_proxy_host); + options->owned_proxy_host = nullptr; + } + if (proxy_host == nullptr) { + options->proxy_host = nullptr; + return false; + } + + const size_t proxy_host_length = strlen(proxy_host) + 1; + char *owned_ptr = (char *)malloc(proxy_host_length); + if (owned_ptr != nullptr) { + memcpy(owned_ptr, proxy_host, proxy_host_length); + options->proxy_host = owned_ptr; + options->owned_proxy_host = owned_ptr; + } else { + options->proxy_host = proxy_host; + options->owned_proxy_host = nullptr; + } + + return true; } uint16_t tox_options_get_proxy_port(const Tox_Options *options) { @@ -282,21 +308,61 @@ void tox_options_set_experimental_disable_dns(Tox_Options *options, bool experim { options->experimental_disable_dns = experimental_disable_dns; } +bool tox_options_get_experimental_owned_data(const Tox_Options *options) +{ + return options->experimental_owned_data; +} +void tox_options_set_experimental_owned_data( + Tox_Options *options, bool experimental_owned_data) +{ + options->experimental_owned_data = experimental_owned_data; +} const uint8_t *tox_options_get_savedata_data(const Tox_Options *options) { return options->savedata_data; } -void tox_options_set_savedata_data(Tox_Options *options, const uint8_t *savedata_data, size_t length) +bool tox_options_set_savedata_data(Tox_Options *options, const uint8_t *savedata_data, size_t length) { - options->savedata_data = savedata_data; + if (!options->experimental_owned_data) { + options->savedata_data = savedata_data; + options->savedata_length = length; + return true; + } + + if (options->owned_savedata_data != nullptr) { + free(options->owned_savedata_data); + options->owned_savedata_data = nullptr; + } + if (savedata_data == nullptr) { + options->savedata_data = nullptr; + options->savedata_length = 0; + return false; + } + + uint8_t *owned_ptr = (uint8_t *)malloc(length); + if (owned_ptr != nullptr) { + memcpy(owned_ptr, savedata_data, length); + options->savedata_data = owned_ptr; + options->owned_savedata_data = owned_ptr; + } else { + options->savedata_data = savedata_data; + options->owned_savedata_data = nullptr; + } options->savedata_length = length; + + return true; } void tox_options_default(Tox_Options *options) { if (options != nullptr) { + // Free any owned data. + tox_options_set_proxy_host(options, nullptr); + tox_options_set_savedata_data(options, nullptr, 0); + + // Set the rest to default values. const Tox_Options default_options = {false}; *options = default_options; tox_options_set_ipv6_enabled(options, true); @@ -308,6 +374,7 @@ void tox_options_default(Tox_Options *options) tox_options_set_experimental_thread_safety(options, false); tox_options_set_experimental_groups_persistence(options, false); tox_options_set_experimental_disable_dns(options, false); + tox_options_set_experimental_owned_data(options, false); } } @@ -327,7 +394,12 @@ Tox_Options *tox_options_new(Tox_Err_Options_New *error) void tox_options_free(Tox_Options *options) { - free(options); + if (options != nullptr) { + // Free any owned data. + tox_options_set_proxy_host(options, nullptr); + tox_options_set_savedata_data(options, nullptr, 0); + free(options); + } } const char *tox_user_status_to_string(Tox_User_Status value)