blog tags:

About:

I'm Dmitry Popov,
lead developer and director of Infognition.

Known in the interwebs as Dee Mon since 1997. You could see me as thedeemon on reddit or LiveJournal.

RSS
Articles Technology Blog News Company
Blog
Buggy VirtualDub filters
August 16, 2012

The same day I was dealing with VDFilter issue described in previous post I ran Video Enhancer (which also uses VDFilter), picked a random VirtualDub plugin and tried to process one file. Suddenly I've got a message telling me about an exception arised inside that VirtualDub plugin. Most VD plugins have been here for a while and are known for thair speed, stability and high quality, so I immediately decided the problem was in VDFilter, our DirectShow wrapper for those plugins. I started a debug session to find what caused the exception and luckily the source code for that plugin was available on its web page. The plugin is called Flip 1.1 (ef_flip.vdf from the big collection of filters by Emiliano Ferrari). To my surprise however I've found the bug quite fast and it was not in VDFilter, this time it was in the plugin itself. Source code of the main routine is pretty short:

void Rotate180 (Pixel32 *dst,Pixel32 *tmp,const int pitch,const int w,const int h,
                const FilterFunctions *ff)
{
  Pixel32 *a,*b;
  int i;

  a= dst;
  b= dst + (h*pitch);
  int alf = h/2;
  if (h&1) alf++;

  for (int j=0; j<alf; j++)
  {
    _memcpy (tmp,a,w*sizeof(Pixel32)); // tmp= a;
    a+= w;
    for (i=0; i<w; i++) *a--= *b++;   // a=b
    for (i=0; i<w; i++) *b--= *tmp++; // b=tmp
    tmp-= w;
    a+= pitch;
    b-= pitch;
  }
  if (!(h&1)) // even lines
  {
    _memcpy (tmp,a,w*sizeof(Pixel32));
    a+= w;
    for (i=0; i<w; i++) *a--= *tmp++;
  }
}
Take a look at the two red lines. h is the image height and pitch here is equal to the number of Pixel32 values in one row of image, so h*pitch is the number of pixels in whole image. At first pointer b points to dst + (h*pitch), i.e. the first byte outside the image buffer! And then in the loop it's being read and then incremented to point even farther from the end of the buffer. It didn't cause crashes in VirtualDub because for some reason memory after the image buffer always belonged to the application, however it did read garbage there so the first line of "rotated" image should contain garbage after applying this filter. In case of VDFilter and its use in Video Enhancer one line of memory after the image buffer not always completely belonged to the program, so for small frames it worked ok but with a larger frame the b pointer walked too far and caused a segmentation fault which was caught as an exception and caused our wrapper to show the message box.

It may be the case that author assumed pitch to be a negative value, however this assumption doesn't look correct. Here's a quote from VirtualDub Plugin SDK:
"Bitmaps can be stored top-down as well as bottom-up. The pitch value value is positive if the image is stored bottom-up in memory and negative if the image is stored top-down. This is only permitted if the filter declares support for flexible formats by returning FILTERPARAM_SUPPORTS_ALTFORMATS from paramProc; otherwise, the host ensures that the filter receives a bottom-up orientation with a positive pitch, flipping the bitmap beforehand if necessary."

Lessons learned: 1) some VirtualDub plugins, even very simple ones, may contain bugs. 2) pointer arithmetic requires a lot of attention to be used correctly.