Skip to content

Pointers to array types should have sane pointer arithmetic #7159

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

Closed
mb64 opened this issue Nov 19, 2020 · 4 comments
Closed

Pointers to array types should have sane pointer arithmetic #7159

mb64 opened this issue Nov 19, 2020 · 4 comments
Milestone

Comments

@mb64
Copy link
Contributor

mb64 commented Nov 19, 2020

Pointers to array types (such as *[8]u8) allow arithmetic, but add multiples of the whole array, not of the element.

$ cat test.zig
const std = @import("std");

pub fn main() void {
    var arr: [8]u8 = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };

    var bad_ptr = &arr + 1; // dangling pointer!
    std.debug.print("bad: {*}\n", .{bad_ptr});

    var good_ptr = @ptrCast([*]u8, &arr) + 1;
    std.debug.print("good:   {*}\n", .{good_ptr});

    std.debug.assert(@ptrToInt(good_ptr) + 7 == @ptrToInt(bad_ptr));
}
$ zig run test.zig
bad: [8]u8@7ffd8e8ffd40
good:   u8@7ffd8e8ffd39

In this example, adding 1 to &arr results in a dangling pointer to the 8-byte chunk following arr in memory. I would expect &arr + offset to either be an error, or result in a pointer to the offset'th element of the array.

@foobles
Copy link
Contributor

foobles commented Nov 19, 2020

What benefit would this add other than making slightly more sense to programmers coming from C? This also makes the language more inconsistent since it adds another special case.

I am not a big fan of this idea. If you need to offset the pointer, just index the array and take the address of the result. Or, possibly, take a pointer to the first element and do arithmetic on that.

@andrewrk
Copy link
Member

Duplicate of #2018. I'll add a "bug", "breaking", and "miscompilation" label to the issue since the status quo before is incorrect.

@ikskuh
Copy link
Contributor

ikskuh commented Nov 19, 2020

I agree with @theInkSquid:
The problem is that generic code won't work anymore for arrays, but for everything else. ptr + 1 should always increment a single element, and not "one day, a sub-element, the other day a element"

@mb64
Copy link
Contributor Author

mb64 commented Nov 19, 2020

I'm not trying to propose anything -- this is simply a bug report -- so could you clarify what it is you think I'm proposing that you don't like?

Specifically, the issue is that according to the docs, pointer arithmetic only works on multi-item [*]T pointers, like [*]i32 and [*]u8, and not single-item *T pointers, like *i32 and *[8]u8 (a pointer to a single [8]u8 item). However, arithmetic is mistakenly allowed on pointers to array:

var x: i32 = 5;
var array: [8]i32 = [8]i32{ 1, 2, 3, 4, 5, 6, 7, 8 };

// These don't compile:
// Correctly disallowed
const p1 = &x + 1;
// Correctly disallowed (can't "take a pointer to the first element and do arithmetic on that")
const p2 = &array[0] + 1;

// These *do* compile:
// Correctly allowed -- p3 points to array[1]
const ptr_to_items: [*]i32 = &array;
const p3 = ptr_to_items + 1;
// Incorrectly allowed -- p4 points to the empty space after the end of array
const p4 = &array + 1;

With &array + 1, one of two things should happen:

  • It should be an error, like &x + 1, instead of miscompiling to yield a dangling pointer
  • &array should automatically coerce to a [*]i32, where it would behave like p3

I'm not sure what generic code you have, but if any generic code depends on this behavior, it would already be failing to compile for non-array types.

@andrewrk andrewrk added this to the 0.8.0 milestone Jan 3, 2021
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

No branches or pull requests

4 participants