Strdup does not calls redefined malloc/free

Hello I use freertos with heap-Model heap_4.
I have redefined the malloc and free function according the many suggestions you find online

#include <stdlib.h>

void* malloc(size_t size)
{
    void* ptr = NULL;

    if(size > 0)
    {
        // We simply wrap the FreeRTOS call into a standard form
        ptr = pvPortMalloc(size);
    } // else NULL if there was an error

    return ptr;
}

void free(void* ptr)
{
    if(ptr)
    {
        // We simply wrap the FreeRTOS call into a standard form
        vPortFree(ptr);
    }
}

But strdup() does not call the redefined malloc when i run this little test-Programm

#include <string.h>

static void testMem()
{
   // This works correctly
   char* testA = (char*)malloc(100);
   free(testA);
   
   char* testB = strdup("Banana");
   // Here is the Error. Because perviously strdup Does not call the redefined malloc
   free(testB);
}

I can think of two possible solutions ?

  1. To rebuild the stdlib to force strdup() to use the redefined malloc ?
    At the moment i am not sure if it is the stdlib and i have no idea how to rebuild it.
  2. Use a separte free() function e.g free_native
void free_native(void* ptr)
{
   free(ptr)
}

Thank you very much for your help.

(new)lib (also) uses _malloc_r internally.
So you should override the reentrant versions of the allocation symbols, too.
Note that you should take care about malloc(_r), free(_r), calloc(_r) and realloc(_r).

C doesn’t “Allow” you to change the standard library reliably. Many implementations (like newlib as Hartmut mentions) make malloc just a “wrapper” function, and something internal is used for the actual work, and this is all ok by the standard.

If your library IS newlib (as is common), you can look into your system and see if it was created with the hooks _malloc_lock() / _malloc_unlock() compiled in, which if they are, it makes it easy to just make malloc() and free() and the rest “Thread Safe” by a proper definition of them.

The strdup is defined from newlib in this way:

char *
_DEFUN (_strdup_r, (reent_ptr, str), 
        struct _reent *reent_ptr  _AND
        _CONST char   *str)
{
  size_t len = strlen (str) + 1;
  char *copy = _malloc_r (reent_ptr, len);
  if (copy)
    {
      memcpy (copy, str, len);
    }
  return copy;
}

so the problem seems that it calls _malloc_r(reentr_ptr,len)
which is not redefined and therefore does not use pvPortMalloc().

When i try to redefine _malloc_r(rentr_ptr,len) the linker aborts with a “multiple
definition error”.

Am i completely wrong when i try to redefine malloc/free to
secure that heap_4 works sufficient ?

I’m using the --wrap GCC linker option to wrap the allocation API mentioned before.
I think there a some online resources describing this method.

First, replacing library routines is putting you into the domain of you need to really know what you are doing, as it is easy to really break things.

The big point about replacing _malloc_r(), is that you also need to replace every other entry point in that module, or you get the sort of error you got. That includes not only _free_r() but also things like _realloc_r() which FreeRTOS doesn’t have the equivalent of, and maybe even things like _malloc_stats_r() if used. IF you really want to do this, the best course of action is to find what library your implementation uses, and down load the library source for it, and then you can modify that file to do what you want.

As I mentioned, I find it easier, if the implementation is using newlib, to make sure it is using __malloc_lock() and __malloc_unlock() and implement those to make malloc thread safe (and then make pvPortMalloc() and vPortFree() call these malloc and free functions). If your newlib wasn’t compiled with that option in, then you need to download the newlib source and build a version with that option enabled.

i already use the newlib and the flag USE_NEWLIB_REENTRANT is Enabled.
My problem is that strdup does not use malloc but _maolloc_r() which i don’t
want to redefine (this is what you have suggested).

Then just don’t use strdup - I’d recommend this anyway - and friends using malloc_r internally and you’ll be fine.

USE_NEWLIB_REENTRANT, while helping with some problems, doesn’t make malloc and family thread safe. For that you need to define __malloc_lock() and __malloc_unlock() (and make sure your version of newlib uses them). The lock can be just a call to vTaskSuspendAll() and unlock to xTaskResumeAll(), and then a direct call to malloc and family works like the heap_3.c version.