Commit e4b77daa authored by Markus Armbruster's avatar Markus Armbruster
Browse files

coverity: Model GLib string allocation partially



Without a model, Coverity can't know that the result of g_strdup()
needs to be fed to g_free().

One way to get such a model is to scan GLib, build a derived model
file with cov-collect-models, and use that when scanning QEMU.
Unfortunately, the Coverity Scan service we use doesn't support that.

Thus, we're stuck with the other way: write a user model.  Doing that
for all of GLib is hardly practical.  I'm doing it for the "String
Utility Functions" we actually use that return dynamically allocated
strings.

In a local scan, this flags 20 additional RESOURCE_LEAKs.  The ones I
checked look genuine.

It also loses a NULL_RETURNS about ppce500_init() using
qemu_find_file() without error checking.  I don't understand why.

Signed-off-by: default avatarMarkus Armbruster <armbru@redhat.com>
Acked-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 9d7a4c66
Loading
Loading
Loading
Loading
+89 −0
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@ typedef unsigned long long uint64_t;
typedef long long int64_t;
typedef _Bool bool;

typedef struct va_list_str *va_list;

/* exec.c */

typedef struct AddressSpace AddressSpace;
@@ -232,6 +234,93 @@ void *g_try_realloc(void *ptr, size_t size)
    return g_try_realloc_n(ptr, 1, size);
}

/*
 * GLib string allocation functions
 */

char *g_strdup(const char *s)
{
    char *dup;
    size_t i;

    if (!s) {
        return NULL;
    }

    __coverity_string_null_sink__(s);
    __coverity_string_size_sink__(s);
    dup = __coverity_alloc_nosize__();
    __coverity_mark_as_afm_allocated__(dup, AFM_free);
    for (i = 0; (dup[i] = s[i]); i++) ;
    return dup;
}

char *g_strndup(const char *s, size_t n)
{
    char *dup;
    size_t i;

    __coverity_negative_sink__(n);

    if (!s) {
        return NULL;
    }

    dup = g_malloc(n + 1);
    for (i = 0; i < n && (dup[i] = s[i]); i++) ;
    dup[i] = 0;
    return dup;
}

char *g_strdup_printf(const char *format, ...)
{
    char ch, *s;
    size_t len;

    __coverity_string_null_sink__(format);
    __coverity_string_size_sink__(format);

    ch = *format;

    s = __coverity_alloc_nosize__();
    __coverity_writeall__(s);
    __coverity_mark_as_afm_allocated__(s, AFM_free);
    return s;
}

char *g_strdup_vprintf(const char *format, va_list ap)
{
    char ch, *s;
    size_t len;

    __coverity_string_null_sink__(format);
    __coverity_string_size_sink__(format);

    ch = *format;
    ch = *(char *)ap;

    s = __coverity_alloc_nosize__();
    __coverity_writeall__(s);
    __coverity_mark_as_afm_allocated__(s, AFM_free);

    return len;
}

char *g_strconcat(const char *s, ...)
{
    char *s;

    /*
     * Can't model: last argument must be null, the others
     * null-terminated strings
     */

    s = __coverity_alloc_nosize__();
    __coverity_writeall__(s);
    __coverity_mark_as_afm_allocated__(s, AFM_free);
    return s;
}

/* Other glib functions */

typedef struct _GIOChannel GIOChannel;