[Pixman] [PATCH v3] test: add fence-image-self-test

Pekka Paalanen ppaalanen at gmail.com
Wed Sep 2 01:15:24 PDT 2015


From: Pekka Paalanen <pekka.paalanen at collabora.co.uk>

Tests that fence_malloc and fence_image_create_bits actually work: that
out-of-bounds and out-of-row (unused stride area) accesses trigger
SIGSEGV.

If fence_malloc is a dummy (FENCE_MALLOC_ACTIVE not defined), this test
is skipped.

Changes in v2:

- check FENCE_MALLOC_ACTIVE value, not whether it is defined
- test that reading bytes near the fence pages does not cause a
  segmentation fault

Changes in v3:

- Do not print progress messages unless VERBOSE environment variable is
  set. Avoid spamming the terminal output of 'make check' on some
  versions of autotools.

Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
 test/Makefile.sources        |   1 +
 test/fence-image-self-test.c | 237 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 238 insertions(+)
 create mode 100644 test/fence-image-self-test.c

diff --git a/test/Makefile.sources b/test/Makefile.sources
index d0d7928..dd7582a 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -3,6 +3,7 @@ TESTPROGRAMS =			      \
 	oob-test		      \
 	infinite-loop		      \
 	trap-crasher		      \
+	fence-image-self-test	      \
 	region-translate-test	      \
 	fetch-test		      \
 	a1-trap-test		      \
diff --git a/test/fence-image-self-test.c b/test/fence-image-self-test.c
new file mode 100644
index 0000000..c883038
--- /dev/null
+++ b/test/fence-image-self-test.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright © 2015 Raspberry Pi Foundation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  The copyright holders make no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "utils.h"
+
+
+#if FENCE_MALLOC_ACTIVE && defined (HAVE_SIGACTION)
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+pixman_bool_t verbose;
+
+static void
+segv_handler (int sig, siginfo_t *si, void *unused)
+{
+    _exit (EXIT_SUCCESS);
+}
+
+static void
+die (const char *msg, int err)
+{
+    if (err)
+        perror (msg);
+    else
+        fprintf (stderr, "%s\n", msg);
+
+    abort ();
+}
+
+static void
+prinfo (const char *fmt, ...)
+{
+    va_list ap;
+
+    if (!verbose)
+        return;
+
+    va_start (ap, fmt);
+    vfprintf (stderr, fmt, ap);
+    va_end (ap);
+}
+
+static void
+do_expect_segv (void (*fn)(void *), void *data)
+{
+    struct sigaction sa;
+
+    sa.sa_flags = SA_SIGINFO;
+    sigemptyset (&sa.sa_mask);
+    sa.sa_sigaction = segv_handler;
+    if (sigaction (SIGSEGV, &sa, NULL) == -1)
+        die ("sigaction failed", errno);
+
+    (*fn)(data);
+
+    _exit (EXIT_FAILURE);
+}
+
+/* Check that calling fn(data) causes a segmentation fault.
+ *
+ * You cannot portably return from a SIGSEGV handler in any way,
+ * so we fork, and do the test in the child process. Child's
+ * exit status will reflect the result. Its SEGV handler causes it
+ * to exit with success, and return failure otherwise.
+ */
+static pixman_bool_t
+expect_segv (void (*fn)(void *), void *data)
+{
+    pid_t pid, wp;
+    int status;
+
+    pid = fork ();
+    if (pid == -1)
+        die ("fork failed", errno);
+
+    if (pid == 0)
+        do_expect_segv (fn, data); /* never returns */
+
+    wp = waitpid (pid, &status, 0);
+    if (wp != pid)
+        die ("waitpid did not work", wp == -1 ? errno : 0);
+
+    if (WIFEXITED (status) && WEXITSTATUS (status) == EXIT_SUCCESS)
+        return TRUE;
+
+    return FALSE;
+}
+
+static void
+read_u8 (void *data)
+{
+    volatile uint8_t *p = data;
+
+    *p;
+}
+
+static pixman_bool_t
+test_read_fault (uint8_t *p, int offset)
+{
+    prinfo ("*(uint8_t *)(%p + %d)", p, offset);
+
+    if (expect_segv (read_u8, p + offset))
+    {
+        prinfo ("\tSEGV OK\n");
+
+        return TRUE;
+    }
+
+    prinfo ("\tFAILED\n");
+
+    return FALSE;
+}
+
+static void
+test_read_ok (uint8_t *p, int offset)
+{
+    prinfo ("*(uint8_t *)(%p + %d)", p, offset);
+
+    /* If fails, SEGV. */
+    read_u8 (p + offset);
+
+    prinfo ("\tOK\n");
+}
+
+static pixman_bool_t
+test_read_faults (pixman_image_t *image)
+{
+    pixman_bool_t ok = TRUE;
+    pixman_format_code_t format = pixman_image_get_format (image);
+    int width = pixman_image_get_width (image);
+    int height = pixman_image_get_height (image);
+    int stride = pixman_image_get_stride (image);
+    uint8_t *p = (void *)pixman_image_get_data (image);
+    int row_bytes = width * PIXMAN_FORMAT_BPP (format) / 8;
+
+    prinfo ("%s %dx%d, row %d B, stride %d B:\n",
+            format_name (format), width, height, row_bytes, stride);
+
+    assert (height > 3);
+
+    test_read_ok (p, 0);
+    test_read_ok (p, row_bytes - 1);
+    test_read_ok (p, stride);
+    test_read_ok (p, stride + row_bytes - 1);
+    test_read_ok (p, 2 * stride);
+    test_read_ok (p, 2 * stride + row_bytes - 1);
+    test_read_ok (p, 3 * stride);
+    test_read_ok (p, (height - 1) * stride + row_bytes - 1);
+
+    ok &= test_read_fault (p, -1);
+    ok &= test_read_fault (p, row_bytes);
+    ok &= test_read_fault (p, stride - 1);
+    ok &= test_read_fault (p, stride + row_bytes);
+    ok &= test_read_fault (p, 2 * stride - 1);
+    ok &= test_read_fault (p, 2 * stride + row_bytes);
+    ok &= test_read_fault (p, 3 * stride - 1);
+    ok &= test_read_fault (p, height * stride);
+
+    return ok;
+}
+
+static pixman_bool_t
+test_image_faults (pixman_format_code_t format, int min_width, int height)
+{
+    pixman_bool_t ok;
+    pixman_image_t *image;
+
+    image = fence_image_create_bits (format, min_width, height, TRUE);
+    ok = test_read_faults (image);
+    pixman_image_unref (image);
+
+    return ok;
+}
+
+int
+main (int argc, char **argv)
+{
+    pixman_bool_t ok = TRUE;
+
+    if (getenv ("VERBOSE") != NULL)
+        verbose = TRUE;
+
+    ok &= test_image_faults (PIXMAN_a8r8g8b8, 7, 5);
+    ok &= test_image_faults (PIXMAN_r8g8b8, 7, 5);
+    ok &= test_image_faults (PIXMAN_r5g6b5, 7, 5);
+    ok &= test_image_faults (PIXMAN_a8, 7, 5);
+    ok &= test_image_faults (PIXMAN_a4, 7, 5);
+    ok &= test_image_faults (PIXMAN_a1, 7, 5);
+
+    if (ok)
+        return EXIT_SUCCESS;
+
+    return EXIT_FAILURE;
+}
+
+#else /* FENCE_MALLOC_ACTIVE */
+
+int
+main (int argc, char **argv)
+{
+    /* Automake return code for test SKIP. */
+    return 77;
+}
+
+#endif /* FENCE_MALLOC_ACTIVE */
-- 
2.4.6



More information about the Pixman mailing list