mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-30 04:10:54 -08:00
Check in HTML version of the manual (writable on client) so that it will display automatically on the Ravenbrook server and so that we can easily include it in product releases. Copied from Perforce Change: 180338 ServerID: perforce.ravenbrook.com
415 lines
No EOL
28 KiB
HTML
415 lines
No EOL
28 KiB
HTML
|
|
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
|
|
|
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
|
|
<title>4. Debugging with the Memory Pool System — Memory Pool System 1.111.0 documentation</title>
|
|
|
|
<link rel="stylesheet" href="../_static/mps.css" type="text/css" />
|
|
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
|
|
|
<script type="text/javascript">
|
|
var DOCUMENTATION_OPTIONS = {
|
|
URL_ROOT: '../',
|
|
VERSION: '1.111.0',
|
|
COLLAPSE_INDEX: false,
|
|
FILE_SUFFIX: '.html',
|
|
HAS_SOURCE: true
|
|
};
|
|
</script>
|
|
<script type="text/javascript" src="../_static/jquery.js"></script>
|
|
<script type="text/javascript" src="../_static/underscore.js"></script>
|
|
<script type="text/javascript" src="../_static/doctools.js"></script>
|
|
<link rel="copyright" title="Copyright" href="../copyright.html" />
|
|
<link rel="top" title="Memory Pool System 1.111.0 documentation" href="../index.html" />
|
|
<link rel="up" title="Guide" href="index.html" />
|
|
<link rel="next" title="5. Tuning the Memory Pool System for performance" href="perf.html" />
|
|
<link rel="prev" title="3. Garbage collecting a language with the Memory Pool System" href="lang.html" />
|
|
</head>
|
|
<body>
|
|
<div class="related">
|
|
<h3>Navigation</h3>
|
|
<ul>
|
|
<li class="right" style="margin-right: 10px">
|
|
<a href="../genindex.html" title="General Index"
|
|
accesskey="I">index</a></li>
|
|
<li class="right" >
|
|
<a href="perf.html" title="5. Tuning the Memory Pool System for performance"
|
|
accesskey="N">next</a> |</li>
|
|
<li class="right" >
|
|
<a href="lang.html" title="3. Garbage collecting a language with the Memory Pool System"
|
|
accesskey="P">previous</a> |</li>
|
|
<li><a href="../index.html">Memory Pool System 1.111.0 documentation</a> »</li>
|
|
<li><a href="index.html" accesskey="U">Guide</a> »</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="document">
|
|
<div class="documentwrapper">
|
|
<div class="bodywrapper">
|
|
<div class="body">
|
|
|
|
<div class="section" id="debugging-with-the-memory-pool-system">
|
|
<span id="guide-debug"></span><span id="index-0"></span><h1>4. Debugging with the Memory Pool System<a class="headerlink" href="#debugging-with-the-memory-pool-system" title="Permalink to this headline">¶</a></h1>
|
|
<p>Memory management errors are some of the most stubborn and difficult
|
|
to track down, because the effect so often appears at a distant point
|
|
in the program that is seemingly unrelated to the cause, and by the
|
|
time the error is revealed, the information needed to reconstruct the
|
|
cause has long vanished. Immediately after an <a class="reference internal" href="../glossary/o.html#term-overwriting-error"><em class="xref std std-term">overwriting
|
|
error</em></a>, the block that overran its bounds is fine, and the block that
|
|
was overwritten may not be visited for a long time. A failure to
|
|
<a class="reference internal" href="../glossary/f.html#term-fix"><em class="xref std std-term">fix</em></a> a <a class="reference internal" href="../glossary/r.html#term-reference"><em class="xref std std-term">reference</em></a> does not necessarily cause the object
|
|
pointed to by the missed reference to die immediately: there may be
|
|
other references to that object, or a garbage collection may be
|
|
delayed. And even if it does die, the space it occupies may not be
|
|
re-allocated for some time.</p>
|
|
<div class="section" id="general-debugging-advice">
|
|
<h2>4.1. General debugging advice<a class="headerlink" href="#general-debugging-advice" title="Permalink to this headline">¶</a></h2>
|
|
<ol class="arabic">
|
|
<li><p class="first">Compile with debugging information turned on (<tt class="docutils literal"><span class="pre">-g</span></tt> on the GCC or
|
|
Clang command line).</p>
|
|
</li>
|
|
<li><p id="index-1">Build the <a class="reference internal" href="../glossary/c.html#term-cool"><em class="xref std std-term">cool</em></a> <a class="reference internal" href="../glossary/v.html#term-variety"><em class="xref std std-term">variety</em></a> of the MPS (by defining the
|
|
preprocessor constant <tt class="docutils literal"><span class="pre">CONFIG_VAR_COOL</span></tt>, for example by setting
|
|
<tt class="docutils literal"><span class="pre">-DCONFIG_VAR_COOL</span></tt> on the GCC or Clang command line). This
|
|
variety contains many internal consistency checks (including such
|
|
checks on the <a class="reference internal" href="../glossary/c.html#term-critical-path"><em class="xref std std-term">critical path</em></a>, which make it too slow for use
|
|
in production), and can generate profiling output in the form of
|
|
the <a class="reference internal" href="../glossary/t.html#term-telemetry-stream"><em class="xref std std-term">telemetry stream</em></a>.</p>
|
|
</li>
|
|
<li><p id="index-2">Prepare a reproducible test case if possible. The MPS may be
|
|
<a class="reference internal" href="../glossary/a.html#term-asynchronous-garbage-collector"><em class="xref std std-term">asynchronous</em></a>, but it is
|
|
deterministic, so in single-threaded applications you should be
|
|
able to get consistent results. (But you need to beware of <a class="reference external" href="http://en.wikipedia.org/wiki/Address_space_layout_randomization">address
|
|
space layout randomization</a>: if you perform computation based on
|
|
the addresses of objects, for example, hashing objects by their
|
|
address, then ASLR will cause your hash tables to be laid out
|
|
differently on each run, which may affect the order of memory
|
|
management operations.)</p>
|
|
<p>A fact that assists with reproducibility is that the more
|
|
frequently the collector runs, the sooner and more reliably errors
|
|
are discovered. So if you have a bug that’s hard to reproduce, or
|
|
which manifests itself in different ways on different runs, you may
|
|
be able to provoke it more reliably, or get a more consistent
|
|
result, by having a mode for testing in which you run frequent
|
|
collections (by calling <a class="reference internal" href="../topic/arena.html#mps_arena_collect" title="mps_arena_collect"><tt class="xref c c-func docutils literal"><span class="pre">mps_arena_collect()</span></tt></a> followed by
|
|
<a class="reference internal" href="../topic/arena.html#mps_arena_release" title="mps_arena_release"><tt class="xref c c-func docutils literal"><span class="pre">mps_arena_release()</span></tt></a>), perhaps as frequently as every
|
|
allocation.</p>
|
|
</li>
|
|
<li><p id="index-3">Run your test case inside the debugger. Use <tt class="docutils literal"><span class="pre">assert</span></tt> and
|
|
<tt class="docutils literal"><span class="pre">abort</span></tt> in your error handler (rather than <tt class="docutils literal"><span class="pre">exit</span></tt>) so that you
|
|
can enter the debugger with the contents of the control stack
|
|
available for inspection.</p>
|
|
<p>You may need to make sure that the debugger isn’t entered on
|
|
<a class="reference internal" href="../glossary/b.html#term-barrier-1"><em class="xref std std-term">barrier<sup>(1)</sup></em></a> hits (because the MPS uses barriers to protect
|
|
parts of memory, and barrier hits are common and expected).</p>
|
|
<p>In particular, if you are using GDB on Mac OS X, you will need to
|
|
run these commands:</p>
|
|
<div class="highlight-none"><div class="highlight"><pre>set dont-handle-bad-access 1
|
|
handle SIGBUS pass nostop noprint
|
|
</pre></div>
|
|
</div>
|
|
<p>Add them to your <tt class="docutils literal"><span class="pre">.gdbinit</span></tt> if appropriate.</p>
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
<div class="section" id="example-underscanning">
|
|
<span id="guide-debug-underscanning"></span><span id="index-4"></span><h2>4.2. Example: underscanning<a class="headerlink" href="#example-underscanning" title="Permalink to this headline">¶</a></h2>
|
|
<p>An easy mistake to make is to omit to <a class="reference internal" href="../glossary/f.html#term-fix"><em class="xref std std-term">fix</em></a> a <a class="reference internal" href="../glossary/r.html#term-reference"><em class="xref std std-term">reference</em></a>
|
|
when <a class="reference internal" href="../glossary/s.html#term-scan"><em class="xref std std-term">scanning</em></a> a <a class="reference internal" href="../glossary/f.html#term-formatted-object"><em class="xref std std-term">formatted object</em></a>. For example,
|
|
in the Scheme interpreter’s <a class="reference internal" href="lang.html#guide-lang-scan"><em>scan method</em></a>, I
|
|
might have forgetten to fix the first element of a pair:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">case</span> <span class="n">TYPE_PAIR</span>:
|
|
<span class="hll"> <span class="cm">/* oops, forgot: FIX(CAR(obj)); */</span>
|
|
</span> <span class="n">FIX</span><span class="p">(</span><span class="n">CDR</span><span class="p">(</span><span class="n">obj</span><span class="p">));</span>
|
|
<span class="n">base</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">base</span> <span class="o">+</span> <span class="n">ALIGN</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">pair_s</span><span class="p">));</span>
|
|
<span class="k">break</span><span class="p">;</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>This means that as far as the MPS is concerned, the first element of
|
|
the pair is <a class="reference internal" href="../glossary/u.html#term-unreachable"><em class="xref std std-term">unreachable</em></a> and so <a class="reference internal" href="../glossary/d.html#term-dead"><em class="xref std std-term">dead</em></a>, so after
|
|
collecting the region of memory containing this object, the space will
|
|
be reused for other objects. So <tt class="docutils literal"><span class="pre">CAR(obj)</span></tt> might end up pointing to
|
|
the start of a valid object (but the wrong one), or to the middle of a
|
|
valid object, or to an unused region of memory, or into an MPS
|
|
internal control structure.</p>
|
|
<p>The reproducible test case is simple. Run a garbage collection by
|
|
calling <tt class="docutils literal"><span class="pre">(gc)</span></tt> and then evaluate any expression:</p>
|
|
<div class="highlight-none"><div class="highlight"><pre>$ gdb ./scheme
|
|
GNU gdb 6.3.50-20050815 (Apple version gdb-1820) (Sat Jun 16 02:40:11 UTC 2012)
|
|
|
|
(gdb) run
|
|
Starting program: example/scheme/scheme
|
|
Reading symbols for shared libraries +............................. done
|
|
MPS Toy Scheme Example
|
|
7944, 0> (gc)
|
|
Collection started.
|
|
Why: Client requests: immediate full collection.
|
|
Clock: 11357
|
|
Collection finished.
|
|
live 1888
|
|
condemned 7968
|
|
not_condemned 0
|
|
clock: 12008
|
|
7968, 1> foo
|
|
Assertion failed: (TYPE(frame) == TYPE_PAIR), function lookup_in_frame, file scheme.c, line 1065.
|
|
|
|
Program received signal SIGABRT, Aborted.
|
|
0x00007fff91aeed46 in __kill ()
|
|
</pre></div>
|
|
</div>
|
|
<p>What’s going on?</p>
|
|
<div class="highlight-none"><div class="highlight"><pre>(gdb) backtrace
|
|
#0 0x00007fff91aeed46 in __kill ()
|
|
#1 0x00007fff90509df0 in abort ()
|
|
#2 0x00007fff9050ae2a in __assert_rtn ()
|
|
#3 0x0000000100003f55 in lookup_in_frame (frame=0x1003fa7d0, symbol=0x1003faf20) at scheme.c:1066
|
|
#4 0x0000000100003ea6 in lookup (env=0x1003fb130, symbol=0x1003faf20) at scheme.c:1087
|
|
#5 0x000000010000341f in eval (env=0x1003fb130, op_env=0x1003fb148, exp=0x1003faf20) at scheme.c:1135
|
|
#6 0x000000010000261b in start (p=0x0, s=0) at scheme.c:3204
|
|
#7 0x0000000100011ded in ProtTramp (resultReturn=0x7fff5fbff7d0, f=0x100002130 <start>, p=0x0, s=0) at protix.c:132
|
|
#8 0x0000000100011d34 in mps_tramp (r_o=0x7fff5fbff7d0, f=0x100002130 <start>, p=0x0, s=0) at mpsi.c:1346
|
|
#9 0x0000000100001ef7 in main (argc=1, argv=0x7fff5fbff830) at scheme.c:3314
|
|
(gdb) frame 4
|
|
#4 0x0000000100003ea6 in lookup (env=0x1003fb130, symbol=0x1003faf20) at scheme.c:1087
|
|
1086 binding = lookup_in_frame(CAR(env), symbol);
|
|
(gdb) print (char *)symbol->symbol.string
|
|
$1 = 0x1003faf30 "foo"
|
|
</pre></div>
|
|
</div>
|
|
<p>The backtrace shows that the interpreter is in the middle of looking
|
|
up the symbol <tt class="docutils literal"><span class="pre">foo</span></tt> in the environment. The Scheme intrepreter
|
|
implements the environment as a list of <em>frames</em>, each of which is a
|
|
list of <em>bindings</em>, each binding being a pair of a symbol and its
|
|
value, as shown here:</p>
|
|
<div class="figure align-center">
|
|
<img alt="Diagram: The environment data structure in the Scheme interpreter." src="../_images/scheme-env.svg" /><p class="caption">The environment data structure in the Scheme interpreter.</p>
|
|
</div>
|
|
<p>In this case, because the evaluation is taking place at top level,
|
|
there is only one frame in the environment (the global frame). And
|
|
it’s this frame that’s corrupt:</p>
|
|
<div class="highlight-none"><div class="highlight"><pre>(gdb) frame 3
|
|
#3 0x0000000100003f55 in lookup_in_frame (frame=0x1003fa7d0, symbol=0x1003faf20) at scheme.c:1066
|
|
1066 assert(TYPE(frame) == TYPE_PAIR);
|
|
(gdb) list
|
|
1061 */
|
|
1062
|
|
1063 static obj_t lookup_in_frame(obj_t frame, obj_t symbol)
|
|
1064 {
|
|
1065 while(frame != obj_empty) {
|
|
<span class="hll">1066 assert(TYPE(frame) == TYPE_PAIR);
|
|
</span>1067 assert(TYPE(CAR(frame)) == TYPE_PAIR);
|
|
1068 assert(TYPE(CAAR(frame)) == TYPE_SYMBOL);
|
|
1069 if(CAAR(frame) == symbol)
|
|
1070 return CAR(frame);
|
|
(gdb) print frame->type.type
|
|
$2 = 13
|
|
</pre></div>
|
|
</div>
|
|
<p>The number 13 is the value <tt class="docutils literal"><span class="pre">TYPE_PAD</span></tt>. So instead of the expected
|
|
pair, <tt class="docutils literal"><span class="pre">frame</span></tt> points to a <a class="reference internal" href="../glossary/p.html#term-padding-object"><em class="xref std std-term">padding object</em></a>.</p>
|
|
<p>You might guess at this point that the frame had not been fixed, and
|
|
since you know that the frame is referenced by the <tt class="docutils literal"><span class="pre">car</span></tt> of the
|
|
first pair in the environment, that’s the suspect reference. But in a
|
|
more complex situation this might not yet be clear. In such a
|
|
situation it can be useful to look at the sequence of events leading
|
|
up to the detection of the error. See <a class="reference internal" href="../topic/telemetry.html#topic-telemetry"><em>Telemetry</em></a>.</p>
|
|
</div>
|
|
<div class="section" id="example-allocating-with-wrong-size">
|
|
<span id="guide-debug-size"></span><span id="index-5"></span><h2>4.3. Example: allocating with wrong size<a class="headerlink" href="#example-allocating-with-wrong-size" title="Permalink to this headline">¶</a></h2>
|
|
<p>Here’s another kind of mistake: an off-by-one error in <tt class="docutils literal"><span class="pre">make_string</span></tt>
|
|
leading to the allocation of string objects with the wrong size:</p>
|
|
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="n">obj_t</span> <span class="nf">make_string</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">length</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">string</span><span class="p">)</span>
|
|
<span class="p">{</span>
|
|
<span class="n">obj_t</span> <span class="n">obj</span><span class="p">;</span>
|
|
<span class="n">mps_addr_t</span> <span class="n">addr</span><span class="p">;</span>
|
|
<span class="hll"> <span class="kt">size_t</span> <span class="n">size</span> <span class="o">=</span> <span class="n">ALIGN</span><span class="p">(</span><span class="n">offsetof</span><span class="p">(</span><span class="n">string_s</span><span class="p">,</span> <span class="n">string</span><span class="p">)</span> <span class="o">+</span> <span class="n">length</span><span class="cm">/* oops, forgot: +1 */</span><span class="p">);</span>
|
|
</span> <span class="k">do</span> <span class="p">{</span>
|
|
<span class="n">mps_res_t</span> <span class="n">res</span> <span class="o">=</span> <span class="n">mps_reserve</span><span class="p">(</span><span class="o">&</span><span class="n">addr</span><span class="p">,</span> <span class="n">obj_ap</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">res</span> <span class="o">!=</span> <span class="n">MPS_RES_OK</span><span class="p">)</span> <span class="n">error</span><span class="p">(</span><span class="s">"out of memory in make_string"</span><span class="p">);</span>
|
|
<span class="n">obj</span> <span class="o">=</span> <span class="n">addr</span><span class="p">;</span>
|
|
<span class="n">obj</span><span class="o">-></span><span class="n">string</span><span class="p">.</span><span class="n">type</span> <span class="o">=</span> <span class="n">TYPE_STRING</span><span class="p">;</span>
|
|
<span class="n">obj</span><span class="o">-></span><span class="n">string</span><span class="p">.</span><span class="n">length</span> <span class="o">=</span> <span class="n">length</span><span class="p">;</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">string</span><span class="p">)</span> <span class="n">memcpy</span><span class="p">(</span><span class="n">obj</span><span class="o">-></span><span class="n">string</span><span class="p">.</span><span class="n">string</span><span class="p">,</span> <span class="n">string</span><span class="p">,</span> <span class="n">length</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
|
|
<span class="k">else</span> <span class="n">memset</span><span class="p">(</span><span class="n">obj</span><span class="o">-></span><span class="n">string</span><span class="p">.</span><span class="n">string</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">length</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
|
|
<span class="p">}</span> <span class="k">while</span><span class="p">(</span><span class="o">!</span><span class="n">mps_commit</span><span class="p">(</span><span class="n">obj_ap</span><span class="p">,</span> <span class="n">addr</span><span class="p">,</span> <span class="n">size</span><span class="p">));</span>
|
|
<span class="n">total</span> <span class="o">+=</span> <span class="n">size</span><span class="p">;</span>
|
|
<span class="k">return</span> <span class="n">obj</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Here’s a test case that exercises this bug:</p>
|
|
<div class="highlight-scheme"><div class="highlight"><pre><span class="p">(</span><span class="k">define </span><span class="p">(</span><span class="nf">church</span> <span class="nv">n</span> <span class="nv">f</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">eqv? </span><span class="nv">n</span> <span class="mi">0</span><span class="p">)</span> <span class="nv">a</span> <span class="p">(</span><span class="nf">church</span> <span class="p">(</span><span class="nb">- </span><span class="nv">n</span> <span class="mi">1</span><span class="p">)</span> <span class="nv">f</span> <span class="p">(</span><span class="nf">f</span> <span class="nv">a</span><span class="p">))))</span>
|
|
<span class="p">(</span><span class="nf">church</span> <span class="mi">1000</span> <span class="p">(</span><span class="k">lambda </span><span class="p">(</span><span class="nf">s</span><span class="p">)</span> <span class="p">(</span><span class="nb">string-append </span><span class="nv">s</span> <span class="s">"x"</span><span class="p">))</span> <span class="s">""</span><span class="p">)</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>And here’s how it shows up in the debugger:</p>
|
|
<div class="highlight-none"><div class="highlight"><pre>$ gdb ./scheme
|
|
GNU gdb 6.3.50-20050815 (Apple version gdb-1820) (Sat Jun 16 02:40:11 UTC 2012)
|
|
[...]
|
|
(gdb) run < test.scm
|
|
Starting program: example/scheme/scheme < test.scm
|
|
Reading symbols for shared libraries +............................. done
|
|
MPS Toy Scheme Example
|
|
[...]
|
|
9960, 0> church
|
|
Assertion failed: (0), function obj_skip, file scheme.c, line 2940.
|
|
10816, 0>
|
|
Program received signal SIGABRT, Aborted.
|
|
0x00007fff91aeed46 in __kill ()
|
|
(gdb) backtrace
|
|
#0 0x00007fff91aeed46 in __kill ()
|
|
#1 0x00007fff90509df0 in abort ()
|
|
#2 0x00007fff9050ae2a in __assert_rtn ()
|
|
#3 0x00000001000014e3 in obj_skip (base=0x1003f9b88) at scheme.c:2940
|
|
#4 0x0000000100068050 in amcScanNailedOnce (totalReturn=0x7fff5fbfef2c, moreReturn=0x7fff5fbfef28, ss=0x7fff5fbff0a0, pool=0x1003fe278, seg=0x1003fe928, amc=0x1003fe278) at poolamc.c:1485
|
|
#5 0x0000000100067ca1 in amcScanNailed (totalReturn=0x7fff5fbff174, ss=0x7fff5fbff0a0, pool=0x1003fe278, seg=0x1003fe928, amc=0x1003fe278) at poolamc.c:1522
|
|
#6 0x000000010006631f in AMCScan (totalReturn=0x7fff5fbff174, ss=0x7fff5fbff0a0, pool=0x1003fe278, seg=0x1003fe928) at poolamc.c:1595
|
|
#7 0x000000010002686d in PoolScan (totalReturn=0x7fff5fbff174, ss=0x7fff5fbff0a0, pool=0x1003fe278, seg=0x1003fe928) at pool.c:405
|
|
#8 0x0000000100074106 in traceScanSegRes (ts=1, rank=1, arena=0x10012a000, seg=0x1003fe928) at trace.c:1162
|
|
#9 0x000000010002b399 in traceScanSeg (ts=1, rank=1, arena=0x10012a000, seg=0x1003fe928) at trace.c:1222
|
|
#10 0x000000010002d020 in TraceQuantum (trace=0x10012a5a0) at trace.c:1833
|
|
#11 0x000000010001f2d2 in TracePoll (globals=0x10012a000) at trace.c:1981
|
|
#12 0x000000010000d75f in ArenaPoll (globals=0x10012a000) at global.c:684
|
|
#13 0x000000010000ea40 in mps_ap_fill (p_o=0x7fff5fbff3e0, mps_ap=0x1003fe820, size=208) at mpsi.c:961
|
|
#14 0x000000010000447d in make_string (length=190, string=0x0) at scheme.c:468
|
|
#15 0x0000000100008ca2 in entry_string_append (env=0x1003cbe38, op_env=0x1003cbe50, operator=0x1003fad48, operands=0x1003f9af8) at scheme.c:2562
|
|
#16 0x0000000100002fe4 in eval (env=0x1003cbe38, op_env=0x1003cbe50, exp=0x1003f9ae0) at scheme.c:1159
|
|
#17 0x0000000100005ff5 in entry_interpret (env=0x1003cb958, op_env=0x1003cb970, operator=0x1003f99d8, operands=0x1003f9948) at scheme.c:1340
|
|
#18 0x0000000100002fe4 in eval (env=0x1003cb958, op_env=0x1003cb970, exp=0x1003f9878) at scheme.c:1159
|
|
#19 0x000000010000206b in start (p=0x0, s=0) at scheme.c:3213
|
|
#20 0x000000010001287d in ProtTramp (resultReturn=0x7fff5fbff7a0, f=0x100001b80 <start>, p=0x0, s=0) at protix.c:132
|
|
#21 0x00000001000127c4 in mps_tramp (r_o=0x7fff5fbff7a0, f=0x100001b80 <start>, p=0x0, s=0) at mpsi.c:1346
|
|
#22 0x0000000100001947 in main (argc=1, argv=0x7fff5fbff808) at scheme.c:3314
|
|
(gdb) frame 3
|
|
#3 0x00000001000014e3 in obj_skip (base=0x1003f9b88) at scheme.c:2940
|
|
2940 assert(0);
|
|
(gdb) list
|
|
2935 break;
|
|
2936 case TYPE_PAD1:
|
|
2937 base = (char *)base + ALIGN(sizeof(pad1_s));
|
|
2938 break;
|
|
2939 default:
|
|
<span class="hll">2940 assert(0);
|
|
</span>2941 fprintf(stderr, "Unexpected object on the heap\n");
|
|
2942 abort();
|
|
2943 return NULL;
|
|
2944 }
|
|
</pre></div>
|
|
</div>
|
|
<p>The object being skipped is corrupt:</p>
|
|
<div class="highlight-none"><div class="highlight"><pre>(gdb) print obj->type.type
|
|
$1 = 4168560
|
|
</pre></div>
|
|
</div>
|
|
<p>What happened to it? It’s often helpful in these situations to have a
|
|
look at nearby memory.</p>
|
|
<div class="highlight-none"><div class="highlight"><pre>(gdb) x/20g obj
|
|
0x1003f9b88: 0x00000001003f9b70 0x00000001003fb000
|
|
0x1003f9b98: 0x0000000000000000 0x00000001003f9c90
|
|
0x1003f9ba8: 0x00000001003fb130 0x0000000000000000
|
|
0x1003f9bb8: 0x00000001003fb000 0x00000001003fb148
|
|
0x1003f9bc8: 0x0000000000000000 0x00000001003f9730
|
|
0x1003f9bd8: 0x00000001003f9a58 0x0000000000000000
|
|
0x1003f9be8: 0x00000001003f9bc8 0x00000001003fb000
|
|
0x1003f9bf8: 0x0000000000000000 0x00000001003fb0a0
|
|
0x1003f9c08: 0x00000001003f9b40 0x0000000000000004
|
|
0x1003f9c18: 0x000000010007b14a 0x0000000100005e30
|
|
</pre></div>
|
|
</div>
|
|
<p>You can see that this is a block containing mostly pairs (which have
|
|
tag 0 and consist of three words), though you can see an operator
|
|
(with tag 4) near the bottom. But what’s that at the start of the
|
|
block, where <tt class="docutils literal"><span class="pre">obj</span></tt>‘s tag should be? It looks like a pointer. So
|
|
what’s in the memory just below <tt class="docutils literal"><span class="pre">obj</span></tt>? Let’s look at the previous
|
|
few words:</p>
|
|
<div class="highlight-none"><div class="highlight"><pre>(gdb) x/10g (mps_word_t*)obj-8
|
|
0x1003f9b48: 0x00000001003f9ae0 0x00000001003fb000
|
|
0x1003f9b58: 0x0000000000000000 0x00000001003f9a80
|
|
0x1003f9b68: 0x00000001003f9b80 0x0000000000000005
|
|
0x1003f9b78: 0x0000000000000000 0x0000000000000000
|
|
0x1003f9b88: 0x00000001003f9b70 0x00000001003fb000
|
|
</pre></div>
|
|
</div>
|
|
<p>Yes: there’s a pair (with tag 0) at <tt class="docutils literal"><span class="pre">0x1003f9b80</span></tt>. So it looks as
|
|
though the previous object was allocated with one size, but skipped
|
|
with a different size. The previous object being the string (with tag
|
|
5) at <tt class="docutils literal"><span class="pre">0x1003f9b70</span></tt> which has length 0 and so is three words long as
|
|
far as <tt class="docutils literal"><span class="pre">obj_skip</span></tt> is concerned:</p>
|
|
<div class="highlight-none"><div class="highlight"><pre>(gdb) print obj_skip(0x1003f9b70)
|
|
$2 = (mps_addr_t) 0x1003f9b88
|
|
</pre></div>
|
|
</div>
|
|
<p>but the next object (the pair) was clearly allocated at
|
|
<tt class="docutils literal"><span class="pre">0x1003f9b80</span></tt> (overwriting the last word of the string), so the
|
|
string must have been allocated with a size of only two words. This
|
|
should be enough evidence to track down the cause.</p>
|
|
</div>
|
|
<div class="section" id="what-next">
|
|
<h2>4.4. What next?<a class="headerlink" href="#what-next" title="Permalink to this headline">¶</a></h2>
|
|
<p>If you tracked down all your bugs, then the next step is the chapter
|
|
<a class="reference internal" href="perf.html#guide-perf"><em>Tuning the Memory Pool System for performance</em></a>.</p>
|
|
<p>But if you’re still struggling, please <a class="reference internal" href="../contact.html#contact"><em>contact us</em></a> and
|
|
see if we can help.</p>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sphinxsidebar">
|
|
<div class="sphinxsidebarwrapper">
|
|
<p class="logo"><a href="../index.html">
|
|
<img class="logo" src="../_static/logo.png" alt="Logo"/>
|
|
</a></p>
|
|
<h3><a href="../index.html">Table Of Contents</a></h3>
|
|
<ul>
|
|
<li><a class="reference internal" href="#">4. Debugging with the Memory Pool System</a><ul>
|
|
<li><a class="reference internal" href="#general-debugging-advice">4.1. General debugging advice</a></li>
|
|
<li><a class="reference internal" href="#example-underscanning">4.2. Example: underscanning</a></li>
|
|
<li><a class="reference internal" href="#example-allocating-with-wrong-size">4.3. Example: allocating with wrong size</a></li>
|
|
<li><a class="reference internal" href="#what-next">4.4. What next?</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
|
|
<h4>Previous topic</h4>
|
|
<p class="topless"><a href="lang.html"
|
|
title="previous chapter">3. Garbage collecting a language with the Memory Pool System</a></p>
|
|
<h4>Next topic</h4>
|
|
<p class="topless"><a href="perf.html"
|
|
title="next chapter">5. Tuning the Memory Pool System for performance</a></p><h4>Contact us</h4>
|
|
|
|
<p class="topless"><a href="mailto:mps-questions@ravenbrook.com">mps-questions@ravenbrook.com</a></p>
|
|
</div>
|
|
</div>
|
|
<div class="clearer"></div>
|
|
</div>
|
|
<div class="related">
|
|
<h3>Navigation</h3>
|
|
<ul>
|
|
<li class="right" style="margin-right: 10px">
|
|
<a href="../genindex.html" title="General Index"
|
|
>index</a></li>
|
|
<li class="right" >
|
|
<a href="perf.html" title="5. Tuning the Memory Pool System for performance"
|
|
>next</a> |</li>
|
|
<li class="right" >
|
|
<a href="lang.html" title="3. Garbage collecting a language with the Memory Pool System"
|
|
>previous</a> |</li>
|
|
<li><a href="../index.html">Memory Pool System 1.111.0 documentation</a> »</li>
|
|
<li><a href="index.html" >Guide</a> »</li>
|
|
</ul>
|
|
</div>
|
|
<div class="footer">
|
|
© <a href="../copyright.html">Copyright</a> 2012, Ravenbrook Limited.
|
|
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
|
|
</div>
|
|
</body>
|
|
</html> |