Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slice operation permits creation of invalid pointers at compile time #19797

Open
amp-59 opened this issue Apr 28, 2024 · 0 comments · May be fixed by #19764
Open

Slice operation permits creation of invalid pointers at compile time #19797

amp-59 opened this issue Apr 28, 2024 · 0 comments · May be fixed by #19764

Comments

@amp-59
Copy link
Contributor

amp-59 commented Apr 28, 2024

Zig Version

0.13.0-dev.46+3648d7df1

Steps to Reproduce and Observed Behaviour

Compile example program with zig build-obj demo_various_unusable_results.zig
demo_various_unusable_results.zig:

const T = extern struct {
    a: usize = 1,
    b: u32 = 0,
    c: [4]u16 = .{ 2, 3, 4, 5 },
};
const S = extern struct {
    a: usize = 1,
    b: T = .{},
    c: [4]u8 = .{ 2, 3, 4, 5 },
};
var mem1: [2]S = .{ .{}, .{} };
const mem2: [2]S = .{ .{}, .{} };
comptime {
    const ptr1: [*]usize = @ptrCast(&mem1);
    const len1: usize = (2 * @sizeOf(S)) / @sizeOf(usize);
    const slice1: []usize = ptr1[0..len1];

    _ = ptr1[slice1.len + 1 ..];
}
comptime {
    const ptr1: [*]const usize = @ptrCast(&mem2);
    const ptr2: [*]const u32 = @ptrCast(ptr1[2..]);
    const len2: usize = ((2 * @sizeOf(S)) - 2 * @sizeOf(usize)) / @sizeOf(u32);
    const slice2: []const u32 = ptr2[0..len2];

    _ = ptr2[slice2.len + 1 ..];
}
comptime {
    var mem3: [2]S = .{ .{}, .{} };
    const ptr1: [*]usize = @ptrCast(&mem3);
    const ptr2: [*]u32 = @ptrCast(ptr1[2..]);
    const ptr3: [*]u8 = @ptrCast(ptr2[1..]);
    const len3: usize = (((2 * @sizeOf(S)) - 2 * @sizeOf(usize)) - @sizeOf(u32)) / @sizeOf(u8);
    const slice3: []u8 = ptr3[0..len3];

    _ = ptr3[slice3.len + 1 ..];
}
comptime {
    const mem4: [2]S = .{ .{}, .{} };
    const ptr4: [*]const u16 = @ptrCast(&mem4[0].b.c[2]);
    const len4: usize = ((2 * @sizeOf(S)) - (@offsetOf(S, "b") + @offsetOf(T, "c") + (2 * @sizeOf(u16)))) / @sizeOf(u16);
    const slice4: []const u16 = ptr4[0..len4];

    _ = ptr4[slice4.len + 1 ..];
}
comptime {
    var mem5: comptime_int = 0;
    const ptr5: [*]comptime_int = @ptrCast(&mem5);
    const slice5: []comptime_int = ptr5[0..1];

    _ = ptr5[slice5.len + 1 ..];
}
comptime {
    var mem6: comptime_int = 0;
    const ptr6: [*]type = @ptrCast(&mem6);

    _ = ptr6[0..1];
}

Output:

zig build-obj demo_various_unusable_results.zig

Each of the six discarded expressions are invalid. The first five are out of bounds, while the sixth is an impossible reinterpretation. The program compiles normally.

The primary issue with allowing the creation of invalid references at compile time is that they are indistinguishable from valid references at runtime by runtime safety checks.

Compile and run example program with zig run ub_subsequent_runtime_use.zig
ub_subsequent_runtime_use.zig:

var data: [32]u8 = .{'a'} ** 32;
pub fn main() void {
    const ptr1: [*]u8 = data[0..32];

    // Slice of 32 bytes above the actual declaration at runtime.
    const ptr2 = ptr1[32..64];

    // All subsequent runtime safety checks are based on incorrect information.
    const less: []const u8 = ptr2[0..16];

    // The random memory will probably be usable.
    @import("std").debug.print("{s}\n", .{less[0..16] ++ ptr2[16..]});
}

Output:

zig run ub_subsequent_runtime_use.zig
thread {} panic: invalid error 

At this point the state of the program is completely undefined and the best outcome is SIGSEGV.

Expected Behaviour

Slicing should not permit the creation of slices which are known to be invalid at compile time.

@amp-59 amp-59 linked a pull request Apr 28, 2024 that will close this issue
40 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant