我对这个相当本地化的问题表示歉意,但是我希望得到别人的看法,以确保我没有做出明显错误的事情。
我相信我遇到了Visual C ++运行时库或Microsoft std::stringstream
实现中的一个bug。 这个问题只performance在以下几个方面:
imbue()
来更改stringstream
的语言环境 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; }
如果:
ptr += 64;
在localMalloc()
或 ss.imbue()
的ss.imbue()
调用 被注释掉,代码按预期工作,断言不会发生。
我试图尽可能多地使用debugging器进入代码,但是我目前无法确定STL代码失败的位置,因为Visual Studio在逐出basic_stringbuf::overflow()
后将其转储到原始反汇编模式basic_stringbuf::overflow()
使debugging几乎不可能。 据我所知,我没有看到在被分配的内存之外有任何无效的内存写入,所以我不完全确定CRT在检查堆的位置,或者为什么它认为指针是无效的。
请注意,为简洁起见, operator delete
是故意忽略此testing用例中的空闲。 如果在内存块上正确调用了free()
则没有区别。
到目前为止,在以下编译器和平台上进行testing的结果是:
有人在这里看到什么奇怪的,我错过了?
这很可能不是一个错误,而是您的版本的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在线编译器结果。