Skip to content

Commit

Permalink
fix #3764
Browse files Browse the repository at this point in the history
This answer a static analysis tool,
which complains that a buffer allocation is not free() just before exit().

In general, this requirement is not necessary, because invoking exit() will make the OS reclaim all buffers from the terminated process.

I could articulate this new requirement in a "not too heavy" way with the use of a new macro, `CONTROL_EXIT()`.
But "not too heavy" is still a form of maintenance burden: whenever the code is modified, by adding, removing or changing some of these buffers, it requires some form of coordination with exit points, which is easy to let go wrong.
Besides, I wouldn't be surprised if there were some more complex scenarios left, typically across multiple levels of functions, where a call to `exit()` is made while some other buffers, inaccessible from the function, are still allocated. Tackling such issues would require a very different approach, typically forbidding the use of `exit()`, which was meant to simplify code maintenance by reducing the nb and complexity of error paths.
I question the need to make the code more complex to read and maintain, just to tackle a largely theoretical problem with no practical impact on target platforms.
  • Loading branch information
Cyan4973 committed Oct 8, 2023
1 parent c692b8d commit bfeb456
Showing 1 changed file with 12 additions and 7 deletions.
19 changes: 12 additions & 7 deletions programs/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,17 @@ extern "C" {
* It's designed for failures that may happen rarely,
* but we don't want to maintain a specific error code path for them,
* such as a malloc() returning NULL for example.
* Since it's always active, this macro can trigger side effects.
*/
#define CONTROL(c) { \
#define CONTROL(c) CONTROL_EXIT(c, {})

/* CONTROL_EXIT:
* Same as CONTROL, but can also run a last action before exit()
*/
#define CONTROL_EXIT(c, _action) { \
if (!(c)) { \
UTIL_DISPLAYLEVEL(1, "Error : %s, %i : %s", \
UTIL_DISPLAYLEVEL(1, "Error : %s, %i : %s not respected", \
__FILE__, __LINE__, #c); \
{ _action; } \
exit(1); \
} }

Expand Down Expand Up @@ -685,7 +690,7 @@ UTIL_createFileNamesTable_fromFileName(const char* inputFileName)
}

{ const char** filenamesTable = (const char**) malloc(nbFiles * sizeof(*filenamesTable));
CONTROL(filenamesTable != NULL);
CONTROL_EXIT(filenamesTable != NULL, free(buf));

{ size_t fnb;
for (fnb = 0, pos = 0; fnb < nbFiles; fnb++) {
Expand Down Expand Up @@ -774,12 +779,12 @@ UTIL_mergeFileNamesTable(FileNamesTable* table1, FileNamesTable* table2)
newTotalTableSize = getTotalTableSize(table1) + getTotalTableSize(table2);

buf = (char*) calloc(newTotalTableSize, sizeof(*buf));
CONTROL ( buf != NULL );
CONTROL_EXIT ( buf != NULL, UTIL_freeFileNamesTable(newTable) );

newTable->buf = buf;
newTable->tableSize = table1->tableSize + table2->tableSize;
newTable->fileNames = (const char **) calloc(newTable->tableSize, sizeof(*(newTable->fileNames)));
CONTROL ( newTable->fileNames != NULL );
CONTROL_EXIT ( newTable->fileNames != NULL, { free(buf); UTIL_freeFileNamesTable(newTable); } );

{ unsigned idx1;
for( idx1=0 ; (idx1 < table1->tableSize) && table1->fileNames[idx1] && (pos < newTotalTableSize); ++idx1, ++newTableIdx) {
Expand Down Expand Up @@ -1266,7 +1271,7 @@ void UTIL_mirrorSourceFilesDirectories(const char** inFileNames, unsigned int nb
for (i = 0; i < nbFile; ++i) {
if (isFileNameValidForMirroredOutput(inFileNames[i])) {
char* fname = STRDUP(inFileNames[i]);
CONTROL(fname != NULL);
CONTROL_EXIT(fname != NULL, free(srcFileNames));
srcFileNames[validFilenamesNr++] = fname;
}
}
Expand Down

0 comments on commit bfeb456

Please sign in to comment.