Subject: bug#66375: 30.0.50; (error "Maximum buffer size exceeded") from (insert-file-contents "/dev/null")

From: Po Lu <[email-masked]>
Date: Sat, 07 Oct 2023 14:43:45 +0800

Eli Zaretskii <[email-masked]> writes:

>> From: Sam Steingold <[email-masked]>
>> Date: Fri, 06 Oct 2023 13:11:35 -0400
>> 
>> 
>> emacs -Q
>> 
>> (insert-file-contents "/dev/null")
>> ==>
>> Debugger entered--Lisp error: (error "Maximum buffer size exceeded")
>>   insert-file-contents("/dev/null")
>
> This is a "feature".  From the doc string:
>
>   When inserting data from a special file (e.g., /dev/urandom), you
>   can’t specify VISIT or BEG, and END should be specified to avoid
>   inserting unlimited data into the buffer from some special files
>   which otherwise could supply infinite amounts of data.
>
> Maybe we could make a special exception for the null-device, whose
> name we generally know on each supported system.
>
> Technically, the problem is that the null device is seekable, so this:
>
>   if (seekable || !NILP (end))
>     total = end_offset - beg_offset;
>
> computes 'total' to be a very large value, and then this:
>
>   /* Ensure the gap is at least one byte larger than needed for the
>      estimated file size, so that in the usual case we read to EOF
>      without reallocating.  */
>   if (GAP_SIZE <= total)
>     make_gap (total - GAP_SIZE + 1);
>
> attempts to make a gap very large, which errors out.  And that is
> before we try to read even a single byte from the file.
>
> Po Lu and Paul, any ideas?

I think treating /dev/null specially is suitable, but there is a
different shortcoming in the approach presently taken by
insert-file-contents:

      if (!regular)
	end_offset = TYPE_MAXIMUM (off_t);
      else
	{
	  end_offset = st.st_size;

I think that the code computing total is presently beset by a
presumption that special files are uniformly non-seekable and loses if
that assumption proves untrue.  Perhaps it should disregard end_offset
if isn't expressly provided by the caller and the file is special, which
if true implies that end_offset is TYPE_MAXIMUM (off_t); much as in the
following untested patch:

diff --git a/src/fileio.c b/src/fileio.c
index 8919e08e1fd..e09616fb337 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -4746,7 +4746,7 @@ DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
       goto handled;
     }
 
-  if (seekable || !NILP (end))
+  if (((regular || !NILP (end)) && seekable) || !NILP (end))
     total = end_offset - beg_offset;
   else
     /* For a special file, all we can do is guess.  */