http://llvm.org/bugs/show_bug.cgi?id=21573

            Bug ID: 21573
           Summary: libxcb-1.11 miscompiles with Clang -O2 on x86_32/linux
           Product: new-bugs
           Version: unspecified
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P
         Component: new bugs
          Assignee: [email protected]
          Reporter: [email protected]
                CC: [email protected]
    Classification: Unclassified

The function get_peer_sock_name in src/xcb_auth.c of libxcb-1.11 generates
broken assembly code on x86_32 when compiled with Clang/LLVM-3.5.0 using -O2
optimization level, this does not happen on -O1 or lower level, it also seems
to work correctly on x86_64 even with -O2.

The C code first calls malloc(), then checks the returned pointer for NULL,
finally calls the function getpeername() or getsockname() via a function
pointer, using the malloc'ed pointer as second argument.

When compiled with -O2 the assembly code generated will (incorrectly)
dereference the pointer returned by malloc() and pass the value pointed at as
second argument to the getpeername() function call.

By coincidence, the uninitialized malloced area may contain a valid pointer
which results in a corrupt heap since the getpeername function will write its
result to an incorrect address.

C-code snippet below:

/* Return a dynamically allocated socket address structure according
   to the value returned by either getpeername() or getsockname()
   (according to POSIX, applications should not assume a particular
   length for `sockaddr_un.sun_path') */
static struct sockaddr *get_peer_sock_name(int (*socket_func)(int,
                                                              struct sockaddr
*,
                                                              socklen_t *),
                                           int fd)
{
    socklen_t socknamelen = sizeof(struct sockaddr) + INITIAL_SOCKNAME_SLACK;
    socklen_t actual_socknamelen = socknamelen;
    struct sockaddr *sockname = malloc(socknamelen);

    if (sockname == NULL)
        return NULL;

    /* Both getpeername() and getsockname() truncates sockname if
       there is not enough space and set the required length in
       actual_socknamelen */
    if (socket_func(fd, sockname, &actual_socknamelen) == -1) // <======= This
is where the incorrect dereference happens. /////////////
        goto sock_or_realloc_error;

    if (actual_socknamelen > socknamelen)
    {
        struct sockaddr *new_sockname = NULL;
        socknamelen = actual_socknamelen;

        if ((new_sockname = realloc(sockname, actual_socknamelen)) == NULL)
            goto sock_or_realloc_error;

        sockname = new_sockname;

        if (socket_func(fd, sockname, &actual_socknamelen) == -1 ||
            actual_socknamelen > socknamelen)
            goto sock_or_realloc_error;
    }

    return sockname;

 sock_or_realloc_error:
    free(sockname);
    return NULL;
}

-- 
You are receiving this mail because:
You are on the CC list for the bug.
_______________________________________________
LLVMbugs mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/llvmbugs

Reply via email to