📄 mc-manual.html
字号:
<p>Read this section if you want to know, in detail, exactlywhat and how Memcheck is checking.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="mc-manual.value"></a>3.5.1.燰alid-value (V) bits</h3></div></div></div><p>It is simplest to think of Memcheck implementing a synthetic CPUwhich is identical to a real CPU, except for one crucial detail. Everybit (literally) of data processed, stored and handled by the real CPUhas, in the synthetic CPU, an associated "valid-value" bit, which sayswhether or not the accompanying bit has a legitimate value. In thediscussions which follow, this bit is referred to as the V (valid-value)bit.</p><p>Each byte in the system therefore has a 8 V bits which follow itwherever it goes. For example, when the CPU loads a word-size item (4bytes) from memory, it also loads the corresponding 32 V bits from abitmap which stores the V bits for the process' entire address space.If the CPU should later write the whole or some part of that value tomemory at a different address, the relevant V bits will be stored backin the V-bit bitmap.</p><p>In short, each bit in the system has an associated V bit, whichfollows it around everywhere, even inside the CPU. Yes, all the CPU'sregisters (integer, floating point, vector and condition registers) havetheir own V bit vectors.</p><p>Copying values around does not cause Memcheck to check for, orreport on, errors. However, when a value is used in a way which mightconceivably affect the outcome of your program's computation, theassociated V bits are immediately checked. If any of these indicatethat the value is undefined, an error is reported.</p><p>Here's an (admittedly nonsensical) example:</p><pre class="programlisting">int i, j;int a[10], b[10];for ( i = 0; i < 10; i++ ) { j = a[i]; b[i] = j;}</pre><p>Memcheck emits no complaints about this, since it merely copiesuninitialised values from <code class="varname">a[]</code> into<code class="varname">b[]</code>, and doesn't use them in any way. However, ifthe loop is changed to:</p><pre class="programlisting">for ( i = 0; i < 10; i++ ) { j += a[i];}if ( j == 77 ) printf("hello there\n");</pre><p>then Valgrind will complain, at the<code class="computeroutput">if</code>, that the condition depends onuninitialised values. Note that it <span><strong class="command">doesn't</strong></span> complainat the <code class="varname">j += a[i];</code>, since at that point theundefinedness is not "observable". It's only when a decision has to bemade as to whether or not to do the <code class="function">printf</code> -- anobservable action of your program -- that Memcheck complains.</p><p>Most low level operations, such as adds, cause Memcheck to use theV bits for the operands to calculate the V bits for the result. Even ifthe result is partially or wholly undefined, it does notcomplain.</p><p>Checks on definedness only occur in three places: when a value isused to generate a memory address, when control flow decision needs tobe made, and when a system call is detected, Valgrind checks definednessof parameters as required.</p><p>If a check should detect undefinedness, an error message isissued. The resulting value is subsequently regarded as well-defined.To do otherwise would give long chains of error messages. In effect, wesay that undefined values are non-infectious.</p><p>This sounds overcomplicated. Why not just check all reads frommemory, and complain if an undefined value is loaded into a CPUregister? Well, that doesn't work well, because perfectly legitimate Cprograms routinely copy uninitialised values around in memory, and wedon't want endless complaints about that. Here's the canonical example.Consider a struct like this:</p><pre class="programlisting">struct S { int x; char c; };struct S s1, s2;s1.x = 42;s1.c = 'z';s2 = s1;</pre><p>The question to ask is: how large is <code class="varname">struct S</code>,in bytes? An <code class="varname">int</code> is 4 bytes and a<code class="varname">char</code> one byte, so perhaps a <code class="varname">structS</code> occupies 5 bytes? Wrong. All (non-toy) compilers we knowof will round the size of <code class="varname">struct S</code> up to a wholenumber of words, in this case 8 bytes. Not doing this forces compilersto generate truly appalling code for subscripting arrays of<code class="varname">struct S</code>'s.</p><p>So <code class="varname">s1</code> occupies 8 bytes, yet only 5 of them willbe initialised. For the assignment <code class="varname">s2 = s1</code>, gccgenerates code to copy all 8 bytes wholesale into <code class="varname">s2</code>without regard for their meaning. If Memcheck simply checked values asthey came out of memory, it would yelp every time a structure assignmentlike this happened. So the more complicated semantics described aboveis necessary. This allows <code class="literal">gcc</code> to copy<code class="varname">s1</code> into <code class="varname">s2</code> any way it likes, and awarning will only be emitted if the uninitialised values are laterused.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="mc-manual.vaddress"></a>3.5.2.燰alid-address (A) bits</h3></div></div></div><p>Notice that the previous subsection describes how the validity ofvalues is established and maintained without having to say whether theprogram does or does not have the right to access any particular memorylocation. We now consider the latter issue.</p><p>As described above, every bit in memory or in the CPU has anassociated valid-value (V) bit. In addition, all bytes in memory, butnot in the CPU, have an associated valid-address (A) bit. Thisindicates whether or not the program can legitimately read or write thatlocation. It does not give any indication of the validity or the dataat that location -- that's the job of the V bits -- only whether or notthe location may be accessed.</p><p>Every time your program reads or writes memory, Memcheck checksthe A bits associated with the address. If any of them indicate aninvalid address, an error is emitted. Note that the reads and writesthemselves do not change the A bits, only consult them.</p><p>So how do the A bits get set/cleared? Like this:</p><div class="itemizedlist"><ul type="disc"><li><p>When the program starts, all the global data areas are marked as accessible.</p></li><li><p>When the program does malloc/new, the A bits for exactly the area allocated, and not a byte more, are marked as accessible. Upon freeing the area the A bits are changed to indicate inaccessibility.</p></li><li><p>When the stack pointer register (<code class="literal">SP</code>) moves up or down, A bits are set. The rule is that the area from <code class="literal">SP</code> up to the base of the stack is marked as accessible, and below <code class="literal">SP</code> is inaccessible. (If that sounds illogical, bear in mind that the stack grows down, not up, on almost all Unix systems, including GNU/Linux.) Tracking <code class="literal">SP</code> like this has the useful side-effect that the section of stack used by a function for local variables etc is automatically marked accessible on function entry and inaccessible on exit.</p></li><li><p>When doing system calls, A bits are changed appropriately. For example, mmap() magically makes files appear in the process' address space, so the A bits must be updated if mmap() succeeds.</p></li><li><p>Optionally, your program can tell Valgrind about such changes explicitly, using the client request mechanism described above.</p></li></ul></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="mc-manual.together"></a>3.5.3.燩utting it all together</h3></div></div></div><p>Memcheck's checking machinery can be summarised asfollows:</p><div class="itemizedlist"><ul type="disc"><li><p>Each byte in memory has 8 associated V (valid-value) bits, saying whether or not the byte has a defined value, and a single A (valid-address) bit, saying whether or not the program currently has the right to read/write that address.</p></li><li><p>When memory is read or written, the relevant A bits are consulted. If they indicate an invalid address, Valgrind emits an Invalid read or Invalid write error.</p></li><li><p>When memory is read into the CPU's registers, the relevant V bits are fetched from memory and stored in the simulated CPU. They are not consulted.</p></li><li><p>When a register is written out to memory, the V bits for that register are written back to memory too.</p></li><li><p>When values in CPU registers are used to generate a memory address, or to determine the outcome of a conditional branch, the V bits for those values are checked, and an error emitted if any of them are undefined.</p></li><li><p>When values in CPU registers are used for any other purpose, Valgrind computes the V bits for the result, but does not check them.</p></li><li><p>One the V bits for a value in the CPU have been checked, they are then set to indicate validity. This avoids long chains of errors.</p></li><li><p>When values are loaded from memory, valgrind checks the A bits for that location and issues an illegal-address warning if needed. In that case, the V bits loaded are forced to indicate Valid, despite the location being invalid.</p><p>This apparently strange choice reduces the amount of confusing information presented to the user. It avoids the unpleasant phenomenon in which memory is read from a place which is both unaddressible and contains invalid values, and, as a result, you get not only an invalid-address (read/write) error, but also a potentially large set of uninitialised-value errors, one for every time the value is used.</p><p>There is a hazy boundary case to do with multi-byte loads from addresses which are partially valid and partially invalid. See details of the flag <code class="option">--partial-loads-ok</code> for details. </p></li></ul></div><p>Memcheck intercepts calls to malloc, calloc, realloc, valloc,memalign, free, new, new[], delete and delete[]. The behaviour you getis:</p><div class="itemizedlist"><ul type="disc"><li><p>malloc/new/new[]: the returned memory is marked as addressible but not having valid values. This means you have to write on it before you can read it.</p></li><li><p>calloc: returned memory is marked both addressible and valid, since calloc() clears the area to zero.</p></li><li><p>realloc: if the new size is larger than the old, the new section is addressible but invalid, as with malloc.</p></li><li><p>If the new size is smaller, the dropped-off section is marked as unaddressible. You may only pass to realloc a pointer previously issued to you by malloc/calloc/realloc.</p></li><li><p>free/delete/delete[]: you may only pass to these functions a pointer previously issued to you by the corresponding allocation function. Otherwise, Valgrind complains. If the pointer is indeed valid, Valgrind marks the entire area it points at as unaddressible, and places the block in the freed-blocks-queue. The aim is to defer as long as possible reallocation of this block. Until that happens, all attempts to access it will elicit an invalid-address error, as you would hope.</p></li></ul></div></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="mc-manual.clientreqs"></a>3.6.燙lient Requests</h2></div></div></div><p>The following client requests are defined in<code class="filename">memcheck.h</code>.See <code class="filename">memcheck.h</code> for exact details of theirarguments.</p><div class="itemizedlist"><ul type="disc"><li><p><code class="varname">VALGRIND_MAKE_MEM_NOACCESS</code>, <code class="varname">VALGRIND_MAKE_MEM_UNDEFINED</code> and <code class="varname">VALGRIND_MAKE_MEM_DEFINED</code>. These mark address ranges as completely inaccessible, accessible but containing undefined data, and accessible and containing defined data, respectively. Subsequent errors may have their faulting addresses described in terms of these blocks. Returns a "block handle". Returns zero when not run on Valgrind.</p></li><li><p><code class="varname">VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE</code>. This is just like <code class="varname">VALGRIND_MAKE_MEM_DEFINED</code> but only affects those bytes that are already addressable.</p></li><li><p><code class="varname">VALGRIND_DISCARD</code>: At some point you may want Valgrind to stop reporting errors in terms of the blocks defined by the previous three macros. To do this, the above macros return a small-integer "block handle". You can pass this block handle to <code class="varname">VALGRIND_DISCARD</code>. After doing so, Valgrind will no longer be able to relate addressing errors to the user-defined block associated with the handle. The permissions settings associated with the handle remain in place; this just affects how errors are reported, not whether they are reported. Returns 1 for an invalid handle and 0 for a valid handle (although passing invalid handles is harmless). Always returns 0 when not run on Valgrind.</p></li><li><p><code class="varname">VALGRIND_CHECK_MEM_IS_ADDRESSABLE</code> and <code class="varname">VALGRIND_CHECK_MEM_IS_DEFINED</code>: check immediately whether or not the given address range has the relevant property, and if not, print an error message. Also, for the convenience of the client, returns zero if the relevant property holds; otherwise, the returned value is the address of the first byte for which the property is not true. Always returns 0 when not run on Valgrind.</p></li><li><p><code class="varname">VALGRIND_CHECK_VALUE_IS_DEFINED</code>: a quick and easy way to find out whether Valgrind thinks a particular value (lvalue, to be precise) is addressable and defined. Prints an error message if not. Returns no value.</p></li><li><p><code class="varname">VALGRIND_DO_LEAK_CHECK</code>: run the memory leak detector right now. Returns no value. I guess this could be used to incrementally check for leaks between arbitrary places in the program's execution. Warning: not properly tested!</p></li><li><p><code class="varname">VALGRIND_COUNT_LEAKS</code>: fills in the four arguments with the number of bytes of memory found by the previous leak check to be leaked, dubious, reachable and suppressed. Again, useful in test harness code, after calling <code class="varname">VALGRIND_DO_LEAK_CHECK</code>.</p></li><li><p><code class="varname">VALGRIND_GET_VBITS</code> and <code class="varname">VALGRIND_SET_VBITS</code>: allow you to get and set the V (validity) bits for an address range. You should probably only set V bits that you have got with <code class="varname">VALGRIND_GET_VBITS</code>. Only for those who really know what they are doing.</p></li></ul></div></div></div><div><br><table class="nav" width="100%" cellspacing="3" cellpadding="2" border="0" summary="Navigation footer"><tr><td rowspan="2" width="40%" align="left"><a accesskey="p" href="manual-core.html"><<
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -