From 73863208112e1b280b5e967b761df1ef324dffb8 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 24 Mar 2007 03:54:58 +0000 Subject: [PATCH] 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 | 12 ++ archivers/lzma.c | 3 +- archivers/qpak.c | 3 +- archivers/zip.c | 13 +- physfs.c | 515 ++++++++++++++++++++++++++++---------------- physfs_internal.h | 32 +++ platform/pocketpc.c | 26 ++- platform/posix.c | 7 +- platform/windows.c | 13 +- 9 files changed, 414 insertions(+), 210 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 675e6466..643f0b42 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -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 diff --git a/archivers/lzma.c b/archivers/lzma.c index b3c73306..1f526205 100644 --- a/archivers/lzma.c +++ b/archivers/lzma.c @@ -479,13 +479,14 @@ static void *LZMA_openArchive(const char *name, int forWriting) 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 */ diff --git a/archivers/qpak.c b/archivers/qpak.c index a11d0772..f4aa7e7b 100644 --- a/archivers/qpak.c +++ b/archivers/qpak.c @@ -378,13 +378,14 @@ static PHYSFS_sint32 qpak_find_start_of_dir(QPAKinfo *info, const char *path, 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 */ diff --git a/archivers/zip.c b/archivers/zip.c index 04ed6a62..33de4758 100644 --- a/archivers/zip.c +++ b/archivers/zip.c @@ -682,15 +682,15 @@ static int zip_resolve_symlink(void *in, ZIPinfo *info, ZIPentry *entry) 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 @@ static int zip_resolve_symlink(void *in, ZIPinfo *info, ZIPentry *entry) rc = ((rc == Z_OK) || (rc == Z_STREAM_END)); } /* if */ } /* if */ - allocator.Free(compressed); + __PHYSFS_smallFree(compressed); } /* if */ } /* else */ @@ -1177,13 +1177,14 @@ static PHYSFS_sint32 zip_find_start_of_dir(ZIPinfo *info, const char *path, 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 */ diff --git a/physfs.c b/physfs.c index d1419475..a5e3470f 100644 --- a/physfs.c +++ b/physfs.c @@ -538,15 +538,17 @@ static DirHandle *createDirHandle(const char *newDir, 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 @@ static DirHandle *createDirHandle(const char *newDir, strcat(dirHandle->mountPoint, "/"); } /* if */ + __PHYSFS_smallFree(tmpmntpnt); return(dirHandle); badDirHandle: @@ -575,6 +578,7 @@ static DirHandle *createDirHandle(const char *newDir, allocator.Free(dirHandle); } /* if */ + __PHYSFS_smallFree(tmpmntpnt); return(NULL); } /* createDirHandle */ @@ -620,8 +624,7 @@ static char *calculateUserDir(void) 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 @@ void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback callback, void *data) } /* 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 @@ int PHYSFS_setSaneConfig(const char *organization, const char *appName, 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 @@ int PHYSFS_setSaneConfig(const char *organization, const char *appName, 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 @@ int PHYSFS_setSaneConfig(const char *organization, const char *appName, { 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 @@ static int verifyPath(DirHandle *h, char **_fname, int allowMissing) } /* 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 @@ int PHYSFS_mkdir(const char *_dname) __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 @@ int PHYSFS_delete(const char *_fname) __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 = ((_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) + char *fname = NULL; + size_t len; + + 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 @@ char **PHYSFS_enumerateFiles(const char *path) /* - * 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; - if (!sanitizePlatformIndependentPath(_fname, fname)) - return; + BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, /*0*/); + BAIL_IF_MACRO(callback == NULL, ERR_INVALID_ARGUMENT, /*0*/); - __PHYSFS_platformGrabMutex(stateLock); - noSyms = !allowSymLinks; - for (i = searchPath; i != NULL; i = i->next) + len = strlen(_fname) + 1; + fname = (char *) __PHYSFS_smallAlloc(len); + BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, /*0*/); + + if (sanitizePlatformIndependentPath(_fname, fname)) { - char *arcfname = fname; - if (partOfMountPoint(i, arcfname)) - enumerateFromMountPoint(i, arcfname, callback, _fname, data); + DirHandle *i; + int noSyms; - else if (verifyPath(i, &arcfname, 0)) + __PHYSFS_platformGrabMutex(stateLock); + noSyms = !allowSymLinks; + for (i = searchPath; i != NULL; i = i->next) { - i->funcs->enumerateFiles(i->opaque, arcfname, noSyms, - callback, _fname, data); - } /* else if */ - } /* for */ - __PHYSFS_platformReleaseMutex(stateLock); + 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); + } /* if */ + + __PHYSFS_smallFree(fname); } /* PHYSFS_enumerateFilesCallback */ @@ -1550,130 +1608,178 @@ int PHYSFS_exists(const char *fname) PHYSFS_sint64 PHYSFS_getLastModTime(const char *_fname) { - DirHandle *i; PHYSFS_sint64 retval = -1; - int fileExists = 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); + char *fname; + size_t len; - 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); - __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 always a dir. :) */ + + 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; - 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 == 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); - BAIL_IF_MACRO_MUTEX(!writeDir, ERR_NO_WRITE_DIR, stateLock, NULL); + if (sanitizePlatformIndependentPath(_fname, fname)) + { + void *opaque = NULL; + DirHandle *h = NULL; + const PHYSFS_Archiver *f; - h = writeDir; - BAIL_IF_MACRO_MUTEX(!verifyPath(h, &fname, 0), NULL, stateLock, NULL); + __PHYSFS_platformGrabMutex(stateLock); - f = h->funcs; - if (appending) - opaque = f->openAppend(h->opaque, fname); - else - opaque = f->openWrite(h->opaque, fname); + GOTO_IF_MACRO(!writeDir, ERR_NO_WRITE_DIR, doOpenWriteEnd); - BAIL_IF_MACRO_MUTEX(opaque == NULL, NULL, stateLock, NULL); + h = writeDir; + GOTO_IF_MACRO(!verifyPath(h, &fname, 0), NULL, doOpenWriteEnd); - fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle)); - if (fh == NULL) - { - f->fileClose(opaque); - BAIL_MACRO_MUTEX(ERR_OUT_OF_MEMORY, stateLock, NULL); + f = h->funcs; + if (appending) + opaque = f->openAppend(h->opaque, fname); + else + opaque = f->openWrite(h->opaque, fname); + + GOTO_IF_MACRO(opaque == NULL, NULL, doOpenWriteEnd); + + 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_openAppend(const char *filename) PHYSFS_File *PHYSFS_openRead(const char *_fname) { FileHandle *fh = NULL; - int fileExists = 0; - DirHandle *i = NULL; - fvoid *opaque = NULL; + 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); + 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); + if (sanitizePlatformIndependentPath(_fname, fname)) + { + int fileExists = 0; + DirHandle *i = NULL; + fvoid *opaque = NULL; - BAIL_IF_MACRO_MUTEX(!searchPath, ERR_NO_SUCH_PATH, stateLock, NULL); + __PHYSFS_platformGrabMutex(stateLock); - /* !!! FIXME: Why aren't we using a for loop here? */ - i = searchPath; + GOTO_IF_MACRO(!searchPath, ERR_NO_SUCH_PATH, openReadEnd); - do - { - char *arcfname = fname; - if (verifyPath(i, &arcfname, 0)) + /* !!! FIXME: Why aren't we using a for loop here? */ + i = searchPath; + + do { - opaque = i->funcs->openRead(i->opaque, arcfname, &fileExists); - if (opaque) - break; - } /* if */ - i = i->next; - } while ((i != NULL) && (!fileExists)); + 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)); - BAIL_IF_MACRO_MUTEX(opaque == NULL, NULL, stateLock, NULL); + /* !!! 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); - BAIL_MACRO_MUTEX(ERR_OUT_OF_MEMORY, stateLock, NULL); - } /* if */ + fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle)); + if (fh == NULL) + { + i->funcs->fileClose(opaque); + GOTO_MACRO(ERR_OUT_OF_MEMORY, openReadEnd); + } /* 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); + 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 */ + __PHYSFS_smallFree(fname); return((PHYSFS_File *) fh); } /* PHYSFS_openRead */ @@ -2055,5 +2172,37 @@ static void setDefaultAllocator(void) } /* 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 ... */ diff --git a/physfs_internal.h b/physfs_internal.h index 5f1e5998..f8449d08 100644 --- a/physfs_internal.h +++ b/physfs_internal.h @@ -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. diff --git a/platform/pocketpc.c b/platform/pocketpc.c index 7d116e34..96f4a413 100644 --- a/platform/pocketpc.c +++ b/platform/pocketpc.c @@ -64,12 +64,14 @@ static const char *win32strerror(void) 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 @@ static char *getExePath() 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 @@ int __PHYSFS_platformExists(const char *fname) 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 @@ int __PHYSFS_platformIsDirectory(const char *fname) 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 @@ char *__PHYSFS_platformCvtToDependent(const char *prepend, 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 @@ void __PHYSFS_platformEnumerateFiles(const char *dirname, 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 @@ void __PHYSFS_platformEnumerateFiles(const char *dirname, 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 @@ char *__PHYSFS_platformRealPath(const char *path) 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 @@ static void *doOpen(const char *fname, DWORD mode, DWORD creation, int rdonly) 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 @@ int __PHYSFS_platformDelete(const char *path) 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 */ diff --git a/platform/posix.c b/platform/posix.c index 5464face..00512556 100644 --- a/platform/posix.c +++ b/platform/posix.c @@ -186,8 +186,7 @@ void __PHYSFS_platformEnumerateFiles(const char *dirname, dir = opendir(dirname); if (dir == NULL) { - if (buf != NULL) - allocator.Free(buf); + allocator.Free(buf); return; } /* if */ @@ -220,9 +219,7 @@ void __PHYSFS_platformEnumerateFiles(const char *dirname, callback(callbackdata, origdir, ent->d_name); } /* while */ - if (buf != NULL) - allocator.Free(buf); - + allocator.Free(buf); closedir(dir); } /* __PHYSFS_platformEnumerateFiles */ diff --git a/platform/windows.c b/platform/windows.c index b43e1299..e8c98f48 100644 --- a/platform/windows.c +++ b/platform/windows.c @@ -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 @@ static char *getExePath(const char *argv0) 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 @@ void __PHYSFS_platformEnumerateFiles(const char *dirname, 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 @@ void __PHYSFS_platformEnumerateFiles(const char *dirname, strcat(SearchPath, "*"); dir = FindFirstFile(SearchPath, &ent); + __PHYSFS_smallFree(SearchPath); if (dir == INVALID_HANDLE_VALUE) return;