为什么 std::copy 没有溢出缓冲区;只收到 clang sanitizer 警告“未定义的行为”?

问题描述 投票:0回答:1

我担心代码审查中的 std::copy 行。我在上面喷了消毒剂,确认了气味。我进入调试器,发现副本没有像我预期的那样溢出到结构中的下一个字段,我不明白为什么会出现这种情况。

在下面的程序中,在 std::copy 中,

8
旨在表示 8 个元素(long 类型);但是,
src.arr[0]
的类型是
pointer to long[4]
。因此,我预计
8
会尝试复制 8 个 long[4] 项,从而溢出
arr
之后的数组;即
overflowArray
字段。但在我的测试中,它没有,并且在审查的程序中它也可以正常工作而不会溢出。


#include <cstdlib>
#include <iostream>
#include <numeric>
#include <cstring>

struct Astruct
{
    long arr[2][4];
    long overflowArray[8];
};

void printAstruct(Astruct str)
{
    std::cout << "arr: ";
    for( size_t i = 0; i < 2; ++i)
    {
        for( size_t j = 0; j < 4; ++j)
        {
            std::cout << str.arr[i][j] << " ";
        }
    }
    std::cout << ";  overflowArray: ";
    for( size_t k = 0; k < 8; ++k)
    {
        std::cout << str.overflowArray[k] << " ";
    }
    std::cout << std::endl;
}

void fillArray(Astruct& );

int main()
{
    Astruct src{};
    Astruct dst{};

    std::cout << "src size: " << sizeof(src.arr) << "; dst size:" << sizeof(src.overflowArray) << std::endl;
    // SETUP
    std::cout << "dst before copy" << std::endl;
    printAstruct(dst);
    long* srcStart = &src.arr[0][0];
    memset(srcStart, 0xFF, sizeof(src.arr));

    std::cout << "src:" << std::endl;
    printAstruct(src);
    
    // the Smell: src.arr[0] is type: array of 4 longs:
    std::copy(src.arr[0], src.arr[0] + 8, dst.arr[0]); // <--  Undefined Behavior

    std::cout << "\ndst after copy:" << std::endl;
    printAstruct(dst);
}

输出:

src size: 32; dst size:32
dst before copy
arr: 0 0 0 0 0 0 0 0 ;  overflowArray: 0 0 0 0 0 0 0 0 
src:
arr: -1 -1 -1 -1 -1 -1 -1 -1 ;  overflowArray: 0 0 0 0 0 0 0 0 

dst after copy:
arr: -1 -1 -1 -1 -1 -1 -1 -1 ;  overflowArray: 0 0 0 0 0 0 0 0  <-- I expected these 0's to be overwritten

看来我看到的

smell
是正确的,经clang sanitizer确认,但我不明白为什么没有发生溢出,因为
8
应该将结束地址提前超过8个
long

用消毒剂叮当响并确认气味:

runtime error: index 8 out of bounds for type 'long[4]'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior

为什么overflowArray没有被覆盖?它可以在另一个平台和/或编译器中被覆盖吗?

我将代码更改为:

std::copy(&src.arr[0][0], &src.arr[0][0] + 8, &dst.arr[0][0]); 

因为

&src.arr[0][0]
pointer to long
。 但被告知这太混乱了,而且原始地址和我的更改中的地址都是相同的。

c++ multidimensional-array c++17 clang address-sanitizer
1个回答
0
投票

这一行:

memset(srcStart, 0xFF, sizeof(src.arr));

仅将

src.arr
设置为0xFF模式,
src.overflow
保持为0。将其更改为:

memset(srcStart, 0xFF, sizeof(src));

您会看到整个

dst
被覆盖。

© www.soinside.com 2019 - 2024. All rights reserved.