Seite 1 von 1

Segfault in Konstruktor von QCoreApplication ?!?

Verfasst: 5. November 2008 10:01
von schulze
Vielleicht mache ich ja auch irgendwas grundsätzlich falsch...

Ich arbeite unter Ubuntu 8.04 Desktop auf einem Notebook IBM R52 an einem Open-Source Projekt "Fingerprint GUI" und benutze Qt4 für die Entwicklung der Benutzeroberfläche. Ziel des Projektes ist es, Login und Athentication über PAM mittels Fingerabdruck-Sensor unter Linux zu ermöglichen. Wesentliche Teile des Projektes funktionieren schon. Man findet das Projekt unter "http://www.pdfserver.net/fingerprint".

Funktionsweise (für diejenigen, die nicht genau wissen, wie PAM funktioniert):
Wenn z.B. ein Login über Fingerprint gewünscht ist, fordert der Gnome Displaymanager "GDM" über die PAM-Library "libpam.so" eine Authentifizierung des Benutzers an. Abhängig von der
PAM-Konfiguration in "/etc/pam.d" ruft libpam.so den betreffenden PAM-Modul (in meinen Falle libpam_fingerprint.so) auf und wartet auf Benutzer-Authentifizierung. Diese libpam_fingerprint.so ist Bestandteil meines Projektes. Sie aktiviert einen QtDialog und fordert den Benutzer auf, sich mit Fingerprint zu identifizieren.

Nun aber zu meinem Problem:
Während verschiedene Anwendungen wie GDM, su, sudo und gksu problemlos funktionieren, kommt es im Falle von gnome-screensaver zu einem "segfault", wenn das QCoreApplication Objekt initialisiert wird (Eintrag in /var/log/syslog):

"gnome-screensav[14369]: segfault at 00000008 eip b68702cf esp bf982130 error 4"


Der Fehler passiert _immer_ in Zeile 457 von qcoreapplication.cpp. Hier ein Auszug:

--------

Code: Alles auswählen

// ### move to QCoreApplicationPrivate constructor?
void QCoreApplication::init()
{
    Q_D(QCoreApplication);

#ifdef Q_OS_UNIX
    setlocale(LC_ALL, "");                // use correct char set mapping
    setlocale(LC_NUMERIC, "C");        // make sprintf()/scanf() work
#endif

#ifdef Q_WS_WIN
    // Get the application name/instance if qWinMain() was not invoked
    set_winapp_name();
#endif

    Q_ASSERT_X(!self, "QCoreApplication", "there should be only one application object");
    QCoreApplication::self = this;

#ifndef QT_NO_THREAD
    QThread::initialize();
#endif

    // use the event dispatcher created by the app programmer (if any)
    if (!QCoreApplicationPrivate::eventDispatcher)
        QCoreApplicationPrivate::eventDispatcher = d->threadData->eventDispatcher;
    // otherwise we create one
    if (!QCoreApplicationPrivate::eventDispatcher)
        d->createEventDispatcher();                 //HIER PASSIERT ES!!!!!!!!!!
    Q_ASSERT(QCoreApplicationPrivate::eventDispatcher != 0);
----------

Ich habe es sowohl mit version 2.22.2 (Ubuntu) als auch 2.20.x (suse) von gnome-screensaver getestet. Auch die Qt versionen 4.3.4-0 (Ubuntu) oder 4.4.3 (aus qt-x11-opensource-src-4.4.3) machen keinen Unterschied.

Um auszuschließen, dass der Fehler durch meine "libpam_fingerprint.so" verursacht wird, habe ich nun eine ganz simple "libpam_dummy.so" erzeugt. Diese zeigt bei Aufruf
einen simplen QDialog und gibt beim Beenden ein PAM_SUCCESS zurück. Die Quellen dafür habe ich als "pam_dummy.tar.gz" hier angehängt. Auch mit diesem PAM-Modul kommt immer der gleiche segfault and der o.g. Stelle in "qcoreapplication.cpp".

Ich weiss mir nun wirklich keinen Rat mehr! Sollte es wirklich ein Bug in Qt sein?? Kann mir vielleicht jemand helfen, das Problem genauer zu untersuchen?

Danke für jeden Hinweis!

W.U.

Verfasst: 6. November 2008 09:54
von schulze
...zu kompliziert für dieses Board??

Verfasst: 6. November 2008 10:07
von macman
Ich würde ehr sagen 'zu speziell'. Deutlich zu sehen an dem 0-mal herunter geladen. Ich nutze nichts von dem was Du aufgelistet hast, also könnte ich es auch nicht nachvollziehen. Schätze mal das geht den meisten so.

Verfasst: 6. November 2008 10:33
von schulze
...die Frage ist, wie ich das Problem lösen kann. Das soll kein Vorwurf an die (nicht antwortenden) Mitglieder dieses Boards sein!

Aber ich befinde mich in einem Dilemma: Es sind immer mindestens drei Applikationen beteiligt: die aufrufende (in diesem Falls gnome-screensaver), die PAM library (libpam.so) in der Mitte und mein PAM-Modul (libpam_dummy.so), der Qt benutzt, welches den Segfault wirft.

Ich weiss nicht, wen ich da fragen soll. Meine Kenntnisse bezüglich debugging sind da am Ende, wo ich herausgefunden habe, an welcher Stelle der Fehler auftritt und ob es unter allen Umständen die selbe Stelle ist.

Einen Bug-Report traue ich mich nicht auszulösen, weil ich gar nicht weiss, wohin ich den senden soll; an das Gnome-Projekt, an das PAM-Projekt oder an das Qt-Projekt. Ich hatte gehofft, hier einen Hinweis zu bekommen, ob ich generell etwas falsch mache. So nach dem Motto "gnome-screensaver verwendet library X und jeder weiss, dass das mit Qt nicht funktionieren kann".

W.U.

Verfasst: 6. November 2008 10:42
von Christian81
Das Modul wird ja nicht direkt aufgerufen sondern von einem anderen Program (wer auch immer, ist egal) - kann es sein dass dort schon eine QApplication läuft? Zwei Instanzen in einem Prozess gehen nämlich nicht.
Irgendwo gabs mal eine Seite die sich mit Q(Core)Application in einer externen Library beschäftigt haben. Ich glaube auch diese Frage kommt ab und zu auf Qt-Interest - dort lohnt es sich ggf. mal nachzufragen.

Verfasst: 6. November 2008 11:00
von schulze
Danke für den Hinweis. Aber den habe ich beachtet. In meiner Original-Library libpam_fingerprint.so gibt es eine Abfrage, die etwa so aussieht:

Code: Alles auswählen

    if(qApp!=NULL){  // If this pointer is not NULL we are called from a QtApplication
        syslog(LOG_DEBUG,"Called from QApplication.");
        calledFromQt=true;
    }

...

                QApplication *app;
                if(calledFromQt){   // We are called from a Qt application; it becomes tricky now.
                    app=qApp;
                }
                else{
                    app=new QApplication(argc,(char**)argv);
                }

...

                    lastResult=app->exec();
...
Allerdings ist im Falle von gnome-screensaver der Pointer "qApp" immer NULL und es weist auch sonst nichts darauf hin, dass gnome-screensaver eine Qt-Applikation ist.

W.U.

Verfasst: 6. November 2008 11:06
von Christian81
Mehr fällt mir leider dazu nicht ein.
Ist d NULL oder crasht es innerhalb von createEventDispatch() ?

Verfasst: 6. November 2008 11:26
von schulze
Nein d ist nicht NULL (wäre viel zu schön gewesen).

Aber "createEventDispatch()" wird nicht mehr aufgerufen (ich habe dort als erste Zeile eine Syslog-Ausgabe eingefügt, die nicht mehr ausgegeben wird).

W.U.

Verfasst: 6. November 2008 11:35
von Christian81
Dann schau mal ob this noch korrekt ist. Mehr weiß ich aber auch nicht mehr :(

Verfasst: 6. November 2008 11:41
von solarix
waere es evt. denkbar, innerhalb der (extern "C"?) Funktion "pam_sm_authenticate" ein komplett unabhaengiges, externes Programm (system()) zu starten? Dann haette man einen sauberen Dialog mit main, einer eindeutigen QApplication usw...

Verfasst: 6. November 2008 11:52
von schulze
Das ist sicher möglich. Ich verstehe aber noch nicht ganz, wozu das führen soll. Meinst Du das jetzt als Lösung für das Problem oder als eine Möglichkeit zum debuggen?

Problematisch ist ja hier, dass der gnome-screensaver gerade den Bildschirm gesperrt hat und das ganze während des "Entsperrens" passiert.

W.U.

Verfasst: 6. November 2008 12:09
von solarix
Als Workaround fuer alle denkbaren Probleme (C/C++-Mix, mehrere oder zum falschen Zeitpunkt erstellte oder falsch erstellte QApplications, fehlende Qt-Environment, Multithreading,.. usw).

Und falls du unbedingt den Dialog direkt in der Callbackfunktion starten moechtest, gaebe dir den Versuch mit dem externen Programm immerhin den Hinweis, ob deine Bedenken ("
Problematisch ist ja hier, dass der gnome-screensaver gerade den Bildschirm gesperrt hat und das ganze während des "Entsperrens" passiert. ") berechtigt sind, oder nicht....

Verfasst: 6. November 2008 12:30
von schulze
OK. Habe ich jetzt wie folgt gemacht:

Code: Alles auswählen

// Call from PAM ---------------------------------------------------------------
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc,const char **argv){
    
    openlog(syslogIdent.data(),LOG_NDELAY|LOG_PID,LOG_AUTH);
    setlogmask(-1);
    syslog(LOG_DEBUG,"started.");
    
//    QApplication app(argc,(char**)argv);
//    syslog(LOG_DEBUG,"QApplication created.");
//    TestDialog test;
//    syslog(LOG_DEBUG,"TestDialog created.");
//    app.exec();
//    syslog(LOG_DEBUG,"QApplication ended.");

    syslog(LOG_DEBUG,"calling fingerprintIdentifier.");
    int rc=system("fingerprintIdentifier");
    syslog(LOG_DEBUG,"fingerprintIdentifier returned %d.",rc);
    
    return PAM_SUCCESS;
}
"fingerprintIdentifier" läuft und wird nach Anwendung eines Fingerprints auch ordnungsgemäß beendet. Danach gibt gnome-screensaver auch den Bildschirm wieder frei (wegen PAM_SUCCESS). Bis dahin ist allerdings der QDialog des "fingerprintIdentifiers" nicht zu sehen, da ja der Bildschirm gesperrt ist (aber natürlich reagiert er auf Fingerprints).

Zur Erklärung: "fingerprintIdentifier" ist eine Qt-Applikation, die auch zu meinem Projekt "Fingerprint GUI" gehört. Sie dient normalerweise dazu, einen Benutzer anhand seines Fingerprints zu identifizieren und ist nicht für "PAM-Zwecke" gedacht.

Aber was habe ich jetzt gewonnen? Das heisst doch nur, dass man aus PAM heraus eine Qt-Anwendung als neuen Prozess starten kann.

W.U.

Verfasst: 6. November 2008 13:22
von solarix
Aber was habe ich jetzt gewonnen?
Wir wissen, dass die Applikation grundsaetzlich funktioniert, aber nicht sichtbar ist.. daher meine Gegenfrage: wenn das externe Programm startet aber nicht sichtbar ist, warum sollten denn ein in der Callback-Funktion erstellter Qt-Dialog sichbar sein? Wie erstellt man überhaupt Dialoge, welche über dem Screensaver erscheinen?

Verfasst: 6. November 2008 13:39
von schulze
...Es geht gar nicht um Sichtbarkeit. Wenn PAM nicht von gnome-screensaver aufgerufen wird, sondern z.B. von GDM (vor dem Login), dann funktionierts ja auch. Es geht hier darum, dass der segfault im Konstruktor von QCoreApplication nur auftritt, wenn PAM vom gnome-screensaver aus aufgerufen wurde.

Das Problem der Sichtbarkeit habe ich in der "richtigen" libpam_fingerprint.so wie folgt gelöst:

Code: Alles auswählen

#define KEEP_ON_TOP \
    raise(); \
    activateWindow();
...

void PamGUI::timerTick(){
//we don't want to lose the keyboard, so we grab it with every timerTick and bring the window on top
    KEEP_ON_TOP
...
}
Der Timer ist auf 1 Sekunde eingestellt. Damit bleibt der Dialog maximal für eine Sekunde unsichtbar. Das funktioniert ja auch problemlos, wenn das ganze nicht gerade von gnome-screensaver initialisiert wurde. Im "dummy"-Modul ("libpam_dummy.so") habe ich ganz bewusst darauf verzichtet um auszuschließen dass das irgendein Problem verursacht. D.h. der Dummy wird nicht sichtbar sein. Das ist aber nicht das Problem. Das Problem besteht darin, dass erst gar kein QApplication Objekt erzeugt wird (wegen des Segfault).

W.U.