From 2de57d242d08d4fd958c1b405b08e81cb5fa8952 Mon Sep 17 00:00:00 2001 From: Timothy Stack Date: Thu, 31 Dec 2020 15:24:28 -0800 Subject: [PATCH] [leak] fix leak of yajl error msgs --- src/json-extension-functions.cc | 20 +++++++++++++------- src/lnav_commands.cc | 18 +++++++++++++----- src/lnav_config.cc | 15 +++++++++++---- src/log_format_loader.cc | 11 +++++++---- src/yajlpp/drive_json_op.cc | 15 +++++++++++---- src/yajlpp/json_ptr.hh | 10 +++++++--- src/yajlpp/yajlpp.cc | 12 ++++++++---- 7 files changed, 70 insertions(+), 31 deletions(-) diff --git a/src/json-extension-functions.cc b/src/json-extension-functions.cc index 41a1b195..befa882b 100644 --- a/src/json-extension-functions.cc +++ b/src/json-extension-functions.cc @@ -196,7 +196,7 @@ static void sql_jget(sqlite3_context *context, json_ptr jp(ptr_in); sql_json_op jo(jp); auto_mem handle(yajl_free); - const unsigned char *err; + unsigned char *err; yajlpp_gen gen; yajl_gen_config(gen, yajl_gen_beautify, false); @@ -209,10 +209,13 @@ static void sql_jget(sqlite3_context *context, handle.reset(yajl_alloc(&json_op::ptr_callbacks, nullptr, &jo)); switch (yajl_parse(handle.in(), (const unsigned char *)json_in, strlen(json_in))) { - case yajl_status_error: - err = yajl_get_error(handle.in(), 0, (const unsigned char *)json_in, strlen(json_in)); - sqlite3_result_error(context, (const char *)err, -1); + case yajl_status_error: { + err = yajl_get_error(handle.in(), 0, (const unsigned char *) json_in, + strlen(json_in)); + sqlite3_result_error(context, (const char *) err, -1); + yajl_free_error(handle.in(), err); return; + } case yajl_status_client_canceled: if (jo.jo_ptr.jp_state == json_ptr::MS_ERR_INVALID_ESCAPE) { sqlite3_result_error(context, jo.jo_ptr.error_msg().c_str(), -1); @@ -226,10 +229,13 @@ static void sql_jget(sqlite3_context *context, } switch (yajl_complete_parse(handle.in())) { - case yajl_status_error: - err = yajl_get_error(handle.in(), 0, (const unsigned char *)json_in, strlen(json_in)); - sqlite3_result_error(context, (const char *)err, -1); + case yajl_status_error: { + err = yajl_get_error(handle.in(), 0, (const unsigned char *) json_in, + strlen(json_in)); + sqlite3_result_error(context, (const char *) err, -1); + yajl_free_error(handle.in(), err); return; + } case yajl_status_client_canceled: if (jo.jo_ptr.jp_state == json_ptr::MS_ERR_INVALID_ESCAPE) { sqlite3_result_error(context, jo.jo_ptr.error_msg().c_str(), -1); diff --git a/src/lnav_commands.cc b/src/lnav_commands.cc index 04ac21e8..11ddddb5 100644 --- a/src/lnav_commands.cc +++ b/src/lnav_commands.cc @@ -550,7 +550,7 @@ static void json_write_row(yajl_gen handle, int row) switch (hm.hm_sub_type) { case 74: { auto_mem parse_handle(yajl_free); - const unsigned char *err; + unsigned char *err; json_ptr jp(""); json_op jo(jp); @@ -561,22 +561,30 @@ static void json_write_row(yajl_gen handle, int row) const unsigned char *json_in = (const unsigned char *) dls.dls_rows[row][col]; switch (yajl_parse(parse_handle.in(), json_in, strlen((const char *) json_in))) { case yajl_status_error: - case yajl_status_client_canceled: - err = yajl_get_error(parse_handle.in(), 0, json_in, strlen((const char *) json_in)); + case yajl_status_client_canceled: { + err = yajl_get_error(parse_handle.in(), 0, json_in, + strlen( + (const char *) json_in)); log_error("unable to parse JSON cell: %s", err); obj_map.gen(dls.dls_rows[row][col]); + yajl_free_error(parse_handle.in(), err); return; + } default: break; } switch (yajl_complete_parse(parse_handle.in())) { case yajl_status_error: - case yajl_status_client_canceled: - err = yajl_get_error(parse_handle.in(), 0, json_in, strlen((const char *) json_in)); + case yajl_status_client_canceled: { + err = yajl_get_error(parse_handle.in(), 0, json_in, + strlen( + (const char *) json_in)); log_error("unable to parse JSON cell: %s", err); obj_map.gen(dls.dls_rows[row][col]); + yajl_free_error(parse_handle.in(), err); return; + } default: break; } diff --git a/src/lnav_config.cc b/src/lnav_config.cc index ff9d0505..5774bc70 100644 --- a/src/lnav_config.cc +++ b/src/lnav_config.cc @@ -359,14 +359,21 @@ void install_extra_formats() if (yajl_parse(jhandle, buffer, rc) != yajl_status_ok) { - fprintf(stderr, "Unable to parse remote-config.json -- %s", - yajl_get_error(jhandle, 1, buffer, rc)); + auto msg = yajl_get_error(jhandle, 1, buffer, rc); + fprintf(stderr, + "Unable to parse remote-config.json -- %s", + msg); + yajl_free_error(jhandle, msg); return; } } if (yajl_complete_parse(jhandle) != yajl_status_ok) { - fprintf(stderr, "Unable to parse remote-config.json -- %s", - yajl_get_error(jhandle, 1, buffer, rc)); + auto msg = yajl_get_error(jhandle, 1, buffer, rc); + + fprintf(stderr, + "Unable to parse remote-config.json -- %s", + msg); + yajl_free_error(jhandle, msg); } } } diff --git a/src/log_format_loader.cc b/src/log_format_loader.cc index b040f6f0..0ba2940b 100644 --- a/src/log_format_loader.cc +++ b/src/log_format_loader.cc @@ -931,10 +931,13 @@ void load_formats(const std::vector &extra_paths, yajl_config(handle, yajl_allow_comments, 1); auto sf = bsf.to_string_fragment(); if (ypc_builtin.parse(sf) != yajl_status_ok) { - errors.push_back("builtin: invalid json -- " + - string((char *) yajl_get_error(handle, 1, - (const unsigned char *) sf.data(), - sf.length()))); + unsigned char *msg = yajl_get_error(handle, 1, + (const unsigned char *) sf.data(), + sf.length()); + + errors.push_back(fmt::format( + FMT_STRING("builtin: invalid json -- {}"), msg)); + yajl_free_error(handle, msg); } ypc_builtin.complete_parse(); yajl_free(handle); diff --git a/src/yajlpp/drive_json_op.cc b/src/yajlpp/drive_json_op.cc index d47ddbdb..322c964c 100644 --- a/src/yajlpp/drive_json_op.cc +++ b/src/yajlpp/drive_json_op.cc @@ -172,9 +172,13 @@ int main(int argc, char *argv[]) while ((rc = read(STDIN_FILENO, buffer, sizeof(buffer))) > 0) { status = yajl_parse(handle, buffer, rc); if (status == yajl_status_error) { - fprintf(stderr, "error:cannot parse JSON input -- %s\n", - yajl_get_error(handle, 1, buffer, rc)); + auto msg = yajl_get_error(handle, 1, buffer, rc); + + fprintf(stderr, + "error:cannot parse JSON input -- %s\n", + msg); retval = EXIT_FAILURE; + yajl_free_error(handle, msg); break; } else if (status == yajl_status_client_canceled) { @@ -184,8 +188,11 @@ int main(int argc, char *argv[]) } status = yajl_complete_parse(handle); if (status == yajl_status_error) { - fprintf(stderr, "error:cannot parse JSON input -- %s\n", - yajl_get_error(handle, 1, buffer, rc)); + auto msg = yajl_get_error(handle, 1, buffer, rc); + fprintf(stderr, + "error:cannot parse JSON input -- %s\n", + msg); + yajl_free_error(handle, msg); retval = EXIT_FAILURE; } else if (status == yajl_status_client_canceled) { diff --git a/src/yajlpp/json_ptr.hh b/src/yajlpp/json_ptr.hh index 0a15f1d6..29a81788 100644 --- a/src/yajlpp/json_ptr.hh +++ b/src/yajlpp/json_ptr.hh @@ -75,11 +75,15 @@ public: case yajl_status_client_canceled: this->jpw_error_msg = "internal error"; break; - case yajl_status_error: - this->jpw_error_msg = std::string((const char *)yajl_get_error( - this->jpw_handle, 1, (const unsigned char *)buffer, len)); + case yajl_status_error: { + auto msg = yajl_get_error( + this->jpw_handle, 1, (const unsigned char *) buffer, len); + this->jpw_error_msg = std::string((const char *) msg); + + yajl_free_error(this->jpw_handle, msg); break; } + } }; void clear() { diff --git a/src/yajlpp/yajlpp.cc b/src/yajlpp/yajlpp.cc index 54c075ec..14a545ca 100644 --- a/src/yajlpp/yajlpp.cc +++ b/src/yajlpp/yajlpp.cc @@ -738,13 +738,15 @@ yajlpp_parse_context::parse(const unsigned char *jsonText, size_t jsonTextLen) this->ypc_json_text = nullptr; if (retval != yajl_status_ok && this->ypc_error_reporter) { + auto msg = yajl_get_error(this->ypc_handle, 1, jsonText, jsonTextLen); + this->ypc_error_reporter( *this, lnav_log_level_t::ERROR, fmt::format("error:{}:{}:invalid json -- {}", this->ypc_source, this->get_line_number(), - yajl_get_error(this->ypc_handle, 1, - jsonText, jsonTextLen)).c_str()); + msg).c_str()); + yajl_free_error(this->ypc_handle, msg); } return retval; @@ -755,12 +757,14 @@ yajl_status yajlpp_parse_context::complete_parse() yajl_status retval = yajl_complete_parse(this->ypc_handle); if (retval != yajl_status_ok && this->ypc_error_reporter) { + auto msg = yajl_get_error(this->ypc_handle, 0, nullptr, 0); + this->ypc_error_reporter( *this, lnav_log_level_t::ERROR, fmt::format("error:{}:invalid json -- {}", this->ypc_source, - yajl_get_error(this->ypc_handle, 0, - nullptr, 0)).c_str()); + msg).c_str()); + yajl_free_error(this->ypc_handle, msg); } return retval;