wma_afh: Fix two bugs in convert_utf8_to_utf16().
authorAndre Noll <maan@tuebingen.mpg.de>
Fri, 21 Apr 2017 19:49:20 +0000 (21:49 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Fri, 21 Apr 2017 20:57:37 +0000 (22:57 +0200)
This function has two issues:

* If iconv_open() fails and src is NULL (or *src is NULL) we attempt
to close an invalid file descriptor.

* On errors, we free *dst but miss to set it to NULL, causing a double
free in the caller.

This patch addresses both issues. The double free was found by the
clang static analyzer.

wma_afh.c

index 4c9d87e..b4935f0 100644 (file)
--- a/wma_afh.c
+++ b/wma_afh.c
@@ -316,22 +316,24 @@ static const char top_level_header_object_guid[] = {
 
 static int convert_utf8_to_utf16(char *src, char **dst)
 {
-       /*
-        * Without specifying LE (little endian), iconv includes a byte order
-        * mark (e.g. 0xFFFE) at the beginning.
-        */
-       iconv_t cd = iconv_open("UTF-16LE", "UTF-8");
+       iconv_t cd;
        size_t sz, inbytes, outbytes, inbytesleft, outbytesleft;
        char *inbuf, *outbuf;
        int ret;
 
        if (!src || !*src) {
                *dst = para_calloc(2);
-               ret = 0;
-               goto out;
+               return 0;
        }
-       if (cd == (iconv_t) -1)
+       /*
+        * Without specifying LE (little endian), iconv includes a byte order
+        * mark (e.g. 0xFFFE) at the beginning.
+        */
+       cd = iconv_open("UTF-16LE", "UTF-8");
+       if (cd == (iconv_t)-1) {
+               *dst = NULL;
                return -ERRNO_TO_PARA_ERROR(errno);
+       }
        inbuf = src;
        /* even though src is in UTF-8, strlen() should DTRT */
        inbytes = inbytesleft = strlen(src);
@@ -340,6 +342,8 @@ static int convert_utf8_to_utf16(char *src, char **dst)
        sz = iconv(cd, ICONV_CAST &inbuf, &inbytesleft, &outbuf, &outbytesleft);
        if (sz == (size_t)-1) {
                ret = -ERRNO_TO_PARA_ERROR(errno);
+               free(*dst);
+               *dst = NULL;
                goto out;
        }
        assert(outbytes >= outbytesleft);
@@ -351,8 +355,6 @@ static int convert_utf8_to_utf16(char *src, char **dst)
        *dst = outbuf;
        PARA_INFO_LOG("converted %s to %d UTF-16 bytes\n", src, ret);
 out:
-       if (ret < 0)
-               free(*dst);
        if (iconv_close(cd) < 0)
                PARA_WARNING_LOG("iconv_close: %s\n", strerror(errno));
        return ret;