C API: Does reimplementing calloc work on device?

I do not have a device to test on, so I'm basing this entirely off of information from the docs and from here on the forum:

I'm writing an app in C that uses a few libraries to accomplish core tasks, and one of the libraries uses calloc internally. I read here that calloc does not work on device, so in the interest of solving as many problems as I can ahead of receiving my Playdate, I thought I'd try overriding calloc with an implementation that used malloc and memset internally, similarly to how the SDK's setup.c redefines malloc/free/realloc with implementations that use playdate->system->realloc. (somewhat related: C API: Why isn't setup.c included in Simulator builds?)

I used DidierMalenfant's example implementation, swapping the custom pd_malloc out for malloc. Following the format in setup.c, I define the implementation as _calloc_r if targeting the Playdate hardware, or as calloc if instead targeting the Simulator. This seems to work in the Simulator, but I'd greatly appreciate it if someone could confirm that this workaround works on hardware. Worst case scenario, if redefining _calloc_r on hardware doesn't end up working, I can just set the one library to use the custom calloc implementation directly. I'd also love to know what happens on hardware when calloc is used without being redefined.

Full implementation:
#include <pd_api.h>

// https://devforum.play.date/t/a-list-of-helpful-libraries-and-code/221/85
#if TARGET_PLAYDATE
void* _calloc_r(struct _reent* _REENT, size_t nb_of_items, size_t item_size)
#else
void* calloc(size_t nb_of_items, size_t item_size)
#endif
{
    if (item_size && (nb_of_items > (SIZE_MAX / item_size))) {
        return NULL;
    }

    size_t size = nb_of_items * item_size;
    void* memory = malloc(size);
    if(memory != NULL) {
        memset(memory, 0, size);
    }

    return memory;
}

Thanks!

Calloc does work on device; but it's not an official public API. We'll see about adding it to the setup.c file in a future release.

1 Like

Maybe a playdate->system->calloc() to go alongside the realloc() already in the API?

I don't suppose Playdate's realloc() already erases the contents of the returned buffer, does it? I understand Linux will do that for security reasons (accessing a previous process's leftover data), but there probably aren't such concerns on Playdate.

Okay, thank you. I assume I should continue to reimplement _calloc_r until it's added officially to setup.c?

Also, if you don't mind me asking, how does adding --specs=nosys.specs to the linker flags affect the situation around calloc (and malloc, free, etc.)? I added it early on in my project to resolve linker errors, which were likely because my libraries include stdlib.h. Am I better off removing the flag and explicitly removing all usages of stdlib.h?

I don't think there is any harm in reimplementing _calloc_r. As for using nosys.specs, my official recommendation is if it works, keep using it. :slight_smile: But be aware it could break or not work using a different compiler.

Awesome, thank you so much!

Just want to put an update here in case anyone else stumbles upon this thread:
calloc seems to work without doing anything special. Reimplementing it doesn't seem to be necessary.