From efc22528768048643b3d641160313cb9529138de Mon Sep 17 00:00:00 2001 From: Piotr Kosko Date: Thu, 5 Nov 2020 12:20:21 +0100 Subject: [PATCH] [NBS] Add validation of instance to prevent crash [Bug] In case of destroying instance before the operation: * requestRouteToHost * releaseRouteToHost is finished, invalidated instance was used in code. [Reproduction] In my case it was execution of below code max 10 times: function crashApplicationWithNBS() { try { tizen.networkbearerselection.releaseRouteToHost( "CELLULAR", "www.onet.pl", addRouteAndReload, addRouteAndReload); } catch (e) { addRouteAndReload(); } } function addRouteAndReload() { var statuscb = { onsuccess: function () { console.log("onsuccess func is called"); }, ondisconnected: function () { console.log("ondisconnected func is called"); } }; function ecb(e) { console.log("error callback is called: " + e.message + ": " + e.code); } setTimeout(() => { try { tizen.networkbearerselection.requestRouteToHost( "CELLULAR", "www.onet.pl", statuscb, ecb) } catch (e) { console.log(e) } }, 500); setTimeout(() => { location.href = "index.html"; }, 490); } [Verification] * Crash does not occur. Crash situation is only signalled with log: DoAndPostMessage(264) > Trying to post message to non-existing instance: [0xb8cb1730], ignoring * Success and error callbacks are properly triggered Change-Id: I6adac13a8a99dbc114102bbd2ffced6bf012cfce --- src/common/extension.cc | 14 ++++++++ src/common/extension.h | 1 + .../networkbearerselection_instance.cc | 38 ++++++++++++---------- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/common/extension.cc b/src/common/extension.cc index 713e03e..6a0a2c3 100644 --- a/src/common/extension.cc +++ b/src/common/extension.cc @@ -238,6 +238,20 @@ Instance::~Instance() { Assert(xw_instance_ == 0); } +void Instance::DoAndPostMessage(Instance* that, const std::function& work, + const picojson::value& json) { + ScopeLogger(); + if (nullptr != that) { + std::lock_guard lock{instances_mutex_}; + if (all_instances_.end() != all_instances_.find(that)) { + work(); + that->PostMessage(json.serialize().c_str()); + return; + } + } + LoggerE("Trying to post message to non-existing instance: [%p], ignoring", that); +} + void Instance::PostMessage(Instance* that, const char* msg) { ScopeLogger(); if (nullptr != that) { diff --git a/src/common/extension.h b/src/common/extension.h index f9e0e68..f35c822 100644 --- a/src/common/extension.h +++ b/src/common/extension.h @@ -93,6 +93,7 @@ class Instance { Instance(); virtual ~Instance(); + static void DoAndPostMessage(Instance* that, const std::function& work, const picojson::value& json); static void PostMessage(Instance* that, const char* msg); static void PostMessage(Instance* that, const picojson::value& json); void PostMessage(const char* msg); diff --git a/src/networkbearerselection/networkbearerselection_instance.cc b/src/networkbearerselection/networkbearerselection_instance.cc index f4175fe..d7e1dd0 100644 --- a/src/networkbearerselection/networkbearerselection_instance.cc +++ b/src/networkbearerselection/networkbearerselection_instance.cc @@ -86,21 +86,22 @@ void NetworkBearerSelectionInstance::NetworkBearerSelectionRequestRouteToHost( auto request = [=]() -> void { auto response = [this, domain_name, id](const common::PlatformResult result) -> void { ScopeLogger(); - picojson::value value{picojson::object{}}; picojson::object& obj = value.get(); obj["id"] = picojson::value(static_cast(id)); obj["listenerId"] = picojson::value(kNBSCallback + std::to_string(id)); - if (result.IsSuccess()) { - ReportSuccess(obj); - this->addDomainListener(domain_name, id); - } else { - LogAndReportError(result, &obj); - } - - Instance::PostMessage(this, value.serialize().c_str()); + Instance::DoAndPostMessage(this, + [this, &domain_name, &id, &result, &obj]() -> void { + if (result.IsSuccess()) { + ReportSuccess(obj); + this->addDomainListener(domain_name, id); + } else { + LogAndReportError(result, &obj); + } + }, + value); }; NetworkBearerSelectionManager::GetInstance()->requestRouteToHost(domain_name, response); @@ -138,20 +139,21 @@ void NetworkBearerSelectionInstance::NetworkBearerSelectionReleaseRouteToHost( auto release = [=]() -> void { auto response = [this, domain_name, id](const common::PlatformResult result) -> void { ScopeLogger(); - picojson::value value{picojson::object{}}; picojson::object& obj = value.get(); obj["callbackId"] = picojson::value(id); - if (result.IsSuccess()) { - ReportSuccess(obj); - this->removeDomainListener(domain_name); - } else { - LogAndReportError(result, &obj); - } - - Instance::PostMessage(this, value.serialize().c_str()); + Instance::DoAndPostMessage(this, + [this, &domain_name, &result, &obj]() -> void { + if (result.IsSuccess()) { + ReportSuccess(obj); + this->removeDomainListener(domain_name); + } else { + LogAndReportError(result, &obj); + } + }, + value); }; NetworkBearerSelectionManager::GetInstance()->releaseRouteToHost(domain_name, response); -- 2.7.4