[FIX] file_functions: three integer conversions in the read path (truncated seek, unsigned underflow, signed/unsigned compare) - #2325
Merged
Conversation
get_file_size() stored an LSEEK result in an int. LSEEK returns a 64-bit offset, so a successful seek back to a position at or beyond 2 GB truncated to a negative int and the function reported failure for a seek that worked. ccx_demuxer_get_file_size() is the same routine written correctly with an LLONG; this copy had drifted. Latent today -- the only caller opens each file fresh, so the position is always 0 -- but it is a trap for the next caller. buffered_read_opt() computed the bytes left in the file buffer as "bytesinbuffer - filebuffer_pos" on two unsigned ints. That is the underflow that made the bounds checks in file_buffer.h pass when they should have failed; the helper added to fix those, buffered_bytes_left(), belongs here too. The end-of-input test compared inputsize, a signed 64-bit size, against origin_buffer_size, a size_t. The usual arithmetic conversions turned a negative inputsize -- what get_filesize() returns when the size cannot be determined -- into a huge unsigned value, so the test silently read as "the input is enormous". The comparison is now spelled out. An unknown size still does not count as fitting in one read, and the short-circuit order is unchanged, so switch_to_next_file() is called exactly when it was before. Verified against the current master binary: byte-identical output on 99 files from the sample library, and on the --bufferinput, multi-file concat and stdin paths, with matching exit codes throughout.
Collaborator
CCExtractor CI platform finished running the test files on linux. Below is a summary of the test results, when compared to test for commit 128175e...:
Your PR breaks these cases:
NOTE: The following tests have been failing on the master branch as well as the PR:
Congratulations: Merging this PR would fix the following tests:
It seems that not all tests were passed completely. This is an indication that the output of some files is not as expected (but might be according to you). Check the result page for more info. |
Collaborator
CCExtractor CI platform finished running the test files on windows. Below is a summary of the test results, when compared to test for commit 128175e...:
Your PR breaks these cases:
NOTE: The following tests have been failing on the master branch as well as the PR:
Congratulations: Merging this PR would fix the following tests:
It seems that not all tests were passed completely. This is an indication that the output of some files is not as expected (but might be according to you). Check the result page for more info. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #2322. While reading the MSVC narrowing warnings on that PR I checked each one in
file_functions.c; most are benign, three are not. All three are the same family as #2322 — an integer conversion that quietly turns a check into something other than what it reads as.1.
get_file_size()truncates a 64-bit offsetA successful seek back to a position at or beyond 2 GB truncates to a negative
int, so the function reports failure for a seek that worked, and the caller sees the file size as-1.ccx_demuxer_get_file_size()(ccx_demuxer.c:236) is the same routine written correctly withLLONG ret— this copy had drifted.Latent, not observable today: the only caller,
get_total_file_size(), opens each file fresh, socurrentis always 0. Fixed because the next caller has no way to know that.2. Same unsigned underflow #2322 fixed, one layer down
Both operands are
unsigned int. This is exactly the subtraction that made thefile_buffer.hbounds checks pass when they should have failed. #2322 addedbuffered_bytes_left()for it; this site was missed.3. End-of-input test compares signed against unsigned
inputsizeisLLONG,origin_buffer_sizeissize_t, so the usual arithmetic conversions make the comparison unsigned.get_filesize()returns −1 when the size cannot be determined (ccx_demuxer.c:246), and that −1 becomesSIZE_MAX— the test silently reads as "the input is enormous".Now spelled out:
Behaviour is unchanged. For
inputsize >= 0the unsigned comparison is identical to before. Forinputsize < 0both the old and new forms yield false, so an unknown size still does not count as fitting in one read. The hoisted expression is a pure field read and comparison, so the short-circuit order is preserved andswitch_to_next_file()— the one clause with side effects — is still called exactly when it was.Testing
This file sits on every input path, so the changes were A/B'd against a binary built from current master (
128175ea):--out=srt --latin1--bufferinput(10 samples)switch_to_next_file)-stdin, whereinputsizecan be negative)Builds clean with no compiler messages;
clang-formatreports no changes.Noted, not changed
buffered_read_opt()has a vacuous guard at what is now line 374:opisLLONGandbytesissize_t, so the sum is unsigned and can never be negative — and every caller passes a non-negativebytesanyway, so it could not fire even with correct types. It is dead rather than wrong, and removing it is a separate judgement call about whether the intended check should exist at all. Flagging it here rather than widening this PR.