Skip to content

Uninitialized variable replace usage in charmapencode_output (Objects/unicodeobject.c) discovered by scan-build #146429

Description

@ashm-dev

Bug report

Bug description:

Static analysis with scan-build points to a potential use of an uninitialized variable in Objects/unicodeobject.c, specifically within the charmapencode_output function.

The variable unsigned char replace is declared on the stack without initialization. It is passed by reference to charmapencode_lookup(&replace). Later, inside the if (PyLong_Check(rep)) block, replace is cast and assigned to the output buffer:

outstart[(*outpos)++] = (char)replace; // scan-build: Assigned value is uninitialized

If charmapencode_lookup returns a valid PyLong object but fails to update the reference to replace (or purely from a static analysis perspective), this leads to reading uninitialized stack memory.

Suggested Fix:
Either initialize replace upon declaration or retrieve the value directly from the rep object, which is guaranteed to be a PyLong in that scope:

// Instead of using 'replace':
outstart[(*outpos)++] = (char)PyLong_AsLong(rep);

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Activity

  1. vstinner commented on Mar 25, 2026

    @vstinner
    Member

    Static analysis with scan-build points to a potential use of an uninitialized variable in Objects/unicodeobject.c

    What is scan-build? Is it a static analyzer?

    If charmapencode_lookup returns a valid PyLong object but fails to update the reference to replace (or purely from a static analysis perspective), this leads to reading uninitialized stack memory.

    I don't understand the "fails to update the reference to replace" part.

    If charmapencode_lookup() returns a Python int (if PyLong_Check() is true), replace is initialized and so it's safe to use it.

    I don't see any code path where replace is used whereas it's not initialized. It looks like a false-alarm of a static analyzer to me.

  2. ashm-dev commented on Mar 25, 2026

    @ashm-dev
    ContributorAuthor

    @vstinner
    scan-build is the standard command-line utility for the Clang Static Analyzer (LLVM project). It essentially runs clang --analyze.

    Even if charmapencode_lookup guarantees writing to replace (making this a false positive for now), the compiler cannot verify this invariant. This leaves the code fragile:

    1. It triggers warnings in standard static analysis tools.
    2. Future changes to charmapencode_lookup could silently break this implicit contract, introducing UB.

    Zero-cost initialization (unsigned char replace = 0;) fixes the warning and future-proofs the code.

  3. vstinner commented on Mar 25, 2026

    @vstinner
    Member

    Zero-cost initialization (unsigned char replace = 0;)

    I'm not sure that it has a zero-cost. We don't have to fix all false-alarms triggered by the various static analyzers.

    cc @serhiy-storchaka who modified charmapencode_lookup() recently.

    I suggest closing this issue as "won't fix".

  4. serhiy-storchaka commented on Mar 26, 2026

    @serhiy-storchaka
    Member

    I agree with @vstinner. This is a problem of the static analyzing tool.

    The code is not simple, and I do not see a way to rewrite it in significantly simpler way. An attempt to rewrite is the event that can introduce a bug. Adding initialization to silence the static analyzer complain can hide future bugs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions