BUG discovery & possible explanation

My name is Lion.
I think I’ve discovered the source of a bug.

Thank you very much. The solution, I think, is to add a FreeWAV API.
I had suspected that this might be a problem, and I thank you for the
confirmation. :slight_smile:

It will be fixed in the next CVS release.

Background: Windows 98, Visual C++ 6.0, SDL 0.9.9, .dll [Working on
BumpRacer]

Bug location:
This bug works in two parts: mixer.c, and SDL_wave.c

I’ve shown context code, so that you can get your bearings as you look at
this.

----------------------- mixer.c ------------------------------------

if ( wavecvt.len_mult == 1 ) {
wavecvt.len = chunk->alen;
wavecvt.buf = chunk->abuf;
} else {
wavecvt.len = chunk->alen;
wavecvt.buf = (Uint8 )malloc(wavecvt.lenwavecvt.len_mult);
if ( wavecvt.buf == NULL ) {
SDL_SetError(“Out of memory”);
free(chunk->abuf);
free(chunk);
return(NULL);
}
memcpy(wavecvt.buf, chunk->abuf, chunk->alen);

  // LION // The code wiggs out here.

//////////////////////////////////////////////////////////////////
// LION //
// LION // _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)) fails, and
pHead->nBlockUse is returning 1
// LION //
//

  free(chunk->abuf);
  //
  // LION

////////////////////////////////////////////////////////////////////////////
//////////////////
}

/* Run the audio converter */
if ( SDL_ConvertAudio(&wavecvt) < 0 ) {
free(wavecvt.buf);
free(chunk);
return(NULL);
}

and
SDL_AudioSpec *SDL_LoadWAV(const char *file, SDL_AudioSpec *spec, Uint8
**audio_buf, Uint32 *audio_len);

----------------------- SDL_Wave.c ------------------------------------

static int ReadChunk(FILE *fp, Chunk *chunk)
{
chunk->magic = SDL_ReadLE32(fp);
chunk->length = SDL_ReadLE32(fp);

// LION
////////////////////////////////////////////////////////////////////////////
// LION //
// LION // I believe that this is the source of the malloc that is being
freed.
// LION //
//
chunk->data = (Uint8 *)malloc(chunk->length);
//
// LION
////////////////////////////////////////////////////////////////////////////

if ( chunk->data == NULL ) {
SDL_Error(SDL_ENOMEM);
return(-1);
}
if ( fread(chunk->data, chunk->length, 1, fp) != 1 ) {
SDL_Error(SDL_EFREAD);
free(chunk->data);
return(-1);
}
return(chunk->length);
}


As I understand it, the assertion failure is caused because mixer.c is
attempting to free memory that belongs to a heap other than it’s own. In
Windows, every dll has it’s own heap. When SDL_Wave.c allocates the memory,
the memory is allocated within the SDL dll’s. When BumpRacer, which is using
mixer.c, tries to free the memory through the pointer given to it by SDL,
Visual C++ complains (_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse))
fails). And I believe that this is because the information is inside SDL’s
dll’s heap space.

When I did a web search to find a solution, I discovered the following:

" Memory Management
Most C runtime libraries (including the one with Visual C++) maintain
separate heaps for allocation in each module (DLL or main program). This
means that memory allocated in one module’s code cannot be freed in another
module’s code.
Some of the support functions allocate dynamic memory which you may need to
free later. You must use the wsapi_free() function to free memory allocated
by a support function. This calls back into the server so that the memory
gets freed from the server’s heap instaead of the DLL’s heap.

The cleanest way to handle dynamic memory is to use the wsapi_ versions of
the memory management functions for everything. That way, no matter how the
memory originally got allocated, you are safe in freeing it with
wsapi_free()."

Here’s another quote from another source:
"Creating 16-bit DLLs was not an easy task. Memory management became a real
problem, special compiler options were needed, and it was easy to lose and
abuse various system resources. One of the problems with memory management
was keeping track of who allocated memory and how memory pointers were
managed.

The big problem with memory management was that your EXE and DLL each had
their own memory heaps. When memory was allocated calling malloc() inside
the DLL, the memory was owned by the DLL and had to be managed by the DLL.
If the memory was allocated in your EXE, it was owned by the EXE and had to
be managed according. If your DLL tried to free() a block that was
malloc()ed by the EXE, or vice versa, the result was a corrupted heap."
-Windows Developer’s Journal, May 1998
(http://www.wdj.com/archive/0905/bug.html)

I hope this helps.

Please feel free to put me on whatever SDL mailing lists that you think I
would like to be on.

Take care,
Lion {:)}=

=-=-=-=-=-=-=-=-= Lion Kimbro =-=-=-=-=-=-=-=-=

http://home.sprynet.com/~snowlion/SnowLion.htm

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

-Sam Lantinga				(slouken at devolution.com)

Lead Programmer, Loki Entertainment Software–
Author of Simple DirectMedia Layer -
http://www.devolution.com/~slouken/SDL/