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