Skip to content

Commit f04ebe2

Browse files
authored
bpo-32030: Add _PyMainInterpreterConfig.program_name (#4548)
* Py_Main() now calls Py_SetProgramName() earlier to be able to get the program name in _PyMainInterpreterConfig_ReadEnv(). * Rename prog to program_name * Rename progpath to program_name
1 parent 46972b7 commit f04ebe2

File tree

5 files changed

+96
-70
lines changed

5 files changed

+96
-70
lines changed

Include/pystate.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ typedef struct {
6464
wchar_t *module_search_path_env;
6565
/* PYTHONHOME environment variable, see also Py_SetPythonHome(). */
6666
wchar_t *home;
67+
/* Program name, see also Py_GetProgramName() */
68+
wchar_t *program_name;
6769
} _PyMainInterpreterConfig;
6870

6971
#define _PyMainInterpreterConfig_INIT \

Modules/getpath.c

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ extern "C" {
112112
typedef struct {
113113
wchar_t prefix[MAXPATHLEN+1];
114114
wchar_t exec_prefix[MAXPATHLEN+1];
115-
wchar_t progpath[MAXPATHLEN+1];
115+
wchar_t program_name[MAXPATHLEN+1];
116116
wchar_t *module_search_path;
117117
} PyPathConfig;
118118

@@ -121,7 +121,7 @@ typedef struct {
121121
wchar_t *home; /* PYTHONHOME environment variable */
122122
wchar_t *module_search_path_env; /* PYTHONPATH environment variable */
123123

124-
wchar_t *prog; /* Program name */
124+
wchar_t *program_name; /* Program name */
125125
wchar_t *pythonpath; /* PYTHONPATH define */
126126
wchar_t *prefix; /* PREFIX define */
127127
wchar_t *exec_prefix; /* EXEC_PREFIX define */
@@ -602,8 +602,8 @@ calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config)
602602
* other way to find a directory to start the search from. If
603603
* $PATH isn't exported, you lose.
604604
*/
605-
if (wcschr(calculate->prog, SEP)) {
606-
wcsncpy(config->progpath, calculate->prog, MAXPATHLEN);
605+
if (wcschr(calculate->program_name, SEP)) {
606+
wcsncpy(config->program_name, calculate->program_name, MAXPATHLEN);
607607
}
608608
#ifdef __APPLE__
609609
/* On Mac OS X, if a script uses an interpreter of the form
@@ -616,11 +616,13 @@ calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config)
616616
* will fail if a relative path was used. but in that case,
617617
* absolutize() should help us out below
618618
*/
619-
else if(0 == _NSGetExecutablePath(execpath, &nsexeclength) && execpath[0] == SEP) {
620-
size_t r = mbstowcs(config->progpath, execpath, MAXPATHLEN+1);
619+
else if(0 == _NSGetExecutablePath(execpath, &nsexeclength) &&
620+
execpath[0] == SEP)
621+
{
622+
size_t r = mbstowcs(config->program_name, execpath, MAXPATHLEN+1);
621623
if (r == (size_t)-1 || r > MAXPATHLEN) {
622624
/* Could not convert execpath, or it's too long. */
623-
config->progpath[0] = '\0';
625+
config->program_name[0] = '\0';
624626
}
625627
}
626628
#endif /* __APPLE__ */
@@ -634,38 +636,38 @@ calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config)
634636
if (len > MAXPATHLEN) {
635637
len = MAXPATHLEN;
636638
}
637-
wcsncpy(config->progpath, path, len);
638-
*(config->progpath + len) = '\0';
639+
wcsncpy(config->program_name, path, len);
640+
*(config->program_name + len) = '\0';
639641
}
640642
else {
641-
wcsncpy(config->progpath, path, MAXPATHLEN);
643+
wcsncpy(config->program_name, path, MAXPATHLEN);
642644
}
643645

644-
joinpath(config->progpath, calculate->prog);
645-
if (isxfile(config->progpath)) {
646+
joinpath(config->program_name, calculate->program_name);
647+
if (isxfile(config->program_name)) {
646648
break;
647649
}
648650

649651
if (!delim) {
650-
config->progpath[0] = L'\0';
652+
config->program_name[0] = L'\0';
651653
break;
652654
}
653655
path = delim + 1;
654656
}
655657
}
656658
else {
657-
config->progpath[0] = '\0';
659+
config->program_name[0] = '\0';
658660
}
659-
if (config->progpath[0] != SEP && config->progpath[0] != '\0') {
660-
absolutize(config->progpath);
661+
if (config->program_name[0] != SEP && config->program_name[0] != '\0') {
662+
absolutize(config->program_name);
661663
}
662664
}
663665

664666

665667
static void
666668
calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config)
667669
{
668-
wcsncpy(calculate->argv0_path, config->progpath, MAXPATHLEN);
670+
wcsncpy(calculate->argv0_path, config->program_name, MAXPATHLEN);
669671
calculate->argv0_path[MAXPATHLEN] = '\0';
670672

671673
#ifdef WITH_NEXT_FRAMEWORK
@@ -700,10 +702,10 @@ calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config)
700702
if (!ismodule(calculate->argv0_path)) {
701703
/* We are in the build directory so use the name of the
702704
executable - we know that the absolute path is passed */
703-
wcsncpy(calculate->argv0_path, config->progpath, MAXPATHLEN);
705+
wcsncpy(calculate->argv0_path, config->program_name, MAXPATHLEN);
704706
}
705707
else {
706-
/* Use the location of the library as the progpath */
708+
/* Use the location of the library as the program_name */
707709
wcsncpy(calculate->argv0_path, wbuf, MAXPATHLEN);
708710
}
709711
PyMem_RawFree(wbuf);
@@ -712,15 +714,15 @@ calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config)
712714

713715
#if HAVE_READLINK
714716
wchar_t tmpbuffer[MAXPATHLEN+1];
715-
int linklen = _Py_wreadlink(config->progpath, tmpbuffer, MAXPATHLEN);
717+
int linklen = _Py_wreadlink(config->program_name, tmpbuffer, MAXPATHLEN);
716718
while (linklen != -1) {
717719
if (tmpbuffer[0] == SEP) {
718720
/* tmpbuffer should never be longer than MAXPATHLEN,
719721
but extra check does not hurt */
720722
wcsncpy(calculate->argv0_path, tmpbuffer, MAXPATHLEN);
721723
}
722724
else {
723-
/* Interpret relative to progpath */
725+
/* Interpret relative to program_name */
724726
reduce(calculate->argv0_path);
725727
joinpath(calculate->argv0_path, tmpbuffer);
726728
}
@@ -897,6 +899,7 @@ calculate_init(PyCalculatePath *calculate,
897899
{
898900
calculate->home = main_config->home;
899901
calculate->module_search_path_env = main_config->module_search_path_env;
902+
calculate->program_name = main_config->program_name;
900903

901904
size_t len;
902905
char *path = getenv("PATH");
@@ -907,8 +910,6 @@ calculate_init(PyCalculatePath *calculate,
907910
}
908911
}
909912

910-
calculate->prog = Py_GetProgramName();
911-
912913
calculate->pythonpath = Py_DecodeLocale(PYTHONPATH, &len);
913914
if (!calculate->pythonpath) {
914915
return DECODE_LOCALE_ERR("PYTHONPATH define", len);
@@ -950,7 +951,9 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config)
950951
calculate_zip_path(calculate, config);
951952
calculate_exec_prefix(calculate, config);
952953

953-
if ((!calculate->prefix_found || !calculate->exec_prefix_found) && !Py_FrozenFlag) {
954+
if ((!calculate->prefix_found || !calculate->exec_prefix_found) &&
955+
!Py_FrozenFlag)
956+
{
954957
fprintf(stderr,
955958
"Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]\n");
956959
}
@@ -1018,10 +1021,11 @@ Py_SetPath(const wchar_t *path)
10181021
return;
10191022
}
10201023

1021-
wchar_t *prog = Py_GetProgramName();
1022-
wcsncpy(path_config.progpath, prog, MAXPATHLEN);
1024+
wchar_t *program_name = Py_GetProgramName();
1025+
wcsncpy(path_config.program_name, program_name, MAXPATHLEN);
10231026
path_config.exec_prefix[0] = path_config.prefix[0] = L'\0';
1024-
path_config.module_search_path = PyMem_RawMalloc((wcslen(path) + 1) * sizeof(wchar_t));
1027+
size_t size = (wcslen(path) + 1) * sizeof(wchar_t);
1028+
path_config.module_search_path = PyMem_RawMalloc(size);
10251029
if (path_config.module_search_path != NULL) {
10261030
wcscpy(path_config.module_search_path, path);
10271031
}
@@ -1074,7 +1078,7 @@ Py_GetProgramFullPath(void)
10741078
if (!path_config.module_search_path) {
10751079
calculate_path(NULL);
10761080
}
1077-
return path_config.progpath;
1081+
return path_config.program_name;
10781082
}
10791083

10801084
#ifdef __cplusplus

Modules/main.c

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,6 +1452,13 @@ _PyMainInterpreterConfig_ReadEnv(_PyMainInterpreterConfig *config)
14521452
return err;
14531453
}
14541454

1455+
/* FIXME: _PyMainInterpreterConfig_Read() has the same code. Remove it
1456+
here? See also pymain_get_program_name() and pymain_parse_envvars(). */
1457+
config->program_name = _PyMem_RawWcsdup(Py_GetProgramName());
1458+
if (config->program_name == NULL) {
1459+
return _Py_INIT_NO_MEMORY();
1460+
}
1461+
14551462
return _Py_INIT_OK();
14561463
}
14571464

@@ -1480,6 +1487,15 @@ pymain_parse_envvars(_PyMain *pymain)
14801487
}
14811488
core_config->allocator = Py_GETENV("PYTHONMALLOC");
14821489

1490+
/* FIXME: move pymain_get_program_name() code into
1491+
_PyMainInterpreterConfig_ReadEnv().
1492+
Problem: _PyMainInterpreterConfig_ReadEnv() doesn't have access
1493+
to argv[0]. */
1494+
Py_SetProgramName(pymain->program_name);
1495+
/* Don't free program_name here: the argument to Py_SetProgramName
1496+
must remain valid until Py_FinalizeEx is called. The string is freed
1497+
by pymain_free(). */
1498+
14831499
_PyInitError err = _PyMainInterpreterConfig_ReadEnv(&pymain->config);
14841500
if (_Py_INIT_FAILED(pymain->err)) {
14851501
pymain->err = err;
@@ -1569,11 +1585,6 @@ pymain_init_python(_PyMain *pymain)
15691585
return -1;
15701586
}
15711587

1572-
Py_SetProgramName(pymain->program_name);
1573-
/* Don't free program_name here: the argument to Py_SetProgramName
1574-
must remain valid until Py_FinalizeEx is called. The string is freed
1575-
by pymain_free(). */
1576-
15771588
if (pymain_add_xoptions(pymain)) {
15781589
return -1;
15791590
}

PC/getpathp.c

Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@
118118

119119
typedef struct {
120120
wchar_t prefix[MAXPATHLEN+1];
121-
wchar_t progpath[MAXPATHLEN+1];
121+
wchar_t program_name[MAXPATHLEN+1];
122122
wchar_t dllpath[MAXPATHLEN+1];
123123
wchar_t *module_search_path;
124124
} PyPathConfig;
@@ -132,7 +132,7 @@ typedef struct {
132132
wchar_t *machine_path; /* from HKEY_LOCAL_MACHINE */
133133
wchar_t *user_path; /* from HKEY_CURRENT_USER */
134134

135-
wchar_t *prog; /* Program name */
135+
wchar_t *program_name; /* Program name */
136136
wchar_t argv0_path[MAXPATHLEN+1];
137137
wchar_t zip_path[MAXPATHLEN+1];
138138
} PyCalculatePath;
@@ -484,22 +484,22 @@ getpythonregpath(HKEY keyBase, int skipcore)
484484

485485

486486
static void
487-
get_progpath(PyCalculatePath *calculate, wchar_t *progpath, wchar_t *dllpath)
487+
get_progpath(PyCalculatePath *calculate, PyPathConfig *config)
488488
{
489489
wchar_t *path = calculate->path_env;
490490

491491
#ifdef Py_ENABLE_SHARED
492492
extern HANDLE PyWin_DLLhModule;
493-
/* static init of progpath ensures final char remains \0 */
493+
/* static init of program_name ensures final char remains \0 */
494494
if (PyWin_DLLhModule) {
495-
if (!GetModuleFileNameW(PyWin_DLLhModule, dllpath, MAXPATHLEN)) {
496-
dllpath[0] = 0;
495+
if (!GetModuleFileNameW(PyWin_DLLhModule, config->dllpath, MAXPATHLEN)) {
496+
config->dllpath[0] = 0;
497497
}
498498
}
499499
#else
500-
dllpath[0] = 0;
500+
config->dllpath[0] = 0;
501501
#endif
502-
if (GetModuleFileNameW(NULL, progpath, MAXPATHLEN)) {
502+
if (GetModuleFileNameW(NULL, config->program_name, MAXPATHLEN)) {
503503
return;
504504
}
505505

@@ -509,12 +509,12 @@ get_progpath(PyCalculatePath *calculate, wchar_t *progpath, wchar_t *dllpath)
509509
* $PATH isn't exported, you lose.
510510
*/
511511
#ifdef ALTSEP
512-
if (wcschr(calculate->prog, SEP) || wcschr(calculate->prog, ALTSEP))
512+
if (wcschr(calculate->program_name, SEP) || wcschr(calculate->program_name, ALTSEP))
513513
#else
514-
if (wcschr(calculate->prog, SEP))
514+
if (wcschr(calculate->program_name, SEP))
515515
#endif
516516
{
517-
wcsncpy(progpath, calculate->prog, MAXPATHLEN);
517+
wcsncpy(config->program_name, calculate->program_name, MAXPATHLEN);
518518
}
519519
else if (path) {
520520
while (1) {
@@ -524,28 +524,28 @@ get_progpath(PyCalculatePath *calculate, wchar_t *progpath, wchar_t *dllpath)
524524
size_t len = delim - path;
525525
/* ensure we can't overwrite buffer */
526526
len = min(MAXPATHLEN,len);
527-
wcsncpy(progpath, path, len);
528-
*(progpath + len) = '\0';
527+
wcsncpy(config->program_name, path, len);
528+
*(config->program_name + len) = '\0';
529529
}
530530
else {
531-
wcsncpy(progpath, path, MAXPATHLEN);
531+
wcsncpy(config->program_name, path, MAXPATHLEN);
532532
}
533533

534534
/* join() is safe for MAXPATHLEN+1 size buffer */
535-
join(progpath, calculate->prog);
536-
if (exists(progpath)) {
535+
join(config->program_name, calculate->program_name);
536+
if (exists(config->program_name)) {
537537
break;
538538
}
539539

540540
if (!delim) {
541-
progpath[0] = '\0';
541+
config->program_name[0] = '\0';
542542
break;
543543
}
544544
path = delim + 1;
545545
}
546546
}
547547
else {
548-
progpath[0] = '\0';
548+
config->program_name[0] = '\0';
549549
}
550550
}
551551

@@ -695,14 +695,9 @@ calculate_init(PyCalculatePath *calculate,
695695
{
696696
calculate->home = main_config->home;
697697
calculate->module_search_path_env = main_config->module_search_path_env;
698+
calculate->program_name = main_config->program_name;
698699

699700
calculate->path_env = _wgetenv(L"PATH");
700-
701-
wchar_t *prog = Py_GetProgramName();
702-
if (prog == NULL || *prog == '\0') {
703-
prog = L"python";
704-
}
705-
calculate->prog = prog;
706701
}
707702

708703

@@ -714,8 +709,8 @@ get_pth_filename(wchar_t *spbuffer, PyPathConfig *config)
714709
return 1;
715710
}
716711
}
717-
if (config->progpath[0]) {
718-
if (!change_ext(spbuffer, config->progpath, L"._pth") && exists(spbuffer)) {
712+
if (config->program_name[0]) {
713+
if (!change_ext(spbuffer, config->program_name, L"._pth") && exists(spbuffer)) {
719714
return 1;
720715
}
721716
}
@@ -784,9 +779,9 @@ static void
784779
calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config,
785780
const _PyMainInterpreterConfig *main_config)
786781
{
787-
get_progpath(calculate, config->progpath, config->dllpath);
788-
/* progpath guaranteed \0 terminated in MAXPATH+1 bytes. */
789-
wcscpy_s(calculate->argv0_path, MAXPATHLEN+1, config->progpath);
782+
get_progpath(calculate, config);
783+
/* program_name guaranteed \0 terminated in MAXPATH+1 bytes. */
784+
wcscpy_s(calculate->argv0_path, MAXPATHLEN+1, config->program_name);
790785
reduce(calculate->argv0_path);
791786

792787
/* Search for a sys.path file */
@@ -798,7 +793,7 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config,
798793

799794
/* Calculate zip archive path from DLL or exe path */
800795
change_ext(calculate->zip_path,
801-
config->dllpath[0] ? config->dllpath : config->progpath,
796+
config->dllpath[0] ? config->dllpath : config->program_name,
802797
L".zip");
803798

804799
if (calculate->home == NULL || *calculate->home == '\0') {
@@ -1057,8 +1052,8 @@ Py_SetPath(const wchar_t *path)
10571052
return;
10581053
}
10591054

1060-
wchar_t *prog = Py_GetProgramName();
1061-
wcsncpy(path_config.progpath, prog, MAXPATHLEN);
1055+
wchar_t *program_name = Py_GetProgramName();
1056+
wcsncpy(path_config.program_name, program_name, MAXPATHLEN);
10621057
path_config.prefix[0] = L'\0';
10631058
path_config.module_search_path = PyMem_RawMalloc((wcslen(path) + 1) * sizeof(wchar_t));
10641059
if (path_config.module_search_path != NULL) {
@@ -1110,7 +1105,7 @@ Py_GetProgramFullPath(void)
11101105
if (!path_config.module_search_path) {
11111106
calculate_path(NULL);
11121107
}
1113-
return path_config.progpath;
1108+
return path_config.program_name;
11141109
}
11151110

11161111

0 commit comments

Comments
 (0)