From 3065543d27b0c265f71bd4d194a6aa341a6a0d3c Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Thu, 19 Oct 2023 19:39:44 +0100 Subject: [PATCH 1/3] JSON crash fixes, atari json query no longer needs device prefix Apple test changes to track crashing JSON Ensure json query starts with slash to stop crashes. do not fail atari json query not starting with device spec Fix debug line endings --- lib/device/iwm/network.cpp | 2 +- lib/device/sio/network.cpp | 38 +++++++++++++++++++++++--------------- lib/fnjson/fnjson.cpp | 15 ++++++++++++--- lib/utils/utils.cpp | 7 +++++++ lib/utils/utils.h | 3 +++ 5 files changed, 46 insertions(+), 19 deletions(-) diff --git a/lib/device/iwm/network.cpp b/lib/device/iwm/network.cpp index 6f37df71a..c26cfe30d 100755 --- a/lib/device/iwm/network.cpp +++ b/lib/device/iwm/network.cpp @@ -389,7 +389,7 @@ void iwmNetwork::json_query(iwm_decoded_cmd_t cmd) // addy |= ((cmd.g7byte6 & 0x7f) | ((cmd.grp7msb << 6) & 0x80)) << 8; // addy |= ((cmd.g7byte7 & 0x7f) | ((cmd.grp7msb << 7) & 0x80)) << 16; - Debug_printf("Query set to: %s\n", string((char *)data_buffer, data_len).c_str()); + Debug_printf("\r\nQuery set to: %s, data_len: %d\r\n", string((char *)data_buffer, data_len).c_str(), data_len); json.setReadQuery(string((char *)data_buffer, data_len),cmdFrame.aux2); } diff --git a/lib/device/sio/network.cpp b/lib/device/sio/network.cpp index 696ffbb28..454401427 100755 --- a/lib/device/sio/network.cpp +++ b/lib/device/sio/network.cpp @@ -7,7 +7,10 @@ #include "network.h" #include +#include #include +#include +#include #include "../../include/debug.h" #include "../../include/pinmap.h" @@ -1106,7 +1109,6 @@ void sioNetwork::sio_set_json_query() { uint8_t in[256]; const char *inp = NULL; - uint8_t *tmp; memset(in, 0, sizeof(in)); @@ -1119,22 +1121,28 @@ void sioNetwork::sio_set_json_query() in[i] = 0x00; } - inp = strrchr((const char *)in, ':'); - - if (inp == NULL) - { - sio_error(); - return; + std::string in_string(reinterpret_cast(in)); + size_t last_colon_pos = in_string.rfind(':'); + + std::string inp_string; + if (last_colon_pos != std::string::npos) { + Debug_printf("sioNetwork::sio_set_json_query - skipped device spec. Application should be updated to remove it from query."); + inp_string = in_string.substr(last_colon_pos + 1); + } else { + inp_string = in_string; } - inp++; - json->setReadQuery(string(inp), cmdFrame.aux2); - json_bytes_remaining = json->readValueLen(); - tmp = (uint8_t *)malloc(json->readValueLen()); - json->readValue(tmp,json_bytes_remaining); - *receiveBuffer += string((const char *)tmp,json_bytes_remaining); - free(tmp); - Debug_printf("Query set to %s\n",inp); + json->setReadQuery(inp_string, cmdFrame.aux2); + json_bytes_remaining = json->json_bytes_remaining; + + std::vector tmp(json_bytes_remaining); + json->readValue(tmp.data(), json_bytes_remaining); + + // don't copy past first nul char in tmp + auto null_pos = std::find(tmp.begin(), tmp.end(), 0); + *receiveBuffer += std::string(tmp.begin(), null_pos); + + Debug_printf("Query set to >%s<\r\n", inp_string.c_str()); sio_complete(); } diff --git a/lib/fnjson/fnjson.cpp b/lib/fnjson/fnjson.cpp index 3e77a175b..0de875a45 100644 --- a/lib/fnjson/fnjson.cpp +++ b/lib/fnjson/fnjson.cpp @@ -66,6 +66,7 @@ void FNJSON::setQueryParam(uint8_t qp) */ void FNJSON::setReadQuery(const string &queryString, uint8_t queryParam) { + Debug_printf("FNJSON::setReadQuery queryString: %s, queryParam: %d\r\n", queryString.c_str(), queryParam); _queryString = queryString; _queryParam = queryParam; _item = resolveQuery(); @@ -77,9 +78,9 @@ void FNJSON::setReadQuery(const string &queryString, uint8_t queryParam) */ cJSON *FNJSON::resolveQuery() { - if (_queryString.empty()) - return _json; - + // Queries must start with a slash, else the JSON parsing crashes FujiNet + // An alternative fix would be to check if the returned value was equal to _json and do something with it, but this is simpler. + _queryString = prependSlash(_queryString); return cJSONUtils_GetPointer(_json, _queryString.c_str()); } @@ -149,6 +150,14 @@ string FNJSON::processString(string in) */ string FNJSON::getValue(cJSON *item) { + if (item == NULL) + { + Debug_printf("\r\nFNJSON::getValue called with null item, returning empty string.\r\n"); + return string(""); + } + + // char *asString = cJSON_PrintUnformatted(item); + // Debug_printf("FNJSON::getValue called with item: >%s<\r\n", asString); stringstream ss; if (cJSON_IsString(item)) diff --git a/lib/utils/utils.cpp b/lib/utils/utils.cpp index 5276e9d88..798d24016 100644 --- a/lib/utils/utils.cpp +++ b/lib/utils/utils.cpp @@ -896,3 +896,10 @@ char *util_hexdump(const void *buf, size_t len) { bool isApproximatelyInteger(double value, double tolerance) { return std::abs(value - std::floor(value)) < tolerance; } + +std::string prependSlash(const std::string& str) { + if (str.empty() || str[0] != '/') { + return "/" + str; + } + return str; +} \ No newline at end of file diff --git a/lib/utils/utils.h b/lib/utils/utils.h index a825ed983..a0c14539f 100644 --- a/lib/utils/utils.h +++ b/lib/utils/utils.h @@ -95,4 +95,7 @@ char *util_hexdump(const void *buf, size_t len); // check if a double is very close to an integer bool isApproximatelyInteger(double value, double tolerance = 1e-6); +// ensure string starts with a "/" +std::string prependSlash(const std::string& str); + #endif // _FN_UTILS_H From ba553dd5e22fbaff6e1e66c3b023d624167d38bd Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Fri, 20 Oct 2023 16:07:49 +0100 Subject: [PATCH 2/3] Add CRLF to debug output for json query in SIO --- lib/device/sio/network.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/sio/network.cpp b/lib/device/sio/network.cpp index 454401427..47b85be16 100755 --- a/lib/device/sio/network.cpp +++ b/lib/device/sio/network.cpp @@ -1126,7 +1126,7 @@ void sioNetwork::sio_set_json_query() std::string inp_string; if (last_colon_pos != std::string::npos) { - Debug_printf("sioNetwork::sio_set_json_query - skipped device spec. Application should be updated to remove it from query."); + Debug_printf("sioNetwork::sio_set_json_query - skipped device spec. Application should be updated to remove it from query (%s)\r\n", in_string.c_str()); inp_string = in_string.substr(last_colon_pos + 1); } else { inp_string = in_string; From 6799e3d909dcdddee8cff1fef8e4636abc8c2391 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Fri, 20 Oct 2023 18:12:55 +0100 Subject: [PATCH 3/3] Fix JSON parsing crashing on empty objects --- lib/fnjson/fnjson.cpp | 44 ++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/lib/fnjson/fnjson.cpp b/lib/fnjson/fnjson.cpp index 0de875a45..be0c2f70e 100644 --- a/lib/fnjson/fnjson.cpp +++ b/lib/fnjson/fnjson.cpp @@ -78,9 +78,9 @@ void FNJSON::setReadQuery(const string &queryString, uint8_t queryParam) */ cJSON *FNJSON::resolveQuery() { - // Queries must start with a slash, else the JSON parsing crashes FujiNet - // An alternative fix would be to check if the returned value was equal to _json and do something with it, but this is simpler. - _queryString = prependSlash(_queryString); + if (_queryString.empty()) + return _json; + return cJSONUtils_GetPointer(_json, _queryString.c_str()); } @@ -156,8 +156,6 @@ string FNJSON::getValue(cJSON *item) return string(""); } - // char *asString = cJSON_PrintUnformatted(item); - // Debug_printf("FNJSON::getValue called with item: >%s<\r\n", asString); stringstream ss; if (cJSON_IsString(item)) @@ -204,21 +202,29 @@ string FNJSON::getValue(cJSON *item) setLineEnding("\x0a"); #endif - item = item->child; - - do + if (item->child == NULL) + { + Debug_printf("FNJSON::getValue OBJECT has no CHILD, adding empty string\r\n"); + ss << lineEnding; + } + else { - #ifdef BUILD_IEC - // Convert key to PETSCII - string tempStr = string((const char *)item->string); - mstr::toPETSCII(tempStr); - ss << tempStr; - #else - ss << item->string; - #endif - - ss << lineEnding + getValue(item); - } while ((item = item->next) != NULL); + item = item->child; + do + { + #ifdef BUILD_IEC + // Convert key to PETSCII + string tempStr = string((const char *)item->string); + mstr::toPETSCII(tempStr); + ss << tempStr; + #else + ss << item->string; + #endif + + ss << lineEnding + getValue(item); + } while ((item = item->next) != NULL); + } + } else if (cJSON_IsArray(item)) {