From: mahilata@vogon.mathi.uni-heidelberg.de (Earthworm society)
Subject: Request for comment: fake sbrk, dbmalloc on the next
Organization: Matlab, University of Heidelberg
Date: Sun, 24 Jan 93 10:26:26 GMT

This is a request for comment for a fake sbrk as well as for
dbmalloc for the next.


Fake sbrk RFC

Many programs that are around work by sbrk instead of malloc, and
use the property of sbrk to extend the existing memory
such as to keep it a contigous array of whatever.

Such as f.ex gap, kant, and (I suspect) Maple.

Now the sbrk which next does have (unsupported), indeed obtains exactly 4M,
and after that crashes (and this is exactly the behaviour of maple)

So I looked around and found that vm_allocate can be told at which
virtual address to put the new chunk. So, after a bit of experimenting,
I came up with following
=============================== fakesbrk.c ==============================
#ifdef NeXT
#import <mach.h>
#import <stddef.h>
#import <stdlib.h>

/*
   NeXT does not have sbrk (or at least they claim so)
   so we use a fake, and use
   vm_allocate.  I still cannot decide if dbmalloc wants
   its working memory contiguous, such as sbrk returns,
   so I depend on vm_allocate to return a virtual chunk
   at a specified address on request.

   The env variable MALLOC_ARRAY tells dbmalloc how large one chunk
   got to be. Else it will assume 4M.

   This fake sbrk will be used by sbrk_using programs as well,
   via malloc.h
*/

#define DFLT_ASIZE 4194304
static int fake_array_length;
static int fake_array_chunk;
static char *fake_array;
static char *current_pointer;

extern int sprintf(char *s, const char *format, ...);

void
init_fake_sbrk()


{
    kern_return_t rtn;
    char *cptr;

    if( (cptr=getenv("MALLOC_ARRAY")) != NULL )
	{
		int xxx=atoi(cptr);
		fake_array_chunk = round_page(xxx);

		if( fake_array_chunk < 10000 )
		{
			fake_array_chunk = DFLT_ASIZE;
		}
	}
    else fake_array_chunk = DFLT_ASIZE;

    if ((rtn=vm_allocate(task_self(), (vm_address_t *)&fake_array,
		fake_array_chunk, TRUE)) != KERN_SUCCESS)
	{   mach_error("vm_allocate failed", rtn);
	    exit(-1);
	}
    current_pointer=fake_array;
    fake_array_length=fake_array_chunk;
/*
{
char aaa[100];
sprintf(aaa,"%d",fake_array_length);
mach_error("YouHoy",0); mach_error(aaa,0);
}
*/
}

char *
fake_sbrk(int amount)
{
    char * tmp;
    if ((current_pointer+amount)>(fake_array+fake_array_length))
    {	int more, more0;
	char *fake_more=fake_array+fake_array_length;
	char *fmore=fake_more;
        kern_return_t rtn;

	more0=(current_pointer+amount)-(fake_array+fake_array_length);
	more=round_page(more0);
	if (more<fake_array_chunk) more=fake_array_chunk;
        if ((rtn=vm_allocate(task_self(), (vm_address_t *)&fake_more,
			more, FALSE)) != KERN_SUCCESS)
	    {	mach_error("out of luck",KERN_NO_SPACE);
		exit(-1); /* didn't get any */
	    }
	if (fake_more!=fmore)
	    {	mach_error("bad luck",KERN_NO_SPACE);
		exit(-1); /* got it wrong */
	    }
	fake_array_length+=more;
/*
{
char aaa[100];
sprintf(aaa,"%d",fake_array_length);
mach_error("Yahooo",0); mach_error(aaa,0);
}
*/
    }
    tmp=current_pointer;
    current_pointer+=amount;
    return(tmp);
}

#endif
======================================================

and a little test program

======================================================
#include <stdio.h>

char *fake_sbrk();

main()

{ char *a, *b, *c, *d;
  int x;
  int i=0;

  scanf("%d",&x);
init_fake_sbrk();

  a=fake_sbrk(0);
  printf("%d\n\n",(int)a);
  scanf("%d",&x);

  while (1)
  { i++;
    b=fake_sbrk((int)32768);
    *b='a';

    printf("%d: %d \n", i, (int)b-(int)a);
    a=b;
  }
}
======================================================

and lo! this does not crash anymore after 4M.

Since this is my first attempt at the innards of next, I would
be really glad over comments about the validity of this.

Is this really freely accessible memory?
(I mean the *b='a'; test might not mean really much)

and what about the chances for the condition termed
"bad luck" which is memory not contiguous?

What about nextstep3? (it *seems* to work)

======================================================
======================================================

The second RFC concerns dbmalloc (earlier mallocdebug),
which was in comp.sources.misc volume 32 (I think) (last year)
and which is tremendously more powerful than MallocDebug
(at least when you cannot use the MallocDebug app since you
 don't debug an app).

(In comp.sys.next.programmer there I saw remarks about a great
 many programs handling malloc/free erroneously. I found myself
 quite a few such. dbmalloc on whichever machine is a great tool
 to hunt down things. MallocDebug I found little help)

It is for this why I designed the fakesbrk in the first place.

But then it turned out that nearly everything of interest
got loaded twice since libsys_s.a is full of crosspointers.
I did not dare to untangle all this, nor to fake it, like
MallocDebug seems to have done. So I dropped all the base
functions malloc, realloc,free (see annexed diff), and
have to trust to the db's malloc.h to switch names.

This means that toolbox library
malloc is not caught anymore at ld time. which means that there
are two sets of malloc/free/whatever routines operating
(hopefully) independently of each other. I think this is
a case of what the docs say intermixing of raw vm_allocate
with OS-own malloc, and which has been warned against.

On the other hand. I did successfully operate this thing.
In particular on the next I am able to use gdb with this
which I cannot do on a sun nor on an rs6000
(Don't ask me why but it crashes at once)


Is there any more info out there? Ideas? Suggestions?
Dirty tricks with libsys_s.a? A new pointers.o perhaps?

Lastly the diff of dbmalloc. include fakesbrk.c and
insert it in the Makefile.

 -mahilata@mathi.uni-heidelberg.de

=======================================================
*** gamal/calloc.c	Wed Jan 20 01:06:06 1993
--- ./calloc.c	Sun Jan 24 00:34:10 1993
***************
*** 32,37 ****
--- 32,38 ----
   *
   * Narrative:	call debug_calloc and return it's return
   */
+ #ifndef NeXT
  DATATYPE *
  calloc(nelem,elsize)
  	SIZETYPE 	  nelem;
***************
*** 39,44 ****
--- 40,46 ----
  {
  	return( debug_calloc((char *)NULL,(int)-1,nelem,elsize) );
  }
+ #endif
  
  /*
   * Function:	debug_calloc()
*** gamal/dgmalloc.c	Wed Jan 20 01:06:09 1993
--- ./dgmalloc.c	Sun Jan 24 00:58:34 1993
***************
*** 67,72 ****
--- 67,73 ----
      return( dbmallopt(cmd,&value) );
  }
  
+ #ifndef NeXT
  MEMDATA  *
  _bcopy(ptr2, ptr1, len)
  	CONST MEMDATA	* ptr2;
***************
*** 75,81 ****
--- 76,84 ----
  {
  	return( DBbcopy((char *)NULL,0,ptr2,ptr1,len) );
  }
+ #endif
  
+ #ifndef NeXT
  MEMDATA  *
  _bzero(ptr1, len)
  	MEMDATA		* ptr1;
***************
*** 83,88 ****
--- 86,92 ----
  {
  	return( DBbzero((char *)NULL,0,ptr1,len) );
  }
+ #endif
  
  int
  _bcmp(ptr2, ptr1, len)
*** gamal/free.c	Wed Jan 20 01:06:13 1993
--- ./free.c	Sun Jan 24 00:44:41 1993
***************
*** 43,48 ****
--- 43,49 ----
  char rcs_hdr[] = "$Id: free.c,v 1.29 1992/08/22 16:27:13 cpcahil Exp $";
  #endif
  
+ #ifndef NeXT
  FREETYPE
  free(cptr)
  	DATATYPE	* cptr;
***************
*** 49,54 ****
--- 50,56 ----
  {
  	debug_free((char *)NULL, 0, cptr);
  }
+ #endif
  
  FREETYPE
  debug_free(file,line,cptr)
*** gamal/m_init.c	Wed Jan 20 01:06:14 1993
--- ./m_init.c	Sat Jan 23 20:48:37 1993
***************
*** 51,56 ****
--- 51,60 ----
  		return;
  	}
  
+ #ifdef NeXT
+ 	init_fake_sbrk();
+ #endif
+ 
  
  	malloc_data_start = sbrk(0);
  	malloc_data_end = malloc_data_start;
*** gamal/malloc.c	Wed Jan 20 01:06:22 1993
--- ./malloc.c	Sun Jan 24 00:43:33 1993
***************
*** 89,94 ****
--- 89,95 ----
   * Narrative:
   *
   */
+ #ifndef NeXT
  DATATYPE *
  malloc(size)
  	SIZETYPE	  size;
***************
*** 95,100 ****
--- 96,102 ----
  {
  	return( debug_malloc(NULL,-1,size) );
  }
+ #endif
  
  /*
   * Function:	debug_malloc()
*** gamal/malloc.h.org	Wed Jan 20 01:06:16 1993
--- ./malloc.h.org	Sat Jan 23 21:49:35 1993
***************
*** 15,20 ****
--- 15,24 ----
   * $Id: malloc.h.org,v 1.38 1992/08/22 16:27:13 cpcahil Exp $
   */
  
+ #ifdef NeXT
+ #define sbrk fake_sbrk
+ #endif
+ 
  #ifndef _DEBUG_MALLOC_INC
  #define _DEBUG_MALLOC_INC 1
  
*** gamal/memory.c	Wed Jan 20 01:06:30 1993
--- ./memory.c	Sun Jan 24 00:47:35 1993
***************
*** 128,133 ****
--- 128,134 ----
   * memcpy  - copy one memory area to another
   * memmove - copy one memory area to another
   */
+ #ifndef NeXT
  MEMDATA  * 
  memmove(ptr1, ptr2, len)
  	MEMDATA 		* ptr1;
***************
*** 136,141 ****
--- 137,143 ----
  {
  	return( DBmemmove( (char *) NULL, 0,ptr1, ptr2, len) );
  }
+ #endif
  
  MEMDATA  * 
  DBmemmove(file,line,ptr1, ptr2, len)
***************
*** 250,255 ****
--- 252,258 ----
  /*
   * memset - set all bytes of a memory block to a specified value
   */
+ #ifndef NeXT
  MEMDATA  * 
  memset(ptr1, ch, len)
  	MEMDATA 		* ptr1;
***************
*** 258,263 ****
--- 261,267 ----
  {
  	return( DBmemset((char *)NULL,0,ptr1,ch,len) );
  }
+ #endif
  
  MEMDATA  * 
  DBmemset(file,line,ptr1, ch, len)
*** gamal/realloc.c	Sun Jan 24 12:00:01 1993
--- ./realloc.c	Sun Jan 24 00:38:40 1993
***************
*** 21,26 ****
--- 21,27 ----
  
  #include "mallocin.h"
  
+ #ifndef NeXT
  DATATYPE *
  realloc(cptr,size)
  	DATATYPE		* cptr;
***************
*** 28,33 ****
--- 29,35 ----
  {
  	return( debug_realloc(NULL,-1,cptr,size) );
  }
+ #endif
  
  DATATYPE *
  debug_realloc(file,line,cptr,size)
*** gamal/stack.c	Sun Jan 24 01:34:05 1993
--- ./stack.c	Sun Jan 24 01:47:07 1993
***************
*** 99,106 ****
  	 * if there are no entries below this func yet,
  	 */
  	if( this->below == NULL )
! 	{
! 		this->below = StackNew(func,file,line);
  		this->below->above = this;
  		current = this->below;
  	}
--- 99,107 ----
  	 * if there are no entries below this func yet,
  	 */
  	if( this->below == NULL )
! 	{   struct stack *xxx; xxx=StackNew(func,file,line);
! 	  /* NeXT cc bug? */
! 		this->below = xxx;
  		this->below->above = this;
  		current = this->below;
  	}
***************
*** 321,329 ****
  		/*
  		 * perform some simple sanity checking on the node pointer
  		 */
! 		if(    (((DATATYPE *)node) < malloc_data_start)
  		    || (((DATATYPE *)node) > malloc_data_end)
! 		    || ((((long)node) & 0x1) != 0) )
  		{
  			WRITEOUT(fd,"INVALID/BROKEN STACK CHAIN!!!\n",30);
  			break;
--- 322,334 ----
  		/*
  		 * perform some simple sanity checking on the node pointer
  		 */
! 		if(  
! #ifndef NeXT
! 			(((DATATYPE *)node) < malloc_data_start)
  		    || (((DATATYPE *)node) > malloc_data_end)
! 		    ||
! #endif
! 			 ((((long)node) & 0x1) != 0) )
  		{
  			WRITEOUT(fd,"INVALID/BROKEN STACK CHAIN!!!\n",30);
  			break;
*** gamal/string.c	Wed Jan 20 01:06:34 1993
--- ./string.c	Sun Jan 24 00:59:21 1993
***************
*** 451,456 ****
--- 451,457 ----
  /*
   * strcpy - copy a string somewhere else
   */
+ #ifndef NeXT
  char *
  strcpy(str1,str2)
  	register char		* str1;
***************
*** 458,463 ****
--- 459,465 ----
  {
  	return( DBstrcpy((char *)NULL, 0, str1, str2) );
  }
+ #endif
  
  char *
  DBstrcpy(file, line, str1, str2)
***************
*** 486,491 ****
--- 488,494 ----
  /*
   * strncpy - copy a string upto a specified number of chars somewhere else
   */
+ #ifndef NeXT
  char *
  strncpy(str1,str2,len)
  	register char		* str1;
***************
*** 494,499 ****
--- 497,503 ----
  {
  	return( DBstrncpy((char *)NULL, 0, str1, str2, len) );
  }
+ #endif
  
  char *
  DBstrncpy(file,line,str1,str2,len)
***************
*** 543,548 ****
--- 547,553 ----
  /*
   * strlen - determine length of a string
   */
+ #ifndef NeXT
  STRSIZE 
  strlen(str1)
  	CONST char	* str1;
***************
*** 549,554 ****
--- 554,560 ----
  {
  	return( DBstrlen((char *) NULL, 0, str1) );
  }
+ #endif
  
  STRSIZE 
  DBstrlen(file, line, str1)
***************
*** 668,673 ****
--- 674,686 ----
  /*
   * index - find location of character within string
   */
+ 
+ #ifdef NeXT
+ #ifdef index
+ #undef index
+ #endif
+ #endif
+ 
  char *
  index(str1,c)
  	CONST char		* str1;
***************
*** 688,693 ****
--- 701,712 ----
  /*
   * rindex - find rightmost location of character within string
   */
+ #ifdef NeXT
+ #ifdef rindex
+ #undef rindex
+ #endif
+ #endif
+ 
  char *
  rindex(str1,c)
  	CONST char	* str1;
*** gamal/testmalloc.c	Wed Jan 20 01:06:36 1993
--- ./testmalloc.c	Sun Jan 24 01:05:24 1993
***************
*** 71,77 ****
--- 71,79 ----
  
  	double * dblptr;		/* pointer for doubleword test */
  
+ #ifndef NeXT
  	extern char end;		/* memory before heap */
+ #endif
  	char *sbrk();
  	long atol();
  	union dbmalloptarg m;
***************
*** 120,128 ****
--- 122,132 ----
  	for( i = 0; i < MAXOBJS; i++ )
  		objs[ i ] = NULL;
  
+ #ifndef NeXT
  	startsize = sbrk(0) - &end;
  	printf( "Memory use at start: %ld bytes\n", startsize );
  	fflush(stdout);
+ #endif
  
  	printf("Starting the test...\n");
  	fflush(stdout);
***************
*** 223,229 ****
--- 227,235 ----
  
  	printf( "Did %ld iterations, %d objects, %d mallocs, %d reallocs\n",
  		n, cnt, nm, nre );
+ #ifndef NeXT
  	printf( "Memory use at end: %ld bytes\n", sbrk(0) - &end );
+ #endif
  	fflush( stdout );
  
  	/* free all the objects */
***************
*** 242,247 ****
--- 248,254 ----
  		}
  	}
  
+ #ifndef NeXT
  	endsize = sbrk(0) - &end;
  	printf( "Memory use after free: %ld bytes\n", endsize );
  	fflush( stdout );
***************
*** 248,253 ****
--- 255,261 ----
  
  	if( startsize != endsize )
  		printf("startsize %ld != endsize %d\n", startsize, endsize );
+ #endif
  
  	free( (DATATYPE *) objs );
  	free( (DATATYPE *) sizes );
-- 


 --mahilata@mathi.uni-heidelberg.de