Bug 345765 - [OS X] okular crashing opening PDF from URL
Summary: [OS X] okular crashing opening PDF from URL
Status: RESOLVED FIXED
Alias: None
Product: okular
Classification: Applications
Component: general (show other bugs)
Version: 0.20.3
Platform: Compiled Sources macOS
: NOR crash
Target Milestone: ---
Assignee: Okular developers
URL:
Keywords: drkonqi
Depends on:
Blocks:
 
Reported: 2015-04-01 16:58 UTC by RJVB
Modified: 2015-04-13 23:39 UTC (History)
3 users (show)

See Also:
Latest Commit:
Version Fixed In:


Attachments
example.cpp (345 bytes, text/x-c++src)
2015-04-10 16:13 UTC, Albert Astals Cid
Details
After asking around, Qt's Thiago Macieira provided the answer: all of Okular::Part's parent classes weren't exported, in particular Okular::VIewerInterface wasn't. The attached patch corrects that. (938 bytes, patch)
2015-04-11 20:22 UTC, RJVB
Details

Note You need to log in before you can comment on or make changes to this bug.
Description RJVB 2015-04-01 16:58:35 UTC
Application: okular (0.20.3)
KDE Platform Version: 4.14.5 (Compiled from sources)
Qt Version: 4.8.6
Operating System: Darwin 13.4.0 x86_64
Distribution (Platform): MacPorts Packages

-- Information about the crash:
- What I was doing when the application crashed:

I clicked on a link to download a PDF, in Konqueror. Using "Save As" that link proposed a filename ending in .htm, though its contents are valid PDF. Using "Open With Okular" resulted in this crash.

-- Backtrace:
Application: Okular (okular), signal: Segmentation fault: 11
(lldb) process attach --pid 50297
Process 50297 stopped
Executable module set to "/Applications/MacPorts/KDE4/okular.app/Contents/MacOS/okular".
Architecture set to: x86_64-apple-macosx.
(lldb) set set term-width 200
(lldb) thread info
thread #1: tid = 0x1f8ef33, 0x00007fff869d4e20 libsystem_kernel.dylib`__wait4 + 8, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP

(lldb) bt all
* thread #1: tid = 0x1f8ef33, 0x00007fff869d4e20 libsystem_kernel.dylib`__wait4 + 8, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  * frame #0: 0x00007fff869d4e20 libsystem_kernel.dylib`__wait4 + 8
    frame #1: 0x00000001043c9aae libkdeui.5.dylib`KCrash::startProcess(int, char const**, bool) [inlined] startProcessInternal(argc=<unavailable>, directly=<unavailable>) + 265 at kcrash.cpp:556
    frame #2: 0x00000001043c99a5 libkdeui.5.dylib`KCrash::startProcess(argc=<unavailable>, argv=<unavailable>, waitAndExit=<unavailable>) + 21 at kcrash.cpp:538
    frame #3: 0x00000001043c8bd9 libkdeui.5.dylib`KCrash::defaultCrashHandler(sig=<unavailable>) + 1209 at kcrash.cpp:441
    frame #4: 0x00007fff8c1375aa libsystem_platform.dylib`_sigtramp + 26
    frame #5: 0x00000001038dea41 okular`Shell::openDocument(QString const&, QString const&) + 129
    frame #6: 0x00000001038dae33 okular`Okular::main(QStringList const&, QString const&) + 5523
    frame #7: 0x00000001038d8462 okular`main + 1666
    frame #8: 0x00007fff9158f5fd libdyld.dylib`start + 1
    frame #9: 0x00007fff9158f5fd libdyld.dylib`start + 1

  thread #2: tid = 0x1f8ef37, 0x00007fff869d5662 libsystem_kernel.dylib`kevent64 + 10, queue = 'com.apple.libdispatch-manager'
    frame #0: 0x00007fff869d5662 libsystem_kernel.dylib`kevent64 + 10
    frame #1: 0x00007fff9217a421 libdispatch.dylib`_dispatch_mgr_invoke + 239
    frame #2: 0x00007fff9217a136 libdispatch.dylib`_dispatch_mgr_thread + 52

  thread #3: tid = 0x1f8ef3e, 0x00007fff869d49aa libsystem_kernel.dylib`__select + 10, name = 'com.apple.CFSocket.private'
    frame #0: 0x00007fff869d49aa libsystem_kernel.dylib`__select + 10
    frame #1: 0x00007fff910b4a03 CoreFoundation`__CFSocketManager + 867
    frame #2: 0x00007fff87c50899 libsystem_pthread.dylib`_pthread_body + 138
    frame #3: 0x00007fff87c5072a libsystem_pthread.dylib`_pthread_start + 137
    frame #4: 0x00007fff87c54fc9 libsystem_pthread.dylib`thread_start + 13

  thread #4: tid = 0x1f8ef40, 0x00007fff869d4e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #0: 0x00007fff869d4e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x00007fff87c51f08 libsystem_pthread.dylib`_pthread_wqthread + 330
    frame #2: 0x00007fff87c54fb9 libsystem_pthread.dylib`start_wqthread + 13

  thread #5: tid = 0x1f901fe, 0x00007fff869d4e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #0: 0x00007fff869d4e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x00007fff87c51f08 libsystem_pthread.dylib`_pthread_wqthread + 330
    frame #2: 0x00007fff87c54fb9 libsystem_pthread.dylib`start_wqthread + 13
(lldb) detach
Process 50297 detached
(lldb) (lldb) quit

Possible duplicates by query: bug 345759, bug 345748, bug 345744, bug 345728, bug 345727.

Reported using DrKonqi
Comment 1 Albert Astals Cid 2015-04-01 18:24:40 UTC
Is there any chance we can get numbers on the okular lines of the trace?
Comment 2 RJVB 2015-04-01 20:01:07 UTC
Ouch.

I can rebuild okular trying to ensure that it keeps its debug info, but triggering the bug again is going to be complicated to do exactly the same way. That PDF was a confirmation of an action I can't repeat ...
I'll see what I can do.
Comment 3 RJVB 2015-04-03 14:27:32 UTC
Here's the backtrace requested. Okular was invoked as
/Applications/MacPorts/KDE4/okular.app/Contents/MacOS/okular https://some.web.site/courriersweb/affichagepdf:pdf/2014239153763 --icon okular -caption Okular

Application: Okular (okular), signal: Segmentation fault: 11
(lldb) process attach --pid 52015
Process 52015 stopped
Executable module set to "/Applications/MacPorts/KDE4/okular.app/Contents/MacOS/okular".
Architecture set to: x86_64-apple-macosx.
(lldb) set set term-width 200
(lldb) thread info
thread #1: tid = 0x20b5799, 0x00007fff869d4e20 libsystem_kernel.dylib`__wait4 + 8, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP

(lldb) bt all
* thread #1: tid = 0x20b5799, 0x00007fff869d4e20 libsystem_kernel.dylib`__wait4 + 8, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  * frame #0: 0x00007fff869d4e20 libsystem_kernel.dylib`__wait4 + 8
    frame #1: 0x000000010f5ceaae libkdeui.5.dylib`KCrash::startProcess(int, char const**, bool) [inlined] startProcessInternal(argc=<unavailable>, directly=<unavailable>) + 265 at kcrash.cpp:556
    frame #2: 0x000000010f5ce9a5 libkdeui.5.dylib`KCrash::startProcess(argc=<unavailable>, argv=<unavailable>, waitAndExit=<unavailable>) + 21 at kcrash.cpp:538
    frame #3: 0x000000010f5cdbd9 libkdeui.5.dylib`KCrash::defaultCrashHandler(sig=<unavailable>) + 1209 at kcrash.cpp:441
    frame #4: 0x00007fff8c1375aa libsystem_platform.dylib`_sigtramp + 26
    frame #5: 0x000000010eadd821 okular`Shell::openDocument(this=0x00007fbe2e1a88d0, url=0x00007fff5112db60, serializedOptions=0x00007fff5112e048) + 129 at shell.cpp:174
    frame #6: 0x000000010ead9913 okular`Okular::main(paths=0x00007fff5112e058, serializedOptions=0x00007fff5112e048) + 5619 at okular_main.cpp:148
    frame #7: 0x000000010ead6ee2 okular`main(argc=<unavailable>, argv=<unavailable>) + 1666 at main.cpp:51
    frame #8: 0x00007fff9158f5fd libdyld.dylib`start + 1
    frame #9: 0x00007fff9158f5fd libdyld.dylib`start + 1

  thread #2: tid = 0x20b579a, 0x00007fff869d5662 libsystem_kernel.dylib`kevent64 + 10, queue = 'com.apple.libdispatch-manager'
    frame #0: 0x00007fff869d5662 libsystem_kernel.dylib`kevent64 + 10
    frame #1: 0x00007fff9217a421 libdispatch.dylib`_dispatch_mgr_invoke + 239
    frame #2: 0x00007fff9217a136 libdispatch.dylib`_dispatch_mgr_thread + 52

  thread #3: tid = 0x20b579b, 0x00007fff869d4e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #0: 0x00007fff869d4e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x00007fff87c51f08 libsystem_pthread.dylib`_pthread_wqthread + 330
    frame #2: 0x00007fff87c54fb9 libsystem_pthread.dylib`start_wqthread + 13

  thread #4: tid = 0x20b57b4, 0x00007fff869d4e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #0: 0x00007fff869d4e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x00007fff87c51f08 libsystem_pthread.dylib`_pthread_wqthread + 330
    frame #2: 0x00007fff87c54fb9 libsystem_pthread.dylib`start_wqthread + 13

  thread #5: tid = 0x20b57b9, 0x00007fff869d49aa libsystem_kernel.dylib`__select + 10, name = 'com.apple.CFSocket.private'
    frame #0: 0x00007fff869d49aa libsystem_kernel.dylib`__select + 10
    frame #1: 0x00007fff910b4a03 CoreFoundation`__CFSocketManager + 867
    frame #2: 0x00007fff87c50899 libsystem_pthread.dylib`_pthread_body + 138
    frame #3: 0x00007fff87c5072a libsystem_pthread.dylib`_pthread_start + 137
    frame #4: 0x00007fff87c54fc9 libsystem_pthread.dylib`thread_start + 13

  thread #6: tid = 0x20b5967, 0x00007fff869d4e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #0: 0x00007fff869d4e6a libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x00007fff87c51f08 libsystem_pthread.dylib`_pthread_wqthread + 330
    frame #2: 0x00007fff87c54fb9 libsystem_pthread.dylib`start_wqthread + 13
(lldb) detach
Process 52015 detached
(lldb) (lldb) quit
Comment 4 RJVB 2015-04-03 14:34:05 UTC
Running Okular with all its debug domains activated through kdebugdialog didn't teach me anything useful (no output at all).
Comment 5 Albert Astals Cid 2015-04-03 15:21:17 UTC
Looks like dynamic_cast<Okular::ViewerInterface*>(part) may be failing

Can you in shell.cpp just before line 174

qDebug() << part;
kDebug() << part;
qDebug() << dynamic_cast<Okular::ViewerInterface*>(part);
kDebug() << dynamic_cast<Okular::ViewerInterface*>(part);

And see the ouput that gives?
Comment 6 RJVB 2015-04-03 15:57:32 UTC
Looks like it's that indeed. I had to add the block to canOpenDocs too

part= Okular::Part(0x7ffb3e05f9f0) 
okular(56591) Shell::canOpenDocs: part= Okular::Part(0x7ffb3e05f9f0)
dynamic_cast<Okular::ViewerInterface*>(part)= 0x0 
okular(56591) Shell::canOpenDocs: dynamic_cast<Okular::ViewerInterface*>(part)= 0x0
part= Okular::Part(0x7ffb3e05f9f0) 
okular(56591) Shell::openDocument: part= Okular::Part(0x7ffb3e05f9f0)
dynamic_cast<Okular::ViewerInterface*>(part)= 0x0 
okular(56591) Shell::openDocument: dynamic_cast<Okular::ViewerInterface*>(part)= 0x0

I've encountered something like this before, with ktimetracker. I've never understood why this happens.

The "good" news is that if I do

    Okular::ViewerInterface *viFace = dynamic_cast<Okular::ViewerInterface*>(part);
    // Return false if we can't open new tabs and the only part is occupied
    if ( viFace && !viFace->openNewFilesInTabs()
         && !part->url().isEmpty()
         && !ShellUtils::unique(serializedOptions))
    {
        return false;
    }

the document opens, ultimately.

Similar patches in canOpenDoc and openUrl prevent the crash and also the issue at https://trac.macports.org/ticket/47054
Comment 7 RJVB 2015-04-03 15:58:37 UTC
Maybe I ought to return false when !viFace?
Comment 8 Albert Astals Cid 2015-04-03 17:17:41 UTC
No, you need to find out why casting an Okular::Part to an Okular::ViewerInterface returns null since Okular::Part *is* an Okular::ViewerInterface as you can see in part.h

class OKULAR_PART_EXPORT Part : public KParts::ReadWritePart, public Okular::DocumentObserver, public KDocumentViewer, public Okular::ViewerInterface
Comment 9 RJVB 2015-04-03 18:41:42 UTC
Yes, well, I tried that with ktimetracker and failed, probably mostly because I have no idea how a cast can fail (or what a dynamic_cast really does, and how). Is this a feature that relies on Qt tech?
Naive question: if Okular::Part *is* an Okular::ViewerInterface then why does a good old "normal" cast not work? AFAIK parent and sibling classes can be cast either way at compile time in C++ (contrary to ObjC where that would indeed have no effect at all).

Has this been tested with clang on Linux? If it works there, could it be a problem in libc++ (which is basically the only relevant thing that should be different when using compilers of the same version).
Comment 10 Albert Astals Cid 2015-04-03 20:50:27 UTC
dynamic_cast is a normal cast, i have no idea if it works on clang on Linux or not sorry.
Comment 11 RJVB 2015-04-03 21:46:55 UTC
I don't think that it's a normal "C" cast (which is what I should have written). A cast that "returns" a NULL pointer when casting a variable that's not NULL is not a normal cast in my book.

The times I tried to follow what's going on with this kind of cast, I got the impression that

Okular::ViewerInterface *viFace = dynamic_cast<Okular::ViewerInterface*>(part);

is comparable to

Okular::ViewerInterface *viFace = new Okular::ViewerInterface((Okular::ViewerInterface*)part);

except that somehow you don't have to delete the result when you're done with it.
Comment 12 Albert Astals Cid 2015-04-03 22:27:07 UTC
Right, dynamic_cast is not a C cast, it's a C++ cast.

No, it is not what you wrote, what you wrote is creating a new object, which is not what dynamic_cast does, dynamic_cast just "changes" the pointer in run-time to the target type if the source type can be converted to that type, which in this case it should be as the debug output shows, but something in your runtime thinks it can not, when it can.
Comment 13 RJVB 2015-04-04 08:34:18 UTC
RIght, it's a cast that's done at runtime, and I'm pretty sure that when I followed what happened a while ago, the original and cast objects were not at the same memory address, which is why I wrote the new statement above. Maybe that indeed happens in some cases. (And I don't mean that the cast object was NULL after the operation :))

So I come back to my earlier question: why use dynamic_cast, why not use 

(Okular::ViewInterface*)(part)

or however you'd write the equivalent of int(foo)? I can see why it would be necessary when casting a parent class to a child class, but Okular::Part inherits Okular::ViewInterface. Can I assume that the ViewInterface ctor has been called when the Okular::Part instance was created?

And is what I wrote above at least equivalent, in other words, could it be used as a workaround?
Comment 14 Albert Astals Cid 2015-04-05 15:22:53 UTC
One could use static_cast, but that's poors man solution, if dynamic_cast doesn't work, you're going to have problems everywhere, so spend some time finding out why dynamic_cast is broken.
Comment 15 RJVB 2015-04-09 22:54:09 UTC
I may have a beginning of an explanation. When I query the `typeid()` information of the `part` pointer that fails to cast, it turns out to be a `KParts::ReadWritePart` and not an `Okular::Part`. KParts::ReadWritePart and Okular::ViewerInterface are not related (no common ancestor), so it *seems* logical to me that the cast fails.
See http://stackoverflow.com/questions/29469787/what-does-it-mean-when-a-dynamic-cast-fails/29469895
Comment 16 Albert Astals Cid 2015-04-10 16:12:41 UTC
That should be fine, since the class that inherits from KParts::ReadWritePart  that the pointer actually contains is a children of Okular::ViewerInterface 

Can you please try to compile this example with clang (i.e. clang++ example.cpp) and run it and see what's the output?
Comment 17 Albert Astals Cid 2015-04-10 16:13:06 UTC
Created attachment 91978 [details]
example.cpp
Comment 18 RJVB 2015-04-10 16:45:09 UTC
(In reply to Albert Astals Cid from comment #16)
> That should be fine, since the class that inherits from
> KParts::ReadWritePart  that the pointer actually contains is a children of
> Okular::ViewerInterface 

So the typeid info isn't correct (I checked with your example: it does indeed provide the pointer's type, not the allocated class type).

> Can you please try to compile this example with clang (i.e. clang++
> example.cpp) and run it and see what's the output?

A: 0x7fc0e34037f0
B: 0x7fc0e34037f0
C: 0x7fc0e3403800

NB: "B" above is the result of dynamic_cast<C*> and "C" the result of dynamic_cast<B*> ...
Comment 19 RJVB 2015-04-11 20:22:01 UTC
Created attachment 91986 [details]
After asking around, Qt's Thiago Macieira provided the answer: all of Okular::Part's parent classes weren't exported, in particular Okular::VIewerInterface wasn't. The attached patch corrects that.

The patch indeed appears to solve the issue.
Comment 20 Albert Astals Cid 2015-04-12 13:24:10 UTC
Comment on attachment 91986 [details]
After asking around, Qt's Thiago Macieira provided the answer: all of Okular::Part's parent classes weren't exported, in particular Okular::VIewerInterface wasn't. The attached patch corrects that.

I'd say the second needs to be OKULAR_PART_EXPORT ?
Comment 21 RJVB 2015-04-12 13:34:03 UTC
Yes, probably. Not sure if it makes any difference though (clearly OKULAR_EXPORT expands to KDE_EXPORT in this case ... or the keyword is only of importance for the ViewerInterface class).
Comment 22 Albert Astals Cid 2015-04-13 23:39:24 UTC
Git commit 7f6c9987ab9578ab22cb44204520eb8f9768ed71 by Albert Astals Cid, on behalf of René J.V. Bertin.
Committed on 13/04/2015 at 23:39.
Pushed by aacid into branch 'Applications/15.04'.

Fix crashes on Mac

Seems Mac and/or clang need these to be exported

M  +1    -1    interfaces/viewerinterface.h
M  +3    -1    kdocumentviewer.h

http://commits.kde.org/okular/7f6c9987ab9578ab22cb44204520eb8f9768ed71