-
Notifications
You must be signed in to change notification settings - Fork 77
Use validator output if it exits first, for interactive problems #77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
It mixed spaces and tabs.
Before this change, if a validator detected, say, an invalid input format and exited, it would close its output pipe, and the submission would proceed to read EOF and possibly crash/TLE. The output of the submission would then be displayed to the user. This isn't great -- it either results in confusing judgements, or necessitates adding convoluted clean exit protocols to the problem to deal with these cases. In the latter case, the contestant needs to add probably-unnecessary hard-to-test code, and the description of the protocol can bog down the problem statement (see e.g. "Go, Gopher" from Google Code Jam 2018: https://goo.gl/ccT6t3). This commit takes the stand that if the validator exits first with a WA status, that should take precedence. Note that this may result in WA statuses where the time limit is exceeded.
Now also with another (not yet tested) fix for validator SIGPIPEs. Unrelated but pretty similar to (and dependent upon) the rest of the PR. |
@austrin Think you could review this? Does the approach make sense? |
@austrin Ping! Or are you trying to safeguard yourself against interactive problems in the coding cup finals? ;) |
@austrin Re-ping. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with the goal of giving the validator a bit more say. One general concern I have however is that this breaks the invariant "judgement = TLE <=> runtime > timelim", and I really don't want to do that. I can see two ways of addressing that:
- Change it so that if runtime > timelim then result is TLE regardless of what validator says (but if submission crashed or exceeded walltime limit, which are probably more common ways of failing after validator has terminated, then validator gets its say).
- Set runtime=timelim in the case when validator terminated first with WA but submission ran over time
I think option 2 is pretty ugly so would prefer option 1.
volatile int val_pid = -1, user_pid = -1; | ||
volatile int user_status = -1, val_status = -1; | ||
volatile static rusage user_ru; | ||
volatile static rusage val_ru; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you think these (and others below) need to be volatile?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are used from a signal handler, so it seemed "more correct" (even if still actually incorrect -- only volatile sig_atomic_t
s and atomics are allowed, and even then we have race conditions that make the whole approach wrong). But until the signal handler is fixed properly, this may at least prevent the compiler from reordering some assignments etc. which I wouldn't be surprised if it does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense!
support/interactive/interactive.cc
Outdated
while (remaining > 0) { | ||
int status; | ||
struct rusage ru; | ||
int r = wait4(-1, &status, 0, &ru); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change this to wait3
?
support/interactive/interactive.cc
Outdated
if (r == user_pid) { | ||
// In case of broken pipes, let validator decide | ||
user_status = (WIFSIGNALED(status) && WTERMSIG(status) == SIGPIPE ? 0 : status); | ||
memcpy((void*)&val_ru, &ru, sizeof(rusage)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be user_ru
not val_ru
.
With the PR as is walltime limit exceeded will practically never happen when the validator exits early, because then we close all pipes and you cannot block on them forever. We could of course decide not to close the pipes and then wait for the wall time limit to hit, but that seems somewhat silly in that it only prolongs time until error... How about setting runtime = min(validator exit time, submission exit time)? |
Right, I agree. (But the crashing part is still probably the most common way for a solution to fail after the validator has terminated.)
I don't think that makes sense, the two programs may need very differing amounts of CPU time and there is no reason why the CPU time of the validator would be any reasonable measure of the CPU time of the submission. However, one possibility that I think would make a lot of sense would be to fetch the current CPU time of the submission process at the time the validator exits. |
If it's just "the most common way" then it doesn't help because you still need to know about the edge case... Also, I'm not sure my experiences agree with crashing being more likely than TLE.
Sounds good! I'll see if I can make this work here and in Kattis (tomorrow or so). |
Also worth mentioning: the first approach I had to this was to kill the submission when the validator exited; however, it turns out that that doesn't work well with isolate, which runs as |
Agreed, that would give the expected results. Because what you would actually really want is...
... to kill the submissions as soon as the validator has decided to give up.
👍 |
It appears to be pretty hard to get to that information.
|
There is also the (also bad) option of keeping TLE if process uses too much CPU. I would slightly prefer that, but I am also fine with capping runtime at timelim in the case when validator decides on WA before the user process exits. |
In my view that's more or less equivalent to (maybe slightly worse than) wontfixing this PR, since it would still require explaining in the problem statement that you must (somehow, by some problem-specific scheme) exit nicely when the validator exits to avoid confusing verdicts. But sure, it's an option. Anyway, I pushed a commit for the |
Sounds good. How about also adding a test submission to |
Thanks for merging! I agree that a test is a great idea, I'll try to get to that at some point if you don't do it before me. Also, does this need some sort of spec update or coordination with other judges? |
…, override TLE. See Kattis/problemtools#77 for an in-depth discussion. With this, all test submissions of the example guess problem give the expected answer, but we need to do some cleanup and UI/import changes before we can close DOMjudge#465.
…, override TLE. See Kattis/problemtools#77 for an in-depth discussion. With this, all test submissions of the example guess problem give the expected answer, but we need to do some cleanup and UI/import changes before we can close #465.
As per the commit message:
With a few other cleanups thrown in.
Changes the output format of
interactive.cc
, I don't know if that matters for other consumers than kattis.