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. Cryptic malloc crash
Forum Updated to NodeBB v4.3 + New Features

Cryptic malloc crash

Scheduled Pinned Locked Moved Solved General and Desktop
7 Posts 5 Posters 122 Views 2 Watching
  • 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.
  • J Online
    J Online
    Jackmill
    wrote last edited by
    #1

    I have a basic QAction set up as a sort of test action:

    actions_.network_ping_ = new QAction(tr("Ping"), this);
    	connect(actions_.network_ping_, &QAction::triggered,
    		this, [this] {
    			osc_service_->send(EosOscMessage::ping());
    		});
    

    Whenever I trigger this action, it works as expected, and does exactly as prescribed, but then my program crashes with an error that I don't know what to do with:

    PaletteRepo(74405,0x16d1ab000) malloc: Corruption of free object 0x14402bb90: msizes 25903/0 disagree
    PaletteRepo(74405,0x16d1ab000) malloc: *** set a breakpoint in malloc_error_break to debug
    

    This still happens if I rewrite that lambda in the connect call into a slot.

    If I set a breakpoint and step through, it takes me to qobjectdefs_impl.h, specifically line 116:

    template <typename, typename, typename, typename> struct FunctorCall;
        template <size_t... II, typename... SignalArgs, typename R, typename Function>
    struct FunctorCall<std::index_sequence<II...>, List<SignalArgs...>, R, Function> : FunctorCallBase
        {
            static void call(Function &f, void **arg)
            {
                call_internal<R>(arg, [&] {
                    return f((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...); // < This line
                });
            }
        };
    

    I'm not super familiar with malloc so I don't know what malloc_error_break is or how to set a breakpoint there as the error suggests.

    Does anybody have any guidance here?

    This is in CLion on macOS Sequoia.

    Pl45m4P JonBJ 2 Replies Last reply
    0
    • J Jackmill

      I have a basic QAction set up as a sort of test action:

      actions_.network_ping_ = new QAction(tr("Ping"), this);
      	connect(actions_.network_ping_, &QAction::triggered,
      		this, [this] {
      			osc_service_->send(EosOscMessage::ping());
      		});
      

      Whenever I trigger this action, it works as expected, and does exactly as prescribed, but then my program crashes with an error that I don't know what to do with:

      PaletteRepo(74405,0x16d1ab000) malloc: Corruption of free object 0x14402bb90: msizes 25903/0 disagree
      PaletteRepo(74405,0x16d1ab000) malloc: *** set a breakpoint in malloc_error_break to debug
      

      This still happens if I rewrite that lambda in the connect call into a slot.

      If I set a breakpoint and step through, it takes me to qobjectdefs_impl.h, specifically line 116:

      template <typename, typename, typename, typename> struct FunctorCall;
          template <size_t... II, typename... SignalArgs, typename R, typename Function>
      struct FunctorCall<std::index_sequence<II...>, List<SignalArgs...>, R, Function> : FunctorCallBase
          {
              static void call(Function &f, void **arg)
              {
                  call_internal<R>(arg, [&] {
                      return f((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...); // < This line
                  });
              }
          };
      

      I'm not super familiar with malloc so I don't know what malloc_error_break is or how to set a breakpoint there as the error suggests.

      Does anybody have any guidance here?

      This is in CLion on macOS Sequoia.

      Pl45m4P Offline
      Pl45m4P Offline
      Pl45m4
      wrote last edited by
      #2

      @Jackmill

      What type is actions_.network_ping?
      And does it also crash when you remove the 3rd Party function from your lambda/slot?


      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
      1
      • J Jackmill

        I have a basic QAction set up as a sort of test action:

        actions_.network_ping_ = new QAction(tr("Ping"), this);
        	connect(actions_.network_ping_, &QAction::triggered,
        		this, [this] {
        			osc_service_->send(EosOscMessage::ping());
        		});
        

        Whenever I trigger this action, it works as expected, and does exactly as prescribed, but then my program crashes with an error that I don't know what to do with:

        PaletteRepo(74405,0x16d1ab000) malloc: Corruption of free object 0x14402bb90: msizes 25903/0 disagree
        PaletteRepo(74405,0x16d1ab000) malloc: *** set a breakpoint in malloc_error_break to debug
        

        This still happens if I rewrite that lambda in the connect call into a slot.

        If I set a breakpoint and step through, it takes me to qobjectdefs_impl.h, specifically line 116:

        template <typename, typename, typename, typename> struct FunctorCall;
            template <size_t... II, typename... SignalArgs, typename R, typename Function>
        struct FunctorCall<std::index_sequence<II...>, List<SignalArgs...>, R, Function> : FunctorCallBase
            {
                static void call(Function &f, void **arg)
                {
                    call_internal<R>(arg, [&] {
                        return f((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...); // < This line
                    });
                }
            };
        

        I'm not super familiar with malloc so I don't know what malloc_error_break is or how to set a breakpoint there as the error suggests.

        Does anybody have any guidance here?

        This is in CLion on macOS Sequoia.

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote last edited by
        #3

        @Jackmill
        As @Pl45m4 has written.
        Do you mean it crashes after the connect() call, or do you mean it crashes after the first time the signal is actually emitted and the slot/lambda is called?
        Make the body of the slot/lambda just do a qDebug() << "Hello world"; and not call anything else.

        1 Reply Last reply
        0
        • J Online
          J Online
          Jackmill
          wrote last edited by Jackmill
          #4

          I think I've figured out my issue, but maybe you knowledgeable folks can confirm:

          That lambda/slot was calling some static functions from another class:

          void MainWindow::s_oscSendPing() const {
          	osc_service_->sendMessage(EosOscMessage::ping());
          }
          

          --

          class EosOscMessage {
          public:
          	static osc::OutboundPacketStream ping() {
          		return msgStart() << osc::BeginMessage("/eos/ping") << osc::EndMessage;
          	}
          
          private:
          	static osc::OutboundPacketStream msgStart() {
          		QByteArray buffer;
          		buffer.reserve(OscService::k_max_len);
          
          		return {buffer.data(), OscService::k_max_len};
          	}
          

          };

          Those stream operators and osc namespace are from an external library that operate on objects take a char* as data and an int as size.

          I think my issue was that I was calling reserve on the QByteArray in msgStart and not resize. When I change it to resize this problem stops happening.

          I 1 Reply Last reply
          0
          • J Jackmill

            I think I've figured out my issue, but maybe you knowledgeable folks can confirm:

            That lambda/slot was calling some static functions from another class:

            void MainWindow::s_oscSendPing() const {
            	osc_service_->sendMessage(EosOscMessage::ping());
            }
            

            --

            class EosOscMessage {
            public:
            	static osc::OutboundPacketStream ping() {
            		return msgStart() << osc::BeginMessage("/eos/ping") << osc::EndMessage;
            	}
            
            private:
            	static osc::OutboundPacketStream msgStart() {
            		QByteArray buffer;
            		buffer.reserve(OscService::k_max_len);
            
            		return {buffer.data(), OscService::k_max_len};
            	}
            

            };

            Those stream operators and osc namespace are from an external library that operate on objects take a char* as data and an int as size.

            I think my issue was that I was calling reserve on the QByteArray in msgStart and not resize. When I change it to resize this problem stops happening.

            I Offline
            I Offline
            IgKh
            wrote last edited by IgKh
            #5

            @Jackmill reserve vs resize isn't the root cause here; though resize is the correct method to use.

            The problem is that by the time msgStart returns, buffer (which is local) is destroyed and the pointer taken from buffer.data() is dangling. Assuming osc::OutboundPacketStream holds on to that pointer (otherwise the method is pretty pointless), it will still crash sooner or later.

            In this case you need to make sure that the buffer lives long enough. Check the library documentation, to see if the OutboundPacketStream can be used in a mode which owns its' buffer.

            jeremy_kJ 1 Reply Last reply
            3
            • I IgKh

              @Jackmill reserve vs resize isn't the root cause here; though resize is the correct method to use.

              The problem is that by the time msgStart returns, buffer (which is local) is destroyed and the pointer taken from buffer.data() is dangling. Assuming osc::OutboundPacketStream holds on to that pointer (otherwise the method is pretty pointless), it will still crash sooner or later.

              In this case you need to make sure that the buffer lives long enough. Check the library documentation, to see if the OutboundPacketStream can be used in a mode which owns its' buffer.

              jeremy_kJ Offline
              jeremy_kJ Offline
              jeremy_k
              wrote last edited by jeremy_k
              #6

              @IgKh said in Cryptic malloc crash:

              @Jackmill reserve vs resize isn't the root cause here; though resize is the correct method to use.

              The problem is that by the time msgStart returns, buffer (which is local) is destroyed and the pointer taken from buffer.data() is dangling.

              Correction: msgStart() returns the pointer returned by QByteArray::data(). If it returned buffer, the lifetime of the object would have been extended to the end of EosOscMessage::osc::OutboundPacketStream().

              #include <QByteArray>
              #include <QString>
              #include <QDebug>
              
              struct Array : public QByteArray {
                  QString m_tag;
                  Array(QString tag) : m_tag(tag) { qDebug() << Q_FUNC_INFO << tag; }
                  ~Array() { qDebug() << Q_FUNC_INFO << m_tag; }
              };
              
              Array returnArray()
              {
                  Array a("returnArray");
                  return a;
              }
              
              char * returnData() {
                  Array a("returnData");
                  return a.data();
              }
              
              int main(int argc, char *argv[])
              {
                  qDebug() << "returnArray()";
                  auto array = returnArray();
                  qDebug() << "/returnArray()";
                  qDebug() << "returnData()";
                  auto data = returnData();
                  qDebug() << "returnData()";
              }
              

              Output:

              returnArray()
              Array::Array(QString) "returnArray"
              /returnArray()
              returnData()
              Array::Array(QString) "returnData"
              Array::~Array() "returnData"
              returnData()
              Array::~Array() "returnArray"
              

              Asking a question about code? http://eel.is/iso-c++/testcase/

              1 Reply Last reply
              0
              • J Online
                J Online
                Jackmill
                wrote last edited by
                #7

                Okay; so I have to find a way to make sure that QByteArray persists through the entirety of the call to write in the socket it eventually gets passed to.

                Thanks all!

                1 Reply Last reply
                0
                • J Jackmill has marked this topic as solved

                • Login

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