記錄一次關於Segment Fault的愚蠢錯誤

背景

在公司項目裏寫了個類,裏面簡單的流程就是,先讀取下本機名字和IP,然後創建一個線程,差不多就是下面代碼裏的樣子

class A
{
public:
	void start()
	{
		// Get Hostname
		char tmp_hostname[256];
		gethostname(tmp_hostname, sizeof(tmp_hostname));
		hostname = tmp_hostname;
		
		// Get ip
		hostent *host = gethostbyname(hostname.c_str());
		ip = inet_ntoa(*(struct in_addr*)*host->h_addr_list);
	
		// 注意這句話
		pthread_create(pthread_create(reinterpret_cast<pthread_t *>(&thread_id), NULL, service_func, (void *)this);
	}

	void* server_func(void* args)
	{
		// service loop
		while (1)
		{}
		return NULL;
	}
private:
	int thread_id;
	string hostname;
	string ip;
};

然後這段代碼出現了segment fault,打印堆棧發現是hostname出了問題,當時查了半天沒查出來,因爲是在項目裏面,當時機子跑了別的任務,24核跑滿了,編譯起來特別慢,有些卡,就換了個機子把這段代碼單獨拿出來跑,結果怎麼跑都沒出現同樣的問題,就很奇怪,誒,怎麼同一段代碼,放在別的機子上就好了呢。。。

最後沒辦法換了種寫法,代碼就好了,當時覺得是玄學。。。

發現問題

過了幾天,在thread_id下面加了別的變量,寫了點新東西,大概就是下面這個樣子

class A
{
public:
	...
private:
	int thread_id;
	char peer_ip[20];
};

然後這次發現,每次打印peer_ip總是不對,但是只要在peer_ip下面隨便再搞個變量去用,就沒有問題,這次結合上次的問題,突然發現。。。上次段錯誤好像是因爲有地方把string的東西給改掉了,這次是有地方把peer_ip給改掉了,唯一有可能改掉的地方就是用thread_id的地方,因爲peer_ip我都是正常操作的。

查找thread_id修改的唯一的地方,就是pthread_create的地方,打印peer_ip的每個字節,發現peer_ip的前四個字節被改掉了。4+4就是8個字節。

問題所在

看下pthread_t是個unsigned long,然後突然反應過來,我項目運行的機器是裝的64位的Debian,但是我的另一臺沒問題的機器是32位ubuntu,呃,突然發現問題覺得自己很蠢:

  • 32位下的unsigned long是4字節的,所以用int給pthread_t用沒有任何問題
  • 64位下的unsigned long是8字節的,所以用int給pthread_t用少了4字節。。

以上導致了segment fault,我太蠢了,所以同一段代碼,這臺沒問題,另一臺有問題。

總結

傳參數的時候,不,是所有涉及到類型不一致的時候,除非確定沒問題,否則類型要對應,不能瞎強轉。

寫一篇博客記錄這個愚蠢的問題,博君一笑~

發佈了90 篇原創文章 · 獲贊 97 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章