Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does pow() calculate wrong when Webkit is running?

Tags:

c++

webkit

pow

qt

x87

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?

Sample (x64 only)

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={&quot;clip&quot;:{&quot;url&quot;:&quot;mp4:vod/demo.flowplayer/buffalo_soldiers.mp4&quot;,&quot;scaling&quot;:&quot;fit&quot;,&quot;provider&quot;:&quot;hddn&quot;,&quot;live&quot;:true},&quot;plugins&quot;:{&quot;hddn&quot;:{&quot;url&quot;:&quot;js/plugins/flowplayer.rtmp-3.2.13.swf&quot;,&quot;netConnectionUrl&quot;:&quot;rtmp://r.demo.flowplayer.netdna-cdn.com/play&quot;}},&quot;canvas&quot;:{&quot;backgroundGradient&quot;:&quot;none&quot;}}'>
    </object>
</div>  

Here is a fully working program with sources: Download 15MB

like image 235
Ezee Avatar asked Jul 17 '14 06:07

Ezee


1 Answers

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.

like image 165
Ezee Avatar answered Sep 24 '22 09:09

Ezee