~ chicken-core (chicken-5) 2cebcd70d4ac3258600410c771108dadee91fee0


commit 2cebcd70d4ac3258600410c771108dadee91fee0
Author:     felix <felix@call-with-current-continuation.org>
AuthorDate: Mon Dec 30 22:21:07 2024 +0100
Commit:     felix <felix@call-with-current-continuation.org>
CommitDate: Mon Dec 30 22:21:07 2024 +0100

    Use wide-char win32 API for retrieving command line
    
    (to avoid security issues pointed out by wasamasa)

diff --git a/chicken.h b/chicken.h
index ccdefe87..49e38d75 100644
--- a/chicken.h
+++ b/chicken.h
@@ -1610,7 +1610,11 @@ typedef void (C_ccall *C_proc)(C_word, C_word *) C_noret;
  * "/proc/<pid>/exe" or some similar trick).
  */
 #ifdef SEARCH_EXE_PATH
-# define C_set_main_exe(fname)          C_main_exe = C_resolve_executable_pathname(fname)
+# if defined(_WIN32) && !defined(__CYGWIN__)
+#  define C_set_main_exe(fname)          C_main_exe = C_resolve_executable_pathname(C_utf8(fname))
+# else
+#  define C_set_main_exe(fname)          C_main_exe = C_resolve_executable_pathname(fname)
+# endif
 #else
 # define C_set_main_exe(fname)
 #endif
@@ -1625,10 +1629,19 @@ typedef void (C_ccall *C_proc)(C_word, C_word *) C_noret;
     C_private_repository();				\
     return CHICKEN_main(0, NULL, (void *)C_toplevel); \
   }
+# elif defined(_WIN32) && !defined(__CYGWIN__)
+#  define C_main_entry_point            \
+  int wmain(int argc, wchar_t *argv[]) \
+ { \
+    C_set_gui_mode; \
+    C_set_main_exe(argv[0]);				\
+    C_private_repository();				\
+    return CHICKEN_main(argc, argv, (void*)C_toplevel); \
+  }
 # else
 #  define C_main_entry_point            \
   int main(int argc, char *argv[]) \
-  { \
+ { \
     C_set_gui_mode; \
     C_set_main_exe(argv[0]);				\
     C_private_repository();				\
@@ -1758,7 +1771,7 @@ C_varextern int
 C_varextern C_uword
   C_heap_growth,
   C_heap_shrinkage;
-C_varextern char
+C_varextern C_WCHAR
   **C_main_argv,
 #ifdef SEARCH_EXE_PATH
   *C_main_exe,
@@ -1775,7 +1788,7 @@ C_varextern C_word (*C_get_unbound_variable_value_hook)(C_word sym);
 C_BEGIN_C_DECLS
 
 C_fctexport void C_register_debug_info(C_DEBUG_INFO *);
-C_fctexport int CHICKEN_main(int argc, char *argv[], void *toplevel);
+C_fctexport int CHICKEN_main(int argc, C_WCHAR *argv[], void *toplevel);
 C_fctexport int CHICKEN_initialize(int heap, int stack, int symbols, void *toplevel);
 C_fctexport C_word CHICKEN_run(void *toplevel);
 C_fctexport C_word CHICKEN_continue(C_word k);
diff --git a/runtime.c b/runtime.c
index ec40f219..0efc4f13 100644
--- a/runtime.c
+++ b/runtime.c
@@ -604,19 +604,44 @@ C_dbg(C_char *prefix, C_char *fstr, ...)
 
 /* Startup code: */
 
-int CHICKEN_main(int argc, char *argv[], void *toplevel)
+int CHICKEN_main(int argc, C_WCHAR *argv[], void *toplevel)
 {
   C_word h, s, n;
 
   if(C_gui_mode) {
 #ifdef _WIN32
-    parse_argv(GetCommandLine());
+    parse_argv(C_utf8(GetCommandLineW()));
     argc = C_main_argc;
     argv = C_main_argv;
 #else
     /* ??? */
 #endif
   }
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  else {
+    int i, n;
+    C_char *aptr, *arg;
+    C_main_argv = (C_char **)malloc((MAXIMAL_NUMBER_OF_COMMAND_LINE_ARGUMENTS + 1) * sizeof(C_char *));
+
+    if(C_main_argv == NULL)
+      panic(C_text("cannot allocate argument-list buffer"));
+
+    for(i = 0; i < argc; ++i) {
+    	arg = C_utf8(argv[ i ]);
+    	n = strlen(arg);
+       aptr = (C_char *)malloc(n + 1);
+
+       if(!aptr) panic(C_text("cannot allocate argument buffer"));
+
+       C_strlcpy(aptr, arg, n + 1);
+       C_main_argv[ i ] = aptr;
+    }
+
+    C_main_argc = argc;
+    C_main_argv[ argc ] = NULL;
+    argv = C_main_argv;
+  }
+#endif
 
   pass_serious_signals = 0;
   CHICKEN_parse_command_line(argc, argv, &h, &s, &n);
@@ -629,22 +654,20 @@ int CHICKEN_main(int argc, char *argv[], void *toplevel)
 }
 
 
-/* Custom argv parser for Windoze: */
+/* Custom argv parser for Windowz: */
 
 void parse_argv(C_char *cmds)
 {
-  C_char *ptr = cmds,
-         *bptr0, *bptr, *aptr;
+  C_char *ptr = cmds, *bptr0, *bptr, *aptr;
   int n = 0;
-
-  C_main_argv = (C_char **)malloc(MAXIMAL_NUMBER_OF_COMMAND_LINE_ARGUMENTS * sizeof(C_char *));
+  C_main_argv = (C_char **)malloc((MAXIMAL_NUMBER_OF_COMMAND_LINE_ARGUMENTS + 1) * sizeof(C_char *));
 
   if(C_main_argv == NULL)
     panic(C_text("cannot allocate argument-list buffer"));
 
   C_main_argc = 0;
 
-  for(;;) {
+  while(C_main_argc < MAXIMAL_NUMBER_OF_COMMAND_LINE_ARGUMENTS) {
     while(C_utf_isspace((int)(*ptr))) ++ptr;
 
     if(*ptr == '\0') break;
@@ -653,15 +676,15 @@ void parse_argv(C_char *cmds)
       ++n;
 
     *bptr = '\0';
+    aptr = (C_char*)malloc(n + 1);
 
-    aptr = (C_char*) malloc(sizeof(C_char) * (n + 1));
-    if (!aptr)
-      panic(C_text("cannot allocate argument buffer"));
-
-    C_strlcpy(aptr, bptr0, sizeof(C_char) * (n + 1));
+    if(!aptr) panic(C_text("cannot allocate argument buffer"));
 
+    C_strlcpy(aptr, bptr0, n + 1);
     C_main_argv[ C_main_argc++ ] = aptr;
   }
+
+  C_main_argv[ C_main_argc ] = NULL;
 }
 
 /* simple linear congruential PRNG, to avoid OpenBSD warnings.
Trap