Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Thu, 9 Nov 2017 16:53:31 -0500
From: Rich Felker <dalias@...c.org>
To: musl@...ts.openwall.com
Subject: Re: misc minor undefined behaviors in musl

On Thu, Nov 09, 2017 at 09:19:03PM +0000, Pascal Cuoq wrote:
> Hello,
> 
> this message contains a collection of three issues that we have
> found running musl's source code inside tis-interpreter. They are
> all very minor, so it seems like the best format may be for me to
> put all of them in a single message, so that subscribers that aren't
> interested by C minutiae ignore the discussion more easily.
> 
> I can provide more detail on each of them, but again perhaps I'll
> only do this if someone thinks the individual issue deserves it.
> Unlike UB that the musl developers are certainly aware of but that
> involve difficult trade-offs (e.g. HASZERO in string functions),
> these seemed to be easy to fix if one deems it worth it, and a fix
> is suggested each time.
> 
> a) pointer arithmetic on NULL pointer in __fputwc_unlocked
> 
> • f->wpos may be NULL when reaching the test:
>  } else if (f->wpos + MB_LEN_MAX < f->wend) {
>  Pointer arithmetic using a null pointer is UB.
> 
> • fix: add a f->wpos != NULL test.

Normally I'd want to just compare f->wend - f->wpos, but subtracting 2
null pointers is also a problem. This problem already exists in
several other places. I believe the only clean solution that doesn't
worsen codegen is to assign a dummy value instead of null, but then
we'd have to do it uniformly everywhere AND fix a few places where
check-against-null is used to see if it's initialized to the desired
(read/write) mode. This is all a huge mess of a known issue, and I'm
not sure how to solve it cleanly withour major uglification and/or
harm to code generation.

> b) __pthread_tsd_run_dtors does not have a prototype
> 
> • in cleanup_fromsig, __pthread_tsd_run_dtors is called with an argument:
> https://git.musl-libc.org/cgit/musl/tree/src/time/timer_create.c?id=1b9406b03c0a94ebe2076a8fc1746a8c45e78a83#n27
> It is defined without a prototype here:
> https://git.musl-libc.org/cgit/musl/tree/src/thread/pthread_key_create.c?id=1b9406b03c0a94ebe2076a8fc1746a8c45e78a83#n38
> It is also called without an argument here:
> https://git.musl-libc.org/cgit/musl/tree/src/thread/pthread_create.c?id=1b9406b03c0a94ebe2076a8fc1746a8c45e78a83#n38
> and weak_alias'd to dummy_0 here:
> https://git.musl-libc.org/cgit/musl/tree/src/thread/pthread_create.c?id=1b9406b03c0a94ebe2076a8fc1746a8c45e78a83#n18
> 
> • it seems like the above is on purpose, especially the definition
> of __pthread_tsd_run_dtors without a prototype, which is still valid
> in C11and does not mean the same thing as expecting void. Still, for
> the sake of simplicity, would it be possible to uniformize to
> __pthread_tsd_run_dtors always taking an argument? Can the
> invocation without an argument in pthread_create.c end up being
> linked with an implementation of __pthread_tsd_run_dtors that takes
> an argument and actually uses it?

This looks like just a failure to update the one in timer_create.c.
Rather than spending time analzing the issue we should just fix it;
the argument is not needed.

> c) definition of MAP_FAILED
> 
> • tis-interpreter does not like the definition of MAP_FAILED as
> (void*)-1. While mmap is a bit outside the scope of what it was
> initially designed to do, some simple uses of mmap can be emulated
> pretty well on a case-by-case basis by making mmap return the
> address of a preallocated array of chars. When we do this, then the
> comparison to MAP_FAILED at the call site becomes the next problem,
> because unlike (void *)0, nothing guarantees that (void*)-1 does not
> happen to be, by bad luck, the address of the array.

Multiple things guarantee this. For one, MAP_FAILED is just defined by
POSIX that way, so the implementation of mmap must ensure that the
return value on success is never equal to MAP_FAILED, whatever the
implementation defines it as. But that's already guaranteed for this
particular value anyway, since mmap is required to return page-aligned
memory.

> • we fixed this by defining MAP_FAILED as the address of a const char
> variable defined for this purpose. Since everyone else is defining
> MAP_FAILED as (void*)-1, this will never be wrong, but I wonder
> whether someone can see ways in which our solution is better or
> worse than the original.

It's a nice idea, but this can't actually be changed because it's
application ABI. The application needs to be able to compare against
MAP_FAILED to determine if mmap failed.

Rich

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.