delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2015/03/28/05:12:38

X-Authentication-Warning: delorie.com: mail set sender to djgpp-bounces using -f
X-Recipient: djgpp AT delorie DOT com
Message-ID: <55167074.3070503@iki.fi>
Date: Sat, 28 Mar 2015 11:12:20 +0200
From: Andris Pavenis <andris DOT pavenis AT iki DOT fi>
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.4.0
MIME-Version: 1.0
To: djgpp AT delorie DOT com
Subject: Re: djgpp v2.04 release?
References: <almarsoft DOT 626743527885021598 AT news DOT free DOT fr> <201503280004 DOT t2S044ke019699 AT envy DOT delorie DOT com>
In-Reply-To: <201503280004.t2S044ke019699@envy.delorie.com>
Reply-To: djgpp AT delorie DOT com

This is a multi-part message in MIME format.
--------------080207060608030503020708
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 7bit

On 03/28/2015 02:04 AM, DJ Delorie wrote:
>> I guess the real question would be: is there anything inherently
>> wrong with v2.04 that it is kept in beta stage ? or any roadmap that
>> would indicate what is missing yet?
> Originally, there were issues with malloc(), but now it's probably
> just that nobody has bothered to go through the motions to rename
> 2.04beta to 2.04.
Problem with malloc is still there. I have used nmalloc for DJGPP port of GCC already for years as 
v2.04 memory management is much too slow.
I mentioned patch ready for commit in
http://www.delorie.com/djgpp/mail-archives/browse.cgi?p=djgpp-workers/2014/04/21/12:11:02
but did not get any response then. Now I noticed that the patch is no more at the URL mentioned in 
message. I'm attaching it to this message to avoid loosing it again.

We cannot ask author of nmalloc any more but the following message could be interpreted as it is OK
http://www.delorie.com/djgpp/mail-archives/browse.cgi?p=djgpp/2006/10/23/02:01:09
It is however not my decision.

Also DJGPP v2.03 and upcoming v2.04 are different enough that we would perhaps to need to rename 
current directory to v203 and beta to current. Simple overwriting would not be a good idea. My vote 
would be releasing 2.04 as 3.0, but it is not my decision again.

About available build environments:
- I'm using mostly Windows Vista Business (old Lenovo notebook) for DJGPP native builds (all DJGPP 
native builds of GCC are done on this system)
- I tried Dosemu under Fedora Linux earlier, but DPMI does not seem to work any more under Dosemu 
for me. I have not have time to investigate that in more details though.
- I also tried Windows XP mode under Windows 7 Pro 64 bit. It seems however too slow.

  Andris


--------------080207060608030503020708
Content-Type: text/x-patch;
 name="djcrx-use-nmalloc.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="djcrx-use-nmalloc.patch"

diff -r -p -N ../djgpp/include/libc/malldbg.h djgpp/include/libc/malldbg.h
*** ../djgpp/include/libc/malldbg.h	1970-01-01 02:00:00.000000000 +0200
--- djgpp/include/libc/malldbg.h	2014-04-21 13:01:01.000000000 +0300
***************
*** 0 ****
--- 1,50 ----
+ /* -------- malldbg.h ----------- */
+ 
+ /* Copyright (c) 2003 by Charles B. Falconer
+    Licensed under the terms of the GNU LIBRARY GENERAL PUBLIC
+    LICENSE and/or the terms of COPYING.DJ, all available at
+    <http://www.delorie.com>.
+ 
+    Bug reports to <mailto:cbfalconer AT worldnet DOT att DOT net>
+ */
+ 
+ #ifndef malldbg_h
+ #define malldbg_h
+ 
+ /* This is to be used in conjunction with a version of
+    nmalloc.c compiled with:
+ 
+      gcc -DNDEBUG -o malloc.o -c nmalloc.c
+ 
+    after which linking malldbg.o and malloc.o will
+    provide the usual malloc, free, realloc calls.
+    Both malloc.o and malldbg.o can be components
+    of the normal run time library.
+ */
+ 
+ #include <stddef.h>
+ #include <libc/sysquery.h>
+ 
+ struct mallinfo {
+    int arena;           /* Total space being managed */
+    int ordblks;         /* Count of allocated & free blocks */
+    int smblks;
+    int hblks;           /* Count of free blocks */
+    int hblkhd;          /* Size of the 'lastsbrk' block */
+    int usmblks;
+    int fsmblks;
+    int uordblks;        /* Heap space in use w/o overhead */
+    int fordblks;        /* Total space in free lists */
+    int keepcost;        /* Overhead in tracking storage */
+ };
+ 
+ struct mallinfo mallinfo(void);
+ int             malloc_verify(void);
+ int             malloc_debug(int level);
+ void            mallocmap(void);
+ FILE           *malldbgdumpfile(FILE *fp);
+ M_HOOKFN        mallsethook(enum m_hook_kind which,
+                             M_HOOKFN newhook);
+ 
+ #endif
+ /* -------- malldbg.h ----------- */
diff -r -p -N ../djgpp/include/libc/sysquery.h djgpp/include/libc/sysquery.h
*** ../djgpp/include/libc/sysquery.h	1970-01-01 02:00:00.000000000 +0200
--- djgpp/include/libc/sysquery.h	2014-04-11 20:27:44.000000000 +0300
***************
*** 0 ****
--- 1,53 ----
+ /* -------- sysquery.h ------------ */
+ 
+ /* Copyright (c) 2003 by Charles B. Falconer
+    Licensed under the terms of the GNU LIBRARY GENERAL PUBLIC
+    LICENSE and/or the terms of COPYING.DJ, all available at
+    <http://www.delorie.com>.
+ 
+    Bug reports to <mailto:cbfalconer AT worldnet DOT att DOT net>
+ */
+ 
+ #ifndef sysquery_h
+ #define sysquery_h
+ #ifdef __cplusplus
+    extern "C" {
+ #endif
+ 
+ /* The settable hooks, identifiers */
+ /* HKCOUNT is illegal value */
+ enum m_hook_kind {malloc_HK,  malloc_fail_HK,
+                   free_HK,    free_null_HK,
+                   realloc_HK, realloc_exit_HK,
+                   HKCOUNT};
+ 
+ /* Depending on kind, some params may be meaningless */
+ typedef void (*M_HOOKFN)(size_t sz, void *bk);
+ 
+ /* returns previous value of the appropriate function */
+ typedef M_HOOKFN (*set_m_hook)(enum m_hook_kind which,
+                                M_HOOKFN newhook);
+ 
+ /* This allows a clean connection to debugging software      */
+ /* NOTE: ANY value equivalent to -1 means data not available */
+ /*       for the unsigned chars this means 0xffh.            */
+ struct _sysquery {
+    unsigned char data, gdlo, sz, prvf, nxtf, nxt, prv, ohead;
+    void *        nilp;    /* dummy NULL, &freeptrs[1] */
+    void *        anchors; /* of memory chains */
+    set_m_hook    hookset; /* how to set a hook */
+ };
+ 
+ /* This can return the above values, hopefully in a register    */
+ /* NONE is used in nextfree, prevfree as the equivalent of NULL */
+ /* With the unclean knowledge that nil is actually a pointer to */
+ /* freehdrs[1], and that lastsbrk is actually freehdrs[0], the  */
+ /* entire malloc structure is open to debuggery.                */
+ struct _sysquery _sysmalloc(void);
+ 
+ #ifdef __cplusplus
+    }
+ #endif
+ 
+ #endif
+ /* -------- sysquery.h ------------ */
diff -r -p -N ../djgpp/include/stdlib.h djgpp/include/stdlib.h
*** ../djgpp/include/stdlib.h	2014-04-21 09:17:33.190582892 +0300
--- djgpp/include/stdlib.h	2014-04-21 17:39:13.954749212 +0300
*************** void *		xrealloc(void *ptr, size_t _size
*** 172,202 ****
  
  extern int __system_flags;
  
- extern void (*__libc_malloc_hook)(size_t, void *);
- extern void (*__libc_malloc_fail_hook)(size_t);
- extern void (*__libc_free_hook)(void *);
- extern void (*__libc_free_null_hook)(void);
- extern void (*__libc_realloc_hook)(void *, size_t);
- 
- struct mallinfo {
-   int arena;
-   int ordblks;
-   int smblks;
-   int hblks;
-   int hblkhd;
-   int usmblks;
-   int fsmblks;
-   int uordblks;
-   int fordblks;
-   int keepcost;
- };
- 
- struct mallinfo mallinfo(void);
- 
- int malloc_verify(void);
- int malloc_debug(int);
- void mallocmap(void);
- 
  #endif /* !_POSIX_SOURCE */
  #endif /* !__STRICT_ANSI__ */
  #endif /* !__dj_ENFORCE_ANSI_FREESTANDING */
--- 172,177 ----
diff -r -p -N ../djgpp/src/docs/kb/wc204.txi djgpp/src/docs/kb/wc204.txi
*** ../djgpp/src/docs/kb/wc204.txi	2014-04-21 09:17:42.581488438 +0300
--- djgpp/src/docs/kb/wc204.txi	2014-04-21 17:35:58.355486321 +0300
*************** recorded in the profiling data.
*** 458,463 ****
--- 458,464 ----
  @findex malloc_verify AT r{, added to the library}
  @findex malloc_debug AT r{, added to the library}
  @findex mallocmap AT r{, added to the library}
+ @findex malldbgdumpfile AT r{, added to the library}
  @findex malloc AT r{, debug facilities}
  There are new @code{malloc} debug facilities.  While not as powerful and
  versatile as existing external packages, such as @acronym{YAMD}, these
diff -r -p -N ../djgpp/src/libc/ansi/stdlib/makefile djgpp/src/libc/ansi/stdlib/makefile
*** ../djgpp/src/libc/ansi/stdlib/makefile	2002-12-01 11:45:26.000000000 +0200
--- djgpp/src/libc/ansi/stdlib/makefile	2014-04-21 18:37:27.991777244 +0300
*************** SRC += atol.c
*** 14,20 ****
  SRC += atold.c
  SRC += atoll.c
  SRC += bsearch.c
- SRC += calloc.c
  SRC += div.c
  SRC += exit.c
  SRC += getenv.c
--- 14,19 ----
*************** SRC += labs.c
*** 22,29 ****
  SRC += ldiv.c
  SRC += llabs.c
  SRC += lldiv.c
! SRC += malloc.c
! SRC += malldbg.c
  SRC += qsort.c
  SRC += rand.c
  SRC += strtod.c
--- 21,28 ----
  SRC += ldiv.c
  SRC += llabs.c
  SRC += lldiv.c
! SRC += nmalloc.c
! SRC += nmalldbg.c
  SRC += qsort.c
  SRC += rand.c
  SRC += strtod.c
diff -r -p -N ../djgpp/src/libc/ansi/stdlib/malloc.txh djgpp/src/libc/ansi/stdlib/malloc.txh
*** ../djgpp/src/libc/ansi/stdlib/malloc.txh	2003-04-26 01:32:01.000000000 +0300
--- djgpp/src/libc/ansi/stdlib/malloc.txh	1970-01-01 02:00:00.000000000 +0200
***************
*** 1,482 ****
- @node malloc, memory
- @findex malloc
- @subheading Syntax
- 
- @example
- #include <stdlib.h>
- 
- void *malloc(size_t size);
- @end example
- 
- @subheading Description
- 
- This function allocates a chunk of memory from the heap large enough to
- hold any object that is @var{size} bytes in length.  This memory must be
- returned to the heap with @code{free} (@pxref{free}). 
- 
- Note: this version of malloc is designed to reduce memory usage.  A
- faster but less efficient version is available in the libc sources
- (@file{djlsr*.zip}) in the file @file{src/libc/ansi/stdlib/fmalloc.c}.
- 
- @subheading Return Value
- 
- A pointer to the allocated memory, or @code{NULL} if there isn't enough
- free memory to satisfy the request. 
- 
- @subheading Portability
- 
- @portability ansi, posix
- 
- @subheading Example
- 
- @example
- char *c = (char *)malloc(100);
- @end example
- 
- @c ----------------------------------------------------------------------
- 
- @node free, memory
- @findex free
- @subheading Syntax
- 
- @example
- #include <stdlib.h>
- 
- void free(void *ptr);
- @end example
- 
- @subheading Description
- 
- Returns the allocated memory to the heap (@pxref{malloc}).  If the
- @var{ptr} is @code{NULL}, @code{free} does nothing. 
- 
- @subheading Return Value
- 
- None.
- 
- @subheading Portability
- 
- @portability ansi, posix
- 
- @subheading Example
- 
- @example
- char *q = (char *)malloc(20);
- free(q);
- @end example
- 
- @c ----------------------------------------------------------------------
- 
- @node realloc, memory
- @findex realloc
- @subheading Syntax
- 
- @example
- #include <stdlib.h>
- 
- void *realloc(void *ptr, size_t size);
- @end example
- 
- @subheading Description
- 
- This function changes the size of the region pointed to by @var{ptr}. 
- If it can, it will reuse the same memory space, but it may have to
- allocate a new memory space to satisfy the request.  In either case, it
- will return the pointer that you should use to refer to the (possibly
- new) memory area.  The pointer passed may be @code{NULL}, in which case
- this function acts just like @code{malloc} (@pxref{malloc}).
- 
- An application that wants to be robust in the face of a possible failure
- of @code{realloc} to enlarge a buffer should save a copy of the old
- pointer in a local variable, to be able to use the original buffer in
- case @code{realloc} returns @code{NULL}.  See the example below for
- details.
- 
- @subheading Return Value
- 
- On success, a pointer is returned to the memory you should now refer
- to.  On failure, @code{NULL} is returned and the memory pointed to by
- @var{ptr} prior to the call is not freed.
- 
- @subheading Portability
- 
- @portability ansi, posix
- 
- @subheading Example
- 
- @example
- if (now+new > max)
- @{
-   char *old = p;
- 
-   max = now+new;
-   p = realloc(p, max);
-   if (p == NULL)
-     p = old;  /* retain the old pointer */
- @}
- @end example
- 
- @c ----------------------------------------------------------------------
- 
- @node mallinfo, memory
- @findex mallinfo
- @tindex mallinfo AT r{ structure}
- @subheading Syntax
- 
- @example
- #include <stdlib.h>
- 
- struct mallinfo mallinfo(void);
- @end example
- 
- @subheading Description
- 
- This function returns information about heap space usage.  It is
- intended to be used for debugging dynamic memory allocation and tracking
- heap usage.  The @code{struct mallinfo} structure is defined by
- @file{stdlib.h} as follows:
- 
- @example
-  struct mallinfo @{
-    int arena;
-    int ordblks;
-    int smblks;
-    int hblks;
-    int hblkhd;
-    int usmblks;
-    int fsmblks;
-    int uordblks;
-    int fordblks;
-    int keepcost;
-  @};
- @end example
- 
- @noindent
- whose members are:
- 
- @table @code
- @item arena
- The total amount of space, in bytes, handed by @code{sbrk} to
- @code{malloc}.  Note that this is not the same as @code{sbrk(0)}, since
- @code{sbrk} allocates memory in large chunks and then subdivides them
- and passes them to @code{malloc} as required.  In particular, the result
- of @code{sbrk(0)} might be much larger than the @code{arena} member of
- @code{struct mallinfo} when the DPMI host allocates memory in
- non-contiguous regions (happens on MS-Windows).
- 
- @item ordblks
- The number of ``ordinary blocks'': the total number of allocated and
- free blocks maintained by @code{malloc}.
- 
- @item smblks
- The number of ``small blocks''.  This is normally zero, unless
- @code{malloc} was compiled with the symbol @code{NUMSMALL} defined to a
- non-zero value.  Doing so activates an optional algorithm which serves
- small allocations quickly from a special pool.  If this option is
- activated, the @code{smblks} member returns the number of free small
- blocks (the allocated small blocks are included in the value of
- @code{ordblks}).
- 
- @item hblks
- @itemx hblkhd
- Always zero, kept for compatibility with other systems.
- 
- @item usmblks
- The space (in bytes) in ``small blocks'' that are in use.  This is
- always zero in the DJGPP implementation.
- 
- @item fsmblks
- The space in free ``small blocks''.  Non-zero only of @code{malloc} was
- compiled with @code{NUMSMALL} defined to a non-zero value.  In that
- case, gives the amount of space in bytes in free small blocks.
- 
- @item uordblks
- The amount of space, in bytes, in the heap space currently used by the
- application.  This does not include the small overhead (8 bytes per
- block) used by @code{malloc} to maintain its hidden information in each
- allocated block.
- 
- @item fordblks
- The amount of free heap space maintained by @code{malloc} in its free
- list.
- 
- @item keepcost
- Always zero, kept for compatibility.
- @end table
- 
- @subheading Return Value
- 
- The @code{mallinfo} structure filled with information.
- 
- @subheading Portability
- 
- @port-note posix This function is available on many Unix systems.
- @portability !ansi, !posix
- 
- @subheading Example
- 
- @example
-  struct mallinfo info = mallinfo();
- 
-  printf("Memory in use: %d bytes\n",
-         info.usmblks + info.uordblks);
-  printf("Total heap size: %d bytes\n", info.arena);
- @end example
- 
- @c ----------------------------------------------------------------------
- 
- @node malloc_verify, memory
- @findex malloc_verify
- @subheading Syntax
- 
- @example
- #include <stdlib.h>
- 
- int malloc_verify(void);
- @end example
- 
- @subheading Description
- 
- This function attempts to determine if the heap has been corrupted.  It
- scans all the blocks allocated by @code{malloc} and handed to the
- application, and also all the free blocks maintained by @code{malloc}
- and @code{free} in the internal free list.  Each block is checked for
- consistency of the hidden bookkeeping information recorded in it by
- @code{malloc} and @code{free}.  The blocks on the free list are
- additionally validated by chasing all the @code{next} pointers in the
- linked list and checking them against limits for valid pointers (between
- 0x1000 and the data segment limit), and the alignment.  (Unaligned
- pointers are probably corrupted, since @code{malloc} always returns a
- properly aligned storage.)
- 
- What happens when a bad block is found depends on the current
- @dfn{malloc diagnostics level}: for example, the block can be reported,
- or the program may be aborted.  @xref{malloc_debug}, for the details.
- 
- @subheading Return Value
- 
- If the program isn't aborted during the function's run (this depends on
- the current diagnostics level), @code{malloc_verify} returns 1 if the
- heap passes all tests, or zero of some of the tests failed.
- 
- @subheading Portability
- 
- @port-note posix This function is available on many Unix systems.
- @portability !ansi, !posix
- 
- @subheading Example
- 
- @example
-  if (malloc_verify() == 0)
-    printf ("Heap corruption detected!\n");
- @end example
- 
- @c ----------------------------------------------------------------------
- 
- @node malloc_debug, memory
- @findex malloc_debug
- @vindex MALLOC_DEBUG AT r{ environment variable}
- @subheading Syntax
- 
- @example
- #include <stdlib.h>
- 
- int malloc_debug(int level);
- @end example
- 
- @subheading Description
- 
- This function sets the level of error diagnosis and reporting during
- subsequent calls to @code{malloc}, @code{free}, @code{realloc}, and all
- functions which call them internally.  The argument @var{level} is
- interpreted as follows:
- 
- @table @asis
- @item Level 0
- No checking; the memory allocation functions behave as they do if
- @code{malloc_debug} was never called.  Memory in use by the application
- which was allocated while level 0 was in effect cannot be checked by
- @code{malloc_verify} unless it is @code{free}d first.
- 
- @item Level 1
- Each one of the allocated blocks is recorded in a special structure,
- where @code{malloc_verify} can test them for corruption, even if these
- blocks were not yet @code{free}d.  If errors are detected by
- @code{malloc_verify}, it prints diagnostic messages to the standard
- error stream, with address and size of the offending block and other
- pertinent information.  This level slows down memory allocation to some
- extent due to additional overhead of calling special functions which
- record extra debugging info.
- 
- @item Level 2
- Like level 1, but in addition the consistency of the entire heap is
- verified (by calling @code{malloc_verify}) on every call to the memory
- allocation functions.  @emph{Warning: this may significantly slow down
- the application.}
- 
- @item Level 3
- Like level 2, except that the program is aborted whenever a heap
- corruption is detected.  In addition, failed allocations (i.e.@: when
- @code{malloc} returns @code{NULL} because it cannot satisfy a request)
- are reported to standard error.  Also, if the storage where allocated
- blocks are recorded is exhausted, a message to that effect is printed.
- 
- @item Level 4
- Like level 3, but calls to @code{free} with a @code{NULL} pointer as an
- argument are also reported.
- @end table
- 
- When @code{malloc_debug} is first called with a positive argument, it
- allocates storage for recording blocks in use.  To avoid reentrancy
- problems, this storage is allocated via a direct call to @code{sbrk},
- and its size is fixed.  The size used to allocate this storage is by
- default 400KB, which is enough to record 100 thousand allocated blocks.
- You can tailor the size to your needs by setting the environment
- variable @code{MALLOC_DEBUG} to the maximum number of blocks you want to
- be able to track.  (The value of @code{MALLOC_DEBUG} should only be as
- large as the maximum number of allocations which is expected to be in
- use at any given time, because when a buffer is freed, it is removed
- from this storage and its cell can be reused for another allocation.)
- Note that the larger this storage size, the more slow-down will your
- program experience when the diagnostic level is set to a non-zero value,
- since the debugging code needs to search the list of recorded blocks in
- use each time you call @code{malloc} or @code{free}.
- 
- @subheading Return Value
- 
- @code{malloc_debug} returns the previous error diagnostic level.  The
- default level is 0.
- 
- @subheading Portability
- 
- @port-note posix This function is available on many Unix systems.
- @portability !ansi, !posix
- 
- @subheading Example
- 
- @example
-  malloc_debug(2);
-  ...
-  malloc_verify();
- @end example
- 
- @c ----------------------------------------------------------------------
- 
- @node mallocmap, memory
- @findex mallocmap
- @subheading Syntax
- 
- @example
- #include <stdlib.h>
- 
- void mallocmap(void);
- @end example
- 
- @subheading Description
- 
- This function prints a map of the heap storage to standard output.  For
- each block, its address and size are printed, as well as an indication
- whether it is free or in use.  If the @dfn{slop} (a special free block
- cached for performance reasons) and the small blocks are available, they
- are printed as well (these two are variants of free blocks).  Blocks in
- use will only be printed if the diagnostic level was set to a non-zero
- value by a call to @code{malloc_debug} (@pxref{malloc_debug}), since
- otherwise the allocated blocks are not recorded by @code{malloc}.
- 
- @subheading Return Value
- 
- None.
- 
- @subheading Portability
- 
- @port-note posix This function is available on many Unix systems.
- @portability !ansi, !posix
- 
- @c ----------------------------------------------------------------------
- 
- @node malloc hook functions, memory
- @vindex __libc_malloc_hook
- @vindex __libc_malloc_fail_hook
- @vindex __libc_free_hook
- @vindex __libc_free_null_hook
- @vindex __libc_realloc_hook
- @subheading Syntax
- 
- @example
- #include <stdlib.h>
- #include <libc/malloc.h>
- 
- void (*__libc_malloc_hook)(size_t size, void *block);
- void (*__libc_malloc_fail_hook)(size_t size);
- void (*__libc_free_hook)(void *block);
- void (*__libc_free_null_hook)(void);
- void (*__libc_realloc_hook)(void *block, size_t size);
- @end example
- 
- @subheading Description
- 
- These hooks are provided for building custom @code{malloc} debugging
- packages.  Such packages typically need to be notified when memory is
- allocated and freed by the application, in order to be able to find
- memory leaks, code that writes beyond the limits of allocated buffers or
- attempts to free buffers which were not allocated by @code{malloc}, etc.
- These hooks can be used to define callback functions which will be
- called by the library at strategic points.  Each callback is only called
- if it is non- AT code{NULL}; by default, all of them are initialized to a
- @code{NULL} value.
- 
- @table @code
- @item __libc_malloc_hook
- Called just before a chunk of memory is about to be returned to the
- application in response to an allocation request.  @var{size} is the
- size requested by the application (@strong{not} the actual size of the
- allocated buffer, which may be larger).  @var{block} is a pointer to the
- block that was allocated, which is 4 bytes before the pointer that
- @code{malloc} will return to the application; these 4 bytes are used to
- record the actual size of the buffer.  An additional copy of the block's
- size is recorded immediately after the buffer's end.  Thus,
- @w{@code{*(size_t *)((char *)block + 4 + (BLOCK *)block->size)}} gives
- the second copy of the block's size.
- 
- @item __libc_malloc_fail_hook
- Called if @code{malloc} failed to find a free block large enough to
- satisfy a request, and also failed to obtain additional memory from
- @code{sbrk}.  @var{size} is the requested allocation size.
- 
- @item __libc_free_hook
- Called when a buffer is about to be freed.  @var{block} is a pointer 4
- bytes before the address passed to @code{free} by the application,
- i.e.@: it is a pointer to the beginning of the size information
- maintained before the user buffer.
- 
- @item __libc_free_null_hook
- Called whenever a @code{NULL} pointer is passed to @code{free}.
- @acronym{ANSI} C specifically rules that this is allowed and should have
- no effect, but you might want to catch such cases if your program needs
- to be portable to old compilers whose libraries don't like @code{NULL}
- pointers in @code{free}.
- 
- @item __libc_realloc_hook
- Called at entry to @code{realloc}, before the actual reallocation.
- @var{block} is a pointer 4 bytes before the address passed to
- @code{free} by the application, i.e.@: it is a pointer to the beginning
- of the size information maintained before the user buffer.  @var{size}
- is the new size requested by the application.  (This hook is called
- @emph{in addition} to the other hooks which will be called by
- @code{free} and @code{malloc} if and when @code{realloc} calls them.)
- @end table
- 
- The @code{BLOCK} data type is used by @code{malloc} and @code{free} to
- maintain the heap.  The only member which is always guaranteed to be
- valid is @code{size} (the additional copy of the size, recorded beyond
- the buffer's end, is also guaranteed to be valid).  The @code{next}
- member is valid in all blocks that are part of the free list.  This
- means that @code{__libc_malloc_hook} can use the @code{next} member, but
- @code{__libc_free_hook} cannot.
- 
- @subheading Portability
- 
- @portability !ansi, !posix
- 
- These hooks are specific to DJGPP.
- 
--- 0 ----
diff -r -p -N ../djgpp/src/libc/ansi/stdlib/nmalldbg.c djgpp/src/libc/ansi/stdlib/nmalldbg.c
*** ../djgpp/src/libc/ansi/stdlib/nmalldbg.c	1970-01-01 02:00:00.000000000 +0200
--- djgpp/src/libc/ansi/stdlib/nmalldbg.c	2014-04-21 10:29:32.000000000 +0300
***************
*** 0 ****
--- 1,432 ----
+ /* -------- malldbg.c --------- */
+ 
+ /* Copyright (c) 2003 by Charles B. Falconer
+    Licensed under the terms of the GNU LIBRARY GENERAL PUBLIC
+    LICENSE and/or the terms of COPYING.DJ, all available at
+    <http://www.delorie.com>.
+ 
+    Bug reports to <mailto:cbfalconer AT worldnet DOT att DOT net>
+ */
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <limits.h>
+ #include <signal.h>   /* raise, SIGABRT */
+ #include <libc/malldbg.h>  /* and sysquery.h */
+ 
+ /* This is to be used in conjunction with a version of
+    nmalloc.c compiled with:
+ 
+      gcc -DNDEBUG -o malloc.o -c nmalloc.c
+ */
+ 
+ static int   dbglevel;
+ static FILE *dumpfile;
+ static int   initialized;
+ 
+ /* array of hook function pointers, for cleaner interface */
+ /* This is purely a record of values set by sethook()     */
+ static M_HOOKFN hookptr[HKCOUNT];
+ 
+ /* Number of free lists in system */
+ #define NFLISTS ((int)(CHAR_BIT * sizeof(size_t)))
+ 
+ /* Loaded by initsysinfo() to access nmalloc guts */
+ static struct _sysquery sysinfo;
+ 
+ /* freehdrsp is pointer to array[NFLISTS] of void* */
+ /* These are the headers of the actual free lists  */
+ /* also loaded by initsysinfo() call               */
+ static void          *(*freehdrsp)[NFLISTS];
+ 
+ #define NONE          sysinfo.nilp
+ #define lastsbrk      freehdrs[0]
+ #define memblockp     void*
+ typedef unsigned int  ulong;
+ typedef unsigned char byte;
+ 
+ /* conversion and access macros */
+ #define DATAOFFSET sysinfo.data
+ 
+ #define MEMBLKp(p) (memblockp)((byte*)(p) - DATAOFFSET)
+ #define PTR(m)     (void*)((byte*)(m) + DATAOFFSET)
+ 
+ /* This accesses the list of discrete memory chains     */
+ /* which are created when sbrk returns unexpected value */
+ #define SBRKBGN    ((void **)(sysinfo.anchors))
+ 
+ /* field access macros (AFTER sysinfo loaded)    */
+ /* Examples - replace "m->prv" by "fld(m, prv)"  */
+ /*            replace "m->sz"  by "szof(m)"      */
+ /* where field is prvf, nxtf, prv, nxt           */
+ #define fld(m, field)   *((void**)((char*)m + sysinfo.field))
+ #define szof(m)         *(ulong*)((char*)m + sysinfo.sz)
+ #define freehdrs        (*freehdrsp)
+ 
+ /* ----------------- */
+ 
+ /* Set up the access to the nmalloc module */
+ static void initsysinfo(void)
+ {
+    sysinfo   = _sysmalloc();
+    freehdrsp = (void*)((byte*)(sysinfo.nilp)-sizeof(void*));
+    if (!dumpfile) dumpfile = stderr;
+    initialized = 1;
+ } /* initsysinfo */
+ 
+ /* 1------------------1 */
+ 
+ /* m is the allocated ptr treated by MEMBLKp    */
+ /* Fouls if sysinfo has not been initialized    */
+ /* Display info about a particular memory block */
+ static void xshowblock(FILE *f, void *m, const char *id)
+ {
+    if (NULL == f) return;
+    if (m) {
+       fprintf(f, " %s %p", id, m);
+       fprintf(f, " sz=%u nxt=%p prv=%p nxtf=",
+              szof(m), fld(m, nxt), fld(m, prv));
+       if (fld(m, nxtf)) {
+          if (NONE == fld(m, nxtf))
+             fprintf(f, "NONE prvf=");
+          else
+             fprintf(f, "%p prvf=", fld(m, nxtf));
+          if (NONE == fld(m, prvf))
+             fprintf(f, "NONE");
+          else
+             fprintf(f, "%p", fld(m, prvf));
+       }
+       else fprintf(f, "0");
+    }
+    else
+       fprintf(f, " %s NULL", id);
+    fflush(f);  /* to coexist with internal debuggery */
+ } /* xshowblock */
+ 
+ /* 1------------------1 */
+ 
+ /* dump the entire free chain group             */
+ /* Fouls if sysinfo has not been initialized    */
+ /* See main for sysinfo initialization sequence */
+ static void xdumpfree(FILE *f)
+ {
+    int       i;
+    memblockp m;
+    ulong     totfree;
+ 
+    if (NULL == f) return;
+    totfree = 0;
+    for (i = 0; i < NFLISTS; i++) {
+       if ((m = freehdrs[i])) {
+          fprintf(f, "\n%2d: ", i);
+          do {
+             fprintf(f, "%p(%u)->", m, szof(m));
+             totfree += szof(m);
+             m = fld(m, nxtf);
+          } while (m && (NONE != m));
+          fprintf(f, "0");
+          m = freehdrs[i];
+          while (m && (NONE !=m )) {
+             xshowblock(f, m, "\n     ");
+             m = fld(m, nxtf);
+          }
+       }
+    }
+    fprintf(f, "\nTotal Free = %u\n", totfree);
+    fflush(f);  /* to coexist with internal debuggery */
+ } /* xdumpfree */
+ 
+ /* ----------------- */
+ 
+ /* show the content of a block, flag it as BAD */
+ static void showbad(FILE *f, void * m)
+ {
+    void *n;
+ 
+    if ((dbglevel >= 3) && (NULL == f)) f = dumpfile;
+    if (f) {
+       n = fld(m, nxt);
+       xshowblock(f, m, "\n BAD?:");
+       xshowblock(f, n, "\n BAD?:");
+       putc('\n', f);
+       fflush(f);
+    }
+ } /* showbad */
+ 
+ /* ----------------- */
+ 
+ /* scans the complete malloc structures to collect
+    info.  If f is non-NULL outputs a detailed listing
+    returns NULL unless a bad block is found.
+    Any bad blocks are displayed on dumpfile */
+ static void * mallocscan(FILE *f, struct mallinfo *mi)
+ {
+    unsigned long totalmem, totalfree, blks, freeblks;
+    void *m, *n, *badblk;
+    int   i;
+ 
+    badblk = NULL;
+    if (!initialized) initsysinfo();
+    mi->smblks = mi->hblks = mi->hblkhd = mi->usmblks = 0;
+    mi->fsmblks = mi->keepcost = 0;
+ 
+    /* this initialization accounts for the fact that
+       the lastsbrk field will be counted as used */
+    blks = 0; totalmem = 0;
+    mi->hblkhd = totalfree = szof(freehdrs[0]);
+    freeblks = 1;
+ 
+    for (i = 0; (m = SBRKBGN[i]); i++) {
+       if (f) fprintf(f, "\n\nGroup %d:", i);
+       do {
+          n = fld(m, nxt);
+          if (f) xshowblock(f, m, "\n ");
+          totalmem += szof(m);
+          blks++;
+          if (dbglevel && n)
+             if (m != fld(n, prv)) {
+                badblk = m;
+                showbad(dumpfile, m);
+                if (dbglevel >= 3) {
+                   fflush(dumpfile);
+                   raise(SIGABRT);
+                }
+             }
+          if (fld(m, nxtf)) { /* a free block */
+             freeblks++;
+             totalfree += szof(m);
+          }
+       } while ((m = n));
+    }
+    if (f) fprintf(f, "\n");
+ 
+    /* return the collected info in struct mi */
+    mi->arena    = totalmem;
+    mi->ordblks  = blks;
+    mi->hblks    = freeblks;
+    mi->uordblks = totalmem - totalfree
+                        - DATAOFFSET * (blks - freeblks);
+    mi->fordblks = totalfree;
+    mi->keepcost = DATAOFFSET * blks;
+ 
+    return badblk;
+ } /* mallocscan */
+ 
+ /* ----------------- */
+ 
+ /* Return summary details about the arena */
+ struct mallinfo mallinfo(void)
+ {
+    struct mallinfo mi;
+    int    valid;
+ 
+    if (!initialized) initsysinfo();
+    valid = (NULL == mallocscan(NULL, &mi));
+    (void)valid;
+    return mi;
+ } /* mallinfo */
+ 
+ /* ----------------- */
+ 
+ /* Verify the integrity of the arena */
+ int malloc_verify(void)
+ {
+    struct mallinfo mi;
+    void  *badblk;
+ 
+    if (!initialized) initsysinfo();
+    badblk = mallocscan(NULL, &mi);
+    if (badblk) showbad(dumpfile, badblk);
+    return (NULL == badblk);
+ } /* malloc_verify */
+ 
+ /* ----------------- */
+ 
+ /* dump a complete map of the arena */
+ void mallocmap(void)
+ {
+    struct mallinfo mi;
+    void  *badblk;
+ 
+    if (!initialized) initsysinfo();
+    fprintf(dumpfile, "\nmallocmap at level %d\n", dbglevel);
+    xdumpfree(dumpfile);
+    badblk = mallocscan(dumpfile, &mi);
+    (void)badblk;
+ } /* mallocmap */
+ 
+ /* ----------------- */
+ 
+ /* Set the file on which to display results */
+ FILE *malldbgdumpfile(FILE *fp)
+ {
+    FILE *tmp;
+ 
+    if (!initialized) initsysinfo();
+    tmp = dumpfile;
+    if (fp) dumpfile = fp;
+    else dumpfile = stderr;
+    return tmp;
+ } /* malldbgdumpfile */
+ 
+ /* ----------------- */
+ 
+ /* The following three functions are called by hooks */
+ 
+ /* Do malloc_verify function via hook ptr */
+ /* No output unless a bad block found     */
+ /* This is suitable for setting hooks.    */
+ static void checkarena(size_t sz, void *bk)
+ {
+    struct mallinfo mi;
+    void  *badblk;
+ 
+    if (bk) sz = sz; /* anti warn */
+    if (dbglevel > 1) {  /* else ignore, safety */
+       if ((badblk = mallocscan(NULL, &mi)))
+          showbad(dumpfile, badblk);
+    }
+ } /* checkarena */
+ 
+ /* ----------------- */
+ 
+ static void freenullalert(size_t sz, void *bk)
+ {
+    if (bk) sz = sz; /* anti warn */
+    fputs("\n***Freeing NULL\n", dumpfile);
+ } /* freenullalert */
+ 
+ /* ----------------- */
+ 
+ static void mallocfailalert(size_t sz, void *bk)
+ {
+    if (bk)
+       fprintf(dumpfile,
+               "\n***realloc failed expanding %p to %lu bytes\n",
+               bk, (unsigned long)sz);
+    else
+       fprintf(dumpfile,
+               "\n***malloc failed allocating %lu bytes\n",
+               (unsigned long)sz);
+ } /* mallocfailalert */
+ 
+ /* ----------------- */
+ 
+ /* Check that no hooks are presently in use */
+ /* uses the locally stored copy of hooks so */
+ /* mistakes are possible.  Maybe sysinfo    */
+ /* should contain a pointer to the real tbl */
+ /* Our own hooks are allowable              */
+ static int somehookinuse(void)
+ {
+    enum m_hook_kind hk;
+ 
+    for (hk = malloc_HK; hk < HKCOUNT; hk++) {
+       /* structured for ease of modification */
+       if (NULL            == hookptr[hk]) continue;
+       if (checkarena      == hookptr[hk]) continue;
+       if (freenullalert   == hookptr[hk]) continue;
+       if (mallocfailalert == hookptr[hk]) continue;
+       return 1;
+    }
+    return 0;
+ } /* somehookinuse */
+ 
+ /* ----------------- */
+ 
+ /* sethook, bypassing validity checks */
+ static M_HOOKFN sethook(enum m_hook_kind which,
+                         M_HOOKFN newhook)
+ {
+    M_HOOKFN tmp;
+ 
+    hookptr[which] = newhook; /* keep local record */
+    tmp = (*sysinfo.hookset)(which, newhook);
+    return tmp;
+ } /* sethook */
+ 
+ /* ----------------- */
+ 
+ M_HOOKFN mallsethook(enum m_hook_kind which,
+                      M_HOOKFN newhook)
+ {
+    if (!initialized) initsysinfo();
+    if (which >= HKCOUNT) return NULL; /* validity check */
+    if (dbglevel != 1) return NULL;    /* in use, refuse */
+ 
+    return sethook(which, newhook);
+ } /* mallsethook */
+ 
+ /* ----------------- */
+ 
+ static void releaseallhooks(void)
+ {
+    enum m_hook_kind hk;
+ 
+    for (hk = malloc_HK; hk < HKCOUNT; hk++)
+       sethook(hk, NULL);
+ } /* freeallhooks */
+ 
+ /* ----------------- */
+ 
+ static inline void setfreenullhook(void)
+ {
+    sethook(free_null_HK, freenullalert);
+ } /* setfreenullhook */
+ 
+ /* ----------------- */
+ 
+ static inline void setmallocfailhook(void)
+ {
+    sethook(malloc_fail_HK, mallocfailalert);
+ } /* setmallocfailhook */
+ 
+ /* ----------------- */
+ 
+ static inline void setverifyhooks(void)
+ {
+    sethook(malloc_HK,  checkarena);
+    sethook(free_HK,    checkarena);
+    sethook(realloc_HK, checkarena);
+ } /* setverifyhooks */
+ 
+ /* ----------------- */
+ 
+ /* level  action
+       0   Only passive checks
+       1   Passive checks, hook setting enabled
+       2   Checks on each alloc/realloc, no hooks allowed
+       3   Same, but aborts if fault found, signals malloc_fail
+       4   Same, but signals on free(NULL)
+ 
+    A level value outside 0..4 is rejected.
+    Returns current debug_level (before any change).
+ */
+ int malloc_debug(int level)
+ {
+    int oldlevel;
+ 
+    if (!initialized) initsysinfo();
+    oldlevel = dbglevel;
+    if ((level >= 0) && (level <= 4) && (level != oldlevel)) {
+       if ((oldlevel < 2) && (level >= 2)) {
+          if (somehookinuse()) { /* refuse */
+             fprintf(dumpfile, "\n***malldbglvl refused\n");
+             return oldlevel;
+          }
+       }
+       /* Either all hooks free or our own, or level < 2 */
+       /* The change is feasible, level is changed and valid */
+       dbglevel = level;
+       releaseallhooks();
+       switch (level) { /* falling through */
+ case 4:  setfreenullhook();
+ case 3:  setmallocfailhook();
+ case 2:  setverifyhooks();
+ default: break;
+       } /* switch (level) */
+    } /* valid level change */
+    return oldlevel;
+ } /* malloc_debug */
+ 
+ /* -------- malldbg.c ----------- */
diff -r -p -N ../djgpp/src/libc/ansi/stdlib/nmalloc.c djgpp/src/libc/ansi/stdlib/nmalloc.c
*** ../djgpp/src/libc/ansi/stdlib/nmalloc.c	1970-01-01 02:00:00.000000000 +0200
--- djgpp/src/libc/ansi/stdlib/nmalloc.c	2014-04-21 12:53:20.000000000 +0300
***************
*** 0 ****
--- 1,1167 ----
+ /* --------- nmalloc.c ----------- */
+ 
+ /* Copyright (c) 2003, 2007 by Charles B. Falconer
+    Licensed under the terms of the GNU LIBRARY GENERAL PUBLIC
+    LICENSE and/or the terms of COPYING.DJ, all available at
+    <http://www.delorie.com>.
+ 
+    Bug reports to <mailto:djgpp AT delorie DOT com>
+ 
+    Revised 2007-01-04 to include calloc.
+    Revised 2007-01-28 per bug report by Florian Xaver. *f1*
+    Revised 2014-04-21 for use in DJGPP libcby andris DOT pavenis AT iki DOT fi   
+ */
+ 
+ /* A re-implementation of malloc and friends for DJGPP 2.03/2.04
+    This includes many bits modeled after DJs original scheme.
+    This is NOT portable - it builds in knowledge of int size etc.
+    i.e. unsigned ints and pointers are both 32 bits (size 4)
+ 
+    The system is NOT thread and interrupt safe, although use of a
+    suitable critical section call could make it such.  Nothing
+    herein executes for any unusual length of time (with NDEBUG).
+ */
+ 
+ /* Some critical tuning constants. Search for them:
+    MINSBRK    controls minimal access to sbrk
+    ALIGN      controls alignment of pointers
+    SAVEMEMORY reduces overhead at expense of checkability
+    INT_MAX    (system) controls maximum allocation quantum.
+ */
+ 
+ /* To avoid unexpected problems, the default has been changed
+    so we now require NEWMALLDBG to enable the original action
+ */
+ 
+ #define MEMALIGN
+ 
+ #ifndef NEWMALLDBG
+ #  undef  NDEBUG
+ #  define NDEBUG
+ #else
+ #  undef  NDEBUG
+ #endif
+ 
+ #ifndef NDEBUG
+    /* diddle these to control areas debugged */
+ #  define DEBUGM 1     /* malloc */
+ #  define DEBUGF 1     /* free */
+ #  define DEBUGR 1     /* realloc */
+ #else
+ #  define DEBUGM 0
+ #  define DEBUGF 0
+ #  define DEBUGR 0
+    /* the HOOKABLE variant is only for development   */
+    /* It allows some other package to define malloc, */
+    /* free, realloc, and to call this package.       */
+ #  ifndef HOOKABLE
+ #     define nmalloc  malloc
+ #     define nfree    free
+ #     define nrealloc realloc
+ #     define nmemalign memalign
+ #     define ncalloc  calloc
+ #  else
+ #     define nmalloc  _malloc
+ #     define nfree    _free
+ #     define nrealloc _realloc
+ #     define nmemalign _memalign
+ #     define ncalloc   calloc  /* can't hook this */
+ #  endif
+ #  define fakesbrk sbrk
+ #endif
+ 
+ #define SAVEMEMORY 1  /* 0/1 to use/eliminate extra storage */
+ 
+ typedef unsigned char byte;
+ typedef unsigned int  ulong;
+ 
+ #include <stddef.h> /* offsetof() */
+ #include <stdlib.h> /* malloc, free, realloc, exit, EXIT_FAILURE */
+ #include <unistd.h> /* sbrk, write */
+ #include <signal.h> /* raise, SIGABRT */
+ #include <string.h> /* strlen, memmove, memcpy, memset */
+ #include <limits.h> /* CHAR_BIT, INT_MAX */
+ #include <malloc.h>
+ #include <libc/sysquery.h> /* available debugger linkages */
+ 
+ /* system dependant magic.  Only STDIN, STDERR used */
+ enum {STDIN = 0, STDOUT, STDERR, STDAUX, STDPRN}; /* handles */
+ 
+ /* Incorporation into the system should require deleting the
+    following <nmalloc.h>, changing all references to nmalloc
+    to malloc, nfree to free, nrealloc to realloc.  Change the
+    single call to fakesbrk to sbrk.  Also normally set all
+    DEBUGx values above to 0 in place of 1.  Later many
+    routines will be made inline.  For debugging compilations
+    are done with "/Dinline= " switch.  For production use
+    the "/DNDEBUG=1" switch, which does all the above except
+    the inlining. But see NEWMALLDBG above.
+ */
+ #ifndef NDEBUG
+ #  include "nmalloc.h" /* while testing before name changes */
+ #else
+ #  ifdef HOOKABLE
+ #     include "hookmem.h"
+ #  endif
+ #endif
+ 
+ /* ============================================================
+    Macros and storage for debugging, works before init on DJGPP
+    WARNING - GNU extensions used here!!
+    Note: many messages are designed for easy search with grep
+          and also serve as comments.
+ */
+ #if DEBUGM || DEBUGF || DEBUGR
+ #  include <stdio.h>     /* sprintf, for DEBUG only */
+ #  include "fakesbrk.h"  /* repeatable sbrk */
+ #  define EOL "\n"       /* for DEBUG printouts only, allow crlf */
+    static char  dbgbuff[1024];
+    static char *dbgbp = dbgbuff;
+ #  define DBGFLUSH do {if (dbgbp != dbgbuff) { \
+                          /* write it out */ \
+                          write(STDOUT, dbgbuff, strlen(dbgbuff)); \
+                          dbgbp = dbgbuff; \
+                       } \
+                    } while (0)
+ #  define DBGEOLN do { \
+                      DBGPRT(EOL); \
+                      DBGFLUSH; \
+                   } while (0)
+ #  define DBGPRT(msg, args...) do { \
+                     if ((dbgbp - dbgbuff) > 924) DBGFLUSH; \
+                     dbgbp +=sprintf(dbgbp, msg , ## args); \
+                  } while (0)
+ #  define SHOWBLK(m, id) showblock(m, id)
+ #  if DEBUGM
+ #     define DBGPRTM(msg, args...) \
+                      dbgbp +=sprintf(dbgbp, msg , ## args)
+ #     define SHOWBLKM(m, id) showblock(m, id)
+ #  else
+ #     define DBGPRTM(msg, args...)
+ #     define SHOWBLKM(m, id)
+ #  endif
+ #  if DEBUGF
+ #     define DBGPRTF(msg, args...) \
+                      dbgbp +=sprintf(dbgbp, msg , ## args)
+ #     define SHOWBLKF(m, id) showblock(m, id)
+ #  else
+ #     define DBGPRTF(msg, args...)
+ #     define SHOWBLKF(m, id)
+ #  endif
+ #  if DEBUGR
+ #     define DBGPRTR(msg, args...) \
+                      dbgbp +=sprintf(dbgbp, msg , ## args)
+ #     define SHOWBLKR(m, id) showblock(m, id)
+ #  else
+ #     define DBGPRTR(msg, args...)
+ #     define SHOWBLKR(m, id)
+ #  endif
+ #else
+ #  define DBGFLUSH
+ #  define DBGEOLN
+ #  define DBGPRT(msg, args...)
+ #  define SHOWBLK(m, id)
+ #  define DBGPRTM(msg, args...)
+ #  define SHOWBLKM(m, id)
+ #  define DBGPRTF(msg, args...)
+ #  define SHOWBLKF(m, id)
+ #  define DBGPRTR(msg, args...)
+ #  define SHOWBLKR(m, id)
+ #endif
+ 
+ /* This is intended to allow finding the header area from
+    the address of the immediately adjacent memblocks.
+    The guardxx avoid destruction by an off by one pointer
+    and serve no real logical purpose.  Note that in some
+    cases sz may be recovered from next or next may be
+    recovered from sz.
+ */
+ typedef struct memblock {
+    struct memblock *prev;   /* 1st, protect against overrun */
+    struct memblock *next;   /* makes this less clobberable  */
+    ulong            sz;                 /* of this memblock */
+    /* An allocated block has the next two (1) fields NULL */
+    /* A free block has them both non-NULL  */
+    struct memblock *nextfree;
+    struct memblock *prevfree; /* actually data w/SAVEMEMORY */
+ #if SAVEMEMORY == 0
+    ulong            guardlo;     /* may hold size requested */
+ #endif
+    /* here lies the actual assigned storage                 */
+    /* so the following must be addressed by adding offset   */
+    /* storage must always be a multiple of 8 in size        */
+    /* thus these items are fictional, i.e. for zero data    */
+ } memblock, *memblockp;
+ 
+ /* Notice that with SAVEMEMORY the prevfree field only
+    exists for free blocks; it reuses data space.  This
+    is why we cannot allow 0 sized blocks.
+ */
+ #if SAVEMEMORY
+ #  define DATAOFFSET (offsetof(memblock, prevfree))
+ #else
+ #  define DATAOFFSET sizeof(memblock)
+ #endif
+ 
+ /* conversion and access macros */
+ #define MEMBLKp(p) (memblockp)((byte*)(p) - DATAOFFSET)
+ #define PTR(m)     (void*)((byte*)(m) + DATAOFFSET)
+ 
+ #define ALIGN 8
+ #define ALIGNMASK (ALIGN-1)
+ 
+ /* We can never use an allocation smaller than this */
+ #define MINSAVE   (ALIGN + DATAOFFSET)
+ 
+ /* Alternate form of NULL to distinguish free lists
+    This is self protection, because freehdrs[1] is otherwise
+    unused.  freehdrs[0] is reserved to hold lastsbrk.  In turn
+    this means that ALIGN must be >= 4.
+ */
+ #define NONE (memblockp)&freehdrs[1]
+ 
+ /* Magic constants.  MINSBRK must be MINSAVE or larger */
+ enum {NFLISTS = (int)(CHAR_BIT * sizeof(size_t)), MINSBRK = 1024};
+ 
+ /* ============== Globals ============= */
+ 
+ /* Headers of lists holding free blocks of 2**2 thru 2**31 size */
+ /* freehdr[n] holds items sized 2**n thru 2**(n+1) - 1          */
+ 
+ static memblockp freehdrs[NFLISTS]; /* yes, low indices are waste */
+ #define lastsbrk freehdrs[0]
+ 
+ /* keep track of the bases of each new sbrk block */
+ #define MAXSBRKS 100     /* I have never seen more than 5 needed */
+ static int   lastsbrkbgn;       /* zeroed on load */
+ static void *sbrkbgn[MAXSBRKS]; /* NULLS on load */
+ 
+ /* This holds pointers to hooks, initialized to NULLs */
+ /* see enum m_hook_kind for actual identifiers in sysquery.h */
+ static M_HOOKFN hookptr[HKCOUNT];
+ 
+ /* Forward declaration to allow sysquery init below */
+ static M_HOOKFN sethook(enum m_hook_kind which,
+                         M_HOOKFN         newhook);
+ 
+ /* This allows a clean connection to debugging software */
+ static struct _sysquery sysquery = {
+         DATAOFFSET,
+ #if SAVEMEMORY
+         0xff,
+ #else
+         offsetof(memblock, guardlo),
+ #endif
+         offsetof(memblock, sz),
+         offsetof(memblock, prevfree),
+         offsetof(memblock, nextfree),
+         offsetof(memblock, next),
+         offsetof(memblock, prev),
+         sizeof(memblock),
+         NONE,         /* also &freehds[1] */
+         &sbrkbgn,     /* anchors field */
+         sethook       /* hookset field */
+ };
+ 
+ /* 1------------------1 */
+ 
+ /* This can return the above values, hopefully in a register */
+ /* The use of NONE in nextfree, prevfree may cause confusion */
+ struct _sysquery _sysmalloc(void)
+ {
+    return sysquery;
+ } /* _sysmalloc */
+ 
+ /* 1------------------1 */
+ 
+ #if DEBUGM || DEBUGF || DEBUGR
+ 
+ /* These two routines are actually available in any user  */
+ /* application by use of the _sysmalloc call above.  They */
+ /* are retained here to show the derivation of user code, */
+ /* and in case needed during system initialization.       */
+ 
+ static void showblock(memblockp m, char *id)
+ {
+    if (m) {
+       DBGPRT(" %s %p sz=%u nxt=%p prv=%p nxtf=",
+              id, m, m->sz, m->next, m->prev);
+       if (m->nextfree) {
+          if (NONE == m->nextfree)
+             DBGPRT("NONE prvf=");
+          else
+             DBGPRT("%p prvf=", m->nextfree);
+          if (NONE == m->prevfree)
+             DBGPRT("NONE");
+          else
+             DBGPRT("%p", m->prevfree);
+       }
+       else DBGPRT("0");
+    }
+    else
+       DBGPRT(" %s NULL", id);
+ } /* showblock */
+ 
+ /* 1------------------1 */
+ 
+ /* dump the entire free chain group */
+ static void dumpfree(void)
+ {
+    int       i;
+    memblockp m;
+ 
+    for (i = 0; i < NFLISTS; i++) {
+       if ((m = freehdrs[i])) {
+          DBGPRT(EOL "%2d: ", i);
+          do {
+             DBGPRT("%p(%u)->", m, m->sz);
+             m = m->nextfree;
+          } while (m && (NONE != m));
+          DBGPRT("0");
+          m = freehdrs[i];
+          while (m && (NONE !=m )) {
+             SHOWBLK(m, EOL "     ");
+             m = m->nextfree;
+          }
+       }
+    }
+    DBGEOLN;
+ } /* dumpfree */
+ #endif
+ 
+ /* 1------------------1 */
+ 
+ /* This is accessible only through the pointer    */
+ /* returned in the sysquery record by _sysmalloc. */
+ /* Only of use in the malldbg package.            */
+ /* No safeties implemented here - see malldbg     */
+ static M_HOOKFN sethook(enum m_hook_kind which,
+                         M_HOOKFN         newhook)
+ {
+    M_HOOKFN tmp = NULL;
+ 
+    if (which < HKCOUNT) {
+       tmp = hookptr[which];
+       hookptr[which] = newhook;
+    }
+    return tmp;
+ } /* sethook */
+ 
+ /* 1------------------1 */
+ 
+ /* inserts bases of sbrk chains in sbrkbgn array  */
+ /* This ensures we can find all controlled memory */
+ /* gets called when we find an unexpected sbrk.   */
+ /* Note that if the sbrk was unaligned bk has now */
+ /* been aligned, and we have no record of wastage */
+ /* As long as nothing is returned to sbrk this is */
+ /* not a problem.  This only for the malldbg pkg. */
+ static void recordnewsbrk(memblockp bk)
+ {
+    int i;
+ 
+    if (lastsbrkbgn < MAXSBRKS - 1) {
+       /* This check for a previous entry is probably not
+          needed, but it is a rare occurance, so safety */
+       for (i = 0; i < lastsbrkbgn; i++) {
+          if (bk == sbrkbgn[i]) return;
+       }
+       sbrkbgn[lastsbrkbgn++] = bk;
+    }
+ /* else we abandon trying to keep track */
+ } /* recordnewsbrk */
+ 
+ /* 1------------------1 */
+ 
+ static inline ulong roundup(size_t sz)
+ {
+    ulong size;
+ 
+    size = ((sz + ALIGNMASK) & ~ALIGNMASK) + DATAOFFSET;
+    return size;
+ } /* roundup */
+ 
+ /* 1------------------1 */
+ 
+ static inline int size2bucket(ulong sz)
+ {
+    int b;
+ 
+    for (b = 0; sz; sz >>= 1, b++) continue;
+    return b;
+ } /* size2bucket */
+ 
+ /* 1------------------1 */
+ 
+ static void badcallabort(const char *msg, int lgh, memblockp m)
+ {
+ #if DEBUGM || DEBUGF || DEBUGR
+    DBGEOLN;
+ #endif
+    write(STDERR, msg, lgh);
+    write(STDERR, ": memory fouled\n", 16);
+ #if DEBUGM || DEBUGF || DEBUGR
+    SHOWBLK(m, "");
+    dumpfree();
+ #else
+    (void)m;  /* anti unused warning */
+ #endif
+    raise(SIGABRT);
+ } /* badcallabort */
+ 
+ /* 1------------------1 */
+ 
+ #define ISFREE(m) (m && (m != NONE) && m->nextfree && m->prevfree)
+ #if SAVEMEMORY
+ #define FOULED(m) (!lastsbrk || m->nextfree)
+ #else
+ #define FOULED(m) (!lastsbrk || (m->guardlo != 0xDEADBEEF))
+ #endif
+ 
+ /* 1------------------1 */
+ 
+ /* Unlike rmvfromfree, this extracts a block that */
+ /* may be buried deep within the free list by     */
+ /* unlinking.  m is already known a free block    */
+ static void extractfree(memblockp m)
+ {
+    int       b;
+    memblockp mnxtf, mprvf;
+ 
+    if (m) {
+       b = size2bucket(m->sz);
+       SHOWBLKF(m, EOL "  extractfree blk");
+ 
+       /* ease further tests */
+       if (NONE == (mnxtf = m->nextfree)) m->nextfree = NULL;
+       if (NONE == (mprvf = m->prevfree)) m->prevfree = NULL;
+ 
+       if      (m->nextfree) m->nextfree->prevfree = mprvf;
+ 
+       if      (m->prevfree) m->prevfree->nextfree = mnxtf;
+       else if (m->nextfree) freehdrs[b] = mnxtf;
+       else                  freehdrs[b] = NULL;
+ 
+       /* mark the block non-free */
+       m->nextfree = m->prevfree = NULL;
+ 
+       DBGPRTF(EOL "  freehdrs %d", b);
+       SHOWBLKF(freehdrs[b], "is blk");
+    }
+ } /* extractfree */
+ 
+ /* 1------------------1 */
+ 
+ static inline memblockp combinelo(memblockp m)
+ {
+    memblockp m1;
+ 
+    m1 = m;
+    if (ISFREE(m->prev)) {
+       if (m->prev->next != m) {
+          badcallabort("combinelo", 9, m);
+          exit(EXIT_FAILURE);  /* prevent user trapping SIGABRT */
+       }
+       m1 = m->prev;
+       extractfree(m1);
+       if (NULL != (m1->next = m->next))
+          m1->next->prev = m1;
+       m1->sz += m->sz;
+    }
+    return m1;
+ } /* combinelo */
+ 
+ /* 1------------------1 */
+ 
+ /* used to combine with lastsbrk, so no ISFREE test */
+ /* because lastsbrk is not kept in the free lists   */
+ static memblockp combinehi(memblockp m)
+ {
+    memblockp m1;
+ 
+    if (m && m->next) {
+       SHOWBLK(m,       EOL "  combinehi");
+       SHOWBLK(m->next, EOL "  with");
+       if (m->next->prev != m) {
+          badcallabort("combinehi", 9, m);
+          exit(EXIT_FAILURE);  /* prevent user trapping SIGABRT */
+       }
+       m1 = m->next;
+       if (m1 != lastsbrk) extractfree(m1);
+       if (NULL != (m->next = m->next->next))
+          m->next->prev = m;
+       m->sz += m1->sz;
+       SHOWBLK(m,       EOL "  giving");
+    }
+    return m;
+ } /* combinehi */
+ 
+ /* 1------------------1 */
+ 
+ /* This takes care of marking the block as free */
+ static void mv2freelist(memblockp m)
+ {
+    int       b;
+ 
+    if (m) {
+       if (ISFREE(m->next)) m = combinehi(m);
+       b = size2bucket(m->sz);
+       DBGPRT(EOL "  mv2freelist %d", b); SHOWBLK(m, "blk");
+       if (lastsbrk && (m->next == lastsbrk)) {
+          SHOWBLKF(lastsbrk, EOL "  Combine with lastsbrk");
+          lastsbrk = combinehi(m);
+          lastsbrk->nextfree = lastsbrk->prevfree = NULL;
+          SHOWBLKF(lastsbrk, EOL "  Resulting in lastsbrk");
+          return;
+       }
+       else if (freehdrs[b]) {
+          m->nextfree = freehdrs[b];
+          freehdrs[b]->prevfree = m;
+       }
+       else {
+          m->nextfree = NONE;
+       }
+       m->prevfree = NONE;
+       if (freehdrs[b]) freehdrs[b]->prevfree = m;
+       freehdrs[b] = m;
+       DBGPRT(EOL "  Exit mv2freelist");
+    }
+ } /* mv2freelist */
+ 
+ /* 1------------------1 */
+ 
+ /* this always marks the block as non-free */
+ static inline void rmvfromfree(memblockp m)
+ {
+    int b;
+ 
+    if (m) {
+       b = size2bucket(m->sz);
+       DBGPRTM(EOL "  rmvfromfree %d", b); SHOWBLKM(m, "blk");
+       if (m != freehdrs[b]) {
+          DBGPRTM(" NOT FREE");
+          badcallabort("rmvfromfree", 11, m);
+          exit(EXIT_FAILURE);  /* prevent user trapping SIGABRT */
+       }
+       else {
+          if (NONE == m->nextfree)
+             freehdrs[b] = NULL;
+          else {
+             freehdrs[b] = m->nextfree;
+             freehdrs[b]->prevfree = NONE;
+          }
+ #if SAVEMEMORY
+          m->nextfree = NULL;
+ #else
+          m->nextfree = m->prevfree = NULL;
+ #endif
+          DBGPRTM(EOL "  freehdrs %d", b);
+          SHOWBLKM(freehdrs[b], "is blk");
+       }
+    }
+ } /* rmvfromfree */
+ 
+ /* 1------------------1 */
+ 
+ static int searchfree(ulong szneed)
+ {
+    int b;
+ 
+    b = size2bucket(szneed);
+    DBGPRT(EOL "  freelist search from bucket %d", b);
+ 
+    if (! freehdrs[b] || (freehdrs[b]->sz < szneed)) {
+       do {
+          b++;
+       } while ((b < NFLISTS) && ! freehdrs[b]);
+    }
+    /* if found we will break off a piece and housekeep */
+    if (b < NFLISTS)
+       DBGPRT(", using %d", b);
+    else {
+       b = 0;
+       DBGPRT(", none found");
+    }
+    return b;
+ } /* searchfree */
+ 
+ /* 1------------------1 */
+ 
+ /* The higher portion is returned in *mp,     */
+ /* the lower portion via the function return. */
+ /* and the lower portion is marked non-free   */
+ static memblockp split(memblockp *mp, ulong sz)
+ {
+    memblockp m1, m;
+ 
+    m = *mp;
+    m1 = (memblockp)((char *)m + sz);
+    if (m->sz < (sz + DATAOFFSET)) {
+       badcallabort("memblockpsz", 11, m);
+       exit(EXIT_FAILURE);  /* prevent user trapping SIGABRT */
+    }
+    memcpy(m1, m, DATAOFFSET);
+    m1->prev = m;
+    m1->sz = m->sz - sz;
+    m->next = m1;
+    m->sz = sz;
+    m->nextfree = NULL;
+ #if SAVEMEMORY
+ #else
+    m->prevfree = NULL;
+ #endif
+    *mp = m1;
+    if (m1->next) {
+       if (m1->next->prev != m) {
+          badcallabort("memblockpnxt", 12, m1);
+          exit(EXIT_FAILURE);  /* prevent user trapping SIGABRT */
+       }
+       m1->next->prev = m1;
+    }
+    SHOWBLKM(m, EOL "  split returns");
+    return m;
+ } /* split */
+ 
+ /* 1------------------1 */
+ 
+ /* Get the memory, see if it extends the present lastsbrk
+    If not, put the old lastsbrk into the appropriate freelist
+       and replace lastsbrk by the new, setting the headers up
+    else update the size markers in lastsbrk.  When done either
+    lastsbrk can supply the memory szextra, or NULL is returned.
+    A revised lastsbrk block is marked as non-free.
+ */
+ static memblockp extendsbrk(ulong szxtra)
+ {
+    memblockp  m;
+    byte      *expected;
+    int        alignerr;
+    int        aligndelta;
+ 
+    DBGPRTM(", extending sbrk");
+ 
+    /* we have to ensure that the new lastsbrk always has    */
+    /* room to both realign and to leave a header when split */
+    szxtra += (2 * ALIGN + DATAOFFSET);
+    if (szxtra < MINSBRK) szxtra = MINSBRK;
+ 
+    if (lastsbrk)
+       expected = ((byte*)lastsbrk) + lastsbrk->sz;
+    else expected = NULL;
+ 
+    if ((aligndelta = (ulong)expected & ALIGNMASK)) {
+       /* lastsbrk end was misaligned, try to align end of this */
+       szxtra += ALIGN - aligndelta;
+       aligndelta = 0;
+    }
+ 
+    m = fakesbrk(szxtra);
+    if (-1 == (int)m) return NULL;
+    else {
+       if ((byte*)m == expected) {  /* Extending size of lastsbrk */
+          DBGPRTM(EOL "  sbrk(%4u=0x%05x) got expected %p"
+                      " lastsbrk %p sz %d",
+                        szxtra, szxtra, expected,
+                        lastsbrk, expected - (byte*)lastsbrk);
+          lastsbrk->sz += szxtra;
+          m = lastsbrk;
+       }
+       else {
+          /* Here we have to check & fix alignment */
+          DBGPRTM(EOL "=>sbrk(%4u=0x%05x) got UNEXPECTED %p/%p"
+                      " lastsbrk %p sz %d",
+                        szxtra, szxtra, m, expected,
+                        lastsbrk, expected - (byte*)lastsbrk);
+          if ((alignerr = (ALIGNMASK & (ulong)m))) {
+ /*f1*/      m = (memblockp)((char*)m +
+                             (aligndelta = ALIGN - alignerr));
+             DBGPRTM(", szerr %d/%d", aligndelta, alignerr);
+          }
+          m->sz = szxtra - aligndelta; /* discard alignerr bytes */
+          m->prev = m->next = NULL;
+ #if SAVEMEMORY
+          m->nextfree = NULL;
+ #else
+          m->nextfree = m->prevfree = NULL;
+          m->guardlo    = 0xDEADBEEF;
+ #endif
+          mv2freelist(lastsbrk);
+          lastsbrk = m;
+          recordnewsbrk(m); /* save in list of chains */
+       }
+    }
+    return m;
+ } /* extendsbrk */
+ 
+ /* 1------------------1 */
+ 
+ /* The mechanism:
+    All available memory is kept on the free list, and all adjacent
+    blocks, assigned or free, are linked by next/prev fields in order
+    of address.  Freehdrs[n] holds the first of a list of free blocks
+    of sizes between 2**n and 2**n+1. A pointer to the free portion
+    of the block last acquired via sbrk is held in lastsbrk.
+ 
+    All blocks on the freelist are marked by having a non-NULL value
+    in the nextfree or prevfree fields.  The special value NONE is
+    used to replace NULL to terminate these lists.  Because of the
+    misalignment possibilities it is necessary to keep accurate byte
+    count lengths in the sz component of lastsbrk.
+ 
+    1.  An allocation is made from the first fit freehdrs list. Note
+    that there MAY be a usable piece in the next lower freehdr, but
+    that is ignored because we do not want to search possibly long
+    lists.  The block is removed from the freelist, and any excess
+    space is broken off (if large enough to be usable) and assigned
+    to the appropriate free list.
+ 
+    2.  If no suitable free block is found, allocation is attempted
+    from the last block created by an sbrk call.  Such a block must
+    be large enough to maintain an sbrk pointer after splitting off
+    the desired allocation.
+ 
+    3.  If this fails a new block is created (or extended) via an
+    sbrk call.  If possible, the previous lastsbrk block is extended.
+    If extension is not possible the remains of the old block alone
+    is placed in the freelist.  This (non-extension) case results in
+    the prev field of the lastsbrk block being NULL.  The next field
+    of the lastsbrk block is always NULL. In this case only it is
+    necessary to check and correct memory alignment.
+ 
+    Insertion is always done into the start of any given freelist.
+    Thus there is no list walking needed.  Similarly, any block is
+    always removed from the head of the appropriate freelist.
+ 
+    It is assumed that sbrk will never return a lower address than
+    did a previous sbrk.  I am not sure if this affects anything. I
+    believe it does not.
+ */
+ void *nmalloc(size_t size)
+ {
+    memblockp m = NULL, m1;
+    ulong     szneed;
+    int       b;
+    void     *p = NULL;
+    size_t    sz = size; /* preserve arg for hooks */
+ 
+    /* compute the rounded up size needed */
+    if (!sz) sz++;     /* avoid any 0 space allocation */
+    szneed = roundup(sz);
+    DBGPRTM("malloc(%5lu) [%5u]", sz, szneed);
+    SHOWBLKM(lastsbrk, EOL "  lastsbrk");
+ 
+    /* Check for oversize allocation request */
+    if (szneed < ((ulong)(INT_MAX - 65536))) {
+       /* search the free lists for one */
+       b = searchfree(szneed);
+ 
+       if (b) {
+          rmvfromfree(m1 = freehdrs[b]);
+          if (m1->sz < szneed + MINSAVE)
+             m = m1;
+          else {
+             m = split(&m1, szneed);
+             mv2freelist(m1);
+          }
+       }
+       else if (lastsbrk &&
+               (lastsbrk->sz >= (szneed + DATAOFFSET))) {
+          m = split(&lastsbrk, szneed);
+       }
+       /* if not found get more from system */
+       else if ((m1 = extendsbrk(szneed))) {
+          if (m1->sz < szneed + MINSAVE) {
+             m = m1;
+             DBGPRTM(EOL "**FOULED lastsbrk\a");
+          }
+          else {
+             m = split(&lastsbrk, szneed);
+          }
+       }
+    /* else abject_failure(); */
+    /* abject_failure COULD check the first possible freehdrs */
+    /* list as a last chance to find some suitable memory     */
+ 
+       if (m) p = PTR(m);
+       else {
+          DBGPRTM(dbgbp, ", FAILURE");
+          p = NULL;
+       }
+    }
+ /* else m and p are NULL for oversize; */
+ 
+ #if DEBUGM
+    DBGPRTM(EOL "returns %p", p);
+    if (m) DBGPRTM("(%lu)", m->sz - DATAOFFSET);
+    DBGEOLN;
+ #endif
+ 
+    if (hookptr[malloc_HK]) hookptr[malloc_HK](size, p);
+    if (!p && hookptr[malloc_fail_HK])
+       hookptr[malloc_fail_HK](size, NULL);
+ 
+    return p;
+ } /* nmalloc */
+ 
+ /* 1------------------1 */
+ 
+ static void dofree(memblockp m)
+ {
+    /* mark the block free */
+    m->nextfree = m->prevfree = NONE;
+ 
+    /* try to combine with lower or higher blocks in memory */
+    if (ISFREE(m->next)) m = combinehi(m);
+    if (ISFREE(m->prev)) m = combinelo(m);
+ 
+    if (lastsbrk && (lastsbrk == m->prev) )
+       DBGPRTF(EOL "**Found decreasing sbrk!! FOUL");
+    else mv2freelist(m);
+ } /* dofree */
+ 
+ /* 1------------------1 */
+ 
+ void nfree(void *ptr)
+ {
+    memblockp m;
+ 
+    if (hookptr[free_HK]) hookptr[free_HK](0, ptr);
+ 
+    if (ptr) {
+       m = MEMBLKp(ptr);
+       DBGPRTF("free(%p)", ptr); SHOWBLKF(m, "");
+       if (ISFREE(m) ||     /* bad, refreeing block */
+           FOULED(m) ) {    /* block is fouled */
+          badcallabort("free", 4, m);
+          return;           /* he can trap this SIGABRT */
+       }
+       dofree(m);
+ #if DEBUGF
+       DBGEOLN;
+ #endif
+    }
+    else if (hookptr[free_null_HK])
+       hookptr[free_null_HK](0, NULL);
+ } /* nfree */
+ 
+ /* 1------------------1 */
+ 
+ static memblockp mv2lastsbrk(memblockp m, ulong szneed)
+ {
+    memblockp m1;
+ 
+    m1 = split(&lastsbrk, szneed);
+ 
+    /* Now m1 is the proposed new block, of the right size */
+    /* links are already revised so copy data from m to m2 */
+    memcpy(PTR(m1), PTR(m), m->sz - DATAOFFSET);
+ 
+    dofree(m);
+    return m1;
+ } /* mv2lastsbrk */
+ 
+ /* 1------------------1 */
+ 
+ void *nrealloc(void *ptr, size_t size)
+ {
+    memblockp m, m1, m2;
+    void     *p;
+    ulong     szneed;
+    int       b;
+    size_t    sz = size;
+ 
+    if (hookptr[realloc_HK]) hookptr[realloc_HK](sz, ptr);
+ 
+    if (!ptr) {
+       p = nmalloc(sz);
+       if (hookptr[realloc_exit_HK])
+          hookptr[realloc_exit_HK](size, p);
+       return p;
+    }
+ 
+    m = m1 = MEMBLKp(ptr);
+    if (!sz) sz++;     /* avoid any 0 space allocation */
+    szneed = roundup(sz);
+    DBGPRTR("realloc(%p:%lu[%u])", ptr, sz, szneed);
+    SHOWBLKR(m, EOL "  was");
+    if (ISFREE(m) ||     /* bad, realloc of free block */
+        FOULED(m) ) {    /* storage fouled */
+       badcallabort("realloc", 7, m);
+       p = NULL;
+       goto exeunt;      /* he can trap this SIGABRT */
+    }
+    SHOWBLKR(lastsbrk, EOL "  lastsbrk");
+ 
+    /* if decreasing simply reduce size and move excess to free */
+    if (szneed <= m->sz) {
+       DBGPRTR(EOL "  Realloc is reducing");
+       if ((m->sz - szneed) >= MINSAVE) {
+          m = split(&m1, szneed);
+          mv2freelist(m1);
+       }
+    /* else just return old pointer, i.e. NOP */
+    }
+    else if (szneed > ((ulong)(INT_MAX - 65536))) {
+       /* reject excessive size request */
+       p = NULL; goto exeunt;
+    }
+    else if (ISFREE(m->next) &&
+             (szneed <= (m->sz + m->next->sz)) ) {
+       /* the 'next' block is free and adequate so use it */
+       DBGPRTR(EOL "  Realloc is combining, next is free");
+       m = m1 = combinehi(m);
+       /* now split off the excess, if any */
+       if ((m->sz - szneed) >= MINSAVE) {
+          m = split(&m1, szneed);
+          mv2freelist(m1);
+       }
+    /* else m is the oversized return block */
+    }
+    else if ((lastsbrk == m->next)  &&
+             ((szneed + MINSAVE) <= (m->sz + lastsbrk->sz)) ) {
+       /* lastsbrk is adequate and adjacent so use it */
+       DBGPRTR(EOL "  Realloc is using lastsbrk to extend");
+       m = m1 = combinehi(m1);
+       m = split(&m1, szneed);
+       lastsbrk = m1;
+    }
+    else if (ISFREE(m->prev) &&
+             (szneed <= (m->sz + m->prev->sz)) ) {
+       /* the 'prev' block is free and adequate so use it */
+       DBGPRTR(EOL "  Realloc is combining low free, moving data");
+       m1 = m->prev;
+       extractfree(m1);
+       m1->sz += m->sz;     /* revise the links */
+       if ((m1->next = m->next)) m1->next->prev = m1;
+       /* we are now done with m links, except sz */
+ 
+       /* This involves copying the data, overlapping */
+       memmove(PTR(m1), PTR(m), m->sz - DATAOFFSET);
+ 
+       m = m1;        /* done with the old m value */
+       /* Is there something leftover */
+       if ((m->sz - szneed) >= MINSAVE) {
+          m = split(&m1, szneed);
+          mv2freelist(m1);
+       }
+    }
+    else if ((b = searchfree(szneed))) {
+       /* An adequate free block exists, copy over, free old */
+       DBGPRTR(EOL "  Realloc is using free block, copying");
+       rmvfromfree(m1 = freehdrs[b]);
+       if (m1->sz < szneed + MINSAVE) {
+          m2 = m1;
+       }
+       else {
+          m2 = split(&m1, szneed);
+          mv2freelist(m1);
+       }
+       /* Now m2 is the proposed new block, of the right size */
+       /* links are already revised so copy data from m to m2 */
+       memcpy(PTR(m2), PTR(m), m->sz - DATAOFFSET);
+ 
+       dofree(m);
+       m = m2;
+    }
+    else if (lastsbrk &&
+             ((szneed + MINSAVE) <= lastsbrk->sz) ) {
+       DBGPRTR(EOL "  Realloc is copying into lastsbrk");
+       m = mv2lastsbrk(m, szneed);
+    }
+    /* else malloc new size, copy data, and free old */
+    else if ((m1 = extendsbrk(szneed))) {
+       if (lastsbrk == m->next) {
+          DBGPRTR(EOL "  Realloc is now using lastsbrk extended");
+          /* last chance to avoid copying */
+          m = m1 = combinehi(m);
+          m = split(&m1, szneed);
+          lastsbrk = m1;
+       }
+       else {
+          /* At this point lastsbrk is adequate size */
+          /* split off, copy over, and free old      */
+          DBGPRTR(EOL "  Realloc is making complete new copy");
+          m = mv2lastsbrk(m, szneed);
+       }
+    }
+    else m = NULL;  /* failure */
+ 
+    if (m) p = PTR(m);
+    else {
+       DBGPRTR(dbgbp, ", FAILURE");
+       p = NULL;
+    }
+ 
+ #if DEBUGR
+    DBGPRTR(EOL "returns %p", p);
+    if (m) DBGPRTR("(%lu)", m->sz - DATAOFFSET);
+    DBGEOLN;
+ #endif
+ 
+ exeunt:       /* label used on realloc of free block */
+               /* and on trap of oversize request */
+    if (!p && ptr && hookptr[malloc_fail_HK])
+       hookptr[malloc_fail_HK](size, ptr);
+    if (hookptr[realloc_exit_HK])
+       hookptr[realloc_exit_HK](size, p);
+ 
+    return p;
+ } /* nrealloc */
+ 
+ /* 1------------------1 */
+ 
+ /* calloc included here to ensure that it handles the
+    same range of sizes (s * n) as does malloc.  The
+    multiplication n*s can wrap, yielding a too small
+    value, so we must ensure calloc rejects this.
+ */
+ void *ncalloc(size_t n, size_t s)
+ {
+    void   *result;
+    size_t  sz;
+ 
+    result = NULL;
+    if (!n || (((size_t)-1) / n) > s) {
+       sz = n * s;
+       if ((result = nmalloc(sz))) memset(result, 0, sz);
+       }
+    return result;
+ } /* ncalloc */
+ 
+ /* 1------------------1 */
+ 
+ /* The remaining code is an attempt to graft on the
+    memalign function.  It can do with improvement.
+    The idea is to do this without disturbing the
+    already checked and debugged package.
+ 
+    In units of ALIGN (== 8 here) bytes.  The value of
+    DATAOFFSET depends on SAVEMEMORY, either 2 or 3.  The
+    following assumes SAVEMEMORY is set and DATAOFFSET = 2.
+ 
+    Initial malloc block (alignment > ALIGN):
+     ____________________________________________________
+    |          |            |              |             |
+    |          |            |              |             |
+    |DATAOFFSET|   size     |  xtra for    |             |
+    | control  |            | realignment  |             |
+    |__________|____________|______________|_____________|
+               ^
+               ^
+ A: If this point is aligned, then we simply cut the assignment.
+    Immediate use of realloc will avoid any data movement.
+ 
+ B: Worst case when this is 1 (DELTA) above an alignment point.
+    becomes (since alignment > ALIGN and thus
+                   alignment >= DATAOFFSET):
+     ____________________________________________________
+    |          |            |              |             |
+    |alignment |DATAOFFSET  |              |     0       |
+    | - DELTA  |   for      |    size      |  nothing    |
+    |to freespc| control    |              | needed BUT: |
+    |________ _|____________|______________|_____________|
+                            ^              ^
+                            ^              ^
+    Now this point is suitably aligned     ^
+     ALIGNMENT - DELTA >= DATAOFFSET       ^
+                                           ^
+    For the intermediate cases make sure this block to be moved
+    to free space is at least 3 units long.  Easiest is to set
+    the initial extra value so that this worst case is 3, not 0
+  ?  This makes the initial extra size alignment+4 ??
+ 
+ C: The initial alignment point is 1 low.  (DELTA = -1)
+     ____________________________________________________
+    |          |            |              |             |
+    |    3     |            |              |             |
+    |control+1 |    2       |    size      |  xtra-3     |
+    |to freespc|  control   |              |to freespc   |
+    |__________|____________|______________|_____________|
+                            ^              ^
+                            ^              ^
+    This point is aligned --^     This goes to freespace
+ 
+ D: The initial alignment point is 2 low.  (DELTA = -2)
+     ____________________________________________________
+    |          |            |              |             |
+    |          |            |              |             |
+    |          |    2       |    size      |             |
+    |          |  control   |              |to freespc   |
+    |__________|____________|______________|_____________|
+                            ^              ^
+                            ^              ^
+    This point is aligned --^     This goes to freespace
+ 
+    The minimum of 3 units to freespace is because 2 are
+    required for control, and without further space the
+    block is useless.  In fact it needs the further space
+    to implement the free block linking mechanism.
+ */
+ 
+ /* 1------------------1 */
+ 
+ /* Check alignment is a non-zero power of two <= 65536. */
+ /* Return 0 if so, else non-zero                        */
+ static inline int invalid(size_t alignment)
+ {
+    if (alignment && (alignment <= 65536))
+       return (alignment & (alignment - 1));
+    else return 1;  /* 0 is invalid */
+ } /* invalid */
+ 
+ /* 1------------------1 */
+ 
+ /* define the XTRA storage needed to assure chopping up feasible
+    and that chopped off storage is large enough to be usable.
+    XTRA is always a multiple of ALIGN.
+ */
+ 
+ #define XTRA (alignment + 3 * ALIGN)
+ 
+ /* 1------------------1 */
+ 
+ /* return memory aligned so that the return value is a */
+ /* multiple of alignment.  Otherwise similar to malloc */
+ /* alignment MUST be a power of two, max 65536.        */
+ 
+ void *nmemalign(size_t alignment, size_t size)
+ {
+    memblockp m = NULL;
+    void     *minit;
+    ulong     misalign;
+    size_t    szneed, sz = size; /* preserve arg for hooks */
+ 
+    /* compute the rounded up size needed */
+    if (!sz) sz++;     /* avoid any 0 space allocation */
+    szneed = roundup(sz);
+    DBGPRTM("memalign(%5lu) [%5lu] %5lu", sz, szneed, alignment);
+    DBGEOLN;
+ 
+    if (size < ((ulong)(INT_MAX - 65536)) &&
+        !invalid(alignment)) {
+       /* parameters seem to be valid */
+       if (alignment <= ALIGN) {
+          DBGPRTM("  alignment value ignored"); DBGEOLN;
+          return nmalloc(szneed);                      /* EXIT */
+       }
+       else if ((minit = nmalloc(szneed + XTRA))) {
+          /* alignment >= 2*ALIGN and power of 2 if here */
+          misalign = (ulong)minit % alignment;
+          DBGPRTM("  misalignment = %d", misalign);
+          if (0 == misalign) { /* aligned, just return XTRA */
+             DBGPRTM(" Just realloc the block."); DBGEOLN;
+             return nrealloc(minit, size);             /* EXIT */
+          }
+          else {
+             /* two or more chunks to release */
+             /* for now, just return NULL and have a leak */
+             DBGPRTM("  Complex case, release multiple chunks");
+             DBGEOLN;
+          }
+       } /* alignment > ALIGN */
+    } /* valid parameters */
+    if (m) return PTR(m);
+    else return NULL;
+ } /* nmemalign */
+ 
+ /* --------- nmalloc.c ----------- */
diff -r -p -N ../djgpp/src/libc/ansi/stdlib/nmalloc.txh djgpp/src/libc/ansi/stdlib/nmalloc.txh
*** ../djgpp/src/libc/ansi/stdlib/nmalloc.txh	1970-01-01 02:00:00.000000000 +0200
--- djgpp/src/libc/ansi/stdlib/nmalloc.txh	2014-04-21 17:34:29.010243504 +0300
***************
*** 0 ****
--- 1,659 ----
+ @node malloc, memory
+ @subheading Syntax
+ 
+ @example
+ #include <stdlib.h>
+ 
+ void *malloc(size_t size);
+ @end example
+ 
+ @subheading Description
+ 
+ This function allocates a chunk of memory from the heap large
+ enough to hold any object that is @var{size} bytes in length.
+ This memory must be returned to the heap with @code{free}
+ (@pxref{free}).
+ 
+ Note: excessively large requests are rejected.  At present
+ excessively large means over @code{INT_MAX} - 65536.
+ 
+ Note: this version of malloc is designed to reduce memory usage.
+ A faster but less efficient version is available in the libc
+ sources (@file{djlsr*.zip}) in the file
+ @file{src/libc/ansi/stdlib/fmalloc.c}.
+ 
+ @subheading Return Value
+ 
+ A pointer to the allocated memory, or @code{NULL} if there isn't
+ enough free memory to satisfy the request.
+ 
+ @subheading Portability
+ 
+ @portability ansi, posix
+ 
+ @subheading Example
+ 
+ @example
+ char *c = malloc(100);
+ @end example
+ 
+ @c -------------------------------------------------------------
+ 
+ @node free, memory
+ @subheading Syntax
+ 
+ @example
+ #include <stdlib.h>
+ 
+ void free(void *ptr);
+ @end example
+ 
+ @subheading Description
+ 
+ Returns the allocated memory to the heap (@pxref{malloc}).  If
+ the @var{ptr} is @code{NULL}, @code{free} does nothing.
+ 
+ @subheading Return Value
+ 
+ None.
+ 
+ @subheading Portability
+ 
+ @portability ansi, posix
+ 
+ @subheading Example
+ 
+ @example
+ char *q = malloc(20);
+ free(q);
+ @end example
+ 
+ @c -------------------------------------------------------------
+ 
+ @node realloc, memory
+ @subheading Syntax
+ 
+ @example
+ #include <stdlib.h>
+ 
+ void *realloc(void *ptr, size_t size);
+ @end example
+ 
+ @subheading Description
+ 
+ This function changes the size of the region pointed to by
+ @var{ptr}. If it can, it will reuse the same memory space, but
+ it may have to allocate a new memory space to satisfy the
+ request.  In either case, it will return the pointer that you
+ should use to refer to the (possibly new) memory area.  The
+ pointer passed may be @code{NULL}, in which case this function
+ acts just like @code{malloc} (@pxref{malloc}).
+ 
+ An application that wants to be robust in the face of a possible
+ failure of @code{realloc} to enlarge a buffer should save a copy
+ of the old pointer in a local variable, to be able to use the
+ original buffer in case @code{realloc} returns @code{NULL}.  See
+ the example below for details.
+ 
+ Note: excessively large requests are rejected.  At present
+ excessively large means over @code{INT_MAX} - 65536.
+ 
+ @subheading Return Value
+ 
+ On success, a pointer is returned to the memory you should now
+ refer to.  On failure, @code{NULL} is returned and the memory
+ pointed to by @var{ptr} prior to the call is not freed.
+ 
+ @subheading Portability
+ 
+ @portability ansi, posix
+ 
+ @subheading Example
+ 
+ @example
+ if (now + new > max)
+ @{
+   char *old = p;
+ 
+   oldmax = max;
+   max = now + new;
+   p = realloc(p, max);
+   if (p == NULL) @{
+     p = old;  /* retain the old pointer */
+     max = oldmax;
+   @}
+ @}
+ @end example
+ 
+ @c -------------------------------------------------------------
+ 
+ @node mallinfo, memory
+ @subheading Syntax
+ 
+ @example
+ #include <stdlib.h>
+ #include <malldbg.h> /* on non-DJGPP systems */
+ 
+ struct mallinfo mallinfo(void);
+ @end example
+ 
+ @subheading Description
+ 
+ This function returns information about heap space usage.  It is
+ intended to be used for debugging dynamic memory allocation and
+ tracking heap usage.  The @code{struct mallinfo} structure is
+ defined by @file{stdlib.h} as follows:
+ 
+ @example
+  struct mallinfo @{
+    int arena;
+    int ordblks;
+    int smblks;
+    int hblks;
+    int hblkhd;
+    int usmblks;
+    int fsmblks;
+    int uordblks;
+    int fordblks;
+    int keepcost;
+  @};
+ @end example
+ 
+ @noindent
+ whose members are:
+ 
+ @table @code
+ @item arena
+ The total amount of space, in bytes, handed by @code{sbrk} to
+ @code{malloc}.  Note that this is not the same as
+ @code{sbrk(0)}, since @code{sbrk} allocates memory in large
+ chunks and then subdivides them and passes them to @code{malloc}
+ as required.  In particular, the result of @code{sbrk(0)} might
+ be much larger than the @code{arena} member of @code{struct
+ mallinfo} when the DPMI host allocates memory in non-contiguous
+ regions (happens on MS-Windows).
+ 
+ @item ordblks
+ The number of ``ordinary blocks'': the total number of allocated
+ and free blocks maintained by @code{malloc}.
+ 
+ @item smblks
+ The number of ``small blocks''.  This is normally zero, unless
+ a special version of @code{malloc} was installed.
+ 
+ @item hblks
+ The count of freeblocks maintained in the malloc arena.  This
+ is normally much smaller than the number of freed blocks, since
+ such blocks have been combined into larger blocks.
+ 
+ @item hblkhd
+ The size of the currently available top portion of the memory
+ assigned by @code{sbrk}.  Sometimes known as @dfn{slop}.
+ 
+ @item usmblks
+ The space (in bytes) in ``small blocks'' that are in use.  This
+ is always zero in the DJGPP implementation.
+ 
+ @item fsmblks
+ The space in free ``small blocks''.  Normally zero in the DJGPP
+ implementation.
+ 
+ @item uordblks
+ The amount of space, in bytes, in the heap space currently used
+ by the application.  This does not include the small overhead
+ used by @code{malloc} to maintain its hidden information in each
+ allocated block.
+ 
+ @item fordblks
+ The amount of free heap space maintained by @code{malloc} in its
+ free list of hblks chunks.
+ 
+ @item keepcost
+ The total overhead used by @code{malloc} in maintaining the
+ currently allocated blocks.
+ @end table
+ 
+ @subheading Return Value
+ 
+ The @code{mallinfo} structure filled with information.
+ 
+ @subheading Portability
+ 
+ @port-note posix This function is available on many Unix systems.
+ @portability !ansi, !posix
+ 
+ @subheading Example
+ 
+ @example
+  struct mallinfo info = mallinfo();
+ 
+  printf("Memory in use: %d bytes\n",
+         info.usmblks + info.uordblks);
+  printf("Total heap size: %d bytes\n", info.arena);
+ @end example
+ 
+ @c -------------------------------------------------------------
+ 
+ @node malloc_verify, memory
+ @subheading Syntax
+ 
+ @example
+ #include <stdlib.h>
+ #include <malldbg.h> /* on non-DJGPP systems */
+ 
+ int malloc_verify(void);
+ @end example
+ 
+ @subheading Description
+ This function attempts to determine if the heap has been
+ corrupted.  It scans all the blocks allocated by @code{malloc}
+ and handed to the application, and also all the free blocks
+ maintained by @code{malloc} and @code{free} in the internal free
+ list.  Each block is checked for consistency of the hidden
+ bookkeeping information recorded in it by @code{malloc} and
+ @code{free}.
+ 
+ What happens when a bad block is found depends on the current
+ @dfn{malloc diagnostics level}: for example, the block can be
+ reported, or the program may be aborted.  @xref{malloc_debug},
+ for the details.
+ 
+ @subheading Return Value
+ If the program isn't aborted during the function's run (this
+ depends on the current diagnostics level), @code{malloc_verify}
+ returns 1 if the heap passes all tests, or zero of some of the
+ tests failed.
+ 
+ @subheading Portability
+ 
+ @port-note posix This function is available on many Unix systems.
+ @portability !ansi, !posix
+ 
+ @subheading Example
+ 
+ @example
+  if (malloc_verify() == 0)
+    printf ("Heap corruption detected!\n");
+ @end example
+ 
+ @c -------------------------------------------------------------
+ 
+ @node malloc_debug, memory
+ @subheading Syntax
+ 
+ @example
+ #include <stdlib.h>
+ #include <malldbg.h> /* on non-DJGPP systems */
+ 
+ int malloc_debug(int level);
+ @end example
+ 
+ @subheading Description
+ This function sets the level of error diagnosis and reporting
+ during subsequent calls to @code{malloc}, @code{free},
+ @code{realloc}, and all functions which call them internally.
+ The argument @var{level} is interpreted as follows:
+ 
+ @table @asis 
+ @item Level 0
+ The memory allocation functions behave as they do if
+ @code{malloc_debug} was never called.  Only passive checks are
+ allowed, including @code{malloc_verify}, @code{mallocmap}, and
+ @code{malldbgdumpfile} (to set the output file).  In particular
+ @code{mallsethook} is disabled, to avoid accidents.  The actual
+ functioning of the malloc system remains unaffected.  Any malloc
+ hooks set by @code{mallsethook} are reset. If errors are detected by
+ @code{malloc_verify}, it prints diagnostic messages to the
+ @dfn{dumpfile} (default standard error stream), with address
+ and size of the offending block and other pertinent information.
+ 
+ @item Level 1
+ All the passive checks of level 0 are allowed.  In addition
+ @code{mallsethook} is enabled, thus allowing construction of
+ custom debugging packages.
+ 
+ @item Level 2
+ Similar to level 1, but the consistency of the entire heap is
+ also verified (by calling @code{malloc_verify}) on every call to
+ the memory allocation functions.  @emph{Warning: this may
+ significantly slow down the application.}  Since the malloc
+ hooks are in use to connect to this system, @code{mallsethook}
+ is disabled.  If there are hooks already in use the change to
+ level 2 or above is rejected.
+ 
+ @item Level 3
+ Similar to level 2, except that the program is aborted whenever
+ a heap corruption is detected.  In addition, failed allocations
+ (i.e.@: when @code{malloc} or @code{realloc} returns @code{NULL}
+ because it cannot satisfy a request) are reported to the
+ dumpfile (default standard error).
+ 
+ @item Level 4
+ Similar to level 3, but calls to @code{free} with a @code{NULL}
+ pointer as an argument are also reported.
+ 
+ @item Level -1
+ Does not alter the debug level, but returns the current value.
+ @end table
+ 
+ @subheading Return Value
+ 
+ @code{malloc_debug} returns the previous error diagnostic level.  The
+ default level is 0.
+ 
+ @subheading Portability
+ 
+ @port-note posix This function is available on many Unix systems.
+ @portability !ansi, !posix
+ 
+ @subheading Example
+ 
+ @example
+  malloc_debug(2);
+  ...
+  malloc_verify();
+ @end example
+ 
+ @c -------------------------------------------------------------
+ 
+ @node mallocmap, memory
+ @subheading Syntax
+ 
+ @example
+ #include <stdlib.h>
+ #include <malldbg.h> /* on non-DJGPP systems */
+ 
+ void mallocmap(void);
+ @end example
+ 
+ @subheading Description
+ 
+ This function prints a map of the heap storage to the selected
+ @file{dumpfile}. @xref{malldbgdumpfile}. For each block, its
+ address and size are printed, as well as an indication whether
+ it is free or in use, together with pointers to adjacent blocks.
+ 
+ @subheading Return Value
+ 
+ None.
+ 
+ @subheading Portability
+ 
+ @port-note posix This function is available on many Unix systems.
+ @portability !ansi, !posix
+ 
+ @c -------------------------------------------------------------
+ 
+ @node malldbgdumpfile, memory
+ 
+ @subheading Syntax
+ 
+ @example
+   FILE *fNew = fopen("mallocdbg.out", "w");
+   FIKE *fOld = malldbgdumpfile(fNew);
+ @end example
+ 
+ @subheading Description
+ 
+ Specifies the file used by memory allocation debug functions
+ 
+ @subheading Return Value
+ 
+ Returns file used earlier (before call) for this purpose.
+ Initial value of output file is stderr.
+ 
+ @subheading Portability
+ @portability !ansi, !posix
+ 
+ @c -------------------------------------------------------------
+ 
+ @node mallsethook, memory
+ @subheading Syntax
+ 
+ @example
+ #include <stdlib.h>
+ #include <malldbg.h> /* on non-DJGPP systems */
+ 
+ M_HOOKFN mallsethook(enum m_hook_kind which,
+                      M_HOOKFN newhook);
+ @end example
+ 
+ @subheading Description
+ Several @dfn{hooks} are provided for building custom
+ @code{malloc} debugging packages.  Such packages typically need
+ to be notified when memory is allocated and freed by the
+ application, in order to be able to find memory leaks, code that
+ writes beyond the limits of allocated buffers or attempts to
+ @code{free} buffers which were not allocated by @code{malloc},
+ etc. These hooks can be used to define callback functions which
+ will be called by the library at strategic points.  Each
+ callback is only called if it is non- AT code{NULL}; by default,
+ all of them are initialized to a @code{NULL} value.
+ 
+ The actual hook to be set is described by the following
+ constants, enumerated in @file{stdlib.h}:
+ 
+ @table @code
+ @item malloc_HK = 0    
+ on entry to malloc
+ 
+ @item malloc_fail_HK   
+ when malloc or realloc fails
+ 
+ @item free_HK          
+ on entry to free
+ 
+ @item free_null_HK     
+ when free is called with a NULL pointer
+ 
+ @item realloc_HK       
+ on entry to realloc
+ 
+ @item realloc_exit_HK  
+ when realloc exits.
+ 
+ @item HKCOUNT          
+ The first invalid value for a hook descriptor.
+ @end table
+ 
+ @noindent
+ and each ``callback'' function is described by:
+ 
+ @example
+    typedef void (*M_HOOKFN)(size_t sz, void *ptr);
+ @end example
+ 
+ @noindent
+ in @file{stdlib.h}.  Note that in some cases the parameters
+ supplied to the ``callback'' function will be meaningless, in
+ which case they will be zero or @code{NULL} as appropriate.  The
+ callback function must @strong{NOT} call any of @code{malloc},
+ @code{free}, or @code{realloc}.
+ 
+ @code{mallsethook} action is disabled unless the debug_level is
+ set to 1.  This interlock avoids accidental use before enabling
+ the package, and avoids altering hooks that are already in use
+ for debug_level of 2 or higher.
+ 
+ For access to the internal storage of the malloc arena, see the
+ @code{_sysmalloc} call and the @code{_sysinfo} struct.
+ 
+ @table @code
+ 
+ @item malloc_HK
+ Called just before a chunk of memory is about to be returned to
+ the application in response to an allocation request.
+ @var{sz} is the size requested by the application
+ (@strong{not} the actual size of the allocated buffer, which may
+ be larger).  @var{ptr} is a pointer to the block that was
+ allocated.
+ 
+ @item malloc_fail_HK
+ Called if @code{malloc} failed to find a free block large enough
+ to satisfy a request, and also failed to obtain additional
+ memory from @code{sbrk}.  @var{sz} is the requested allocation
+ size.
+ 
+ @item free_HK
+ Called when a buffer is about to be freed.  @var{ptr} is a
+ pointer to the block to be freed.  Its validity has not been
+ checked.
+ 
+ @item free_null_HK
+ Called whenever a @code{NULL} pointer is passed to @code{free}.
+ @acronym{ANSI} C specifically rules that this is allowed and
+ should have no effect, but you might want to catch such cases if
+ your program needs to be portable to old compilers whose
+ libraries don't like @code{NULL} pointers in @code{free}.
+ 
+ @item realloc_HK
+ Called at entry to @code{realloc}, before the actual
+ reallocation. @var{ptr} is the pointer whose contents are to be
+ reallocated.  @var{sz} is the new size requested by the
+ application.  (This hook is called @emph{in addition} to the
+ other hooks which may be called by @code{malloc} if and when
+ @code{realloc} calls them.)
+ 
+ @item realloc_exit_HK
+ Called at exit from @code{realloc}.  @var{sz} is the requested
+ size, and @var{ptr} is the (possibly) revised value of the user
+ pointer which will be returned by @code{realloc}.  This may be
+ @code{NULL} if realloc was unable to allocate the space, in
+ which case @emph{ONLY} the original value of @var{ptr} (as
+ reported by @code{realloc_HK}) remains valid.
+ 
+ @end table
+ 
+ @subheading Return Value
+ 
+ @code{mallsethook} returns the previous hook pointer, (usually
+ @code{NULL}). If @code{mallsethook} is disabled it will also
+ return @code{NULL}.
+ 
+ @subheading Portability
+ 
+ @portability !ansi, !posix
+ 
+ These hooks and the function are specific to DJGPP.
+ 
+ @subheading Example
+ 
+ @example
+ 
+  static void mallocfailalert(size_t sz, void *ptr)
+  @{
+     printf("Failed to malloc %lu bytes\n", (unsigned long)sz);
+  @}
+ 
+  malloc_debug(1);
+  mallsethook(malloc_fail_HK, mallocfailalert);
+  ...
+  /* any malloc failure will result in a message */
+  
+ @end example
+ 
+ @c -------------------------------------------------------------
+ 
+ @node malldbgdmpfile, memory
+ @subheading Syntax
+ 
+ @example
+ #include <stdlib.h>
+ #include <malldbg.h> (on non-DJGPP systems)
+ 
+ FILE *malldbgdmpfile(FILE *fp);
+ @end example
+ 
+ @subheading Description
+ 
+ This function allows diverting the output of the malldbg package
+ to any suitable text file, known as the @dfn{dumpfile}.  By
+ default the package uses @code{stderr}.
+ 
+ @subheading Return Value
+ 
+ The previous identity of the dumpfile.
+ 
+ @subheading Portability
+ 
+ @portability !ansi, !posix
+ 
+ This function is specific to DJGPP.
+ 
+ @subheading Example
+ 
+ @example
+ FILE *oldfile = malldbgdmpfile(stdout);
+ @end example
+ 
+ @c -------------------------------------------------------------
+ 
+ @node _sysmalloc, memory
+ @subheading Syntax
+ 
+ @example
+ #include <stdlib.h>
+ #include <malldbg.h>  /* on non-DJGPP systems */
+ #include <sysquery.h> /* alternative on non-DJGPP systems */
+ 
+ struct _sysquery _sysmalloc(void);
+ @end example
+ 
+ @subheading Description
+ 
+ This function exports the internal structure of the malloc arena
+ and thus allows construction of such packages as malldbg.  It 
+ avoids accidental exposure of system critical values, and also
+ permits such values to be changed and reflected in external
+ packages.
+ 
+ @subheading Return Value
+ 
+ A @code{struct _sysquery}, described as follows:
+ 
+ @example
+ struct _sysquery @{
+   unsigned char data, gdlo, sz, prvf, nxtf, nxt, prv, ohead;
+   void         *nilp;
+   void         *anchors;
+   set_m_hook    hookset;
+ @};
+ @end example
+ 
+ Any unsigned char field set to 255 signifies the value is
+ meaningless.  The @code{ohead} value is not useful in the
+ present implementation.  The remaining values are small offsets
+ from the internal pointers to the appropriate fields.  In
+ particular @code{data} is the offset between the internal
+ pointer and the user pointers.  @code{nxt} and @code{prv} link
+ all allocated memory blocks, while @code{nxtf} and @code{prvf}
+ are used only to link free blocks. @code{sz} is the internal
+ size of the block, not the user size, and is normally rounded
+ upward.  Thus the @code{nxt} field is redundant to the @code{sz}
+ field (except when no @code{nxt} exists) and is used in validity
+ checking. A @code{NULL} value in @code{nxtf} field signifies
+ that the block is not free. The special value @code{nilp} is
+ used in @code{nxtf} and @code{prvf} as a @code{NULL} value
+ distinguishable from @code{NULL}.
+ 
+ @code{anchors} points to a @code{NULL} terminated list of sets
+ of chains of memory blocks.  These were allocated by @code{sbrk}
+ and were not contiguous to any previous allocations.
+ 
+ @code{hookset} is a pointer to a function that can set malloc
+ hooks, as described in @code{mallsethook}.  It is only available
+ through this link.
+ 
+ @subheading Portability
+ 
+ @portability !ansi, !posix
+ 
+ This function is specific to DJGPP.
+ 
+ @subheading Example
+ 
+ @example
+ struct _sysquery sysinfo = _sysmalloc();
+ @end example
+ 
+ @c -------------------------------------------------------------

--------------080207060608030503020708--

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019