views:

656

answers:

2

I'm running a sort of "sandbox" in C on Ubuntu: it takes a program, and runs it safely under the user nobody (and intercepts signals, etc). Also, it assigns memory and time limits, and measures time and memory usage.
(In case you're curious, it's for a sort of "online judge" to mark programs on test data)

Currently I've adapted the safeexec module from mooshak. Though most things work properly, the memory usage seems to be a problem. (It's highly inaccurate)

Now I've tried the advice here and parsed VM from /proc/pid/stat, and now the accuracy problem is fixed. However, for programs that finish really quickly it doesn't work and just gives back 0.

The safeexec program seems to work like this:

  1. It fork()s
  2. Uses execv() in the child process to run the desired program
  3. Monitors the program from the parent process until the child process terminates (using wait4, which happens to return CPU usage - but not memory?)
    So it parses /proc/../stat of the child process (which has been replaced by the execv)

So why is VM in /proc/child_pid/stat sometimes equal to 0?
Is it because the execv() finishes too quickly, and /proc/child_pid/stat just isn't available?
If so, is there some sort of other way to get the memory usage of the child?
(Since this is meant to judge programs under a time limit, I can't afford something with a performance penalty like valgrind)

Thanks in advance.

+1  A: 

Can you arrange for the child process to use your own version of malloc() et al and have that log the HWM memory usage (perhaps using a handler registered with atexit())? Perhaps you'd use LD_PRELOAD to load your memory management library. This won't help with huge static arrays or huge automatic arrays.


Hmm, sounds interesting. Any way to track the static/automatic arrays, though?

Static memory can be analyzed with the 'size' command - more or less.

Automatic arrays are a problem - I'm not sure how you could handle those. Your memory allocation code could look at how much stack is in use when it is called (look at the address of a local variable). But there's no guarantee that the memory will be allocated when the maximum amount of local array is in use, so it gives at best a crude measure.

One other thought: perhaps you could use debugger technology - the ptrace() system call - to control the child process, and in particular, to hold it up for long enough to be able to collect the memory usage statistics from /proc/....

Jonathan Leffler
Hmm, sounds interesting.Any way to track the static/automatic arrays, though?
v3
Wow, ptrace is really neat. Thanks! (Since ptrace causes the child process to pause when it execv()s, I'm able to measure the memory usage just as it starts)
v3
+1  A: 

You could set the hard resource limit (setrlimit for RLIMIT_AS resource) before execve(). The program will not be able to allocate more than that amount of memory. If it tries to do so, memory allocation calls (brk, mmap, mremap) will fail. If the program does not handle the out-of-memory condition, it will segfault, which will be reflected in the exit status returned by wait4.

zvrba
I'm doing that already - I'd like to know how much it's actually using, though (to compare solutions)
v3