Skip to content

Random crashes when using Console Writer and multiple goroutines #105

@tekert

Description

@tekert

They are very very random but they all pop at the same time, always the same error, same function involved, no code change between errors.
Using version 1.0.119

This is the crash: happenes just after printing a line that has emoticon.
log.Info().Str("address", config.Server.ListenAddress).Msg("🌐 Starting HTTP server")
Then.. CRASH

unexpected fault address 0xffffffffffffffff
fatal error: fault
[signal 0xc0000005 code=0x0 addr=0xffffffffffffffff pc=0x81e3e5]

goroutine 1 gp=0xc0000021c0 m=0 mp=0x1054320 [running]:
runtime.throw({0xc066a5?, 0xc00016fb00?})
        C:/Program Files/Go/src/runtime/panic.go:1101 +0x4d fp=0xc00016fac8 sp=0xc00016fa98 pc=0x715e4d
runtime.sigpanic()
        C:/Program Files/Go/src/runtime/signal_windows.go:414 +0xd0 fp=0xc00016fb10 sp=0xc00016fac8 pc=0x6f7c70
github.com/phuslu/log.parseFormatterArgs({0xc000302100, 0x70, 0x100}, 0xc00016fd30?)
        E:/Sources/go/sdk/Tekert/go/pkg/mod/github.com/phuslu/log@v1.0.119/formatter.go:115 +0x485 fp=0xc00016fbd8 sp=0xc00016fb10 pc=0x81e3e5
github.com/phuslu/log.(*ConsoleWriter).write(0xc0001ba5e0, {0xcce100, 0xc000070068}, {0xc000368000, 0x70, 0x400})
        E:/Sources/go/sdk/Tekert/go/pkg/mod/github.com/phuslu/log@v1.0.119/console.go:62 +0x19c fp=0xc00016fc80 sp=0xc00016fbd8 pc=0x81931c
github.com/phuslu/log.(*ConsoleWriter).WriteEntry(0xc0001c6348?, 0x27?)
        E:/Sources/go/sdk/Tekert/go/pkg/mod/github.com/phuslu/log@v1.0.119/console_windows.go:42 +0x7e fp=0xc00016fcc0 sp=0xc00016fc80 pc=0x81b1de

IA analisys:
Analysis
Consistent Crash Point: All three stack traces you've provided are identical in their cause. They all crash inside github.com/phuslu/log.parseFormatterArgs with a memory access violation (addr=0xffffffffffffffff). This function is called by log.(*ConsoleWriter).write.

The Root Cause is a Race Condition: This is a classic race condition related to resource pooling. The phuslu/log library uses a sync.Pool to reuse log.Entry objects for performance. Here's the sequence of events that leads to the crash:

Your application starts up, and multiple goroutines (main, http server, etw session) begin logging concurrently.
Goroutine A calls log.Info()...Msg("..."). It gets a log.Entry object from the pool and writes the log data into its internal buffer (e.buf).
The Msg() function calls the writer's WriteEntry method. In your case, this is main.(*safeWriter).WriteEntry.
Crucially, as soon as the WriteEntry call is made, the log.Entry object is put back into the sync.Pool for reuse (logger.go:1849).
Goroutine B, running concurrently, makes another log call. It gets the exact same log.Entry object that Goroutine A just returned to the pool.
Goroutine B immediately resets the buffer (e.buf = e.buf[:0]) to write its own log message.
Meanwhile, the ConsoleWriter from Goroutine A's call is still busy parsing the buffer in parseFormatterArgs. It suddenly finds that the memory it's reading has been wiped or overwritten, leading to the memory access violation and the crash.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions