Skip to content
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

OutStream in struct gives runtime unreachable in debug and release-safe #1633

Closed
numsim1415 opened this issue Oct 4, 2018 · 3 comments
Closed

Comments

@numsim1415
Copy link

numsim1415 commented Oct 4, 2018

The following code compiles but crashes on runtime.
The crash happens only if the variable doesMatter is there and only if debug or --release-safe is used.

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

pub const Mandelbrot = struct {
    out: @typeOf((io.getStdOut() catch unreachable).outStream().stream),
    
    pub fn init(m: *Mandelbrot) void{
        m.out = (io.getStdOut() catch unreachable).outStream().stream;
    }
};
pub fn main() void {
    var doesntMatter : usize = 1234; 
    var mb : Mandelbrot = undefined;
    Mandelbrot.init(&mb);
    
    // comment this variable and the runtime crash won't happen
    var doesMatter : usize = 42;
    
    _ = mb.out.print("{}\n",@intCast(usize,123));  // crash
}

By the way, it does not compile on 0.3, only on Master, see https://godbolt.org/z/0yVCLg .
Is my code flawed or is this a zig bug ?

The crash output is

reached unreachable code
/scratch/tmp/lkazaz/lll/ziginst/lib/zig/std/os/index.zig:368:28: 0x21d3c1 in ??? (lkerrs4)
            posix.EBADF => unreachable, // always a race condition
                           ^
/scratch/tmp/lkazaz/lll/ziginst/lib/zig/std/os/file.zig:411:30: 0x206493 in ??? (lkerrs4)
            try os.posixWrite(self.handle, bytes);
                             ^
/scratch/tmp/lkazaz/lll/ziginst/lib/zig/std/os/file.zig:457:35: 0x2059f5 in ??? (lkerrs4)
            return self.file.write(bytes);
                                  ^
/scratch/tmp/lkazaz/lll/ziginst/lib/zig/std/fmt/index.zig:755:22: 0x221270 in ??? (lkerrs4)
        return output(context, padded_buf);
                     ^
/scratch/tmp/lkazaz/lll/ziginst/lib/zig/std/fmt/index.zig:683:33: 0x220c0a in ??? (lkerrs4)
        return formatIntUnsigned(value, base, uppercase, width, context, Errors, output);
                                ^
/scratch/tmp/lkazaz/lll/ziginst/lib/zig/std/fmt/index.zig:317:21: 0x222cd1 in ??? (lkerrs4)
    return formatInt(value, radix, uppercase, width, context, Errors, output);
                    ^
/scratch/tmp/lkazaz/lll/ziginst/lib/zig/std/fmt/index.zig:270:52: 0x222c69 in ??? (lkerrs4)
        builtin.TypeId.Int => return formatIntValue(value, fmt, context, Errors, output),
                                                   ^
/scratch/tmp/lkazaz/lll/ziginst/lib/zig/std/fmt/index.zig:120:31: 0x222bc9 in ??? (lkerrs4)
            return formatValue(value, fmt, context, Errors, output);
                              ^
/scratch/tmp/lkazaz/lll/ziginst/lib/zig/std/fmt/index.zig:53:35: 0x222aa9 in ??? (lkerrs4)
                    try formatType(args[next_arg], fmt[0..0], context, Errors, output);
                                  ^
/scratch/tmp/lkazaz/lll/ziginst/lib/zig/std/io.zig:203:34: 0x222978 in ??? (lkerrs4)
            return std.fmt.format(self, Error, self.writeFn, format, args);
                                 ^
/scratch/tmp/lkazaz/lll/benchmarksgame-sourcecode/mandelbrot/lkerrs4.zig:25:21: 0x2227d4 in ??? (lkerrs4)
    _ = mb.out.print("{}\n",@intCast(usize,123));  // crash
                    ^
/scratch/tmp/lkazaz/lll/ziginst/lib/zig/std/special/bootstrap.zig:86:22: 0x2226c9 in ??? (lkerrs4)
            root.main();
                     ^
/scratch/tmp/lkazaz/lll/ziginst/lib/zig/std/special/bootstrap.zig:70:20: 0x222675 in ??? (lkerrs4)
    return callMain();
                   ^
/scratch/tmp/lkazaz/lll/ziginst/lib/zig/std/special/bootstrap.zig:64:39: 0x2224d8 in ??? (lkerrs4)
    std.os.posix.exit(callMainWithArgs(argc, argv, envp));
                                      ^
/scratch/tmp/lkazaz/lll/ziginst/lib/zig/std/special/bootstrap.zig:37:5: 0x222390 in ??? (lkerrs4)
    @noInlineCall(posixCallMainAndExit);
    ^
Aborted

Thank you in advance.

@Hejsil
Copy link
Contributor

Hejsil commented Oct 4, 2018

This is related to #591.

Basically, what you're doing is copying a field you should never copy. File.OutStream is defined like this:

pub const OutStream = struct {
    file: File,
    stream: Stream,

    pub const Error = WriteError;
    pub const Stream = io.OutStream(Error);

    fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
        const self = @fieldParentPtr(OutStream, "stream", out_stream);
        return self.file.write(bytes);
    }
};

The writeFn is what's important here. It's the function that io.OutStream uses to implement all its helper functions. This function expects, that out_stream is embedded in File.OutStream and therefore uses @fieldParentPtr to get to its implementation. You just copied stream out of its implementation, so @fieldParentPtr returns invalid memory.

@Hejsil
Copy link
Contributor

Hejsil commented Oct 4, 2018

This should fix your code (haven't tested):

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

pub const Mandelbrot = struct {
    out: @typeOf((io.getStdOut() catch unreachable).outStream()),
    
    pub fn init(m: *Mandelbrot) void{
        m.out = (io.getStdOut() catch unreachable).outStream();
    }
};
pub fn main() void {
    var doesntMatter : usize = 1234; 
    var mb : Mandelbrot = undefined;
    Mandelbrot.init(&mb);
    
    // comment this variable and the runtime crash won't happen
    var doesMatter : usize = 42;
    
    _ = mb.out.stream.print("{}\n",@intCast(usize,123));  // crash
}

@numsim1415
Copy link
Author

Thank you, it seems this is a known zig issue. It's funny how optimizations suppress the crash.

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

2 participants