macOS (arm64) 上での TigerVNC vncviewer クラッシュ — 原因と対処
概要
brewでインストールしたtigervnc-viewerが、動かなくなった。具体的には、vnc画面が出た後、それをマウスクリックするとクラッシュする。
githubのソースから、一部修正してビルドすることで解決できた。
vncviewerが依存しているFLTKが、なんかnull返すらしくて落ちるらしい。
全部 github copilotさんがやってくれたので、以下のcopilotさんの解説を見て下さい。
欲しい人が居たら、どこかにバイナリをアップするのでコメントかメッセージ下さい。
問題
FLTK の Cocoa 側実装が macOS の入力ソース取得 API (TISCreateInputSourceList) から NULL を返されたケースを想定しておらず、そのまま CFRelease を呼んでしまうためにクラッシュが発生します。結果として、vncviewer で画面が表示されても、ウィンドウ上でクリックや入力を行ったタイミングで内部のリソース解放処理が走り、*** CFRelease() called with NULL *** のようなクラッシュレポートが出力されアプリが終了します。
解決方法
1) FLTK 側の最小パッチ
- 変更ファイル:
deps/fltk-release-1.4.4/src/Fl_cocoa.mm - 変更方針:
TISCreateInputSourceList(...)の戻りが NULL の場合、TSMSetDocumentPropertyやCFRelease(inputSources)を呼ばないようにガードする。
概念的な差分:
- inputSources = TISCreateInputSourceList(...);
- // そのまま利用して CFRelease(inputSources)
+ inputSources = TISCreateInputSourceList(...);
+ if (inputSources) {
+ // inputSources を安全に利用
+ TSMSetDocumentProperty(..., inputSources);
+ CFRelease(inputSources);
+ }
- 目的:
CFRelease(NULL)を呼ばないことで macOS 上の即時トラップ(SIGTRAP)を回避する。
2) FLTK のビルドとインストール
- パッチを当てた FLTK をローカル prefix にビルド・インストールする。shared/dylib 版で検証してから、必要であれば static 版も作る。
3) TigerVNC 側の CMake 修正(static 組み込み時の対策)
- 問題: static な FLTK をリンクしたときに、FLTK の Cocoa 実装が参照する macOS 固有クラス(
SCContentFilter等)に由来する未解決シンボルが発生する。 - 対策:
vncviewerの CMake に弱リンク(-weak_framework)を追加してアプリ側でフレームワークを解決させる。
変更例(vncviewer/CMakeLists.txt の該当箇所):
target_link_libraries(vncviewer "-framework Cocoa")
target_link_libraries(vncviewer "-framework Carbon")
target_link_libraries(vncviewer "-framework IOKit")
+ // FLTK 1.4+ が使用するフレームワーク(弱リンク)
+ target_link_libraries(vncviewer "-weak_framework ScreenCaptureKit")
+ target_link_libraries(vncviewer "-weak_framework UniformTypeIdentifiers")
- これにより、static 組み込み時に linker error(未解決の
_OBJC_CLASS_$_SCContentFilter等)が解消される。
ビルド手順
以下はワークツリールートでの手順例です。
1) FLTK (パッチ適用済み) を shared としてビルド/インストール
cmake -S deps/fltk-release-1.4.4 -B deps/fltk-build-shared \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=$PWD/deps/fltk-install-shared \
-DFLTK_BUILD_SHARED_LIBS=ON \
-DFLTK_BUILD_TEST=OFF -DFLTK_BUILD_EXAMPLES=OFF
cmake --build deps/fltk-build-shared --target install -j
2) TigerVNC を shared-FLTK を使ってビルド
cmake -S . -B build-arm64-fltkpatched-shared \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH=$PWD/deps/fltk-install-shared
cmake --build build-arm64-fltkpatched-shared --target vncviewer -j
3a) shared FLTK を使って実行(DYLD_LIBRARY_PATH が必要)
DYLD_LIBRARY_PATH=$PWD/deps/fltk-install-shared/lib:$DYLD_LIBRARY_PATH \
./build-arm64-fltkpatched-shared/vncviewer/vncviewer :6
3b) static 組み込みでビルド(vncviewer/CMakeLists.txt を上記のように修正済み)
# FLTK を static でインストールしてあることを前提
cmake -S . -B build-arm64-fltkpatched-static \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH=$PWD/deps/fltk-install
cmake --build build-arm64-fltkpatched-static --target vncviewer -j
# 実行(DYLD_LIBRARY_PATH 不要)
./build-arm64-fltkpatched-static/vncviewer/vncviewer :6
補足・注意点
- 起動時の
Failed to determine locale directoryは翻訳ファイル探索の警告で、機能には致命的ではありません。po/localeの配置を整えれば消えます。 - FLTK の CMake は既に SDK を検出して
-weak_framework ScreenCaptureKitを扱うロジックを持っていますが、static 組み込み時はアプリ側に弱リンクを追加するのが実用的な対策です。 - 完全に OS のフレームワークまで全て静的に固める(完全静的化)は現実的でないため、今回の対処は実用的妥協になります。
参考(今回の作業で行ったファイル変更)
-
deps/fltk-release-1.4.4/src/Fl_cocoa.mm—TISCreateInputSourceListの戻り値 NULL ガードの追加(パッチ) -
vncviewer/CMakeLists.txt—-weak_framework ScreenCaptureKit/-weak_framework UniformTypeIdentifiersの追加(static 組み込み時のリンク対策)