2

I have a routine calling gSoap API function soap_malloc. But the program gives me a segmentation fault whenever I try to access the memory allocated by soap_malloc. When I use gdb to debug it. I find that inside soap_malloc, return value stored in register %rax is 0x7fffec0018f0. But on return, %rax changed to 0xffffffffec0018f0. Only the lower 32-bit was retained, the higher 32-bit all changed to 1. And that lead to accessing an address which is quite high, therefore caused the routine stopped. Thanks for you all to give me any ideas on how can this be happening. I'm running my multi-thread program in Ubuntu12.04 x86-64.

This is how I call it:

void *temp = soap_malloc(soap, 96);

And this is the soap_malloc implementation(only that else part is executed, and macro SOAP_MALLOC is just passing the second argument to malloc, SOAP_CANARY is constant 0xC0DE):

#ifndef SOAP_MALLOC         /* use libc malloc */
# define SOAP_MALLOC(soap, size) malloc(size)
#endif

#ifndef SOAP_CANARY
# define SOAP_CANARY (0xC0DE)
#endif

void* soap_malloc(struct soap *soap, size_t n)
{ register char *p;
  if (!n)
    return (void*)SOAP_NON_NULL;
  if (!soap)
    return SOAP_MALLOC(soap, n);
  if (soap->fmalloc)
    p = (char*)soap->fmalloc(soap, n);
  else
  { n += sizeof(short);
    n += (-(long)n) & (sizeof(void*)-1); /* align at 4-, 8- or 16-byte boundary */
    if (!(p = (char*)SOAP_MALLOC(soap, n + sizeof(void*) + sizeof(size_t))))
    { soap->error = SOAP_EOM;
      return NULL;
    }
    /* set the canary to detect corruption */
    *(unsigned short*)(p + n - sizeof(unsigned short)) = (unsigned short)SOAP_CANARY;
    /* keep chain of alloced cells for destruction */
    *(void**)(p + n) = soap->alist;
    *(size_t*)(p + n + sizeof(void*)) = n;
    soap->alist = p + n;
  }
  soap->alloced = 1;
  return p;
}

This is the definition of SOAP_NON_NULL:

static const char soap_padding[4] = "\0\0\0";
#define SOAP_NON_NULL (soap_padding)

Updates(2013-03-12)
I explicitly declared soap_malloc as returning void * and the problem solved. Previously, the returned value is truncated to int and the sign bit 1 was extended when assigning the result to void *temp.

leowang
  • 481
  • 5
  • 12
  • Can you provide a minimal code example that reproduces this problem? – Michael Foukarakis Mar 11 '13 at 13:11
  • In some places you use **soap_malloc** in others you use **SOAP_MALLOC**. What is the definition of **SOAP_MALLOC** or is that part of the gSoap library? – Jere Mar 11 '13 at 13:28
  • @Jere I describe `SOAP_MALLOC` is a macro which just passing the second argument to `malloc`. Sorry for that, I'll edit them into the code body. – leowang Mar 11 '13 at 13:32
  • @MichaelFoukarakis where else do you think can cause this problem? I mean, I use a `void *` variable to store the returned value by `soap_malloc` which is also of type `void *`. `%rax` stays `0x7fffec0018f0` until `soap_malloc` returns. – leowang Mar 11 '13 at 13:46
  • @Jere Yes, it is part of gSoap library. – leowang Mar 11 '13 at 13:48
  • I compiled and printed calls to this code (using MinGW G++) and did not see any errors. Out of curiosity, what platform/os version/compiler are you using? – Jere Mar 11 '13 at 20:45
  • @Jere I put a explicit `extern void *soap_malloc(struct soap *, size_t)` in the file, and the problem solved.`The return value is indeed truncated. I will edit the question once again. – leowang Mar 12 '13 at 04:36

1 Answers1

3

Does the calling code have a proper prototype for the soap_malloc() function in scope?

It seems the void * is being converted to int, i.e. the default return type. This happens if the function hasn't been properly declared.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • sorry, I should have put the calling code above `soap_malloc`. I just used a `void *temp` to stored the return value. – leowang Mar 11 '13 at 13:00
  • @leowang Not sure I understand your correction ... That doesn't matter. If you call plain old `malloc()` *without* including the header like this: `void *p = malloc(1024)`, you *will* get an `int`-sized result. The type on the left-hand side of the `=` doesn't matter. – unwind Mar 11 '13 at 13:01
  • I'm sorry I don't get it. Anything wrong with `malloc`? What do you mean by `the header`? – leowang Mar 11 '13 at 13:15
  • Forgot to mention that even if I use a pointer of structure to cast the returned value of `soap_malloc`, the higher 32 bits still changed to `1` – leowang Mar 11 '13 at 13:59
  • What leowang is saying is somewhere you need have a extern declaration for the function **malloc** that defines it like you would find in the **stdlib.h** header file: **extern void * malloc(size_t);**. If you do not have this somewhere the compile may be assuming **extern int malloc()** which would result in your code assuming an integer is being returned not a void pointer which could be the cause of your truncation. – Jere Mar 11 '13 at 20:21