Skip to content

purego: remove pooling of syscall#452

Open
TotallyGamerJet wants to merge 1 commit into
ebitengine:mainfrom
TotallyGamerJet:#451_memory_race
Open

purego: remove pooling of syscall#452
TotallyGamerJet wants to merge 1 commit into
ebitengine:mainfrom
TotallyGamerJet:#451_memory_race

Conversation

@TotallyGamerJet
Copy link
Copy Markdown
Collaborator

What issue is this addressing?

Closes #451

What type of issue is this addressing?

Bug

What this PR does | solves

This removes the pool which was occasionally causing issues. Unfortunately this does increase the memory cost of each call

Copy link
Copy Markdown
Member

@hajimehoshi hajimehoshi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

My understanding is, introducing a pool broke some invariations for nosplit functions: is that correct?

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes the shared sync.Pool used for *syscallArgs during FFI calls, addressing a concurrency regression where concurrent calls could observe corrupted/swapped return values (issue #451). The change trades reduced allocations for correctness by ensuring each call uses a distinct syscallArgs instance.

Changes:

  • Remove sync.Pool-backed reuse of *syscallArgs and allocate fresh syscallArgs per call path.
  • Update syscall dispatch implementations (syscall.go, syscall_32bit.go, syscall_ppc64le.go) to no longer Get/Put pooled structs.
  • Add a new concurrent malloc/free test intended to exercise the pointer-return path under contention.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
func.go Removes global sync.Pool and stops pooling *syscallArgs in RegisterFunc call paths.
syscall.go Stops pooling in SyscallN path by allocating a fresh syscallArgs.
syscall_32bit.go Same as above for 32-bit/arm builds.
syscall_ppc64le.go Same as above for ppc64le build path.
func_test.go Adds a new concurrency test invoking malloc/free across goroutines.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread func_test.go
}
}

func TestRegisterFunc_(t *testing.T) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh this point makes sense

Comment thread func_test.go
Comment on lines +49 to +66
var alloc func(uint64) *byte
var free func(*byte)
purego.RegisterLibFunc(&alloc, libc, "malloc")
purego.RegisterLibFunc(&free, libc, "free")

var wg sync.WaitGroup

for i := 0; i < runtime.NumCPU(); i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
for j := 0; j < 400_000; j++ {
ptr := alloc(5)
if ptr == nil {
continue
}
free(ptr)
}
Comment thread func_test.go
Comment on lines +54 to +60
var wg sync.WaitGroup

for i := 0; i < runtime.NumCPU(); i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
for j := 0; j < 400_000; j++ {
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.

func.go: Concurrent calls swap return-value pointers (sync.Pool of *syscall15Args, regressed in #282)

3 participants