Skip to content

feat: TypeArchive type-add/update/rename/delete notifications#39

Merged
tinysec merged 1 commit into
masterfrom
feat/type-archive-notifications
Jul 8, 2026
Merged

feat: TypeArchive type-add/update/rename/delete notifications#39
tinysec merged 1 commit into
masterfrom
feat/type-archive-notifications

Conversation

@tinysec

@tinysec tinysec commented Jul 8, 2026

Copy link
Copy Markdown
Owner

What

Mirrors Python TypeArchiveNotification (typearchive.py:732) — the last big callback surface the C# binding lacked (parity audit gap #17).

  • TypeArchiveNotificationabstract class with four virtual methods (empty default bodies, override selectively): OnTypeAdded, OnTypeUpdated, OnTypeRenamed, OnTypeDeleted.
  • TypeArchive.RegisterNotification / UnregisterNotification over the existing BNRegister/BNUnregisterTypeArchiveNotification P/Invokes.

Delegate lifetime (the hard part)

A TypeArchiveNotificationContext roots the four native wrapper delegates and the allocated BNTypeArchiveNotification struct for the registration lifetime — the same delegate-rooting pattern as Activity / AnalysisCompletionEvent. The core holds bare function pointers; without rooting, the GC could reclaim the delegates (and their pointers) while core still holds the registration.

Each callback marshals its native args and forwards to the user override:

  • archive → TypeArchive.BorrowHandle
  • id → Marshal.PtrToStringAnsi (non-freeing; core owns)
  • type → Type.NewFromHandle (owned ref, mirrors Python)
  • names → Marshal.PtrToStructure<BNQualifiedName> + QualifiedName.FromNative (archive owns storage, read without free)

A throwing override is swallowed (Python logs and continues) so a user callback cannot abort core dispatch. The context is kept in the archives registration map; UnregisterNotification frees the struct + GCHandle and is idempotent.

E2E (local harness, not in this repo)

sharp-binaryninja-tests: TypeArchiveNotificationTests.AddRenameDeleteFireMatchingCallbacks — recording subclass; AddTypeOnTypeAdded, RenameTypeOnTypeRenamed (asserts id + old/new names), DeleteTypeOnTypeDeleted (asserts id), then idempotent unregister.

Depends on #38 (AddType convenience) — already merged to master.

Verified

  • dotnet build -c Release — 0 warnings, 0 errors.
  • Full harness regression — 66 passed, 0 failed.

Mirrors Python TypeArchiveNotification (typearchive.py:732) with four virtual
methods (OnTypeAdded/OnTypeUpdated/OnTypeRenamed/OnTypeDeleted) plus
TypeArchive.RegisterNotification/UnregisterNotification over the existing
BNRegister/BNUnregisterTypeArchiveNotification P/Invokes.

A TypeArchiveNotificationContext roots the four native wrapper delegates and the
allocated BNTypeArchiveNotification struct for the registration lifetime (mirrors
the Activity/AnalysisCompletionEvent delegate-rooting pattern), marshals each
callback's native args (archive via BorrowHandle, id via PtrToStringAnsi, type via
NewFromHandle, names via PtrToStructure<BNQualifiedName>+FromNative), and swallows
exceptions so a throwing override cannot abort core dispatch.
@tinysec tinysec merged commit 4d3d121 into master Jul 8, 2026
1 check passed
@tinysec tinysec deleted the feat/type-archive-notifications branch July 8, 2026 17:43
tinysec added a commit that referenced this pull request Jul 9, 2026
…DataNotification (#40)

Closes parity gap #0. Mirrors Python BinaryDataNotification (binaryview.py:247)
and the C BNBinaryDataNotification struct (55 callback slots), using the same
delegate-rooting pattern as PR #39 (TypeArchive notifications):

- Struct/BNBinaryDataNotification.cs: flesh out the empty stub into an abstract
  BinaryDataNotification base with 55 virtual methods (On*), each citing its
  Python source line. The six OnExternalLibrary*/OnExternalLocation* events have
  no Python equivalent and expose the struct slots directly.
- Delegate/BinaryDataNotificationCallbacks.cs: 9 delegate types (shared by
  signature shape) + BinaryDataNotificationContext that roots 55 wrapper
  delegates, marshals each native callback into managed objects, and builds/frees
  the BNBinaryDataNotification struct. Borrowed handles are add-ref'd via the
  existing NewFromHandle factories; borrowed struct pointers (BNDataVariable*,
  BNTagReference*, BNDerivedString*) are read via PtrToStructure. Throwing
  overrides are swallowed (Python logs and continues).
- Handle/BNBinaryView.cs: RegisterDataNotification/UnregisterDataNotification
  + per-view context map, replacing the two generator-emitted TODOs.

Python's NotificationType opt-in filtering is not reproduced: all 55 slots are
always wired (matching the TypeArchive approach). The notification_barrier slot
is wired but driven by the core's notification loop, so it is not delivered in a
static headless database.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant