diff --git a/libcxx/include/fstream b/libcxx/include/fstream index c86f709bedb80..6d3f20fff688f 100644 --- a/libcxx/include/fstream +++ b/libcxx/include/fstream @@ -401,6 +401,14 @@ private: } } } + + _LIBCPP_HIDE_FROM_ABI typename traits_type::int_type __overflow_failed() { + if (this->pptr() == this->epptr() + 1) { + this->pbump(-1); // lose the character we overflowed above -- we don't really have a + // choice since we couldn't commit the contents of the put area + } + return traits_type::eof(); + } }; template @@ -841,8 +849,9 @@ typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits> if (__always_noconv_) { size_t __n = static_cast(this->pptr() - this->pbase()); - if (std::fwrite(this->pbase(), sizeof(char_type), __n, __file_) != __n) - return traits_type::eof(); + if (std::fwrite(this->pbase(), sizeof(char_type), __n, __file_) != __n) { + return __overflow_failed(); + } } else { if (!__cv_) std::__throw_bad_cast(); @@ -854,34 +863,38 @@ typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits> char* __extbuf_end = __extbuf_; do { codecvt_base::result __r = __cv_->out(__st_, __b, __p, __end, __extbuf_, __extbuf_ + __ebs_, __extbuf_end); - if (__end == __b) - return traits_type::eof(); + if (__end == __b) { + return __overflow_failed(); + } // No conversion needed: output characters directly to the file, done. if (__r == codecvt_base::noconv) { size_t __n = static_cast(__p - __b); - if (std::fwrite(__b, 1, __n, __file_) != __n) - return traits_type::eof(); + if (std::fwrite(__b, 1, __n, __file_) != __n) { + return __overflow_failed(); + } break; // Conversion successful: output the converted characters to the file, done. } else if (__r == codecvt_base::ok) { size_t __n = static_cast(__extbuf_end - __extbuf_); - if (std::fwrite(__extbuf_, 1, __n, __file_) != __n) - return traits_type::eof(); + if (std::fwrite(__extbuf_, 1, __n, __file_) != __n) { + return __overflow_failed(); + } break; // Conversion partially successful: output converted characters to the file and repeat with the // remaining characters. } else if (__r == codecvt_base::partial) { size_t __n = static_cast(__extbuf_end - __extbuf_); - if (std::fwrite(__extbuf_, 1, __n, __file_) != __n) - return traits_type::eof(); + if (std::fwrite(__extbuf_, 1, __n, __file_) != __n) { + return __overflow_failed(); + } __b = const_cast(__end); continue; } else { - return traits_type::eof(); + return __overflow_failed(); } } while (true); } diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/overflow.writefail.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/overflow.writefail.pass.cpp new file mode 100644 index 0000000000000..27e06982d749b --- /dev/null +++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/overflow.writefail.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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: no-filesystem + +// setrlimit(RLIMIT_FSIZE) seems to only work as intended on Apple platforms +// REQUIRES: target={{.+}}-apple-{{.+}} + +// + +// Make sure that we properly handle the case where we try to write content to a file +// but we fail to do so because std::fwrite fails. + +#include +#include +#include +#include +#include + +#include "platform_support.h" +#include "test_macros.h" + +#if __has_include() +# include +void limit_file_size_to(std::size_t bytes) { + rlimit lim = {bytes, bytes}; + assert(setrlimit(RLIMIT_FSIZE, &lim) == 0); + + std::signal(SIGXFSZ, [](int) {}); // ignore SIGXFSZ to ensure std::fwrite fails +} +#else +# error No known way to limit the amount of filesystem space available +#endif + +template +void test() { + std::string temp = get_temp_file_name(); + std::basic_filebuf fbuf; + assert(fbuf.open(temp, std::ios::out | std::ios::trunc)); + + std::size_t const limit = 100000; + limit_file_size_to(limit); + + std::basic_string large_block(limit / 10, CharT(42)); + + std::streamsize ret; + std::size_t bytes_written = 0; + while ((ret = fbuf.sputn(large_block.data(), large_block.size())) != 0) { + bytes_written += ret; + + // In theory, it's possible for an implementation to allow writing arbitrarily more bytes than + // set by setrlimit, but in practice if we bust 100x our limit, something else is wrong with the + // test and we'd end up looping forever. + assert(bytes_written < 100 * limit); + } + + fbuf.close(); +} + +int main(int, char**) { + test(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); +#endif + + return 0; +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index 2529e78f78bca..633b860b5784c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -1053,6 +1053,16 @@ ClangASTImporter::MapCompleter::~MapCompleter() = default; llvm::Expected ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) { + // FIXME: The Minimal import mode of clang::ASTImporter does not correctly + // import Lambda definitions. Work around this for now by not importing + // lambdas at all. This is most likely encountered when importing decls from + // the `std` module (not from debug-info), where lambdas can be defined in + // inline function bodies. Those will be imported by LLDB. + if (const auto *CXX = llvm::dyn_cast(From)) + if (CXX->isLambda()) + return llvm::make_error( + ASTImportError::UnsupportedConstruct); + if (m_std_handler) { std::optional D = m_std_handler->Import(From); if (D) { diff --git a/lldb/test/API/lang/cpp/lambdas/TestLambdas.py b/lldb/test/API/lang/cpp/lambdas/TestLambdas.py index c8308c16011e0..112f375c0ef2f 100644 --- a/lldb/test/API/lang/cpp/lambdas/TestLambdas.py +++ b/lldb/test/API/lang/cpp/lambdas/TestLambdas.py @@ -1,4 +1,12 @@ from lldbsuite.test import lldbinline from lldbsuite.test import decorators -lldbinline.MakeInlineTest(__file__, globals()) +lldbinline.MakeInlineTest( + __file__, + globals(), + [ + decorators.expectedFailureAll( + bugnumber="https://github.com/llvm/llvm-project/issues/149477" + ) + ], +) diff --git a/lldb/test/Shell/Expr/TestLambdaExprImport.test b/lldb/test/Shell/Expr/TestLambdaExprImport.test new file mode 100644 index 0000000000000..c57ce06453fe2 --- /dev/null +++ b/lldb/test/Shell/Expr/TestLambdaExprImport.test @@ -0,0 +1,26 @@ +# Test that we can successfully ASTImport clang::LambdaExpr nodes. +# Currently this is not supported in MinimalImport mode (which LLDB +# uses always). + +# RUN: split-file %s %t +# RUN: %clang_host -g -gdwarf %t/main.cpp -o %t.out +# RUN: %lldb -o "settings set interpreter.stop-command-source-on-error false" \ +# RUN: -x -b -s %t/commands.input %t.out 2>&1 \ +# RUN: | FileCheck %s + +#--- main.cpp + +int main() { + __builtin_debugtrap(); +} + +#--- commands.input + +run +expression --top-level -- void method(int x) { [x=x] { ; }; } +target dump typesystem + +# CHECK: expression +# CHECK: target dump typesystem +# CHECK-NOT: FunctionDecl +# CHECK-NOT: LambdaExpr