Checking code on memory freeing

I am using the code below as a WebAssembly container. I want to use as a “captalizing” machine.

I am unsure of my code so I am here to learn.

I call the function allocated_memory_ptr twice, once for the WebAssembly user to get a pointer to write the input string to, and once to send to the WebAssembly user the output pointer that contains the result.

I was concerned about memory allocation but I realise that the WebAssembly caller should manage it, not Zig since it’s only using a view, the slice, nothing else.

Thks.

export fn allocated_memory_ptr(len: usize) ?[*]u8 {
    return if (allocator.alloc(u8, len)) |slice|
        slice.ptr
    else |_|
        null;
}

export fn to_uppercase(ptr: [*]const u8, input_len: usize, output_ptr: [*]u8) void {
    // Create a slice from the input pointer and length
    const input = ptr[0..input_len];
    // Convert to uppercase directly in memory
    for (input, 0..) |char, i| {
        output_ptr[i] = std.ascii.toUpper(char);
    }
}

I’m a bit confused:

it seems to me that you are not “returning” the modified string?
if you were to return the “output”, then I don’t think you can use defer... free... in that function because the variable that you return would be freed before you can use it where you call the function?

Typically I would use a pattern (in pseudo code):

...
create input
create output = call function with input
free input
use output
...

If the function would free the input memory, then it would be harder to read the code. What if I need to use both the original input and the uppercase output?

No, I can’t return a string in WebAssembly. It return the pointer to the result.

Ah, yes, you are right. I added the cleaner below and call it from the host. This should clean the memory

export fn free_memory(ptr: [*]u8, len: usize) void {
    const slice = ptr[0..len];
    allocator.free(slice);
}

The host has a copy of the result, so this keeps the WebAssembly container clean I guess.