Commit 1a38d8d5 authored by jan.koester's avatar jan.koester
Browse files

test

parent d34ea4e7
Loading
Loading
Loading
Loading
+19 −7
Changes for include/cxx/memory: 19 added lines, 7 removed lines.
Original line number Diff line number Diff line
@@ -303,7 +303,14 @@ public:
    typedef T element_type;
    typedef Deleter deleter_type;

    unique_ptr() noexcept : _p(nullptr), _d() {}
    /* constexpr, as the standard has it: a namespace-scope unique_ptr is
     * then constant-initialized, with no initializer code at all. Without
     * it, a plugin carrying its own copy of a global the executable also
     * defines (blogi's letsencrypt.so, from the static libblogidev.a)
     * re-ran "Cfg = nullptr" through the GOT on dlopen() -- onto the
     * executable's live object (real gap: blogi SIGSEGV after loading
     * its plugins). */
    constexpr unique_ptr() noexcept : _p(nullptr), _d() {}
    constexpr unique_ptr(decltype(nullptr)) noexcept : _p(nullptr), _d() {}
    explicit unique_ptr(T* p) noexcept : _p(p), _d() {}
    unique_ptr(T* p, const Deleter& d) noexcept : _p(p), _d(d) {}
@@ -359,7 +366,11 @@ public:
        return *this;
    }

    ~unique_ptr() { if (_p) _d(_p); }
    /* leaves the pointer null, as libstdc++'s does: a second destructor
     * run on the same object -- the executable's global and a plugin's
     * own copy of it, both registered with __cxa_atexit -- is a no-op,
     * not a double delete */
    ~unique_ptr() { if (_p) _d(_p); _p = nullptr; }

    T* get() const noexcept { return _p; }
    Deleter& get_deleter() noexcept { return _d; }
@@ -473,7 +484,7 @@ public:
    typedef T element_type;
    typedef Deleter deleter_type;

    unique_ptr() noexcept : _p(nullptr), _d() {}
    constexpr unique_ptr() noexcept : _p(nullptr), _d() {}
    constexpr unique_ptr(decltype(nullptr)) noexcept : _p(nullptr), _d() {}
    explicit unique_ptr(T* p) noexcept : _p(p), _d() {}
    unique_ptr(T* p, const Deleter& d) noexcept : _p(p), _d(d) {}
@@ -488,7 +499,7 @@ public:
    }
    unique_ptr& operator=(decltype(nullptr)) noexcept { reset(); return *this; }

    ~unique_ptr() { if (_p) _d(_p); }
    ~unique_ptr() { if (_p) _d(_p); _p = nullptr; }

    T* get() const noexcept { return _p; }
    Deleter& get_deleter() noexcept { return _d; }
@@ -648,12 +659,13 @@ public:
    template<class U> friend class shared_ptr;
    template<class U> friend class weak_ptr;

    shared_ptr() noexcept : _p(nullptr), _ctrl(nullptr) {}
    /* constexpr for constant initialization, see unique_ptr() */
    constexpr shared_ptr() noexcept : _p(nullptr), _ctrl(nullptr) {}
    template<class Y, class = enable_if_t<is_convertible<Y*, T*>::value>>
    explicit shared_ptr(Y* p) : _p(p), _ctrl(__internal::make_owner(p)) {
        __wire_enable_shared_from_this(p);
    }
    shared_ptr(decltype(nullptr)) noexcept : _p(nullptr), _ctrl(nullptr) {}
    constexpr shared_ptr(decltype(nullptr)) noexcept : _p(nullptr), _ctrl(nullptr) {}

    /* Real custom-deleter constructors: d(p) runs instead of `delete p`
     * when the last owner goes away -- also for a null p, as the
@@ -917,7 +929,7 @@ class weak_ptr {
public:
    template<class U> friend class weak_ptr;

    weak_ptr() noexcept : _p(nullptr), _ctrl(nullptr) {}
    constexpr weak_ptr() noexcept : _p(nullptr), _ctrl(nullptr) {}

    weak_ptr(const weak_ptr& o) noexcept : _p(o._p), _ctrl(o._ctrl) {
        if (_ctrl) __internal::__ref_inc(_ctrl->weak_count);
+5 −2
Changes for include/cxx/mutex: 5 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -47,7 +47,10 @@ inline constexpr adopt_lock_t adopt_lock{};

class mutex {
public:
    mutex() noexcept { pthread_mutex_init(&_m, nullptr); }
    /* constexpr, as the standard has it (constant initialization, see
     * unique_ptr() in <memory>): the all-zero pthread_mutex_t is exactly
     * the unlocked state pthread_mutex_init() establishes */
    constexpr mutex() noexcept : _m() {}
    ~mutex() { pthread_mutex_destroy(&_m); }
    mutex(const mutex&) = delete;
    mutex& operator=(const mutex&) = delete;
@@ -198,7 +201,7 @@ void lock(L1& l1, L2& l2) {
struct once_flag {
    pthread_mutex_t m{};
    bool called = false;
    once_flag() noexcept { pthread_mutex_init(&m, nullptr); }
    constexpr once_flag() noexcept {}   // all-zero: unlocked, see mutex()
};

template<class F, class... Args>
+2 −1
Changes for src/test/e2e/CMakeLists.txt: 2 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -3711,7 +3711,8 @@ add_test(NAME e2e_lldb_stdlib_gaps71 COMMAND e2e_lldb_stdlib_gaps71)
# C++20 calendar types in <chrono> (day/month/year/year_month_day),
# from_stream() and std::formatter for sys_time/year_month_day -- real
# gap: blogi's sitemap and std::format("{:%Y-%m-%d %T}", now()) --
# and sregex_iterator over a non-const string's begin()/end().
# sregex_iterator over a non-const string's begin()/end(), and constant
# initialization of global unique_ptr/shared_ptr/weak_ptr/mutex/once_flag.
add_executable(e2e_blogi_stdlib_gaps blogi_stdlib_gaps_test.cpp)
set_target_properties(e2e_blogi_stdlib_gaps PROPERTIES OUTPUT_NAME "blogi_stdlib_gaps_test")
target_compile_options(e2e_blogi_stdlib_gaps PRIVATE -fPIE)
+33 −1
Changes for src/test/e2e/blogi_stdlib_gaps_test.cpp: 33 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -3,13 +3,18 @@
 * year_month_day), from_stream() and the std::formatter for
 * sys_time/year_month_day (blogi's sitemap and its
 * std::format("{:%Y-%m-%d %T}", system_clock::now()) timestamps), and
 * sregex_iterator over a non-const string's begin()/end(). */
 * sregex_iterator over a non-const string's begin()/end(), and constant
 * initialization of namespace-scope unique_ptr/shared_ptr/weak_ptr/mutex/
 * once_flag (a plugin's own copy of such a global re-ran its initializer
 * onto the executable's object on dlopen(): blogi SIGSEGV). */

#include <stdio.h>
#include <string.h>
#include <chrono>
#include <format>
#include <map>
#include <memory>
#include <mutex>
#include <regex>
#include <sstream>
#include <string>
@@ -94,6 +99,32 @@ static int test_format() {
    return 0;
}

/* constinit fails to compile unless these are constant-initialized */
constinit std::unique_ptr<std::string> g_unique;
constinit std::unique_ptr<int[]> g_unique_array;
constinit std::shared_ptr<int> g_shared;
constinit std::shared_ptr<int> g_shared_null(nullptr);
constinit std::weak_ptr<int> g_weak;
constinit std::mutex g_mutex;
constinit std::once_flag g_once;

static int test_constant_init() {
    g_unique = std::make_unique<std::string>("x");
    CHECK(*g_unique == "x", "constinit unique_ptr is usable");
    std::lock_guard<std::mutex> lk(g_mutex);
    int n = 0;
    std::call_once(g_once, [&] { n++; });
    std::call_once(g_once, [&] { n++; });
    CHECK(n == 1, "constinit once_flag runs once");
    CHECK(!g_shared && !g_shared_null && g_weak.expired() && !g_unique_array, "constinit pointers start empty");
    /* the destructor leaves it null: a second run is a no-op */
    alignas(std::unique_ptr<int>) unsigned char buf[sizeof(std::unique_ptr<int>)];
    auto* up = new (buf) std::unique_ptr<int>(new int(7));
    up->~unique_ptr();
    CHECK(up->get() == nullptr, "~unique_ptr leaves the pointer null");
    return 0;
}

static int test_sregex_nonconst() {
    std::string content = "<div id=\"a\"></div><p id='b'></p>";
    std::regex idRegex("\\bid=[\"']([^\"']+)[\"']");
@@ -111,6 +142,7 @@ int main() {
    if (test_from_stream()) return 1;
    if (test_format()) return 1;
    if (test_sregex_nonconst()) return 1;
    if (test_constant_init()) return 1;
    printf("PASS: blogi_stdlib_gaps\n");
    return 0;
}