Skip to content

tests: fix type promotion on 32-bit arches in http test code - #22210

Closed
charles2910 wants to merge 1 commit into
curl:masterfrom
charles2910:fix-type-promotion-on-32-bit-arch
Closed

tests: fix type promotion on 32-bit arches in http test code#22210
charles2910 wants to merge 1 commit into
curl:masterfrom
charles2910:fix-type-promotion-on-32-bit-arch

Conversation

@charles2910

@charles2910 charles2910 commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

As reported in the bug:

On a 32-bit architecture (i386):

  1. chunks * chunk_size evaluates to unsigned int (32-bit
    unsigned).
  2. Due to Usual Arithmetic Conversions in C, the signed -1 (int)
    operand of the ternary operator is promoted to unsigned int,
    yielding 4294967295 (0xFFFFFFFF).
  3. The ternary operator returns 4294967295 as an unsigned int.
  4. This unsigned value is then assigned to r->clength (apr_off_t,
    64-bit signed). Since the source is unsigned, it is zero-extended,
    resulting in r->clength becoming +4294967295.
  5. The subsequently executed check if(r->clength >= 0) evaluates to
    true.
  6. Inside the block, apr_ltoa(r->pool, (long)r->clength) casts it to
    a 32-bit signed long (on 32-bit platforms), which truncates it
    back to -1, formatting it as "-1" and sending the
    "Content-Length: -1" header.

On a 64-bit architecture (amd64), size_t is 64-bit, and -1 (32-bit
int) is promoted to unsigned long (64-bit), yielding
18446744073709551615. When assigned to r->clength (64-bit signed),
it wraps back to -1, which correctly skips the Content-Length
generation.

This type promotion mismatch can be safely fixed by avoiding the
signed/unsigned mixture in the ternary operator.

Origin: debian, https://bugs.debian.org/1140793
Bug-Debian: https://bugs.debian.org/1140793

These are standard Debian patches' trailers, I can get rid of then if you prefer.

I've tested the fix using debusine on i386 runner:

782s tests/http/test_05_errors.py::TestErrors::test_05_04_unclean_tls_shutdown[http/1.0] PASSED [ 17%]
782s tests/http/test_05_errors.py::TestErrors::test_05_04_unclean_tls_shutdown[http/1.1] PASSED [ 18%]
782s tests/http/test_05_errors.py::TestErrors::test_05_04_unclean_tls_shutdown[h2] PASSED [ 18%]

Versus the i386 run in Debian's infrastructure:

2690s tests/http/test_05_errors.py::TestErrors::test_05_04_unclean_tls_shutdown[http/1.0] FAILED [ 17%]
2690s tests/http/test_05_errors.py::TestErrors::test_05_04_unclean_tls_shutdown[http/1.1] PASSED [ 18%]
2690s tests/http/test_05_errors.py::TestErrors::test_05_04_unclean_tls_shutdown[h2] PASSED [ 18%]

@github-actions github-actions Bot added the tests label Jun 28, 2026
@bagder
bagder requested a review from icing June 29, 2026 05:52
Comment thread tests/http/testenv/mod_curltest/mod_curltest.c Outdated
As reported in the bug:

> On a 32-bit architecture (i386):
> 1. `chunks * chunk_size` evaluates to `unsigned int` (32-bit
>    unsigned).
> 2. Due to Usual Arithmetic Conversions in C, the signed `-1` (int)
>    operand of the ternary operator is promoted to `unsigned int`,
>    yielding `4294967295` (0xFFFFFFFF).
> 3. The ternary operator returns `4294967295` as an `unsigned int`.
> 4. This unsigned value is then assigned to `r->clength` (apr_off_t,
>    64-bit signed). Since the source is unsigned, it is zero-extended,
>    resulting in `r->clength` becoming `+4294967295`.
> 5. The subsequently executed check `if(r->clength >= 0)` evaluates to
>    true.
> 6. Inside the block, `apr_ltoa(r->pool, (long)r->clength)` casts it to
>    a 32-bit signed `long` (on 32-bit platforms), which truncates it
>    back to `-1`, formatting it as "-1" and sending the
>    "Content-Length: -1" header.
>
> On a 64-bit architecture (amd64), `size_t` is 64-bit, and `-1` (32-bit
> int) is promoted to `unsigned long` (64-bit), yielding
> `18446744073709551615`. When assigned to `r->clength` (64-bit signed),
> it wraps back to `-1`, which correctly skips the Content-Length
> generation.
>
> This type promotion mismatch can be safely fixed by avoiding the
> signed/unsigned mixture in the ternary operator.

Origin: debian, https://bugs.debian.org/1140793
Bug-Debian: https://bugs.debian.org/1140793

Co-authored-by: Viktor Szakats <vszakats@users.noreply.github.com>

@vszakats vszakats left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested the type bump method (#22210 (comment)), but it's no good, chunk_size is better kept as size_t.

(Ref: #22359 (comment))

@vszakats vszakats closed this in 703a999 Jul 20, 2026
@vszakats

Copy link
Copy Markdown
Member

Thanks Charles, merged now!

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

Labels

Development

Successfully merging this pull request may close these issues.

3 participants