Stream: t-compiler/help

Topic: who initialized LOCAL_STDOUT in stdio.rs


yunhua (May 05 2020 at 17:35, on Zulip):

Hi I'm trying to understand how stdio::_print_to works internally, in libstd/io/stdio.rs

thread_local! {
    /// Stdout used by print! and println! macros
    static LOCAL_STDOUT: RefCell<Option<Box<dyn Write + Send>>> = {
        RefCell::new(None)
    }
}

LOCAL_STDOUT was initialized to None, but when I run a simple "Hello Rust" program with rust-gdb, I saw the value is not None.
p local_s
$1 = (struct LocalKey<core::cell::RefCell<core::option::Option<alloc::boxed::Box<Write>>>> *) 0x5555558227d8
My question is who initialized LOCAL_STDOUT? Thanks.

bjorn3 (May 05 2020 at 17:37, on Zulip):

https://github.com/rust-lang/rust/blob/f8d394e5184fe3af761ea1e5ba73f993cfb36dfe/src/libstd/io/stdio.rs#L524-L542

bjorn3 (May 05 2020 at 17:38, on Zulip):

Wait, wrong code

bjorn3 (May 05 2020 at 17:43, on Zulip):

LOCAL_STDOUT should only be Some when during tests.

Looking at the code I see that _print calls print_to with a reference to LOCAL_STDOUT`: https://github.com/rust-lang/rust/blob/f8d394e5184fe3af761ea1e5ba73f993cfb36dfe/src/libstd/io/stdio.rs#L890

print_to then simply uses the global output when LOCAL_STDOUT is none: https://github.com/rust-lang/rust/blob/f8d394e5184fe3af761ea1e5ba73f993cfb36dfe/src/libstd/io/stdio.rs#L854-L880

yunhua (May 05 2020 at 17:57, on Zulip):

Thanks! @bjorn3 seems LOCAL_STDOUT is not none in my simple "Hello Rust" program. I compiled rustc by myself, so line number is little different.

Breakpoint 1, std::io::stdio::print_to::_$u7b$$u7b$closure$u7d$$u7d$::h42c135b27158b526 (s=0x7ffff7fa0760) at src/libstd/io/stdio.rs:781
781             if let Ok(mut borrowed) = s.try_borrow_mut() {
(gdb) p s
$2 = (struct RefCell<core::option::Option<alloc::boxed::Box<Write>>> *) 0x7ffff7fa0760
(gdb) n
781             if let Ok(mut borrowed) = s.try_borrow_mut() {
782                 if let Some(w) = borrowed.as_mut() {
(gdb) p borrowed
$3 = RefMut<core::option::Option<alloc::boxed::Box<Write>>> = {value = 0x7ffff7fa0768, borrow = BorrowRefMut = {borrow = 0x7ffff7fa0760}}

borrowed.as_mut() returned None, so it called global_s().write_fmt(args)
I don't understand who set LOCAL_STDOUT to Some()

using grep, I found LOCAL_STDOUT in src/librustc_codegen_llvm/consts.rs, not sure if that related.

bjorn3 (May 05 2020 at 18:57, on Zulip):

What does borrowed.value dereference to? borrowed.value is a pointer to the Option<Box<dyn Write>>.

bjorn3 (May 05 2020 at 19:55, on Zulip):

@yunhua ^

yunhua (May 05 2020 at 20:23, on Zulip):

@bjorn3

(gdb) p borrowed
$16 = RefMut<core::option::Option<alloc::boxed::Box<Write>>> = {value = 0x7ffff7fa0768, borrow = BorrowRefMut = {borrow = 0x7ffff7fa0760}}
(gdb) p *borrowed.value
$17 = Option<alloc::boxed::Box<Write>>
(gdb) x/2w borrowed.value
0x7ffff7fa0768: 0       0

So can we confirm borrowed.value is None here? As x/2w given 0,0. Thanks.

Last update: Jan 22 2021 at 13:15UTC