Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-100508

SEGFAULT Crash on QQuickOpenGLShaderEffectMaterial::updateTextures()

XMLWordPrintable

    • Linux/X11
    • 81bbd0b45a (qt/qtdeclarative/dev) 81bbd0b45a (qt/tqtc-qtdeclarative/dev) 5561df5ac4 (qt/qtdeclarative/6.2) 5561df5ac4 (qt/tqtc-qtdeclarative/6.2) 27daadc214 (qt/qtdeclarative/6.3) 684ed0323c (qt/tqtc-qtquickcontrols2/5.15)

      Using QQuickNinePatch Image as a provider, an crash occurs on QQuickOpenGLShaderEffectMaterial::updateTextures() in qt5.15 and QSGRhiShaderEffectNode::preprocess() in Qt6.2. 

      The brief reason of this crash is that ShaderEffect is trying to use wrong texture invalidated already by wrong image source.

      The major factors of this crash are

      • use QQuickNinePatchImage.
      • QQuickNinePatchImage's cache: false.
      • use the QQuickNinePatchImage as a source of other Shader related object like ShaderEffect or OpacityMask or something.
      • change the QQuickNinePatchImage's source to invalid image after running with valid image. 
      •  after above, update them. 

      Test codes are below.

      Window {
          id: root
          width: 640
          height: 480
          visible: true
          title: qsTr("Hello World")
      
          NinePatchImage {
                  id: np
                  source : "qrc://aaa.png"           // any valid image.
                  cache: false
                  visible: false
          }
      
      /* 
       * this is for Qt6
          ShaderEffect {
              width: 300
              height: 300
              property variant source: np
              property real amplitude: 0.04
              property real frequency: 20
              property real time: 0
              fragmentShader: "content/shaders/wobble.frag.qsb"      // any shader codes. this fragment shader code was from QtQuick ShaderEffect example
          }
      */
      
      // this is for Qt5
          ShaderEffect {
              width: 300
              height: 300
              property variant src: np
              
              // any vertex shader
              vertexShader: "
                                 uniform highp mat4 qt_Matrix;
                                 attribute highp vec4 qt_Vertex;
                                 attribute highp vec2 qt_MultiTexCoord0;
                                 varying highp vec2 coord;
                                 void main() {
                                     coord = qt_MultiTexCoord0;
                                     gl_Position = qt_Matrix * qt_Vertex;
                                 }"
              // any fragment shader
              fragmentShader: "
                                 varying highp vec2 coord;
                                 uniform sampler2D src;
                                 uniform lowp float qt_Opacity;
                                 void main() {
                                     lowp vec4 tex = texture2D(src, coord);
                                     gl_FragColor = vec4(vec3(dot(tex.rgb,
                                                         vec3(0.344, 0.5, 0.156))),
                                                              tex.a) * qt_Opacity;
                                 }"
          }
      
          Timer{
              running: true
      
              interval: 2000
              onTriggered: {
                  np.source =""
              }
          }
      
          MouseArea {
              anchors.fill: parent
              onClicked: {
                  root.update();
              }
          }
      }

       

      If QQuickImage is used instead, these is no problem because QQuickImage updates provider's texture before checking invalidation of current texture while updating like this. 

      // qtdeclarative/src/quick/items/qquickimage.cpp
      
      QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
      {
          Q_D(QQuickImage);    QSGTexture *texture = d->sceneGraphRenderContext()->textureForFactory(d->pix.textureFactory(), window());    // Copy over the current texture state into the texture provider...
          if (d->provider) {
              d->provider->m_smooth = d->smooth;
              d->provider->m_mipmap = d->mipmap;
              d->provider->updateTexture(texture);
          }       
      
          if (!texture || width() <= 0 || height() <= 0) {
              delete oldNode;
              return nullptr;
          }
      
      // ...
      
      }

      in QQuickNinePatchImage, however, provider's texture remains regardless whether current image is valid or not. it seems to cause dangling problem. 

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

            qt.team.quick.subscriptions Qt Quick and Widgets Team
            sukyoungoh Oh Sukyoung
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: