shithub: choc

Download patch

ref: a28f2f4333102961668354d75850c7ffebbdb194
parent: c878d6bc494457a2ca70f171a60d2ec5b85a9987
author: Simon Howard <fraggle@soulsphere.org>
date: Sun Aug 16 15:55:47 EDT 2015

wad: Change type of lumpinfo[] array.

Originally lumpinfo[] was an array of lumpinfo_t structs. However,
this is problematic because the array must be realloc()ed to
increase its size with each load of a new WAD. If data from one of
the WADs has already been cached in memory, the zone memory system's
user pointer can end up pointing at freed memory.

Therefore, any modification to lumpinfo[] had to be carefully
controlled - see previous commit d5b6bb70919f that applied an
attempted fix. However, this fix did not fix loading using the
merging command line parameters, which change lumpinfo[] in far more
complicated ways.

Instead, this fixes the issue in a more fundamental way. lumpinfo[]
is now an array of pointers to lumpinfo_t structs, disconnecting
their memory locations from their location in the lumpinfo[] array.
It's now possible to change or rearrange the array in any desired
way without the zone user pointers getting out of sync.

This also includes a minor change to define a lumpindex_t type for
representing lumpinfo[] indices, to make the WAD API more literate.

Thanks to Fabian Greffrath for identifying that the bug was still
present when using the merge parameters. This fixes #442 (again).

--- a/src/deh_io.c
+++ b/src/deh_io.c
@@ -120,7 +120,7 @@
     context->input_buffer_pos = 0;
 
     context->filename = malloc(9);
-    M_StringCopy(context->filename, lumpinfo[lumpnum].name, 9);
+    M_StringCopy(context->filename, lumpinfo[lumpnum]->name, 9);
 
     return context;
 }
--- a/src/doom/d_main.c
+++ b/src/doom/d_main.c
@@ -739,12 +739,12 @@
 
         for (i=0; i<numlumps; ++i)
         {
-            if (!strncasecmp(lumpinfo[i].name, "MAP01", 8))
+            if (!strncasecmp(lumpinfo[i]->name, "MAP01", 8))
             {
                 gamemission = doom2;
                 break;
             } 
-            else if (!strncasecmp(lumpinfo[i].name, "E1M1", 8))
+            else if (!strncasecmp(lumpinfo[i]->name, "E1M1", 8))
             {
                 gamemission = doom;
                 break;
@@ -1531,7 +1531,7 @@
 
         if (D_AddFile(file))
         {
-            M_StringCopy(demolumpname, lumpinfo[numlumps - 1].name,
+            M_StringCopy(demolumpname, lumpinfo[numlumps - 1]->name,
                          sizeof(demolumpname));
         }
         else
@@ -1566,7 +1566,7 @@
 
         for (i = numiwadlumps; i < numlumps; ++i)
         {
-            if (!strncmp(lumpinfo[i].name, "DEHACKED", 8))
+            if (!strncmp(lumpinfo[i]->name, "DEHACKED", 8))
             {
                 DEH_LoadLump(i, false, false);
                 loaded++;
--- a/src/doom/r_data.c
+++ b/src/doom/r_data.c
@@ -832,7 +832,7 @@
 	if (flatpresent[i])
 	{
 	    lump = firstflat + i;
-	    flatmemory += lumpinfo[lump].size;
+	    flatmemory += lumpinfo[lump]->size;
 	    W_CacheLumpNum(lump, PU_CACHE);
 	}
     }
@@ -869,7 +869,7 @@
 	for (j=0 ; j<texture->patchcount ; j++)
 	{
 	    lump = texture->patches[j].patch;
-	    texturememory += lumpinfo[lump].size;
+	    texturememory += lumpinfo[lump]->size;
 	    W_CacheLumpNum(lump , PU_CACHE);
 	}
     }
@@ -898,7 +898,7 @@
 	    for (k=0 ; k<8 ; k++)
 	    {
 		lump = firstspritelump + sf->lump[k];
-		spritememory += lumpinfo[lump].size;
+		spritememory += lumpinfo[lump]->size;
 		W_CacheLumpNum(lump , PU_CACHE);
 	    }
 	}
--- a/src/doom/r_things.c
+++ b/src/doom/r_things.c
@@ -208,22 +208,22 @@
 	//  filling in the frames for whatever is found
 	for (l=start+1 ; l<end ; l++)
 	{
-	    if (!strncasecmp(lumpinfo[l].name, spritename, 4))
+	    if (!strncasecmp(lumpinfo[l]->name, spritename, 4))
 	    {
-		frame = lumpinfo[l].name[4] - 'A';
-		rotation = lumpinfo[l].name[5] - '0';
+		frame = lumpinfo[l]->name[4] - 'A';
+		rotation = lumpinfo[l]->name[5] - '0';
 
 		if (modifiedgame)
-		    patched = W_GetNumForName (lumpinfo[l].name);
+		    patched = W_GetNumForName (lumpinfo[l]->name);
 		else
 		    patched = l;
 
 		R_InstallSpriteLump (patched, frame, rotation, false);
 
-		if (lumpinfo[l].name[6])
+		if (lumpinfo[l]->name[6])
 		{
-		    frame = lumpinfo[l].name[6] - 'A';
-		    rotation = lumpinfo[l].name[7] - '0';
+		    frame = lumpinfo[l]->name[6] - 'A';
+		    rotation = lumpinfo[l]->name[7] - '0';
 		    R_InstallSpriteLump (l, frame, rotation, true);
 		}
 	    }
--- a/src/heretic/d_main.c
+++ b/src/heretic/d_main.c
@@ -1018,7 +1018,7 @@
 
         if (D_AddFile(file))
         {
-            M_StringCopy(demolumpname, lumpinfo[numlumps - 1].name,
+            M_StringCopy(demolumpname, lumpinfo[numlumps - 1]->name,
                          sizeof(demolumpname));
         }
         else
--- a/src/heretic/r_data.c
+++ b/src/heretic/r_data.c
@@ -671,7 +671,7 @@
         if (flatpresent[i])
         {
             lump = firstflat + i;
-            flatmemory += lumpinfo[lump].size;
+            flatmemory += lumpinfo[lump]->size;
             W_CacheLumpNum(lump, PU_CACHE);
         }
 
@@ -701,7 +701,7 @@
         for (j = 0; j < texture->patchcount; j++)
         {
             lump = texture->patches[j].patch;
-            texturememory += lumpinfo[lump].size;
+            texturememory += lumpinfo[lump]->size;
             W_CacheLumpNum(lump, PU_CACHE);
         }
     }
@@ -731,7 +731,7 @@
             for (k = 0; k < 8; k++)
             {
                 lump = firstspritelump + sf->lump[k];
-                spritememory += lumpinfo[lump].size;
+                spritememory += lumpinfo[lump]->size;
                 W_CacheLumpNum(lump, PU_CACHE);
             }
         }
--- a/src/heretic/r_things.c
+++ b/src/heretic/r_things.c
@@ -175,15 +175,15 @@
         // scan the lumps, filling in the frames for whatever is found
         //
         for (l = start + 1; l < end; l++)
-            if (!strncasecmp(lumpinfo[l].name, spritename, 4))
+            if (!strncasecmp(lumpinfo[l]->name, spritename, 4))
             {
-                frame = lumpinfo[l].name[4] - 'A';
-                rotation = lumpinfo[l].name[5] - '0';
+                frame = lumpinfo[l]->name[4] - 'A';
+                rotation = lumpinfo[l]->name[5] - '0';
                 R_InstallSpriteLump(l, frame, rotation, false);
-                if (lumpinfo[l].name[6])
+                if (lumpinfo[l]->name[6])
                 {
-                    frame = lumpinfo[l].name[6] - 'A';
-                    rotation = lumpinfo[l].name[7] - '0';
+                    frame = lumpinfo[l]->name[6] - 'A';
+                    rotation = lumpinfo[l]->name[7] - '0';
                     R_InstallSpriteLump(l, frame, rotation, true);
                 }
             }
--- a/src/hexen/h2_main.c
+++ b/src/hexen/h2_main.c
@@ -663,7 +663,7 @@
 
         if (W_AddFile(file) != NULL)
         {
-            M_StringCopy(demolumpname, lumpinfo[numlumps - 1].name,
+            M_StringCopy(demolumpname, lumpinfo[numlumps - 1]->name,
                          sizeof(demolumpname));
         }
         else
--- a/src/hexen/r_data.c
+++ b/src/hexen/r_data.c
@@ -627,7 +627,7 @@
         if (flatpresent[i])
         {
             lump = firstflat + i;
-            flatmemory += lumpinfo[lump].size;
+            flatmemory += lumpinfo[lump]->size;
             W_CacheLumpNum(lump, PU_CACHE);
         }
 
@@ -658,7 +658,7 @@
         for (j = 0; j < texture->patchcount; j++)
         {
             lump = texture->patches[j].patch;
-            texturememory += lumpinfo[lump].size;
+            texturememory += lumpinfo[lump]->size;
             W_CacheLumpNum(lump, PU_CACHE);
         }
     }
@@ -688,7 +688,7 @@
             for (k = 0; k < 8; k++)
             {
                 lump = firstspritelump + sf->lump[k];
-                spritememory += lumpinfo[lump].size;
+                spritememory += lumpinfo[lump]->size;
                 W_CacheLumpNum(lump, PU_CACHE);
             }
         }
--- a/src/hexen/r_things.c
+++ b/src/hexen/r_things.c
@@ -178,15 +178,15 @@
         // scan the lumps, filling in the frames for whatever is found
         //
         for (l = start + 1; l < end; l++)
-            if (!strncmp(lumpinfo[l].name, namelist[i], 4))
+            if (!strncmp(lumpinfo[l]->name, namelist[i], 4))
             {
-                frame = lumpinfo[l].name[4] - 'A';
-                rotation = lumpinfo[l].name[5] - '0';
+                frame = lumpinfo[l]->name[4] - 'A';
+                rotation = lumpinfo[l]->name[5] - '0';
                 R_InstallSpriteLump(l, frame, rotation, false);
-                if (lumpinfo[l].name[6])
+                if (lumpinfo[l]->name[6])
                 {
-                    frame = lumpinfo[l].name[6] - 'A';
-                    rotation = lumpinfo[l].name[7] - '0';
+                    frame = lumpinfo[l]->name[6] - 'A';
+                    rotation = lumpinfo[l]->name[7] - '0';
                     R_InstallSpriteLump(l, frame, rotation, true);
                 }
             }
--- a/src/i_sdlmusic.c
+++ b/src/i_sdlmusic.c
@@ -752,7 +752,7 @@
 
     for (lumpnum = 0; lumpnum < numlumps; ++lumpnum)
     {
-        strncpy(name, lumpinfo[lumpnum].name, 8);
+        strncpy(name, lumpinfo[lumpnum]->name, 8);
         name[8] = '\0';
 
         if (!IsMusicLump(lumpnum))
--- a/src/strife/d_main.c
+++ b/src/strife/d_main.c
@@ -1629,7 +1629,7 @@
 
         if (D_AddFile (file))
         {
-            M_StringCopy(demolumpname, lumpinfo[numlumps - 1].name,
+            M_StringCopy(demolumpname, lumpinfo[numlumps - 1]->name,
                          sizeof(demolumpname));
         }
         else
--- a/src/strife/r_data.c
+++ b/src/strife/r_data.c
@@ -938,7 +938,7 @@
 	if (flatpresent[i])
 	{
 	    lump = firstflat + i;
-	    flatmemory += lumpinfo[lump].size;
+	    flatmemory += lumpinfo[lump]->size;
 	    W_CacheLumpNum(lump, PU_CACHE);
 	}
     }
@@ -975,7 +975,7 @@
 	for (j=0 ; j<texture->patchcount ; j++)
 	{
 	    lump = texture->patches[j].patch;
-	    texturememory += lumpinfo[lump].size;
+	    texturememory += lumpinfo[lump]->size;
 	    W_CacheLumpNum(lump , PU_CACHE);
 	}
     }
@@ -1004,7 +1004,7 @@
 	    for (k=0 ; k<8 ; k++)
 	    {
 		lump = firstspritelump + sf->lump[k];
-		spritememory += lumpinfo[lump].size;
+		spritememory += lumpinfo[lump]->size;
 		W_CacheLumpNum(lump , PU_CACHE);
 	    }
 	}
--- a/src/strife/r_things.c
+++ b/src/strife/r_things.c
@@ -211,22 +211,22 @@
 	//  filling in the frames for whatever is found
 	for (l=start+1 ; l<end ; l++)
 	{
-	    if (!strncasecmp(lumpinfo[l].name, spritename, 4))
+	    if (!strncasecmp(lumpinfo[l]->name, spritename, 4))
 	    {
-		frame = lumpinfo[l].name[4] - 'A';
-		rotation = lumpinfo[l].name[5] - '0';
+		frame = lumpinfo[l]->name[4] - 'A';
+		rotation = lumpinfo[l]->name[5] - '0';
 
 		if (modifiedgame)
-		    patched = W_GetNumForName (lumpinfo[l].name);
+		    patched = W_GetNumForName (lumpinfo[l]->name);
 		else
 		    patched = l;
 
 		R_InstallSpriteLump (patched, frame, rotation, false);
 
-		if (lumpinfo[l].name[6])
+		if (lumpinfo[l]->name[6])
 		{
-		    frame = lumpinfo[l].name[6] - 'A';
-		    rotation = lumpinfo[l].name[7] - '0';
+		    frame = lumpinfo[l]->name[6] - 'A';
+		    rotation = lumpinfo[l]->name[7] - '0';
 		    R_InstallSpriteLump (l, frame, rotation, true);
 		}
 	    }
--- a/src/w_checksum.c
+++ b/src/w_checksum.c
@@ -33,7 +33,7 @@
     int i;
     int result;
 
-    for (i=0; i<num_open_wadfiles; ++i)
+    for (i = 0; i < num_open_wadfiles; ++i)
     {
         if (open_wadfiles[i] == handle)
         {
@@ -77,11 +77,11 @@
     // Go through each entry in the WAD directory, adding information
     // about each entry to the SHA1 hash.
 
-    for (i=0; i<numlumps; ++i)
+    for (i = 0; i < numlumps; ++i)
     {
-        ChecksumAddLump(&sha1_context, &lumpinfo[i]);
+        ChecksumAddLump(&sha1_context, lumpinfo[i]);
     }
-    
+
     SHA1_Final(digest, &sha1_context);
 }
 
--- a/src/w_merge.c
+++ b/src/w_merge.c
@@ -39,7 +39,7 @@
 
 typedef struct
 {
-    lumpinfo_t *lumps;
+    lumpinfo_t **lumps;
     int numlumps;
 } searchlist_t;
 
@@ -74,7 +74,7 @@
 
     for (i=0; i<list->numlumps; ++i)
     {
-        if (!strncasecmp(list->lumps[i].name, name, 8))
+        if (!strncasecmp(list->lumps[i]->name, name, 8))
             return i;
     }
 
@@ -352,7 +352,7 @@
     
     for (i=0; i<iwad_sprites.numlumps; ++i)
     {
-        AddSpriteLump(&iwad_sprites.lumps[i]);
+        AddSpriteLump(iwad_sprites.lumps[i]);
     }
     
     // Add all sprites from the PWAD
@@ -360,7 +360,7 @@
 
     for (i=0; i<pwad_sprites.numlumps; ++i)
     {
-        AddSpriteLump(&pwad_sprites.lumps[i]);
+        AddSpriteLump(pwad_sprites.lumps[i]);
     }
 }
 
@@ -386,13 +386,13 @@
 static void DoMerge(void)
 {
     section_t current_section;
-    lumpinfo_t *newlumps;
+    lumpinfo_t **newlumps;
     int num_newlumps;
     int lumpindex;
     int i, n;
-    
+
     // Can't ever have more lumps than we already have
-    newlumps = malloc(sizeof(lumpinfo_t) * numlumps);
+    newlumps = calloc(numlumps, sizeof(lumpinfo_t *));
     num_newlumps = 0;
 
     // Add IWAD lumps
@@ -400,7 +400,7 @@
 
     for (i=0; i<iwad.numlumps; ++i)
     {
-        lumpinfo_t *lump = &iwad.lumps[i];
+        lumpinfo_t *lump = iwad.lumps[i];
 
         switch (current_section)
         {
@@ -414,7 +414,7 @@
                     current_section = SECTION_SPRITES;
                 }
 
-                newlumps[num_newlumps++] = *lump;
+                newlumps[num_newlumps++] = lump;
 
                 break;
 
@@ -432,7 +432,7 @@
                         newlumps[num_newlumps++] = pwad_flats.lumps[n];
                     }
 
-                    newlumps[num_newlumps++] = *lump;
+                    newlumps[num_newlumps++] = lump;
 
                     // back to normal reading
                     current_section = SECTION_NORMAL;
@@ -448,7 +448,7 @@
 
                     if (lumpindex < 0)
                     {
-                        newlumps[num_newlumps++] = *lump;
+                        newlumps[num_newlumps++] = lump;
                     }
                 }
 
@@ -460,11 +460,11 @@
 
                 if (!strncasecmp(lump->name, "S_END", 8))
                 {
-                    // add all the pwad sprites
+                    // add all the PWAD sprites
 
                     for (n=0; n<pwad_sprites.numlumps; ++n)
                     {
-                        if (SpriteLumpNeeded(&pwad_sprites.lumps[n]))
+                        if (SpriteLumpNeeded(pwad_sprites.lumps[n]))
                         {
                             newlumps[num_newlumps++] = pwad_sprites.lumps[n];
                         }
@@ -471,7 +471,7 @@
                     }
 
                     // copy the ending
-                    newlumps[num_newlumps++] = *lump;
+                    newlumps[num_newlumps++] = lump;
 
                     // back to normal reading
                     current_section = SECTION_NORMAL;
@@ -483,7 +483,7 @@
 
                     if (SpriteLumpNeeded(lump))
                     {
-                        newlumps[num_newlumps++] = *lump;
+                        newlumps[num_newlumps++] = lump;
                     }
                 }
 
@@ -496,7 +496,7 @@
 
     for (i=0; i<pwad.numlumps; ++i)
     {
-        lumpinfo_t *lump = &pwad.lumps[i];
+        lumpinfo_t *lump = pwad.lumps[i];
 
         switch (current_section)
         {
@@ -515,7 +515,7 @@
                 {
                     // Don't include the headers of sections
        
-                    newlumps[num_newlumps++] = *lump;
+                    newlumps[num_newlumps++] = lump;
                 }
                 break;
 
@@ -550,7 +550,6 @@
     free(lumpinfo);
     lumpinfo = newlumps;
     numlumps = num_newlumps;
-
 }
 
 void W_PrintDirectory(void)
@@ -560,8 +559,8 @@
     // debug
     for (i=0; i<numlumps; ++i)
     {
-        for (n=0; n<8 && lumpinfo[i].name[n] != '\0'; ++n)
-            putchar(lumpinfo[i].name[n]);
+        for (n=0; n<8 && lumpinfo[i]->name[n] != '\0'; ++n)
+            putchar(lumpinfo[i]->name[n]);
         putchar('\n');
     }
 }
@@ -579,7 +578,7 @@
     if (W_AddFile(filename) == NULL)
         return;
 
-    // iwad is at the start, pwad was appended to the end
+    // IWAD is at the start, PWAD was appended to the end
 
     iwad.lumps = lumpinfo;
     iwad.numlumps = old_numlumps;
@@ -606,25 +605,23 @@
 {
     int i;
 
-    // Go through the IWAD list given, replacing lumps with lumps of 
+    // Go through the IWAD list given, replacing lumps with lumps of
     // the same name from the PWAD
-
     for (i=0; i<list->numlumps; ++i)
     {
         int index;
 
-        index = FindInList(&pwad, list->lumps[i].name);
+        index = FindInList(&pwad, list->lumps[i]->name);
 
         if (index > 0)
         {
-            memcpy(&list->lumps[i], &pwad.lumps[index], 
+            memcpy(list->lumps[i], pwad.lumps[index],
                    sizeof(lumpinfo_t));
         }
     }
-    
 }
 
-// Merge sprites and flats in the way NWT does with its -af and -as 
+// Merge sprites and flats in the way NWT does with its -af and -as
 // command-line options.
 
 void W_NWTMergeFile(char *filename, int flags)
@@ -638,7 +635,7 @@
     if (W_AddFile(filename) == NULL)
         return;
 
-    // iwad is at the start, pwad was appended to the end
+    // IWAD is at the start, PWAD was appended to the end
 
     iwad.lumps = lumpinfo;
     iwad.numlumps = old_numlumps;
@@ -645,13 +642,13 @@
 
     pwad.lumps = lumpinfo + old_numlumps;
     pwad.numlumps = numlumps - old_numlumps;
-    
+
     // Setup sprite/flat lists
 
     SetupLists();
 
     // Merge in flats?
-    
+
     if (flags & W_NWT_MERGE_FLATS)
     {
         W_NWTAddLumps(&iwad_flats);
@@ -690,7 +687,7 @@
         return;
     }
 
-    // iwad is at the start, pwad was appended to the end
+    // IWAD is at the start, PWAD was appended to the end
 
     iwad.lumps = lumpinfo;
     iwad.numlumps = old_numlumps;
@@ -697,7 +694,7 @@
 
     pwad.lumps = lumpinfo + old_numlumps;
     pwad.numlumps = numlumps - old_numlumps;
-    
+
     // Setup sprite/flat lists
 
     SetupLists();
@@ -706,12 +703,12 @@
 
     for (i=0; i<iwad_sprites.numlumps; ++i)
     {
-        if (FindInList(&pwad, iwad_sprites.lumps[i].name) >= 0)
+        if (FindInList(&pwad, iwad_sprites.lumps[i]->name) >= 0)
         {
             // Replace this entry with an empty string.  This is what
             // nwt -merge does.
 
-            M_StringCopy(iwad_sprites.lumps[i].name, "", 8);
+            M_StringCopy(iwad_sprites.lumps[i]->name, "", 8);
         }
     }
 
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -57,16 +57,17 @@
 //
 
 // Location of each lump on disk.
-lumpinfo_t *lumpinfo;
+lumpinfo_t **lumpinfo;
 unsigned int numlumps = 0;
 
 // Hash table for fast lookups
-static lumpinfo_t **lumphash;
+static lumpindex_t *lumphash;
 
 // Variables for the reload hack: filename of the PWAD to reload, and the
 // lumps from WADs before the reload file, so we can resent numlumps and
 // load the file again.
 static wad_file_t *reloadhandle = NULL;
+static lumpinfo_t *reloadlumps = NULL;
 static char *reloadname = NULL;
 static int reloadlump = -1;
 
@@ -87,46 +88,6 @@
     return result;
 }
 
-// Increase the size of the lumpinfo[] array to the specified size.
-static void ExtendLumpInfo(int newnumlumps)
-{
-    lumpinfo_t *newlumpinfo;
-    unsigned int i;
-
-    newlumpinfo = calloc(newnumlumps, sizeof(lumpinfo_t));
-
-    if (newlumpinfo == NULL)
-    {
-	I_Error ("Couldn't realloc lumpinfo");
-    }
-
-    // Copy over lumpinfo_t structures from the old array. If any of
-    // these lumps have been cached, we need to update the user
-    // pointers to the new location.
-    for (i = 0; i < numlumps && i < newnumlumps; ++i)
-    {
-        memcpy(&newlumpinfo[i], &lumpinfo[i], sizeof(lumpinfo_t));
-
-        if (newlumpinfo[i].cache != NULL)
-        {
-            Z_ChangeUser(newlumpinfo[i].cache, &newlumpinfo[i].cache);
-        }
-
-        // We shouldn't be generating a hash table until after all WADs have
-        // been loaded, but just in case...
-        if (lumpinfo[i].next != NULL)
-        {
-            int nextlumpnum = lumpinfo[i].next - lumpinfo;
-            newlumpinfo[i].next = &newlumpinfo[nextlumpnum];
-        }
-    }
-
-    // All done.
-    free(lumpinfo);
-    lumpinfo = newlumpinfo;
-    numlumps = newnumlumps;
-}
-
 //
 // LUMP BASED ROUTINES.
 //
@@ -143,14 +104,14 @@
 wad_file_t *W_AddFile (char *filename)
 {
     wadinfo_t header;
-    lumpinfo_t *lump_p;
-    unsigned int i;
+    lumpindex_t i;
     wad_file_t *wad_file;
     int length;
     int startlump;
     filelump_t *fileinfo;
     filelump_t *filerover;
-    int newnumlumps;
+    lumpinfo_t *filelumps;
+    int numfilelumps;
 
     // If the filename begins with a ~, it indicates that we should use the
     // reload hack.
@@ -180,15 +141,6 @@
 	return NULL;
     }
 
-    // If this is the reload file, we need to save the file handle so that we
-    // can close it later on when we do a reload.
-    if (reloadname)
-    {
-        reloadhandle = wad_file;
-    }
-
-    newnumlumps = numlumps;
-
     if (strcasecmp(filename+strlen(filename)-3 , "wad" ) )
     {
 	// single lump file
@@ -206,9 +158,9 @@
         // extension).
 
 	M_ExtractFileBase (filename, fileinfo->name);
-	newnumlumps++;
+	numfilelumps = 1;
     }
-    else 
+    else
     {
 	// WAD file
         W_Read(wad_file, 0, &header, sizeof(header));
@@ -221,8 +173,8 @@
 		I_Error ("Wad file %s doesn't have IWAD "
 			 "or PWAD id\n", filename);
 	    }
-	    
-	    // ???modifiedgame = true;		
+
+	    // ???modifiedgame = true;
 	}
 
 	header.numlumps = LONG(header.numlumps);
@@ -231,26 +183,36 @@
 	fileinfo = Z_Malloc(length, PU_STATIC, 0);
 
         W_Read(wad_file, header.infotableofs, fileinfo, length);
-	newnumlumps += header.numlumps;
+	numfilelumps = header.numlumps;
     }
 
     // Increase size of numlumps array to accomodate the new file.
+    filelumps = calloc(numfilelumps, sizeof(lumpinfo_t));
+    if (filelumps == NULL)
+    {
+        I_Error("Failed to allocate array for lumps from new file.");
+    }
+
     startlump = numlumps;
-    ExtendLumpInfo(newnumlumps);
+    numlumps += numfilelumps;
+    lumpinfo = realloc(lumpinfo, numlumps * sizeof(lumpinfo_t *));
+    if (lumpinfo == NULL)
+    {
+        I_Error("Failed to increase lumpinfo[] array size.");
+    }
 
-    lump_p = &lumpinfo[startlump];
-
     filerover = fileinfo;
 
-    for (i=startlump; i<numlumps; ++i)
+    for (i = startlump; i < numlumps; ++i)
     {
-	lump_p->wad_file = wad_file;
-	lump_p->position = LONG(filerover->filepos);
-	lump_p->size = LONG(filerover->size);
+        lumpinfo_t *lump_p = &filelumps[i - startlump];
+        lump_p->wad_file = wad_file;
+        lump_p->position = LONG(filerover->filepos);
+        lump_p->size = LONG(filerover->size);
         lump_p->cache = NULL;
-	strncpy(lump_p->name, filerover->name, 8);
+        strncpy(lump_p->name, filerover->name, 8);
+        lumpinfo[i] = lump_p;
 
-        ++lump_p;
         ++filerover;
     }
 
@@ -262,6 +224,14 @@
         lumphash = NULL;
     }
 
+    // If this is the reload file, we need to save some details about the
+    // file so that we can close it later on when we do a reload.
+    if (reloadname)
+    {
+        reloadhandle = wad_file;
+        reloadlumps = filelumps;
+    }
+
     return wad_file;
 }
 
@@ -282,10 +252,9 @@
 // Returns -1 if name not found.
 //
 
-int W_CheckNumForName (char* name)
+lumpindex_t W_CheckNumForName(char* name)
 {
-    lumpinfo_t *lump_p;
-    int i;
+    lumpindex_t i;
 
     // Do we have a hash table yet?
 
@@ -292,28 +261,28 @@
     if (lumphash != NULL)
     {
         int hash;
-        
+
         // We do! Excellent.
 
         hash = W_LumpNameHash(name) % numlumps;
-        
-        for (lump_p = lumphash[hash]; lump_p != NULL; lump_p = lump_p->next)
+
+        for (i = lumphash[hash]; i != -1; i = lumpinfo[i]->next)
         {
-            if (!strncasecmp(lump_p->name, name, 8))
+            if (!strncasecmp(lumpinfo[i]->name, name, 8))
             {
-                return lump_p - lumpinfo;
+                return i;
             }
         }
-    } 
+    }
     else
     {
         // We don't have a hash table generate yet. Linear search :-(
-        // 
+        //
         // scan backwards so patch lump files take precedence
 
-        for (i=numlumps-1; i >= 0; --i)
+        for (i = numlumps - 1; i >= 0; --i)
         {
-            if (!strncasecmp(lumpinfo[i].name, name, 8))
+            if (!strncasecmp(lumpinfo[i]->name, name, 8))
             {
                 return i;
             }
@@ -332,12 +301,12 @@
 // W_GetNumForName
 // Calls W_CheckNumForName, but bombs out if not found.
 //
-int W_GetNumForName (char* name)
+lumpindex_t W_GetNumForName(char* name)
 {
-    int	i;
+    lumpindex_t i;
 
     i = W_CheckNumForName (name);
-    
+
     if (i < 0)
     {
         I_Error ("W_GetNumForName: %s not found!", name);
@@ -351,7 +320,7 @@
 // W_LumpLength
 // Returns the buffer size needed to load the given lump.
 //
-int W_LumpLength (unsigned int lump)
+int W_LumpLength(lumpindex_t lump)
 {
     if (lump >= numlumps)
     {
@@ -358,7 +327,7 @@
 	I_Error ("W_LumpLength: %i >= numlumps", lump);
     }
 
-    return lumpinfo[lump].size;
+    return lumpinfo[lump]->size;
 }
 
 
@@ -368,29 +337,29 @@
 // Loads the lump into the given buffer,
 //  which must be >= W_LumpLength().
 //
-void W_ReadLump(unsigned int lump, void *dest)
+void W_ReadLump(lumpindex_t lump, void *dest)
 {
     int c;
     lumpinfo_t *l;
-	
+
     if (lump >= numlumps)
     {
-	I_Error ("W_ReadLump: %i >= numlumps", lump);
+        I_Error ("W_ReadLump: %i >= numlumps", lump);
     }
 
-    l = lumpinfo+lump;
-	
-    I_BeginRead ();
-	
+    l = lumpinfo[lump];
+
+    I_BeginRead();
+
     c = W_Read(l->wad_file, l->position, dest, l->size);
 
     if (c < l->size)
     {
-	I_Error ("W_ReadLump: only read %i of %i on lump %i",
-		 c, l->size, lump);	
+        I_Error("W_ReadLump: only read %i of %i on lump %i",
+                c, l->size, lump);
     }
 
-    I_EndRead ();
+    I_EndRead();
 }
 
 
@@ -408,7 +377,7 @@
 // when no longer needed (do not use Z_ChangeTag).
 //
 
-void *W_CacheLumpNum(int lumpnum, int tag)
+void *W_CacheLumpNum(lumpindex_t lumpnum, int tag)
 {
     byte *result;
     lumpinfo_t *lump;
@@ -418,7 +387,7 @@
 	I_Error ("W_CacheLumpNum: %i >= numlumps", lumpnum);
     }
 
-    lump = &lumpinfo[lumpnum];
+    lump = lumpinfo[lumpnum];
 
     // Get the pointer to return.  If the lump is in a memory-mapped
     // file, we can just return a pointer to within the memory-mapped
@@ -470,7 +439,7 @@
 // complicated ...
 //
 
-void W_ReleaseLumpNum(int lumpnum)
+void W_ReleaseLumpNum(lumpindex_t lumpnum)
 {
     lumpinfo_t *lump;
 
@@ -479,7 +448,7 @@
 	I_Error ("W_ReleaseLumpNum: %i >= numlumps", lumpnum);
     }
 
-    lump = &lumpinfo[lumpnum];
+    lump = lumpinfo[lumpnum];
 
     if (lump->wad_file->mapped != NULL)
     {
@@ -566,7 +535,7 @@
 
 void W_GenerateHashTable(void)
 {
-    unsigned int i;
+    lumpindex_t i;
 
     // Free the old hash table, if there is one:
     if (lumphash != NULL)
@@ -577,19 +546,23 @@
     // Generate hash table
     if (numlumps > 0)
     {
-        lumphash = Z_Malloc(sizeof(lumpinfo_t *) * numlumps, PU_STATIC, NULL);
-        memset(lumphash, 0, sizeof(lumpinfo_t *) * numlumps);
+        lumphash = Z_Malloc(sizeof(lumpindex_t) * numlumps, PU_STATIC, NULL);
 
-        for (i=0; i<numlumps; ++i)
+        for (i = 0; i < numlumps; ++i)
         {
+            lumphash[i] = -1;
+        }
+
+        for (i = 0; i < numlumps; ++i)
+        {
             unsigned int hash;
 
-            hash = W_LumpNameHash(lumpinfo[i].name) % numlumps;
+            hash = W_LumpNameHash(lumpinfo[i]->name) % numlumps;
 
             // Hook into the hash table
 
-            lumpinfo[i].next = lumphash[hash];
-            lumphash[hash] = &lumpinfo[i];
+            lumpinfo[i]->next = lumphash[hash];
+            lumphash[hash] = i;
         }
     }
 
@@ -605,7 +578,7 @@
 void W_Reload(void)
 {
     char *filename;
-    int i;
+    lumpindex_t i;
 
     if (reloadname == NULL)
     {
@@ -615,9 +588,9 @@
     // We must free any lumps being cached from the PWAD we're about to reload:
     for (i = reloadlump; i < numlumps; ++i)
     {
-        if (lumpinfo[i].cache != NULL)
+        if (lumpinfo[i]->cache != NULL)
         {
-            Z_Free(lumpinfo[i].cache);
+            Z_Free(lumpinfo[i]->cache);
         }
     }
 
@@ -628,6 +601,8 @@
     filename = reloadname;
 
     W_CloseFile(reloadhandle);
+    free(reloadlumps);
+
     reloadname = NULL;
     reloadlump = -1;
     reloadhandle = NULL;
@@ -656,7 +631,7 @@
 void W_CheckCorrectIWAD(GameMission_t mission)
 {
     int i;
-    int lumpnum;
+    lumpindex_t lumpnum;
 
     for (i = 0; i < arrlen(unique_lumps); ++i)
     {
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -37,6 +37,7 @@
 //
 
 typedef struct lumpinfo_s lumpinfo_t;
+typedef int lumpindex_t;
 
 struct lumpinfo_s
 {
@@ -47,32 +48,31 @@
     void       *cache;
 
     // Used for hash table lookups
-
-    lumpinfo_t *next;
+    lumpindex_t next;
 };
 
 
-extern lumpinfo_t *lumpinfo;
+extern lumpinfo_t **lumpinfo;
 extern unsigned int numlumps;
 
-wad_file_t *W_AddFile (char *filename);
-void    W_Reload (void);
+wad_file_t *W_AddFile(char *filename);
+void W_Reload(void);
 
-int	W_CheckNumForName (char* name);
-int	W_GetNumForName (char* name);
+lumpindex_t W_CheckNumForName(char *name);
+lumpindex_t W_GetNumForName(char *name);
 
-int	W_LumpLength (unsigned int lump);
-void    W_ReadLump (unsigned int lump, void *dest);
+int W_LumpLength(lumpindex_t lump);
+void W_ReadLump(lumpindex_t lump, void *dest);
 
-void*	W_CacheLumpNum (int lump, int tag);
-void*	W_CacheLumpName (char* name, int tag);
+void *W_CacheLumpNum(lumpindex_t lump, int tag);
+void *W_CacheLumpName(char *name, int tag);
 
-void    W_GenerateHashTable(void);
+void W_GenerateHashTable(void);
 
 extern unsigned int W_LumpNameHash(const char *s);
 
-void    W_ReleaseLumpNum(int lump);
-void    W_ReleaseLumpName(char *name);
+void W_ReleaseLumpNum(lumpindex_t lump);
+void W_ReleaseLumpName(char *name);
 
 void W_CheckCorrectIWAD(GameMission_t mission);