Bug #82892 `thd->owned_gtid_set` cause mysqld crash
Submitted: 7 Sep 2016 12:21 Modified: 12 Sep 2016 9:52
Reporter: baizhong zhao (OCA) Email Updates:
Status: Can't repeat Impact on me:
None 
Category:MySQL Server: Replication Severity:S2 (Serious)
Version:5.7.14 OS:Any
Assigned to: CPU Architecture:Any
Tags: GTID

[7 Sep 2016 12:21] baizhong zhao
Description:
The bug happens if `HAVE_GTID_NEXT_LIST` macro is specified,  and if `thd->owned_gtid_set` has more than one gtid.

It cause  mysqld to crash at `update_gtids_impl` function in the commit stage of binlog commiting. 

This is because the `prev_sidno` in the follow code has not correct value, cause to `sid_lock` to locked repeatly; 

And  `sid_lock` also  forget to  be unlocked.  

#ifdef HAVE_GTID_NEXT_LIST
    rpl_sidno prev_sidno= 0;
    Gtid_set::Gtid_iterator git(&thd->owned_gtid_set);
    Gtid g= git.get();
    while (g.sidno != 0)
    {
      if (g.sidno != prev_sidno)
        sid_locks.lock(g.sidno);
      owned_gtids.remove_gtid(g);
      git.next();
      g= git.get();
      if (is_commit)
        executed_gtids._add_gtid(g);
    }

    if (is_commit && !thd->owned_gtid_set.is_empty())
      thd->rpl_thd_ctx.session_gtids_ctx().
        notify_after_gtid_executed_update(thd);

    thd->variables.gtid_next.set_undefined();
    thd->owned_gtid.dbug_print(NULL,
                               "set owned_gtid (clear; old was gtid_set) "
                               "in update_gtids_impl");
    thd->clear_owned_gtids();
#else

How to repeat:
1. compile mysqld with `HAVE_GTID_NEXT_LIST`
2. let `thd->owned_gtid_set` has more than one gtid
3. execute some sql statement that generate binlog

Suggested fix:

#ifdef HAVE_GTID_NEXT_LIST
    rpl_sidno prev_sidno= 0;
    Gtid_set::Gtid_iterator git(&thd->owned_gtid_set);
    Gtid g= git.get();
    while (g.sidno != 0)
    {
      if (g.sidno != prev_sidno)
        sid_locks.lock(g.sidno);
      owned_gtids.remove_gtid(g);
      prev_sidno = g.sidno; // correct it
	  if (is_commit) {
		  executed_gtids._add_gtid(g);
		  if (thd->slave_thread && opt_bin_log && !opt_log_slave_updates)
		  {
			  lost_gtids._add_gtid(g);
			  gtids_only_in_table._add_gtid(g);
		  }
	  }
      git.next();
      g= git.get();
    }

    if (is_commit && !thd->owned_gtid_set.is_empty())
      thd->rpl_thd_ctx.session_gtids_ctx().
        notify_after_gtid_executed_update(thd);

	broadcast_owned_sidnos(thd);
	unlock_owned_sidnos(thd);
	thd->clear_owned_gtids();  // unlock the sid

	if (thd->variables.gtid_next.type == GTID_GROUP)
	{
		DBUG_ASSERT(!more_transactions_with_same_gtid_next);
		thd->variables.gtid_next.set_undefined();
	}
#else
[12 Sep 2016 9:52] MySQL Verification Team
Hello baizhong,

Thank you for the report.
Could you please provide exact repeatable test case for this issue?
If you can provide more information, feel free to add it to this bug and change the status back to 'Open'.

Thanks,
Umesh