Open joseph-montanez opened 1 month ago
An alternative workaround until this is fixed is to make a c binding for this function so that you don't have to edit translate-c output:
// workaround.h
#include zend headers
zend_string *workaround_zend_string_init (const char *str, size_t len, bool persistent);
// workaround.c
#include workaround.h
zend_string *workaround_zend_string_init (const char *str, size_t len, bool persistent)
{
return zend_string_init(str, len, persistent);
}
Then, add the workaround.c to your build and call workaround_zend_string_init from zig
Reproduction:
There's nothing wrong with the memcpy, the problem is zig assuming that the array access shouldn't go out of bounds when that's how it was intended to be used in c.
// repro.c
struct example {
char val[1];
};
char example_fn(struct example* ex, int index) {
return ex->val[index];
}
// repro.zig
const translated = @cImport({
@cInclude("repro.c");
});
test "example_fn" {
var buf: [6]u8 = .{'H', 'e', 'l', 'l', 'o', '\x00'};
for(buf, 0..) |expected, i| {
try @import("std").testing.expectEqual(expected, translated.example_fn(@ptrCast(&buf), @intCast(i)));
}
}
$> zig test repro.zig -I. -lc
thread 22064 panic: index out of bounds: index 1, len 1
cimport.zig:65:20: 0x8e1451 in example_fn (test.exe.obj)
return ex.*.val[@as(c_uint, @intCast(index))];
^
Linking the C code instead, it works as expected:
// repro.zig
extern fn example_fn(ex: *const anyopaque, index: c_int) u8;
test "example_fn" {
var buf: [6]u8 = .{'H', 'e', 'l', 'l', 'o', '\x00'};
for(buf, 0..) |expected, i| {
try @import("std").testing.expectEqual(expected, example_fn(@ptrCast(&buf), @intCast(i)));
}
}
$> zig test repro.zig repro.c -lc
All 1 tests passed.
Thanks! I understand now, and as a note I tried another way:
@as([*c]u8, @ptrCast(&ret.*.val))[len] = '\x00';
However it seems that as long as its not set to another variable, Zig just doesn't have enough information to correctly understand. Which is why this version works:
const ret_val_ptr: [*c]u8 = @as([*c]u8, @ptrCast(&ret.*.val));
ret_val_ptr[arg_len] = 0;
Zig Version
0.14.0-dev.1860+2e2927735
Steps to Reproduce and Observed Behavior
I am not sure what to call this specific issue.
This is from the php-src repository: php-src/Zend/zend_string.h
This is in the headers which is included:
This is the automatic conversion:
The specific issue is here:
This would result in only the first letter of the string to be copied and that determined the limit of the string. So if the expected string is supposed 5 characters long (which its only a single character), the next line
ret.*.val[len] = '\x00';
would throw an out of bounds "thread 337505 panic: index out of bounds: index 5, len 1"I had to go in and change cimport.zig for the corrected code.
Further up in the same cimport.zig is the memcpy defintion:
I just moved from Swift to Zig because it has the same exact problem with this same function and its auto import system. I am assuming my solution is still wrong as it problem creates a memory leak, but its a bit more than I can handle right now on how Zig handles this.
Expected Behavior
Should copy the entire buffer and not just the first byte.