(root)/
Python-3.12.0/
Programs/
_testembed.c
       1  #ifndef Py_BUILD_CORE_MODULE
       2  #  define Py_BUILD_CORE_MODULE
       3  #endif
       4  
       5  /* Always enable assertion (even in release mode) */
       6  #undef NDEBUG
       7  
       8  #include <Python.h>
       9  #include "pycore_initconfig.h"    // _PyConfig_InitCompatConfig()
      10  #include "pycore_runtime.h"       // _PyRuntime
      11  #include "pycore_import.h"        // _PyImport_FrozenBootstrap
      12  #include <inttypes.h>
      13  #include <stdio.h>
      14  #include <stdlib.h>               // putenv()
      15  #include <wchar.h>
      16  
      17  int main_argc;
      18  char **main_argv;
      19  
      20  /*********************************************************
      21   * Embedded interpreter tests that need a custom exe
      22   *
      23   * Executed via Lib/test/test_embed.py
      24   *********************************************************/
      25  
      26  // Use to display the usage
      27  #define PROGRAM "test_embed"
      28  
      29  /* Use path starting with "./" avoids a search along the PATH */
      30  #define PROGRAM_NAME L"./_testembed"
      31  
      32  #define INIT_LOOPS 4
      33  
      34  // Ignore Py_DEPRECATED() compiler warnings: deprecated functions are
      35  // tested on purpose here.
      36  _Py_COMP_DIAG_PUSH
      37  _Py_COMP_DIAG_IGNORE_DEPR_DECLS
      38  
      39  
      40  static void error(const char *msg)
      41  {
      42      fprintf(stderr, "ERROR: %s\n", msg);
      43      fflush(stderr);
      44  }
      45  
      46  
      47  static void config_set_string(PyConfig *config, wchar_t **config_str, const wchar_t *str)
      48  {
      49      PyStatus status = PyConfig_SetString(config, config_str, str);
      50      if (PyStatus_Exception(status)) {
      51          PyConfig_Clear(config);
      52          Py_ExitStatusException(status);
      53      }
      54  }
      55  
      56  
      57  static void config_set_program_name(PyConfig *config)
      58  {
      59      const wchar_t *program_name = PROGRAM_NAME;
      60      config_set_string(config, &config->program_name, program_name);
      61  }
      62  
      63  
      64  static void init_from_config_clear(PyConfig *config)
      65  {
      66      PyStatus status = Py_InitializeFromConfig(config);
      67      PyConfig_Clear(config);
      68      if (PyStatus_Exception(status)) {
      69          Py_ExitStatusException(status);
      70      }
      71  }
      72  
      73  
      74  static void _testembed_Py_InitializeFromConfig(void)
      75  {
      76      PyConfig config;
      77      _PyConfig_InitCompatConfig(&config);
      78      config_set_program_name(&config);
      79      init_from_config_clear(&config);
      80  }
      81  
      82  static void _testembed_Py_Initialize(void)
      83  {
      84     Py_SetProgramName(PROGRAM_NAME);
      85     Py_Initialize();
      86  }
      87  
      88  
      89  /*****************************************************
      90   * Test repeated initialisation and subinterpreters
      91   *****************************************************/
      92  
      93  static void print_subinterp(void)
      94  {
      95      /* Output information about the interpreter in the format
      96         expected in Lib/test/test_capi.py (test_subinterps). */
      97      PyThreadState *ts = PyThreadState_Get();
      98      PyInterpreterState *interp = ts->interp;
      99      int64_t id = PyInterpreterState_GetID(interp);
     100      printf("interp %" PRId64 " <0x%" PRIXPTR ">, thread state <0x%" PRIXPTR ">: ",
     101              id, (uintptr_t)interp, (uintptr_t)ts);
     102      fflush(stdout);
     103      PyRun_SimpleString(
     104          "import sys;"
     105          "print('id(modules) =', id(sys.modules));"
     106          "sys.stdout.flush()"
     107      );
     108  }
     109  
     110  static int test_repeated_init_and_subinterpreters(void)
     111  {
     112      PyThreadState *mainstate, *substate;
     113      PyGILState_STATE gilstate;
     114  
     115      for (int i=1; i <= INIT_LOOPS; i++) {
     116          printf("--- Pass %d ---\n", i);
     117          _testembed_Py_InitializeFromConfig();
     118          mainstate = PyThreadState_Get();
     119  
     120          PyEval_ReleaseThread(mainstate);
     121  
     122          gilstate = PyGILState_Ensure();
     123          print_subinterp();
     124          PyThreadState_Swap(NULL);
     125  
     126          for (int j=0; j<3; j++) {
     127              substate = Py_NewInterpreter();
     128              print_subinterp();
     129              Py_EndInterpreter(substate);
     130          }
     131  
     132          PyThreadState_Swap(mainstate);
     133          print_subinterp();
     134          PyGILState_Release(gilstate);
     135  
     136          PyEval_RestoreThread(mainstate);
     137          Py_Finalize();
     138      }
     139      return 0;
     140  }
     141  
     142  #define EMBEDDED_EXT_NAME "embedded_ext"
     143  
     144  static PyModuleDef embedded_ext = {
     145      PyModuleDef_HEAD_INIT,
     146      .m_name = EMBEDDED_EXT_NAME,
     147      .m_size = 0,
     148  };
     149  
     150  static PyObject*
     151  PyInit_embedded_ext(void)
     152  {
     153      return PyModule_Create(&embedded_ext);
     154  }
     155  
     156  /****************************************************************************
     157   * Call Py_Initialize()/Py_Finalize() multiple times and execute Python code
     158   ***************************************************************************/
     159  
     160  // Used by bpo-46417 to test that structseq types used by the sys module are
     161  // cleared properly and initialized again properly when Python is finalized
     162  // multiple times.
     163  static int test_repeated_init_exec(void)
     164  {
     165      if (main_argc < 3) {
     166          fprintf(stderr, "usage: %s test_repeated_init_exec CODE\n", PROGRAM);
     167          exit(1);
     168      }
     169      const char *code = main_argv[2];
     170  
     171      for (int i=1; i <= INIT_LOOPS; i++) {
     172          fprintf(stderr, "--- Loop #%d ---\n", i);
     173          fflush(stderr);
     174  
     175          _testembed_Py_InitializeFromConfig();
     176          int err = PyRun_SimpleString(code);
     177          Py_Finalize();
     178          if (err) {
     179              return 1;
     180          }
     181      }
     182      return 0;
     183  }
     184  
     185  /****************************************************************************
     186   * Test the Py_Initialize(Ex) convenience/compatibility wrappers
     187   ***************************************************************************/
     188  // This is here to help ensure there are no wrapper resource leaks (gh-96853)
     189  static int test_repeated_simple_init(void)
     190  {
     191      for (int i=1; i <= INIT_LOOPS; i++) {
     192          fprintf(stderr, "--- Loop #%d ---\n", i);
     193          fflush(stderr);
     194  
     195          _testembed_Py_Initialize();
     196          Py_Finalize();
     197          printf("Finalized\n"); // Give test_embed some output to check
     198      }
     199      return 0;
     200  }
     201  
     202  
     203  /*****************************************************
     204   * Test forcing a particular IO encoding
     205   *****************************************************/
     206  
     207  static void check_stdio_details(const char *encoding, const char * errors)
     208  {
     209      /* Output info for the test case to check */
     210      if (encoding) {
     211          printf("Expected encoding: %s\n", encoding);
     212      } else {
     213          printf("Expected encoding: default\n");
     214      }
     215      if (errors) {
     216          printf("Expected errors: %s\n", errors);
     217      } else {
     218          printf("Expected errors: default\n");
     219      }
     220      fflush(stdout);
     221      /* Force the given IO encoding */
     222      Py_SetStandardStreamEncoding(encoding, errors);
     223      _testembed_Py_InitializeFromConfig();
     224      PyRun_SimpleString(
     225          "import sys;"
     226          "print('stdin: {0.encoding}:{0.errors}'.format(sys.stdin));"
     227          "print('stdout: {0.encoding}:{0.errors}'.format(sys.stdout));"
     228          "print('stderr: {0.encoding}:{0.errors}'.format(sys.stderr));"
     229          "sys.stdout.flush()"
     230      );
     231      Py_Finalize();
     232  }
     233  
     234  static int test_forced_io_encoding(void)
     235  {
     236      /* Check various combinations */
     237      printf("--- Use defaults ---\n");
     238      check_stdio_details(NULL, NULL);
     239      printf("--- Set errors only ---\n");
     240      check_stdio_details(NULL, "ignore");
     241      printf("--- Set encoding only ---\n");
     242      check_stdio_details("iso8859-1", NULL);
     243      printf("--- Set encoding and errors ---\n");
     244      check_stdio_details("iso8859-1", "replace");
     245  
     246      /* Check calling after initialization fails */
     247      Py_Initialize();
     248  
     249      if (Py_SetStandardStreamEncoding(NULL, NULL) == 0) {
     250          printf("Unexpected success calling Py_SetStandardStreamEncoding");
     251      }
     252      Py_Finalize();
     253      return 0;
     254  }
     255  
     256  /*********************************************************
     257   * Test parts of the C-API that work before initialization
     258   *********************************************************/
     259  
     260  /* The pre-initialization tests tend to break by segfaulting, so explicitly
     261   * flushed progress messages make the broken API easier to find when they fail.
     262   */
     263  #define _Py_EMBED_PREINIT_CHECK(msg) \
     264      do {printf(msg); fflush(stdout);} while (0);
     265  
     266  static int test_pre_initialization_api(void)
     267  {
     268      /* the test doesn't support custom memory allocators */
     269      putenv("PYTHONMALLOC=");
     270  
     271      /* Leading "./" ensures getpath.c can still find the standard library */
     272      _Py_EMBED_PREINIT_CHECK("Checking Py_DecodeLocale\n");
     273      wchar_t *program = Py_DecodeLocale("./spam", NULL);
     274      if (program == NULL) {
     275          fprintf(stderr, "Fatal error: cannot decode program name\n");
     276          return 1;
     277      }
     278      _Py_EMBED_PREINIT_CHECK("Checking Py_SetProgramName\n");
     279      Py_SetProgramName(program);
     280  
     281      _Py_EMBED_PREINIT_CHECK("Initializing interpreter\n");
     282      Py_Initialize();
     283      _Py_EMBED_PREINIT_CHECK("Check sys module contents\n");
     284      PyRun_SimpleString("import sys; "
     285                         "print('sys.executable:', sys.executable)");
     286      _Py_EMBED_PREINIT_CHECK("Finalizing interpreter\n");
     287      Py_Finalize();
     288  
     289      _Py_EMBED_PREINIT_CHECK("Freeing memory allocated by Py_DecodeLocale\n");
     290      PyMem_RawFree(program);
     291      return 0;
     292  }
     293  
     294  
     295  /* bpo-33042: Ensure embedding apps can predefine sys module options */
     296  static int test_pre_initialization_sys_options(void)
     297  {
     298      /* We allocate a couple of the options dynamically, and then delete
     299       * them before calling Py_Initialize. This ensures the interpreter isn't
     300       * relying on the caller to keep the passed in strings alive.
     301       */
     302      const wchar_t *static_warnoption = L"once";
     303      const wchar_t *static_xoption = L"also_not_an_option=2";
     304      size_t warnoption_len = wcslen(static_warnoption);
     305      size_t xoption_len = wcslen(static_xoption);
     306      wchar_t *dynamic_once_warnoption = \
     307               (wchar_t *) calloc(warnoption_len+1, sizeof(wchar_t));
     308      wchar_t *dynamic_xoption = \
     309               (wchar_t *) calloc(xoption_len+1, sizeof(wchar_t));
     310      wcsncpy(dynamic_once_warnoption, static_warnoption, warnoption_len+1);
     311      wcsncpy(dynamic_xoption, static_xoption, xoption_len+1);
     312  
     313      _Py_EMBED_PREINIT_CHECK("Checking PySys_AddWarnOption\n");
     314      PySys_AddWarnOption(L"default");
     315      _Py_EMBED_PREINIT_CHECK("Checking PySys_ResetWarnOptions\n");
     316      PySys_ResetWarnOptions();
     317      _Py_EMBED_PREINIT_CHECK("Checking PySys_AddWarnOption linked list\n");
     318      PySys_AddWarnOption(dynamic_once_warnoption);
     319      PySys_AddWarnOption(L"module");
     320      PySys_AddWarnOption(L"default");
     321      _Py_EMBED_PREINIT_CHECK("Checking PySys_AddXOption\n");
     322      PySys_AddXOption(L"not_an_option=1");
     323      PySys_AddXOption(dynamic_xoption);
     324  
     325      /* Delete the dynamic options early */
     326      free(dynamic_once_warnoption);
     327      dynamic_once_warnoption = NULL;
     328      free(dynamic_xoption);
     329      dynamic_xoption = NULL;
     330  
     331      _Py_EMBED_PREINIT_CHECK("Initializing interpreter\n");
     332      _testembed_Py_InitializeFromConfig();
     333      _Py_EMBED_PREINIT_CHECK("Check sys module contents\n");
     334      PyRun_SimpleString("import sys; "
     335                         "print('sys.warnoptions:', sys.warnoptions); "
     336                         "print('sys._xoptions:', sys._xoptions); "
     337                         "warnings = sys.modules['warnings']; "
     338                         "latest_filters = [f[0] for f in warnings.filters[:3]]; "
     339                         "print('warnings.filters[:3]:', latest_filters)");
     340      _Py_EMBED_PREINIT_CHECK("Finalizing interpreter\n");
     341      Py_Finalize();
     342  
     343      return 0;
     344  }
     345  
     346  
     347  /* bpo-20891: Avoid race condition when initialising the GIL */
     348  static void bpo20891_thread(void *lockp)
     349  {
     350      PyThread_type_lock lock = *((PyThread_type_lock*)lockp);
     351  
     352      PyGILState_STATE state = PyGILState_Ensure();
     353      if (!PyGILState_Check()) {
     354          error("PyGILState_Check failed!");
     355          abort();
     356      }
     357  
     358      PyGILState_Release(state);
     359  
     360      PyThread_release_lock(lock);
     361  }
     362  
     363  static int test_bpo20891(void)
     364  {
     365      /* the test doesn't support custom memory allocators */
     366      putenv("PYTHONMALLOC=");
     367  
     368      /* bpo-20891: Calling PyGILState_Ensure in a non-Python thread must not
     369         crash. */
     370      PyThread_type_lock lock = PyThread_allocate_lock();
     371      if (!lock) {
     372          error("PyThread_allocate_lock failed!");
     373          return 1;
     374      }
     375  
     376      _testembed_Py_InitializeFromConfig();
     377  
     378      unsigned long thrd = PyThread_start_new_thread(bpo20891_thread, &lock);
     379      if (thrd == PYTHREAD_INVALID_THREAD_ID) {
     380          error("PyThread_start_new_thread failed!");
     381          return 1;
     382      }
     383      PyThread_acquire_lock(lock, WAIT_LOCK);
     384  
     385      Py_BEGIN_ALLOW_THREADS
     386      /* wait until the thread exit */
     387      PyThread_acquire_lock(lock, WAIT_LOCK);
     388      Py_END_ALLOW_THREADS
     389  
     390      PyThread_free_lock(lock);
     391  
     392      Py_Finalize();
     393  
     394      return 0;
     395  }
     396  
     397  static int test_initialize_twice(void)
     398  {
     399      _testembed_Py_InitializeFromConfig();
     400  
     401      /* bpo-33932: Calling Py_Initialize() twice should do nothing
     402       * (and not crash!). */
     403      Py_Initialize();
     404  
     405      Py_Finalize();
     406  
     407      return 0;
     408  }
     409  
     410  static int test_initialize_pymain(void)
     411  {
     412      wchar_t *argv[] = {L"PYTHON", L"-c",
     413                         (L"import sys; "
     414                          L"print(f'Py_Main() after Py_Initialize: "
     415                          L"sys.argv={sys.argv}')"),
     416                         L"arg2"};
     417      _testembed_Py_InitializeFromConfig();
     418  
     419      /* bpo-34008: Calling Py_Main() after Py_Initialize() must not crash */
     420      Py_Main(Py_ARRAY_LENGTH(argv), argv);
     421  
     422      Py_Finalize();
     423  
     424      return 0;
     425  }
     426  
     427  
     428  static void
     429  dump_config(void)
     430  {
     431      (void) PyRun_SimpleStringFlags(
     432          "import _testinternalcapi, json; "
     433          "print(json.dumps(_testinternalcapi.get_configs()))",
     434          0);
     435  }
     436  
     437  
     438  static int test_init_initialize_config(void)
     439  {
     440      _testembed_Py_InitializeFromConfig();
     441      dump_config();
     442      Py_Finalize();
     443      return 0;
     444  }
     445  
     446  
     447  static void config_set_argv(PyConfig *config, Py_ssize_t argc, wchar_t * const *argv)
     448  {
     449      PyStatus status = PyConfig_SetArgv(config, argc, argv);
     450      if (PyStatus_Exception(status)) {
     451          PyConfig_Clear(config);
     452          Py_ExitStatusException(status);
     453      }
     454  }
     455  
     456  
     457  static void
     458  config_set_wide_string_list(PyConfig *config, PyWideStringList *list,
     459                              Py_ssize_t length, wchar_t **items)
     460  {
     461      PyStatus status = PyConfig_SetWideStringList(config, list, length, items);
     462      if (PyStatus_Exception(status)) {
     463          PyConfig_Clear(config);
     464          Py_ExitStatusException(status);
     465      }
     466  }
     467  
     468  
     469  static int check_init_compat_config(int preinit)
     470  {
     471      PyStatus status;
     472  
     473      if (preinit) {
     474          PyPreConfig preconfig;
     475          _PyPreConfig_InitCompatConfig(&preconfig);
     476  
     477          status = Py_PreInitialize(&preconfig);
     478          if (PyStatus_Exception(status)) {
     479              Py_ExitStatusException(status);
     480          }
     481      }
     482  
     483      PyConfig config;
     484      _PyConfig_InitCompatConfig(&config);
     485  
     486      config_set_program_name(&config);
     487      init_from_config_clear(&config);
     488  
     489      dump_config();
     490      Py_Finalize();
     491      return 0;
     492  }
     493  
     494  
     495  static int test_preinit_compat_config(void)
     496  {
     497      return check_init_compat_config(1);
     498  }
     499  
     500  
     501  static int test_init_compat_config(void)
     502  {
     503      return check_init_compat_config(0);
     504  }
     505  
     506  
     507  static int test_init_global_config(void)
     508  {
     509      /* FIXME: test Py_IgnoreEnvironmentFlag */
     510  
     511      putenv("PYTHONUTF8=0");
     512      Py_UTF8Mode = 1;
     513  
     514      /* Test initialization from global configuration variables (Py_xxx) */
     515      Py_SetProgramName(L"./globalvar");
     516  
     517      /* Py_IsolatedFlag is not tested */
     518      Py_NoSiteFlag = 1;
     519      Py_BytesWarningFlag = 1;
     520  
     521      putenv("PYTHONINSPECT=");
     522      Py_InspectFlag = 1;
     523  
     524      putenv("PYTHONOPTIMIZE=0");
     525      Py_InteractiveFlag = 1;
     526  
     527      putenv("PYTHONDEBUG=0");
     528      Py_OptimizeFlag = 2;
     529  
     530      /* Py_DebugFlag is not tested */
     531  
     532      putenv("PYTHONDONTWRITEBYTECODE=");
     533      Py_DontWriteBytecodeFlag = 1;
     534  
     535      putenv("PYTHONVERBOSE=0");
     536      Py_VerboseFlag = 1;
     537  
     538      Py_QuietFlag = 1;
     539      Py_NoUserSiteDirectory = 1;
     540  
     541      putenv("PYTHONUNBUFFERED=");
     542      Py_UnbufferedStdioFlag = 1;
     543  
     544      Py_FrozenFlag = 1;
     545  
     546      /* FIXME: test Py_LegacyWindowsFSEncodingFlag */
     547      /* FIXME: test Py_LegacyWindowsStdioFlag */
     548  
     549      Py_Initialize();
     550      dump_config();
     551      Py_Finalize();
     552      return 0;
     553  }
     554  
     555  
     556  static int test_init_from_config(void)
     557  {
     558      PyPreConfig preconfig;
     559      _PyPreConfig_InitCompatConfig(&preconfig);
     560  
     561      putenv("PYTHONMALLOC=malloc_debug");
     562      preconfig.allocator = PYMEM_ALLOCATOR_MALLOC;
     563  
     564      putenv("PYTHONUTF8=0");
     565      Py_UTF8Mode = 0;
     566      preconfig.utf8_mode = 1;
     567  
     568      PyStatus status = Py_PreInitialize(&preconfig);
     569      if (PyStatus_Exception(status)) {
     570          Py_ExitStatusException(status);
     571      }
     572  
     573      PyConfig config;
     574      _PyConfig_InitCompatConfig(&config);
     575  
     576      config.install_signal_handlers = 0;
     577  
     578      /* FIXME: test use_environment */
     579  
     580      putenv("PYTHONHASHSEED=42");
     581      config.use_hash_seed = 1;
     582      config.hash_seed = 123;
     583  
     584      /* dev_mode=1 is tested in test_init_dev_mode() */
     585  
     586      putenv("PYTHONFAULTHANDLER=");
     587      config.faulthandler = 1;
     588  
     589      putenv("PYTHONTRACEMALLOC=0");
     590      config.tracemalloc = 2;
     591  
     592      putenv("PYTHONPROFILEIMPORTTIME=0");
     593      config.import_time = 1;
     594  
     595      putenv("PYTHONNODEBUGRANGES=0");
     596      config.code_debug_ranges = 0;
     597  
     598      config.show_ref_count = 1;
     599      /* FIXME: test dump_refs: bpo-34223 */
     600  
     601      putenv("PYTHONMALLOCSTATS=0");
     602      config.malloc_stats = 1;
     603  
     604      putenv("PYTHONPYCACHEPREFIX=env_pycache_prefix");
     605      config_set_string(&config, &config.pycache_prefix, L"conf_pycache_prefix");
     606  
     607      Py_SetProgramName(L"./globalvar");
     608      config_set_string(&config, &config.program_name, L"./conf_program_name");
     609  
     610      wchar_t* argv[] = {
     611          L"python3",
     612          L"-W",
     613          L"cmdline_warnoption",
     614          L"-X",
     615          L"cmdline_xoption",
     616          L"-c",
     617          L"pass",
     618          L"arg2",
     619      };
     620      config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
     621      config.parse_argv = 1;
     622  
     623      wchar_t* xoptions[3] = {
     624          L"config_xoption1=3",
     625          L"config_xoption2=",
     626          L"config_xoption3",
     627      };
     628      config_set_wide_string_list(&config, &config.xoptions,
     629                                  Py_ARRAY_LENGTH(xoptions), xoptions);
     630  
     631      wchar_t* warnoptions[1] = {
     632          L"config_warnoption",
     633      };
     634      config_set_wide_string_list(&config, &config.warnoptions,
     635                                  Py_ARRAY_LENGTH(warnoptions), warnoptions);
     636  
     637      /* FIXME: test pythonpath_env */
     638      /* FIXME: test home */
     639      /* FIXME: test path config: module_search_path .. dll_path */
     640  
     641      putenv("PYTHONPLATLIBDIR=env_platlibdir");
     642      status = PyConfig_SetBytesString(&config, &config.platlibdir, "my_platlibdir");
     643      if (PyStatus_Exception(status)) {
     644          PyConfig_Clear(&config);
     645          Py_ExitStatusException(status);
     646      }
     647  
     648      putenv("PYTHONVERBOSE=0");
     649      Py_VerboseFlag = 0;
     650      config.verbose = 1;
     651  
     652      Py_NoSiteFlag = 0;
     653      config.site_import = 0;
     654  
     655      Py_BytesWarningFlag = 0;
     656      config.bytes_warning = 1;
     657  
     658      putenv("PYTHONINSPECT=");
     659      Py_InspectFlag = 0;
     660      config.inspect = 1;
     661  
     662      Py_InteractiveFlag = 0;
     663      config.interactive = 1;
     664  
     665      putenv("PYTHONOPTIMIZE=0");
     666      Py_OptimizeFlag = 1;
     667      config.optimization_level = 2;
     668  
     669      /* FIXME: test parser_debug */
     670  
     671      putenv("PYTHONDONTWRITEBYTECODE=");
     672      Py_DontWriteBytecodeFlag = 0;
     673      config.write_bytecode = 0;
     674  
     675      Py_QuietFlag = 0;
     676      config.quiet = 1;
     677  
     678      config.configure_c_stdio = 1;
     679  
     680      putenv("PYTHONUNBUFFERED=");
     681      Py_UnbufferedStdioFlag = 0;
     682      config.buffered_stdio = 0;
     683  
     684      putenv("PYTHONIOENCODING=cp424");
     685      Py_SetStandardStreamEncoding("ascii", "ignore");
     686  #ifdef MS_WINDOWS
     687      /* Py_SetStandardStreamEncoding() sets Py_LegacyWindowsStdioFlag to 1.
     688         Force it to 0 through the config. */
     689      config.legacy_windows_stdio = 0;
     690  #endif
     691      config_set_string(&config, &config.stdio_encoding, L"iso8859-1");
     692      config_set_string(&config, &config.stdio_errors, L"replace");
     693  
     694      putenv("PYTHONNOUSERSITE=");
     695      Py_NoUserSiteDirectory = 0;
     696      config.user_site_directory = 0;
     697  
     698      config_set_string(&config, &config.check_hash_pycs_mode, L"always");
     699  
     700      Py_FrozenFlag = 0;
     701      config.pathconfig_warnings = 0;
     702  
     703      config.safe_path = 1;
     704  
     705      putenv("PYTHONINTMAXSTRDIGITS=6666");
     706      config.int_max_str_digits = 31337;
     707  
     708      init_from_config_clear(&config);
     709  
     710      dump_config();
     711      Py_Finalize();
     712      return 0;
     713  }
     714  
     715  
     716  static int check_init_parse_argv(int parse_argv)
     717  {
     718      PyConfig config;
     719      PyConfig_InitPythonConfig(&config);
     720  
     721      config.parse_argv = parse_argv;
     722  
     723      wchar_t* argv[] = {
     724          L"./argv0",
     725          L"-E",
     726          L"-c",
     727          L"pass",
     728          L"arg1",
     729          L"-v",
     730          L"arg3",
     731      };
     732      config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
     733      init_from_config_clear(&config);
     734  
     735      dump_config();
     736      Py_Finalize();
     737      return 0;
     738  }
     739  
     740  
     741  static int test_init_parse_argv(void)
     742  {
     743      return check_init_parse_argv(1);
     744  }
     745  
     746  
     747  static int test_init_dont_parse_argv(void)
     748  {
     749      return check_init_parse_argv(0);
     750  }
     751  
     752  
     753  static void set_most_env_vars(void)
     754  {
     755      putenv("PYTHONHASHSEED=42");
     756      putenv("PYTHONMALLOC=malloc");
     757      putenv("PYTHONTRACEMALLOC=2");
     758      putenv("PYTHONPROFILEIMPORTTIME=1");
     759      putenv("PYTHONNODEBUGRANGES=1");
     760      putenv("PYTHONMALLOCSTATS=1");
     761      putenv("PYTHONUTF8=1");
     762      putenv("PYTHONVERBOSE=1");
     763      putenv("PYTHONINSPECT=1");
     764      putenv("PYTHONOPTIMIZE=2");
     765      putenv("PYTHONDONTWRITEBYTECODE=1");
     766      putenv("PYTHONUNBUFFERED=1");
     767      putenv("PYTHONPYCACHEPREFIX=env_pycache_prefix");
     768      putenv("PYTHONNOUSERSITE=1");
     769      putenv("PYTHONFAULTHANDLER=1");
     770      putenv("PYTHONIOENCODING=iso8859-1:replace");
     771      putenv("PYTHONPLATLIBDIR=env_platlibdir");
     772      putenv("PYTHONSAFEPATH=1");
     773      putenv("PYTHONINTMAXSTRDIGITS=4567");
     774  }
     775  
     776  
     777  static void set_all_env_vars(void)
     778  {
     779      set_most_env_vars();
     780  
     781      putenv("PYTHONWARNINGS=EnvVar");
     782      putenv("PYTHONPATH=/my/path");
     783  }
     784  
     785  
     786  static int test_init_compat_env(void)
     787  {
     788      /* Test initialization from environment variables */
     789      Py_IgnoreEnvironmentFlag = 0;
     790      set_all_env_vars();
     791      _testembed_Py_InitializeFromConfig();
     792      dump_config();
     793      Py_Finalize();
     794      return 0;
     795  }
     796  
     797  
     798  static int test_init_python_env(void)
     799  {
     800      set_all_env_vars();
     801  
     802      PyConfig config;
     803      PyConfig_InitPythonConfig(&config);
     804  
     805      config_set_program_name(&config);
     806      init_from_config_clear(&config);
     807  
     808      dump_config();
     809      Py_Finalize();
     810      return 0;
     811  }
     812  
     813  
     814  static void set_all_env_vars_dev_mode(void)
     815  {
     816      putenv("PYTHONMALLOC=");
     817      putenv("PYTHONFAULTHANDLER=");
     818      putenv("PYTHONDEVMODE=1");
     819  }
     820  
     821  
     822  static int test_init_env_dev_mode(void)
     823  {
     824      /* Test initialization from environment variables */
     825      Py_IgnoreEnvironmentFlag = 0;
     826      set_all_env_vars_dev_mode();
     827      _testembed_Py_InitializeFromConfig();
     828      dump_config();
     829      Py_Finalize();
     830      return 0;
     831  }
     832  
     833  
     834  static int test_init_env_dev_mode_alloc(void)
     835  {
     836      /* Test initialization from environment variables */
     837      Py_IgnoreEnvironmentFlag = 0;
     838      set_all_env_vars_dev_mode();
     839      putenv("PYTHONMALLOC=malloc");
     840      _testembed_Py_InitializeFromConfig();
     841      dump_config();
     842      Py_Finalize();
     843      return 0;
     844  }
     845  
     846  
     847  static int test_init_isolated_flag(void)
     848  {
     849      /* Test PyConfig.isolated=1 */
     850      PyConfig config;
     851      PyConfig_InitPythonConfig(&config);
     852  
     853      Py_IsolatedFlag = 0;
     854      config.isolated = 1;
     855      // These options are set to 1 by isolated=1
     856      config.safe_path = 0;
     857      config.use_environment = 1;
     858      config.user_site_directory = 1;
     859  
     860      config_set_program_name(&config);
     861      set_all_env_vars();
     862      init_from_config_clear(&config);
     863  
     864      dump_config();
     865      Py_Finalize();
     866      return 0;
     867  }
     868  
     869  
     870  /* PyPreConfig.isolated=1, PyConfig.isolated=0 */
     871  static int test_preinit_isolated1(void)
     872  {
     873      PyPreConfig preconfig;
     874      _PyPreConfig_InitCompatConfig(&preconfig);
     875  
     876      preconfig.isolated = 1;
     877  
     878      PyStatus status = Py_PreInitialize(&preconfig);
     879      if (PyStatus_Exception(status)) {
     880          Py_ExitStatusException(status);
     881      }
     882  
     883      PyConfig config;
     884      _PyConfig_InitCompatConfig(&config);
     885  
     886      config_set_program_name(&config);
     887      set_all_env_vars();
     888      init_from_config_clear(&config);
     889  
     890      dump_config();
     891      Py_Finalize();
     892      return 0;
     893  }
     894  
     895  
     896  /* PyPreConfig.isolated=0, PyConfig.isolated=1 */
     897  static int test_preinit_isolated2(void)
     898  {
     899      PyPreConfig preconfig;
     900      _PyPreConfig_InitCompatConfig(&preconfig);
     901  
     902      preconfig.isolated = 0;
     903  
     904      PyStatus status = Py_PreInitialize(&preconfig);
     905      if (PyStatus_Exception(status)) {
     906          Py_ExitStatusException(status);
     907      }
     908  
     909      /* Test PyConfig.isolated=1 */
     910      PyConfig config;
     911      _PyConfig_InitCompatConfig(&config);
     912  
     913      Py_IsolatedFlag = 0;
     914      config.isolated = 1;
     915  
     916      config_set_program_name(&config);
     917      set_all_env_vars();
     918      init_from_config_clear(&config);
     919  
     920      dump_config();
     921      Py_Finalize();
     922      return 0;
     923  }
     924  
     925  
     926  static int test_preinit_dont_parse_argv(void)
     927  {
     928      PyPreConfig preconfig;
     929      PyPreConfig_InitIsolatedConfig(&preconfig);
     930  
     931      preconfig.isolated = 0;
     932  
     933      /* -X dev must be ignored by isolated preconfiguration */
     934      wchar_t *argv[] = {L"python3",
     935                         L"-E",
     936                         L"-I",
     937                         L"-P",
     938                         L"-X", L"dev",
     939                         L"-X", L"utf8",
     940                         L"script.py"};
     941      PyStatus status = Py_PreInitializeFromArgs(&preconfig,
     942                                                 Py_ARRAY_LENGTH(argv), argv);
     943      if (PyStatus_Exception(status)) {
     944          Py_ExitStatusException(status);
     945      }
     946  
     947      PyConfig config;
     948      PyConfig_InitIsolatedConfig(&config);
     949  
     950      config.isolated = 0;
     951  
     952      /* Pre-initialize implicitly using argv: make sure that -X dev
     953         is used to configure the allocation in preinitialization */
     954      config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
     955      config_set_program_name(&config);
     956      init_from_config_clear(&config);
     957  
     958      dump_config();
     959      Py_Finalize();
     960      return 0;
     961  }
     962  
     963  
     964  static int test_preinit_parse_argv(void)
     965  {
     966      PyConfig config;
     967      PyConfig_InitPythonConfig(&config);
     968  
     969      /* Pre-initialize implicitly using argv: make sure that -X dev
     970         is used to configure the allocation in preinitialization */
     971      wchar_t *argv[] = {L"python3", L"-X", L"dev", L"-P", L"script.py"};
     972      config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
     973      config_set_program_name(&config);
     974      init_from_config_clear(&config);
     975  
     976      dump_config();
     977      Py_Finalize();
     978      return 0;
     979  }
     980  
     981  
     982  
     983  
     984  static void set_all_global_config_variables(void)
     985  {
     986      Py_IsolatedFlag = 0;
     987      Py_IgnoreEnvironmentFlag = 0;
     988      Py_BytesWarningFlag = 2;
     989      Py_InspectFlag = 1;
     990      Py_InteractiveFlag = 1;
     991      Py_OptimizeFlag = 1;
     992      Py_DebugFlag = 1;
     993      Py_VerboseFlag = 1;
     994      Py_QuietFlag = 1;
     995      Py_FrozenFlag = 0;
     996      Py_UnbufferedStdioFlag = 1;
     997      Py_NoSiteFlag = 1;
     998      Py_DontWriteBytecodeFlag = 1;
     999      Py_NoUserSiteDirectory = 1;
    1000  #ifdef MS_WINDOWS
    1001      Py_LegacyWindowsStdioFlag = 1;
    1002  #endif
    1003  }
    1004  
    1005  
    1006  static int check_preinit_isolated_config(int preinit)
    1007  {
    1008      PyStatus status;
    1009      PyPreConfig *rt_preconfig;
    1010  
    1011      /* environment variables must be ignored */
    1012      set_all_env_vars();
    1013  
    1014      /* global configuration variables must be ignored */
    1015      set_all_global_config_variables();
    1016  
    1017      if (preinit) {
    1018          PyPreConfig preconfig;
    1019          PyPreConfig_InitIsolatedConfig(&preconfig);
    1020  
    1021          status = Py_PreInitialize(&preconfig);
    1022          if (PyStatus_Exception(status)) {
    1023              Py_ExitStatusException(status);
    1024          }
    1025  
    1026          rt_preconfig = &_PyRuntime.preconfig;
    1027          assert(rt_preconfig->isolated == 1);
    1028          assert(rt_preconfig->use_environment == 0);
    1029      }
    1030  
    1031      PyConfig config;
    1032      PyConfig_InitIsolatedConfig(&config);
    1033  
    1034      config_set_program_name(&config);
    1035      init_from_config_clear(&config);
    1036  
    1037      rt_preconfig = &_PyRuntime.preconfig;
    1038      assert(rt_preconfig->isolated == 1);
    1039      assert(rt_preconfig->use_environment == 0);
    1040  
    1041      dump_config();
    1042      Py_Finalize();
    1043      return 0;
    1044  }
    1045  
    1046  
    1047  static int test_preinit_isolated_config(void)
    1048  {
    1049      return check_preinit_isolated_config(1);
    1050  }
    1051  
    1052  
    1053  static int test_init_isolated_config(void)
    1054  {
    1055      return check_preinit_isolated_config(0);
    1056  }
    1057  
    1058  
    1059  static int check_init_python_config(int preinit)
    1060  {
    1061      /* global configuration variables must be ignored */
    1062      set_all_global_config_variables();
    1063      Py_IsolatedFlag = 1;
    1064      Py_IgnoreEnvironmentFlag = 1;
    1065      Py_FrozenFlag = 1;
    1066      Py_UnbufferedStdioFlag = 1;
    1067      Py_NoSiteFlag = 1;
    1068      Py_DontWriteBytecodeFlag = 1;
    1069      Py_NoUserSiteDirectory = 1;
    1070  #ifdef MS_WINDOWS
    1071      Py_LegacyWindowsStdioFlag = 1;
    1072  #endif
    1073  
    1074      if (preinit) {
    1075          PyPreConfig preconfig;
    1076          PyPreConfig_InitPythonConfig(&preconfig);
    1077  
    1078          PyStatus status = Py_PreInitialize(&preconfig);
    1079          if (PyStatus_Exception(status)) {
    1080              Py_ExitStatusException(status);
    1081          }
    1082      }
    1083  
    1084      PyConfig config;
    1085      PyConfig_InitPythonConfig(&config);
    1086  
    1087      config_set_program_name(&config);
    1088      init_from_config_clear(&config);
    1089  
    1090      dump_config();
    1091      Py_Finalize();
    1092      return 0;
    1093  }
    1094  
    1095  
    1096  static int test_preinit_python_config(void)
    1097  {
    1098      return check_init_python_config(1);
    1099  }
    1100  
    1101  
    1102  static int test_init_python_config(void)
    1103  {
    1104      return check_init_python_config(0);
    1105  }
    1106  
    1107  
    1108  static int test_init_dont_configure_locale(void)
    1109  {
    1110      PyPreConfig preconfig;
    1111      PyPreConfig_InitPythonConfig(&preconfig);
    1112  
    1113      preconfig.configure_locale = 0;
    1114      preconfig.coerce_c_locale = 1;
    1115      preconfig.coerce_c_locale_warn = 1;
    1116  
    1117      PyStatus status = Py_PreInitialize(&preconfig);
    1118      if (PyStatus_Exception(status)) {
    1119          Py_ExitStatusException(status);
    1120      }
    1121  
    1122      PyConfig config;
    1123      PyConfig_InitPythonConfig(&config);
    1124  
    1125      config_set_program_name(&config);
    1126      init_from_config_clear(&config);
    1127  
    1128      dump_config();
    1129      Py_Finalize();
    1130      return 0;
    1131  }
    1132  
    1133  
    1134  static int test_init_dev_mode(void)
    1135  {
    1136      PyConfig config;
    1137      PyConfig_InitPythonConfig(&config);
    1138  
    1139      putenv("PYTHONFAULTHANDLER=");
    1140      putenv("PYTHONMALLOC=");
    1141      config.dev_mode = 1;
    1142      config_set_program_name(&config);
    1143      init_from_config_clear(&config);
    1144  
    1145      dump_config();
    1146      Py_Finalize();
    1147      return 0;
    1148  }
    1149  
    1150  static PyObject *_open_code_hook(PyObject *path, void *data)
    1151  {
    1152      if (PyUnicode_CompareWithASCIIString(path, "$$test-filename") == 0) {
    1153          return PyLong_FromVoidPtr(data);
    1154      }
    1155      PyObject *io = PyImport_ImportModule("_io");
    1156      if (!io) {
    1157          return NULL;
    1158      }
    1159      return PyObject_CallMethod(io, "open", "Os", path, "rb");
    1160  }
    1161  
    1162  static int test_open_code_hook(void)
    1163  {
    1164      int result = 0;
    1165  
    1166      /* Provide a hook */
    1167      result = PyFile_SetOpenCodeHook(_open_code_hook, &result);
    1168      if (result) {
    1169          printf("Failed to set hook\n");
    1170          return 1;
    1171      }
    1172      /* A second hook should fail */
    1173      result = PyFile_SetOpenCodeHook(_open_code_hook, &result);
    1174      if (!result) {
    1175          printf("Should have failed to set second hook\n");
    1176          return 2;
    1177      }
    1178  
    1179      Py_IgnoreEnvironmentFlag = 0;
    1180      _testembed_Py_InitializeFromConfig();
    1181      result = 0;
    1182  
    1183      PyObject *r = PyFile_OpenCode("$$test-filename");
    1184      if (!r) {
    1185          PyErr_Print();
    1186          result = 3;
    1187      } else {
    1188          void *cmp = PyLong_AsVoidPtr(r);
    1189          Py_DECREF(r);
    1190          if (cmp != &result) {
    1191              printf("Did not get expected result from hook\n");
    1192              result = 4;
    1193          }
    1194      }
    1195  
    1196      if (!result) {
    1197          PyObject *io = PyImport_ImportModule("_io");
    1198          PyObject *r = io
    1199              ? PyObject_CallMethod(io, "open_code", "s", "$$test-filename")
    1200              : NULL;
    1201          if (!r) {
    1202              PyErr_Print();
    1203              result = 5;
    1204          } else {
    1205              void *cmp = PyLong_AsVoidPtr(r);
    1206              Py_DECREF(r);
    1207              if (cmp != &result) {
    1208                  printf("Did not get expected result from hook\n");
    1209                  result = 6;
    1210              }
    1211          }
    1212          Py_XDECREF(io);
    1213      }
    1214  
    1215      Py_Finalize();
    1216      return result;
    1217  }
    1218  
    1219  static int _audit_hook_clear_count = 0;
    1220  
    1221  static int _audit_hook(const char *event, PyObject *args, void *userdata)
    1222  {
    1223      assert(args && PyTuple_CheckExact(args));
    1224      if (strcmp(event, "_testembed.raise") == 0) {
    1225          PyErr_SetString(PyExc_RuntimeError, "Intentional error");
    1226          return -1;
    1227      } else if (strcmp(event, "_testembed.set") == 0) {
    1228          if (!PyArg_ParseTuple(args, "n", userdata)) {
    1229              return -1;
    1230          }
    1231          return 0;
    1232      } else if (strcmp(event, "cpython._PySys_ClearAuditHooks") == 0) {
    1233          _audit_hook_clear_count += 1;
    1234      }
    1235      return 0;
    1236  }
    1237  
    1238  static int _test_audit(Py_ssize_t setValue)
    1239  {
    1240      Py_ssize_t sawSet = 0;
    1241  
    1242      Py_IgnoreEnvironmentFlag = 0;
    1243      PySys_AddAuditHook(_audit_hook, &sawSet);
    1244      _testembed_Py_InitializeFromConfig();
    1245  
    1246      if (PySys_Audit("_testembed.raise", NULL) == 0) {
    1247          printf("No error raised");
    1248          return 1;
    1249      }
    1250      if (PySys_Audit("_testembed.nop", NULL) != 0) {
    1251          printf("Nop event failed");
    1252          /* Exception from above may still remain */
    1253          PyErr_Clear();
    1254          return 2;
    1255      }
    1256      if (!PyErr_Occurred()) {
    1257          printf("Exception not preserved");
    1258          return 3;
    1259      }
    1260      PyErr_Clear();
    1261  
    1262      if (PySys_Audit("_testembed.set", "n", setValue) != 0) {
    1263          PyErr_Print();
    1264          printf("Set event failed");
    1265          return 4;
    1266      }
    1267  
    1268      if (sawSet != 42) {
    1269          printf("Failed to see *userData change\n");
    1270          return 5;
    1271      }
    1272      return 0;
    1273  }
    1274  
    1275  static int test_audit(void)
    1276  {
    1277      int result = _test_audit(42);
    1278      Py_Finalize();
    1279      if (_audit_hook_clear_count != 1) {
    1280          return 0x1000 | _audit_hook_clear_count;
    1281      }
    1282      return result;
    1283  }
    1284  
    1285  static volatile int _audit_subinterpreter_interpreter_count = 0;
    1286  
    1287  static int _audit_subinterpreter_hook(const char *event, PyObject *args, void *userdata)
    1288  {
    1289      printf("%s\n", event);
    1290      if (strcmp(event, "cpython.PyInterpreterState_New") == 0) {
    1291          _audit_subinterpreter_interpreter_count += 1;
    1292      }
    1293      return 0;
    1294  }
    1295  
    1296  static int test_audit_subinterpreter(void)
    1297  {
    1298      Py_IgnoreEnvironmentFlag = 0;
    1299      PySys_AddAuditHook(_audit_subinterpreter_hook, NULL);
    1300      _testembed_Py_InitializeFromConfig();
    1301  
    1302      Py_NewInterpreter();
    1303      Py_NewInterpreter();
    1304      Py_NewInterpreter();
    1305  
    1306      Py_Finalize();
    1307  
    1308      switch (_audit_subinterpreter_interpreter_count) {
    1309          case 3: return 0;
    1310          case 0: return -1;
    1311          default: return _audit_subinterpreter_interpreter_count;
    1312      }
    1313  }
    1314  
    1315  typedef struct {
    1316      const char* expected;
    1317      int exit;
    1318  } AuditRunCommandTest;
    1319  
    1320  static int _audit_hook_run(const char *eventName, PyObject *args, void *userData)
    1321  {
    1322      AuditRunCommandTest *test = (AuditRunCommandTest*)userData;
    1323      if (strcmp(eventName, test->expected)) {
    1324          return 0;
    1325      }
    1326  
    1327      if (test->exit) {
    1328          PyObject *msg = PyUnicode_FromFormat("detected %s(%R)", eventName, args);
    1329          if (msg) {
    1330              printf("%s\n", PyUnicode_AsUTF8(msg));
    1331              Py_DECREF(msg);
    1332          }
    1333          exit(test->exit);
    1334      }
    1335  
    1336      PyErr_Format(PyExc_RuntimeError, "detected %s(%R)", eventName, args);
    1337      return -1;
    1338  }
    1339  
    1340  static int test_audit_run_command(void)
    1341  {
    1342      AuditRunCommandTest test = {"cpython.run_command"};
    1343      wchar_t *argv[] = {PROGRAM_NAME, L"-c", L"pass"};
    1344  
    1345      Py_IgnoreEnvironmentFlag = 0;
    1346      PySys_AddAuditHook(_audit_hook_run, (void*)&test);
    1347  
    1348      return Py_Main(Py_ARRAY_LENGTH(argv), argv);
    1349  }
    1350  
    1351  static int test_audit_run_file(void)
    1352  {
    1353      AuditRunCommandTest test = {"cpython.run_file"};
    1354      wchar_t *argv[] = {PROGRAM_NAME, L"filename.py"};
    1355  
    1356      Py_IgnoreEnvironmentFlag = 0;
    1357      PySys_AddAuditHook(_audit_hook_run, (void*)&test);
    1358  
    1359      return Py_Main(Py_ARRAY_LENGTH(argv), argv);
    1360  }
    1361  
    1362  static int run_audit_run_test(int argc, wchar_t **argv, void *test)
    1363  {
    1364      PyConfig config;
    1365      PyConfig_InitPythonConfig(&config);
    1366  
    1367      config.argv.length = argc;
    1368      config.argv.items = argv;
    1369      config.parse_argv = 1;
    1370      config.program_name = argv[0];
    1371      config.interactive = 1;
    1372      config.isolated = 0;
    1373      config.use_environment = 1;
    1374      config.quiet = 1;
    1375  
    1376      PySys_AddAuditHook(_audit_hook_run, test);
    1377  
    1378      PyStatus status = Py_InitializeFromConfig(&config);
    1379      if (PyStatus_Exception(status)) {
    1380          Py_ExitStatusException(status);
    1381      }
    1382  
    1383      return Py_RunMain();
    1384  }
    1385  
    1386  static int test_audit_run_interactivehook(void)
    1387  {
    1388      AuditRunCommandTest test = {"cpython.run_interactivehook", 10};
    1389      wchar_t *argv[] = {PROGRAM_NAME};
    1390      return run_audit_run_test(Py_ARRAY_LENGTH(argv), argv, &test);
    1391  }
    1392  
    1393  static int test_audit_run_startup(void)
    1394  {
    1395      AuditRunCommandTest test = {"cpython.run_startup", 10};
    1396      wchar_t *argv[] = {PROGRAM_NAME};
    1397      return run_audit_run_test(Py_ARRAY_LENGTH(argv), argv, &test);
    1398  }
    1399  
    1400  static int test_audit_run_stdin(void)
    1401  {
    1402      AuditRunCommandTest test = {"cpython.run_stdin"};
    1403      wchar_t *argv[] = {PROGRAM_NAME};
    1404      return run_audit_run_test(Py_ARRAY_LENGTH(argv), argv, &test);
    1405  }
    1406  
    1407  static int test_init_read_set(void)
    1408  {
    1409      PyStatus status;
    1410      PyConfig config;
    1411      PyConfig_InitPythonConfig(&config);
    1412  
    1413      status = PyConfig_SetBytesString(&config, &config.program_name,
    1414                                       "./init_read_set");
    1415      if (PyStatus_Exception(status)) {
    1416          goto fail;
    1417      }
    1418  
    1419      status = PyConfig_Read(&config);
    1420      if (PyStatus_Exception(status)) {
    1421          goto fail;
    1422      }
    1423  
    1424      status = PyWideStringList_Insert(&config.module_search_paths,
    1425                                       1, L"test_path_insert1");
    1426      if (PyStatus_Exception(status)) {
    1427          goto fail;
    1428      }
    1429  
    1430      status = PyWideStringList_Append(&config.module_search_paths,
    1431                                       L"test_path_append");
    1432      if (PyStatus_Exception(status)) {
    1433          goto fail;
    1434      }
    1435  
    1436      /* override executable computed by PyConfig_Read() */
    1437      config_set_string(&config, &config.executable, L"my_executable");
    1438      init_from_config_clear(&config);
    1439  
    1440      dump_config();
    1441      Py_Finalize();
    1442      return 0;
    1443  
    1444  fail:
    1445      PyConfig_Clear(&config);
    1446      Py_ExitStatusException(status);
    1447  }
    1448  
    1449  
    1450  static int test_init_sys_add(void)
    1451  {
    1452      PySys_AddXOption(L"sysadd_xoption");
    1453      PySys_AddXOption(L"faulthandler");
    1454      PySys_AddWarnOption(L"ignore:::sysadd_warnoption");
    1455  
    1456      PyConfig config;
    1457      PyConfig_InitPythonConfig(&config);
    1458  
    1459      wchar_t* argv[] = {
    1460          L"python3",
    1461          L"-W",
    1462          L"ignore:::cmdline_warnoption",
    1463          L"-X",
    1464          L"cmdline_xoption",
    1465      };
    1466      config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
    1467      config.parse_argv = 1;
    1468  
    1469      PyStatus status;
    1470      status = PyWideStringList_Append(&config.xoptions,
    1471                                       L"config_xoption");
    1472      if (PyStatus_Exception(status)) {
    1473          goto fail;
    1474      }
    1475  
    1476      status = PyWideStringList_Append(&config.warnoptions,
    1477                                       L"ignore:::config_warnoption");
    1478      if (PyStatus_Exception(status)) {
    1479          goto fail;
    1480      }
    1481  
    1482      config_set_program_name(&config);
    1483      init_from_config_clear(&config);
    1484  
    1485      dump_config();
    1486      Py_Finalize();
    1487      return 0;
    1488  
    1489  fail:
    1490      PyConfig_Clear(&config);
    1491      Py_ExitStatusException(status);
    1492  }
    1493  
    1494  
    1495  static int test_init_setpath(void)
    1496  {
    1497      char *env = getenv("TESTPATH");
    1498      if (!env) {
    1499          error("missing TESTPATH env var");
    1500          return 1;
    1501      }
    1502      wchar_t *path = Py_DecodeLocale(env, NULL);
    1503      if (path == NULL) {
    1504          error("failed to decode TESTPATH");
    1505          return 1;
    1506      }
    1507      Py_SetPath(path);
    1508      PyMem_RawFree(path);
    1509      putenv("TESTPATH=");
    1510  
    1511      Py_Initialize();
    1512      dump_config();
    1513      Py_Finalize();
    1514      return 0;
    1515  }
    1516  
    1517  
    1518  static int test_init_setpath_config(void)
    1519  {
    1520      PyPreConfig preconfig;
    1521      PyPreConfig_InitPythonConfig(&preconfig);
    1522  
    1523      /* Explicitly preinitializes with Python preconfiguration to avoid
    1524        Py_SetPath() implicit preinitialization with compat preconfiguration. */
    1525      PyStatus status = Py_PreInitialize(&preconfig);
    1526      if (PyStatus_Exception(status)) {
    1527          Py_ExitStatusException(status);
    1528      }
    1529  
    1530      char *env = getenv("TESTPATH");
    1531      if (!env) {
    1532          error("missing TESTPATH env var");
    1533          return 1;
    1534      }
    1535      wchar_t *path = Py_DecodeLocale(env, NULL);
    1536      if (path == NULL) {
    1537          error("failed to decode TESTPATH");
    1538          return 1;
    1539      }
    1540      Py_SetPath(path);
    1541      PyMem_RawFree(path);
    1542      putenv("TESTPATH=");
    1543  
    1544      PyConfig config;
    1545      PyConfig_InitPythonConfig(&config);
    1546  
    1547      config_set_string(&config, &config.program_name, L"conf_program_name");
    1548      config_set_string(&config, &config.executable, L"conf_executable");
    1549      init_from_config_clear(&config);
    1550  
    1551      dump_config();
    1552      Py_Finalize();
    1553      return 0;
    1554  }
    1555  
    1556  
    1557  static int test_init_setpythonhome(void)
    1558  {
    1559      char *env = getenv("TESTHOME");
    1560      if (!env) {
    1561          error("missing TESTHOME env var");
    1562          return 1;
    1563      }
    1564      wchar_t *home = Py_DecodeLocale(env, NULL);
    1565      if (home == NULL) {
    1566          error("failed to decode TESTHOME");
    1567          return 1;
    1568      }
    1569      Py_SetPythonHome(home);
    1570      PyMem_RawFree(home);
    1571      putenv("TESTHOME=");
    1572  
    1573      Py_Initialize();
    1574      dump_config();
    1575      Py_Finalize();
    1576      return 0;
    1577  }
    1578  
    1579  
    1580  static int test_init_is_python_build(void)
    1581  {
    1582      // gh-91985: in-tree builds fail to check for build directory landmarks
    1583      // under the effect of 'home' or PYTHONHOME environment variable.
    1584      char *env = getenv("TESTHOME");
    1585      if (!env) {
    1586          error("missing TESTHOME env var");
    1587          return 1;
    1588      }
    1589      wchar_t *home = Py_DecodeLocale(env, NULL);
    1590      if (home == NULL) {
    1591          error("failed to decode TESTHOME");
    1592          return 1;
    1593      }
    1594  
    1595      PyConfig config;
    1596      _PyConfig_InitCompatConfig(&config);
    1597      config_set_program_name(&config);
    1598      config_set_string(&config, &config.home, home);
    1599      PyMem_RawFree(home);
    1600      putenv("TESTHOME=");
    1601  
    1602      // Use an impossible value so we can detect whether it isn't updated
    1603      // during initialization.
    1604      config._is_python_build = INT_MAX;
    1605      env = getenv("NEGATIVE_ISPYTHONBUILD");
    1606      if (env && strcmp(env, "0") != 0) {
    1607          config._is_python_build = INT_MIN;
    1608      }
    1609      init_from_config_clear(&config);
    1610      Py_Finalize();
    1611      // Second initialization
    1612      config._is_python_build = -1;
    1613      init_from_config_clear(&config);
    1614      dump_config();  // home and _is_python_build are cached in _Py_path_config
    1615      Py_Finalize();
    1616      return 0;
    1617  }
    1618  
    1619  
    1620  static int test_init_warnoptions(void)
    1621  {
    1622      putenv("PYTHONWARNINGS=ignore:::env1,ignore:::env2");
    1623  
    1624      PySys_AddWarnOption(L"ignore:::PySys_AddWarnOption1");
    1625      PySys_AddWarnOption(L"ignore:::PySys_AddWarnOption2");
    1626  
    1627      PyConfig config;
    1628      PyConfig_InitPythonConfig(&config);
    1629  
    1630      config.dev_mode = 1;
    1631      config.bytes_warning = 1;
    1632  
    1633      config_set_program_name(&config);
    1634  
    1635      PyStatus status;
    1636      status = PyWideStringList_Append(&config.warnoptions,
    1637                                       L"ignore:::PyConfig_BeforeRead");
    1638      if (PyStatus_Exception(status)) {
    1639          Py_ExitStatusException(status);
    1640      }
    1641  
    1642      wchar_t* argv[] = {
    1643          L"python3",
    1644          L"-Wignore:::cmdline1",
    1645          L"-Wignore:::cmdline2"};
    1646      config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
    1647      config.parse_argv = 1;
    1648  
    1649      status = PyConfig_Read(&config);
    1650      if (PyStatus_Exception(status)) {
    1651          Py_ExitStatusException(status);
    1652      }
    1653  
    1654      status = PyWideStringList_Append(&config.warnoptions,
    1655                                       L"ignore:::PyConfig_AfterRead");
    1656      if (PyStatus_Exception(status)) {
    1657          Py_ExitStatusException(status);
    1658      }
    1659  
    1660      status = PyWideStringList_Insert(&config.warnoptions,
    1661                                       0, L"ignore:::PyConfig_Insert0");
    1662      if (PyStatus_Exception(status)) {
    1663          Py_ExitStatusException(status);
    1664      }
    1665  
    1666      init_from_config_clear(&config);
    1667      dump_config();
    1668      Py_Finalize();
    1669      return 0;
    1670  }
    1671  
    1672  
    1673  static int tune_config(void)
    1674  {
    1675      PyConfig config;
    1676      PyConfig_InitPythonConfig(&config);
    1677      if (_PyInterpreterState_GetConfigCopy(&config) < 0) {
    1678          PyConfig_Clear(&config);
    1679          PyErr_Print();
    1680          return -1;
    1681      }
    1682  
    1683      config.bytes_warning = 2;
    1684  
    1685      if (_PyInterpreterState_SetConfig(&config) < 0) {
    1686          PyConfig_Clear(&config);
    1687          return -1;
    1688      }
    1689      PyConfig_Clear(&config);
    1690      return 0;
    1691  }
    1692  
    1693  
    1694  static int test_init_set_config(void)
    1695  {
    1696      // Initialize core
    1697      PyConfig config;
    1698      PyConfig_InitIsolatedConfig(&config);
    1699      config_set_string(&config, &config.program_name, PROGRAM_NAME);
    1700      config._init_main = 0;
    1701      config.bytes_warning = 0;
    1702      init_from_config_clear(&config);
    1703  
    1704      // Tune the configuration using _PyInterpreterState_SetConfig()
    1705      if (tune_config() < 0) {
    1706          PyErr_Print();
    1707          return 1;
    1708      }
    1709  
    1710      // Finish initialization: main part
    1711      PyStatus status = _Py_InitializeMain();
    1712      if (PyStatus_Exception(status)) {
    1713          Py_ExitStatusException(status);
    1714      }
    1715  
    1716      dump_config();
    1717      Py_Finalize();
    1718      return 0;
    1719  }
    1720  
    1721  
    1722  static void configure_init_main(PyConfig *config)
    1723  {
    1724      wchar_t* argv[] = {
    1725          L"python3", L"-c",
    1726          (L"import _testinternalcapi, json; "
    1727           L"print(json.dumps(_testinternalcapi.get_configs()))"),
    1728          L"arg2"};
    1729  
    1730      config->parse_argv = 1;
    1731  
    1732      config_set_argv(config, Py_ARRAY_LENGTH(argv), argv);
    1733      config_set_string(config, &config->program_name, L"./python3");
    1734  }
    1735  
    1736  
    1737  static int test_init_run_main(void)
    1738  {
    1739      PyConfig config;
    1740      PyConfig_InitPythonConfig(&config);
    1741  
    1742      configure_init_main(&config);
    1743      init_from_config_clear(&config);
    1744  
    1745      return Py_RunMain();
    1746  }
    1747  
    1748  
    1749  static int test_init_main(void)
    1750  {
    1751      PyConfig config;
    1752      PyConfig_InitPythonConfig(&config);
    1753  
    1754      configure_init_main(&config);
    1755      config._init_main = 0;
    1756      init_from_config_clear(&config);
    1757  
    1758      /* sys.stdout don't exist yet: it is created by _Py_InitializeMain() */
    1759      int res = PyRun_SimpleString(
    1760          "import sys; "
    1761          "print('Run Python code before _Py_InitializeMain', "
    1762                 "file=sys.stderr)");
    1763      if (res < 0) {
    1764          exit(1);
    1765      }
    1766  
    1767      PyStatus status = _Py_InitializeMain();
    1768      if (PyStatus_Exception(status)) {
    1769          Py_ExitStatusException(status);
    1770      }
    1771  
    1772      return Py_RunMain();
    1773  }
    1774  
    1775  
    1776  static int test_run_main(void)
    1777  {
    1778      PyConfig config;
    1779      PyConfig_InitPythonConfig(&config);
    1780  
    1781      wchar_t *argv[] = {L"python3", L"-c",
    1782                         (L"import sys; "
    1783                          L"print(f'Py_RunMain(): sys.argv={sys.argv}')"),
    1784                         L"arg2"};
    1785      config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
    1786      config_set_string(&config, &config.program_name, L"./python3");
    1787      init_from_config_clear(&config);
    1788  
    1789      return Py_RunMain();
    1790  }
    1791  
    1792  
    1793  static int test_run_main_loop(void)
    1794  {
    1795      // bpo-40413: Calling Py_InitializeFromConfig()+Py_RunMain() multiple
    1796      // times must not crash.
    1797      for (int i=0; i<5; i++) {
    1798          int exitcode = test_run_main();
    1799          if (exitcode != 0) {
    1800              return exitcode;
    1801          }
    1802      }
    1803      return 0;
    1804  }
    1805  
    1806  
    1807  static int test_get_argc_argv(void)
    1808  {
    1809      PyConfig config;
    1810      PyConfig_InitPythonConfig(&config);
    1811  
    1812      wchar_t *argv[] = {L"python3", L"-c", L"pass", L"arg2"};
    1813      config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
    1814      config_set_string(&config, &config.program_name, L"./python3");
    1815  
    1816      // Calling PyConfig_Read() twice must not change Py_GetArgcArgv() result.
    1817      // The second call is done by Py_InitializeFromConfig().
    1818      PyStatus status = PyConfig_Read(&config);
    1819      if (PyStatus_Exception(status)) {
    1820          PyConfig_Clear(&config);
    1821          Py_ExitStatusException(status);
    1822      }
    1823  
    1824      init_from_config_clear(&config);
    1825  
    1826      int get_argc;
    1827      wchar_t **get_argv;
    1828      Py_GetArgcArgv(&get_argc, &get_argv);
    1829      printf("argc: %i\n", get_argc);
    1830      assert(get_argc == Py_ARRAY_LENGTH(argv));
    1831      for (int i=0; i < get_argc; i++) {
    1832          printf("argv[%i]: %ls\n", i, get_argv[i]);
    1833          assert(wcscmp(get_argv[i], argv[i]) == 0);
    1834      }
    1835  
    1836      Py_Finalize();
    1837  
    1838      printf("\n");
    1839      printf("test ok\n");
    1840      return 0;
    1841  }
    1842  
    1843  
    1844  static int check_use_frozen_modules(const char *rawval)
    1845  {
    1846      wchar_t optval[100];
    1847      if (rawval == NULL) {
    1848          wcscpy(optval, L"frozen_modules");
    1849      }
    1850      else if (swprintf(optval, 100,
    1851  #if defined(_MSC_VER)
    1852          L"frozen_modules=%S",
    1853  #else
    1854          L"frozen_modules=%s",
    1855  #endif
    1856          rawval) < 0) {
    1857          error("rawval is too long");
    1858          return -1;
    1859      }
    1860  
    1861      PyConfig config;
    1862      PyConfig_InitPythonConfig(&config);
    1863  
    1864      config.parse_argv = 1;
    1865  
    1866      wchar_t* argv[] = {
    1867          L"./argv0",
    1868          L"-X",
    1869          optval,
    1870          L"-c",
    1871          L"pass",
    1872      };
    1873      config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
    1874      init_from_config_clear(&config);
    1875  
    1876      dump_config();
    1877      Py_Finalize();
    1878      return 0;
    1879  }
    1880  
    1881  static int test_init_use_frozen_modules(void)
    1882  {
    1883      const char *envvar = getenv("TESTFROZEN");
    1884      return check_use_frozen_modules(envvar);
    1885  }
    1886  
    1887  
    1888  static int test_unicode_id_init(void)
    1889  {
    1890      // bpo-42882: Test that _PyUnicode_FromId() works
    1891      // when Python is initialized multiples times.
    1892  
    1893      // This is equivalent to `_Py_IDENTIFIER(test_unicode_id_init)`
    1894      // but since `_Py_IDENTIFIER` is disabled when `Py_BUILD_CORE`
    1895      // is defined, it is manually expanded here.
    1896      static _Py_Identifier PyId_test_unicode_id_init = {
    1897          .string = "test_unicode_id_init",
    1898          .index = -1,
    1899      };
    1900  
    1901      // Initialize Python once without using the identifier
    1902      _testembed_Py_InitializeFromConfig();
    1903      Py_Finalize();
    1904  
    1905      // Now initialize Python multiple times and use the identifier.
    1906      // The first _PyUnicode_FromId() call initializes the identifier index.
    1907      for (int i=0; i<3; i++) {
    1908          _testembed_Py_InitializeFromConfig();
    1909  
    1910          PyObject *str1, *str2;
    1911  
    1912          str1 = _PyUnicode_FromId(&PyId_test_unicode_id_init);
    1913          assert(str1 != NULL);
    1914          assert(_Py_IsImmortal(str1));
    1915  
    1916          str2 = PyUnicode_FromString("test_unicode_id_init");
    1917          assert(str2 != NULL);
    1918  
    1919          assert(PyUnicode_Compare(str1, str2) == 0);
    1920  
    1921          Py_DECREF(str2);
    1922  
    1923          Py_Finalize();
    1924      }
    1925      return 0;
    1926  }
    1927  
    1928  
    1929  static int test_init_main_interpreter_settings(void)
    1930  {
    1931      _testembed_Py_Initialize();
    1932      (void) PyRun_SimpleStringFlags(
    1933          "import _testinternalcapi, json; "
    1934          "print(json.dumps(_testinternalcapi.get_interp_settings(0)))",
    1935          0);
    1936      Py_Finalize();
    1937      return 0;
    1938  }
    1939  
    1940  
    1941  #ifndef MS_WINDOWS
    1942  #include "test_frozenmain.h"      // M_test_frozenmain
    1943  
    1944  static int test_frozenmain(void)
    1945  {
    1946      static struct _frozen frozen_modules[4] = {
    1947          {"__main__", M_test_frozenmain, sizeof(M_test_frozenmain)},
    1948          {0, 0, 0}   // sentinel
    1949      };
    1950  
    1951      char* argv[] = {
    1952          "./argv0",
    1953          "-E",
    1954          "arg1",
    1955          "arg2",
    1956      };
    1957      PyImport_FrozenModules = frozen_modules;
    1958      return Py_FrozenMain(Py_ARRAY_LENGTH(argv), argv);
    1959  }
    1960  #endif  // !MS_WINDOWS
    1961  
    1962  static int test_repeated_init_and_inittab(void)
    1963  {
    1964      // bpo-44441: Py_RunMain() must reset PyImport_Inittab at exit.
    1965      // It must be possible to call PyImport_AppendInittab() or
    1966      // PyImport_ExtendInittab() before each Python initialization.
    1967      for (int i=1; i <= INIT_LOOPS; i++) {
    1968          printf("--- Pass %d ---\n", i);
    1969  
    1970          // Call PyImport_AppendInittab() at each iteration
    1971          if (PyImport_AppendInittab(EMBEDDED_EXT_NAME,
    1972                                     &PyInit_embedded_ext) != 0) {
    1973              fprintf(stderr, "PyImport_AppendInittab() failed\n");
    1974              return 1;
    1975          }
    1976  
    1977          // Initialize Python
    1978          wchar_t* argv[] = {PROGRAM_NAME, L"-c", L"pass"};
    1979          PyConfig config;
    1980          PyConfig_InitPythonConfig(&config);
    1981          config.isolated = 1;
    1982          config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
    1983          init_from_config_clear(&config);
    1984  
    1985          // Py_RunMain() calls _PyImport_Fini2() which resets PyImport_Inittab
    1986          int exitcode = Py_RunMain();
    1987          if (exitcode != 0) {
    1988              return exitcode;
    1989          }
    1990      }
    1991      return 0;
    1992  }
    1993  
    1994  static void wrap_allocator(PyMemAllocatorEx *allocator);
    1995  static void unwrap_allocator(PyMemAllocatorEx *allocator);
    1996  
    1997  static void *
    1998  malloc_wrapper(void *ctx, size_t size)
    1999  {
    2000      PyMemAllocatorEx *allocator = (PyMemAllocatorEx *)ctx;
    2001      unwrap_allocator(allocator);
    2002      PyEval_GetFrame();  // BOOM!
    2003      wrap_allocator(allocator);
    2004      return allocator->malloc(allocator->ctx, size);
    2005  }
    2006  
    2007  static void *
    2008  calloc_wrapper(void *ctx, size_t nelem, size_t elsize)
    2009  {
    2010      PyMemAllocatorEx *allocator = (PyMemAllocatorEx *)ctx;
    2011      return allocator->calloc(allocator->ctx, nelem, elsize);
    2012  }
    2013  
    2014  static void *
    2015  realloc_wrapper(void *ctx, void *ptr, size_t new_size)
    2016  {
    2017      PyMemAllocatorEx *allocator = (PyMemAllocatorEx *)ctx;
    2018      return allocator->realloc(allocator->ctx, ptr, new_size);
    2019  }
    2020  
    2021  static void
    2022  free_wrapper(void *ctx, void *ptr)
    2023  {
    2024      PyMemAllocatorEx *allocator = (PyMemAllocatorEx *)ctx;
    2025      allocator->free(allocator->ctx, ptr);
    2026  }
    2027  
    2028  static void
    2029  wrap_allocator(PyMemAllocatorEx *allocator)
    2030  {
    2031      PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, allocator);
    2032      PyMemAllocatorEx wrapper = {
    2033          .malloc = &malloc_wrapper,
    2034          .calloc = &calloc_wrapper,
    2035          .realloc = &realloc_wrapper,
    2036          .free = &free_wrapper,
    2037          .ctx = allocator,
    2038      };
    2039      PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &wrapper);
    2040  }
    2041  
    2042  static void
    2043  unwrap_allocator(PyMemAllocatorEx *allocator)
    2044  {
    2045      PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, allocator);
    2046  }
    2047  
    2048  static int
    2049  test_get_incomplete_frame(void)
    2050  {
    2051      _testembed_Py_InitializeFromConfig();
    2052      PyMemAllocatorEx allocator;
    2053      wrap_allocator(&allocator);
    2054      // Force an allocation with an incomplete (generator) frame:
    2055      int result = PyRun_SimpleString("(_ for _ in ())");
    2056      unwrap_allocator(&allocator);
    2057      Py_Finalize();
    2058      return result;
    2059  }
    2060  
    2061  
    2062  /* *********************************************************
    2063   * List of test cases and the function that implements it.
    2064   *
    2065   * Names are compared case-sensitively with the first
    2066   * argument. If no match is found, or no first argument was
    2067   * provided, the names of all test cases are printed and
    2068   * the exit code will be -1.
    2069   *
    2070   * The int returned from test functions is used as the exit
    2071   * code, and test_capi treats all non-zero exit codes as a
    2072   * failed test.
    2073   *********************************************************/
    2074  struct TestCase
    2075  {
    2076      const char *name;
    2077      int (*func)(void);
    2078  };
    2079  
    2080  static struct TestCase TestCases[] = {
    2081      // Python initialization
    2082      {"test_repeated_init_exec", test_repeated_init_exec},
    2083      {"test_repeated_simple_init", test_repeated_simple_init},
    2084      {"test_forced_io_encoding", test_forced_io_encoding},
    2085      {"test_repeated_init_and_subinterpreters", test_repeated_init_and_subinterpreters},
    2086      {"test_repeated_init_and_inittab", test_repeated_init_and_inittab},
    2087      {"test_pre_initialization_api", test_pre_initialization_api},
    2088      {"test_pre_initialization_sys_options", test_pre_initialization_sys_options},
    2089      {"test_bpo20891", test_bpo20891},
    2090      {"test_initialize_twice", test_initialize_twice},
    2091      {"test_initialize_pymain", test_initialize_pymain},
    2092      {"test_init_initialize_config", test_init_initialize_config},
    2093      {"test_preinit_compat_config", test_preinit_compat_config},
    2094      {"test_init_compat_config", test_init_compat_config},
    2095      {"test_init_global_config", test_init_global_config},
    2096      {"test_init_from_config", test_init_from_config},
    2097      {"test_init_parse_argv", test_init_parse_argv},
    2098      {"test_init_dont_parse_argv", test_init_dont_parse_argv},
    2099      {"test_init_compat_env", test_init_compat_env},
    2100      {"test_init_python_env", test_init_python_env},
    2101      {"test_init_env_dev_mode", test_init_env_dev_mode},
    2102      {"test_init_env_dev_mode_alloc", test_init_env_dev_mode_alloc},
    2103      {"test_init_dont_configure_locale", test_init_dont_configure_locale},
    2104      {"test_init_dev_mode", test_init_dev_mode},
    2105      {"test_init_isolated_flag", test_init_isolated_flag},
    2106      {"test_preinit_isolated_config", test_preinit_isolated_config},
    2107      {"test_init_isolated_config", test_init_isolated_config},
    2108      {"test_preinit_python_config", test_preinit_python_config},
    2109      {"test_init_python_config", test_init_python_config},
    2110      {"test_preinit_isolated1", test_preinit_isolated1},
    2111      {"test_preinit_isolated2", test_preinit_isolated2},
    2112      {"test_preinit_parse_argv", test_preinit_parse_argv},
    2113      {"test_preinit_dont_parse_argv", test_preinit_dont_parse_argv},
    2114      {"test_init_read_set", test_init_read_set},
    2115      {"test_init_run_main", test_init_run_main},
    2116      {"test_init_main", test_init_main},
    2117      {"test_init_sys_add", test_init_sys_add},
    2118      {"test_init_setpath", test_init_setpath},
    2119      {"test_init_setpath_config", test_init_setpath_config},
    2120      {"test_init_setpythonhome", test_init_setpythonhome},
    2121      {"test_init_is_python_build", test_init_is_python_build},
    2122      {"test_init_warnoptions", test_init_warnoptions},
    2123      {"test_init_set_config", test_init_set_config},
    2124      {"test_run_main", test_run_main},
    2125      {"test_run_main_loop", test_run_main_loop},
    2126      {"test_get_argc_argv", test_get_argc_argv},
    2127      {"test_init_use_frozen_modules", test_init_use_frozen_modules},
    2128      {"test_init_main_interpreter_settings", test_init_main_interpreter_settings},
    2129  
    2130      // Audit
    2131      {"test_open_code_hook", test_open_code_hook},
    2132      {"test_audit", test_audit},
    2133      {"test_audit_subinterpreter", test_audit_subinterpreter},
    2134      {"test_audit_run_command", test_audit_run_command},
    2135      {"test_audit_run_file", test_audit_run_file},
    2136      {"test_audit_run_interactivehook", test_audit_run_interactivehook},
    2137      {"test_audit_run_startup", test_audit_run_startup},
    2138      {"test_audit_run_stdin", test_audit_run_stdin},
    2139  
    2140      // Specific C API
    2141      {"test_unicode_id_init", test_unicode_id_init},
    2142  #ifndef MS_WINDOWS
    2143      {"test_frozenmain", test_frozenmain},
    2144  #endif
    2145      {"test_get_incomplete_frame", test_get_incomplete_frame},
    2146  
    2147      {NULL, NULL}
    2148  };
    2149  
    2150  
    2151  int main(int argc, char *argv[])
    2152  {
    2153      main_argc = argc;
    2154      main_argv = argv;
    2155  
    2156      if (argc > 1) {
    2157          for (struct TestCase *tc = TestCases; tc && tc->name; tc++) {
    2158              if (strcmp(argv[1], tc->name) == 0)
    2159                  return (*tc->func)();
    2160          }
    2161      }
    2162  
    2163      /* No match found, or no test name provided, so display usage */
    2164      printf("Python " PY_VERSION " _testembed executable for embedded interpreter tests\n"
    2165             "Normally executed via 'EmbeddingTests' in Lib/test/test_embed.py\n\n"
    2166             "Usage: %s TESTNAME\n\nAll available tests:\n", argv[0]);
    2167      for (struct TestCase *tc = TestCases; tc && tc->name; tc++) {
    2168          printf("  %s\n", tc->name);
    2169      }
    2170  
    2171      /* Non-zero exit code will cause test_embed.py tests to fail.
    2172         This is intentional. */
    2173      return -1;
    2174  }