blob: ae3c5e9a1177cc1d5cab1127b7cda087b8d915b2 [file] [log] [blame]
Inside the Go playground
Francesc Campoy Flores
Developer Advocate, Gopher
@francesc
campoy@golang.org
http://campoy.cat
* Agenda
- What is the Go playground
- What could go wrong
- What did we do to avoid it
- An animated ASCII train
* The Go playground
.image playground/img/play.png 500 _
.caption [[/play/][go.dev/play]]
* De facto pastebin of the Go community
.image playground/img/share.png 500 _
.caption [[/play/p/bJYnajZ6Kp][go.dev/play/p/bJYnajZ6Kp]]
* The Go tour
.image playground/img/tour.png 500 _
.caption [[/tour/][go.dev/tour]]
* Executable examples on documentation
.image playground/img/examples.png 500 _
.caption [[/pkg/strings/#example_Fields][go.dev/pkg/strings]]
* Executable code on blog posts
.image playground/img/blog.png 500 _
.caption [[/blog/slices][go.dev/blog/slices]]
* Executable slides
.play playground/hello.go
These slides are driven by the `present` Go tool
go get code.google.com/go.tools/cmd/present
* Naive implementation
* Architecture
.image playground/img/arch.png 500 _
* Backend
Let's start with something simple
- receive code
- compile it
- run it
* What could go wrong?
.image playground/img/areyousure.png 500 _
###########
## Issues #
###########
* Resource exhaustion
* Exhausting memory on the stack
`stack`overflow`
.play playground/stack.go
The runtime catches the error and panics.
* Too much memory on the heap
`out`of`memory`
.play playground/heap.go
Again the runtime catches the error and panics.
* Too much CPU time
.play playground/loop.go
* Stealing resources by sleeping
.play playground/sleep.go
A sleeping program still consumes resources.
Easy way of having a Denial of Service attack.
* Accessing things you shouldn't
* File system access
User code shouldn't be able to modify the backend's file system.
- Reading sensitive information
- Installing backdoors
- General mayhem
.play playground/removeall.go /func main/,/^}/
* Network access
.play playground/http.go /func main/,/^}/
* Use your imagination
.image playground/img/cat.jpg 500 _
###################
# Countermeasures #
###################
* Countermeasures
* Restricting resource usage with ulimit
Default limits are not safe enough.
`ulimit` could solve this.
-d maximum size of data segment or heap (in kbytes)
-s maximum size of stack segment (in kbytes)
-t maximum CPU time (in seconds)
-v maximum size of virtual memory (in kbytes)
* Native Client
Originally designed to execute native code in Chrome safely.
NaCl defines restrictions on the binaries being executed.
The code runs in a sandbox isolated from the underlying OS.
- No file access
- No network access
.image playground/img/nacl.png 300 _
* Isolating process execution with NaCl
We use NaCl to:
- limit CPU time
- limit memory
- isolate from the filesystem
- isolate from the network
Process can only write to stdout/stderr.
* Limiting user time
"No sleeping in the playground."
Custom runtime with a fake `time` package.
func Sleep(d time.Duration) {
panic("No sleeping in the playground")
}
* Restoring functionality
* Faking the file system
The `syscall` package is the only link between user code and the OS kernel.
The playground runtime has a custom `syscall` package.
File system operations operate on a fake in-memory file system.
.play playground/file.go /func main/,
* Faking the network
All network operations also use the `syscall` package.
The network stack is also faked in-memory.
.play playground/net.go /func main/,/^}/
* Faking the network (continued)
.play playground/net.go /func dial/,/^}/
##########
## TIME ##
##########
* Sleeping in the playground
Go is about concurrency.
We need to demonstrate concurrency in blog posts and talks.
And demonstrating concurrency without `time` is hard.
* What to do if an open source project lacks a feature?
.image playground/img/gopherbw.png 500 _
* File a bug!
.image playground/img/bug.png 500 _
.caption [[https://code.google.com/p/go/issues/detail?id=4280][bug 4280]]
* Normal behavior
There's a special goroutine managing timers `T`.
A goroutine `G` calls `time.Sleep`:
1. `G` adds a timer to the timer heap.
2. `G` puts itself to sleep.
3. `T` tells the OS to wake it when the next timer expires and puts itself to sleep.
4. When `T` is woken up it looks at the timer on the top of the heap, and wakes the corresponding goroutine.
* Intermission: deadlocks
.play playground/deadlock.go
Many flavors of deadlocks.
One common property: all goroutines are asleep.
* New behavior
A goroutine `G` calls `time.Sleep`:
1. `G` adds a timer to the timer heap.
2. `G` puts itself to sleep.
3. The scheduler detects a deadlock, checks the timer heap for pending timers.
4. The internal clock is advanced to the next timer expiration.
5. The corresponding goroutines are woken up.
* Sleeping fast
Faking time allows precise sleep durations.
.play playground/sleepfast.go
* So there's no actual sleep?
The playground's `write` syscall inserts a timestamp before each write.
The front end translates that into a series of "events" that the browser can play back.
.play playground/sleep.go /func main/,
Returns directly
{
"Errors":"",
"Events":[
{"Message":"Good night\n","Delay":0},
{"Message":"Good morning\n","Delay":28800000000000}
]
}
* So the bug was fixed
.image playground/img/andrew.png _ 1000
.caption [[/play/p/3fv0L3-z0s][go.dev/play/p/3fv0L3-z0s]]
* And people were happy
.image playground/img/brad.png _ 1000
.caption [[/play/p/rX_3WcpUOZ][go.dev/play/p/rX_3WcpUOZ]]
* Very happy
.image playground/img/jan.png _ 1000
.caption [[/play/p/P-Dk0NH_vf][go.dev/play/p/P-Dk0NH_vf]]
.image playground/img/mattn.png _ 1000
.caption [[/play/p/NOycgN2i6b][go.dev/play/p/NOycgN2i6b]]
* References
These slides: [[/talks/2014/playground.slide]]
More about the Go tour:
- Inside the Go playground: [[/blog/playground][go.dev/blog/playground]]
- The Go tour: [[/tour/][go.dev/tour]]
More about Go on NaCl:
- Running Go under Native Client: [[https://code.google.com/p/go-wiki/wiki/NativeClient]]
- Go 1.3 Native Client Support: [[/s/go13nacl]]