Fix use after free error on abort()

When aborting, the Global shared pointer for memory usage tracking
would be freed before Blender's temporary directory was purged.

Removing the temporary directory would then use MEM_* functions which
accessed the freed memory usage class.

Resolve by using malloc/free for the internal recursive_operation(..)
utility function.

Remove strip_last_slash utility function as it's a specific operation
which can be written in 2 lines & was only used once after this change.
This commit is contained in:
Campbell Barton
2023-12-18 12:09:19 +11:00
parent 29b5919ad1
commit 27fdda2f85

View File

@@ -857,16 +857,19 @@ enum {
typedef int (*RecursiveOp_Callback)(const char *from, const char *to);
/* appending of filename to dir (ensures for buffer size before appending) */
/**
* Append `file` to `dir` (ensures for buffer size before appending).
* \param dst: The destination memory (allocated by `malloc`).
*/
static void join_dirfile_alloc(char **dst, size_t *alloc_len, const char *dir, const char *file)
{
size_t len = strlen(dir) + strlen(file) + 1;
if (*dst == nullptr) {
*dst = MEM_cnew_array<char>(len + 1, "join_dirfile_alloc path");
*dst = static_cast<char *>(malloc(len + 1));
}
else if (*alloc_len < len) {
*dst = static_cast<char *>(MEM_reallocN(*dst, len + 1));
*dst = static_cast<char *>(realloc(*dst, len + 1));
}
*alloc_len = len;
@@ -874,14 +877,6 @@ static void join_dirfile_alloc(char **dst, size_t *alloc_len, const char *dir, c
BLI_path_join(*dst, len + 1, dir, file);
}
static char *strip_last_slash(const char *dirpath)
{
char *result = BLI_strdup(dirpath);
BLI_path_slash_rstrip(result);
return result;
}
/**
* Scans \a startfrom, generating a corresponding destination name for each item found by
* prefixing it with startto, recursively scanning subdirectories, and invoking the specified
@@ -893,7 +888,7 @@ static char *strip_last_slash(const char *dirpath)
* RecursiveOp_Callback_StopRecurs to skip the subdirectory.
* \param callback_file: Optional, to be invoked on each file found.
* \param callback_dir_post: optional, to be invoked after leaving a subdirectory.
* \return
* \return Zero on success.
*/
static int recursive_operation(const char *startfrom,
const char *startto,
@@ -901,6 +896,11 @@ static int recursive_operation(const char *startfrom,
RecursiveOp_Callback callback_file,
RecursiveOp_Callback callback_dir_post)
{
/* NOTE(@ideasman42): This function must *not* use any `MEM_*` functions
* as it's used to purge temporary files on when the processed is aborted,
* in this case the `MEM_*` state may have already been freed (memory usage tracking for e.g.)
* causing freed memory access, potentially crashing. This constraint doesn't apply to the
* callbacks themselves - unless they might also be called when aborting. */
struct stat st;
char *from = nullptr, *to = nullptr;
char *from_path = nullptr, *to_path = nullptr;
@@ -910,9 +910,11 @@ static int recursive_operation(const char *startfrom,
do { /* once */
/* ensure there's no trailing slash in file path */
from = strip_last_slash(startfrom);
from = strdup(startfrom);
BLI_path_slash_rstrip(from);
if (startto) {
to = strip_last_slash(startto);
to = strdup(startto);
BLI_path_slash_rstrip(to);
}
ret = lstat(from, &st);
@@ -1016,16 +1018,16 @@ static int recursive_operation(const char *startfrom,
free(dirlist);
}
if (from_path != nullptr) {
MEM_freeN(from_path);
free(from_path);
}
if (to_path != nullptr) {
MEM_freeN(to_path);
free(to_path);
}
if (from != nullptr) {
MEM_freeN(from);
free(from);
}
if (to != nullptr) {
MEM_freeN(to);
free(to);
}
return ret;
@@ -1408,7 +1410,8 @@ static const char *path_destination_ensure_filename(const char *path_src,
size_t buf_size)
{
if (BLI_is_dir(path_dst)) {
char *path_src_no_slash = strip_last_slash(path_src);
char *path_src_no_slash = BLI_strdup(path_src);
BLI_path_slash_rstrip(path_src_no_slash);
const char *filename_src = BLI_path_basename(path_src_no_slash);
if (filename_src != path_src_no_slash) {
const size_t buf_size_needed = strlen(path_dst) + 1 + strlen(filename_src) + 1;