First of all, kudos for posting clear repro code. Now a couple of issues with your code:
Most importantly, the cb pointer you're receiving in set_callback (from the C# ref parameter) and storing in cbStruct isn't safe to store. There's no guarantee that the struct it's pointing to will stay around after set_callback returns. If you change your code so a copy of the struct is passed by value instead, I think your errors will go away.
All three Marshal.GetFunctionPointerForDelegate calls are passed the first delegate.
If you want to be really sure that the delegates remain valid, insert calls to GC.KeepAlive(cb.c_cb1) etc after the call to exec_callbacks.