diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def
index f32ed667864daf0cf2754be554be4f08d75f21d8..5fdc6f6f3dc8cb6291acbf820383e6ef9b5030a9 100644
--- a/mysql-test/t/disabled.def
+++ b/mysql-test/t/disabled.def
@@ -24,4 +24,4 @@ subselect       : Bug#15706
 type_time       : Bug#15805
 rpl000002       : Bug#15920 Temporary tables are not binlogged in SBR
 ps_7ndb         : Bug#15923 Core dump in RBR mode when executing test suite
-sp_trans        : Bug#15924 Code dump in RBR mode when executing test suite
+#sp_trans        : Bug#15924 Code dump in RBR mode when executing test suite
diff --git a/sql/log.cc b/sql/log.cc
index 44d3869e9d56ff71cd60f067b75771e98f14a34a..dd08ca7b9b5c5afc6148622241b5f7f8d17d5f5e 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -241,13 +241,15 @@ static int binlog_savepoint_set(THD *thd, void *sv)
   DBUG_ENTER("binlog_savepoint_set");
   binlog_trx_data *const trx_data=
     (binlog_trx_data*) thd->ha_data[binlog_hton.slot];
-  IO_CACHE *trans_log= &trx_data->trans_log;
-  DBUG_ASSERT(mysql_bin_log.is_open() && my_b_tell(trans_log));
+  DBUG_ASSERT(mysql_bin_log.is_open() && my_b_tell(&trx_data->trans_log));
 
-  *(my_off_t *)sv= my_b_tell(trans_log);
+  *(my_off_t *)sv= my_b_tell(&trx_data->trans_log);
   /* Write it to the binary log */
-  Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE);
-  DBUG_RETURN(mysql_bin_log.write(&qinfo));
+  
+  int const error=
+    thd->binlog_query(THD::STMT_QUERY_TYPE,
+                      thd->query, thd->query_length, TRUE, FALSE);
+  DBUG_RETURN(error);
 }
 
 static int binlog_savepoint_rollback(THD *thd, void *sv)
@@ -265,8 +267,10 @@ static int binlog_savepoint_rollback(THD *thd, void *sv)
   */
   if (unlikely(thd->options & OPTION_STATUS_NO_TRANS_UPDATE))
   {
-    Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE);
-    DBUG_RETURN(mysql_bin_log.write(&qinfo));
+    int const error=
+      thd->binlog_query(THD::STMT_QUERY_TYPE,
+                        thd->query, thd->query_length, TRUE, FALSE);
+    DBUG_RETURN(error);
   }
   reinit_io_cache(trans_log, WRITE_CACHE, *(my_off_t *)sv, 0, 0);
   DBUG_RETURN(0);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 08d89228a7203a2f882b4b6b295715f33f2b335f..2bc0d8d59ab69ef8ccd33b18a64c82465208bcb9 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1969,6 +1969,23 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup,
   backup->client_capabilities= client_capabilities;
   backup->savepoints= transaction.savepoints;
 
+  /*
+    For row-based replication and before executing a function/trigger,
+    the pending rows event has to be flushed.  The function/trigger
+    might execute statement that require the pending event to be
+    flushed. A simple example:
+
+      CREATE FUNCTION foo() RETURNS INT
+      BEGIN
+        SAVEPOINT x;
+        RETURN 0;
+      END
+
+      INSERT INTO t1 VALUES (1), (foo()), (2);
+  */
+  if (binlog_row_based)
+    thd->binlog_flush_pending_rows_event(false);
+
   if ((!lex->requires_prelocking() || is_update_query(lex->sql_command)) &&
       !binlog_row_based)
     options&= ~OPTION_BIN_LOG;