1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- The leak checker. mc_leakcheck.c ---*/ 4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This file is part of MemCheck, a heavyweight Valgrind tool for 8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown detecting memory errors. 9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 10b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Copyright (C) 2000-2011 Julian Seward 11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown jseward@acm.org 12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This program is free software; you can redistribute it and/or 14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown modify it under the terms of the GNU General Public License as 15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown published by the Free Software Foundation; either version 2 of the 16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown License, or (at your option) any later version. 17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This program is distributed in the hope that it will be useful, but 19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown WITHOUT ANY WARRANTY; without even the implied warranty of 20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown General Public License for more details. 22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown You should have received a copy of the GNU General Public License 24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown along with this program; if not, write to the Free Software 25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 02111-1307, USA. 27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The GNU General Public License is contained in the file COPYING. 29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_basics.h" 32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_vki.h" 33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_aspacehl.h" 34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_aspacemgr.h" 35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_execontext.h" 36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_hashtable.h" 37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcbase.h" 38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcassert.h" 39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcprint.h" 40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcsignal.h" 41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_machine.h" 42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_mallocfree.h" 43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_options.h" 44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_oset.h" 45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_signals.h" 46b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include "pub_tool_libcsetjmp.h" // setjmp facilities 47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_tooliface.h" // Needed for mc_include.h 48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "mc_include.h" 50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- An overview of leak checking. ---*/ 53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Leak-checking is a directed-graph traversal problem. The graph has 56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// two kinds of nodes: 57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - root-set nodes: 58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - GP registers of all threads; 59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - valid, aligned, pointer-sized data words in valid client memory, 60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// including stacks, but excluding words within client heap-allocated 61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// blocks (they are excluded so that later on we can differentiate 62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// between heap blocks that are indirectly leaked vs. directly leaked). 63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - heap-allocated blocks. A block is a mempool chunk or a malloc chunk 64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// that doesn't contain a mempool chunk. Nb: the terms "blocks" and 65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// "chunks" are used interchangeably below. 66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// There are two kinds of edges: 68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - start-pointers, i.e. pointers to the start of a block; 69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - interior-pointers, i.e. pointers to the interior of a block. 70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// We use "pointers" rather than "edges" below. 72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Root set nodes only point to blocks. Blocks only point to blocks; 74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// a block can point to itself. 75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// The aim is to traverse the graph and determine the status of each block. 77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// There are 9 distinct cases. See memcheck/docs/mc-manual.xml for details. 79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Presenting all nine categories to the user is probably too much. 80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Currently we do this: 81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - definitely lost: case 3 82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - indirectly lost: case 4, 9 83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - possibly lost: cases 5..8 84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - still reachable: cases 1, 2 85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// It's far from clear that this is the best possible categorisation; it's 87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// accreted over time without any central guiding principle. 88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- XXX: Thoughts for improvement. ---*/ 91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// From the user's point of view: 94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - If they aren't using interior-pointers, they just have to fix the 95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// directly lost blocks, and the indirectly lost ones will be fixed as 96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// part of that. Any possibly lost blocks will just be due to random 97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// pointer garbage and can be ignored. 98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - If they are using interior-pointers, the fact that they currently are not 100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// being told which ones might be directly lost vs. indirectly lost makes 101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// it hard to know where to begin. 102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// All this makes me wonder if new option is warranted: 104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// --follow-interior-pointers. By default it would be off, the leak checker 105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// wouldn't follow interior-pointers and there would only be 3 categories: 106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// R, DL, IL. 107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// If turned on, then it would show 7 categories (R, DL, IL, DR/DL, IR/IL, 109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// IR/IL/DL, IL/DL). That output is harder to understand but it's your own 110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// damn fault for using interior-pointers... 111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ---- 113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Also, why are two blank lines printed between each loss record? 115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// [bug 197930] 116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ---- 118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Also, --show-reachable is a bad name because it also turns on the showing 120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// of indirectly leaked blocks(!) It would be better named --show-all or 121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// --show-all-heap-blocks, because that's the end result. 122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ---- 124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Also, the VALGRIND_LEAK_CHECK and VALGRIND_QUICK_LEAK_CHECK aren't great 126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// names. VALGRIND_FULL_LEAK_CHECK and VALGRIND_SUMMARY_LEAK_CHECK would be 127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// better. 128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ---- 130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Also, VALGRIND_COUNT_LEAKS and VALGRIND_COUNT_LEAK_BLOCKS aren't great as 132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// they combine direct leaks and indirect leaks into one. New, more precise 133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ones (they'll need new names) would be good. If more categories are 134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// used, as per the --follow-interior-pointers option, they should be 135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// updated accordingly. And they should use a struct to return the values. 136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ---- 138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Also, for this case: 140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// (4) p4 BBB ---> AAA 142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// BBB is definitely directly lost. AAA is definitely indirectly lost. 144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Here's the relevant loss records printed for a full check (each block is 145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 16 bytes): 146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ==20397== 16 bytes in 1 blocks are indirectly lost in loss record 9 of 15 148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ==20397== at 0x4C2694E: malloc (vg_replace_malloc.c:177) 149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ==20397== by 0x400521: mk (leak-cases.c:49) 150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ==20397== by 0x400578: main (leak-cases.c:72) 151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ==20397== 32 (16 direct, 16 indirect) bytes in 1 blocks are definitely 153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// lost in loss record 14 of 15 154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ==20397== at 0x4C2694E: malloc (vg_replace_malloc.c:177) 155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ==20397== by 0x400521: mk (leak-cases.c:49) 156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ==20397== by 0x400580: main (leak-cases.c:72) 157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// The first one is fine -- it describes AAA. 159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// The second one is for BBB. It's correct in that 16 bytes in 1 block are 161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// directly lost. It's also correct that 16 are indirectly lost as a result, 162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// but it means that AAA is being counted twice in the loss records. (It's 163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// not, thankfully, counted twice in the summary counts). Argh. 164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// This would be less confusing for the second one: 166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ==20397== 16 bytes in 1 blocks are definitely lost in loss record 14 168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// of 15 (and 16 bytes in 1 block are indirectly lost as a result; they 169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// are mentioned elsewhere (if --show-reachable=yes is given!)) 170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ==20397== at 0x4C2694E: malloc (vg_replace_malloc.c:177) 171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ==20397== by 0x400521: mk (leak-cases.c:49) 172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ==20397== by 0x400580: main (leak-cases.c:72) 173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// But ideally we'd present the loss record for the directly lost block and 175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// then the resultant indirectly lost blocks and make it clear the 176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// dependence. Double argh. 177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- The actual algorithm. ---*/ 180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Find all the blocks (a.k.a. chunks) to check. Mempool chunks require 183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// some special treatment because they can be within malloc'd blocks. 184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Scan every word in the root set (GP registers and valid 185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// non-heap memory words). 186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - First, we skip if it doesn't point to valid memory. 187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Then, we see if it points to the start or interior of a block. If 188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// so, we push the block onto the mark stack and mark it as having been 189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// reached. 190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Then, we process the mark stack, repeating the scanning for each block; 191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// this can push more blocks onto the mark stack. We repeat until the 192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// mark stack is empty. Each block is marked as definitely or possibly 193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// reachable, depending on whether interior-pointers were required to 194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// reach it. 195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - At this point we know for every block if it's reachable or not. 196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - We then push each unreached block onto the mark stack, using the block 197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// number as the "clique" number. 198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - We process the mark stack again, this time grouping blocks into cliques 199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// in order to facilitate the directly/indirectly lost categorisation. 200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - We group blocks by their ExeContexts and categorisation, and print them 201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// if --leak-check=full. We also print summary numbers. 202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// A note on "cliques": 204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - A directly lost block is one with no pointers to it. An indirectly 205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// lost block is one that is pointed to by a directly or indirectly lost 206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// block. 207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Each directly lost block has zero or more indirectly lost blocks 208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// hanging off it. All these blocks together form a "clique". The 209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// directly lost block is called the "clique leader". The clique number 210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// is the number (in lc_chunks[]) of the clique leader. 211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Actually, a directly lost block may be pointed to if it's part of a 212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// cycle. In that case, there may be more than one choice for the clique 213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// leader, and the choice is arbitrary. Eg. if you have A-->B and B-->A 214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// either A or B could be the clique leader. 215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Cliques cannot overlap, and will be truncated to avoid this. Eg. if we 216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// have A-->C and B-->C, the two cliques will be {A,C} and {B}, or {A} and 217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// {B,C} (again the choice is arbitrary). This is because we don't want 218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// to count a block as indirectly lost more than once. 219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// A note on 'is_prior_definite': 221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - This is a boolean used in various places that indicates if the chain 222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// up to the prior node (prior to the one being considered) is definite. 223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - In the clique == -1 case: 224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - if True it means that the prior node is a root-set node, or that the 225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// prior node is a block which is reachable from the root-set via 226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// start-pointers. 227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - if False it means that the prior node is a block that is only 228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// reachable from the root-set via a path including at least one 229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// interior-pointer. 230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - In the clique != -1 case, currently it's always True because we treat 231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// start-pointers and interior-pointers the same for direct/indirect leak 232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// checking. If we added a PossibleIndirectLeak state then this would 233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// change. 234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Define to debug the memory-leak-detector. 237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define VG_DEBUG_LEAKCHECK 0 238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define VG_DEBUG_CLIQUE 0 239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Getting the initial chunks, and searching them. ---*/ 243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Compare the MC_Chunks by 'data' (i.e. the address of the block). 246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int compare_MC_Chunks(void* n1, void* n2) 247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_Chunk* mc1 = *(MC_Chunk**)n1; 249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_Chunk* mc2 = *(MC_Chunk**)n2; 250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (mc1->data < mc2->data) return -1; 251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (mc1->data > mc2->data) return 1; 252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if VG_DEBUG_LEAKCHECK 256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Used to sanity-check the fast binary-search mechanism. 257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic 258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt find_chunk_for_OLD ( Addr ptr, 259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_Chunk** chunks, 260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int n_chunks ) 261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i; 264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr a_lo, a_hi; 265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown PROF_EVENT(70, "find_chunk_for_OLD"); 266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < n_chunks; i++) { 267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown PROF_EVENT(71, "find_chunk_for_OLD(loop)"); 268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown a_lo = chunks[i]->data; 269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown a_hi = ((Addr)chunks[i]->data) + chunks[i]->szB; 270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (a_lo <= ptr && ptr < a_hi) 271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return i; 272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return -1; 274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Find the i such that ptr points at or inside the block described by 278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// chunks[i]. Return -1 if none found. This assumes that chunks[] 279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// has been sorted on the 'data' field. 280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic 281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt find_chunk_for ( Addr ptr, 282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_Chunk** chunks, 283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int n_chunks ) 284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr a_mid_lo, a_mid_hi; 286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int lo, mid, hi, retVal; 287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // VG_(printf)("find chunk for %p = ", ptr); 288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown retVal = -1; 289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lo = 0; 290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown hi = n_chunks-1; 291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (True) { 292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Invariant: current unsearched space is from lo to hi, inclusive. 293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (lo > hi) break; // not found 294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mid = (lo + hi) / 2; 296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown a_mid_lo = chunks[mid]->data; 297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown a_mid_hi = chunks[mid]->data + chunks[mid]->szB; 298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Extent of block 'mid' is [a_mid_lo .. a_mid_hi). 299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Special-case zero-sized blocks - treat them as if they had 300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // size 1. Not doing so causes them to not cover any address 301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // range at all and so will never be identified as the target of 302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // any pointer, which causes them to be incorrectly reported as 303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // definitely leaked. 304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (chunks[mid]->szB == 0) 305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown a_mid_hi++; 306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ptr < a_mid_lo) { 308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown hi = mid-1; 309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ptr >= a_mid_hi) { 312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lo = mid+1; 313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(ptr >= a_mid_lo && ptr < a_mid_hi); 316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown retVal = mid; 317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# if VG_DEBUG_LEAKCHECK 321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(retVal == find_chunk_for_OLD ( ptr, chunks, n_chunks )); 322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif 323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // VG_(printf)("%d\n", retVal); 324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return retVal; 325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic MC_Chunk** 329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownfind_active_chunks(UInt* pn_chunks) 330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Our goal is to construct a set of chunks that includes every 332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // mempool chunk, and every malloc region that *doesn't* contain a 333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // mempool chunk. 334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_Mempool *mp; 335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_Chunk **mallocs, **chunks, *mc; 336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt n_mallocs, n_chunks, m, s; 337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool *malloc_chunk_holds_a_pool_chunk; 338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // First we collect all the malloc chunks into an array and sort it. 340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // We do this because we want to query the chunks by interior 341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // pointers, requiring binary search. 342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mallocs = (MC_Chunk**) VG_(HT_to_array)( MC_(malloc_list), &n_mallocs ); 343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (n_mallocs == 0) { 344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(mallocs == NULL); 345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *pn_chunks = 0; 346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return NULL; 347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(ssort)(mallocs, n_mallocs, sizeof(VgHashNode*), compare_MC_Chunks); 349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Then we build an array containing a Bool for each malloc chunk, 351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // indicating whether it contains any mempools. 352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown malloc_chunk_holds_a_pool_chunk = VG_(calloc)( "mc.fas.1", 353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown n_mallocs, sizeof(Bool) ); 354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown n_chunks = n_mallocs; 355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Then we loop over the mempool tables. For each chunk in each 357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // pool, we set the entry in the Bool array corresponding to the 358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // malloc chunk containing the mempool chunk. 359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(HT_ResetIter)(MC_(mempool_list)); 360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while ( (mp = VG_(HT_Next)(MC_(mempool_list))) ) { 361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(HT_ResetIter)(mp->chunks); 362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while ( (mc = VG_(HT_Next)(mp->chunks)) ) { 363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // We'll need to record this chunk. 365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown n_chunks++; 366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Possibly invalidate the malloc holding the beginning of this chunk. 368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m = find_chunk_for(mc->data, mallocs, n_mallocs); 369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (m != -1 && malloc_chunk_holds_a_pool_chunk[m] == False) { 370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(n_chunks > 0); 371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown n_chunks--; 372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown malloc_chunk_holds_a_pool_chunk[m] = True; 373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Possibly invalidate the malloc holding the end of this chunk. 376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (mc->szB > 1) { 377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown m = find_chunk_for(mc->data + (mc->szB - 1), mallocs, n_mallocs); 378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (m != -1 && malloc_chunk_holds_a_pool_chunk[m] == False) { 379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(n_chunks > 0); 380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown n_chunks--; 381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown malloc_chunk_holds_a_pool_chunk[m] = True; 382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(n_chunks > 0); 387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Create final chunk array. 389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown chunks = VG_(malloc)("mc.fas.2", sizeof(VgHashNode*) * (n_chunks)); 390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s = 0; 391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Copy the mempool chunks and the non-marked malloc chunks into a 393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // combined array of chunks. 394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(HT_ResetIter)(MC_(mempool_list)); 395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while ( (mp = VG_(HT_Next)(MC_(mempool_list))) ) { 396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(HT_ResetIter)(mp->chunks); 397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while ( (mc = VG_(HT_Next)(mp->chunks)) ) { 398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(s < n_chunks); 399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown chunks[s++] = mc; 400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (m = 0; m < n_mallocs; ++m) { 403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!malloc_chunk_holds_a_pool_chunk[m]) { 404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(s < n_chunks); 405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown chunks[s++] = mallocs[m]; 406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(s == n_chunks); 409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Free temporaries. 411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(free)(mallocs); 412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(free)(malloc_chunk_holds_a_pool_chunk); 413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *pn_chunks = n_chunks; 415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return chunks; 417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- The leak detector proper. ---*/ 421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Holds extra info about each block during leak checking. 424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef 425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct { 426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt state:2; // Reachedness. 427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt pending:1; // Scan pending. 428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SizeT indirect_szB : (sizeof(SizeT)*8)-3; // If Unreached, how many bytes 429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // are unreachable from here. 430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LC_Extra; 432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// An array holding pointers to every chunk we're checking. Sorted by address. 434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic MC_Chunk** lc_chunks; 435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// How many chunks we're dealing with. 436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int lc_n_chunks; 437b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// chunks will be converted and merged in loss record, maintained in lr_table 438b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// lr_table elements are kept from one leak_search to another to implement 439b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// the "print new/changed leaks" client request 440b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic OSet* lr_table; 441b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 442b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// DeltaMode used the last time we called detect_memory_leaks. 443b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// The recorded leak errors must be output using a logic based on this delta_mode. 444b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// The below avoids replicating the delta_mode in each LossRecord. 445b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovLeakCheckDeltaMode MC_(detect_memory_leaks_last_delta_mode); 446b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// This has the same number of entries as lc_chunks, and each entry 449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// in lc_chunks corresponds with the entry here (ie. lc_chunks[i] and 450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// lc_extras[i] describe the same block). 451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic LC_Extra* lc_extras; 452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Records chunks that are currently being processed. Each element in the 454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// stack is an index into lc_chunks and lc_extras. Its size is 455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// 'lc_n_chunks' because in the worst case that's how many chunks could be 456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// pushed onto it (actually I think the maximum is lc_n_chunks-1 but let's 457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// be conservative). 458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int* lc_markstack; 459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// The index of the top element of the stack; -1 if the stack is empty, 0 if 460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// the stack has one element, 1 if it has two, etc. 461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int lc_markstack_top; 462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Keeps track of how many bytes of memory we've scanned, for printing. 464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// (Nb: We don't keep track of how many register bytes we've scanned.) 465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SizeT lc_scanned_szB; 466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSizeT MC_(bytes_leaked) = 0; 469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSizeT MC_(bytes_indirect) = 0; 470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSizeT MC_(bytes_dubious) = 0; 471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSizeT MC_(bytes_reachable) = 0; 472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSizeT MC_(bytes_suppressed) = 0; 473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSizeT MC_(blocks_leaked) = 0; 475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSizeT MC_(blocks_indirect) = 0; 476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSizeT MC_(blocks_dubious) = 0; 477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSizeT MC_(blocks_reachable) = 0; 478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSizeT MC_(blocks_suppressed) = 0; 479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Determines if a pointer is to a chunk. Returns the chunk number et al 482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// via call-by-reference. 483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool 484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownlc_is_a_chunk_ptr(Addr ptr, Int* pch_no, MC_Chunk** pch, LC_Extra** pex) 485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int ch_no; 487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_Chunk* ch; 488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LC_Extra* ex; 489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Quick filter. 491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!VG_(am_is_valid_for_client)(ptr, 1, VKI_PROT_READ)) { 492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ch_no = find_chunk_for(ptr, lc_chunks, lc_n_chunks); 495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(ch_no >= -1 && ch_no < lc_n_chunks); 496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ch_no == -1) { 498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Ok, we've found a pointer to a chunk. Get the MC_Chunk and its 501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // LC_Extra. 502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ch = lc_chunks[ch_no]; 503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ex = &(lc_extras[ch_no]); 504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(ptr >= ch->data); 506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(ptr < ch->data + ch->szB + (ch->szB==0 ? 1 : 0)); 507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_DEBUG_LEAKCHECK) 509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("ptr=%#lx -> block %d\n", ptr, ch_no); 510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *pch_no = ch_no; 512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *pch = ch; 513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *pex = ex; 514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; 516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Push a chunk (well, just its index) onto the mark stack. 521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void lc_push(Int ch_no, MC_Chunk* ch) 522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!lc_extras[ch_no].pending) { 524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) { 525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("pushing %#lx-%#lx\n", ch->data, ch->data + ch->szB); 526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_markstack_top++; 528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(lc_markstack_top < lc_n_chunks); 529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_markstack[lc_markstack_top] = ch_no; 530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(!lc_extras[ch_no].pending); 531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_extras[ch_no].pending = True; 532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Return the index of the chunk on the top of the mark stack, or -1 if 536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// there isn't one. 537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool lc_pop(Int* ret) 538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (-1 == lc_markstack_top) { 540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(0 <= lc_markstack_top && lc_markstack_top < lc_n_chunks); 543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *ret = lc_markstack[lc_markstack_top]; 544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_markstack_top--; 545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(lc_extras[*ret].pending); 546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_extras[*ret].pending = False; 547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; 548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 551b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// Partial fix for https://bugs.kde.org/show_bug.cgi?id=280271 552b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov// Only used in valgrind-variant now. 553b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic Bool vv_lc_is_start_pointer(Addr ptr, MC_Chunk* chunk) 554b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{ 555b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // Pointers to the start of the chunk are indeed start-pointers 556b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (ptr == chunk->data) 557b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return True; 558b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 559b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // Below are a few heuristics to reduce the number of false positive 560b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // "possibly lost" reports on C++ types by treating some interior-pointers 561b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // as start-pointers (inspired by the Dr. Memory article at CGO2011). 562b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 563b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // Shortcut: heuristics assume 'ptr' is word-aligned. 564b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (ptr != VG_ROUNDUP(ptr, sizeof(Addr))) 565b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return False; 566b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 567b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (ptr == chunk->data + sizeof(Addr)) { 568b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // Pointer to a new[]-allocated buffer? 569b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov SizeT sz_from_header = *(SizeT*)chunk->data, 570b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov expected_sz = chunk->szB - sizeof(Addr); 571b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (sz_from_header > 0 && sz_from_header <= expected_sz && 572b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov expected_sz % sz_from_header == 0) 573b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return True; 574b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 575b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 576b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (ptr == chunk->data + 3*sizeof(Addr)) { 577b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // Pointer to std::string internals? 578b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov SizeT assumed_len = *(SizeT*)chunk->data, 579b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov assumed_capacity = *((SizeT*)chunk->data + 1); 580b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (assumed_len <= assumed_capacity) { 581b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // std::string 582b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (chunk->szB - 3*sizeof(SizeT) == assumed_capacity + 1) 583b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return True; 584b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 585b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // std::basic_string<unsigned short> a.k.a. string16 586b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (chunk->szB - 3*sizeof(SizeT) == 2*(assumed_capacity + 1)) 587b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return True; 588b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 589b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // std::basic_string<wchar_t> on Linux 590b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (chunk->szB - 3*sizeof(SizeT) == 4*(assumed_capacity + 1)) 591b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return True; 592b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 593b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 594b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 595b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (ptr == chunk->data + 2*sizeof(Addr)) { 596b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // Pointer to a nss_ZAlloc-allocated buffer? 597b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // It adds a header like this: 'struct { void *ptr; uint32 size };' 598b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov SizeT sz_from_header = *(UInt*)(chunk->data + sizeof(Addr)), 599b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov expected_sz = chunk->szB - 2*sizeof(Addr); 600b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov tl_assert(sizeof(UInt) == 4); 601b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (sz_from_header == expected_sz) 602b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return True; 603b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 604b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 605b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov return False; 606b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov} 607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// If 'ptr' is pointing to a heap-allocated block which hasn't been seen 609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// before, push it onto the mark stack. 610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void 611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownlc_push_without_clique_if_a_chunk_ptr(Addr ptr, Bool is_prior_definite) 612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int ch_no; 614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_Chunk* ch; 615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LC_Extra* ex; 616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if ( ! lc_is_a_chunk_ptr(ptr, &ch_no, &ch, &ex) ) 618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Possibly upgrade the state, ie. one of: 621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // - Unreached --> Possible 622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // - Unreached --> Reachable 623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // - Possible --> Reachable 624b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (vv_lc_is_start_pointer(ptr, ch) && 625b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov is_prior_definite && ex->state != Reachable) { 626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // 'ptr' points to the start of the block, and the prior node is 627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // definite, which means that this block is definitely reachable. 628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ex->state = Reachable; 629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // State has changed to Reachable so (re)scan the block to make 631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // sure any blocks it points to are correctly marked. 632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_push(ch_no, ch); 633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else if (ex->state == Unreached) { 635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Either 'ptr' is a interior-pointer, or the prior node isn't definite, 636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // which means that we can only mark this block as possibly reachable. 637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ex->state = Possible; 638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // State has changed to Possible so (re)scan the block to make 640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // sure any blocks it points to are correctly marked. 641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_push(ch_no, ch); 642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void 646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownlc_push_if_a_chunk_ptr_register(Addr ptr) 647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_push_without_clique_if_a_chunk_ptr(ptr, /*is_prior_definite*/True); 649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// If ptr is pointing to a heap-allocated block which hasn't been seen 652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// before, push it onto the mark stack. Clique is the index of the 653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// clique leader. 654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void 655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownlc_push_with_clique_if_a_chunk_ptr(Addr ptr, Int clique) 656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int ch_no; 658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_Chunk* ch; 659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LC_Extra* ex; 660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(0 <= clique && clique < lc_n_chunks); 662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if ( ! lc_is_a_chunk_ptr(ptr, &ch_no, &ch, &ex) ) 664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // If it's not Unreached, it's already been handled so ignore it. 667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // If ch_no==clique, it's the clique leader, which means this is a cyclic 668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // structure; again ignore it because it's already been handled. 669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ex->state == Unreached && ch_no != clique) { 670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Note that, unlike reachable blocks, we currently don't distinguish 671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // between start-pointers and interior-pointers here. We probably 672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // should, though. 673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ex->state = IndirectLeak; 674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_push(ch_no, ch); 675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Add the block to the clique, and add its size to the 677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // clique-leader's indirect size. Also, if the new block was 678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // itself a clique leader, it isn't any more, so add its 679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // indirect_szB to the new clique leader. 680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_DEBUG_CLIQUE) { 681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ex->indirect_szB > 0) 682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)(" clique %d joining clique %d adding %lu+%lu\n", 683b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ch_no, clique, (unsigned long)ch->szB, 684b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov (unsigned long)ex->indirect_szB); 685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else 686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)(" block %d joining clique %d adding %lu\n", 687b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ch_no, clique, (unsigned long)ch->szB); 688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_extras[clique].indirect_szB += ch->szB; 691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_extras[clique].indirect_szB += ex->indirect_szB; 692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ex->indirect_szB = 0; // Shouldn't matter. 693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void 697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownlc_push_if_a_chunk_ptr(Addr ptr, Int clique, Bool is_prior_definite) 698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (-1 == clique) 700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_push_without_clique_if_a_chunk_ptr(ptr, is_prior_definite); 701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else 702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_push_with_clique_if_a_chunk_ptr(ptr, clique); 703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 706b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic VG_MINIMAL_JMP_BUF(memscan_jmpbuf); 707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic 709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid scan_all_valid_memory_catcher ( Int sigNo, Addr addr ) 710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) 712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("OUCH! sig=%d addr=%#lx\n", sigNo, addr); 713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sigNo == VKI_SIGSEGV || sigNo == VKI_SIGBUS) 714b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_MINIMAL_LONGJMP(memscan_jmpbuf); 715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Scan a block of memory between [start, start+len). This range may 718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// be bogus, inaccessable, or otherwise strange; we deal with it. For each 719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// valid aligned word we assume it's a pointer to a chunk a push the chunk 720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// onto the mark stack if so. 721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void 722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownlc_scan_memory(Addr start, SizeT len, Bool is_prior_definite, Int clique) 723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr ptr = VG_ROUNDUP(start, sizeof(Addr)); 725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr end = VG_ROUNDDN(start+len, sizeof(Addr)); 726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vki_sigset_t sigmask; 727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_DEBUG_LEAKCHECK) 729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("scan %#lx-%#lx (%lu)\n", start, end, len); 730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(sigprocmask)(VKI_SIG_SETMASK, NULL, &sigmask); 732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(set_fault_catcher)(scan_all_valid_memory_catcher); 733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // We might be in the middle of a page. Do a cheap check to see if 735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // it's valid; if not, skip onto the next page. 736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!VG_(am_is_valid_for_client)(ptr, sizeof(Addr), VKI_PROT_READ)) 737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ptr = VG_PGROUNDUP(ptr+1); // First page is bad - skip it. 738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (ptr < end) { 740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr addr; 741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Skip invalid chunks. 743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if ( ! MC_(is_within_valid_secondary)(ptr) ) { 744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ptr = VG_ROUNDUP(ptr+1, SM_SIZE); 745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Look to see if this page seems reasonable. 749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if ((ptr % VKI_PAGE_SIZE) == 0) { 750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!VG_(am_is_valid_for_client)(ptr, sizeof(Addr), VKI_PROT_READ)) { 751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ptr += VKI_PAGE_SIZE; // Bad page - skip it. 752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 756b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (VG_MINIMAL_SETJMP(memscan_jmpbuf) == 0) { 757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if ( MC_(is_valid_aligned_word)(ptr) ) { 758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_scanned_szB += sizeof(Addr); 759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown addr = *(Addr *)ptr; 760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // If we get here, the scanned word is in valid memory. Now 761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // let's see if its contents point to a chunk. 762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_push_if_a_chunk_ptr(addr, clique, is_prior_definite); 763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else if (0 && VG_DEBUG_LEAKCHECK) { 764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("%#lx not valid\n", ptr); 765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ptr += sizeof(Addr); 767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // We need to restore the signal mask, because we were 769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // longjmped out of a signal handler. 770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL); 771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ptr = VG_PGROUNDUP(ptr+1); // Bad page - skip it. 773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL); 777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(set_fault_catcher)(NULL); 778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Process the mark stack until empty. 782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void lc_process_markstack(Int clique) 783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int top = -1; // shut gcc up 785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool is_prior_definite; 786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while (lc_pop(&top)) { 788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(top >= 0 && top < lc_n_chunks); 789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // See comment about 'is_prior_definite' at the top to understand this. 791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown is_prior_definite = ( Possible != lc_extras[top].state ); 792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_scan_memory(lc_chunks[top]->data, lc_chunks[top]->szB, 794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown is_prior_definite, clique); 795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Word cmp_LossRecordKey_LossRecord(const void* key, const void* elem) 799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LossRecordKey* a = (LossRecordKey*)key; 801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LossRecordKey* b = &(((LossRecord*)elem)->key); 802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Compare on states first because that's fast. 804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (a->state < b->state) return -1; 805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (a->state > b->state) return 1; 806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Ok, the states are equal. Now compare the locations, which is slower. 807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_(eq_ExeContext)( 808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_(clo_leak_resolution), a->allocated_at, b->allocated_at)) 809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Different locations. Ordering is arbitrary, just use the ec pointer. 811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (a->allocated_at < b->allocated_at) return -1; 812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (a->allocated_at > b->allocated_at) return 1; 813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(tool_panic)("bad LossRecord comparison"); 814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int cmp_LossRecords(void* va, void* vb) 817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LossRecord* lr_a = *(LossRecord**)va; 819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LossRecord* lr_b = *(LossRecord**)vb; 820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SizeT total_szB_a = lr_a->szB + lr_a->indirect_szB; 821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SizeT total_szB_b = lr_b->szB + lr_b->indirect_szB; 822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // First compare by sizes. 824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (total_szB_a < total_szB_b) return -1; 825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (total_szB_a > total_szB_b) return 1; 826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // If size are equal, compare by states. 827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (lr_a->key.state < lr_b->key.state) return -1; 828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (lr_a->key.state > lr_b->key.state) return 1; 829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // If they're still equal here, it doesn't matter that much, but we keep 830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // comparing other things so that regtests are as deterministic as 831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // possible. So: compare num_blocks. 832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (lr_a->num_blocks < lr_b->num_blocks) return -1; 833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (lr_a->num_blocks > lr_b->num_blocks) return 1; 834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Finally, compare ExeContext addresses... older ones are likely to have 835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // lower addresses. 836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (lr_a->key.allocated_at < lr_b->key.allocated_at) return -1; 837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (lr_a->key.allocated_at > lr_b->key.allocated_at) return 1; 838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 841b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void print_results(ThreadId tid, LeakCheckParams lcp) 842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i, n_lossrecords; 844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LossRecord** lr_array; 845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LossRecord* lr; 846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool is_suppressed; 847b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov SizeT old_bytes_leaked = MC_(bytes_leaked); /* to report delta in summary */ 848b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov SizeT old_bytes_indirect = MC_(bytes_indirect); 849b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov SizeT old_bytes_dubious = MC_(bytes_dubious); 850b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov SizeT old_bytes_reachable = MC_(bytes_reachable); 851b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov SizeT old_bytes_suppressed = MC_(bytes_suppressed); 852b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov SizeT old_blocks_leaked = MC_(blocks_leaked); 853b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov SizeT old_blocks_indirect = MC_(blocks_indirect); 854b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov SizeT old_blocks_dubious = MC_(blocks_dubious); 855b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov SizeT old_blocks_reachable = MC_(blocks_reachable); 856b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov SizeT old_blocks_suppressed = MC_(blocks_suppressed); 857b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 858b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (lr_table == NULL) 859b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // Create the lr_table, which holds the loss records. 860b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // If the lr_table already exists, it means it contains 861b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // loss_records from the previous leak search. The old_* 862b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // values in these records are used to implement the 863b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // leak check delta mode 864b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov lr_table = 865b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(OSetGen_Create)(offsetof(LossRecord, key), 866b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov cmp_LossRecordKey_LossRecord, 867b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(malloc), "mc.pr.1", 868b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(free)); 869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Convert the chunks into loss records, merging them where appropriate. 872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < lc_n_chunks; i++) { 873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_Chunk* ch = lc_chunks[i]; 874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LC_Extra* ex = &(lc_extras)[i]; 875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LossRecord* old_lr; 876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LossRecordKey lrkey; 877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lrkey.state = ex->state; 878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lrkey.allocated_at = ch->where; 879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown old_lr = VG_(OSetGen_Lookup)(lr_table, &lrkey); 881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (old_lr) { 882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // We found an existing loss record matching this chunk. Update the 883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // loss record's details in-situ. This is safe because we don't 884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // change the elements used as the OSet key. 885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown old_lr->szB += ch->szB; 886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown old_lr->indirect_szB += ex->indirect_szB; 887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown old_lr->num_blocks++; 888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // No existing loss record matches this chunk. Create a new loss 890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // record, initialise it from the chunk, and insert it into lr_table. 891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lr = VG_(OSetGen_AllocNode)(lr_table, sizeof(LossRecord)); 892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lr->key = lrkey; 893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lr->szB = ch->szB; 894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lr->indirect_szB = ex->indirect_szB; 895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lr->num_blocks = 1; 896b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov lr->old_szB = 0; 897b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov lr->old_indirect_szB = 0; 898b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov lr->old_num_blocks = 0; 899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(OSetGen_Insert)(lr_table, lr); 900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown n_lossrecords = VG_(OSetGen_Size)(lr_table); 903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Create an array of pointers to the loss records. 905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lr_array = VG_(malloc)("mc.pr.2", n_lossrecords * sizeof(LossRecord*)); 906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i = 0; 907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(OSetGen_ResetIter)(lr_table); 908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while ( (lr = VG_(OSetGen_Next)(lr_table)) ) { 909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lr_array[i++] = lr; 910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(i == n_lossrecords); 912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Sort the array by loss record sizes. 914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(ssort)(lr_array, n_lossrecords, sizeof(LossRecord*), 915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown cmp_LossRecords); 916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Zero totals. 918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_(blocks_leaked) = MC_(bytes_leaked) = 0; 919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_(blocks_indirect) = MC_(bytes_indirect) = 0; 920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_(blocks_dubious) = MC_(bytes_dubious) = 0; 921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_(blocks_reachable) = MC_(bytes_reachable) = 0; 922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_(blocks_suppressed) = MC_(bytes_suppressed) = 0; 923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Print the loss records (in size order) and collect summary stats. 925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < n_lossrecords; i++) { 926b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov Bool count_as_error, print_record, delta_considered; 927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Rules for printing: 928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // - We don't show suppressed loss records ever (and that's controlled 929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // within the error manager). 930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // - We show non-suppressed loss records that are not "reachable" if 931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // --leak-check=yes. 932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // - We show all non-suppressed loss records if --leak-check=yes and 933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // --show-reachable=yes. 934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // 935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Nb: here "reachable" means Reachable *or* IndirectLeak; note that 936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // this is different to "still reachable" used elsewhere because it 937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // includes indirectly lost blocks! 938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // 939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lr = lr_array[i]; 940b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov switch (lcp.deltamode) { 941b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov case LCD_Any: 942b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov delta_considered = lr->num_blocks > 0; 943b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov break; 944b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov case LCD_Increased: 945b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov delta_considered 946b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov = lr_array[i]->szB > lr_array[i]->old_szB 947b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov || lr_array[i]->indirect_szB > lr_array[i]->old_indirect_szB 948b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov || lr->num_blocks > lr->old_num_blocks; 949b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov break; 950b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov case LCD_Changed: 951b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov delta_considered = lr_array[i]->szB != lr_array[i]->old_szB 952b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov || lr_array[i]->indirect_szB != lr_array[i]->old_indirect_szB 953b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov || lr->num_blocks != lr->old_num_blocks; 954b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov break; 955b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov default: 956b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov tl_assert(0); 957b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 958b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 959b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov print_record = lcp.mode == LC_Full && delta_considered && 960b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ( lcp.show_reachable || 961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Unreached == lr->key.state || 962b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov ( lcp.show_possibly_lost && 963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Possible == lr->key.state ) ); 964b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // We don't count a leaks as errors with lcp.mode==LC_Summary. 965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Otherwise you can get high error counts with few or no error 966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // messages, which can be confusing. Also, you could argue that 967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // indirect leaks should be counted as errors, but it seems better to 968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // make the counting criteria similar to the printing criteria. So we 969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // don't count them. 970b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov count_as_error = lcp.mode == LC_Full && delta_considered && 971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ( Unreached == lr->key.state || 972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Possible == lr->key.state ); 973b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if ((Reachable == lr->key.state && !MC_(clo_show_reachable)) || 974b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov (Possible == lr->key.state && !MC_(clo_show_possibly_lost))) 975b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov is_suppressed = False; 976b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov else 977b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov is_suppressed = MC_(record_leak_error)(tid, i+1, n_lossrecords, lr, 978b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov print_record, count_as_error); 979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (is_suppressed) { 981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_(blocks_suppressed) += lr->num_blocks; 982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_(bytes_suppressed) += lr->szB; 983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else if (Unreached == lr->key.state) { 985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_(blocks_leaked) += lr->num_blocks; 986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_(bytes_leaked) += lr->szB; 987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else if (IndirectLeak == lr->key.state) { 989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_(blocks_indirect) += lr->num_blocks; 990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_(bytes_indirect) += lr->szB; 991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else if (Possible == lr->key.state) { 993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_(blocks_dubious) += lr->num_blocks; 994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_(bytes_dubious) += lr->szB; 995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else if (Reachable == lr->key.state) { 997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_(blocks_reachable) += lr->num_blocks; 998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_(bytes_reachable) += lr->szB; 999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(tool_panic)("unknown loss mode"); 1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1005b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov for (i = 0; i < n_lossrecords; i++) 1006b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov { 1007b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (lr->num_blocks == 0) 1008b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // remove from lr_table the old loss_records with 0 bytes found 1009b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(OSetGen_Remove) (lr_table, &lr_array[i]->key); 1010b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov else 1011b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov { 1012b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // move the leak sizes to old_* and zero the current sizes 1013b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // for next leak search 1014b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov lr_array[i]->old_szB = lr_array[i]->szB; 1015b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov lr_array[i]->old_indirect_szB = lr_array[i]->indirect_szB; 1016b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov lr_array[i]->old_num_blocks = lr_array[i]->num_blocks; 1017b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov lr_array[i]->szB = 0; 1018b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov lr_array[i]->indirect_szB = 0; 1019b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov lr_array[i]->num_blocks = 0; 1020b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 1021b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 1022b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(free)(lr_array); 1023b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) { 1025b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov char d_bytes[20]; 1026b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov char d_blocks[20]; 1027b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(umsg)("LEAK SUMMARY:\n"); 1029b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(umsg)(" definitely lost: %'lu%s bytes in %'lu%s blocks\n", 1030b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(bytes_leaked), 1031b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(snprintf_delta) (d_bytes, 20, MC_(bytes_leaked), old_bytes_leaked, lcp.deltamode), 1032b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(blocks_leaked), 1033b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(snprintf_delta) (d_blocks, 20, MC_(blocks_leaked), old_blocks_leaked, lcp.deltamode)); 1034b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(umsg)(" indirectly lost: %'lu%s bytes in %'lu%s blocks\n", 1035b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(bytes_indirect), 1036b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(snprintf_delta) (d_bytes, 20, MC_(bytes_indirect), old_bytes_indirect, lcp.deltamode), 1037b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(blocks_indirect), 1038b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(snprintf_delta) (d_blocks, 20, MC_(blocks_indirect), old_blocks_indirect, lcp.deltamode) ); 1039b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(umsg)(" possibly lost: %'lu%s bytes in %'lu%s blocks\n", 1040b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(bytes_dubious), 1041b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(snprintf_delta) (d_bytes, 20, MC_(bytes_dubious), old_bytes_dubious, lcp.deltamode), 1042b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(blocks_dubious), 1043b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(snprintf_delta) (d_blocks, 20, MC_(blocks_dubious), old_blocks_dubious, lcp.deltamode) ); 1044b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(umsg)(" still reachable: %'lu%s bytes in %'lu%s blocks\n", 1045b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(bytes_reachable), 1046b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(snprintf_delta) (d_bytes, 20, MC_(bytes_reachable), old_bytes_reachable, lcp.deltamode), 1047b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(blocks_reachable), 1048b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(snprintf_delta) (d_blocks, 20, MC_(blocks_reachable), old_blocks_reachable, lcp.deltamode) ); 1049b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(umsg)(" suppressed: %'lu%s bytes in %'lu%s blocks\n", 1050b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(bytes_suppressed), 1051b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(snprintf_delta) (d_bytes, 20, MC_(bytes_suppressed), old_bytes_suppressed, lcp.deltamode), 1052b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(blocks_suppressed), 1053b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(snprintf_delta) (d_blocks, 20, MC_(blocks_suppressed), old_blocks_suppressed, lcp.deltamode) ); 1054b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (lcp.mode != LC_Full && 1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (MC_(blocks_leaked) + MC_(blocks_indirect) + 1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_(blocks_dubious) + MC_(blocks_reachable)) > 0) { 1057b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (lcp.requested_by_monitor_command) 1058b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(umsg)("To see details of leaked memory, give 'full' arg to leak_check\n"); 1059b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov else 1060b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(umsg)("Rerun with --leak-check=full to see details " 1061b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov "of leaked memory\n"); 1062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1063b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (lcp.mode == LC_Full && 1064b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(blocks_reachable) > 0 && !lcp.show_reachable) 1065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(umsg)("Reachable blocks (those to which a pointer " 1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "was found) are not shown.\n"); 1068b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (lcp.requested_by_monitor_command) 1069b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(umsg)("To see them, add 'reachable any' args to leak_check\n"); 1070b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov else 1071b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(umsg)("To see them, rerun with: --leak-check=full " 1072b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov "--show-reachable=yes\n"); 1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(umsg)("\n"); 1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Top-level entry point. ---*/ 1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1082b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid MC_(detect_memory_leaks) ( ThreadId tid, LeakCheckParams lcp) 1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i, j; 1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1086b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov tl_assert(lcp.mode != LC_Off); 1087b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov 1088b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov MC_(detect_memory_leaks_last_delta_mode) = lcp.deltamode; 1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Get the chunks, stop if there were none. 1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_chunks = find_active_chunks(&lc_n_chunks); 1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (lc_n_chunks == 0) { 1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(lc_chunks == NULL); 1094b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (lr_table != NULL) { 1095b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // forget the previous recorded LossRecords as next leak search will in any case 1096b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // just create new leaks. 1097b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // Maybe it would be better to rather call print_result ? 1098b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // (at least when leak decrease are requested) 1099b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov // This will then output all LossRecords with a size decreasing to 0 1100b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(OSetGen_Destroy) (lr_table); 1101b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov } 1102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_(clo_verbosity) >= 1 && !VG_(clo_xml)) { 1103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(umsg)("All heap blocks were freed -- no leaks are possible\n"); 1104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(umsg)("\n"); 1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 1107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Sort the array so blocks are in ascending order in memory. 1110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(ssort)(lc_chunks, lc_n_chunks, sizeof(VgHashNode*), compare_MC_Chunks); 1111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Sanity check -- make sure they're in order. 1113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < lc_n_chunks-1; i++) { 1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert( lc_chunks[i]->data <= lc_chunks[i+1]->data); 1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Sanity check -- make sure they don't overlap. The one exception is that 1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // we allow a MALLOCLIKE block to sit entirely within a malloc() block. 1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // This is for bug 100628. If this occurs, we ignore the malloc() block 1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // for leak-checking purposes. This is a hack and probably should be done 1121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // better, but at least it's consistent with mempools (which are treated 1122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // like this in find_active_chunks). Mempools have a separate VgHashTable 1123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // for mempool chunks, but if custom-allocated blocks are put in a separate 1124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // table from normal heap blocks it makes free-mismatch checking more 1125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // difficult. 1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // 1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // If this check fails, it probably means that the application 1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // has done something stupid with VALGRIND_MALLOCLIKE_BLOCK client 1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // requests, eg. has made overlapping requests (which are 1130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // nonsensical), or used VALGRIND_MALLOCLIKE_BLOCK for stack locations; 1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // again nonsensical. 1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // 1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < lc_n_chunks-1; i++) { 1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_Chunk* ch1 = lc_chunks[i]; 1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_Chunk* ch2 = lc_chunks[i+1]; 1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr start1 = ch1->data; 1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr start2 = ch2->data; 1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr end1 = ch1->data + ch1->szB - 1; 1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr end2 = ch2->data + ch2->szB - 1; 1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool isCustom1 = ch1->allockind == MC_AllocCustom; 1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool isCustom2 = ch2->allockind == MC_AllocCustom; 1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (end1 < start2) { 1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Normal case - no overlap. 1146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // We used to allow exact duplicates, I'm not sure why. --njn 1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown //} else if (start1 == start2 && end1 == end2) { 1149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Degenerate case: exact duplicates. 1150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else if (start1 >= start2 && end1 <= end2 && isCustom1 && !isCustom2) { 1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Block i is MALLOCLIKE and entirely within block i+1. 1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Remove block i+1. 1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (j = i+1; j < lc_n_chunks-1; j++) { 1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_chunks[j] = lc_chunks[j+1]; 1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_n_chunks--; 1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else if (start2 >= start1 && end2 <= end1 && isCustom2 && !isCustom1) { 1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Block i+1 is MALLOCLIKE and entirely within block i. 1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Remove block i. 1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (j = i; j < lc_n_chunks-1; j++) { 1163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_chunks[j] = lc_chunks[j+1]; 1164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_n_chunks--; 1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(umsg)("Block 0x%lx..0x%lx overlaps with block 0x%lx..0x%lx", 1169b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov start1, end1, start2, end2); 1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(umsg)("This is usually caused by using VALGRIND_MALLOCLIKE_BLOCK"); 1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(umsg)("in an inappropriate way."); 1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert (0); 1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Initialise lc_extras. 1177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_extras = VG_(malloc)( "mc.dml.2", lc_n_chunks * sizeof(LC_Extra) ); 1178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < lc_n_chunks; i++) { 1179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_extras[i].state = Unreached; 1180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_extras[i].pending = False; 1181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_extras[i].indirect_szB = 0; 1182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Initialise lc_markstack. 1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_markstack = VG_(malloc)( "mc.dml.2", lc_n_chunks * sizeof(Int) ); 1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < lc_n_chunks; i++) { 1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_markstack[i] = -1; 1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_markstack_top = -1; 1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Verbosity. 1192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_(clo_verbosity) > 1 && !VG_(clo_xml)) { 1193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(umsg)( "Searching for pointers to %'d not-freed blocks\n", 1194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_n_chunks ); 1195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Scan the memory root-set, pushing onto the mark stack any blocks 1198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // pointed to. 1199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 1200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int n_seg_starts; 1201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr* seg_starts = VG_(get_segment_starts)( &n_seg_starts ); 1202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(seg_starts && n_seg_starts > 0); 1204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_scanned_szB = 0; 1206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // VG_(am_show_nsegments)( 0, "leakcheck"); 1208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < n_seg_starts; i++) { 1209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SizeT seg_size; 1210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown NSegment const* seg = VG_(am_find_nsegment)( seg_starts[i] ); 1211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(seg); 1212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (seg->kind != SkFileC && seg->kind != SkAnonC) continue; 1214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!(seg->hasR && seg->hasW)) continue; 1215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (seg->isCH) continue; 1216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Don't poke around in device segments as this may cause 1218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // hangs. Exclude /dev/zero just in case someone allocated 1219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // memory by explicitly mapping /dev/zero. 1220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (seg->kind == SkFileC 1221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown && (VKI_S_ISCHR(seg->mode) || VKI_S_ISBLK(seg->mode))) { 1222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HChar* dev_name = VG_(am_get_filename)( (NSegment*)seg ); 1223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (dev_name && 0 == VG_(strcmp)(dev_name, "/dev/zero")) { 1224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Don't skip /dev/zero. 1225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 1226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Skip this device mapping. 1227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 1228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) 1232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("ACCEPT %2d %#lx %#lx\n", i, seg->start, seg->end); 1233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Scan the segment. We use -1 for the clique number, because this 1235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // is a root-set. 1236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg_size = seg->end - seg->start + 1; 1237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_(clo_verbosity) > 2) { 1238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(message)(Vg_DebugMsg, 1239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown " Scanning root segment: %#lx..%#lx (%lu)\n", 1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown seg->start, seg->end, seg_size); 1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_scan_memory(seg->start, seg_size, /*is_prior_definite*/True, -1); 1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Scan GP registers for chunk pointers. 1247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(apply_to_GP_regs)(lc_push_if_a_chunk_ptr_register); 1248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Process the pushed blocks. After this, every block that is reachable 1250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // from the root-set has been traced. 1251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_process_markstack(/*clique*/-1); 1252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_(clo_verbosity) > 1 && !VG_(clo_xml)) { 1254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(umsg)("Checked %'lu bytes\n", lc_scanned_szB); 1255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(umsg)( "\n" ); 1256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Trace all the leaked blocks to determine which are directly leaked and 1259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // which are indirectly leaked. For each Unreached block, push it onto 1260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // the mark stack, and find all the as-yet-Unreached blocks reachable 1261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // from it. These form a clique and are marked IndirectLeak, and their 1262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // size is added to the clique leader's indirect size. If one of the 1263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // found blocks was itself a clique leader (from a previous clique), then 1264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // the cliques are merged. 1265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < lc_n_chunks; i++) { 1266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MC_Chunk* ch = lc_chunks[i]; 1267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown LC_Extra* ex = &(lc_extras[i]); 1268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_DEBUG_CLIQUE) 1270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("cliques: %d at %#lx -> Loss state %d\n", 1271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i, ch->data, ex->state); 1272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(lc_markstack_top == -1); 1274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ex->state == Unreached) { 1276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_DEBUG_CLIQUE) 1277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("%d: gathering clique %#lx\n", i, ch->data); 1278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Push this Unreached block onto the stack and process it. 1280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_push(i, ch); 1281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown lc_process_markstack(i); 1282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(lc_markstack_top == -1); 1284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(ex->state == Unreached); 1285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 1287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1288b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov print_results( tid, lcp); 1289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(free) ( lc_chunks ); 1291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(free) ( lc_extras ); 1292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(free) ( lc_markstack ); 1293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 1294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 1295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 1296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end ---*/ 1297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 1298