From ef6f3f182a54dea97f69bb2c7e8e3b8291c08813 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 4 Jan 2023 21:17:12 +0100 Subject: [PATCH] Fixed issue #1242 (KLayout 0.28.2 crashes when registering a plugin if a layout exists) Problem was twofold: first, events are triggered during construction of the plugin which met an uninitialized pointer. Second, the clearing of existing plugins failed because of iterating a vector while destroying it's members erased member of it. --- src/laybasic/laybasic/layLayoutViewBase.cc | 5 ++-- src/layview/layview/layLayoutView_qt.cc | 16 ++++++++--- testdata/ruby/layLayoutView.rb | 33 ++++++++++++++++++++++ 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc index e27ee26b1..5bd487cbf 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.cc +++ b/src/laybasic/laybasic/layLayoutViewBase.cc @@ -578,10 +578,11 @@ void LayoutViewBase::drop_url (const std::string &path_or_url) void LayoutViewBase::clear_plugins () { - for (std::vector::iterator p = mp_plugins.begin (); p != mp_plugins.end (); ++p) { + std::vector plugins; + mp_plugins.swap (plugins); + for (std::vector::iterator p = plugins.begin (); p != plugins.end (); ++p) { delete *p; } - mp_plugins.clear (); mp_active_plugin = 0; } diff --git a/src/layview/layview/layLayoutView_qt.cc b/src/layview/layview/layLayoutView_qt.cc index 495c9beab..90f7b6ea4 100644 --- a/src/layview/layview/layLayoutView_qt.cc +++ b/src/layview/layview/layLayoutView_qt.cc @@ -98,15 +98,23 @@ namespace lay // LayoutViewWidget implementation LayoutViewWidget::LayoutViewWidget (db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, QWidget *parent, unsigned int options) - : QFrame (parent) + : QFrame (parent), mp_view (0) { - mp_view = new LayoutView (mgr, editable, plugin_parent, this, options); + // NOTE: construction the LayoutView may trigger events (script code executed etc.) which must + // not meet an invalid mp_view pointer (e.g. in eventFilter). Hence, mp_view is 0 first, and set only + // after the LayoutView is successfully constructed. + std::unique_ptr view (new LayoutView (mgr, editable, plugin_parent, this, options)); + mp_view = view.release (); } LayoutViewWidget::LayoutViewWidget (lay::LayoutView *source, db::Manager *mgr, bool editable, lay::Plugin *plugin_parent, QWidget *parent, unsigned int options) - : QFrame (parent) + : QFrame (parent), mp_view (0) { - mp_view = new LayoutView (source, mgr, editable, plugin_parent, this, options); + // NOTE: construction the LayoutView may trigger events (script code executed etc.) which must + // not meet an invalid mp_view pointer (e.g. in eventFilter). Hence, mp_view is 0 first, and set only + // after the LayoutView is successfully constructed. + std::unique_ptr view (new LayoutView (source, mgr, editable, plugin_parent, this, options)); + mp_view = view.release (); } LayoutViewWidget::~LayoutViewWidget () diff --git a/testdata/ruby/layLayoutView.rb b/testdata/ruby/layLayoutView.rb index 6aeccd326..c22c891d8 100644 --- a/testdata/ruby/layLayoutView.rb +++ b/testdata/ruby/layLayoutView.rb @@ -498,6 +498,39 @@ class LAYLayoutView_TestClass < TestBase end + class DummyPlugin < RBA::Plugin + def initialize(manager, view) + self.manager = manager + self.view = view + end + end + + class DummyPluginFactory < RBA::PluginFactory + def initialize() + register(1000, "dummy_plugin", "Dummy Plugin") + end + def create_plugin(manager, unused, view) + DummyPlugin::new(manager, view) + end + end + + # issue-1242 + def test_6 + + # Create a new layout + main_window = RBA::MainWindow.instance() + main_window.close_all + main_window.create_layout(2) + + # Register plugin -> crashes in issue-1242 + dpi = DummyPluginFactory::new + + main_window.close_all + + dpi._destroy + + end + end load("test_epilogue.rb")