diff --git a/src/box/box.cc b/src/box/box.cc
index 1146bc902e1639bd70c867b4779f07cba12420f8..f26a0235e879217ebae8a4a2074d3b3f204fa4fe 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -58,6 +58,7 @@
 #include "vinyl.h"
 #include "space.h"
 #include "index.h"
+#include "result.h"
 #include "port.h"
 #include "txn.h"
 #include "txn_limbo.h"
@@ -297,6 +298,8 @@ box_process_rw(struct request *request, struct space *space,
 	bool return_tuple = false;
 	struct txn *txn = in_txn();
 	bool is_autocommit = txn == NULL;
+	struct result_processor res_proc;
+	int rc;
 	if (is_autocommit && (txn = txn_begin()) == NULL)
 		return -1;
 	assert(iproto_type_is_dml(request->type));
@@ -305,14 +308,19 @@ box_process_rw(struct request *request, struct space *space,
 		goto rollback;
 	if (txn_begin_stmt(txn, space, request->type) != 0)
 		goto rollback;
-	if (space_execute_dml(space, txn, request, &tuple) != 0) {
+	result_process_prepare(&res_proc, space);
+	rc = space_execute_dml(space, txn, request, &tuple);
+	if (result == NULL)
+		tuple = NULL;
+	result_process(&res_proc, &rc, &tuple);
+	if (rc != 0) {
 		txn_rollback_stmt(txn);
 		goto rollback;
 	}
 	if (result != NULL)
 		*result = tuple;
 
-	return_tuple = result != NULL && tuple != NULL;
+	return_tuple = tuple != NULL;
 	if (return_tuple) {
 		/*
 		 * Pin the tuple locally before the commit,
@@ -2444,7 +2452,10 @@ box_select(uint32_t space_id, uint32_t index_id,
 	struct tuple *tuple;
 	port_c_create(port);
 	while (found < limit) {
+		struct result_processor res_proc;
+		result_process_prepare(&res_proc, space);
 		rc = iterator_next(it, &tuple);
+		result_process(&res_proc, &rc, &tuple);
 		if (rc != 0 || tuple == NULL)
 			break;
 		if (offset > 0) {
@@ -2455,6 +2466,11 @@ box_select(uint32_t space_id, uint32_t index_id,
 		if (rc != 0)
 			break;
 		found++;
+		/*
+		 * Refresh the pointer to the space, because the space struct
+		 * could be freed if the iterator yielded.
+		 */
+		space = iterator_space(it);
 	}
 	iterator_delete(it);
 
diff --git a/src/box/index.cc b/src/box/index.cc
index 80d982cb9b6da0850147bd6a331d32bf9ed9cb15..5bd4b2fbd78afafb89e0c49526a383ebad23e3a4 100644
--- a/src/box/index.cc
+++ b/src/box/index.cc
@@ -34,6 +34,7 @@
 #include "schema.h"
 #include "user_def.h"
 #include "space.h"
+#include "result.h"
 #include "iproto_constants.h"
 #include "txn.h"
 #include "rmean.h"
@@ -216,7 +217,11 @@ box_index_random(uint32_t space_id, uint32_t index_id, uint32_t rnd,
 	if (check_index(space_id, index_id, &space, &index) != 0)
 		return -1;
 	/* No tx management, random() is for approximation anyway. */
-	if (index_random(index, rnd, result) != 0)
+	struct result_processor res_proc;
+	result_process_prepare(&res_proc, space);
+	int rc = index_random(index, rnd, result);
+	result_process(&res_proc, &rc, result);
+	if (rc != 0)
 		return -1;
 	if (*result != NULL)
 		tuple_bless(*result);
@@ -247,7 +252,11 @@ box_index_get(uint32_t space_id, uint32_t index_id, const char *key,
 	struct txn_ro_savepoint svp;
 	if (txn_begin_ro_stmt(space, &txn, &svp) != 0)
 		return -1;
-	if (index_get(index, key, part_count, result) != 0) {
+	struct result_processor res_proc;
+	result_process_prepare(&res_proc, space);
+	int rc = index_get(index, key, part_count, result);
+	result_process(&res_proc, &rc, result);
+	if (rc != 0) {
 		txn_rollback_stmt(txn);
 		return -1;
 	}
@@ -284,7 +293,11 @@ box_index_min(uint32_t space_id, uint32_t index_id, const char *key,
 	struct txn_ro_savepoint svp;
 	if (txn_begin_ro_stmt(space, &txn, &svp) != 0)
 		return -1;
-	if (index_min(index, key, part_count, result) != 0) {
+	struct result_processor res_proc;
+	result_process_prepare(&res_proc, space);
+	int rc = index_min(index, key, part_count, result);
+	result_process(&res_proc, &rc, result);
+	if (rc != 0) {
 		txn_rollback_stmt(txn);
 		return -1;
 	}
@@ -319,7 +332,11 @@ box_index_max(uint32_t space_id, uint32_t index_id, const char *key,
 	struct txn_ro_savepoint svp;
 	if (txn_begin_ro_stmt(space, &txn, &svp) != 0)
 		return -1;
-	if (index_max(index, key, part_count, result) != 0) {
+	struct result_processor res_proc;
+	result_process_prepare(&res_proc, space);
+	int rc = index_max(index, key, part_count, result);
+	result_process(&res_proc, &rc, result);
+	if (rc != 0) {
 		txn_rollback_stmt(txn);
 		return -1;
 	}
@@ -408,7 +425,16 @@ int
 box_iterator_next(box_iterator_t *itr, box_tuple_t **result)
 {
 	assert(result != NULL);
-	if (iterator_next(itr, result) != 0)
+	struct space *space = iterator_space(itr);
+	if (space == NULL) {
+		*result = NULL;
+		return 0;
+	}
+	struct result_processor res_proc;
+	result_process_prepare(&res_proc, space);
+	int rc = iterator_next(itr, result);
+	result_process(&res_proc, &rc, result);
+	if (rc != 0)
 		return -1;
 	if (*result != NULL)
 		tuple_bless(*result);
diff --git a/src/box/result.h b/src/box/result.h
new file mode 100644
index 0000000000000000000000000000000000000000..032a8ac11d873658607073e5d2378d98e31b622b
--- /dev/null
+++ b/src/box/result.h
@@ -0,0 +1,53 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright 2010-2022, Tarantool AUTHORS, please see AUTHORS file.
+ */
+#pragma once
+
+struct space;
+struct tuple;
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* defined(__cplusplus) */
+
+/**
+ * Helpers that apply various transformations to tuples fetched from a space.
+ * The procedure is split in two parts, because the read operation may yield,
+ * which opens a time window during which the space struct can be deleted.
+ * The 'prepare' phase is supposed to reference and store in result_processor
+ * all data structures needed to apply transforamtions.
+ *
+ * Used by box methods that read tuples from a space and return them to
+ * the user like this:
+ *
+ *   struct result_processor res_proc;
+ *   result_process_prepare(&res_proc, space);
+ *   rc = index_get(index, key, part_count, result);
+ *   result_process(&res_proc, &rc, result);
+ *
+ * Note, if result_process_prepare() was called, then result_process()
+ * must be called as well, because it may need to free some resources.
+ */
+struct result_processor {
+};
+
+static inline void
+result_process_prepare(struct result_processor *p, struct space *space)
+{
+	(void)p;
+	(void)space;
+}
+
+static inline void
+result_process(struct result_processor *p, int *rc, struct tuple **result)
+{
+	(void)p;
+	(void)rc;
+	(void)result;
+}
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif /* defined(__cplusplus) */