config_file: drop the redundant stat before reading a config

config_file_new_from_path_to_string() guarded the read with
path_is_valid(), a stat, and then called filestream_read_file(),
which opens the file itself and returns 0 when it cannot.  The stat
repeated the lookup the open already does.

No caller can tell the two apart: a path that fails path_is_valid and
one that fails to open both leave the function through the same NULL
return, and none of the ~46 callers inspects why.  So the stat's
result was never visible - pure duplicate work.

Removing it also closes the small window between the stat and the
open in which the file could be replaced or deleted, the usual
time-of-check/time-of-use gap.

Behaviour is unchanged: a valid file parses, a missing file and a
NULL path both return NULL, since filestream_read_file() and
filestream_open() already reject both.  Verified against all three.

The cost is immaterial - about a third of a millisecond across 300
core-info files on a warm cache - so this is a simplification and a
TOCTOU removal, not a speedup.  It matters a little more where a stat
is dear: cold cache, network shares, the slow flash on handhelds.
This commit is contained in:
libretroadmin committed 2026-07-25 00:57:54 +02:00
1 parent 285f966632
commit 41157ba829
1 file changed
+19 -15
+19 -15
View File
@@ -828,24 +828,28 @@ config_file_t *config_file_new_from_string(char *from_string,
config_file_t *config_file_new_from_path_to_string(const char *path)
{
if (path_is_valid(path))
uint8_t *ret_buf = NULL;
int64_t length = 0;
/* No path_is_valid() first: filestream_read_file() opens the file
* itself and returns 0 when it cannot, so a preceding stat only
* repeats the lookup the open already does - and no caller can see
* its result, since a missing file and an unreadable one both land
* on the same NULL return. Dropping it also closes the window
* between the stat and the open in which the file could change. */
if (filestream_read_file(path, (void**)&ret_buf, &length))
{
uint8_t *ret_buf = NULL;
int64_t length = 0;
if (filestream_read_file(path, (void**)&ret_buf, &length))
{
config_file_t *conf = NULL;
/* Note: 'ret_buf' is not used outside this
* function - we do not care that it will be
* modified by config_file_new_from_string() */
if (length >= 0)
conf = config_file_new_from_string((char*)ret_buf, path);
config_file_t *conf = NULL;
/* Note: 'ret_buf' is not used outside this
* function - we do not care that it will be
* modified by config_file_new_from_string() */
if (length >= 0)
conf = config_file_new_from_string((char*)ret_buf, path);
if ((void*)ret_buf)
free((void*)ret_buf);
if ((void*)ret_buf)
free((void*)ret_buf);
return conf;
}
return conf;
}
return NULL;