使用stringstream :: imbue和自定义全局运算符newdebugging断言失败

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

我相信我遇到了Visual C ++运行时库或Microsoft std::stringstream实现中的一个bug。 这个问题只performance在以下几个方面:

  1. 调用imbue()来更改stringstream的语言环境
  2. 使用自定义全局operator new ,它返回由用于分配块的malloc()返回的基地址的指针偏移量。

我已经能够重现这与以下最小的testing用例:

 #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. ptr += 64;localMalloc()
  2. ss.imbue()ss.imbue()调用

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

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

请注意,为简洁起见, operator delete是故意忽略此testing用例中的空闲。 如果在内存块上正确调用了free()则没有区别。

到目前为止,在以下编译器和平台上进行testing的结果是:

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

有人在这里看到什么奇怪的,我错过了?

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

从这个参考文献( 全球替代品 ) ,当这种情况发生时,行为被说成是未定义的。

从C ++ ISO标准:

3.7.4动态存储时间[basic.stc.dynamic]
// …

§2库提供了全局分配和释放函数的默认定义。 一些全球分配和释放功能是可以替换的(18.6.1)。 C ++程序至多应该提供一个可替换的分配或释放函数的定义。


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

Visual Studio 2015在线编译器结果。