⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mc-manual.html

📁 memory checking tool 源代码valgrind-3.2.1.tar.gz 这是英文使用手册
💻 HTML
📖 第 1 页 / 共 3 页
字号:
<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 &lt; 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 &lt; 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">&lt;&lt;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -