1 /*
2     memalloc.c:
3 
4     Copyright (C) 1991 Barry Vercoe, John ffitch, Richard Dobson,
5               (C) 2005 Istvan Varga
6 
7     This file is part of Csound.
8 
9     The Csound Library is free software; you can redistribute it
10     and/or modify it under the terms of the GNU Lesser General Public
11     License as published by the Free Software Foundation; either
12     version 2.1 of the License, or (at your option) any later version.
13 
14     Csound is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU Lesser General Public License for more details.
18 
19     You should have received a copy of the GNU Lesser General Public
20     License along with Csound; if not, write to the Free Software
21     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22     02110-1301 USA
23 */
24 
25 #include "csoundCore.h"                 /*              MEMALLOC.C      */
26 
27 /* This code wraps malloc etc with maintaining a list of allocated memory
28    so it can be freed on a reset.  It would not be necessary with a zoned
29    allocator.
30 */
31 #if defined(BETA) && !defined(MEMDEBUG)
32 #define MEMDEBUG  1
33 #endif
34 
35 #define MEMALLOC_MAGIC  0x6D426C6B
36 /* The memory list must be controlled by mutex */
37 #define CSOUND_MEM_SPINLOCK csoundSpinLock(&csound->memlock);
38 #define CSOUND_MEM_SPINUNLOCK csoundSpinUnLock(&csound->memlock);
39 
40 typedef struct memAllocBlock_s {
41 #ifdef MEMDEBUG
42     int                     magic;      /* 0x6D426C6B ("mBlk")          */
43     void                    *ptr;       /* pointer to allocated area    */
44 #endif
45     struct memAllocBlock_s  *prv;       /* previous structure in chain  */
46     struct memAllocBlock_s  *nxt;       /* next structure in chain      */
47 } memAllocBlock_t;
48 
49 #define HDR_SIZE    (((int) sizeof(memAllocBlock_t) + 7) & (~7))
50 #define ALLOC_BYTES(n)  ((size_t) HDR_SIZE + (size_t) (n))
51 #define DATA_PTR(p) ((void*) ((unsigned char*) (p) + (int) HDR_SIZE))
52 #define HDR_PTR(p)  ((memAllocBlock_t*) ((unsigned char*) (p) - (int) HDR_SIZE))
53 
54 #define MEMALLOC_DB (csound->memalloc_db)
55 
memdie(CSOUND * csound,size_t nbytes)56 static void memdie(CSOUND *csound, size_t nbytes)
57 {
58     csound->ErrorMsg(csound, Str("memory allocate failure for %zd"),
59                              nbytes);
60     csound->LongJmp(csound, CSOUND_MEMORY);
61 }
62 
mmalloc(CSOUND * csound,size_t size)63 void *mmalloc(CSOUND *csound, size_t size)
64 {
65     void  *p;
66 
67 #ifdef MEMDEBUG
68     if (UNLIKELY(size == (size_t) 0)) {
69       csound->DebugMsg(csound,
70               " *** internal error: mmalloc() called with zero nbytes\n");
71       return NULL;
72     }
73 #endif
74     /* allocate memory */
75     if (UNLIKELY((p = malloc(ALLOC_BYTES(size))) == NULL)) {
76         memdie(csound, size);     /* does a long jump */
77     }
78     /* link into chain */
79 #ifdef MEMDEBUG
80     ((memAllocBlock_t*) p)->magic = MEMALLOC_MAGIC;
81     ((memAllocBlock_t*) p)->ptr = DATA_PTR(p);
82 #endif
83     CSOUND_MEM_SPINLOCK
84     ((memAllocBlock_t*) p)->prv = (memAllocBlock_t*) NULL;
85     ((memAllocBlock_t*) p)->nxt = (memAllocBlock_t*) MEMALLOC_DB;
86     if (MEMALLOC_DB != NULL)
87       ((memAllocBlock_t*) MEMALLOC_DB)->prv = (memAllocBlock_t*) p;
88     MEMALLOC_DB = (void*) p;
89     CSOUND_MEM_SPINUNLOCK
90     /* return with data pointer */
91     return DATA_PTR(p);
92 }
93 
mmallocDebug(CSOUND * csound,size_t size,char * file,int line)94 void *mmallocDebug(CSOUND *csound, size_t size, char *file, int line)
95 {
96     void *ans = mmalloc(csound,size);
97     printf("Alloc %p (%zu) %s:%d\n", ans, size, file, line);
98     return ans;
99 }
100 
mcalloc(CSOUND * csound,size_t size)101 void *mcalloc(CSOUND *csound, size_t size)
102 {
103     void  *p;
104 
105 #ifdef MEMDEBUG
106     if (UNLIKELY(size == (size_t) 0)) {
107       csound->DebugMsg(csound,
108               " *** internal error: csound->Calloc() called with zero nbytes\n");
109       return NULL;
110     }
111 #endif
112     /* allocate memory */
113     if (UNLIKELY((p = calloc(ALLOC_BYTES(size), (size_t) 1)) == NULL)) {
114       memdie(csound, size);     /* does longjump */
115     }
116     /* link into chain */
117 #ifdef MEMDEBUG
118     ((memAllocBlock_t*) p)->magic = MEMALLOC_MAGIC;
119     ((memAllocBlock_t*) p)->ptr = DATA_PTR(p);
120 #endif
121     CSOUND_MEM_SPINLOCK
122     ((memAllocBlock_t*) p)->prv = (memAllocBlock_t*) NULL;
123     ((memAllocBlock_t*) p)->nxt = (memAllocBlock_t*) MEMALLOC_DB;
124     if (MEMALLOC_DB != NULL)
125       ((memAllocBlock_t*) MEMALLOC_DB)->prv = (memAllocBlock_t*) p;
126     MEMALLOC_DB = (void*) p;
127     CSOUND_MEM_SPINUNLOCK
128     /* return with data pointer */
129     return DATA_PTR(p);
130 }
131 
mcallocDebug(CSOUND * csound,size_t size,char * file,int line)132 void *mcallocDebug(CSOUND *csound, size_t size, char *file, int line)
133 {
134     void *ans = mcalloc(csound,size);
135     printf("Alloc %p (%zu) %s:%d\n", ans, size, file, line);
136     return ans;
137 }
138 
139 
mfree(CSOUND * csound,void * p)140 void mfree(CSOUND *csound, void *p)
141 {
142     memAllocBlock_t *pp;
143 
144     if (UNLIKELY(p == NULL))
145       return;
146     pp = HDR_PTR(p);
147  #ifdef MEMDEBUG
148     if (UNLIKELY(pp->magic != MEMALLOC_MAGIC || pp->ptr != p)) {
149       csound->Warning(csound, "csound->Free() called with invalid "
150                       "pointer (%p) %x %p %x",
151                       p, pp->magic, pp->ptr, MEMALLOC_MAGIC);
152       /* exit() is ugly, but this is a fatal error that can only occur */
153       /* as a result of a bug */
154       /*  exit(-1);  */
155       /*VL 28-12-12 - returning from here instead of exit() */
156       return;
157     }
158     pp->magic = 0;
159  #endif
160     CSOUND_MEM_SPINLOCK
161     /* unlink from chain */
162     {
163       memAllocBlock_t *prv = pp->prv, *nxt = pp->nxt;
164       if (nxt != NULL)
165         nxt->prv = prv;
166       if (prv != NULL)
167         prv->nxt = nxt;
168       else
169         MEMALLOC_DB = (void*)nxt;
170     }
171     //csound->Message(csound, "free\n");
172     /* free memory */
173     free((void*) pp);
174     CSOUND_MEM_SPINUNLOCK
175 }
176 
mfreeDebug(CSOUND * csound,void * ans,char * file,int line)177 void mfreeDebug(CSOUND *csound, void *ans, char *file, int line)
178 {
179     printf("Free %p %s:%d\n", ans, file, line);
180     mfree(csound,ans);
181 }
182 
mrealloc(CSOUND * csound,void * oldp,size_t size)183 void *mrealloc(CSOUND *csound, void *oldp, size_t size)
184 {
185     memAllocBlock_t *pp;
186     void            *p;
187 
188     if (UNLIKELY(oldp == NULL))
189       return mmalloc(csound, size);
190     if (UNLIKELY(size == (size_t) 0)) {
191       mfree(csound, oldp);
192       return NULL;
193     }
194     pp = HDR_PTR(oldp);
195 #ifdef MEMDEBUG
196     if (UNLIKELY(pp->magic != MEMALLOC_MAGIC || pp->ptr != oldp)) {
197       csound->DebugMsg(csound, " *** internal error: mrealloc() called with invalid "
198                       "pointer (%p)\n", oldp);
199       /* exit() is ugly, but this is a fatal error that can only occur */
200       /* as a result of a bug */
201       exit(-1);
202     }
203     /* mark old header as invalid */
204     pp->magic = 0;
205     pp->ptr = NULL;
206 #endif
207     /* allocate memory */
208     p = realloc((void*) pp, ALLOC_BYTES(size));
209     if (UNLIKELY(p == NULL)) {
210 #ifdef MEMDEBUG
211       CSOUND_MEM_SPINLOCK
212       /* alloc failed, restore original header */
213       pp->magic = MEMALLOC_MAGIC;
214       pp->ptr = oldp;
215       CSOUND_MEM_SPINUNLOCK
216 #endif
217       memdie(csound, size);
218       return NULL;
219     }
220     CSOUND_MEM_SPINLOCK
221     /* create new header and update chain pointers */
222     pp = (memAllocBlock_t*) p;
223 #ifdef MEMDEBUG
224     pp->magic = MEMALLOC_MAGIC;
225     pp->ptr = DATA_PTR(pp);
226 #endif
227     {
228       memAllocBlock_t *prv = pp->prv, *nxt = pp->nxt;
229       if (nxt != NULL)
230         nxt->prv = pp;
231       if (prv != NULL)
232         prv->nxt = pp;
233       else
234         MEMALLOC_DB = (void*) pp;
235     }
236     CSOUND_MEM_SPINUNLOCK
237     /* return with data pointer */
238     return DATA_PTR(pp);
239 }
240 
mreallocDebug(CSOUND * csound,void * oldp,size_t size,char * file,int line)241 void *mreallocDebug(CSOUND *csound, void *oldp, size_t size, char *file, int line)
242 {
243     void *p = mrealloc(csound, oldp, size);
244     printf("Realloc %p->%p (%zu) %s:%d\n", oldp, p, size, file, line);
245     return p;
246 }
247 
memRESET(CSOUND * csound)248 void memRESET(CSOUND *csound)
249 {
250     memAllocBlock_t *pp, *nxtp;
251 
252     pp = (memAllocBlock_t*) MEMALLOC_DB;
253     MEMALLOC_DB = NULL;
254     while (pp != NULL) {
255       nxtp = pp->nxt;
256 #ifdef MEMDEBUG
257       pp->magic = 0;
258 #endif
259       free((void*) pp);
260       pp = nxtp;
261     }
262 }
263