You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-04 22:03:09 +02:00
checkasm: Implement helpers for defining and checking padded rects
This backports similar functionality from dav1d, from commits 35d1d011fda4a92bcaf42d30ed137583b27d7f6d and d130da9c315d5a1d3968d278bbee2238ad9051e7. This allows detecting writes out of bounds, on all 4 sides of the intended destination rectangle. The bounds checking also can optionally allow small overwrites (up to a specified alignment), while still checking for larger overwrites past the intended allowed region. Signed-off-by: Martin Storsjö <martin@martin.st>
This commit is contained in:
@ -1168,24 +1168,40 @@ void checkasm_report(const char *name, ...)
|
||||
}
|
||||
}
|
||||
|
||||
static int check_err(const char *file, int line,
|
||||
const char *name, int w, int h,
|
||||
int *err)
|
||||
{
|
||||
if (*err)
|
||||
return 0;
|
||||
if (!checkasm_fail_func("%s:%d", file, line))
|
||||
return 1;
|
||||
*err = 1;
|
||||
fprintf(stderr, "%s (%dx%d):\n", name, w, h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DEF_CHECKASM_CHECK_FUNC(type, fmt) \
|
||||
int checkasm_check_##type(const char *file, int line, \
|
||||
const type *buf1, ptrdiff_t stride1, \
|
||||
const type *buf2, ptrdiff_t stride2, \
|
||||
int w, int h, const char *name) \
|
||||
int w, int h, const char *name, \
|
||||
int align_w, int align_h, \
|
||||
int padding) \
|
||||
{ \
|
||||
int aligned_w = (w + align_w - 1) & ~(align_w - 1); \
|
||||
int aligned_h = (h + align_h - 1) & ~(align_h - 1); \
|
||||
int err = 0; \
|
||||
int y = 0; \
|
||||
stride1 /= sizeof(*buf1); \
|
||||
stride2 /= sizeof(*buf2); \
|
||||
for (y = 0; y < h; y++) \
|
||||
if (memcmp(&buf1[y*stride1], &buf2[y*stride2], w*sizeof(*buf1))) \
|
||||
break; \
|
||||
if (y == h) \
|
||||
return 0; \
|
||||
if (!checkasm_fail_func("%s:%d", file, line)) \
|
||||
if (y != h) { \
|
||||
if (check_err(file, line, name, w, h, &err)) \
|
||||
return 1; \
|
||||
fprintf(stderr, "%s:\n", name); \
|
||||
while (h--) { \
|
||||
for (y = 0; y < h; y++) { \
|
||||
for (int x = 0; x < w; x++) \
|
||||
fprintf(stderr, " " fmt, buf1[x]); \
|
||||
fprintf(stderr, " "); \
|
||||
@ -1198,7 +1214,42 @@ int checkasm_check_##type(const char *file, int line, \
|
||||
buf2 += stride2; \
|
||||
fprintf(stderr, "\n"); \
|
||||
} \
|
||||
buf1 -= h*stride1; \
|
||||
buf2 -= h*stride2; \
|
||||
} \
|
||||
for (y = -padding; y < 0; y++) \
|
||||
if (memcmp(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \
|
||||
(w + 2*padding)*sizeof(*buf1))) { \
|
||||
if (check_err(file, line, name, w, h, &err)) \
|
||||
return 1; \
|
||||
fprintf(stderr, " overwrite above\n"); \
|
||||
break; \
|
||||
} \
|
||||
for (y = aligned_h; y < aligned_h + padding; y++) \
|
||||
if (memcmp(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \
|
||||
(w + 2*padding)*sizeof(*buf1))) { \
|
||||
if (check_err(file, line, name, w, h, &err)) \
|
||||
return 1; \
|
||||
fprintf(stderr, " overwrite below\n"); \
|
||||
break; \
|
||||
} \
|
||||
for (y = 0; y < h; y++) \
|
||||
if (memcmp(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \
|
||||
padding*sizeof(*buf1))) { \
|
||||
if (check_err(file, line, name, w, h, &err)) \
|
||||
return 1; \
|
||||
fprintf(stderr, " overwrite left\n"); \
|
||||
break; \
|
||||
} \
|
||||
for (y = 0; y < h; y++) \
|
||||
if (memcmp(&buf1[y*stride1 + aligned_w], &buf2[y*stride2 + aligned_w], \
|
||||
padding*sizeof(*buf1))) { \
|
||||
if (check_err(file, line, name, w, h, &err)) \
|
||||
return 1; \
|
||||
fprintf(stderr, " overwrite right\n"); \
|
||||
break; \
|
||||
} \
|
||||
return err; \
|
||||
}
|
||||
|
||||
DEF_CHECKASM_CHECK_FUNC(uint8_t, "%02x")
|
||||
|
@ -375,11 +375,30 @@ typedef struct CheckasmPerf {
|
||||
#define PERF_STOP(t) while(0)
|
||||
#endif
|
||||
|
||||
#define BUF_RECT(type, name, w, h) \
|
||||
LOCAL_ALIGNED_32(type, name##_buf, [((h)+32)*(FFALIGN(w,64)+64) + 64]); \
|
||||
av_unused ptrdiff_t name##_stride = sizeof(type)*(FFALIGN(w,64)+64); \
|
||||
av_unused int name##_buf_h = (h)+32; \
|
||||
type *name = name##_buf + (FFALIGN(w,64)+64)*16 + 64
|
||||
|
||||
#define PIXEL_RECT(name, w, h) \
|
||||
LOCAL_ALIGNED_32(uint8_t, name##_buf, [sizeof(uint16_t) * (((h)+32)*(FFALIGN(w,64)+64) + 64)],); \
|
||||
av_unused ptrdiff_t name##_stride = sizeof(uint16_t) * (FFALIGN(w,64)+64); \
|
||||
av_unused int name##_buf_h = (h)+32; \
|
||||
uint8_t *name = name##_buf + (FFALIGN(w,64)+64)*16 + 64
|
||||
|
||||
#define CLEAR_BUF_RECT(name) \
|
||||
memset(name##_buf, 0x99, name##_stride * name##_buf_h + 64)
|
||||
#define CLEAR_PIXEL_RECT(name) \
|
||||
CLEAR_BUF_RECT(name)
|
||||
|
||||
#define DECL_CHECKASM_CHECK_FUNC(type) \
|
||||
int checkasm_check_##type(const char *file, int line, \
|
||||
const type *buf1, ptrdiff_t stride1, \
|
||||
const type *buf2, ptrdiff_t stride2, \
|
||||
int w, int h, const char *name)
|
||||
int w, int h, const char *name, \
|
||||
int align_w, int align_h, \
|
||||
int padding)
|
||||
|
||||
DECL_CHECKASM_CHECK_FUNC(uint8_t);
|
||||
DECL_CHECKASM_CHECK_FUNC(uint16_t);
|
||||
@ -390,18 +409,36 @@ DECL_CHECKASM_CHECK_FUNC(int32_t);
|
||||
#define PASTE(a,b) a ## b
|
||||
#define CONCAT(a,b) PASTE(a,b)
|
||||
|
||||
#define checkasm_check(prefix, ...) CONCAT(checkasm_check_, prefix)(__FILE__, __LINE__, __VA_ARGS__)
|
||||
#define checkasm_check2(prefix, ...) CONCAT(checkasm_check_, prefix)(__FILE__, __LINE__, __VA_ARGS__)
|
||||
#define checkasm_check(prefix, ...) checkasm_check2(prefix, __VA_ARGS__, 0, 0, 0)
|
||||
/* Check a pointer from BUF_RECT, checking whether there have been
|
||||
* writes outside of the designated area. */
|
||||
#define checkasm_check_padded(...) \
|
||||
checkasm_check2(__VA_ARGS__, 1, 1, 8)
|
||||
/* Check a pointer from BUF_RECT, checking whether there have been
|
||||
* writes outside of the designated area. Allow writing slightly past the
|
||||
* end of the buffer, by aligning w/h to align_w/align_h, and checking
|
||||
* for overwrites outside of that. */
|
||||
#define checkasm_check_padded_align(...) \
|
||||
checkasm_check2(__VA_ARGS__, 8)
|
||||
|
||||
/* This assumes that there is a local variable named "bit_depth".
|
||||
* For tests that don't have that and only operate on a single
|
||||
* bitdepth, just call checkasm_check(uint8_t, ...) directly. */
|
||||
#define checkasm_check_pixel(buf1, stride1, buf2, stride2, ...) \
|
||||
#define checkasm_check_pixel2(buf1, stride1, buf2, stride2, ...) \
|
||||
((bit_depth > 8) ? \
|
||||
checkasm_check(uint16_t, (const uint16_t*)buf1, stride1, \
|
||||
checkasm_check2(uint16_t, (const uint16_t*)buf1, stride1, \
|
||||
(const uint16_t*)buf2, stride2, \
|
||||
__VA_ARGS__) : \
|
||||
checkasm_check(uint8_t, (const uint8_t*) buf1, stride1, \
|
||||
checkasm_check2(uint8_t, (const uint8_t*) buf1, stride1, \
|
||||
(const uint8_t*) buf2, stride2, \
|
||||
__VA_ARGS__))
|
||||
#define checkasm_check_pixel(...) \
|
||||
checkasm_check_pixel2(__VA_ARGS__, 0, 0, 0)
|
||||
#define checkasm_check_pixel_padded(...) \
|
||||
checkasm_check_pixel2(__VA_ARGS__, 1, 1, 8)
|
||||
#define checkasm_check_pixel_padded_align(...) \
|
||||
checkasm_check_pixel2(__VA_ARGS__, 8)
|
||||
|
||||
|
||||
#endif /* TESTS_CHECKASM_CHECKASM_H */
|
||||
|
Reference in New Issue
Block a user