From 250d031a103fafac805fcf28bccf2120cc936994 Mon Sep 17 00:00:00 2001
From: Roman Tsisyk <roman@tsisyk.com>
Date: Wed, 12 Feb 2014 17:45:03 +0400
Subject: [PATCH] Explicitly use thread-local buffer for C++ exceptions

This patch explicitly saves Exception to a thread-local variable inside
struct cord on tnt_raise(). This variable can be used to safetly
re-throw last exception from any place (not only from catch() block).
This technique requires exception to be thrown and catched by pointers.
tnt_raise macros was rewritten and all 'catch (Exception &)' blocks were
substituted with 'catch (Exception *e)'.

This patch also adds a new feature to box.raise() function.
When called without arguments box.raise() re-throws last exception (if
any).

These changes needed to implement proper handlings of exception for FFI
calls.
---
 client/tarantar/update.cc      |  2 +-
 doc/user/stored-procedures.xml |  2 ++
 src/box/bitset_index.cc        |  2 +-
 src/box/box.cc                 |  6 +++---
 src/box/lua/call.cc            | 12 ++++++++++--
 src/box/lua/tuple.cc           |  2 +-
 src/box/space.cc               |  2 +-
 src/box/tuple.cc               |  2 +-
 src/coio.cc                    |  6 +++---
 src/evio.cc                    |  8 ++++----
 src/exception.cc               | 36 ++++++++++++++++++++++++++++++++++
 src/exception.h                |  5 ++++-
 src/fiber.cc                   |  9 ++++++---
 src/fiber.h                    |  4 ++++
 src/iproto.cc                  | 22 ++++++++++-----------
 src/iproto_port.cc             |  9 ++++-----
 src/iproto_port.h              |  2 +-
 src/lua/fiber.cc               | 14 ++++++-------
 src/lua/init.cc                | 10 +++++-----
 src/lua/socket.cc              | 22 ++++++++++-----------
 src/lua/utils.h                |  2 +-
 src/recovery.cc                |  2 +-
 src/replica.cc                 |  8 ++++----
 src/session.cc                 |  6 +++---
 src/tarantool.cc               |  5 +++--
 test/box/misc.result           | 17 ++++++++++++++++
 test/box/misc.test.lua         | 10 ++++++++++
 27 files changed, 155 insertions(+), 72 deletions(-)

diff --git a/client/tarantar/update.cc b/client/tarantar/update.cc
index e787d9fbfc..36cc671ecd 100644
--- a/client/tarantar/update.cc
+++ b/client/tarantar/update.cc
@@ -94,7 +94,7 @@ ts_update(struct tnt_request *r, struct tnt_tuple *old)
 		memset(buf, 0, new_size);
 
 		tuple_update_execute(u, (char*)buf);
-	} catch (const Exception&) {
+	} catch (Exception *e) {
 		if (buf)
 			free(buf);
 		region_reset(&tss.ra);
diff --git a/doc/user/stored-procedures.xml b/doc/user/stored-procedures.xml
index 408a4ef8b1..42316b6092 100644
--- a/doc/user/stored-procedures.xml
+++ b/doc/user/stored-procedures.xml
@@ -1118,6 +1118,8 @@ localhost&gt; <userinput>setopt delimiter=''!</userinput>
                 message can be arbitrary.
                 Lua procedures can use <code>box.raise()</code> to emulate
                 request errors (for example: unique key exception).
+                When called without arguments this function re-throws last
+                thrown error.
             </para>
             <para>
               Parameters: <code>errcode-number</code> = number taken from the complete list of errors,
diff --git a/src/box/bitset_index.cc b/src/box/bitset_index.cc
index 6f085fcd19..0b9f9b2be5 100644
--- a/src/box/bitset_index.cc
+++ b/src/box/bitset_index.cc
@@ -259,7 +259,7 @@ BitsetIndex::initIterator(struct iterator *iterator, enum iterator_type type,
 		}
 
 		bitset_expr_destroy(&expr);
-	} catch (const Exception& e) {
+	} catch (Exception *e) {
 		bitset_expr_destroy(&expr);
 		throw;
 	}
diff --git a/src/box/box.cc b/src/box/box.cc
index ba395c1368..1a75a8b4bc 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -91,7 +91,7 @@ process_rw(struct port *port, struct request *request)
 		port_send_tuple(port, txn);
 		port_eof(port);
 		txn_finish(txn);
-	} catch (const Exception& e) {
+	} catch (Exception *e) {
 		txn_rollback(txn);
 		throw;
 	}
@@ -126,8 +126,8 @@ recover_row(void *param __attribute__((unused)), const struct log_row *row)
 		request_create(&request, op);
 		request_decode(&request, data, end - data);
 		process_rw(&null_port, &request);
-	} catch (const Exception& e) {
-		e.log();
+	} catch (Exception *e) {
+		e->log();
 		return -1;
 	}
 
diff --git a/src/box/lua/call.cc b/src/box/lua/call.cc
index 51d0baaeba..7ff4224ff0 100644
--- a/src/box/lua/call.cc
+++ b/src/box/lua/call.cc
@@ -231,7 +231,7 @@ lbox_process(lua_State *L)
 		 * use fiber->cleanup and fiber->gc.
 		 */
 		region_truncate(&fiber()->gc, allocated_size);
-	} catch (const Exception &e) {
+	} catch (Exception *e) {
 		region_truncate(&fiber()->gc, allocated_size);
 		throw;
 	}
@@ -338,7 +338,15 @@ lbox_delete(lua_State *L)
 static int
 lbox_raise(lua_State *L)
 {
-	if (lua_gettop(L) != 2)
+	if (lua_gettop(L) == 0) {
+		/* re-throw saved exceptions (if any) */
+		if (cord()->exc == NULL)
+			return 0;
+		throw cord()->exc;
+		return 0;
+	}
+
+	if (lua_gettop(L) < 2)
 		luaL_error(L, "box.raise(): bad arguments");
 	uint32_t code = lua_tointeger(L, 1);
 	if (!code)
diff --git a/src/box/lua/tuple.cc b/src/box/lua/tuple.cc
index b21548b860..5c71c113b2 100644
--- a/src/box/lua/tuple.cc
+++ b/src/box/lua/tuple.cc
@@ -581,7 +581,7 @@ lua_totuple(struct lua_State *L, int first, int last)
 	struct tbuf *b = tbuf_new(&fiber()->gc);
 	try {
 		luamp_encodestack(L, b, first, last);
-	} catch (const Exception &e) {
+	} catch (Exception *e) {
 		throw;
 	} catch (...) {
 		tnt_raise(ClientError, ER_PROC_LUA, lua_tostring(L, -1));
diff --git a/src/box/space.cc b/src/box/space.cc
index f431db99ae..c484bb2255 100644
--- a/src/box/space.cc
+++ b/src/box/space.cc
@@ -183,7 +183,7 @@ space_replace_all_keys(struct space *space, struct tuple *old_tuple,
 			index->replace(old_tuple, new_tuple, DUP_INSERT);
 		}
 		return old_tuple;
-	} catch (const Exception &e) {
+	} catch (Exception *e) {
 		/* Rollback all changes */
 		for (; i > 0; i--) {
 			Index *index = space->index[i-1];
diff --git a/src/box/tuple.cc b/src/box/tuple.cc
index 6bc690c8ca..c509a545a0 100644
--- a/src/box/tuple.cc
+++ b/src/box/tuple.cc
@@ -395,7 +395,7 @@ tuple_update(struct tuple_format *format,
 
 	try {
 		tuple_init_field_map(format, new_tuple, (uint32_t *)new_tuple);
-	} catch (const Exception&) {
+	} catch (Exception *e) {
 		tuple_delete(new_tuple);
 		throw;
 	}
diff --git a/src/coio.cc b/src/coio.cc
index 77e000186c..519909767e 100644
--- a/src/coio.cc
+++ b/src/coio.cc
@@ -155,7 +155,7 @@ coio_connect_addrinfo(struct ev_io *coio, struct addrinfo *ai,
 			if (res)
 				evio_close(loop, coio);
 			return res;
-		} catch (const SocketError& e) {
+		} catch (SocketError *e) {
 			if (res)
 				evio_close(loop, coio);
 			if (ai->ai_next == NULL)
@@ -376,7 +376,7 @@ coio_flush(int fd, struct iovec *iov, ssize_t offset, int iovcnt)
 		sio_add_to_iov(iov, -offset);
 		nwr = sio_writev(fd, iov, iovcnt);
 		sio_add_to_iov(iov, offset);
-	} catch (const Exception& e) {
+	} catch (Exception *e) {
 		sio_add_to_iov(iov, offset);
 		throw;
 	}
@@ -542,7 +542,7 @@ coio_service_on_accept(struct evio_service *evio_service,
 	try {
 		iobuf = iobuf_new(iobuf_name);
 		f = fiber_new(fiber_name, service->handler);
-	} catch (const Exception& e) {
+	} catch (Exception *e) {
 		say_error("can't create a handler fiber, dropping client connection");
 		evio_close(loop(), &coio);
 		if (iobuf)
diff --git a/src/evio.cc b/src/evio.cc
index 73b0709abc..962c040587 100644
--- a/src/evio.cc
+++ b/src/evio.cc
@@ -151,7 +151,7 @@ evio_bind_addrinfo(struct ev_io *evio, struct addrinfo *ai)
 				return; /* success. */
 			}
 			assert(errno == EADDRINUSE);
-		} catch (const SocketError& e) {
+		} catch (SocketError *e) {
 			if (ai->ai_next == NULL) {
 				close(fd);
 				throw;
@@ -202,10 +202,10 @@ evio_service_accept_cb(ev_loop * /* loop */, ev_io *watcher,
 		 */
 		service->on_accept(service, fd, &addr);
 
-	} catch (const Exception& e) {
+	} catch (Exception *e) {
 		if (fd >= 0)
 			close(fd);
-		e.log();
+		e->log();
 	}
 }
 
@@ -237,7 +237,7 @@ evio_service_bind_and_listen(struct evio_service *service)
 		if (service->on_bind)
 			service->on_bind(service->on_bind_param);
 
-	} catch (const Exception& e) {
+	} catch (Exception *e) {
 		close(fd);
 		throw;
 	}
diff --git a/src/exception.cc b/src/exception.cc
index de73973914..d048633690 100644
--- a/src/exception.cc
+++ b/src/exception.cc
@@ -28,11 +28,47 @@
  */
 #include "exception.h"
 #include "say.h"
+#include "fiber.h"
 
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
 
+/* Statically allocate out-of-memory exception */
+static ClientError out_of_memory(__FILE__, __LINE__, ER_MEMORY_ISSUE, 0,
+			  "exception", "new");
+
+void*
+Exception::operator new(size_t size)
+{
+	/* Explicity call destructor for previous exception */
+	if (cord()->exc)
+		cord()->exc->~Exception();
+
+	/* Reuse memory allocated for exception */
+	if (cord()->exc_size < size) {
+		size_t new_size = cord()->exc_size > 0 ? cord()->exc_size : 512;
+		while (new_size < size)
+			new_size *= 2;
+		void *exc = realloc(cord()->exc, new_size);
+		if (exc == NULL)
+			throw &out_of_memory;
+		cord()->exc = (Exception *) exc;
+		cord()->exc_size = new_size;
+	}
+
+	return cord()->exc;
+}
+
+void
+Exception::operator delete(void*)
+{
+	/* Free memory allocated for exception */
+	free(cord()->exc);
+	cord()->exc = NULL;
+	cord()->exc_size = 0;
+}
+
 Exception::Exception(const char *file, unsigned line)
 	: m_file(file), m_line(line)
 {
diff --git a/src/exception.h b/src/exception.h
index 3829d16cb5..e46e611187 100644
--- a/src/exception.h
+++ b/src/exception.h
@@ -35,6 +35,9 @@
 
 class Exception: public Object {
 public:
+	void *operator new(size_t size);
+	void operator delete(void*);
+
 	const char *
 	errmsg() const
 	{
@@ -125,7 +128,7 @@ class ErrorInjection: public LoggedError {
 #define tnt_raise(...) tnt_raise0(__VA_ARGS__)
 #define tnt_raise0(class, ...) do {					\
 	say_debug("%s at %s:%i", #class, __FILE__, __LINE__);		\
-	throw class(__FILE__, __LINE__, ##__VA_ARGS__);			\
+	throw new class(__FILE__, __LINE__, ##__VA_ARGS__);		\
 } while (0)
 
 #endif /* TARANTOOL_EXCEPTION_H_INCLUDED */
diff --git a/src/fiber.cc b/src/fiber.cc
index 46c157cd76..63fd8ccdb3 100644
--- a/src/fiber.cc
+++ b/src/fiber.cc
@@ -377,12 +377,12 @@ fiber_loop(void *data __attribute__((unused)))
 		       fiber()->fid != 0);
 		try {
 			fiber()->f(fiber()->f_data);
-		} catch (const FiberCancelException& e) {
+		} catch (FiberCancelException *e) {
 			say_info("fiber `%s' has been cancelled",
 				 fiber_name(fiber()));
 			say_info("fiber `%s': exiting", fiber_name(fiber()));
-		} catch (const Exception& e) {
-			e.log();
+		} catch (Exception *e) {
+			e->log();
 		} catch (...) {
 			/*
 			 * This can only happen in case of a bug
@@ -526,6 +526,9 @@ cord_destroy(struct cord *cord)
 	}
 	slab_cache_destroy(&cord->slabc);
 	ev_loop_destroy(cord->loop);
+	/* Cleanup memory allocated for exceptions */
+	if (cord->exc)
+		delete cord->exc;
 }
 
 struct cord_thread_arg
diff --git a/src/fiber.h b/src/fiber.h
index 06d3b62ff4..e1a10de3b1 100644
--- a/src/fiber.h
+++ b/src/fiber.h
@@ -111,6 +111,7 @@ struct fiber {
 };
 
 enum { FIBER_CALL_STACK = 16 };
+struct Exception;
 
 /**
  * @brief An independent execution unit that can be managed by a separate OS
@@ -151,6 +152,9 @@ struct cord {
 	/** A runtime slab cache for general use in this cord. */
 	struct slab_cache slabc;
 	char name[FIBER_NAME_MAX];
+	/** Last thrown exception */
+	struct Exception *exc;
+	size_t exc_size;
 };
 
 extern __thread struct cord *cord_ptr;
diff --git a/src/iproto.cc b/src/iproto.cc
index ebcd483aca..cad3173ab5 100644
--- a/src/iproto.cc
+++ b/src/iproto.cc
@@ -555,8 +555,8 @@ iproto_connection_on_input(ev_loop *loop, struct ev_io *watcher,
 		 */
 		if (!ev_is_active(&con->input))
 			ev_feed_event(loop, &con->input, EV_READ);
-	} catch (const Exception& e) {
-		e.log();
+	} catch (Exception *e) {
+		e->log();
 		iproto_connection_shutdown(con);
 	}
 }
@@ -593,7 +593,7 @@ iproto_flush(struct iobuf *iobuf, int fd, struct obuf_svp *svp)
 		nwr = sio_writev(fd, iov, iovcnt);
 
 		sio_add_to_iov(iov, svp->iov_len);
-	} catch (const Exception &) {
+	} catch (Exception *e) {
 		sio_add_to_iov(iov, svp->iov_len);
 		throw;
 	}
@@ -630,8 +630,8 @@ iproto_connection_on_output(ev_loop *loop, struct ev_io *watcher,
 		}
 		if (ev_is_active(&con->output))
 			ev_io_stop(loop, &con->output);
-	} catch (const Exception& e) {
-		e.log();
+	} catch (Exception *e) {
+		e->log();
 		iproto_connection_shutdown(con);
 	}
 }
@@ -691,7 +691,7 @@ iproto_process_request(struct iproto_request *ireq)
 		request_create(&request, ireq->code);
 		request_decode(&request, ireq->body, ireq->len);
 		(*con->handler)((struct port *) &port, &request);
-	} catch (const ClientError &e) {
+	} catch (ClientError *e) {
 		if (port.found)
 			obuf_rollback_to_svp(out, &port.svp);
 		iproto_reply_error(out, e, ireq->sync);
@@ -711,17 +711,17 @@ iproto_process_connect(struct iproto_request *request)
 	int fd = con->input.fd;
 	try {              /* connect. */
 		con->session = session_create(fd, con->cookie);
-	} catch (const ClientError& e) {
+	} catch (ClientError *e) {
 		iproto_reply_error(&iobuf->out, e, request->sync);
 		try {
 			iproto_flush(iobuf, fd, &con->write_pos);
-		} catch (const Exception& e) {
-			e.log();
+		} catch (Exception *e) {
+			e->log();
 		}
 		iproto_connection_shutdown(con);
 		return;
-	} catch (const Exception& e) {
-		e.log();
+	} catch (Exception *e) {
+		e->log();
 		assert(con->session == NULL);
 		iproto_connection_shutdown(con);
 		return;
diff --git a/src/iproto_port.cc b/src/iproto_port.cc
index f76efb0a5b..2822aff42c 100644
--- a/src/iproto_port.cc
+++ b/src/iproto_port.cc
@@ -71,24 +71,23 @@ iproto_reply_ping(struct obuf *out, uint32_t sync)
 }
 
 void
-iproto_reply_error(struct obuf *out, const ClientError &e,
-		   uint32_t sync)
+iproto_reply_error(struct obuf *out, ClientError *e, uint32_t sync)
 {
-	uint32_t msg_len = strlen(e.errmsg());
+	uint32_t msg_len = strlen(e->errmsg());
 
 	struct iproto_header_bin header = iproto_header_bin;
 	struct iproto_body_bin body = iproto_error_bin;
 
 	uint32_t len = sizeof(header) - 5 + sizeof(body) + msg_len;
 	header.v_len = mp_bswap_u32(len);
-	header.v_code = mp_bswap_u32(tnt_errcode_val(e.errcode()));
+	header.v_code = mp_bswap_u32(tnt_errcode_val(e->errcode()));
 	header.v_sync = mp_bswap_u32(sync);
 
 	body.v_data_len = mp_bswap_u32(msg_len);
 
 	obuf_dup(out, &header, sizeof(header));
 	obuf_dup(out, &body, sizeof(body));
-	obuf_dup(out, e.errmsg(), msg_len);
+	obuf_dup(out, e->errmsg(), msg_len);
 }
 
 static inline struct iproto_port *
diff --git a/src/iproto_port.h b/src/iproto_port.h
index 93d8fc2307..6ebb9ebf74 100644
--- a/src/iproto_port.h
+++ b/src/iproto_port.h
@@ -84,7 +84,7 @@ iproto_reply_ping(struct obuf *out, uint32_t sync);
 
 /** Send an error packet back. */
 void
-iproto_reply_error(struct obuf *out, const ClientError &e,
+iproto_reply_error(struct obuf *out, ClientError *e,
 		   uint32_t sync);
 
 #endif /* TARANTOOL_IPROTO_PORT_H_INCLUDED */
diff --git a/src/lua/fiber.cc b/src/lua/fiber.cc
index ffe2acd754..73f1ca7e79 100644
--- a/src/lua/fiber.cc
+++ b/src/lua/fiber.cc
@@ -406,7 +406,7 @@ box_lua_fiber_run(va_list ap __attribute__((unused)))
 		lua_pushboolean(L, true);
 		/* move 'true' to stack start */
 		lua_insert(L, 1);
-	} catch (const FiberCancelException &e) {
+	} catch (FiberCancelException *e) {
 		if (box_lua_fiber_get_coro(L, fiber())) {
 			struct fiber *caller = box_lua_fiber_get_caller(L);
 			fiber_wakeup(caller);
@@ -420,16 +420,16 @@ box_lua_fiber_run(va_list ap __attribute__((unused)))
 		 */
 
 		throw;
-	} catch (const Exception &e) {
+	} catch (Exception *e) {
 		/* pop any possible garbage */
 		lua_settop(L, 0);
 		/* completion status */
 		lua_pushboolean(L, false);
 		/* error message */
-		lua_pushstring(L, e.errmsg());
+		lua_pushstring(L, e->errmsg());
 
 		/* Always log the error. */
-		e.log();
+		e->log();
 	}
 	/*
 	 * L stack contains nothing but call results.
@@ -551,10 +551,10 @@ box_lua_fiber_run_detached(va_list ap)
 	struct lua_State *L = va_arg(ap, struct lua_State *);
 	try {
 		lbox_call(L, lua_gettop(L) - 1, LUA_MULTRET);
-	} catch (const FiberCancelException &e) {
+	} catch (FiberCancelException *e) {
 		throw;
-	} catch (const Exception &e) {
-		e.log();
+	} catch (Exception *e) {
+		e->log();
 	}
 }
 
diff --git a/src/lua/init.cc b/src/lua/init.cc
index 1fa60ef6fc..025ae5745b 100644
--- a/src/lua/init.cc
+++ b/src/lua/init.cc
@@ -197,7 +197,7 @@ lbox_pcall(struct lua_State *L)
 		lua_pushboolean(L, true);
 		/* move 'true' to stack start */
 		lua_insert(L, 1);
-	} catch (const ClientError& e) {
+	} catch (ClientError *e) {
 		/*
 		 * Note: FiberCancelException passes through this
 		 * catch and thus leaves garbage on coroutine
@@ -208,7 +208,7 @@ lbox_pcall(struct lua_State *L)
 		/* completion status */
 		lua_pushboolean(L, false);
 		/* error message */
-		lua_pushstring(L, e.errmsg());
+		lua_pushstring(L, e->errmsg());
 	}
 	return lua_gettop(L);
 }
@@ -359,11 +359,11 @@ tarantool_lua_dostring(struct lua_State *L, const char *str)
 	}
 	try {
 		lbox_call(L, 0, LUA_MULTRET);
-	} catch (const FiberCancelException& e) {
+	} catch (FiberCancelException *e) {
 		throw;
-	} catch (const Exception& e) {
+	} catch (Exception *e) {
 		lua_settop(L, 0);
-		lua_pushstring(L, e.errmsg());
+		lua_pushstring(L, e->errmsg());
 		return 1;
 	}
 	return 0;
diff --git a/src/lua/socket.cc b/src/lua/socket.cc
index 88ef6cf3fb..a586cae900 100644
--- a/src/lua/socket.cc
+++ b/src/lua/socket.cc
@@ -332,7 +332,7 @@ lbox_socket_connect(struct lua_State *L)
 
 		/* set coio reader socket */
 		s->io_r.fd = s->io_w.fd;
-	} catch (const SocketError& e) {
+	} catch (SocketError *e) {
 		freeaddrinfo(ai);
 		return bio_pushsockerror(L, s, errno);
 	}
@@ -389,12 +389,12 @@ lbox_socket_send(struct lua_State *L)
 		}
 
 		mutex_unlock(&s->io_w_mutex);
-	} catch (const SocketError& e) {
+	} catch (SocketError *e) {
 		mutex_unlock(&s->io_w_mutex);
 
 		rc = bio_pushsenderror(L, s, 0, errno);
 		return rc;
-	} catch (const Exception& e) {
+	} catch (Exception *e) {
 		mutex_unlock(&s->io_w_mutex);
 		throw;
 	}
@@ -457,12 +457,12 @@ lbox_socket_recv(struct lua_State *L)
 			nrd = coio_bread_timeout(&s->io_r, in, to_read,
 						 delay);
 			mutex_unlock(&s->io_r_mutex);
-		} catch (const SocketError& e) {
+		} catch (SocketError *e) {
 			mutex_unlock(&s->io_r_mutex);
 
 			rc = bio_pushrecverror(L, s, errno);
 			return rc;
-		} catch (const Exception& e) {
+		} catch (Exception *e) {
 			mutex_unlock(&s->io_r_mutex);
 			throw;
 		}
@@ -694,11 +694,11 @@ lbox_socket_readline(struct lua_State *L)
 		}
 
 		mutex_unlock(&s->io_r_mutex);
-	} catch (const SocketError& e) {
+	} catch (SocketError *e) {
 		mutex_unlock(&s->io_r_mutex);
 		rc = bio_pushrecverror(L, s, errno);
 		return rc;
-	} catch (const Exception& e) {
+	} catch (Exception *e) {
 		mutex_unlock(&s->io_r_mutex);
 		throw;
 	}
@@ -739,7 +739,7 @@ lbox_socket_bind(struct lua_State *L)
 	try {
 		evio_bind_addrinfo(&s->io_w, ai);
 		freeaddrinfo(ai);
-	} catch (const SocketError& e) {
+	} catch (SocketError *e) {
 		/* case #2: error */
 		freeaddrinfo(ai);
 		return bio_pusherror(L, s, errno);
@@ -797,7 +797,7 @@ lbox_socket_accept(struct lua_State *L)
 		client->io_w.fd = coio_accept(&s->io_w, (struct sockaddr_in*)&addr,
 					     sizeof(addr), timeout);
 		client->io_r.fd = client->io_w.fd;
-	} catch (const SocketError& e) {
+	} catch (SocketError *e) {
 		return bio_pusherror(L, s, errno);
 	}
 	/* get user host and port */
@@ -870,7 +870,7 @@ lbox_socket_sendto(struct lua_State *L)
 		if (a) {
 			freeaddrinfo(a);
 		}
-	} catch (const SocketError& e) {
+	} catch (SocketError *e) {
 		/* case #2-3: error or timeout */
 		if (a) {
 			freeaddrinfo(a);
@@ -918,7 +918,7 @@ lbox_socket_recvfrom(struct lua_State *L)
 		nrd = coio_recvfrom_timeout(&s->io_w, in->pos, buf_size, 0,
 					    (struct sockaddr_in*)&addr,
 					    sizeof(addr), timeout);
-	} catch (const SocketError& e) {
+	} catch (SocketError *e) {
 		return bio_pushrecverror(L, s, errno);
 	}
 	if (nrd == 0) {
diff --git a/src/lua/utils.h b/src/lua/utils.h
index e481e5bf10..656083abc2 100644
--- a/src/lua/utils.h
+++ b/src/lua/utils.h
@@ -184,7 +184,7 @@ lbox_call(struct lua_State *L, int nargs, int nreturns)
 {
 	try {
 		lua_call(L, nargs, nreturns);
-	} catch (const Exception &e) {
+	} catch (Exception *e) {
 		/* Let all well-behaved exceptions pass through. */
 		throw;
 	} catch (...) {
diff --git a/src/recovery.cc b/src/recovery.cc
index d70674a940..80d1d22217 100644
--- a/src/recovery.cc
+++ b/src/recovery.cc
@@ -176,7 +176,7 @@ recovery_wait_lsn(struct recovery_state *r, int64_t lsn)
 		try {
 			fiber_yield();
 			wait_lsn_clear(&r->wait_lsn);
-		} catch (const Exception& e) {
+		} catch (Exception *e) {
 			wait_lsn_clear(&r->wait_lsn);
 			throw;
 		}
diff --git a/src/replica.cc b/src/replica.cc
index a6946641ea..aeaa75d09d 100644
--- a/src/replica.cc
+++ b/src/replica.cc
@@ -132,14 +132,14 @@ pull_from_remote(va_list ap)
 
 			iobuf_gc(iobuf);
 			fiber_gc();
-		} catch (const FiberCancelException& e) {
+		} catch (FiberCancelException *e) {
 			title("replica", "%s/%s", r->remote->source, "failed");
 			iobuf_delete(iobuf);
 			evio_close(loop, &coio);
 			throw;
-		} catch (const Exception& e) {
+		} catch (Exception *e) {
 			title("replica", "%s/%s", r->remote->source, "failed");
-			e.log();
+			e->log();
 			if (! warning_said) {
 				if (err != NULL)
 					say_info("%s", err);
@@ -195,7 +195,7 @@ recovery_follow_remote(struct recovery_state *r, const char *addr)
 
 	try {
 		f = fiber_new(name, pull_from_remote);
-	} catch (const Exception& ) {
+	} catch (Exception *e) {
 		return;
 	}
 
diff --git a/src/session.cc b/src/session.cc
index a2dc0d4337..624439d6fb 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -74,7 +74,7 @@ session_create(int fd, uint64_t cookie)
 	fiber_set_session(fiber(), session);
 	try {
 		trigger_run(&session_on_connect, NULL);
-	} catch (const Exception& e) {
+	} catch (Exception *e) {
 		fiber_set_session(fiber(), NULL);
 		mh_i32ptr_remove(session_registry, &node, NULL);
 		mempool_free(&session_pool, session);
@@ -92,8 +92,8 @@ session_destroy(struct session *session)
 
 	try {
 		trigger_run(&session_on_disconnect, NULL);
-	} catch (const Exception& e) {
-		e.log();
+	} catch (Exception *e) {
+		e->log();
 	} catch (...) {
 		/* catch all. */
 	}
diff --git a/src/tarantool.cc b/src/tarantool.cc
index cc5e942a32..c71d94aa9f 100644
--- a/src/tarantool.cc
+++ b/src/tarantool.cc
@@ -815,10 +815,11 @@ main(int argc, char **argv)
 			signal_start();
 			ev_run(loop(), 0);
 		}
-	} catch (const Exception& e) {
-		e.log();
+	} catch (Exception *e) {
+		e->log();
 		panic("%s", "fatal error, exiting the event loop");
 	}
+
 	if (start_loop)
 		say_crit("exiting the event loop");
 	/* freeing resources */
diff --git a/test/box/misc.result b/test/box/misc.result
index 9488a70b35..726b8a3f65 100644
--- a/test/box/misc.result
+++ b/test/box/misc.result
@@ -59,6 +59,12 @@ t = nil
 ----------------
 -- # box.raise
 ----------------
+--# stop server default
+--# start server default
+-- do nothing - no exceptions were thrown before
+box.raise()
+---
+...
 1 + 1
 ---
 - 2
@@ -75,6 +81,17 @@ box.raise(12, 345)
 ---
 - error: '345'
 ...
+box.raise()
+---
+- error: '345'
+...
+box.raise()
+---
+- error: '345'
+...
+space = box.space.tweedledum
+---
+...
 ----------------
 -- # box.stat
 ----------------
diff --git a/test/box/misc.test.lua b/test/box/misc.test.lua
index dd96ea4866..417761580c 100644
--- a/test/box/misc.test.lua
+++ b/test/box/misc.test.lua
@@ -12,10 +12,20 @@ t = nil
 ----------------
 -- # box.raise
 ----------------
+
+--# stop server default
+--# start server default
+-- do nothing - no exceptions were thrown before
+box.raise()
+
 1 + 1
 box.raise(123, 'test')
 box.raise(0, 'the other test')
 box.raise(12, 345)
+box.raise()
+box.raise()
+
+space = box.space.tweedledum
 
 ----------------
 -- # box.stat
-- 
GitLab