Qt random crash

Mar 11, 2020 at 8:02am
Hi, so here is the problem.

I made an ecosystem simulation with Qt.

The simulation is perfectly working on 800x800m maps, but I don't know why, when I go over this size, I've a random crash happening at a random place (with cout, I just saw that sometimes it crashes after a point, but sometimes it crashes before...).

The only thing I'm sure about is that it never pass again in my slotted function (called withn a timer and which is working with smaller map).
1
2
3
4
5
6
7
8
void Widget::stepEcosys() {
    if (_ecosys != nullptr) {
        _ecosys->step(true); // sometimes crash happen inside this function
        // sometimes happen between these both functions
        this->update();
        // sometimes get here but never loop again
    }
}


Thank you for help.
Edit: My code is pretty long so I don't know what to post, so don't hesitate to ask to me.
Last edited on Mar 11, 2020 at 8:03am
Mar 11, 2020 at 9:53am
Is it possible that _ecosys can be pointing to just random memory, or to an object that has already been deleted? Do you have a guarantee that it will always either be nullptr, or that the object it points to will never have been destroyed?


_ecosys->step(true); // sometimes crash happen inside this function
Well what code is inside that function? On what line inside that function is the crash?
Last edited on Mar 11, 2020 at 9:54am
Mar 11, 2020 at 10:59am
There's only one instance of Ecosys and no delete of it (I'm sure of that).

When I say the program is crashing inside the step() function, well there's no precise location, that's totally random. Here's the code if it may help you:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
void Ecosys::step(bool debug) {
    if (_plants.size() == 0) return;

    _timeElapsed += _timelapsePerStep;

    // -- perf --
    typedef std::chrono::high_resolution_clock Clock;
    typedef std::chrono::milliseconds milliseconds;
    // --

    doGrowth();
    doReproduce();
    Clock::time_point t0 = Clock::now();
    Clock::time_point t1;
    milliseconds ms;

    std::vector<std::thread> threads;

    std::vector<std::vector<Plant*>> pointerMap;
    for (unsigned int i(0); i < (unsigned) _height; ++i) {
        pointerMap.push_back(std::vector<Plant*>((unsigned) _width, nullptr));
    }
    for (unsigned int i(0); i < _plants.size(); ++i) {
        pointerMap[(unsigned) _plants[i].getPosition().getY()][(unsigned) _plants[i].getPosition().getX()] = &_plants[i];
    }
    std::sort(_plants.begin(), _plants.end(), [](const Plant & a, const Plant & b){return a.getSize() > b.getSize();});

    const int nbCores((int) std::thread::hardware_concurrency());

    for (int i(0); i < nbCores; ++i) {
        int value = (int) (_plants.size() / (unsigned long long) nbCores);
        int end = value * (i + 1);
        if (i >= nbCores - 1) end = (int) _plants.size();
        threads.push_back(std::thread(setConflicts, value * i,
                                      end,
                                      std::ref(pointerMap),
                                      std::ref(_plants),
                                      _width,
                                      _height));
    }

    for (auto & t: threads) t.join();

    // -- perf --
    t1 = Clock::now();
    ms = std::chrono::duration_cast<milliseconds>(t1 - t0);
    // --

    if (debug) std::cout << (int) ms.count() << "ms" << std::endl;

    for (unsigned int i(0); i < _plants.size(); ++i) {
        if (_plants[i].getState() == __DEAD__ || _plants[i].getAge() > _plants[i].getMaxAge() * YEAR_DURATION) {
            _plants.erase(_plants.begin() + i);
            --i;
        }
    }
}
Mar 11, 2020 at 12:57pm
Well, line 24 looks dubious. Next: On line 36 you send the local variable pointerMap as a reference to a thread but it will be invalid as soon as step(...) ends. Line 53 doesn't make it anyway better...
Mar 11, 2020 at 1:08pm
Also, just wanted to say, don't start identifiers or macros with 2 underscores (e.g. __DEAD__) or one underscore followed by a capital letter. They are reserved by the standard.
Mar 11, 2020 at 10:33pm
@coder777
I'm calling a join() for each thread at line 42, so there's no reason the function ends before threads. Or maybe I missunderstood what you wanted to say.

@Ganado
Thank you for the tip, I though underscores where some kind of convention of naming.
Topic archived. No new replies allowed.