Pytanie Dlaczego pow () oblicza błędnie, gdy działa Webkit?


Mam aplikację Qt C ++, w której istnieje wątek GUI, w którym odbywa się obliczanie zmiennoprzecinkowe. To również się otwiera QWebView gdzie jest flash player z jakimś wideo.

Oczywiste jest, że zamknięcie QWebView zakłóca działanie następnej operacji zmiennoprzecinkowej. Więc pow(double, double) zwraca określone, ale niepoprawne wartości.

W jednym przypadku zwrócono wartości 1000 razy więcej niż poprawny. Innym razem powrócił 1.#inf gdy jest używany z argumentami pow(10.0, 2.0).

Muszę nadmienić, że jest testowany na różnych komputerach i nie jest specyficzny dla konkretnego procesora.

Czy masz jakieś sugestie, jak zlokalizować to miejsce w Webkit, które robi coś złego z koprocesorem i jak temu zapobiec?

Próbka (tylko x 64)

Środowisko: Qt 4.7.4, C ++, HTML i 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>  

Oto w pełni działający program ze źródłami: Pobierz 15 MB


11
2017-07-17 06:02


pochodzenie


Dodaj kod do odtworzenia problemu. Jak sądzisz, w jaki sposób webkit zakłóca działanie funkcji pow ()? - Sebastian Lange
@ sebastian-lange To w jakiś sposób przeszkadza. Popatrz tutaj: Zrzut ekranu Dowiedziałem się, że tylko pierwsze wezwanie o powrocie zwraca zły wynik. Zrobię co w mojej mocy, aby zrobić próbną próbkę, ponieważ w prawdziwej aplikacji są tysiące linii kodu. - Ezee
@Ezee Twoje kroki do odtworzenia są zrzutem ekranu dwóch linii kodu w XCode? Całkowicie nie rozumiesz do czego one służą. Wierzymy ci. Nie prosimy o dostarczenie DOWODY, że tak się dzieje. Musimy OPRACOWAĆ problem, aby dać ci prawidłowe wyjaśnienie. Jak mamy przejść od zrzutu ekranu zawierającego dwie linie kodów? (Zauważ, że "my" to StackOverflow, a nie ja w szczególności). - Pascal Cuoq
@Ezee To jest genialne pytanie, a ja obstawię go, jeśli nie otrzyma odpowiedzi w ciągu 48 godzin. Ogólna uwaga jest taka, że ​​matematyka zmiennoprzecinkowa jest implementowana wewnątrz jednostki FPU, która ma stan (w szczególności bieżący tryb zaokrąglania). Państwo zmienia się w sposób imperatywny (do obliczenia 2.0 + 3.0zaokrąglone w górę sekwencja instrukcji to tryb "zmień na" zaokrąglić ", a następnie oblicz 2.0 + 3.0, następnie zmień ponownie tryb zaokrąglania - lub nie "). Niektóre podstawowe funkcje zmiennoprzecinkowe (np. sin i pow) są implementowane z subtelną arytmetyką zmiennoprzecinkową, która może przejść CAŁKOWICIE nieprawidłowo, jeśli tryb zaokrąglania ... - Pascal Cuoq
MSDN stwierdza, że ​​zarówno dla x87 i SSE słowa kontrolne, "Użytkownik, który modyfikuje którekolwiek z pól w FPCSR, musi je przywrócić przed powrotem do swojego rozmówcy. Ponadto, wywołujący, który zmodyfikował którekolwiek z tych pól, musi przywrócić je do swoich standardowych wartości przed wywołaniem osoby, która się wykupiła, chyba że w porozumieniu osoba oczekująca oczekuje zmodyfikowanego wartości. ". Standardowa precyzja i tryb zaokrąglania przy wejściu / wyjściu do dowolnej funkcji to Double i Round-to-Nearest. Czy możesz to sprawdzić? - Iwillnotexist Idonotexist


Odpowiedzi:


Przyczyna nieprawidłowego wyniku pow jest to, że rejestry x87 stały się ST0-ST3 1#SNAN a więc TAGS = 0xFF. Dzieje się tak podczas niszczenia QWebView zawierającego obiekt flash wideo. Słowa kontrolne x87 i SSE zawierają poprawne wartości. Testowana biblioteka Adove Flash: NPSWF64_14_0_0_125.dll

Zdarza się, gdy WebCore::PluginView::stop metoda wywołuje destruktor obiektu wtyczki Adobe Flash.

NPError npErr = m_plugin->pluginFuncs()->destroy(m_instance, &savedData);

Oto procedura (NPSWF64.dll), która psuje rejestry (w rzeczywistości używa rejestrów MMX powiązanych z rejestrami x87):

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         

Aby zapobiec błędnym obliczeniom pow spowodowane przez ten błąd, konieczne jest przywrócenie wartości rejestru. Używam najprostszego sposobu, aby to zrobić. Kiedy wtyczka zostanie zniszczona, zadzwonię pow z pewnymi argumentami i przywraca rejestry. Następne połączenie będzie poprawne.
Istnieje bardziej skomplikowany (ale prawdopodobnie poprawny) sposób, aby zrobić to samo, wpisując nowe wartości do rejestrów za pomocą metod z float.h biblioteka.


6
2017-07-26 13:25



@ Pascal-cuoq Byłbym wdzięczny za komentarze na temat wyników dochodzenia. - Ezee


Żeby dodać do tego nieco, myślę, że natknąłem się na ten sam problem (w 64-bitowej aplikacji C #, która wywołuje Math.Cos, a także pokazuje wideo Flash w formancie Windows Forms WebBrowser).

Podobnie w moim przypadku wydaje się, że poniższy kod w 64-bitowym Flash OCX (16.0.0.305) pozostawia za sobą nieprawidłowe wartości w rejestrach MM0, MM1, MM2, MM3 (ten kod wydaje się być pewnego rodzaju szybkim kopiowaniem pamięci) :

C:\Windows\System32\Macromed\Flash\Flash64_16_0_0_305.ocx
00000000`2f9833c0 48894c2408      mov     qword ptr [rsp+8],rcx
00000000`2f9833c5 4889542410      mov     qword ptr [rsp+10h],rdx
00000000`2f9833ca 4c89442418      mov     qword ptr [rsp+18h],r8
00000000`2f9833cf 56              push    rsi
00000000`2f9833d0 57              push    rdi
00000000`2f9833d1 53              push    rbx
00000000`2f9833d2 488b7c2420      mov     rdi,qword ptr [rsp+20h]
00000000`2f9833d7 488b742428      mov     rsi,qword ptr [rsp+28h]
00000000`2f9833dc 488b4c2430      mov     rcx,qword ptr [rsp+30h]
00000000`2f9833e1 4881f920000000  cmp     rcx,20h
00000000`2f9833e8 7e43            jle     Flash64_16_0_0_305!DllUnregisterServer+0x3c2a2d (00000000`2f98342d)
00000000`2f9833ea 4881e920000000  sub     rcx,20h
00000000`2f9833f1 0f6f06          movq    mm0,mmword ptr [rsi]
00000000`2f9833f4 0f6f4e08        movq    mm1,mmword ptr [rsi+8]
00000000`2f9833f8 0f6f5610        movq    mm2,mmword ptr [rsi+10h]
00000000`2f9833fc 0f6f5e18        movq    mm3,mmword ptr [rsi+18h]
00000000`2f983400 4881c620000000  add     rsi,20h
00000000`2f983407 0f7f07          movq    mmword ptr [rdi],mm0
00000000`2f98340a 0f7f4f08        movq    mmword ptr [rdi+8],mm1
00000000`2f98340e 0f7f5710        movq    mmword ptr [rdi+10h],mm2
00000000`2f983412 0f7f5f18        movq    mmword ptr [rdi+18h],mm3
00000000`2f983416 4881c720000000  add     rdi,20h
00000000`2f98341d 4881e920000000  sub     rcx,20h
00000000`2f983424 7dcb            jge     Flash64_16_0_0_305!DllUnregisterServer+0x3c29f1 (00000000`2f9833f1)
00000000`2f983426 4881c120000000  add     rcx,20h
00000000`2f98342d f3a4            rep movs byte ptr [rdi],byte ptr [rsi]
00000000`2f98342f 5b              pop     rbx
00000000`2f983430 5f              pop     rdi
00000000`2f983431 5e              pop     rsi
00000000`2f983432 c3              ret

Powyższy kod w programie Flash OCX jest wykonywany, gdy przeglądarka internetowa odsuwa się od strony z filmem Flash.

Zanim ten kod wykona rejestry zmiennoprzecinkowe były następujące (zbadane przy użyciu WinDbg.exe):

fpcw=027f fpsw=3820 fptw=0080
st0= 6.00000000000000000000000...0e+0001 (0:4004:f000000000000000)
st1= 0.00000000000000000000000...0e+0000 (0:0000:0000000000000000)
st2= 0.00000000000000000000000...0e+0000 (0:0000:0000000000000000)
st3= 0.00000000000000000000000...0e+0000 (0:0000:0000000000000000)
st4= 0.00000000000000000000000...0e+0000 (0:0000:0000000000000000)
st5= 1.00000000000000000000000...0e+0000 (0:3fff:8000000000000000)
st6= 8.94231504669236176852000...0e-0001 (0:3ffe:e4ec5b1b9b742000)
st7= 0.00000000000000000000000...0e+0000 (0:0000:0000000000000000)
mxcsr=00001fa4

Po wykonaniu powyższego kodu rejestry zmiennoprzecinkowe były następujące:

fpcw=027f fpsw=0020 fptw=00ff
st0=-1.#SNAN000000000000000000...0e+0000 (1:7fff:0000000000000000)
st1=-1.#SNAN000000000000000000...0e+0000 (1:7fff:0000000000000000)
st2=-1.#SNAN000000000000000000...0e+0000 (1:7fff:0000000000000000)
st3=-1.#SNAN000000000000000000...0e+0000 (1:7fff:0000000000000000)
st4= 1.00000000000000000000000...0e+0000 (0:3fff:8000000000000000)
st5= 8.94231504669236176852000...0e-0001 (0:3ffe:e4ec5b1b9b742000)
st6= 0.00000000000000000000000...0e+0000 (0:0000:0000000000000000)
st7= 6.00000000000000000000000...0e+0001 (0:4004:f000000000000000)
mxcsr=00001fa4

W tym momencie rejestry zmiennoprzecinkowe wydają się być "uszkodzone".

Więc później, w programie C #, podczas wykonywania Math.Cos, ops fld nie powiedzie się, ponieważ próbuje przenieść wartość 2.0 na stos zmiennoprzecinkowy (tj. Gdy próbuje przygotować się do obliczenia cosinusa w wersji 2.0):

COMDouble::Cos:
000007FE`E1D01570  movsd   mmword ptr [rsp+8],xmm0
000007FE`E1D01576  fld     qword ptr [rsp+8]
000007FE`E1D0157A  fcos
000007FE`E1D0157C  fstp    qword ptr [rsp+8]
000007FE`E1D01580  movsd   xmm0,mmword ptr [rsp+8]
000007FE`E1D01586  ret

Bezpośrednio przed wykonaniem opcode fld, rejestry zmiennoprzecinkowe były dokładnie tak, jak zostały pozostawione przez Flash OCX (tj. Jak wyżej):

fpcw=027f fpsw=0020 fptw=00ff
st0=-1.#SNAN000000000000000000...0e+0000 (1:7fff:0000000000000000)
st1=-1.#SNAN000000000000000000...0e+0000 (1:7fff:0000000000000000)
st2=-1.#SNAN000000000000000000...0e+0000 (1:7fff:0000000000000000)
st3=-1.#SNAN000000000000000000...0e+0000 (1:7fff:0000000000000000)
st4= 1.00000000000000000000000...0e+0000 (0:3fff:8000000000000000)
st5= 8.94231504669236176852000...0e-0001 (0:3ffe:e4ec5b1b9b742000)
st6= 0.00000000000000000000000...0e+0000 (0:0000:0000000000000000)
st7= 6.00000000000000000000000...0e+0001 (0:4004:f000000000000000)
mxcsr=00001fa4

Natychmiast po wykonaniu faksu, rejestry zmiennoprzecinkowe były następujące (zauważ, że st0 wynosi #IND zamiast oczekiwanej wartości 2.00000000000000000000000 ... 0e + 0000):

fpcw=027f fpsw=3a61 fptw=00ff
st0=-1.#IND0000000000000000000...0e+0000 (1:7fff:c000000000000000)
st1=-1.#SNAN000000000000000000...0e+0000 (1:7fff:0000000000000000)
st2=-1.#SNAN000000000000000000...0e+0000 (1:7fff:0000000000000000)
st3=-1.#SNAN000000000000000000...0e+0000 (1:7fff:0000000000000000)
st4=-1.#SNAN000000000000000000...0e+0000 (1:7fff:0000000000000000)
st5= 1.00000000000000000000000...0e+0000 (0:3fff:8000000000000000)
st6= 8.94231504669236176852000...0e-0001 (0:3ffe:e4ec5b1b9b742000)
st7= 0.00000000000000000000000...0e+0000 (0:0000:0000000000000000)
mxcsr=00001fa4

Oznacza to, że kod opcji fcos próbuje obliczyć cosinus o wartości #IND. I tak kończy się, że wartość zwracana Math.Cos w C # to Double.NaN zamiast oczekiwanego -0,416146836547142.

Usunięcie wartości słowa statusowego zmiennoprzecinkowego (FPSW) o wartości 0x3a61 powyżej wskazuje, że problem polega na "próbie załadowania wartości do rejestru, który nie jest wolny":

3a61: 0011 1010 0110 0001

    TOP (13,12,11):          111
    C3,C2,C1,C0 (14,10,9,8): 0 010  (ie. C1 is 1)  <-- loading a value into a register which is not free
    IR (7):                  0  Interrupt Request
    SF (6):                  1  Stack Fault  <-- loading a value into a register which is not free
    P (5):                   1  Precision
    U (4):                   0  Underflow
    O (3):                   0  Overflow
    Z (2):                   0  Zero Divide
    D (1):                   0  Denormalised
    I (0):                   1  Invalid Operation

Zauważ, że problem występuje tylko przy pierwszej próbie Math.Cos (2) (tj. Wkrótce po odejściu ze strony Flash video). Druga i kolejne próby obliczenia Math.Cos (2) kończą się pomyślnie.

Problem występuje również wtedy, gdy kontrolka WebBrowser jest usuwana podczas odtwarzania wideo Flash (lub jest wstrzymana).

Oto niektóre potencjalne rozwiązania:

  1. Wykonaj jedno pozorne obliczenia matematyczne i zignoruj ​​wynik.

  2. Napisz 64-bitową bibliotekę DLL, która eksportuje funkcję, która wykonuje opcodes finit lub emms (w celu zresetowania stanu rejestrów zmiennoprzecinkowych). Wywołaj tę funkcję z C #.

  3. Uruchom jako proces 32-bitowy.

Uwaga: wyrzucenie pozornego wyjątku w języku C #, a następnie wychwycenie tego wyjątku nie pomogło (jest to zalecane dla innych problemów z korupcją zmiennoprzecinkowa).

Oto kod C #, który odtwarza problem (upewnij się, że kompiluje się i działa jako 64-bitowy, kliknij przycisk Oblicz po rozpoczęciu odtwarzania wideo).

using System;
using System.IO;
using System.Windows.Forms;

namespace FlashTest
{
    public partial class TestForm : Form
    {
        public TestForm()
        {
            // Windows 7 SP1 64 bit
            // Internet Explorer 11 (11.0.9600.17633)
            // Flash Player 16.0.0.305
            // Visual Studio 2013 (12.0.31101.00)
            // .NET 4.5 (4.0.30319.34209)

            InitializeComponent();
            addressTextBox.Text = "http://www.youtube.com/v/JVGdyC9CvFQ?autoplay=1";
            GoButtonClickHandler(this, EventArgs.Empty);
        }

        private void GoButtonClickHandler(object sender, EventArgs e)
        {
            string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".html");
            File.WriteAllText(path, string.Format(@"<html><body>
                <object classid=""clsid:D27CDB6E-AE6D-11CF-96B8-444553540000"" width=""100%"" height=""100%"" id=""youtubeviewer"">
                    <param name=""movie"" value=""{0}"">
                </object></body></html>", addressTextBox.Text));
            webBrowser.Navigate(path);
        }

        private void CalculateButtonClickHandler(object sender, EventArgs e)
        {
            webBrowser.DocumentCompleted += DocumentCompletedHandler;
            webBrowser.Navigate("about:blank");
        }

        private void DocumentCompletedHandler(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            webBrowser.DocumentCompleted -= DocumentCompletedHandler;
            MessageBox.Show("Math.Cos(2) returned " + Math.Cos(2));
        }
    }
}

namespace FlashTest
{
    partial class TestForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.webBrowser = new System.Windows.Forms.WebBrowser();
            this.addressTextBox = new System.Windows.Forms.TextBox();
            this.goButton = new System.Windows.Forms.Button();
            this.calculateButton = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // webBrowser
            // 
            this.webBrowser.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.webBrowser.Location = new System.Drawing.Point(12, 41);
            this.webBrowser.MinimumSize = new System.Drawing.Size(20, 20);
            this.webBrowser.Name = "webBrowser";
            this.webBrowser.Size = new System.Drawing.Size(560, 309);
            this.webBrowser.TabIndex = 3;
            // 
            // addressTextBox
            // 
            this.addressTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
            this.addressTextBox.Location = new System.Drawing.Point(12, 14);
            this.addressTextBox.Name = "addressTextBox";
            this.addressTextBox.Size = new System.Drawing.Size(398, 20);
            this.addressTextBox.TabIndex = 0;
            // 
            // goButton
            // 
            this.goButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.goButton.Location = new System.Drawing.Point(416, 12);
            this.goButton.Name = "goButton";
            this.goButton.Size = new System.Drawing.Size(75, 23);
            this.goButton.TabIndex = 1;
            this.goButton.Text = "&Go";
            this.goButton.UseVisualStyleBackColor = true;
            this.goButton.Click += new System.EventHandler(this.GoButtonClickHandler);
            // 
            // calculateButton
            // 
            this.calculateButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.calculateButton.Location = new System.Drawing.Point(497, 12);
            this.calculateButton.Name = "calculateButton";
            this.calculateButton.Size = new System.Drawing.Size(75, 23);
            this.calculateButton.TabIndex = 2;
            this.calculateButton.Text = "&Calculate";
            this.calculateButton.UseVisualStyleBackColor = true;
            this.calculateButton.Click += new System.EventHandler(this.CalculateButtonClickHandler);
            // 
            // TestForm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(584, 362);
            this.Controls.Add(this.webBrowser);
            this.Controls.Add(this.goButton);
            this.Controls.Add(this.addressTextBox);
            this.Controls.Add(this.calculateButton);
            this.Name = "TestForm";
            this.Text = "Adobe Flash Test";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.WebBrowser webBrowser;
        private System.Windows.Forms.TextBox addressTextBox;
        private System.Windows.Forms.Button goButton;
        private System.Windows.Forms.Button calculateButton;
    }
}

2
2018-02-13 13:55





Najwyraźniej trafiłeś błąd w wersji Qt twojej webkit. Nie mogę odtworzyć w QT 5.3 z kompilacją QtCreator, używając MSVC 13 x64 w wersji i debugowaniu.

Zgłoszono już kilka błędów dla QtWebKit z punktami zmiennoprzecinkowymi:


1
2017-07-17 16:06



* Ten błąd nie jest związany z problemem. * Testowałem to w Qt 4.7 i 4.8. - Ezee
Wiem, chcę tylko powiedzieć, że nie jesteś pierwszy, który to uderzył uprzejmy błędu z webkitem. :) - fjardon
W rzeczywistości okazało się, że jest to błąd w wtyczce Adobe Flash Player. - Ezee