Cryptic malloc crash
-
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 whatmalloc_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.
-
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 whatmalloc_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.
-
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 whatmalloc_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.
-
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 achar*
as data and anint
as size.I think my issue was that I was calling
reserve
on the QByteArray inmsgStart
and notresize
. When I change it toresize
this problem stops happening. -
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 achar*
as data and anint
as size.I think my issue was that I was calling
reserve
on the QByteArray inmsgStart
and notresize
. When I change it toresize
this problem stops happening.@Jackmill
reserve
vsresize
isn't the root cause here; thoughresize
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 frombuffer.data()
is dangling. Assumingosc::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. -
@Jackmill
reserve
vsresize
isn't the root cause here; thoughresize
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 frombuffer.data()
is dangling. Assumingosc::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.@IgKh said in Cryptic malloc crash:
@Jackmill
reserve
vsresize
isn't the root cause here; thoughresize
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"
-