


















                                         SafeHeap
                                         SafeHeap
                                         SafeHeap


                                       version  1.0








                    copyright (c) 1992 SeaBreeze Software Systems and

                                     Kenneth R. Stott



          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual


























































                                     - 2 -



               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0



                                    Table of Contents
                                    Table of Contents
                                    Table of Contents


               1. Introduction..........................................4


               2. Getting Started.......................................4


               3. Creating A Hardware Address File......................7


               4. Registering A Based Heap..............................8


               5. Registering An Autovariable or Static Variable........8


               6. Validating Routines...................................9


               7. Writing Your Own Validating Routines..................11


               8. SafeHeap Runtime Error Messages.......................12


               9. Using SafeHeap In An Overlaid System..................13


               10. Using SafeHeap Selectively...........................15


               11. Reconfiguring Your Application For Distribution......17


               12. Limitations..........................................17


               13. Support..............................................18


               14. Index................................................21



























                                          - 3 -



          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual





          1. Introduction
          1. Introduction
          1. Introduction


          SafeHeap is a cheap, quick, method of checking for errors in

          the usage of buffer manipulation and string routines. It

          requires no recompilation. Just relink, run your application

          and any suspect calls are reported to disk. Including

          suspected reads, writes, the name of the calling routine,

          the name of the called routine, an indication of the problem

          (like read from freed far heap pointer), and other

          statistics about the call. SafeHeap works with Borland C++,

          Microsoft C 6, and will also work with MoreHeap our heap

          replacement library. (MoreHeap is not required.)


          SafeHeap cannot find errors caused by direct assignment to

          memory locations, so the use of more general purpose

          overwrite detection software, like Bounds Checker, can still

          be helpful. Likewise, Bounds Checker may not find heap

          overwrite problems, or global data overwrite problems, until

          several calls after the original call (i.e. until the

          program's data is so badly corrupted that it causes a code

          overwrite). We view both of these products as complementary,

          and important quality control checks.


          SafeHeap will find overwrites of code, global data, the far

          heap, the near heap, based heaps, and reads and writes to

          wild pointers, and freed heap blocks--provided the read or

          write is done through the string or buffer manipulation

          routines. Because SafeHeap is a linkable solution it is

          often a better solution when working in C++ than solutions

          which depend on the preprocessor.


          SafeHeap will add about 8-9K to your application size and

          has zero overhead per heap allocation. SafeHeap must store a

          symbol table in memory but if it is available it will store

          the table in the high memory area, taking no space from your

          program's heap. The symbol table is limited to about 1,500

          public symbols, both data and code are included in the

          symbol table. In practice, very few programs should exceed

          this limit.



          2. Getting Started
          2. Getting Started
          2. Getting Started



          To use SafeHeap you must copy the SafeHeap modules to the

          appropriate directory for your project. The SafeHeap modules

          are:


          SHTCP
          SHTCP
          SHTCPX
               X
               X.OBJ
                .OBJ
                .OBJ:    The Turbo/Borland C++ SafeHeap modules where

          X represents Small, Medium, Large, Compact, and Huge memory

          models.



                                     - 4 -



               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0



               SHMC6
               SHMC6
               SHMC6X
                    X
                    X.OBJ
                     .OBJ
                     .OBJ:    The Microsoft C 6 SafeHeap modules where X

               represents Small, Medium, Large, Compact, and Huge memory

               models.


               Although you may not use it, you should also copy the

               SafeHeap header file, SafeHeap.h
                                     SafeHeap.h
                                     SafeHeap.h to the appropriate

               directory.


               Under Turbo/Borland C++, from the IDE simply include the

               appropriate SafeHeap module in your project file list and

               turn on the detailed map file option.


               If not in the Borland C++ IDE include the module name in

               tlink's OBJ file list and use the /m switch to create a

               detailed map file.


                    tlink c0l shtcpl test, test.exe, test.map, cl.lib /m
                    tlink c0l shtcpl test, test.exe, test.map, cl.lib /m
                    tlink c0l shtcpl test, test.exe, test.map, cl.lib /m


               When linking you may get duplicate symbols warnings--this is

               OK.


               Under Microsoft C 6 include the appropriate SafeHeap module

               in link's OBJ file list and make sure you use the /NOE

               switch (no extended dictionary search) and the /MAP switch

               (the detailed map file switch).


                    link /NOI /NOE /MAP shmc6l test, test.exe, test.map;
                    link /NOI /NOE /MAP shmc6l test, test.exe, test.map;
                    link /NOI /NOE /MAP shmc6l test, test.exe, test.map;


               After relinking your program make sure that the detailed map

               file and the executable file have the same name (e.g.

               TEST.EXE and TEST.MAP) and that they are located in the same

               directory. Now, just run your program. Depending on the

               number of calls to buffer and string manipulation routines

               your program's performance may degrade somewhat. When your

               program terminates look for a file with the same name as

               your executable file and an SHP extension (e.g. TEST.SHP).


               You can print this file or view it in your favorite editor.

               The sample report TEST.SHP illustrates the kind of

               information generated by SafeHeap. SafeHeap will report the

               following information when it suspects a problem.


               Problem


               Write to unreg'd region
               Write to unreg'd region
               Write to unreg'd region

               Read from unreg'd region
               Read from unreg'd region
               Read from unreg'd region   Write or Read from an unknown

                                          location. You have attempted to

                                          read data from a location that

                                          has not been registered through

                                          the MAP file, the SH_Register()

                                          function, or the Hardware Address

                                          File. The address cannot be an




                                          - 5 -



          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual



                                     autovariable because it falls

                                     outside of the stack.


          Write to freed heap block
          Write to freed heap block
          Write to freed heap block

          Read from freed heap block
          Read from freed heap block
          Read from freed heap block Write or Read from an area that

                                     is marked as free by the heap

                                     manager.


          Write to code region
          Write to code region
          Write to code region

          Read from code region
          Read from code region
          Read from code region      Write or Read from an area that

                                     appears to be code. Note that

                                     this check is not available under

                                     the huge memory model. Also,

                                     under Borland C++ reads/writes to

                                     arrays declared as far may be

                                     incorrectly reported as

                                     read/writes from/to code. In

                                     practice, there the number of

                                     arrays declared as far is quite

                                     limited. Under this situation we

                                     recommend you SH_Register() the

                                     array.


          Write past end of region
          Write past end of region
          Write past end of region

          Read past end of region
          Read past end of region
          Read past end of region    A Read or Write started from

                                     within a known region but

                                     extended beyond the end of the

                                     region.


          Bad Heap
          Bad Heap
          Bad Heap                   The heap has been corrupted


          VARIABLE


          The name of the region that the operation was attempted on:


          NEARHEAP
          NEARHEAP
          NEARHEAP       The heap manager's near heap region


          STACK
          STACK
          STACK          The item appears to be an autovariable


          FARHEAP
          FARHEAP
          FARHEAP        The heap manager's far heap region


          BASEHEAP
          BASEHEAP
          BASEHEAP       A Microsoft C based heap region


          ?              Not applicable based on the error code


          Other 
          Other 
          Other          The name of a global variable, function, a

                         named hardware address region, or a

                         registered region (via the SH_Register()

                         function).







                                     - 6 -



               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0



               VAR ADDR


               The beginning address of the region. If the region is

               unknown this is a ?.


               VAR SIZE



               The estimated length of the region. If unknown, shows as a

               ?.


               OP ADDR


               The beginning address of the operation.


               OP BYTES


               The number of bytes that the operation is attempting to read

               or write


               FUNCNAME


               The name of the string or buffer manipulation routine which

               is attempting the read or write.


               CALLED BY


               The name of the function that called the string/buffer

               manipulation routine. (Best guess as described above.)



               3. Creating A Hardware Address File
               3. Creating A Hardware Address File
               3. Creating A Hardware Address File


               The hardware address file allows you to specify regions of

               memory that are OK to read and write to but that do not

               represent declared variables or allocated memory, video ram

               for example. The hardware address file should be located in

               the same directory as your executable and have the same

               name, but with a HDW extension (e.g. TEST.EXE and TEST.HDW).


               The hardware address file must follow a very specific

               layout. SafeHeap provides no checking on valid syntax so it

               is important that you properly format this file. For example

               to indicate that it is OK to access the first 4K of video

               ram, in text mode, you would put this into the file.


                    B800:0000 04096 Video Ram
                    B800:0000 04096 Video Ram
                    B800:0000 04096 Video Ram


               The file must have no blank lines, positions 1-4 must be the

               region's segment in hex, positions 6-9 must be the regions

               offset in hex, positions 11-15 must be the region's length

               in decimal, and positions 17-48 is the region's name.




                                          - 7 -



          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual



          4. Registering A Based Heap
          4. Registering A Based Heap
          4. Registering A Based Heap


          If you are using the Microsoft C based heap routines you

          must either register the heap base segment through the

          hardware address file or must register it via the

          SH_BaseHeapReg() function.  For example, if you were using

          the expanded memory page frame starting at E000:0000 as a

          based heap you could register the heap by inserting this

          statement into your code:


               SH_BaseHeapReg ( 0xE000 );
               SH_BaseHeapReg ( 0xE000 );
               SH_BaseHeapReg ( 0xE000 );


          Once you have done this SafeHeap will now include the based

          heap at address 0xE000:0000 in its search for valid

          read/write regions.



          5. Registering An Autovariable or Static Variable
          5. Registering An Autovariable or Static Variable
          5. Registering An Autovariable or Static Variable



          When SafeHeap attempts to validate a read/write to an

          autovariable it is able to determine that the item is an

          autovariable but it can only guess at its size. Effectively

          SafeHeap assigns a size by subtracting the beginning address

          from the ending address of the stack. In this way SafeHeap

          can detect a write past the end of the stack, but not a

          write past the end of the autovariable storage itself.


          If you suspect an autovariable is being overwritten you may

          want to register that autovariable so that SafeHeap can use

          its exact size when determining if a read or write is valid.

          Remember, to register the autovariable only when it is in

          scope and unregister it before it goes out of scope, like

          this:


          #include "SAFEHEAP.H"
          #include "SAFEHEAP.H"
          #include "SAFEHEAP.H"


          void foo ( void )
          void foo ( void )
          void foo ( void )

          {
          {
          {

               int x;
               int x;
               int x;

               SH_Register
               SH_Register
               SH_Register(x);
                          (x);
                          (x);

               .
               .
               .

               .
               .
               .

               .
               .
               .

               SH_Unregister
               SH_Unregister
               SH_Unregister(x);
                            (x);
                            (x);

          }
          }
          }



          Similarly, when SafeHeap attempts to validate a read/write

          to a static variable it is able to determine that the item

          is global but it can only guess at the beginning of its

          region and its size. Effectively SafeHeap uses the beginning

          of the "previous" global variable and then uses the

          beginning of the "next" global variable to calculate its


                                     - 8 -



               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0



               size. In this way SafeHeap can detect a write past the end

               of the static, provided it is followed by a global.


               If you want the actual size and storage location of a static

               variable to be "known" by SafeHeap you can register it.

               using SH_Register() in the same way that autovariable's can

               be registered.


               SH_Register and SH_Unregister are macros which will only

               work on variables. If, for example, you wanted to register

               your program's program segment prefix ("PSP") you would use

               the function equivalent like this:


               .
               .
               .

               .
               .
               .

               .
               .
               .

               _sh_register
               _sh_register
               _sh_register ( "_PSP_", MK_FP ( psp, 0 ), 128 );
                            ( "_PSP_", MK_FP ( psp, 0 ), 128 );
                            ( "_PSP_", MK_FP ( psp, 0 ), 128 );

               .
               .
               .

               .
               .
               .

               .
               .
               .


               In a similar manner if your program reads or writes the

               environment table through the buffer manipulation routines

               you could register the environment table like this:


               .
               .
               .

               .
               .
               .

               .
               .
               .

               _sh_register
               _sh_register
               _sh_register (
                            (
                            (

                    "Environment Table",
                    "Environment Table",
                    "Environment Table",

                    SH_EnvTable
                    SH_EnvTable
                    SH_EnvTable(),SH_EnvLength
                               (),SH_EnvLength
                               (),SH_EnvLength()
                                              ()
                                              ()

               );
               );
               );

               .
               .
               .

               .
               .
               .

               .
               .
               .



               6. Validating Routines
               6. Validating Routines
               6. Validating Routines


               SafeHeap replaces the following routines with validating

               versions. Refer to your compiler's RTL manual for

               information on usage of these functions:


                    void *memccpy 
                    void *memccpy 
                    void *memccpy ( void *dest, const void *src, int c,
                                  ( void *dest, const void *src, int c,
                                  ( void *dest, const void *src, int c,

                      size_t n )
                      size_t n )
                      size_t n )


                    void far * far _fmemccpy
                    void far * far _fmemccpy
                    void far * far _fmemccpy(void far *dest, const void far
                                            (void far *dest, const void far
                                            (void far *dest, const void far

                      *src, int c, size_t n )
                      *src, int c, size_t n )
                      *src, int c, size_t n )


                    void *memcpy 
                    void *memcpy 
                    void *memcpy ( void *__dest,               const void *
                                 ( void *__dest,               const void *
                                 ( void *__dest,               const void *

                      __src, size_t __n )
                      __src, size_t __n )
                      __src, size_t __n )





                                          - 9 -



          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual



               char far * far _fmemcpy
               char far * far _fmemcpy
               char far * far _fmemcpy ( char far *__dest, const char
                                       ( char far *__dest, const char
                                       ( char far *__dest, const char

                 far *__src, size_t __n )
                 far *__src, size_t __n )
                 far *__src, size_t __n )


               void setmem
               void setmem
               void setmem(void *dest, int length, char value)
                          (void *dest, int length, char value)
                          (void *dest, int length, char value)


               void *memset
               void *memset
               void *memset(void *s, int c, size_t n)
                           (void *s, int c, size_t n)
                           (void *s, int c, size_t n)


               void far * far _fmemset 
               void far * far _fmemset 
               void far * far _fmemset (void far *s, int c, size_t n)
                                       (void far *s, int c, size_t n)
                                       (void far *s, int c, size_t n)


               void *memmove 
               void *memmove 
               void *memmove ( void *__dest, const void * __src,
                             ( void *__dest, const void * __src,
                             ( void *__dest, const void * __src,

                 size_t __n )
                 size_t __n )
                 size_t __n )


               void movmem 
               void movmem 
               void movmem ( void *src, void *dest,          unsigned
                           ( void *src, void *dest,          unsigned
                           ( void *src, void *dest,          unsigned

                 length )
                 length )
                 length )


               void movedata 
               void movedata 
               void movedata ( unsigned srcseg, unsigned srcoff,
                             ( unsigned srcseg, unsigned srcoff,
                             ( unsigned srcseg, unsigned srcoff,

                 unsigned destseg, unsigned destoff, size_t n )
                 unsigned destseg, unsigned destoff, size_t n )
                 unsigned destseg, unsigned destoff, size_t n )


               void far * far _fmemcpy 
               void far * far _fmemcpy 
               void far * far _fmemcpy ( void far *__dest, const void
                                       ( void far *__dest, const void
                                       ( void far *__dest, const void

                 far * __src, size_t __n )
                 far * __src, size_t __n )
                 far * __src, size_t __n )


               char *strcpy 
               char *strcpy 
               char *strcpy ( char * dest, const char *src )
                            ( char * dest, const char *src )
                            ( char * dest, const char *src )


               char far * far _fstrcpy 
               char far * far _fstrcpy 
               char far * far _fstrcpy ( char far *dest, const char
                                       ( char far *dest, const char
                                       ( char far *dest, const char

                 far *src )
                 far *src )
                 far *src )


               char *stpcpy 
               char *stpcpy 
               char *stpcpy ( char * dest, const char *src )
                            ( char * dest, const char *src )
                            ( char * dest, const char *src )


               char far * far _fstpcpy
               char far * far _fstpcpy
               char far * far _fstpcpy ( char far *dest, const char
                                       ( char far *dest, const char
                                       ( char far *dest, const char

                 far *src )
                 far *src )
                 far *src )


               char *strcat 
               char *strcat 
               char *strcat ( char *dest, const char *src )
                            ( char *dest, const char *src )
                            ( char *dest, const char *src )


               char far * far _fstrcat
               char far * far _fstrcat
               char far * far _fstrcat ( char far *dest, const char
                                       ( char far *dest, const char
                                       ( char far *dest, const char

                 far *src )
                 far *src )
                 far *src )


               char *strncat 
               char *strncat 
               char *strncat ( char *dest, const char *src, size_t
                             ( char *dest, const char *src, size_t
                             ( char *dest, const char *src, size_t

                 maxlen )
                 maxlen )
                 maxlen )


               char far * far _fstrncat
               char far * far _fstrncat
               char far * far _fstrncat ( char far *dest, const char
                                        ( char far *dest, const char
                                        ( char far *dest, const char

                 far *src, size_t maxlen )
                 far *src, size_t maxlen )
                 far *src, size_t maxlen )


               char *strnset 
               char *strnset 
               char *strnset ( char *s, int ch, size_t n )
                             ( char *s, int ch, size_t n )
                             ( char *s, int ch, size_t n )


               char far * far _fstrnset
               char far * far _fstrnset
               char far * far _fstrnset ( char far *s, int ch, size_t
                                        ( char far *s, int ch, size_t
                                        ( char far *s, int ch, size_t

                 n )
                 n )
                 n )


               char *strset 
               char *strset 
               char *strset ( char *s, int ch )
                            ( char *s, int ch )
                            ( char *s, int ch )


               char far * far _fstrset
               char far * far _fstrset
               char far * far _fstrset ( char far *s, int ch )
                                       ( char far *s, int ch )
                                       ( char far *s, int ch )


               char *strncpy 
               char *strncpy 
               char *strncpy ( char * dest, const char *src, size_t n
                             ( char * dest, const char *src, size_t n
                             ( char * dest, const char *src, size_t n

                 )
                 )
                 )



                                     - 10 -



               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0



                    char far * far _fstrncpy
                    char far * far _fstrncpy
                    char far * far _fstrncpy ( char far *dest, const char
                                             ( char far *dest, const char
                                             ( char far *dest, const char

                      far *src, size_t n )
                      far *src, size_t n )
                      far *src, size_t n )


                    char *strrev
                    char *strrev
                    char *strrev(char *s)
                                (char *s)
                                (char *s)


                    char far * far _fstrrev
                    char far * far _fstrrev
                    char far * far _fstrrev(char far *s)
                                           (char far *s)
                                           (char far *s)


                    char *strlwr 
                    char *strlwr 
                    char *strlwr ( char *s )
                                 ( char *s )
                                 ( char *s )


                    char far * far _fstrlwr
                    char far * far _fstrlwr
                    char far * far _fstrlwr ( char far *s )
                                            ( char far *s )
                                            ( char far *s )


                    char *strupr 
                    char *strupr 
                    char *strupr ( char *s )
                                 ( char *s )
                                 ( char *s )


                    char far * far _fstrupr 
                    char far * far _fstrupr 
                    char far * far _fstrupr ( char far *s )
                                            ( char far *s )
                                            ( char far *s )



               7. Writing Your Own Validating Routines
               7. Writing Your Own Validating Routines
               7. Writing Your Own Validating Routines


               If you want to write validating versions of other RTL

               routines or your own routines you can use these functions:


                    void far *SH_GetRetAddress
                    void far *SH_GetRetAddress
                    void far *SH_GetRetAddress ( unsigned ss, unsigned bp);
                                               ( unsigned ss, unsigned bp);
                                               ( unsigned ss, unsigned bp);



               Pass the stack segment and base pointer to this function and

               it returns the last return address on the stack.


                    int SH_ReadOK 
                    int SH_ReadOK 
                    int SH_ReadOK ( void far *__src, size_t __n,
                                  ( void far *__src, size_t __n,
                                  ( void far *__src, size_t __n,

                      char funcname, void far *raddr );
                      char funcname, void far *raddr );
                      char funcname, void far *raddr );



               Pass a pointer to a region, a length, the name of function

               wanting to read the region,  and the return address. Returns

               a 1 if permission is granted, otherwise returns a 0.


                    int SH_WriteOK 
                    int SH_WriteOK 
                    int SH_WriteOK ( void far *__src, size_t __n, char
                                   ( void far *__src, size_t __n, char
                                   ( void far *__src, size_t __n, char

                      *funcname, void far *raddr );
                      *funcname, void far *raddr );
                      *funcname, void far *raddr );



               Pass a pointer to a region, a length, the name of function

               wanting to write to the region,  and the return address.

               Returns a 1 if permission is granted, otherwise returns a 0.


                    int SH_TransferOK ( void * far __dest,
                    int SH_TransferOK ( void * far __dest,
                    int SH_TransferOK ( void * far __dest,

                      const void far *__src, size_t __n,
                      const void far *__src, size_t __n,
                      const void far *__src, size_t __n,

                      char *funcname, void far raddr);
                      char *funcname, void far raddr);
                      char *funcname, void far raddr);



               Pass a pointer to a destination region, a source region, the

               number of bytes to transfer, the name of function wanting to

               write to the region,  and the return address. Returns a 1 if

               the bytes were transferred, returns a 0 if denied. Note that

               this function is different than SH_ReadOK() and SH_WriteOK()



                                          - 11 -



          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual



          in that it also does the transfer as opposed to just asking

          for permission.


          For example, a strlwr() function would be implemented like

          this:


          #include "SAFEHEAP.H"
          #include "SAFEHEAP.H"
          #include "SAFEHEAP.H"

          #include <ctype.h>
          #include <ctype.h>
          #include <ctype.h>


          char *strlwr
          char *strlwr
          char *strlwr ( char *s )
                       ( char *s )
                       ( char *s )

          {
          {
          {

               char *_s = s;
               char *_s = s;
               char *_s = s;       // Make copy to increment on.
                                   // Make copy to increment on.
                                   // Make copy to increment on.

               unsigned i;
               unsigned i;
               unsigned i;         // Counter.
                                   // Counter.
                                   // Counter.

               unsigned l;
               unsigned l;
               unsigned l;         // Length of string.
                                   // Length of string.
                                   // Length of string.

               unsigned __bp;
               unsigned __bp;
               unsigned __bp;      // Base pointer to stack.
                                   // Base pointer to stack.
                                   // Base pointer to stack.

               unsigned __s;
               unsigned __s;
               unsigned __s;       // Stack segment.
                                   // Stack segment.
                                   // Stack segment.

               asm{mov __bp,BP}
               asm{mov __bp,BP}
               asm{mov __bp,BP}    // Get base pointer.
                                   // Get base pointer.
                                   // Get base pointer.

               asm{mov __s,SS}
               asm{mov __s,SS}
               asm{mov __s,SS}     // Get stack segment.
                                   // Get stack segment.
                                   // Get stack segment.

               for ( l = 0; *_s;
               for ( l = 0; *_s;
               for ( l = 0; *_s;

                    l++, _s++ );
                    l++, _s++ );
                    l++, _s++ );   // Get length of string.
                                   // Get length of string.
                                   // Get length of string.


               // Ask for permission to write to string.
               // Ask for permission to write to string.
               // Ask for permission to write to string.

               if (
               if (
               if (

                    SH_WriteOK 
                    SH_WriteOK 
                    SH_WriteOK (
                               (
                               (

                         // Pointer to region.
                         // Pointer to region.
                         // Pointer to region.

                         // Length of write.
                         // Length of write.
                         // Length of write.

                         "strlwr", // Name of function.
                         "strlwr", // Name of function.
                         "strlwr", // Name of function.

                         // Use this function to get return 
                         // Use this function to get return 
                         // Use this function to get return 

                         // address.
                         // address.
                         // address.

                         SH_GetRetAddress 
                         SH_GetRetAddress 
                         SH_GetRetAddress ( __s, __bp )
                                          ( __s, __bp )
                                          ( __s, __bp )

                    )
                    )
                    )

               ) {
               ) {
               ) {

                    // Convert string.
                    // Convert string.
                    // Convert string.

                    for ( _s = s, i = 0; i < l; i++, _s++ ) {
                    for ( _s = s, i = 0; i < l; i++, _s++ ) {
                    for ( _s = s, i = 0; i < l; i++, _s++ ) {

                       *_s = _tolower ( *_s );
                       *_s = _tolower ( *_s );
                       *_s = _tolower ( *_s );

                   }
                   }
                   }

               }
               }
               }

               return ( s );
               return ( s );
               return ( s );

          }
          }
          }



          8. SafeHeap Runtime Error Messages
          8. SafeHeap Runtime Error Messages
          8. SafeHeap Runtime Error Messages


          SafeHeap may terminate your application with the following

          error messages:



          Unable to open XXX.SHP. Press any key to terminate.
          Unable to open XXX.SHP. Press any key to terminate.
          Unable to open XXX.SHP. Press any key to terminate.


          For some reason SafeHeap could not open its report file.

          Check to make sure that there is enough disk space on the

          same drive your executable file is located.




                                     - 12 -



               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0



               Unable to locate XXX.MAP Press any key to terminate.
               Unable to locate XXX.MAP Press any key to terminate.
               Unable to locate XXX.MAP Press any key to terminate.



               For some reason SafeHeap could not find the map file. Check

               to make sure that a valid map file exists.


               Unable to allocate enough space for symbol table.
               Unable to allocate enough space for symbol table.
               Unable to allocate enough space for symbol table.

               Press any key to terminate.
               Press any key to terminate.
               Press any key to terminate.


               SafeHeap could not allocate enough space for its symbol

               table. Try installing HIMEM.SYS to allow SafeHeap to use the

               High Memory Area for its symbol table. SafeHeap can only

               handle about 1,500 public symbols in a map file.


               If HIMEM.SYS is installed and your application has less than

               1,500 public symbols, but your application does not exit

               through the exit() function, you have probably used the high

               memory area in a previous run without releasing it. Reboot

               your machine to reset the high memory area, then modify your

               code to terminate through the exit() function and rebuild

               your executable.



               9. Using SafeHeap In An Overlaid System
               9. Using SafeHeap In An Overlaid System
               9. Using SafeHeap In An Overlaid System


               If you are using SafeHeap with an overlay linker, that

               overlays code, the calling function will not be reported

               correctly. As an alternative you can create your own debug

               callback function and then using a debugger set a break on

               the callback function. When the callback function is

               executed you should be able to use the stack display of your

               debugger to determine the offending caller. (You might also

               want to use this feature when using C++.  C++ name mangling

               may make function names derived from the map file not

               useful.)


               A debug callback function must take the following arguments:


               void sh_prob (
               void sh_prob (
               void sh_prob (

                    int op, unsigned sz,
                    int op, unsigned sz,
                    int op, unsigned sz,

                    char far *vname, void far *vaddr,
                    char far *vname, void far *vaddr,
                    char far *vname, void far *vaddr,

                    void far *baddr, char far * func,
                    void far *baddr, char far * func,
                    void far *baddr, char far * func,

                    char far * cfunc, unsigned long vsz
                    char far * cfunc, unsigned long vsz
                    char far * cfunc, unsigned long vsz );



               op
               op
               op          represents the error code. op
                                                      op
                                                      op can be one of

                           these defined constants:


                           INIT
                           INIT
                           INIT         Create the output file and write

                                        the report headings.


                           WUNK 
                           WUNK 
                           WUNK or
                                or
                                or

                           RUNK
                           RUNK
                           RUNK         Write or Read from an unknown

                                        location. You have attempted to


                                          - 13 -



          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual



                                   read data from a location that has

                                   not been registered through the MAP

                                   file, the SH_Register() function,

                                   or the Hardware Address File. The

                                   address cannot be an autovariable

                                   because it falls outside of the

                                   stack.


                      WCODE
                      WCODE
                      WCODE 
                            
                            or
                            or
                            or

                      RCODE
                      RCODE
                      RCODE        Write or Read to a location that

                                   appears to be code. You have

                                   attempted to read data from a

                                   location that based on an analysis

                                   of the map file appears to be code.

                                   This check is not performed under

                                   the huge memory model. Likewise,

                                   under Borland C++ this error may be

                                   incorrectly generated when

                                   accessing an array declared as far

                                   when under the large or medium

                                   memory model.


                      WFRE 
                      WFRE 
                      WFRE or
                           or
                           or

                      RFRE
                      RFRE
                      RFRE         Write or Read from an area that is

                                   marked as free by the heap manager.


                      ORD 
                      ORD 
                      ORD or OWRT
                             OWRT
                             OWRT  A Read or Write started from within

                                   a known region but extended beyond

                                   the end of the region.


          sz
          sz
          sz          is the number of bytes being read or written.


          vname
          vname
          vname       is the name of the regions being read or

                      written.


          vaddr
          vaddr
          vaddr       is a far pointer to the beginning of the region

                      being read or written.


          baddr
          baddr
          baddr       is a far pointer to the beginning of the

                      read/write operation.


          func
          func
          func        is the name of the buffer or string

                      manipulation routine being used.


          cfunc
          cfunc
          cfunc       is the name of the function calling the string

                      or buffer manipulation routine.


          vsz
          vsz
          vsz         the length of the region being read

                      from/written to.







                                     - 14 -



               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0



               You register the callback function like this:


               #include "SAFEHEAP.H"
               #include "SAFEHEAP.H"
               #include "SAFEHEAP.H"

               void problem (
               void problem (
               void problem (

                    int op, unsigned sz,
                    int op, unsigned sz,
                    int op, unsigned sz,

                    char far *vname, 
                    char far *vname, 
                    char far *vname,    void far *vaddr,
                                        void far *vaddr,
                                        void far *vaddr,

                    void far *baddr, 
                    void far *baddr, 
                    void far *baddr,    char far * func,
                                        char far * func,
                                        char far * func,

                    char far * cfunc )
                    char far * cfunc )
                    char far * cfunc )

               {
               {
               {

                    printf("problem")
                    printf("problem")
                    printf("problem")

               }
               }
               }


               void main ( void )
               void main ( void )
               void main ( void )

               {
               {
               {

                    SH_SetErrFunc
                    SH_SetErrFunc
                    SH_SetErrFunc ( problem );
                                  ( problem );
                                  ( problem );

                    .
                    .
                    .

                    .
                    .
                    .

                    .
                    .
                    .

               }
               }
               }


               Remember to register the callback function as soon as

               possible. Otherwise, you may find that your callback

               function will miss the initialization call. If your callback

               function specifically relies on the INIT notification this

               could create a situation where the report file is not

               created, does not contain column headings, or other similar

               problems.


               If you are using an overlay linker that overlays data as

               well, you can configure SafeHeap to only check buffer and

               string manipulation routines writing or reading the heap

               area by calling the function SH_HeapOnly() as your first

               statement in main(), like this:


               #include "SAFEHEAP.H"
               #include "SAFEHEAP.H"
               #include "SAFEHEAP.H"

               void main ( void )
               void main ( void )
               void main ( void )

               {
               {
               {

                    SH_HeapOnly();
                    SH_HeapOnly();
                    SH_HeapOnly();

                    .
                    .
                    .

                    .
                    .
                    .

                    .
                    .
                    .

               }
               }
               }


               10. Using SafeHeap Selectively
               10. Using SafeHeap Selectively
               10. Using SafeHeap Selectively


               SafeHeap can degrade performance. To improve performance you

               can "turn off" SafeHeap by calling SH_Disable(), to reenable

               SafeHeap just call SH_Enable(). Every SH_Disable() must be

               matched by and SH_Enable() to reenable SafeHeap.







                                          - 15 -



          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual



          For example, if you have a screen intensive application that

          memcpy()'s to video ram often you may want to disable

          SafeHeap during screen updates. You could do that like this:


          #include "SAFEHEAP.H"
          #include "SAFEHEAP.H"
          #include "SAFEHEAP.H"


          void UpdateScreen ( void )
          void UpdateScreen ( void )
          void UpdateScreen ( void )

          {
          {
          {

               SH_Disable();
               SH_Disable();
               SH_Disable();

               .
               .
               .

               // Update screen here
               // Update screen here
               // Update screen here

               .
               .
               .

               SH_Enable();
               SH_Enable();
               SH_Enable();

          }
          }
          }


          You can also affect SafeHeap's operation through environment

          variables. If the environment variable SAFEHEAP does not

          exist and SafeHeap detects a bad buffer manipulation request

          it will report the problem and NOT perform the operation,

          this is the default mode of operation. If the environment

          variable SAFEHEAP exists, however, SafeHeap will operate in

          one of four modes as follows:


          set SAFEHEAP=OFF
          set SAFEHEAP=OFF
          set SAFEHEAP=OFF


          SafeHeap will not attempt to detect bad buffer manipulation

          requests. (Speeds up your program).


          set SAFEHEAP=ON
          set SAFEHEAP=ON
          set SAFEHEAP=ON


          Equivalent to the default mode of operation, where SafeHeap

          will detect bad buffer manipulation requests, report them,

          and NOT perform them. WARNING! This mode of operation may

          "break" programs that read or write to the program segment

          prefix, the program's environment table, or other

          "unregistered" locations. In this case you may want to

          either modify your code to register these locations or use

          the following option.


          For example, if your program writes to the PSP you might

          want to include this code:


          .
          .
          .

          .
          .
          .

          .
          .
          .

          _sh_register
          _sh_register
          _sh_register ( "_PSP_", MK_FP ( _psp, 0 ), 128 );
                       ( "_PSP_", MK_FP ( _psp, 0 ), 128 );
                       ( "_PSP_", MK_FP ( _psp, 0 ), 128 );

          .
          .
          .

          .
          .
          .

          .
          .
          .


          set SAFEHEAP=REPORT
          set SAFEHEAP=REPORT
          set SAFEHEAP=REPORT





                                     - 16 -



               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0



               SafeHeap will detect bad buffer manipulation requests,

               report them, and perform them (This may affect the integrity

               of your application).


               set SAFEHEAP=ABORT
               set SAFEHEAP=ABORT
               set SAFEHEAP=ABORT


               SafeHeap will detect bad buffer manipulation requests,

               report them, not perform them, and immediately abort the

               application.



               11. Reconfiguring Your Application For Distribution
               11. Reconfiguring Your Application For Distribution
               11. Reconfiguring Your Application For Distribution


               If you have used any SafeHeap specific calls in your

               application you can recompile with the constant NOSAFEHEAP

               defined. This will #define out any SafeHeap-specific calls.

               In addition, remove the SafeHeap module from your linker

               instructions.



               12. Limitations
               12. Limitations
               12. Limitations



               SafeHeap uses the map file and the heap structures to

               determine the block of memory being written to or read from.

               Because the map file only lists public symbols SafeHeap can

               only guess at the size of certain items. For example, if a

               global integer (2 bytes) called nelem, is followed by a

               static integer in a module SafeHeap will incorrectly "guess"

               that the symbol nelem is 4 bytes long. In practice this is

               rarely a problem, but it does mean that writes to global

               data that write past it and into statically declared data

               will not be detected by SafeHeap.


               In a similar manner, the calling function is determined by

               interrogating the map file. If a buffer manipulation routine

               is called from a statically declared function the report

               file will improperly report that the routine was called by

               the function which is located "above" it in that module.


               SafeHeap will "guess" that pointers to physical addresses,

               like video ram or the EMS page frame are invalid and report

               writes to and reads from them.  To get around this you can

               supply a list of valid regions, their physical addresses and

               lengths, in a hardware address file.  SafeHeap will read

               this file and NOT report reads and writes within these

               regions.


               SafeHeap cannot check the validity of Microsoft C based

               pointers. It will assume that any reads or writes to based

               pointers are invalid. If the based pointer references the

               EMS page frame, the High Memory Area, or some other physical

               address you can add the region to the hardware address file.

               Or, you can modify the code to register the based heap's


                                          - 17 -



          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual
          SafeHeap version 1.0                        Reference Manual



          segment. Once this is done SafeHeap will include the based

          heap in its checking algorithms.


          SafeHeap can determine that a pointer references an item on

          the stack but it can't tell how big the item is. It can

          compute a maximum length, based on the total size of the

          stack, and determine if you are reading or writing past the

          end of the stack. If you suspect that an autovariable is

          being overwritten you can modify the code by including a

          function to register the autovariable with SafeHeap. This

          provides SafeHeap with the actual size of the item and

          allows it to do a better job of checking.


          SafeHeap cannot check for code overwrites under the huge

          memory model. Likewise, SafeHeap may incorrectly report

          accesses to arrays declared as far under Borland C++ and the

          large or medium memory models as read/writes from/to code.

          We recommend that you SH_Register() arrays declared far like

          this:


          far char BigBuffer[50000];
          far char BigBuffer[50000];
          far char BigBuffer[50000];

          void main ( void )
          void main ( void )
          void main ( void )

          {
          {
          {

               .
               .
               .

               .
               .
               .

               .
               .
               .

               SH_Register
               SH_Register
               SH_Register ( BigBuffer );
                           ( BigBuffer );
                           ( BigBuffer );

               .
               .
               .

               .
               .
               .

               .
               .
               .

          }
          }
          }


          SafeHeap will not find doubly-freed pointers or dangling

          pointers. SeaBreeze's MoreHeap can provide these features

          for you as well as provide virtual memory management, heap

          defragmentation and compaction, and automatic detection and

          use of extra addressable memory supplied by DOS5, QEMM,

          QRAM, and HIMEM.



          13. Support
          13. Support
          13. Support


          Registered users may obtain technical support Monday-Friday

          9:00AM to 5:00PM EST.  Support is available via:


                    Compuserve, e-mail to account 72330,705.


                    Voice, (609) 924-6793


                    BBS, (908) 359-0546 (300/1200/2400, N-8-1)


          Please provide your name and registration number and a

          detailed description of your problem or question.  In the

          event of a problem also provide your compiler manufacturer


                                     - 18 -



               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0
               Reference Manual                        SafeHeap version 1.0



               and version number, computer hardware configuration, and the

               contents of your autoexec.bat and config.sys files.






















































                                          - 19 -



               Reference Manual                             SafeHeap
               Reference Manual                             SafeHeap
               Reference Manual                             SafeHeap

               version 1.0
               version 1.0
               version 1.0



               14. Index
               14. Index
               14. Index



               _fmemccpy, 9                    hardware address file,

               _fmemcpy, 10                    7,14,17

                                               hardware address region, 6

               _fmemset, 10

               _fstpcpy, 10                    High Memory Area, 13

                                               HIMEM.SYS, 13

               _fstrcat, 10

               _fstrcpy, 10                    huge memory model, 6,14,18

                                               INIT, 13,15

               _fstrlwr, 11

               _fstrncat, 10                   map file, 5,13,17

                                               memccpy, 9

               _fstrncpy, 11

               _fstrnset, 10                   memcpy, 9

                                               memmove, 10

               _fstrrev, 11

               _fstrset, 10                    memory models, 4

                                               memset, 10

               _fstrupr, 11

               _sh_register, 9,16              Microsoft C, 4,8,17

                                               MoreHeap, 4,18

               autovariable, 8,14,18

               Bad Heap, 6                     movedata, 10

                                               movmem, 10

               based heap, 8,17

               based pointers, 17              NEARHEAP, 6

                                               NOSAFEHEAP, 17

               BASEHEAP, 6

               BBS, 18                         ORD, 14

                                               overhead, 4

               Borland C++, 4,6,14,18

               Bounds Checker, 4               overlay linker, 13,15

                                               OWRT, 14

               callback function, 15

               Compuserve, 18                  physical addresses, 17

                                               program segment prefix, 9

               dangling pointers, 18

               doubly-freed pointers, 18       project file, 5

                                               PSP, 9,16

               duplicate symbols, 5

               e-mail, 18                      RCODE, 14

                                               Read from code region, 6

               EMS page frame, 17

               environment table, 9            Read from freed heap block,

                                               6

               environment variables, 16       Read from unreg'd region, 5

               Error Messages, 12

                                               report, 5

               FARHEAP, 6                      report file, 12,17

               global variable, 6


                                          - 21 -



          SafeHeap version 1.0                             Reference
          SafeHeap version 1.0                             Reference
          SafeHeap version 1.0                             Reference

          Manual
          Manual
          Manual


          RFRE, 14                        technical support, 18


          RUNK, 13,14                     unregister, 8

          SAFEHEAP=ABORT, 17              Validating Routines, 11


          SAFEHEAP=OFF, 16                variable sizes, 17

          SAFEHEAP=ON, 16                 video ram, 17


          SAFEHEAP=REPORT, 16             WCODE, 14

          setmem, 10                      WFRE, 14


          SH_BaseHeapReg, 8               Write to code region, 6

          SH_Disable(), 15                Write to freed heap block,

                                          6

          SH_Enable, 15

          SH_EnvLength, 9                 Write to unreg'd region, 5

                                          WUNK, 13,14

          SH_EnvTable, 9

          SH_GetRetAddress, 11,12


          SH_HeapOnly(), 15

          SH_ReadOK, 11


          SH_Register,

          5,6,8,9,14,16,18

          SH_SetErrFunc, 15


          SH_Unregister, 8,9

          SH_WriteOK, 11,12


          STACK, 6

          static variable, 8


          statically declared

          functions, 17

          stpcpy, 10


          strcat, 10

          strcpy, 10


          strlwr, 11,12

          strncat, 10


          strncpy, 10

          strnset, 10


          strrev, 11

          strset, 10


          strupr, 11

          symbol table, 4,13


          symbol table limit, 4



                                     - 22 -