Replaced some Malloc and all the alloca() calls with __PHYSFS_smallAlloc(),
authorRyan C. Gordon <icculus@icculus.org>
Sat, 24 Mar 2007 03:54:58 +0000
changeset 852 9467e96abdf1
parent 851 dcfbb779ff40
child 853 8df352657911
Replaced some Malloc and all the alloca() calls with __PHYSFS_smallAlloc(), which will stack allocate small (128 or less bytes) blocks and Malloc the rest...naturally these now have to be paired with __PHYSFS_smallFree() calls, so you can't be as lazy as a basic alloca() would let you be. The benefit is both less malloc pressure for those temporary allocations and better stack overflow safety (so if some jerk tries to push a 78 megabyte string through the library as a filename, we won't try to strcpy it to the stack).
CHANGELOG.txt
archivers/lzma.c
archivers/qpak.c
archivers/zip.c
physfs.c
physfs_internal.h
platform/pocketpc.c
platform/posix.c
platform/windows.c
--- a/CHANGELOG.txt	Wed Mar 21 20:19:20 2007 +0000
+++ b/CHANGELOG.txt	Sat Mar 24 03:54:58 2007 +0000
@@ -1,6 +1,18 @@
 /*
  * CHANGELOG.
  */
+
+03222007 - Replaced some Malloc and all the alloca() calls with
+           __PHYSFS_smallAlloc(), which will stack allocate small (128 or
+           less bytes) blocks and Malloc the rest...naturally these now have
+           to be paired with __PHYSFS_smallFree() calls, so you can't be as
+           lazy as a basic alloca() would let you be. The benefit is both less
+           malloc pressure for those temporary allocations and better stack
+           overflow safety (so if some jerk tries to push a 78 megabyte string
+           through the library as a filename, we won't try to strcpy it to
+           the stack). Hopefully some internal interfaces can now get
+           refactored to stop generating heap pointers and let the caller use
+           smallAlloc to further reduce malloc pressure.
 03212007 - Replaced LONGLONGLITERAL with __PHYSFS_UI64/__PHYSFS_SI64 ...
 03202007 - Removed platform/skeleton.c (it was out of date), added
            platform/macosx.c (To further Macify the code and get the #ifdefs
--- a/archivers/lzma.c	Wed Mar 21 20:19:20 2007 +0000
+++ b/archivers/lzma.c	Sat Mar 24 03:54:58 2007 +0000
@@ -479,13 +479,14 @@
 static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
                            const char *odir, const char *str, PHYSFS_sint32 ln)
 {
-    char *newstr = alloca(ln + 1);
+    char *newstr = __PHYSFS_smallAlloc(ln + 1);
     if (newstr == NULL)
         return;
 
     memcpy(newstr, str, ln);
     newstr[ln] = '\0';
     cb(callbackdata, odir, newstr);
+    __PHYSFS_smallFree(newstr);
 } /* doEnumCallback */
 
 
--- a/archivers/qpak.c	Wed Mar 21 20:19:20 2007 +0000
+++ b/archivers/qpak.c	Sat Mar 24 03:54:58 2007 +0000
@@ -378,13 +378,14 @@
 static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
                            const char *odir, const char *str, PHYSFS_sint32 ln)
 {
-    char *newstr = alloca(ln + 1);
+    char *newstr = __PHYSFS_smallAlloc(ln + 1);
     if (newstr == NULL)
         return;
 
     memcpy(newstr, str, ln);
     newstr[ln] = '\0';
     cb(callbackdata, odir, newstr);
+    __PHYSFS_smallFree(newstr);
 } /* doEnumCallback */
 
 
--- a/archivers/zip.c	Wed Mar 21 20:19:20 2007 +0000
+++ b/archivers/zip.c	Sat Mar 24 03:54:58 2007 +0000
@@ -682,15 +682,15 @@
     else  /* symlink target path is compressed... */
     {
         z_stream stream;
-        PHYSFS_uint32 compsize = entry->compressed_size;
-        PHYSFS_uint8 *compressed = (PHYSFS_uint8 *) allocator.Malloc(compsize);
+        PHYSFS_uint32 complen = entry->compressed_size;
+        PHYSFS_uint8 *compressed = (PHYSFS_uint8*) __PHYSFS_smallAlloc(complen);
         if (compressed != NULL)
         {
-            if (__PHYSFS_platformRead(in, compressed, compsize, 1) == 1)
+            if (__PHYSFS_platformRead(in, compressed, complen, 1) == 1)
             {
                 initializeZStream(&stream);
                 stream.next_in = compressed;
-                stream.avail_in = compsize;
+                stream.avail_in = complen;
                 stream.next_out = (unsigned char *) path;
                 stream.avail_out = size;
                 if (zlib_err(inflateInit2(&stream, -MAX_WBITS)) == Z_OK)
@@ -702,7 +702,7 @@
                     rc = ((rc == Z_OK) || (rc == Z_STREAM_END));
                 } /* if */
             } /* if */
-            allocator.Free(compressed);
+            __PHYSFS_smallFree(compressed);
         } /* if */
     } /* else */
 
@@ -1177,13 +1177,14 @@
 static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
                            const char *odir, const char *str, PHYSFS_sint32 ln)
 {
-    char *newstr = alloca(ln + 1);
+    char *newstr = __PHYSFS_smallAlloc(ln + 1);
     if (newstr == NULL)
         return;
 
     memcpy(newstr, str, ln);
     newstr[ln] = '\0';
     cb(callbackdata, odir, newstr);
+    __PHYSFS_smallFree(newstr);
 } /* doEnumCallback */
 
 
--- a/physfs.c	Wed Mar 21 20:19:20 2007 +0000
+++ b/physfs.c	Sat Mar 24 03:54:58 2007 +0000
@@ -538,15 +538,17 @@
                                   int forWriting)
 {
     DirHandle *dirHandle = NULL;
+    char *tmpmntpnt = NULL;
 
     GOTO_IF_MACRO(!newDir, ERR_INVALID_ARGUMENT, badDirHandle);
     if (mountPoint != NULL)
     {
-        char *mntpnt = (char *) alloca(strlen(mountPoint) + 1);
-        GOTO_IF_MACRO(!mntpnt, ERR_OUT_OF_MEMORY, badDirHandle);
-        if (!sanitizePlatformIndependentPath(mountPoint, mntpnt))
+        const size_t len = strlen(mountPoint) + 1;
+        tmpmntpnt = (char *) __PHYSFS_smallAlloc(len);
+        GOTO_IF_MACRO(!tmpmntpnt, ERR_OUT_OF_MEMORY, badDirHandle);
+        if (!sanitizePlatformIndependentPath(mountPoint, tmpmntpnt))
             goto badDirHandle;
-        mountPoint = mntpnt;  /* sanitized version. */
+        mountPoint = tmpmntpnt;  /* sanitized version. */
     } /* if */
 
     dirHandle = openDirectory(newDir, forWriting);
@@ -564,6 +566,7 @@
         strcat(dirHandle->mountPoint, "/");
     } /* if */
 
+    __PHYSFS_smallFree(tmpmntpnt);
     return(dirHandle);
 
 badDirHandle:
@@ -575,6 +578,7 @@
         allocator.Free(dirHandle);
     } /* if */
 
+    __PHYSFS_smallFree(tmpmntpnt);
     return(NULL);
 } /* createDirHandle */
 
@@ -620,8 +624,7 @@
         else
             sprintf(retval, "%susers%s%s", baseDir, dirsep, str);
 
-        if (uname != NULL)
-            allocator.Free((void *) uname);
+        allocator.Free((void *) uname);
     } /* else */
 
     return(retval);
@@ -1053,6 +1056,22 @@
 } /* PHYSFS_getSearchPathCallback */
 
 
+/* Split out to avoid stack allocation in a loop. */
+static void setSaneCfgAddPath(const char *i, const size_t l, const char *dirsep,
+                              int archivesFirst)
+{
+    const char *d = PHYSFS_getRealDir(i);
+    const size_t allocsize = strlen(d) + strlen(dirsep) + l + 1;
+    char *str = (char *) __PHYSFS_smallAlloc(allocsize);
+    if (str != NULL)
+    {
+        sprintf(str, "%s%s%s", d, dirsep, i);
+        PHYSFS_addToSearchPath(str, archivesFirst == 0);
+        __PHYSFS_smallFree(str);
+    } /* if */
+} /* setSaneCfgAddPath */
+
+
 int PHYSFS_setSaneConfig(const char *organization, const char *appName,
                          const char *archiveExt, int includeCdRoms,
                          int archivesFirst)
@@ -1060,15 +1079,17 @@
     const char *basedir = PHYSFS_getBaseDir();
     const char *userdir = PHYSFS_getUserDir();
     const char *dirsep = PHYSFS_getDirSeparator();
-    char *str;
+    PHYSFS_uint64 len = 0;
+    char *str = NULL;
 
     BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
 
     /* set write dir... */
-    str = (char *) allocator.Malloc(
-            strlen(userdir) + (strlen(organization) * 2) +
+    len = (strlen(userdir) + (strlen(organization) * 2) +
             (strlen(appName) * 2) + (strlen(dirsep) * 3) + 2);
 
+    str = (char *) __PHYSFS_smallAlloc(len);
+
     BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, 0);
     sprintf(str, "%s.%s%s%s", userdir, organization, dirsep, appName);
 
@@ -1091,14 +1112,14 @@
         if (no_write)
         {
             PHYSFS_setWriteDir(NULL);   /* just in case. */
-            allocator.Free(str);
+            __PHYSFS_smallFree(str);
             BAIL_MACRO(ERR_CANT_SET_WRITE_DIR, 0);
         } /* if */
     } /* if */
 
     /* Put write dir first in search path... */
     PHYSFS_addToSearchPath(str, 0);
-    allocator.Free(str);
+    __PHYSFS_smallFree(str);
 
         /* Put base path on search path... */
     PHYSFS_addToSearchPath(basedir, 1);
@@ -1129,17 +1150,7 @@
             {
                 ext = (*i) + (l - extlen);
                 if (__PHYSFS_stricmpASCII(ext, archiveExt) == 0)
-                {
-                    const char *d = PHYSFS_getRealDir(*i);
-                    size_t allocsize = strlen(d) + strlen(dirsep) + l + 1;
-                    str = (char *) allocator.Malloc(allocsize);
-                    if (str != NULL)
-                    {
-                        sprintf(str, "%s%s%s", d, dirsep, *i);
-                        PHYSFS_addToSearchPath(str, archivesFirst == 0);
-                        allocator.Free(str);
-                    } /* if */
-                } /* if */
+                    setSaneCfgAddPath(*i, l, dirsep, archivesFirst);
             } /* if */
         } /* for */
 
@@ -1315,17 +1326,14 @@
 } /* verifyPath */
 
 
-int PHYSFS_mkdir(const char *_dname)
+static int doMkdir(const char *_dname, char *dname)
 {
     DirHandle *h;
     char *start;
     char *end;
     int retval = 0;
     int exists = 1;  /* force existance check on first path element. */
-    char *dname;
 
-    dname = ((_dname) ? (char *) alloca(strlen(_dname) + 1) : NULL);
-    BAIL_IF_MACRO(dname == NULL, ERR_INVALID_ARGUMENT, 0);
     BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_dname, dname), NULL, 0);
 
     __PHYSFS_platformGrabMutex(stateLock);
@@ -1359,16 +1367,29 @@
 
     __PHYSFS_platformReleaseMutex(stateLock);
     return(retval);
+} /* doMkdir */
+
+
+int PHYSFS_mkdir(const char *_dname)
+{
+    int retval = 0;
+    char *dname;
+    size_t len;
+
+    BAIL_IF_MACRO(_dname == NULL, ERR_INVALID_ARGUMENT, 0);
+    len = strlen(_dname) + 1;
+    dname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(dname == NULL, ERR_OUT_OF_MEMORY, 0);
+    retval = doMkdir(_dname, dname);
+    __PHYSFS_smallFree(dname);
+    return(retval);
 } /* PHYSFS_mkdir */
 
 
-int PHYSFS_delete(const char *_fname)
+static int doDelete(const char *_fname, char *fname)
 {
     int retval;
     DirHandle *h;
-
-    char *fname = ((_fname) ? (char *) alloca(strlen(_fname) + 1) : NULL);
-    BAIL_IF_MACRO(fname == NULL, ERR_INVALID_ARGUMENT, 0);
     BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_fname, fname), NULL, 0);
 
     __PHYSFS_platformGrabMutex(stateLock);
@@ -1380,32 +1401,54 @@
 
     __PHYSFS_platformReleaseMutex(stateLock);
     return(retval);
+} /* doDelete */
+
+
+int PHYSFS_delete(const char *_fname)
+{
+    int retval;
+    char *fname;
+    size_t len;
+
+    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, 0);
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, 0);
+    retval = doDelete(_fname, fname);
+    __PHYSFS_smallFree(fname);
+    return(retval);
 } /* PHYSFS_delete */
 
 
 const char *PHYSFS_getRealDir(const char *_fname)
 {
-    DirHandle *i;
     const char *retval = NULL;
+    char *fname = NULL;
+    size_t len;
 
-    char *fname = ((_fname) ? (char *) alloca(strlen(_fname) + 1) : NULL);
-    BAIL_IF_MACRO(fname == NULL, ERR_INVALID_ARGUMENT, NULL);
-    BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_fname, fname), NULL, NULL);
-
-    __PHYSFS_platformGrabMutex(stateLock);
-    for (i = searchPath; ((i != NULL) && (retval == NULL)); i = i->next)
+    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, NULL);
+    len = strlen(_fname) + 1;
+    fname = __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, NULL);
+    if (sanitizePlatformIndependentPath(_fname, fname))
     {
-        char *arcfname = fname;
-        if (partOfMountPoint(i, arcfname))
-            retval = i->dirName;
-        else if (verifyPath(i, &arcfname, 0))
+        DirHandle *i;
+        __PHYSFS_platformGrabMutex(stateLock);
+        for (i = searchPath; ((i != NULL) && (retval == NULL)); i = i->next)
         {
-            if (i->funcs->exists(i->opaque, arcfname))
+            char *arcfname = fname;
+            if (partOfMountPoint(i, arcfname))
                 retval = i->dirName;
-        } /* if */
-    } /* for */
-    __PHYSFS_platformReleaseMutex(stateLock);
+            else if (verifyPath(i, &arcfname, 0))
+            {
+                if (i->funcs->exists(i->opaque, arcfname))
+                    retval = i->dirName;
+            } /* if */
+        } /* for */
+        __PHYSFS_platformReleaseMutex(stateLock);
+    } /* if */
 
+    __PHYSFS_smallFree(fname);
     return(retval);
 } /* PHYSFS_getRealDir */
 
@@ -1491,54 +1534,69 @@
 
 
 /*
- * Broke out to seperate function so we can use alloca() gratuitously.
+ * Broke out to seperate function so we can use stack allocation gratuitously.
  */
 static void enumerateFromMountPoint(DirHandle *i, const char *arcfname,
                                     PHYSFS_EnumFilesCallback callback,
                                     const char *_fname, void *data)
 {
-    size_t len = strlen(arcfname);
+    const size_t len = strlen(arcfname);
     char *ptr = NULL;
     char *end = NULL;
-    char *mountPoint = (char *) alloca(strlen(i->mountPoint) + 1);
+    const size_t slen = strlen(i->mountPoint) + 1;
+    char *mountPoint = (char *) __PHYSFS_smallAlloc(slen);
+
+    if (mountPoint == NULL)
+        return;  /* oh well. */
+
     strcpy(mountPoint, i->mountPoint);
     ptr = mountPoint + ((len) ? len + 1 : 0);
     end = strchr(ptr, '/');
     assert(end);  /* should always find a terminating '/'. */
     *end = '\0';
     callback(data, _fname, ptr);
+    __PHYSFS_smallFree(mountPoint);
 } /* enumerateFromMountPoint */
 
 
-
+/* !!! FIXME: this should report error conditions. */
 void PHYSFS_enumerateFilesCallback(const char *_fname,
                                    PHYSFS_EnumFilesCallback callback,
                                    void *data)
 {
-    DirHandle *i;
-    int noSyms;
-    char *fname = ((_fname) ? (char *) alloca(strlen(_fname) + 1) : NULL);
-    if ((fname == NULL) || (callback == NULL))
-        return;  /* oh well. */
+    size_t len;
+    char *fname;
+
+    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, /*0*/);
+    BAIL_IF_MACRO(callback == NULL, ERR_INVALID_ARGUMENT, /*0*/);
 
-    if (!sanitizePlatformIndependentPath(_fname, fname))
-        return;
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, /*0*/);
+
+    if (sanitizePlatformIndependentPath(_fname, fname))
+    {
+        DirHandle *i;
+        int noSyms;
 
-    __PHYSFS_platformGrabMutex(stateLock);
-    noSyms = !allowSymLinks;
-    for (i = searchPath; i != NULL; i = i->next)
-    {
-        char *arcfname = fname;
-        if (partOfMountPoint(i, arcfname))
-            enumerateFromMountPoint(i, arcfname, callback, _fname, data);
+        __PHYSFS_platformGrabMutex(stateLock);
+        noSyms = !allowSymLinks;
+        for (i = searchPath; i != NULL; i = i->next)
+        {
+            char *arcfname = fname;
+            if (partOfMountPoint(i, arcfname))
+                enumerateFromMountPoint(i, arcfname, callback, _fname, data);
 
-        else if (verifyPath(i, &arcfname, 0))
-        {
-            i->funcs->enumerateFiles(i->opaque, arcfname, noSyms,
-                                     callback, _fname, data);
-        } /* else if */
-    } /* for */
-    __PHYSFS_platformReleaseMutex(stateLock);
+            else if (verifyPath(i, &arcfname, 0))
+            {
+                i->funcs->enumerateFiles(i->opaque, arcfname, noSyms,
+                                         callback, _fname, data);
+            } /* else if */
+        } /* for */
+        __PHYSFS_platformReleaseMutex(stateLock);
+    } /* if */
+
+    __PHYSFS_smallFree(fname);
 } /* PHYSFS_enumerateFilesCallback */
 
 
@@ -1550,130 +1608,178 @@
 
 PHYSFS_sint64 PHYSFS_getLastModTime(const char *_fname)
 {
-    DirHandle *i;
     PHYSFS_sint64 retval = -1;
-    int fileExists = 0;
+    char *fname;
+    size_t len;
 
-    char *fname = ((_fname) ? (char *) alloca(strlen(_fname) + 1) : NULL);
-    BAIL_IF_MACRO(fname == NULL, ERR_INVALID_ARGUMENT, 0);
-    BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_fname, fname), NULL, 0);
-
-    if (*fname == '\0')   /* eh...punt if it's the root dir. */
-        return(1);  /* !!! FIXME: Maybe this should be an error? */
+    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, -1);
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, -1);
 
-    __PHYSFS_platformGrabMutex(stateLock);
-    for (i = searchPath; ((i != NULL) && (!fileExists)); i = i->next)
+    if (sanitizePlatformIndependentPath(_fname, fname))
     {
-        char *arcfname = fname;
-        fileExists = partOfMountPoint(i, arcfname);
-        if (fileExists)
-            retval = 1; /* !!! FIXME: What's the right value? */
-        else if (verifyPath(i, &arcfname, 0))
-            retval = i->funcs->getLastModTime(i->opaque,arcfname,&fileExists);
-    } /* for */
-    __PHYSFS_platformReleaseMutex(stateLock);
+        if (*fname == '\0')   /* eh...punt if it's the root dir. */
+            retval = 1;  /* !!! FIXME: Maybe this should be an error? */
+        else
+        {
+            DirHandle *i;
+            int exists = 0;
+            __PHYSFS_platformGrabMutex(stateLock);
+            for (i = searchPath; ((i != NULL) && (!exists)); i = i->next)
+            {
+                char *arcfname = fname;
+                exists = partOfMountPoint(i, arcfname);
+                if (exists)
+                    retval = 1; /* !!! FIXME: What's the right value? */
+                else if (verifyPath(i, &arcfname, 0))
+                {
+                    retval = i->funcs->getLastModTime(i->opaque, arcfname,
+                                                      &exists);
+                } /* else if */
+            } /* for */
+            __PHYSFS_platformReleaseMutex(stateLock);
+        } /* else */
+    } /* if */
 
+    __PHYSFS_smallFree(fname);
     return(retval);
 } /* PHYSFS_getLastModTime */
 
 
 int PHYSFS_isDirectory(const char *_fname)
 {
-    DirHandle *i;
     int retval = 0;
-    int fileExists = 0;
+    size_t len;
+    char *fname;
 
-    char *fname = ((_fname) ? (char *) alloca(strlen(_fname) + 1) : NULL);
-    BAIL_IF_MACRO(fname == NULL, ERR_INVALID_ARGUMENT, 0);
-    BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_fname, fname), NULL, 0);
-    BAIL_IF_MACRO(*fname == '\0', NULL, 1); /* Root is always a dir.  :) */
+    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, 0);
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, 0);
+
+    if (!sanitizePlatformIndependentPath(_fname, fname))
+        retval = 0;
+
+    else if (*fname == '\0')
+        retval = 1;  /* Root is always a dir.  :) */
 
-    __PHYSFS_platformGrabMutex(stateLock);
-    for (i = searchPath; ((i != NULL) && (!fileExists)); i = i->next)
+    else
     {
-        char *arcfname = fname;
-        if ((fileExists = partOfMountPoint(i, arcfname)) != 0)
-            retval = 1;
-        else if (verifyPath(i, &arcfname, 0))
-            retval = i->funcs->isDirectory(i->opaque, arcfname, &fileExists);
-    } /* for */
-    __PHYSFS_platformReleaseMutex(stateLock);
+        DirHandle *i;
+        int exists = 0;
 
+        __PHYSFS_platformGrabMutex(stateLock);
+        for (i = searchPath; ((i != NULL) && (!exists)); i = i->next)
+        {
+            char *arcfname = fname;
+            if ((exists = partOfMountPoint(i, arcfname)) != 0)
+                retval = 1;
+            else if (verifyPath(i, &arcfname, 0))
+                retval = i->funcs->isDirectory(i->opaque, arcfname, &exists);
+        } /* for */
+        __PHYSFS_platformReleaseMutex(stateLock);
+    } /* else */
+
+    __PHYSFS_smallFree(fname);
     return(retval);
 } /* PHYSFS_isDirectory */
 
 
 int PHYSFS_isSymbolicLink(const char *_fname)
 {
-    DirHandle *i;
     int retval = 0;
-    int fileExists = 0;
+    size_t len;
     char *fname;
 
     BAIL_IF_MACRO(!allowSymLinks, ERR_SYMLINK_DISALLOWED, 0);
 
-    fname = ((_fname) ? (char *) alloca(strlen(_fname) + 1) : NULL);
-    BAIL_IF_MACRO(fname == NULL, ERR_INVALID_ARGUMENT, 0);
-    BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_fname, fname), NULL, 0);
-    BAIL_IF_MACRO(*fname == '\0', NULL, 0);   /* Root is never a symlink */
+    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, 0);
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, 0);
 
-    __PHYSFS_platformGrabMutex(stateLock);
-    for (i = searchPath; ((i != NULL) && (!fileExists)); i = i->next)
+    if (!sanitizePlatformIndependentPath(_fname, fname))
+        retval = 0;
+
+    else if (*fname == '\0')
+        retval = 1;  /* Root is never a symlink. */
+
+    else
     {
-        char *arcfname = fname;
-        if ((fileExists = partOfMountPoint(i, arcfname)) != 0)
-            retval = 0;  /* virtual dir...not a symlink. */
-        else if (verifyPath(i, &arcfname, 0))
-            retval = i->funcs->isSymLink(i->opaque, arcfname, &fileExists);
-    } /* for */
-    __PHYSFS_platformReleaseMutex(stateLock);
+        DirHandle *i;
+        int fileExists = 0;
 
+        __PHYSFS_platformGrabMutex(stateLock);
+        for (i = searchPath; ((i != NULL) && (!fileExists)); i = i->next)
+        {
+            char *arcfname = fname;
+            if ((fileExists = partOfMountPoint(i, arcfname)) != 0)
+                retval = 0;  /* virtual dir...not a symlink. */
+            else if (verifyPath(i, &arcfname, 0))
+                retval = i->funcs->isSymLink(i->opaque, arcfname, &fileExists);
+        } /* for */
+        __PHYSFS_platformReleaseMutex(stateLock);
+    } /* else */
+
+    __PHYSFS_smallFree(fname);
     return(retval);
 } /* PHYSFS_isSymbolicLink */
 
 
 static PHYSFS_File *doOpenWrite(const char *_fname, int appending)
 {
-    void *opaque = NULL;
     FileHandle *fh = NULL;
-    DirHandle *h = NULL;
-    const PHYSFS_Archiver *f;
+    size_t len;
+    char *fname;
+
+    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, 0);
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, 0);
 
-    char *fname = ((_fname) ? (char *) alloca(strlen(_fname) + 1) : NULL);
-    BAIL_IF_MACRO(fname == NULL, ERR_INVALID_ARGUMENT, 0);
-    BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_fname, fname), NULL, 0);
+    if (sanitizePlatformIndependentPath(_fname, fname))
+    {
+        void *opaque = NULL;
+        DirHandle *h = NULL;
+        const PHYSFS_Archiver *f;
 
-    __PHYSFS_platformGrabMutex(stateLock);
-    BAIL_IF_MACRO_MUTEX(!writeDir, ERR_NO_WRITE_DIR, stateLock, NULL);
+        __PHYSFS_platformGrabMutex(stateLock);
 
-    h = writeDir;
-    BAIL_IF_MACRO_MUTEX(!verifyPath(h, &fname, 0), NULL, stateLock, NULL);
+        GOTO_IF_MACRO(!writeDir, ERR_NO_WRITE_DIR, doOpenWriteEnd);
+
+        h = writeDir;
+        GOTO_IF_MACRO(!verifyPath(h, &fname, 0), NULL, doOpenWriteEnd);
 
-    f = h->funcs;
-    if (appending)
-        opaque = f->openAppend(h->opaque, fname);
-    else
-        opaque = f->openWrite(h->opaque, fname);
+        f = h->funcs;
+        if (appending)
+            opaque = f->openAppend(h->opaque, fname);
+        else
+            opaque = f->openWrite(h->opaque, fname);
 
-    BAIL_IF_MACRO_MUTEX(opaque == NULL, NULL, stateLock, NULL);
+        GOTO_IF_MACRO(opaque == NULL, NULL, doOpenWriteEnd);
 
-    fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
-    if (fh == NULL)
-    {
-        f->fileClose(opaque);
-        BAIL_MACRO_MUTEX(ERR_OUT_OF_MEMORY, stateLock, NULL);
+        fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
+        if (fh == NULL)
+        {
+            f->fileClose(opaque);
+            GOTO_MACRO(ERR_OUT_OF_MEMORY, doOpenWriteEnd);
+        } /* if */
+        else
+        {
+            memset(fh, '\0', sizeof (FileHandle));
+            fh->opaque = opaque;
+            fh->dirHandle = h;
+            fh->funcs = h->funcs;
+            fh->next = openWriteList;
+            openWriteList = fh;
+        } /* else */
+
+        doOpenWriteEnd:
+        __PHYSFS_platformReleaseMutex(stateLock);
     } /* if */
-    else
-    {
-        memset(fh, '\0', sizeof (FileHandle));
-        fh->opaque = opaque;
-        fh->dirHandle = h;
-        fh->funcs = h->funcs;
-        fh->next = openWriteList;
-        openWriteList = fh;
-    } /* else */
 
-    __PHYSFS_platformReleaseMutex(stateLock);
+    __PHYSFS_smallFree(fname);
     return((PHYSFS_File *) fh);
 } /* doOpenWrite */
 
@@ -1693,51 +1799,62 @@
 PHYSFS_File *PHYSFS_openRead(const char *_fname)
 {
     FileHandle *fh = NULL;
-    int fileExists = 0;
-    DirHandle *i = NULL;
-    fvoid *opaque = NULL;
-
-    char *fname = ((_fname) ? (char *) alloca(strlen(_fname) + 1) : NULL);
-    BAIL_IF_MACRO(fname == NULL, ERR_INVALID_ARGUMENT, 0);
-    BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_fname, fname), NULL, 0);
+    char *fname;
+    size_t len;
 
-    __PHYSFS_platformGrabMutex(stateLock);
-
-    BAIL_IF_MACRO_MUTEX(!searchPath, ERR_NO_SUCH_PATH, stateLock, NULL);
+    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, 0);
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, 0);
 
-    /* !!! FIXME: Why aren't we using a for loop here? */
-    i = searchPath;
-
-    do
+    if (sanitizePlatformIndependentPath(_fname, fname))
     {
-        char *arcfname = fname;
-        if (verifyPath(i, &arcfname, 0))
+        int fileExists = 0;
+        DirHandle *i = NULL;
+        fvoid *opaque = NULL;
+
+        __PHYSFS_platformGrabMutex(stateLock);
+
+        GOTO_IF_MACRO(!searchPath, ERR_NO_SUCH_PATH, openReadEnd);
+
+        /* !!! FIXME: Why aren't we using a for loop here? */
+        i = searchPath;
+
+        do
         {
-            opaque = i->funcs->openRead(i->opaque, arcfname, &fileExists);
-            if (opaque)
-                break;
+            char *arcfname = fname;
+            if (verifyPath(i, &arcfname, 0))
+            {
+                opaque = i->funcs->openRead(i->opaque, arcfname, &fileExists);
+                if (opaque)
+                    break;
+            } /* if */
+            i = i->next;
+        } while ((i != NULL) && (!fileExists));
+
+        /* !!! FIXME: may not set an error if openRead didn't fail. */
+        GOTO_IF_MACRO(opaque == NULL, NULL, openReadEnd);
+
+        fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
+        if (fh == NULL)
+        {
+            i->funcs->fileClose(opaque);
+            GOTO_MACRO(ERR_OUT_OF_MEMORY, openReadEnd);
         } /* if */
-        i = i->next;
-    } while ((i != NULL) && (!fileExists));
-
-    BAIL_IF_MACRO_MUTEX(opaque == NULL, NULL, stateLock, NULL);
 
-    fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
-    if (fh == NULL)
-    {
-        i->funcs->fileClose(opaque);
-        BAIL_MACRO_MUTEX(ERR_OUT_OF_MEMORY, stateLock, NULL);
+        memset(fh, '\0', sizeof (FileHandle));
+        fh->opaque = opaque;
+        fh->forReading = 1;
+        fh->dirHandle = i;
+        fh->funcs = i->funcs;
+        fh->next = openReadList;
+        openReadList = fh;
+
+        openReadEnd:
+        __PHYSFS_platformReleaseMutex(stateLock);
     } /* if */
 
-    memset(fh, '\0', sizeof (FileHandle));
-    fh->opaque = opaque;
-    fh->forReading = 1;
-    fh->dirHandle = i;
-    fh->funcs = i->funcs;
-    fh->next = openReadList;
-    openReadList = fh;
-    __PHYSFS_platformReleaseMutex(stateLock);
-
+    __PHYSFS_smallFree(fname);
     return((PHYSFS_File *) fh);
 } /* PHYSFS_openRead */
 
@@ -2055,5 +2172,37 @@
     } /* if */
 } /* setDefaultAllocator */
 
+
+void *__PHYSFS_initSmallAlloc(void *ptr, PHYSFS_uint64 len)
+{
+    const char useHeap = ((ptr == NULL) ? 1 : 0);
+    if (useHeap)  /* too large for stack allocation or alloca() failed. */
+        ptr = allocator.Malloc(len+1);
+
+    if (ptr != NULL)
+    {
+        char *retval = (char *) ptr;
+        /*printf("%s alloc'd (%d) bytes at (%p).\n",
+                useHeap ? "heap" : "stack", (int) len, ptr);*/
+        *retval = useHeap;
+        return(retval+1);
+    } /* if */
+
+    return(NULL);  /* allocation failed. */
+} /* __PHYSFS_initSmallAlloc */
+
+
+void __PHYSFS_smallFree(void *ptr)
+{
+    if (ptr != NULL)
+    {
+        char *block = ((char *) ptr) - 1;
+        const char useHeap = *block;
+        if (useHeap)
+            allocator.Free(block);
+        /*printf("%s free'd (%p).\n", useHeap ? "heap" : "stack", block);*/
+    } /* if */
+} /* __PHYSFS_smallFree */
+
 /* end of physfs.c ... */
 
--- a/physfs_internal.h	Wed Mar 21 20:19:20 2007 +0000
+++ b/physfs_internal.h	Sat Mar 24 03:54:58 2007 +0000
@@ -33,6 +33,38 @@
 extern "C" {
 #endif
 
+/*
+ * Interface for small allocations. If you need a little scratch space for
+ *  a throwaway buffer or string, use this. It will make small allocations
+ *  on the stack if possible, and use allocator.Malloc() if they are too
+ *  large. This helps reduce malloc pressure.
+ * There are some rules, though:
+ * NEVER return a pointer from this, as stack-allocated buffers go away
+ *  when your function returns.
+ * NEVER allocate in a loop, as stack-allocated pointers will pile up. Call
+ *  a function that uses smallAlloc from your loop, so the allocation can
+ *  free each time.
+ * NEVER call smallAlloc with any complex expression (it's a macro that WILL
+ *  have side effects...it references the argument multiple times). Use a
+ *  variable or a literal.
+ * NEVER free a pointer from this with anything but smallFree. It will not
+ *  be a valid pointer to the allocator, regardless of where the memory came
+ *  from.
+ * NEVER realloc a pointer from this.
+ * NEVER forget to use smallFree: it may not be a pointer from the stack.
+ * NEVER forget to check for NULL...allocation can fail here, of course!
+ */
+#define __PHYSFS_SMALLALLOCTHRESHOLD 128
+void *__PHYSFS_initSmallAlloc(void *ptr, PHYSFS_uint64 len);
+
+#define __PHYSFS_smallAlloc(bytes) ( \
+    __PHYSFS_initSmallAlloc(((bytes < __PHYSFS_SMALLALLOCTHRESHOLD) ? \
+                             alloca(bytes+1) : NULL), bytes) \
+)
+
+void __PHYSFS_smallFree(void *ptr);
+
+
 /* Use the allocation hooks. */
 #define malloc(x) Do not use malloc() directly.
 #define realloc(x, y) Do not use realloc() directly.
--- a/platform/pocketpc.c	Wed Mar 21 20:19:20 2007 +0000
+++ b/platform/pocketpc.c	Sat Mar 24 03:54:58 2007 +0000
@@ -64,12 +64,14 @@
     return((const char *) msgbuf);
 } /* win32strerror */
 
+
+/* !!! FIXME: need to check all of these for NULLs. */
 #define UTF8_TO_UNICODE_STACK_MACRO(w_assignto, str) { \
     if (str == NULL) \
         w_assignto = NULL; \
     else { \
         const PHYSFS_uint64 len = (PHYSFS_uint64) ((strlen(str) * 4) + 1); \
-        w_assignto = (char *) alloca(len); \
+        w_assignto = (char *) __PHYSFS_smallAlloc(len); \
         PHYSFS_uc2fromutf8(str, (PHYSFS_uint16 *) w_assignto, len); \
     } \
 } \
@@ -86,6 +88,7 @@
 
     retval[0] = _T('\0');
     /* !!! FIXME: don't preallocate here? */
+    /* !!! FIXME: use smallAlloc? */
     buflen = GetModuleFileName(NULL, retval, MAX_PATH + 1);
     if (buflen <= 0)
         __PHYSFS_setError(win32strerror());
@@ -172,6 +175,7 @@
     UTF8_TO_UNICODE_STACK_MACRO(w_fname, fname);
     if (w_fname != NULL)
         retval = (GetFileAttributes(w_fname) != INVALID_FILE_ATTRIBUTES);
+    __PHYSFS_smallFree(w_fname);
 
     return(retval);
 } /* __PHYSFS_platformExists */
@@ -191,6 +195,7 @@
     UTF8_TO_UNICODE_STACK_MACRO(w_fname, fname);
     if (w_fname != NULL)
         retval = ((GetFileAttributes(w_fname) & FILE_ATTRIBUTE_DIRECTORY) != 0);
+    __PHYSFS_smallFree(w_fname);
 
     return(retval);
 } /* __PHYSFS_platformIsDirectory */
@@ -228,9 +233,10 @@
 static int doEnumCallback(const wchar_t *w_fname)
 {
     const PHYSFS_uint64 len = (PHYSFS_uint64) ((wcslen(w_fname) * 4) + 1);
-    char *str = (char *) alloca(len);
+    char *str = (char *) __PHYSFS_smallAlloc(len);
     PHYSFS_utf8fromucs2((const PHYSFS_uint16 *) w_fname, str, len);
     callback(callbackdata, origdir, str);
+    __PHYSFS_smallFree(str);
     return 1;
 } /* doEnumCallback */
 
@@ -248,7 +254,7 @@
     size_t len = strlen(dirname);
 
     /* Allocate a new string for path, maybe '\\', "*", and NULL terminator */
-    SearchPath = (char *) alloca(len + 3);
+    SearchPath = (char *) __PHYSFS_smallAlloc(len + 3);
     BAIL_IF_MACRO(SearchPath == NULL, ERR_OUT_OF_MEMORY, NULL);    
 
     /* Copy current dirname */
@@ -265,7 +271,9 @@
     strcat(SearchPath, "*");
 
     UTF8_TO_UNICODE_STACK_MACRO(w_SearchPath, SearchPath);
+    __PHYSFS_smallFree(SearchPath);
     dir = FindFirstFile(w_SearchPath, &ent);
+    __PHYSFS_smallFree(w_SearchPath);
 
     if (dir == INVALID_HANDLE_VALUE)
         return;
@@ -304,9 +312,15 @@
 
 int __PHYSFS_platformMkDir(const char *path)
 {
+    int retval = 0;
     wchar_t *w_path = NULL;
     UTF8_TO_UNICODE_STACK_MACRO(w_path, path);
-    return ( (w_path != NULL) && (CreateDirectory(w_path, NULL)) );
+    if (w_path != NULL)
+    {
+        retval = CreateDirectory(w_path, NULL);
+        __PHYSFS_smallFree(w_fname);
+    } /* if */
+    return(retval);
 } /* __PHYSFS_platformMkDir */
 
 
@@ -317,9 +331,9 @@
     wchar_t *w_fname = NULL;
 
     UTF8_TO_UNICODE_STACK_MACRO(w_fname, fname);
-
     fileHandle = CreateFile(w_fname, mode, FILE_SHARE_READ, NULL,
                             creation, FILE_ATTRIBUTE_NORMAL, NULL);
+    __PHYSFS_smallFree(w_fname);
 
     BAIL_IF_MACRO(fileHandle == INVALID_HANDLE_VALUE, win32strerror(), NULL);
 
@@ -533,11 +547,13 @@
     if (GetFileAttributes(w_path) == FILE_ATTRIBUTE_DIRECTORY)
     {
         int retval = !RemoveDirectory(w_path);
+        __PHYSFS_smallFree(w_path);
         BAIL_IF_MACRO(retval, win32strerror(), 0);
     } /* if */
     else
     {
         int retval = !DeleteFile(w_path);
+        __PHYSFS_smallFree(w_path);
         BAIL_IF_MACRO(retval, win32strerror(), 0);
     } /* else */
 
--- a/platform/posix.c	Wed Mar 21 20:19:20 2007 +0000
+++ b/platform/posix.c	Sat Mar 24 03:54:58 2007 +0000
@@ -186,8 +186,7 @@
     dir = opendir(dirname);
     if (dir == NULL)
     {
-        if (buf != NULL)
-            allocator.Free(buf);
+        allocator.Free(buf);
         return;
     } /* if */
 
@@ -220,9 +219,7 @@
         callback(callbackdata, origdir, ent->d_name);
     } /* while */
 
-    if (buf != NULL)
-        allocator.Free(buf);
-
+    allocator.Free(buf);
     closedir(dir);
 } /* __PHYSFS_platformEnumerateFiles */
 
--- a/platform/windows.c	Wed Mar 21 20:19:20 2007 +0000
+++ b/platform/windows.c	Sat Mar 24 03:54:58 2007 +0000
@@ -21,14 +21,6 @@
 
 #include "physfs_internal.h"
 
-#if (!defined alloca)
-    #if ((defined _MSC_VER)
-        #define alloca(x) _alloca(x)
-    #elif (defined __MINGW32__)  /* scary...hopefully this is okay. */
-        #define alloca(x) __builtin_alloca(x) 
-    #endif
-#endif
-
 #define LOWORDER_UINT64(pos) (PHYSFS_uint32) \
     (pos & 0x00000000FFFFFFFF)
 #define HIGHORDER_UINT64(pos) (PHYSFS_uint32) \
@@ -116,6 +108,8 @@
     BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
 
     retval[0] = '\0';
+    /* !!! FIXME: don't preallocate here? */
+    /* !!! FIXME: use smallAlloc? */
     buflen = GetModuleFileName(NULL, retval, MAX_PATH + 1);
     if (buflen <= 0)
         __PHYSFS_setError(win32strerror());
@@ -390,7 +384,7 @@
     char *SearchPath;
 
     /* Allocate a new string for path, maybe '\\', "*", and NULL terminator */
-    SearchPath = (char *) alloca(len + 3);
+    SearchPath = (char *) __PHYSFS_smallAlloc(len + 3);
     if (SearchPath == NULL)
         return;
 
@@ -408,6 +402,7 @@
     strcat(SearchPath, "*");
 
     dir = FindFirstFile(SearchPath, &ent);
+    __PHYSFS_smallFree(SearchPath);
     if (dir == INVALID_HANDLE_VALUE)
         return;