ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.65k stars 2.53k forks source link

Set undefined memory in debug mode don't work #20859

Closed lmarzocchetti closed 3 months ago

lmarzocchetti commented 3 months ago

Zig Version

0.14.0-dev.655+d30d37e35

Steps to Reproduce and Observed Behavior

I have "var min_col: i32 = undefined;", when i try to set the variable to some value (the first value is always setted, then i use it to find a minimum) it doesn't work in Debug mode. I tried in ReleaseSafe and it all works correctly

Expected Behavior

To behave like in Release mode, and set the memory to a value

alexrp commented 3 months ago

Please give a complete example that reproduces the issue.

lmarzocchetti commented 3 months ago
const std = @import("std");
const rl = @import("raylib");

// Random Generator
const SEED = 42;
var rand_prng = std.Random.DefaultPrng.init(SEED);
const rand_gen = rand_prng.random();

// Constants
const COLS = 10;
const ROWS = 20;
const HIDDEN_ROWS = 2;
const TOTAL_ROWS = ROWS + HIDDEN_ROWS;

const Square = [2]i32;

const PieceKind = enum {
    T,
    J,
    Z,
    O,
    S,
    L,
    I,
};

const Piece = struct {
    kind: PieceKind,
    squares: [4]Square,

    pub fn left_square(self: Piece) i32 {
        var min_col: i32 = undefined;
        // var min_col: i32 = 100;
        for (self.squares) |square| {
            if (min_col == undefined or square[1] < min_col) {
                min_col = square[1];
            }
        }
        return min_col;
    }

    pub fn right_square(self: Piece) i32 {
        var max_col: i32 = undefined;
        // var max_col: i32 = 0;
        for (self.squares) |square| {
            if (max_col == undefined or square[1] > max_col) {
                max_col = square[1];
            }
        }
        return max_col;
    }
};

const Direction = enum {
    Left,
    Right,
};

const Board = [TOTAL_ROWS][COLS]bool;

const Game = struct {
    board: Board,
    active_piece: Piece,

    pub fn init() Game {
        var board: Board = undefined;
        for (board, 0..) |rows, row| {
            for (rows, 0..) |_, col| {
                board[row][col] = false;
            }
        }
        return Game{
            .board = board,
            .active_piece = undefined,
        };
    }

    fn spawn_piece(self: *Game) void {
        const piece_kind_to_spawn = rand_gen.enumValue(PieceKind);
        var piece_to_spawn: Piece = undefined;
        piece_to_spawn.kind = piece_kind_to_spawn;
        switch (piece_kind_to_spawn) {
            .T => {
                piece_to_spawn.squares = .{
                    .{ ROWS, 5 },
                    .{ ROWS + 1, 4 },
                    .{ ROWS + 1, 5 },
                    .{ ROWS + 1, 6 },
                };
            },
            .I => {
                piece_to_spawn.squares = .{
                    .{ ROWS, 4 },
                    .{ ROWS, 5 },
                    .{ ROWS, 6 },
                    .{ ROWS, 7 },
                };
            },
            .J => {
                piece_to_spawn.squares = .{
                    .{ ROWS, 4 },
                    .{ ROWS, 5 },
                    .{ ROWS, 6 },
                    .{ ROWS + 1, 6 },
                };
            },
            .Z => {
                piece_to_spawn.squares = .{
                    .{ ROWS, 4 },
                    .{ ROWS, 5 },
                    .{ ROWS + 1, 5 },
                    .{ ROWS + 1, 6 },
                };
            },
            .O => {
                piece_to_spawn.squares = .{
                    .{ ROWS, 4 },
                    .{ ROWS, 5 },
                    .{ ROWS + 1, 4 },
                    .{ ROWS + 1, 5 },
                };
            },
            .S => {
                piece_to_spawn.squares = .{
                    .{ ROWS, 5 },
                    .{ ROWS, 6 },
                    .{ ROWS + 1, 4 },
                    .{ ROWS + 1, 5 },
                };
            },
            .L => {
                piece_to_spawn.squares = .{
                    .{ ROWS, 4 },
                    .{ ROWS, 5 },
                    .{ ROWS, 6 },
                    .{ ROWS + 1, 4 },
                };
            },
        }
        self.active_piece = piece_to_spawn;
    }

    pub fn gravity_active_piece(self: *Game) void {
        for (&self.active_piece.squares) |*square| {
            square[0] -= 1;
        }
    }

    pub fn move_active_piece(self: *Game, direction: Direction) void {
        switch (direction) {
            .Left => {
                if (self.active_piece.left_square() > 0) {
                    for (&self.active_piece.squares) |*square| {
                        square[1] -= 1;
                    }
                }
            },
            .Right => {
                std.debug.print("DEBUG: {}\n", .{self.active_piece.right_square()});
                if (self.active_piece.right_square() < COLS - 1) {
                    for (&self.active_piece.squares) |*square| {
                        square[1] += 1;
                    }
                }
            },
        }
    }

    pub fn rotate_active_piece(self: *Game) void {
        _ = self; // autofix
    }

    pub fn print(self: Game) void {
        for (self.board, 0..) |rows, row| {
            for (rows, 0..) |square, col| {
                if (square == false) {
                    var square_printed = false;
                    for (self.active_piece.squares) |piece_square| {
                        if (piece_square[0] == TOTAL_ROWS - row and piece_square[1] == col) {
                            std.debug.print("X", .{});
                            square_printed = true;
                        }
                    }
                    if (square_printed == false) {
                        std.debug.print("O", .{});
                    }
                } else {
                    std.debug.print("X", .{});
                }
            }
            std.debug.print("\n", .{});
        }
    }
};

fn clear_terminal() void {
    std.debug.print("\x1B[2J\x1B[H", .{});
}

pub fn main() !void {
    const screenWidth = 800;
    const screenHeight = 450;

    rl.initWindow(screenWidth, screenHeight, "Tetrig");
    defer rl.closeWindow();
    rl.setTargetFPS(30);

    var game = Game.init();

    game.spawn_piece();

    // std.debug.print("DEBUG: {}\n", .{game.active_piece.left_square()});

    while (!rl.windowShouldClose()) {
        clear_terminal();

        game.move_active_piece(Direction.Right);

        // Key Handling
        if (rl.isKeyDown(rl.KeyboardKey.key_right)) game.move_active_piece(Direction.Right);
        if (rl.isKeyDown(rl.KeyboardKey.key_left)) game.move_active_piece(Direction.Left);

        // Draw
        game.print();
        std.time.sleep(1_000_000_000);
        game.gravity_active_piece();

        rl.beginDrawing();
        rl.clearBackground(rl.Color.ray_white);
        rl.endDrawing();
    }
}

The raylib part is useless for this kind of problem, but if you want i followed the instruction of "https://github.com/Not-Nik/raylib-zig" to install it.

I've found another kind of strange behaviour, the commented lines below max_col and min_col are a workaround to make the program works in debug mode, BUT in ReleaseSafe mode it doesn't work anymore, and i think this is even more strange

squeek502 commented 3 months ago

max_col == undefined

Comparison against undefined is always a bug. I suggest you read the documentation for undefined: https://ziglang.org/documentation/master/#undefined

You probably want to use optionals instead: https://ziglang.org/documentation/master/#Optionals

Related issues:


In the future, please direct questions like this to one of the community spaces first

lmarzocchetti commented 3 months ago

Thank you for your time, i'm sorry for open this dumb issue. Next time i'll ask on other channels