使用stringstream :: imbue和自定义全局运算符new

时间:2016-07-27 10:09:51

标签: c++ windows assert stringstream

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

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

    调用
  1. imbue()来更改stringstream
  2. 上的区域设置
  3. 使用自定义全局operator new,其中返回指针偏移量,该指针偏离用于分配块的malloc()返回的基址。
  4. 我已经能够使用以下最小测试用例重现这一点:

    #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;
    2. 中的localMalloc()
    3. ss.imbue()
    4. 中的main()来电

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

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

      请注意,operator delete在此测试用例中故意忽略free以简化。如果在内存块上正确调用free(),则没有区别。

      到目前为止,对以下编译器和平台的测试已导致:

      1. VS2015更新2:失败
      2. VS2015更新3:失败
      3. VS2015 Update 3 + KB3165756:失败
      4. OSX上的
      5. clang-703.0.31:确定
      6. 有没有人在这里看到我错过的任何奇怪的东西?

1 个答案:

答案 0 :(得分:1)

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

this reference (Global replacements)开始,当发生这种情况时,表明行为是未定义的。

来自C ++ ISO标准:

  

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

     

§2该库提供全局分配的默认定义   和释放功能。一些全局分配和解除分配   功能是可替换的(18.6.1)。 C ++程序应提供at   可替换分配或释放的大多数定义   功能

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

Visual Studio 2015 online compiler results.