Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Defining user symbols from more than one thread at the same time, with no undo transaction open, crashes the core

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

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

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

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
48/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
cpp, python

調査の方向性

Reproduce the crash with concurrent_user_symbols.py against /bin/ls, then start at the BNDefineUserSymbol entry point and the undo path used by define_user_symbol when no transaction is open. Compare the failing headless case with begin_undo_actions() and define_auto_symbol; done means concurrent user-symbol operations no longer crash or corrupt memory, with the behavior covered by an appropriate regression test.

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

説明

The following issue was identified, triaged and written by Claude Fable 5.1, I have read through it to make sure the information is coherent and useful.


Version and Platform (required):

  • Binary Ninja Version: 6.1.10594-dev
  • Edition: Ultimate
  • OS: macOS
  • OS Version: 26.5.1
  • CPU Architecture: Apple Silicon (arm64)

Bug Description:
Defining user symbols from more than one thread at the same time, with no undo transaction open, crashes the core. With four Python threads each redefining the user symbol at every function start of /bin/ls, the headless process dies on most runs, either with a segmentation fault or with libmalloc aborting on a bad free: ___BUG_IN_CLIENT_OF_LIBMALLOC_POINTER_BEING_FREED_WAS_NOT_ALLOCATED, thirteen frames below BNDefineUserSymbol.

The same loop on one thread never crashes. The same loop with define_auto_symbol in place of define_user_symbol never crashes with eight threads. And the same loop headless with the whole run inside one begin_undo_actions() / commit_undo_actions() pair never crashes either, while the GUI Python console, which runs each command inside a transaction, survived 17 runs. So the fault looks to be in the undo entry that each user-symbol call opens and commits for itself when no transaction is open. The threads do not need to touch the same addresses: giving each thread its own disjoint set of function starts still crashes 2 of 5 runs.

Steps To Reproduce:

  1. Save the script below as concurrent_user_symbols.py.
  2. Run it headless with any Mach-O: python3 concurrent_user_symbols.py /bin/ls
  3. It dies within a second or two. If a run happens to survive, run it again; here it crashed 5 of 5 runs with four threads.
"""Redefining user symbols from several threads at once crashes the core.

Run with any Mach-O, e.g.:  python3 concurrent_user_symbols.py /bin/ls

Each thread walks every function start, undefines whatever symbol is there and defines a user
symbol with a fresh name, four times over. Four threads crash the process on most runs; the same
loop on one thread never does, and neither does the same loop with define_auto_symbol in place of
define_user_symbol.
"""
import sys
import threading

import binaryninja as bn

bv = bn.load(sys.argv[1])
bv.update_analysis_and_wait()
starts = [f.start for f in bv.functions]


def redefine(tag):
    for round in range(4):
        for start in starts:
            existing = bv.get_symbol_at(start)
            if existing is not None:
                if existing.auto:
                    bv.undefine_auto_symbol(existing)
                else:
                    bv.undefine_user_symbol(existing)
            bv.define_user_symbol(bn.Symbol(bn.SymbolType.FunctionSymbol, start, f"{tag}_{round}_{start:x}"))


threads = [threading.Thread(target=redefine, args=(f"t{i}",)) for i in range(4)]
for t in threads:
    t.start()
for t in threads:
    t.join()
print("no crash this run; run it again")

Crash frequency over five runs per configuration, headless, all with BN_DISABLE_USER_PLUGINS=1:

Threads Operation per address Undo transaction Crashes
4 undefine existing, then define_user_symbol none 5 / 5
4 define_user_symbol only none 2 / 5
4 undefine, then define_user_symbol, each thread on disjoint addresses none 2 / 5
4 undefine, then define_user_symbol one, opened before the threads start and committed after they join 0 / 5
4 undefine, then define_user_symbol one per thread 2 / 5
2 undefine, then define_user_symbol none 0 / 5
1, with update_analysis() running alongside undefine, then define_user_symbol none 0 / 5
8 define_auto_symbol only none 0 / 5

Expected Behavior:
Either the calls are safe to make from several threads, as the rest of the BinaryView API is, or the documentation says user-symbol definition must be serialised by the caller, or made inside an undo transaction. Silent memory corruption is neither.

Screenshots/Video Recording:
Not applicable; the crashing thread from the macOS crash report of one run (SIGABRT variant):

exception: EXC_CRASH SIGABRT
  0 libsystem_kernel.dylib             __pthread_kill + 8
  1 libsystem_pthread.dylib            pthread_kill + 296
  2 libsystem_c.dylib                  abort + 148
  3 libsystem_malloc.dylib             malloc_vreport + 892
  4 libsystem_malloc.dylib             malloc_report + 64
  5 libsystem_malloc.dylib             ___BUG_IN_CLIENT_OF_LIBMALLOC_POINTER_BEING_FREED_WAS_NOT_ALLOCATED + 76
  6 libbinaryninjacore.1.dylib         +0xe15010
  7 libbinaryninjacore.1.dylib         +0xe12810
  8 libbinaryninjacore.1.dylib         +0xe123a4
  9 libbinaryninjacore.1.dylib         +0x5a2c08
 10 libbinaryninjacore.1.dylib         +0x95b7a4
 11 libbinaryninjacore.1.dylib         +0x58ef30
 12 libbinaryninjacore.1.dylib         +0x28d45c
 13 libbinaryninjacore.1.dylib         BNDefineUserSymbol + 60
 14 libffi.dylib                       ffi_call_SYSV + 80
 15 libffi.dylib                       ffi_call_int + 1220
 16 _ctypes.cpython-313-darwin.so      _ctypes_callproc + 732
 17 _ctypes.cpython-313-darwin.so      PyCFuncPtr_call + 264
 18 Python                             _PyObject_MakeTpCall + 120
 19 Python                             _PyEval_EvalFrameDefault + 19532
 20 Python                             method_vectorcall + 152
 21 Python                             thread_run + 180

Other runs die with EXC_BAD_ACCESS / SIGSEGV in the same region of the core (frames +0xe15010 and +0xe123a4 recur). The full .ips files can be attached on request.

Binary:
Not binary-specific: /bin/ls from macOS 26.5.1 was used, and any Mach-O with a few dozen functions reproduces it.

Additional Information:
The GUI Python console does not reproduce this: the same loop pasted there survived 17 runs (16 with four threads, one with eight). Headless, it also stops reproducing when the whole run is wrapped in a single bv.begin_undo_actions() / bv.commit_undo_actions() pair (0 of 5), while one transaction per thread still crashes (2 of 5). So the fault appears to be in the undo entry each user-symbol call creates and commits for itself when no transaction is open, which is the situation in every headless script and never in the console. Python 3.13 headless with the API module from the application bundle and no user plugins loaded. The undefine-then-define pair is the shape that crashes most reliably, but define_user_symbol alone from four threads is enough.

主要言語
C++
スター
1.3k
フォーク
297
平均マージ
3日 11時間
マージ済み PR(30日)
17

環境構築

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

はじめの一歩

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

Vector35/binaryninja-api のほかの issue

Vector35/binaryninja-api の issue をすべて見る

似ている issue

C++ の issue をもっと見る

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

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