On 7. 7. 25 11:08, Branko Čibej wrote:
As you've probably noticed, I've been going through compilation warnings, especially implicit narrowing conversions, and trying to fix them in a sane way. Many of them, by the way, I don't see with gcc because it doesn't have a -Wshorten-64-to-32 flag, so I'm using clang. This time I found a gem:


   .../protocols/http2_stream.c:162:48: warning: implicit conversion loses integer precision:          'apr_size_t' (aka 'unsigned long') to 'apr_uint32_t' (aka 'unsigned int') [-Wshorten-64-to-32]
      146 | max_payload_size,
          | ^~~~~~~~~~~~~~~~


This is in a call to serf__bucket_http2_frame_create(), which expects max_payload_size as an apr_uint32_t.


But then it goes on to allocate a serf_http2_frame_context_t (see: http2_frame_buckets.h line 603) which has a member max_payload_size that is an apr_size_t. And if that's not funny enough, here's how the struct initialisation actually happens:


   serf__bucket_http2_frame_create(serf_bucket_t *stream,
                                    unsigned char frame_type,
                                    unsigned char flags,
                                    apr_int32_t *stream_id,
                                    void(*stream_id_alloc)(
                                        void *baton,
                                        apr_int32_t *stream_id),
                                    void *stream_id_baton,
                                    apr_uint32_t max_payload_size,
                                    serf_bucket_alloc_t *alloc)
   {
        serf_http2_frame_context_t *ctx = serf_bucket_mem_alloc(alloc,
sizeof(*ctx));

        ctx->alloc = alloc;
        ctx->stream = stream;
        ctx->chunk = serf_bucket_aggregate_create(alloc);
        ctx->max_payload_size = max_payload_size;
        ctx->frametype = frame_type;
        ctx->flags = flags;

        if (max_payload_size > 0xFFFFFF)
            max_payload_size = 0xFFFFFF;
   ...



From this point onward, max_payload_size (the function argument, an apr_uint32_t) is not used. Um. The size adjustment is a no-op?


So to silence the warning, it would be enough to change the type of the function argument. But this bit of code is actually nonsense. Should the max size be limited to 16 MiB or not? If yes, and it isn't, how does the HTTP/2 code even work correctly? Or maybe we just haven't encountered a case where it breaks?


I don't know anything about HTTP/2 framing. RFC 9113/4.2 says that 16 MiB is the upper limit. My gut feeling is to move the size adjustment before 'ctx' initialisation, and to change the type of the parameter -- the latter because Serf operates with apr_size_t all the time.


Specifically, this silences the warning and all tests still pass, including a checkout with Subversion over https (though I've no idea how to verify if that actually uses HTTP/2; any pointers would be welcome).


Index: buckets/http2_frame_buckets.c
===================================================================
--- buckets/http2_frame_buckets.c       (revision 1927021)
+++ buckets/http2_frame_buckets.c       (working copy)
@@ -630,12 +630,17 @@
                                     void *baton,
                                     apr_int32_t *stream_id),
                                 void *stream_id_baton,
-                                apr_uint32_t max_payload_size,
+                                apr_size_t max_payload_size,
                                 serf_bucket_alloc_t *alloc)
 {
     serf_http2_frame_context_t *ctx = serf_bucket_mem_alloc(alloc,
                                                             sizeof(*ctx));
+ /* The upper limit for HTTP/2 MAX_FRAME_SIZE is 16 M1B.
+https://www.rfc-editor.org/rfc/rfc9113.html#section-4.2  */
+    if (max_payload_size > 0xFFFFFF)
+        max_payload_size = 0xFFFFFF;
+
     ctx->alloc = alloc;
     ctx->stream = stream;
     ctx->chunk = serf_bucket_aggregate_create(alloc);
@@ -643,9 +648,6 @@
     ctx->frametype = frame_type;
     ctx->flags = flags;
- if (max_payload_size > 0xFFFFFF)
-        max_payload_size = 0xFFFFFF;
-
     if (!stream_id_alloc || (stream_id && *stream_id >= 0))
     {
       /* Avoid all alloc handling; we know the final id */
@@ -980,4 +982,3 @@
     serf_http2_frame_get_remaining,
     serf_http2_frame_set_config
 };
-
Index: protocols/http2_buckets.h
===================================================================
--- protocols/http2_buckets.h   (revision 1927021)
+++ protocols/http2_buckets.h   (working copy)
@@ -202,7 +202,7 @@
                                       void *baton,
                                       apr_int32_t *stream_id),
                                 void *stream_id_baton,
-                                apr_uint32_t max_payload_size,
+                                apr_size_t max_payload_size,
                                 serf_bucket_alloc_t *alloc);
/* ==================================================================== */


Index: buckets/http2_frame_buckets.c
===================================================================
--- buckets/http2_frame_buckets.c       (revision 1927021)
+++ buckets/http2_frame_buckets.c       (working copy)
@@ -630,12 +630,17 @@
                                     void *baton,
                                     apr_int32_t *stream_id),
                                 void *stream_id_baton,
-                                apr_uint32_t max_payload_size,
+                                apr_size_t max_payload_size,
                                 serf_bucket_alloc_t *alloc)
 {
     serf_http2_frame_context_t *ctx = serf_bucket_mem_alloc(alloc,
                                                             sizeof(*ctx));
 
+    /* The upper limit for HTTP/2 MAX_FRAME_SIZE is 16 M1B.
+      https://www.rfc-editor.org/rfc/rfc9113.html#section-4.2 */
+    if (max_payload_size > 0xFFFFFF)
+        max_payload_size = 0xFFFFFF;
+
     ctx->alloc = alloc;
     ctx->stream = stream;
     ctx->chunk = serf_bucket_aggregate_create(alloc);
@@ -643,9 +648,6 @@
     ctx->frametype = frame_type;
     ctx->flags = flags;
 
-    if (max_payload_size > 0xFFFFFF)
-        max_payload_size = 0xFFFFFF;
-
     if (!stream_id_alloc || (stream_id && *stream_id >= 0))
     {
       /* Avoid all alloc handling; we know the final id */
@@ -980,4 +982,3 @@
     serf_http2_frame_get_remaining,
     serf_http2_frame_set_config
 };
-
Index: protocols/http2_buckets.h
===================================================================
--- protocols/http2_buckets.h   (revision 1927021)
+++ protocols/http2_buckets.h   (working copy)
@@ -202,7 +202,7 @@
                                       void *baton,
                                       apr_int32_t *stream_id),
                                 void *stream_id_baton,
-                                apr_uint32_t max_payload_size,
+                                apr_size_t max_payload_size,
                                 serf_bucket_alloc_t *alloc);
 
 /* ==================================================================== */

Reply via email to