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

オープン
#2,442 コメント 5 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
72/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
cpp, macos
領域
desktop

調査の方向性

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.

索引モデルが issue の本文から書いたものです。

説明

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
主要言語
C++
スター
1.2k
フォーク
305
平均マージ
3日 2時間
マージ済み PR(30日)
11

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

KLayout/klayout のほかの issue

KLayout/klayout の issue をすべて見る

似ている issue

C++ の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。