# Provide my own malloc and free to C dependency?

**URL:** <https://ziggit.dev/t/provide-my-own-malloc-and-free-to-c-dependency/9280>\
**Category:** Help\
**Tags:** language, c\
**Created:** [March 27, 2025, 5:38am UTC](https://ziggit.dev/t/provide-my-own-malloc-and-free-to-c-dependency/9280 "2025-03-27T05:38:39Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![jeffective](https://ziggit.dev/user_avatar/ziggit.dev/jeffective/32/3116_2.png) [@jeffective](https://ziggit.dev/u/jeffective)\
**Post date:** [March 27, 2025, 5:38am UTC](https://ziggit.dev/t/provide-my-own-malloc-and-free-to-c-dependency/9280/1 "2025-03-27T05:38:39Z")

</div>

Is it possible for me to provide my own allocator to a c dependency so I can detect leaks?

---

<div class="post-metadata">

**Author:** ![yataro](https://ziggit.dev/letter_avatar_proxy/v4/letter/y/6de8d8/32.png) [@yataro](https://ziggit.dev/u/yataro)\
**Post date:** [March 27, 2025, 5:54am UTC](https://ziggit.dev/t/provide-my-own-malloc-and-free-to-c-dependency/9280/2 "2025-03-27T05:54:18Z")

</div>

Some C libraries allow you to customize `malloc` and `free`functions, some do not. If your dependency doesn’t, the best thing to do is to patch the code. Other methods include providing your own libc, `LD_PRELOAD` (global effect) on Linux and hooking.

Leak detection requires check after all memory is supposed to be freed, so I don’t think an elegant solution is available unless the library provides an allocator changing interface.

---

<div class="post-metadata">

**Author:** ![yataro](https://ziggit.dev/letter_avatar_proxy/v4/letter/y/6de8d8/32.png) [@yataro](https://ziggit.dev/u/yataro)\
**Post date:** [March 28, 2025, 8:11am UTC](https://ziggit.dev/t/provide-my-own-malloc-and-free-to-c-dependency/9280/3 "2025-03-28T08:11:45Z")

</div>

I was thinking about how could this be achieved the most pleasant way without patching, and came to this solution:

build.zig

```zig
const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const exe = b.addExecutable(.{
        .name = "main",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
        .link_libc = true,
    });

    exe.addCSourceFile(.{
        .file = b.path("src/lib.c"),
    });

    exe.root_module.addCMacro("malloc", "lib_malloc");
    exe.root_module.addCMacro("free", "lib_free");

    b.installArtifact(exe);

    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }

    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);
}

```

src/main.zig

```zig
const std = @import("std");

var lib_allocator: std.mem.Allocator = undefined;

export fn lib_malloc(size: usize) ?*anyopaque {
    const total_size = @sizeOf(usize) + size;
    const ptr = lib_allocator.alignedAlloc(u8, @alignOf(usize), total_size) catch {
        // you should set errno here, auxiliary C function will work
        return null;
    };
    @as(*usize, @ptrCast(ptr)).* = total_size;

    return ptr.ptr + @sizeOf(usize);
}

export fn lib_free(ptr: ?*align(@sizeOf(usize)) anyopaque) void {
    if (ptr == null) return;

    const to_free = @as([*]align(@sizeOf(usize)) u8, @ptrCast(ptr.?)) - @sizeOf(usize);
    const total_size = @as(*usize, @ptrCast(to_free)).*;

    lib_allocator.free(to_free[0..total_size]);
}

extern fn do_work() void;

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();

    const allocator = gpa.allocator();
    lib_allocator = allocator;

    do_work();
}

```

src/lib.c

```zig
#include <stdlib.h>

void do_work(void) {
    void *data = malloc(8); // leak
    (void)data;

    void *data2 = malloc(8);
    free(data2); // no leak
}

```

It reports leak correctly:

```zig
 $ zig build run
error(gpa): memory address 0x78a2c0a7c000 leaked:
/tmp/tmp.w7qI6cwFrg/src/main.zig:7:43: 0x10351e4 in lib_malloc (main)
    const ptr = lib_allocator.alignedAlloc(u8, @alignOf(usize), total_size) catch {
                                          ^
src/lib.c:4:18: 0x1034831 in do_work (/tmp/tmp.w7qI6cwFrg/src/lib.c)
    void *data = malloc(8); // leak
                 ^
/tmp/tmp.w7qI6cwFrg/src/main.zig:34:12: 0x10348b8 in main (main)
    do_work();
           ^
/usr/lib/zig/std/start.zig:524:37: 0x1034da0 in main (main)
            const result = root.main() catch |err| {
                                    ^
???:?:?: 0x78a2c0864487 in ??? (libc.so.6)
???:?:?: 0x78a2c086454b in ??? (libc.so.6)

```

It works by defining `malloc` and `free` macros, but I think this solution is not elegant. Real world case will also export `malloc`, `free`, `calloc`, `realloc`, GNU stuff like `aligned_alloc`, `malloc_usable_size`, `memalign`, etc. Don’t forget about `reallocarray`, `strdup`, and others. I think the “hack” presented here would fit small codebases, but for something more complex consider patching code.

EDIT: fix small mistake

---

<div class="post-metadata">

**Author:** ![jeffective](https://ziggit.dev/user_avatar/ziggit.dev/jeffective/32/3116_2.png) [@jeffective](https://ziggit.dev/u/jeffective)\
**Post date:** [March 28, 2025, 4:47pm UTC](https://ziggit.dev/t/provide-my-own-malloc-and-free-to-c-dependency/9280/4 "2025-03-28T16:47:20Z")

</div>

Looks like my dependency has some aliases for malloc already, perhaps there is some kind of DEFINE mechanism or something to customize it…

> <https://github.com/eclipse-zenoh/zenoh-c/blob/main/include/zenoh_memory.h>

```c
/*------------------ Memory ------------------*/
static inline void *z_malloc(size_t size) { return malloc(size); }
static inline void *z_realloc(void *ptr, size_t size) { return realloc(ptr, size); }
static inline void z_free(void *ptr) { free(ptr); }

```

Edit: nevermind, this has nothing to do with that. Its just for the library maintaining comptability with other implementations: zenoh-pico: [GitHub · Where software is built](https://github.com/eclipse-zenoh/zenoh-pico/issues)

---

<div class="post-metadata">

**Author:** ![yataro](https://ziggit.dev/letter_avatar_proxy/v4/letter/y/6de8d8/32.png) [@yataro](https://ziggit.dev/u/yataro)\
**Post date:** [March 28, 2025, 5:28pm UTC](https://ziggit.dev/t/provide-my-own-malloc-and-free-to-c-dependency/9280/5 "2025-03-28T17:28:08Z")

</div>

There’s no configuration mechanism, `zenoh_memory.h` is included unconditionally in `zenoh.h`. You can use define “hack” as there’s only 3 functions to mock (`malloc`, `realloc` and `free`) or replace `zenoh_memory.h` with Zig build system.

---

<div class="post-metadata">

**Author:** ![jeffective](https://ziggit.dev/user_avatar/ziggit.dev/jeffective/32/3116_2.png) [@jeffective](https://ziggit.dev/u/jeffective)\
**Post date:** [March 28, 2025, 5:54pm UTC](https://ziggit.dev/t/provide-my-own-malloc-and-free-to-c-dependency/9280/6 "2025-03-28T17:54:24Z")

</div>

The library is actually written in rust, and uses the rust global allocator, so there isn’t really any guarantee that I can replace its allocator (rust could choose to use something other than libc, though I think its unlikely).  
I guess I’m really just searching for a means to ensure that I `drop` all the the things I am supposed to drop when using this library.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://ziggit.dev/user_avatar/ziggit.dev/mnemnion/32/2478_2.png) [@mnemnion](https://ziggit.dev/u/mnemnion)\
**Post date:** [March 28, 2025, 6:08pm UTC](https://ziggit.dev/t/provide-my-own-malloc-and-free-to-c-dependency/9280/7 "2025-03-28T18:08:14Z")

</div>

The Rust global allocator can be replaced [at link time](https://users.rust-lang.org/t/global-allocator-replaceable-from-c/104526), with enough fiddling about it seems you could use Zig `export` functions to provide the FFI interface using the allocator of your choice.

No idea if this is actually practical for your use case, but it seemed worth mentioning.

---

<div class="post-metadata">

**Author:** ![weskoerber](https://ziggit.dev/user_avatar/ziggit.dev/weskoerber/32/2129_2.png) [@weskoerber](https://ziggit.dev/u/weskoerber)\
**Post date:** [March 29, 2025, 8:22pm UTC](https://ziggit.dev/t/provide-my-own-malloc-and-free-to-c-dependency/9280/8 "2025-03-29T20:22:16Z")

</div>

What are the benefits of using your own malloc and free over using something link Valgrind to detect leaks?

---

<div class="post-metadata">

**Author:** ![pachde](https://ziggit.dev/user_avatar/ziggit.dev/pachde/32/2485_2.png) [@pachde](https://ziggit.dev/u/pachde)\
**Post date:** [March 30, 2025, 2:50pm UTC](https://ziggit.dev/t/provide-my-own-malloc-and-free-to-c-dependency/9280/9 "2025-03-30T14:50:24Z")

</div>

Valgrind doesn’t work on Windows, where I work most of the time.

---

<div class="post-metadata">

**Author:** ![yataro](https://ziggit.dev/letter_avatar_proxy/v4/letter/y/6de8d8/32.png) [@yataro](https://ziggit.dev/u/yataro)\
**Post date:** [March 30, 2025, 3:26pm UTC](https://ziggit.dev/t/provide-my-own-malloc-and-free-to-c-dependency/9280/10 "2025-03-30T15:26:13Z")

</div>

As pachde said, built-in memory leak checking is useful on Windows, but I believe it is more like using Zig allocator features, including arena, scoped allocations, write tests with failing allocator, ability to adjust allocator settings (for example see [DebugAllocatorConfig](https://ziglang.org/documentation/master/std/#std.heap.DebugAllocatorConfig)), use more performant allocators.

---

<div class="post-metadata">

**Author:** ![jeffective](https://ziggit.dev/user_avatar/ziggit.dev/jeffective/32/3116_2.png) [@jeffective](https://ziggit.dev/u/jeffective)\
**Post date:** [March 30, 2025, 3:28pm UTC](https://ziggit.dev/t/provide-my-own-malloc-and-free-to-c-dependency/9280/11 "2025-03-30T15:28:28Z")

</div>

Also, zig is its own language. Sometimes people learn zig first and not C, so they don’t have experience with the C tooling 🙂 (me)

---

<div class="post-metadata">

**Author:** ![weskoerber](https://ziggit.dev/user_avatar/ziggit.dev/weskoerber/32/2129_2.png) [@weskoerber](https://ziggit.dev/u/weskoerber)\
**Post date:** [March 30, 2025, 6:45pm UTC](https://ziggit.dev/t/provide-my-own-malloc-and-free-to-c-dependency/9280/12 "2025-03-30T18:45:32Z")

</div>

Those are all great points, thanks guys!

I honestly had no idea Valgrind doesn’t work on Windows, that’s good to know.
