/** * Frees memory and adjusts pointers. * * @param pointer pointer to delete * @param addr pointer to the caller * @param is_array flag indicating whether it is invoked by a * <code>delete[]</code> call */ void __debug_new_recorder::free_pointer(void* pointer, void* addr, bool is_array) { if (pointer == NULL) { return; } new_ptr_list_t* ptr = (new_ptr_list_t*)((char*)pointer - ALIGNED_LIST_ITEM_SIZE); if (ptr->magic != MAGIC) { { fast_mutex_autolock lock(new_output_lock); const char * msg_out = "[QxOrm] delete%s: invalid pointer %p"; Q_UNUSED(msg_out); qDebug(msg_out, (is_array ? "[]" : ""), pointer); } check_mem_corruption(); fflush(new_output_fp); _DEBUG_NEW_ERROR_ACTION; } if (is_array != ptr->is_array) { const char * msg; if (is_array) { msg = "[QxOrm] delete[] after new"; } else { msg = "[QxOrm] delete after new[]"; } fast_mutex_autolock lock(new_output_lock); const char * msg_out_file = "[QxOrm] %s: pointer %p (size %u)\n\tat %p\n\toriginally allocated at %s:%d"; Q_UNUSED(msg_out_file); const char * msg_out_no_file = "[QxOrm] %s: pointer %p (size %u)\n\tat %p\n\toriginally allocated at <Unknown>"; Q_UNUSED(msg_out_no_file); if (ptr->line != 0) { qDebug(msg_out_file, msg, ((char*)ptr + ALIGNED_LIST_ITEM_SIZE), ptr->size, addr, ptr->file, ptr->line); } #if (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) else { qDebug(msg_out_no_file, msg, ((char*)ptr + ALIGNED_LIST_ITEM_SIZE), ptr->size, addr); } #endif // (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) fflush(new_output_fp); _DEBUG_NEW_ERROR_ACTION; } #if _DEBUG_NEW_TAILCHECK if (!check_tail(ptr)) { check_mem_corruption(); fflush(new_output_fp); _DEBUG_NEW_ERROR_ACTION; } #endif { fast_mutex_autolock lock(new_ptr_lock); total_mem_alloc -= ptr->size; ptr->magic = 0; ptr->prev->next = ptr->next; ptr->next->prev = ptr->prev; } if (new_verbose_flag) { fast_mutex_autolock lock(new_output_lock); const char * msg_out = "[QxOrm] delete%s: freed %p (size %u, %u bytes still allocated)"; Q_UNUSED(msg_out); qDebug(msg_out, (is_array ? "[]" : ""), ((char*)ptr + ALIGNED_LIST_ITEM_SIZE), ptr->size, total_mem_alloc); } free(ptr); return; }
/** * Checks for memory leaks. * * @return zero if no leakage is found; the number of leaks otherwise */ int check_leaks() { int leak_cnt = 0; fast_mutex_autolock lock_ptr(new_ptr_lock); fast_mutex_autolock lock_output(new_output_lock); new_ptr_list_t* ptr = new_ptr_list.next; while (ptr != &new_ptr_list) { const char* const pointer = (char*)ptr + ALIGNED_LIST_ITEM_SIZE; if (ptr->magic != MAGIC) { fprintf(new_output_fp, "warning: heap data corrupt near %p\n", pointer); } #if _DEBUG_NEW_TAILCHECK if (!check_tail(ptr)) { fprintf(new_output_fp, "warning: overwritten past end of object at %p\n", pointer); } #endif fprintf(new_output_fp, "Leaked object at %p (size %lu, ", pointer, (unsigned long)ptr->size); if (ptr->line != 0) print_position(ptr->file, ptr->line); else print_position(ptr->addr, ptr->line); if( new_verbose_flag ) { fprintf(new_output_fp, "):\n"); dump_leak(pointer, ptr); } else { fprintf(new_output_fp, ")\n"); } ptr = ptr->next; ++leak_cnt; } if (new_verbose_flag || leak_cnt) fprintf(new_output_fp, "*** %d leaks found\n", leak_cnt); return leak_cnt; }
/** * Checks for heap corruption. * * @return zero if no problem is found; the number of found memory * corruptions otherwise */ int check_mem_corruption() { int corrupt_cnt = 0; fast_mutex_autolock lock_ptr(new_ptr_lock); fast_mutex_autolock lock_output(new_output_lock); fprintf(new_output_fp, "*** Checking for memory corruption: START\n"); for (new_ptr_list_t* ptr = new_ptr_list.next; ptr != &new_ptr_list; ptr = ptr->next) { const char* const pointer = (char*)ptr + ALIGNED_LIST_ITEM_SIZE; if (ptr->magic == MAGIC #if _DEBUG_NEW_TAILCHECK && check_tail(ptr) #endif ) continue; #if _DEBUG_NEW_TAILCHECK if (ptr->magic != MAGIC) { #endif fprintf(new_output_fp, "Heap data corrupt near %p (size %lu, ", pointer, (unsigned long)ptr->size); #if _DEBUG_NEW_TAILCHECK } else { fprintf(new_output_fp, "Overwritten past end of object at %p (size %lu, ", pointer, (unsigned long)ptr->size); } #endif if (ptr->line != 0) print_position(ptr->file, ptr->line); else print_position(ptr->addr, ptr->line); fprintf(new_output_fp, ")\n"); ++corrupt_cnt; } fprintf(new_output_fp, "*** Checking for memory corruption: %d FOUND\n", corrupt_cnt); return corrupt_cnt; }
/** * Checks for heap corruption. * * @return zero if no problem is found; the number of found memory * corruptions otherwise */ int check_mem_corruption() { int corrupt_cnt = 0; fast_mutex_autolock lock_ptr(new_ptr_lock); fast_mutex_autolock lock_output(new_output_lock); const char * msg_out_check_mem_start = "[QxOrm] **** Checking for memory corruption: START ****"; Q_UNUSED(msg_out_check_mem_start); qDebug("%s", msg_out_check_mem_start); for (new_ptr_list_t* ptr = new_ptr_list.next; ptr != &new_ptr_list; ptr = ptr->next) { const char* const pointer = (char*)ptr + ALIGNED_LIST_ITEM_SIZE; if (ptr->magic == MAGIC #if _DEBUG_NEW_TAILCHECK && check_tail(ptr) #endif ) continue; #if _DEBUG_NEW_TAILCHECK if (ptr->magic != MAGIC) { #endif const char * msg_out_file = "[QxOrm] Heap data corrupt near %p (size %u, %s:%d)"; Q_UNUSED(msg_out_file); const char * msg_out_no_file = "[QxOrm] Heap data corrupt near %p (size %u, <Unknown>)"; Q_UNUSED(msg_out_no_file); if (ptr->line != 0) { qDebug(msg_out_file, pointer, ptr->size, ptr->file, ptr->line); ++corrupt_cnt; } #if (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) else { qDebug(msg_out_no_file, pointer, ptr->size); ++corrupt_cnt; } #endif // (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) #if _DEBUG_NEW_TAILCHECK } else { const char * msg_out_file = "[QxOrm] Overwritten past end of object at %p (size %u, %s:%d)"; Q_UNUSED(msg_out_file); const char * msg_out_no_file = "[QxOrm] Overwritten past end of object at %p (size %u, <Unknown>)"; Q_UNUSED(msg_out_no_file); if (ptr->line != 0) { qDebug(msg_out_file, pointer, ptr->size, ptr->file, ptr->line); ++corrupt_cnt; } #if (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) else { qDebug(msg_out_no_file, pointer, ptr->size); ++corrupt_cnt; } #endif // (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) } #endif } const char * msg_out_check_mem_end = "[QxOrm] **** Checking for memory corruption: %d FOUND ****"; Q_UNUSED(msg_out_check_mem_end); qDebug(msg_out_check_mem_end, corrupt_cnt); return corrupt_cnt; }
/** * Checks for memory leaks. * * @return zero if no leakage is found; the number of leaks otherwise */ int check_leaks() { int leak_cnt = 0; fast_mutex_autolock lock_ptr(new_ptr_lock); fast_mutex_autolock lock_output(new_output_lock); new_ptr_list_t* ptr = new_ptr_list.next; while (ptr != &new_ptr_list) { const char* const pointer = (char*)ptr + ALIGNED_LIST_ITEM_SIZE; if (ptr->magic != MAGIC) { const char * msg_out = "[QxOrm] warning: heap data corrupt near %p"; Q_UNUSED(msg_out); qDebug(msg_out, pointer); } #if _DEBUG_NEW_TAILCHECK if (!check_tail(ptr)) { const char * msg_out = "[QxOrm] warning: overwritten past end of object at %p"; Q_UNUSED(msg_out); qDebug(msg_out, pointer); } #endif const char * msg_out_file = "[QxOrm] Leaked object at %p (size %u, %s:%d)"; Q_UNUSED(msg_out_file); const char * msg_out_no_file = "[QxOrm] Leaked object at %p (size %u, <Unknown>)"; Q_UNUSED(msg_out_no_file); if (ptr->line != 0) { qDebug(msg_out_file, pointer, ptr->size, ptr->file, ptr->line); ++leak_cnt; } #if (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) else { qDebug(msg_out_no_file, pointer, ptr->size); ++leak_cnt; } #endif // (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) ptr = ptr->next; } if (new_verbose_flag || leak_cnt) { const char * msg_out_leak_cnt = "[QxOrm] **** %d memory leaks found ****"; Q_UNUSED(msg_out_leak_cnt); qDebug(msg_out_leak_cnt, leak_cnt); } return leak_cnt; }
/** * Frees memory and adjusts pointers. * * @param pointer pointer to the previously allocated memory * @param addr pointer to the caller * @param is_array flag indicating whether it is invoked by a * <code>delete[]</code> call */ static void free_pointer(void* pointer, void* addr, bool is_array) { if (pointer == NULL) return; new_ptr_list_t* ptr = (new_ptr_list_t*)((char*)pointer - ALIGNED_LIST_ITEM_SIZE); if (ptr->magic != MAGIC) { { fast_mutex_autolock lock(new_output_lock); fprintf(new_output_fp, "delete%s: invalid pointer %p (", is_array ? "[]" : "", pointer); print_position(addr, 0); fprintf(new_output_fp, ")\n"); } check_mem_corruption(); fflush(new_output_fp); _DEBUG_NEW_ERROR_ACTION; } if (is_array != ptr->is_array) { const char* msg; if (is_array) msg = "delete[] after new"; else msg = "delete after new[]"; fast_mutex_autolock lock(new_output_lock); fprintf(new_output_fp, "%s: pointer %p (size %lu)\n\tat ", msg, (char*)ptr + ALIGNED_LIST_ITEM_SIZE, (unsigned long)ptr->size); print_position(addr, 0); fprintf(new_output_fp, "\n\toriginally allocated at "); if (ptr->line != 0) print_position(ptr->file, ptr->line); else print_position(ptr->addr, ptr->line); fprintf(new_output_fp, "\n"); fflush(new_output_fp); _DEBUG_NEW_ERROR_ACTION; } #if _DEBUG_NEW_TAILCHECK if (!check_tail(ptr)) { check_mem_corruption(); fflush(new_output_fp); _DEBUG_NEW_ERROR_ACTION; } #endif { fast_mutex_autolock lock(new_ptr_lock); total_mem_alloc -= ptr->size; ptr->magic = 0; ptr->prev->next = ptr->next; ptr->next->prev = ptr->prev; } if (new_verbose_flag) { fast_mutex_autolock lock(new_output_lock); fprintf(new_output_fp, "delete%s: freed %p (size %lu, %lu bytes still allocated)\n", is_array ? "[]" : "", (char*)ptr + ALIGNED_LIST_ITEM_SIZE, (unsigned long)ptr->size, (unsigned long)total_mem_alloc); } free(ptr); return; }