On 15 Jul 2016, at 15:49, Daniel Kahn Gillmor <d...@fifthhorseman.net> wrote:
> 
> On Fri 2016-07-15 14:19:51 +0200, Maik Zumstrull wrote:

>> As a quick fix, I suggest declaring these variables thread-local:
>> 
>> static __thread FILE *groupsfile = NULL;
>> static __thread FILE *shadowfile = NULL;
>> static __thread FILE *usersfile = NULL;
>> 
>> It's not necessarily the most elegant solution, but it should make the code 
>> fully reentrant.
> 
> Are you sure this wouldn't cause the different thread's understanding of
> the underlying file descriptors to get out of sync?  declaring them
> thread-local wouldn't prevent them sharing the same file descriptor,
> right?

It should. The semantics are that every thread "sees" its own version of that 
pointer, so if thread A opens the file, thread B, C, D, etc will still have 
NULL in their version of the variable and will do groupsfile = 
fopen(GROUPSFILE, "r"); which should create a new FILE structure and open a new 
file descriptor, whether any other thread has the file open or not.

That's why I called the solution inelegant - it's not efficient to open the 
file seven times if seven threads want something - but it should be safe 
because nothing is shared between threads.

> This seems like a way to cause some even more subtle bug, for example:
> 
> thread A causes libnss-extrausers to scan the groups file for some
>    value, and it reads up to block X, while
> thread B causes libnss-extrausers to scan the groups file for some
>    other value, and it reads up to block Y
> 
> then thread A resumes; the underlying file descriptor is advanced to
> position Y but the FILE* buffers in thread A have only cached enough
> data to represent block X.  what happens then?

That's the situation we have now, because everything from the FILE pointer to 
the FILE struct down to the file descriptor is currently shared.

Reply via email to