[macOS] Crash with Signal 6 on double-clicking layout files with non-ASCII paths (missing exception handling in GuiApplication::event)

Aperta
#2,442 5 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
72/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
cpp, macos
Ambito
desktop

Direzione di ricerca

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.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

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_MAC is obsolete and was removed in Qt 5 (Qt 5+ uses Q_OS_MAC or Q_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 LANG or LC_* environment variables from the user shell.
  • When setlocale(LC_ALL, "") runs without LANG/LC_ALL set, nl_langinfo(CODESET) returns US-ASCII.
  • As a result, ms_system_codec is set to US-ASCII. When converting the path with string_to_system(source) (or tl::to_local), any non-ASCII character (such as 个人 in ~/Library/CloudStorage/OneDrive-个人/...) is replaced with ? or stripped, causing POSIX open() / gzopen() to fail with errno=2 (ENOENT).
  • (When run directly from Terminal where LANG=...UTF-8 is present, nl_langinfo(CODESET) is UTF-8, which is why the command-line launch does not trigger this error).
Suggested Fix
  1. In src/lay/lay/layApplication.cc, wrap the FileOpen handler in BEGIN_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
      }
  }
  1. In src/tl/tl/tlInternational.cc, update Q_WS_MAC to Q_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
Lingua principale
C++
Stelle
1.2k
Fork
305
Merge medio
3g 2h
PR unite (30g)
11

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di KLayout/klayout

Tutte le issue di KLayout/klayout

Issue simili

Altre issue su C++

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.