c++ - 使用 stringstream::imbue 和自定义全局运算符 new 调试断言失败

标签 c++ windows assert stringstream

对于这个相当本地化的问题,我深表歉意,但我希望得到其他人的看法,以确保我没有做明显错误的事情。

我相信我在 Visual C++ 运行时库或 Microsoft 的 std::stringstream 实现中的某处遇到了错误。该问题仅在以下情况下出现:

  1. imbue() 被调用以更改 stringstream 上的语言环境,并且
  2. 使用了一个自定义的全局operator new,它返回一个指针偏移量,该指针与用于分配 block 的malloc() 返回的基址相距。

我已经能够使用以下最小测试用例重现此内容:

#include <sstream>

static void *localMalloc(size_t bytes)
{
    unsigned char *ptr = static_cast<unsigned char *>( malloc(bytes + 64) );
    ptr += 64;
    printf("malloc of %d bytes: %ph\n", bytes, ptr);
    return ptr;
}

void *operator new(size_t bytes) { return localMalloc(bytes); }
void *operator new[](size_t bytes) { return localMalloc(bytes); }
void operator delete(void *ptr) throw() { /* do nothing */ }
void operator delete[](void *ptr) throw() { /* do nothing */ }

struct DecimalSeparator : std::numpunct<char>
{
    char do_decimal_point() const
    {
        return '.';
    }
};

int main()
{
    std::stringstream ss;
    ss.imbue(std::locale(std::locale(), new DecimalSeparator));
    ss << 5;  // <-- is_block_type_valid(header->_block_use) assertion failure here
    return 0;
}

如果是:

  1. localMalloc()
  2. 中的 ptr += 64;
  3. main()中的ss.imbue()调用

被注释掉,代码按预期工作,断言没有发生。

我已尝试尽可能多地使用调试器进入代码,但我目前无法查明代码在 STL 中失败的位置,因为 Visual Studio 在退出后将我转储到原始反汇编模式basic_stringbuf::overflow() 使得调试几乎不可能。据我所知,我没有在分配的内存之外看到任何无效的内存写入,所以我不完全确定 CRT 正在检查堆的位置或者它认为指针无效的原因。

请注意,为简洁起见,operator delete 有意忽略了此测试用例中的 free。 free() 是否在内存块上被正确调用都没有关系。

到目前为止,在以下编译器和平台上的测试结果:

  1. VS2015 更新 2:失败
  2. VS2015 更新 3:失败
  3. VS2015 更新 3 + KB3165756:失败
  4. OSX 上的 clang-703.0.31:OK

有没有人看到我错过的任何奇怪的地方?

最佳答案

这很可能不是错误,而是您的 delete 版本没有被调用,而是 Visual Studio 的调试运行时库版本的全局 delete叫做。在同一程序中使用两个或多个版本的全局 delete 运算符是未定义的行为。

来自 this reference (Global replacements) ,当发生这种情况时,行为被声明为未定义。

来自 C++ ISO 标准:

3.7.4 Dynamic storage duration [basic.stc.dynamic]
//...

§2 The library provides default definitions for the global allocation and deallocation functions. Some global allocation and deallocation functions are replaceable (18.6.1). A C++ program shall provide at most one definition of a replaceable allocation or deallocation function.


使用发行版 Visual Studio 运行时库与 Visual Studio 2015 一起运行不会产生此错误,并且替换全局 delete 实际上会被调用。

Visual Studio 2015 online compiler results.

关于c++ - 使用 stringstream::imbue 和自定义全局运算符 new 调试断言失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38609960/

相关文章:

c++ - 在 C++ 中是否有 C# 中的关键字 "where"的类似物?

c++ - 将集合插入/读取到 map 中

c++ - 从 0 数到 99

c++ - 如何连接两个程序(c++、qt)

windows - 如何检查Windows中的vbs脚本是否正在运行?

unit-testing - 如何获得可以抛出我正在使用 XCTAssertNoThrow(...) 测试的函数的返回值

c++ - 如何将结构传递给函数?

为 Windows(64 位)编译 SQLite

android - 我可以在 Android 设备上使用断言吗?

c++ - assert() 是否充当 Release模式下的身份函数?