I have attached my attempt at converting new.cpp "self" test to the new
driver.

Liviu
/***************************************************************************
 *
 * 0.new.cpp - test exercising replacement operator new and delete
 *
 * $Id$
 *
 ***************************************************************************
 *
 * Copyright (c) 1994-2005 Quovadx,  Inc., acting through its  Rogue Wave
 * Software division. Licensed under the Apache License, Version 2.0 (the
 * "License");  you may  not use this file except  in compliance with the
 * License.    You    may   obtain   a   copy   of    the   License    at
 * http://www.apache.org/licenses/LICENSE-2.0.    Unless   required    by
 * applicable law  or agreed to  in writing,  software  distributed under
 * the License is distributed on an "AS IS" BASIS,  WITHOUT WARRANTIES OR
 * CONDITIONS OF  ANY KIND, either  express or implied.  See  the License
 * for the specific language governing permissions  and limitations under
 * the License.
 * 
 **************************************************************************/

#include <new>

#include <cstddef>

#include <setjmp.h>
#include <signal.h>
#include <stdio.h>

#include <rw_new.h>
#include <driver.h>

int exit_status /* = 0 */;

extern "C" {

int line;
int fail;

jmp_buf env;

void handle_ABRT (int)
{
    fail = 0;

    longjmp (env, 1);
}

}

#define FAIL(code)                                                      \
    fail = line = __LINE__;                                             \
    signal (SIGABRT, handle_ABRT);                                      \
    if (0 == setjmp (env)) {                                            \
        code;                                                           \
        exit_status = 1;                                                \
        rw_assert (false, __FILE__, line, "expected assertion");        \
    }                                                                   \
    else                                                                \
        (void)0

#define PASS(code)                                                      \
    fail = -1; line = __LINE__;                                         \
    signal (SIGABRT, handle_ABRT);                                      \
    if (0 == setjmp (env))                                              \
        code;                                                           \
    else if (fail != line) {                                            \
        exit_status = 1;                                                \
        rw_assert (false, __FILE__, line, "unexpected assertion");      \
    } (void)0

/**************************************************************************/

void test_new_delete ()
{
    rw_info (0, __FILE__, __LINE__, 
             "exercising successful allocation and deallocation");

    {
        void *p = 0;
        PASS (p = operator new (0));
        rw_assert (p != 0, __FILE__, __LINE__, "operator new(0) != 0");
        operator delete (p);
    }

    {
        void *p = 0;
        PASS (p = operator new (1));
        rw_assert (p != 0, __FILE__, __LINE__, "operator new(1) != 0");
        operator delete (p);
    }

    {
        void *p = 0;
        PASS (p = operator new (2));
        rw_assert (p != 0, __FILE__, __LINE__, "operator new(2) != 0");
        operator delete (p);
    }

    {
        void *p = 0;
        PASS (p = operator new (1024));
        rw_assert (p != 0, __FILE__, __LINE__, "operator new(1024) != 0");
        operator delete (p);
    }
}

/**************************************************************************/

#define CATCH(code)                                     \
    try { code; fail = 1; }                             \
    catch (_RWSTD_BAD_ALLOC) { fail = 0; }              \
    catch (...) { fail = 2; }                           \
    rw_assert (!fail, __FILE__, __LINE__,               \
               "%s", 1 == fail ? "failed to throw" :    \
               "threw an unknown exception")

#define NOTHROW(code)                                                   \
    try { fail = 0; code; }                                             \
    catch (...) { fail = 1; }                                           \
    rw_assert (!fail, __FILE__, __LINE__, "unexpected exception")

void test_bad_alloc ()
{
    rw_info (0, __FILE__, __LINE__, 
             "exercising the ability of ordinary "
             "operator new to throw std::bad_alloc");

    rwt_free_store* const pst = rwt_get_free_store (0);

    *pst->throw_at_blocks_ [0] = pst->blocks_ [0];

    CATCH (operator new (0));
    CATCH (operator new (1));
    CATCH (operator new (2));
    CATCH (operator new (1024));

    {
        void *p = 0;
        NOTHROW (p = operator new[](0));
        operator delete[](p);
    }

    {
        void *p = 0;
        NOTHROW (p = operator new[](1));
        operator delete[](p);
    }

    {
        void *p = 0;
        NOTHROW (p = operator new[](2));
        operator delete[](p);
    }

    {
        void *p = 0;
        NOTHROW (p = operator new[](1024));
        operator delete[](p);
    }

    rw_info (0, __FILE__, __LINE__, 
             "exercising the ability of the array form "
             "of operator new to throw std::bad_alloc");

    *pst->throw_at_blocks_ [0] = std::size_t (-1);
    *pst->throw_at_blocks_ [1] = pst->blocks_ [1];

    CATCH (operator new[](0));
    CATCH (operator new[](1));
    CATCH (operator new[](2));
    CATCH (operator new[](1024));

    {
        void *p = 0;
        NOTHROW (p = operator new (0));
        rw_assert (p != 0, __FILE__, __LINE__, "operator new[](0) != 0");
        operator delete (p);
    }

    {
        void *p = 0;
        NOTHROW (p = operator new (1));
        rw_assert (p != 0, __FILE__, __LINE__, "operator new[](1) != 0");
        operator delete (p);
    }

    {
        void *p = 0;
        NOTHROW (p = operator new (32));
        rw_assert (p != 0, __FILE__, __LINE__, "operator new[](32) != 0");
        operator delete (p);
    }

    {
        void *p = 0;
        NOTHROW (p = operator new (4096));
        rw_assert (p != 0, __FILE__, __LINE__, "operator new[](4096) != 0");
        operator delete (p);
    }

    *pst->throw_at_blocks_ [1] = std::size_t (-1);
}

/**************************************************************************/

void test_new_delete_mismatch ()
{
    rw_info (0, __FILE__, __LINE__, 
             "exercising the ability to detect "
             "allocation/deallocation mismatches");
    
    {
        // detect allocations by operator new() deallocated
        // using (the array form of) operator delete[]
        void *p = 0;
        PASS (p = operator new (0));
        FAIL (operator delete[](p));
        PASS (operator delete (p));
    }

    {
        void *p = 0;
        PASS (p = operator new (1));
        FAIL (operator delete[](p));
        PASS (operator delete (p));
    }

    {
        void *p = 0;
        PASS (p = operator new[](33));
        FAIL (operator delete (p));
        PASS (operator delete[] (p));
    }
}

/**************************************************************************/

void test_bad_delete ()
{
    rw_info (0, __FILE__, __LINE__, 
             "exercising the ability to detect "
             "deletion of unallocated storage");

    {
        char *p = 0;
        PASS (p = new char);

        FAIL (delete (p - 1));
        FAIL (delete (p + 1));

        PASS (delete (p));
    }

    {
        char *p = 0;
        PASS (p = new char [4]);

        FAIL (delete (p - 1));
        FAIL (delete (p + 1));
        FAIL (delete (p + 2));
        FAIL (delete (p + 3));
        FAIL (delete (p + 4));

        FAIL (delete[] (p - 1));
        FAIL (delete[] (p + 1));
        FAIL (delete[] (p + 2));
        FAIL (delete[] (p + 3));
        FAIL (delete[] (p + 4));

        PASS (delete[] p);
    }
}

/**************************************************************************/

void test_double_delete ()
{
    rw_info (0, __FILE__, __LINE__, 
             "exercising the ability to detect double deletion");

    {
        char *p = 0;
        PASS (p = new char);

        PASS (delete (p));
        FAIL (delete (p));
    }

    {
        char *p = 0;
        PASS (p = new char [32]);

        PASS (delete[] p);
        FAIL (delete[] p);
        FAIL (delete p);
    }
}

/**************************************************************************/

void test_corruption ()
{
    rw_info (0, __FILE__, __LINE__, 
             "exercising the ability to detect memory corruption");

    // corrupt (and restore) memory past the end of the allocated block
    for (std::size_t i = 1; i != 8; ++i) {
        char *p = 0;
        PASS (p = new char);

        // save the value of the byte past the end of the block
        // and temporarily overwrite it with another value
        const char save = p [i];
        p [i] = ~p [i];

        // expect operator delete to diagnose the corruption
        // and call abort() without actually freeing the block
        FAIL (delete p);

        // restore the corrupted byte to its original value
        p [i] = save;

        // expect operator delete not to complain
        PASS (delete p);
    }
}

/**************************************************************************/

#define LEAK(code, bytes, blks)                                         \
    do {                                                                \
        /* establish a checkpoint for memory leaks */                   \
        rwt_check_leaks (0, 0);                                         \
                                                                        \
        code;                                                           \
                                                                        \
        /* find memory leaks since the last checkpoint */               \
        std::size_t nbytes;                                             \
        const std::size_t nblocks = rwt_check_leaks (&nbytes, 0);       \
                                                                        \
        rw_assert (blks == nblocks && bytes == nbytes,                  \
                   __FILE__, __LINE__,                                  \
                   "failed to detect a leak of %d bytes in "            \
                   "%d blocks: got %zu bytes in %zu blocks",            \
                   bytes, blks, nbytes, nblocks);                       \
    } while (0)


void test_leaks ()
{
    rw_info (0, __FILE__, __LINE__, 
             "exercising the ability to detect memory leaks");

    {
        void *p = 0;
        LEAK (p = operator new (0), 0, 1);
        PASS (operator delete (p));
    }

    {
        void *p = 0;
        LEAK (p = operator new (1), 1, 1);
        PASS (operator delete (p));
    }

    {
        void *p = 0;
        LEAK (p = operator new (1234), 1234, 1);
        PASS (operator delete (p));
    }

    {
        void *p0 = 0;
        void *p1 = 0;
        LEAK (p0 = operator new (32);
              p1 = operator new (64), 96, 2);
        PASS (operator delete (p0));
        PASS (operator delete (p1));
    }

    {
        void *p = 0;
        LEAK (p = operator new[] (12345), 12345, 1);
        PASS (operator delete[] (p));
    }
}

/**************************************************************************/

void stress_test ()
{
    rw_info (0, __FILE__, __LINE__, 
             "stress-testing replacement operators new and delete");

    rwt_free_store* const pst = rwt_get_free_store (0);

    std::size_t nblocks = pst->blocks_ [0] + pst->blocks_ [1];
    std::size_t nbytes  = pst->bytes_ [0] + pst->bytes_ [1];

    void* ptrs [1000];

    const std::size_t N = sizeof ptrs / sizeof *ptrs;

    for (std::size_t i = 0; i != N; ++i) {
        if (i % 2) {
            PASS (ptrs [i] = operator new[](i));
        }
        else {
            PASS (ptrs [i] = operator new (i));
        }
    }

    for (std::size_t i = 0; i < N; ++i) {

        const std::size_t j = (i * (i + 17)) % N;

        if (j % 2) {
            PASS (operator delete[](ptrs [j]));
        }
        else {
            PASS (operator delete (ptrs [j]));
        }

        ptrs [j] = 0;
    }

    for (std::size_t i = 0; i < N; ++i) {
        if (i % 2) {
            PASS (operator delete[](ptrs [i]));
        }
        else {
            PASS (operator delete (ptrs [i]));
        }
    }

    nblocks = pst->blocks_ [0] + pst->blocks_ [1] - nblocks;
    nbytes  = pst->bytes_ [0] + pst->bytes_ [1] - nbytes;

    rw_assert (0 == nblocks && 0 == nbytes, __FILE__, __LINE__,
               "false leaks detected: %zu bytes in %zu blocks", 
               nbytes, nblocks);
}

/**************************************************************************/

int run_test (int, char**)
{
    test_new_delete ();

    test_bad_alloc ();

    test_new_delete_mismatch ();

    test_double_delete ();

    test_bad_delete ();

    test_corruption ();

    test_leaks ();

    stress_test ();

    return 0;
}

/**************************************************************************/

int main (int argc, char** argv)
{
    return rw_test (argc, argv, __FILE__,
                    0 /* no clause */,
                    0 /* no comment */,
                    run_test, 0);
}

Reply via email to