I have a Qt C++ application where there is a GUI thread in which some floating point calculation happens. It also opens QWebView
where there is a flash player with some video.
It is obvious that closing of QWebView interfere on new next floating point operation.
So pow(double, double)
returns definite but incorrect values.
In one case it returned values 1000
times more then the correct one. Another time it returned 1.#inf
when used with arguments pow(10.0, 2.0)
.
I have to mention that it is tested on different computers and is not specific to a particular CPU.
Do you have any suggestion about how to locate the place in Webkit that does something wrong with co-processor and how to prevent it?
Environment: Qt 4.7.4, C++, HTML and flowplayer
cpp
wrongpow::wrongpow(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
QVBoxLayout* layout = new QVBoxLayout(0);
m_view = new QWebView(this);
m_view->setMinimumSize(400, 400);
m_view->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
m_view->settings()->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls, true);
layout->addWidget(m_view);
QDir dir(QApplication::applicationDirPath());
dir.cd("media");
m_view->load(QUrl(QFileInfo(dir, "index.html").absoluteFilePath()));
QPushButton* button = new QPushButton(QLatin1String("Click on video start"), this);
layout->addWidget(button);
Q_ASSERT(connect(button, SIGNAL(clicked()), this, SLOT(closeView())));
setLayout(layout);
adjustSize();
}
Q_SLOT void wrongpow::closeView()
{
delete m_view;
m_view = NULL;
double wrongResult = pow(10.0, 2.0);
Q_ASSERT(wrongResult == 100.0);
}
html
<div id='player' style='width:100%; height:100%;'>
<object width='100%' height='100%' id='_494187117' name='_494187117' data='js/plugins/flowplayer-3.2.18.swf' type='application/x-shockwave-flash'>
<param name='wmode' value='opaque'>
<param name='flashvars' value='config={"clip":{"url":"mp4:vod/demo.flowplayer/buffalo_soldiers.mp4","scaling":"fit","provider":"hddn","live":true},"plugins":{"hddn":{"url":"js/plugins/flowplayer.rtmp-3.2.13.swf","netConnectionUrl":"rtmp://r.demo.flowplayer.netdna-cdn.com/play"}},"canvas":{"backgroundGradient":"none"}}'>
</object>
</div>
Here is a fully working program with sources: Download 15MB
Reason of the incorrect result of pow
is that x87 registers ST0-ST3 became 1#SNAN
and so TAGS = 0xFF. It happens during destruction of QWebView containing a video flash object. The control words of x87 and SSE contain correct values.
Tested Adove Flash library: NPSWF64_14_0_0_125.dll
It happens when WebCore::PluginView::stop
method calls a destructor of the Adobe Flash plugin object.
NPError npErr = m_plugin->pluginFuncs()->destroy(m_instance, &savedData);
Here is the procedure (NPSWF64.dll) which spoil the registers (actually it uses MMX registers associated with x87 registers):
mov qword ptr [rsp+8],rcx
mov qword ptr [rsp+10h],rdx
mov qword ptr [rsp+18h],r8
push rsi
push rdi
push rbx
mov rdi,qword ptr [rsp+20h]
mov rsi,qword ptr [rsp+28h]
mov rcx,qword ptr [rsp+30h]
cmp rcx,20h
jle 000000002F9D8A2D
sub rcx,20h
// writes wrong values to the registers:
movq mm0,mmword ptr [rsi]
movq mm1,mmword ptr [rsi+8]
movq mm2,mmword ptr [rsi+10h]
movq mm3,mmword ptr [rsi+18h]
add rsi,20h
movq mmword ptr [rdi],mm0
movq mmword ptr [rdi+8],mm1
movq mmword ptr [rdi+10h],mm2
movq mmword ptr [rdi+18h],mm3
add rdi,20h
sub rcx,20h
jge 000000002F9D89F1
add rcx,20h
rep movs byte ptr [rdi],byte ptr [rsi]
pop rbx
pop rdi
pop rsi
ret
To prevent wrong calculation of pow
caused by this bug it's needed to restore the register values. I use the simplest way to do that. When the plugin is destroyed I call pow
with some arguments and it restores the registers. The next call will be correct.
There is a more complicated (but probably correct) way to do the same by writing new values to the registers using methods from float.h
library.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With