This is an archive of the discontinued LLVM Phabricator instance.

[SimplifyLibcalls] Don't replace locked IO (fgetc/fgets/fputc/fputs/fread/fwrite) with unlocked IO (*_unlocked)
ClosedPublic

Authored by MaskRay on Mar 10 2020, 9:50 AM.

Details

Summary

This revert the SimplifyLibcalls part change of D45736 [SimplifyLibcalls] Replace locked IO with unlocked IO.

C11 7.21.5.2 The fflush function

If stream is a null pointer, the fflush function performs this flushing action on all streams for which the behavior is defined above.

i.e. fopen'ed FILE* is inherently captured.

POSIX.1-2017 getc_unlocked, getchar_unlocked, putc_unlocked, putchar_unlocked - stdio with explicit client locking

These functions can safely be used in a multi-threaded program if and only if they are called while the invoking thread owns the ( FILE *) object, as is the case after a successful call to the flockfile() or ftrylockfile() functions.

After a thread fopen'ed a FILE*, when it is calling foobar() which is now replaced by foobar_unlocked(),
if another thread is concurrently calling fflush(0), the behavior is undefined.

C11 7.22.4.4 The exit function

Next, all open streams with unwritten buffered data are flushed, all open streams are closed, and all files created by the tmpfile function are removed.

The replacement is only feasible if the program is single threaded, or exit or fflush(0) is never called.
See also http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20180528/556615.html
for how the replacement makes libc interceptors difficult to implement.

dalias: in a worst case, it's unbounded data corruption because of concurrent access to pointers
without synchronization. f->wpos or rpos could get outside of the buffer, thread A could do
f->wpos += j after knowing j is in bounds, while thread B also changes it concurrently.

This can produce exploitable conditions depending on libc internals.

Revert the SimplifyLibcalls part change because the cons obviously
overweigh the pros. Even when the replacement is feasible, the benefit
is indemonstrable, more so in an application instead of an artificial
glibc benchmark. Theoretically the replacement could be beneficial when
calling getc_unlocked/putc_unlocked in a loop, but then it is better
using a blocked IO operation and the user is likely aware of that.

The function attribute inference is still useful and thus kept.

Diff Detail

Event Timeline

MaskRay created this revision.Mar 10 2020, 9:50 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 10 2020, 9:50 AM
xbolva00 accepted this revision.Mar 10 2020, 10:26 AM

OK, feel free to revert BuildLibcalls and and SimplifyLibcalls changes. I think other changes can stay.

This revision is now accepted and ready to land.Mar 10 2020, 10:26 AM
MaskRay updated this revision to Diff 249449.Mar 10 2020, 10:49 AM
MaskRay retitled this revision from Revert D45736 [SimplifyLibcalls] Replace locked IO with unlocked IO to Revert SimplifyLibcalls part change of D45736 [SimplifyLibcalls] Replace locked IO with unlocked IO.
MaskRay edited the summary of this revision. (Show Details)

Only revert SimplifyLibcalls part changes and some BuildLibCalls.cpp utilities.

MaskRay updated this revision to Diff 249456.Mar 10 2020, 11:06 AM
MaskRay retitled this revision from Revert SimplifyLibcalls part change of D45736 [SimplifyLibcalls] Replace locked IO with unlocked IO to [SimplifyLibcalls] Don't replace locked IO (fgetc/fgets/fputc/fputs/fread/fwrite) with unlocked IO (*_unlocked) This revert the SimplifyLibcalls part change of D45736 [SimplifyLibcalls] Replace locked IO with unlocked IO..

Make the title clearer

  1. Updating D75933: [SimplifyLibcalls] Don't replace locked IO (fgetc/fgets/fputc/fputs/fread/fwrite) with unlocked IO (*_unlocked)
MaskRay retitled this revision from [SimplifyLibcalls] Don't replace locked IO (fgetc/fgets/fputc/fputs/fread/fwrite) with unlocked IO (*_unlocked) This revert the SimplifyLibcalls part change of D45736 [SimplifyLibcalls] Replace locked IO with unlocked IO. to [SimplifyLibcalls] Don't replace locked IO (fgetc/fgets/fputc/fputs/fread/fwrite) with unlocked IO (*_unlocked).Mar 10 2020, 11:06 AM
MaskRay edited the summary of this revision. (Show Details)
This revision was automatically updated to reflect the committed changes.
llvm/test/Transforms/InstCombine/unlocked-stdio-mingw.ll