Il giorno mer 17 dic 2025 alle ore 09:07 Paul Eggert
<[email protected]> ha scritto:
>
> On 2025-12-14 18:18, Matteo Croce wrote:
> > Il giorno dom 14 dic 2025 alle ore 01:44 Paul Eggert
> > <[email protected]> ha scritto:
> >> On 2025-12-13 08:09, Matteo Croce wrote:
> >>> That was the purpose of the patch, even if maybe I should calculate it
> >>> by using sysconf(_SC_PAGESIZE).
> >> OK, but I'm not seeing why the patch would be a good idea for the
> >> coreutils master branch. Without the patch, doesn't 'cat' work well on
> >> all porting targets? Why add an unnecessary syscall?
> > Which syscall? sysconf doesn't ask the kernel for page size.
>
> Fair enough. But why add an unnecessary call? How would it improve cat's
> behavior, from the user's viewpoint?
I'm investigating a kernel bug[1] where it seems that if (file offset
+ read size > LONG_MAX), then all I/O fails with EINVAL.
This can be triggered with a huge file:
$ truncate -s $((2**63 - 1)) file1
$ ( dd bs=1M skip=$((2**43 - 2)) count=0 && cat ) < file1
0+0 records in
0+0 records out
0 bytes copied, 2,825e-05 s, 0,0 kB/s
cat: -: Invalid argument
$ dd if=file1 bs=1M skip=$((2**43 - 2))
dd: error reading 'file1': Invalid argument
1+0 records in
1+0 records out
1048576 bytes (1,0 MB, 1,0 MiB) copied, 0,103536 s, 10,1 MB/s
or with a small file and a huge read, e.g. as in the attached file.
[1]
https://lore.kernel.org/linux-fsdevel/[email protected]/T/
--
Matteo Croce
perl -e 'for($t=0;;$t++){print chr($t*($t>>8|$t>>13)&255)}' |aplay
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <limits.h>
#include <err.h>
int main(int argc, char *argv[])
{
// Just a MB less than LONG_MAX
size_t size = LONG_MAX - (1024 * 1024);
int in, pipefd[2], r;
in = open(argv[1], O_RDONLY);
if (in < 0)
err(1, "open");
r = pipe(pipefd);
if (r < 0)
err(1, "pipe");
r = fork();
if (r < 0)
err(1, "fork");
if (!r) {
// Discard data from pipe
char *buffer = malloc(1024 * 1024);
while (read(pipefd[0], buffer, 1024 * 1024) > 0)
/* do nothing */ ;
return 0;
}
// splice data from file to pipe
for (ssize_t copied = 1; copied; ) {
copied = splice(in, NULL, pipefd[1], NULL, size, 0);
if (copied < 0) {
perror("splice");
// splice() will fail when file pos + size exceeds LONG_MAX
fprintf(stderr, "Failed to splice %zu bytes at offset %ld\n", size, lseek(in, 0, SEEK_CUR));
return 1;
}
}
return 0;
}