That could work, too, but could place limits on the type/amount of string error message returned and the lifetime of the struct. Most implementations just use the heap so there are no gotchas with what kind of message you can return back and when you can access it.
Interesting. You could also use a static segment error buffer pool. Presumably error rates are low enough that contention on a lock would not be a problem. And during signals, there are no other threads running anyway, I think, so you could skip the lock.