Have pixel_swizzler_fuzzer use no-r/w guard pages
diff --git a/fuzz/c/std/pixel_swizzler_fuzzer.c b/fuzz/c/std/pixel_swizzler_fuzzer.c
index 2ce1e87..fb5fd02 100644
--- a/fuzz/c/std/pixel_swizzler_fuzzer.c
+++ b/fuzz/c/std/pixel_swizzler_fuzzer.c
@@ -52,6 +52,9 @@
#define WUFFS_CONFIG__MODULES
#define WUFFS_CONFIG__MODULE__BASE
+#include <sys/mman.h>
+#include <unistd.h>
+
// If building this program in an environment that doesn't easily accommodate
// relative includes, you can use the script/inline-c-relative-includes.go
// program to generate a stand-alone C file.
@@ -79,6 +82,23 @@
WUFFS_BASE__PIXEL_BLEND__SRC_OVER,
};
+// allocate_guarded_page allocates (2 * page_size) bytes of memory. The first
+// page has read|write permissions. The second page has no permissions, so that
+// attempting to read or write to it will cause a segmentation fault.
+const char* //
+allocate_guarded_page(uint8_t** ptr_out, int page_size) {
+ void* ptr =
+ mmap(NULL, 2 * page_size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ if (ptr == MAP_FAILED) {
+ return "fuzz: internal error: mmap failed";
+ }
+ if (mprotect(ptr, page_size, PROT_READ | PROT_WRITE)) {
+ return "fuzz: internal error: mprotect failed";
+ }
+ *ptr_out = ptr;
+ return NULL;
+}
+
// fuzz tests that, regardless of the randomized inputs, calling
// wuffs_base__pixel_swizzler__swizzle_interleaved_from_slice will not crash
// the fuzzer (e.g. due to reads or write past buffer bounds).
@@ -87,7 +107,7 @@
uint8_t dst_palette_array[1024];
uint8_t src_palette_array[1024];
if ((src->meta.wi - src->meta.ri) < 2048) {
- return "not enough data";
+ return "fuzz: not enough data";
}
memcpy(dst_palette_array, src->data.ptr + src->meta.ri, 1024);
src->meta.ri += 1024;
@@ -117,43 +137,45 @@
return wuffs_base__status__message(&status);
}
- const char* ret = NULL;
- wuffs_base__slice_u8 dst_slice = ((wuffs_base__slice_u8){});
- wuffs_base__slice_u8 src_slice = ((wuffs_base__slice_u8){});
-
- // Use a {} code block so that "goto exit" doesn't trigger "jump bypasses
- // variable initialization" warnings.
- {
- if ((src->meta.wi - src->meta.ri) < dst_len) {
- ret = "not enough data";
- goto exit;
- }
- dst_slice = wuffs_base__malloc_slice_u8(malloc, dst_len);
- if (!dst_slice.ptr) {
- ret = "out of memory";
- goto exit;
- }
- memcpy(dst_slice.ptr, src->data.ptr + src->meta.ri, dst_len);
- src->meta.ri += dst_len;
-
- if ((src->meta.wi - src->meta.ri) < src_len) {
- ret = "not enough data";
- goto exit;
- }
- src_slice = wuffs_base__malloc_slice_u8(malloc, src_len);
- if (!src_slice.ptr) {
- ret = "out of memory";
- goto exit;
- }
- memcpy(src_slice.ptr, src->data.ptr + src->meta.ri, src_len);
- src->meta.ri += src_len;
-
- wuffs_base__pixel_swizzler__swizzle_interleaved_from_slice(
- &swizzler, dst_slice, dst_palette, src_slice);
+ int page_size = getpagesize();
+ if (page_size < 0x100) {
+ return "fuzz: internal error: page_size is too small";
}
-exit:
- free(src_slice.ptr);
- free(dst_slice.ptr);
- return ret;
+ static uint8_t* dst_alloc = NULL;
+ if (!dst_alloc) {
+ const char* z = allocate_guarded_page(&dst_alloc, page_size);
+ if (z != NULL) {
+ return z;
+ }
+ }
+
+ static uint8_t* src_alloc = NULL;
+ if (!src_alloc) {
+ const char* z = allocate_guarded_page(&src_alloc, page_size);
+ if (z != NULL) {
+ return z;
+ }
+ }
+
+ // Position dst_slice and src_slice so that reading or writing one byte past
+ // their end will cause a segmentation fault.
+ if ((src->meta.wi - src->meta.ri) < (dst_len + src_len)) {
+ return "fuzz: not enough data";
+ }
+ wuffs_base__slice_u8 dst_slice =
+ wuffs_base__make_slice_u8(dst_alloc + page_size - dst_len, dst_len);
+ memcpy(dst_slice.ptr, src->data.ptr + src->meta.ri, dst_len);
+ src->meta.ri += dst_len;
+ wuffs_base__slice_u8 src_slice =
+ wuffs_base__make_slice_u8(src_alloc + page_size - src_len, src_len);
+ memcpy(src_slice.ptr, src->data.ptr + src->meta.ri, src_len);
+ src->meta.ri += src_len;
+
+ // Calling etc__swizzle_interleaved_from_slice should not crash, whether for
+ // reading/writing out of bounds or for other reasons.
+ wuffs_base__pixel_swizzler__swizzle_interleaved_from_slice(
+ &swizzler, dst_slice, dst_palette, src_slice);
+
+ return NULL;
}