[libcxx-commits] [libcxx] Add test case for xsgetn in basic_filebuf (PR #167937)

via libcxx-commits libcxx-commits at lists.llvm.org
Mon Nov 17 16:07:15 PST 2025


https://github.com/Sterling-Augustine updated https://github.com/llvm/llvm-project/pull/167937

>From a7ddd924414f512a853b04d96d5102dc8df3aa50 Mon Sep 17 00:00:00 2001
From: Sterling Augustine <saugustine at google.com>
Date: Thu, 13 Nov 2025 11:38:36 -0800
Subject: [PATCH 1/2] Add test case for xsgetn in basic_filebuf

This is the promised follow-up to #167779. It simply adds a test case.
---
 .../fstreams/ifstream.members/xsgetn.pass.cpp | 72 +++++++++++++++++++
 .../fstreams/ifstream.members/xsgetn.test.dat |  1 +
 2 files changed, 73 insertions(+)
 create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp
 create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.test.dat

diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp
new file mode 100644
index 0000000000000..ec555ea4d259b
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// FILE_DEPENDENCIES: xsgetn.test.dat
+
+// <fstream>
+
+// template <class charT, class traits = char_traits<charT> >
+// class basic_ifstream
+
+// streamsize xsgetn(char_type*, streamsize) override;
+
+// This isn't a required override by the standard, but most implementations override it, since it allows for
+// significantly improved performance in some cases. All of this code is required to work, so this isn't a libc++
+// extension
+
+#include <cassert>
+#include <fstream>
+
+#include "test_macros.h"
+
+int main(int, char**) {
+  {
+    char buffer[10];
+    std::ifstream fs("xsgetn.test.dat");
+    std::filebuf* fb = fs.rdbuf();
+    fb->pubsetbuf(buffer, 10);
+
+    // Ensure that the buffer is set up
+    assert(fb->sgetc() == 't');
+
+    std::string str(5, '\0');
+
+    { // Check that a read smaller than the buffer works fine
+      assert(fb->sgetn(str.data(), 5) == 5);
+      assert(str == "this ");
+    }
+    { // Check that reading up to the buffer end works fine
+      assert(fb->sgetn(str.data(), 5) == 5);
+      assert(str == "is so");
+    }
+    { // Check that reading from an empty buffer, but more than the buffer can hold works fine
+      str.resize(12);
+      assert(fb->sgetn(str.data(), 12) == 12);
+      assert(str == "me random da");
+    }
+    { // Check that reading from a non-empty buffer, and more than the buffer can hold works fine
+      // Fill the buffer up
+      str.resize(2);
+      assert(fb->sgetn(str.data(), 2) == 2);
+      assert(str == "ta");
+
+      // Do the actual check
+      str.resize(12);
+      assert(fb->sgetn(str.data(), 12) == 12);
+      assert(str == " to be able ");
+    }
+    { // Check that trying to read more than the file size works fine
+      str.resize(30);
+      assert(fb->sgetn(str.data(), 30) == 24);
+      str.resize(24);
+      assert(str == "to test buffer behaviour");
+    }
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.test.dat b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.test.dat
new file mode 100644
index 0000000000000..06d663b9bf23d
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.test.dat
@@ -0,0 +1 @@
+this is some random data to be able to test buffer behaviour
\ No newline at end of file

>From c328003e09bd74873dc1edccc4217a8791857655 Mon Sep 17 00:00:00 2001
From: Sterling Augustine <saugustine at google.com>
Date: Mon, 17 Nov 2025 16:06:03 -0800
Subject: [PATCH 2/2] Fix scoping. Use vectors for buffers.

Writing data to a buffer obtained by data() is undefined behavior. Fix that.
---
 .../fstreams/ifstream.members/xsgetn.pass.cpp | 81 ++++++++++---------
 1 file changed, 41 insertions(+), 40 deletions(-)

diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp
index ec555ea4d259b..9438679823d50 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp
@@ -15,57 +15,58 @@
 
 // streamsize xsgetn(char_type*, streamsize) override;
 
-// This isn't a required override by the standard, but most implementations override it, since it allows for
-// significantly improved performance in some cases. All of this code is required to work, so this isn't a libc++
-// extension
+// This isn't a required override by the standard, but most implementations
+// override it, since it allows for significantly improved performance in some
+// cases. All of this code is required to work, so this isn't a libc++ extension
 
 #include <cassert>
 #include <fstream>
+#include <vector>
 
 #include "test_macros.h"
 
 int main(int, char**) {
-  {
-    char buffer[10];
-    std::ifstream fs("xsgetn.test.dat");
-    std::filebuf* fb = fs.rdbuf();
-    fb->pubsetbuf(buffer, 10);
+  std::vector<char> stream_buffer(10);
+  std::ifstream fs("xsgetn.test.dat");
+  std::filebuf* fb = fs.rdbuf();
+  fb->pubsetbuf(stream_buffer.data(), 10);
 
-    // Ensure that the buffer is set up
-    assert(fb->sgetc() == 't');
+  // Ensure that the buffer is set up
+  assert(fb->sgetc() == 't');
 
-    std::string str(5, '\0');
+  std::vector<char> test_buffer(5);
+  test_buffer[0] = '\0';
 
-    { // Check that a read smaller than the buffer works fine
-      assert(fb->sgetn(str.data(), 5) == 5);
-      assert(str == "this ");
-    }
-    { // Check that reading up to the buffer end works fine
-      assert(fb->sgetn(str.data(), 5) == 5);
-      assert(str == "is so");
-    }
-    { // Check that reading from an empty buffer, but more than the buffer can hold works fine
-      str.resize(12);
-      assert(fb->sgetn(str.data(), 12) == 12);
-      assert(str == "me random da");
-    }
-    { // Check that reading from a non-empty buffer, and more than the buffer can hold works fine
-      // Fill the buffer up
-      str.resize(2);
-      assert(fb->sgetn(str.data(), 2) == 2);
-      assert(str == "ta");
+  { // Check that a read smaller than the buffer works fine
+    assert(fb->sgetn(test_buffer.data(), 5) == 5);
+    assert(std::string(test_buffer.data()) == "this ");
+  }
+  { // Check that reading up to the buffer end works fine
+    assert(fb->sgetn(test_buffer.data(), 5) == 5);
+    assert(std::string(test_buffer.data(), 5) == "is so");
+  }
+  { // Check that reading from an empty buffer, but more than the buffer can
+    // hold works fine
+    test_buffer.resize(12);
+    assert(fb->sgetn(test_buffer.data(), 12) == 12);
+    assert(std::string(test_buffer.data(), 12) == "me random da");
+  }
+  { // Check that reading from a non-empty buffer, and more than the buffer can
+    // hold works fine Fill the buffer up
+    test_buffer.resize(2);
+    assert(fb->sgetn(test_buffer.data(), 2) == 2);
+    assert(std::string(test_buffer.data(), 2) == "ta");
 
-      // Do the actual check
-      str.resize(12);
-      assert(fb->sgetn(str.data(), 12) == 12);
-      assert(str == " to be able ");
-    }
-    { // Check that trying to read more than the file size works fine
-      str.resize(30);
-      assert(fb->sgetn(str.data(), 30) == 24);
-      str.resize(24);
-      assert(str == "to test buffer behaviour");
-    }
+    // Do the actual check
+    test_buffer.resize(12);
+    assert(fb->sgetn(test_buffer.data(), 12) == 12);
+    assert(std::string(test_buffer.data(), 12) == " to be able ");
+  }
+  { // Check that trying to read more than the file size works fine
+    test_buffer.resize(30);
+    assert(fb->sgetn(test_buffer.data(), 30) == 24);
+    test_buffer.resize(24);
+    assert(std::string(test_buffer.data(), 24) == "to test buffer behaviour");
   }
 
   return 0;



More information about the libcxx-commits mailing list