1 /*
2 A* -------------------------------------------------------------------
3 B* This file contains source code for the PyMOL computer program
4 C* Copyright (c) Schrodinger, LLC.
5 D* -------------------------------------------------------------------
6 E* It is unlawful to modify or remove this copyright notice.
7 F* -------------------------------------------------------------------
8 G* Please see the accompanying LICENSE file for further information.
9 H* -------------------------------------------------------------------
10 I* Additional authors of this source file include:
11 -*
12 -*
13 -*
14 Z* -------------------------------------------------------------------
15 */
16 
17 #include"os_predef.h"
18 #include"ov_port.h"
19 
20 #include"MemoryDebug.h"
21 #include"MemoryCache.h"
22 
23 #define GDB_ENTRY
24 
MemoryReallocForSureSafe(void * ptr,size_t new_size,size_t old_size)25 void *MemoryReallocForSureSafe(void *ptr, size_t new_size, size_t old_size)
26 {
27   if(new_size < old_size) {
28     auto tmp = pymol::malloc<char>(new_size);
29     if(tmp && new_size && old_size) {
30       memcpy(tmp, ptr, new_size);
31     }
32     FreeP(ptr);
33     return tmp;
34   } else {
35     return pymol::realloc((char*) ptr, new_size);
36   }
37 }
38 
MemoryReallocForSure(void * ptr,size_t new_size)39 void *MemoryReallocForSure(void *ptr, size_t new_size)
40 {                               /* unsafe -- replace with above */
41   auto tmp = pymol::malloc<char>(new_size);
42   if(tmp)
43     memcpy(tmp, ptr, new_size);
44   FreeP(ptr);
45   return tmp;
46 }
47 
DieOutOfMemory(void)48 static void DieOutOfMemory(void)
49 {
50   printf
51     ("****************************************************************************\n");
52   printf
53     ("*** EEK!  PyMOL just ran out of memory and crashed.  To get around this, ***\n");
54   printf
55     ("*** you may need to reduce the quality, size, or complexity of the scene ***\n");
56   printf
57     ("*** that you are viewing or rendering.    Sorry for the inconvenience... ***\n");
58   printf
59     ("****************************************************************************\n");
60 
61 #if defined(_PYMOL_IOS) && !defined(_WEBGL)
62   fireMemoryWarning();
63   return;
64 #endif
65 
66 #ifdef GDB_ENTRY
67   abort();
68 #endif
69 
70   exit(EXIT_FAILURE);
71 }
72 
MemoryZero(char * p,char * q)73 void MemoryZero(char *p, char *q)
74 {
75   if(q - p)
76     memset(p, 0, q - p);
77 }
78 
79 /**
80  * Update `size` and reallocate this vla
81  *
82  * @param size number of elements
83  * @return reallocated pointer or NULL if realloc failed
84  */
VLARec_resize(VLARec * vla,ov_size size)85 static VLARec* VLARec_resize(VLARec* vla, ov_size size)
86 {
87   vla->size = size;
88   return (VLARec*) pymol::realloc(
89       (char*) (void*) vla, (vla->unit_size * size) + sizeof(VLARec));
90 }
91 
VLAExpand(void * ptr,ov_size rec)92 void *VLAExpand(void *ptr, ov_size rec)
93 {
94   VLARec *vla;
95   char *start, *stop;
96   size_t soffset = 0;
97   vla = &(((VLARec *) ptr)[-1]);
98   if(rec >= vla->size) {
99     if(vla->auto_zero)
100       soffset = sizeof(VLARec) + (vla->unit_size * vla->size);
101 
102     // back off on the request size until it actually fits
103     while (true) {
104       auto resized_vla = VLARec_resize(vla, rec * vla->grow_factor + 1);
105       if (resized_vla) {
106         vla = resized_vla;
107         break;
108       }
109 
110       vla->grow_factor = (vla->grow_factor - 1.0F) / 2.0F + 1.0F;
111 
112       if (vla->grow_factor < 1.001F) {
113         mfree(vla);
114         printf("VLAExpand-ERR: realloc failed.\n");
115         DieOutOfMemory();
116         return nullptr;
117       }
118     }
119     if(vla->auto_zero) {
120       start = ((char *) vla) + soffset;
121       stop = ((char *) vla) + sizeof(VLARec) + (vla->unit_size * vla->size);
122       MemoryZero(start, stop);
123     }
124   }
125   return ((void *) &(vla[1]));
126 }
127 
VLAMalloc(ov_size init_size,ov_size unit_size,unsigned int grow_factor,int auto_zero)128 void *VLAMalloc(ov_size init_size, ov_size unit_size, unsigned int grow_factor,
129                 int auto_zero)
130 {
131   VLARec *vla;
132   char *start, *stop;
133   vla = (VLARec*) pymol::malloc<char>((init_size * unit_size) + sizeof(VLARec));
134 
135   if(!vla) {
136     printf("VLAMalloc-ERR: malloc failed\n");
137     DieOutOfMemory();
138     return nullptr;
139   }
140   vla->size = init_size;
141   vla->unit_size = unit_size;
142   vla->grow_factor = (1.0F + grow_factor * 0.1F);
143   vla->auto_zero = auto_zero;
144   if(vla->auto_zero) {
145     start = ((char *) vla) + sizeof(VLARec);
146     stop = ((char *) vla) + sizeof(VLARec) + (vla->unit_size * vla->size);
147     MemoryZero(start, stop);
148   }
149   return ((void *) &(vla[1]));
150 }
151 
VLAFree(void * ptr)152 void VLAFree(void *ptr)
153 {
154   VLARec *vla;
155   if(!ptr) {
156     printf("VLAFree-ERR: tried to free NULL pointer!\n");
157     exit(EXIT_FAILURE);
158   }
159   vla = &(((VLARec *) ptr)[-1]);
160   mfree(vla);
161 }
162 
VLAGetSize(const void * ptr)163 size_t VLAGetSize(const void *ptr)
164 {
165   const VLARec *vla;
166   vla = &((VLARec *) ptr)[-1];
167   return (vla->size);
168 }
169 
VLANewCopy(const void * ptr)170 void *VLANewCopy(const void *ptr)
171 {
172   if(ptr) {                     /* NULL protected */
173     const VLARec *vla;
174     VLARec *new_vla;
175     vla = &((VLARec *) ptr)[-1];
176     auto size = (vla->unit_size * vla->size) + sizeof(VLARec);
177     new_vla = (VLARec*) pymol::malloc<char>(size);
178     if(!new_vla) {
179       printf("VLACopy-ERR: mmalloc failed\n");
180       exit(EXIT_FAILURE);
181     } else {
182       memcpy(new_vla, vla, size);
183     }
184     return ((void *) &(new_vla[1]));
185   } else {
186     return NULL;
187   }
188 }
189 
VLASetSize(void * ptr,size_t new_size)190 void *VLASetSize(void *ptr, size_t new_size)
191 {
192   VLARec *vla;
193   char *start = NULL;
194   char *stop;
195   size_t soffset = 0;
196   vla = &((VLARec *) ptr)[-1];
197   if(vla->auto_zero) {
198     soffset = sizeof(VLARec) + (vla->unit_size * vla->size);
199   }
200   vla = VLARec_resize(vla, new_size);
201   if(!vla) {
202     printf("VLASetSize-ERR: realloc failed.\n");
203     DieOutOfMemory();
204   }
205   if(vla->auto_zero) {
206     start = ((char *) vla) + soffset;
207     stop = ((char *) vla) + sizeof(VLARec) + (vla->unit_size * vla->size);
208     if(start < stop)
209       MemoryZero(start, stop);
210   }
211   return ((void *) &(vla[1]));
212 }
213 
VLADeleteRaw(void * ptr,int index,unsigned int count)214 void *VLADeleteRaw(void *ptr, int index, unsigned int count)
215 {
216   if(ptr) {
217     VLARec *vla = ((VLARec *) ptr) - 1;
218     ov_size old_size = vla->size;
219 
220     /* failsafe range-handling logic */
221 
222     if(index<0) {
223       if(index < -old_size)
224         index = 0;
225       else
226         index = old_size + 1 + index;
227       if(index<0) index = 0;
228     }
229 
230     if((count+index) > vla->size) {
231       count = vla->size - index;
232     }
233 
234     if((index >= 0) && (count > 0) &&
235        (index < vla->size) && ((count + index) <= vla->size)) {
236       ov_size new_size = old_size - count;
237       ov_char *base = (ov_char *) ptr;
238       ov_os_memmove(base + index * vla->unit_size,
239                     base + (count + index) * vla->unit_size,
240                     ((vla->size - index) - count) * vla->unit_size);
241       ptr = VLASetSize(ptr,new_size);
242     }
243   }
244   return ptr;
245 }
246 
VLAInsertRaw(void * ptr,int index,unsigned int count)247 void *VLAInsertRaw(void *ptr, int index, unsigned int count)
248 {
249   if(ptr) {
250     VLARec *vla = ((VLARec *) ptr) - 1;
251     ov_size old_size = vla->size;
252 
253     /* failsafe range-handling logic */
254 
255     if(index<0) {
256       if(index < -old_size)
257         index = 0;
258       else
259         index = old_size + 1 + index;
260       if(index<0) index = 0;
261     }
262 
263     if(index > old_size)
264       index = old_size;
265 
266     if((index >= 0) && (count > 0) && (index <= old_size)) {
267       ov_int new_size = old_size + count;
268 
269       ptr = VLASetSize(ptr,new_size);
270       if(ptr) {
271         ov_char *base = (ov_char *) ptr;
272         VLARec *vla = ((VLARec *) ptr) - 1;
273         ov_os_memmove(base + (index + count) * vla->unit_size,
274                 base + index * vla->unit_size, (old_size - index) * vla->unit_size);
275         if(vla->auto_zero)
276           ov_os_memset(base + index * vla->unit_size, 0, vla->unit_size * count);
277       }
278     }
279   }
280   return ptr;
281 }
282 
VLASetSizeForSure(void * ptr,size_t new_size)283 void *VLASetSizeForSure(void *ptr, size_t new_size)
284 {
285   VLARec *vla;
286   char *start = NULL;
287   char *stop;
288   size_t soffset = 0;
289   vla = &((VLARec *) ptr)[-1];
290   if(vla->auto_zero) {
291     soffset = sizeof(VLARec) + (vla->unit_size * vla->size);
292   }
293   if(new_size < vla->size) {
294     vla = (VLARec*) MemoryReallocForSureSafe(vla,
295                                    (vla->unit_size * new_size) + sizeof(VLARec),
296                                    (vla->unit_size * vla->size) + sizeof(VLARec));
297     vla->size = new_size;
298   } else {
299     vla = VLARec_resize(vla, new_size);
300   }
301   if(!vla) {
302     printf("VLASetSize-ERR: realloc failed.\n");
303     DieOutOfMemory();
304   }
305   if(vla->auto_zero) {
306     start = ((char *) vla) + soffset;
307     stop = ((char *) vla) + sizeof(VLARec) + (vla->unit_size * vla->size);
308     if(start < stop)
309       MemoryZero(start, stop);
310   }
311   return ((void *) &(vla[1]));
312 }
313