diff --git a/src/jsonrpc-machine-c-api.cpp b/src/jsonrpc-machine-c-api.cpp index dde5c4685..31e8ad9c3 100644 --- a/src/jsonrpc-machine-c-api.cpp +++ b/src/jsonrpc-machine-c-api.cpp @@ -120,9 +120,7 @@ cm_error cm_jsonrpc_get_default_config(const cm_jsonrpc_mgr *mgr, const char **c } const auto *cpp_mgr = convert_from_c(mgr); const cartesi::machine_config cpp_config = cartesi::jsonrpc_virtual_machine::get_default_config(*cpp_mgr); - static THREAD_LOCAL std::string config_storage; - config_storage = cartesi::to_json(cpp_config).dump(); - *config = config_storage.c_str(); + *config = cm_set_temp_string(cartesi::to_json(cpp_config).dump()); return cm_result_success(); } catch (...) { if (config) { @@ -169,9 +167,7 @@ cm_error cm_jsonrpc_fork(const cm_jsonrpc_mgr *mgr, const char **address, int32_ } const auto *cpp_mgr = convert_from_c(mgr); const auto result = cartesi::jsonrpc_virtual_machine::fork(*cpp_mgr); - static THREAD_LOCAL std::string address_storage; - address_storage = result.address; - *address = address_storage.c_str(); + *address = cm_set_temp_string(result.address); if (pid) { *pid = static_cast(result.pid); } @@ -190,9 +186,7 @@ cm_error cm_jsonrpc_rebind(const cm_jsonrpc_mgr *mgr, const char *address, const const auto *cpp_mgr = convert_from_c(mgr); const std::string cpp_new_address = cartesi::jsonrpc_virtual_machine::rebind(*cpp_mgr, address); if (new_address) { - static THREAD_LOCAL std::string new_address_storage; - new_address_storage = cpp_new_address; - *new_address = new_address_storage.c_str(); + *new_address = cm_set_temp_string(cpp_new_address); } return cm_result_success(); } catch (...) { @@ -223,9 +217,7 @@ cm_error cm_jsonrpc_get_version(const cm_jsonrpc_mgr *mgr, const char **version) } const auto *cpp_mgr = convert_from_c(mgr); const cartesi::semantic_version cpp_version = cartesi::jsonrpc_virtual_machine::get_version(*cpp_mgr); - static THREAD_LOCAL std::string version_storage; - version_storage = cartesi::to_json(cpp_version).dump(); - *version = version_storage.c_str(); + *version = cm_set_temp_string(cartesi::to_json(cpp_version).dump()); return cm_result_success(); } catch (...) { if (version) { diff --git a/src/jsonrpc-machine-c-api.h b/src/jsonrpc-machine-c-api.h index 00ebff752..c788f7b82 100644 --- a/src/jsonrpc-machine-c-api.h +++ b/src/jsonrpc-machine-c-api.h @@ -45,7 +45,7 @@ CM_API void cm_jsonrpc_destroy_mgr(const cm_jsonrpc_mgr *mgr); /// \brief Forks the remote server. /// \param mgr Pointer to a valid JSONRPC connection manager. /// \param address Receives address of new server if function execution succeeds or NULL otherwise, -/// remains valid until the next time this same function is called on the same thread. +/// guaranteed to remain valid only until the next C API is called from the same thread. /// \param pid Receives the forked child process id if function execution succeeds or 0 otherwise. /// \returns 0 for success, non zero code for error. CM_API cm_error cm_jsonrpc_fork(const cm_jsonrpc_mgr *mgr, const char **address, int32_t *pid); @@ -54,7 +54,7 @@ CM_API cm_error cm_jsonrpc_fork(const cm_jsonrpc_mgr *mgr, const char **address, /// \param mgr Pointer to a valid JSONRPC connection manager. /// \param address New address that the remote server should bind to. /// \param new_address Receives the new address that the remote server actually bound to, -/// remains valid until the next time this same function is called on the same thread. +/// guaranteed to remain valid only until the next C API is called from the same thread. /// \returns 0 for success, non zero code for error. CM_API cm_error cm_jsonrpc_rebind(const cm_jsonrpc_mgr *mgr, const char *address, const char **new_address); @@ -66,14 +66,14 @@ CM_API cm_error cm_jsonrpc_shutdown(const cm_jsonrpc_mgr *mgr); /// \brief Gets the semantic version of the remote server. /// \param mgr Pointer to a valid JSONRPC connection manager. /// \param semantic_version Receives the semantic version as a JSON string, -/// remains valid until the next time this same function is called on the same thread. +/// guaranteed to remain valid only until the next C API is called from the same thread. /// \returns 0 for success, non zero code for error. CM_API cm_error cm_jsonrpc_get_version(const cm_jsonrpc_mgr *mgr, const char **version); /// \brief Gets a JSON string for the default machine config from the remote server. /// \param mgr Pointer to a valid JSONRPC connection manager. /// \param config Receives the default configuration, -/// remains valid until the next time this same function is called on the same thread. +/// guaranteed to remain valid only until the next C API is called from the same thread. /// \returns 0 for success, non zero code for error. CM_API cm_error cm_jsonrpc_get_default_config(const cm_jsonrpc_mgr *mgr, const char **config); diff --git a/src/machine-c-api-internal.h b/src/machine-c-api-internal.h index b6fe2f0d4..6ccb96e11 100644 --- a/src/machine-c-api-internal.h +++ b/src/machine-c-api-internal.h @@ -35,4 +35,7 @@ cm_error cm_result_success(); /// \brief Helper function that parses hash from C api structure cartesi::machine_merkle_tree::hash_type convert_from_c(const cm_hash *c_hash); +/// \brief Helper function that stores a string to a temporary thread local. +const char *cm_set_temp_string(const std::string &s); + #endif // CM_C_API_INTERNAL_H diff --git a/src/machine-c-api.cpp b/src/machine-c-api.cpp index ac2750779..fb6d59b4b 100644 --- a/src/machine-c-api.cpp +++ b/src/machine-c-api.cpp @@ -47,6 +47,12 @@ const char *cm_get_last_error_message() { return last_err_msg.c_str(); } +const char *cm_set_temp_string(const std::string &s) { + static THREAD_LOCAL std::string temp_string; + temp_string = s; + return temp_string.c_str(); +} + cm_error cm_result_failure() try { throw; } catch (std::exception &e) { try { last_err_msg = e.what(); @@ -245,9 +251,7 @@ cm_error cm_log_reset_uarch(cm_machine *m, int32_t log_type, const char **log) t auto *cpp_machine = convert_from_c(m); cartesi::access_log::type cpp_log_type(log_type); cartesi::access_log cpp_log = cpp_machine->log_reset_uarch(cpp_log_type); - static THREAD_LOCAL std::string access_log_storage; - access_log_storage = cartesi::to_json(cpp_log).dump(); - *log = access_log_storage.c_str(); + *log = cm_set_temp_string(cartesi::to_json(cpp_log).dump()); return cm_result_success(); } catch (...) { if (log) { @@ -277,9 +281,7 @@ cm_error cm_log_step_uarch(cm_machine *m, int32_t log_type, const char **log) tr auto *cpp_machine = convert_from_c(m); cartesi::access_log::type cpp_log_type(log_type); cartesi::access_log cpp_log = cpp_machine->log_step_uarch(cpp_log_type); - static THREAD_LOCAL std::string access_log_storage; - access_log_storage = cartesi::to_json(cpp_log).dump(); - *log = access_log_storage.c_str(); + *log = cm_set_temp_string(cartesi::to_json(cpp_log).dump()); return cm_result_success(); } catch (...) { if (log) { @@ -322,9 +324,7 @@ cm_error cm_get_proof(const cm_machine *m, uint64_t address, int32_t log2_size, } const auto *cpp_machine = convert_from_c(m); const cartesi::machine_merkle_tree::proof_type cpp_proof = cpp_machine->get_proof(address, log2_size); - static THREAD_LOCAL std::string proof_storage; - proof_storage = cartesi::to_json(cpp_proof).dump(); - *proof = proof_storage.c_str(); + *proof = cm_set_temp_string(cartesi::to_json(cpp_proof).dump()); return cm_result_success(); } catch (...) { if (proof) { @@ -561,9 +561,7 @@ cm_error cm_get_initial_config(const cm_machine *m, const char **config) try { } const auto *cpp_machine = convert_from_c(m); const cartesi::machine_config cpp_config = cpp_machine->get_initial_config(); - static THREAD_LOCAL std::string config_storage; - config_storage = cartesi::to_json(cpp_config).dump(); - *config = config_storage.c_str(); + *config = cm_set_temp_string(cartesi::to_json(cpp_config).dump()); return cm_result_success(); } catch (...) { if (config) { @@ -577,9 +575,7 @@ cm_error cm_get_default_config(const char **config) try { throw std::invalid_argument("invalid config output"); } const cartesi::machine_config cpp_config = cartesi::machine::get_default_config(); - static THREAD_LOCAL std::string config_storage; - config_storage = cartesi::to_json(cpp_config).dump(); - *config = config_storage.c_str(); + *config = cm_set_temp_string(cartesi::to_json(cpp_config).dump()); return cm_result_success(); } catch (...) { if (config) { @@ -645,9 +641,7 @@ cm_error cm_get_memory_ranges(const cm_machine *m, const char **ranges) try { } const auto *cpp_machine = convert_from_c(m); const cartesi::machine_memory_range_descrs cpp_ranges = cpp_machine->get_memory_ranges(); - static THREAD_LOCAL std::string ranges_storage; - ranges_storage = cartesi::to_json(cpp_ranges).dump(); - *ranges = ranges_storage.c_str(); + *ranges = cm_set_temp_string(cartesi::to_json(cpp_ranges).dump()); return cm_result_success(); } catch (...) { if (ranges) { @@ -731,9 +725,7 @@ cm_error cm_log_send_cmio_response(cm_machine *m, uint16_t reason, const uint8_t auto *cpp_machine = convert_from_c(m); cartesi::access_log::type cpp_log_type(log_type); cartesi::access_log cpp_log = cpp_machine->log_send_cmio_response(reason, data, length, cpp_log_type); - static THREAD_LOCAL std::string access_log_storage; - access_log_storage = cartesi::to_json(cpp_log).dump(); - *log = access_log_storage.c_str(); + *log = cm_set_temp_string(cartesi::to_json(cpp_log).dump()); return cm_result_success(); } catch (...) { if (log) { diff --git a/src/machine-c-api.h b/src/machine-c-api.h index 89903d013..1e19765a9 100644 --- a/src/machine-c-api.h +++ b/src/machine-c-api.h @@ -314,8 +314,7 @@ CM_API const char *cm_get_last_error_message(); /// \brief Obtains a JSON object with the default machine config as a string. /// \param config Receives the default configuration as a JSON object in a string, -/// guaranteed to remain valid only until the the next time this same function -/// is called again on the same thread. +/// guaranteed to remain valid only until the next C API is called from the same thread. /// \returns 0 for success, non zero code for error. /// \details The returned config is not sufficient to run a machine. /// Additional configurations, such as RAM length, RAM image, flash drives, @@ -381,17 +380,15 @@ CM_API cm_error cm_replace_memory_range(cm_machine *m, uint64_t start, uint64_t /// \brief Obtains a JSON object with the machine config used to initialize the machine. /// \param m Pointer to a valid machine instance. -/// \param config Receives the initial configuration as a JSON object in a -/// string, guaranteed to remain valid only until the the next time this same function -/// is called again on the same thread. +/// \param config Receives the initial configuration as a JSON object in a string, +/// guaranteed to remain valid only until the next C API is called from the same thread. /// \returns 0 for success, non zero code for error. CM_API cm_error cm_get_initial_config(const cm_machine *m, const char **config); /// \brief Obtains a list with all memory ranges in the machine. /// \param m Pointer to a valid machine instance. /// \param ranges Receives the memory ranges as a JSON object in a string, -/// guaranteed to remain valid only until the the next time this same function is -/// called again on the same thread. +/// guaranteed to remain valid only until the next C API is called from the same thread. /// \returns 0 for success, non zero code for error. CM_API cm_error cm_get_memory_ranges(const cm_machine *m, const char **ranges); @@ -407,9 +404,8 @@ CM_API cm_error cm_get_root_hash(const cm_machine *m, cm_hash *hash); /// \param log2_size The log base 2 of the size subtended by target node. /// Must be between CM_TREE_LOG2_WORD_SIZE (for a word) and CM_TREE_LOG2_ROOT_SIZE /// (for the entire address space), inclusive. -/// \param proof Receives the proof as a JSON object in a string, guaranteed to -/// remain valid only until the the next time this same function is called again on -/// the same thread. +/// \param proof Receives the proof as a JSON object in a string, +/// guaranteed to remain valid only until the next C API is called from the same thread. /// \returns 0 for success, non zero code for error. CM_API cm_error cm_get_proof(const cm_machine *m, uint64_t address, int32_t log2_size, const char **proof); @@ -616,7 +612,7 @@ CM_API cm_error cm_send_cmio_response(cm_machine *m, uint16_t reason, const uint /// \param m Pointer to valid machine instance. /// \param log_type Type of access log to generate. /// \param log Receives the state access log as a JSON object in a string, -/// remains valid until the next time this same function is called on the same thread. +/// guaranteed to remain valid only until the next C API is called from the same thread. /// \returns 0 for success, non zero code for error. CM_API cm_error cm_log_step_uarch(cm_machine *m, int32_t log_type, const char **log); @@ -624,7 +620,7 @@ CM_API cm_error cm_log_step_uarch(cm_machine *m, int32_t log_type, const char ** /// \param m Pointer to valid machine instance. /// \param log_type Type of access log to generate. /// \param log Receives the state access log as a JSON object in a string, -/// remains valid until the next time this same function is called on the same thread. +/// guaranteed to remain valid only until the next C API is called from the same thread. /// \returns 0 for success, non zero code for error. CM_API cm_error cm_log_reset_uarch(cm_machine *m, int32_t log_type, const char **log); @@ -635,7 +631,7 @@ CM_API cm_error cm_log_reset_uarch(cm_machine *m, int32_t log_type, const char * /// \param length Length of response data. /// \param log_type Type of access log to generate. /// \param log Receives the state access log as a JSON object in a string, -/// remains valid until the next time this same function is called on the same thread. +/// guaranteed to remain valid only until the next C API is called from the same thread. /// \returns 0 for success, non zero code for error. CM_API cm_error cm_log_send_cmio_response(cm_machine *m, uint16_t reason, const uint8_t *data, uint64_t length, int32_t log_type, const char **log);