tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Fwd: Re: fmtcheck() query



On Sat, Dec 09, 2017 at 09:43:56 +0900, Rin Okuyama wrote:

> We are discussing how fmtcheck(3) should be. Previously, it allows
> format strings consuming less arguments than the default one, as long
> as consumed args are of correct types. Recently, I've changed it to
> reject such a string as documented in man page. However, we are not
> sure which behavior is preferable.
> 
> Both may be incomplete. fmtcheck(3) should support positional args.
> Then, format strings should be allowed if consumed args have correct
> types, and the number of args is less than or equal to the default one.
> 
> How do you think? And how is your version?

Ok, it seems to be coming back slowly now...

It started when I was cleaning up usr.bin/man in July 2013.  In
man.conf(5) you can specify shell commands with _build and _crunch
keywords so I thought that it would be nice to verify them like gcc
does statically.  I didn't know that we had fmtcheck(3) already, so I
hacked together a quick prototype over the weekend, but didn't
complete it.

Positional arguments are not in ANSI C, I used SUS as my reference:
http://pubs.opengroup.org/onlinepubs/007908799/xsh/fprintf.html

This prototype was lying around until November when Christos found out
about it and provided some feedback.  So I hacked on it a bit more and
that's what's in that hg repo.

My version doesn't support %p and %n.  IIRC this should be trivial to
add.

It permits signed/unsigned confusion (e.g. it will accept format %u as
ok given the %d template) - iirc, it's needed to let e.g. %x stand for
%d.

I didn't bother with "lose" matches that take actual type widths into
account (e.g. accept %ld for %d if type sizes happen to be the same on
the host) - I don't think this should be allowed even as an option.

I haven't thought about the effects of promotions vs ellipsis at all.

My version currently complains about unused arguments, but there's an
XXX comment about that.  For the numbered case the relevant passage
is:

  "When numbered argument specifications are used, specifying the Nth
  argument requires that all the leading arguments, from the first to
  the (N-1)th, are specified in the format string."

i.e. it's ok to consume less, but you have to consume all the ones
before.  The latter is obviously not a concern for the usual
sequential access.

I don't remember why the code complains if the tempalte refers to the
same argument multiple times.  I guess I was too lazy to make sure the
two references are compatible.


So after hacking on it a bit more that one weekend I dropped it again.
IIRC b/c it was the boring part of figuring out the good API for error
reporting etc.  E.g. I strongly dislike fmtcheck() return value, it
seduces you into using fmtcheck() call directly as the format string
argument.

Eventually I've committed a fix to man to use fmtcheck() along with
this:

  /*
   * A do-nothing counterpart to fmtcheck(3) that only supplies the
   * __format_arg marker.  Actual fmtcheck(3) call is done once in
   * config().
   */
  __always_inline __format_arg(2)
  static inline const char *
  fmtcheck_ok(const char *userfmt, const char *template)
  {
          return userfmt;
  }

used like:

  snprintf(cmd, sizeof(cmd), fmtcheck_ok(buf, "%s"), p);

Of course this depends on the actual call to fmtcheck() to be made
with the same template format string.

With those fixes committed we could drop -Wno-format-nonliteral.  And
then - out of sight, out of mind - I forgot about this code.

If you want to use it to check the nvi catalog, then I guess you
should be able to just use it right away, probably as-is.  The test
code contains main() that checks argv[2] format against argv[1]
template, e.g.

    $ ./printf_checkformat '%d' 'r=0x%1$08x (%1$d)'

Note that the order is the inverse compared to fmtcheck().

Hope that helps.  Sorry for the saga.

-uwe


Home | Main Index | Thread Index | Old Index