Fix bug 4463. The crash was due to a call to X from inside a child process.

The main change is to support/ForkedCalls.{h,cpp}. We introduce a static variable IAmAChild and a corresponding accessor. This is set to true in a new fork() method, in the branch taken by the child. (Note: fork() is safe cross-platform, as it just returns -1 if we don't have fork().) This ForkedProcess::iAmAChild() method is then used to protect GuiView::message().

As Abdel has pointed out, there may be other such calls to be protected, e.g., the emission of the Buffer::changed() signal. Those are not addressed here.

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@22587 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Richard Heck 2008-01-15 18:26:53 +00:00
parent 2baffdb590
commit 1741c87a4e
4 changed files with 38 additions and 5 deletions

View File

@ -2260,14 +2260,12 @@ private:
};
#if !defined (HAVE_FORK)
# define fork() -1
#endif
int AutoSaveBuffer::generateChild()
{
// tmp_ret will be located (usually) in /tmp
// will that be a problem?
// Note that this calls ForkedCalls::fork(), so it's
// ok cross-platform.
pid_t const pid = fork();
// If you want to debug the autosave
// you should set pid to -1, and comment out the fork.

View File

@ -54,6 +54,7 @@
#include "support/FileFilterList.h"
#include "support/FileName.h"
#include "support/filetools.h"
#include "support/ForkedCalls.h"
#include "support/lstrings.h"
#include "support/os.h"
#include "support/Package.h"
@ -459,6 +460,9 @@ void GuiView::dropEvent(QDropEvent* event)
void GuiView::message(docstring const & str)
{
if (ForkedProcess::iAmAChild())
return;
statusBar()->showMessage(toqstr(str));
d.statusbar_timer_.stop();
d.statusbar_timer_.start(3000);

View File

@ -108,6 +108,9 @@ ForkedProcess::ForkedProcess()
{}
bool ForkedProcess::IAmAChild = false;
void ForkedProcess::emitSignal()
{
if (signal_.get()) {
@ -123,6 +126,10 @@ int ForkedProcess::run(Starttype type)
pid_ = generateChild();
if (pid_ <= 0) { // child or fork failed.
retval_ = 1;
if (pid_ == 0)
//we also do this in fork(), too, but maybe someone will try
//to bypass that
IAmAChild = true;
return retval_;
}
@ -184,6 +191,18 @@ void ForkedProcess::kill(int tol)
}
pid_t ForkedProcess::fork() {
#if !defined (HAVE_FORK)
return -1;
#else
pid_t pid = ::fork();
if (pid == 0)
IAmAChild = true;
return pid;
#endif
}
// Wait for child process to finish. Returns returncode from child.
int ForkedProcess::waitForChild()
{

View File

@ -43,7 +43,7 @@ public:
///
virtual boost::shared_ptr<ForkedProcess> clone() const = 0;
/** A SignalType signal is can be emitted once the forked process
/** A SignalType signal can be emitted once the forked process
* has finished. It passes:
* the PID of the child and;
* the return value from the child.
@ -97,12 +97,21 @@ public:
*/
void kill(int tolerance = 5);
/// Returns true if this is a child process
static bool iAmAChild() { return IAmAChild; }
protected:
/** Spawn the child process.
* Returns returncode from child.
*/
int run(Starttype type);
/// implement our own version of fork()
/// it just returns -1 if ::fork() is not defined
/// otherwise, it forks and sets the global child-process
/// boolean IAmAChild
pid_t fork();
/// Callback function
SignalTypePtr signal_;
@ -118,6 +127,9 @@ private:
/// generate child in background
virtual int generateChild() = 0;
///
static bool IAmAChild;
/// Wait for child process to finish. Updates returncode from child.
int waitForChild();
};