I’ve been attempting to write a browser game lately, using THREE.js for the graphics, Javascript for the frontend, and Python for the backend. I’m doing this to reinforce the principles I learned over the summer (MVC, web development technologies, etc), as well as to simply produce something cool. The result of the project will be a Final Fantasy Tactics battle system.
Lately, I was thinking about how to reduce code duplication on the server. There’s a lot of things that have to be done twice, on the client and on the server, since we can’t trust the client to compute them; it’s very easy to just send a message to the server saying “Hey, I did 9999 damage to this unit!” Anything that doesn’t have to do with how things are displayed must be validated on the server, but it’s a bad idea to have code in two places. In the beginning, teachers will tell you to take this for granted; later on, you realize just how painful it is to have the same code in multiple places. It’s extremely easy, and annoying, to change a number in one place and forget to do it in the other. Not to mention it’s just plain more efficient to not repeat yourself.
In an attempt to remedy this issue, I introduced a new dependency - PyV8. This is a python wrapper around google’s V8 engine, which runs all the javascript in the Chrome browser. With this, I can write all my calculations - unit damage, movement, and whatever else - in Javascript functions and then run them on both the client and the server. Easy enough, I suppose.
The installation of PyV8 wasn’t quite painless, as the PyV8 documentation isn’t that great, but several nice people that live on the internet helped me out. However, when it actually came time to test it on the server, python… segfaults? How does one segfault python?
Edit! Actually, what follows was probably not the solution; I was still having intermittent issues with the same exact error even after taking the measures described. What I think was really the problem is that Django runs threads, and PyV8 doesn’t like threads. It seems that you need to use a lock to prevent some resource from being used at the same time, as per this stack overflow thread. Basically, you just need to do this:
`with PyV8.JSLocker(): ctxt = PyV8.JSContext() ctxt.enter()
… your ctxt.eval() code here …
ctxt.leave() `
This makes more sense - it explains why the code wasn’t crashing in the shell, and why it was only crashing if I refreshed the web browser and then tried to execute some JS code (it wouldn’t crash on the first request the browser made).
Here ends the edit. You can still read what I have below if the above doesn’t fix it…
The answer, of course, is that python itself didn’t segfault at all; as I said, PyV8 is a wrapper around the V8 engine, which is written in C, and that’s what segfaulted. Well, I figure I need to figure out what segfaulted. All programmers know that the first step to debugging is to put in print statments! I spend about a minute doing this until I realize that I’m running Django under Apache and WSGI, and they use stdout/stdin to communicate, which means my print statements will completely mess up the application. Well, whatever - I’ll just switch to the django development server. To be honest, I’m not sure why I’m not using it in the first place…
Anyway, I do this, and I find out that it’s segfaulting on context creation, or more specifically, this line of code:
ctxt = PyV8.JSContext()
Well, that’s odd. I’m kind of at a loss as to what to do, since there’s not really a reason there should be any problems with this. I dither around a bit until I remember I can run the django environment from the command line, using python3 manage.py shell. I try the same line of code, but this time, from the shell:
`»> import PyV8
ctxt = PyV8.JSContext() `
What? It worked without issues? That’s… rather bewildering. I dismiss this as a dead end and head to google, and search what to do if Python segfaults. Someone suggests using gdb, and I silently thank my coworker from two summers ago for teaching me how to debug C++ under gdb. I run gdb python3, run the server, and it gives me this error:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff6ad8317 in kill () at ../sysdeps/unix/syscall-template.S:81
81 ../sysdeps/unix/syscall-template.S: No such file or directory.
At this point, I’m completely lost. What is that file? Why is there a “../” on it? What place is it trying to get this file from? Why does it even need this file? I turn to google again, and I get this link. It proves to be the last step to solve the problem; for whatever reason, PyV8 needs the source to libc to be able to run. Just to be sure, I run strace on the test server and, indeed, I get similar output to what that person had. After a bit of package searching, I run this command:
sudo apt-get install eglibc-source
And PyV8 works. The only thing I still don’t understand is why it worked in the shell, and not when I was actually running django under the server; maybe it has something to do with paths? Well, I probably will never know. If you do, I’m interested to hear.
In case you skipped ahead, make sure you go back up and read the edit. This was not actually what solved my issue.