调试断言失败与字符串流::灌输和自定义全局运算符新
Debug assertion failure with stringstream::imbue and custom global operator new
对于这个相当本地化的问题,我深表歉意,但我希望得到其他人的看法,以确保我没有做明显错误的事情。
我相信我在可视化C++运行时库中或Microsoft的std::stringstream
实现中的某个地方遇到了错误。 该问题仅在以下情况下表现出来:
- 调用
imbue()
来更改stringstream
上的语言环境,并且 - 使用自定义全局
operator new
,该返回指针偏移量,该指针偏移量与用于分配块的基址返回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: %phn", 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()
呼唤main()
被注释掉,代码按预期工作,断言不会发生。
我尝试尽可能多地使用调试器单步执行代码,但我目前无法确定代码在 STL 中失败的位置,因为 Visual Studio 在退出 basic_stringbuf::overflow()
后将我转储到原始反汇编模式,使调试几乎不可能。 据我所知,我没有看到任何在分配的内存之外进行无效的内存写入,所以我不完全确定 CRT 正在检查堆的位置或为什么它认为指针无效。
请注意,为了简洁起见,operator delete
故意忽略此测试用例中的 free。 是否在内存块上正确调用free()
没有区别。
到目前为止,对以下编译器和平台的测试已产生:
- VS2015 更新 2:失败
- VS2015 更新 3:失败
- VS2015 更新 3 + KB3165756:失败
- OSX 上的 clang-703.0.31:正常
有没有人在这里看到我错过的奇怪之处?
这很可能不是错误,而是没有调用delete
版本,而是调用了 Visual Studio 的调试运行时库的全局delete
版本。 在同一程序中具有两个或多个版本的全局delete
运算符是未定义的行为。
根据此引用(全局替换(,发生这种情况时,行为被声明为未定义。
从C++ ISO 标准:
3.7.4 动态存储时长
//...§2 库为全局分配提供默认定义 和释放功能。一些全局分配和解除分配 函数是可替换的 (18.6.1(。C++计划应提供 可替换分配或取消分配的大多数定义 功能。
使用发布版本 Visual Studio 运行时库运行 Visual Studio 2015 不会产生此错误,并且实际上会调用替换全局delete
。
Visual Studio 2015 联机编译器结果。
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 如何将点击的信号和插槽添加到qt中的自定义按钮中
- C++自定义比较函数
- 如何比较自定义类的std::变体
- std::设置自定义比较器
- 如何正确实现和访问运算符的各种自定义枚举器
- flutter:即使shouldRepaint()返回true,自定义画家也不会重新绘制
- 自定义先决条件对移动分配运算符有效吗
- 使用VS Code和CMake Tools运行自定义命令
- 如何创建从Maya(或类似程序)到虚幻引擎的自定义数据导出插件
- std::ranges::elements_view,用于自定义类似元组的数据
- 跟随整数索引列表的自定义类迭代器
- 参数化自定义CMake工具链
- 使用自定义比较函数使用std::sort()对矢量字符串进行排序时出现问题
- C++自定义全局新建/删除覆盖系统库
- 将全局新与自定义内存管理器结合使用
- 具有自定义返回类型的全局命名空间中的友元函数
- 为什么 Boost 使用全局函数覆盖来实现自定义验证程序"Program Options"
- 调试断言失败与字符串流::灌输和自定义全局运算符新
- 捕捉全局鼠标滚动,并向应用程序发送自定义鼠标滚动事件