diff options
authorNeels Hofmeyr <neels@hofmeyr.de>2018-08-27 21:54:49 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2018-08-29 02:02:10 +0200
commit3ea8baeab00964217bd20027d6d61c625e62b5e4 (patch)
parentd8b41fc677ad4a83a414d17215da2cd767cc47ad (diff)
lchan_fsm: lchan_fail_to(): store target state early
lchan_fail_to() is a macro to preserve useful source file:line information in logging. But a side effect is that its target state argument might evaluate differently at the end of the macro, if, say, the fi->state has changed. I hit such an instance on timeout of WAIT_RLL_RTP_ESTABLISH: lchan_fsm_timer_cb() calls macro lchan_fail(), which calls lchan_fail_to(lchan_fsm_on_error[fi->state]). Unlike for normal function invocation, this argument changes as fi->state changes. Since releasing the lchan_rtp_fsm already transitions the lchan fi into WAIT_RF_RELEASE_ACK, the final state change of lchan_fail_to() suddenly evaluates to the broken state instead of the intended WAIT_RF_RELEASE_ACK. Early in lchan_fail_to(), store the argument's value as of macro invocation. Change-Id: Id9bf4580a112ee5629f553a8bcb6b5b03b1c5f53
1 files changed, 3 insertions, 1 deletions
diff --git a/src/osmo-bsc/lchan_fsm.c b/src/osmo-bsc/lchan_fsm.c
index 9c22bded4..e0015cbeb 100644
--- a/src/osmo-bsc/lchan_fsm.c
+++ b/src/osmo-bsc/lchan_fsm.c
@@ -211,9 +211,11 @@ struct state_timeout lchan_fsm_timeouts[32] = {
/* Set a failure message, trigger the common actions to take on failure, transition to a state to
* continue with (using state timeouts from lchan_fsm_timeouts[]). Assumes local variable fi exists. */
-#define lchan_fail_to(state_chg, fmt, args...) do { \
+#define lchan_fail_to(STATE_CHG, fmt, args...) do { \
struct gsm_lchan *_lchan = fi->priv; \
uint32_t state_was = fi->state; \
+ /* Snapshot the target state, in case the macro argument evaluates differently later */ \
+ const uint32_t state_chg = STATE_CHG; \
lchan_set_last_error(_lchan, "lchan %s in state %s: " fmt, \
_lchan->activate.concluded ? "failure" : "allocation failed", \
osmo_fsm_state_name(fi->fsm, state_was), ## args); \