Bug 209544 - Konsole crashes after resume from suspend to RAM [LinuxProcessInfo::readProcInfo , UnixProcessInfo::readProcessInfo, Session::updateForegroundProcessInfo]
Summary: Konsole crashes after resume from suspend to RAM [LinuxProcessInfo::readProcI...
Status: RESOLVED FIXED
Alias: None
Product: konsole
Classification: Applications
Component: general (show other bugs)
Version: unspecified
Platform: Unlisted Binaries Linux
: NOR crash
Target Milestone: ---
Assignee: Konsole Developer
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-10-05 18:03 UTC by Török Edwin
Modified: 2009-10-11 01:16 UTC (History)
1 user (show)

See Also:
Latest Commit:
Version Fixed In:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Török Edwin 2009-10-05 18:03:20 UTC
Application that crashed: konsole
Version of the application: 2.3
KDE Version: 4.3.1 (KDE 4.3.1)
Qt Version: 4.5.2
Operating System: Linux 2.6.31 x86_64
Distribution: Debian GNU/Linux unstable (sid)

What I was doing when the application crashed:
I had konsole open with a few tabs, as usual.
Then I suspended the system by using sudo s2ram -f. I've done this many times, and nothing crashed upon resume.
This time though konsole has crashed after resuming from s2ram. I haven't upgraded the KDE packages lately, so this must be somehow related to what apps I had open in konsole.
Since konsole crashed I can't tell exactly what they were, but here's an approximate list:
- some vim processes in background
- mplayer playing a song over the network
- maybe a forgotten cgdb process
- icedove in the background

This happened on x86-64 system, with kernel 2.6.31, libc 2.9.


 -- Backtrace:
Application: Konsole (kdeinit4), signal: Segmentation fault
[KCrash Handler]
#5  0x000000341987f679 in LinuxProcessInfo::readProcInfo(int) () from /usr/lib/libkonsoleprivate.so
#6  0x000000341987b9a7 in Konsole::UnixProcessInfo::readProcessInfo (this=<value optimized out>, pid=<value optimized out>, enableEnvironmentRead=<value optimized out>)
    at ../../../../apps/konsole/src/ProcessInfo.cpp:336
#7  0x000000341988ef5e in Konsole::Session::updateForegroundProcessInfo (this=<value optimized out>) at ../../../../apps/konsole/src/Session.cpp:839
#8  0x000000341988efa9 in Konsole::Session::isForegroundProcessActive (this=<value optimized out>) at ../../../../apps/konsole/src/Session.cpp:1180
#9  0x000000341988f019 in Konsole::Session::getProcessInfo (this=<value optimized out>) at ../../../../apps/konsole/src/Session.cpp:802
#10 0x00000034198909b2 in Konsole::Session::updateWorkingDirectory (this=<value optimized out>) at ../../../../apps/konsole/src/Session.cpp:231
#11 0x0000003419891303 in Konsole::Session::getDynamicTitle (this=<value optimized out>) at ../../../../apps/konsole/src/Session.cpp:849
#12 0x00000034198969d1 in Konsole::SessionController::snapshot (this=<value optimized out>) at ../../../../apps/konsole/src/SessionController.cpp:206
#13 0x000000341989dc3d in Konsole::SessionController::qt_metacall (this=<value optimized out>, _c=<value optimized out>, _id=<value optimized out>, _a=<value optimized out>)
    at ./SessionController.moc:170
#14 0x0000003418567682 in QMetaObject::activate (sender=<value optimized out>, from_signal_index=<value optimized out>, to_signal_index=<value optimized out>, argv=<value optimized out>)
    at kernel/qobject.cpp:3112
#15 0x0000003418561bf3 in QObject::event (this=<value optimized out>, e=<value optimized out>) at kernel/qobject.cpp:1074
#16 0x0000003418bd780d in QApplicationPrivate::notify_helper (this=<value optimized out>, receiver=<value optimized out>, e=<value optimized out>) at kernel/qapplication.cpp:4056
#17 0x0000003418bdf86a in QApplication::notify (this=<value optimized out>, receiver=<value optimized out>, e=<value optimized out>) at kernel/qapplication.cpp:4021
#18 0x000000341de2443b in KApplication::notify (this=<value optimized out>, receiver=<value optimized out>, event=<value optimized out>) at ../../kdeui/kernel/kapplication.cpp:302
#19 0x000000341855251c in QCoreApplication::notifyInternal (this=<value optimized out>, receiver=<value optimized out>, event=<value optimized out>) at kernel/qcoreapplication.cpp:610
#20 0x000000341857e826 in QCoreApplication::sendEvent (this=<value optimized out>) at ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:213
#21 QTimerInfoList::activateTimers (this=<value optimized out>) at kernel/qeventdispatcher_unix.cpp:572
#22 0x000000341857ac9d in timerSourceDispatch (source=<value optimized out>) at kernel/qeventdispatcher_glib.cpp:165
#23 0x0000003414a3986a in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0
#24 0x0000003414a3ceb8 in ?? () from /usr/lib/libglib-2.0.so.0
#25 0x0000003414a3d06c in g_main_context_iteration () from /usr/lib/libglib-2.0.so.0
#26 0x000000341857abff in QEventDispatcherGlib::processEvents (this=<value optimized out>, flags=<value optimized out>) at kernel/qeventdispatcher_glib.cpp:327
#27 0x0000003418c6e64f in QGuiEventDispatcherGlib::processEvents (this=<value optimized out>, flags=<value optimized out>) at kernel/qguieventdispatcher_glib.cpp:202
#28 0x0000003418550de2 in QEventLoop::processEvents (this=<value optimized out>, flags=<value optimized out>) at kernel/qeventloop.cpp:149
#29 0x00000034185511b4 in QEventLoop::exec (this=<value optimized out>, flags=<value optimized out>) at kernel/qeventloop.cpp:201
#30 0x0000003418553424 in QCoreApplication::exec () at kernel/qcoreapplication.cpp:888
#31 0x000000341cc101fe in kdemain (argc=<value optimized out>, argv=<value optimized out>) at ../../../../apps/konsole/src/main.cpp:104
#32 0x0000000000407264 in launch (argc=5, _name=0x19a71b8 "konsole", args=<value optimized out>, cwd=0x0, envc=0, envs=0x19a7221 "", reset_env=false, tty=0x0, avoid_loops=false, 
    startup_id_str=0x40a0ff "0") at ../../kinit/kinit.cpp:677
#33 0x0000000000407a28 in handle_launcher_request (sock=7, who=<value optimized out>) at ../../kinit/kinit.cpp:1169
#34 0x0000000000407fae in handle_requests (waitForPid=0) at ../../kinit/kinit.cpp:1362
#35 0x000000000040863b in main (argc=2, argv=0x7fffe142c1c8, envp=0x7fffe142c1e0) at ../../kinit/kinit.cpp:1793

Reported using DrKonqi
Comment 1 Dario Andres 2009-10-06 01:12:56 UTC
The backtrace looks related to bug 201119 / bug 195265.
Thanks
Comment 2 Török Edwin 2009-10-06 09:00:38 UTC
(In reply to comment #1)
> The backtrace looks related to bug 201119 / bug 195265.
> Thanks

I can't find a way to reproduce this, but I looked at the source code.
There is at least one race condition I spotted:


void UnixProcessInfo::readUserName()
{
    bool ok = false;
    int uid = userId(&ok);
    if (!ok) return;

    struct passwd *pwuser = getpwuid(uid);
    if (pwuser)
        setUserName(QString(pwuser->pw_name));
    else
        setUserName(QString());
}

getpwuid is not thread-safe, according to the manpage "The return value may point to a static area, and may be overwritten by subsequent calls to  getpwent(3),  getpwnam(),  or  getp‐wuid()."

So if there are multiple tabs in konsole open, each of them looking up the username at the same time, they'll access the same buffer of getpwuid(),
and one of the threads may read the pw_name field while being updated, so it could not contain proper NULL terminators, etc.

Another possible problem is that the process might die while reading it status info:
        if ( statusInfo.open(QIODevice::ReadOnly) )
        {
            QTextStream stream(&statusInfo);
            QString data = stream.readAll();
            int uidIndex = data.indexOf("Uid:");
            QString uidLine = data.mid(uidIndex + 4, 16); // grab some data
            QString uidString = uidLine.split('\t', QString::SkipEmptyParts)[0];

There is no check for uidIndex there, if the process happens to die, after you opened the status file, and after a process dies there's no guarantee that status contains correct info, I think the file is just truncated:
fs/proc/base.c:proc_single_show:
	task = get_pid_task(pid, PIDTYPE_PID);
	if (!task)
		return -ESRCH;

and in fs/seq_file.c:seq_read:
if (err) {
			/* With prejudice... */
			m->read_pos = 0;
			m->version = 0;
			m->index = 0;
			m->count = 0;
			goto Done;
}
....
while(1) {
     ....
     err = m->op->show(m, p);
     if (err < 0)
	break;
     ....
}
m->op->stop(m, p);
m->count = 0;
goto Done;

This suggests that the file is truncated during read() if the process dies during that (or between the time open is called and read is called).

To sum up: use thread-safe functions instead of non-threadsafe ones (getpwuid_r instead of getpwuid), and don't assume any file you read from /proc/<pid>/ is exactly the format you expect it to be, since it can get truncated.
Comment 3 Kurt Hindenburg 2009-10-06 17:17:57 UTC
Thanks for the detailed info - I've already commited a fix for reading the format of the status file.  I'm working on using getpwuid_r
Comment 4 Kurt Hindenburg 2009-10-11 01:16:51 UTC
SVN commit 1033757 by hindenburg:

Fix issues with reading /proc/pid/status and use thread safe getpwuid_r.

Backport - already in trunk

BUG: 209544



 M  +35 -7     ProcessInfo.cpp  


WebSVN link: http://websvn.kde.org/?view=rev&revision=1033757