Message ID | 20241206175556.1227554-1-jwakely@redhat.com |
---|---|
State | New |
Headers | show |
Series | libstdc++: Add workaround for read(2) EINVAL on macOS and FreeBSD [PR102259] | expand |
On Fri, 6 Dec 2024 at 17:56, Jonathan Wakely <jwakely@redhat.com> wrote: > > On macOS and FreeBSD read(2) system call can return EINVAL for large > sizes, so limit the maximum that we try to read. The calling code in > filebuf::xsgetn will loop until it gets the size it wants, so we don't > need to loop here. > > libstdc++-v3/ChangeLog: > > PR libstdc++/102259 > * config/io/basic_file_stdio.cc (basic_file::xsgetn): Limit n to > INT_MAX-1 when _GLIBCXX_READ_RETURNS_EINVAL_OVER_INT_MAX is > defined. > * config/os/bsd/darwin/os_defines.h (_GLIBCXX_READ_RETURNS_EINVAL_OVER_INT_MAX): > Define. > * config/os/bsd/freebsd/os_defines.h (_GLIBCXX_READ_RETURNS_EINVAL_OVER_INT_MAX): > Define. > --- > > Any suggestions for a better name for the new macro? > > I haven't tested this, but I'll ask the bug submitter to do so. If they > don't do so, I'll ask Iain or try a FreeBSD VM next week some time. Iain and the submitter have both tested it on macOS now. > > libstdc++-v3/config/io/basic_file_stdio.cc | 6 ++++++ > libstdc++-v3/config/os/bsd/darwin/os_defines.h | 3 +++ > libstdc++-v3/config/os/bsd/freebsd/os_defines.h | 3 +++ > 3 files changed, 12 insertions(+) > > diff --git a/libstdc++-v3/config/io/basic_file_stdio.cc b/libstdc++-v3/config/io/basic_file_stdio.cc > index 9b529490f08..508e2d2a469 100644 > --- a/libstdc++-v3/config/io/basic_file_stdio.cc > +++ b/libstdc++-v3/config/io/basic_file_stdio.cc > @@ -338,6 +338,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > if (__ret == 0 && ferror(this->file())) > __ret = -1; > #else > + > +#ifdef _GLIBCXX_READ_RETURNS_EINVAL_OVER_INT_MAX Maybe a better design would be to define the macro to the maximum supported value: #ifdef _GLIBCXX_MAX_READ_SIZE if (__builtin_expect(__n > _GLIBCXX_MAX_READ_SIZE, 0)) __n = _GLIBCXX_MAX_READ_SIZE; #endif > + if (__builtin_expect(__n >= __INT_MAX__, 0)) > + __n = __INT_MAX__ - 1; > +#endif > + > do > __ret = read(this->fd(), __s, __n); > while (__ret == -1L && errno == EINTR); > diff --git a/libstdc++-v3/config/os/bsd/darwin/os_defines.h b/libstdc++-v3/config/os/bsd/darwin/os_defines.h > index 6bc7930bdba..826c863e481 100644 > --- a/libstdc++-v3/config/os/bsd/darwin/os_defines.h > +++ b/libstdc++-v3/config/os/bsd/darwin/os_defines.h > @@ -54,4 +54,7 @@ > // No support for referencing weak symbols without a definition. > #define _GLIBCXX_USE_WEAK_REF 0 > > +// read(2) can return EINVAL for n > INT_MAX. > +#define _GLIBCXX_READ_RETURNS_EINVAL_OVER_INT_MAX 1 > + > #endif > diff --git a/libstdc++-v3/config/os/bsd/freebsd/os_defines.h b/libstdc++-v3/config/os/bsd/freebsd/os_defines.h > index 125dfdc1888..4889bb4ec00 100644 > --- a/libstdc++-v3/config/os/bsd/freebsd/os_defines.h > +++ b/libstdc++-v3/config/os/bsd/freebsd/os_defines.h > @@ -50,4 +50,7 @@ > #define _GLIBCXX_USE_C99_FLOAT_TRANSCENDENTALS_DYNAMIC 0 > #endif > > +// read(2) can return EINVAL for n > INT_MAX. > +#define _GLIBCXX_READ_RETURNS_EINVAL_OVER_INT_MAX 1 > + > #endif > -- > 2.47.1 >
diff --git a/libstdc++-v3/config/io/basic_file_stdio.cc b/libstdc++-v3/config/io/basic_file_stdio.cc index 9b529490f08..508e2d2a469 100644 --- a/libstdc++-v3/config/io/basic_file_stdio.cc +++ b/libstdc++-v3/config/io/basic_file_stdio.cc @@ -338,6 +338,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__ret == 0 && ferror(this->file())) __ret = -1; #else + +#ifdef _GLIBCXX_READ_RETURNS_EINVAL_OVER_INT_MAX + if (__builtin_expect(__n >= __INT_MAX__, 0)) + __n = __INT_MAX__ - 1; +#endif + do __ret = read(this->fd(), __s, __n); while (__ret == -1L && errno == EINTR); diff --git a/libstdc++-v3/config/os/bsd/darwin/os_defines.h b/libstdc++-v3/config/os/bsd/darwin/os_defines.h index 6bc7930bdba..826c863e481 100644 --- a/libstdc++-v3/config/os/bsd/darwin/os_defines.h +++ b/libstdc++-v3/config/os/bsd/darwin/os_defines.h @@ -54,4 +54,7 @@ // No support for referencing weak symbols without a definition. #define _GLIBCXX_USE_WEAK_REF 0 +// read(2) can return EINVAL for n > INT_MAX. +#define _GLIBCXX_READ_RETURNS_EINVAL_OVER_INT_MAX 1 + #endif diff --git a/libstdc++-v3/config/os/bsd/freebsd/os_defines.h b/libstdc++-v3/config/os/bsd/freebsd/os_defines.h index 125dfdc1888..4889bb4ec00 100644 --- a/libstdc++-v3/config/os/bsd/freebsd/os_defines.h +++ b/libstdc++-v3/config/os/bsd/freebsd/os_defines.h @@ -50,4 +50,7 @@ #define _GLIBCXX_USE_C99_FLOAT_TRANSCENDENTALS_DYNAMIC 0 #endif +// read(2) can return EINVAL for n > INT_MAX. +#define _GLIBCXX_READ_RETURNS_EINVAL_OVER_INT_MAX 1 + #endif