Skip to content

"Conditional jump or move depends on uninitialised value(s)" on feature(generator) #47253

@dwrensha

Description

@dwrensha

Valgrind reports use of uninitialized memory in the following program, which was reduced from tokio-rs/tokio-timer#36 and alexcrichton/futures-await#47.

// main.rs
#![feature(conservative_impl_trait, generators, generator_trait)]

pub type Poll<T, E> = Result<Async<T>, E>;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Async<T> {
    Ready(T),
    NotReady,
}

pub trait Future {
    type Item;
    type Error;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error>;
}

impl<F, T, E> Future for Option<F> where F: Future<Item=T, Error=E> {
    type Item = Option<T>;
    type Error = E;
    fn poll(&mut self) -> Poll<Option<T>, E> {
        match *self {
            None => Ok(Async::Ready(None)),
            Some(ref mut x) => match x.poll() {
                Ok(Async::Ready(t)) => Ok(Async::Ready(Some(t))),
                Ok(Async::NotReady) => Ok(Async::NotReady),
                Err(e) => Err(e),
            }
        }
    }
}

pub mod __rt {
    pub use std::ops::Generator;
    use super::Poll;
    use super::{Future, Async};
    use std::ops::GeneratorState;

    pub trait MyFuture<T: IsResult>: Future<Item=T::Ok, Error = T::Err> {}

    impl<F, T> MyFuture<T> for F
        where F: Future<Item = T::Ok, Error = T::Err > + ?Sized,
              T: IsResult
    {}

    pub trait IsResult {
        type Ok;
        type Err;

        fn into_result(self) -> Result<Self::Ok, Self::Err>;
    }
    impl<T, E> IsResult for Result<T, E> {
        type Ok = T;
        type Err = E;

        fn into_result(self) -> Result<Self::Ok, Self::Err> { self }
    }

    pub struct GenFuture<T>(pub T);

    pub enum Mu {}

    impl<T> Future for GenFuture<T>
        where T: Generator<Yield = Async<Mu>>,
              T::Return: IsResult,
    {
        type Item = <T::Return as IsResult>::Ok;
        type Error = <T::Return as IsResult>::Err;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            match self.0.resume() {
                GeneratorState::Yielded(Async::NotReady)
                    => Ok(Async::NotReady),
                GeneratorState::Yielded(Async::Ready(mu))
                    => match mu {},
                GeneratorState::Complete(e)
                    => e.into_result().map(Async::Ready),
            }
        }
    }
}

pub struct Foo {
    _a: Option<usize>,
    _b: Option<String>,
}

fn ola() -> impl __rt::MyFuture<Result<(), String>> + 'static {
    __rt::GenFuture(move || -> Result<(), String> {
        let _f = Foo { _a: None, _b: None };
        yield Async::NotReady;
        return Ok(());
    })
}

fn main() {
    let ft = ola();
    let _ = Some(ft).poll();
}
$ rustc -v -V
rustc 1.25.0-nightly (6828cf901 2018-01-06)
binary: rustc
commit-hash: 6828cf90146c7fefc4ba4f16dffe75f763f2d910
commit-date: 2018-01-06
host: x86_64-unknown-linux-gnu
release: 1.25.0-nightly
LLVM version: 4.0
$ rustc main.rs
$ valgrind ./main
==2217== Memcheck, a memory error detector
==2217== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2217== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==2217== Command: ./main
==2217== 
==2217== Conditional jump or move depends on uninitialised value(s)
==2217==    at 0x10FAF4: <core::option::Option<F> as main::Future>::poll (in /home/dwrensha/Desktop/main)
==2217==    by 0x10F59A: main::main (in /home/dwrensha/Desktop/main)
==2217==    by 0x10F7E2: std::rt::lang_start::{{closure}} (in /home/dwrensha/Desktop/main)
==2217==    by 0x119E17: {{closure}} (rt.rs:59)
==2217==    by 0x119E17: _ZN3std9panicking3try7do_call17hffb5315d0c0f678dE.llvm.3A805FA6 (panicking.rs:480)
==2217==    by 0x123D9E: __rust_maybe_catch_panic (lib.rs:102)
==2217==    by 0x11034F: try<i32,closure> (panicking.rs:459)
==2217==    by 0x11034F: catch_unwind<closure,i32> (panic.rs:365)
==2217==    by 0x11034F: std::rt::lang_start_internal (rt.rs:58)
==2217==    by 0x10F7C6: std::rt::lang_start (in /home/dwrensha/Desktop/main)
==2217==    by 0x10F62D: main (in /home/dwrensha/Desktop/main)
==2217== 
==2217== Conditional jump or move depends on uninitialised value(s)
==2217==    at 0x10FB06: <core::option::Option<F> as main::Future>::poll (in /home/dwrensha/Desktop/main)
==2217==    by 0x10F59A: main::main (in /home/dwrensha/Desktop/main)
==2217==    by 0x10F7E2: std::rt::lang_start::{{closure}} (in /home/dwrensha/Desktop/main)
==2217==    by 0x119E17: {{closure}} (rt.rs:59)
==2217==    by 0x119E17: _ZN3std9panicking3try7do_call17hffb5315d0c0f678dE.llvm.3A805FA6 (panicking.rs:480)
==2217==    by 0x123D9E: __rust_maybe_catch_panic (lib.rs:102)
==2217==    by 0x11034F: try<i32,closure> (panicking.rs:459)
==2217==    by 0x11034F: catch_unwind<closure,i32> (panic.rs:365)
==2217==    by 0x11034F: std::rt::lang_start_internal (rt.rs:58)
==2217==    by 0x10F7C6: std::rt::lang_start (in /home/dwrensha/Desktop/main)
==2217==    by 0x10F62D: main (in /home/dwrensha/Desktop/main)
==2217== 
==2217== 
==2217== HEAP SUMMARY:
==2217==     in use at exit: 0 bytes in 0 blocks
==2217==   total heap usage: 6 allocs, 6 frees, 2,000 bytes allocated
==2217== 
==2217== All heap blocks were freed -- no leaks are possible
==2217== 
==2217== For counts of detected and suppressed errors, rerun with: -v
==2217== Use --track-origins=yes to see where uninitialised values come from
==2217== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions