File: | jdk/src/java.desktop/share/native/common/awt/debug/debug_mem.c |
Warning: | line 127, column 13 Array access (from variable 'area') results in a null pointer dereference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. | |||
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |||
4 | * | |||
5 | * This code is free software; you can redistribute it and/or modify it | |||
6 | * under the terms of the GNU General Public License version 2 only, as | |||
7 | * published by the Free Software Foundation. Oracle designates this | |||
8 | * particular file as subject to the "Classpath" exception as provided | |||
9 | * by Oracle in the LICENSE file that accompanied this code. | |||
10 | * | |||
11 | * This code is distributed in the hope that it will be useful, but WITHOUT | |||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
14 | * version 2 for more details (a copy is included in the LICENSE file that | |||
15 | * accompanied this code). | |||
16 | * | |||
17 | * You should have received a copy of the GNU General Public License version | |||
18 | * 2 along with this work; if not, write to the Free Software Foundation, | |||
19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |||
20 | * | |||
21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |||
22 | * or visit www.oracle.com if you need additional information or have any | |||
23 | * questions. | |||
24 | */ | |||
25 | ||||
26 | #if defined(DEBUG1) | |||
27 | ||||
28 | #include "debug_util.h" | |||
29 | ||||
30 | #define DMEM_MIN(a,b)(a) < (b) ? (a) : (b) (a) < (b) ? (a) : (b) | |||
31 | #define DMEM_MAX(a,b)(a) > (b) ? (a) : (b) (a) > (b) ? (a) : (b) | |||
32 | ||||
33 | typedef char byte_t; | |||
34 | ||||
35 | static const byte_t ByteInited = '\xCD'; | |||
36 | static const byte_t ByteFreed = '\xDD'; | |||
37 | static const byte_t ByteGuard = '\xFD'; | |||
38 | ||||
39 | enum { | |||
40 | MAX_LINENUM = 50000, /* I certainly hope we don't have source files bigger than this */ | |||
41 | MAX_CHECK_BYTES = 27, /* max bytes to check at start of block */ | |||
42 | MAX_GUARD_BYTES = 8, /* size of guard areas on either side of a block */ | |||
43 | MAX_DECIMAL_DIGITS = 15 | |||
44 | }; | |||
45 | ||||
46 | /* Debug Info Header to precede allocated block */ | |||
47 | typedef struct MemoryBlockHeader { | |||
48 | char filename[FILENAME_MAX4096+1]; /* filename where alloc occurred */ | |||
49 | int linenumber; /* line where alloc occurred */ | |||
50 | size_t size; /* size of the allocation */ | |||
51 | int order; /* the order the block was allocated in */ | |||
52 | struct MemoryListLink * listEnter; /* pointer to the free list node */ | |||
53 | byte_t guard[MAX_GUARD_BYTES]; /* guard area for underrun check */ | |||
54 | } MemoryBlockHeader; | |||
55 | ||||
56 | /* Tail to follow allocated block */ | |||
57 | typedef struct MemoryBlockTail { | |||
58 | byte_t guard[MAX_GUARD_BYTES]; /* guard area overrun check */ | |||
59 | } MemoryBlockTail; | |||
60 | ||||
61 | /* Linked list of allocated memory blocks */ | |||
62 | typedef struct MemoryListLink { | |||
63 | struct MemoryListLink * next; | |||
64 | MemoryBlockHeader * header; | |||
65 | int freed; | |||
66 | } MemoryListLink; | |||
67 | ||||
68 | /************************************************** | |||
69 | * Global Data structures | |||
70 | */ | |||
71 | static DMemState DMemGlobalState; | |||
72 | extern const DMemState * DMemStatePtr = &DMemGlobalState; | |||
73 | static MemoryListLink MemoryList = {NULL((void*)0),NULL((void*)0),FALSE0}; | |||
74 | static dmutex_t DMemMutex = NULL((void*)0); | |||
75 | ||||
76 | /**************************************************/ | |||
77 | ||||
78 | /************************************************* | |||
79 | * Client callback invocation functions | |||
80 | */ | |||
81 | static void * DMem_ClientAllocate(size_t size) { | |||
82 | if (DMemGlobalState.pfnAlloc != NULL((void*)0)) { | |||
83 | return (*DMemGlobalState.pfnAlloc)(size); | |||
84 | } | |||
85 | return malloc(size); | |||
86 | } | |||
87 | ||||
88 | static void DMem_ClientFree(void * ptr) { | |||
89 | if (DMemGlobalState.pfnFree != NULL((void*)0)) { | |||
90 | (*DMemGlobalState.pfnFree)(ptr); | |||
91 | } | |||
92 | free(ptr); | |||
93 | } | |||
94 | ||||
95 | static dbool_t DMem_ClientCheckPtr(void * ptr, size_t size) { | |||
96 | if (DMemGlobalState.pfnCheckPtr != NULL((void*)0)) { | |||
97 | return (*DMemGlobalState.pfnCheckPtr)(ptr, size); | |||
98 | } | |||
99 | return ptr != NULL((void*)0); | |||
100 | } | |||
101 | ||||
102 | /**************************************************/ | |||
103 | ||||
104 | /************************************************* | |||
105 | * Debug Memory Manager implementation | |||
106 | */ | |||
107 | ||||
108 | static MemoryListLink * DMem_TrackBlock(MemoryBlockHeader * header) { | |||
109 | MemoryListLink * link; | |||
110 | ||||
111 | link = (MemoryListLink *)DMem_ClientAllocate(sizeof(MemoryListLink)); | |||
112 | if (link != NULL((void*)0)) { | |||
113 | link->header = header; | |||
114 | link->header->listEnter = link; | |||
115 | link->next = MemoryList.next; | |||
116 | link->freed = FALSE0; | |||
117 | MemoryList.next = link; | |||
118 | } | |||
119 | ||||
120 | return link; | |||
121 | } | |||
122 | ||||
123 | static int DMem_VerifyGuardArea(const byte_t * area) { | |||
124 | int nbyte; | |||
125 | ||||
126 | for ( nbyte = 0; nbyte < MAX_GUARD_BYTES; nbyte++ ) { | |||
127 | if (area[nbyte] != ByteGuard) { | |||
| ||||
128 | return FALSE0; | |||
129 | } | |||
130 | } | |||
131 | return TRUE1; | |||
132 | } | |||
133 | ||||
134 | static void DMem_VerifyHeader(MemoryBlockHeader * header) { | |||
135 | DASSERTMSG( DMem_ClientCheckPtr(header, sizeof(MemoryBlockHeader)), "Invalid header" )if ( !(DMem_ClientCheckPtr(header, sizeof(MemoryBlockHeader)) ) ) { DAssert_Impl( ("Invalid header"), "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/common/awt/debug/debug_mem.c" , 135); } else { }; | |||
136 | DASSERTMSG( DMem_VerifyGuardArea(header->guard), "Header corruption, possible underwrite" )if ( !(DMem_VerifyGuardArea(header->guard)) ) { DAssert_Impl ( ("Header corruption, possible underwrite"), "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/common/awt/debug/debug_mem.c" , 136); } else { }; | |||
137 | DASSERTMSG( header->linenumber > 0 && header->linenumber < MAX_LINENUM, "Header corruption, bad line number" )if ( !(header->linenumber > 0 && header->linenumber < MAX_LINENUM) ) { DAssert_Impl( ("Header corruption, bad line number" ), "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/common/awt/debug/debug_mem.c" , 137); } else { }; | |||
138 | DASSERTMSG( header->size <= DMemGlobalState.biggestBlock, "Header corruption, block size is too large")if ( !(header->size <= DMemGlobalState.biggestBlock) ) { DAssert_Impl( ("Header corruption, block size is too large") , "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/common/awt/debug/debug_mem.c" , 138); } else { }; | |||
139 | DASSERTMSG( header->order <= DMemGlobalState.totalAllocs, "Header corruption, block order out of range")if ( !(header->order <= DMemGlobalState.totalAllocs) ) { DAssert_Impl( ("Header corruption, block order out of range" ), "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/common/awt/debug/debug_mem.c" , 139); } else { }; | |||
140 | } | |||
141 | ||||
142 | static void DMem_VerifyTail(MemoryBlockTail * tail) { | |||
143 | DASSERTMSG( DMem_ClientCheckPtr(tail, sizeof(MemoryBlockTail)), "Tail corruption, invalid pointer")if ( !(DMem_ClientCheckPtr(tail, sizeof(MemoryBlockTail))) ) { DAssert_Impl( ("Tail corruption, invalid pointer"), "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/common/awt/debug/debug_mem.c" , 143); } else { }; | |||
144 | DASSERTMSG( DMem_VerifyGuardArea(tail->guard), "Tail corruption, possible overwrite" )if ( !(DMem_VerifyGuardArea(tail->guard)) ) { DAssert_Impl ( ("Tail corruption, possible overwrite"), "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/common/awt/debug/debug_mem.c" , 144); } else { }; | |||
145 | } | |||
146 | ||||
147 | static MemoryBlockHeader * DMem_VerifyBlock(void * memptr) { | |||
148 | MemoryBlockHeader * header; | |||
149 | MemoryBlockTail * tail; | |||
150 | ||||
151 | /* check if the pointer is valid */ | |||
152 | DASSERTMSG( DMem_ClientCheckPtr(memptr, 1), "Invalid pointer")if ( !(DMem_ClientCheckPtr(memptr, 1)) ) { DAssert_Impl( ("Invalid pointer" ), "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/common/awt/debug/debug_mem.c" , 152); } else { }; | |||
153 | ||||
154 | /* check if the block header is valid */ | |||
155 | header = (MemoryBlockHeader *)((byte_t *)memptr - sizeof(MemoryBlockHeader)); | |||
156 | DMem_VerifyHeader(header); | |||
157 | /* check that the memory itself is valid */ | |||
158 | DASSERTMSG( DMem_ClientCheckPtr(memptr, DMEM_MIN(MAX_CHECK_BYTES,header->size)), "Block memory invalid" )if ( !(DMem_ClientCheckPtr(memptr, (MAX_CHECK_BYTES) < (header ->size) ? (MAX_CHECK_BYTES) : (header->size))) ) { DAssert_Impl ( ("Block memory invalid"), "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/common/awt/debug/debug_mem.c" , 158); } else { }; | |||
159 | /* check that the pointer to the alloc list is valid */ | |||
160 | DASSERTMSG( DMem_ClientCheckPtr(header->listEnter, sizeof(MemoryListLink)), "Header corruption, alloc list pointer invalid" )if ( !(DMem_ClientCheckPtr(header->listEnter, sizeof(MemoryListLink ))) ) { DAssert_Impl( ("Header corruption, alloc list pointer invalid" ), "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/common/awt/debug/debug_mem.c" , 160); } else { }; | |||
161 | /* check the tail of the block for overruns */ | |||
162 | tail = (MemoryBlockTail *) ( (byte_t *)memptr + header->size ); | |||
163 | DMem_VerifyTail(tail); | |||
164 | ||||
165 | return header; | |||
166 | } | |||
167 | ||||
168 | static MemoryBlockHeader * DMem_GetHeader(void * memptr) { | |||
169 | MemoryBlockHeader * header = DMem_VerifyBlock(memptr); | |||
170 | return header; | |||
171 | } | |||
172 | ||||
173 | /* | |||
174 | * Should be called before any other DMem_XXX function | |||
175 | */ | |||
176 | void DMem_Initialize() { | |||
177 | DMemMutex = DMutex_Create(); | |||
178 | DMutex_Enter(DMemMutex); | |||
179 | DMemGlobalState.pfnAlloc = NULL((void*)0); | |||
180 | DMemGlobalState.pfnFree = NULL((void*)0); | |||
181 | DMemGlobalState.pfnCheckPtr = NULL((void*)0); | |||
182 | DMemGlobalState.biggestBlock = 0; | |||
183 | DMemGlobalState.maxHeap = INT_MAX2147483647; | |||
184 | DMemGlobalState.totalHeapUsed = 0; | |||
185 | DMemGlobalState.failNextAlloc = FALSE0; | |||
186 | DMemGlobalState.totalAllocs = 0; | |||
187 | DMutex_Exit(DMemMutex); | |||
188 | } | |||
189 | ||||
190 | void DMem_Shutdown() { | |||
191 | DMutex_Destroy(DMemMutex); | |||
192 | } | |||
193 | /* | |||
194 | * Allocates a block of memory, reserving extra space at the start and end of the | |||
195 | * block to store debug info on where the block was allocated, it's size, and | |||
196 | * 'guard' areas to catch overwrite/underwrite bugs | |||
197 | */ | |||
198 | void * DMem_AllocateBlock(size_t size, const char * filename, int linenumber) { | |||
199 | MemoryBlockHeader * header; | |||
200 | MemoryBlockTail * tail; | |||
201 | size_t debugBlockSize; | |||
202 | byte_t * memptr = NULL((void*)0); | |||
203 | ||||
204 | DMutex_Enter(DMemMutex); | |||
205 | if (DMemGlobalState.failNextAlloc) { | |||
206 | /* force an allocation failure if so ordered */ | |||
207 | DMemGlobalState.failNextAlloc = FALSE0; /* reset flag */ | |||
208 | goto Exit; | |||
209 | } | |||
210 | ||||
211 | /* allocate a block large enough to hold extra debug info */ | |||
212 | debugBlockSize = sizeof(MemoryBlockHeader) + size + sizeof(MemoryBlockTail); | |||
213 | header = (MemoryBlockHeader *)DMem_ClientAllocate(debugBlockSize); | |||
214 | if (header == NULL((void*)0)) { | |||
215 | goto Exit; | |||
216 | } | |||
217 | ||||
218 | /* add block to list of allocated memory */ | |||
219 | header->listEnter = DMem_TrackBlock(header); | |||
220 | if ( header->listEnter == NULL((void*)0) ) { | |||
221 | DMem_ClientFree(header); | |||
222 | goto Exit; | |||
223 | } | |||
224 | ||||
225 | /* store size of requested block */ | |||
226 | header->size = size; | |||
227 | /* update maximum block size */ | |||
228 | DMemGlobalState.biggestBlock = DMEM_MAX(header->size, DMemGlobalState.biggestBlock)(header->size) > (DMemGlobalState.biggestBlock) ? (header ->size) : (DMemGlobalState.biggestBlock); | |||
229 | /* update used memory total */ | |||
230 | DMemGlobalState.totalHeapUsed += header->size; | |||
231 | /* store filename and linenumber where allocation routine was called */ | |||
232 | strncpy(header->filename, filename, FILENAME_MAX4096); | |||
233 | header->linenumber = linenumber; | |||
234 | /* store the order the block was allocated in */ | |||
235 | header->order = DMemGlobalState.totalAllocs++; | |||
236 | /* initialize memory to a recognizable 'inited' value */ | |||
237 | memptr = (byte_t *)header + sizeof(MemoryBlockHeader); | |||
238 | memset(memptr, ByteInited, size); | |||
239 | /* put guard area before block */ | |||
240 | memset(header->guard, ByteGuard, MAX_GUARD_BYTES); | |||
241 | /* put guard area after block */ | |||
242 | tail = (MemoryBlockTail *)(memptr + size); | |||
243 | memset(tail->guard, ByteGuard, MAX_GUARD_BYTES); | |||
244 | ||||
245 | Exit: | |||
246 | DMutex_Exit(DMemMutex); | |||
247 | return memptr; | |||
248 | } | |||
249 | ||||
250 | /* | |||
251 | * Frees block of memory allocated with DMem_AllocateBlock | |||
252 | */ | |||
253 | void DMem_FreeBlock(void * memptr) { | |||
254 | MemoryBlockHeader * header; | |||
255 | ||||
256 | DMutex_Enter(DMemMutex); | |||
257 | if ( memptr == NULL((void*)0)) { | |||
258 | goto Exit; | |||
259 | } | |||
260 | ||||
261 | /* get the debug block header preceding the allocated memory */ | |||
262 | header = DMem_GetHeader(memptr); | |||
263 | /* fill memory with recognizable 'freed' value */ | |||
264 | memset(memptr, ByteFreed, header->size); | |||
265 | /* mark block as freed */ | |||
266 | header->listEnter->freed = TRUE1; | |||
267 | /* update used memory total */ | |||
268 | DMemGlobalState.totalHeapUsed -= header->size; | |||
269 | Exit: | |||
270 | DMutex_Exit(DMemMutex); | |||
271 | } | |||
272 | ||||
273 | static void DMem_DumpHeader(MemoryBlockHeader * header) { | |||
274 | char report[FILENAME_MAX4096+MAX_DECIMAL_DIGITS*3+1]; | |||
275 | static const char * reportFormat = | |||
276 | "file: %s, line %d\n" | |||
277 | "size: %d bytes\n" | |||
278 | "order: %d\n" | |||
279 | "-------"; | |||
280 | ||||
281 | DMem_VerifyHeader(header); | |||
282 | sprintf(report, reportFormat, header->filename, header->linenumber, header->size, header->order)__builtin___sprintf_chk (report, 2 - 1, __builtin_object_size (report, 2 > 1), reportFormat, header->filename, header ->linenumber, header->size, header->order); | |||
283 | DTRACE_PRINTLN(report){ static dtrace_id _dt_lineid_ = UNDEFINED_TRACE_ID; DTrace_PrintFunction ((DTrace_VPrintln), &_Dt_FileTraceId, &_dt_lineid_, "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/common/awt/debug/debug_mem.c" , 283, (0), ((report)), (0), (0), (0), (0), (0), (0), (0), (0 ) ); }; | |||
284 | } | |||
285 | ||||
286 | /* | |||
287 | * Call this function at shutdown time to report any leaked blocks | |||
288 | */ | |||
289 | void DMem_ReportLeaks() { | |||
290 | MemoryListLink * link; | |||
291 | ||||
292 | DMutex_Enter(DMemMutex); | |||
293 | ||||
294 | /* Force memory leaks to be output regardless of trace settings */ | |||
295 | DTrace_EnableFile(__FILE__"/home/daniel/Projects/java/jdk/src/java.desktop/share/native/common/awt/debug/debug_mem.c", TRUE1); | |||
296 | DTRACE_PRINTLN("--------------------------"){ static dtrace_id _dt_lineid_ = UNDEFINED_TRACE_ID; DTrace_PrintFunction ((DTrace_VPrintln), &_Dt_FileTraceId, &_dt_lineid_, "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/common/awt/debug/debug_mem.c" , 296, (0), (("--------------------------")), (0), (0), (0), ( 0), (0), (0), (0), (0) ); }; | |||
297 | DTRACE_PRINTLN("Debug Memory Manager Leaks"){ static dtrace_id _dt_lineid_ = UNDEFINED_TRACE_ID; DTrace_PrintFunction ((DTrace_VPrintln), &_Dt_FileTraceId, &_dt_lineid_, "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/common/awt/debug/debug_mem.c" , 297, (0), (("Debug Memory Manager Leaks")), (0), (0), (0), ( 0), (0), (0), (0), (0) ); }; | |||
298 | DTRACE_PRINTLN("--------------------------"){ static dtrace_id _dt_lineid_ = UNDEFINED_TRACE_ID; DTrace_PrintFunction ((DTrace_VPrintln), &_Dt_FileTraceId, &_dt_lineid_, "/home/daniel/Projects/java/jdk/src/java.desktop/share/native/common/awt/debug/debug_mem.c" , 298, (0), (("--------------------------")), (0), (0), (0), ( 0), (0), (0), (0), (0) ); }; | |||
299 | ||||
300 | /* walk through allocated list and dump any blocks not marked as freed */ | |||
301 | link = MemoryList.next; | |||
302 | while (link != NULL((void*)0)) { | |||
| ||||
303 | if ( !link->freed ) { | |||
304 | DMem_DumpHeader(link->header); | |||
305 | } | |||
306 | link = link->next; | |||
307 | } | |||
308 | ||||
309 | DMutex_Exit(DMemMutex); | |||
310 | } | |||
311 | ||||
312 | void DMem_SetAllocCallback( DMEM_ALLOCFN pfn ) { | |||
313 | DMutex_Enter(DMemMutex); | |||
314 | DMemGlobalState.pfnAlloc = pfn; | |||
315 | DMutex_Exit(DMemMutex); | |||
316 | } | |||
317 | ||||
318 | void DMem_SetFreeCallback( DMEM_FREEFN pfn ) { | |||
319 | DMutex_Enter(DMemMutex); | |||
320 | DMemGlobalState.pfnFree = pfn; | |||
321 | DMutex_Exit(DMemMutex); | |||
322 | } | |||
323 | ||||
324 | void DMem_SetCheckPtrCallback( DMEM_CHECKPTRFN pfn ) { | |||
325 | DMutex_Enter(DMemMutex); | |||
326 | DMemGlobalState.pfnCheckPtr = pfn; | |||
327 | DMutex_Exit(DMemMutex); | |||
328 | } | |||
329 | ||||
330 | void DMem_DisableMutex() { | |||
331 | DMemMutex = NULL((void*)0); | |||
332 | } | |||
333 | ||||
334 | #endif /* defined(DEBUG) */ | |||
335 | ||||
336 | /* The following line is only here to prevent compiler warnings | |||
337 | * on release (non-debug) builds | |||
338 | */ | |||
339 | static int dummyVariable = 0; |