使用 stringstream::imbue 和自定义全局运算符 new 调试断言失败
Debug assertion failure with stringstream::imbue and custom global operator new
对于这个相当本地化的问题,我深表歉意,但我希望得到其他人的看法,以确保我没有做明显错误的事情。
我相信我 运行 遇到了 Visual C++ 运行时库或 Microsoft 的 std::stringstream
实现中某处的错误。该问题仅通过 when:
的组合表现出来
imbue()
被调用以更改 stringstream
上的语言环境,
- 使用自定义全局
operator new
,其中 returns 与 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;
}
如果是:
localMalloc()
或 中的 ptr += 64;
行
ss.imbue()
调用 main()
被注释掉,代码按预期工作,断言没有发生。
我已尝试尽可能多地使用调试器进入代码,但我目前无法查明代码在 STL 中失败的位置,因为 Visual Studio 将我转储为 raw退出 basic_stringbuf::overflow()
后的反汇编模式使得调试几乎不可能。据我所知,在分配的内存之外我没有看到任何无效的内存写入,所以我不完全确定 CRT 正在检查堆的位置或者为什么它认为指针无效。
请注意,为了简洁起见,operator delete
有意忽略了此测试用例中的 free。 free()
是否在内存块上正确调用没有区别。
到目前为止,在以下编译器和平台上的测试结果为:
- VS2015 更新 2:失败
- VS2015 更新 3:失败
- VS2015 更新 3 + KB3165756:失败
- 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 2015 使用发布版本 Visual Studio 运行时库不会产生此错误,替换全局 delete
实际上会被调用。
对于这个相当本地化的问题,我深表歉意,但我希望得到其他人的看法,以确保我没有做明显错误的事情。
我相信我 运行 遇到了 Visual C++ 运行时库或 Microsoft 的 std::stringstream
实现中某处的错误。该问题仅通过 when:
imbue()
被调用以更改stringstream
上的语言环境,- 使用自定义全局
operator new
,其中 returns 与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;
}
如果是:
localMalloc()
或 中的 ss.imbue()
调用main()
ptr += 64;
行
被注释掉,代码按预期工作,断言没有发生。
我已尝试尽可能多地使用调试器进入代码,但我目前无法查明代码在 STL 中失败的位置,因为 Visual Studio 将我转储为 raw退出 basic_stringbuf::overflow()
后的反汇编模式使得调试几乎不可能。据我所知,在分配的内存之外我没有看到任何无效的内存写入,所以我不完全确定 CRT 正在检查堆的位置或者为什么它认为指针无效。
请注意,为了简洁起见,operator delete
有意忽略了此测试用例中的 free。 free()
是否在内存块上正确调用没有区别。
到目前为止,在以下编译器和平台上的测试结果为:
- VS2015 更新 2:失败
- VS2015 更新 3:失败
- VS2015 更新 3 + KB3165756:失败
- 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 2015 使用发布版本 Visual Studio 运行时库不会产生此错误,替换全局 delete
实际上会被调用。