Static Resource Allocation in Functional Safety — IEC 61508

31 August 2025 · Dr. Michel Houtermans · 5 min read

Static resource allocation is a software design technique where all memory and resources are reserved at compile-time — with no dynamic allocation at runtime. It eliminates a whole class of systematic failures related to unpredictable memory behaviour, making it a core technique for safety-related software under IEC 61508.

What is static resource allocation?

Static resource allocation means all variables, objects, and buffers are allocated at compile-time. No dynamic variables or objects are created while the program runs. Because the memory layout is fixed, the compiler and static analysis tools can verify sizes and addresses, and the system avoids runtime effects such as fragmentation or allocation failure.

How it supports functional safety

By eliminating runtime allocation, the technique removes a whole class of systematic failures related to unpredictable memory behaviour — insufficient heap, undetected overlay or overwrite, and allocator defects.

With a fixed layout, timing remains deterministic and verification becomes simpler. Although it primarily addresses systematic issues, the fixed structure also makes it easier to detect manifestations of random or common-cause hardware faults in memory (e.g. stuck bits), because expected addresses and bounds are known and can be checked.

The key question is: can you prove that your safety-related software never allocates memory at runtime — including in third-party libraries?

When to use

  • Safety functions must meet strict real-time deadlines and worst-case execution time analysis
  • The standard or safety case restricts dynamic allocation (e.g. IEC 61508-3 Tables A.2/B.1; Annex C.2.6.3)
  • Independent verification needs a static, auditable memory map and bounded resource usage

Inputs and outputs

Inputs

  • Hardware memory map (RAM/flash, stack limits, MMU/MPU configuration)
  • Worst-case resource demands (buffers, task stacks, queues, tables)

Outputs

  • Fixed allocation plan (symbols, sections, linker script)
  • Evidence: compiler maps, static-analysis reports, and allocation ban checks

Procedure

  1. Inventory memory needs. Enumerate all buffers, task stacks, message queues, and persistent objects. Define credible worst-case sizes.
  2. Design the layout. Assign static storage (globals, static locals, fixed-size pools). Define sections in the linker script (e.g. .bss, .data, dedicated IO buffers).
  3. Ban dynamic allocation. Remove and forbid malloc/calloc/realloc/free, new/delete. Configure build rules and LINT to fail on use — including in third-party libraries.
  4. Prove bounds. Add compile-time asserts and runtime guards. Generate and review the map file. Verify each buffer has explicit bounds checks at interfaces.
  5. Validate timing. Measure worst-case execution time with the static layout. Confirm no allocation hotspots exist in task paths.
  6. Document and test. Record assumptions, margins, and safe reactions for overflow conditions. Include unit and integration tests that exercise near-capacity cases.
Certification evidence goes beyond "no malloc." Show that all credible worst-case sizes are justified and tested, and that third-party components are audited for hidden allocators.

Worked example — reactor feed valve controller

A safety PLC regulates a reactor feed valve. Loss or corruption of control data due to heap exhaustion could leave the valve command undefined. By allocating fixed-size input/output buffers and prohibiting dynamic allocation, the control loop always has memory, and any oversize frame is detected and handled safely.

Code-level example

// Example: static buffers and bounds checks (C-like)

#define RX_FRAME_MAX 64
#define TX_FRAME_MAX 64
static uint8_t rx_frame[RX_FRAME_MAX];
static uint8_t tx_frame[TX_FRAME_MAX];

bool handle_rx(const uint8_t* data, size_t len) {
    if (len > RX_FRAME_MAX) {
        // SAFE REACTION: discard frame, raise diagnostic, hold last known safe output
        raise_diagnostic(DIAG_RX_OVERSIZE);
        return false;
    }
    memcpy(rx_frame, data, len);
    return true;
}

void control_step(void) {
    // No dynamic allocation anywhere in the control path
    size_t out_len = build_command(tx_frame, TX_FRAME_MAX);
    if (out_len == 0) {
        // SAFE REACTION: enter safe state (close valve)
        command_valve(CLOSE_VALVE);
    } else {
        send_command(tx_frame, out_len);
    }
}

Quality criteria

  • Determinism: No runtime allocation in safety-related paths; timing shown for worst-case conditions.
  • Completeness: Every buffer, stack, and queue has a justified size and documented headroom margin.
  • Verification: Automated checks (lint/build rules) enforce allocator ban; map file and static-analysis reports reviewed.
  • Protection: Bounds checks at all interfaces; safe reactions specified, implemented, and tested.

Common pitfalls

Hidden allocators in libraries

Third-party libraries may call malloc internally without documenting it.

Mitigation: Audit dependencies. Link with stubs that fail the build on allocation calls.

Underestimated worst case leading to overflow

Buffer sizes based on typical conditions rather than credible worst-case scenarios.

Mitigation: Derive sizes from credible worst-case scenarios. Add assertions and tests at capacity limits.

Excessive over-allocation wastes RAM

Defensive over-sizing consumes memory needed by other functions.

Mitigation: Iterate sizing with measurements. Separate safety-critical from non-critical buffers.

Assuming "static" implies "safe"

Static allocation alone does not prevent out-of-bounds writes or data corruption.

Mitigation: Still implement bounds checks, diagnostics, and safe reactions.

Frequently asked questions

Does IEC 61508 always forbid dynamic memory?

No. It requires restrictions where dynamic behaviour cannot be accurately predicted by static analysis. Many safety cases choose a full ban in safety-related paths to simplify assurance.

How do I deal with variable-length payloads without malloc?

Use fixed-size buffers with length fields, ring buffers, or statically sized memory pools. Validate lengths and apply safe reactions on overflow.

Can I mix static allocation in safety code with dynamic allocation elsewhere?

Yes, if freedom-from-interference is demonstrated (e.g. MPU/partitioning) so non-safety allocation cannot impact safety resources.

What evidence should I keep for audits?

Allocator ban rules, dependency audits, linker map files, static-analysis reports, worst-case sizing rationale, and tests showing correct safe reactions at capacity.

Related techniques

  • Defensive programming — complements static allocation with explicit checks and safe defaults
  • Range checks — ensures inputs never exceed fixed buffer sizes

References

  • IEC 61508-3:2010 — Tables A.2/B.1; Annex C.2.6.3
  • MISRA C — Guidelines for the Use of the C Language in Critical Systems
  • ISO 26262-6:2018 — Product development at the software level

Go deeper — IEC 61508 Certification Course

Our IEC 61508 course covers software safety techniques, architectural design, SIL verification, and safety case preparation — for engineers building safety-related systems.

Explore the course → Ask us a question
We use cookies
Cookie preferences
Below you may find information about the purposes for which we and our partners use cookies and process data. You can exercise your preferences for processing, and/or see details on our partners' websites.
Analytical cookies Disable all
Functional cookies
Other cookies
We use cookies to personalize content and ads, to provide social media features and to analyze our traffic. Learn more about our cookie policy.
Accept all Decline all Change preferences
Cookies