Skip to content

Download progress bar divides by zero without Content-Length and prints ~2.1 billion spaces per tick #4550

Description

@Daksha1611

Describe the bug

When a model download is served over a response with no Content-Length (chunked transfer encoding), the progress bar divides by zero and then prints roughly 2.1 billion spaces per progress tick. The pull appears to hang; the transfer itself is fine.

src/pull_module/curl_downloader.cpp:49-63:

static void print_progress(size_t count, size_t max, bool first_run, size_t elapsed_time) {
    float progress = (float)count / max;          // :50   max == 0 -> inf
    if (!first_run && progress < 0.01 && count > 0)
        return;

    const int bar_width = 50;
    int bar_length = progress * bar_width;        // :55   (int)inf is undefined
    ...
    for (i = bar_length; i < bar_width; ++i) {    // :62
        printf(" ");
    }

max is libcurl's dltotal, which is 0 when the server does not announce a size. The guard in progress_callback (src/pull_module/curl_downloader.cpp:133-135) only short-circuits while dltotal == dlnow:

if ((dltotal == dlnow) && dltotal < 10000) {
    return 0;
}

Once any bytes have arrived, dlnow > 0 == dltotal, so the callback falls through to print_progress(dlnow, 0, ...).

progress becomes inf. Converting an infinite float to int is undefined behaviour; on x86-64 it yields INT_MIN. The bar-fill loop at :59 therefore does not run at all, and the padding loop at :62 runs from INT_MIN to bar_width.

Compiling exactly those two lines and counting the padding iterations:

bar_length = -2147483648
padding loop would run 2147483698 times

That is ~2.1 billion printf(" ") calls on every tick, and progress_callback prints once a second.

Related, same function: bar_length is never clamped, so a server reporting more bytes than it announced (dlnow > dltotal, which happens with some content encodings) makes progress > 1 and overruns the bar in the other direction.

To Reproduce

Point a pull at any HTTP endpoint that responds with Transfer-Encoding: chunked and no Content-Length — a local mirror, a proxy, an internal registry, or a plain python3 -m http.server in front of the artifacts:

ovms --pull --source_model <model> --model_repository_path /tmp/repo

The download proceeds but the console stops being usable and the process appears stuck.

Expected behavior

With an unknown total size, print a running byte count (or a spinner) rather than a percentage bar, and never divide by max when max == 0. The bar length should also be clamped to the bar width so no ratio can drive the loops out of range.

Logs

Console output only — the terminal fills with whitespace and the \r-based progress line never completes.

Configuration

  1. OVMS version: main @ fadb3314
  2. Any --pull against a source served without Content-Length
  3. CPU
  4. N/A
  5. Any model

Additional context

Suggested fix: early-return from print_progress when max == 0 and report bytes received instead, and move the bar arithmetic into a small helper that returns 0 for an unknown total and clamps to [0, barWidth].

I have a patch for this and will open a PR shortly.

Activity

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

Metadata

Metadata

Assignees

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