【问题标题】:stringstream overflow at 4GB4GB 的字符串流溢出
【发布时间】:2012-08-28 20:11:22
【问题描述】:

我无法超过 4GB 的 stringstream 限制,即使它运行在具有足够内存的 64 位 Linux 机器上。

下面的测试代码(阅读您的 cmets 后修改)核心转储 4GB。

从 gdb 跟踪中,stringstream 使用默认的 std::char_traits,其中 int_type 设置为 32bit int,而不是 64bit size_t。有什么建议可以解决吗?

#include <stdint.h>
#include <iostream>
#include <sstream>
#include <math.h>
using namespace std;

int main(int narg, char** argv)
{
    string str;
    stringstream ss;
    const size_t GB = (size_t)pow(2, 30);

    str.resize(GB, '1');
    cerr << "1GB=" << str.size()
             << ", string::max_size=" << str.max_size()/GB << "GB"
             << ", sizeof(int)=" << sizeof(int)
             << ", sizeof(int64_t)=" << sizeof(int64_t)
             << ", sizeof(size_t)=" << sizeof(size_t)
             << endl;
    string().swap(str);

    str.resize(6*GB, '6');
    cerr << "str.size()=" << (str.size() / GB) << "GB allocated successfully"
            << ", ended with " << str.substr(str.size()-5, 5) << endl;
    string().swap(str);

    str.resize(GB/4, 'Q');
    cerr << "writing to stringstream..." << std::flush;
    for (int i = 0; i < 30; ++i) {
        ss << str << endl;
        cerr << double(ss.str().size())/GB << "GB " << std::flush;
    }
    cerr << endl;
    exit(0);
}

输出是:

1GB=1073741824, string::max_size=4294967295GB, sizeof(int)=4, sizeof(int64_t)=8, sizeof(size_t)=8
str.size()=6GB allocated successfully, ended with 66666
writing to stringstream...0.25GB 0.5GB 0.75GB 1GB 1.25GB 1.5GB 1.75GB 2GB 2.25GB 2.5GB 2.75GB 3GB 3.25GB 3.5GB 3.75GB Segmentation fault (core dumped)

gdb 堆栈跟踪是:

(gdb) where
#0  0x00002aaaaad5e0c1 in std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::overflow(int) () from /usr/lib64/libstdc++.so.6
#1  0x00002aaaaad62cbd in std::basic_streambuf<char, std::char_traits<char> >::xsputn(char const*, long) () from /usr/lib64/libstdc++.so.6
#2  0x00002aaaaad5657d in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) () from /usr/lib64/libstdc++.so.6
#3  0x000000000040112b in main ()

二进制似乎是 64 位的。

$ file a.out
a.out: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped

尼克,检查预处理器输出的好点。不知何故,std::char_straits 覆盖了 __gnu_cxx::char_straits,并将 int_type 重新定义为 int,而不是像 __gnu_cxx::char_straits 中的 unsigned long。这太令人惊讶了!

namespace __gnu_cxx
{
# 61 "/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/char_traits.h" 3
  template <class _CharT>
    struct _Char_types
    {
      typedef unsigned long int_type;
      typedef std::streampos pos_type;
      typedef std::streamoff off_type;
      typedef std::mbstate_t state_type;
    };
# 86 "/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/char_traits.h" 3
  template<typename _CharT>
    struct char_traits
    {
      typedef _CharT char_type;
      typedef typename _Char_types<_CharT>::int_type int_type;
      typedef typename _Char_types<_CharT>::pos_type pos_type;
      typedef typename _Char_types<_CharT>::off_type off_type;
      typedef typename _Char_types<_CharT>::state_type state_type;
              ....
               };

namespace std
{
# 224 "/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/char_traits.h" 3
  template<class _CharT>
    struct char_traits : public __gnu_cxx::char_traits<_CharT>
    { };



  template<>
    struct char_traits<char>
    {
      typedef char char_type;
      typedef int int_type;
      typedef streampos pos_type;
      typedef streamoff off_type;
      typedef mbstate_t state_type;
              ...
              };

编辑:下面来自 STL 网站http://www.cplusplus.com/reference/string/char_traits/,其中 char_traits 专业化使用 int。

typedef INT_T int_type; 
Where INT_T is a type that can represent all the valid characters representable by a    char_type plus an end-of-file value (eof) which is compatible with iostream class member functions.
For char_traits<char> this is int, and for char_traits<wchar_t> this is wint_t 

【问题讨论】:

  • 建议:内置64位模式
  • 我认为你的问题是内存管理。当达到每个应用程序的内存限制时,它可以杀死你的应用程序。
  • 看看 gcc 的实现,它似乎做了一些合理的事情。您是否确认您可以分配大于 4GB 的内存块,例如8GB?在内部,gcc 的字符串缓冲区似乎每次需要增加缓冲区时都会将其缓冲区大小加倍。另外,有点吹毛求疵(这不是你的问题):在代码的末尾应该是delete[] GB,因为你已经分配了一个数组对象。
  • string::reserve(WHAT_YOU_WANT) 和 string::apend(GB) 怎么样?
  • @Ping C,在程序员(相对于硬盘制造商)中,GB 通常定义为2^30 字节,而不是您的10^9。您的程序在 ~3.9581GB 处崩溃,这强烈建议使用 32 位寻址。

标签: c++ stl overflow stringstream


【解决方案1】:

你能发布一个预处理的源文件吗?

删除了对 _Char_types 的引用,因为它具有误导性。

我不确定 int_type 是否相关,char 的特化确实将 int 用于 int_type。

int_type 是一个 typedef,用于保存单个字符(即 ascii 至少一个字节,wchar_t 更高)。它不用于存储一系列字符(参见下面的 std::streamoff)。


根据您的预处理输出,我怀疑 std::streamoff 可能是罪魁祸首。从我系统上的标题中:

# 90 "/usr/include/c++/4.6/bits/postypes.h" 3
  typedef long streamoff;

std::streamoff 在 std::streampos 中使用,如果定义不正确,我认为会导致 stringstream 调用溢出函数。

您是否检查过是否包含正确的标题?

# 61 "/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/char_traits.h" 3

是以下路径:

/usr/include/c++/4.1.2/bits/char_traits.h

-尼克

【讨论】:

  • 是的,路径和流量与您的匹配。 STL std::char_traits 专业化使用 int,如他们的文档中所述,我想这意味着 int 用于寻址内存(如溢出签名中),因此限制为 4GB。我当前的解决方法(将字符串转换为 ostream)是使用 boost::iostreams::filtering_ostream ostream(back_inserter(str))。好奇其他选择...
  • @PingC.:想知道sizeof(size_t) 在 PingC 的程序中是什么。
猜你喜欢
  • 2011-09-05
  • 2011-12-22
  • 2022-11-30
  • 1970-01-01
  • 2014-09-04
  • 2021-07-12
  • 1970-01-01
  • 1970-01-01
  • 2021-01-10
相关资源
最近更新 更多