Infinite loop in spa_v4l2_enum_format
I'm not sure I entirely understand the code, so bear with me. Basically, I noticed that pipewire was using 100% CPU on my machine and leaking memory like a sieve. I checked out the master
branch, compiled it, ran pipewire
, and it had the same behavior.
Attaching strace shows the following, repeated over and over:
stat("/dev/video1", {st_mode=S_IFCHR|0660, st_rdev=makedev(81, 1), ...}) = 0
openat(AT_FDCWD, "/dev/video1", O_RDWR|O_NONBLOCK) = 16
ioctl(16, VIDIOC_QUERYCAP, {driver="facetimehd", card="Apple Facetime HD", bus_info="PCI:0000:04:00.0", version=4.15.3, capabilities=V4L2_CAP_VIDEO_CAPTURE|V4L2_CAP_READWRITE|V4L2_CAP_STREAMING|V4L2_CAP_DEVICE_CAPS|V4L2_CAP_EXT_PIX_FORMAT, device_caps=V4L2_CAP_VIDEO_CAPTURE|V4L2_CAP_READWRITE|V4L2_CAP_STREAMING|V4L2_CAP_EXT_PIX_FORMAT}) = 0
ioctl(16, VIDIOC_ENUM_FRAMEINTERVALS, {index=0, pixel_format=v4l2_fourcc('Y', 'U', 'Y', 'V'), width=320, height=240, type=V4L2_FRMIVAL_TYPE_STEPWISE, stepwise={min=33/1000, max=500/1000, step=1/1000}}) = 0
close(16) = 0
stat("/dev/video1", {st_mode=S_IFCHR|0660, st_rdev=makedev(81, 1), ...}) = 0
openat(AT_FDCWD, "/dev/video1", O_RDWR|O_NONBLOCK) = 16
ioctl(16, VIDIOC_QUERYCAP, {driver="facetimehd", card="Apple Facetime HD", bus_info="PCI:0000:04:00.0", version=4.15.3, capabilities=V4L2_CAP_VIDEO_CAPTURE|V4L2_CAP_READWRITE|V4L2_CAP_STREAMING|V4L2_CAP_DEVICE_CAPS|V4L2_CAP_EXT_PIX_FORMAT, device_caps=V4L2_CAP_VIDEO_CAPTURE|V4L2_CAP_READWRITE|V4L2_CAP_STREAMING|V4L2_CAP_EXT_PIX_FORMAT}) = 0
ioctl(16, VIDIOC_ENUM_FRAMEINTERVALS, {index=0, pixel_format=v4l2_fourcc('Y', 'U', 'Y', 'V'), width=320, height=240, type=V4L2_FRMIVAL_TYPE_STEPWISE, stepwise={min=33/1000, max=500/1000, step=1/1000}}) = 0
close(16) = 0
stat("/dev/video1", {st_mode=S_IFCHR|0660, st_rdev=makedev(81, 1), ...}) = 0
openat(AT_FDCWD, "/dev/video1", O_RDWR|O_NONBLOCK) = 16
ioctl(16, VIDIOC_QUERYCAP, {driver="facetimehd", card="Apple Facetime HD", bus_info="PCI:0000:04:00.0", version=4.15.3, capabilities=V4L2_CAP_VIDEO_CAPTURE|V4L2_CAP_READWRITE|V4L2_CAP_STREAMING|V4L2_CAP_DEVICE_CAPS|V4L2_CAP_EXT_PIX_FORMAT, device_caps=V4L2_CAP_VIDEO_CAPTURE|V4L2_CAP_READWRITE|V4L2_CAP_STREAMING|V4L2_CAP_EXT_PIX_FORMAT}) = 0
ioctl(16, VIDIOC_ENUM_FRAMEINTERVALS, {index=0, pixel_format=v4l2_fourcc('Y', 'U', 'Y', 'V'), width=320, height=240, type=V4L2_FRMIVAL_TYPE_STEPWISE, stepwise={min=33/1000, max=500/1000, step=1/1000}}) = 0
close(16) = 0
I attached gdb and observed that spa_v4l2_enum_format
gets invoked repeatedly with a NULL filter
and an ever-increasing *index
. From reading the code, it looks like this function will be called until it returns zero, and there's no way for it to return zero with a NULL filter
: the only places that goto enum_end
are inside if(filter) { ... }
.
Sorry I don't understand the code well enough to submit a PR, but hopefully it's a trivial fix. :) If you need more to go on, please let me know.