Fix crash using "--command" on Windows

Use after free error accessing command line arguments on windows.
Resolve by duplicating the arguments when a "--command" is passed in.
This commit is contained in:
Campbell Barton
2024-04-10 11:49:08 +10:00
parent 256dbce9fa
commit d3ae39571e
3 changed files with 40 additions and 4 deletions

View File

@@ -567,8 +567,8 @@ int main(int argc,
if (G.background) { if (G.background) {
int exit_code; int exit_code;
if (app_state.main_arg_deferred != nullptr) { if (app_state.main_arg_deferred != nullptr) {
exit_code = main_arg_handle_deferred(); exit_code = main_arg_deferred_handle();
MEM_freeN(app_state.main_arg_deferred); main_arg_deferred_free();
} }
else { else {
exit_code = G.is_break ? EXIT_FAILURE : EXIT_SUCCESS; exit_code = G.is_break ? EXIT_FAILURE : EXIT_SUCCESS;

View File

@@ -429,6 +429,28 @@ fail:
* (Python in particular) * to be initialized. * (Python in particular) * to be initialized.
* \{ */ * \{ */
/* When the deferred argument is handled on Windows the `argv` will have been freed,
* see `USE_WIN32_UNICODE_ARGS` in `creator.cc`. */
# ifdef WIN32
static char **argv_duplicate(const char **argv, int argc)
{
char **argv_copy = static_cast<char **>(MEM_mallocN(sizeof(*argv_copy) * argc, __func__));
for (int i = 0; i < argc; i++) {
argv_copy[i] = BLI_strdup(argv[i]);
}
return argv_copy;
}
static void argv_free(char **argv, int argc)
{
for (int i = 0; i < argc; i++) {
MEM_freeN(argv[i]);
}
MEM_freeN(argv);
}
# endif /* !WIN32 */
struct BA_ArgCallback_Deferred { struct BA_ArgCallback_Deferred {
BA_ArgCallback func; BA_ArgCallback func;
int argc; int argc;
@@ -453,9 +475,22 @@ static void main_arg_deferred_setup(BA_ArgCallback func, int argc, const char **
d->argv = argv; d->argv = argv;
d->data = data; d->data = data;
d->exit_code = 0; d->exit_code = 0;
# ifdef WIN32
d->argv = const_cast<const char **>(argv_duplicate(d->argv, d->argc));
# endif
app_state.main_arg_deferred = d; app_state.main_arg_deferred = d;
} }
void main_arg_deferred_free()
{
BA_ArgCallback_Deferred *d = app_state.main_arg_deferred;
app_state.main_arg_deferred = nullptr;
# ifdef WIN32
argv_free(const_cast<char **>(d->argv), d->argc);
# endif
MEM_freeN(d);
}
static void main_arg_deferred_exit_code_set(int exit_code) static void main_arg_deferred_exit_code_set(int exit_code)
{ {
BA_ArgCallback_Deferred *d = app_state.main_arg_deferred; BA_ArgCallback_Deferred *d = app_state.main_arg_deferred;
@@ -463,7 +498,7 @@ static void main_arg_deferred_exit_code_set(int exit_code)
d->exit_code = exit_code; d->exit_code = exit_code;
} }
int main_arg_handle_deferred() int main_arg_deferred_handle()
{ {
BA_ArgCallback_Deferred *d = app_state.main_arg_deferred; BA_ArgCallback_Deferred *d = app_state.main_arg_deferred;
d->func(d->argc, d->argv, d->data); d->func(d->argc, d->argv, d->data);

View File

@@ -38,7 +38,8 @@ int main_args_handle_load_file(int argc, const char **argv, void *data);
* Handle an argument which requested deferred evaluation. * Handle an argument which requested deferred evaluation.
* Needed when arguments which evaluate early need Python to be initialized for example. * Needed when arguments which evaluate early need Python to be initialized for example.
*/ */
int main_arg_handle_deferred(); int main_arg_deferred_handle();
void main_arg_deferred_free();
/* `creator_signals.cc` */ /* `creator_signals.cc` */