Skip to content

Freeze, when running multiple tests #2140

@qarmin

Description

@qarmin

Bug description

While adding new tests to my project, I noticed that one of them started hanging.
Interestingly, inserting a dbg!(&iter) inside the loop in iterator makes the problem disappear.

At first glance, this looks like either a bug in the iterator logic or some form of undefined behavior.
However, running the tests under Address Sanitizer and Valgrind did not report any errors.

In my project the issue appeared in debug mode, but in the minimal example (below) it only reproduces in release mode.

Code

use std::fs;
use gtk4::prelude::*;
mod tests;
fn main() {
    let txt = r##"
      #[gtk4::test]
    fn test_list_store_iterxxxxxx() {
        let columns_types: &[Type] = &[Type::STRING];
        let list_store = gtk4::ListStore::new(columns_types);
        let values = ["a", "b", "c"];
        for v in &values {
            let iter = list_store.append();
            list_store.set(&iter, &[(0, &(*v))]);
        }
        let collected: Vec<String> = list_store.custom_iter().map(|iter| list_store.get::<String>(&iter, 0)).collect();
        assert_eq!(collected, values.iter().map(|s| s.to_string()).collect::<Vec<_>>());
        let empty = gtk4::ListStore::new(&[Type::STRING]);
        let mut it = empty.custom_iter();
        assert!(it.next().is_none());
    }

    "##;

    let mut all = r#"
#[cfg(test)]
mod tests {
    use gtk4::prelude::*;
    use crate::ListStoreIterExt;
use glib::types::Type;
"#.to_string();
    for i in 0..400 {
        all += txt.replace("xxxxxx", &i.to_string()).as_str();
    }

    all += "}\n";
    fs::write("src/tests.rs", all).expect("Unable to write file");
}


pub struct ListStoreIter<'a> {
    list_store: &'a gtk4::ListStore,
    current: Option<gtk4::TreeIter>,
}

impl<'a> ListStoreIter<'a> {
    pub fn new(list_store: &'a gtk4::ListStore) -> Self {
        let current = list_store.iter_first();
        Self { list_store, current }
    }
}

impl<'a> Iterator for ListStoreIter<'a> {
    type Item = gtk4::TreeIter;
    fn next(&mut self) -> Option<Self::Item> {
        match &mut self.current {
            None => None,
            Some(iter) => {
                // dbg!(&iter);
                let result = Some(*iter);
                let next_iter = *iter;
                if self.list_store.iter_next(&next_iter) {
                    self.current = Some(next_iter);
                } else {
                    self.current = None;
                }
                result
            }
        }
    }
}

pub trait ListStoreIterExt {
    fn custom_iter(&self) -> ListStoreIter;
}

impl ListStoreIterExt for gtk4::ListStore {
    fn custom_iter(&self) -> ListStoreIter {
        ListStoreIter::new(self)
    }
}

Project - t.zip

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