eclipse-score / eclipse-score/baselibs

Nothrow: Substitutes for standard C++ containers and memory resources, with pluggable pointer storage policies

Open
#167 9 comments 1 reaction 0 assignees View on GitHub
enhancement
Dominant language
C++
Stars
26
Forks
85
Avg merge
2d 13h
Merged PRs (30d)
47

Description

### Component Request /Modification Description

`score::nothrow` provides nothrow substitutes for standard C++ containers and memory resources, with pluggable pointer storage policies.

The most important deviation from the standard library is the explicit error return path for allocation failure. In real systems, memory resources are usually dimensioned and owned in parts of the architecture that are separate from the individual business logic operating on containers. That business logic therefore cannot reliably know whether a size-changing container operation will succeed.

The C++ standard library does not provide the missing building blocks needed to make such code robust without exceptions: there is no standard API to query remaining allocatable memory, no way to ask a container which future growth steps will require allocation, and no standard atomic test-and-allocate operation that would let callers prove a mutation is safe before performing it. As a consequence, standard library containers are not suitable for writing robust no-exception code that must survive allocation failure without crashing. This matters especially when allocation size is influenced by external requests: treating allocation failure only as an abort condition can turn memory pressure into a denial-of-service vector instead of a contained error path.

Pointer storage policies aim to minimize the performance impact of offset pointers, so that container types using them remain type-compatible in applications and in zero-copy SHM locations.

The general pattern of containers planned in `score::nothrow` is:

- Functional clones of the standard counterparts.
- All member functions could be noexcept.
- Note: the explicit `noexcept` spec may be omitted to allow exception traversal, but they do not throw.
- Member functions that are non-throwing in the standard interface keep the standard spelling and signature as closely as possible to preserve named interface requirements.
- Bounds checking member functions, e.g. `at()`, `back()`, `front()` keep the standard spelling and signature, plus noexcept, and shall abort in case of failure. The user can check these preconditions easily in advance and does not depend on doing a post-invocation check of function result.
- Member functions that are potentially throwing `std::bad_alloc` in the standard interface (most size-changing operations) cannot be guarded reliably by callers: memory budgets are typically decided elsewhere in the architecture, there is no API to query available memory, container growth strategy is an implementation detail out of user control, and there are no standard atomic test-and-allocate operations. Therefore they are provided in two variants with the same parameter list:
- An error-propagating variant with PascalCase naming, returning `score::Result` or `score::ResultBlank`.
- An aborting variant with PascalCase naming and `OrAbort` suffix, returning the original value category and aborting on failure. These shall be used when an out-of-memory situation is algorithmically impossible, for example because the user prepared the memory resource in the same scope as using the container. Returning results would require a user to implement untestable error handling. Use of these functions implies asserting that memory is sufficient, and failure would be correctly classified as a bug and result in abort.
- Alternative return mode selection: `score::safe_math::ReturnMode`
- Member functions provided as error handling derivatives described above are not provided with their standard library signature.
- Pointer members in container state are persisted via the selected pointer policy: default `score::nothrow::OffsetSlotPolicy` uses `OffsetSlot` / `NullableOffsetSlot`, while `score::nothrow::RawSlotPolicy` uses `RawSlot` for both pointer aliases.
- Pointer parameters, type aliases, and local variables follow the standard/raw-pointer style where possible; wrapping/unwrapping is used only for persisted container state.
- All containers use `score::nothrow::PolymorphicAllocator` as default allocator.
- Error propagation uses `score::nothrow::ContainerErrorCode` and `MakeError(...)`.
- Fallible construction is exposed as static factory methods:
- `Create(...)` returns `score::Result`
- `CreateOrAbort(...)` delegates to `Create(...)` and aborts on error
- `score::nothrow::MemoryResource` / `score::nothrow::PolymorphicAllocator` follow the overall model of `std::pmr::memory_resource` and `std::pmr::polymorphic_allocator`. Their primary purpose is providing a nothrow allocation interface that returns `nullptr` on failure, which is the contract expected by `score::nothrow` containers.
- `score::nothrow::OffsetSlot` / `score::nothrow::NullableOffsetSlot` provide relative-pointer storage semantics (pointer slot with offset encoding).
- `score::nothrow::RawSlot` provides identity-encoded pointer slots for policy-based container experiments and benchmarks.

### Expected Changes ot work products

- [x] Requirements
- [x] Architecture
- [x] Safety Analysis
- [ ] Security Analysis
- [x] Detailed Design
- [x] Implementation and Testing
- [ ] all

### Impact analysis

These C++ container substitutes improve failure handling and deployment safety in no-exception systems, but they do so by making some failures explicit results and others hard aborts. They help safety in three main ways:

- Allocation failure is explicit. Instead of std::bad_alloc or unchecked termination, size-changing operations return `score::Result...`, so out-of-memory can be handled as a normal error path.
- They reduce denial-of-service risk under memory pressure. For code influenced by external input, failed growth can be contained instead of turning into a crash.
- They support zero-copy / shared-memory use cases. Pointer storage policies, especially offset-based ones, make persisted container state usable in SHM-style layouts with fewer process-local assumptions.

The main safety tradeoffs are:

- Some APIs still abort by design. `OrAbort`, `at()`, `front()`, and similar operations treat violated assumptions as bugs, not recoverable runtime events.
- Callers must choose the right mode. Safety depends on using error-returning operations where memory sufficiency is not provable.
- Behavior is safer than standard containers for no-exception code, but not universally more forgiving. The model is “explicit error propagation or deliberate fail-fast,” not silent recovery.

### Safety or Security relevance

- [ ] none
- [x] Safety relevant
- [ ] Security relevant

### Expected required ASIL classification

ASIL_B

### Expected Implementation Version (Release)

1.0

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.