mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 09:27:59 +00:00
Tweak crWaitUntil macros for greater robustness.
I've rewritten these macros so that they don't keep rewriting the same value into the crLine variable. They now write it just once, before ever testing the condition. The point isn't the extra efficiency (which is surely negligible); it's to make it safe to abort a coroutine and free its entire state at unexpected moments. If you use one of these macros with a condition that has side effects, say crWaitUntil(func()), and one of the side effects can be to free the entire object that holds the coroutine state, then the write to crLine after testing the condition would previously have caused a stale-pointer dereference. But now that only happened once, _before_ the condition was first evaluated; so as long as func() returns false in the event that it frees the coroutine state, it's safe - crWaitUntil will see the false condition and return without touching the state object, and then it'll never be called again because the whole object will have gone away.
This commit is contained in:
parent
06b721ca03
commit
60d95b6a62
39
sshcr.h
39
sshcr.h
@ -46,9 +46,40 @@
|
||||
} while (0)
|
||||
#define crStop(z) do{ *crLine = 0; return (z); }while(0)
|
||||
#define crStopV do{ *crLine = 0; return; }while(0)
|
||||
#define crWaitUntil(c) do { crReturn(0); } while (!(c))
|
||||
#define crWaitUntilV(c) do { crReturnV; } while (!(c))
|
||||
#define crMaybeWaitUntil(c) do { while (!(c)) crReturn(0); } while (0)
|
||||
#define crMaybeWaitUntilV(c) do { while (!(c)) crReturnV; } while (0)
|
||||
|
||||
/*
|
||||
* The crMaybeWaitUntil macros could have been more easily written in
|
||||
* terms of the simple crReturn above, by writing things like
|
||||
*
|
||||
* while (!condition) { crReturn(whatever); }
|
||||
*
|
||||
* (or do-while in the case of crWaitUntil). But it's better to do it
|
||||
* directly by writing _once_ to crLine before first testing the
|
||||
* condition, because this way it's robust against the condition check
|
||||
* potentially freeing the entire coroutine state structure as a side
|
||||
* effect (as long as it also evaluates false if it does that),
|
||||
* because we don't write into crLine between the condition evaluating
|
||||
* to false and the 'return' statement.
|
||||
*/
|
||||
#define crMaybeWaitUntil(c) \
|
||||
do { \
|
||||
*crLine =__LINE__; \
|
||||
case __LINE__: if (!(c)) return 0; \
|
||||
} while (0)
|
||||
#define crMaybeWaitUntilV(c) \
|
||||
do { \
|
||||
*crLine =__LINE__; \
|
||||
case __LINE__: if (!(c)) return; \
|
||||
} while (0)
|
||||
#define crWaitUntil(c) \
|
||||
do { \
|
||||
*crLine =__LINE__; return; \
|
||||
case __LINE__: if (!(c)) return 0; \
|
||||
} while (0)
|
||||
#define crWaitUntilV(c) \
|
||||
do { \
|
||||
*crLine =__LINE__; return; \
|
||||
case __LINE__: if (!(c)) return; \
|
||||
} while (0)
|
||||
|
||||
#endif /* PUTTY_SSHCR_H */
|
||||
|
Loading…
Reference in New Issue
Block a user