<p>This problem has really captured my fancy. <a href="https://www.reddit.com/r/golang/comments/4klmwe/code_challenge_can_go_be_rendered_unusable/" rel="nofollow">Previous post.</a></p>
<p>Here's the full dialog so far. I repeat much of what was said in that post because I'm trying to gather my thoughts.</p>
<p>The goal is to write some code in Go such that, for arbitrary user code confined to a certain scope of it, Go does not satisfy all of the following criteria for something to be considered a programming language:</p>
<ul>
<li>It supports some representation of positive integers.
<ul>
<li>Impossible. While we can erase the names of the built-in integer types by shadowing them, <code>:=</code> lets the user freely initialize integers.</li>
</ul></li>
<li>It supports some representation of lists or tuples.
<ul>
<li>Impossible due to list and string literals.</li>
</ul></li>
<li>It can determine the sum of two positive integers: either by adding them together, or taking in a tuple of three integers and outputting a boolean indicating whether one is the sum of the other two.
<ul>
<li>Impossible due to the built-in "+" operator.</li>
</ul></li>
<li>It can determine whether a positive integer is prime.
<ul>
<li>Again impossible.</li>
</ul></li>
<li>The result of the above two computations can affect the program's output.</li>
</ul>
<p>This last criterion appears to be the only one we can destroy.</p>
<p>The obvious solution is to confine the user's code to the end of <code>main</code>, and shadow the built-in functions <code>panic</code>, <code>print</code>, and <code>println</code> as constants. Without the ability to import anything, the user fights back: they can panic by improperly indexing an array, say:</p>
<pre><code>panicker := []interface{}{}
_ = panicker[1]
</code></pre>
<p>We can counteract this easily by calling recover to absorb panics, so our program now looks like this:</p>
<pre><code>package main
func main() {
defer func() {
recover()
}()
const (
panic = iota
print
println
)
// User code here
}
</code></pre>
<p>If Go were a lesser language, we might declare victory here. But this only absorbs panics in the <code>main</code> goroutine. Thanks to Go's concurrency features the user can simply create new goroutines and panic in them! The fact that all goroutines terminate when <code>main</code> does won't help, because the user can block the goroutine they're using with <code>select {}</code> and allow others to execute.</p>
<p>At this point, I see two possible paths:</p>
<ul>
<li>Prevent the user from accessing any possible means of output.</li>
</ul>
<p>We can <code>import . os</code>; call <code>Close()</code> on <code>Stdin</code>, <code>Stdout</code>, and <code>Stderr</code>; and then shadow everything else in the package as constants. This is almost what we want, as even panics don't print anything. But the user has one last bit of IO that we can't control: the process's exit code. A Go program terminated by a panic has exit status 2, which is even printed if you use <code>go run</code>. With this the user can add and detect primes by the decisional model.</p>
<ul>
<li>Prevent any code in user-created goroutines from executing.</li>
</ul>
<p>This appears to be <em>just</em> shy of possible. My first thought was</p>
<pre><code>import . "runtime"
GOMAXPROCS(1)
LockOSThread()
</code></pre>
<p>But <code>GOMAXPROCS</code> limits only the number of <em>parallel</em> goroutines, not the number of runnable goroutines (<a href="http://stackoverflow.com/questions/37426511/why-doesnt-gos-lockosthread-lock-this-os-thread" rel="nofollow">stack overflow</a>. My next thought was to limit the OS threads usable by the program with</p>
<pre><code>import . "runtime/debug"
SetMaxThreads(...)
</code></pre>
<p>I'm sure these results will vary from system to system. On my system, 4 or fewer as the argument to <code>SetMaxThreads</code> instantly crashes the program (and we must actually execute the user's code), and 5 or greater appears to have no effect. Perhaps a Go concurrency whiz can help me in this respect.</p>
<p>As a branch-off from the above idea:</p>
<ul>
<li>Create another goroutine that is constantly communicating back and forth with <code>main</code>, where the user's code lives. If <code>main</code>'s communications cease, because it has been blocked that a user-created goroutine might execute, the other goroutine kills the program.</li>
</ul>
<p>Again, <em>just</em> shy of possible. How can the helper tell that <code>main</code>'s communications have ceased? Goroutines have no identity. A little bit of brainstorming led to this odd code:</p>
<pre><code>c := make(chan bool, 2)
c <- true
c <- true
go func() {
for {
<-c
if len(c) == 0 {
os.Exit(0)
}
}
}()
for {
c <- true
// User code here
}
</code></pre>
<p>This prevents the user from blocking <code>main</code>, but by wrapping the code in a loop, we prevent <code>main</code> from destroying user goroutines that would be destroyed if the user <em>didn't</em> block main. Is it one or the other, or does this idea have merit?</p>
<p>Thanks for reading. I can't wait to hear your suggestions.</p>
<hr/>**评论:**<br/><br/>TheMerovius: <pre><p>How would this be forbidden by the rules?</p>
<pre><code>runtime.GOMAXPROCS(1)
go func() { for {} }()
</code></pre>
<p>If I'm not mistaken that should starve the main goroutine, i.e. prevent any computation to take place. At least in gc?</p></pre>Partageons: <pre><p>First, <a href="https://play.golang.org/p/xYWd3jAlhn" rel="nofollow">it doesn't work</a>. Second, even if it did work, then the user's code will not be executed, which is a sub-requirement of the challenge as stated later on. If things like that were allowed, I would have stopped at <code>SetMaxThreads(4)</code>, which instantly crashes the program.</p></pre>twanies: <pre><p>Plz solve real life problems with Go.</p></pre>dlsniper: <pre><p>What's the point of this? Who would ever need this? Why? How can this be meaningful in any way? Call me shortsighted but I fail to see why should one make this effort?</p></pre>barsonme: <pre><p>fun of it. same reason why people code golf.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传