Hi Dmytro,

Thank you for the structured report with detailed minimal example and for testing of our pre-release version.

Please share also the following data:

 * The size of your test file used for uploads
 * Your OS and kernel version
 * gcc --version
 * curl --version
 * Any extra options used for MHD2 configure

You may get additional data by testing with MHD2 built with "./configure --enable-build-type=debug" or "./configure --enable-build-type=debugger". I would appreciate if you try with MHD2 with such settings.

Thank you!

--
Best,
Evgeny

On 28/02/2026 15:30, Dmytro Zhukov wrote:

Hi,

I found a bug in the MHD2 multipart POST parser where |size| passed to |MHD_PostDataReader| occasionally wraps to a huge value (e.g. |18446744073709551518|, which is |-98| as a signed value), and the |off| parameter simultaneously regresses by the same amount.

*Tested on:* commit |afe8b43| (current master)

*Minimal reproducer:
*#include <microhttpd2.h>
#include <stdio.h>

static const struct MHD_UploadAction *post_data_reader(
    struct MHD_Request *req, void *cls, const struct MHD_String *name,
    const struct MHD_StringNullable *filename,
    const struct MHD_StringNullable *content_type,
    const struct MHD_StringNullable *encoding, size_t size, const void *data,
    uint_fast64_t off, enum MHD_Bool final_data) {
    if (filename && filename->cstr)
        printf("f=%s off=%llu size=%zu final=%d\n", filename->cstr,
               (unsigned long long)off, size, (int)final_data);
    return MHD_upload_action_continue(req);
}

static const struct MHD_UploadAction *
post_done(struct MHD_Request *req, void *cls, enum MHD_PostParseResult result) {
    return (const struct MHD_UploadAction *)MHD_action_from_response(
        req, MHD_response_from_buffer_static(MHD_HTTP_STATUS_OK, 2, "OK"));
}

static const struct MHD_Action *handle_request(void *cls,
                                               struct MHD_Request *req,
                                               const struct MHD_String *path,                                                enum MHD_HTTP_Method method,                                                uint_fast64_t upload_size) {
    if (method == MHD_HTTP_METHOD_POST)
        return MHD_action_parse_post(
            req,
            4 * 1024, // small buffer for regular fields
            0,        // stream everything including files
            MHD_HTTP_POST_ENCODING_OTHER, &post_data_reader, NULL, &post_done,
            NULL);

    return MHD_action_from_response(
        req, MHD_response_from_buffer_static(MHD_HTTP_STATUS_METHOD_NOT_ALLOWED,
                                             0, ""));
}

int main(void) {
    struct MHD_Daemon *d;
    static const struct MHD_DaemonOptionAndValue bind_opt =
        MHD_D_OPTION_BIND_PORT(MHD_AF_AUTO, 8080);

    d = MHD_daemon_create(&handle_request, NULL);
    if (MHD_SC_OK != MHD_DAEMON_SET_OPTIONS(
                         d, MHD_D_OPTION_BIND_PORT(MHD_AF_AUTO, 8080),
                         MHD_D_OPTION_WM_WORKER_THREADS(4),
                         MHD_D_OPTION_LARGE_POOL_SIZE(16 * 1024 * 1024))) {
        fprintf(stderr, "Failed to set options\n");
        MHD_daemon_destroy(d);
        return 1;
    }
    MHD_daemon_start(d);
    printf("Listening on :8080\n");
    (void)getchar();
    MHD_daemon_destroy(d);
    return 0;
}

*Buil**d:
*gcc -o mhd_test mhd_test.c \
-I.../libmicrohttpd2/src/include \
.../libmicrohttpd2/src/mhd2/.libs/libmicrohttpd2.a

*Reproduce:*
curl -X POST http://localhost:8080/ -F "file=@any_large_file.png"

*Output showing the bug:*
f=IMG_7717.PNG off=616227 size=18446744073709551518 final=0
f=IMG_7717.PNG off=616129 size=3999 final=0 ← offset regressed by 98 bytes

The offset regression equals exactly |2^64 - size|, suggesting a signed underflow in the chunk size calculation at certain multipart boundary alignments. The bug is deterministic and reproducible across multiple uploads of the same file.

------------------------------------------------------------------------



Reply via email to