ma_test.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,089 行 · 第 1/3 页

C
1,089
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  Heap management functions test.
*
****************************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <conio.h>

#ifdef __SW_BW
    #include <wdefwin.h>
#endif

#ifndef TRUE
    #define TRUE        1
    #define FALSE       0
#endif
#define ARGLENGTH       256
#define DOT_INTERVAL    512
#define WSIZE           sizeof(int)
#define SIZE_MARGIN     16

#define TEST_PASS       0
#define TEST_FAIL       1
#define TEST_NOMEM      2
#define TEST_NOSEG      3

#define TYPE_DEFAULT    0
#define TYPE_NEAR       1
#define TYPE_FAR        2
#define TYPE_BASED      3
#define TYPE_HUGE       4

#define FREED_BEFORE    0
#define FREED_AFTER     1
#define INTERNAL_ERR    255

#if !defined(__386__) && !defined(__AXP__) // Only appropriate to 16-bit versions
    #define     HUGE_NUM_EL     16384 // Must be a power of 2
#endif

#define NUM_EL  8175    // For double, 8175 * 8 = 65400 < 64k
// Note that NUM_EL has to be < 8192. Otherwise, we get overflow when
// calling malloc( NUM_EL * sizeof( double ) ).

#define BASED_HEAP_SIZE 512

// Casting _NULLOFF to long produces 0xFFFFFFFF, while casting the return of
// failing based heap routines to long produces 0xFFFF. At this point it is
// unclear whether that is a compiler bug, whether the _NULLOFF macro is wrong,
// or whether the test makes bad assumptions. For the moment, get around it
// by casting to unsigned in a few specific cases. This hack should be removed
// when it is determined what's actually wrong and the original problem fixed.
#define HACK_CAST   (unsigned)

// This is a macro performing everything needed before returning the call
#if defined(__386__) || defined(__AXP__)
    #define _CRET() {                                                   \
        if( doheapwlk ) AskHeapWlk( FREED_BEFORE, type, __LINE__ );     \
        if( type == TYPE_DEFAULT ) {                                    \
            free( (char *) ptr_char );                                  \
            free( (int *) ptr_int );                                    \
            free( (double *) ptr_double );                              \
        } else if( type == TYPE_NEAR ) {                                \
            _nfree( (char __near *) ptr_char );                         \
            _nfree( (int __near *) ptr_int );                           \
            _nfree( (double __near *) ptr_double );                     \
        }                                                               \
        if( doheapwlk ) AskHeapWlk( FREED_AFTER, type, __LINE__ );      \
        memavail = _memavl();                                           \
        return;                                                         \
    }
#else
    #define _CRET() {                                                   \
        if( doheapwlk ) AskHeapWlk( FREED_BEFORE, type, __LINE__ );     \
        if( type == TYPE_DEFAULT ) {                                    \
            free( (void *) ptr_char );                                  \
            free( (void *) ptr_int );                                   \
            free( (void *) ptr_double );                                \
        } else if( type == TYPE_NEAR ) {                                \
            _nfree( (void __near *) ptr_char );                         \
            _nfree( (void __near *) ptr_int );                          \
            _nfree( (void __near *) ptr_double );                       \
        } else if( type == TYPE_FAR ) {                                 \
            _ffree( (void __far *) ptr_char );                          \
            _ffree( (void __far *) ptr_int );                           \
            _ffree( (void __far *) ptr_double );                        \
        } else if( type == TYPE_BASED ) {                               \
            _DOBFREE();                                                 \
        } else if( type == TYPE_HUGE ) {                                \
            hfree( (void __huge *) ptr_char );                          \
            hfree( (void __huge *) ptr_int );                           \
            hfree( (void __huge *) ptr_double );                        \
        }                                                               \
        if( doheapwlk ) AskHeapWlk( FREED_AFTER, type, __LINE__ );      \
        memavail = _memavl();                                           \
        return;                                                         \
    }
#endif

// _NUL combines NULL and _NULLOFF
#if defined( __AXP__ ) || defined( __UNIX__ )
    #define _NUL        NULL
#else
    #define _NUL        (type == TYPE_BASED ? (long)_NULLOFF: (long)NULL)
#endif

// Macro to free based pointers and the corresponding segment
#define _DOBFREE() {                                            \
  if( (char __based(seg)*)ptr_char != _NULLOFF ) {              \
      _bfree( seg, (char __based(seg)*)ptr_char );              \
  }                                                             \
  if( (int __based(seg)*)ptr_int != _NULLOFF ) {                \
      _bfree( seg,(int __based(seg)*)ptr_int );                 \
  }                                                             \
  if( (double __based(seg)*)ptr_double != _NULLOFF ) {          \
      _bfree( seg,(double __based(seg)*)ptr_double);            \
  }                                                             \
}

typedef struct _test_result {
    char    funcname[80];
    int     status;
    char    msg[256];
} test_result;

#if !defined(__WINDOWS__) && !defined(__386__) && !defined(__AXP__)
    size_t      memrecord;
#endif
size_t memavail;
int more_debug = FALSE;
int nomem_lineno = 0;
int noseg_lineno = 0;
int dotrace = FALSE;
int dopause = FALSE;
int tracethisloop;
int doheapwlk = FALSE;
#if !defined(__386__) && !defined(__AXP__)
    __segment   seg = _NULLSEG;
#endif

static const char *errmsg[] = {
    "ABLE TO ALLOCATE MORE THAN ALL OF THE AVAILABLE STACK",            // 0
    "CANNOT ALLOCATE HALF OF THE AVAILABLE STACK",                      // 1
    "RETURNED NULL FOR char BUT SUCCEEDED FOR int OR double",           // 2
    "RETURNED NULL FOR int BUT SUCCEEDED FOR double",                   // 3
    "NOT ABLE TO CLEAR THE ALLOCATED MEMORY (SET TO ZERO)",             // 4
    "NOT ABLE TO REALLOCATE HALF THE ORIGINAL MEMORY BLOCK",            // 5
    "CONTENT OF THE REALLOCATED MEMORY IS ALTERED",                     // 6
    "_memavl() RETURNED A VALUE WHICH IS LESS THAN _memmax()",          // 7
    "NEAR AVAILABLE HEAP SHRINKED AFTER THIS FUNCTION CALL",            // 8
    "RETURNED VALUE IS INCORRECT",                                      // 9
    "REPORTED THAT LESS THAN 1 DOUBLE CAN BE ALLOCATED, BUG?",          // 10
    "CANNOT ALLOCATE THE RETURNED NUMBER OF DOUBLES",                   // 11
    "UNABLE TO ALLOCATE MEMORY OF SIZE SPECIFIED BY _memmax()",         // 12
    "VALUES RETURNED BY _memmax() are inconsistant",                    // 13
    "SUCCEEDED IN ALLOCATING MORE THAN AVAILABLE HEAP",                 // 14
    "NOT ABLE TO EXPAND THE BLOCK BACK TO THE SIZE IT WAS BEFORE",      // 15
    "FAILED IN ALLOCATING MEMORY FROM A FAR HEAP",                      // 16
    "FAILED IN ALLOCATING MEMORY FROM A 32-BIT NEAR HEAP",              // 17
    "FREE NEAR HEAP HAS SHRUNK AFTER ALLOCATING MEMORY FROM A FAR HEAP" // 18
};

void ShowDot( int ctr )
{
    if( ( ctr % DOT_INTERVAL ) == 0 ) putch( '.' );
}

void AskHeapWlk( int timing, int type, int lineno )
{
    char ans;

    if( type == TYPE_HUGE ) return;     // No huge _heapwalk()
    cprintf( "[-h] Dump the heap %s freeing? ",
             (timing == FREED_BEFORE ) ? "before" : "after" );
    ans = getche();
    cprintf( "\n\r" );
    if( ans == 'y' || ans == 'Y' ) {
        struct _heapinfo h_info;
        int heap_status;

        h_info._pentry = NULL;
        printf( "-----------------------------------------\n" );
        printf( "Heap walk result (%s freeing memory):\n",
                (timing == FREED_BEFORE ) ? "before" : "after" );
        for( ;; ) {
            switch( type ) {
                case TYPE_DEFAULT:
                    heap_status = _heapwalk( &h_info );
                    break;
                case TYPE_NEAR:
                    heap_status = _nheapwalk( &h_info );
                    break;
#if !defined(__386__) && !defined(__AXP__)
                case TYPE_FAR:
                    heap_status = _fheapwalk( &h_info );
                    break;
                case TYPE_BASED:
                    heap_status = _bheapwalk( seg, &h_info );
                    break;
#endif
                default:
                    heap_status = INTERNAL_ERR;
                    break;
            }
            if( heap_status != _HEAPOK ) break;
            printf( "  %s block at %Fp of size %4.4X\n",
                    ( h_info._useflag == _USEDENTRY ? "USED" : "FREE" ),
                    h_info._pentry, h_info._size );
        }
        switch( heap_status ) {
            case _HEAPEND:
                printf( "OK - end of heap\n" );
                break;
            case _HEAPEMPTY:
                printf( "OK - heap is empty\n" );
                break;
            case _HEAPBADBEGIN:
                printf( "ERROR - heap is damaged\n" );
                printf( "Reference: line #%d in source.\n", lineno );
                break;
            case _HEAPBADPTR:
                printf( "ERROR - bad pointer to heap\n" );
                printf( "Reference: line #%d in source.\n", lineno );
                break;
            case _HEAPBADNODE:
                printf( "ERROR - bad node in heap\n" );
                printf( "Reference: line #%d in source.\n", lineno );
                break;
            case INTERNAL_ERR:
                printf( "INTERNAL ERROR - unrecognized heap type\n" );
                break;
            default:
                break;
        }
        printf( "-----------------------------------------\n" );
    }
}

void Test_alloca_stackavail__memavl__memmax( test_result *result )
{
    size_t      ctr, buffsize, memsize;
    char        *buffer;
    char __near *near_buffer;

    if( more_debug ) {
        printf( "Testing: alloca(), stackavail(), " );
        printf( "_memavl(), _memmax()...\n" );
    }
    strcpy( result->funcname,"_memavl() or _memmax()" );
    memsize = _memmax();
    if( _memavl() < memsize ) {
        result->status = TEST_FAIL;
        strcpy( result->msg, errmsg[7] );
        return;
    }
    near_buffer = (char __near *) _nmalloc( memsize );
    if( near_buffer == NULL ) {
        strcpy( result->funcname, "_memmax() or _nmalloc()" );
        result->status = TEST_FAIL;
        strcpy( result->msg, errmsg[12] );
        return;
    }
    _nfree( near_buffer );
    if( memsize != _memmax() ) {
        strcpy( result->funcname, "_memmax() or _nfree()" );
        result->status = TEST_FAIL;
        strcpy( result->msg, errmsg[13] );
        return;
    }
    memsize = _memavl();
    strcpy( result->funcname,"stackavail() and/or alloca()" );

    buffsize = stackavail() + 1;
    buffer = alloca( buffsize ); // Allocate more than available stack size
    if( buffer != NULL ) {
        result->status = TEST_FAIL;
        strcpy( result->msg, errmsg[0] );
        return;
    }

    buffsize = stackavail() >> 1;
    buffer = alloca( buffsize ); // Allocate half of available stack size
    if( buffer == NULL ) {
        result->status = TEST_FAIL;
        strcpy( result->msg, errmsg[1] );
        return;
    }
    if( _memavl() < memsize ) {
        result->status = TEST_FAIL;
        strcpy( result->msg, errmsg[8] );
    }
    tracethisloop = AskTrace( result->funcname, __LINE__ );
    for( ctr = 0; ctr < buffsize; ++ctr ) {
        *(buffer + ctr) = 6;
        if( tracethisloop ) ShowDot( ctr );
    }   // Make sure that the buffer is accessible before returning
    if( tracethisloop ) cprintf( "\r\nTrace done. No problems detected.\r\n");
    result->status = TEST_PASS;
}

void Test_calloc__msize( test_result *result, int type )
{
    long        ptr_char   = NULL;
    long        ptr_int    = NULL;
    long        ptr_double = NULL;
    size_t      ctr, size, retsize, chkmemavl;

    switch( type ) {
        case TYPE_DEFAULT:
            if( more_debug ) {
                printf( "Testing: calloc(), msize()...\n" );
            }
            strcpy( result->funcname,"calloc()" );
            ptr_char   = (long) calloc( NUM_EL, sizeof( char ) );
            ptr_int    = (long) calloc( NUM_EL, sizeof( int ) );
            chkmemavl = _memavl();
            ptr_double = (long) calloc( NUM_EL, sizeof( double ) );
            break;
        case TYPE_NEAR:
            if( more_debug ) {
                printf( "Testing: _ncalloc(), _nmsize()...\n" );
            }
            strcpy( result->funcname,"_ncalloc()" );
            ptr_char   = (long) _ncalloc( NUM_EL, sizeof( char ) );
            ptr_int    = (long) _ncalloc( NUM_EL, sizeof( int ) );
            ptr_double = (long) _ncalloc( NUM_EL, sizeof( double ) );
            break;
#if !defined(__386__) && !defined(__AXP__)
        case TYPE_FAR:
            if( more_debug ) {
                printf( "Testing: _fcalloc(), _fmsize()...\n" );
            }
            strcpy( result->funcname,"_fcalloc()" );
            ptr_char   = (long) _fcalloc( NUM_EL, sizeof( char ) );

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?