safemalloc.c 17.4 KB
Newer Older
unknown's avatar
unknown committed
1 2 3 4 5 6 7 8
/* Copyright (C) 2000 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
unknown's avatar
unknown committed
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
unknown's avatar
unknown committed
10 11 12 13 14 15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
unknown's avatar
unknown committed
16 17 18 19

/*
 * Memory sub-system, written by Bjorn Benson
   Fixed to use my_sys scheme by Michael Widenius
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61

  [This posting refers to an article entitled "oops, corrupted memory
  again!" in net.lang.c.  I am posting it here because it is source.]

  My tool for approaching this problem is to build another level of data
  abstraction on top of malloc() and free() that implements some checking.
  This does a number of things for you:
	- Checks for overruns and underruns on allocated data
	- Keeps track of where in the program the memory was malloc'ed
	- Reports on pieces of memory that were not free'ed
	- Records some statistics such as maximum memory used
	- Marks newly malloc'ed and newly free'ed memory with special values
  You can use this scheme to:
	- Find bugs such as overrun, underrun, etc because you know where
	  a piece of data was malloc'ed and where it was free'ed
	- Find bugs where memory was not free'ed
	- Find bugs where newly malloc'ed memory is used without initializing
	- Find bugs where newly free'ed memory is still used
	- Determine how much memory your program really uses
	- and other things

  To implement my scheme you must have a C compiler that has __LINE__ and
  __FILE__ macros.  If your compiler doesn't have these then (a) buy another:
  compilers that do are available on UNIX 4.2bsd based systems and the PC,
  and probably on other machines; or (b) change my scheme somehow.  I have
  recomendations on both these points if you would like them (e-mail please).

  There are 4 functions in my package:
	char *NEW( uSize )	Allocate memory of uSize bytes
				(equivalent to malloc())
	char *REA( pPtr, uSize) Allocate memory of uSize bytes, move data and
				free pPtr.
				(equivalent to realloc())
	FREE( pPtr )		Free memory allocated by NEW
				(equivalent to free())
	TERMINATE(file)		End system, report errors and stats on file
  I personally use two more functions, but have not included them here:
	char *STRSAVE( sPtr )	Save a copy of the string in dynamic memory
	char *RENEW( pPtr, uSize )
				(equivalent to realloc())

*/
unknown's avatar
unknown committed
62 63 64 65 66 67 68 69 70 71

#ifndef SAFEMALLOC
#define SAFEMALLOC			/* Get protos from my_sys */
#endif

#include "mysys_priv.h"
#include <m_string.h>
#include "my_static.h"
#include "mysys_err.h"

unknown's avatar
unknown committed
72
ulonglong safemalloc_mem_limit = ~(ulonglong)0;
73 74

#ifdef THREAD
75
pthread_t shutdown_th,main_th,signal_th;
76
#endif
unknown's avatar
unknown committed
77

unknown's avatar
unknown committed
78 79 80 81 82
#define pNext		tInt._pNext
#define pPrev		tInt._pPrev
#define sFileName	tInt._sFileName
#define uLineNum	tInt._uLineNum
#define uDataSize	tInt._uDataSize
83
#define thread_id       tInt.thread_id
unknown's avatar
unknown committed
84 85
#define lSpecialValue	tInt._lSpecialValue

86
#ifndef PEDANTIC_SAFEMALLOC
87 88 89 90 91 92
/*
  Set to 1 after TERMINATE() if we had to fiddle with cNewCount and
  the linked list of blocks so that _sanity() will not fuss when it
  is not supposed to
*/
static int sf_malloc_tampered = 0;
93 94 95
#endif
				   

unknown's avatar
unknown committed
96 97 98 99 100 101 102
	/* Static functions prototypes */

static int check_ptr(const char *where, byte *ptr, const char *sFile,
		     uint uLine);
static int _checkchunk(struct remember *pRec, const char *sFile, uint uLine);

/*
103 104 105 106
  Note: both these refer to the NEW'ed data only.  They do not include
  malloc() roundoff or the extra space required by the remember
  structures.
*/
unknown's avatar
unknown committed
107

108 109 110 111 112 113 114 115 116 117
/*
  NEW'ed memory is filled with this value so that references to it will
  end up being very strange.
*/
#define ALLOC_VAL	(uchar) 0xA5
/*
  FEEE'ed memory is filled with this value so that references to it will
  end up being very strange.
*/
#define FREE_VAL	(uchar) 0x8F
unknown's avatar
unknown committed
118
#define MAGICKEY	0x14235296	/* A magic value for underrun key */
119 120 121 122 123 124 125 126

/*
  Warning: do not change the MAGICEND? values to something with the
  high bit set.  Various C compilers (like the 4.2bsd one) do not do
  the sign extension right later on in this code and you will get
  erroneous errors.
*/

unknown's avatar
unknown committed
127 128 129 130 131 132
#define MAGICEND0	0x68		/* Magic values for overrun keys  */
#define MAGICEND1	0x34		/*		"		  */
#define MAGICEND2	0x7A		/*		"		  */
#define MAGICEND3	0x15		/*		"		  */


133
/* Allocate some memory. */
unknown's avatar
unknown committed
134 135 136 137 138 139 140

gptr _mymalloc (uint uSize, const char *sFile, uint uLine, myf MyFlags)
{
    struct remember *pTmp;
    DBUG_ENTER("_mymalloc");
    DBUG_PRINT("enter",("Size: %u",uSize));

unknown's avatar
unknown committed
141

unknown's avatar
unknown committed
142 143 144
    if (!sf_malloc_quick)
      (void) _sanity (sFile, uLine);

145
    if (uSize + lCurMemory > safemalloc_mem_limit)
unknown's avatar
unknown committed
146 147
      pTmp = 0;
    else
148
    {
unknown's avatar
unknown committed
149 150
       /* Allocate the physical memory */
       pTmp = (struct remember *) malloc (
unknown's avatar
unknown committed
151 152 153 154 155 156
		sizeof (struct irem)			/* remember data  */
		+ sf_malloc_prehunc
		+ uSize					/* size requested */
		+ 4					/* overrun mark   */
		+ sf_malloc_endhunc
		);
157
    }
unknown's avatar
unknown committed
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
    /* Check if there isn't anymore memory avaiable */
    if (pTmp == NULL)
    {
      if (MyFlags & MY_FAE)
	error_handler_hook=fatal_error_handler_hook;
      if (MyFlags & (MY_FAE+MY_WME))
      {
	char buff[SC_MAXWIDTH];
	my_errno=errno;
	sprintf(buff,"Out of memory at line %d, '%s'", uLine, sFile);
	my_message(EE_OUTOFMEMORY,buff,MYF(ME_BELL+ME_WAITTANG));
	sprintf(buff,"needed %d byte (%ldk), memory in use: %ld bytes (%ldk)",
		uSize, (uSize + 1023L) / 1024L,
		lMaxMemory, (lMaxMemory + 1023L) / 1024L);
	my_message(EE_OUTOFMEMORY,buff,MYF(ME_BELL+ME_WAITTANG));
      }
      DBUG_PRINT("error",("Out of memory, in use: %ld at line %d, '%s'",
			  lMaxMemory,uLine, sFile));
      if (MyFlags & MY_FAE)
	exit(1);
      DBUG_RETURN ((gptr) NULL);
    }

    /* Fill up the structure */
    *((long*) ((char*) &pTmp -> lSpecialValue+sf_malloc_prehunc)) = MAGICKEY;
    pTmp -> aData[uSize + sf_malloc_prehunc+0] = MAGICEND0;
    pTmp -> aData[uSize + sf_malloc_prehunc+1] = MAGICEND1;
    pTmp -> aData[uSize + sf_malloc_prehunc+2] = MAGICEND2;
    pTmp -> aData[uSize + sf_malloc_prehunc+3] = MAGICEND3;
    pTmp -> sFileName = (my_string) sFile;
    pTmp -> uLineNum = uLine;
    pTmp -> uDataSize = uSize;
190
#ifdef THREAD
191
    pTmp->thread_id = pthread_self();
192
#endif
unknown's avatar
unknown committed
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
    pTmp -> pPrev = NULL;

    /* Add this remember structure to the linked list */
    pthread_mutex_lock(&THR_LOCK_malloc);
    if ((pTmp->pNext=pRememberRoot))
    {
      pRememberRoot -> pPrev = pTmp;
    }
    pRememberRoot = pTmp;

    /* Keep the statistics */
    lCurMemory += uSize;
    if (lCurMemory > lMaxMemory) {
	lMaxMemory = lCurMemory;
    }
    cNewCount++;
    pthread_mutex_unlock(&THR_LOCK_malloc);

    /* Set the memory to the aribtrary wierd value */
#ifdef HAVE_purify
    if (MyFlags & MY_ZEROFILL)
#endif
      bfill(&pTmp -> aData[sf_malloc_prehunc],uSize,
	    (char) (MyFlags & MY_ZEROFILL ? 0 : ALLOC_VAL));
    /* Return a pointer to the real data */
    DBUG_PRINT("exit",("ptr: %lx",&(pTmp -> aData[sf_malloc_prehunc])));
    if (sf_min_adress > &(pTmp -> aData[sf_malloc_prehunc]))
      sf_min_adress = &(pTmp -> aData[sf_malloc_prehunc]);
    if (sf_max_adress < &(pTmp -> aData[sf_malloc_prehunc]))
      sf_max_adress = &(pTmp -> aData[sf_malloc_prehunc]);
    DBUG_RETURN ((gptr) &(pTmp -> aData[sf_malloc_prehunc]));
}

/*
227 228 229
  Allocate some new memory and move old memoryblock there.
  Free then old memoryblock
*/
unknown's avatar
unknown committed
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259

gptr _myrealloc (register gptr pPtr, register uint uSize,
		 const char *sFile, uint uLine, myf MyFlags)
{
  struct remember *pRec;
  gptr ptr;
  DBUG_ENTER("_myrealloc");

  if (!pPtr && (MyFlags & MY_ALLOW_ZERO_PTR))
    DBUG_RETURN(_mymalloc(uSize,sFile,uLine,MyFlags));

  if (!sf_malloc_quick)
    (void) _sanity (sFile, uLine);

  if (check_ptr("Reallocating",(byte*) pPtr,sFile,uLine))
    DBUG_RETURN((gptr) NULL);

  pRec = (struct remember *) ((char*) pPtr - sizeof (struct irem)-
			      sf_malloc_prehunc);
  if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc))
      != MAGICKEY)
  {
    fprintf (stderr, "Reallocating unallocated data at line %d, '%s'\n",
	     uLine, sFile);
    DBUG_PRINT("safe",("Reallocating unallocated data at line %d, '%s'",
		       uLine, sFile));
    (void) fflush(stderr);
    DBUG_RETURN((gptr) NULL);
  }

260
  if ((ptr=_mymalloc(uSize,sFile,uLine,MyFlags))) /* Allocate new area */
unknown's avatar
unknown committed
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
  {
    uSize=min(uSize,pRec-> uDataSize);		/* Move as much as possibly */
    memcpy((byte*) ptr,pPtr,(size_t) uSize);	/* Copy old data */
    _myfree(pPtr,sFile,uLine,0);		/* Free not needed area */
  }
  else
  {
    if (MyFlags & MY_HOLD_ON_ERROR)
      DBUG_RETURN(pPtr);
    if (MyFlags & MY_FREE_ON_ERROR)
      _myfree(pPtr,sFile,uLine,0);
  }
  DBUG_RETURN(ptr);
} /* _myrealloc */


277
/* Deallocate some memory. */
unknown's avatar
unknown committed
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295

void _myfree (gptr pPtr, const char *sFile, uint uLine, myf myflags)
{
  struct remember *pRec;
  DBUG_ENTER("_myfree");
  DBUG_PRINT("enter",("ptr: %lx",pPtr));

  if (!sf_malloc_quick)
    (void) _sanity (sFile, uLine);

  if ((!pPtr && (myflags & MY_ALLOW_ZERO_PTR)) ||
      check_ptr("Freeing",(byte*) pPtr,sFile,uLine))
    DBUG_VOID_RETURN;

  /* Calculate the address of the remember structure */
  pRec = (struct remember *) ((byte*) pPtr-sizeof(struct irem)-
			      sf_malloc_prehunc);

296 297 298 299 300 301 302 303
  /*
    Check to make sure that we have a real remember structure.
    Note: this test could fail for four reasons:
    	(1) The memory was already free'ed
	(2) The memory was never new'ed
	(3) There was an underrun
	(4) A stray pointer hit this location
  */
unknown's avatar
unknown committed
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376

  if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc))
      != MAGICKEY)
  {
    fprintf (stderr, "Freeing unallocated data at line %d, '%s'\n",
	     uLine, sFile);
    DBUG_PRINT("safe",("Unallocated data at line %d, '%s'",uLine,sFile));
    (void) fflush(stderr);
    DBUG_VOID_RETURN;
  }

  /* Remove this structure from the linked list */
  pthread_mutex_lock(&THR_LOCK_malloc);
  if (pRec -> pPrev) {
    pRec -> pPrev -> pNext = pRec -> pNext;
  } else {
    pRememberRoot = pRec -> pNext;
  }
  if (pRec -> pNext) {
    pRec -> pNext -> pPrev = pRec -> pPrev;
  }
  /* Handle the statistics */
  lCurMemory -= pRec -> uDataSize;
  cNewCount--;
  pthread_mutex_unlock(&THR_LOCK_malloc);

#ifndef HAVE_purify
  /* Mark this data as free'ed */
  bfill(&pRec->aData[sf_malloc_prehunc],pRec->uDataSize,(pchar) FREE_VAL);
#endif
  *((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc)) = ~MAGICKEY;

  /* Actually free the memory */
  free ((my_string ) pRec);
  DBUG_VOID_RETURN;
}

	/* Check if we have a wrong  pointer */

static int check_ptr(const char *where, byte *ptr, const char *sFile,
		     uint uLine)
{
  if (!ptr)
  {
    fprintf (stderr, "%s NULL pointer at line %d, '%s'\n",
	     where,uLine, sFile);
    DBUG_PRINT("safe",("Null pointer at line %d '%s'", uLine, sFile));
    (void) fflush(stderr);
    return 1;
  }
#ifndef _MSC_VER
  if ((long) ptr & (MY_ALIGN(1,sizeof(char *))-1))
  {
    fprintf (stderr, "%s wrong aligned pointer at line %d, '%s'\n",
	     where,uLine, sFile);
    DBUG_PRINT("safe",("Wrong aligned pointer at line %d, '%s'",
		       uLine,sFile));
    (void) fflush(stderr);
    return 1;
  }
#endif
  if (ptr < sf_min_adress || ptr > sf_max_adress)
  {
    fprintf (stderr, "%s pointer out of range at line %d, '%s'\n",
	     where,uLine, sFile);
    DBUG_PRINT("safe",("Pointer out of range at line %d '%s'",
		       uLine,sFile));
    (void) fflush(stderr);
    return 1;
  }
  return 0;
}

unknown's avatar
unknown committed
377 378

#if !defined(PEDANTIC_SAFEMALLOC) && defined(THREAD)
379 380
static int legal_leak(struct remember* pPtr)
{
381
  /* TODO: This code needs to be made more general */
unknown's avatar
unknown committed
382 383 384 385
  return (pthread_equal(pthread_self(), pPtr->thread_id) ||
	  pthread_equal(main_th, pPtr->thread_id) ||
	  pthread_equal(shutdown_th,pPtr->thread_id) ||
	  pthread_equal(signal_th,pPtr->thread_id));
386
}
unknown's avatar
unknown committed
387 388
#endif /* THREAD */

unknown's avatar
unknown committed
389 390

/*
391 392 393
  TERMINATE(FILE *file)
    Report on all the memory pieces that have not been
    free'ed as well as the statistics.
unknown's avatar
unknown committed
394 395 396 397 398 399 400 401
 */

void TERMINATE (FILE *file)
{
  struct remember *pPtr;
  DBUG_ENTER("TERMINATE");
  pthread_mutex_lock(&THR_LOCK_malloc);

402 403 404 405 406
  /*
    Report the difference between number of calls to
    NEW and the number of calls to FREE.  >0 means more
    NEWs than FREEs.  <0, etc.
  */
unknown's avatar
unknown committed
407

408 409 410 411 412 413 414 415
#if !defined(PEDANTIC_SAFEMALLOC) && defined(THREAD)
  /*
    Avoid false alarms for blocks that we cannot free before my_end()
    This does miss some positives, but that is ok. This will only miss
    failures to free things allocated in the main thread which 
    performs only one-time allocations. If you really need to
    debug memory allocations in the main thread,
    #define PEDANTIC_SAFEMALLOC
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
  */
  if ((pPtr=pRememberRoot))
  {
    while (pPtr)
    {
      if (legal_leak(pPtr))
      {
	sf_malloc_tampered=1;
	cNewCount--;
	lCurMemory -= pPtr->uDataSize;
	if (pPtr->pPrev)
	{
	  struct remember* tmp;
	  tmp = pPtr->pPrev->pNext = pPtr->pNext;
	  if (tmp)
	   tmp->pPrev = pPtr->pPrev; 
	  pPtr->pNext = pPtr->pPrev = 0;
	  pPtr = tmp;
	}
	else
	{
	  pRememberRoot = pPtr->pNext;
	  pPtr->pNext = pPtr->pPrev = 0;
	  pPtr = pRememberRoot;
	  if (pPtr)
	    pPtr->pPrev=0;
	}
      }
      else
	pPtr = pPtr->pNext;
    }
  }
#endif  
  
unknown's avatar
unknown committed
450 451 452 453 454 455 456 457 458 459
  if (cNewCount)
  {
    if (file)
    {
      fprintf (file, "cNewCount: %d\n", cNewCount);
      (void) fflush(file);
    }
    DBUG_PRINT("safe",("cNewCount: %d",cNewCount));
  }

460 461 462 463
  /*
    Report on all the memory that was allocated with NEW
    but not free'ed with FREE.
  */
unknown's avatar
unknown committed
464 465 466 467 468 469 470 471 472 473 474 475 476 477

  if ((pPtr=pRememberRoot))
  {
    if (file)
    {
      fprintf(file, "Memory that was not free'ed (%ld bytes):\n",lCurMemory);
      (void) fflush(file);
    }
    DBUG_PRINT("safe",("Memory that was not free'ed (%ld bytes):",lCurMemory));
    while (pPtr)
    {
      if (file)
      {
	fprintf (file,
478
		 "\t%6u bytes at 0x%09lx, allocated at line %4u in '%s'",
unknown's avatar
unknown committed
479 480 481
		 pPtr -> uDataSize,
		 (ulong) &(pPtr -> aData[sf_malloc_prehunc]),
		 pPtr -> uLineNum, pPtr -> sFileName);
482 483 484 485
#ifdef THREAD
	fprintf(file, " in thread %ld", pPtr->thread_id);
#endif
	fprintf(file, "\n");
unknown's avatar
unknown committed
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
	(void) fflush(file);
      }
      DBUG_PRINT("safe",
		 ("%6u bytes at 0x%09lx, allocated at line %4d in '%s'",
		  pPtr -> uDataSize, &(pPtr -> aData[sf_malloc_prehunc]),
		  pPtr -> uLineNum, pPtr -> sFileName));
      pPtr = pPtr -> pNext;
    }
  }
  /* Report the memory usage statistics */
  if (file)
  {
    fprintf (file, "Maximum memory usage: %ld bytes (%ldk)\n",
	     lMaxMemory, (lMaxMemory + 1023L) / 1024L);
    (void) fflush(file);
  }
  DBUG_PRINT("safe",("Maximum memory usage: %ld bytes (%ldk)",
		     lMaxMemory, (lMaxMemory + 1023L) / 1024L));
  pthread_mutex_unlock(&THR_LOCK_malloc);
  DBUG_VOID_RETURN;
}


	/* Returns 0 if chunk is ok */

static int _checkchunk (register struct remember *pRec, const char *sFile,
			uint uLine)
{
  reg1 uint uSize;
  reg2 my_string magicp;
  reg3 int flag=0;

  /* Check for a possible underrun */
  if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc))
      != MAGICKEY)
  {
    fprintf (stderr, "Memory allocated at %s:%d was underrun,",
	     pRec -> sFileName, pRec -> uLineNum);
    fprintf (stderr, " discovered at %s:%d\n", sFile, uLine);
    (void) fflush(stderr);
    DBUG_PRINT("safe",("Underrun at %lx, allocated at %s:%d",
		       &(pRec -> aData[sf_malloc_prehunc]),
		       pRec -> sFileName,
		       pRec -> uLineNum));
    flag=1;
  }

  /* Check for a possible overrun */
  uSize = pRec -> uDataSize;
  magicp = &(pRec -> aData[uSize+sf_malloc_prehunc]);
  if (*magicp++ != MAGICEND0 ||
      *magicp++ != MAGICEND1 ||
      *magicp++ != MAGICEND2 ||
      *magicp++ != MAGICEND3)
  {
    fprintf (stderr, "Memory allocated at %s:%d was overrun,",
	     pRec -> sFileName, pRec -> uLineNum);
    fprintf (stderr, " discovered at '%s:%d'\n", sFile, uLine);
    (void) fflush(stderr);
    DBUG_PRINT("safe",("Overrun at %lx, allocated at %s:%d",
		       &(pRec -> aData[sf_malloc_prehunc]),
		       pRec -> sFileName,
		       pRec -> uLineNum));
    flag=1;
  }
  return(flag);
}


	/* Returns how many wrong chunks */

int _sanity (const char *sFile, uint uLine)
{
  reg1 struct remember *pTmp;
  reg2 int flag=0;
  uint count=0;

  pthread_mutex_lock(&THR_LOCK_malloc);
564 565 566 567
#ifndef PEDANTIC_SAFEMALLOC  
  if (sf_malloc_tampered && cNewCount < 0)
    cNewCount=0;
#endif  
unknown's avatar
unknown committed
568 569 570 571 572 573 574 575
  count=cNewCount;
  for (pTmp = pRememberRoot; pTmp != NULL && count-- ; pTmp = pTmp -> pNext)
    flag+=_checkchunk (pTmp, sFile, uLine);
  pthread_mutex_unlock(&THR_LOCK_malloc);
  if (count || pTmp)
  {
    const char *format="Safemalloc link list destroyed, discovered at '%s:%d'";
    fprintf (stderr, format, sFile, uLine); fputc('\n',stderr);
576
    fprintf (stderr, "root=%p,count=%d,pTmp=%p\n", pRememberRoot,count,pTmp);
unknown's avatar
unknown committed
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
    (void) fflush(stderr);
    DBUG_PRINT("safe",(format, sFile, uLine));
    flag=1;
  }
  return flag;
} /* _sanity */


	/* malloc and copy */

gptr _my_memdup(const byte *from, uint length, const char *sFile, uint uLine,
		myf MyFlags)
{
  gptr ptr;
  if ((ptr=_mymalloc(length,sFile,uLine,MyFlags)) != 0)
    memcpy((byte*) ptr, (byte*) from,(size_t) length);
  return(ptr);
} /*_my_memdup */


my_string _my_strdup(const char *from, const char *sFile, uint uLine,
		     myf MyFlags)
{
  gptr ptr;
  uint length=(uint) strlen(from)+1;
  if ((ptr=_mymalloc(length,sFile,uLine,MyFlags)) != 0)
    memcpy((byte*) ptr, (byte*) from,(size_t) length);
  return((my_string) ptr);
} /* _my_strdup */