[macOS] Crash with Signal 6 on double-clicking layout files with non-ASCII paths (missing exception handling in GuiApplication::event)
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 72/100
Research direction
Start with src/lay/lay/layApplication.cc and compare the macOS QEvent::FileOpen handler with the protected calls in MainWindow::dropEvent and MainWindow::cm_open. Then inspect src/tl/tl/tlInternational.cc, including the Q_WS_MAC conditional. Done means Finder-launched files with non-ASCII paths no longer abort KLayout and failures show the existing error dialog; verify on macOS with Qt5/Qt6.
Written by the indexing model from the issue text.
Description
Summary
Double-clicking a layout file (.gds, .oas, etc.) in macOS Finder crashes KLayout with Signal number: 6 (SIGABRT) if the file path contains non-ASCII characters (such as CJK characters, e.g. the default Microsoft OneDrive directory OneDrive-个人).
When the same file is dragged into an already running KLayout instance, KLayout does not crash; instead, it safely shows an error dialog:
Unable to open file: ... (errno=2)
Environment
- KLayout Version: 0.30.12 (and earlier versions on Qt5/Qt6)
- OS: macOS (Apple Silicon / arm64)
Crash Backtrace
Signal number: 6
Address: 0x18af2c5e8
Program Version: KLayout 0.30.12
Backtrace:
libklayout_lay.0.dylib _ZN3lay25enable_signal_handler_guiEb
libsystem_platform.dylib _sigtramp
libsystem_pthread.dylib pthread_kill
libsystem_c.dylib abort
libc++abi.dylib _ZN10__cxxabiv116__shim_type_infoD1Ev
libc++abi.dylib _ZSt14set_unexpectedPFvvE
libobjc.A.dylib _ZL15_objc_terminatev
libc++abi.dylib _ZSt11__terminatePFvvE
libc++abi.dylib _ZN10__cxxabiv1L13is_class_typeEPKNS_16__shim_type_infoE
libklayout_lay.0.dylib _ZN3lay10MainWindow21create_or_load_layoutEPKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPKN2db17LoadLayoutOptionsERS8_i
libklayout_lay.0.dylib _ZN3lay14GuiApplication5eventEP6QEvent
QtWidgets _ZN19QApplicationPrivate13notify_helperEP7QObjectP6QEvent
QtWidgets _ZN12QApplication6notifyEP7QObjectP6QEvent
libklayout_lay.0.dylib _ZN3lay14GuiApplication9do_notifyEP7QObjectP6QEvent
QtCore _ZN16QCoreApplication15notifyInternal2EP7QObjectP6QEvent
QtGui _ZN22QGuiApplicationPrivate20processFileOpenEventEPN29QWindowSystemInterfacePrivate13FileOpenEventE
QtGui _ZN22QWindowSystemInterface19handleFileOpenEventERK7QString
libqcocoa.dylib qt_plugin_instance
AppKit -[NSApplication(NSAppleEventHandling) _openURLs:requestedBySourceApp:completionHandler:]
AppKit __69-[NSApplication(NSAppleEventHandling) _handleAEOpenDocumentsForURLs:]_block_invoke
AppKit __102-[NSApplication _reopenWindowsAsNecessaryIncludingRestorableState:withFullFidelity:completionHandler:]_block_invoke
AppKit -[NSApplication run]
...
Root Cause Analysis
There are two interrelated issues causing this bug:
1. Missing Exception Handling in GuiApplication::event for QEvent::FileOpen
In src/lay/lay/layApplication.cc:
bool
GuiApplication::event (QEvent *event)
{
#if defined(__APPLE__)
if (event->type() == QEvent::FileOpen) {
QFileOpenEvent *openEvent = static_cast<QFileOpenEvent *>(event);
if (mp_mw)
{
const std::string tech = mp_mw->initial_technology();
const std::string file = tl::to_string (openEvent->file());
const int mode = 1; // open in new window
mp_mw->load_layout (file, tech, mode);
mp_mw->add_mru (file, tech);
}
}
#endif
return QApplication::event(event);
}
In MainWindow::dropEvent and MainWindow::cm_open, calls to load_layout are protected with BEGIN_PROTECTED ... END_PROTECTED.
In GuiApplication::event, however, mp_mw->load_layout(...) is called without BEGIN_PROTECTED or try...catch.
When load_layout fails for any reason (e.g. non-existent path, permission error, corrupted file), create_or_load_layout re-throws tl::Exception. The uncaught C++ exception escapes the Qt Cocoa plugin boundary into AppKit's Objective-C runloop (_openURLs:requestedBySourceApp:completionHandler:), triggering _objc_terminatev -> std::terminate() -> abort() -> SIGABRT (Signal 6).
2. Locale and Encoding Fallback on macOS GUI Launch
Why does load_layout fail with errno=2 (ENOENT) in the first place when files reside in paths with non-ASCII characters?
In src/tl/tl/tlInternational.cc:
void initialize_codecs ()
{
// determine encoder for system strings
#ifdef _WIN32
ms_system_codec = 0;
#elif defined(Q_WS_MAC)
ms_system_codec = QTextCodec::codecForName ("UTF-8");
#else
setlocale (LC_ALL, "");
ms_system_codec = QTextCodec::codecForName (nl_langinfo (CODESET));
if (! ms_system_codec) {
ms_system_codec = QTextCodec::codecForName ("Latin-1");
}
#endif
Q_WS_MACis obsolete and was removed in Qt 5 (Qt 5+ usesQ_OS_MACorQ_OS_MACOS). Therefore, the#elif defined(Q_WS_MAC)branch is never compiled under Qt 5 / Qt 6.- On macOS, applications launched from Finder (via LaunchServices) do not inherit
LANGorLC_*environment variables from the user shell. - When
setlocale(LC_ALL, "")runs withoutLANG/LC_ALLset,nl_langinfo(CODESET)returnsUS-ASCII. - As a result,
ms_system_codecis set toUS-ASCII. When converting the path withstring_to_system(source)(ortl::to_local), any non-ASCII character (such as个人in~/Library/CloudStorage/OneDrive-个人/...) is replaced with?or stripped, causing POSIXopen()/gzopen()to fail witherrno=2(ENOENT). - (When run directly from Terminal where
LANG=...UTF-8is present,nl_langinfo(CODESET)is UTF-8, which is why the command-line launch does not trigger this error).
Suggested Fix
- In
src/lay/lay/layApplication.cc, wrap theFileOpenhandler inBEGIN_PROTECTED ... END_PROTECTED:
if (event->type() == QEvent::FileOpen) {
QFileOpenEvent *openEvent = static_cast<QFileOpenEvent *>(event);
if (mp_mw)
{
BEGIN_PROTECTED
const std::string tech = mp_mw->initial_technology();
const std::string file = tl::to_string (openEvent->file());
const int mode = 1; // open in new window
mp_mw->load_layout (file, tech, mode);
mp_mw->add_mru (file, tech);
END_PROTECTED
}
}
- In
src/tl/tl/tlInternational.cc, updateQ_WS_MACtoQ_OS_MAC:
#ifdef _WIN32
ms_system_codec = 0;
#elif defined(Q_OS_MAC)
ms_system_codec = QTextCodec::codecForName ("UTF-8");
#else
setlocale (LC_ALL, "");
ms_system_codec = QTextCodec::codecForName (nl_langinfo (CODESET));
if (! ms_system_codec) {
ms_system_codec = QTextCodec::codecForName ("Latin-1");
}
#endif
- Dominant language
- C++
- Stars
- 1.2k
- Forks
- 305
- Avg merge
- 3d 2h
- Merged PRs (30d)
- 11
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from KLayout/klayout
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
KLayout/klayout#2554 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
KLayout/klayout#2412 · 3 comments ·
Maintainers usually reply within 1 day
-
DRC functions not working properly with clip in placePossibly taken @klayoutmatthias claimed this today. Openbug
KLayout/klayout#2553 · 1 assignee ·
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 50/100
Maintainers usually reply within 1 day
-
Deep DRC can miss violations when a cell has many shapesMay be free again A pull request for this issue was closed without being merged. Open
Difficulty 4/5 3-5 days Newbie friendliness 52/100
KLayout/klayout#2546 · 5 comments ·
Maintainers usually reply within 1 day
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 3 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
LaneDibello/Kotor-Patch-Manager#375 ·
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
Maintainers usually reply within 1 day