<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Debugging on Mini Fish</title>
    <link>https://blog.minifish.org/tags/debugging/</link>
    <description>Recent content in Debugging on Mini Fish</description>
    <image>
      <title>Mini Fish</title>
      <url>https://blog.minifish.org/android-chrome-512x512.png</url>
      <link>https://blog.minifish.org/android-chrome-512x512.png</link>
    </image>
    <generator>Hugo -- 0.154.5</generator>
    <language>en-US</language>
    <copyright>Mini Fish 2014-present. Licensed under CC-BY-NC</copyright>
    <lastBuildDate>Mon, 16 Sep 2019 13:24:00 +0800</lastBuildDate>
    <atom:link href="https://blog.minifish.org/tags/debugging/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Using delve to Debug Golang Programs</title>
      <link>https://blog.minifish.org/posts/using-delve-to-debug-golang-programs/</link>
      <pubDate>Mon, 16 Sep 2019 13:24:00 +0800</pubDate>
      <guid>https://blog.minifish.org/posts/using-delve-to-debug-golang-programs/</guid>
      <description>&lt;h2 id=&#34;background&#34;&gt;Background&lt;/h2&gt;
&lt;p&gt;When I first started writing Golang, I was always looking for a convenient debugging tool. Back then, I came across documentation about using &lt;code&gt;gdb&lt;/code&gt; to debug and also tried &lt;code&gt;delve&lt;/code&gt;, but neither felt easy to use. Later, on someone&amp;rsquo;s advice, I went back to the good old &lt;code&gt;print&lt;/code&gt; statements&amp;hellip;&lt;/p&gt;
&lt;p&gt;Over the past couple of days, I was debugging &lt;code&gt;go test&lt;/code&gt; and found that tests would always hang when run per package. I couldn&amp;rsquo;t think of a suitable method at first, so I thought of &lt;code&gt;delve&lt;/code&gt; again. After giving it a try, I found it has become much more mature than before.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="background">Background</h2>
<p>When I first started writing Golang, I was always looking for a convenient debugging tool. Back then, I came across documentation about using <code>gdb</code> to debug and also tried <code>delve</code>, but neither felt easy to use. Later, on someone&rsquo;s advice, I went back to the good old <code>print</code> statements&hellip;</p>
<p>Over the past couple of days, I was debugging <code>go test</code> and found that tests would always hang when run per package. I couldn&rsquo;t think of a suitable method at first, so I thought of <code>delve</code> again. After giving it a try, I found it has become much more mature than before.</p>
<h2 id="usage">Usage</h2>
<p><code>dlv attach ${pid}</code> is the method I use most often. After attaching, you can use debugging commands similar to <code>gdb</code>. You can use <code>help</code> to view specific commands.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>(dlv) help
</span></span><span style="display:flex;"><span>The following commands are available:
</span></span><span style="display:flex;"><span>    args ------------------------ Print function arguments.
</span></span><span style="display:flex;"><span>    break (alias: b) ------------ Sets a breakpoint.
</span></span><span style="display:flex;"><span>    breakpoints (alias: bp) ----- Print out info for active breakpoints.
</span></span><span style="display:flex;"><span>    call ------------------------ Resumes process, injecting a function call (EXPERIMENTAL!!!)
</span></span><span style="display:flex;"><span>    clear ----------------------- Deletes breakpoint.
</span></span><span style="display:flex;"><span>    clearall -------------------- Deletes multiple breakpoints.
</span></span><span style="display:flex;"><span>    condition (alias: cond) ----- Set breakpoint condition.
</span></span><span style="display:flex;"><span>    config ---------------------- Changes configuration parameters.
</span></span><span style="display:flex;"><span>    continue (alias: c) --------- Run until breakpoint or program termination.
</span></span><span style="display:flex;"><span>    deferred -------------------- Executes command in the context of a deferred call.
</span></span><span style="display:flex;"><span>    disassemble (alias: disass) - Disassembler.
</span></span><span style="display:flex;"><span>    down ------------------------ Move the current frame down.
</span></span><span style="display:flex;"><span>    edit (alias: ed) ------------ Open where you are in $DELVE_EDITOR or $EDITOR
</span></span><span style="display:flex;"><span>    exit (alias: quit | q) ------ Exit the debugger.
</span></span><span style="display:flex;"><span>    frame ----------------------- Set the current frame, or execute command on a different frame.
</span></span><span style="display:flex;"><span>    funcs ----------------------- Print list of functions.
</span></span><span style="display:flex;"><span>    goroutine (alias: gr) ------- Shows or changes current goroutine.
</span></span><span style="display:flex;"><span>    goroutines (alias: grs) ----- List program goroutines.
</span></span><span style="display:flex;"><span>    help (alias: h) ------------- Prints the help message.
</span></span><span style="display:flex;"><span>    libraries ------------------- List loaded dynamic libraries.
</span></span><span style="display:flex;"><span>    list (alias: ls | l) -------- Show source code.
</span></span><span style="display:flex;"><span>    locals ---------------------- Print local variables.
</span></span><span style="display:flex;"><span>    next (alias: n) ------------- Step over to next source line.
</span></span><span style="display:flex;"><span>    on -------------------------- Executes a command when a breakpoint is hit.
</span></span><span style="display:flex;"><span>    print (alias: p) ------------ Evaluate an expression.
</span></span><span style="display:flex;"><span>    regs ------------------------ Print contents of CPU registers.
</span></span><span style="display:flex;"><span>    restart (alias: r) ---------- Restart process.
</span></span><span style="display:flex;"><span>    set ------------------------- Changes the value of a variable.
</span></span><span style="display:flex;"><span>    source ---------------------- Executes a file containing a list of delve commands.
</span></span><span style="display:flex;"><span>    sources --------------------- Print list of source files.
</span></span><span style="display:flex;"><span>    stack (alias: bt) ----------- Print stack trace.
</span></span><span style="display:flex;"><span>    step (alias: s) ------------- Single step through program.
</span></span><span style="display:flex;"><span>    step-instruction (alias: si)  Single step a single CPU instruction.
</span></span><span style="display:flex;"><span>    stepout (alias: so) --------- Step out of the current function.
</span></span><span style="display:flex;"><span>    thread (alias: tr) ---------- Switch to the specified thread.
</span></span><span style="display:flex;"><span>    threads --------------------- Print out info for every traced thread.
</span></span><span style="display:flex;"><span>    trace (alias: t) ------------ Set tracepoint.
</span></span><span style="display:flex;"><span>    types ----------------------- Print list of types.
</span></span><span style="display:flex;"><span>    up -------------------------- Move the current frame up.
</span></span><span style="display:flex;"><span>    vars ------------------------ Print package variables.
</span></span><span style="display:flex;"><span>    whatis ---------------------- Prints type of an expression.
</span></span><span style="display:flex;"><span>Type help followed by a command for full documentation.
</span></span></code></pre></div><p>Many of these commands are the same as those in <code>gdb</code>. Another command I use frequently is <code>grs</code>, which outputs all goroutines. You can also use <code>grs -t</code>, which is equivalent to <code>gdb</code>&rsquo;s <code>t a a bt</code>. The only slight drawback is that it only outputs 10 stack frames, and any additional ones are truncated.</p>
<p>Additionally, it seems that processes forked by <code>go test</code> can&rsquo;t be attached to. If you want to test, you must first compile it into a test file and then execute it. You can refer to <a href="https://github.com/pingcap/tidb/issues/12184">this issue</a> for more details.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>$ dlv attach 19654
</span></span><span style="display:flex;"><span>could not attach to pid 19654: decoding dwarf section info at offset 0x0: too short
</span></span></code></pre></div><p>Furthermore, by default, Go&rsquo;s <code>test</code> caches results, which can be controlled via environment variables. However, with Go modules (<code>go mod</code>), it&rsquo;s recommended to use <code>./ddl.test -test.count=1</code> to disable caching. It doesn&rsquo;t feel very elegant.</p>
]]></content:encoded>
    </item>
    <item>
      <title>How Immediate is Golang&#39;s Panic</title>
      <link>https://blog.minifish.org/posts/how-immediate-is-golangs-panic/</link>
      <pubDate>Thu, 26 Jul 2018 14:24:00 +0800</pubDate>
      <guid>https://blog.minifish.org/posts/how-immediate-is-golangs-panic/</guid>
      <description>&lt;p&gt;Let&amp;rsquo;s first look at the following code snippet:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;runtime&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;time&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;runtime&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GOMAXPROCS&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] = &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sleep&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] &amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1000000&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Exit&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After compiling and running it (assuming your machine has 2 or more cores), you will get the following error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fatal error: concurrent map read and map write
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;goroutine 1 [running]:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;runtime.throw(0x10c3e05, 0x21)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        /usr/local/Cellar/go/1.10.3/libexec/src/runtime/panic.go:616 +0x81 fp=0xc42004bf00 sp=0xc42004bee0 pc=0x10263f1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;runtime.mapaccess1_fast64(0x10a5b60, 0xc42007e180, 0x1, 0xc42008e048)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        /usr/local/Cellar/go/1.10.3/libexec/src/runtime/hashmap_fast.go:101 +0x197 fp=0xc42004bf28 sp=0xc42004bf00 pc=0x1008d27
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;main.main()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        /Users/yusp/test/panic3/main.go:22 +0x7c fp=0xc42004bf88 sp=0xc42004bf28 pc=0x108e28c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;runtime.main()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        /usr/local/Cellar/go/1.10.3/libexec/src/runtime/proc.go:198 +0x212 fp=0xc42004bfe0 sp=0xc42004bf88 pc=0x1027c62
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;runtime.goexit()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        /usr/local/Cellar/go/1.10.3/libexec/src/runtime/asm_amd64.s:2361 +0x1 fp=0xc42004bfe8 sp=0xc42004bfe0 pc=0x104e501
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;goroutine 5 [runnable]:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;time.Sleep(0x3e8)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        /usr/local/Cellar/go/1.10.3/libexec/src/runtime/time.go:102 +0x166
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;main.main.func1(0xc42007e180)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        /Users/yusp/test/panic3/main.go:18 +0x61
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;created by main.main
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        /Users/yusp/test/panic3/main.go:13 +0x59
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It seems straightforward; Golang&amp;rsquo;s map is not thread-safe, and concurrent read and write cause a panic. However, look at the error information on line &lt;code&gt;/Users/yusp/test/panic3/main.go:18 +0x61&lt;/code&gt;, which points to line 18 of main.go where &lt;code&gt;Sleep&lt;/code&gt; is called, not the actual point of concurrency issue. In a vast stack trace, it becomes even harder to locate the problem.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Let&rsquo;s first look at the following code snippet:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-golang" data-lang="golang"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> (
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;fmt&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;os&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;runtime&#34;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">&#34;time&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">runtime</span>.<span style="color:#a6e22e">GOMAXPROCS</span>(<span style="color:#ae81ff">2</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">a</span> <span style="color:#f92672">:=</span> make(<span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">int</span>]<span style="color:#66d9ef">int</span>)
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">go</span> <span style="color:#66d9ef">func</span>() {
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">i</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">for</span> {
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">a</span>[<span style="color:#ae81ff">1</span>] = <span style="color:#a6e22e">i</span>
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">i</span><span style="color:#f92672">++</span>
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Sleep</span>(<span style="color:#ae81ff">1000</span>)
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>	}()
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">for</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">a</span>[<span style="color:#ae81ff">1</span>] &gt; <span style="color:#ae81ff">1000000</span> {
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">a</span>[<span style="color:#ae81ff">1</span>])
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Exit</span>(<span style="color:#ae81ff">1</span>)
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>After compiling and running it (assuming your machine has 2 or more cores), you will get the following error:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>fatal error: concurrent map read and map write
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>goroutine 1 [running]:
</span></span><span style="display:flex;"><span>runtime.throw(0x10c3e05, 0x21)
</span></span><span style="display:flex;"><span>        /usr/local/Cellar/go/1.10.3/libexec/src/runtime/panic.go:616 +0x81 fp=0xc42004bf00 sp=0xc42004bee0 pc=0x10263f1
</span></span><span style="display:flex;"><span>runtime.mapaccess1_fast64(0x10a5b60, 0xc42007e180, 0x1, 0xc42008e048)
</span></span><span style="display:flex;"><span>        /usr/local/Cellar/go/1.10.3/libexec/src/runtime/hashmap_fast.go:101 +0x197 fp=0xc42004bf28 sp=0xc42004bf00 pc=0x1008d27
</span></span><span style="display:flex;"><span>main.main()
</span></span><span style="display:flex;"><span>        /Users/yusp/test/panic3/main.go:22 +0x7c fp=0xc42004bf88 sp=0xc42004bf28 pc=0x108e28c
</span></span><span style="display:flex;"><span>runtime.main()
</span></span><span style="display:flex;"><span>        /usr/local/Cellar/go/1.10.3/libexec/src/runtime/proc.go:198 +0x212 fp=0xc42004bfe0 sp=0xc42004bf88 pc=0x1027c62
</span></span><span style="display:flex;"><span>runtime.goexit()
</span></span><span style="display:flex;"><span>        /usr/local/Cellar/go/1.10.3/libexec/src/runtime/asm_amd64.s:2361 +0x1 fp=0xc42004bfe8 sp=0xc42004bfe0 pc=0x104e501
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>goroutine 5 [runnable]:
</span></span><span style="display:flex;"><span>time.Sleep(0x3e8)
</span></span><span style="display:flex;"><span>        /usr/local/Cellar/go/1.10.3/libexec/src/runtime/time.go:102 +0x166
</span></span><span style="display:flex;"><span>main.main.func1(0xc42007e180)
</span></span><span style="display:flex;"><span>        /Users/yusp/test/panic3/main.go:18 +0x61
</span></span><span style="display:flex;"><span>created by main.main
</span></span><span style="display:flex;"><span>        /Users/yusp/test/panic3/main.go:13 +0x59
</span></span></code></pre></div><p>It seems straightforward; Golang&rsquo;s map is not thread-safe, and concurrent read and write cause a panic. However, look at the error information on line <code>/Users/yusp/test/panic3/main.go:18 +0x61</code>, which points to line 18 of main.go where <code>Sleep</code> is called, not the actual point of concurrency issue. In a vast stack trace, it becomes even harder to locate the problem.</p>
<p>A workaround that comes to mind is if you only see the read stack and want to see the write stack, set a variable at the read position, reset it after reading, and check the value of this variable at the write position. If reading is currently happening, panic will be triggered.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
