Files
sdk/runtime/vm/native_message_handler.cc
Alexander Aprelev 5a98fe5564 [vm/isolates] Avoid leaving isolate as part of native message handling.
Letting isolate go seems to be problematic. If this native messaging api is used during runtime call, then original isolate might end up on a different worker os thread causing remembered frame pointer(remembered as part of entering runtime call) to become invalid due to different stack bounds of this new thread. Invalid frame pointer causes immediate assertion failures during stack walk done for GC purposes or for exception handling.

TEST=ci, https://dart-review.git.corp.google.com/c/sdk/+/486522/comments/ee54d99f_a5c2a9d4

Change-Id: If69076bb9e107502dfef819de73829d9682bb134
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/501220
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Alexander Aprelev <aam@google.com>
2026-05-06 14:42:04 -07:00

106 lines
2.8 KiB
C++

// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/native_message_handler.h"
#include <memory>
#include <utility>
#include "vm/dart_api_message.h"
#include "vm/isolate.h"
#include "vm/message.h"
#include "vm/message_snapshot.h"
#include "vm/snapshot.h"
namespace dart {
Monitor* NativeMessageHandler::monitor_ = nullptr;
intptr_t NativeMessageHandler::pending_deletions_ = 0;
NativeMessageHandler::NativeMessageHandler(const char* name,
Dart_NativeMessageHandler func,
intptr_t max_concurrency)
: name_(Utils::StrDup(name)), func_(func), pool_(max_concurrency) {}
NativeMessageHandler::~NativeMessageHandler() {}
namespace {
class HandleMessage : public ThreadPool::Task {
public:
HandleMessage(Dart_NativeMessageHandler handler,
std::unique_ptr<Message> message)
: handler_(handler), message_(std::move(message)) {
ASSERT(handler != nullptr);
}
virtual void Run() {
ApiNativeScope scope;
Dart_CObject* object = ReadApiMessage(scope.zone(), message_.get());
handler_(message_->dest_port(), object);
}
private:
Dart_NativeMessageHandler handler_;
std::unique_ptr<Message> message_;
DISALLOW_COPY_AND_ASSIGN(HandleMessage);
};
} // namespace
void NativeMessageHandler::PostMessage(std::unique_ptr<Message> message,
bool before_events /* = false */) {
if (message->IsOOB()) {
UNREACHABLE();
}
pool_.Run<HandleMessage>(func_, std::move(message));
}
void NativeMessageHandler::RequestDeletion(NativeMessageHandler* handler) {
{
MonitorLocker ml(monitor_);
pending_deletions_++;
}
ThreadPool::RequestShutdown(&handler->pool_, [handler]() {
delete handler;
// Once the handler and its pool is gone make sure to wake up
// |NativeMessageHandler::Cleanup| which might be waiting.
{
MonitorLocker ml(monitor_);
pending_deletions_--;
if (pending_deletions_ == 0) {
ml.Notify();
}
}
});
}
void NativeMessageHandler::Shutdown() {
pool_.Shutdown();
}
void NativeMessageHandler::Init() {
monitor_ = new Monitor();
}
void NativeMessageHandler::Cleanup() {
{
MonitorLocker ml(monitor_);
// By the time we get here we don't really expect new deletions to be
// requested. We proceed with VM shutdown once we have no pending deletions.
// In other words words don't try to guard against a race between
// |Dart_CloseNativePort| and |Dart_Cleanup| - that's considered an API
// misuse.
while (pending_deletions_ > 0) {
ml.Wait();
}
}
delete monitor_;
monitor_ = nullptr;
}
} // namespace dart