From a793d371cdef1ac8d92ecf7ac704eaf28fdb2871 Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Fri, 20 Jun 2025 09:48:43 +0200 Subject: [PATCH] Move string-pointer-array handling to posix.c * libguile/posix.c (free_string_pointers): (free_string_pointers_on_unwind): (allocate_string_pointers): Move here from string.c, and use malloc/free instead of GC facilities. Adapt all users. * libguile/strings.h: * libguile/strings.c (scm_i_allocate_string_pointers): Remove. --- libguile/posix.c | 71 +++++++++++++++++++++++++++++++++++++++++----- libguile/strings.c | 46 ------------------------------ libguile/strings.h | 3 +- 3 files changed, 65 insertions(+), 55 deletions(-) diff --git a/libguile/posix.c b/libguile/posix.c index 0cd4e4ec4..ff97b35a9 100644 --- a/libguile/posix.c +++ b/libguile/posix.c @@ -1138,6 +1138,55 @@ SCM_DEFINE (scm_tcsetpgrp, "tcsetpgrp", 2, 0, 0, #undef FUNC_NAME #endif /* HAVE_TCSETPGRP */ +/* Return a newly allocated array of char pointers to each of the strings + in args, with a terminating NULL pointer. The strings are encoded using + the current locale. */ + +static void +free_string_pointers (char **pointers) +{ + for (char **walk = pointers; *walk; walk++) + free (*walk); + free (pointers); +} + +static void +free_string_pointers_on_unwind (void *data) +{ + free_string_pointers (data); +} + +static char ** +allocate_string_pointers (SCM list) +{ + int list_len = scm_ilength (list); + int i; + + if (list_len < 0) + scm_wrong_type_arg_msg (NULL, 0, list, "proper list"); + + char **result = scm_calloc ((list_len + 1) * sizeof (char *)); + + scm_dynwind_begin (0); + scm_dynwind_unwind_handler (free_string_pointers_on_unwind, result, 0); + + for (i = 0; i < list_len; i++, list = scm_cdr (list)) + { + SCM str = scm_car (list); + size_t len; /* String length in bytes */ + char *c_str = scm_to_locale_stringn (str, &len); + result[i] = malloc (len + 1); + memcpy (result[i], c_str, len); + result[i][len] = '\0'; + free (c_str); + } + + scm_dynwind_end (); + + return result; +} + + SCM_DEFINE (scm_execl, "execl", 1, 0, 1, (SCM filename, SCM args), "Executes the file named by @var{filename} as a new process image.\n" @@ -1159,7 +1208,7 @@ SCM_DEFINE (scm_execl, "execl", 1, 0, 1, exec_file = scm_to_locale_string (filename); scm_dynwind_free (exec_file); - exec_argv = scm_i_allocate_string_pointers (args); + exec_argv = allocate_string_pointers (args); #ifdef __MINGW32__ execv (exec_file, (const char * const *)exec_argv); @@ -1192,7 +1241,7 @@ SCM_DEFINE (scm_execlp, "execlp", 1, 0, 1, exec_file = scm_to_locale_string (filename); scm_dynwind_free (exec_file); - exec_argv = scm_i_allocate_string_pointers (args); + exec_argv = allocate_string_pointers (args); #ifdef __MINGW32__ execvp (exec_file, (const char * const *)exec_argv); @@ -1229,8 +1278,8 @@ SCM_DEFINE (scm_execle, "execle", 2, 0, 1, exec_file = scm_to_locale_string (filename); scm_dynwind_free (exec_file); - exec_argv = scm_i_allocate_string_pointers (args); - exec_env = scm_i_allocate_string_pointers (env); + exec_argv = allocate_string_pointers (args); + exec_env = allocate_string_pointers (env); #ifdef __MINGW32__ execve (exec_file, (const char * const *) exec_argv, (const char * const *) exec_env); @@ -1474,12 +1523,18 @@ SCM_DEFINE (scm_spawn_process, "spawn", 2, 0, 1, exec_file = scm_to_locale_string (program); scm_dynwind_free (exec_file); - exec_argv = scm_i_allocate_string_pointers (arguments); + exec_argv = allocate_string_pointers (arguments); + scm_dynwind_unwind_handler (free_string_pointers_on_unwind, exec_argv, + SCM_F_WIND_EXPLICITLY); if (SCM_UNBNDP (env)) exec_env = environ; else - exec_env = scm_i_allocate_string_pointers (env); + { + exec_env = allocate_string_pointers (env); + scm_dynwind_unwind_handler (free_string_pointers_on_unwind, exec_env, + SCM_F_WIND_EXPLICITLY); + } if (SCM_UNBNDP (in_scm)) in_scm = scm_current_input_port (); @@ -1530,7 +1585,7 @@ piped_process (pid_t *pid, SCM prog, SCM args, SCM from, SCM to) char **exec_env = environ; exec_file = scm_to_locale_string (prog); - exec_argv = scm_i_allocate_string_pointers (scm_cons (prog, args)); + exec_argv = allocate_string_pointers (scm_cons (prog, args)); reading = scm_is_pair (from); writing = scm_is_pair (to); @@ -1575,6 +1630,8 @@ piped_process (pid_t *pid, SCM prog, SCM args, SCM from, SCM to) *pid = do_spawn (exec_file, exec_argv, exec_env, in, out, err, 1); int errno_save = (*pid < 0) ? errno : 0; + free_string_pointers (exec_argv); + if (reading) close (c2p[1]); if (writing) diff --git a/libguile/strings.c b/libguile/strings.c index 9d87d0d14..dd4103f16 100644 --- a/libguile/strings.c +++ b/libguile/strings.c @@ -2430,52 +2430,6 @@ scm_makfromstrs (int argc, char **argv) return lst; } -/* Return a newly allocated array of char pointers to each of the strings - in args, with a terminating NULL pointer. The strings are encoded using - the current locale. */ - -char ** -scm_i_allocate_string_pointers (SCM list) -#define FUNC_NAME "scm_i_allocate_string_pointers" -{ - char **result; - int list_len = scm_ilength (list); - int i; - - if (list_len < 0) - scm_wrong_type_arg_msg (NULL, 0, list, "proper list"); - - result = scm_gc_malloc ((list_len + 1) * sizeof (char *), - "string pointers"); - result[list_len] = NULL; - - /* The list might have been modified in another thread, so - we check LIST before each access. - */ - for (i = 0; i < list_len && scm_is_pair (list); i++) - { - SCM str = SCM_CAR (list); - size_t len; /* String length in bytes */ - char *c_str = scm_to_locale_stringn (str, &len); - - /* OPTIMIZE-ME: Right now, scm_to_locale_stringn always uses - scm_malloc to allocate the returned string, which must be - explicitly deallocated. This forces us to copy the string a - second time into a new buffer. Ideally there would be variants - of scm_to_*_stringn that can return garbage-collected buffers. */ - - result[i] = scm_gc_malloc_pointerless (len + 1, "string"); - memcpy (result[i], c_str, len); - result[i][len] = '\0'; - free (c_str); - - list = SCM_CDR (list); - } - - return result; -} -#undef FUNC_NAME - void scm_i_get_substring_spec (size_t len, SCM start, size_t *cstart, diff --git a/libguile/strings.h b/libguile/strings.h index d417514f8..4b0d85857 100644 --- a/libguile/strings.h +++ b/libguile/strings.h @@ -1,7 +1,7 @@ #ifndef SCM_STRINGS_H #define SCM_STRINGS_H -/* Copyright 1995-1998,2000-2001,2004-2006,2008-2011,2013,2015-2019,2022 +/* Copyright 1995-1998,2000-2001,2004-2006,2008-2011,2013,2015-2019,2022,2025 Free Software Foundation, Inc. This file is part of Guile. @@ -265,7 +265,6 @@ SCM_INTERNAL void scm_decoding_error (const char *subr, int err, /* internal utility functions. */ -SCM_INTERNAL char **scm_i_allocate_string_pointers (SCM list); SCM_INTERNAL void scm_i_get_substring_spec (size_t len, SCM start, size_t *cstart, SCM end, size_t *cend);