svn commit: r352795 - head/lib/libc/sys

Mateusz Guzik mjguzik at gmail.com
Sat Sep 28 01:20:18 UTC 2019


On 9/27/19, Warner Losh <imp at bsdimp.com> wrote:
> On Fri, Sep 27, 2019 at 2:38 PM Mateusz Guzik <mjguzik at gmail.com> wrote:
>
>> On 9/27/19, Konstantin Belousov <kostikbel at gmail.com> wrote:
>> > On Fri, Sep 27, 2019 at 08:32:20PM +0200, Mateusz Guzik wrote:
>> >> On 9/27/19, Warner Losh <imp at freebsd.org> wrote:
>> >> >   Document varadic args as int, since you can't have short varadic
>> args
>> >> > (they are
>> >> >   promoted to ints).
>> >> >
>> >> >   - `mode_t` is `uint16_t` (`sys/sys/_types.h`)
>> >> >   - `openat` takes variadic args
>> >> >   - variadic args cannot be 16-bit, and indeed the code uses int
>> >> >   - the manpage currently kinda implies the argument is 16-bit by
>> >> > saying
>> >> > `mode_t`
>> >> >
>> >> But opengroup says it is mode_t. Perhaps it is mode_t which needs
>> >> to be changed?
>> >
>> > Yes, users must pass mode_t, and the man page is written for users.
>> > Implementation needs to be aware of the implicit promotion and handle
>> > it accordingly.
>> >
>> > In theory, mode_t might be wider than int.
>> >
>>
>> So I think the change should be reverted. Whatever workaround is being
>> in place in rust should remain for the current codebase.
>>
>
> Rust needs to understand that it's not C. It's mistake was assuming it was
> just like C and this is a case where the languages differ because C is so
> quirky.
>
>
>> If anyone is to fixed the problem they should bump mode_t to uint32_t,
>> to match Linux. This is ABI breakage, I don't know how that's handled.
>>
>
> That's not going to happen. And there's no need. It would cause more
> heartache than it's worth.
>
>

In isolation, sure. Someone(tm) should do a type comprehensive type
check against Linux. There are probably many cases where something
has a different size, but software hardcodes what happens to work on
Linux (instead of using the type documented by opengroup or whatever
else is applicable).

>> I have no interest in handling any of this, but the change committed
>> is definitely wrong.
>>
>
> I tend to agree, but the manual was/is incomplete. The arg *IS* promoted to
> an int, per normal C rules, so that part is right and there's no
> type-checking against truncation or the wrong type being used as would be
> the case if it weren't varadic (so don't pass a long here).
>

But the fact there is any need for promotion in the first place is only
an implementation wart.

> However, type purity aside, that's not how things are implemented. Open is
> expecting an int (as is openat):
>
> int
> open(const char *path, int flags, ...)
> {
>         va_list ap;
>         int mode;
>
>         if ((flags & O_CREAT) != 0) {
>                 va_start(ap, flags);
>                 mode = va_arg(ap, int);
>                 va_end(ap);
>         } else {
>                 mode = 0;
>         }
>         return (((int (*)(int, const char *, int, ...))
>             __libc_interposing[INTERPOS_openat])(fd, path, flags, mode));
> }
>
> so the change, from that perspective, actually documents the interface (so
> isn't definitely wrong, and my guarded 'tend to agree'). So if you did
> change the type of mode_t, the above code might be wrong afterwards (hence
> my can of worms comment). And then we're passing it again through a varadic
> function pointer...
>
> So while POSIX says one thing, we implement something else. Should we
> document POSIX or what we implement? Or do we fix our implementation to
> match the docs? For all programs that don't pass in a 'long' or a pointer,
> the difference is zero, however.
>
> To be honest, though, quibbling over how it should be implemented aside, I
> think we should actually do the following:
>
> diff --git a/lib/libc/sys/open.2 b/lib/libc/sys/open.2
> index a771461e2e49..aa912b797f74 100644
> --- a/lib/libc/sys/open.2
> +++ b/lib/libc/sys/open.2
> @@ -61,7 +61,7 @@ In this case
>  and
>  .Fn openat
>  require an additional argument
> -.Fa "int mode" ,
> +.Fa "mode_t mode" ,
>  and the file is created with mode
>  .Fa mode
>  as described in
> @@ -615,3 +615,8 @@ permits searches.
>  The present implementation of the
>  .Fa openat
>  checks the current permissions of directory instead.
> +.Pp
> +The
> +.Fa mode
> +argument is varadic and may result in different calling conventions
> +than might otherwise be expected.
>
> Is what I was thinking of committing instead. It's in the BUGS section, and
> is useful to know if you are debugging code that has this in the call path
> (since values may be on the stack instead of in registers, depending on the
> calling convention for the underlying architecture).
>

I think this is fine. I mostly object to telling people to pass int instead of
mode_t.

-- 
Mateusz Guzik <mjguzik gmail.com>


More information about the svn-src-all mailing list