Changeset 1294 for python


Ignore:
Timestamp:
Feb 9, 2018, 10:00:18 PM (8 years ago)
Author:
dmik
Message:

python: Improve handling of BEGINLIBPATH and other pseudo-env vars.

This fix avoids pollution of os.environ with unset pseudo-env vars and also
adds support for temporarily enabling their action when passed in env
argument to os.execve and os.spawnve calls (not thread-safe).

Closes #299.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • python/trunk/Modules/posixmodule.c

    r1281 r1294  
    577577#endif
    578578
     579#if defined(PYOS_OS2)
     580static PyObject *
     581os2_error(int code);
     582
     583#define OS2_SPECIAL_ENVVAR_CNT 3
     584
     585/* Returns a var ID if it is a special pseudo-environment variable or 0 */
     586static ULONG
     587os2_envvar_special(const char *var)
     588{
     589    ULONG flag = 0;
     590    if (stricmp(var, "BEGINLIBPATH") == 0) {
     591        flag = BEGIN_LIBPATH;
     592    } else if (stricmp(var, "ENDLIBPATH") == 0) {
     593        flag = END_LIBPATH;
     594#ifdef LIBPATHSTRICT
     595    } else if (stricmp(var, "LIBPATHSTRICT") == 0) {
     596        flag = LIBPATHSTRICT;
     597#endif
     598    }
     599
     600    return flag;
     601}
     602
     603/* Sets and optionally gets a special pseudo-environment variable.
     604 * Returns 0 on success or non-zero on failure (with a respective Python
     605 * exception pending). If val is NULL, no set operation is performed. An old
     606 * value of the variable is returned in oldval if it is not NULL. If *oldval is
     607 * NULL on input, a buffer will be allocaed with PyMem_NEW which must be freed
     608 * with PyMem_DEL by the caller. */
     609static int
     610os2_putenv_special(const ULONG id, const char *val, char **oldval)
     611{
     612    APIRET rc;
     613
     614    if (oldval) {
     615        if (*oldval == NULL) {
     616            /* OS/2 Provides a Documented Max of 1024 Chars */
     617            *oldval = PyMem_NEW(char, 1024);
     618            if (*oldval == NULL) {
     619                PyErr_NoMemory();
     620                return -1;
     621            }
     622        }
     623        /* LIBPATHSTRICT only returns T or nothing so set the zero terminator */
     624        if (id == LIBPATHSTRICT)
     625            memset(*oldval, '\0', 4);
     626        rc = DosQueryExtLIBPATH(*oldval, id);
     627        if (rc != NO_ERROR) {
     628            os2_error(rc);
     629            return -1;
     630        }
     631    }
     632
     633    if (val) {
     634        /* Validate input */
     635        if (id == LIBPATHSTRICT) {
     636            if (val[0] != '\0' && (val[0] != 'T' || val[1] != '\0')) {
     637                PyErr_SetString(PyExc_ValueError,
     638                                "LIBPATHSTRICT value must be T or empty");
     639                return -1;
     640            }
     641        } else {
     642            if (strlen(val) > 1023) {
     643                PyErr_SetString(PyExc_ValueError,
     644                                "BEGINLIBPATH/ENDLIBPATH length must not "
     645                                "exceed 1023 chars");
     646                return -1;
     647            }
     648        }
     649        rc = DosSetExtLIBPATH(val, id);
     650        if (rc != NO_ERROR) {
     651            os2_error(rc);
     652            return -1;
     653        }
     654    }
     655
     656    return 0;
     657}
     658#endif
     659
    579660/* Return a dictionary corresponding to the POSIX environment table */
    580661#if defined(WITH_NEXT_FRAMEWORK) || (defined(__APPLE__) && defined(Py_ENABLE_SHARED))
     
    595676    char **e;
    596677#if defined(PYOS_OS2)
    597     APIRET rc;
    598678    char   buffer[1024]; /* OS/2 Provides a Documented Max of 1024 Chars */
     679    const char *sp_envvars[OS2_SPECIAL_ENVVAR_CNT] =
     680        { "BEGINLIBPATH", "ENDLIBPATH", "LIBPATHSTRICT" };
     681    ULONG sp_envids[OS2_SPECIAL_ENVVAR_CNT] =
     682        { BEGIN_LIBPATH, END_LIBPATH, LIBPATHSTRICT };
     683    int i;
    599684#endif
    600685    d = PyDict_New();
     
    633718    }
    634719#if defined(PYOS_OS2)
    635     rc = DosQueryExtLIBPATH(buffer, BEGIN_LIBPATH);
    636     if (rc == NO_ERROR) { /* (not a type, envname is NOT 'BEGIN_LIBPATH') */
    637         PyObject *v = PyString_FromString(buffer);
    638             PyDict_SetItemString(d, "BEGINLIBPATH", v);
    639         Py_DECREF(v);
    640     }
    641     rc = DosQueryExtLIBPATH(buffer, END_LIBPATH);
    642     if (rc == NO_ERROR) { /* (not a typo, envname is NOT 'END_LIBPATH') */
    643         PyObject *v = PyString_FromString(buffer);
    644             PyDict_SetItemString(d, "ENDLIBPATH", v);
    645         Py_DECREF(v);
    646     }
    647 #ifdef LIBPATHSTRICT
    648     buffer[0] = buffer[1] = buffer[2] = buffer[3] = '\0';
    649     rc = DosQueryExtLIBPATH(buffer, LIBPATHSTRICT);
    650     if (rc == NO_ERROR) { /* (not a typo, envname is NOT 'LIBPATH_STRICT') */
    651         PyObject *v = PyString_FromString(buffer);
    652         PyDict_SetItemString(d, "LIBPATHSTRICT", v);
    653         Py_DECREF(v);
    654     }
    655 #endif
     720    for (i = 0; i < OS2_SPECIAL_ENVVAR_CNT; ++i) {
     721        char *val = buffer;
     722        if (os2_putenv_special(sp_envids[i], NULL, &val)) {
     723            PyErr_Clear();
     724            continue;
     725        }
     726        /* Do not pollute the einvironment with unset pseudo-env variables */
     727        if (*val) {
     728            PyObject *v = PyString_FromString(val);
     729            PyDict_SetItemString(d, sp_envvars[i], v);
     730            Py_DECREF(v);
     731        }
     732    }
    656733#endif
    657734    return d;
     
    32093286    PyObject *(*getitem)(PyObject *, Py_ssize_t);
    32103287    Py_ssize_t lastarg = 0;
     3288#if defined(PYOS_OS2)
     3289    char *sp_envvars[OS2_SPECIAL_ENVVAR_CNT] = { NULL };
     3290    ULONG sp_envids[OS2_SPECIAL_ENVVAR_CNT] = { 0 };
     3291    Py_ssize_t sp_envc = 0;
     3292    ULONG envid;
     3293#endif
    32113294
    32123295    /* execve has three arguments: (path, argv, env), where
     
    32963379
    32973380#if defined(PYOS_OS2)
    3298         /* Omit Pseudo-Env Vars that Would Confuse Programs if Passed On */
    3299         if (stricmp(k, "BEGINLIBPATH") != 0 && stricmp(k, "ENDLIBPATH") != 0
    3300          && stricmp(k, "LIBPATHSTRICT") != 0) {
     3381        envid = os2_envvar_special(k);
     3382        if (envid) {
     3383            /* Process pseudo-env vars and omit them from the environment as
     3384             * they could coufuse programs if passed on. Note that this code is
     3385             * not thread-safe but we have no other option here. */
     3386            sp_envids[sp_envc] = envid;
     3387            if (os2_putenv_special(envid, v, &sp_envvars[sp_envc])) {
     3388                if (sp_envvars[sp_envc])
     3389                    PyMem_DEL(sp_envvars[sp_envc]);
     3390                goto fail_2;
     3391            }
     3392            ++sp_envc;
     3393        } else {
    33013394#endif
    33023395        len = PyString_Size(key) + PyString_Size(val) + 2;
     
    33213414
    33223415  fail_2:
     3416#if defined(PYOS_OS2)
     3417    while (--sp_envc >= 0) {
     3418        /* Restore the pseudo-env var's value */
     3419        os2_putenv_special(sp_envids[sp_envc], sp_envvars[sp_envc], NULL);
     3420        PyMem_DEL(sp_envvars[sp_envc]);
     3421    }
     3422#endif
    33233423    while (--envc >= 0)
    33243424        PyMem_DEL(envlist[envc]);
     
    34453545    PyObject *(*getitem)(PyObject *, Py_ssize_t);
    34463546    Py_ssize_t lastarg = 0;
     3547#if defined(PYOS_OS2)
     3548    char *sp_envvars[OS2_SPECIAL_ENVVAR_CNT] = { NULL };
     3549    ULONG sp_envids[OS2_SPECIAL_ENVVAR_CNT] = { 0 };
     3550    Py_ssize_t sp_envc = 0;
     3551    ULONG envid;
     3552#endif
    34473553
    34483554    /* spawnve has four arguments: (mode, path, argv, env), where
     
    35303636            goto fail_2;
    35313637        }
     3638#if defined(PYOS_OS2)
     3639        envid = os2_envvar_special(k);
     3640        if (envid) {
     3641            /* Process pseudo-env vars and omit them from the environment as
     3642             * they could coufuse programs if passed on. Note that this code is
     3643             * not thread-safe but we have no other option here. */
     3644            sp_envids[sp_envc] = envid;
     3645            if (os2_putenv_special(envid, v, &sp_envvars[sp_envc])) {
     3646                if (sp_envvars[sp_envc])
     3647                    PyMem_DEL(sp_envvars[sp_envc]);
     3648                goto fail_2;
     3649            }
     3650            ++sp_envc;
     3651        } else {
     3652#endif
    35323653        len = PyString_Size(key) + PyString_Size(val) + 2;
    35333654        p = PyMem_NEW(char, len);
     
    35383659        PyOS_snprintf(p, len, "%s=%s", k, v);
    35393660        envlist[envc++] = p;
     3661#if defined(PYOS_OS2)
     3662        }
     3663#endif
    35403664    }
    35413665    envlist[envc] = 0;
     
    35643688
    35653689  fail_2:
     3690#if defined(PYOS_OS2)
     3691    while (--sp_envc >= 0) {
     3692        /* Restore the pseudo-env var's value */
     3693        os2_putenv_special(sp_envids[sp_envc], sp_envvars[sp_envc], NULL);
     3694        PyMem_DEL(sp_envvars[sp_envc]);
     3695    }
     3696#endif
    35663697    while (--envc >= 0)
    35673698        PyMem_DEL(envlist[envc]);
     
    71347265
    71357266#if defined(PYOS_OS2)
    7136     if (stricmp(s1, "BEGINLIBPATH") == 0) {
    7137         APIRET rc;
    7138 
    7139         rc = DosSetExtLIBPATH(s2, BEGIN_LIBPATH);
    7140         if (rc != NO_ERROR)
    7141             return os2_error(rc);
    7142 
    7143     } else if (stricmp(s1, "ENDLIBPATH") == 0) {
    7144         APIRET rc;
    7145 
    7146         rc = DosSetExtLIBPATH(s2, END_LIBPATH);
    7147         if (rc != NO_ERROR)
    7148             return os2_error(rc);
    7149 #ifdef LIBPATHSTRICT
    7150     } else if (stricmp(s1, "LIBPATHSTRICT") == 0) {
    7151         APIRET rc;
    7152 
    7153         rc = DosSetExtLIBPATH(s2, LIBPATHSTRICT);
    7154         if (rc != NO_ERROR)
    7155             return os2_error(rc);
    7156 #endif
     7267    int envid = os2_envvar_special(s1);
     7268    if (envid) {
     7269        if (os2_putenv_special(envid, s2, NULL))
     7270            return NULL; /* Signal to Python that an Exception is Pending */
    71577271    } else {
    71587272#endif /* OS2 */
     
    89429056                goto fail_2;
    89439057            }
     9058            /* Note that we don't process pseudo-env vars here as they are
     9059             * processed internally by spawn2() to guarantee thread safety
     9060             * in P_2_THREADSAFE mode. */
    89449061            len = PyString_Size(key) + PyString_Size(val) + 2;
    89459062            p = PyMem_NEW(char, len);
Note: See TracChangeset for help on using the changeset viewer.