Your message does not include the memory allocated with malloc(), so it is not replicated within the queue. msgsnd() sees your message as simply an array of bytes, and knows nothing about it's makeup. Moreover, if you free the memory, it will invalidate the copy of the pointer (the one now on the queue) to it, since it will then point to memory which may have been re-used. You should free the memory in the consumer thread, once it has been de-referenced, and no longer used.
Somehow this seems like a clumsy way of sharing data, when the memory, and the pointers used to reference it are already visible to both the producer and consumer threads (because it uses pthreads). Any process outside the main thread will be unable to safely de-reference the pointer to the malloc()'d memory.