static BloatEntry* GetBloatEntry(const char* aTypeName, uint32_t aInstanceSize) { if (!gBloatView) { RecreateBloatView(); } BloatEntry* entry = NULL; if (gBloatView) { entry = (BloatEntry*)PL_HashTableLookup(gBloatView, aTypeName); if (entry == NULL && aInstanceSize > 0) { entry = new BloatEntry(aTypeName, aInstanceSize); PLHashEntry* e = PL_HashTableAdd(gBloatView, aTypeName, entry); if (e == NULL) { delete entry; entry = NULL; } } else { NS_ASSERTION(aInstanceSize == 0 || entry->GetClassSize() == aInstanceSize, "bad size recorded"); } } return entry; }
static BloatEntry* GetBloatEntry(const char* aTypeName, uint32_t aInstanceSize) { if (!gBloatView) { RecreateBloatView(); } BloatEntry* entry = nullptr; if (gBloatView) { entry = (BloatEntry*)PL_HashTableLookup(gBloatView, aTypeName); if (!entry && aInstanceSize > 0) { entry = new BloatEntry(aTypeName, aInstanceSize); PLHashEntry* e = PL_HashTableAdd(gBloatView, aTypeName, entry); if (!e) { delete entry; entry = nullptr; } } else { #ifdef DEBUG static const char kMismatchedSizesMessage[] = "Mismatched sizes were recorded in the memory leak logging table. " "The usual cause of this is having a templated class that uses " "MOZ_COUNT_{C,D}TOR in the constructor or destructor, respectively. " "As a workaround, the MOZ_COUNT_{C,D}TOR calls can be moved to a " "non-templated base class."; NS_ASSERTION(aInstanceSize == 0 || entry->GetClassSize() == aInstanceSize, kMismatchedSizesMessage); #endif } } return entry; }
static void InitTraceLog(void) { if (gInitialized) return; gInitialized = true; bool defined; defined = InitLog("XPCOM_MEM_BLOAT_LOG", "bloat/leaks", &gBloatLog); if (!defined) gLogLeaksOnly = InitLog("XPCOM_MEM_LEAK_LOG", "leaks", &gBloatLog); if (defined || gLogLeaksOnly) { RecreateBloatView(); if (!gBloatView) { NS_WARNING("out of memory"); gBloatLog = nullptr; gLogLeaksOnly = false; } } (void)InitLog("XPCOM_MEM_REFCNT_LOG", "refcounts", &gRefcntsLog); (void)InitLog("XPCOM_MEM_ALLOC_LOG", "new/delete", &gAllocLog); defined = InitLog("XPCOM_MEM_LEAKY_LOG", "for leaky", &gLeakyLog); if (defined) { gLogToLeaky = true; PRFuncPtr p = nullptr, q = nullptr; #ifdef HAVE_DLOPEN { PRLibrary *lib = nullptr; p = PR_FindFunctionSymbolAndLibrary("__log_addref", &lib); if (lib) { PR_UnloadLibrary(lib); lib = nullptr; } q = PR_FindFunctionSymbolAndLibrary("__log_release", &lib); if (lib) { PR_UnloadLibrary(lib); } } #endif if (p && q) { leakyLogAddRef = (void (*)(void*,int,int)) p; leakyLogRelease = (void (*)(void*,int,int)) q; } else { gLogToLeaky = false; fprintf(stdout, "### ERROR: XPCOM_MEM_LEAKY_LOG defined, but can't locate __log_addref and __log_release symbols\n"); fflush(stdout); } } const char* classes = getenv("XPCOM_MEM_LOG_CLASSES"); #ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR if (classes) { (void)InitLog("XPCOM_MEM_COMPTR_LOG", "nsCOMPtr", &gCOMPtrLog); } else { if (getenv("XPCOM_MEM_COMPTR_LOG")) { fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but XPCOM_MEM_LOG_CLASSES is not defined\n"); } } #else const char* comptr_log = getenv("XPCOM_MEM_COMPTR_LOG"); if (comptr_log) { fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but it will not work without dynamic_cast\n"); } #endif if (classes) { // if XPCOM_MEM_LOG_CLASSES was set to some value, the value is interpreted // as a list of class names to track gTypesToLog = PL_NewHashTable(256, PL_HashString, PL_CompareStrings, PL_CompareValues, &typesToLogHashAllocOps, NULL); if (!gTypesToLog) { NS_WARNING("out of memory"); fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- unable to log specific classes\n"); } else { fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- only logging these classes: "); const char* cp = classes; for (;;) { char* cm = (char*) strchr(cp, ','); if (cm) { *cm = '\0'; } PL_HashTableAdd(gTypesToLog, nsCRT::strdup(cp), (void*)1); fprintf(stdout, "%s ", cp); if (!cm) break; *cm = ','; cp = cm + 1; } fprintf(stdout, "\n"); } gSerialNumbers = PL_NewHashTable(256, HashNumber, PL_CompareValues, PL_CompareValues, &serialNumberHashAllocOps, NULL); } const char* objects = getenv("XPCOM_MEM_LOG_OBJECTS"); if (objects) { gObjectsToLog = PL_NewHashTable(256, HashNumber, PL_CompareValues, PL_CompareValues, NULL, NULL); if (!gObjectsToLog) { NS_WARNING("out of memory"); fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- unable to log specific objects\n"); } else if (! (gRefcntsLog || gAllocLog || gCOMPtrLog)) { fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- but none of XPCOM_MEM_(REFCNT|ALLOC|COMPTR)_LOG is defined\n"); } else { fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- only logging these objects: "); const char* cp = objects; for (;;) { char* cm = (char*) strchr(cp, ','); if (cm) { *cm = '\0'; } intptr_t top = 0; intptr_t bottom = 0; while (*cp) { if (*cp == '-') { bottom = top; top = 0; ++cp; } top *= 10; top += *cp - '0'; ++cp; } if (!bottom) { bottom = top; } for (intptr_t serialno = bottom; serialno <= top; serialno++) { PL_HashTableAdd(gObjectsToLog, (const void*)serialno, (void*)1); fprintf(stdout, "%ld ", serialno); } if (!cm) break; *cm = ','; cp = cm + 1; } fprintf(stdout, "\n"); } } if (gBloatLog || gRefcntsLog || gAllocLog || gLeakyLog || gCOMPtrLog) { gLogging = true; } gTraceLock = PR_NewLock(); }
static void InitTraceLog() { if (gInitialized) { return; } gInitialized = true; bool defined = InitLog("XPCOM_MEM_BLOAT_LOG", "bloat/leaks", &gBloatLog); if (!defined) { gLogLeaksOnly = InitLog("XPCOM_MEM_LEAK_LOG", "leaks", &gBloatLog); } if (defined || gLogLeaksOnly) { RecreateBloatView(); if (!gBloatView) { NS_WARNING("out of memory"); maybeUnregisterAndCloseFile(gBloatLog); gLogLeaksOnly = false; } } InitLog("XPCOM_MEM_REFCNT_LOG", "refcounts", &gRefcntsLog); InitLog("XPCOM_MEM_ALLOC_LOG", "new/delete", &gAllocLog); const char* classes = getenv("XPCOM_MEM_LOG_CLASSES"); #ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR if (classes) { InitLog("XPCOM_MEM_COMPTR_LOG", "nsCOMPtr", &gCOMPtrLog); } else { if (getenv("XPCOM_MEM_COMPTR_LOG")) { fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but XPCOM_MEM_LOG_CLASSES is not defined\n"); } } #else const char* comptr_log = getenv("XPCOM_MEM_COMPTR_LOG"); if (comptr_log) { fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but it will not work without dynamic_cast\n"); } #endif if (classes) { // if XPCOM_MEM_LOG_CLASSES was set to some value, the value is interpreted // as a list of class names to track gTypesToLog = PL_NewHashTable(256, PL_HashString, PL_CompareStrings, PL_CompareValues, &typesToLogHashAllocOps, nullptr); if (!gTypesToLog) { NS_WARNING("out of memory"); fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- unable to log specific classes\n"); } else { fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- only logging these classes: "); const char* cp = classes; for (;;) { char* cm = (char*)strchr(cp, ','); if (cm) { *cm = '\0'; } PL_HashTableAdd(gTypesToLog, strdup(cp), (void*)1); fprintf(stdout, "%s ", cp); if (!cm) { break; } *cm = ','; cp = cm + 1; } fprintf(stdout, "\n"); } gSerialNumbers = PL_NewHashTable(256, HashNumber, PL_CompareValues, PL_CompareValues, &serialNumberHashAllocOps, nullptr); } const char* objects = getenv("XPCOM_MEM_LOG_OBJECTS"); if (objects) { gObjectsToLog = PL_NewHashTable(256, HashNumber, PL_CompareValues, PL_CompareValues, nullptr, nullptr); if (!gObjectsToLog) { NS_WARNING("out of memory"); fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- unable to log specific objects\n"); } else if (!(gRefcntsLog || gAllocLog || gCOMPtrLog)) { fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- but none of XPCOM_MEM_(REFCNT|ALLOC|COMPTR)_LOG is defined\n"); } else { fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- only logging these objects: "); const char* cp = objects; for (;;) { char* cm = (char*)strchr(cp, ','); if (cm) { *cm = '\0'; } intptr_t top = 0; intptr_t bottom = 0; while (*cp) { if (*cp == '-') { bottom = top; top = 0; ++cp; } top *= 10; top += *cp - '0'; ++cp; } if (!bottom) { bottom = top; } for (intptr_t serialno = bottom; serialno <= top; serialno++) { PL_HashTableAdd(gObjectsToLog, (const void*)serialno, (void*)1); fprintf(stdout, "%" PRIdPTR " ", serialno); } if (!cm) { break; } *cm = ','; cp = cm + 1; } fprintf(stdout, "\n"); } } if (gBloatLog) { gLogging = OnlyBloatLogging; } if (gRefcntsLog || gAllocLog || gCOMPtrLog) { gLogging = FullLogging; } gTraceLock = PR_NewLock(); }