Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/exelib/common/memcheck.c
6000 views
1
/*******************************************************************************
2
* Copyright (c) 1991, 2021 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21
*******************************************************************************/
22
23
#include "j9cfg.h"
24
#include "exelib_internal.h"
25
#include "memchknls.h"
26
#include "memcheck.h"
27
#ifdef J9ZOS390
28
#include "atoe.h"
29
#endif
30
31
/* uncomment this line if you want support the 'simulate' option */
32
/*#define J9VM_MEMCHK_SIM_SUP
33
*/
34
35
#ifdef J9VM_MEMCHK_SIM_SUP
36
#define SIM_TAG "/*MEMSIM*/"
37
#endif
38
39
#include <stdlib.h>
40
#include <stdio.h>
41
#include <string.h>
42
#include "j9port.h"
43
#include "j9protos.h"
44
#include "avl_api.h"
45
#include "libhlp.h" /* uses main_setNLSCatalog */
46
#include "omrmutex.h"
47
#include "ute_core.h"
48
49
#if defined (WIN32) && !defined(BREW)
50
/* windows.h defined UDATA. Ignore its definition */
51
#define UDATA UDATA_win32_
52
#include <windows.h>
53
#undef UDATA /* this is safe because our UDATA is a typedef, not a macro */
54
#endif
55
56
/* Padding size for the beginning and end of each block, in bytes. This should be a multiple
57
of 8 (for alignment purposes). If the padding size is smaller than sizeof(J9MemoryCheckHeader)
58
it will be increased to that size automatically. */
59
#define J9_MEMCHECK_PADDING_SIZE 512
60
#define J9_MEMCHECK_DATA_PADDING_VALUE ((U_32) 0xDEADBEEF )
61
#define J9_MEMCHECK_DATA_FILL_VALUE ((U_32) 0xE7E7E7E7 )
62
#define J9_MEMCHECK_DATA_FREED_VALUE ((U_32) 0xBEF0DDED )
63
#define J9_MEMCHECK_CODE_PADDING_VALUE ((U_32) 0xBAADF00D )
64
#define J9_MEMCHECK_CODE_FILL_VALUE ((U_32) 0xF7F7F7F7 )
65
#define J9_MEMCHECK_CODE_FREED_VALUE ((U_32) 0xCCCCCCCC )
66
/* Must be defined, this limits the number of leaked memory blocks that will be dumped on shutdown.
67
otherwise, it might print out thousands of blocks... ;) */
68
#define J9_MEMCHECK_MAX_DUMP_LEAKED_BLOCKS 32
69
typedef void *(* J9_MEM_ALLOCATE_FUNC)(OMRPortLibrary *, UDATA byteAmount, const char *callsite, U_32 category);
70
typedef void (* J9_MEM_FREE_FUNC)(OMRPortLibrary *, void *memoryPointer);
71
typedef void (* J9_MEM_FREE_CODE_FUNC)(OMRPortLibrary *, void *memoryPointer, UDATA size);
72
typedef I_32 (* J9_SHUTDOWN_FUNC)(OMRPortLibrary *);
73
typedef void (* J9_SHUTDOWN_AND_EXIT_FUNC)(OMRPortLibrary *, I_32 exitCode);
74
typedef I_32 (* J9_PORT_CONTROL_FUNC)(OMRPortLibrary *portLib, const char* key, UDATA value);
75
typedef void (* J9_MEM_SHUTDOWN_FUNC)(OMRPortLibrary *);
76
77
#define J9_MEMCHECK_FREED_SIZE (~(UDATA)0)
78
79
/* Mode flags. */
80
#define J9_MCMODE_PAD_BLOCKS 0x00000001
81
#define J9_MCMODE_FULL_SCANS 0x00000002
82
#define J9_MCMODE_NEVER_FREE 0x00000004
83
#define J9_MCMODE_FAIL_AT 0x00000008
84
#define J9_MCMODE_SKIP_TO 0x00000010
85
#define J9_MCMODE_TOP_DOWN 0x00000020
86
#define J9_MCMODE_SIMULATE 0x00000040
87
#define J9_MCMODE_PRINT_CALLSITES 0x00000080
88
#define J9_MCMODE_PRINT_CALLSITES_SMALL 0x00000100
89
#define J9_MCMODE_ZERO 0x00000200
90
#define J9_MCMODE_LIMIT 0x00000400
91
#define J9_MCMODE_IGNORE_UNKNOWN_BLOCKS 0x00000800
92
#define J9_MCMODE_SUB_ALLOCATOR 0x00001000
93
#define J9_MCMODE_MPROTECT 0x00002000
94
#define J9_MCMODE_NO_SCAN 0x00004000
95
96
#define J9_MEMCHECK_SHUTDOWN_NORMAL 0
97
#define J9_MEMCHECK_SHUTDOWN_EXIT 1
98
99
static UDATA j9thrDescriptor = 0;
100
static IDATA (*f_omrthread_attach_ex)(omrthread_t* handle, omrthread_attr_t *attr);
101
static void (*f_omrthread_detach)(omrthread_t thread);
102
103
static MUTEX mcMutex;
104
105
static UtInterface *uteInterface = NULL;
106
107
/* Internal memorycheck portLibrary */
108
OMRPortLibrary memCheckPortLibStruct; /* Stack allocated Struct */
109
OMRPortLibrary *memCheckPortLib; /* Pointer to it */
110
111
/* Memory Protect related variables for working with vmem */
112
static J9HashTable *vmemIDTable = NULL; /* For MEMORY_PROTECT */
113
static const UDATA lockMode = 0;
114
static const UDATA unlockMode = J9PORT_VMEM_MEMORY_MODE_READ | J9PORT_VMEM_MEMORY_MODE_WRITE /*| J9PORT_VMEM_MEMORY_MODE_EXECUTE*/;
115
static const UDATA allocateMode = J9PORT_VMEM_MEMORY_MODE_READ | J9PORT_VMEM_MEMORY_MODE_WRITE | J9PORT_VMEM_MEMORY_MODE_COMMIT;
116
static UDATA J9_ALIGN_BOTTOM = 1;
117
118
/* Standard memCheck variables */
119
static J9MemoryCheckHeader *mostRecentBlock = NULL;
120
static J9MemoryCheckHeader *mostRecentFreedBlock = NULL;
121
static J9AVLTree *avl_tree;
122
static UDATA mode = 0;
123
static UDATA failAtAlloc = 0;
124
static UDATA skipToAlloc = 0;
125
static UDATA callSitePrintCount = 0;
126
static UDATA limitAlloc = 0;
127
128
static J9_MEM_ALLOCATE_FUNC globalAllocator = NULL;
129
static J9_MEM_FREE_FUNC globalDeallocator = NULL;
130
static J9_MEM_FREE_FUNC globalAdviseDeallocator = NULL;
131
static J9_MEM_ALLOCATE_FUNC globalAllocator32 = NULL;
132
static J9_MEM_FREE_FUNC globalDeallocator32 = NULL;
133
134
static J9_MEM_ALLOCATE_FUNC old_mem_allocate_memory = NULL;
135
static J9_MEM_FREE_FUNC old_mem_free_memory = NULL;
136
static J9_MEM_FREE_FUNC old_mem_advise_and_free_memory = NULL;
137
static J9_MEM_ALLOCATE_FUNC old_mem_allocate_memory32 = NULL;
138
static J9_MEM_FREE_FUNC old_mem_free_memory32 = NULL;
139
static J9_SHUTDOWN_FUNC old_port_shutdown_library = NULL;
140
static J9_SHUTDOWN_AND_EXIT_FUNC old_shutdown_and_exit = NULL;
141
static J9_PORT_CONTROL_FUNC old_port_control = NULL;
142
static J9_MEM_SHUTDOWN_FUNC old_mem_shutdown = NULL;
143
144
static J9MemoryCheckStats memStats;
145
static char hexd[] = "0123456789ABCDEF";
146
147
static UDATA memoryCheck_get_page_size(OMRPortLibrary *portLib);
148
static IDATA memoryCheck_lockGuardPages(OMRPortLibrary *portLib, void *memcheckHeader, UDATA size, UDATA mode );
149
static IDATA memoryCheck_lockWrappedBlock(OMRPortLibrary *portLib, J9MemoryCheckHeader *blockHeader, const UDATA mode);
150
#define J9_MEMCHECK_PAGE_SIZE memoryCheck_get_page_size(memCheckPortLib)
151
152
/* MEMORY_PROTECT related macros */
153
#define J9_MEMCHECK_LOCK( ptr )\
154
((J9MemoryCheckHeader *) ptr)->isLocked = 1; /* Set to Locked */\
155
((memoryCheck_lockGuardPages( memCheckPortLib, (ptr), J9_MEMCHECK_PAGE_SIZE, lockMode ) == 0) ? \
156
(void)0 : memCheckPortLib->tty_printf( memCheckPortLib, "LOCK FAIL: (%s)(%d)\n", __FILE__, __LINE__ ) )
157
158
#define J9_MEMCHECK_UNLOCK( ptr )\
159
((memoryCheck_lockGuardPages( memCheckPortLib, (ptr), J9_MEMCHECK_PAGE_SIZE, unlockMode ) == 0) ? \
160
(void)0 : memCheckPortLib->tty_printf( memCheckPortLib, "UNLOCK FAIL: (%s)(%d)\n", __FILE__, __LINE__ ) );\
161
((J9MemoryCheckHeader *)(ptr))->isLocked = 0 /* Set to unlocked */
162
163
#define J9_MEMCHECK_LOCK_BODY( blockHeader )\
164
memoryCheck_lockWrappedBlock( memCheckPortLib, (blockHeader), lockMode )
165
166
#define J9_MEMCHECK_UNLOCK_BODY( blockHeader )\
167
memoryCheck_lockWrappedBlock( memCheckPortLib, (blockHeader), unlockMode )
168
169
/*
170
* Following is for the suballocator
171
*
172
* It is based loosely on a Donald Knuth algorithm from his Art of Computer Programming books
173
* Some of the memory is allocated from a small array of small structures (2400 bytes in this
174
* version, to keep the "small" * memory from fragmented the heap.
175
* The size and quantity of this may need to be adjusted depending on the application.
176
* All references to smallblock could be removed, however, and just the heap manager used to
177
* provide memory.
178
*
179
* If the MEMDEBUG macro is defined, additional printf's (and pool audits, etc.) are
180
* activated, helping to resolve issues. This will make the allocate run much slower, however.
181
*/
182
183
/* subAllocator heap size in bytes (Note: heap is initialized in 4 byte blocks) */
184
static UDATA heapSizeMegaBytes = 0;
185
#define DEFAULT_HEAP_SIZE_BYTES J9_MEMORY_MAX
186
static IDATA* j9heap;
187
188
/*
189
* The following variable is used for aligning mallocs happening in conjunction
190
* with the subAllocator option. This keeps mallocs on double
191
* boundaries and forces bottom padding to end on a double word boundary - so
192
* that the next top padding will start on a double word boundary when using
193
* the subAllocator. Reference CMVC 119506, related to xscale.
194
*
195
* "sizeof double" was chosen because some quick internet research indicated that
196
* double is the standard basis used for allocating memory.
197
*/
198
#define BYTES_FOR_ALIGNMENT(numberOfBytes) (U_32)((sizeof(double) - (((UDATA) numberOfBytes) & (sizeof(double) - 1))) & (sizeof(double) - 1))
199
200
#define STARTIDX 3
201
202
#define start j9heap[STARTIDX-2]
203
#define heapsize (j9heap[STARTIDX-3])
204
205
/*
206
* smallest block (in words) allocated,
207
* plus level at which block is extended to
208
* absorb next block to prevent fragmentation
209
*/
210
#define FRAGTHRESHOLD 6
211
212
#define MAX_SMALL_BLOCK 50
213
struct smblk {
214
UDATA data [ FRAGTHRESHOLD ];
215
} smblk;
216
static struct smblk smallBlock [MAX_SMALL_BLOCK];
217
static unsigned char smblkstatus[MAX_SMALL_BLOCK];
218
static UDATA smblkindex;
219
static UDATA meminuse;
220
221
/* setting ignoredCallsites to be 128 bytes, hoping we won't try to ignore too many callsites */
222
#define IGNORECALLSITESTRLENGTH 128
223
#define MAX_CALLSITE_COUNT 10
224
#define MAX_CALLSITE_LENGTH 32
225
226
static char ignoreCallSiteStr[IGNORECALLSITESTRLENGTH];
227
#define CALLSITE_DELIMITER ":"
228
229
#ifdef MEMDEBUG
230
static UDATA freemem;
231
static UDATA usedmem;
232
static UDATA total;
233
static void *pTop;
234
static void *pBot;
235
static UDATA freeCnt;
236
static UDATA usedCnt;
237
static UDATA bucket[6];
238
/* audit masks: */
239
#define AUDIT 0x0001
240
#define FREE 0x0002
241
#define BUCKET 0x0004
242
#define USED 0x0008
243
#endif
244
245
246
static void memoryCheck_exit_shutdown_and_exit(OMRPortLibrary *portLib, I_32 exitCode );
247
static void memoryCheck_update_callSites_allocate(OMRPortLibrary *portLib, J9MemoryCheckHeader *header, const char *callSite, UDATA byteAmount);
248
static void *memoryCheck_wrapper_allocate_memory(OMRPortLibrary *portLib, UDATA byteAmount, char const *operationName, J9_MEM_ALLOCATE_FUNC allocator, U_32 paddingValue, U_32 fillValue, U_32 freedValue, const char *callSite, U_32 category);
249
static void memoryCheck_dump_callSite_small(OMRPortLibrary *portLibrary, J9AVLTreeNode *node);
250
static void memoryCheck_dump_bytes(OMRPortLibrary *portLib, void *dumpAddress, UDATA dumpSize);
251
static void memoryCheck_free_memory(OMRPortLibrary *portLib, void *memoryPointer);
252
static void memoryCheck_advise_and_free_memory(OMRPortLibrary *portLib, void *memoryPointer);
253
static void memoryCheck_free_memory32(OMRPortLibrary *portLib, void *memoryPointer);
254
static void memoryCheck_fill_bytes(OMRPortLibrary *portLib, U_8 *fillAddress, UDATA fillSize, U_32 fillValue, U_8 *blockAddress);
255
static void memoryCheck_update_callSites_free (J9MEMAVLTreeNode *node, UDATA byteAmount);
256
static void memoryCheck_null_mem_free_memory(OMRPortLibrary *portLib, void *memoryPointer);
257
static BOOLEAN memoryCheck_describe_freed_block(OMRPortLibrary *portLib, char const *operationName, J9MemoryCheckHeader *blockHeader);
258
static void OMRNORETURN memoryCheck_abort(OMRPortLibrary *portLib);
259
static UDATA memoryCheck_filter_nonVM_unFreed_Blcoks(OMRPortLibrary *portLib);
260
static void memoryCheck_print_summary(OMRPortLibrary *portLib, I_32 shutdownMode);
261
static void memoryCheck_shutdown_internal(OMRPortLibrary *portLib, I_32 shutdownMode);
262
static void memoryCheck_print_stats(OMRPortLibrary *portLib);
263
static void memoryCheck_dump_callSites_small(OMRPortLibrary *portLibrary, J9AVLTree *tree);
264
static I_32 memoryCheck_control(OMRPortLibrary *portLib, const char* key, UDATA value);
265
static BOOLEAN memoryCheck_scan_block(OMRPortLibrary *portLib, J9MemoryCheckHeader *blockHeader);
266
static void *memoryCheck_wrapper_reallocate_memory(OMRPortLibrary *portLib, void *memoryPointer, UDATA byteAmount, char const *operationName, J9_MEM_ALLOCATE_FUNC allocator, J9_MEM_FREE_FUNC deallocator, U_32 paddingValue, U_32 fillValue, U_32 freedValue, const char *callSite, U_32 category);
267
static UDATA memoryCheck_verify_backward(OMRPortLibrary *portLib, U_8 *fillAddress, UDATA fillSize, U_32 fillValue, U_8 *blockAddress);
268
static void memoryCheck_print_stats_callSite(OMRPortLibrary *portLib, J9MEMAVLTreeNode *node);
269
static void * memoryCheck_reallocate_memory (struct OMRPortLibrary *portLibrary, void *memoryPointer, UDATA byteAmount, const char *callsite, U_32 category);
270
static void memoryCheck_free_AVLTreeNode(OMRPortLibrary *portLib, J9AVLTreeNode *node);
271
static I_32 memoryCheck_port_shutdown_library(OMRPortLibrary *portLib);
272
static void *memoryCheck_allocate_memory(OMRPortLibrary *portLib, UDATA byteAmount, const char *callSite, U_32 category);
273
static void *memoryCheck_allocate_memory32(OMRPortLibrary *portLib, UDATA byteAmount, const char *callSite, U_32 category);
274
static void memoryCheck_dump_callSites(OMRPortLibrary *portLibrary, J9AVLTree *tree);
275
static void memoryCheck_dump_callSite(OMRPortLibrary *portLibrary, J9AVLTreeNode *node);
276
static IDATA memoryCheck_insertion_Compare(J9AVLTree *tree, J9AVLTreeNode *insertNode, J9AVLTreeNode *walk);
277
static UDATA memoryCheck_verify_forward(OMRPortLibrary *portLib, U_8 *fillAddress, UDATA fillSize, U_32 fillValue, U_8 *blockAddress);
278
static BOOLEAN memoryCheck_parseOption(OMRPortLibrary *portLib, char const *option, size_t optionLen);
279
static IDATA memoryCheck_search_Compare(J9AVLTree *tree, UDATA search, J9AVLTreeNode *walk);
280
static void memoryCheck_initialize_AVLTree_stats (J9MEMAVLTreeNode *node, UDATA byteAmount);
281
static void memoryCheck_print_stats_callSite_small(OMRPortLibrary *portLib, J9MEMAVLTreeNode *node);
282
static void memoryCheck_wrapper_free_memory(OMRPortLibrary *portLib, void *memoryPointer, char const *operationName, J9_MEM_FREE_FUNC deallocator, U_32 paddingValue, U_32 fillValue, U_32 freedValue);
283
static void memoryCheck_set_AVLTree_prevStats (J9MEMAVLTreeNode *node);
284
static BOOLEAN memoryCheck_describe_block(OMRPortLibrary *portLib, char const *operationName, J9MemoryCheckHeader *blockHeader);
285
static BOOLEAN memoryCheck_scan_all_blocks(OMRPortLibrary *portLib);
286
static void memoryCheck_free_AVLTree(OMRPortLibrary *portLib, J9AVLTree *tree);
287
static void subAllocator_init_heap(void* memptr, UDATA size);
288
static void* subAllocator_allocate_memory(OMRPortLibrary *portLib, UDATA size, const char *callSite, U_32 category);
289
static void subAllocator_free_memory(OMRPortLibrary *portLib, void *ptr);
290
static UDATA memoryCheck_hashFn (void *vmemId, void *userData);
291
static UDATA memoryCheck_hashEqualFn (void *leftEntry, void *rightEntry, void *userData);
292
static UDATA memoryCheck_hashDoFn (void *entry, void *portLib);
293
294
/* we shouldn't need this with a dedicated portlib for memCheck */
295
#if 0
296
static void memoryCheck_mem_shutdown(OMRPortLibrary *portLib);
297
#endif
298
299
static void memoryCheck_lockAllBlocks(OMRPortLibrary *portLib, J9MemoryCheckHeader *listHead, const UDATA lockFlags, const UDATA lockBody);
300
static void memoryCheck_restore_old_shutdown_functions(OMRPortLibrary *portLib);
301
302
303
304
#define J9_MEMCHECK_MINIMUM_HEADER_SIZE (sizeof(J9MemoryCheckHeader) + 4*sizeof(U_32))
305
#define J9_MEMCHECK_ADJUSTED_PADDING \
306
((((J9_MEMCHECK_PADDING_SIZE > J9_MEMCHECK_MINIMUM_HEADER_SIZE) ? \
307
J9_MEMCHECK_PADDING_SIZE : J9_MEMCHECK_MINIMUM_HEADER_SIZE) + 7) & ~7)
308
309
IDATA
310
memoryCheck_initialize(J9PortLibrary *j9portLibrary, char const *modeStr, char **argv)
311
{
312
#define DLL_NAME J9_THREAD_DLL_NAME
313
OMRPortLibrary *portLib = OMRPORT_FROM_J9PORT(j9portLibrary);
314
if (old_port_shutdown_library) {
315
/* We were already initialized! */
316
return 1;
317
}
318
319
if (portLib->sl_open_shared_library(portLib, DLL_NAME, &j9thrDescriptor, J9PORT_SLOPEN_DECORATE)) {
320
portLib->nls_printf(portLib, J9NLS_ERROR, J9NLS_MEMCHK_INIT_ERROR);
321
return -1;
322
}
323
324
if (portLib->sl_lookup_name(portLib, j9thrDescriptor, "omrthread_attach_ex", (UDATA*)&f_omrthread_attach_ex, "LL")) {
325
portLib->nls_printf(portLib, J9NLS_ERROR, J9NLS_MEMCHK_INIT_ERROR);
326
return -1;
327
}
328
329
if (portLib->sl_lookup_name(portLib, j9thrDescriptor, "omrthread_detach", (UDATA*)&f_omrthread_detach, "L")) {
330
portLib->nls_printf(portLib, J9NLS_ERROR, J9NLS_MEMCHK_INIT_ERROR);
331
return -1;
332
}
333
334
if (!MUTEX_INIT(mcMutex)) {
335
/* Print warning and fail. */
336
portLib->nls_printf(portLib, J9NLS_ERROR, J9NLS_MEMCHK_INIT_ERROR);
337
return -1;
338
}
339
340
mode = J9_MCMODE_FULL_SCANS | J9_MCMODE_PAD_BLOCKS;
341
memset(ignoreCallSiteStr, '\0', IGNORECALLSITESTRLENGTH);
342
while (modeStr && *modeStr) {
343
char const *q = strchr(modeStr, ',');
344
345
if (!memoryCheck_parseOption(portLib, modeStr, (q ? q-modeStr : strlen(modeStr)))) {
346
portLib->nls_printf(portLib, J9NLS_ERROR, J9NLS_MEMCHK_UNRECOGNIZED_OPTION, modeStr);
347
MUTEX_DESTROY(mcMutex);
348
return 2;
349
}
350
351
if (q) {
352
q++;
353
}
354
355
modeStr = q;
356
}
357
358
/* check to see if we have legal options */
359
/* noscan is only supported with callsite, callsitesmall, failat, and zero */
360
if (0 != (mode & J9_MCMODE_NO_SCAN)) {
361
/* disable full scan and pad blocks (which are set by default) */
362
mode = mode & ~(J9_MCMODE_PAD_BLOCKS | J9_MCMODE_FULL_SCANS);
363
/* check for other options */
364
if (0 != (mode&(~J9_MCMODE_PRINT_CALLSITES_SMALL)&(~J9_MCMODE_PRINT_CALLSITES)&(~J9_MCMODE_ZERO)
365
&(~J9_MCMODE_NO_SCAN)&(~J9_MCMODE_SUB_ALLOCATOR)&(~J9_MCMODE_FAIL_AT))) {
366
/* TODO - this should be an NLS message */
367
portLib->tty_err_printf(portLib, "-Xcheck:memory:noscan is only supported with 'callsitesmall', 'callsite', 'failat' and 'zero'. Calling exit(3)\n", mode);
368
exit(3);
369
}
370
}
371
372
/* Set up a private portLibrary for the memoryCheck to use */
373
memCheckPortLib = &memCheckPortLibStruct;
374
if (0 != portLib->port_init_library(memCheckPortLib, sizeof(OMRPortLibrary))) {
375
portLib->tty_printf(portLib, "Error creating the private portLibrary for memoryCheck.\n");
376
return -1;
377
}
378
379
/* Set up the hashTable to hold the J9PortVmemIdentifiers */
380
vmemIDTable = hashTableNew( memCheckPortLib, J9_GET_CALLSITE(), 9391, sizeof( J9PortVmemIdentifier *), 0, 0, OMRMEM_CATEGORY_VM, memoryCheck_hashFn, memoryCheck_hashEqualFn, NULL, NULL );
381
if ( NULL == vmemIDTable ) {
382
memCheckPortLib->tty_printf( memCheckPortLib, "Error creating vmemID hashTable.\n");
383
return -1;
384
}
385
386
/* The hashtable is not allowed to grow or it will cause crashes due to NULL pointers */
387
hashTableSetFlag( vmemIDTable, J9HASH_TABLE_DO_NOT_GROW );
388
/* Save original versions of memory allocation and port shutdown functions. */
389
old_mem_allocate_memory = portLib->mem_allocate_memory;
390
old_mem_free_memory = portLib->mem_free_memory;
391
old_mem_advise_and_free_memory = portLib->mem_advise_and_free_memory;
392
old_mem_allocate_memory32 = portLib->mem_allocate_memory32;
393
old_mem_free_memory32 = portLib->mem_free_memory32;
394
old_mem_shutdown = portLib->mem_shutdown;
395
old_port_shutdown_library = portLib->port_shutdown_library;
396
old_shutdown_and_exit = portLib->exit_shutdown_and_exit;
397
old_port_control = portLib->port_control;
398
399
/* allocate the subAllocator's heap, and initialize it */
400
if (mode & J9_MCMODE_SUB_ALLOCATOR) {
401
int i = 0;
402
UDATA heapSizeBytes = heapSizeMegaBytes * 1024 * 1024;
403
j9heap = memCheckPortLib->mem_allocate_memory(portLib, heapSizeBytes, J9_GET_CALLSITE(), OMRMEM_CATEGORY_VM);
404
405
if (NULL == j9heap) {
406
/* We failed our first attempt, try something smaller */
407
/* TODO - we should output how the user can change this */
408
portLib->tty_printf(portLib, "Initial allocation of subAllocator heap failed. Tried for %i MB\n", heapSizeMegaBytes);
409
410
while (heapSizeBytes >= 1 * 1024 * 1024) {
411
heapSizeBytes = heapSizeBytes/2;
412
j9heap = memCheckPortLib->mem_allocate_memory(portLib, heapSizeBytes, J9_GET_CALLSITE(), OMRMEM_CATEGORY_VM);
413
if (NULL != j9heap) {
414
break;
415
}
416
}
417
418
heapSizeMegaBytes = (heapSizeBytes) / (1024 *1024);
419
}
420
421
if (NULL == j9heap) {
422
/* give up */
423
portLib->tty_printf(portLib, "Unable to allocate subAllocator heap of size %i MB), calling exit(3)\n\n", heapSizeMegaBytes);
424
exit(3);
425
}
426
427
portLib->tty_printf(portLib, "Successfully allocated subAllocator heap of size %i MB\n\n", heapSizeMegaBytes);
428
subAllocator_init_heap(j9heap, heapSizeBytes/sizeof(UDATA)); /* NOTE: the j9heap is an array of UDATA sized blocks */
429
globalAllocator = subAllocator_allocate_memory;
430
globalDeallocator = subAllocator_free_memory;
431
globalAllocator32 = memCheckPortLib->mem_allocate_memory32;
432
globalDeallocator32 = memCheckPortLib->mem_free_memory32;
433
} else {
434
globalAllocator = memCheckPortLib->mem_allocate_memory;
435
globalDeallocator = memCheckPortLib->mem_free_memory;
436
globalAdviseDeallocator = memCheckPortLib->mem_advise_and_free_memory;
437
globalAllocator32 = memCheckPortLib->mem_allocate_memory32;
438
globalDeallocator32 = memCheckPortLib->mem_free_memory32;
439
}
440
441
/* Shutdown the portLibrary and reinitialize it so that memorycheck is used from the beginning */
442
j9portLibrary->port_shutdown_library(j9portLibrary);
443
444
/* Substitute checking versions for the memory allocation
445
* and port shutdown functions. */
446
portLib->mem_allocate_memory = memoryCheck_allocate_memory;
447
portLib->mem_free_memory = memoryCheck_free_memory;
448
portLib->mem_advise_and_free_memory = memoryCheck_advise_and_free_memory;
449
450
/* MPROTECT mode test will time out if original allocate/free_memory32 is replaced */
451
if ((mode & J9_MCMODE_MPROTECT) == 0) {
452
portLib->mem_allocate_memory32 = memoryCheck_allocate_memory32;
453
portLib->mem_free_memory32 = memoryCheck_free_memory32;
454
}
455
456
portLib->mem_reallocate_memory = memoryCheck_reallocate_memory;
457
458
/* TODO we can consider to remove this given the two separate port libraries */
459
# if 0
460
portLib->mem_shutdown = memoryCheck_mem_shutdown;
461
#endif
462
463
portLib->port_control = memoryCheck_control;
464
portLib->port_shutdown_library = memoryCheck_port_shutdown_library;
465
portLib->exit_shutdown_and_exit = memoryCheck_exit_shutdown_and_exit;
466
467
/* Restart the portLibrary */
468
if(j9portLibrary->port_startup_library(j9portLibrary)) {
469
/* If the port library should fail to (re)start, we're going to
470
* crash trying to continue the normal VM shutdown sequence since
471
* we have pre-maturely shutdown the portlibrary a few lines up.
472
*
473
* Exit with 'magic' exit code to indicate this condition
474
*/
475
exit( 1 );
476
}
477
478
/* Create AVL Tree to store callSite information. This information is useful for describing blocks
479
* even if callsite is not passed as a parameter to memcheck
480
*/
481
avl_tree = old_mem_allocate_memory(memCheckPortLib, sizeof(J9AVLTree), J9_GET_CALLSITE(), OMRMEM_CATEGORY_VM);
482
if(avl_tree) {
483
memset(avl_tree, 0, sizeof(J9AVLTree));
484
avl_tree->insertionComparator = memoryCheck_insertion_Compare;
485
avl_tree->searchComparator = memoryCheck_search_Compare;
486
avl_tree->genericActionHook = NULL;
487
avl_tree->rootNode = NULL;
488
} else {
489
memCheckPortLib->nls_printf(memCheckPortLib, J9NLS_ERROR, J9NLS_MEMCHK_AVL_ERROR);
490
}
491
492
/* Reset up NLS - this must be after the setup of the AVL tree */
493
if ( argv != NULL ) {
494
/* j9vm/jvm.c currently calls this function with a null argv, but it has also already setup
495
* and NLS catalog. */
496
main_setNLSCatalog(j9portLibrary, argv);
497
}
498
499
return 0;
500
}
501
502
static BOOLEAN memoryCheck_parseOption(OMRPortLibrary *portLib, char const *option, size_t optionLen)
503
{
504
char const *optStrAll = "all";
505
size_t optLenAll = strlen(optStrAll);
506
char const *optStrQuick = "quick";
507
size_t optLenQuick = strlen(optStrQuick);
508
char const *optStrNofree = "nofree";
509
size_t optLenNofree = strlen(optStrNofree);
510
char const *optStrFailat = "failat=";
511
size_t optLenFailat = strlen(optStrFailat);
512
char const *optStrSkipto = "skipto=";
513
size_t optLenSkipto = strlen(optStrSkipto);
514
char const *optTopDown = "topdown";
515
size_t optLenTopDown = strlen(optTopDown);
516
char const *optStrCallPrint = "callsite=";
517
size_t optLenCallPrint = strlen(optStrCallPrint);
518
char const *optStrCallPrintSmall = "callsitesmall=";
519
size_t optLenCallPrintSmall = strlen(optStrCallPrintSmall);
520
char const *optStrZero = "zero";
521
size_t optLenZero = strlen(optStrZero);
522
char const *optStrLimit = "limit=";
523
size_t optLenLimit = strlen(optStrLimit);
524
char const *optStrIgnoreUnknownBlocks = "ignoreUnknownBlocks";
525
size_t optLenIgnoreUnknownBlocks = strlen(optStrIgnoreUnknownBlocks);
526
char const *optStrSubAllocator = "subAllocator";
527
size_t optLenSubAllocator = strlen(optStrSubAllocator);
528
529
char const *optStrMProtect = "mprotect=";
530
size_t optLenMProtect = strlen(optStrMProtect);
531
char const *optStrAlignTop = "top";
532
size_t optLenAlignTop = strlen(optStrAlignTop);
533
char const *optStrAlignBottom = "bottom";
534
size_t optLenAlignBottom = strlen(optStrAlignBottom);
535
536
char const *optStrNoScan = "noscan";
537
size_t optLenNoScan = strlen(optStrNoScan);
538
539
/* undocumented. used to ignore unfreed blocks from specified callsites
540
* the format is -Xcheck:memory:ignoreUnfreedCallsite=[site1]:[site2]:...
541
*
542
* Note, each site string is meant to be a prefix match to call site info.
543
* if string is 'zip/', it will ignore all unfreed blocks with callsite string with 'zip/'
544
* Conversely, if a call site is abc/de.c, specifying a string of de.c will not be a match */
545
char const *optStrIgnoreUnfreedCallsite = "ignoreUnfreedCallsite=";
546
size_t optLenIgnoreUnfreedCallsite = strlen(optStrIgnoreUnfreedCallsite);
547
548
549
#ifdef J9VM_MEMCHK_SIM_SUP
550
char const *optStrSimulate = "simulate";
551
size_t optLenSimulate = strlen(optStrSimulate);
552
553
if ((optionLen == optLenSimulate) && !strncmp(option, optStrSimulate, optLenSimulate)) {
554
mode |= J9_MCMODE_SIMULATE;
555
return TRUE;
556
}
557
#endif
558
559
if ((optionLen > optLenIgnoreUnfreedCallsite) && !strncmp(option, optStrIgnoreUnfreedCallsite, optLenIgnoreUnfreedCallsite)) {
560
if (strlen (&(option[optLenIgnoreUnfreedCallsite])) < IGNORECALLSITESTRLENGTH) {
561
strcpy(ignoreCallSiteStr, &(option[optLenIgnoreUnfreedCallsite]));
562
} else {
563
portLib->tty_printf(portLib,"WARNING : IgnoreUnfreedCallsite option too long for internal buffer. Ignoring\n");
564
565
}
566
return TRUE;
567
}
568
569
if ((optionLen > optLenMProtect) && !strncmp(option, optStrMProtect, optLenMProtect)) {
570
char temp[20];
571
IDATA tempSize = optionLen - optLenMProtect;
572
573
mode |= J9_MCMODE_PAD_BLOCKS;
574
if (tempSize > 19) {
575
tempSize = 19;
576
}
577
strncpy(temp, option + optLenMProtect, tempSize);
578
temp[tempSize] = '\0';
579
if (!strncmp(temp, optStrAlignTop, optLenAlignTop) ) {
580
mode |= J9_MCMODE_MPROTECT;
581
J9_ALIGN_BOTTOM = 0;
582
return TRUE;
583
}
584
else if (!strncmp(temp, optStrAlignBottom, optLenAlignBottom)) {
585
mode |= J9_MCMODE_MPROTECT;
586
J9_ALIGN_BOTTOM = 1;
587
return TRUE;
588
}
589
return FALSE;
590
}
591
592
if ((optionLen == optLenAll) && !strncmp(option, optStrAll, optLenAll)) {
593
mode |= J9_MCMODE_PAD_BLOCKS | J9_MCMODE_FULL_SCANS;
594
return TRUE;
595
}
596
if ((optionLen == optLenQuick) && !strncmp(option, optStrQuick, optLenQuick)) {
597
mode |= J9_MCMODE_PAD_BLOCKS;
598
mode &= ~J9_MCMODE_FULL_SCANS;
599
return TRUE;
600
}
601
if ((optionLen == optLenNofree) && !strncmp(option, optStrNofree, optLenNofree)) {
602
mode |= J9_MCMODE_NEVER_FREE;
603
return TRUE;
604
}
605
if ((optionLen == optLenTopDown) && !strncmp(option, optTopDown, optLenTopDown)) {
606
mode |= J9_MCMODE_TOP_DOWN;
607
mode &= ~J9_MCMODE_SUB_ALLOCATOR;
608
return TRUE;
609
}
610
if ((optionLen > optLenCallPrint) && !strncmp(option, optStrCallPrint, optLenCallPrint)) {
611
char temp[20];
612
IDATA tempSize = optionLen - optLenCallPrint;
613
if (tempSize > 19)
614
tempSize = 19;
615
strncpy(temp, option + optLenCallPrint, tempSize);
616
temp[tempSize] = '\0';
617
if (!(callSitePrintCount = atoi(temp)))
618
return FALSE;
619
mode |= J9_MCMODE_PRINT_CALLSITES;
620
/* remove the bits for J9_MCMODE_PRINT_CALLSITES_SMALL since J9_MCMODE_PRINT_CALLSITES was defined after */
621
mode &= ~J9_MCMODE_PRINT_CALLSITES_SMALL;
622
return TRUE;
623
}
624
if ((optionLen > optLenCallPrintSmall) && !strncmp(option, optStrCallPrintSmall, optLenCallPrintSmall)) {
625
char temp[20];
626
IDATA tempSize = optionLen - optLenCallPrintSmall;
627
if (tempSize > 19)
628
tempSize = 19;
629
strncpy(temp, option + optLenCallPrintSmall, tempSize);
630
temp[tempSize] = '\0';
631
if (!(callSitePrintCount = atoi(temp)))
632
return FALSE;
633
mode |= J9_MCMODE_PRINT_CALLSITES_SMALL;
634
/* remove the bits for J9_MCMODE_PRINT_CALLSITES since J9_MCMODE_PRINT_CALLSITES_SMALL was defined after */
635
mode &= ~J9_MCMODE_PRINT_CALLSITES;
636
return TRUE;
637
}
638
if ((optionLen == optLenZero) && !strncmp(option, optStrZero, optLenZero)) {
639
mode |= J9_MCMODE_ZERO;
640
return TRUE;
641
}
642
if ((optionLen > optLenSkipto) && (!strncmp(option, optStrSkipto, optLenSkipto))) {
643
char temp[20];
644
IDATA tempSize = optionLen - optLenSkipto;
645
if (tempSize > 19)
646
tempSize = 19;
647
strncpy(temp, option + optLenSkipto, tempSize);
648
temp[tempSize] = '\0';
649
if (!(skipToAlloc = atoi(temp)))
650
return FALSE;
651
mode |= J9_MCMODE_SKIP_TO;
652
return TRUE;
653
}
654
if ((optionLen > optLenFailat) && (!strncmp(option, optStrFailat, optLenFailat))) {
655
char temp[20];
656
IDATA tempSize = optionLen - optLenFailat;
657
if (tempSize > 19)
658
tempSize = 19;
659
strncpy(temp, option + optLenFailat, tempSize);
660
temp[tempSize] = '\0';
661
if (!(failAtAlloc = atoi(temp)))
662
return FALSE;
663
mode |= J9_MCMODE_FAIL_AT;
664
return TRUE;
665
}
666
if ((optionLen > optLenLimit) && (!strncmp(option, optStrLimit, optLenLimit))) {
667
char temp[20];
668
IDATA tempSize = optionLen - optLenLimit;
669
if (tempSize > 19)
670
tempSize = 19;
671
strncpy(temp, option + optLenLimit, tempSize);
672
temp[tempSize] = '\0';
673
if (!(limitAlloc = atoi(temp)))
674
return FALSE;
675
mode |= J9_MCMODE_LIMIT;
676
return TRUE;
677
}
678
if ((optionLen == optLenIgnoreUnknownBlocks) && !strncmp(option, optStrIgnoreUnknownBlocks, optLenIgnoreUnknownBlocks)) {
679
mode |= J9_MCMODE_IGNORE_UNKNOWN_BLOCKS;
680
return TRUE;
681
}
682
/* The heap sub allocator cannot be used with top down */
683
if ((optionLen >= optLenSubAllocator) && !strncmp(option, optStrSubAllocator, optLenSubAllocator)) {
684
char temp[20];
685
IDATA tempSize = optionLen - optLenSubAllocator;
686
if (tempSize > 19) {
687
tempSize = 19;
688
}
689
strncpy(temp, option + optLenSubAllocator + 1, tempSize);
690
temp[tempSize] = '\0';
691
if (tempSize == 0) {
692
heapSizeMegaBytes = DEFAULT_HEAP_SIZE_BYTES / (1024 * 1024);
693
} else if (!(heapSizeMegaBytes = atoi(temp))) {
694
return FALSE;
695
}
696
mode &= ~J9_MCMODE_TOP_DOWN;
697
mode |= J9_MCMODE_SUB_ALLOCATOR;
698
return TRUE;
699
}
700
701
if ((optionLen == optLenNoScan) && !strncmp(option, optStrNoScan, optLenNoScan)) {
702
/* This is only supported with Callsite or Zero
703
* We will check for other options in memoryCHeck initialize */
704
mode |= J9_MCMODE_NO_SCAN;
705
return TRUE;
706
}
707
708
return FALSE;
709
}
710
711
712
static void OMRNORETURN memoryCheck_abort(OMRPortLibrary *portLib)
713
{
714
715
if ( mode & J9_MCMODE_MPROTECT ) {
716
/* Unlock ALL blocks */
717
memoryCheck_lockAllBlocks( memCheckPortLib, mostRecentBlock, unlockMode, 0 );
718
memoryCheck_lockAllBlocks( memCheckPortLib, mostRecentFreedBlock, unlockMode, 1 );
719
}
720
721
memoryCheck_print_stats(portLib);
722
723
if ( mode & J9_MCMODE_MPROTECT ) {
724
/* free everything from the hashTable*/
725
/* TODO - why are we freeing anything if we just crashed */
726
hashTableForEachDo( vmemIDTable, memoryCheck_hashDoFn, memCheckPortLib );
727
hashTableFree( vmemIDTable );
728
}
729
730
memCheckPortLib->tty_printf( memCheckPortLib, "Memory error(s) discovered, calling exit(3)\n");
731
memCheckPortLib->exit_shutdown_and_exit(memCheckPortLib, 3);
732
733
dontreturn: goto dontreturn; /* avoid warnings */
734
}
735
736
737
/* This function passes memoryCheck's private portLibrary memCheckPortLibrary on, NOT the portlib passed into it. */
738
static void *memoryCheck_allocate_memory(OMRPortLibrary *portLib, UDATA byteAmount, const char *callSite, U_32 category)
739
{
740
741
#ifdef DEBUG
742
memCheckPortLib->tty_printf( memCheckPortLib, "allocate_memory(%d)\n", byteAmount);
743
#endif
744
745
return memoryCheck_wrapper_allocate_memory(memCheckPortLib, byteAmount, "allocate_memory", globalAllocator,
746
J9_MEMCHECK_DATA_PADDING_VALUE, J9_MEMCHECK_DATA_FILL_VALUE, J9_MEMCHECK_DATA_FREED_VALUE, callSite, category);
747
}
748
749
static void *memoryCheck_allocate_memory32(OMRPortLibrary *portLib, UDATA byteAmount, const char *callSite, U_32 category)
750
{
751
752
#ifdef DEBUG
753
memCheckPortLib->tty_printf( memCheckPortLib, "allocate_memory32(%d)\n", byteAmount);
754
#endif
755
756
return memoryCheck_wrapper_allocate_memory(memCheckPortLib, byteAmount, "allocate_memory", globalAllocator32,
757
J9_MEMCHECK_DATA_PADDING_VALUE, J9_MEMCHECK_DATA_FILL_VALUE, J9_MEMCHECK_DATA_FREED_VALUE, callSite, category);
758
}
759
760
761
/* This method prints whatever information as it can gather about a block from the block and its immediate neighbors (if any).
762
If the block looks like a correct block, TRUE is returned. If anything bogus is discovered about the block, FALSE is returned. */
763
/* @precondition: If #defined MEMORY_PROTECT, this function must be passed UNLOCK'ed blocks */
764
/* @internal The memCheckPortLib is the one that should always be passed to this function */
765
766
static BOOLEAN memoryCheck_describe_block(OMRPortLibrary *portLib, char const *operationName,
767
J9MemoryCheckHeader *blockHeader)
768
{
769
BOOLEAN everythingOkay = TRUE;
770
UDATA topPaddingSize = 0;
771
UDATA bottomPaddingSize = 0;
772
U_32 paddingValue;
773
UDATA topPaddingSmashed, bottomPaddingSmashed;
774
775
U_8 *topPadding = ((U_8 *) blockHeader) + sizeof(J9MemoryCheckHeader);
776
U_8 *wrappedBlock = NULL;
777
U_8 *bottomPadding = NULL;
778
U_8 *dumpPos = topPadding;
779
780
if ( !(mode & J9_MCMODE_MPROTECT) ) {
781
topPaddingSize = J9_MEMCHECK_ADJUSTED_PADDING - sizeof(J9MemoryCheckHeader);
782
783
/* Adjust bottomPadding to force it to end on a double boundary */
784
bottomPaddingSize = J9_MEMCHECK_ADJUSTED_PADDING + BYTES_FOR_ALIGNMENT (blockHeader->wrappedBlockSize);
785
wrappedBlock = ((U_8 *) blockHeader) + J9_MEMCHECK_ADJUSTED_PADDING;
786
} else {
787
wrappedBlock = blockHeader->wrappedBlock;
788
if (J9_ALIGN_BOTTOM) {
789
topPaddingSize = wrappedBlock - (((U_8 *)blockHeader) + sizeof(J9MemoryCheckHeader));
790
} else {
791
topPaddingSize = J9_MEMCHECK_PAGE_SIZE - sizeof(J9MemoryCheckHeader);
792
}
793
794
/* Adjust bottomPadding to force it to end on a double boundary */
795
bottomPaddingSize = J9_MEMCHECK_PAGE_SIZE + BYTES_FOR_ALIGNMENT (blockHeader->wrappedBlockSize);
796
}
797
798
/* TODO - this doesn't take into account the offset area */
799
bottomPadding = wrappedBlock + blockHeader->wrappedBlockSize;
800
801
portLib->tty_printf(portLib, "%s describing block at %p (header at %p):\n", operationName, wrappedBlock,
802
blockHeader);
803
804
if ( mode & J9_MCMODE_MPROTECT ) {
805
if ( J9_ALIGN_BOTTOM ) {
806
U_32 offsetArea = BYTES_FOR_ALIGNMENT (blockHeader->wrappedBlockSize);
807
wrappedBlock = blockHeader->bottomPage - blockHeader->wrappedBlockSize - offsetArea;
808
bottomPadding = wrappedBlock + blockHeader->wrappedBlockSize;
809
}
810
}
811
812
/* Make a guess at what the block should look like by peeking right after the header.. */
813
814
if (!memoryCheck_verify_forward(portLib, topPadding, 8, J9_MEMCHECK_DATA_PADDING_VALUE, wrappedBlock)) {
815
paddingValue = J9_MEMCHECK_DATA_PADDING_VALUE;
816
} else if (!memoryCheck_verify_forward(portLib, topPadding, 8, J9_MEMCHECK_CODE_PADDING_VALUE, wrappedBlock)) {
817
paddingValue = J9_MEMCHECK_CODE_PADDING_VALUE;
818
} else {
819
/* TODO: check for legal padding with wrong wrappedBlock bits here? */
820
821
/* Test for alignment off by 4 */
822
if ( (UDATA)topPadding%8 == 4 ) {
823
if (!memoryCheck_verify_forward(portLib, topPadding+4, 8, J9_MEMCHECK_DATA_PADDING_VALUE, wrappedBlock)) {
824
paddingValue = J9_MEMCHECK_DATA_PADDING_VALUE;
825
} else if (!memoryCheck_verify_forward(portLib, topPadding +4, 8, J9_MEMCHECK_CODE_PADDING_VALUE, wrappedBlock)) {
826
paddingValue = J9_MEMCHECK_CODE_PADDING_VALUE;
827
}
828
829
portLib->tty_printf(portLib, "Block has unrecognized padding %08x %08x (header is probably trashed)!\n",
830
((U_32 *) topPadding)[0], ((U_32 *) topPadding)[1]);
831
everythingOkay = FALSE;
832
goto dump_header_only;
833
} else {
834
portLib->tty_printf(portLib, "Block has unrecognized padding %08x %08x (header is probably trashed)!\n",
835
((U_32 *) topPadding)[0], ((U_32 *) topPadding)[1]);
836
everythingOkay = FALSE;
837
goto dump_header_only;
838
}
839
}
840
841
topPaddingSmashed = memoryCheck_verify_forward(portLib, topPadding, topPaddingSize, paddingValue, wrappedBlock);
842
if (topPaddingSmashed) {
843
portLib->tty_printf(portLib, "Last %d bytes of top padding are damaged\n", topPaddingSmashed);
844
everythingOkay = FALSE;
845
}
846
847
/* Do additional checks to see if header is sane. If not, we won't trust its length field */
848
/* and we won't worry about the bottom padding. */
849
850
if ( mode & J9_MCMODE_MPROTECT ) {
851
const UDATA pageSize = J9_MEMCHECK_PAGE_SIZE;
852
UDATA checkSize = pageSize;
853
854
if (J9_ALIGN_BOTTOM) {
855
856
/* Size to check on the bottom is the bottomPage and the alignment bytes. */
857
/* Possible enhancement: don't check the bottom page as it can't be touched anyway */
858
checkSize += BYTES_FOR_ALIGNMENT (blockHeader->wrappedBlockSize);
859
}
860
else {
861
UDATA addMod = blockHeader->wrappedBlockSize % pageSize;
862
863
if ( addMod ) {
864
checkSize += pageSize - (blockHeader->wrappedBlockSize % pageSize);
865
}
866
}
867
bottomPaddingSmashed = memoryCheck_verify_backward(portLib, bottomPadding, checkSize , paddingValue, wrappedBlock);
868
} else {
869
bottomPaddingSmashed = memoryCheck_verify_backward(portLib, bottomPadding, bottomPaddingSize, paddingValue, wrappedBlock);
870
}
871
872
if (bottomPaddingSmashed) {
873
portLib->tty_printf(portLib, "First %d bytes of bottom padding are damaged\n", bottomPaddingSmashed);
874
everythingOkay = FALSE;
875
}
876
877
portLib->tty_printf(portLib, "Wrapped block size is %d, allocation number is %d\n",
878
blockHeader->wrappedBlockSize, blockHeader->allocationNumber);
879
880
if (blockHeader->node) {
881
portLib->tty_printf(portLib, "Block was allocated by %s\n", blockHeader->node->callSite);
882
}
883
884
if (everythingOkay) {
885
UDATA size = blockHeader->wrappedBlockSize < 32 ? blockHeader->wrappedBlockSize : 32;
886
portLib->tty_printf(portLib, "First %d bytes:\n", size);
887
memoryCheck_dump_bytes(portLib, wrappedBlock, size);
888
889
return TRUE;
890
}
891
892
if ( mode & J9_MCMODE_MPROTECT ) {
893
portLib->tty_printf(portLib, "Extra Top Padding:\n");
894
memoryCheck_dump_bytes(portLib, blockHeader->self, blockHeader->topPage - blockHeader->self);
895
}
896
897
portLib->tty_printf(portLib, "Block header:\n");
898
memoryCheck_dump_bytes(portLib, blockHeader, sizeof(*blockHeader));
899
portLib->tty_printf(portLib, "Top padding:\n");
900
memoryCheck_dump_bytes(portLib, topPadding, topPaddingSize);
901
portLib->tty_printf(portLib, "Block contents:\n");
902
memoryCheck_dump_bytes(portLib, wrappedBlock, blockHeader->wrappedBlockSize);
903
portLib->tty_printf(portLib, "Bottom padding:\n");
904
if ( mode & J9_MCMODE_MPROTECT ) {
905
memoryCheck_dump_bytes(portLib, bottomPadding, blockHeader->totalAllocation - (bottomPadding - blockHeader->self));
906
} else {
907
memoryCheck_dump_bytes(portLib, bottomPadding, bottomPaddingSize);
908
}
909
return everythingOkay;
910
911
dump_header_only:
912
portLib->tty_printf(portLib, "(only top padding + first 64 bytes of user data will be printed here)\n");
913
if ( mode & J9_MCMODE_MPROTECT ) {
914
portLib->tty_printf(portLib, "Extra Top Padding:\n");
915
memoryCheck_dump_bytes(portLib, blockHeader->self, blockHeader->topPage - blockHeader->self);
916
}
917
portLib->tty_printf(portLib, "Block header:\n");
918
memoryCheck_dump_bytes(portLib, blockHeader, sizeof(*blockHeader));
919
portLib->tty_printf(portLib, "Top padding:\n");
920
memoryCheck_dump_bytes(portLib, topPadding, topPaddingSize);
921
portLib->tty_printf(portLib, "First 64 bytes at block contents:\n");
922
memoryCheck_dump_bytes(portLib, wrappedBlock, 64);
923
return everythingOkay;
924
}
925
926
927
928
/* This method fills fillSize bytes at fillAddress with copies of a 64-bit value formed by splitting fillValue into 2 16-bit values and inserting
929
the low 32 bits of the block address in between. Each instance of fillValue is aligned on an 8-byte boundary, so if fillAddress and/or
930
fillAddress+fillSize is not 8-byte aligned, a partial copy will appear at the start and/or end. */
931
932
static void memoryCheck_fill_bytes(OMRPortLibrary *portLib, U_8 *fillAddress, UDATA fillSize, U_32 fillValue, U_8 *blockAddress)
933
{
934
U_8 fillWith[8];
935
I_32 blockAddressInt = (I_32)(IDATA)blockAddress;
936
937
U_8 *c;
938
UDATA index = ((UDATA)fillAddress) & 7;
939
940
memcpy(fillWith, &fillValue, 2);
941
memcpy(fillWith+2, &blockAddressInt, 4);
942
memcpy(fillWith+6, ((U_8 *)(&fillValue)) + 2, 2);
943
944
for (c = fillAddress; c < fillAddress+fillSize; c++) {
945
*c = fillWith[index];
946
index++;
947
index &= 7;
948
}
949
}
950
951
952
953
/* @internal The portLibrary passed on to other functions must be the memCheckPortLib. */
954
static void
955
memoryCheck_free_memory(OMRPortLibrary *portLib, void *memoryPointer)
956
{
957
#ifdef DEBUG
958
memCheckPortLib->tty_printf( memCheckPortLib, "free_memory(%p)\n", memoryPointer);
959
#endif
960
961
memoryCheck_wrapper_free_memory( memCheckPortLib, memoryPointer, "free_memory", globalDeallocator,
962
J9_MEMCHECK_DATA_PADDING_VALUE, J9_MEMCHECK_DATA_FILL_VALUE, J9_MEMCHECK_DATA_FREED_VALUE);
963
}
964
965
static void
966
memoryCheck_advise_and_free_memory(OMRPortLibrary *portLib, void *memoryPointer)
967
{
968
#ifdef DEBUG
969
memCheckPortLib->tty_printf( memCheckPortLib, "advise_and_free_memory(%p)\n", memoryPointer);
970
#endif
971
972
memoryCheck_wrapper_free_memory( memCheckPortLib, memoryPointer, "advise_and_free_memory", globalAdviseDeallocator,
973
J9_MEMCHECK_DATA_PADDING_VALUE, J9_MEMCHECK_DATA_FILL_VALUE, J9_MEMCHECK_DATA_FREED_VALUE);
974
}
975
976
static void
977
memoryCheck_free_memory32(OMRPortLibrary *portLib, void *memoryPointer)
978
{
979
#ifdef DEBUG
980
memCheckPortLib->tty_printf( memCheckPortLib, "free_memory(%p)\n", memoryPointer);
981
#endif
982
983
memoryCheck_wrapper_free_memory( memCheckPortLib, memoryPointer, "free_memory", globalDeallocator32,
984
J9_MEMCHECK_DATA_PADDING_VALUE, J9_MEMCHECK_DATA_FILL_VALUE, J9_MEMCHECK_DATA_FREED_VALUE);
985
}
986
987
/* Designed to override the original port library shut down routine
988
*
989
* Shuts down the passed in portLibrary (which should be the user's)
990
* using the original shut down routines, then shut's down memcheck */
991
static I_32
992
memoryCheck_port_shutdown_library(OMRPortLibrary *portLib)
993
{
994
I_32 rc = 0;
995
996
memoryCheck_restore_old_shutdown_functions(portLib);
997
998
rc = portLib->port_shutdown_library(portLib);
999
1000
memoryCheck_shutdown_internal( memCheckPortLib, J9_MEMCHECK_SHUTDOWN_NORMAL );
1001
1002
return rc;
1003
}
1004
1005
/**
1006
* Returns the page size to be used in the memorycheck calls.
1007
* The page size must always be large enough to hold the J9MemoryCheckHeader struct
1008
* as well as some scratch padding. If the default pagesize is less then this size,
1009
* then a multiple of the page size will be returned which is at least
1010
* J9_MEMCHECK_ADJUSTED_PADDING in size.
1011
*/
1012
static UDATA memoryCheck_get_page_size(OMRPortLibrary *portLib)
1013
{
1014
UDATA pageSize;
1015
1016
pageSize = (portLib->vmem_supported_page_sizes( portLib )) [0];
1017
if ( pageSize < J9_MEMCHECK_ADJUSTED_PADDING ) {
1018
UDATA systemPageSize = portLib->vmem_supported_page_sizes( portLib )[0];
1019
1020
pageSize = (J9_MEMCHECK_ADJUSTED_PADDING / systemPageSize)*systemPageSize +
1021
(J9_MEMCHECK_ADJUSTED_PADDING % systemPageSize ? systemPageSize : 0 );
1022
}
1023
return pageSize;
1024
}
1025
1026
/**
1027
* Used by the hashTableForEachDo iterator to call
1028
* omrvmem_free_memory() for each reserved section of virtual memory
1029
* and to free the J9PortVmemIdentifier struct.
1030
*
1031
* @param[in] entry The hashTable node.
1032
* @param[in] userData A pointer to an initialized OMRPortLibrary; The "memCheckPortLibrary" must be the one passed in.
1033
* This is the portLibrary with its original functions
1034
* @return Always returns TRUE so that the nodes in the hash table will be deallocated.
1035
*/
1036
static UDATA
1037
memoryCheck_hashDoFn( void *entry, void *portLib )
1038
{
1039
if ( entry && portLib ) {
1040
J9PortVmemIdentifier **vmemID = (J9PortVmemIdentifier **)entry;
1041
OMRPORT_ACCESS_FROM_OMRPORT(portLib);
1042
1043
/* Ensure the node was allocated by us, as every node will have an address which is a multiple of J9_MEMCHECK_PAGE_SIZE */
1044
/* TODO - consider removing if no one else could have allocated it?? */
1045
if ( *vmemID && (UDATA)(*vmemID)->address % J9_MEMCHECK_PAGE_SIZE == 0 ) {
1046
/* Release the virtual mem and free the struct holding the vmemIdentifier */
1047
omrvmem_free_memory((*vmemID)->address, (*vmemID)->size, *vmemID);
1048
omrmem_free_memory(*vmemID);
1049
*vmemID = NULL;
1050
}
1051
}
1052
return TRUE;
1053
}
1054
/**
1055
* This is the function used to determine if two hashed items are the same item or not. This is
1056
* done by determining they have the same address in the J9PortVmemIdentifier structs's address
1057
* field. As Each address in the address space should only be mapped into the table once for
1058
* each allocation, this should always be a unique way to determine if two items are equal.
1059
*
1060
* @param[in] leftEntry A valid J9PortVmemIdentifier
1061
* @param[in] rightEntry A valid J9PortVmemIdentifier
1062
* @param[in] userData An ignored parameter required by the format used by the hashTable fcn pointer.
1063
* @return A UDATA with 1 if equal, 0 if not.
1064
*/
1065
static UDATA
1066
memoryCheck_hashEqualFn(void *leftEntry, void *rightEntry, void *userData)
1067
{
1068
if ( leftEntry && rightEntry && *(J9PortVmemIdentifier **)leftEntry && *(J9PortVmemIdentifier **)rightEntry ) {
1069
return ( *(J9PortVmemIdentifier **) leftEntry)->address == ( *(J9PortVmemIdentifier **) rightEntry)->address;
1070
} else {
1071
return 0;
1072
}
1073
}
1074
1075
/**
1076
* This is the hash function to be used by the hashTable. The magic constant 2654435761 is the
1077
* golden ratio of 2^32 and the shift by 3 is because memorycheck assumes 8 byte alignment.
1078
*
1079
* @param[in] vmemId A valid J9PortVmemIdentifier struct pointer to reserved and committed memory.
1080
* @param[in] userData An ignored parameter required by the format used by the hashTable fcn pointer.
1081
* @return The hashkey that will return the pointer to the J9PortVmemIdentifier struct for later use.
1082
*/
1083
static UDATA
1084
memoryCheck_hashFn(void *vmemId, void *userData)
1085
{
1086
UDATA key;
1087
key = (UDATA) (*(J9PortVmemIdentifier **)vmemId)->address;
1088
return (key >> 3) * 0x9E3779B1;
1089
}
1090
1091
/**
1092
* This function unlocks all of the blocks on a given list.
1093
*
1094
* @param[in] portLib An initialized OMRPortLibrary with its original functions
1095
* @param[in] listHead The block to start unlocking the list from.
1096
* @param[in] lockFlags The LockMode: lockMode to lock, unlockMode to unlock
1097
* @param[in] lockBody Whether the body of the block needs to be unlocked. It should
1098
* only be set to true for the mostRecentFreedBlock list.
1099
*/
1100
static void
1101
memoryCheck_lockAllBlocks(OMRPortLibrary *portLib, J9MemoryCheckHeader *listHead, const UDATA lockFlags, const UDATA lockBody)
1102
{
1103
if ( mode & J9_MCMODE_MPROTECT ) {
1104
/* Unlock ALL the blocks */
1105
if ( listHead ) {
1106
J9MemoryCheckHeader *blockHeader = listHead;
1107
while ( blockHeader != NULL ) {
1108
if ( lockFlags == lockMode ) {
1109
if ( blockHeader->nextBlock ) {
1110
if ( lockBody ) {
1111
J9_MEMCHECK_LOCK_BODY( blockHeader ->nextBlock );
1112
}
1113
J9_MEMCHECK_LOCK( blockHeader->nextBlock );
1114
}
1115
if ( !blockHeader->previousBlock ) {
1116
if ( lockBody ) {
1117
J9_MEMCHECK_LOCK_BODY( blockHeader );
1118
}
1119
J9_MEMCHECK_LOCK( blockHeader );
1120
break;
1121
}
1122
} else if ( lockFlags == unlockMode ) {
1123
J9_MEMCHECK_UNLOCK( blockHeader );
1124
if ( lockBody ) {
1125
J9_MEMCHECK_UNLOCK_BODY( blockHeader );
1126
}
1127
}
1128
blockHeader = blockHeader->previousBlock;
1129
}
1130
blockHeader = NULL;
1131
}
1132
}
1133
return;
1134
}
1135
1136
/**
1137
* This function is used to lock and unlock the guardpage above and below the wrappedBlock.
1138
* It is usually called through one of two macros: UNLOCK( portLib, header ) or LOCK( portLib, header ).
1139
*
1140
* @precondition The global variable "J9HashTable vmemIDTable" must be already initialized.
1141
* @param[in] portLib An initialized OMRPortLibrary structure with its original functions
1142
* @param[in] memcheckHeader An initialized J9MemoryCheckheader.
1143
* @param[in] requestedMode The flags to apply to the guardPages. This should be either lockMode or unlockMode;
1144
* @return 0 on Success, -1 on failure
1145
*/
1146
static IDATA
1147
memoryCheck_lockGuardPages(OMRPortLibrary *portLib, void *memcheckHeader, UDATA size, UDATA requestedMode)
1148
{
1149
if ( mode & J9_MCMODE_MPROTECT ) {
1150
void *ret = NULL;
1151
U_8 *topPageBoundary = NULL;
1152
J9PortVmemIdentifier getFromTable;
1153
J9PortVmemIdentifier *getFromTablePtr;
1154
J9PortVmemIdentifier **block = NULL;
1155
J9MemoryCheckHeader *head = (J9MemoryCheckHeader *)memcheckHeader;
1156
UDATA oldMode;
1157
OMRPORT_ACCESS_FROM_OMRPORT(portLib);
1158
1159
if ( !J9_ALIGN_BOTTOM ) {
1160
topPageBoundary = (U_8 *)memcheckHeader;
1161
}
1162
else {
1163
#if defined(J9ZOS390)
1164
topPageBoundary = (U_8 *)head->self;
1165
#else
1166
topPageBoundary = (U_8 *)memcheckHeader; /* Pointer to the J9MemoryCheckHeader */
1167
topPageBoundary = topPageBoundary - (UDATA)topPageBoundary % J9_MEMCHECK_PAGE_SIZE; /* Align it to a page Boundary */
1168
#endif
1169
}
1170
1171
/* Get the correct struct from the hashTable */
1172
getFromTable.address = topPageBoundary;
1173
getFromTablePtr = &getFromTable;
1174
block = hashTableFind( vmemIDTable, &getFromTablePtr );
1175
if ( block ) {
1176
getFromTablePtr = *block;
1177
oldMode = getFromTablePtr->mode;
1178
1179
/* Update it so it has the correct access mode and recommit the mem to allow reading */
1180
getFromTablePtr->mode = unlockMode;
1181
ret = omrvmem_commit_memory( getFromTablePtr->address, getFromTablePtr->pageSize, getFromTablePtr );
1182
if ( NULL == ret ) {
1183
getFromTablePtr->mode = oldMode;
1184
return -1;
1185
}
1186
1187
/* Apply user passed in mode to the topPage and bottom page */
1188
getFromTablePtr->mode = requestedMode;
1189
ret = omrvmem_commit_memory( head->bottomPage, getFromTablePtr->pageSize, getFromTablePtr );
1190
if ( NULL == ret ) {
1191
getFromTablePtr->mode = oldMode;
1192
return -1;
1193
}
1194
1195
ret = omrvmem_commit_memory( topPageBoundary, getFromTablePtr->pageSize, getFromTablePtr );
1196
if ( NULL == ret ) {
1197
getFromTablePtr->mode = oldMode;
1198
return -1;
1199
}
1200
getFromTablePtr->mode = oldMode;
1201
1202
return 0;
1203
}
1204
return -1;
1205
}
1206
return 0;
1207
}
1208
1209
/**
1210
* This function is used to lock and unlock the wrappedBlock. It is usually called through
1211
* one of two macros: UNLOCK_BODY( portLib, header ) or LOCK_BODY( portLib, header ).
1212
*
1213
* @precondition The blockHeader must be unlocked before calling this function
1214
* @param[in] portLib An initialized OMRPortLibrary structure with its original functions
1215
* @param[in] blockHeader An initialized blockHeader which already has its guard pages unlocked.
1216
* @param[in] requestedMode The flags to apply to the wrappedBlock. This should be either lockMode or unlockMode;
1217
* @return 0 on Success, -1 on failure
1218
*/
1219
static IDATA
1220
memoryCheck_lockWrappedBlock(OMRPortLibrary *portLib, J9MemoryCheckHeader *blockHeader, const UDATA requestedMode)
1221
{
1222
if ( mode & J9_MCMODE_MPROTECT ) {
1223
void *ret = NULL;
1224
U_8 *topPageBoundary = NULL;
1225
J9PortVmemIdentifier getFromTable;
1226
J9PortVmemIdentifier *getFromTablePtr = NULL;
1227
J9PortVmemIdentifier **block = NULL;
1228
J9MemoryCheckHeader *head = (J9MemoryCheckHeader *)blockHeader;
1229
UDATA userPages = 0;
1230
UDATA oldMode;
1231
OMRPORT_ACCESS_FROM_OMRPORT(portLib);
1232
1233
if ( !J9_ALIGN_BOTTOM ) {
1234
topPageBoundary = (U_8 *)blockHeader;
1235
}
1236
else {
1237
topPageBoundary = (U_8 *)blockHeader; /* Pointer to the J9MemoryCheckHeader */
1238
topPageBoundary = topPageBoundary - (UDATA)topPageBoundary % J9_MEMCHECK_PAGE_SIZE; /* Align it to a page Boundary */
1239
}
1240
1241
/* Get the correct struct from the hashTable */
1242
getFromTable.address = topPageBoundary;
1243
getFromTablePtr = &getFromTable;
1244
block = hashTableFind( vmemIDTable, &getFromTablePtr );
1245
getFromTablePtr = *block;
1246
1247
/* Determine the number of pages that are used to hold the 'body' or user-allocated mem */
1248
userPages = blockHeader->wrappedBlockSize/J9_MEMCHECK_PAGE_SIZE + ( blockHeader->wrappedBlockSize % J9_MEMCHECK_PAGE_SIZE ? 1 : 0 );
1249
1250
/* Update and commit struct to lock the userPages */
1251
oldMode = getFromTablePtr->mode;
1252
getFromTablePtr->mode = requestedMode;
1253
ret = omrvmem_commit_memory( topPageBoundary + getFromTablePtr->pageSize, userPages * getFromTablePtr->pageSize, getFromTablePtr );
1254
getFromTablePtr->mode = oldMode;
1255
if ( NULL == ret ) {
1256
return -1;
1257
}
1258
}
1259
return 0;
1260
}
1261
1262
1263
/* This method scans the entire list of allocated blocks to make sure none of the padding has been scratched.
1264
We do this on every allocate and every free to make sure we notice trashing as early as possible. If a
1265
screwed up block is detected, details are printed to the console. If possible, the scan is continued to print
1266
out other screwed up blocks. Returns FALSE if any blocks are screwed up, or TRUE if everything looks okay. */
1267
/* @internal The passed in portLib should be the memCheckPortLib with its original functions */
1268
1269
static BOOLEAN memoryCheck_scan_all_blocks(OMRPortLibrary *portLib)
1270
{
1271
J9MemoryCheckHeader *blockHeader, *prevBlockHeader;
1272
BOOLEAN everythingOkay = TRUE;
1273
char const *operationName = "scan_all_blocks";
1274
UDATA topPaddingSize = 0;
1275
UDATA bottomPaddingSize;
1276
1277
if ( !(mode & J9_MCMODE_MPROTECT) ) {
1278
/* topPaddingSize is constant with all blocks if MPROTECT is not enabled */
1279
topPaddingSize = J9_MEMCHECK_ADJUSTED_PADDING - sizeof(J9MemoryCheckHeader);
1280
}
1281
1282
if ( mode & J9_MCMODE_MPROTECT ) {
1283
/* Unlock ALL blocks */
1284
memoryCheck_lockAllBlocks( memCheckPortLib, mostRecentBlock, unlockMode, 0 );
1285
memoryCheck_lockAllBlocks( memCheckPortLib, mostRecentFreedBlock, unlockMode, 1 );
1286
}
1287
1288
for (prevBlockHeader = NULL, blockHeader = mostRecentBlock;
1289
blockHeader != NULL; prevBlockHeader = blockHeader, blockHeader = blockHeader->previousBlock) {
1290
1291
U_8 *topPadding = ((U_8 *) blockHeader) + sizeof(J9MemoryCheckHeader);
1292
U_8 *wrappedBlock;
1293
U_8 *bottomPadding;
1294
1295
if (mode & J9_MCMODE_MPROTECT) {
1296
topPaddingSize = blockHeader->wrappedBlock - topPadding;
1297
wrappedBlock = blockHeader->wrappedBlock;
1298
} else {
1299
/* topPaddingSize was already calculated above */
1300
wrappedBlock = topPadding + topPaddingSize;
1301
}
1302
1303
/* Verify top padding */
1304
if ( (mode & J9_MCMODE_MPROTECT) && !J9_ALIGN_BOTTOM ) {
1305
/* all the top padding is write protected, no point in scanning */
1306
} else {
1307
if (memoryCheck_verify_forward
1308
(portLib, topPadding, topPaddingSize, J9_MEMCHECK_DATA_PADDING_VALUE, wrappedBlock)) {
1309
if (memoryCheck_verify_forward
1310
(portLib, topPadding, topPaddingSize, J9_MEMCHECK_CODE_PADDING_VALUE, wrappedBlock)) {
1311
1312
if (blockHeader->wrappedBlockSize == J9_MEMCHECK_FREED_SIZE) {
1313
portLib->tty_printf(portLib,
1314
"ERROR: Found an already freed block %p (header at %p) on the allocated list (should never happen)!\n",
1315
wrappedBlock, blockHeader);
1316
goto describe_block_and_fail;
1317
}
1318
1319
/* Block not freed yet, but top padding at least is damaged. If the nextBlock pointer is damaged too
1320
then we assume the header is useless and we stop scanning (to reduce the chances of a GPF). */
1321
1322
if (blockHeader->nextBlock != prevBlockHeader) {
1323
portLib->tty_printf(portLib,
1324
"ERROR: Header of block at %p (header at %p) is damaged, scan stopped.\n",
1325
wrappedBlock, blockHeader);
1326
goto describe_block_and_fail;
1327
}
1328
1329
everythingOkay = FALSE;
1330
goto describe_block_and_continue;
1331
}
1332
}
1333
}
1334
1335
if (blockHeader->allocationNumber > memStats.totalBlocksAllocated) {
1336
portLib->tty_printf(portLib, "ERROR: Invalid allocation number %d in block %p (header at %p)\n",
1337
blockHeader->allocationNumber, wrappedBlock, blockHeader);
1338
goto describe_block_and_fail; /* If header is screwed then we risk a GPF by continuing.. */
1339
}
1340
1341
if (prevBlockHeader && (blockHeader->allocationNumber >= prevBlockHeader->allocationNumber)) {
1342
portLib->tty_printf(portLib, "ERROR: Allocation number %d in block %p (header at %p) should be lower than %d in block %p (header at %p)\n",
1343
blockHeader->allocationNumber, wrappedBlock, blockHeader,
1344
prevBlockHeader->allocationNumber, ((U_8 *) prevBlockHeader) + J9_MEMCHECK_ADJUSTED_PADDING, prevBlockHeader);
1345
goto describe_block_and_fail; /* If header is screwed then we risk a GPF by continuing.. */
1346
}
1347
1348
if (blockHeader->nextBlock != prevBlockHeader) {
1349
portLib->tty_printf(portLib,
1350
"ERROR: Allocated list links between %p (header at %p) and %p (header at %p) are corrupt\n",
1351
((U_8 *) prevBlockHeader) + J9_MEMCHECK_ADJUSTED_PADDING, prevBlockHeader, wrappedBlock,
1352
blockHeader);
1353
}
1354
1355
bottomPadding = wrappedBlock + blockHeader->wrappedBlockSize;
1356
1357
if ( mode & J9_MCMODE_MPROTECT ) {
1358
1359
/* Adjust bottomPadding to force it to end on a double boundary */
1360
bottomPaddingSize = blockHeader->totalAllocation - J9_MEMCHECK_PAGE_SIZE - (bottomPadding - blockHeader->topPage);
1361
} else {
1362
1363
/* Adjust bottomPadding to force it to end on a double boundary */
1364
bottomPaddingSize = J9_MEMCHECK_ADJUSTED_PADDING + BYTES_FOR_ALIGNMENT (blockHeader->wrappedBlockSize);
1365
}
1366
1367
if (memoryCheck_verify_forward
1368
(portLib, bottomPadding, bottomPaddingSize, J9_MEMCHECK_DATA_PADDING_VALUE, wrappedBlock)) {
1369
if (memoryCheck_verify_forward
1370
(portLib, bottomPadding, bottomPaddingSize, J9_MEMCHECK_CODE_PADDING_VALUE, wrappedBlock)) {
1371
1372
/* Bottom padding is damaged. */
1373
goto describe_block_and_continue;
1374
1375
}
1376
}
1377
1378
/* This block looked okay, so go back up to top of loop */
1379
continue;
1380
1381
/*
1382
* Comes here when bottom padding is damaged. But, we still
1383
* want to continue with other blocks.
1384
* TODO: Consider refactor code to avoid gotos
1385
* TODO: Why is return value from memoryCheck_describe_block() ignored?
1386
*/
1387
describe_block_and_continue:
1388
everythingOkay = FALSE;
1389
memoryCheck_describe_block(portLib, operationName, blockHeader);
1390
}
1391
1392
if (mode & J9_MCMODE_NEVER_FREE) {
1393
/* Scan all previously freed blocks too */
1394
for (prevBlockHeader = NULL, blockHeader = mostRecentFreedBlock;
1395
blockHeader != NULL; prevBlockHeader = blockHeader, blockHeader = blockHeader->previousBlock) {
1396
1397
U_8 *topPadding = ((U_8 *) blockHeader) + sizeof(J9MemoryCheckHeader);
1398
U_8 *bottomPadding, *wrappedBlock;
1399
UDATA bottomSize; /* this includes the wrappedblock plus the bottom padding */
1400
1401
if (mode & J9_MCMODE_MPROTECT) {
1402
topPaddingSize = blockHeader->wrappedBlock - topPadding;
1403
wrappedBlock = blockHeader->wrappedBlock;
1404
} else {
1405
/* topPaddingSize was already calculated above */
1406
wrappedBlock = topPadding + topPaddingSize;
1407
}
1408
1409
if ( (mode & J9_MCMODE_MPROTECT) && !J9_ALIGN_BOTTOM ) {
1410
/* all the top padding is write protected, no point in scanning */
1411
} else {
1412
if (memoryCheck_verify_forward
1413
(portLib, topPadding, topPaddingSize, J9_MEMCHECK_DATA_FREED_VALUE, wrappedBlock)) {
1414
if (memoryCheck_verify_forward
1415
(portLib, topPadding, topPaddingSize, J9_MEMCHECK_CODE_FREED_VALUE, wrappedBlock)) {
1416
1417
/* Freed block: top padding at least is damaged. If the nextBlock pointer is damaged too
1418
then we assume the header is useless and we stop scanning (to reduce the chances of a GPF). */
1419
1420
if (blockHeader->nextBlock != prevBlockHeader) {
1421
portLib->tty_printf(portLib,
1422
"ERROR: Header of previously freed block at %p (header at %p) is damaged, scan stopped.\n",
1423
wrappedBlock, blockHeader);
1424
goto describe_freed_block_and_fail;
1425
}
1426
1427
everythingOkay = FALSE;
1428
goto describe_freed_block_and_continue;
1429
}
1430
}
1431
}
1432
1433
if (blockHeader->allocationNumber > memStats.totalBlocksAllocated) {
1434
portLib->tty_printf(portLib, "ERROR: Invalid allocation number %d in previously freed block %p (header at %p)\n",
1435
blockHeader->allocationNumber, wrappedBlock, blockHeader);
1436
goto describe_freed_block_and_fail; /* If header is trashed then we risk a GPF by continuing.. */
1437
}
1438
1439
if (blockHeader->nextBlock != prevBlockHeader) {
1440
portLib->tty_printf(portLib,
1441
"ERROR: Previously freed block list links between %p (header at %p) and %p (header at %p) are corrupt\n",
1442
((U_8 *) prevBlockHeader) + J9_MEMCHECK_ADJUSTED_PADDING, prevBlockHeader, wrappedBlock,
1443
blockHeader);
1444
}
1445
1446
bottomPadding = wrappedBlock + blockHeader->wrappedBlockSize;
1447
1448
if ( mode & J9_MCMODE_MPROTECT ) {
1449
bottomPaddingSize = blockHeader->totalAllocation - J9_MEMCHECK_PAGE_SIZE - (bottomPadding - blockHeader->topPage);
1450
} else {
1451
1452
/* Adjust bottomPadding to force it to end on a double boundary */
1453
bottomPaddingSize = J9_MEMCHECK_ADJUSTED_PADDING + BYTES_FOR_ALIGNMENT (blockHeader->wrappedBlockSize);
1454
}
1455
bottomSize = bottomPaddingSize + blockHeader->wrappedBlockSize;
1456
1457
if (memoryCheck_verify_forward
1458
(portLib, wrappedBlock, bottomSize, J9_MEMCHECK_DATA_FREED_VALUE, wrappedBlock)) {
1459
if (memoryCheck_verify_forward
1460
(portLib, wrappedBlock, bottomSize, J9_MEMCHECK_CODE_FREED_VALUE, wrappedBlock)) {
1461
1462
goto describe_freed_block_and_continue;
1463
}
1464
}
1465
1466
/* this block looked okay */
1467
continue;
1468
1469
/* TODO: Why is return value from memoryCheck_describe_block() ignored? */
1470
describe_freed_block_and_continue:
1471
everythingOkay = FALSE;
1472
memoryCheck_describe_freed_block(portLib, operationName, blockHeader);
1473
}
1474
1475
}
1476
1477
if (memStats.totalBlocksFreed > memStats.totalBlocksAllocated) {
1478
/* This shouldn't happen. In order to cause it, somebody has to free garbage (or free a block twice) without
1479
this error being caught by any of the previous checks. If global variables were trashed then we would
1480
hopefully go down in flames before we got here. */
1481
1482
portLib->tty_printf(portLib, "ERROR: More blocks freed (%d) than allocated (%d)!\n",
1483
memStats.totalBlocksFreed, memStats.totalBlocksAllocated);
1484
everythingOkay = FALSE;
1485
}
1486
1487
if ( mode & J9_MCMODE_MPROTECT ) {
1488
/* Lock All the Blocks */
1489
memoryCheck_lockAllBlocks( memCheckPortLib, mostRecentBlock, lockMode, 0 );
1490
memoryCheck_lockAllBlocks( memCheckPortLib, mostRecentFreedBlock, lockMode, 1 );
1491
}
1492
return everythingOkay;
1493
1494
describe_block_and_fail:
1495
memoryCheck_describe_block(portLib, operationName, blockHeader);
1496
if ( mode & J9_MCMODE_MPROTECT ) {
1497
/* Lock All the Blocks */
1498
memoryCheck_lockAllBlocks( memCheckPortLib, mostRecentBlock, lockMode, 0 );
1499
memoryCheck_lockAllBlocks( memCheckPortLib, mostRecentFreedBlock, lockMode, 1 );
1500
}
1501
return FALSE;
1502
1503
describe_freed_block_and_fail:
1504
memoryCheck_describe_freed_block(portLib, operationName, blockHeader);
1505
if ( mode & J9_MCMODE_MPROTECT ) {
1506
/* Lock All the Blocks */
1507
memoryCheck_lockAllBlocks( memCheckPortLib, mostRecentBlock, lockMode, 0 );
1508
memoryCheck_lockAllBlocks( memCheckPortLib, mostRecentFreedBlock, lockMode, 1 );
1509
}
1510
return FALSE;
1511
}
1512
1513
1514
1515
/* @internal The passed in portLib should be the memCheckPortLib */
1516
static void *
1517
memoryCheck_wrapper_allocate_memory(OMRPortLibrary *portLib, UDATA byteAmount, char const *operationName,
1518
J9_MEM_ALLOCATE_FUNC allocator, U_32 paddingValue, U_32 fillValue,
1519
U_32 freedValue, const char *callSite, U_32 category)
1520
{
1521
U_8 *topPadding, *wrappedBlock, *bottomPadding;
1522
J9MemoryCheckHeader *blockHeader;
1523
BOOLEAN everythingOkay = TRUE;
1524
UDATA newAllocationNumber;
1525
UDATA newTotalBytesAllocated;
1526
J9PortVmemIdentifier *vmemID = NULL;
1527
U_8 *topPage = NULL; /* J9_MCMODE_MPROTECT: Points to the first page boundary in the returned data */
1528
U_8 *bottomPage = NULL; /* J9_MCMODE_MPROTECT: Points to the bottom page boundary in the returned data */
1529
UDATA topPaddingSize = 0;
1530
UDATA bottomPaddingSize = 0;
1531
UDATA allocAmount = 0;
1532
1533
MUTEX_ENTER(mcMutex);
1534
/* Disable trace to avoid deadlock between mcMutex and trace global lock. JTC-JAT 93458 */
1535
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
1536
uteInterface->server->DisableTrace(UT_DISABLE_THREAD);
1537
}
1538
1539
if (0 == (mode & J9_MCMODE_NO_SCAN) ) {
1540
1541
if ( mode & J9_MCMODE_MPROTECT ) {
1542
/* Need only allocate 1 extra page above and below b/c j9vmem always returns page aligned pointers */
1543
topPaddingSize = J9_MEMCHECK_PAGE_SIZE - sizeof(J9MemoryCheckHeader);
1544
bottomPaddingSize = J9_MEMCHECK_PAGE_SIZE;
1545
allocAmount = sizeof(J9MemoryCheckHeader) + topPaddingSize + (byteAmount/J9_MEMCHECK_PAGE_SIZE)*J9_MEMCHECK_PAGE_SIZE +
1546
(byteAmount%J9_MEMCHECK_PAGE_SIZE ? 1 : 0 )*J9_MEMCHECK_PAGE_SIZE + bottomPaddingSize;
1547
} else {
1548
1549
/* Adjust bottomPadding to force it to end on a double boundary */
1550
bottomPaddingSize = J9_MEMCHECK_ADJUSTED_PADDING + BYTES_FOR_ALIGNMENT (byteAmount);
1551
topPaddingSize = J9_MEMCHECK_ADJUSTED_PADDING - sizeof(J9MemoryCheckHeader);
1552
allocAmount = sizeof(J9MemoryCheckHeader) + topPaddingSize + byteAmount + bottomPaddingSize;
1553
}
1554
1555
newAllocationNumber = memStats.totalBlocksAllocated+1;
1556
newTotalBytesAllocated = memStats.currentBytesAllocated + byteAmount;
1557
1558
if ((mode & J9_MCMODE_SKIP_TO) && (newAllocationNumber < skipToAlloc)) {
1559
/* We aren't interested in scanning anything yet. */
1560
} else {
1561
if (mode & J9_MCMODE_FULL_SCANS) {
1562
everythingOkay = memoryCheck_scan_all_blocks(portLib);
1563
} else { /* quick mode - just check most recently allocated block */
1564
if (mostRecentBlock) {
1565
J9_MEMCHECK_UNLOCK( mostRecentBlock );
1566
everythingOkay = memoryCheck_scan_block(portLib, mostRecentBlock);
1567
J9_MEMCHECK_LOCK( mostRecentBlock );
1568
}
1569
}
1570
}
1571
if (!everythingOkay) {
1572
memoryCheck_abort(portLib);
1573
}
1574
1575
if ((mode & J9_MCMODE_FAIL_AT) && (newAllocationNumber >= failAtAlloc)) {
1576
++memStats.failedAllocs;
1577
if ((memStats.totalBlocksAllocated+memStats.failedAllocs) == failAtAlloc) {
1578
portLib->tty_printf(portLib, "WARNING: failat: Returning NULL for allocation attempt %d in %s at %s (%d bytes were requested)\n",
1579
(memStats.totalBlocksAllocated+memStats.failedAllocs), operationName, callSite, byteAmount);
1580
portLib->tty_printf(portLib, " All subsequent memory allocation attempt will be failed intentionally\n");
1581
}
1582
1583
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
1584
uteInterface->server->EnableTrace(UT_ENABLE_THREAD);
1585
}
1586
MUTEX_EXIT(mcMutex);
1587
return NULL;
1588
}
1589
if ((mode & J9_MCMODE_LIMIT) && (newTotalBytesAllocated > limitAlloc)) {
1590
if (memStats.currentBytesAllocated <= limitAlloc) {
1591
portLib->tty_printf(portLib, "WARNING: limit: Returning NULL for attempt to allocate %d bytes in %s at %s (%d bytes already allocated)\n",
1592
byteAmount, operationName, callSite, memStats.currentBytesAllocated);
1593
portLib->tty_printf(portLib, " All subsequent memory allocation attempt will be failed intentionally\n");
1594
}
1595
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
1596
uteInterface->server->EnableTrace(UT_ENABLE_THREAD);
1597
}
1598
MUTEX_EXIT(mcMutex);
1599
return NULL;
1600
}
1601
1602
if ( 0 == (mode & J9_MCMODE_MPROTECT) ) {
1603
#if defined (WIN32) && !defined(BREW)
1604
if (mode & J9_MCMODE_TOP_DOWN) {
1605
topPadding = VirtualAlloc(NULL, allocAmount, MEM_COMMIT | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE);
1606
} else {
1607
/* The portLib being used here is the memCheckPortLib, not the user portLib */
1608
topPadding = allocator(portLib, allocAmount, callSite, category);
1609
}
1610
#else
1611
/* The portLib being used here is the memCheckPortLib, not the user portLib */
1612
topPadding = allocator(portLib, allocAmount, callSite, category);
1613
#endif
1614
if (!topPadding) {
1615
++memStats.failedAllocs;
1616
portLib->tty_printf(portLib, "WARNING: Out of memory in %s at %s, returning NULL (%d bytes were requested)\n",
1617
operationName, callSite, byteAmount);
1618
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
1619
uteInterface->server->EnableTrace(UT_ENABLE_THREAD);
1620
}
1621
MUTEX_EXIT(mcMutex);
1622
return NULL;
1623
}
1624
blockHeader = (J9MemoryCheckHeader *) topPadding;
1625
topPadding += sizeof(J9MemoryCheckHeader);
1626
wrappedBlock = topPadding + topPaddingSize;
1627
bottomPadding = wrappedBlock + byteAmount;
1628
/* zero out the header */
1629
memset(blockHeader, 0, sizeof(J9MemoryCheckHeader));
1630
1631
} else {
1632
/* we're in mode = J9_MCMODE_MPROTECT */
1633
/* Allocate the structure.
1634
* NOTE: memCheckPortLib->mem_allocate_memory is the "allocator" function (because we can't be
1635
* using the subAllocator in conjunction with mode J9_MCMODE_MPROTECT).
1636
* making it clear that we are using memCheckPortLib->mem_allocate_memory here because the
1637
* corresponding free is done using memCheckPortLib->mem_free_memory (and we don't want to pass in
1638
* a deallocator to memoryCheck_wrapper_allocate_memory
1639
*/
1640
vmemID = memCheckPortLib->mem_allocate_memory( memCheckPortLib, sizeof(J9PortVmemIdentifier), callSite, OMRMEM_CATEGORY_VM);
1641
if (NULL == vmemID) {
1642
++memStats.failedAllocs;
1643
portLib->tty_printf(portLib, "WARNING: J9PortVmemIdentifier struct could not be allocated!\n"
1644
"WARNING: Out of memory in %s at %s, returning NULL (%d bytes were requested)\n",
1645
operationName, callSite, byteAmount);
1646
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
1647
uteInterface->server->EnableTrace(UT_ENABLE_THREAD);
1648
}
1649
MUTEX_EXIT(mcMutex);
1650
return NULL;
1651
}
1652
/* Reserve and Commit the memory - Pointer is page aligned by j9vmem. Do NOT use the J9_MEMCHECK_PAGE_SIZE
1653
* macro for the pageSize parameter to this function call only! The macro may return a multiple of the system page size
1654
* due to the default implementation of j9vmem using sizeof(UDATA) as a pagesize.
1655
*/
1656
topPage = memCheckPortLib->vmem_reserve_memory( memCheckPortLib, NULL, allocAmount, vmemID, allocateMode,
1657
memCheckPortLib->vmem_supported_page_sizes( memCheckPortLib )[0], category );
1658
1659
if (!topPage) {
1660
++memStats.failedAllocs;
1661
portLib->tty_printf(portLib, "WARNING: Out of memory in %s at %s, returning NULL (%d bytes were requested)\n",
1662
operationName, callSite, byteAmount);
1663
memCheckPortLib->mem_free_memory( memCheckPortLib, vmemID );
1664
vmemID = NULL;
1665
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
1666
uteInterface->server->EnableTrace(UT_ENABLE_THREAD);
1667
}
1668
MUTEX_EXIT(mcMutex);
1669
return NULL;
1670
}
1671
1672
/* Add the vmemID to the hashTable */
1673
if ( !hashTableAdd( vmemIDTable, &vmemID ) ){
1674
memCheckPortLib->vmem_free_memory( memCheckPortLib, vmemID->address, vmemID->size, vmemID );
1675
memCheckPortLib->mem_free_memory( memCheckPortLib, vmemID );
1676
vmemID = NULL;
1677
++memStats.failedAllocs;
1678
portLib->tty_printf(portLib, "WARNING: Unable to add vmemID to hashTable! In %s, returning NULL (%d bytes were requested)\n",
1679
operationName, byteAmount);
1680
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
1681
uteInterface->server->EnableTrace(UT_ENABLE_THREAD);
1682
}
1683
MUTEX_EXIT(mcMutex);
1684
return NULL;
1685
}
1686
1687
blockHeader = (J9MemoryCheckHeader *) topPage;
1688
blockHeader->self = topPage; /* Grab the malloc'd ptr for calls to free */
1689
/* TODO - why is the page size not the same as what was used in vmem_reserve_memory ? */
1690
wrappedBlock = topPage + J9_MEMCHECK_PAGE_SIZE;
1691
topPadding = (U_8*)blockHeader + sizeof(J9MemoryCheckHeader);
1692
bottomPadding = wrappedBlock + byteAmount;
1693
bottomPage = wrappedBlock + (byteAmount/J9_MEMCHECK_PAGE_SIZE)*J9_MEMCHECK_PAGE_SIZE + (byteAmount % J9_MEMCHECK_PAGE_SIZE ? 1 : 0)*J9_MEMCHECK_PAGE_SIZE;
1694
1695
/* Set it to unlocked */
1696
blockHeader->isLocked = 0;
1697
blockHeader->totalAllocation = allocAmount;
1698
blockHeader->topPage = topPage;
1699
blockHeader->wrappedBlock = wrappedBlock;
1700
blockHeader->bottomPage = bottomPage;
1701
blockHeader->wrappedBlockSize = byteAmount;
1702
1703
/* adjust the user pointer the location of the struct. This adjustment only needs to be made if the
1704
* data is to be aligned on the bottom page
1705
*/
1706
if ( J9_ALIGN_BOTTOM ) {
1707
U_32 offsetArea;
1708
/*
1709
* TOP and BOTTOM locked pages don't move, just adjust the data between them and the
1710
* other pointers into the memory. The blockHeader will always be 1 J9_MEMCHECK_PAGE_SIZE above
1711
* the wrappedBlock
1712
*/
1713
offsetArea = BYTES_FOR_ALIGNMENT (byteAmount);
1714
wrappedBlock = bottomPage - byteAmount - offsetArea;
1715
blockHeader->wrappedBlock = wrappedBlock;
1716
/* Ensure header fits entirely in topPage */
1717
if ( wrappedBlock - J9_MEMCHECK_PAGE_SIZE + sizeof(J9MemoryCheckHeader) > topPage + J9_MEMCHECK_PAGE_SIZE ) {
1718
memmove( wrappedBlock - J9_MEMCHECK_PAGE_SIZE - sizeof(J9MemoryCheckHeader), blockHeader, sizeof(J9MemoryCheckHeader) );
1719
blockHeader = (J9MemoryCheckHeader *)(wrappedBlock - J9_MEMCHECK_PAGE_SIZE - sizeof(J9MemoryCheckHeader) );
1720
}
1721
else {
1722
memmove( wrappedBlock - J9_MEMCHECK_PAGE_SIZE, blockHeader, sizeof(J9MemoryCheckHeader) );
1723
blockHeader = (J9MemoryCheckHeader *)(wrappedBlock - J9_MEMCHECK_PAGE_SIZE );
1724
}
1725
topPadding = (U_8 *)blockHeader + sizeof(J9MemoryCheckHeader);
1726
bottomPadding = wrappedBlock + byteAmount;
1727
}
1728
} /* J9_MCMODE_MPROTECT */
1729
1730
if ( !(mode & J9_MCMODE_MPROTECT) ) {
1731
if ((mode & J9_MCMODE_SKIP_TO) && (newAllocationNumber < skipToAlloc)) {
1732
/* We aren't interested in having blocks filled with padding yet. */
1733
} else {
1734
memoryCheck_fill_bytes(portLib, topPadding, topPaddingSize, paddingValue, wrappedBlock);
1735
memoryCheck_fill_bytes(portLib, bottomPadding, bottomPaddingSize, paddingValue, wrappedBlock);
1736
if (mode & J9_MCMODE_ZERO) {
1737
memset(wrappedBlock, 0, byteAmount);
1738
} else {
1739
memoryCheck_fill_bytes(portLib, wrappedBlock, byteAmount, fillValue, wrappedBlock);
1740
}
1741
}
1742
} else {
1743
if ((mode & J9_MCMODE_SKIP_TO) && (newAllocationNumber < skipToAlloc)) {
1744
/* We aren't interested in having blocks filled with padding yet. */
1745
} else {
1746
/* Extra padding above */
1747
if ( blockHeader->self != blockHeader->topPage ) {
1748
memoryCheck_fill_bytes(portLib, blockHeader->self, blockHeader->topPage - blockHeader->self, paddingValue, wrappedBlock);
1749
}
1750
/* Normal top Padding */
1751
memoryCheck_fill_bytes(portLib, topPadding, wrappedBlock - topPadding, paddingValue, wrappedBlock);
1752
/* Extra padding below */
1753
memoryCheck_fill_bytes(portLib, bottomPadding, allocAmount - (bottomPadding - blockHeader->self), paddingValue, wrappedBlock);
1754
if (mode & J9_MCMODE_ZERO) {
1755
memset(wrappedBlock, 0, byteAmount );
1756
} else {
1757
memoryCheck_fill_bytes(portLib, wrappedBlock, byteAmount, fillValue, wrappedBlock);
1758
}
1759
}
1760
}
1761
1762
/* Recompute the allocation number, in case we have been called recursively (due to tracing, for example). */
1763
newAllocationNumber = memStats.totalBlocksAllocated + 1;
1764
1765
#ifdef J9VM_MEMCHK_SIM_SUP
1766
if (mode & J9_MCMODE_SIMULATE) {
1767
portLib->tty_printf(portLib, "void * BLOCK_%d; %s\n", newAllocationNumber, SIM_TAG);
1768
portLib->tty_printf(portLib, "BLOCK_%d = j9mem_allocate_memory(%d); %s\n", newAllocationNumber, byteAmount, SIM_TAG);
1769
}
1770
#endif
1771
1772
} else {
1773
/* (mode & J9_MCMODE_NO_SCAN) */
1774
U_8 * blockStart;
1775
1776
newAllocationNumber = memStats.totalBlocksAllocated + 1;
1777
if ((mode & J9_MCMODE_FAIL_AT) && (newAllocationNumber >= failAtAlloc)) {
1778
++memStats.failedAllocs;
1779
if ((memStats.totalBlocksAllocated+memStats.failedAllocs) == failAtAlloc) {
1780
portLib->tty_printf(portLib, "WARNING: failat: Returning NULL for allocation attempt %d in %s at %s (%d bytes were requested)\n",
1781
(memStats.totalBlocksAllocated+memStats.failedAllocs), operationName, callSite, byteAmount);
1782
portLib->tty_printf(portLib, " All subsequent memory allocation attempt will be failed intentionally\n");
1783
}
1784
1785
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
1786
uteInterface->server->EnableTrace(UT_ENABLE_THREAD);
1787
}
1788
MUTEX_EXIT(mcMutex);
1789
return NULL;
1790
}
1791
1792
allocAmount = sizeof(J9MemoryCheckHeader) + byteAmount;
1793
blockStart = allocator(portLib, allocAmount, callSite, category);
1794
1795
if (NULL == blockStart) {
1796
portLib->tty_printf(portLib, "WARNING: Out of memory in %s at %s, returning NULL (%d bytes were requested)\n",
1797
operationName, callSite, byteAmount);
1798
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
1799
uteInterface->server->EnableTrace(UT_ENABLE_THREAD);
1800
}
1801
MUTEX_EXIT(mcMutex);
1802
return NULL;
1803
}
1804
1805
blockHeader = (J9MemoryCheckHeader *) blockStart;
1806
/* zero out the header */
1807
memset(blockHeader, 0, sizeof(J9MemoryCheckHeader));
1808
1809
wrappedBlock = blockStart + sizeof(J9MemoryCheckHeader);
1810
blockHeader->wrappedBlock = wrappedBlock;
1811
blockHeader->wrappedBlockSize = byteAmount;
1812
1813
if (mode & J9_MCMODE_ZERO) {
1814
memset(wrappedBlock, 0, byteAmount );
1815
}
1816
1817
/* Recompute the allocation number, in case we have been called recursively (due to tracing, for example). */
1818
newAllocationNumber = memStats.totalBlocksAllocated + 1;
1819
1820
} /* (mode & J9_MCMODE_NO_SCAN) */
1821
1822
++memStats.totalBlocksAllocated;
1823
blockHeader->wrappedBlockSize = byteAmount;
1824
blockHeader->allocationNumber = newAllocationNumber;
1825
memStats.totalBytesAllocated += byteAmount;
1826
memStats.currentBlocksAllocated += 1;
1827
if (memStats.currentBlocksAllocated > memStats.hiWaterBlocksAllocated) {
1828
memStats.hiWaterBlocksAllocated = memStats.currentBlocksAllocated;
1829
}
1830
memStats.currentBytesAllocated += byteAmount;
1831
if (memStats.currentBytesAllocated > memStats.hiWaterBytesAllocated) {
1832
memStats.hiWaterBytesAllocated = memStats.currentBytesAllocated;
1833
}
1834
if (byteAmount > memStats.largestBlockAllocated) {
1835
memStats.largestBlockAllocated = byteAmount;
1836
memStats.largestBlockAllocNum = newAllocationNumber;
1837
}
1838
1839
blockHeader->nextBlock = NULL;
1840
if ((mode & J9_MCMODE_SKIP_TO) && (newAllocationNumber < skipToAlloc)) {
1841
/* We don't want this block on the allocated list - no padding or verifying it. */
1842
blockHeader->previousBlock = NULL;
1843
} else {
1844
blockHeader->previousBlock = mostRecentBlock;
1845
if (mostRecentBlock) {
1846
J9_MEMCHECK_UNLOCK( mostRecentBlock );
1847
mostRecentBlock->nextBlock = blockHeader;
1848
J9_MEMCHECK_LOCK( mostRecentBlock );
1849
}
1850
mostRecentBlock = blockHeader;
1851
}
1852
1853
if( avl_tree ) {
1854
memoryCheck_update_callSites_allocate(portLib, blockHeader, callSite, byteAmount);
1855
if( (mode & J9_MCMODE_PRINT_CALLSITES) || (mode & J9_MCMODE_PRINT_CALLSITES_SMALL) ) {
1856
if(memStats.totalBlocksAllocated % callSitePrintCount == 0) {
1857
if (mode & J9_MCMODE_PRINT_CALLSITES) {
1858
memoryCheck_dump_callSites(portLib, avl_tree);
1859
} else if (mode & J9_MCMODE_PRINT_CALLSITES_SMALL) {
1860
memoryCheck_dump_callSites_small(portLib, avl_tree);
1861
}
1862
}
1863
}
1864
}
1865
1866
J9_MEMCHECK_LOCK( blockHeader );
1867
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
1868
uteInterface->server->EnableTrace(UT_ENABLE_THREAD);
1869
}
1870
MUTEX_EXIT(mcMutex);
1871
return wrappedBlock;
1872
}
1873
1874
1875
/* @internal The passed in portLib should be the memCheckPortLib */
1876
static void
1877
memoryCheck_wrapper_free_memory(OMRPortLibrary *portLib, void *memoryPointer, char const *operationName,
1878
J9_MEM_FREE_FUNC deallocator, U_32 paddingValue, U_32 fillValue,
1879
U_32 freedValue)
1880
{
1881
J9MemoryCheckHeader *listBlockHeader, *topHeader;
1882
UDATA topPaddingSize = 0;
1883
UDATA bottomPaddingSize = 0;
1884
U_8 *topPadding = NULL;
1885
U_8 *wrappedBlock;
1886
BOOLEAN listHeadersAndPaddingOkay = TRUE;
1887
BOOLEAN currentBlockOkay = TRUE;
1888
BOOLEAN blockWasSkipped = FALSE;
1889
J9PortVmemIdentifier getFromTable; /* stack allocated object to index into hashTable */
1890
J9PortVmemIdentifier *getFromTablePtr = NULL;
1891
J9PortVmemIdentifier **vmemID = NULL;
1892
1893
MUTEX_ENTER(mcMutex);
1894
/* Disable trace to avoid deadlock between mcMutex and trace global lock. JTC-JAT 93458 */
1895
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
1896
uteInterface->server->DisableTrace(UT_DISABLE_THREAD);
1897
}
1898
1899
if (memoryPointer == NULL) {
1900
if (0 == (mode & J9_MCMODE_NO_SCAN)) {
1901
memoryCheck_scan_all_blocks(portLib); /* just in case */
1902
} else {
1903
/* J9_MCMODE_NO_SCAN - don't scan! */
1904
}
1905
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
1906
uteInterface->server->EnableTrace(UT_ENABLE_THREAD);
1907
}
1908
MUTEX_EXIT(mcMutex);
1909
return;
1910
}
1911
1912
if (0 == (mode & J9_MCMODE_NO_SCAN) ) {
1913
1914
if ( !(mode & J9_MCMODE_MPROTECT) ) {
1915
topPaddingSize = J9_MEMCHECK_ADJUSTED_PADDING - sizeof(J9MemoryCheckHeader);
1916
} else {
1917
topPaddingSize = J9_MEMCHECK_PAGE_SIZE - sizeof(J9MemoryCheckHeader);
1918
}
1919
1920
wrappedBlock = (U_8 *) memoryPointer;
1921
topPadding = wrappedBlock - topPaddingSize;
1922
topHeader = (J9MemoryCheckHeader *) (topPadding - sizeof(J9MemoryCheckHeader));
1923
1924
if ( mode & J9_MCMODE_MPROTECT ) {
1925
/* Find the J9MemoryCheckHeader in the guardPage */
1926
topHeader = (J9MemoryCheckHeader *)(wrappedBlock - J9_MEMCHECK_PAGE_SIZE);
1927
1928
#if defined(J9ZOS390)
1929
/* if unlocking fails subtract sizeof(J9MemoryCheckHeader) from topHeader and try again*/
1930
if (memoryCheck_lockGuardPages( memCheckPortLib, topHeader, J9_MEMCHECK_PAGE_SIZE, unlockMode ) != 0) {
1931
topHeader = (J9MemoryCheckHeader *)((U_8 *)topHeader - sizeof(J9MemoryCheckHeader));
1932
J9_MEMCHECK_UNLOCK( topHeader );
1933
} else {
1934
/* We must set to unlocked here because we did not call the J9_MEMCHECK_UNLOCK() macro */
1935
topHeader->isLocked = 0;
1936
}
1937
topPadding = (U_8 *)topHeader + sizeof(J9MemoryCheckHeader);
1938
#else
1939
/* adjust pointer to the header because the header will be stored so that it is entirely in the guard page */
1940
if ( ( ((UDATA)topHeader & 0XF000) != ((UDATA)((U_8 *)topHeader + sizeof(J9MemoryCheckHeader)) & 0XF000) ) ) {
1941
if ( (UDATA)((U_8*)topHeader + sizeof(J9MemoryCheckHeader)) % J9_MEMCHECK_PAGE_SIZE != 0 ) {
1942
topHeader = (J9MemoryCheckHeader *)((U_8 *)topHeader - sizeof(J9MemoryCheckHeader));
1943
}
1944
}
1945
1946
topPadding = (U_8 *)topHeader + sizeof(J9MemoryCheckHeader);
1947
J9_MEMCHECK_UNLOCK( topHeader );
1948
#endif
1949
1950
}
1951
1952
#ifdef J9VM_MEMCHK_SIM_SUP
1953
if (mode & J9_MCMODE_SIMULATE) {
1954
portLib->tty_printf(portLib, "j9mem_free_memory(BLOCK_%d); %s\n", topHeader->allocationNumber, SIM_TAG);
1955
}
1956
#endif
1957
1958
if (mode & J9_MCMODE_SKIP_TO) {
1959
/* We must trust the allocation number in the header, to know if the block was
1960
considered interesting or not when it was allocated. */
1961
if (topHeader->allocationNumber < skipToAlloc) {
1962
blockWasSkipped = TRUE;
1963
goto found_block;
1964
}
1965
}
1966
1967
currentBlockOkay = memoryCheck_scan_block(portLib, topHeader);
1968
1969
if ( (mode & J9_MCMODE_FULL_SCANS) || (!currentBlockOkay) ) {
1970
/* The current block could be an unknown block, but before we check to see if the block is on the allocate list
1971
* we have to scan all blocks to make sure the list is not trashed */
1972
/* scan all blocks expects all blocks to be locked and returns them as all locked */
1973
J9_MEMCHECK_LOCK( topHeader);
1974
listHeadersAndPaddingOkay = memoryCheck_scan_all_blocks(portLib);
1975
J9_MEMCHECK_UNLOCK(topHeader);
1976
} else { /* quick mode */
1977
if (mostRecentBlock) {
1978
/* memoryCheck_scan_block expects the block to be unlocked */
1979
J9_MEMCHECK_UNLOCK( mostRecentBlock );
1980
listHeadersAndPaddingOkay = memoryCheck_scan_block(portLib, mostRecentBlock);
1981
J9_MEMCHECK_LOCK(mostRecentBlock);
1982
}
1983
}
1984
if (!listHeadersAndPaddingOkay) {
1985
memoryCheck_abort(portLib);
1986
}
1987
1988
if ( (mode & J9_MCMODE_FULL_SCANS) || (!currentBlockOkay && listHeadersAndPaddingOkay) ) {
1989
/* Walk the allocated list to make sure this block is on it. If not, then we're either freeing random garbage or
1990
this block has already been freed, or this block was not allocated by the port library */
1991
1992
J9_MEMCHECK_LOCK( topHeader );
1993
listBlockHeader = mostRecentBlock;
1994
J9_MEMCHECK_UNLOCK( listBlockHeader );
1995
1996
while ( listBlockHeader ) {
1997
if (listBlockHeader == topHeader) {
1998
J9_MEMCHECK_UNLOCK( topHeader );
1999
goto found_block;
2000
}
2001
if ( listBlockHeader->previousBlock ) {
2002
J9_MEMCHECK_UNLOCK( listBlockHeader->previousBlock );
2003
listBlockHeader = listBlockHeader->previousBlock;
2004
if (listBlockHeader->nextBlock ) {
2005
J9_MEMCHECK_LOCK( listBlockHeader->nextBlock );
2006
}
2007
} else {
2008
break;
2009
}
2010
}
2011
2012
J9_MEMCHECK_LOCK( listBlockHeader );
2013
J9_MEMCHECK_UNLOCK( topHeader );
2014
if (mode & J9_MCMODE_IGNORE_UNKNOWN_BLOCKS) {
2015
/* ignore this block and return*/
2016
portLib->tty_printf(portLib, "WARNING: Tried %s on %p (header at %p), but block is not on the allocated list.\n",
2017
operationName, wrappedBlock, topHeader);
2018
memStats.totalUnknownBlocksIgnored++;
2019
J9_MEMCHECK_LOCK( topHeader );
2020
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
2021
uteInterface->server->EnableTrace(UT_ENABLE_THREAD);
2022
}
2023
MUTEX_EXIT(mcMutex);
2024
return;
2025
} else {
2026
portLib->tty_printf(portLib, "ERROR: Tried %s on %p (header at %p), but block is not on the allocated list\n",
2027
operationName, wrappedBlock, topHeader);
2028
goto describe_block_and_fail;
2029
}
2030
} else {
2031
/* Quick mode: Don't walk allocated list, just rely on scanning the block to catch freeing errors. */
2032
J9_MEMCHECK_UNLOCK( topHeader );
2033
}
2034
found_block:
2035
2036
/* Adjust bottomPadding to force it to end on a double boundary */
2037
bottomPaddingSize = J9_MEMCHECK_ADJUSTED_PADDING + BYTES_FOR_ALIGNMENT (topHeader->wrappedBlockSize);
2038
2039
} else {
2040
/* we are in J9_MCMODE_NO_SCAN mode */
2041
wrappedBlock = (U_8 *) memoryPointer;
2042
topHeader = (J9MemoryCheckHeader *) (wrappedBlock - sizeof(J9MemoryCheckHeader));
2043
2044
} /* ( 0 == (mode & J9_MCMODE_NO_SCAN)) */
2045
2046
/* So we scanned it before (unless we were in J9_MCMODE_NO_SCAN mode)
2047
* and it looked okay, unlink the block.. */
2048
if (mostRecentBlock == topHeader) {
2049
mostRecentBlock = topHeader->previousBlock;
2050
}
2051
if (topHeader->nextBlock) {
2052
J9_MEMCHECK_UNLOCK( topHeader->nextBlock );
2053
topHeader->nextBlock->previousBlock = topHeader->previousBlock;
2054
J9_MEMCHECK_LOCK( topHeader->nextBlock );
2055
}
2056
if (topHeader->previousBlock) {
2057
J9_MEMCHECK_UNLOCK( topHeader->previousBlock );
2058
topHeader->previousBlock->nextBlock = topHeader->nextBlock;
2059
J9_MEMCHECK_LOCK( topHeader->previousBlock );
2060
}
2061
topHeader->previousBlock = topHeader->nextBlock = NULL;
2062
2063
if (!blockWasSkipped) {
2064
if ( mode & J9_MCMODE_MPROTECT ) {
2065
if ( J9_ALIGN_BOTTOM ) {
2066
if (topHeader->self != topHeader->topPage ) {
2067
memoryCheck_fill_bytes(portLib, topHeader->self, topHeader->topPage - topHeader->self, freedValue, wrappedBlock);
2068
}
2069
}
2070
memoryCheck_fill_bytes(portLib, topPadding, topHeader->totalAllocation - ((UDATA)topPadding - (UDATA)topHeader->self),
2071
freedValue, wrappedBlock);
2072
} else if (0 == (mode & J9_MCMODE_NO_SCAN)) {
2073
memoryCheck_fill_bytes(portLib, topPadding, topPaddingSize + topHeader->wrappedBlockSize + bottomPaddingSize,
2074
freedValue, wrappedBlock);
2075
}
2076
}
2077
2078
memStats.totalBlocksFreed += 1;
2079
memStats.totalBytesFreed += topHeader->wrappedBlockSize;
2080
memStats.currentBytesAllocated -= topHeader->wrappedBlockSize;
2081
memStats.currentBlocksAllocated -= 1;
2082
2083
/* update the J9MEMAVLTreeNode responsible for this memory block */
2084
memoryCheck_update_callSites_free(topHeader->node, topHeader->wrappedBlockSize);
2085
2086
if (!blockWasSkipped && (mode & J9_MCMODE_NEVER_FREE)) {
2087
/* Block was painted with recognizable contents above. */
2088
/* Put block on freed list. */
2089
topHeader->previousBlock = mostRecentFreedBlock;
2090
if (mostRecentFreedBlock) {
2091
J9_MEMCHECK_UNLOCK( mostRecentFreedBlock);
2092
mostRecentFreedBlock->nextBlock = topHeader;
2093
J9_MEMCHECK_LOCK( mostRecentFreedBlock);
2094
}
2095
mostRecentFreedBlock = topHeader;
2096
2097
/* Lock the data area of the block */
2098
J9_MEMCHECK_UNLOCK( topHeader);
2099
J9_MEMCHECK_LOCK_BODY( topHeader );
2100
J9_MEMCHECK_LOCK( topHeader);
2101
} else {
2102
topHeader->wrappedBlockSize = J9_MEMCHECK_FREED_SIZE;
2103
if ( !(mode & J9_MCMODE_MPROTECT) ) {
2104
#if defined (WIN32) && !defined(BREW)
2105
if (mode & J9_MCMODE_TOP_DOWN) {
2106
VirtualFree(topHeader, 0, MEM_RELEASE);
2107
} else {
2108
/* The portLib being used here is the memCheckPortLib, not the user portLib */
2109
deallocator(portLib, topHeader);
2110
}
2111
#else
2112
/* The portLib being used here is the memCheckPortLib, not the user portLib */
2113
deallocator(portLib, topHeader);
2114
#endif
2115
} else { /* J9_MCMODE_MPROTECT */
2116
/* Create a J9PortVmemIdentifier with the correct address, that can be used to get the right object from the hashTable */
2117
getFromTable.address = topHeader->self;
2118
getFromTablePtr = &getFromTable;
2119
2120
/* Remove from the vmemIDTable and release the vmem */
2121
vmemID = (J9PortVmemIdentifier **)hashTableFind( vmemIDTable, &getFromTablePtr );
2122
if ( vmemID ) {
2123
J9PortVmemIdentifier *realVmemID = *vmemID;
2124
2125
hashTableRemove( vmemIDTable, &getFromTablePtr );
2126
memCheckPortLib->vmem_free_memory( memCheckPortLib, realVmemID->address, realVmemID->size, realVmemID );
2127
memCheckPortLib->mem_free_memory( memCheckPortLib, realVmemID );
2128
}
2129
}
2130
}
2131
2132
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
2133
uteInterface->server->EnableTrace(UT_ENABLE_THREAD);
2134
}
2135
MUTEX_EXIT(mcMutex);
2136
return;
2137
2138
describe_block_and_fail:
2139
memoryCheck_describe_block(portLib, operationName, topHeader);
2140
memoryCheck_abort(portLib);
2141
}
2142
2143
2144
2145
/* This method formats and prints the contents of the indicated region to the console.
2146
*
2147
* @internal The portlibrary passed in should always be the memCheckPortLib
2148
*/
2149
static void
2150
memoryCheck_dump_bytes(OMRPortLibrary *portLib, void *dumpAddress, UDATA dumpSize)
2151
{
2152
U_8 *c;
2153
UDATA digit;
2154
UDATA column = 0;
2155
char buffer[128];
2156
char *bufp, *asciip;
2157
UDATA address;
2158
UDATA skipCols = ((UDATA) dumpAddress) & 15;
2159
2160
for (c = (U_8 *) dumpAddress; c < ((U_8 *) dumpAddress) + dumpSize; c++) {
2161
if (column == 0) {
2162
memset(buffer, ' ', sizeof(buffer));
2163
address = (UDATA) c & ~15;
2164
digit = sizeof(UDATA) * 2;
2165
bufp = buffer + digit;
2166
asciip = buffer + digit + (16 * 3) + 3;
2167
*bufp++ = ':';
2168
while (digit--) {
2169
buffer[digit] = hexd[address & 15];
2170
address >>= 4;
2171
}
2172
}
2173
while (skipCols) {
2174
bufp++;
2175
*bufp++ = '-';
2176
bufp++;
2177
asciip++;
2178
column++;
2179
skipCols--;
2180
}
2181
*bufp++ = ' ';
2182
*bufp++ = hexd[((*c) >> 4) & 15];
2183
*bufp++ = hexd[(*c) & 15];
2184
*asciip++ = (*c >= ' ' && *c <= '~') ? *c : '.';
2185
2186
if (++column >= 16) {
2187
column = 0;
2188
*asciip++ = '\n';
2189
*asciip++ = '\0';
2190
portLib->tty_printf(portLib, "%s", buffer);
2191
}
2192
}
2193
if (column != 0) {
2194
*asciip++ = '\n';
2195
*asciip = '\0';
2196
/*increment asciip here if it needs to be used further*/
2197
portLib->tty_printf(portLib, "%s", buffer);
2198
}
2199
}
2200
2201
2202
/**
2203
* @param portLib The "memCheckPortLib" with its original functions is the one that should be used here (I think that should read:
2204
* ""memCheckPortLib" should be passed into this function "
2205
*/
2206
static void
2207
memoryCheck_print_stats(OMRPortLibrary *portLib)
2208
{
2209
portLib->tty_printf(portLib, "Memory checker statistics:\n");
2210
portLib->tty_printf(portLib, "Total blocks allocated = %u ( = most recent allocationNumber)\n", memStats.totalBlocksAllocated);
2211
portLib->tty_printf(portLib, "Total blocks freed = %u\n", memStats.totalBlocksFreed);
2212
portLib->tty_printf(portLib, "Total bytes allocated = %llu\n", memStats.totalBytesAllocated);
2213
portLib->tty_printf(portLib, "Total bytes freed = %llu\n", memStats.totalBytesFreed);
2214
portLib->tty_printf(portLib, "Total unknown blocks ignored = %u\n", memStats.totalUnknownBlocksIgnored);
2215
portLib->tty_printf(portLib, "High water blocks allocated = %u\n", memStats.hiWaterBlocksAllocated);
2216
portLib->tty_printf(portLib, "High water bytes allocated = %u\n", memStats.hiWaterBytesAllocated);
2217
portLib->tty_printf(portLib, "Largest block ever allocated = size %u, allocation number %u\n",
2218
memStats.largestBlockAllocated, memStats.largestBlockAllocNum);
2219
portLib->tty_printf(portLib, "Failed allocation attempts = %u\n", memStats.failedAllocs);
2220
}
2221
2222
/* This method scans a single block and returns FALSE if it is damaged or TRUE if everything looks okay.
2223
This method does not check links to/from neighboring blocks. If any damage is detected in the block, then
2224
memoryCheck_scan_all_blocks will be run to detect and print out as much damage as it can, and then FALSE
2225
will be returned. Otherwise, this method will return TRUE. */
2226
/*@precondition: The block must be UNLOCKED
2227
* @internal The portLibrary used must be the memCheckPortLib
2228
*/
2229
static BOOLEAN
2230
memoryCheck_scan_block(OMRPortLibrary *portLib, J9MemoryCheckHeader *blockHeader)
2231
{
2232
BOOLEAN everythingOkay = TRUE;
2233
char const *operationName = "scan_block";
2234
UDATA topPaddingSize = 0;
2235
UDATA bottomPaddingSize;
2236
U_8 *wrappedBlock;
2237
2238
U_8 *topPadding = ((U_8 *) blockHeader) + sizeof(J9MemoryCheckHeader);
2239
U_8 *bottomPadding;
2240
2241
if (mode & J9_MCMODE_MPROTECT) {
2242
topPaddingSize = blockHeader->wrappedBlock - topPadding;
2243
wrappedBlock = blockHeader->wrappedBlock;
2244
} else {
2245
topPaddingSize = J9_MEMCHECK_ADJUSTED_PADDING - sizeof(J9MemoryCheckHeader);
2246
wrappedBlock = topPadding + topPaddingSize;
2247
2248
}
2249
2250
/* Verify top padding */
2251
if ( (mode & J9_MCMODE_MPROTECT) && !J9_ALIGN_BOTTOM ) {
2252
/* all the top padding is write protected, no point in scanning */
2253
} else {
2254
if (memoryCheck_verify_forward(
2255
portLib, topPadding, topPaddingSize, J9_MEMCHECK_DATA_PADDING_VALUE, wrappedBlock)) {
2256
if (memoryCheck_verify_forward(
2257
portLib, topPadding, topPaddingSize, J9_MEMCHECK_CODE_PADDING_VALUE, wrappedBlock)) {
2258
2259
/* Either block was already freed, or top padding is damaged. */
2260
goto scan_heap_and_fail;
2261
}
2262
}
2263
}
2264
2265
if (blockHeader->allocationNumber > memStats.totalBlocksAllocated) {
2266
/* Allocation number is clearly invalid. */
2267
goto scan_heap_and_fail;
2268
}
2269
2270
bottomPadding = wrappedBlock + blockHeader->wrappedBlockSize;
2271
2272
if ( mode & J9_MCMODE_MPROTECT ) {
2273
bottomPaddingSize = blockHeader->totalAllocation - J9_MEMCHECK_PAGE_SIZE - (bottomPadding - blockHeader->topPage);
2274
} else {
2275
2276
/* Adjust bottomPadding to force it to end on a double boundary */
2277
bottomPaddingSize = J9_MEMCHECK_ADJUSTED_PADDING + BYTES_FOR_ALIGNMENT (blockHeader->wrappedBlockSize);
2278
}
2279
2280
/* Verify bottom padding */
2281
if (memoryCheck_verify_forward
2282
(portLib, bottomPadding, bottomPaddingSize, J9_MEMCHECK_DATA_PADDING_VALUE, wrappedBlock)) {
2283
if (memoryCheck_verify_forward
2284
(portLib, bottomPadding, bottomPaddingSize, J9_MEMCHECK_CODE_PADDING_VALUE, wrappedBlock)) {
2285
/* Bottom padding looks trashed. */
2286
goto scan_heap_and_fail;
2287
}
2288
}
2289
2290
if (memStats.totalBlocksFreed > memStats.totalBlocksAllocated) {
2291
/* This shouldn't happen. In order to cause it, somebody has to free garbage (or free a block twice) without
2292
this error being caught by any of the previous checks. If global variables were trashed then we would
2293
hopefully go down in flames before we got here. */
2294
goto scan_heap_and_fail;
2295
}
2296
return TRUE;
2297
2298
scan_heap_and_fail:
2299
memoryCheck_scan_all_blocks(portLib);
2300
return FALSE;
2301
}
2302
2303
/**
2304
* This method prints whatever information as it can gather about a block from the block and its immediate neighbors (if any).
2305
* If the block looks like an uncorrupted freed block, TRUE is returned. If detectable corruption of the block is discovered, FALSE
2306
* is returned.
2307
*
2308
* The function will Lock and Unlock the body of the wrappedBlocked, but the top and bottom page must be unlocked when the
2309
* block is passed in
2310
*
2311
* @internal The portLibrary passed in should be the memCheckPortLibrary, not the one from the user
2312
*/
2313
2314
static BOOLEAN memoryCheck_describe_freed_block(OMRPortLibrary *portLib, char const *operationName,
2315
J9MemoryCheckHeader *blockHeader)
2316
{
2317
BOOLEAN everythingOkay = TRUE;
2318
UDATA topPaddingSize = 0;
2319
UDATA bottomPaddingSize = 0;
2320
U_32 paddingValue;
2321
UDATA topPaddingSmashed, bottomPaddingSmashed;
2322
2323
U_8 *topPadding = ((U_8 *) blockHeader) + sizeof(J9MemoryCheckHeader);
2324
U_8 *wrappedBlock = NULL;
2325
U_8 *bottomPadding = NULL;
2326
UDATA dumpSize = 0;
2327
U_8 *dumpPos = topPadding;
2328
2329
if ( !(mode & J9_MCMODE_MPROTECT) ) {
2330
topPaddingSize = J9_MEMCHECK_ADJUSTED_PADDING - sizeof(J9MemoryCheckHeader);
2331
bottomPaddingSize = J9_MEMCHECK_ADJUSTED_PADDING + BYTES_FOR_ALIGNMENT (blockHeader->wrappedBlockSize);
2332
wrappedBlock = ((U_8 *) blockHeader) + J9_MEMCHECK_ADJUSTED_PADDING;
2333
} else {
2334
topPaddingSize = J9_MEMCHECK_PAGE_SIZE - sizeof(J9MemoryCheckHeader);
2335
2336
/* Adjust bottomPadding to force it to end on a double boundary */
2337
bottomPaddingSize = J9_MEMCHECK_PAGE_SIZE + BYTES_FOR_ALIGNMENT (blockHeader->wrappedBlockSize);
2338
wrappedBlock = ((U_8 *) blockHeader) + J9_MEMCHECK_PAGE_SIZE;
2339
}
2340
bottomPadding = wrappedBlock + blockHeader->wrappedBlockSize;
2341
dumpSize = topPaddingSize + blockHeader->wrappedBlockSize + bottomPaddingSize;
2342
2343
if ( mode & J9_MCMODE_MPROTECT ) {
2344
if ( J9_ALIGN_BOTTOM ) {
2345
U_32 offsetArea = BYTES_FOR_ALIGNMENT (blockHeader->wrappedBlockSize);
2346
wrappedBlock = blockHeader->bottomPage - blockHeader->wrappedBlockSize - offsetArea;
2347
}
2348
bottomPadding = wrappedBlock + blockHeader->wrappedBlockSize;
2349
}
2350
2351
portLib->tty_printf(portLib, "%s describing previously freed block at %p (header at %p):\n", operationName, wrappedBlock,
2352
blockHeader);
2353
2354
if (!memoryCheck_verify_forward(portLib, topPadding, 8, J9_MEMCHECK_DATA_FREED_VALUE, wrappedBlock)) {
2355
paddingValue = J9_MEMCHECK_DATA_FREED_VALUE;
2356
} else if (!memoryCheck_verify_forward(portLib, topPadding, 8, J9_MEMCHECK_CODE_FREED_VALUE, wrappedBlock)) {
2357
paddingValue = J9_MEMCHECK_CODE_FREED_VALUE;
2358
} else {
2359
/* TODO: check for legal padding with wrong wrappedBlock bits here? */
2360
2361
/* Test if alignment is off by 4 */
2362
if ( (UDATA)topPadding%8 == 4 ) {
2363
if (!memoryCheck_verify_forward(portLib, topPadding+4, 8, J9_MEMCHECK_DATA_FREED_VALUE, wrappedBlock)) {
2364
paddingValue = J9_MEMCHECK_DATA_FREED_VALUE;
2365
} else if (!memoryCheck_verify_forward(portLib, topPadding +4, 8, J9_MEMCHECK_CODE_FREED_VALUE, wrappedBlock)) {
2366
paddingValue = J9_MEMCHECK_CODE_FREED_VALUE;
2367
}
2368
portLib->tty_printf(portLib, "Previously freed block has unrecognized padding %08x %08x (header is probably trashed)!\n",
2369
((U_32 *) topPadding)[0], ((U_32 *) topPadding)[1]);
2370
everythingOkay = FALSE;
2371
goto dump_header_only;
2372
} else {
2373
portLib->tty_printf(portLib, "Previously freed block has unrecognized padding %08x %08x (header is probably trashed)!\n",
2374
((U_32 *) topPadding)[0], ((U_32 *) topPadding)[1]);
2375
everythingOkay = FALSE;
2376
goto dump_header_only;
2377
}
2378
}
2379
2380
if ( mode & J9_MCMODE_MPROTECT ) {
2381
/* Check if extra top smashed */
2382
if (blockHeader->self != blockHeader->topPage ) {
2383
topPaddingSmashed = memoryCheck_verify_forward(portLib, blockHeader->self,
2384
blockHeader->topPage - blockHeader->self, paddingValue, wrappedBlock);
2385
if (topPaddingSmashed) {
2386
portLib->tty_printf(portLib, "Last %d bytes of extra top padding are damaged\n", topPaddingSmashed);
2387
everythingOkay = FALSE;
2388
}
2389
}
2390
}
2391
2392
topPaddingSmashed = memoryCheck_verify_forward(portLib, topPadding, topPaddingSize, paddingValue, wrappedBlock);
2393
if (topPaddingSmashed) {
2394
portLib->tty_printf(portLib, "Last %d bytes of top padding have been corrupted\n", topPaddingSmashed);
2395
everythingOkay = FALSE;
2396
}
2397
2398
J9_MEMCHECK_UNLOCK_BODY( blockHeader );
2399
2400
if (memoryCheck_verify_forward(portLib, wrappedBlock, blockHeader->wrappedBlockSize, paddingValue, wrappedBlock))
2401
{
2402
portLib->tty_printf(portLib, "Some bytes of wrapped block have been corrupted\n");
2403
everythingOkay = FALSE;
2404
}
2405
2406
if ( mode & J9_MCMODE_MPROTECT ) {
2407
const UDATA pageSize = J9_MEMCHECK_PAGE_SIZE;
2408
UDATA checkSize = pageSize;
2409
2410
if (J9_ALIGN_BOTTOM) {
2411
2412
/* Size to check on the bottom is the bottomPage and the alignment bytes. */
2413
checkSize += BYTES_FOR_ALIGNMENT (blockHeader->wrappedBlockSize);
2414
} else {
2415
UDATA addMod = blockHeader->wrappedBlockSize % pageSize;
2416
if ( addMod ) {
2417
checkSize += pageSize - (blockHeader->wrappedBlockSize % pageSize);
2418
}
2419
}
2420
bottomPaddingSmashed = memoryCheck_verify_backward(portLib, bottomPadding, checkSize , paddingValue, wrappedBlock);
2421
} else {
2422
bottomPaddingSmashed = memoryCheck_verify_backward(portLib, bottomPadding, bottomPaddingSize, paddingValue, wrappedBlock);
2423
}
2424
2425
if (bottomPaddingSmashed) {
2426
portLib->tty_printf(portLib, "First %d bytes of bottom padding have been corrupted\n", bottomPaddingSmashed);
2427
everythingOkay = FALSE;
2428
}
2429
2430
portLib->tty_printf(portLib, "Wrapped block size was %d, allocation number was %d\n",
2431
blockHeader->wrappedBlockSize, blockHeader->allocationNumber);
2432
2433
if (everythingOkay) {
2434
J9_MEMCHECK_LOCK_BODY( blockHeader );
2435
return TRUE;
2436
}
2437
2438
dump_block:
2439
memoryCheck_dump_bytes(portLib, blockHeader, sizeof(blockHeader));
2440
memoryCheck_dump_bytes(portLib, dumpPos, dumpSize);
2441
2442
J9_MEMCHECK_LOCK_BODY( blockHeader );
2443
return everythingOkay;
2444
2445
dump_header_only:
2446
2447
portLib->tty_printf(portLib, "(only top padding + first 64 bytes of wrapped block will be printed here)\n");
2448
dumpSize = topPaddingSize + 64;
2449
goto dump_block;
2450
2451
}
2452
2453
2454
/**
2455
* This function scans the region of fillSize bytes at fillAddress, from lower to higher addresses. It determines the number of correct bytes of padding in
2456
* the scan direction before the first incorrect byte. If an incorrect byte is found, all remaining bytes are considered incorrect, and the number of incorrect
2457
* bytes (remaining+1) is returned.
2458
* @precondition: block must be UNLOCK'ed prior to calling this function
2459
*/
2460
static UDATA
2461
memoryCheck_verify_forward(OMRPortLibrary *portLib, U_8 *fillAddress, UDATA fillSize, U_32 fillValue, U_8 *blockAddress)
2462
{
2463
U_8 fillWith[8];
2464
I_32 blockAddressInt = (I_32)(IDATA)blockAddress;
2465
UDATA smashedBytes = fillSize;
2466
U_8 *c;
2467
UDATA index = ((UDATA) fillAddress) & 7;
2468
2469
memcpy(fillWith, &fillValue, 2);
2470
memcpy(fillWith+2, &blockAddressInt, 4);
2471
memcpy(fillWith+6, ((U_8 *)(&fillValue)) + 2, 2);
2472
2473
for (c = fillAddress; c < fillAddress+fillSize; c++) {
2474
if (*c != fillWith[index]) break;
2475
index++;
2476
index &= 7;
2477
smashedBytes--;
2478
}
2479
return smashedBytes;
2480
}
2481
2482
2483
2484
/**
2485
* This function scans the region of fillSize bytes at fillAddress, from lower to higher addresses. It determines the number of correct bytes of padding in
2486
* the scan direction before the first incorrect byte. If an incorrect byte is found, all remaining bytes are considered incorrect, and the number of incorrect
2487
* bytes (remaining+1) is returned.
2488
* @precondition: block must be UNLOCK'ed prior to calling this function
2489
*/
2490
static UDATA
2491
memoryCheck_verify_backward(OMRPortLibrary *portLib, U_8 *fillAddress, UDATA fillSize, U_32 fillValue, U_8 *blockAddress)
2492
{
2493
U_8 fillWith[8];
2494
I_32 blockAddressInt = (I_32)(IDATA)blockAddress;
2495
UDATA smashedBytes = fillSize;
2496
2497
U_8 *c;
2498
UDATA index = ((UDATA) fillAddress + fillSize - 1) & 7;
2499
2500
memcpy(fillWith, &fillValue, 2);
2501
memcpy(fillWith+2, &blockAddressInt, 4);
2502
memcpy(fillWith+6, ((U_8 *)(&fillValue)) + 2, 2);
2503
2504
for (c = fillAddress+fillSize-1; c >= fillAddress; c--) {
2505
if (*c != fillWith[index]) break;
2506
index--;
2507
index &= 7;
2508
smashedBytes--;
2509
}
2510
return smashedBytes;
2511
}
2512
2513
2514
/*
2515
* Normal shutdown of memory check
2516
*/
2517
void memoryCheck_print_report(J9PortLibrary *j9portLib)
2518
{
2519
if (NULL == old_port_shutdown_library) {
2520
/* We aren't installed */
2521
return;
2522
}
2523
2524
MUTEX_ENTER(mcMutex);
2525
/* Disable trace to avoid deadlock between mcMutex and trace global lock. JTC-JAT 93458 */
2526
if (uteInterface && uteInterface->server) {
2527
uteInterface->server->DisableTrace(UT_DISABLE_THREAD);
2528
}
2529
memoryCheck_print_summary(memCheckPortLib, J9_MEMCHECK_SHUTDOWN_NORMAL);
2530
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
2531
uteInterface->server->EnableTrace(UT_ENABLE_THREAD);
2532
}
2533
MUTEX_EXIT(mcMutex);
2534
}
2535
2536
/*
2537
* Search for a memorycheck option on the command line. Elements in argv
2538
* are searched in reverse order. The first element is always ignored (typically
2539
* the first argv element is the program name, not a command line option).
2540
*
2541
* If one is found, return its index, otherwise return 0.
2542
*
2543
* This should happen before anybody allocates memory! Otherwise, shutdown will
2544
* not work properly.
2545
*/
2546
IDATA
2547
memoryCheck_parseCmdLine(J9PortLibrary *j9portLibrary, UDATA lastLegalArg, char **argv)
2548
{
2549
OMRPortLibrary *portLibrary = OMRPORT_FROM_J9PORT(j9portLibrary);
2550
UDATA i;
2551
2552
for (i = lastLegalArg; i >= 1; i--) {
2553
/* new style -Xcheck:memory options */
2554
if (0 == strcmp("-Xcheck", argv[i])) {
2555
memoryCheck_initialize(j9portLibrary, "all", argv);
2556
return i;
2557
} else if ( (0 == strcmp("-Xcheck:none", argv[i])) ||
2558
(0 == strcmp("-Xcheck:memory:none", argv[i])) ||
2559
(0 == strcmp("-Xcheck:help", argv[i])) ) {
2560
/* stop looking at -Xcheck options */
2561
return -1;
2562
break;
2563
} else if ( (0 == strcmp("-Xcheck:memory:help", argv[i])) ) {
2564
/* print out the -Xcheck:memory:help text */
2565
portLibrary->tty_printf( portLibrary, "\nUsage: Xcheck:memory[:<option>]\n\n");
2566
portLibrary->tty_printf( portLibrary, "options (default is all):\n");
2567
portLibrary->tty_printf( portLibrary, " all\n");
2568
portLibrary->tty_printf( portLibrary, " quick\n");
2569
portLibrary->tty_printf( portLibrary, " nofree\n");
2570
portLibrary->tty_printf( portLibrary, " failat\n");
2571
portLibrary->tty_printf( portLibrary, " skipto\n");
2572
portLibrary->tty_printf( portLibrary, " callsite\n");
2573
portLibrary->tty_printf( portLibrary, " zero\n\n");
2574
return -1;
2575
break;
2576
} else if (0 == strcmp("-Xcheck:memory",argv[i])) {
2577
memoryCheck_initialize(j9portLibrary, "all", argv);
2578
return i;
2579
} else if (0 == strncmp("-Xcheck:memory:", argv[i], sizeof("-Xcheck:memory:") - 1 )) {
2580
memoryCheck_initialize(j9portLibrary, argv[i] + sizeof("-Xcheck:memory:") - 1, argv );
2581
return i;
2582
}
2583
}
2584
2585
return 0;
2586
}
2587
2588
2589
2590
/* The port library only shuts down components that absolutely need to be.
2591
* EG., very few or none of the port library components are shut down.
2592
* Therefore, shutdown memorycheck, restore user's original portlib shutdown
2593
* functions and call the original exit_shutdown_and_exit.
2594
*
2595
*/
2596
static void
2597
memoryCheck_exit_shutdown_and_exit(OMRPortLibrary *portLib, I_32 exitCode)
2598
{
2599
if (!old_shutdown_and_exit) {
2600
/* We aren't installed */
2601
return;
2602
}
2603
2604
2605
memoryCheck_shutdown_internal( memCheckPortLib, J9_MEMCHECK_SHUTDOWN_EXIT );
2606
2607
memoryCheck_restore_old_shutdown_functions( portLib );
2608
2609
portLib->exit_shutdown_and_exit( portLib, exitCode );
2610
}
2611
2612
/* remove all unfreedBlocks that is was not allocated by VM
2613
* The list of ignored callsites are defined in ignoredCallsites
2614
*
2615
* This function assumes mcMutex is acquired
2616
*
2617
*
2618
* returns the number of unfreed blocks that was removed from the link list
2619
*/
2620
2621
static UDATA
2622
memoryCheck_filter_nonVM_unFreed_Blcoks(OMRPortLibrary *portLib)
2623
{
2624
UDATA result = 0;
2625
J9MemoryCheckHeader *blockHeader, *previous, *next;
2626
UDATA unfreedBlocks = memStats.totalBlocksAllocated - memStats.totalBlocksFreed;
2627
UDATA i;
2628
char ignoredCallsites[MAX_CALLSITE_COUNT][MAX_CALLSITE_LENGTH], *strPtr;
2629
UDATA ignoredCallsitesSize = 0;
2630
#ifdef J9ZOS390
2631
char *ebcdic_callsite;
2632
#endif
2633
2634
memset(ignoredCallsites, '\0', MAX_CALLSITE_COUNT * MAX_CALLSITE_LENGTH* sizeof(char));
2635
2636
strPtr = strtok( ignoreCallSiteStr, CALLSITE_DELIMITER );
2637
2638
while (NULL != strPtr) {
2639
if (ignoredCallsitesSize >= MAX_CALLSITE_COUNT) {
2640
portLib->tty_printf(portLib, "internal buffer full, ignoredCallSite %s discarded\n", strPtr);
2641
strPtr = strtok( NULL, CALLSITE_DELIMITER );
2642
continue;
2643
}
2644
if (strlen(strPtr) >= MAX_CALLSITE_LENGTH) {
2645
portLib->tty_printf(portLib, "ignoredCallSite %s length exceeds internal buffer size. Callsite discarded\n", strPtr);
2646
strPtr = strtok( NULL, CALLSITE_DELIMITER );
2647
continue;
2648
}
2649
strcpy(ignoredCallsites[ignoredCallsitesSize++], strPtr);
2650
strPtr = strtok( NULL, CALLSITE_DELIMITER );
2651
}
2652
2653
for (blockHeader = mostRecentBlock; (NULL != blockHeader) && (0 != unfreedBlocks); unfreedBlocks--) {
2654
if (blockHeader->node) {
2655
previous = blockHeader->previousBlock;
2656
next = blockHeader->nextBlock;
2657
#ifdef J9ZOS390
2658
ebcdic_callsite = e2a_string(blockHeader->node->callSite);
2659
#endif
2660
for (i = 0; i < ignoredCallsitesSize; i++) {
2661
if ((0 == strncmp(blockHeader->node->callSite, ignoredCallsites[i], strlen(ignoredCallsites[i])))
2662
#ifdef J9ZOS390
2663
|| (0 == strncmp(ebcdic_callsite, ignoredCallsites[i], strlen(ignoredCallsites[i])))
2664
2665
#endif
2666
) {
2667
#if 0
2668
portLib->tty_printf(portLib, "WARNING: unfreed block #%d allocated by %s is being ignored from memcheck\n",
2669
blockHeader->allocationNumber,blockHeader->node->callSite);
2670
#endif
2671
if (previous) {
2672
previous->nextBlock = next;
2673
}
2674
2675
if (next) {
2676
next->previousBlock = previous;
2677
}
2678
2679
if (blockHeader == mostRecentBlock) {
2680
mostRecentBlock = previous;
2681
}
2682
globalDeallocator(portLib, blockHeader);
2683
result++;
2684
#ifdef J9ZOS390
2685
free(ebcdic_callsite);
2686
#endif
2687
break;
2688
}
2689
}
2690
#ifdef J9ZOS390
2691
free(ebcdic_callsite);
2692
#endif
2693
}
2694
blockHeader = previous;
2695
}
2696
2697
portLib->tty_printf(portLib, "WARNING: %d blocks were ignored per ignoredCallsite parameter\n", result);
2698
return result;
2699
2700
}
2701
2702
/* Does a final scan and prints the final summary/stats. Please note that this
2703
* function expects the caller to have already locked mcMutex.
2704
*
2705
* @internal The portLib should be the memCheckPortLib
2706
*/
2707
static void
2708
memoryCheck_print_summary(OMRPortLibrary *portLib, I_32 shutdownMode)
2709
{
2710
J9MemoryCheckHeader *blockHeader;
2711
UDATA ignored = 0;
2712
2713
if (0 == (mode & J9_MCMODE_NO_SCAN) ) {
2714
memoryCheck_scan_all_blocks(portLib); /* One last check for trashing. */
2715
}
2716
2717
/* don't report memory leaks when terminating with exit_shutdown_and_exit */
2718
if ( (shutdownMode == J9_MEMCHECK_SHUTDOWN_NORMAL) && (mostRecentBlock)) {
2719
UDATA unfreedBlocks = memStats.totalBlocksAllocated - memStats.totalBlocksFreed;
2720
portLib->tty_printf(portLib, "WARNING: %d unfreed blocks remaining at shutdown!\n", unfreedBlocks);
2721
ignored = memoryCheck_filter_nonVM_unFreed_Blcoks(portLib);
2722
if (unfreedBlocks > J9_MEMCHECK_MAX_DUMP_LEAKED_BLOCKS) {
2723
unfreedBlocks = J9_MEMCHECK_MAX_DUMP_LEAKED_BLOCKS;
2724
portLib->tty_printf(portLib, "WARNING: only %d most recent leaked blocks will be described\n",
2725
unfreedBlocks);
2726
}
2727
for (blockHeader = mostRecentBlock; blockHeader && unfreedBlocks; unfreedBlocks--) {
2728
if (0 == (mode & J9_MCMODE_NO_SCAN ) ) {
2729
memoryCheck_describe_block(portLib, "port_shutdown_library", blockHeader);
2730
} else {
2731
UDATA size = blockHeader->wrappedBlockSize < 32 ? blockHeader->wrappedBlockSize : 32;
2732
portLib->tty_printf(portLib, "Wrapped block size is %d, allocation number is %d\n",
2733
blockHeader->wrappedBlockSize, blockHeader->allocationNumber);
2734
2735
if (blockHeader->node) {
2736
portLib->tty_printf(portLib, "Block was allocated by %s\n", blockHeader->node->callSite);
2737
}
2738
portLib->tty_printf(portLib, "First %d bytes:\n", size);
2739
memoryCheck_dump_bytes(portLib, blockHeader->wrappedBlock, size);
2740
}
2741
blockHeader = blockHeader->previousBlock;
2742
}
2743
}
2744
2745
/* If an AVL Tree was created free the memory for the tree */
2746
if(avl_tree) {
2747
if (mode & J9_MCMODE_PRINT_CALLSITES) {
2748
/* Report callsite informtation */
2749
memoryCheck_dump_callSites(portLib, avl_tree);
2750
} else if (mode & J9_MCMODE_PRINT_CALLSITES_SMALL) {
2751
/* Report callsite informtation */
2752
memoryCheck_dump_callSites_small(portLib, avl_tree);
2753
}
2754
/* Free the avl tree and nodes*/
2755
memoryCheck_free_AVLTree(portLib, avl_tree);
2756
}
2757
2758
memoryCheck_print_stats(portLib);
2759
2760
if (memStats.totalBlocksAllocated != (memStats.totalBlocksFreed + ignored)) {
2761
portLib->tty_printf(portLib, "%d allocated blocks totaling %llu bytes were not freed before shutdown!\n",
2762
memStats.totalBlocksAllocated - memStats.totalBlocksFreed,
2763
memStats.totalBytesAllocated - memStats.totalBytesFreed);
2764
if( shutdownMode == J9_MEMCHECK_SHUTDOWN_EXIT ) {
2765
portLib->tty_printf( portLib, "The VM terminated due to exit() so unfreed blocks are expected.\n" );
2766
}
2767
} else {
2768
portLib->tty_printf(portLib, "All allocated blocks were freed.\n");
2769
}
2770
2771
return;
2772
}
2773
2774
/* Does a final scan (if it was not called by memoryCheck_exit_shutdown_and_exit
2775
* and prints the stats.
2776
* Finally, it shuts down the passed in portlibrary (which should be the memCheckPortLib)
2777
*
2778
* @internal The portLib should be the memCheckPortLib */
2779
static void
2780
memoryCheck_shutdown_internal(OMRPortLibrary *portLib, I_32 shutdownMode)
2781
{
2782
omrthread_t thread = NULL;
2783
2784
/* Make sure we are attached, so that we can enter/exit/destroy the mutex */
2785
if (f_omrthread_attach_ex(&thread, J9THREAD_ATTR_DEFAULT)) {
2786
return;
2787
}
2788
2789
MUTEX_ENTER(mcMutex);
2790
/* Disable trace to avoid deadlock between mcMutex and trace global lock. JTC-JAT 93458 */
2791
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
2792
uteInterface->server->DisableTrace(UT_DISABLE_THREAD);
2793
}
2794
2795
if ( mode & J9_MCMODE_MPROTECT ) {
2796
/* Unlock ALL the blocks */
2797
memoryCheck_lockAllBlocks( memCheckPortLib, mostRecentBlock, unlockMode, 0 );
2798
memoryCheck_lockAllBlocks( memCheckPortLib, mostRecentFreedBlock, unlockMode, 1 );
2799
}
2800
2801
memoryCheck_print_summary(portLib, shutdownMode);
2802
2803
/* If the VM is terminating due to exit, the trace engine and other bits of
2804
* the VM may still be operating - so we can't tear their storage out from
2805
* under them.
2806
*/
2807
if ( shutdownMode != J9_MEMCHECK_SHUTDOWN_EXIT && mode & J9_MCMODE_MPROTECT ) {
2808
/* Free all the blocks remaining in the hashTable and then free the Table itself*/
2809
hashTableForEachDo( vmemIDTable, memoryCheck_hashDoFn, memCheckPortLib );
2810
hashTableFree( vmemIDTable );
2811
}
2812
2813
memCheckPortLib->port_shutdown_library(memCheckPortLib);
2814
2815
/* Port library has shut down, don't attempt to re-enable trace at this point */
2816
MUTEX_EXIT(mcMutex);
2817
MUTEX_DESTROY(mcMutex);
2818
2819
f_omrthread_detach(thread);
2820
}
2821
2822
2823
/* Restore the original shutdown functions */
2824
static void
2825
memoryCheck_restore_old_shutdown_functions(OMRPortLibrary *portLib)
2826
{
2827
2828
portLib->port_shutdown_library = old_port_shutdown_library;
2829
portLib->exit_shutdown_and_exit = old_shutdown_and_exit;
2830
}
2831
2832
2833
static I_32
2834
memoryCheck_control(OMRPortLibrary *portLib, const char* key, UDATA value)
2835
{
2836
if (0 == strcmp(key, "MEMCHECK")) {
2837
UDATA everythingOkay;
2838
MUTEX_ENTER(mcMutex);
2839
/* Disable trace to avoid deadlock between mcMutex and trace global lock. JTC-JAT 93458 */
2840
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
2841
uteInterface->server->DisableTrace(UT_DISABLE_THREAD);
2842
}
2843
2844
everythingOkay = memoryCheck_scan_all_blocks(memCheckPortLib);
2845
2846
if (!everythingOkay) {
2847
memoryCheck_abort(memCheckPortLib);
2848
}
2849
2850
if ((NULL != uteInterface) && (NULL != uteInterface->server)) {
2851
uteInterface->server->EnableTrace(UT_ENABLE_THREAD);
2852
}
2853
MUTEX_EXIT(mcMutex);
2854
2855
return 1;
2856
} else {
2857
if (0 == strcmp(key, J9PORT_CTLDATA_TRACE_START) && value) {
2858
MUTEX_ENTER(mcMutex);
2859
uteInterface = (UtInterface*) value;
2860
MUTEX_EXIT(mcMutex);
2861
} else if (0 == strcmp(key, J9PORT_CTLDATA_TRACE_STOP)) {
2862
MUTEX_ENTER(mcMutex);
2863
uteInterface = NULL;
2864
MUTEX_EXIT(mcMutex);
2865
}
2866
2867
return old_port_control(portLib, key, value);
2868
}
2869
}
2870
2871
2872
2873
/* This function will print the stats for the given node and then
2874
* recurse over its children.
2875
*
2876
* @param portLibrary
2877
* @param node J9MEMAVLTreeNode to print callSite information for
2878
* @internal The portLibrary passed in should be the memCheckPortLib->
2879
*
2880
*/
2881
static void
2882
memoryCheck_dump_callSite(OMRPortLibrary *portLibrary, J9AVLTreeNode *node)
2883
{
2884
J9AVLTreeNode *nodePtr = AVL_GETNODE(node);
2885
2886
if (nodePtr == NULL) {
2887
return;
2888
}
2889
2890
memoryCheck_print_stats_callSite(portLibrary, ((J9MEMAVLTreeNode *)nodePtr));
2891
memoryCheck_set_AVLTree_prevStats(((J9MEMAVLTreeNode *)nodePtr));
2892
2893
memoryCheck_dump_callSite(portLibrary, J9AVLTREENODE_LEFTCHILD(nodePtr));
2894
memoryCheck_dump_callSite(portLibrary, J9AVLTREENODE_RIGHTCHILD(nodePtr));
2895
}
2896
2897
2898
/* This function will print the header for the callSite information and
2899
* call memoryCheck_dump_callSite on the root node of the tree
2900
*
2901
* @param portLibrary
2902
* @param tree J9AVLTree storing the callSite information
2903
*
2904
*/
2905
static void
2906
memoryCheck_dump_callSites(OMRPortLibrary *portLibrary, J9AVLTree *tree)
2907
{
2908
if( !(tree) || !(tree->rootNode)) {
2909
return;
2910
}
2911
2912
portLibrary->tty_printf(portLibrary, " total alloc | total freed | delta alloc | delta freed | high water | largest\n");
2913
portLibrary->tty_printf(portLibrary, " blocks| bytes | blocks| bytes | blocks| bytes | blocks| bytes | blocks| bytes | bytes | num | callsite\n");
2914
portLibrary->tty_printf(portLibrary,
2915
"-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+------------\n");
2916
2917
memoryCheck_dump_callSite(portLibrary, tree->rootNode);
2918
portLibrary->tty_printf(portLibrary,
2919
"-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+------------\n");
2920
}
2921
2922
2923
/*
2924
* This function will start the recursive freeing of the nodes and the free
2925
* the memory for the AVL Tree
2926
*
2927
* @parm portLib OMRPortLibrary used to access the memory functions
2928
* @param tree J9AVLTree storing the callSite information
2929
* @internal The portLibrary passed in should be the memCheckPortLib.
2930
*/
2931
static void
2932
memoryCheck_free_AVLTree(OMRPortLibrary *portLib, J9AVLTree *tree)
2933
{
2934
if(!tree) {
2935
return;
2936
}
2937
2938
memoryCheck_free_AVLTreeNode(portLib, tree->rootNode);
2939
2940
portLib->mem_free_memory( portLib, tree );
2941
}
2942
2943
2944
/*
2945
* This function will recurse over the left and right child of the given
2946
* node and then free the memory for itself
2947
*
2948
* @parm portLib OMRPortLibrary used to access the memory functions
2949
* @param tree J9AVLTreeNode the node to free
2950
* @internal The portLibrary passed in should be the memCheckPortLib.
2951
*/
2952
static void
2953
memoryCheck_free_AVLTreeNode(OMRPortLibrary *portLib, J9AVLTreeNode *node)
2954
{
2955
J9AVLTreeNode *nodePtr = AVL_GETNODE(node);
2956
2957
if (nodePtr == NULL) {
2958
return;
2959
}
2960
2961
memoryCheck_free_AVLTreeNode(portLib, J9AVLTREENODE_LEFTCHILD(nodePtr));
2962
memoryCheck_free_AVLTreeNode(portLib, J9AVLTREENODE_RIGHTCHILD(nodePtr));
2963
2964
portLib->mem_free_memory( portLib, nodePtr );
2965
}
2966
2967
2968
/*
2969
* This function is the insertion comparator for the J9AVLTree that stores J9MEMAVLTreeNodes
2970
* It will compare the char * of both nodes.
2971
*
2972
* @param tree J9ALVTree storing the callSite information
2973
* @param insertNode The node which will be inserted into the tree
2974
* @param walk The current search position in the tree
2975
*
2976
* @return IDATA the difference between the two strings alphabetically
2977
*
2978
*/
2979
static IDATA
2980
memoryCheck_insertion_Compare(J9AVLTree *tree, J9AVLTreeNode *insertNode, J9AVLTreeNode *walk)
2981
{
2982
return strcmp(((J9MEMAVLTreeNode *)insertNode)->callSite, ((J9MEMAVLTreeNode *)walk)->callSite);
2983
}
2984
2985
2986
/*
2987
* This function prints the deatils of the callSite
2988
*
2989
* @param portLib OMRPortLibrary used to handle printing
2990
* @param node The node to print the stats for
2991
*
2992
*/
2993
static void
2994
memoryCheck_print_stats_callSite(OMRPortLibrary *portLib, J9MEMAVLTreeNode *node)
2995
{
2996
portLib->tty_printf(portLib, "%7u %7llu %7u %7llu %7u %7lld %7u %7lld %7u %7u %7u %7u %s\n",
2997
node->stats->totalBlocksAllocated,
2998
node->stats->totalBytesAllocated,
2999
node->stats->totalBlocksFreed,
3000
node->stats->totalBytesFreed,
3001
node->stats->totalBlocksAllocated - node->prevStats->totalBlocksAllocated,
3002
node->stats->totalBytesAllocated - node->prevStats->totalBytesAllocated,
3003
node->stats->totalBlocksFreed - node->prevStats->totalBlocksFreed,
3004
node->stats->totalBytesFreed - node->prevStats->totalBytesFreed,
3005
node->stats->hiWaterBlocksAllocated,
3006
node->stats->hiWaterBytesAllocated,
3007
node->stats->largestBlockAllocated,
3008
node->stats->largestBlockAllocNum,
3009
node->callSite);
3010
}
3011
3012
3013
3014
/*
3015
* This function is the search comparator for the J9AVLTree that stores J9MEMAVLTreeNodes
3016
* It will compare the char * with the node callSite.
3017
*
3018
* @param tree J9ALVTree storing the callSite information
3019
* @param search The char * to search for
3020
* @param walk The current search position in the tree
3021
*
3022
* @return IDATA the difference between the two strings alphabetically
3023
*
3024
*/
3025
static IDATA
3026
memoryCheck_search_Compare(J9AVLTree *tree, UDATA search, J9AVLTreeNode *walk)
3027
{
3028
return strcmp((char *)search, ((J9MEMAVLTreeNode *)walk)->callSite);
3029
}
3030
3031
3032
/*
3033
* This function initializes both node->stats and node->prevStats. All
3034
* values for prevStats should be initialized to 0 since at this point there have
3035
* been no previous stats.
3036
*
3037
* @param node J9MEMAVLTreeNode to initialize stats for
3038
* @param byteAmount used to initialize bytesAllocated for node->stats only
3039
*
3040
*/
3041
static void
3042
memoryCheck_initialize_AVLTree_stats(J9MEMAVLTreeNode *node, UDATA byteAmount)
3043
{
3044
node->stats->totalBlocksAllocated = 1;
3045
node->stats->totalBlocksFreed = 0;
3046
node->stats->totalBytesAllocated = byteAmount;
3047
node->stats->totalBytesFreed = 0;
3048
node->stats->totalUnknownBlocksIgnored = 0;
3049
node->stats->largestBlockAllocated = byteAmount;
3050
node->stats->largestBlockAllocNum = 1;
3051
node->stats->currentBlocksAllocated = 1;
3052
node->stats->hiWaterBlocksAllocated = 1;
3053
node->stats->currentBytesAllocated = byteAmount;
3054
node->stats->hiWaterBytesAllocated = byteAmount;
3055
node->stats->failedAllocs = 0;
3056
3057
node->prevStats->totalBlocksAllocated = 0;
3058
node->prevStats->totalBlocksFreed = 0;
3059
node->prevStats->totalBytesAllocated = 0;
3060
node->prevStats->totalBytesFreed = 0;
3061
node->prevStats->totalUnknownBlocksIgnored = 0;
3062
node->prevStats->largestBlockAllocated = 0;
3063
node->prevStats->largestBlockAllocNum = 0;
3064
node->prevStats->currentBlocksAllocated = 0;
3065
node->prevStats->hiWaterBlocksAllocated = 0;
3066
node->prevStats->currentBytesAllocated = 0;
3067
node->prevStats->hiWaterBytesAllocated = 0;
3068
node->prevStats->failedAllocs = 0;
3069
}
3070
3071
3072
3073
/*
3074
* This function inserts or updates the node pertaining to the newly allocated memory block.
3075
*
3076
* @param portLib OMRPortLibrary used for memory functions
3077
* @param header Memory block header which will point to the node
3078
* @param callSite Char * to the location that called the allocation function
3079
* @param byteAmount Number of bytes allocated for the memory block
3080
*
3081
*/
3082
static void
3083
memoryCheck_update_callSites_allocate(OMRPortLibrary *portLib, J9MemoryCheckHeader *header, const char *callSite, UDATA byteAmount)
3084
{
3085
J9MEMAVLTreeNode *node;
3086
3087
node = (J9MEMAVLTreeNode *)avl_search(avl_tree, (UDATA)callSite);
3088
if(node) {
3089
node->stats->totalBlocksAllocated++;
3090
node->stats->totalBytesAllocated += byteAmount;
3091
node->stats->currentBlocksAllocated += 1;
3092
if (node->stats->currentBlocksAllocated > node->stats->hiWaterBlocksAllocated) {
3093
node->stats->hiWaterBlocksAllocated = node->stats->currentBlocksAllocated;
3094
}
3095
node->stats->currentBytesAllocated += byteAmount;
3096
if (node->stats->currentBytesAllocated > node->stats->hiWaterBytesAllocated) {
3097
node->stats->hiWaterBytesAllocated = node->stats->currentBytesAllocated;
3098
}
3099
if (byteAmount > node->stats->largestBlockAllocated) {
3100
node->stats->largestBlockAllocated = byteAmount;
3101
node->stats->largestBlockAllocNum = node->stats->totalBlocksAllocated;
3102
}
3103
header->node = node;
3104
} else {
3105
/* allocate enough room for the node, char *, and two J9MemoryCheckStats */
3106
node = old_mem_allocate_memory(portLib, sizeof(J9MEMAVLTreeNode) + strlen(callSite) + 1 +
3107
sizeof(J9MemoryCheckStats) + sizeof(J9MemoryCheckStats), J9_GET_CALLSITE(), OMRMEM_CATEGORY_VM);
3108
if(node) {
3109
node->parentAVLTreeNode.leftChild = 0;
3110
node->parentAVLTreeNode.rightChild = 0;
3111
node->stats = (J9MemoryCheckStats *)(node + 1);
3112
node->prevStats = (J9MemoryCheckStats *)((UDATA)(node->stats) + sizeof(J9MemoryCheckStats));
3113
3114
memcpy((char *)((UDATA)(node->prevStats) + sizeof(J9MemoryCheckStats)), callSite, strlen(callSite) + 1);
3115
node->callSite = (char *)((UDATA)(node->prevStats) + sizeof(J9MemoryCheckStats));
3116
3117
memoryCheck_initialize_AVLTree_stats(node, byteAmount);
3118
3119
header->node = node;
3120
3121
avl_insert(avl_tree, (J9AVLTreeNode *)node);
3122
}
3123
}
3124
}
3125
3126
3127
/*
3128
* This function sets the node->prevStats to the current value of
3129
* node->stats
3130
*
3131
* @param node J9MEMAVLTreeNode to initialize stats for
3132
*
3133
*/
3134
static void
3135
memoryCheck_set_AVLTree_prevStats(J9MEMAVLTreeNode *node)
3136
{
3137
node->prevStats->totalBlocksAllocated = node->stats->totalBlocksAllocated;
3138
node->prevStats->totalBlocksFreed = node->stats->totalBlocksFreed;
3139
node->prevStats->totalBytesAllocated = node->stats->totalBytesAllocated;
3140
node->prevStats->totalBytesFreed = node->stats->totalBytesFreed;
3141
node->prevStats->largestBlockAllocated = node->stats->largestBlockAllocated;
3142
node->prevStats->largestBlockAllocNum = node->stats->largestBlockAllocNum;
3143
node->prevStats->currentBlocksAllocated = node->stats->currentBlocksAllocated;
3144
node->prevStats->hiWaterBlocksAllocated = node->stats->hiWaterBlocksAllocated;
3145
node->prevStats->currentBytesAllocated = node->stats->currentBytesAllocated;
3146
node->prevStats->hiWaterBytesAllocated = node->stats->hiWaterBytesAllocated;
3147
}
3148
3149
3150
/*
3151
* This function prints the deatils of the callSite. This only
3152
* prints the total/delta alloc/free information.
3153
*
3154
* @param portLib OMRPortLibrary used to handle printing
3155
* @param node The node to print the stats for
3156
*
3157
*/
3158
static void
3159
memoryCheck_print_stats_callSite_small(OMRPortLibrary *portLib, J9MEMAVLTreeNode *node)
3160
{
3161
portLib->tty_printf(portLib, "%7u %7llu %7u %7llu %7u %7llu %7u %7llu %s\n",
3162
node->stats->totalBlocksAllocated,
3163
node->stats->totalBytesAllocated,
3164
node->stats->totalBlocksFreed,
3165
node->stats->totalBytesFreed,
3166
node->stats->totalBlocksAllocated - node->prevStats->totalBlocksAllocated,
3167
node->stats->totalBytesAllocated - node->prevStats->totalBytesAllocated,
3168
node->stats->totalBlocksFreed - node->prevStats->totalBlocksFreed,
3169
node->stats->totalBytesFreed - node->prevStats->totalBytesFreed,
3170
node->callSite);
3171
}
3172
3173
3174
/* This function will print the header for the callSite information and
3175
* call memoryCheck_dump_callSite on the root node of the tree
3176
*
3177
* @param portLibrary
3178
* @param tree J9AVLTree storing the callSite information
3179
* @internal The portLibrary passed in should be the memCheckPortLib->
3180
*
3181
*/
3182
static void
3183
memoryCheck_dump_callSites_small(OMRPortLibrary *portLibrary, J9AVLTree *tree)
3184
{
3185
if(!(tree) || !(tree->rootNode)) {
3186
return;
3187
}
3188
3189
portLibrary->tty_printf(portLibrary, " total alloc | total freed | delta alloc | delta freed\n");
3190
portLibrary->tty_printf(portLibrary, " blocks| bytes | blocks| bytes | blocks| bytes | blocks| bytes | callsite\n");
3191
portLibrary->tty_printf(portLibrary,
3192
"-------+-------+-------+-------+-------+-------+-------+-------+-----------\n");
3193
3194
memoryCheck_dump_callSite_small(portLibrary, tree->rootNode);
3195
portLibrary->tty_printf(portLibrary,
3196
"-------+-------+-------+-------+-------+-------+-------+-------+-----------\n");
3197
}
3198
3199
3200
3201
/* This function will print the stats (only the total/delta for alloc/free) for the given node and then
3202
* recurse over its children.
3203
*
3204
* @param portLibrary
3205
* @param node J9MEMAVLTreeNode to print callSite information for
3206
* @internal The portLibrary passed in should be the memCheckPortLib.
3207
*/
3208
static void
3209
memoryCheck_dump_callSite_small(OMRPortLibrary *portLibrary, J9AVLTreeNode *node)
3210
{
3211
J9AVLTreeNode *nodePtr = AVL_GETNODE(node);
3212
3213
if (nodePtr == NULL) {
3214
return;
3215
}
3216
3217
memoryCheck_print_stats_callSite_small(portLibrary, ((J9MEMAVLTreeNode *)nodePtr));
3218
memoryCheck_set_AVLTree_prevStats(((J9MEMAVLTreeNode *)nodePtr));
3219
3220
memoryCheck_dump_callSite_small(portLibrary, J9AVLTREENODE_LEFTCHILD(nodePtr));
3221
memoryCheck_dump_callSite_small(portLibrary, J9AVLTREENODE_RIGHTCHILD(nodePtr));
3222
}
3223
3224
3225
/*
3226
* This function will update the node to account for the memory block
3227
* which was just freed.
3228
*
3229
* @param node J9MEMAVLTreeNode that will be updated
3230
* @param byteAmount Number of bytes allocated for the memory block
3231
*
3232
*/
3233
static void
3234
memoryCheck_update_callSites_free(J9MEMAVLTreeNode *node, UDATA byteAmount)
3235
{
3236
if(node) {
3237
node->stats->totalBlocksFreed++;
3238
node->stats->totalBytesFreed+=byteAmount;
3239
node->stats->currentBlocksAllocated--;
3240
node->stats->currentBytesAllocated-=byteAmount;
3241
}
3242
}
3243
3244
3245
/**
3246
* @internal The portLibrary passed on will be the memCheckPortLibrary with its original functions
3247
*/
3248
static void *
3249
memoryCheck_reallocate_memory(struct OMRPortLibrary *portLibrary, void *memoryPointer, UDATA byteAmount, const char * callsite, U_32 category)
3250
{
3251
#ifdef DEBUG
3252
memCheckPortLib->tty_printf( memCheckPortLib, "reallocate_memory(%p, %d)\n", memoryPointer, byteAmount);
3253
#endif
3254
return memoryCheck_wrapper_reallocate_memory(memCheckPortLib, memoryPointer, byteAmount, "reallocate_memory", globalAllocator, globalDeallocator,
3255
J9_MEMCHECK_DATA_PADDING_VALUE, J9_MEMCHECK_DATA_FILL_VALUE, J9_MEMCHECK_DATA_FREED_VALUE, NULL == callsite ? "unknown" : callsite, category);
3256
}
3257
3258
3259
3260
/* @internal The portLib passed in should be the memCheckPortLib */
3261
static void *
3262
memoryCheck_wrapper_reallocate_memory(OMRPortLibrary *portLib, void *memoryPointer, UDATA byteAmount, char const *operationName,
3263
J9_MEM_ALLOCATE_FUNC allocator, J9_MEM_FREE_FUNC deallocator, U_32 paddingValue, U_32 fillValue,
3264
U_32 freedValue, const char *callSite, U_32 category)
3265
{
3266
3267
/* It doesn't really make sense to use realloc with memoryCheck since it would try to re-use the
3268
* pointer which would hide most realloc bugs so we will just emulate its behaviour so we get
3269
* the rigorous memoryCheck verifications.
3270
*/
3271
void *newBlock = NULL;
3272
3273
if (memoryPointer == NULL) {
3274
newBlock = memoryCheck_wrapper_allocate_memory(portLib, byteAmount, operationName, allocator, paddingValue, fillValue, freedValue, "unknown", category);
3275
} else if (byteAmount == 0) {
3276
memoryCheck_wrapper_free_memory(portLib, memoryPointer, operationName, deallocator, paddingValue, fillValue, freedValue);
3277
newBlock = NULL;
3278
} else {
3279
newBlock = memoryCheck_wrapper_allocate_memory(portLib, byteAmount, operationName, allocator, paddingValue, fillValue, freedValue, "unknown", category);
3280
3281
if (newBlock != NULL) {
3282
U_8 *wrappedBlock = NULL;
3283
J9MemoryCheckHeader *topHeader = NULL;
3284
UDATA oldByteAmount = 0;
3285
UDATA bytesToCopy = 0;
3286
3287
/* Sniff out the size of the actual wrapped block */
3288
wrappedBlock = (U_8 *) memoryPointer;
3289
if (0 == (mode & J9_MCMODE_NO_SCAN) ) {
3290
if ( mode & J9_MCMODE_MPROTECT ) {
3291
topHeader = (J9MemoryCheckHeader *)(wrappedBlock - J9_MEMCHECK_PAGE_SIZE);
3292
if ( ( ((UDATA)topHeader & 0XF000) != ((UDATA)((U_8 *)topHeader + sizeof(J9MemoryCheckHeader)) & 0XF000) ) ) {
3293
if ( (UDATA)((U_8*)topHeader + sizeof(J9MemoryCheckHeader)) % J9_MEMCHECK_PAGE_SIZE != 0 ) {
3294
topHeader = (J9MemoryCheckHeader *)((U_8 *)topHeader - sizeof(J9MemoryCheckHeader));
3295
}
3296
}
3297
} else {
3298
UDATA topPaddingSize = J9_MEMCHECK_ADJUSTED_PADDING - sizeof(J9MemoryCheckHeader);
3299
topHeader = (J9MemoryCheckHeader *) (wrappedBlock - topPaddingSize - sizeof(J9MemoryCheckHeader));
3300
}
3301
} else {
3302
topHeader = (J9MemoryCheckHeader *) (wrappedBlock - sizeof(J9MemoryCheckHeader));
3303
}
3304
3305
J9_MEMCHECK_UNLOCK( topHeader);
3306
oldByteAmount = topHeader->wrappedBlockSize;
3307
J9_MEMCHECK_LOCK( topHeader);
3308
3309
/* Copy the existing data to the new block */
3310
bytesToCopy = (oldByteAmount <= byteAmount) ? oldByteAmount : byteAmount;
3311
memcpy(newBlock, memoryPointer, bytesToCopy);
3312
3313
/* Free the old block */
3314
memoryCheck_wrapper_free_memory(portLib, memoryPointer, operationName, deallocator, paddingValue, fillValue, freedValue);
3315
}
3316
}
3317
/* Return the new pointer */
3318
return newBlock;
3319
}
3320
3321
3322
3323
3324
/*
3325
* This function is used after memcheck has shut down to prevent crashes
3326
*/
3327
static void
3328
memoryCheck_null_mem_free_memory(OMRPortLibrary *portLib, void *memoryPointer)
3329
{
3330
return;
3331
}
3332
3333
#ifdef MEMDEBUG
3334
static void
3335
subAllocator_audit(OMRPortLibrary *portLib, UDATA mask)
3336
{
3337
UDATA top = STARTIDX;
3338
UDATA bottom;
3339
UDATA i;
3340
3341
OMRPORT_ACCESS_FROM_OMRPORT(portLib);
3342
3343
freemem = 0;
3344
usedmem = 0;
3345
total = 0;
3346
freeCnt = 0;
3347
usedCnt = 0;
3348
3349
bucket[0] = bucket[1] = bucket[2] = bucket[3] = bucket[4] = bucket[5] = 0;
3350
3351
while (top < heapsize-2) {
3352
3353
bottom = top + abs(j9heap[top]);
3354
pTop = &j9heap[top];
3355
pBot = &j9heap[bottom];
3356
3357
if (j9heap[top] != j9heap[bottom]) {
3358
total = freemem + usedmem;
3359
break;
3360
}
3361
3362
if (j9heap[top] > 0) {
3363
freemem += (j9heap[top] + 1);
3364
if (mask & FREE) {
3365
j9tty_printf(NULL, "FR: %7d @ %6d ", j9heap[top], top);
3366
}
3367
freeCnt++;
3368
} else if (j9heap[top] < 0) {
3369
usedmem += (-j9heap[top] + 1);
3370
if (mask & USED) {
3371
j9tty_printf(NULL, "US: %7d @ %6d ", -j9heap[top], top);
3372
}
3373
/* arbitrary values to gauge memory usage; change as needed */
3374
if (-j9heap[top] < 10)
3375
bucket[1]++;
3376
else if (-j9heap[top] < 32)
3377
bucket[2]++;
3378
else if (-j9heap[top] < 256)
3379
bucket[3]++;
3380
else if (-j9heap[top] < 2048)
3381
bucket[4]++;
3382
else
3383
bucket[5]++;
3384
3385
usedCnt++;
3386
}
3387
3388
top = abs(j9heap[top]) + top + 1;
3389
}
3390
total = freemem + usedmem;
3391
3392
for (i=0; i<MAX_SMALL_BLOCK; i++) {
3393
if (smblkstatus[i] != 0)
3394
bucket[0]++;
3395
}
3396
3397
if (mask & AUDIT)
3398
j9tty_printf(NULL, "AUDIT: F %d U %d FC %d UC %d", freemem, usedmem, freeCnt, usedCnt);
3399
3400
if (mask & BUCKET) {
3401
j9tty_printf(NULL, "BUCKET: [%d], %d, %d, %d, %d %d",
3402
bucket[0], bucket[1], bucket[2], bucket[3], bucket[4], bucket[5]);
3403
}
3404
}
3405
#endif
3406
3407
/**
3408
* Initialize the heap, providng a pointer to the heap space and the size of the heap
3409
* These two values can be hard coded at this point, if desired.
3410
* @param[in] void* memptr -- pointer to block of memory used as a heap, or arbitrary size
3411
* @param[in] UDATA size -- size of heap block, in number of words
3412
*/
3413
static void
3414
subAllocator_init_heap(void* memptr, UDATA size)
3415
{
3416
UDATA *j9heap_local = NULL;
3417
3418
j9heap_local = (UDATA *) memptr;
3419
memset(j9heap_local, 0, sizeof(UDATA) * size);
3420
heapsize = size;
3421
3422
/* "Top", at index=2 is 0 */
3423
j9heap_local[STARTIDX-1] = 0;
3424
3425
/* Indicate the size of the initial block, at index = 3*/
3426
j9heap_local[STARTIDX] = heapsize-(STARTIDX+2);
3427
3428
/* Indicate the size of the initial starting block at the second last slot of j9heap */
3429
j9heap_local[heapsize-2] = heapsize-(STARTIDX+2);
3430
3431
/* Place a '0' at the end of the heap */
3432
j9heap_local[heapsize-1] = 0;
3433
start = STARTIDX;
3434
3435
meminuse = 0;
3436
3437
memset(smallBlock, 0, sizeof(smallBlock));
3438
memset(smblkstatus, 0, sizeof(smblkstatus));
3439
smblkindex = 0;
3440
}
3441
3442
3443
static UDATA
3444
subAllocator_findFirstFreeBlock(UDATA index, IDATA *j9heap)
3445
{
3446
IDATA val = j9heap[index];
3447
UDATA maxIndex = heapsize-2;
3448
3449
/* Logically: abs(j9heap[index]), but using IDATA width types */
3450
if (val < 0) {
3451
val *= -1;
3452
}
3453
3454
index += (val + 1);
3455
3456
while (index < maxIndex) {
3457
3458
if (j9heap[index] > 0) {
3459
return index;
3460
}
3461
index = -j9heap[index] + index + 1;
3462
}
3463
return STARTIDX;
3464
}
3465
3466
/*
3467
Release the memory block (if valid). If part of the smallBlock array, return it
3468
If in heap, coalesce with adjacent free blocks as necessary
3469
*/
3470
3471
static void
3472
subAllocator_free_memory(OMRPortLibrary *portLib, void *ptr)
3473
{
3474
UDATA top;
3475
UDATA newtop;
3476
UDATA bottom;
3477
UDATA newval;
3478
3479
OMRPORT_ACCESS_FROM_OMRPORT(portLib);
3480
3481
if ((ptr < (void*) &j9heap[0]) || (ptr > (void*) &j9heap[heapsize-2])) {
3482
if ((ptr < (void*) &smallBlock[0]) || (ptr > (void*) &smallBlock[MAX_SMALL_BLOCK - 1])) {
3483
return;
3484
}
3485
else
3486
{
3487
top = (((UDATA) ptr - (UDATA) &smallBlock[0]) / sizeof(smallBlock[0]));
3488
if (smblkstatus[top]) {
3489
smblkstatus[top] = 0;
3490
smblkindex = top;
3491
/*MSG_FATAL("SMBLK- %d @ %x", top, ptr, 0);*/
3492
return;
3493
}
3494
else
3495
/*error*/;
3496
}
3497
}
3498
top = (((UDATA) ptr - (UDATA) &j9heap[0]) / sizeof(UDATA)) - 1;
3499
3500
/* if (-(j9heap[top]) > 256)
3501
MSG_FATAL("j9 free %7d bytes @ %8X", (-j9heap[top]-1)*4, &j9heap[top+1], 0);*/
3502
#ifdef MEMDEBUG
3503
pTop = &j9heap[top];
3504
# endif
3505
if (j9heap[top] < 0) {
3506
bottom = top + -(j9heap[top]);
3507
3508
#ifdef MEMDEBUG
3509
pBot = &j9heap[bottom];
3510
#endif
3511
if (j9heap[top] == j9heap[bottom]) {
3512
j9heap[top] = -j9heap[top];
3513
j9heap[bottom] = -j9heap[bottom];
3514
3515
/* start is a signed quantity */
3516
if ((IDATA)top < start)
3517
start = top;
3518
3519
meminuse -= ((j9heap[top]+1)*sizeof(UDATA));
3520
3521
if (j9heap[top-1] > 0) {
3522
/* merge blocks */
3523
newtop = top - j9heap[top-1] - 1;
3524
j9heap[newtop] = j9heap[top] + j9heap[top-1] + 1;
3525
j9heap[bottom] = j9heap[newtop];
3526
3527
/* start is a signed quantity */
3528
if ((IDATA)newtop < start)
3529
start = newtop;
3530
}
3531
3532
if (j9heap[bottom+1] > 0) {
3533
newval = j9heap[bottom] + j9heap[bottom+1] + 1;
3534
j9heap[bottom + j9heap[bottom + 1] + 1 ] = newval;
3535
newtop = bottom - j9heap[bottom];
3536
j9heap[ newtop ] = newval;
3537
3538
/* start is a signed quantity */
3539
if ((IDATA)newtop < start)
3540
start = newtop;
3541
}
3542
#ifdef MEMDEBUG
3543
subAllocator_audit(portLib, j9heap, AUDIT|BUCKET);
3544
#endif
3545
return;
3546
}
3547
}
3548
start = STARTIDX;
3549
}
3550
3551
/*
3552
allocate a block of size bytes from the heap, using a minimum of FRAGTHRESHOLD words
3553
*/
3554
3555
static void*
3556
subAllocator_allocate_memory(OMRPortLibrary *portLib, UDATA byteAmount, const char *callSite, U_32 category)
3557
{
3558
IDATA size = (IDATA) byteAmount;
3559
UDATA idx;
3560
const UDATA maxIndex = heapsize-2;
3561
UDATA newstart;
3562
3563
/* round to even heap slot (32/64 bit amount) */
3564
size = ((size + (sizeof(UDATA)-1)) & ~(sizeof(UDATA)-1)) / sizeof(UDATA);
3565
3566
if (size <= FRAGTHRESHOLD)
3567
{
3568
UDATA idx = smblkindex;
3569
while (idx < MAX_SMALL_BLOCK) {
3570
if (0 == smblkstatus[idx])
3571
{
3572
memset(&smallBlock[idx], 0, sizeof(smallBlock[idx]));
3573
smblkstatus [idx] = 1;
3574
/*MSG_FATAL("SMBLK+ %d @ %x", idx, &smallBlock[idx], 0);*/
3575
return &smallBlock[idx];
3576
}
3577
else
3578
{
3579
if (++idx >= MAX_SMALL_BLOCK)
3580
idx = 0;
3581
else if (idx == smblkindex)
3582
break;
3583
}
3584
}
3585
}
3586
3587
#ifdef MEMDEBUG
3588
subAllocator_audit(portLib, j9heap, AUDIT|BUCKET);
3589
#endif
3590
3591
idx = start;
3592
3593
while (idx < maxIndex)
3594
{
3595
if (j9heap [idx] >= size + 1) {
3596
3597
if (j9heap[idx] > size + FRAGTHRESHOLD ) {
3598
j9heap[idx + j9heap[idx]] -= (size + 2);
3599
newstart = idx + size + 2;
3600
j9heap[newstart] = j9heap[idx + j9heap[idx]];
3601
if (start == idx)
3602
start = newstart;
3603
}
3604
else {
3605
/* current block too small to split, use whole thing */
3606
size = j9heap[idx] - 1;
3607
if (start == idx)
3608
start =subAllocator_findFirstFreeBlock(idx, (IDATA *)j9heap);
3609
}
3610
3611
#ifdef MEMDEBUG
3612
pTop = &j9heap[idx];
3613
pBot = &j9heap[idx + size + 1];
3614
#endif
3615
3616
j9heap[idx + size + 1] = -(size + 1);
3617
j9heap[idx] = -(size + 1);
3618
memset(&j9heap[idx+1], 0, size*sizeof(UDATA));
3619
3620
meminuse += ((size+1)*sizeof(UDATA));
3621
3622
#ifdef MEMDEBUG
3623
if (meminuse > (((heapsize/sizeof(UDATA))*3)*sizeof(UDATA))) {
3624
subAllocator_audit(portLib, j9heap, AUDIT|BUCKET|FREE);
3625
}
3626
#endif
3627
/* if (size > 256)
3628
MSG_FATAL("j9 malloc %7d bytes @ %8X", size*4, &j9heap[idx+1], 0);*/
3629
return &j9heap[idx+1];
3630
}
3631
else {
3632
IDATA absoluteIdx = j9heap[idx];
3633
if (absoluteIdx < 0) {
3634
absoluteIdx *= -1;
3635
}
3636
idx = absoluteIdx + idx + 1;
3637
}
3638
}
3639
#ifdef MEMDEBUG
3640
subAllocator_audit(portLib, j9heap, AUDIT|FREE|BUCKET|USED);
3641
#endif
3642
/* MSG_FATAL("j9 malloc fail, sz %d", size*4, 0, 0); */
3643
return 0;
3644
}
3645
3646