# Builder Your Own Code Runner

Nowadays, there are a lot of online coding platform, like LeetCode and CoderPad. Such platforms provide an IDE at the frontend for the user to write code. When they hit ‘Run’, the code will be automatically executed in remote server and have the result back to the user. RunCode is my prototype of such platform. In this article, we will build our own!

## Docker

We need docker to separate each user’s code and output file. By creating individual container for each code execution, we will not worry user’s malicious code like rm -rf / that will delete all the server. Besides, we can separate stdout so that users’ output won’t be interleaved.

After installing docker, we will pull some alpine images for C/C++, Java, Python. I choose alpine because of its small size.

For C&C++, we only need to install g++ (it will install gcc as well). Creating the following Dockerfile.

run docker build -t cpp . to build the image with tag cpp.

For Java and Python, we will use the official alpine image

## Build the Command

### Memory Restriction

It’s important that each user’s program will consume the memory from the host server indefinitely. We need to set memory restraint by using docker -m

For example, limit the maximum memory usage is 64MB.

However, if you see the warning No swap limit support. We need to change /etc/default/grub according to this solution. Especially for Google Cloud, we need to change /etc/default/grub.d/50-cloudimg-settings.cfg instead.

After that, we will not see the warning.

### CleanUp

using docker --rm to clean up once done.

### Timeout

It’s also important to set timeout so that malicious code (while True: pass) will not get executed indefinitely. However, it seems docker doesn’t support this natively. We may need to rely on command timeout to send SIGKILL when some time period is passed (5s). After that, we still need to clean up all the container resources, therefore we may need a random name for each container. So in case of timeout, we can use this name to kill this container first then combined with --rm, the container will be removed.

### Folder mapping

For each code execution, we need to create a new folder that contains the user input file, which will map(mount) it to the docker container by using docker -v

Therefore inside the folder /code of the container, it contains our input file.

### Compile & Run

#### Python

Python is the easiest to do, but we need to use -u to get the output

#### C/C++

I find only in this way we can get the multiprocessing output.

#### Java

Java is the most tricky one, since we need to find the class with function main. Besides, if there is a public class, the filename should be exactly the same as the class name. Therefore, we need to do preprocessing on the input file and rename the file if possible.

Regex /^\s*public class\s+([^\s]+)/m is used to get the public class name, if any, rename the java file to the class name.

Then using runJava.sh to compile and run.

Therefore, an additional read-only mapping for runJava.sh is necessary

## Error&Output

We can determine error, timeout or actual output from err, stdout and stderr like the following Node.js snippet.