-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
add safety checks for pointer casting #2414
Comments
This could be done with "butterfly" data before the pointed address with allocator's help. memory layout:
This is used in V8 (JS runtime) to allow fast indirection with attached metadata (infrequently accessed). Basically, you store type info, undefined-ness to the left side of the butterfly
ProblemsInterop with C may break What if the user only define a struct partially? Have undefined-bit for each field? Existing It's better to have generation + memory address. (to prevent use-after-free with memory reuse). |
What if I want to abuse the pointer casting to temporarily cast to a wrong type (for efficiency sake)? E.g. imagine a sentinel-based doubly linked list (like intrusive lists in boost). Something like const Item = struct {
data1: Data1,
data2: Data2,
link: Link,
};
const Link = struct {
next: *Item,
prev: *Item,
};
const List = struct {
sentinel: Link,
}; (in reality Instead of setting This proposal seems to invalidate the respective implementation. The "workaround" function Edit: actually maybe one doesn't need |
Also what if I want to cast without knowing in advance, whether the memory is undefined or already contains precious data? What if I want a pointer to memory containing garbage (e.g. returned by an allocator), which is not equal to |
Maybe runtime safety checking of pointed to types can be disabled on case-by-case basis. In particular, I could imagine the following approach: const S1 = struct { ... };
const S2 = struct { ... };
const S = struct { field1: S1, field2: S2 };
var var2: S2 = undefined;
const p: *punnable align(@alignOf(S2)) S = @fieldParentPtr("field2", &var2);
fn someFunc(s: *punnable align(@alignOf(S2)) S) void {
const s2 = &s.field2;
s2.doSomething();
}
fn someOtherFunc() void {
someFunc(p);
} The qualifier Note1. In theory the |
I'm excited about this one. This connects a lot of dots and is part of the unofficial Make The Safe Build Modes More Safe project (#2301).
Here are some of the features of Zig this depends on:
undefined
is OK)The proposal is to add a secret safety field to types which have no well-defined in-memory layout, similar to how unions have a secret safety tag field. The secret safety field has an integer which denotes the type id. A unique integer id will be generated for every type across an entire compilation.
Next, augment the rules about undefined values (see #1947) with this: in safe build modes, the bit pattern of
undefined
shall be0xaa
(repeating) across the store size of the type and for types which have no well-defined in-memory layout, the bit pattern0xaa
repeated across the store size shall not match a valid state.This makes it possible to add safety checks to
@ptrCast
,@intToPtr
, and@fieldParentPtr
. It will be detectable illegal behavior (see #2402) if the actual element type does not match the target type specified in the cast, or if the memory has an undefined value.Sometimes it is desired to
@ptrCast
or@intToPtr
when you know the memory is undefined. For these cases we introduce@ptrCastUndef
and@intToPtrUndef
which simultaneously cast and assignundefined
to the memory. These functions allow the programmer to change the type of memory in a legal way.The text was updated successfully, but these errors were encountered: