Zig: Proposal: randomize "undefined" behaviors in debug mode

Created on 31 Jan 2020  路  3Comments  路  Source: ziglang/zig

Idea mostly stolen inspired from Go where iterating map is explicitly randomized by the compiler. This was introduced to prevent people from accidentally depending on order in testing which causes hard-to-reproduce bugs in prod.

Can we apply the same idea for things like struct memory layout? It is documented to be _explicitly undefined_ but the memory is actually static and manually doing byte casting probably will consistently work right now, but it's almost guaranteed to break in the near future.

If we force randomization, it'll expose these bugs earlier and hopefully point towards the right direction.

proposal

Most helpful comment

I like this; with the condition that the seed for randomisation is printed at the start of compilation.
Without knowing the seed, people will just end up blaming "flaky tests" and run their test suite 3 times until it passes....

May want to way until stage 2/3 though.

All 3 comments

I like this; with the condition that the seed for randomisation is printed at the start of compilation.
Without knowing the seed, people will just end up blaming "flaky tests" and run their test suite 3 times until it passes....

May want to way until stage 2/3 though.

Related #168

168 talks about using reversed field order, which is good for some cases but not all of them. I've recently seen some people trying to do stuff like this:

fn GenericType(comptime T: type) type {
    return struct {
        capacity: usize,
        data: []T,
    };
}
const ContainsAnyGeneric = struct {
    pointer: usize,

    // param is pointer to GenericType(?)
    pub fn init(ptr: var) @This() {
        return .{ .pointer = @ptrToInt(ptr) };
    }

    pub fn getCapacity(self: @This()) usize {
        // use u1 as a dummy type, capacity doesn't depend on T
        const dummyGeneric = @intToPtr(*const GenericType(u1), self.pointer);
        return dummyGeneric.capacity;
    }
};

This is subtle UB, because the release-mode compiler may decide to order GenericType(u1) as { capacity, data } and GenericType(SomeOtherT) as { data, capacity }. (it's unlikely that this will happen based on the goals of the reordering, but no guarantee is actually made by the language that this should work). Randomizing field order would catch this, but using reverse fields would not (unless the user tried to use a zero-sized T, which would change the size of the slice).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

komuw picture komuw  路  3Comments

andrewrk picture andrewrk  路  3Comments

DavidYKay picture DavidYKay  路  3Comments

jorangreef picture jorangreef  路  3Comments

andrewrk picture andrewrk  路  3Comments