diff mbox series

libstdc++: Add workaround for read(2) EINVAL on macOS and FreeBSD [PR102259]

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

Commit Message

Jonathan Wakely Dec. 6, 2024, 5:55 p.m. UTC
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.

 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(+)

Comments

Jonathan Wakely Dec. 7, 2024, 11:18 a.m. UTC | #1
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 mbox series

Patch

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