vl_covdet_put_image segfaults on small images
nh2 opened this issue · comments
The docs of vl_covdet_put_image() say:
@a width and @a height must be at least one pixel.
But the function crashes with an invalid memcpy()
segfault when given a small (14x14 pixels) image.
The segfault is:
(gdb) bt
#0 0x00007fbceaff1ab6 in __memmove_sse2_unaligned_erms () from /nix/store/s5309bij5zch4x9qlq4ba3cwanab0xp6-glibc-2.30/lib/libc.so.6
#1 0x00007fbcea6fb034 in memcpy (__len=<optimized out>, __src=0x7fbc9c00c700, __dest=<optimized out>) at /nix/store/9y9hgbczizwqzci2vfl2phnk9rz50fiq-glibc-2.30-dev/include/bits/string_fortified.h:34
#2 copy_and_downsample (numOctaves=0, height=<optimized out>, width=14, source=0x7fbc9c00c700, destination=<optimized out>) at vl/scalespace.c:510
#3 copy_and_downsample (numOctaves=0, height=<optimized out>, width=14, source=0x7fbc9c00c700, destination=<optimized out>) at vl/scalespace.c:498
#4 _vl_scalespace_start_octave_from_image (o=-1, image=0x7fbc9c00c700, self=0x7fbc9c00d240) at vl/scalespace.c:719
#5 vl_scalespace_put_image (self=0x7fbc9c00d240, image=image@entry=0x7fbc9c00c700) at vl/scalespace.c:815
#6 0x00007fbcea71b723 in vl_covdet_put_image (self=self@entry=0x7fbc9c00dee0, image=0x7fbc9c00c700, width=14, height=14) at vl/covdet.c:1742
Without assertions enabled (see e.g. #216), we get:
vl/scalespace.c:396: vl_scalespace_get_level: Assertion `o <= self->geom.lastOctave' failed.
Trace in that case:
(gdb) bt
#0 0x00007fffde72415a in raise () from /nix/store/s5309bij5zch4x9qlq4ba3cwanab0xp6-glibc-2.30/lib/libc.so.6
#1 0x00007fffde70e548 in abort () from /nix/store/s5309bij5zch4x9qlq4ba3cwanab0xp6-glibc-2.30/lib/libc.so.6
#2 0x00007fffde70e42f in __assert_fail_base.cold.0 () from /nix/store/s5309bij5zch4x9qlq4ba3cwanab0xp6-glibc-2.30/lib/libc.so.6
#3 0x00007fffde71cad2 in __assert_fail () from /nix/store/s5309bij5zch4x9qlq4ba3cwanab0xp6-glibc-2.30/lib/libc.so.6
#4 0x00007fffdde94d9f in vl_scalespace_get_level (self=self@entry=0x7fff44006e00, o=o@entry=0, s=-1) at vl/scalespace.c:401
#5 0x00007fffdde953b0 in _vl_scalespace_start_octave_from_image (o=-1, image=0x7fff4403af40, self=0x7fff44006e00) at vl/scalespace.c:718
#6 vl_scalespace_put_image (self=0x7fff44006e00, image=image@entry=0x7fff4403af40) at vl/scalespace.c:815
#7 0x00007fffddeb6917 in vl_covdet_put_image (self=self@entry=0x7fff4400dee0, image=0x7fff4403af40, width=14, height=14) at vl/covdet.c:1742
Printing some details:
(gdb) up
#4 0x00007fffdde94d9f in vl_scalespace_get_level (self=self@entry=0x7fff44006e00, o=o@entry=0, s=-1) at vl/scalespace.c:401
401 in vl/scalespace.c
(gdb) p self->geom
$7 = {width = 14, height = 14, firstOctave = -1, lastOctave = -1, octaveResolution = 3, octaveFirstSubdivision = -1, octaveLastSubdivision = 4, baseScale = 2.0158736798317971, nominalScale = 0.5}
Note here:
- In
vl_scalespace_get_level
(where the assertion is), we haveo=0
- In its caller,
_vl_scalespace_start_octave_from_image
, we haveo=-1
firstOctave = -1, lastOctave = -1
In vl_covdet_put_image()
, lastOctave
is computed as:
vl_size const minOctaveSize = 16 ;
lastOctave = vl_floor_d(vl_log2_d(VL_MIN((double)width-1,(double)height-1) / (minOctaveSize - 1))) ;
which is lastOctave = -1
if you plug in all values.
So this means: With firstOctave = lastOctave = -1
, we should never evaluate octave 0, yet that's what _vl_scalespace_start_octave_from_image
does unconditionally in
Line 719 in 1b9075f
because it uses VL_MAX(0, o)
.
Either:
- the docs are wrong and
at least one pixel
should be "at least 16 pixels" - or the code is wrong and should not evaluate octave 0
Which is it?