{"thread":{"id":"64178","subject":"[PATCH 0/3] Fix curl_easy_setopt() parameter type problem, again","startedAt":"2025-09-21T12:22:41Z","lastAt":"2025-09-26T17:40:43Z","messageCount":12,"participants":["Johannes Schindelin via GitGitGadget","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"526887","messageId":"pull.1974.git.1758457356.gitgitgadget@gmail.com","threadId":"64178","inReplyTo":null,"subject":"[PATCH 0/3] Fix curl_easy_setopt() parameter type problem, again","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-09-21T12:22:33Z","receivedAt":"2025-09-21T12:22:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"As of last week, every CI build of Git for Windows' ARM64 flavor of its SDK\nstarted failing (the first failed build is this here:\nhttps://github.com/git-for-windows/git-sdk-arm64/actions/runs/17633130672/job/50104373185).\n\nThe reason is that we still have one curl_easy_setopt() call that is\nsupposed to pass a long parameter but doesn't.\n\nThe likely explanation is an update to libcurl in the Git for Windows/ARM64\nSDK. A strange thing about this: GCC does not catch the problem, but clang\ndoes. And even more strangely, the relevant parts of cURL's typecheck-gcc.h\nhaven't changed in a way that explains to me why this starts to trigger now.\n\nTo prevent more piecemeal solutions, I vetted all calls of\ncurl_easy_setopt() and satisified myself that all remaining calls that want\nlong parameters do indeed have arguments matching that type.\n\nAs is the custom in the Git project, I use this opportunity to do a bit more\nthan is strictly necessary to address this problem. I replace the affected\ncall with one that expects a wider data type, refactor an already-existing\nfunction to cast to said data type, and use it in the modified call as well\nas in another call which wants to perform the same cast but did so unsafely\n(not that it mattered in practice, really, yet it is in line with other\nrefactors the Git project has seen).\n\nNote for the curious: The affected call used CURLOPT_INFILESIZE\n[https://curl.se/libcurl/c/CURLOPT_INFILESIZE.html] and now uses\nCURLOPT_INFILESIZE_LARGE\n[https://curl.se/libcurl/c/CURLOPT_INFILESIZE_LARGE.html], and it is a bit\nstrange that the latter wasn't used in the first place, given that it was\nintroduced into cURL over a year before Git itself was born, and almost two\nyears before the call was introduced in 58e60dd2033 (Add support for pushing\nto a remote repository using HTTP/DAV, 2005-11-02).\n\nFor the record, these patches apply cleanly all the way back to v2.22,\naccording to git replay. I did not try to test whether it builds, though,\nbecause all kinds of stunts are required nowadays to build this old versions\neven without any patches on top.\n\nJohannes Schindelin (3):\n  http: offer to cast `size_t` to `curl_off_t` safely\n  imap-send: be more careful when casting to `curl_off_t`\n  http-push: avoid new compile error\n\n http-push.c   |  3 ++-\n http.h        | 10 ++++++++++\n imap-send.c   |  2 +-\n remote-curl.c | 14 +++-----------\n 4 files changed, 16 insertions(+), 13 deletions(-)\n\n\nbase-commit: ca2559c1d630eb4f04cdee2328aaf1c768907a9e\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1974%2Fdscho%2Fcurl-easy-setopt-typefix-again-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1974/dscho/curl-easy-setopt-typefix-again-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/1974\n-- \ngitgitgadget\n"},{"id":"526888","messageId":"7caaec91020687f09764bbd50477c3fe889fcfed.1758457356.git.gitgitgadget@gmail.com","threadId":"64178","inReplyTo":"pull.1974.git.1758457356.gitgitgadget@gmail.com","subject":"[PATCH 1/3] http: offer to cast `size_t` to `curl_off_t` safely","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-09-21T12:22:34Z","receivedAt":"2025-09-21T12:22:42Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThis commit moves the `xcurl_off_t()` function, which validates that a\ngiven value fits within the `curl_off_t` data type and then casts it, to\na more central place so that it can be used outside of `remote-curl.c`,\ntoo.\n\nAt the same time, this function is renamed to conform better with the\nnaming convention of the helper functions that safely cast from one data\ntype to another which has been well established in `git-compat-util.h`.\n\nWith this move, the error message can unfortunately no longer be renamed\nbecause the `_(...)` function is not available at the time of\ndefinition.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n http.h        | 10 ++++++++++\n remote-curl.c | 14 +++-----------\n 2 files changed, 13 insertions(+), 11 deletions(-)\n\ndiff --git a/http.h b/http.h\nindex 36202139f4..0a36dbd294 100644\n--- a/http.h\n+++ b/http.h\n@@ -8,6 +8,7 @@ struct packed_git;\n #include <curl/curl.h>\n #include <curl/easy.h>\n \n+#include \"gettext.h\"\n #include \"strbuf.h\"\n #include \"remote.h\"\n \n@@ -95,6 +96,15 @@ static inline int missing__target(int code, int result)\n \n #define missing_target(a) missing__target((a)->http_code, (a)->curl_result)\n \n+static inline curl_off_t cast_size_t_to_curl_off_t(size_t a)\n+{\n+\tuintmax_t size = a;\n+\tif (size > maximum_signed_value_of_type(curl_off_t))\n+\t\tdie(_(\"number too large to represent as curl_off_t \"\n+\t\t      \"on this platform: %\"PRIuMAX), (uintmax_t)a);\n+\treturn (curl_off_t)a;\n+}\n+\n /*\n  * Normalize curl results to handle CURL_FAILONERROR (or lack thereof). Failing\n  * http codes have their \"result\" converted to CURLE_HTTP_RETURNED_ERROR, and\ndiff --git a/remote-curl.c b/remote-curl.c\nindex 84f4694780..69f919454a 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -894,14 +894,6 @@ static int probe_rpc(struct rpc_state *rpc, struct slot_results *results)\n \treturn err;\n }\n \n-static curl_off_t xcurl_off_t(size_t len)\n-{\n-\tuintmax_t size = len;\n-\tif (size > maximum_signed_value_of_type(curl_off_t))\n-\t\tdie(_(\"cannot handle pushes this big\"));\n-\treturn (curl_off_t)size;\n-}\n-\n /*\n  * If flush_received is true, do not attempt to read any more; just use what's\n  * in rpc->buf.\n@@ -999,7 +991,7 @@ retry:\n \t\t * and we just need to send it.\n \t\t */\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, gzip_body);\n-\t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE_LARGE, xcurl_off_t(gzip_size));\n+\t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE_LARGE, cast_size_t_to_curl_off_t(gzip_size));\n \n \t} else if (use_gzip && 1024 < rpc->len) {\n \t\t/* The client backend isn't giving us compressed data so\n@@ -1030,7 +1022,7 @@ retry:\n \n \t\theaders = curl_slist_append(headers, \"Content-Encoding: gzip\");\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, gzip_body);\n-\t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE_LARGE, xcurl_off_t(gzip_size));\n+\t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE_LARGE, cast_size_t_to_curl_off_t(gzip_size));\n \n \t\tif (options.verbosity > 1) {\n \t\t\tfprintf(stderr, \"POST %s (gzip %lu to %lu bytes)\\n\",\n@@ -1043,7 +1035,7 @@ retry:\n \t\t * more normal Content-Length approach.\n \t\t */\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, rpc->buf);\n-\t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE_LARGE, xcurl_off_t(rpc->len));\n+\t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE_LARGE, cast_size_t_to_curl_off_t(rpc->len));\n \t\tif (options.verbosity > 1) {\n \t\t\tfprintf(stderr, \"POST %s (%lu bytes)\\n\",\n \t\t\t\trpc->service_name, (unsigned long)rpc->len);\n-- \ngitgitgadget\n\n"},{"id":"526889","messageId":"e1d5a85f70c514749304fe87efde271e9ed5a92c.1758457356.git.gitgitgadget@gmail.com","threadId":"64178","inReplyTo":"pull.1974.git.1758457356.gitgitgadget@gmail.com","subject":"[PATCH 2/3] imap-send: be more careful when casting to `curl_off_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-09-21T12:22:35Z","receivedAt":"2025-09-21T12:22:44Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWhen casting a `size_t` to `curl_off_t`, there is a currently uncommon\nchance that the value can be cut off (`curl_off_t` is supposed to be\nguaranteed to be 64-bit).\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n imap-send.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/imap-send.c b/imap-send.c\nindex 4bd5b8aa0d..26dda7f328 100644\n--- a/imap-send.c\n+++ b/imap-send.c\n@@ -1721,7 +1721,7 @@ static int curl_append_msgs_to_imap(struct imap_server_conf *server,\n \t\tlf_to_crlf(&msgbuf.buf);\n \n \t\tcurl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,\n-\t\t\t\t (curl_off_t)(msgbuf.buf.len-prev_len));\n+\t\t\t\t cast_size_t_to_curl_off_t(msgbuf.buf.len-prev_len));\n \n \t\tres = curl_easy_perform(curl);\n \n-- \ngitgitgadget\n\n"},{"id":"526890","messageId":"bcb231125c95ff809c618eedab71375b94e6c69e.1758457356.git.gitgitgadget@gmail.com","threadId":"64178","inReplyTo":"pull.1974.git.1758457356.gitgitgadget@gmail.com","subject":"[PATCH 3/3] http-push: avoid new compile error","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-09-21T12:22:36Z","receivedAt":"2025-09-21T12:22:46Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWith the recent update in Git for Windows/ARM64 as of\nhttps://github.com/git-for-windows/git-sdk-arm64/commit/21b288e16358\ncURL was updated from v8.15.0 to v8.16.0, and the LLVM-based builds (but\nstrangely not the GCC-based builds) continuously greet me thusly:\n\n  http-push.c:211:2: error: call to '_curl_easy_setopt_err_long' declared\n  with 'warning' attribute: curl_easy_setopt expects a long argument\n  [-Werror,-Wattribute-warning]\n      CC builtin/apply.o\n    211 |         curl_easy_setopt(curl, CURLOPT_INFILESIZE, buffer->buf.len);\n        |         ^\n  C:/a/git-sdk-arm64/git-sdk-arm64/minimal-sdk/clangarm64/include/curl/typecheck-gcc.h:50:15:\n  note: expanded from macro 'curl_easy_setopt'\n     50 |               _curl_easy_setopt_err_long();                             \\\n        |               ^\n  1 error generated.\n  make: *** [Makefile:2877: http-push.o] Error 1\n\nThe easiest way to shut up that compile error (which is legitimate,\nseeing as the `CURLOPT_INFILESIZE` options expects a `long` parameter,\nbut `buffer->buf.len` refers to the `size_t` attribute of a `strbuf`)\nwould be to simply cast the parameter to a `long`.\n\nHowever, there is a much better solution: To use the\n`CURLOPT_INFILESIZE_LARGE` option instead, which was added in cURL\nv7.11.0 (see https://curl.se/ch/7.11.0.html) and which Git _already_\nuses in `curl_append_msgs_to_imap()`.\n\nThis fix was the motivation for renaming `xcurl_off_t()` to\n`cast_size_t_to_curl_off_t()` and making it available more broadly,\nwhich is the reason why it is used here, too.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n http-push.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex 91a5465afb..7a9b96a6d0 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -208,7 +208,8 @@ static void curl_setup_http(CURL *curl, const char *url,\n \tcurl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);\n \tcurl_easy_setopt(curl, CURLOPT_URL, url);\n \tcurl_easy_setopt(curl, CURLOPT_INFILE, buffer);\n-\tcurl_easy_setopt(curl, CURLOPT_INFILESIZE, buffer->buf.len);\n+\tcurl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,\n+\t\t\t cast_size_t_to_curl_off_t(buffer->buf.len));\n \tcurl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);\n \tcurl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, seek_buffer);\n \tcurl_easy_setopt(curl, CURLOPT_SEEKDATA, buffer);\n-- \ngitgitgadget\n"},{"id":"526896","messageId":"xmqqfrcfx3g9.fsf@gitster.g","threadId":"64178","inReplyTo":"7caaec91020687f09764bbd50477c3fe889fcfed.1758457356.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 1/3] http: offer to cast `size_t` to `curl_off_t` safely","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-09-21T14:52:54Z","receivedAt":"2025-09-21T14:52:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> This commit moves the `xcurl_off_t()` function, which validates that a\n> given value fits within the `curl_off_t` data type and then casts it, to\n> a more central place so that it can be used outside of `remote-curl.c`,\n> too.\n>\n> At the same time, this function is renamed to conform better with the\n> naming convention of the helper functions that safely cast from one data\n> type to another which has been well established in `git-compat-util.h`.\n\nOK.  The code inside the renamed function is the same with an\nupdated message to show the value.\n\n> With this move, the error message can unfortunately no longer be renamed\n> because the `_(...)` function is not available at the time of\n> definition.\n\nIt is not clear to me what change (or lack thereof?) in this patch\nthis paragraph refers to.  Who wants to rename what error message\nand why?\n\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  http.h        | 10 ++++++++++\n>  remote-curl.c | 14 +++-----------\n>  2 files changed, 13 insertions(+), 11 deletions(-)\n\nThanks; will queue.\n\n> +static inline curl_off_t cast_size_t_to_curl_off_t(size_t a)\n> +{\n> +\tuintmax_t size = a;\n> +\tif (size > maximum_signed_value_of_type(curl_off_t))\n> +\t\tdie(_(\"number too large to represent as curl_off_t \"\n> +\t\t      \"on this platform: %\"PRIuMAX), (uintmax_t)a);\n> +\treturn (curl_off_t)a;\n> +}\n> +\n> -static curl_off_t xcurl_off_t(size_t len)\n> -{\n> -\tuintmax_t size = len;\n> -\tif (size > maximum_signed_value_of_type(curl_off_t))\n> -\t\tdie(_(\"cannot handle pushes this big\"));\n> -\treturn (curl_off_t)size;\n> -}\n\n"},{"id":"526897","messageId":"xmqqbjn3x2u5.fsf@gitster.g","threadId":"64178","inReplyTo":"e1d5a85f70c514749304fe87efde271e9ed5a92c.1758457356.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 2/3] imap-send: be more careful when casting to `curl_off_t`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-09-21T15:06:10Z","receivedAt":"2025-09-21T15:06:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> When casting a `size_t` to `curl_off_t`, there is a currently uncommon\n> chance that the value can be cut off (`curl_off_t` is supposed to be\n> guaranteed to be 64-bit).\n\n\"64-bit\" -> \"signed 64-bit\", per what <curl/system.h> says,\ni.e. \"curl_off_t MUST be typedef'ed to a 64-bit * wide signed\nintegral data type.\", perhaps?\n\nmsgbuf.buf is a strbuf, so its .len member is of size_t (so is\nprev_len); prev_len is how big the msgbuf.buf was before the code\nadded some stuff taken from all_msgs, possibly wrapping the result\nin html, and converting lf to crlf, all only enlarging the buffer.\nWe are computing how much we bloated the msgbuf.buf relative to the\noriginal here, so this subtraction should not suffer unsigned\nwraparound.  Now thanks to the previous step, we can consistently\nand safely cast size_t values to curl_off_t easily, which is nice.\n\nLooking good.  Will queue.  Thanks.\n\n> diff --git a/imap-send.c b/imap-send.c\n> index 4bd5b8aa0d..26dda7f328 100644\n> --- a/imap-send.c\n> +++ b/imap-send.c\n> @@ -1721,7 +1721,7 @@ static int curl_append_msgs_to_imap(struct imap_server_conf *server,\n>  \t\tlf_to_crlf(&msgbuf.buf);\n>  \n>  \t\tcurl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,\n> -\t\t\t\t (curl_off_t)(msgbuf.buf.len-prev_len));\n> +\t\t\t\t cast_size_t_to_curl_off_t(msgbuf.buf.len-prev_len));\n>  \n>  \t\tres = curl_easy_perform(curl);\n"},{"id":"526899","messageId":"xmqq7bxrx2nx.fsf@gitster.g","threadId":"64178","inReplyTo":"bcb231125c95ff809c618eedab71375b94e6c69e.1758457356.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 3/3] http-push: avoid new compile error","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-09-21T15:09:54Z","receivedAt":"2025-09-21T15:09:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> However, there is a much better solution: To use the\n> `CURLOPT_INFILESIZE_LARGE` option instead, which was added in cURL\n> v7.11.0 (see https://curl.se/ch/7.11.0.html) and which Git _already_\n> uses in `curl_append_msgs_to_imap()`.\n>\n> This fix was the motivation for renaming `xcurl_off_t()` to\n> `cast_size_t_to_curl_off_t()` and making it available more broadly,\n> which is the reason why it is used here, too.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  http-push.c | 3 ++-\n>  1 file changed, 2 insertions(+), 1 deletion(-)\n\nAs we saw in [1/3], we have been using \"size large\" for posting in\nremote-curl.c and this brings how the size for reading the data is\nhandled to match that.\n\nLooking good.  \n\nWill queue.  Thanks.\n\n\n\n> diff --git a/http-push.c b/http-push.c\n> index 91a5465afb..7a9b96a6d0 100644\n> --- a/http-push.c\n> +++ b/http-push.c\n> @@ -208,7 +208,8 @@ static void curl_setup_http(CURL *curl, const char *url,\n>  \tcurl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);\n>  \tcurl_easy_setopt(curl, CURLOPT_URL, url);\n>  \tcurl_easy_setopt(curl, CURLOPT_INFILE, buffer);\n> -\tcurl_easy_setopt(curl, CURLOPT_INFILESIZE, buffer->buf.len);\n> +\tcurl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,\n> +\t\t\t cast_size_t_to_curl_off_t(buffer->buf.len));\n>  \tcurl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);\n>  \tcurl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, seek_buffer);\n>  \tcurl_easy_setopt(curl, CURLOPT_SEEKDATA, buffer);\n"},{"id":"527412","messageId":"pull.1974.v2.git.1758882772.gitgitgadget@gmail.com","threadId":"64178","inReplyTo":"pull.1974.git.1758457356.gitgitgadget@gmail.com","subject":"[PATCH v2 0/3] Fix curl_easy_setopt() parameter type problem, again","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-09-26T10:32:49Z","receivedAt":"2025-09-26T10:32:55Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"As of last week, every CI build of Git for Windows' ARM64 flavor of its SDK\nstarted failing (the first failed build is this here:\nhttps://github.com/git-for-windows/git-sdk-arm64/actions/runs/17633130672/job/50104373185).\n\nThe reason is that we still have one curl_easy_setopt() call that is\nsupposed to pass a long parameter but doesn't.\n\nThe likely explanation is an update to libcurl in the Git for Windows/ARM64\nSDK. A strange thing about this: GCC does not catch the problem, but clang\ndoes. And even more strangely, the relevant parts of cURL's typecheck-gcc.h\nhaven't changed in a way that explains to me why this starts to trigger now.\n\nTo prevent more piecemeal solutions, I vetted all calls of\ncurl_easy_setopt() and satisified myself that all remaining calls that want\nlong parameters do indeed have arguments matching that type.\n\nAs is the custom in the Git project, I use this opportunity to do a bit more\nthan is strictly necessary to address this problem. I replace the affected\ncall with one that expects a wider data type, refactor an already-existing\nfunction to cast to said data type, and use it in the modified call as well\nas in another call which wants to perform the same cast but did so unsafely\n(not that it mattered in practice, really, yet it is in line with other\nrefactors the Git project has seen).\n\nNote for the curious: The affected call used CURLOPT_INFILESIZE\n[https://curl.se/libcurl/c/CURLOPT_INFILESIZE.html] and now uses\nCURLOPT_INFILESIZE_LARGE\n[https://curl.se/libcurl/c/CURLOPT_INFILESIZE_LARGE.html], and it is a bit\nstrange that the latter wasn't used in the first place, given that it was\nintroduced into cURL over a year before Git itself was born, and almost two\nyears before the call was introduced in 58e60dd2033 (Add support for pushing\nto a remote repository using HTTP/DAV, 2005-11-02).\n\nFor the record, these patches apply cleanly all the way back to v2.22,\naccording to git replay. I did not try to test whether it builds, though,\nbecause all kinds of stunts are required nowadays to build this old versions\neven without any patches on top.\n\nChanges since v1:\n\n * The commit messages now reflect Junio's suggested edits.\n\nJohannes Schindelin (3):\n  http: offer to cast `size_t` to `curl_off_t` safely\n  imap-send: be more careful when casting to `curl_off_t`\n  http-push: avoid new compile error\n\n http-push.c   |  3 ++-\n http.h        | 10 ++++++++++\n imap-send.c   |  2 +-\n remote-curl.c | 14 +++-----------\n 4 files changed, 16 insertions(+), 13 deletions(-)\n\n\nbase-commit: ca2559c1d630eb4f04cdee2328aaf1c768907a9e\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1974%2Fdscho%2Fcurl-easy-setopt-typefix-again-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1974/dscho/curl-easy-setopt-typefix-again-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/1974\n\nRange-diff vs v1:\n\n 1:  7caaec9102 ! 1:  114eb9c8ec http: offer to cast `size_t` to `curl_off_t` safely\n     @@ Commit message\n          naming convention of the helper functions that safely cast from one data\n          type to another which has been well established in `git-compat-util.h`.\n      \n     -    With this move, the error message can unfortunately no longer be renamed\n     -    because the `_(...)` function is not available at the time of\n     -    definition.\n     +    With this move, `gettext.h` must be `#include`d in `http.h` to allow the\n     +    error message to remain translatable.\n      \n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n 2:  e1d5a85f70 ! 2:  fdd1327e7b imap-send: be more careful when casting to `curl_off_t`\n     @@ Commit message\n          imap-send: be more careful when casting to `curl_off_t`\n      \n          When casting a `size_t` to `curl_off_t`, there is a currently uncommon\n     -    chance that the value can be cut off (`curl_off_t` is supposed to be\n     -    guaranteed to be 64-bit).\n     +    chance that the value can be cut off (`curl_off_t` is expected to be a\n     +    signed 64-bit data type).\n      \n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n 3:  bcb231125c = 3:  140755673d http-push: avoid new compile error\n\n-- \ngitgitgadget\n"},{"id":"527413","messageId":"114eb9c8ecfbc5be33edf697ffc05fed6444beb7.1758882772.git.gitgitgadget@gmail.com","threadId":"64178","inReplyTo":"pull.1974.v2.git.1758882772.gitgitgadget@gmail.com","subject":"[PATCH v2 1/3] http: offer to cast `size_t` to `curl_off_t` safely","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-09-26T10:32:50Z","receivedAt":"2025-09-26T10:32:57Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThis commit moves the `xcurl_off_t()` function, which validates that a\ngiven value fits within the `curl_off_t` data type and then casts it, to\na more central place so that it can be used outside of `remote-curl.c`,\ntoo.\n\nAt the same time, this function is renamed to conform better with the\nnaming convention of the helper functions that safely cast from one data\ntype to another which has been well established in `git-compat-util.h`.\n\nWith this move, `gettext.h` must be `#include`d in `http.h` to allow the\nerror message to remain translatable.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n http.h        | 10 ++++++++++\n remote-curl.c | 14 +++-----------\n 2 files changed, 13 insertions(+), 11 deletions(-)\n\ndiff --git a/http.h b/http.h\nindex 36202139f4..0a36dbd294 100644\n--- a/http.h\n+++ b/http.h\n@@ -8,6 +8,7 @@ struct packed_git;\n #include <curl/curl.h>\n #include <curl/easy.h>\n \n+#include \"gettext.h\"\n #include \"strbuf.h\"\n #include \"remote.h\"\n \n@@ -95,6 +96,15 @@ static inline int missing__target(int code, int result)\n \n #define missing_target(a) missing__target((a)->http_code, (a)->curl_result)\n \n+static inline curl_off_t cast_size_t_to_curl_off_t(size_t a)\n+{\n+\tuintmax_t size = a;\n+\tif (size > maximum_signed_value_of_type(curl_off_t))\n+\t\tdie(_(\"number too large to represent as curl_off_t \"\n+\t\t      \"on this platform: %\"PRIuMAX), (uintmax_t)a);\n+\treturn (curl_off_t)a;\n+}\n+\n /*\n  * Normalize curl results to handle CURL_FAILONERROR (or lack thereof). Failing\n  * http codes have their \"result\" converted to CURLE_HTTP_RETURNED_ERROR, and\ndiff --git a/remote-curl.c b/remote-curl.c\nindex 84f4694780..69f919454a 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -894,14 +894,6 @@ static int probe_rpc(struct rpc_state *rpc, struct slot_results *results)\n \treturn err;\n }\n \n-static curl_off_t xcurl_off_t(size_t len)\n-{\n-\tuintmax_t size = len;\n-\tif (size > maximum_signed_value_of_type(curl_off_t))\n-\t\tdie(_(\"cannot handle pushes this big\"));\n-\treturn (curl_off_t)size;\n-}\n-\n /*\n  * If flush_received is true, do not attempt to read any more; just use what's\n  * in rpc->buf.\n@@ -999,7 +991,7 @@ retry:\n \t\t * and we just need to send it.\n \t\t */\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, gzip_body);\n-\t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE_LARGE, xcurl_off_t(gzip_size));\n+\t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE_LARGE, cast_size_t_to_curl_off_t(gzip_size));\n \n \t} else if (use_gzip && 1024 < rpc->len) {\n \t\t/* The client backend isn't giving us compressed data so\n@@ -1030,7 +1022,7 @@ retry:\n \n \t\theaders = curl_slist_append(headers, \"Content-Encoding: gzip\");\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, gzip_body);\n-\t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE_LARGE, xcurl_off_t(gzip_size));\n+\t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE_LARGE, cast_size_t_to_curl_off_t(gzip_size));\n \n \t\tif (options.verbosity > 1) {\n \t\t\tfprintf(stderr, \"POST %s (gzip %lu to %lu bytes)\\n\",\n@@ -1043,7 +1035,7 @@ retry:\n \t\t * more normal Content-Length approach.\n \t\t */\n \t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, rpc->buf);\n-\t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE_LARGE, xcurl_off_t(rpc->len));\n+\t\tcurl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE_LARGE, cast_size_t_to_curl_off_t(rpc->len));\n \t\tif (options.verbosity > 1) {\n \t\t\tfprintf(stderr, \"POST %s (%lu bytes)\\n\",\n \t\t\t\trpc->service_name, (unsigned long)rpc->len);\n-- \ngitgitgadget\n\n"},{"id":"527414","messageId":"fdd1327e7bbc0f42c11c354346859437eb29448b.1758882772.git.gitgitgadget@gmail.com","threadId":"64178","inReplyTo":"pull.1974.v2.git.1758882772.gitgitgadget@gmail.com","subject":"[PATCH v2 2/3] imap-send: be more careful when casting to `curl_off_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-09-26T10:32:51Z","receivedAt":"2025-09-26T10:32:58Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWhen casting a `size_t` to `curl_off_t`, there is a currently uncommon\nchance that the value can be cut off (`curl_off_t` is expected to be a\nsigned 64-bit data type).\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n imap-send.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/imap-send.c b/imap-send.c\nindex 4bd5b8aa0d..26dda7f328 100644\n--- a/imap-send.c\n+++ b/imap-send.c\n@@ -1721,7 +1721,7 @@ static int curl_append_msgs_to_imap(struct imap_server_conf *server,\n \t\tlf_to_crlf(&msgbuf.buf);\n \n \t\tcurl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,\n-\t\t\t\t (curl_off_t)(msgbuf.buf.len-prev_len));\n+\t\t\t\t cast_size_t_to_curl_off_t(msgbuf.buf.len-prev_len));\n \n \t\tres = curl_easy_perform(curl);\n \n-- \ngitgitgadget\n\n"},{"id":"527415","messageId":"140755673d7a5ab211e3e25dd741e705410036cb.1758882772.git.gitgitgadget@gmail.com","threadId":"64178","inReplyTo":"pull.1974.v2.git.1758882772.gitgitgadget@gmail.com","subject":"[PATCH v2 3/3] http-push: avoid new compile error","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-09-26T10:32:52Z","receivedAt":"2025-09-26T10:33:00Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWith the recent update in Git for Windows/ARM64 as of\nhttps://github.com/git-for-windows/git-sdk-arm64/commit/21b288e16358\ncURL was updated from v8.15.0 to v8.16.0, and the LLVM-based builds (but\nstrangely not the GCC-based builds) continuously greet me thusly:\n\n  http-push.c:211:2: error: call to '_curl_easy_setopt_err_long' declared\n  with 'warning' attribute: curl_easy_setopt expects a long argument\n  [-Werror,-Wattribute-warning]\n      CC builtin/apply.o\n    211 |         curl_easy_setopt(curl, CURLOPT_INFILESIZE, buffer->buf.len);\n        |         ^\n  C:/a/git-sdk-arm64/git-sdk-arm64/minimal-sdk/clangarm64/include/curl/typecheck-gcc.h:50:15:\n  note: expanded from macro 'curl_easy_setopt'\n     50 |               _curl_easy_setopt_err_long();                             \\\n        |               ^\n  1 error generated.\n  make: *** [Makefile:2877: http-push.o] Error 1\n\nThe easiest way to shut up that compile error (which is legitimate,\nseeing as the `CURLOPT_INFILESIZE` options expects a `long` parameter,\nbut `buffer->buf.len` refers to the `size_t` attribute of a `strbuf`)\nwould be to simply cast the parameter to a `long`.\n\nHowever, there is a much better solution: To use the\n`CURLOPT_INFILESIZE_LARGE` option instead, which was added in cURL\nv7.11.0 (see https://curl.se/ch/7.11.0.html) and which Git _already_\nuses in `curl_append_msgs_to_imap()`.\n\nThis fix was the motivation for renaming `xcurl_off_t()` to\n`cast_size_t_to_curl_off_t()` and making it available more broadly,\nwhich is the reason why it is used here, too.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n http-push.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex 91a5465afb..7a9b96a6d0 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -208,7 +208,8 @@ static void curl_setup_http(CURL *curl, const char *url,\n \tcurl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);\n \tcurl_easy_setopt(curl, CURLOPT_URL, url);\n \tcurl_easy_setopt(curl, CURLOPT_INFILE, buffer);\n-\tcurl_easy_setopt(curl, CURLOPT_INFILESIZE, buffer->buf.len);\n+\tcurl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,\n+\t\t\t cast_size_t_to_curl_off_t(buffer->buf.len));\n \tcurl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);\n \tcurl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, seek_buffer);\n \tcurl_easy_setopt(curl, CURLOPT_SEEKDATA, buffer);\n-- \ngitgitgadget\n"},{"id":"527437","messageId":"xmqqo6qxaz8n.fsf@gitster.g","threadId":"64178","inReplyTo":"pull.1974.v2.git.1758882772.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 0/3] Fix curl_easy_setopt() parameter type problem, again","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-09-26T17:40:40Z","receivedAt":"2025-09-26T17:40:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> As of last week, every CI build of Git for Windows' ARM64 flavor of its SDK\n> started failing (the first failed build is this here:\n> https://github.com/git-for-windows/git-sdk-arm64/actions/runs/17633130672/job/50104373185).\n> ..\n> For the record, these patches apply cleanly all the way back to v2.22,\n> according to git replay. I did not try to test whether it builds, though,\n> because all kinds of stunts are required nowadays to build this old versions\n> even without any patches on top.\n> Range-diff vs v1:\n>\n>  1:  7caaec9102 ! 1:  114eb9c8ec http: offer to cast `size_t` to `curl_off_t` safely\n>      @@ Commit message\n>           naming convention of the helper functions that safely cast from one data\n>           type to another which has been well established in `git-compat-util.h`.\n>       \n>      -    With this move, the error message can unfortunately no longer be renamed\n>      -    because the `_(...)` function is not available at the time of\n>      -    definition.\n>      +    With this move, `gettext.h` must be `#include`d in `http.h` to allow the\n>      +    error message to remain translatable.\n\nAhh, OK.  Now I understand that's what you meant.\n\n>  2:  e1d5a85f70 ! 2:  fdd1327e7b imap-send: be more careful when casting to `curl_off_t`\n>      @@ Commit message\n>           imap-send: be more careful when casting to `curl_off_t`\n>       \n>           When casting a `size_t` to `curl_off_t`, there is a currently uncommon\n>      -    chance that the value can be cut off (`curl_off_t` is supposed to be\n>      -    guaranteed to be 64-bit).\n>      +    chance that the value can be cut off (`curl_off_t` is expected to be a\n>      +    signed 64-bit data type).\n\nWill replace.  Let me mark the topic for 'next'.\n\nThanks.\n"}]}