[glib: 1/2] Clamp number of vectors to IOV_MAX / UIO_MAXIOV for GOutputStream writev() calls in the implementati



commit 20a2c379c420f03e283d61f2448ba893626ec7c3
Author: Sebastian Dröge <sebastian centricular com>
Date:   Wed May 29 16:04:55 2019 +0300

    Clamp number of vectors to IOV_MAX / UIO_MAXIOV for GOutputStream writev() calls in the implementations
    
    More vectors will give an error and we can simply clamp here and
    consider it like a short write instead.
    
    In case of GSocketOutputStream this is done here instead of inside
    GSocket before calling sendmsg() because we we can't generically handle
    short writes when sending messages on a socket, e.g. for datagram
    sockets this causes only part of the datagram to be sent and an error
    would be more useful in this case than sending corrupted data.
    
    Also reduce the fallback limit to 16 in gsocket.c as that's the minimum
    value required by POSIX and add a static assertion that the limit is
    never bigger than G_MAXINT as that's the type recvmmsg/sendmmsg take.

 gio/gioprivate.h             | 17 +++++++++++++++++
 gio/glocalfileoutputstream.c |  9 +++++----
 gio/gsocket.c                | 27 +++++++++++----------------
 gio/gsocketoutputstream.c    |  9 +++++----
 gio/gunixoutputstream.c      | 17 +++++++++--------
 5 files changed, 47 insertions(+), 32 deletions(-)
---
diff --git a/gio/gioprivate.h b/gio/gioprivate.h
index a917510b9..2bc54e49b 100644
--- a/gio/gioprivate.h
+++ b/gio/gioprivate.h
@@ -35,6 +35,23 @@ gboolean g_output_stream_async_close_is_via_threads (GOutputStream *stream);
 void g_socket_connection_set_cached_remote_address (GSocketConnection *connection,
                                                     GSocketAddress    *address);
 
+/* POSIX defines IOV_MAX/UIO_MAXIOV as the maximum number of iovecs that can
+ * be sent in one go. We define our own version of it here as there are two
+ * possible names, and also define a fall-back value if none of the constants
+ * are defined */
+#if defined(IOV_MAX)
+#define G_IOV_MAX IOV_MAX
+#elif defined(UIO_MAXIOV)
+#define G_IOV_MAX UIO_MAXIOV
+#else
+/* 16 is the minimum value required by POSIX */
+#define G_IOV_MAX 16
+#endif
+
+/* The various functions taking iovecs as parameter use a plain int
+ * for the number of vectors. Limit it to G_MAXINT for this reason.
+ */
+G_STATIC_ASSERT (G_IOV_MAX <= G_MAXINT);
 
 G_END_DECLS
 
diff --git a/gio/glocalfileoutputstream.c b/gio/glocalfileoutputstream.c
index 6d44989bf..a3dd62172 100644
--- a/gio/glocalfileoutputstream.c
+++ b/gio/glocalfileoutputstream.c
@@ -42,6 +42,7 @@
 #endif
 
 #include "glib-private.h"
+#include "gioprivate.h"
 
 #ifdef G_OS_WIN32
 #include <io.h>
@@ -243,11 +244,11 @@ g_local_file_output_stream_writev (GOutputStream        *stream,
   if (bytes_written)
     *bytes_written = 0;
 
-  /* Clamp to G_MAXINT as writev() takes an integer for the number of vectors.
-   * We handle this like a short write in this case
+  /* Clamp the number of vectors if more given than we can write in one go.
+   * The caller has to handle short writes anyway.
    */
-  if (n_vectors > G_MAXINT)
-    n_vectors = G_MAXINT;
+  if (n_vectors > G_IOV_MAX)
+    n_vectors = G_IOV_MAX;
 
   file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
 
diff --git a/gio/gsocket.c b/gio/gsocket.c
index 06514d102..3cdce1053 100644
--- a/gio/gsocket.c
+++ b/gio/gsocket.c
@@ -74,6 +74,7 @@
 #include "gcredentials.h"
 #include "gcredentialsprivate.h"
 #include "glibintl.h"
+#include "gioprivate.h"
 
 #ifdef G_OS_WIN32
 /* For Windows XP runtime compatibility, but use the system's if_nametoindex() if available */
@@ -4960,14 +4961,11 @@ g_socket_send_messages_with_timeout (GSocket        *socket,
     struct mmsghdr *msgvec;
     gint i, num_sent;
 
-#ifdef UIO_MAXIOV
-#define MAX_NUM_MESSAGES UIO_MAXIOV
-#else
-#define MAX_NUM_MESSAGES 1024
-#endif
-
-    if (num_messages > MAX_NUM_MESSAGES)
-      num_messages = MAX_NUM_MESSAGES;
+    /* Clamp the number of vectors if more given than we can write in one go.
+     * The caller has to handle short writes anyway.
+     */
+    if (num_messages > G_IOV_MAX)
+      num_messages = G_IOV_MAX;
 
     msgvec = g_newa (struct mmsghdr, num_messages);
 
@@ -5482,14 +5480,11 @@ g_socket_receive_messages_with_timeout (GSocket        *socket,
     struct mmsghdr *msgvec;
     guint i, num_received;
 
-#ifdef UIO_MAXIOV
-#define MAX_NUM_MESSAGES UIO_MAXIOV
-#else
-#define MAX_NUM_MESSAGES 1024
-#endif
-
-    if (num_messages > MAX_NUM_MESSAGES)
-      num_messages = MAX_NUM_MESSAGES;
+    /* Clamp the number of vectors if more given than we can write in one go.
+     * The caller has to handle short writes anyway.
+     */
+    if (num_messages > G_IOV_MAX)
+      num_messages = G_IOV_MAX;
 
     msgvec = g_newa (struct mmsghdr, num_messages);
 
diff --git a/gio/gsocketoutputstream.c b/gio/gsocketoutputstream.c
index fcca56efc..482ee39b9 100644
--- a/gio/gsocketoutputstream.c
+++ b/gio/gsocketoutputstream.c
@@ -33,6 +33,7 @@
 #include "gioerror.h"
 #include "glibintl.h"
 #include "gfiledescriptorbased.h"
+#include "gioprivate.h"
 
 struct _GSocketOutputStreamPrivate
 {
@@ -146,8 +147,8 @@ g_socket_output_stream_writev (GOutputStream        *stream,
   /* Clamp the number of vectors if more given than we can write in one go.
    * The caller has to handle short writes anyway.
    */
-  if (n_vectors > G_MAXINT)
-    n_vectors = G_MAXINT;
+  if (n_vectors > G_IOV_MAX)
+    n_vectors = G_IOV_MAX;
 
   res = g_socket_send_message_with_timeout (output_stream->priv->socket, NULL,
                                             vectors, n_vectors,
@@ -194,8 +195,8 @@ g_socket_output_stream_pollable_writev_nonblocking (GPollableOutputStream  *poll
   /* Clamp the number of vectors if more given than we can write in one go.
    * The caller has to handle short writes anyway.
    */
-  if (n_vectors > G_MAXINT)
-    n_vectors = G_MAXINT;
+  if (n_vectors > G_IOV_MAX)
+    n_vectors = G_IOV_MAX;
 
   return g_socket_send_message_with_timeout (output_stream->priv->socket,
                                              NULL, vectors, n_vectors,
diff --git a/gio/gunixoutputstream.c b/gio/gunixoutputstream.c
index 5536e00b4..506e09a8c 100644
--- a/gio/gunixoutputstream.c
+++ b/gio/gunixoutputstream.c
@@ -37,6 +37,7 @@
 #include "gasynchelper.h"
 #include "gfiledescriptorbased.h"
 #include "glibintl.h"
+#include "gioprivate.h"
 
 
 /**
@@ -425,11 +426,11 @@ g_unix_output_stream_writev (GOutputStream        *stream,
   if (bytes_written)
     *bytes_written = 0;
 
-  /* Clamp to G_MAXINT as writev() takes an integer for the number of vectors.
-   * We handle this like a short write in this case
+  /* Clamp the number of vectors if more given than we can write in one go.
+   * The caller has to handle short writes anyway.
    */
-  if (n_vectors > G_MAXINT)
-    n_vectors = G_MAXINT;
+  if (n_vectors > G_IOV_MAX)
+    n_vectors = G_IOV_MAX;
 
   unix_stream = G_UNIX_OUTPUT_STREAM (stream);
 
@@ -635,11 +636,11 @@ g_unix_output_stream_pollable_writev_nonblocking (GPollableOutputStream  *stream
       return G_POLLABLE_RETURN_WOULD_BLOCK;
     }
 
-  /* Clamp to G_MAXINT as writev() takes an integer for the number of vectors.
-   * We handle this like a short write in this case
+  /* Clamp the number of vectors if more given than we can write in one go.
+   * The caller has to handle short writes anyway.
    */
-  if (n_vectors > G_MAXINT)
-    n_vectors = G_MAXINT;
+  if (n_vectors > G_IOV_MAX)
+    n_vectors = G_IOV_MAX;
 
   if (G_OUTPUT_VECTOR_IS_IOVEC)
     {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]