Blame test/fence-image-self-test.c

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