79505272

Date: 2025-03-13 02:29:05
Score: 0.5
Natty:
Report link

I was really interested in finding a dynamic reallocation for gsoap, so I decided to give it a shot. Here's what I came up relatively quickly.

The trick is that soap_malloc actually stores the allocation size and the next allocation address at the end of the allocation by adding extra padding.

In short, to reallocate a soap pointer, you need to add extra padding, write the allocation size, write the next pointer address, write the canary word and update the pointer address in the allocation chain.
Failing to do so would result with memory error while disposing of the gsoap instance.
I simply derived the logic from soap_dealloc and soap_malloc.

The following seems to work perfectly fine, but could probably use further testing:

SOAP_FMAC1 void* SOAP_FMAC2
soap_realloc(struct soap *soap, void * ptr, size_t n, size_t * orignalsize){
    char *p;
    size_t k = n;
    if (SOAP_MAXALLOCSIZE > 0 && n > SOAP_MAXALLOCSIZE){
        if (soap)
            soap->error = SOAP_EOM;
        return NULL;
    }
    if (!soap)
        return realloc(ptr, n);

    //Add mandatory extra padding
    n += sizeof(short);
    n += (~n+1) & (sizeof(void*)-1); /* align at 4-, 8- or 16-byte boundary by rounding up */
    if (n + sizeof(void*) + sizeof(size_t) < k){
        soap->error = SOAP_EOM;
        return NULL;
    }

    //Search pointer if memory alloaction list
    char **q;
    for (q = (char**)(void*)&soap->alist; *q; q = *(char***)q){
        if (*(unsigned short*)(char*)(*q - sizeof(unsigned short)) != (unsigned short)SOAP_CANARY){
            printf("ERROR: Data corruption in dynamic allocation\n");
            soap->error = SOAP_MOE;
            return NULL;
        }
        if (ptr == (void*)(*q - *(size_t*)(*q + sizeof(void*)))){
            break;
        }
    }

    if (*q){
        //Extract original allocation size
        if(orignalsize){
            *orignalsize = *(size_t*)(*q + sizeof(void *));
            //Shift original size to exclude original size and canary value
            *orignalsize -= sizeof(void*) - sizeof(size_t) - sizeof(unsigned short); //Handle round up?
        }
        

        //Reattach broken pointer chain
        if(*(char***)q)
            *q = **(char***)q;

        p = (char*) realloc(ptr,n + sizeof(void*) + sizeof(size_t));
        if(!p){
            printf("ERROR: Data corruption in dynamic allocation\n");
            soap->error = SOAP_MOE;
            return NULL;
        }

       /* set a canary word to detect memory overruns and data corruption */
       *(unsigned short*)((char*)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;

       return (void*)p;
   }

   printf("ERROR: Pointer not found in memory allocation cache\n");
   soap->error = SOAP_SVR_FAULT;
   return NULL;
}

Here's a simple example to increment allocation count by 1

__sizeProduct++;
prod_array = soap_realloc(soap, prod_array, sizeof(struct ns1__Product) * __sizeProduct, NULL);
newproduct = &prod_array[__sizeProduct-1];
soap_default_ns1__Product(soap, newproduct); // <----- This is the important part otherwise you will have to populate the entire object manually

Here's a another example to increment allocation count by n amount. This method allows a jump without needing to know the original size.

size_t original_size;
int newsize = n;
prod_array = soap_realloc(soap, prod_array,sizeof(struct ns1__Product) * newsize, &original_size);
for(size_t i=newsize;i>original_size;i--) // <-- Loop newly allocated space
    soap_default_ns1__Product(soap, (struct ns1__Product *) &prod_array[i-1]); // <----- This is the important part otherwise you will have to populate the entire object manually

I originally designed this for my onvifserver project with the goal to lower memory footprint as much as possible.

Reasons:
  • Contains signature (1):
  • Long answer (-1):
  • Has code block (-0.5):
  • Low reputation (1):
Posted by: Quedale