1. 程式人生 > >#pragma pack引起 stl的map/list在insert時報錯:(Suspended : Signal : SIGSEGV:Segmentation fault)

#pragma pack引起 stl的map/list在insert時報錯:(Suspended : Signal : SIGSEGV:Segmentation fault)


最近接手一個老專案,在老專案中使用了map/list儲存快取資料,如下:

map問題:

#include "conf.h"
int Frame::parse()
{

    std::map<string, int64_t> tmpString;
    tmpString.insert(std::map<string, int64_t>::value_type(string("0000"), 12123323));
    tmpString.insert(std::map<string, int64_t>::value_type(string("1111"), 54678456)); //Crashes here.
    tmpString.insert(std::map<string, int64_t>::value_type(string("2222"), 45654548));
}


結果發現每次在insert第二次時程式core。

 
 

堆疊如下:

Thread [3] 29672 [core: 2] (Suspended : Signal : SIGSEGV:Segmentation fault)	
	std::basic_string<char, std::char_traits<char>, std::allocator<char> >::compare(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const at 0x354669c47d	
	std::operator< <char, std::char_traits<char>, std::allocator<char> >() at basic_string.h:2,317 0x449d91	
	std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::operator() at stl_function.h:230 0x44a46b	
	std::_Rb_tree<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, unsigned long>, std::_Select1st<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, unsigned long> >, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, unsigned long> > >::_M_insert_unique() at stl_tree.h:1,170 0x44ef40	
	std::map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned long, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, unsigned long> > >::insert() at stl_map.h:500 0x44e9f5	
	Frame::parse() at AnySDFrame.cpp:220 0x44df6b	

查找了一上午也沒找到原因。最後在stackoverflow中找到了相同的問題,結果找到了原因。

在“conf.h”檔案中,我定義了一些結構體,並使用了#pragma pack(4)來設定結構體記憶體對齊,如下:

#include <string> 

#pragma pack (4)

typedef struct 
{ 
....
}

原因是:沒有在“conf.h”檔案中沒有用“#pragma pack()”恢復位元組對齊,導致包含“conf.h”檔案的檔案都是以4位元組對齊,這樣可能導致map insert函式報錯。


stackoverflow中也說明了器錯誤的應用標頭檔案,導致了這一問題:

Problem solved.

Thought I'd add it here on the off chance anyone else ever does the same thing.

I slowly removed files in my project to try and find the offending file. I was thinking that it must be something defined in a header file that was causing issues (like a static). It took a long time but I think I've found it. I had a header file that defines a number of structs. These are serialized to the wire so I had them 1 byte aligned using #pragma pack (push) which I put at the top of the file and #pragma pack (pop) at the bottom. But I then added a couple of #include statements after the first #pragma definition meaning that these includes were aligned incorrectly and caused some nondeterministic behavior. Thanks everyone that had a look. Should probably use the attribute syntax and I wouldn't had the problem. Offending code is below for completeness.


例如下程式碼:

#pragma pack (push)
#pragma pack (1)

#include <string> //Wrong place for includes!
#include <Units.h> 

typedef struct 
{ 
....
}
#pragma pack (pop) 

Thanks to everyone who had a look at initial problem.


list問題


conf.h中

#pragma pack(4)
namespace SEND_DATA{
	struct send_1{
	...
	}

 	struct send_2{
 	...
 	}
}
#pragma pack()


record.h中


#include "conf.h"

#pragma pack(4)
namespace RECODE{
	struct a1{
	...
	}

 	struct a2{
 	...
 	}

}

#pragma pack()


using namespace RECODE;
using namespace SEND_DATA;


class record {

public:
  list<c_record>  my_record;
  list<send_1>    my_send;

}


 record.cpp中
 
send_1 s1;
s1.* = *;   //初始化
my_send.push_back()		//報錯

堆疊:

Program terminated with signal 11, Segmentation fault.
#0  0x0000003546663843 in std::_List_node_base::hook(std::_List_node_base*) ()
   from /usr/lib64/libstdc++.so.6
Missing separate debuginfos, use: debuginfo-install cyrus-sasl-lib-2.1.23-13.el6.x86_64 glibc-2.12-1.47.el6.x86_64 keyutils-libs-1.4-3.el6.x86_64 krb5-libs-1.9-22.el6.x86_64 libcom_err-1.41.12-11.el6.x86_64 libcurl-7.19.7-40.el6_6.1.x86_64 libgcc-4.4.6-3.el6.x86_64 libidn-1.18-2.el6.x86_64 libselinux-2.0.94-5.2.el6.x86_64 libssh2-1.4.2-1.el6.x86_64 libstdc++-4.4.6-3.el6.x86_64 nspr-4.10.6-1.el6_5.x86_64 nss-3.16.1-14.el6.x86_64 nss-softokn-freebl-3.14.3-17.el6.x86_64 nss-util-3.16.1-3.el6.x86_64 openldap-2.4.23-20.el6.x86_64 openssl-1.0.1e-16.el6_5.7.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) where
#0  0x0000003546663843 in std::_List_node_base::hook(std::_List_node_base*) ()
   from /usr/lib64/libstdc++.so.6
#1  0x000000000041ace6 in std::list<REWARD::CommonReward, std::allocator<REWARD::CommonReward> >::_M_insert (this=0x7fa8717fab0c, __position=..., __x=...)
    at /usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/bits/stl_list.h:1408
#2  0x000000000041a148 in std::list<REWARD::CommonReward, std::allocator<REWARD::CommonReward> >::push_back (this=0x7fa8717fab0c, __x=...)
    at /usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/bits/stl_list.h:920

解決方法:

record.h中的class record包含在#pragma pack()內,就能執行正常。

原因可能是,雖然conf.h中的struct已經被#pragma pack()設定為4位元組對齊,但是在編譯class record時,也需要設定類的對齊方式。

而my_record沒有報錯,可能是c_record的定義是在相同的record.h檔案中,所以正常吧。這是猜想-_-


哎,所以,使用#pragma pack()需謹慎啊!!!

參考:

http://stackoverflow.com/questions/13153047/memory-corruption-due-to-pragma-pack-error-std-map-corruption-crashing-on-in