Skip to content

fix: avoid nil dereferences in plugin hooks - #4226

Open
dlh wants to merge 2 commits into
micro-editor:masterfrom
dlh:fix/plugin-hooks-before-init
Open

dlh wants to merge 2 commits into
micro-editor:masterfrom
dlh:fix/plugin-hooks-before-init

Conversation

@dlh

@dlh dlh commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Plugin hooks can run before the editor's global state exists:

  • onBufPaneOpen fires for the infobar's own pane, which InitGlobals() builds before LogBuf and Tabs are assigned.
  • onBufferOpen fires for the user's files, which load before InitTabs().

A handler that calls an action then hits a nil dereference in Go (e.g. buffer.Log()WriteLog, or micro.CurPane()MainTab()), and startup stops on "Press enter to continue".

Two commits:

  • b706262b: main() and the test helper share one initEditor().
  • b7a3882d: nil guards in MainTab(), micro.CurPane(), WriteLog(), SetGlobalOption(), and Tabs.Resize() for layout options set before InitTabs(); the plugin docs now say which API calls return nil during startup.

Example

~/.config/micro/plug/crashdemo/crashdemo.lua:

local buffer = import("micro/buffer")

-- At startup this also fires for the infobar's pane, before the log buffer exists.
function onBufPaneOpen(bp)
    buffer.Log("opened " .. bp.Buf.Path .. "\n")
end

Run micro README.md.

Before fix

Plugin crashdemo: runtime error: invalid memory address or nil pointer dereference
stack traceback:
	[G]: in function 'Log'
	crashdemo:5: in main chunk
	[G]: ?

Press enter to continue

After fix

micro starts normally. The infobar's call is dropped, since the log buffer does not exist yet; the call for README.md reaches the log.

dlh added 2 commits September 14, 2026 09:06
The test helper had drifted from main(): it skipped preinit and ran
InitGlobals() after InitTabs(), so a test built on it saw a different
startup state than plugins do.

Extract the shared span into initEditor(), with an onErr callback.
Plugin hooks can run before the editor's global state exists:

* onBufPaneOpen fires for the infobar's own pane, which InitGlobals()
  builds before LogBuf and Tabs are assigned
* onBufferOpen fires for the user's files, which load before InitTabs()

A handler that calls an action then hits a nil dereference in Go (e.g.
buffer.Log() -> WriteLog, or micro.CurPane() -> MainTab()), and startup
stops on "Press enter to continue".

MainTab(), micro.CurPane(), WriteLog(), and SetGlobalOption() no longer
assume a tab, pane, or log buffer exists.
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