zig icon indicating copy to clipboard operation
zig copied to clipboard

`read`, etc. should check `slice.len == 0`

Open perillo opened this issue 2 years ago • 6 comments

Zig Version

0.10.0-dev.2103+ac1aaec9c

Steps to Reproduce

Consider this program:

const std = @import("std");
const debug = std.debug;

pub fn main() void {
    var array: [0]u8 = [_]u8{};
    var slice: []u8 = &array;

    const ptr = @ptrToInt(slice.ptr);
    debug.print("ptr: 0x{x}\n", .{ptr});
}

A problem with the current behavior is that passing a zero length buffer to read will crash the program (close returns EFAULT):

const std = @import("std");
const io = std.io;

pub fn main() !void {
    const stdin = io.getStdIn();

    var buf: [0]u8 = [_]u8{};
    _ = try stdin.read(&buf);
}

This C program works as expected: https://glot.io/snippets/g9k7ypryux. This Go program also works as expected: https://go.dev/play/p/5LcVU6It_xZ

Expected Behavior

The output to be:

ptr: 0

Actual Behavior

The output is:

ptr: 0xaaaaaaaaaaaaaaaa

that is, undefined.

perillo avatar May 07 '22 14:05 perillo

Why do you expect the pointer to be 0? That is not even a value allowed by the type.

Vexu avatar May 09 '22 15:05 Vexu

@Vexu, indeed it does not need to be 0. In order for the read example to work, it just needs to be a valid pointer.

Thanks.

perillo avatar May 10 '22 15:05 perillo

But what should it be a pointer too? [0]u8 is zero size so doesn't exist in memory at runtime, so you can't get its address.

leecannon avatar May 10 '22 18:05 leecannon

@leecannon, I think https://github.com/ziglang/zig/issues/6706 should solve this problem.

Current behavior does not feels right, to me. You can not get the address of [0]u, but you can coerce it to a slice, whose .ptr field holds an undefined pointer.

perillo avatar May 11 '22 09:05 perillo

It seems that there is another "unexpected" behavior with empty slices:

test "empty slice ptr from zero bit array" {
    const a: [0]u8 = [_]u8{};
    var b: []u8 = &a;

    debug.print("len b: {}\n", .{b.len});
}
test "empty slice ptr" {
    const a: []u8 = try testing.allocator.alloc(u8, 10);
    defer testing.allocator.free(a);

    var b: []u8 = a[0..0];
    debug.print("len b: {}\n", .{b.len});
    try testing.expectEqual(a.ptr, b.ptr);
}

Both are empty slices, but the latter has a valid pointer.

Code adapted from https://github.com/ziglang/zig/issues/4771.

Thanks.

perillo avatar May 11 '22 09:05 perillo

@Vexu, indeed it does not need to be 0. In order for the read example to work, it just needs to be a valid pointer.

Sounds like the actual bug is read not checking whether the slice has a non zero length before doing any operations on the pointer.

It seems that there is another "unexpected" behavior with empty slices:

I would find it more unexpected for slicing to turn an invalid pointer into a valid one or the other way around. The key property for both of these slices is the length being zero.

Vexu avatar May 17 '22 11:05 Vexu

I think this issue can be closed after commit d0eef26.

perillo avatar Dec 13 '22 10:12 perillo