1 /*
2 ** $Id: lmem.c,v 1.1 2002/02/14 10:46:59 jcatki Exp $
3 ** Interface to Memory Manager
4 ** See Copyright Notice in lua.h
5 */
6 
7 
8 #include <stdlib.h>
9 
10 #include "lua.h"
11 
12 #include "ldo.h"
13 #include "lmem.h"
14 #include "lobject.h"
15 #include "lstate.h"
16 
17 
18 
19 
20 #ifdef LUA_DEBUG
21 /*
22 ** {======================================================================
23 ** Controlled version for realloc.
24 ** =======================================================================
25 */
26 
27 
28 #include <assert.h>
29 #include <limits.h>
30 #include <string.h>
31 
32 #define realloc(b, s)	debug_realloc(b, s)
33 #define malloc(b)	debug_realloc(NULL, b)
34 #define free(b)		debug_realloc(b, 0)
35 
36 
37 /* ensures maximum alignment for HEADER */
38 #define HEADER	(sizeof(union L_Umaxalign))
39 
40 #define MARKSIZE	16
41 #define MARK		0x55  /* 01010101 (a nice pattern) */
42 
43 
44 #define blocksize(b)	((unsigned long *)((char *)(b) - HEADER))
45 
46 unsigned long memdebug_numblocks = 0;
47 unsigned long memdebug_total = 0;
48 unsigned long memdebug_maxmem = 0;
49 unsigned long memdebug_memlimit = LONG_MAX;
50 
51 
checkblock(void * block)52 static void *checkblock (void *block) {
53   unsigned long *b = blocksize(block);
54   unsigned long size = *b;
55   int i;
56   for (i=0;i<MARKSIZE;i++)
57     assert(*(((char *)b)+HEADER+size+i) == MARK+i);  /* corrupted block? */
58   memdebug_numblocks--;
59   memdebug_total -= size;
60   return b;
61 }
62 
63 
freeblock(void * block)64 static void freeblock (void *block) {
65   if (block) {
66     size_t size = *blocksize(block);
67     block = checkblock(block);
68     memset(block, -1, size+HEADER+MARKSIZE);  /* erase block */
69     (free)(block);  /* free original block */
70   }
71 }
72 
73 
debug_realloc(void * block,size_t size)74 static void *debug_realloc (void *block, size_t size) {
75   if (size == 0) {
76     freeblock(block);
77     return NULL;
78   }
79   else if (memdebug_total+size > memdebug_memlimit)
80     return NULL;  /* to test memory allocation errors */
81   else {
82     size_t realsize = HEADER+size+MARKSIZE;
83     char *newblock = (char *)(malloc)(realsize);  /* alloc a new block */
84     int i;
85     if (realsize < size) return NULL;  /* overflow! */
86     if (newblock == NULL) return NULL;
87     if (block) {
88       size_t oldsize = *blocksize(block);
89       if (oldsize > size) oldsize = size;
90       memcpy(newblock+HEADER, block, oldsize);
91       freeblock(block);  /* erase (and check) old copy */
92     }
93     memdebug_total += size;
94     if (memdebug_total > memdebug_maxmem) memdebug_maxmem = memdebug_total;
95     memdebug_numblocks++;
96     *(unsigned long *)newblock = size;
97     for (i=0;i<MARKSIZE;i++)
98       *(newblock+HEADER+size+i) = (char)(MARK+i);
99     return newblock+HEADER;
100   }
101 }
102 
103 
104 /* }====================================================================== */
105 #endif
106 
107 
108 
109 /*
110 ** Real ISO (ANSI) systems do not need these tests;
111 ** but some systems (Sun OS) are not that ISO...
112 */
113 #ifdef OLD_ANSI
114 #define realloc(b,s)	((b) == NULL ? malloc(s) : (realloc)(b, s))
115 #define free(b)		if (b) (free)(b)
116 #endif
117 
118 
luaM_growaux(lua_State * L,void * block,size_t nelems,int inc,size_t size,const char * errormsg,size_t limit)119 void *luaM_growaux (lua_State *L, void *block, size_t nelems,
120                int inc, size_t size, const char *errormsg, size_t limit) {
121   size_t newn = nelems+inc;
122   if (nelems >= limit-inc) lua_error(L, errormsg);
123   if ((newn ^ nelems) <= nelems ||  /* still the same power-of-2 limit? */
124        (nelems > 0 && newn < MINPOWER2))  /* or block already is MINPOWER2? */
125       return block;  /* do not need to reallocate */
126   else  /* it crossed a power-of-2 boundary; grow to next power */
127     return luaM_realloc(L, block, luaO_power2(newn)*size);
128 }
129 
130 
131 /*
132 ** generic allocation routine.
133 */
luaM_realloc(lua_State * L,void * block,lint32 size)134 void *luaM_realloc (lua_State *L, void *block, lint32 size) {
135   if (size == 0) {
136     free(block);  /* block may be NULL; that is OK for free */
137     return NULL;
138   }
139   else if (size >= MAX_SIZET)
140     lua_error(L, "memory allocation error: block too big");
141   block = realloc(block, size);
142   if (block == NULL) {
143     if (L)
144       luaD_breakrun(L, LUA_ERRMEM);  /* break run without error message */
145     else return NULL;  /* error before creating state! */
146   }
147   return block;
148 }
149 
150 
151