<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta http-equiv="Content-Style-Type" content="text/css" />
  <meta name="generator" content="pandoc" />
  <title></title>
  <style type="text/css">code{white-space: pre;}</style>
</head>
<body>
<p>Hi Dennis,</p>
<p>As code within VLC should be able to assume that <code>recvmsg</code> and <code>sendmsg</code>are <em>POSIX</em>-compliant, I vote that some adjustments should be made to these implementations so that we do not run into issues with unexpected behavior in the future.</p>
<p>See the below resource for the specification in full:</p>
<ul>
<li>http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html</li>
</ul>
<p>On 2017-03-13 12:37, Dennis Hamester wrote:</p>
<blockquote style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;color:#500050">
<pre><code> From: Dennis Hamester <dennis.hamester@startmail.com>

  compat/recvmsg.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++-
  compat/sendmsg.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++-
  configure.ac     |  2 ++
  3 files changed, 101 insertions(+), 2 deletions(-)

 diff --git a/compat/recvmsg.c b/compat/recvmsg.c
 index 941249fef7..40ec935fc6 100644
 --- a/compat/recvmsg.c
 +++ b/compat/recvmsg.c
 @@ -1,7 +1,10 @@
  /*****************************************************************************
   * recvmsg.c: POSIX recvmsg() replacement
   *****************************************************************************
 - * Copyright © 2016 Rémi Denis-Courmont
 + * Copyright © 2016-2017 VLC authors and VideoLAN
 + *
 + * Authors: Rémi Denis-Courmont
 + *          Dennis Hamester <dhamester@jusst.de>
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU Lesser General Public License as published by
 @@ -79,3 +82,49 @@ ssize_t recvmsg(int fd, struct msghdr *msg, int flags)
      return -1;
  }
  #endif
 +
 +#ifdef __native_client__
 +#include <errno.h>
 +#include <stdlib.h>
 +#include <string.h>
 +#include <sys/socket.h>
 +
 +ssize_t recvmsg(int fd, struct msghdr *msg, int flags)
 +{
 +    if (msg->msg_controllen != 0)
 +    {
 +        errno = ENOSYS;
 +        return -1;
 +    }
 +
 +    if (msg->msg_iovlen > IOV_MAX)
 +    {</code></pre>
</blockquote>
<p>This check should include <code>msg->msg_iovlen <= 0</code> together with <code>> IOV_MAX</code>, and <code>errno</code> should be set to <code>EMSGSIZE</code> according to POSIX.</p>
<blockquote style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;color:#500050">
<pre><code> +        errno = EINVAL;
 +        return -1;
 +    }
 +
 +    size_t full_size = 0;
 +    for (int i = 0; i < msg->msg_iovlen; ++i)
 +        full_size += msg->msg_iov[i].iov_len;</code></pre>
</blockquote>
<p>According to <em>POSIX</em>, if the total sum of <code>msg->msg_iov[i].iov_len</code> would overflow a <code>ssize_t</code> the function shall return <code>-1</code> and set <code>errno</code> to <code>EINVAL</code>.</p>
<blockquote style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;color:#500050">
<pre><code> +
 +    char *data = malloc(full_size);
 +    if (!data)</code></pre>
</blockquote>
<p><code>errno = ENOMEM</code> on allocation failure, also note that if <code>full_size == 0</code> it is <em>implementation-defined</em> whether <code>malloc</code> will return <code>NULL</code> or not.</p>
<blockquote style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;color:#500050">
<pre><code> +        return -1;
 +
 +    ssize_t res;
 +    if (msg->msg_name)
 +        res = recvfrom(fd, data, full_size, flags, msg->msg_name, &msg->msg_namelen);
 +    else
 +        res = recv(fd, data, full_size, flags);
 +</code></pre>
</blockquote>
<p>If less than <code>full_size</code> bytes of data is read you will <code>memcpy</code> garbage in the loop that follows, which is undesirable.</p>
<blockquote style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;color:#500050">
<pre><code> +    size_t tmp = 0;
 +    for (int i = 0; i < msg->msg_iovlen; ++i) {
 +        memcpy(msg->msg_iov[i].iov_base, data + tmp, msg->msg_iov[i].iov_len);
 +        tmp += msg->msg_iov[i].iov_len;
 +    }
 +
 +    msg->msg_flags = 0;
 +    free(data);
 +    return res;
 +}
 +#endif
 diff --git a/compat/sendmsg.c b/compat/sendmsg.c
 index 451ba298bf..5bbe8c413b 100644
 --- a/compat/sendmsg.c
 +++ b/compat/sendmsg.c
 @@ -1,7 +1,10 @@
  /*****************************************************************************
   * sendmsg.c: POSIX sendmsg() replacement
   *****************************************************************************
 - * Copyright © 2016 Rémi Denis-Courmont
 + * Copyright © 2016-2017 VLC authors and VideoLAN
 + *
 + * Authors: Rémi Denis-Courmont
 + *          Dennis Hamester <dhamester@jusst.de>
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU Lesser General Public License as published by
 @@ -69,3 +72,48 @@ ssize_t sendmsg(int fd, const struct msghdr *msg, int flags)
      return -1;
  }
  #endif
 +
 +#ifdef __native_client__
 +#include <errno.h>
 +#include <stdlib.h>
 +#include <string.h>
 +#include <sys/socket.h>
 +
 +ssize_t sendmsg(int fd, const struct msghdr *msg, int flags)
 +{
 +    if (msg->msg_controllen != 0)
 +    {
 +        errno = ENOSYS;
 +        return -1;
 +    }
 +
 +    if (msg->msg_iovlen > IOV_MAX)
 +    {
 +        errno = EINVAL;
 +        return -1;
 +    }</code></pre>
</blockquote>
<p>See comments regarding <code>recvmsg</code>.</p>
<blockquote style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;color:#500050">
<pre><code> +    size_t full_size = 0;
 +    for (int i = 0; i < msg->msg_iovlen; ++i)
 +        full_size += msg->msg_iov[i].iov_len;
 +
 +    char *data = malloc(full_size);
 +    if (!data)
 +        return -1;
 +
 +    size_t tmp = 0;
 +    for (int i = 0; i < msg->msg_iovlen; ++i) {
 +        memcpy(data + tmp, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
 +        tmp += msg->msg_iov[i].iov_len;
 +    }
 +
 +    ssize_t res;
 +    if (msg->msg_name)
 +        res = sendto(fd, data, full_size, flags, msg->msg_name, msg->msg_namelen);
 +    else
 +        res = send(fd, data, full_size, flags);
 +
 +    free(data);
 +    return res;
 +}
 +#endif
 diff --git a/configure.ac b/configure.ac
 index c9713970fd..787421810e 100644
 --- a/configure.ac
 +++ b/configure.ac
 @@ -300,6 +300,8 @@ case "${host_os}" in
    *nacl*)
      SYS=nacl
      AC_DEFINE([_XOPEN_SOURCE], [700], [POSIX and XPG 7th edition])
 +    AC_LIBOBJ([recvmsg])
 +    AC_LIBOBJ([sendmsg])
      ;;
    *)
      SYS="${host_os}"
 -- 
 2.12.0</code></pre>
</blockquote>
</body>
</html>