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