fd file descriptor in Fpopendir in rtl/linux/ossysc.inc overflows if > 32*1024
Original Reporter info from Mantis: sethdgrover@gmail.com
-
Reporter name: Seth Grover
Original Reporter info from Mantis: sethdgrover@gmail.com
- Reporter name: Seth Grover
Description:
See this thread:
http://lists.freepascal.org/pipermail/fpc-devel/2016-June/037189.html
I am debugging an issue with FPC 3.0 on Linux x86_64 which I believe I have
tracked down to Fpopendir rtl/linux/ossysc.inc:
-----------------------------------------------------------
function Fpopendir(dirname : pchar): pdir; [public, alias :
'FPC_SYSC_OPENDIR'];
var
fd:integer;
st:stat;
ptr:pdir;
begin
Fpopendir:=nil;
if Fpstat(dirname,st)<0 then
exit;
{ Is it a dir ? }
if not((st.st_mode and $f000)=$4000)then
begin
errno:=ESysENOTDIR;
exit
end;
{ Open it}
fd:=Fpopen(dirname,O_RDONLY,438);
if fd<0 then
exit;
new(ptr);
if ptr=nil then
exit;
new(ptr^.dd_buf);
if ptr^.dd_buf=nil then
exit;
ptr^.dd_fd:=fd;
ptr^.dd_loc:=0;
ptr^.dd_size:=0;
ptr^.dd_nextoff:=0;
ptr^.dd_max:=sizeof(ptr^.dd_buf^);
Fpopendir:=ptr;
end;
-----------------------------------------------------------
In this process I have a LOT of open file handles. The system on which it
runs uses "ulimit -n 64000" to set the maximum number of open descriptors
to 64,000. However, once I get above 32768 file handles Fpopendir starts
failing, and causing me to leak directory descriptors. I didn't have debug
compiled down into the RTL, but looking at the machine code I can see
what's happening:
Fpopen is returning a good directory descriptor, for example, 51345.
However, the comparison "fd<0" is evaluating to true, which causes the
routine to error out.
Looking at the machine code:
0x00007ffff7038106 <+118>: callq 0x7ffff7037ee0
<SYSTEM_$$_FPOPEN$PCHAR$LONGINT$LONGINT$$LONGINT>
0x00007ffff703810b <+123>: mov %eax,%ebx
0x00007ffff703810d <+125>: cmp $0x0,%bx
0x00007ffff7038112 <+130>: jl 0x7ffff703816b
<SYSTEM_$$_FPOPENDIR$PCHAR$$PDIR+219>
At +123 I can see that eax/
ebx contains the correct descriptor, 51345.
However, when I print $bx in the debugger, it looks like a negative number,
as if it had overflowed a signed 2-byte integer, so the function errors
out. This causes the file descriptor to be leaked as well, since no
reference to is is retained in the pdir record.
Michael suggested we change the type of fd to a THandle or cInt to avoid the overflow that's happening due to (apparently?) the "integer" type being interpreted to mean a 16-bit signed value here.
Steps to reproduce:
-
Have a linux system where you've set ulimit -n 64000 to increase the number of possible file handles.
-
open > 32*1024 file handles
-
call Fpopendir and see it fail as the file descriptor overflows
Additional information:
See this thread:
http://lists.freepascal.org/pipermail/fpc-devel/2016-June/037189.html