I've been having some fun with this hilarious CodeGolf stack exchange question. Read the challenge for a full and clear specification. Last year, the user Cat posted this Go answer (which I've edited for simplicity):
package main
func main() {
const (
append = iota
cap; close; complex; copy
delete
imag
len
make
new
panic; print; println
real
recover
bool; byte
complex64; complex128
error
float32; float64
int; int8; int16; int32; int64
rune
string
uint; uint8; uint16; uint32; uint64; uintptr
true
false
nil
iota = 0
)
// User code goes here
}
From here on, code samples will go under the // User code goes here
line unless otherwise indicated.
Imports can only be done at the top of the file, which means we can't access fmt
, os.Args
, syscall
, or flag
. We've erased panic
, print
, and println
, which would allow us to affect the output in at least some way.
However, on seeing this answer the thought occurred to me that you don't need to call panic
directly. You can just do something to cause a panic. So we can create a primality test based on panicking or not panicking:
n := 37
for i := 2; i < n; i++ {
if n % i == 0 {
c := []struct{}{}
_ = c[1]
}
}
This will panic if n
is composite and output nothing if it is prime. Luckily, we can plug that leak by adding this code to the top of main
:
defer func() {
_ = recover()
}
Now any panics we create will be absorbed.
That is, any panics in the main
goroutine! Go's concurrency features allow us to bypass this block again by wrapping the code in a go
statement:
go func() {
n := 37
for i := 2; i < n; i++ {
if n % i == 0 {
c := []struct{}{}
_ = c[1]
}
}
}()
var c chan interface{}
<-c
Now the program deadlocks on primes and panics on non-primes.
So how can this leak be plugged, and Go made unusable? The only thing I could think of was using the runtime
package to restrict the number of goroutines, but there appears to be no such facility, so I'm out of ideas.
评论:
tclineks:
joushou:deargodwhy
Partageons:Now returns cleanly on success, and panics on failure.
fail := func() { go func() { _ = []struct{}{}[1] }() var c chan interface{} <-c } n := 37 for i := 2; i < n; i++ { if n%i == 0 { fail() } }
DeedleFake:Since you're the only one who's offered any help, I'm getting closer. Here's what I have now: https://play.golang.org/p/9DLXU2gfMC Despite
main
and the infinite loop goroutine being locked to the two available OS threads, the user can still create a new goroutine and block main to panic within that goroutine.
Partageons:I'm not too clear on a lot of the internals of the runtime, but how about the following:
runtime.GOMAXPROCS(1) runtime.LockOSThread()
metamatic:I've tried that. Somehow the user can break out by blocking the
main
goroutine. https://play.golang.org/p/Gm4QabOFl_
brogrammingsins:It's hard to beat Smalltalk, where you can simply redefine true to be false and watch everything crash.
Carpetsmoker:What's the point behind this? Why would it ever be useful?
hukiki:Code golf are more like puzzles than anything else (i.e. entertainment). Some people seem to enjoy that sort of stuff...
Still better than football :-)
haha this is awesome. I love the JS version of the answer in the original link. Thanks OP.
