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:
+36
-34
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user