Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Bug or Feature: Dereferencing QList::begin() segfaults on an empty QList using Qt 6
QtWS25 Last Chance

Bug or Feature: Dereferencing QList::begin() segfaults on an empty QList using Qt 6

Scheduled Pinned Locked Moved Solved General and Desktop
10 Posts 4 Posters 408 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • L Offline
    L Offline
    l3u_
    wrote on 29 Jun 2024, 10:27 last edited by
    #1

    Hi all,

    When using iterators on an empty list like this:

    QList<int> list;
    qDebug() << "begin:" << *list.begin();
    qDebug() << "end:" << *list.end();
    qDebug() << "max_element:" << *std::max_element(list.begin(), list.end());
    

    I get the following compiling that code using Qt 5:

    begin: 0
    end: 0
    max_element: 0
    

    However if I do the same using Qt 6, the above code segfaults when trying to dereference list.begin(). Which is somehow understandable, as there's nothing the iterator could point to …

    So … is this an intentional change in Qt 6?

    Thanks for all clarification!

    C 1 Reply Last reply 29 Jun 2024, 10:38
    0
    • L l3u_
      29 Jun 2024, 10:27

      Hi all,

      When using iterators on an empty list like this:

      QList<int> list;
      qDebug() << "begin:" << *list.begin();
      qDebug() << "end:" << *list.end();
      qDebug() << "max_element:" << *std::max_element(list.begin(), list.end());
      

      I get the following compiling that code using Qt 5:

      begin: 0
      end: 0
      max_element: 0
      

      However if I do the same using Qt 6, the above code segfaults when trying to dereference list.begin(). Which is somehow understandable, as there's nothing the iterator could point to …

      So … is this an intentional change in Qt 6?

      Thanks for all clarification!

      C Offline
      C Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on 29 Jun 2024, 10:38 last edited by Christian Ehrlicher
      #2

      @l3u_ said in Bug or Feature: Dereferencing QList::begin() segfaults on an empty QList using Qt 6:

      So … is this an intentional change in Qt 6?

      If *list.begin() really did not segfault on Qt5 (which I doubt, maybe it worked in debug mode) this was a bug - the iterator points to nowhere so you can't dereference it. Your usage is simply wrong.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      1 Reply Last reply
      2
      • L Offline
        L Offline
        l3u_
        wrote on 29 Jun 2024, 10:47 last edited by l3u_
        #3

        Looking at the code, I must admit that I wonder why it worked at all, but it did – not only in debug mode, but also when compiling a release build. I simply didn't notice this until my Qt 6 build crashed here (which is understandable).

        So that's actually a Qt 5 bug that has been fixed in Qt 6. Thanks for the confirmation.

        J 1 Reply Last reply 29 Jun 2024, 11:08
        0
        • L l3u_ has marked this topic as solved on 29 Jun 2024, 10:48
        • L l3u_
          29 Jun 2024, 10:47

          Looking at the code, I must admit that I wonder why it worked at all, but it did – not only in debug mode, but also when compiling a release build. I simply didn't notice this until my Qt 6 build crashed here (which is understandable).

          So that's actually a Qt 5 bug that has been fixed in Qt 6. Thanks for the confirmation.

          J Offline
          J Offline
          JonB
          wrote on 29 Jun 2024, 11:08 last edited by JonB
          #4

          @l3u_ said in Bug or Feature: Dereferencing QList::begin() segfaults on an empty QList using Qt 6:

          So that's actually a Qt 5 bug

          For the record, it is/was not a "bug". As @Christian-Ehrlicher says, you cannot dereference an iterator not pointing to a list element (e.g. from begin() on an empty list). I haven't looked it up, but I imagine that would be classed as "Undefined Behaviour". Which means it can result in anything happening, or not happening, no more and no less. If you say it "worked" in Qt5 that behaviour would not be a "bug". A bug would be where defined behaviour failed to work correctly. Undefined behaviour might crash or might work. Nothing wrong with it apparently working in Qt5. Just a "shame" for you because you didn't pick the UB up, but not a bug!

          1 Reply Last reply
          0
          • L Offline
            L Offline
            l3u_
            wrote on 29 Jun 2024, 11:50 last edited by l3u_
            #5

            It actually was defined behavior, because *std::max_element(list.begin(), list.end()) always returned 0 for an empty QList<int>, in each and every case the program ran (and it ran lots of times).

            If it returned some random value like you get when you use an unitialized int or such (which would be "undefined behavior"), the following for loop (that used the return value as a <= condition) would have been executed on some random positive value, and the code within would have crashed.

            And that's why I never found the programming mistake: I tested the code on a non-empty QList<int>, but I always got 0 for an empty one later on. Well, whatever. I now fixed it.

            Maybe this has something to do with a QList being an actual QList in Qt 5 (maybe returning the default value, which would be 0 for a QList<int> for the begin() and end() of an empty list?!), and with Qt 6, a QList is actually a QVector, behaving differently.

            J 1 Reply Last reply 29 Jun 2024, 12:08
            0
            • L Offline
              L Offline
              l3u_
              wrote on 29 Jun 2024, 12:02 last edited by
              #6

              I just tried it with

              QList<int> list;
              QVector<int> vector;
              qDebug() << *list.begin();
              qDebug() << *vector.begin();
              

              You always get 0 for both the QList and the QVector when compiled with Qt 5. And always a crash with Qt 6.

              1 Reply Last reply
              0
              • L l3u_
                29 Jun 2024, 11:50

                It actually was defined behavior, because *std::max_element(list.begin(), list.end()) always returned 0 for an empty QList<int>, in each and every case the program ran (and it ran lots of times).

                If it returned some random value like you get when you use an unitialized int or such (which would be "undefined behavior"), the following for loop (that used the return value as a <= condition) would have been executed on some random positive value, and the code within would have crashed.

                And that's why I never found the programming mistake: I tested the code on a non-empty QList<int>, but I always got 0 for an empty one later on. Well, whatever. I now fixed it.

                Maybe this has something to do with a QList being an actual QList in Qt 5 (maybe returning the default value, which would be 0 for a QList<int> for the begin() and end() of an empty list?!), and with Qt 6, a QList is actually a QVector, behaving differently.

                J Offline
                J Offline
                JonB
                wrote on 29 Jun 2024, 12:08 last edited by JonB
                #7

                @l3u_ said in Bug or Feature: Dereferencing QList::begin() segfaults on an empty QList using Qt 6:

                It actually was defined behavior

                Could you state what the defined behaviour is/was on dereferencing the begin() of an empty list/an iterator not pointing to a valid element? I shall be interested to learn this, as you say at Qt6 at least it seg faults, which is a (possible) symptom of undefined behaviour.

                I tried to point it that just because some compiler/code happens to have produced repeatable or sensible behaviour on a C++ undefined behaviour does not make it C++ defined behaviour. As witness that it no longer produces the same result now. You can test it as many times as you like and it can perhaps produce the same result every time, doesn't make it not be undefined behaviour.

                I don't understand your point at all. Here is the definition of C++ undefined behaviour. I would suggest this one is similar to

                Some examples of undefined behavior are [...], memory accesses outside of array bounds, [...] null pointer dereference,

                *std::max_element(list.begin(), list.end())

                Per the spec std::max_element() return last on empty list, i.e. your list.end(). So this is the same as *last.end(). Which is UB.

                You always get 0 for both the QList and the QVector when compiled with Qt 5. And always a crash with Qt 6.

                And what is your point? It's undefined behaviour. I really don't understand what you are getting at that it happens to work some way under Qt6 and another way under Qt5. That's just the sort of thing that undefined behaviour does :) Though I respect if you are just observing what used to happen versus what happens now, as an observation this is fine. Just that it doesn't make it a "bug" under Qt5. I have said my piece.

                1 Reply Last reply
                0
                • L Offline
                  L Offline
                  l3u_
                  wrote on 29 Jun 2024, 12:37 last edited by
                  #8

                  I'm neither a professional programmer, nor a studied computer scientist. I also already stated I'm surprised why the code worked at all, because It's totally clear to me that dereferencing an iterator pointing to nowhere should segfault, and never return a value – because there's no value to return. That's what Qt 6 does.

                  I thus concluded that returning a valid value (and always the same) for something that's not there instead of crashing could be considered a bug (at least to some clueless outsider).

                  Can we simply agree that I wrote shitty code and you're right?

                  J P 2 Replies Last reply 29 Jun 2024, 12:50
                  0
                  • L l3u_
                    29 Jun 2024, 12:37

                    I'm neither a professional programmer, nor a studied computer scientist. I also already stated I'm surprised why the code worked at all, because It's totally clear to me that dereferencing an iterator pointing to nowhere should segfault, and never return a value – because there's no value to return. That's what Qt 6 does.

                    I thus concluded that returning a valid value (and always the same) for something that's not there instead of crashing could be considered a bug (at least to some clueless outsider).

                    Can we simply agree that I wrote shitty code and you're right?

                    J Offline
                    J Offline
                    JonB
                    wrote on 29 Jun 2024, 12:50 last edited by JonB
                    #9

                    @l3u_
                    Fine, and I did not intend to be "on your case". It's just that in C++ "Undefined Behaviour" has a particular meaning. It wasn't a "bug" that Qt5 did what it did, UB does not mean that it must seg fault or similar, it means it can do anything it wants. If you expect it to error when code is wrong/UB you can be lured into a false sense of security, which later comes to bite you back when behaviour changes, exactly as you have found here with Qt5/6. C++ is like that. Other languages might guarantee to give you an error in a similar case, but not C++. It is probably "coincidence" that Qt5 gave you 0 and Qt6 gives a seg fault, rather than it being "deliberate/planned" for Qt6.

                    We are good :)

                    1 Reply Last reply
                    1
                    • L l3u_
                      29 Jun 2024, 12:37

                      I'm neither a professional programmer, nor a studied computer scientist. I also already stated I'm surprised why the code worked at all, because It's totally clear to me that dereferencing an iterator pointing to nowhere should segfault, and never return a value – because there's no value to return. That's what Qt 6 does.

                      I thus concluded that returning a valid value (and always the same) for something that's not there instead of crashing could be considered a bug (at least to some clueless outsider).

                      Can we simply agree that I wrote shitty code and you're right?

                      P Offline
                      P Offline
                      Pl45m4
                      wrote on 29 Jun 2024, 13:15 last edited by
                      #10

                      @l3u_

                      Undefined Behavior can also mean that code which "shouldn't work", does 7/10 times what your actual intention was (even though the code is wrong) and crashes 3/10 times.
                      This still doesn't make the code correct, even if some resulting behavior leads to crashing your program while the other "seem" to work.


                      If debugging is the process of removing software bugs, then programming must be the process of putting them in.

                      ~E. W. Dijkstra

                      1 Reply Last reply
                      0

                      5/10

                      29 Jun 2024, 11:50

                      • Login

                      • Login or register to search.
                      5 out of 10
                      • First post
                        5/10
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved