-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
fmt: Make sure the goal is always positive when given a positive width #6094
Conversation
GNU testsuite comparison:
|
Looks good, thanks! I wonder why that |
tests/by-util/test_fmt.rs
Outdated
|
||
#[test] | ||
fn test_small_width() { | ||
for width in ["1", "2", "3"] { |
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.
There is one value missing that unfortunately makes the test fail: 0
.
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.
Interesting. I don't see this on the man or info pages, but I'm guessing GNU fmt
treats -w0
as -w1
?
Running this in the uutils/coreutils repo gave no output:
fd -t f -0 | while IFS= read -r -d '' file; do diff <(fmt -0 "$file") <(fmt -1 "$file"); done
I'm not sure whether to special case treating a zero width as one width, or treating the goal as zero in that case (both fix this test when run with "0"
). I'm pushing a PR that changes the calculated goal since that seems like the smaller change, but I'm not sure either are different
Did a bit of git archeology: it looks like that was added in this commit from 2014 by @kwantam , where it was changed from a |
A debug assertion was added to enforce "width >= goal" to catch that case before a panic in linebreak.rs. A few warnings in linebreak.rs were addressed as well, and some isize's that should always be positive (if there's no width/goal bugs) were changed to usizes to catch bugs earlier. test_fmt_width is updated to test for the same result as GNU fmt
11c063a
to
f456b95
Compare
Thanks for the PR :) |
Thanks for the review 🙂 |
Yeah, sorry about the lack of comments. I have little recollection of why I ended up on those particular numbers, but I do seem to recall experimenting with the constants in an attempt to make the output reasonable over a range of widths... |
Currently, the
fmt
utility will panic with an integer overflow when given a small enough width:GNU coreutil's fmt doesn't have a problem with this:
This PR adds a test to tests/by-util/test_fmt.rs reproducing this panic. The root cause is this calculation:
This sets the goal
g
to be zero when the widthw
is three, or negative for smaller widths. This also contradicts the behavior in the argument help and in the GNU fmt info page, both of which just say the goal will be 93% of the width.This PR makes the goal set when only specifying the width be the value expected by the documentation. This avoids the overflow later on in
linebreak.rs
, which comes about from essentially calculating2*goal - width
as a minimum length to consider breakpoints (this can't be correct if, for example, the goal is 2 and the width is 12, but I'm leaving addressing that issue out of this PR).A
.max(..)
call is added to ensure the goal is 1 if the width is positive or zero if the width is zero. This ensures that2*goal - width
is always nonnegative for the code path where a width (but not a goal) is provided.There are a few other things in this PR:
fmt -10 tests/fixtures/fmt/one-word-per-line.txt
. With this PR, I get the same as thefmt
command, so I've updated the test.