Fix getdelim(2) leaking a freed pointer.

This commit is contained in:
Jonas 'Sortie' Termansen 2014-09-08 17:43:45 +02:00
parent e29f0cdd1e
commit ecccf4e1f7
1 changed files with 23 additions and 10 deletions

View File

@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014.
This file is part of the Sortix C Library. This file is part of the Sortix C Library.
@ -28,13 +28,17 @@
extern "C" ssize_t getdelim(char** lineptr, size_t* n, int delim, FILE* fp) extern "C" ssize_t getdelim(char** lineptr, size_t* n, int delim, FILE* fp)
{ {
if ( !lineptr || (*lineptr && !n) || !fp ) { errno = EINVAL; return -1; } if ( !lineptr || (*lineptr && !n) || !fp )
return errno = EINVAL, -1;
const size_t DEFAULT_BUFSIZE = 32UL; const size_t DEFAULT_BUFSIZE = 32UL;
int malloced = !*lineptr; bool malloced = !*lineptr;
if ( malloced ) { *lineptr = (char*) malloc(DEFAULT_BUFSIZE); } if ( malloced )
if ( !*lineptr ) { return -1; } *lineptr = (char*) malloc(DEFAULT_BUFSIZE);
if ( !*lineptr )
return -1;
size_t bufsize = malloced ? DEFAULT_BUFSIZE : *n; size_t bufsize = malloced ? DEFAULT_BUFSIZE : *n;
if ( n ) { *n = bufsize; } if ( n )
*n = bufsize;
ssize_t written = 0; ssize_t written = 0;
int c; int c;
flockfile(fp); flockfile(fp);
@ -42,15 +46,20 @@ extern "C" ssize_t getdelim(char** lineptr, size_t* n, int delim, FILE* fp)
{ {
if ( (c = getc_unlocked(fp)) == EOF ) if ( (c = getc_unlocked(fp)) == EOF )
{ {
if ( written ) { break; } else { goto cleanup; } if ( written )
break;
else
goto cleanup;
} }
if ( bufsize <= (size_t) written + 1UL ) if ( bufsize <= (size_t) written + 1UL )
{ {
size_t newbufsize = 2UL * bufsize; size_t newbufsize = 2UL * bufsize;
char* newbuf = (char*) realloc(*lineptr, newbufsize); char* newbuf = (char*) realloc(*lineptr, newbufsize);
if ( !newbuf ) { goto cleanup; } if ( !newbuf )
goto cleanup;
bufsize = newbufsize; bufsize = newbufsize;
if ( n ) { *n = bufsize; } if ( n )
*n = bufsize;
*lineptr = newbuf; *lineptr = newbuf;
} }
(*lineptr)[written++] = c; (*lineptr)[written++] = c;
@ -61,6 +70,10 @@ extern "C" ssize_t getdelim(char** lineptr, size_t* n, int delim, FILE* fp)
cleanup: cleanup:
funlockfile(fp); funlockfile(fp);
free(malloced ? *lineptr : NULL); if ( malloced )
{
free(*lineptr);
*lineptr = NULL;
}
return -1; return -1;
} }