All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thomas Haller <thaller@redhat.com>
To: Pablo Neira Ayuso <pablo@netfilter.org>
Cc: NetFilter <netfilter-devel@vger.kernel.org>
Subject: Re: [PATCH nft 5/8] src: rework SNPRINTF_BUFFER_SIZE() and avoid "-Wunused-but-set-variable"
Date: Mon, 28 Aug 2023 17:49:53 +0200	[thread overview]
Message-ID: <aa481d83b0320078a17bebf215378992a4f7cb21.camel@redhat.com> (raw)
In-Reply-To: <ZOy5nTEQJvu7zdrx@calendula>

On Mon, 2023-08-28 at 17:13 +0200, Pablo Neira Ayuso wrote:
> On Mon, Aug 28, 2023 at 04:43:55PM +0200, Thomas Haller wrote:
> > SNPRINTF_BUFFER_SIZE() causes a warning with clang.
> > 
> >     evaluate.c:4134:9: error: variable 'size' set but not used [-
> > Werror,-Wunused-but-set-variable]
> >             size_t size = 0;
> >                    ^
> > 
> >     meta.c:1006:9: error: variable 'size' set but not used [-
> > Werror,-Wunused-but-set-variable]
> >             size_t size;
> >                    ^
> > 
> > Fix that, and rework SNPRINTF_BUFFER_SIZE().
> > 
> > - before and now, the macro asserts against truncation. Remove
> > error
> >   handling related to truncation in the callers.
> > 
> > - wrap the macro in "do { ... } while(0)" to make it more
> >   function-like.
> > 
> > - evaluate macro arguments exactly once, to make it more function-
> > like.
> > 
> > - take pointers to the arguments that are being modified.
> > 
> > - use assert() instead of abort().
> > 
> > - use size_t type for arguments related to the buffer size.
> > 
> > - drop "size". It was unused, and, unless the string was truncated,
> >   it was identical to "offset".
> > 
> > - "offset" previously was incremented before checking for
> > truncation.
> >   So it would point somewhere past the buffer. This behavior is not
> >   useful, because we assert against truncation. Now, in case of
> >   truncation, "len" will be zero and "offset" will be the original
> > "len"
> >   (that is, point after the buffer and one byte after the
> > terminating NUL).
> > 
> > Signed-off-by: Thomas Haller <thaller@redhat.com>
> > ---
> >  include/utils.h | 32 +++++++++++++++++++++++---------
> >  src/evaluate.c  | 11 +++++------
> >  src/meta.c      | 10 +++++-----
> >  3 files changed, 33 insertions(+), 20 deletions(-)
> > 
> > diff --git a/include/utils.h b/include/utils.h
> > index cee1e5c1e8ae..873147fb54ec 100644
> > --- a/include/utils.h
> > +++ b/include/utils.h
> > @@ -72,15 +72,29 @@
> >  #define max(_x, _y) ({                         \
> >         _x > _y ? _x : _y; })
> >  
> > -#define SNPRINTF_BUFFER_SIZE(ret, size, len, offset)   \
> > -       if (ret < 0)                                    \
> > -               abort();                                \
> > -       offset += ret;                                  \
> > -       assert(ret < len);                              \
> > -       if (ret > len)                                  \
> > -               ret = len;                              \
> > -       size += ret;                                    \
> > -       len -= ret;
> > +#define SNPRINTF_BUFFER_SIZE(ret, len, offset)                 \
> > +       do { \
> > +               const int _ret = (ret);                         \
> > +               size_t *const _len = (len);                     \
> > +               size_t *const _offset = (offset);               \
> > +               size_t _ret2;                                   \
> > +                                                               \
> > +               assert(_ret >= 0);                              \
> > +                                                               \
> > +               if ((size_t) _ret >= *_len) {                   \
> > +                       /* Fail an assertion on truncation.
> > +                        *
> > +                        * Anyway, we would set "len" to zero and
> > "offset" one
> > +                        * after the buffer size (past the
> > terminating NUL
> > +                        * byte). */                            \
> > +                       assert((size_t) _ret < *_len);          \
> > +                       _ret2 = *_len;                          \
> > +               } else                                          \
> > +                       _ret2 = (size_t) _ret;                  \
> > +                                                               \
> > +               *_offset += _ret2;                              \
> > +               *_len -= _ret2;                                 \
> > +       } while (0)
> 
> This macro is something I made myself, which I am particularly not
> proud of it, but it getting slightly more complicated.

IMO it just got simpler. E.g. it is now function-like; you can easier
see which arguments are modified (we take a pointer to them); one
argument got dropped.

The remaining relevant parts (assertions and truncation check aside) is
literally

   offset += ret;
   len -= ret;


> 
> Probably it time to turn this into a real function?

as it now behaves function-like, it can be easily converted to an
inline function. Only difference is that upon assertion failure, we no
longer see the location of the caller. It does not seem an improvement.


> 
> >  #define MSEC_PER_SEC   1000L
> >  
> > diff --git a/src/evaluate.c b/src/evaluate.c
> > index 1ae2ef0de10c..f8cd7b7afda3 100644
> > --- a/src/evaluate.c
> > +++ b/src/evaluate.c
> > @@ -4129,14 +4129,16 @@ static int stmt_evaluate_queue(struct
> > eval_ctx *ctx, struct stmt *stmt)
> >  static int stmt_evaluate_log_prefix(struct eval_ctx *ctx, struct
> > stmt *stmt)
> >  {
> >         char prefix[NF_LOG_PREFIXLEN] = {}, tmp[NF_LOG_PREFIXLEN] =
> > {};
> > -       int len = sizeof(prefix), offset = 0, ret;
> > +       size_t len = sizeof(prefix);
> > +       size_t offset = 0;
> >         struct expr *expr;
> > -       size_t size = 0;
> >  
> >         if (stmt->log.prefix->etype != EXPR_LIST)
> >                 return 0;
> >  
> >         list_for_each_entry(expr, &stmt->log.prefix->expressions,
> > list) {
> > +               int ret;
> > +
> >                 switch (expr->etype) {
> >                 case EXPR_VALUE:
> >                         expr_to_string(expr, tmp);
> > @@ -4150,12 +4152,9 @@ static int stmt_evaluate_log_prefix(struct
> > eval_ctx *ctx, struct stmt *stmt)
> >                         BUG("unknown expression type %s\n",
> > expr_name(expr));
> >                         break;
> >                 }
> > -               SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
> > +               SNPRINTF_BUFFER_SIZE(ret, &len, &offset);
> >         }
> >  
> > -       if (len == NF_LOG_PREFIXLEN)
> > -               return stmt_error(ctx, stmt, "log prefix is too
> > long");
> 
> No error anymore?
> 
> Not directly related, but are you sure tests we have are sufficient
> to
> cover for all these updates 

No. I am not aware of test coverage.

SNPRINTF_BUFFER_SIZE() rejects truncation of the string by asserting
against it. That behavior is part of the API of that function. Error
checking after an assert seems unnecessary.

The check "if (len == NF_LOG_PREFIXLEN)" seems wrong anyway. After
truncation, "len" would be zero. The code previously checked whether
nothing was appended, but the error string didn't match that situation.


Maybe SNPRINTF_BUFFER_SIZE() should not assert against truncation?


Thomas

  reply	other threads:[~2023-08-28 15:51 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-28 14:43 [PATCH nft 0/8] fix compiler warnings with clang Thomas Haller
2023-08-28 14:43 ` [PATCH nft 1/8] netlink: avoid "-Wenum-conversion" warning in dtype_map_from_kernel() Thomas Haller
2023-08-28 14:43 ` [PATCH nft 2/8] netlink: avoid "-Wenum-conversion" warning in parser_bison.y Thomas Haller
2023-08-28 14:43 ` [PATCH nft 3/8] src: use "%zx" format instead of "%Zx" Thomas Haller
2023-08-28 14:43 ` [PATCH nft 4/8] datatype: avoid cast-align warning with struct sockaddr result from getaddrinfo() Thomas Haller
2023-08-28 14:43 ` [PATCH nft 5/8] src: rework SNPRINTF_BUFFER_SIZE() and avoid "-Wunused-but-set-variable" Thomas Haller
2023-08-28 15:13   ` Pablo Neira Ayuso
2023-08-28 15:49     ` Thomas Haller [this message]
2023-08-28 16:04       ` Pablo Neira Ayuso
2023-08-28 16:45         ` Thomas Haller
2023-08-28 19:53           ` Pablo Neira Ayuso
2023-08-29 13:01             ` Thomas Haller
2023-08-28 14:43 ` [PATCH nft 6/8] src: suppress "-Wunused-but-set-variable" warning with "parser_bison.c" Thomas Haller
2023-08-28 14:43 ` [PATCH nft 7/8] utils: add _NFT_PRAGMA_WARNING_DISABLE()/_NFT_PRAGMA_WARNING_REENABLE helpers Thomas Haller
2023-08-28 14:43 ` [PATCH nft 8/8] datatype: suppress "-Wformat-nonliteral" warning in integer_type_print() Thomas Haller
2023-08-28 15:08   ` Pablo Neira Ayuso
2023-08-28 15:33     ` Thomas Haller
2023-08-28 15:54       ` Pablo Neira Ayuso
2023-08-28 16:24         ` Thomas Haller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aa481d83b0320078a17bebf215378992a4f7cb21.camel@redhat.com \
    --to=thaller@redhat.com \
    --cc=netfilter-devel@vger.kernel.org \
    --cc=pablo@netfilter.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.