memcpy()更改不应触摸的内存

memcpy()更改不应触摸的内存,c,arrays,pointers,memcpy,C,Arrays,Pointers,Memcpy,在我的代码中,我对堆指针int*移位使用数组寻址来将值保存到此数组中。当我使用memcpy在堆区域之间复制数据时,数组移位[y]的内容会改变,即使我看不到缓冲区溢出的可能性。当s->start设置为568时,该问题已经在for循环的第一轮中发生 代码片段是FFmpeg库的一部分。 av_malloc和av_log是malloc和printf上的包装器 我试图输出内存地址,希望找出问题的原因。请原谅可读性差,因为在每一步之后都要打印代码来演示值 typedef struct LineShiftCo

在我的代码中,我对堆指针int*移位使用数组寻址来将值保存到此数组中。当我使用memcpy在堆区域之间复制数据时,数组移位[y]的内容会改变,即使我看不到缓冲区溢出的可能性。当s->start设置为568时,该问题已经在for循环的第一轮中发生

代码片段是FFmpeg库的一部分。 av_malloc和av_log是malloc和printf上的包装器

我试图输出内存地址,希望找出问题的原因。请原谅可读性差,因为在每一步之后都要打印代码来演示值

typedef struct LineShiftContext {
    const AVClass *class;
    /* Command line options: */
    int lines, start;
    /* Internal: */
    int nb_planes;
    int planewidth[4];
    int planeheight[4];
    void *filler[4];
    int *shifts;

    void (*recoverlineshifts)(struct LineShiftContext *s, AVFrame *frame);
} LineShiftContext;
////////////////
    for (int p = 0; p < s->nb_planes; p++) {
        s->filler[p] = av_malloc(s->planewidth[p] * (depth <= 8 ? sizeof(uint8_t) : sizeof(uint16_t)));
        av_log(NULL, AV_LOG_ERROR, "s->planewidth[%d]: %d, s->filler[%d]: %p\n", p, s->planewidth[p], p, s->filler[p]);
    }
    s->shifts = av_malloc(s->planeheight[0]);
    av_log(NULL, AV_LOG_ERROR, "s->planeheight[0]: %d, s->shifts:   %p\n", s->planeheight[0], s->shifts);
////////////////
static void recoverlineshifts(LineShiftContext *s, AVFrame *frame)
{
    uint8_t *data = frame->data[0];
    int16_t lz = frame->linesize[0];
    int width = s->planewidth[0];
    int height = s->planeheight[0];
    int increment = s->lines >= 0 ? 1 : -1; // if negative, run upwards
    uint8_t *temp = (uint8_t *)s->filler[0];
    int *shifts = s->shifts;
    memset(shifts, 0, height);

    for (int y = s->start, shift_old = 0; y != s->start + s->lines; y += increment) {
        shifts[y] = calculate_shift(s, data + (y - increment) * lz, shift_old, width, data + y * lz);

        av_log(NULL, AV_LOG_ERROR, "temp:   %p, line:      %p, lineref: %p, lz: %d, y: %d, yref: %d, shifts: %p, shifts[y]: %d\n",
                temp, data + y * lz, data + (y - increment) * lz, lz, y, y - increment, shifts, shifts[y]);
        av_log(NULL, AV_LOG_ERROR, "temp++: %p, line++:    %p, width: %d\n",
                temp + FFMAX(0, -shifts[y]), data + y * lz + FFMAX(0, shifts[y]), width - abs(shifts[y]));
        av_log(NULL, AV_LOG_ERROR, "shifts: %p, y: %d, shifts[y]: %d, -shifts[y]: %d, FFMAX(0, -shifts[y]): %d\n",
                shifts, y, shifts[y], -shifts[y], FFMAX(0, -shifts[y]));
        memcpy(temp + FFMAX(0, -shifts[y]), data + y * lz + FFMAX(0, shifts[y]), width - abs(shifts[y]));
        av_log(NULL, AV_LOG_ERROR, "shifts: %p, y: %d, shifts[y]: %d, -shifts[y]: %d, FFMAX(0, -shifts[y]): %d\n",
                shifts, y, shifts[y], -shifts[y], FFMAX(0, -shifts[y]));
        ////////////
    }
}
////////////////
    for (int p = 0; p < s->nb_planes; p++)
        av_freep(&s->filler[p]);
    av_freep(&s->shifts);
最后一行的预期值为:

shifts: 0x55f36e0251c0, y: 568, shifts[y]: -12, -shifts[y]: 12, FFMAX(0, -shifts[y]): 12
在for循环的后面部分,我有:

            av_log(NULL, AV_LOG_ERROR, "temp  : %p, lineref:   %p, width: %d\n", temp, data + (y - increment) * lz, FFMAX(0, -shifts[y]));
            memcpy(temp, data + (y - increment) * lz,
                    FFMAX(0, -shifts[y])); // fill left gap from reference line
            av_log(NULL, AV_LOG_ERROR, "temp++: %p, lineref++: %p, width: %d\n", temp + width - FFMAX(0, shifts[y]), data + (y - increment) * lz + width - FFMAX(0, shifts[y]), FFMAX(0, shifts[y]));
            memcpy(temp + width - FFMAX(0, shifts[y]), data + (y - increment) * lz + width - FFMAX(0, shifts[y]),
                    FFMAX(0, shifts[y])); // fill right gap from reference line
            av_log(NULL, AV_LOG_ERROR, "line:   %p, temp:      %p, width: %d\n", data + y * lz, temp, width);
            memcpy(data + y * lz, temp, width);
即使指针也超出范围:

temp  : 0x55f36e025940, lineref:   0x7f8f0e06a780, width: 0
temp++: 0x55f365fb54f9, lineref++: 0x7f8f05ffa339, width: 134678279
。。。这最终会导致内存访问错误。

这里的问题是移位分配不足和初始化不足。如果班次为:

其分配和初始化为:

s->shifts = av_malloc(s->planeheight[0]);

int height = s->planeheight[0];
int *shifts = s->shifts;
memset(shifts, 0, height);
每一个都缺少一个sizeofint的乘法。应该是:

s->shifts = av_malloc(s->planeheight[0] * sizeof(int));

int *shifts = s->shifts;
memset(shifts, 0, height * sizeof(int));

s->filler[p]如果p大于3,或者在FFMAX0,-shift[y]中相同,则会出现问题。我怀疑其中一个地方就是你的问题所在。除此之外,您可以放心,鉴于memcpy更改了不应触摸的内存这一主张,这不是memcpy的错……s->nb_平面在哪里设置?@DavidC.Rankin s->nb_平面是在读取图像文件时从FFmpeg程序设置的。在我的例子中,它被设置为3,在我的代码中,我只使用平面0。我没有认真研究你的程序,所以我不知道,但请确保你没有使用memcpy来处理重叠的范围。如果范围重叠,则需要使用memmove。memcpy针对高速进行了优化,不进行任何检查。您确定在av_mallocing和memseting shift时,它不应该是planeheight[0]*sizeofint?另一种可能是:height*sizeof*shift。这样做的好处是,不可能输入错误,如果将移位类型更改为例如*int16\t,代码仍然正确。
s->shifts = av_malloc(s->planeheight[0]);

int height = s->planeheight[0];
int *shifts = s->shifts;
memset(shifts, 0, height);
s->shifts = av_malloc(s->planeheight[0] * sizeof(int));

int *shifts = s->shifts;
memset(shifts, 0, height * sizeof(int));