【问题标题】:how to avoid buffer overflow with ostrstream如何使用 ostrstream 避免缓冲区溢出
【发布时间】:2015-09-22 09:20:57
【问题描述】:

我有一个代码,我在 vxworks 机器中编译和加载它,我看到缓冲区溢出。

#include<strstream>
#include<iostream>
#include<sstream>

using namespace std;

ostrstream *strm = 0;

int newcout()
{
  if(strm == 0)
  {
    strm = new ostrstream();
  }

  while(1)
  {

   (*strm)<<".VXworks_print"<<endl;

  }
return 0;
}

这里的问题是,while 中的每个循环,内存请求都会不断翻倍。

[maxBlock = 8497968/ allocSize = 12700]

[maxBlock = 8485176/ allocSize = 25500]

[maxBlock = 8459584/ allocSize = 51100]

[maxBlock = 8408392/ allocSize = 102300]

[maxBlock = 8306000/ allocSize = 204700]

[maxBlock = 8101208/ allocSize = 409500]

[maxBlock = 7691616/ allocSize = 819100]

[maxBlock = 7086744/ allocSize = 1638300]

[maxBlock = 7086744/ allocSize = 3276700]

[maxBlock = 7086744/ allocSize = 6553500]

[maxBlock = 8497288/ allocSize = 13107100]

当分配请求超过最大可用块时,会导致陷阱。

我认为我们看到这种行为是因为重用了 ostrstream 对象。

如何纠正这种行为?

【问题讨论】:

  • ostrstream 已被弃用,不应编写使用它的新代码(您应该改用std::ostringstream
  • 此外,endl 运算符不仅仅是“行尾”——它还进行了 flush() 调用。我强烈建议您将其替换为 '\n' 并在循环外调用 flush()。

标签: c++ overflow vxworks sstream


【解决方案1】:

根据文档,您的 ostrstream 将继续为每个调用分配内存。这个内存永远不会被释放。为避免这种情况,请将 ostream 声明为本地对象(在堆栈中),并在完成后(在每个 str() 之后)调用 freeze(false),这样在调用 ostream 的析构函数时会释放内存。

来自:http://en.cppreference.com/w/cpp/io/ostrstream/freeze

调用 str() 后,动态流会自动冻结。在退出创建此 ostrstream 对象的范围之前,需要调用 freeze(false)。否则析构函数会泄漏内存。此外,一旦冻结流的附加输出到达分配缓冲区的末尾,它可能会被截断。

【讨论】:

  • 甚至 str() & freeze(false) 都不能解决问题!!尝试将 ostrstream 对象保持为本地对象,但效果不佳。
【解决方案2】:

正如其他人在 cmets 中已经说过的那样,不推荐使用 ostrstream。

此外,这是 c++ 而不是 java,您不应该使用 new 来分配资源。

只需在堆栈上声明对象即可。

ostrstream strm;

你可以考虑忘记 c++ 流的东西,它的语法和外观相当笨拙。就我个人而言,我更喜欢旧的 printf,即使它不是类型安全的 - 它只是更紧凑。

【讨论】:

  • 您的最后一个建议无疑是不好。不要这样做。不推荐这个。如果您不喜欢 C++ 流式语法,请改用适当的格式库。不要使用printf。它不仅类型不安全,而且根本不可扩展,在正确编写的 C++ 代码中变得毫无用处。
  • 没有什么是无可争辩的。编程不是一门科学,而是一门手艺。在这种情况下,必须在可读性、可维护性和类型安全之间做出选择。 printf 本质上并不比不可读的无尽流链更糟糕。你所说的可扩展到底是什么意思?
  • 每个重要的 C++ 程序都包含非内置类型,您迟早需要进行漂亮打印。 printf 无法处理,句号。 C++ 流(和其他格式库)可以。
  • 是的,但谁会将自定义类型传递给 printf ?漂亮打印的解决方案是在您的自定义类型中有一个 toString() 方法。
  • “谁会通过……”——没有人,因为它不起作用。 这就是问题。你的“解决方案”很糟糕。这不是一个好的解决方案。这并不可怕,但根本没有一个技术论据为什么它会更好,甚至可以与使用适当的 C++ 机制相提并论。一方面,它不组合:尝试输出一个对象向量。使用 C++ 流(或等价物),您可以执行 for_each(begin(vec), end(vec), ostream_iterator(…))。不过,这里的重点不是这个函数的存在,而是可组合性的一般原则,printf 严重支持。
猜你喜欢
  • 2021-01-29
  • 1970-01-01
  • 2021-09-19
  • 1970-01-01
  • 1970-01-01
  • 2018-07-26
  • 2020-01-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多