+#define _GNU_SOURCE
+
#include "utils.h"
#include <signal.h>
+#include <stdlib.h>
#ifdef HAVE_GETTIMEOFDAY
#include <sys/time.h>
#include <sys/mman.h>
#endif
+#ifdef HAVE_FENV_H
+#include <fenv.h>
+#endif
+
+#ifdef HAVE_LIBPNG
+#include <png.h>
+#endif
+
/* Random number seed
*/
return (crc32 ^ 0xFFFFFFFF);
}
+pixman_bool_t
+is_little_endian (void)
+{
+ volatile uint16_t endian_check_var = 0x1234;
+
+ return (*(volatile uint8_t *)&endian_check_var == 0x34);
+}
+
/* perform endian conversion of pixel data
*/
void
-image_endian_swap (pixman_image_t *img, int bpp)
+image_endian_swap (pixman_image_t *img)
{
int stride = pixman_image_get_stride (img);
uint32_t *data = pixman_image_get_data (img);
int height = pixman_image_get_height (img);
+ int bpp = PIXMAN_FORMAT_BPP (pixman_image_get_format (img));
int i, j;
/* swap bytes only on big endian systems */
- volatile uint16_t endian_check_var = 0x1234;
- if (*(volatile uint8_t *)&endian_check_var != 0x12)
+ if (is_little_endian())
+ return;
+
+ if (bpp == 8)
return;
for (i = 0; i < height; i++)
{
uint8_t *line_data = (uint8_t *)data + stride * i;
- /* swap bytes only for 16, 24 and 32 bpp for now */
+
switch (bpp)
{
case 1:
}
break;
default:
+ assert (FALSE);
break;
}
}
int n_bytes;
} info_t;
-#if defined(HAVE_MPROTECT) && defined(HAVE_GETPAGESIZE)
+#if defined(HAVE_MPROTECT) && defined(HAVE_GETPAGESIZE) && defined(HAVE_SYS_MMAN_H) && defined(HAVE_MMAP)
+
+/* This is apparently necessary on at least OS X */
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
void *
-fence_malloc (uint32_t len)
+fence_malloc (int64_t len)
{
unsigned long page_size = getpagesize();
unsigned long page_mask = page_size - 1;
uint8_t *payload;
uint8_t *addr;
+ if (len < 0)
+ abort();
+
addr = mmap (NULL, n_bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
- if (addr == (void *)MAP_FAILED)
+ if (addr == MAP_FAILED)
{
- printf ("mmap failed on %u %u\n", len, n_bytes);
+ printf ("mmap failed on %lld %u\n", (long long int)len, n_bytes);
return NULL;
}
((info_t *)initial_page)->trailing = trailing_protected;
((info_t *)initial_page)->n_bytes = n_bytes;
- if (mprotect (leading_protected, N_LEADING_PROTECTED * page_size,
- PROT_NONE) == -1)
- {
- free (addr);
- return NULL;
- }
-
- if (mprotect (trailing_protected, N_TRAILING_PROTECTED * page_size,
- PROT_NONE) == -1)
+ if ((mprotect (leading_protected, N_LEADING_PROTECTED * page_size,
+ PROT_NONE) == -1) ||
+ (mprotect (trailing_protected, N_TRAILING_PROTECTED * page_size,
+ PROT_NONE) == -1))
{
- mprotect (leading_protected, N_LEADING_PROTECTED * page_size,
- PROT_READ | PROT_WRITE);
-
- free (addr);
+ munmap (addr, n_bytes);
return NULL;
}
uint8_t *leading_protected = payload - N_LEADING_PROTECTED * page_size;
uint8_t *initial_page = leading_protected - page_size;
info_t *info = (info_t *)initial_page;
- uint8_t *trailing_protected = info->trailing;
-
- mprotect (leading_protected, N_LEADING_PROTECTED * page_size,
- PROT_READ | PROT_WRITE);
-
- mprotect (trailing_protected, N_LEADING_PROTECTED * page_size,
- PROT_READ | PROT_WRITE);
munmap (info->addr, info->n_bytes);
}
#else
void *
-fence_malloc (uint32_t len)
+fence_malloc (int64_t len)
{
return malloc (len);
}
return bytes;
}
+void
+a8r8g8b8_to_rgba_np (uint32_t *dst, uint32_t *src, int n_pixels)
+{
+ uint8_t *dst8 = (uint8_t *)dst;
+ int i;
+
+ for (i = 0; i < n_pixels; ++i)
+ {
+ uint32_t p = src[i];
+ uint8_t a, r, g, b;
+
+ a = (p & 0xff000000) >> 24;
+ r = (p & 0x00ff0000) >> 16;
+ g = (p & 0x0000ff00) >> 8;
+ b = (p & 0x000000ff) >> 0;
+
+ if (a != 0)
+ {
+#define DIVIDE(c, a) \
+ do \
+ { \
+ int t = ((c) * 255) / a; \
+ (c) = t < 0? 0 : t > 255? 255 : t; \
+ } while (0)
+
+ DIVIDE (r, a);
+ DIVIDE (g, a);
+ DIVIDE (b, a);
+ }
+
+ *dst8++ = r;
+ *dst8++ = g;
+ *dst8++ = b;
+ *dst8++ = a;
+ }
+}
+
+#ifdef HAVE_LIBPNG
+
+pixman_bool_t
+write_png (pixman_image_t *image, const char *filename)
+{
+ int width = pixman_image_get_width (image);
+ int height = pixman_image_get_height (image);
+ int stride = width * 4;
+ uint32_t *data = malloc (height * stride);
+ pixman_image_t *copy;
+ png_struct *write_struct;
+ png_info *info_struct;
+ pixman_bool_t result = FALSE;
+ FILE *f = fopen (filename, "wb");
+ png_bytep *row_pointers;
+ int i;
+
+ if (!f)
+ return FALSE;
+
+ row_pointers = malloc (height * sizeof (png_bytep));
+
+ copy = pixman_image_create_bits (
+ PIXMAN_a8r8g8b8, width, height, data, stride);
+
+ pixman_image_composite32 (
+ PIXMAN_OP_SRC, image, NULL, copy, 0, 0, 0, 0, 0, 0, width, height);
+
+ a8r8g8b8_to_rgba_np (data, data, height * width);
+
+ for (i = 0; i < height; ++i)
+ row_pointers[i] = (png_bytep)(data + i * width);
+
+ if (!(write_struct = png_create_write_struct (
+ PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)))
+ goto out1;
+
+ if (!(info_struct = png_create_info_struct (write_struct)))
+ goto out2;
+
+ png_init_io (write_struct, f);
+
+ png_set_IHDR (write_struct, info_struct, width, height,
+ 8, PNG_COLOR_TYPE_RGB_ALPHA,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
+ PNG_FILTER_TYPE_BASE);
+
+ png_write_info (write_struct, info_struct);
+
+ png_write_image (write_struct, row_pointers);
+
+ png_write_end (write_struct, NULL);
+
+ result = TRUE;
+
+out2:
+ png_destroy_write_struct (&write_struct, &info_struct);
+
+out1:
+ if (fclose (f) != 0)
+ result = FALSE;
+
+ pixman_image_unref (copy);
+ free (row_pointers);
+ free (data);
+ return result;
+}
+
+#else /* no libpng */
+
+pixman_bool_t
+write_png (pixman_image_t *image, const char *filename)
+{
+ return FALSE;
+}
+
+#endif
+
/*
* A function, which can be used as a core part of the test programs,
* intended to detect various problems with the help of fuzzing input
#endif
}
+uint32_t
+get_random_seed (void)
+{
+ double d = gettime();
+
+ lcg_srand (*(uint32_t *)&d);
+
+ return lcg_rand_u32 ();
+}
+
static const char *global_msg;
static void
#endif
}
+void
+enable_fp_exceptions (void)
+{
+#ifdef HAVE_FENV_H
+#ifdef HAVE_FEENABLEEXCEPT
+ /* Note: we don't enable the FE_INEXACT trap because
+ * that happens quite commonly. It is possible that
+ * over- and underflow should similarly be considered
+ * okay, but for now the test suite passes with them
+ * enabled, and it's useful to know if they start
+ * occuring.
+ */
+ feenableexcept (FE_DIVBYZERO |
+ FE_INVALID |
+ FE_OVERFLOW |
+ FE_UNDERFLOW);
+#endif
+#endif
+}
+
void *
aligned_malloc (size_t align, size_t size)
{
return result;
}
+
+#define CONVERT_15(c, is_rgb) \
+ (is_rgb? \
+ ((((c) >> 3) & 0x001f) | \
+ (((c) >> 6) & 0x03e0) | \
+ (((c) >> 9) & 0x7c00)) : \
+ (((((c) >> 16) & 0xff) * 153 + \
+ (((c) >> 8) & 0xff) * 301 + \
+ (((c) ) & 0xff) * 58) >> 2))
+
+void
+initialize_palette (pixman_indexed_t *palette, uint32_t depth, int is_rgb)
+{
+ int i;
+ uint32_t mask = (1 << depth) - 1;
+
+ for (i = 0; i < 32768; ++i)
+ palette->ent[i] = lcg_rand() & mask;
+
+ memset (palette->rgba, 0, sizeof (palette->rgba));
+
+ for (i = 0; i < mask + 1; ++i)
+ {
+ uint32_t rgba24;
+ pixman_bool_t retry;
+ uint32_t i15;
+
+ /* We filled the rgb->index map with random numbers, but we
+ * do need the ability to round trip, that is if some indexed
+ * color expands to an argb24, then the 15 bit version of that
+ * color must map back to the index. Anything else, we don't
+ * care about too much.
+ */
+ do
+ {
+ uint32_t old_idx;
+
+ rgba24 = lcg_rand();
+ i15 = CONVERT_15 (rgba24, is_rgb);
+
+ old_idx = palette->ent[i15];
+ if (CONVERT_15 (palette->rgba[old_idx], is_rgb) == i15)
+ retry = 1;
+ else
+ retry = 0;
+ } while (retry);
+
+ palette->rgba[i] = rgba24;
+ palette->ent[i15] = i;
+ }
+
+ for (i = 0; i < mask + 1; ++i)
+ {
+ assert (palette->ent[CONVERT_15 (palette->rgba[i], is_rgb)] == i);
+ }
+}
+
+static double
+round_channel (double p, int m)
+{
+ int t;
+ double r;
+
+ t = p * ((1 << m));
+ t -= t >> m;
+
+ r = t / (double)((1 << m) - 1);
+
+ return r;
+}
+
+void
+round_color (pixman_format_code_t format, color_t *color)
+{
+ if (PIXMAN_FORMAT_R (format) == 0)
+ {
+ color->r = 0.0;
+ color->g = 0.0;
+ color->b = 0.0;
+ }
+ else
+ {
+ color->r = round_channel (color->r, PIXMAN_FORMAT_R (format));
+ color->g = round_channel (color->g, PIXMAN_FORMAT_G (format));
+ color->b = round_channel (color->b, PIXMAN_FORMAT_B (format));
+ }
+
+ if (PIXMAN_FORMAT_A (format) == 0)
+ color->a = 1;
+ else
+ color->a = round_channel (color->a, PIXMAN_FORMAT_A (format));
+}
+
+/* Check whether @pixel is a valid quantization of the a, r, g, b
+ * parameters. Some slack is permitted.
+ */
+void
+pixel_checker_init (pixel_checker_t *checker, pixman_format_code_t format)
+{
+ assert (PIXMAN_FORMAT_VIS (format));
+
+ checker->format = format;
+
+ switch (PIXMAN_FORMAT_TYPE (format))
+ {
+ case PIXMAN_TYPE_A:
+ checker->bs = 0;
+ checker->gs = 0;
+ checker->rs = 0;
+ checker->as = 0;
+ break;
+
+ case PIXMAN_TYPE_ARGB:
+ checker->bs = 0;
+ checker->gs = checker->bs + PIXMAN_FORMAT_B (format);
+ checker->rs = checker->gs + PIXMAN_FORMAT_G (format);
+ checker->as = checker->rs + PIXMAN_FORMAT_R (format);
+ break;
+
+ case PIXMAN_TYPE_ABGR:
+ checker->rs = 0;
+ checker->gs = checker->rs + PIXMAN_FORMAT_R (format);
+ checker->bs = checker->gs + PIXMAN_FORMAT_G (format);
+ checker->as = checker->bs + PIXMAN_FORMAT_B (format);
+ break;
+
+ case PIXMAN_TYPE_BGRA:
+ /* With BGRA formats we start counting at the high end of the pixel */
+ checker->bs = PIXMAN_FORMAT_BPP (format) - PIXMAN_FORMAT_B (format);
+ checker->gs = checker->bs - PIXMAN_FORMAT_B (format);
+ checker->rs = checker->gs - PIXMAN_FORMAT_G (format);
+ checker->as = checker->rs - PIXMAN_FORMAT_R (format);
+ break;
+
+ case PIXMAN_TYPE_RGBA:
+ /* With BGRA formats we start counting at the high end of the pixel */
+ checker->rs = PIXMAN_FORMAT_BPP (format) - PIXMAN_FORMAT_R (format);
+ checker->gs = checker->rs - PIXMAN_FORMAT_R (format);
+ checker->bs = checker->gs - PIXMAN_FORMAT_G (format);
+ checker->as = checker->bs - PIXMAN_FORMAT_B (format);
+ break;
+
+ default:
+ assert (0);
+ break;
+ }
+
+ checker->am = ((1 << PIXMAN_FORMAT_A (format)) - 1) << checker->as;
+ checker->rm = ((1 << PIXMAN_FORMAT_R (format)) - 1) << checker->rs;
+ checker->gm = ((1 << PIXMAN_FORMAT_G (format)) - 1) << checker->gs;
+ checker->bm = ((1 << PIXMAN_FORMAT_B (format)) - 1) << checker->bs;
+
+ checker->aw = PIXMAN_FORMAT_A (format);
+ checker->rw = PIXMAN_FORMAT_R (format);
+ checker->gw = PIXMAN_FORMAT_G (format);
+ checker->bw = PIXMAN_FORMAT_B (format);
+}
+
+void
+pixel_checker_split_pixel (const pixel_checker_t *checker, uint32_t pixel,
+ int *a, int *r, int *g, int *b)
+{
+ *a = (pixel & checker->am) >> checker->as;
+ *r = (pixel & checker->rm) >> checker->rs;
+ *g = (pixel & checker->gm) >> checker->gs;
+ *b = (pixel & checker->bm) >> checker->bs;
+}
+
+static int32_t
+convert (double v, uint32_t width, uint32_t mask, uint32_t shift, double def)
+{
+ int32_t r;
+
+ if (!mask)
+ v = def;
+
+ r = (v * ((mask >> shift) + 1));
+ r -= r >> width;
+
+ return r;
+}
+
+static void
+get_limits (const pixel_checker_t *checker, double limit,
+ color_t *color,
+ int *ao, int *ro, int *go, int *bo)
+{
+ *ao = convert (color->a + limit, checker->aw, checker->am, checker->as, 1.0);
+ *ro = convert (color->r + limit, checker->rw, checker->rm, checker->rs, 0.0);
+ *go = convert (color->g + limit, checker->gw, checker->gm, checker->gs, 0.0);
+ *bo = convert (color->b + limit, checker->bw, checker->bm, checker->bs, 0.0);
+}
+
+/* The acceptable deviation in units of [0.0, 1.0]
+ */
+#define DEVIATION (0.004)
+
+void
+pixel_checker_get_max (const pixel_checker_t *checker, color_t *color,
+ int *am, int *rm, int *gm, int *bm)
+{
+ get_limits (checker, DEVIATION, color, am, rm, gm, bm);
+}
+
+void
+pixel_checker_get_min (const pixel_checker_t *checker, color_t *color,
+ int *am, int *rm, int *gm, int *bm)
+{
+ get_limits (checker, - DEVIATION, color, am, rm, gm, bm);
+}
+
+pixman_bool_t
+pixel_checker_check (const pixel_checker_t *checker, uint32_t pixel,
+ color_t *color)
+{
+ int32_t a_lo, a_hi, r_lo, r_hi, g_lo, g_hi, b_lo, b_hi;
+ int32_t ai, ri, gi, bi;
+ pixman_bool_t result;
+
+ pixel_checker_get_min (checker, color, &a_lo, &r_lo, &g_lo, &b_lo);
+ pixel_checker_get_max (checker, color, &a_hi, &r_hi, &g_hi, &b_hi);
+ pixel_checker_split_pixel (checker, pixel, &ai, &ri, &gi, &bi);
+
+ result =
+ a_lo <= ai && ai <= a_hi &&
+ r_lo <= ri && ri <= r_hi &&
+ g_lo <= gi && gi <= g_hi &&
+ b_lo <= bi && bi <= b_hi;
+
+ return result;
+}