Skip to content

Crash after interned reuse #904

Closed
@puuuuh

Description

@puuuuh
    #[test]
    fn repro() {
        #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
        struct BadHash(String);

        impl std::hash::Hash for BadHash {
            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
                0.hash(state);
            }
        }

        #[salsa::input]
        struct Input {
            field: String
        }

        #[salsa::interned]
        struct Interned {
            field: String
        }

        #[salsa::tracked]
        struct Output<'db> {
            pub id: String,

            #[tracked]
            field: Interned<'db>
        }


        #[salsa::tracked]
        fn outer_query<'db>(db: &'db dyn Database, input: Input) -> Vec<Output<'db>> {
            let res: Vec<Output<'_>> = inner_query(db, input)
                .into_iter()
                .map(|i| Output::new(db, input.field(db), i))
                .collect();
            sleep(Duration::from_millis(500));
            db.unwind_if_revision_cancelled();
            for r in &res {
                r.id(db);
                r.field(db);
            }
            res
        }

        #[salsa::tracked]
        fn inner_query<'db>(db: &'db dyn Database, input: Input) -> Vec<Interned<'db>> {
            let res: Vec<Interned<'db>> = (0..10).map(|i| {
                Interned::new(db, format!("{}_{i}", input.field(db)))
            }).collect();
            res
        }


        tracing_subscriber::fmt()
            .with_max_level(Level::ERROR)
            .with_ansi(false)
            .with_writer(std::io::stderr)
            .init();
        let mut threads = vec![];
        let mut db = salsa::DatabaseImpl::default();
        let i1 = Input::new(&db, "i1".to_owned());
        let i2 = Input::new(&db, "i2".to_owned());
        let i3 = Input::new(&db, "i3".to_owned());
        let d = db.clone();
        threads.push(spawn(move || {
            outer_query(&d, i1);
        }));
        let d = db.clone();
        threads.push(spawn(move || {
            outer_query(&d, i2);
        }));
        sleep(Duration::from_millis(1000));
        db.synthetic_write(Durability::HIGH);
        let d = db.clone();
        threads.push(spawn(move || {
            outer_query(&d, i2);
        }));
        sleep(Duration::from_millis(250));
        db.synthetic_write(Durability::HIGH);
        let d = db.clone();
        threads.push(spawn(move || {
            outer_query(&d, i2);
        }));
        sleep(Duration::from_millis(250));
        db.synthetic_write(Durability::HIGH);
        let d = db.clone();
        threads.push(spawn(move || {
            outer_query(&d, i3);
        }));
        sleep(Duration::from_millis(250));
        db.synthetic_write(Durability::HIGH);
        let d = db.clone();
        threads.push(spawn(move || {
            outer_query(&d, i1);
        }));
        sleep(Duration::from_millis(0));
        db.synthetic_write(Durability::HIGH);
        for t in threads {
            t.join();
        }
        for t in outer_query(&db, i1) {
            t.field(&db).field(&db);
        }
    }

Repro is a little bit messy, ill try to reduce it more
Bug introduced in 15c28cd

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions