激动,终于找到 xunsearch-1.4.x 以来的潜伏 BUG

BUG 是这样的,不断有用户反馈说 xunsearch 会出现 signal 11 等各种意外的挂掉。虽然内部的保护和重生机制能保持进程自动重启,但还是非常影响用户体验,甚至偶尔还会出现内存泄露。

再多次 debug 无效后,导出 core 文件分析发现 11 信号来自 malloc 调用,这说明前面的堆内存用法错误或越界破坏了 malloc 内部维护的数据才会导致。

于是根据少得可怜的 backtrace 信息搜寻,很快定位到了问题函数 get_queryparser ,代码是这样的,大家别看后面先自己找找问题在哪?

/**
 * Get a queryparser object from cached chain
 */
static Xapian::QueryParser *get_queryparser()
{
	static struct cache_qp *head;

	pthread_mutex_lock(&qp_mutex);
	for (head = qp_base; head != NULL; head = head->next)
	{
		if (head->in_use == false)
		{
			log_debug("reuse qp (ADDR:%p)", head);
			break;
		}
	}
	if (head == NULL) /* alloc new one */
	{
		debug_malloc(head, sizeof(struct cache_qp), struct cache_qp);
		if (head == NULL)
		{
			pthread_mutex_unlock(&qp_mutex);
			throw new Xapian::InternalError("not enough memory to create cache_qp");
		}
		log_debug("create qp (ADDR:%p)", head);
		head->qp = new Xapian::QueryParser();
		log_debug("new (Xapian::QueryParser *) %p", head->qp);
		head->next = qp_base;
		qp_base = head;
	}
	head->in_use = true;
	pthread_mutex_unlock(&qp_mutex);

	head->qp->clear();
	return head->qp;
}

各位看到这可能还是并没感觉出问题,最大的问题就是 “static”,完全不应该出现在这,由于前面复制代码的时候把全局定义的宣告直接 COPY 过来于是保留了这个  static 关键字。

这还不打紧,后面不是有互斥锁吗?可是多线程调用和调度完全是不可确认的,在锁之外做了 return,在高并发压力下 return 的 head->qp 或许已经不是当年的那个 head 了。。。

于是就出现了内存混乱!!!这问题牵挂了我整整三天,这三天连发三个 xunsearch 版本,实在抱歉啊!!!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>