vlfeat / vlfeat

An open library of computer vision algorithms

Home Page:http://vlfeat.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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 have o=0
  • In its caller, _vl_scalespace_start_octave_from_image, we have o=-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

copy_and_downsample(level, image, self->geom.width, self->geom.height, VL_MAX(0, o)) ;

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?