When a finalizer function is set with runtime.SetFinalizer(), it is run in
a dedicated goroutine, after GC has finished its work.
It means that the finalizer function runs in parrallel with the main and
other threads of the program.
This little program illustrate this:

This means that the finalizer function must be goroutine-safe (access to
shared memory must be synchronized).

But finalizers are often used to release resources.

Let's have the following scenario:

We use cgo with C code to access a database.

We create a Connection object, which is just a proxy struct to a connection
object inside C world.
We also set a finalizer function to this Connection object, so that it
calls a Close() function on it if it goes out of scope.
This Close() function calls many times a "free()" function of a custom
memory allocator THAT IS NON-THREAD-SAFE.

Eventually, the Connection object goes out of scope, and GC schedules the
finalizer to run soon on its dedicated goroutine.

As GC finishes, the main goroutine resumes its work, creating and deleting
other database objects by calling proper C functions of the database API.
Suddenly, the finalizer runs.

The problem is that if the finalizer calls "free()" to our custom memory
allocator in the C world, and that the main goroutine is also calling a
"alloc()" or "free()" function on this allocator at the same time, it will
corrupt this memory allocator. Indeed, the allocator is not thread-safe by
design, because the author wanted to dedicate a fast allocator per each
connection object.
It was not expected, and even forbidden, that two threads access at the
same time this custom allocator.
But by setting a finalizer, it is what happens.

Presently, I am tracking a nasty bug that occurs very rarely, only once in
a hundred or thousand executions of the same program with same input.
This program runs only on one goroutine. When a crash occurs, it is always
a segfault, due to corruption of the custom memory allocator.
The stacktrace shows that it never occurs at the same place, indicating
that the cause must be asynchronous.
The corruption of the memory allocator can occur when two OS threads access
it at the same time.

I imagine that the finalizer is the cause of this bug.
And I have some questions:

1) when GOMAXPROCS is unset, or set to 1, we can have two OS threads
running in parrallel (main thread + finalizer thread) ?

2) the GC never interrupts a cgo call that is executing ? When there are
many threads, GC waits for the threads to come at a rendez-vous point
before running ?

3) if the resource allocator is not thread-safe, how use it in a finalizer ?

You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

Discussion Posts

Follow ups

Related Discussions

Discussion Navigation
viewthread | post
posts ‹ prev | 1 of 6 | next ›
Discussion Overview
groupgolang-nuts @
postedNov 8, '14 at 1:37a
activeNov 11, '14 at 4:09a



site design / logo © 2021 Grokbase