Testing nonstandard assumption

Discussion in 'C Programming' started by Hallvard B Furuseth, Jun 29, 2003.

  1. I've written a program which attempts to test for various nonstandard
    assumptions which a program package (OpenLDAP) makes. I'd appreciate
    advice on how to improve it. (Yes, I know the correct way is to not
    make these assumptions, but that's easier said than done.)

    The program should crash or return failure if an assumption is false.
    Hopefully it will not hang or format the harddisk.

    /*
    * Try to test for the non-ANSI C assumptions in OpenLDAP:
    * two's complement integers,
    * at least 4-byte 'int',
    * 8-bit 'char',
    * 32-bit, no padding bits 'unsigned int' or 'unsigned short',
    * ASCII or EBCDIC character set (or a superset of these),
    * can cast 'int' to 'void *' and back,
    * can cast function pointers to 'void *' and back,
    * can meaningfully compare pointers to different malloced blocks.
    */

    /* #include "confdefs.h" */
    #include <limits.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
    # include <malloc.h>
    #endif
    #ifndef EXIT_SUCCESS
    # define EXIT_SUCCESS 0
    # define EXIT_FAILURE 1
    #endif

    static void
    sorry(const char *msg)
    {
    fprintf(stdout, "%s\n", msg);
    exit(EXIT_FAILURE);
    }

    /*
    * Try to guess if !(ptr1 <= ptr2 < ptr1+malloced_size) holds
    * when ptr1 and ptr2 are two different malloced pointers.
    * Required by slapd/sl_malloc.c.
    */
    static void
    test_malloc(void)
    {
    char *p, *q, *a[20];
    size_t len, n[20];
    int i, j, k, cmp1, cmp2;

    /* Make a[] a sorted array of malloced pointers */
    for (i = 0, k = 1; k <= 2; k++) {
    for (len = k; len < 0x800000ul; len *= 7) {
    p = malloc(len);
    if (p == NULL)
    break;
    /* can't use qsort(), it expects ordering comparison */
    for (j = i; j && a[j-1] > p; --j) {
    a[j] = a[j-1];
    n[j] = n[j-1];
    }
    a[j] = p;
    n[j] = len;
    i++;
    }
    }

    /* check in various ways that the pointers really are sorted */
    for (j = 1; j < i; j++)
    for (k = 0; k < j; k++)
    if (a[j] <= a[k]
    || a[j] + n[j] < a[k]
    || a[j] <= a[k] + n[k]
    || a[j] + n[j] <= a[k] + n[k])
    sorry("Cannot order malloced pointers");
    for (j = 0; j < i; j++)
    free(a[j]);

    /* This test can fail on some more architectures than necessary */
    for (i = 0; i < 256; i++) {
    /* Make two pointers out of random bit patterns */
    for (k = 0; k < (int)sizeof(char *); k++) {
    ((unsigned char *) &p) [k] = rand();
    ((unsigned char *) &q) [k] = rand();
    }
    /* compare them as memory blocks and as pointers */
    cmp1 = memcmp(&p, &q, sizeof(char *));
    if (cmp1 == 0)
    break;
    cmp1 = (cmp1 < 0 ? -1 : 1);
    if (p < q)
    cmp2 = -1;
    else if (p > q)
    cmp2 = 1;
    else
    sorry("Maybe not linear address model");
    if (i == 0) {
    j = (cmp1 != cmp2);
    } else if (cmp1 != (j ? -cmp2 : cmp2)) {
    sorry("Maybe not linear address model");
    }
    }
    }

    int
    main(void)
    {
    int i;
    unsigned int u;
    char *s;

    /* Basic assumptions */
    /* Two's complement, 8-bit char, at least 32-bit int */
    if (~1 != -2 || ~1L != -2L)
    sorry("Not a two's complement machine!");
    if (CHAR_BIT != 8)
    sorry("More than 8 bits in a byte!");
    if (UINT_MAX < 0xffffffffUL || INT_MAX < 0x7fffffffL)
    sorry("Too small int or unsigned int (needs 32 bits).");

    /* int or short is 32-bit without padding */
    /* Required by back-bdb/dbcache.c:bdb_db_hash() */
    if (sizeof(unsigned int) == 4) {
    s = "Padding bits in unsigned int";
    u = (unsigned int) -1;
    } else if (sizeof(unsigned short) == 4) {
    s = "Padding bits in unsigned short";
    u = (unsigned short) -1;
    } else {
    sorry("Couldn't find a 4-byte integer type");
    }
    /* count bits in u, expect 32 */
    for (i = 0; u; i++)
    u >>= 1;
    if ((unsigned)i != 32)
    sorry(s);

    #ifndef HAVE_EBCDIC
    /* Character set is ASCII */
    for (i = 0; i < 95; i++)
    if ((" !\"#$%&'()*+,-./0123456789:;<=>?"
    "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
    "`abcdefghijklmnopqrstuvwxyz{|}~" ) != i+32)
    break;
    if (i != 95 || '\n' != 10)
    sorry("Not an ASCII- or EBCDIC-based character set");
    #endif


    /* The next tests are not fireproof, but are better than nothing */

    /* Can cast function pointer to void* and back */
    /* Required at least by some threading stuff */
    if ((void (*)(const char *)) (void *) sorry != sorry
    || (void (*)(void)) (void *) test_malloc != test_malloc
    || (void *(*)(size_t)) (void *) malloc != malloc
    || (int (*)(const char *)) (void *) puts != puts
    || sizeof(void *) < sizeof(int (*)(void)))
    sorry("Cannot cast function pointers to void* and back");

    /* Test pointer comparison of malloced pointers */
    /* Required by slapd/sl_malloc */
    test_malloc();

    puts("OK");
    return EXIT_SUCCESS;
    }
     
    Hallvard B Furuseth, Jun 29, 2003
    #1
    1. Advertisements

  2. Whoops, that comment should be gone. The program has no such test; I
    believe I've exorcized that assumption from OpenLDAP.
     
    Hallvard B Furuseth, Jun 29, 2003
    #2
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.