Tarantool development patches archive
 help / color / mirror / Atom feed
From: Cyrill Gorcunov <gorcunov@gmail.com>
To: tml <tarantool-patches@dev.tarantool.org>
Subject: [Tarantool-patches] [PATCH v10 3/4] box/applier: prevent nil dereference on applier rollback
Date: Fri, 14 Feb 2020 17:03:38 +0300	[thread overview]
Message-ID: <20200214140339.4085-4-gorcunov@gmail.com> (raw)
In-Reply-To: <20200214140339.4085-1-gorcunov@gmail.com>

Currently when transaction rollback happens we just drop an existing
error setting ClientError to the replicaset.applier.diag. This action
leaves current fiber with diag=nil, which in turn leads to sigsegv once
diag_raise() called right after applier_apply_tx():

 | applier_f
 |   try {
 |   applier_subscribe
 |     applier_apply_tx
 |       // error happens
 |       txn_rollback
 |         diag_set(ClientError, ER_WAL_IO)
 |         diag_move(&fiber()->diag, &replicaset.applier.diag)
 |         // fiber->diag = nil
 |       applier_on_rollback
 |         diag_add_error(&applier->diag, diag_last_error(&replicaset.applier.diag)
 |         fiber_cancel(applier->reader);
 |     diag_raise() -> NULL dereference
 |   } catch { ... }

The applier_f works in try/catch cycle and handles errors depending on
what exactly happened during transaction application. It might reconnect
appliers in some cases, the applier is simply cancelled and reaped out in
others.

The problem is that the shared replicaset.applier.diag is handled on
FiberIsCancelled exception only (while it is set inside transaction
rollback action) and we never trigger this specific exception. But
even if we would the former error which has been causing the applier
abort is vanished by ClientError which is too general.

Thus:

 - log the former error, but leave ClientError as a new one
   to be preserved in replicaset diag instance (I don't want
   to make an intrusive patch which would change a logic since
   I'm far from being expert in this code);

 - put fixme mark into the code: we need to rework it in a
   more sense way.

Part-of #4730

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---
 src/box/applier.cc | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/src/box/applier.cc b/src/box/applier.cc
index 2ed5125d0..a4a73d383 100644
--- a/src/box/applier.cc
+++ b/src/box/applier.cc
@@ -692,9 +692,33 @@ static int
 applier_txn_rollback_cb(struct trigger *trigger, void *event)
 {
 	(void) trigger;
+	/*
+	 * FIXME: Do not clear fiber()->diag since it
+	 * cause nil dereference
+	 *
+	 *   applier_subscribe
+	 *     applier_apply_tx
+	 *       diag_raise
+	 *
+	 * In turn we need to redesign this code:
+	 *  - preserve original error or log it somewhere
+	 *  - make the error path more clear
+	 *
+	 *  We must never reach this point with clean diag
+	 *  area, if we do it means we're simply screwed
+	 *  somewhere and there is a bug.
+	 */
+
+	if (!diag_is_empty(diag_get()))
+		diag_log();
+	else
+		say_warn_ratelimited("applier_txn_rollback_cb: empty diag");
+
 	/* Setup shared applier diagnostic area. */
 	diag_set(ClientError, ER_WAL_IO);
-	diag_move(&fiber()->diag, &replicaset.applier.diag);
+	diag_add_error(&replicaset.applier.diag,
+		       diag_last_error(&fiber()->diag));
+
 	/* Broadcast the rollback event across all appliers. */
 	trigger_run(&replicaset.applier.on_rollback, event);
 	/* Rollback applier vclock to the committed one. */
-- 
2.20.1

  parent reply	other threads:[~2020-02-14 14:04 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-14 14:03 [Tarantool-patches] [PATCH v10 0/4] box/replication: add missing diag set and fix sigsegv Cyrill Gorcunov
2020-02-14 14:03 ` [Tarantool-patches] [PATCH v10 1/4] box/request: add missing OutOfMemory diag_set Cyrill Gorcunov
2020-02-15 17:33   ` Konstantin Osipov
2020-02-14 14:03 ` [Tarantool-patches] [PATCH v10 2/4] box/applier: add missing diag_set on region_alloc failure Cyrill Gorcunov
2020-02-15 17:34   ` Konstantin Osipov
2020-02-14 14:03 ` Cyrill Gorcunov [this message]
2020-02-15 17:37   ` [Tarantool-patches] [PATCH v10 3/4] box/applier: prevent nil dereference on applier rollback Konstantin Osipov
2020-02-15 18:24     ` Cyrill Gorcunov
2020-02-15 18:51       ` Konstantin Osipov
2020-02-14 14:03 ` [Tarantool-patches] [PATCH v10 4/4] test: add replication/applier-rollback Cyrill Gorcunov
2020-02-15 17:38   ` Konstantin Osipov
2020-02-15 17:59     ` Cyrill Gorcunov
2020-02-14 14:12 ` [Tarantool-patches] [PATCH v10 0/4] box/replication: add missing diag set and fix sigsegv Cyrill Gorcunov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200214140339.4085-4-gorcunov@gmail.com \
    --to=gorcunov@gmail.com \
    --cc=tarantool-patches@dev.tarantool.org \
    --subject='Re: [Tarantool-patches] [PATCH v10 3/4] box/applier: prevent nil dereference on applier rollback' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox