zig icon indicating copy to clipboard operation
zig copied to clipboard

zig does not error/silently ignores const refs passed to varargs

Open dylan-conway opened this issue 1 year ago • 2 comments

Zig Version

0.13.0-dev.46+3648d7df1

Steps to Reproduce and Observed Behavior

reproed on linux aarch64

with these files

// lib.c
#include <stdarg.h>
void init_int(...)
{
    va_list args;
    va_start(args);
    int *i = va_arg(args, int *);
    *i = 12345;
    va_end(args);
}
// main.zig
const std = @import("std");

extern fn init_int(...) void;

pub fn main() void {
    const i: c_int = 5;
    init_int(&i);
    std.debug.print("i: {d}\n", .{i});
}

run zig run main.zig lib.a

Received output:

i: 5

Additional information: If I change const i: c_int = 5 to var i: c_int = 5 it will set i to 12345.

Expected Behavior

I expect a compilation error like expected type '*c_int', found '*const c_int' or something similar. Or if this compiled successfully I would expect it to set i to 12345. Either way, I think the current behavior is a bug

dylan-conway avatar May 05 '24 01:05 dylan-conway

that compile error isnt possible unless the language was changed to always require passing mutable pointers to varargs which would be silly. im guessing that here the compiler inlines the 5 since it sees that its (theoretically) impossible for it to change, maybe you could argue that behavior shouldnt happen but i think its fairly reasonable. even clang does the same thing when it has a full view of what happens in the code

// lib.c
#include <stdarg.h>
#include <stdio.h>
void init_int(...)
{
    va_list args;
    va_start(args);
    int *i = va_arg(args, int *);
    *i = 12345;
    va_end(args);
}

int main() {
    const int a = 5;
    init_int(&a);
    printf("%d\n", a);
}
$ clang lib.c -std=c2x
$ ./a.out
5

xdBronch avatar May 05 '24 01:05 xdBronch

that compile error isnt possible unless the language was changed to always require passing mutable pointers to varargs which would be silly

While it may sound silly, I actually think it would properly fix this misbehavior. Say we introduced that requirement, all that changes is that the caller has to wrap the pointer-to-const arguments with @constCast, which clearly signals to be wary when doing this. It's pretty much exactly the scenario for when/why @constCast already exists in status-quo. To me this solution seems like a solid improvement over sticking with status-quo.

rohlem avatar May 05 '24 23:05 rohlem