We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 936

Summary: Segmentation fault when using SDL_DisplayYUVOverlay
Product: SDL Reporter: Paul <kylester36>
Component: videoAssignee: Sam Lantinga <slouken>
Status: RESOLVED FIXED QA Contact: Sam Lantinga <slouken>
Severity: normal    
Priority: P2    
Version: 1.2.14   
Hardware: x86   
OS: Linux   

Description Paul 2010-01-22 12:02:23 UTC
Hi,

Firstly, accept my apologies if I'm going about this the wrong way -- I'm a new user to SDL in the specific, and to Open source development in the general.

I've some software I've written (for Linux) that interacts with a camera, and uses SDL to display the images on the system.  My application was occasionally getting a segmentation fault when displaying images from the camera, depending on the image size, and the size of the display window.

I chased down the error, and I found the 'crux' of the error seems to be from within the SDL_stretch.c module.  More specifically, here is a code snippet from SDL_SoftStretch:

#ifdef USE_ASM_STRETCH
	/* Write the opcodes for this stretch */
	if ( (bpp == 3) ||
	     (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0) ) {
		use_asm = SDL_FALSE;
	}
#endif

and the corresponding definition of generate_rowbytes is found as follows:


static unsigned char copy_row[4096] PAGE_ALIGNED;

static int generate_rowbytes(int src_w, int dst_w, int bpp)
{
	static struct {
		int bpp;
		int src_w;
		int dst_w;
		int status;
	} last;

	int i;
	int pos, inc;
	unsigned char *eip;
	unsigned char load, store;

	/* See if we need to regenerate the copy buffer */
	if ( (src_w == last.src_w) &&
	     (dst_w == last.dst_w) && (bpp == last.bpp) ) {
		return(last.status);
	}
	last.bpp = bpp;
	last.src_w = src_w;
	last.dst_w = dst_w;
	last.status = -1;

	switch (bpp) {
	    case 1:
		load = LOAD_BYTE;
		store = STORE_BYTE;
		break;
	    case 2:
	    case 4:
		load = LOAD_WORD;
		store = STORE_WORD;
		break;
	    default:
		SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp);
		return(-1);
	}
#ifdef HAVE_MPROTECT
	/* Make the code writeable */
	if ( mprotect(copy_row, sizeof(copy_row), PROT_READ|PROT_WRITE) < 0 ) {
		SDL_SetError("Couldn't make copy buffer writeable");
		return(-1);
	}
#endif
	pos = 0x10000;
	inc = (src_w << 16) / dst_w;
	eip = copy_row;
	for ( i=0; i<dst_w; ++i ) {
		while ( pos >= 0x10000L ) {
			if ( bpp == 2 ) {
				*eip++ = PREFIX16;
			}
			*eip++ = load;
			pos -= 0x10000L;
		}
		if ( bpp == 2 ) {
			*eip++ = PREFIX16;
		}
		*eip++ = store;
		pos += inc;
	}
	*eip++ = RETURN;

	/* Verify that we didn't overflow (too late!!!) */
	if ( eip > (copy_row+sizeof(copy_row)) ) {
		SDL_SetError("Copy buffer overflow");
		return(-1);
	}
#ifdef HAVE_MPROTECT
	/* Make the code executable but not writeable */
	if ( mprotect(copy_row, sizeof(copy_row), PROT_READ|PROT_EXEC) < 0 ) {
		SDL_SetError("Couldn't make copy buffer executable");
		return(-1);
	}
#endif
	last.status = 0;
	return(0);
}

The problem I'm having is with the copy_row structure (which BTW -- is really cool, once I figured out what it wsa doing).  In my case the images coming from the camera are 'large' (1600x1200), and the 'scaling' factor is kind of big too -- I'm attempting to display the image in a 640x640 window.  The problem I'm encountering is, the copy_row structure is being overflown, corrupting what happens to reside below the copy_buffer structure.  This (eventually) causes a segmentation fault.

There is code above that 'detects' the overflow, and returns -1 of that is the case -- but as you can see from its use in SDL_SoftStretch, it just makes a point of not using the assembly routines, and carries on none the wiser that damage had been done.

At a suggestion, I changed my local copy to add another static structure after copy_row (called copy_row_limit).  I then changed the loop shown above too:

	for ( i=0; i<dst_w && eip<copy_row_limit; ++i ) {
		while ( pos >= 0x10000L ) {
			if ( bpp == 2 ) {
				*eip++ = PREFIX16;
			}
			*eip++ = load;
			pos -= 0x10000L;
		}
		if ( bpp == 2 ) {
			*eip++ = PREFIX16;
		}
		*eip++ = store;
		pos += inc;
	}
	*eip++ = RETURN;

	/* Verify that we didn't overflow (too late!!!) */
	if ( eip > copy_row_limit ) {
		SDL_SetError("Copy buffer overflow");
		return(-1);
	}
I sized the copy_row_limit to 8 + (4 times the maximum scaling factor that I permit (8)).

Thanks.

/Paul
Comment 1 Sam Lantinga 2010-07-18 10:08:50 UTC
This is fixed in revision abb56f7699ea, thanks!
Comment 2 Sam Lantinga 2010-07-18 10:29:30 UTC
Okay, I put in a safer fix in revision d7cdc25af9a2