Fix a memory leak that can occur in os_unix.c if an IO error occurs within the xUnlock method.

FossilOrigin-Name: 6c5c04eea1f0e8d61883ee8675c249fbf895dc01
This commit is contained in:
dan
2010-06-16 10:55:42 +00:00
parent a4a9095ec0
commit b0ac3e3a17
8 changed files with 247 additions and 69 deletions
+36 -34
View File
@@ -735,18 +735,50 @@ struct unixInodeInfo {
*/
static unixInodeInfo *inodeList = 0;
/*
** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
** If all such file descriptors are closed without error, the list is
** cleared and SQLITE_OK returned.
**
** Otherwise, if an error occurs, then successfully closed file descriptor
** entries are removed from the list, and SQLITE_IOERR_CLOSE returned.
** not deleted and SQLITE_IOERR_CLOSE returned.
*/
static int closePendingFds(unixFile *pFile){
int rc = SQLITE_OK;
unixInodeInfo *pInode = pFile->pInode;
UnixUnusedFd *pError = 0;
UnixUnusedFd *p;
UnixUnusedFd *pNext;
for(p=pInode->pUnused; p; p=pNext){
pNext = p->pNext;
if( close(p->fd) ){
pFile->lastErrno = errno;
rc = SQLITE_IOERR_CLOSE;
p->pNext = pError;
pError = p;
}else{
sqlite3_free(p);
}
}
pInode->pUnused = pError;
return rc;
}
/*
** Release a unixInodeInfo structure previously allocated by findInodeInfo().
**
** The mutex entered using the unixEnterMutex() function must be held
** when this function is called.
*/
static void releaseInodeInfo(unixInodeInfo *pInode){
static void releaseInodeInfo(unixFile *pFile){
unixInodeInfo *pInode = pFile->pInode;
assert( unixMutexHeld() );
if( pInode ){
pInode->nRef--;
if( pInode->nRef==0 ){
assert( pInode->pShmNode==0 );
closePendingFds(pFile);
if( pInode->pPrev ){
assert( pInode->pPrev->pNext==pInode );
pInode->pPrev->pNext = pInode->pNext;
@@ -1152,36 +1184,6 @@ end_lock:
return rc;
}
/*
** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
** If all such file descriptors are closed without error, the list is
** cleared and SQLITE_OK returned.
**
** Otherwise, if an error occurs, then successfully closed file descriptor
** entries are removed from the list, and SQLITE_IOERR_CLOSE returned.
** not deleted and SQLITE_IOERR_CLOSE returned.
*/
static int closePendingFds(unixFile *pFile){
int rc = SQLITE_OK;
unixInodeInfo *pInode = pFile->pInode;
UnixUnusedFd *pError = 0;
UnixUnusedFd *p;
UnixUnusedFd *pNext;
for(p=pInode->pUnused; p; p=pNext){
pNext = p->pNext;
if( close(p->fd) ){
pFile->lastErrno = errno;
rc = SQLITE_IOERR_CLOSE;
p->pNext = pError;
pError = p;
}else{
sqlite3_free(p);
}
}
pInode->pUnused = pError;
return rc;
}
/*
** Add the file descriptor used by file handle pFile to the corresponding
** pUnused list.
@@ -1451,7 +1453,7 @@ static int unixClose(sqlite3_file *id){
*/
setPendingFd(pFile);
}
releaseInodeInfo(pFile->pInode);
releaseInodeInfo(pFile);
rc = closeUnixFile(id);
unixLeaveMutex();
}
@@ -2066,7 +2068,7 @@ static int semClose(sqlite3_file *id) {
semUnlock(id, NO_LOCK);
assert( pFile );
unixEnterMutex();
releaseInodeInfo(pFile->pInode);
releaseInodeInfo(pFile);
unixLeaveMutex();
closeUnixFile(id);
}
@@ -2533,7 +2535,7 @@ static int afpClose(sqlite3_file *id) {
*/
setPendingFd(pFile);
}
releaseInodeInfo(pFile->pInode);
releaseInodeInfo(pFile);
sqlite3_free(pFile->lockingContext);
rc = closeUnixFile(id);
unixLeaveMutex();
+16 -2
View File
@@ -76,7 +76,8 @@ struct Testvfs {
#define TESTVFS_OPEN_MASK 0x00000100
#define TESTVFS_SYNC_MASK 0x00000200
#define TESTVFS_ALL_MASK 0x000003FF
#define TESTVFS_DELETE_MASK 0x00000400
#define TESTVFS_ALL_MASK 0x000007FF
#define TESTVFS_MAX_PAGES 256
@@ -457,7 +458,19 @@ static int tvfsOpen(
** returning.
*/
static int tvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
return sqlite3OsDelete(PARENTVFS(pVfs), zPath, dirSync);
int rc = SQLITE_OK;
Testvfs *p = (Testvfs *)pVfs->pAppData;
if( p->pScript && p->mask&TESTVFS_DELETE_MASK ){
tvfsExecTcl(p, "xDelete",
Tcl_NewStringObj(zPath, -1), Tcl_NewIntObj(dirSync), 0
);
tvfsResultCode(p, &rc);
}
if( rc==SQLITE_OK ){
rc = sqlite3OsDelete(PARENTVFS(pVfs), zPath, dirSync);
}
return rc;
}
/*
@@ -843,6 +856,7 @@ static int testvfs_obj_cmd(
{ "xShmClose", TESTVFS_SHMCLOSE_MASK },
{ "xShmMap", TESTVFS_SHMMAP_MASK },
{ "xSync", TESTVFS_SYNC_MASK },
{ "xDelete", TESTVFS_DELETE_MASK },
{ "xOpen", TESTVFS_OPEN_MASK },
};
Tcl_Obj **apElem = 0;