]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
content_encoding: use writer struct subclasses for different encodings
authorPatrick Monnerat <patrick@monnerat.net>
Fri, 9 Sep 2022 11:25:02 +0000 (13:25 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Sun, 11 Sep 2022 12:46:52 +0000 (14:46 +0200)
The variable-sized encoding-specific storage of a struct contenc_writer
currently relies on void * alignment that may be insufficient with
regards to the specific storage fields, although having not caused any
problems yet.

In addition, gcc 11.3 issues a warning on access to fields of partially
allocated structures that can occur when the specific storage size is 0:

  content_encoding.c: In function ‘Curl_build_unencoding_stack’:
  content_encoding.c:980:21: warning: array subscript ‘struct contenc_writer[0]’ is partly outside array bounds of ‘unsigned char[16]’ [-Warray-bounds]
    980 |     writer->handler = handler;
        |     ~~~~~~~~~~~~~~~~^~~~~~~~~
  In file included from content_encoding.c:49:
  memdebug.h:115:29: note: referencing an object of size 16 allocated by ‘curl_dbg_calloc’
    115 | #define calloc(nbelem,size) curl_dbg_calloc(nbelem, size, __LINE__, __FILE__)
        |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  content_encoding.c:977:60: note: in expansion of macro ‘calloc’
    977 |   struct contenc_writer *writer = (struct contenc_writer *)calloc(1, sz);

To solve both these problems, the current commit replaces the
contenc_writer/params structure pairs by "subclasses" of struct
contenc_writer. These are structures that contain a contenc_writer at
offset 0. Proper field alignment is therefore handled by the compiler and
full structure allocation is performed, silencing the warnings.

Closes #9455

lib/content_encoding.c
lib/content_encoding.h

index 8e8f4df7c6c1ddb507d64411b852a113c10393fb..79ff8363cbd888d715f9b2775f81dd9a3b8c4e11 100644 (file)
@@ -82,8 +82,9 @@ typedef enum {
   ZLIB_INIT_GZIP             /* initialized in transparent gzip mode */
 } zlibInitState;
 
-/* Writer parameters. */
-struct zlib_params {
+/* Deflate and gzip writer. */
+struct zlib_writer {
+  struct contenc_writer super;
   zlibInitState zlib_init;   /* zlib init state */
   uInt trailerlen;           /* Remaining trailer byte count. */
   z_stream z;                /* State structure for zlib. */
@@ -135,7 +136,7 @@ exit_zlib(struct Curl_easy *data,
 }
 
 static CURLcode process_trailer(struct Curl_easy *data,
-                                struct zlib_params *zp)
+                                struct zlib_writer *zp)
 {
   z_stream *z = &zp->z;
   CURLcode result = CURLE_OK;
@@ -162,7 +163,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
                                struct contenc_writer *writer,
                                zlibInitState started)
 {
-  struct zlib_params *zp = (struct zlib_params *) &writer->params;
+  struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;         /* zlib state structure */
   uInt nread = z->avail_in;
   Bytef *orig_in = z->next_in;
@@ -265,7 +266,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
 static CURLcode deflate_init_writer(struct Curl_easy *data,
                                     struct contenc_writer *writer)
 {
-  struct zlib_params *zp = (struct zlib_params *) &writer->params;
+  struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
 
   if(!writer->downstream)
@@ -285,7 +286,7 @@ static CURLcode deflate_unencode_write(struct Curl_easy *data,
                                        struct contenc_writer *writer,
                                        const char *buf, size_t nbytes)
 {
-  struct zlib_params *zp = (struct zlib_params *) &writer->params;
+  struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
 
   /* Set the compressed input when this function is called */
@@ -302,7 +303,7 @@ static CURLcode deflate_unencode_write(struct Curl_easy *data,
 static void deflate_close_writer(struct Curl_easy *data,
                                  struct contenc_writer *writer)
 {
-  struct zlib_params *zp = (struct zlib_params *) &writer->params;
+  struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
 
   exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
@@ -314,7 +315,7 @@ static const struct content_encoding deflate_encoding = {
   deflate_init_writer,
   deflate_unencode_write,
   deflate_close_writer,
-  sizeof(struct zlib_params)
+  sizeof(struct zlib_writer)
 };
 
 
@@ -322,7 +323,7 @@ static const struct content_encoding deflate_encoding = {
 static CURLcode gzip_init_writer(struct Curl_easy *data,
                                  struct contenc_writer *writer)
 {
-  struct zlib_params *zp = (struct zlib_params *) &writer->params;
+  struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
 
   if(!writer->downstream)
@@ -439,7 +440,7 @@ static CURLcode gzip_unencode_write(struct Curl_easy *data,
                                     struct contenc_writer *writer,
                                     const char *buf, size_t nbytes)
 {
-  struct zlib_params *zp = (struct zlib_params *) &writer->params;
+  struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
 
   if(zp->zlib_init == ZLIB_INIT_GZIP) {
@@ -566,7 +567,7 @@ static CURLcode gzip_unencode_write(struct Curl_easy *data,
 static void gzip_close_writer(struct Curl_easy *data,
                               struct contenc_writer *writer)
 {
-  struct zlib_params *zp = (struct zlib_params *) &writer->params;
+  struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
 
   exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
@@ -578,15 +579,16 @@ static const struct content_encoding gzip_encoding = {
   gzip_init_writer,
   gzip_unencode_write,
   gzip_close_writer,
-  sizeof(struct zlib_params)
+  sizeof(struct zlib_writer)
 };
 
 #endif /* HAVE_LIBZ */
 
 
 #ifdef HAVE_BROTLI
-/* Writer parameters. */
-struct brotli_params {
+/* Brotli writer. */
+struct brotli_writer {
+  struct contenc_writer super;
   BrotliDecoderState *br;    /* State structure for brotli. */
 };
 
@@ -631,7 +633,7 @@ static CURLcode brotli_map_error(BrotliDecoderErrorCode be)
 static CURLcode brotli_init_writer(struct Curl_easy *data,
                                    struct contenc_writer *writer)
 {
-  struct brotli_params *bp = (struct brotli_params *) &writer->params;
+  struct brotli_writer *bp = (struct brotli_writer *) writer;
   (void) data;
 
   if(!writer->downstream)
@@ -645,7 +647,7 @@ static CURLcode brotli_unencode_write(struct Curl_easy *data,
                                       struct contenc_writer *writer,
                                       const char *buf, size_t nbytes)
 {
-  struct brotli_params *bp = (struct brotli_params *) &writer->params;
+  struct brotli_writer *bp = (struct brotli_writer *) writer;
   const uint8_t *src = (const uint8_t *) buf;
   char *decomp;
   uint8_t *dst;
@@ -692,7 +694,8 @@ static CURLcode brotli_unencode_write(struct Curl_easy *data,
 static void brotli_close_writer(struct Curl_easy *data,
                                 struct contenc_writer *writer)
 {
-  struct brotli_params *bp = (struct brotli_params *) &writer->params;
+  struct brotli_writer *bp = (struct brotli_writer *) writer;
+
   (void) data;
 
   if(bp->br) {
@@ -707,14 +710,15 @@ static const struct content_encoding brotli_encoding = {
   brotli_init_writer,
   brotli_unencode_write,
   brotli_close_writer,
-  sizeof(struct brotli_params)
+  sizeof(struct brotli_writer)
 };
 #endif
 
 
 #ifdef HAVE_ZSTD
-/* Writer parameters. */
-struct zstd_params {
+/* Zstd writer. */
+struct zstd_writer {
+  struct contenc_writer super;
   ZSTD_DStream *zds;    /* State structure for zstd. */
   void *decomp;
 };
@@ -722,7 +726,8 @@ struct zstd_params {
 static CURLcode zstd_init_writer(struct Curl_easy *data,
                                  struct contenc_writer *writer)
 {
-  struct zstd_params *zp = (struct zstd_params *)&writer->params;
+  struct zstd_writer *zp = (struct zstd_writer *) writer;
+
   (void)data;
 
   if(!writer->downstream)
@@ -738,7 +743,7 @@ static CURLcode zstd_unencode_write(struct Curl_easy *data,
                                     const char *buf, size_t nbytes)
 {
   CURLcode result = CURLE_OK;
-  struct zstd_params *zp = (struct zstd_params *)&writer->params;
+  struct zstd_writer *zp = (struct zstd_writer *) writer;
   ZSTD_inBuffer in;
   ZSTD_outBuffer out;
   size_t errorCode;
@@ -777,7 +782,8 @@ static CURLcode zstd_unencode_write(struct Curl_easy *data,
 static void zstd_close_writer(struct Curl_easy *data,
                               struct contenc_writer *writer)
 {
-  struct zstd_params *zp = (struct zstd_params *)&writer->params;
+  struct zstd_writer *zp = (struct zstd_writer *) writer;
+
   (void)data;
 
   if(zp->decomp) {
@@ -796,7 +802,7 @@ static const struct content_encoding zstd_encoding = {
   zstd_init_writer,
   zstd_unencode_write,
   zstd_close_writer,
-  sizeof(struct zstd_params)
+  sizeof(struct zstd_writer)
 };
 #endif
 
@@ -829,7 +835,7 @@ static const struct content_encoding identity_encoding = {
   identity_init_writer,
   identity_unencode_write,
   identity_close_writer,
-  0
+  sizeof(struct contenc_writer)
 };
 
 
@@ -921,7 +927,7 @@ static const struct content_encoding client_encoding = {
   client_init_writer,
   client_unencode_write,
   client_close_writer,
-  0
+  sizeof(struct contenc_writer)
 };
 
 
@@ -964,7 +970,7 @@ static const struct content_encoding error_encoding = {
   error_init_writer,
   error_unencode_write,
   error_close_writer,
-  0
+  sizeof(struct contenc_writer)
 };
 
 /* Create an unencoding writer stage using the given handler. */
@@ -973,8 +979,10 @@ new_unencoding_writer(struct Curl_easy *data,
                       const struct content_encoding *handler,
                       struct contenc_writer *downstream)
 {
-  size_t sz = offsetof(struct contenc_writer, params) + handler->paramsize;
-  struct contenc_writer *writer = (struct contenc_writer *)calloc(1, sz);
+  struct contenc_writer *writer;
+
+  DEBUGASSERT(handler->writersize >= sizeof(struct contenc_writer));
+  writer = (struct contenc_writer *) calloc(1, handler->writersize);
 
   if(writer) {
     writer->handler = handler;
index 81bddd1be1f0d849b9b4e86edee354ada62d30d3..3c278cf7271ddb3921a87e185fb861de5fb461a6 100644 (file)
@@ -28,7 +28,6 @@
 struct contenc_writer {
   const struct content_encoding *handler;  /* Encoding handler. */
   struct contenc_writer *downstream;  /* Downstream writer. */
-  void *params;  /* Encoding-specific storage (variable length). */
 };
 
 /* Content encoding writer. */
@@ -42,7 +41,7 @@ struct content_encoding {
                              const char *buf, size_t nbytes);
   void (*close_writer)(struct Curl_easy *data,
                        struct contenc_writer *writer);
-  size_t paramsize;
+  size_t writersize;
 };