v4l2: Warn, don't assert if v4l gives us a buffer with a too large size
authorWilliam Manley <will@williammanley.net>
Sat, 8 Oct 2016 16:11:17 +0000 (18:11 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Tue, 1 Nov 2016 18:12:56 +0000 (20:12 +0200)
I've seen problems where the `bytesused` field of `v4l2_buffer` would be
a silly number causing the later call to:

    gst_memory_resize (group->mem[i], 0, group->planes[i].bytesused);

to result in this error to be printed:

    (pulsevideo:11): GStreamer-CRITICAL **: gst_memory_resize: assertion 'size + mem->offset + offset <= mem->maxsize' failed

besides causing who-knows what other problems.

We make the assumption that this buffer has still been dequeued correctly
so just clamp to a valid size so downstream elements won't end up in
undefined behaviour.

The invalid `v4l2_buffer` I saw from my capture device was:

    buffer = {
      index = 0,
      type = 1,
      bytesused = 534748928, // <- Invalid
      flags = 8260, // V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC | V4L2_BUF_FLAG_ERROR | V4L2_BUF_FLAG_DONE
      field = 01330, // <- Invalid
      timestamp = {
        tv_sec = 0,
        tv_usec = 0
      },
      timecode = {
        type = 0,
        flags = 0,
        frames = 0 '\000',
        seconds = 0 '\000',
        minutes = 0 '\000',
        hours = 0 '\000',
        userbits = "\000\000\000"
      },
      sequence = 0,
      memory = 2,
      m = {
        offset = 3537219584,
        userptr = 140706665836544, // Could be nonsense, not sure
        planes = 0x7ff8d2d5b000,
        fd = -757747712
      },
      length = 2764800,
      reserved2 = 0,
      reserved = 0
    }

This is from gdb with my own annotations added.

This was with gst-plugins-good 1.8.1, a Magewell XI100DUSB-HDMI video
capture device and kernel 3.13 using a dodgy HDMI cable which is great at
breaking HDMI capture devices.  I'm using io-mode=userptr and have built
gst-plugins-good without libv4l.

https://bugzilla.gnome.org/show_bug.cgi?id=769765

sys/v4l2/gstv4l2allocator.c

index 923b10f0dc27f0474cedeaac8ea79462ee4ea8e2..655c2cacc36bb7bc79b6f50a893a6481913f657f 100644 (file)
@@ -1327,7 +1327,16 @@ gst_v4l2_allocator_dqbuf (GstV4l2Allocator * allocator,
   } else {
     /* for capture, simply read the size */
     for (i = 0; i < group->n_mem; i++) {
-      gst_memory_resize (group->mem[i], 0, group->planes[i].bytesused);
+      if (G_LIKELY (group->planes[i].bytesused <= group->mem[i]->maxsize))
+        gst_memory_resize (group->mem[i], 0, group->planes[i].bytesused);
+      else {
+        GST_WARNING_OBJECT (allocator,
+            "v4l2 provided buffer that is too big for the memory it was "
+            "writing into.  v4l2 claims %" G_GUINT32_FORMAT " bytes used but "
+            "memory is only %" G_GSIZE_FORMAT "B.  This is probably a driver "
+            "bug.", group->planes[i].bytesused, group->mem[i]->maxsize);
+        gst_memory_resize (group->mem[i], 0, group->mem[i]->maxsize);
+      }
     }
   }