Is it possible to hack Go and modify the content of a string, despite it being immutable?

xuanbao · · 471 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I ask just out of curiosity, and trying to understand how things work internally. =)</p> <p>Take a look on what I tried: <a href="https://play.golang.org/p/pqYju9VpA9" rel="nofollow">https://play.golang.org/p/pqYju9VpA9</a></p> <p>It panics if you try to change the inner <code>[]byte</code> of an <code>string</code>. I&#39;m curious about how Go knows if an <code>[]byte</code> is a <code>string</code> constant or not.</p> <hr/>**评论:**<br/><br/>TheMerovius: <pre><p>strings and slices have a different memory layout: <a href="http://godoc.org/reflect#StringHeader" rel="nofollow">string</a> vs. <a href="http://godoc.org/reflect#SliceHeader" rel="nofollow">slice</a>. For both, the <code>Data</code> element points to the raw bytes. So, first, when you cast <code>*(*[]byte)(unsafe.Pointer(&amp;foo))</code>, you are setting the cap-element of that new slice to… something undefined. Whatever garbage lies behind that string-header.</p> <p>Secondly, Go decides to put the string-contents in read-only memory (because it&#39;s a compile-time constant), so trying to modify that will segfault, because you are violating the memory protection of that data. So to actually modify a string, you need to make sure that it&#39;s dynamically allocated.</p> <p>Lastly, you need to adhere to the <a href="http://godoc.org/unsafe#Pointer" rel="nofollow">unsafe.Pointer rules</a>, if you want even a <em>smidge</em> of safety here. Otherwise the GC might switch move around data under your nose and you end up with a pointer to invalid memory.</p> <p>So, <a href="https://play.golang.org/p/N9xKsDAwLu" rel="nofollow">this works</a>. I hope, the hoops this has to jump through, make clear how friggin&#39; subtle usage of unsafe is. You could only ever use this, if you&#39;re <em>absolutely certain</em>, that the contents of the slice won&#39;t be modified when passing it on, or you&#39;re <em>absolutely certain</em>, that it&#39;s safe to do so. Usually, at least one of the two isn&#39;t given. And even if it is, you still need to be very aware of what you are doing.</p> <p>So, needless to say, <em>don&#39;t do this</em>, even if you think it&#39;s a good idea. It very, very likely isn&#39;t.</p></pre>gopher1717: <pre><p>Great explanation!</p> <blockquote> <p>So, needless to say, don&#39;t do this, even if you think it&#39;s a good idea. It very, very likely isn&#39;t.</p> </blockquote> <p>Don&#39;t worry, I know it&#39;s a good idea. I was just playing with the language, and looking for knowledge.</p></pre>icholy: <pre><p>This is as far as I got: <a href="https://play.golang.org/p/qpLrREIA_r" rel="nofollow">https://play.golang.org/p/qpLrREIA_r</a></p></pre>egonelbre: <pre><p>Some strings are placed into read-only section in executable... but that can only be done to strings that exist at compile-time.</p> <p>For example, if the string is on the heap the modification would succeed: <a href="https://play.golang.org/p/QxBIGjbjWL" rel="nofollow">https://play.golang.org/p/QxBIGjbjWL</a></p> <p><em>This, of course, isn&#39;t guaranteed behavior.</em></p></pre>bkeroack: <pre><p>Your example is very strange.</p> <p><a href="https://play.golang.org/p/NpFR2z8kTW" rel="nofollow">https://play.golang.org/p/NpFR2z8kTW</a></p> <p>It works fine.</p></pre>gopher1717: <pre><p>What I was trying to do something like this:</p> <pre><code>// code to change &#34;foo&#34; constant to &#34;bar&#34; fmt.Println(&#34;foo&#34;) // would print &#34;bar&#34; </code></pre> <p>Because all <code>&#34;foo&#34;</code> in your code share the same memory address.</p> <p>This does a copy, actually:</p> <pre><code>bytes := []byte(&#34;foo&#34;) </code></pre></pre>elagergren: <pre><p>If the compiler knows the string at compile time it&#39;ll put it in read-only memory, which means you can&#39;t modify it with <code>unsafe</code>. However, if you convert a slice of bytes to a string and then use <code>unsafe</code> it&#39;ll work just like you want.</p> <p>All of the above is an implementation detail, though.</p></pre>dominikh: <pre><p>In case abusing Go one way wasn&#39;t enough, here&#39;s another: <a href="https://play.golang.org/p/uYW5UjbKYv" rel="nofollow">https://play.golang.org/p/uYW5UjbKYv</a></p></pre>gopher1717: <pre><p>This makes sense for me. Thanks for the explanation.</p></pre>elagergren: <pre><p>cheers</p></pre>twisted1919: <pre><p>Hehe, good luck trying this on utf-8 strings.</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

471 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传