Issue when passing a pointer to a SLOT from a SIGNAL with QObject::connect
Dear All,
I am using connect in order to send a SIGNAL with 2 variables towards a SLOT. The connect looks like this:
Code:
const bool connected
= QObject::connect(this,
&iVoiceCom
:: stateCallChangedT,
this,
&iVoiceCom
:: onCallStateChanged, Qt
::QueuedConnection);
qDebug() << "Connection established?" << connected;
In the main I am defining the variables to be passed from
Code:
qRegisterMetaType<pjsua_call_id>("pjsua_call_id");
qRegisterMetaType<pjsip_event*>("pjsip_event");
Then in this function I run the emit with the 2 varialbes, one int and a pointer:
Code:
void iVoiceCom:: on_call_state(pjsua_call_id call_id, pjsip_event *e)
{
//callStateChanged(call_id,e);
emit stateCallChangedT(call_id, e);
}
The SIGNAL is emited OK and the function below is run, but the "e" pointer is passed until a certain point
Code:
e->type OK
e->body.tsx_state.type OK
BUT
Code:
e->body.tsx_state.src.rdata->msg_info.msg; is LOST and I do not understand why, the back trace from gdb:
Program received signal SIGSEGV, Segmentation fault.
0x00000000004226da in iVoiceCom:: onCallStateChanged (this=0x7fffffffc9d0, call_id=0, e=0x7fffc7ffdfe0) at iVoiceCom.cpp:1605
1605 int code = msg->line.status.code;
(gdb) p e->type
$1 = PJSIP_EVENT_TSX_STATE
(gdb) p e->body.tsx_state.type
$2 = PJSIP_EVENT_RX_MSG
(gdb) p e->body.tsx_state.src.rdata->msg_info
$7 = {msg_buf = 0x0, len = 0, msg = 0x0, info = 0x0, cid = 0x0, from = 0x0, to = 0x0, via = 0x0, cseq = 0x0, max_fwd = 0x0, route = 0x0, record_route = 0x0, ctype = 0x0, clen = 0x0, require = 0x0,
supported = 0x0, parse_err = {prev = 0x0, next = 0x0, except_code = 0, line = 0, col = 0, hname = {ptr = 0x0, slen = 0}}}
(gdb)
The slot/function:
Code:
void iVoiceCom:: onCallStateChanged(pjsua_call_id call_id, pjsip_event *e)
{
....
if (e->type == PJSIP_EVENT_TSX_STATE)
{
pjsip_msg *msg;
if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
{
msg = e->body.tsx_state.src.rdata->msg_info.msg;
}
else {
msg = e->body.tsx_state.src.tdata->msg;
}
int code = msg->line.status.code;
...
}
Can you please help me to understand what am I doing wrong.
Thank You!
Teo
Re: Issue when passing a pointer to a SLOT from a SIGNAL with QObject::connect
Why do you use a queued connection? Are you sure the pointer is still valid when the slot is executed? I would guess no.
Re: Issue when passing a pointer to a SLOT from a SIGNAL with QObject::connect
Thank You for your reply Christian!
I have tried with: const bool connected = QObject::connect(this, &iVoiceCom::stateCallChangedT,this, &iVoiceCom::onCallStateChanged, Qt::DirectConnection); and also calling directly the function and I receive:
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 0x0x7fff780008c0. Receiver 'pushButton_call' (of type 'QPushButton') was created in thread 0x0x8cdad0", file /home/teodor/qt5/qtbase/src/corelib/kernel/qcoreapplication.cpp, line 578
I have one more thread that is managed by boost, that I am still trying to understand how to access and send my connection towards it but I have not managed yet.
From this function I am trying to change the GUI button, when I use "ui->pushButton_call->setText(action);" everything works but when I try to run setStyleSheet and change the color I get the error above.
Code:
ui->pushButton_call->setText("End");
ui->pushButton_call->setStyleSheet("color: black;background-color: #c7cece;");
I still do not get the whole picture of the connect and boost, I will read some more this days.
For now I do not know how to check if the pointer is still valid but more important is to figure out how to keep it valid when until the function has finished the execution or add it to the right thread ...
It is strage for me that the e->body.tsx_state.type pointer is OK but the rest (e->body.tsx_state.src.rdata->msg_info.msg) is not valid.
Thank You!
Teo
Re: Issue when passing a pointer to a SLOT from a SIGNAL with QObject::connect
Quote:
For now I do not know how to check if the pointer is still valid
It is good practice to either do a runtime check like this or to add an assert for debugging purposes like this:
Code:
if ( e != nullptr )
Code:
assert( e != nullptr )
This doesn't help if the pointer is non-null but also not valid (in other words, you pass a pointer variable that has not been initialized).
The assert will result in your program stopping at that point when you run it in the debugger. From that point, you can use the debugger to trace back through the call stack to find where things went wrong.
If you don't know how to use a debugger, you have to learn. The dump you get from a SEGFAULT when running a realease mode version of your program is pretty much useless for debugging purposes.
Re: Issue when passing a pointer to a SLOT from a SIGNAL with QObject::connect
Checking for nullptr doesn't help here since the pointer for sure is a dangling pointer due to the QueuedConnection. Either pass the value or don't use a Queued Connection or make sure the pointer is valid until the slot is executed.
Re: Issue when passing a pointer to a SLOT from a SIGNAL with QObject::connect
Quote:
Originally Posted by
teodopjsip_eventr
It is strage for me that the e->body.tsx_state.type pointer is OK but the rest (e->body.tsx_state.src.rdata->msg_info.msg) is not valid.
e points at a pjsip_event object that contains a "body" member structure that contains a "tsx_state" structure.
e->body.tsx_state.type is not a pointer, it is an integer member of the "tsx_state" structure and will have a value.
The "tsx_state" structure contains child "src" structure with a pointer members "rdata" and "tdata" pointing to other structures. Either or both of these pointers can be either null or pointing at random memory at the time of access. You copy the value of the "msg" pointer from either the "rdata" or "tdata" objects (which might just be random memory). This pointer can be either null or pointing at random memory at the time of access. When you dereference that pointer it is not valid.
Given that the slot and signal are from different threads the objects being pointed at can become invalid even if they were valid at the time they were received at the slot.
I suggest that you consider moving this logic from the slot into the routine emitting the signal and then pass the "code" (or whatever else you want from these structures) as the parameters of the signal. If any of those things is a C-string then construct a QString from it and pass that (not the char*).
Re: Issue when passing a pointer to a SLOT from a SIGNAL with QObject::connect
WOW ChrisW67, you kind of nailed it big time. Thank You for making some light into my problem!
You are right and your idea worked, I have moved the logic directly into the function and emit the signal only with the needed parameters, no pointers that can be affected or dangling.
Adding the solution maybe it helps someone else:
Code:
qRegisterMetaType<pjsua_call_id>("pjsua_call_id");
qRegisterMetaType<std::string>("std::string");
qRegisterMetaType<QTextCursor>("QTextCursor");
const bool connected2
= QObject::connect(this,
SIGNAL(signalCallStateB
(std
::string,
QString, pjsua_call_id,
QString)),
this,
SLOT(slotUpdateButtons
(std
::string,
QString, pjsua_call_id,
QString)));
qDebug() << "Connection established?" << connected2;
Code:
void iVoiceCom:: on_call_state(pjsua_call_id call_id, pjsip_event *e)
{
...
if (e->type == PJSIP_EVENT_TSX_STATE)
{
pjsip_msg *msg;
if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
{
msg = e->body.tsx_state.src.rdata->msg_info.msg;
}
else {
msg = e->body.tsx_state.src.tdata->msg;
}
int code = msg->line.status.code;
....
emit signalCallStateB(extNumber,"End", call_id, "color: black;background-color: #4287f5;");
}
and in the slot I just update the button with the parameters:
Code:
void iVoiceCom
::slotUpdateButtons(std
::string extNumber,
QString action, pjsua_call_id call_id,
QString style
) {
....
ui->pushButton_call->setText(action);
ui->pushButton_call->setStyleSheet(style);
...
}
Thank You ALL for your help!
I had this problem for a week now and it was great to have your help! I still have a lot to learn ...