memcpy() 改变不应该被触及的内存
memcpy() changes memory which should not be touched
在我的代码中,我使用堆指针上的数组寻址 int *shifts
将值保存到该数组中。当我使用memcpy()
在堆区之间复制数据时,数组shifts[y]
的内容被改变了,即使我没有看到缓冲区溢出的可能性。该问题已在 for
循环的第一轮中发生,s->start
设置为 568
。
代码片段是 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);
结果:
s->planewidth[0]: 704, s->filler[0]: 0x55f36e025940
s->planewidth[1]: 352, s->filler[1]: 0x55f36e025c80
s->planewidth[2]: 352, s->filler[2]: 0x55f36e024a80
s->planeheight[0]: 576, s->shifts: 0x55f36e0251c0
temp: 0x55f36e025940, line: 0x7f8f0e06aa40, lineref: 0x7f8f0e06a780, lz: 704, y: 568, yref: 567, shifts: 0x55f36e0251c0, shifts[y]: -12
temp++: 0x55f36e02594c, line++: 0x7f8f0e06aa40, width: 692
shifts: 0x55f36e0251c0, y: 568, shifts[y]: -12, -shifts[y]: 12, FFMAX(0, -shifts[y]): 12
shifts: 0x55f36e0251c0, y: 568, shifts[y]: 134678279, -shifts[y]: -134678279, FFMAX(0, -shifts[y]): 0
预计(最后一行):
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
...最终导致内存访问错误。
这里的问题是 shifts
正在 under-allocated 和 under-initialized。 if shifts
的定义是:
int *shifts;
它的分配和初始化是:
s->shifts = av_malloc(s->planeheight[0]);
int height = s->planeheight[0];
int *shifts = s->shifts;
memset(shifts, 0, height);
其中每一个都缺少 sizeof(int)
的乘积。应该是:
s->shifts = av_malloc(s->planeheight[0] * sizeof(int));
int *shifts = s->shifts;
memset(shifts, 0, height * sizeof(int));
在我的代码中,我使用堆指针上的数组寻址 int *shifts
将值保存到该数组中。当我使用memcpy()
在堆区之间复制数据时,数组shifts[y]
的内容被改变了,即使我没有看到缓冲区溢出的可能性。该问题已在 for
循环的第一轮中发生,s->start
设置为 568
。
代码片段是 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);
结果:
s->planewidth[0]: 704, s->filler[0]: 0x55f36e025940
s->planewidth[1]: 352, s->filler[1]: 0x55f36e025c80
s->planewidth[2]: 352, s->filler[2]: 0x55f36e024a80
s->planeheight[0]: 576, s->shifts: 0x55f36e0251c0
temp: 0x55f36e025940, line: 0x7f8f0e06aa40, lineref: 0x7f8f0e06a780, lz: 704, y: 568, yref: 567, shifts: 0x55f36e0251c0, shifts[y]: -12
temp++: 0x55f36e02594c, line++: 0x7f8f0e06aa40, width: 692
shifts: 0x55f36e0251c0, y: 568, shifts[y]: -12, -shifts[y]: 12, FFMAX(0, -shifts[y]): 12
shifts: 0x55f36e0251c0, y: 568, shifts[y]: 134678279, -shifts[y]: -134678279, FFMAX(0, -shifts[y]): 0
预计(最后一行):
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
...最终导致内存访问错误。
这里的问题是 shifts
正在 under-allocated 和 under-initialized。 if shifts
的定义是:
int *shifts;
它的分配和初始化是:
s->shifts = av_malloc(s->planeheight[0]);
int height = s->planeheight[0];
int *shifts = s->shifts;
memset(shifts, 0, height);
其中每一个都缺少 sizeof(int)
的乘积。应该是:
s->shifts = av_malloc(s->planeheight[0] * sizeof(int));
int *shifts = s->shifts;
memset(shifts, 0, height * sizeof(int));