diff --git a/httplib.h b/httplib.h index 1c98cc80bc..3cd371cbee 100644 --- a/httplib.h +++ b/httplib.h @@ -5568,6 +5568,15 @@ inline bool mmap::open(const char *path) { is_open_empty_file = true; return false; } + + // A failed mapping must not be left in `addr_`: `is_open()` only compares it + // against nullptr, so the MAP_FAILED sentinel would pass and `data()` would + // hand the caller (const char *)-1. + if (addr_ == MAP_FAILED) { + addr_ = nullptr; + close(); + return false; + } #endif return true; diff --git a/test/test.cc b/test/test.cc index b71171f75d..04e130a18a 100644 --- a/test/test.cc +++ b/test/test.cc @@ -9163,6 +9163,23 @@ TEST(MmapTest, OpenWhileFileHeldForWriting) { } #endif +#ifndef _WIN32 +// A failed ::mmap must not be reported as an open mapping. is_open() only +// compares addr_ against nullptr, so the MAP_FAILED sentinel used to pass it +// and data() handed the caller (const char *)-1. A directory opens and stats +// fine but has no mapping, so ::mmap fails for it. +TEST(MmapTest, FailedMappingIsNotOpen) { + const char *path = "./mmap_failed_mapping_test_dir"; + ASSERT_EQ(0, ::mkdir(path, 0755)); + auto dir_cleanup = detail::scope_exit([&] { ::rmdir(path); }); + + detail::mmap m(path); + EXPECT_FALSE(m.is_open()); + EXPECT_NE(static_cast(m.data()), + static_cast(MAP_FAILED)); +} +#endif + TEST(KeepAliveTest, ReadTimeout) { Server svr;