[libc-commits] [libc] 1bb85fa - [libc] Lock the output stream for the 'puts' call (#76513)

via libc-commits libc-commits at lists.llvm.org
Tue Jan 2 08:07:06 PST 2024


Author: Joseph Huber
Date: 2024-01-02T10:07:01-06:00
New Revision: 1bb85fa9c038044e949dac6e3b07e9835d1110a6

URL: https://github.com/llvm/llvm-project/commit/1bb85fa9c038044e949dac6e3b07e9835d1110a6
DIFF: https://github.com/llvm/llvm-project/commit/1bb85fa9c038044e949dac6e3b07e9835d1110a6.diff

LOG: [libc] Lock the output stream for the 'puts' call (#76513)

Summary:
The `puts` function consists of an initial write and then another write
to append the newline. When executing code in parallel, it is possible
for these writes to becomes disjointed. This code adds an explicit lock
call to ensure that the string is always appended by the newline as the
users expects.

Wasn't sure if this required a test as it would be difficult since
reproducing it would be flaky.

Added: 
    

Modified: 
    libc/src/stdio/generic/puts.cpp

Removed: 
    


################################################################################
diff  --git a/libc/src/stdio/generic/puts.cpp b/libc/src/stdio/generic/puts.cpp
index d8d69332566cd0..0f19ec52676712 100644
--- a/libc/src/stdio/generic/puts.cpp
+++ b/libc/src/stdio/generic/puts.cpp
@@ -15,9 +15,26 @@
 
 namespace LIBC_NAMESPACE {
 
+namespace {
+
+// Simple helper to unlock the file once destroyed.
+struct ScopedLock {
+  ScopedLock(LIBC_NAMESPACE::File *stream) : stream(stream) { stream->lock(); }
+  ~ScopedLock() { stream->unlock(); }
+
+private:
+  LIBC_NAMESPACE::File *stream;
+};
+
+} // namespace
+
 LLVM_LIBC_FUNCTION(int, puts, (const char *__restrict str)) {
   cpp::string_view str_view(str);
-  auto result = LIBC_NAMESPACE::stdout->write(str, str_view.size());
+
+  // We need to lock the stream to ensure the newline is always appended.
+  ScopedLock lock(LIBC_NAMESPACE::stdout);
+
+  auto result = LIBC_NAMESPACE::stdout->write_unlocked(str, str_view.size());
   if (result.has_error())
     libc_errno = result.error;
   size_t written = result.value;
@@ -25,7 +42,7 @@ LLVM_LIBC_FUNCTION(int, puts, (const char *__restrict str)) {
     // The stream should be in an error state in this case.
     return EOF;
   }
-  result = LIBC_NAMESPACE::stdout->write("\n", 1);
+  result = LIBC_NAMESPACE::stdout->write_unlocked("\n", 1);
   if (result.has_error())
     libc_errno = result.error;
   written = result.value;


        


More information about the libc-commits mailing list