Large parts of the code in modules implementing wire protocols (mainly SSH) are structured using a set of macros that implement (something close to) Donald Knuth's ‘coroutines’ concept in C.
Essentially, the purpose of these macros are to arrange that a function can call crReturn()
to return to its caller, and the next time it is called control will resume from just after that crReturn
statement.
This means that any local (automatic) variables declared in such a function will be corrupted every time you call crReturn
. If you need a variable to persist for longer than that, you must make it a field in some appropriate structure containing the persistent state of the coroutine – typically the main state structure for a protocol layer.
See https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
for a more in-depth discussion of what these macros are for and how they work.
Another caveat: most of these coroutines are not guaranteed to run to completion, because the SSH connection (or whatever) that they're part of might be interrupted at any time by an unexpected network event or user action. So whenever a coroutine-managed variable refers to a resource that needs releasing, you should also ensure that the cleanup function for its containing state structure can reliably release it even if the coroutine is aborted at an arbitrary point.
For example, if an SSH packet protocol layer has to have a field that sometimes points to a piece of allocated memory, then you should ensure that when you free that memory you reset the pointer field to NULL
. Then, no matter when the protocol layer's cleanup function is called, it can reliably free the memory if there is any, and not crash if there isn't.