Skip to content
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

compiletest: may truncate compiler output before trying to parse it as json #96229

Closed
nagisa opened this issue Apr 19, 2022 · 4 comments · Fixed by #115706
Closed

compiletest: may truncate compiler output before trying to parse it as json #96229

nagisa opened this issue Apr 19, 2022 · 4 comments · Fixed by #115706
Assignees
Labels
A-testsuite Area: The testsuite used to check the correctness of rustc

Comments

@nagisa
Copy link
Member

nagisa commented Apr 19, 2022

Running a ui test will eventually invoke the following function:

fn into_bytes(self) -> Vec<u8> {
match self {
ProcOutput::Full(bytes) => bytes,
ProcOutput::Abbreviated { mut head, skipped, tail } => {
write!(&mut head, "\n\n<<<<<< SKIPPED {} BYTES >>>>>>\n\n", skipped).unwrap();
head.extend_from_slice(&tail);
head
}
}
}

through

let Output { status, stdout, stderr } =
read2_abbreviated(child).expect("failed to read output");
let result = ProcRes {
status,
stdout: String::from_utf8_lossy(&stdout).into_owned(),
stderr: String::from_utf8_lossy(&stderr).into_owned(),
cmdline,
};

which can truncate a long output from the compiler. The problem is that UI tests ask the compiler to output its output as json and then attempts to parse it later, for example here:

let rustfix_input = json::rustfix_diagnostics_only(&proc_res.stderr);

which can fail due to truncation and output very difficult to investigate output in e.g. CI.

Reference: https://rust-lang.zulipchat.com/#narrow/stream/187780-t-compiler.2Fwg-llvm/topic/Legacy.20PM.20removal/near/279479951

@nagisa nagisa added E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. A-testsuite Area: The testsuite used to check the correctness of rustc labels Apr 19, 2022
@ehuss
Copy link
Contributor

ehuss commented Apr 20, 2022

I think this is somewhat a duplicate of #94322 and #92211.

It might be good to consolidate these issues, and come up with a specific suggestion on how to improve it. The limit needs to be there to prevent OOM, and also as a indicator that perhaps rustc is emitting too much data (as #94327 resolved). So I suspect what is desired is a better way to display the error. I haven't thought about it myself, but I think that should be easy to improve.

@nagisa nagisa removed the E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. label Apr 20, 2022
@nagisa
Copy link
Member Author

nagisa commented Apr 20, 2022

Got it, removed E-easy.

I feel like at least a part of this problem is in the fact that the truncation happens indiscriminately at a byte boundary. And another part is that the failure mode is non-deterministic (paths and such can have varying lengths.)

If the intent is to make “too much output” a failure mode, then we should just straight up fail the test, I feel. Possibly kill/SIGPIPE the compilation process when it exceeds the amount of output bytes but don't truncate the output itself when showing it to the user…?

Alternatively, for JSONL(ines) truncating on line boundaries would make things not fail as terribly. Not to mention, the rendered output is duplicated among other information with JSON output and a test will likely be interested in only parts of it, which will make truncation kick in earlier in some instances than others, so maybe giving an opportunity to map the output in a streaming fashion would help?

@pietroalbini
Copy link
Member

Also hit this due to #96362 (comment) on my local machine...

@pietroalbini
Copy link
Member

Opened a PR to remove the nondeterminism based on the length of the checkout path, which should at least alleviate the problem (abbreviations would still happen, but at least they'd show up on CI): #96551

bors added a commit to rust-lang-ci/rust that referenced this issue Jun 6, 2022
…iating, r=Mark-Simulacrum

[compiletest] Ignore known paths when abbreviating output

To prevent out of memory conditions, compiletest limits the amount of output a test can generate, abbreviating it if the test emits more than a threshold. While the behavior is desirable, it also causes some issues (like rust-lang#96229, rust-lang#94322 and rust-lang#92211).

The latest one happened recently, when the `src/test/ui/numeric/numeric-cast.rs` test started to fail on systems where the path of the rust-lang/rust checkout is too long. This includes my own development machine and [LLVM's CI](rust-lang#96362 (comment)). Rust's CI uses a pretty short directory name for the checkout, which hides these sort of problems until someone runs the test suite on their own computer.

When developing the fix I tried to find the most targeted fix that would prevent this class of failures from happening in the future, deferring the decision on if/how to redesign abbreviation to a later date. The solution I came up with was to ignore known base paths when calculating whether the output exceeds the abbreviation threshold, which removes this kind of nondeterminism.

This PR is best reviewed commit-by-commit.
@bors bors closed this as completed in 8e455db Sep 13, 2023
github-actions bot pushed a commit to rust-lang/miri that referenced this issue Sep 15, 2023
Make compiletest output truncation less disruptive

When the test output becomes too large, compiletest stops recording all of it. However:
- this can lead to invalid JSON, which then causes compiletest itself to throw further errors
- the note that output was truncated is in the middle of the output, with >100kb of text on each side; that makes it almost impossible to actually see that note in the terminal

So assuming that we do need to keep the output truncation, I propose that we only ever do a cut at the end, so that it is very clear by looking at the end of the log that truncation happened. I added a message at the beginning of the output as well. Also I added some logic to make it less likely that we'll cut things off in the middle of a JSON record. (I tested that successfully by reducing the output limit to something very low and running a few ui tests.) Furthermore I increased the max buffer size to 512KB; that's really not a lot of memory compared to how much RAM it takes to build rustc (it's ~25% more than the previous maximum HEAD+TAIL length). And finally, the information that things got truncated is now propagated to the higher levels, so that we can fail the test instead of comparing the truncated output with the reference.

Fixes rust-lang/rust#115675
Fixes rust-lang/rust#96229
Fixes rust-lang/rust#94322
Fixes rust-lang/rust#92211
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-testsuite Area: The testsuite used to check the correctness of rustc
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants