3

I am building an online judge that takes a user's c++ code, and tells them whether or not the output from it is correct. Currently, I'm looking at an open source python project to see how to do it. In the example code, they run both subprocess.check_output() and subprocess.call(), even though they pretty much do the same thing. Since I am a beginner at subprocess and command line arguments in general, I was wondering if there is a reason for this. Thanks!

    if language == "C++":
        filename = "submissions/" + str(runID) + ".cpp"
        try :
            subprocess.check_output('g++ ' + filename, stderr = subprocess.STDOUT , shell=True);
        except subprocess.CalledProcessError, e:
            return (-1 , e.output)
        retval = subprocess.call('g++ ' + filename , shell = True)
        subprocess.call('timeout 1s ./a.out < ' + inpfile + ' > ' + outfile , shell = True)
JaMiT
  • 14,422
  • 4
  • 15
  • 31
Evan Wild
  • 67
  • 5
  • 3
    My first thought was that `retval` was going to be used afterwards, but the code will reach that point only if `retval` is zero. So, it could be just bad code? – Aziz Aug 22 '19 at 00:35

1 Answers1

3

In this case, it looks like this is just bad code.

subprocess.check_output will run g++ with the specified arguments, collecting the output and saving it in e if the compiler exits with an error. The tuple (-1, output) is then returned.

If the compiler succeeds the first time, the code runs the compiler again with the same command-line arguments, just to get the return value. However, barring any system issues like just barely running out of disk space, if the compiler succeeded the first time, it will succeed the second time (doing no useful work since the output has already been written). After this, the output gets run.

On another note: Aside from the fact that it's generally not safe to run untrusted C++ code, using shell=True creates its own security concerns if the filename is user-provided and doesn't get properly sanitized.

nanofarad
  • 40,330
  • 4
  • 86
  • 117
  • Alright, thanks for confirming that it isn't necessary! In this case, should I replace the two lines with subprocess.check_call()? – Evan Wild Aug 22 '19 at 00:45
  • 2
    @EvanWild You could probably do it with just the one subprocess.check_output--it will cover both the return code and the compiler error messages (if you want to report them to the user submitting the code) – nanofarad Aug 22 '19 at 00:52
  • Not a problem; happy to help. Kudos for not just blinding trusting this code; trying to understand design decisions (good and bad) is always a good step to take. – nanofarad Aug 22 '19 at 00:58