關於#pragma pack(n)引發的一系列問題

[前提]
最近在寫新系統代碼的時候, 因爲引用了一個包含了如下內容的頭文件, 導致系統core的莫名奇妙, core在了打log的時候, std::string的析構上, 代碼如下:

... ...
#pragma pack(1)

strcut XXX {
... ...
}

#pragma

所有包含了這一頭文件的cpp中的類, 打log即掛(後面實驗, 要core可以很多種辦法).
後來發現是因爲我編譯加了 -O2, 不加的話不會掛.
這裏請注意, #pragma pack(1)並沒有以#pragma pack()結束.


[原因分析]
GDB檢查了一下core的原因, 是因爲std::string在#pragma後面, 而上面那個寫法比較坑, 並沒有以#pragma pack()結束, 導致後面的string全部都按1字節對齊, 會導致一些計算長度上的誤差, 在-O2編譯的時候, 會出現一系列的 malloc/free 錯誤.
這裏貼上core信息:

0x00000000006224c9 in __gnu_cxx::__exchange_and_add (__val=-1, __mem=0xb1491800007ff7) at /usr/include/c++/4.9/ext/atomicity.h:49
49    { return __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL); }
(gdb) bt
#0  0x00000000006224c9 in __gnu_cxx::__exchange_and_add (__val=-1, __mem=0xb1491800007ff7) at /usr/include/c++/4.9/ext/atomicity.h:49
#1  __gnu_cxx::__exchange_and_add_dispatch (__val=-1, __mem=0xb1491800007ff7) at /usr/include/c++/4.9/ext/atomicity.h:82
#2  std::string::_Rep::_M_dispose (__a=..., this=0xb1491800007fe7) at /usr/include/c++/4.9/bits/basic_string.h:246
#3  std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string (this=0x7fffffffcd4c, __in_chrg=<optimized out>) at /usr/include/c++/4.9/bits/basic_string.h:546
#4  log::LogRecord::~LogRecord (this=0x7fffffffcd20, __in_chrg=<optimized out>) at ....../LogRecord.h:27
#5  pb_monitor::Init (this=this@entry=0x7fffffffd580, config=...) at ....../pb_monitor.cpp:17
#6  0x0000000000577443 in main (argc=<optimized out>, argv=<optimized out>) at ....../main.cpp:9

一開始看得我很是奇怪, 後來直到我在網上看到了這個人的經歷, 我才意識到可能是同樣的原因, 簡直太坑了.
http://blog.csdn.net/superarhow/article/details/30063331

#pragma pack(n)
千萬不要寫一半, 不然真的太危險了.
https://baike.baidu.com/item/%23pragma%20pack

C++11標準下,可以換種寫法,可以考慮這麼寫,屏蔽編譯器和平臺差異:
http://en.cppreference.com/w/cpp/language/alignas


[樣例]
可以自己寫個小程序復現一下便知:

test.h

#ifndef TEST_H_
#define TEST_H_

#pragma pack(1)

#endif /* TEST_H_ */

test.cc

#include "test.h"
#include <iostream>
#include <string>

using namespace std;

int main() {
  std::string name("1234567890.txt");
  std::string::size_type pos = name.rfind(".");
  std::string filename = name.substr(0, pos);
  cout<< filename << endl;
  return 0;
}

g++ -o test -O2 ./test.cc


ALLEN.L.R
2017/09/05

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章