Skip to content

Possible uninitialized curlocales[] #17824

@ppisar

Description

@ppisar

A static analysis on 5.31.1 sources claims that an uninitialized curlocales[] member in locale.c:Perl_init_i18nl10n() can be passed to Safefree(). I believe that that the same flaw exists in the blead sources:

    if (ok < 1) {   /* If we tried to fallback */
        const char* msg;
        if (! setlocale_failure) {  /* fallback succeeded */
           msg = "Falling back to";
        }
        else {  /* fallback failed */
            unsigned int j;

            /* We dropped off the end of the loop, so have to decrement i to
             * get back to the value the last time through */
            i--;

            ok = -1;
            msg = "Failed to fall back to";

            /* To continue, we should use whatever values we've got */

            for (j = 0; j < NOMINAL_LC_ALL_INDEX; j++) {
→               Safefree(curlocales[j]);
                curlocales[j] = savepv(do_setlocale_r(categories[j], NULL));
                DEBUG_LOCALE_INIT(categories[j], NULL, curlocales[j]);
            }
        }

There are only two places where curlocales[] members are initialized:

A place guarded with:

        if (i == 0) {
            unsigned int j;

            if (locwarn) { /* Output failure info only on the first one *

branch. init_i18nl10n() can be called by XS code via init_i18nl14n(aTHX, 0) that will bypass this branch.

And the second place of the initialization is just above that:

#  ifdef LC_ALL

        sl_result[LC_ALL_INDEX] = do_setlocale_c(LC_ALL, trial_locale);
        DEBUG_LOCALE_INIT(LC_ALL, trial_locale, sl_result[LC_ALL_INDEX]);
        if (! sl_result[LC_ALL_INDEX]) {
            setlocale_failure = TRUE;
        }
        else {
            /* Since LC_ALL succeeded, it should have changed all the other
             * categories it can to its value; so we massage things so that the
             * setlocales below just return their category's current values.
             * This adequately handles the case in NetBSD where LC_COLLATE may
             * not be defined for a locale, and setting it individually will
             * fail, whereas setting LC_ALL succeeds, leaving LC_COLLATE set to
             * the POSIX locale. */
            trial_locale = NULL;
        }

#  endif /* LC_ALL */

        if (! setlocale_failure) {
            unsigned int j;
            for (j = 0; j < NOMINAL_LC_ALL_INDEX; j++) {
                curlocales[j]
                        = savepv(do_setlocale_r(categories[j], trial_locale));
                if (! curlocales[j]) {
                    setlocale_failure = TRUE;
                }
                DEBUG_LOCALE_INIT(categories[j], trial_locale, curlocales[j]);
            }

            if (! setlocale_failure) {  /* All succeeded */
                break;  /* Exit trial_locales loop */
            }
        }

If the setlocale_failure is true, e.g. set in the quoted (! sl_result[LC_ALL_INDEX]) condition, then it's possible to never initialize the members of the array.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions