Repository navigation
Version 2.2.0
[Summary]
StormByte Base is the C++26 foundation of the StormByte suite.
Every other module links this library.
This repository is not Buffer, Config, Crypto, Database, Logger, Multimedia, Network or System — those live in their own repos and depend on Base.
Public headers under StormByte/ cover exceptions, Expected, little-endian Serializable, strings, paths, UUID v4, bitmasks, clonable types, ThreadLock, Size, and StormByte::Type concepts.
StormByte::Safe is the owned surface that crosses a DLL without the caller's CRT: collections, wait, and Safe::Thread.
If you landed here from a release link and have not read the tree:
- What this module is, how to build it, and short examples: README.md
- Since 2.0.0 license changed: original source in this repository is dual-licensed, LGPL v3 or later or a commercial license from the copyright holder. The grant does not cover other StormByte modules or
thirdparty/. LICENSE
The API is source compatible, but the Safe::Binary layout changed (it now has a vtable): modules built against 2.1.0 must be rebuilt.
Fixed
StringTestsandWStringTestsuse runtime format validation for dynamic width and precision with Clang and libstdc++ 15 in C++26 mode (GCC PR127220). Other toolchains retain compile-time validation; the formatters and their runtime behavior are unchanged.
Added
Safe::SecureBinary(StormByte/safe/secure_binary.hxx) derives fromSafe::Binaryand has the same API. Every byte it drops is zeroed before it goes: erased, popped and truncated bytes, the previous contents onassignand on copy or move assignment, the old block when the storage grows, shrinks or is reserved, and the whole block in the destructor. The zeroing uses a primitive the optimizer may not drop:SecureZeroMemoryon Windows,explicit_bzero(glibc 2.25+, musl, FreeBSD, OpenBSD),explicit_memset(NetBSD) ormemset_s(macOS). CMake detects which one exists when configuring. If none does, a volatile loop with a compiler barrier is used. Equality runs in constant time whenever one side is aSecureBinary, includingBinary == SecureBinaryand calls through aconst Binary&. Sizes are compared first and are not treated as secret.operator<=>is not constant time. An rvaluestd::vector<std::byte>is zeroed before it is cleared.- Each block is locked in memory (
mlock, orVirtualLockon Windows) so it is not written to swap. This is best effort: pastRLIMIT_MEMLOCKor the Windows minimum working set the block stays unlocked and nothing fails. Locks are counted per page, so blocks that share a page do not unlock each other. - Not provided:
explicit operator std::vector<std::byte>,HexDump()andHexDump(Size)are deleted, andSerializable<Safe::SecureBinary>fails astatic_assert. Each would copy the secret into memory that is never wiped.span()and the implicitstd::spanconversion remain. - Not covered: a move,
swaporappend(&&)between aSecureBinaryand a plainBinaryhands the block over as is, so a secret moved into aBinaryis no longer wiped or locked. AHexDumpthrough aconst Binary&still works. Type::IsSafeandType::IsSafeValuerecognizeSafe::SecureBinary.
- Each block is locked in memory (
platform.hidentifies the C library (GLIBC,MUSL,UCLIBC,BIONIC,NEWLIB,UCRT,MSVCRT,BSD_LIBC) and, in C++, the standard library (LIBSTDCXX,LIBCXX,MSVC_STL). musl has no identifying macro, soMUSLmeans a Linux libc that is none of the others.platform.hnow includes<limits.h>, and<version>in C++.
Changed
- ABI break:
Safe::Binaryis no longerfinal. It has a virtual destructor and four protected hooks, all doing nothing by default.Discard(std::span<std::byte>)receives every byte range the sequence is about to drop or release.AcquireandReleasereceive every allocated block that enters or leaves the object through reallocation, move orswap.ConstantTimeCompare()selects constant-time equality. The protectedWipeandStoragehelpers are available to derived classes. Safe::Binarymanages its capacity itself instead of lettingSafe::Vectorreallocate, so every reallocation reachesDiscard. Growth is still geometric.assign,insertandappendno longer build a temporaryVector; a range that aliases the sequence is remapped in place.insertfrom a single-pass input iterator inserts byte by byte.Safe::Binary(R&&)takes the block of any rvalue derived fromBinary, not only ofBinaryitself.