Fact-checked by Grok 2 weeks ago

Bus error

A bus error is a hardware exception in computing systems, particularly in POSIX-compliant operating systems, that occurs when a process attempts to access memory in an invalid way, such as referencing a non-existent physical address, using an unaligned memory access, or encountering an object-specific hardware fault, resulting in the generation of the SIGBUS signal to notify the offending process. The SIGBUS signal, defined as a positive constant in the <signal.h> header, specifically denotes "Access to an undefined portion of a object" and is supported across all implementations. Its default action is abnormal termination of the process, often accompanied by a for debugging purposes. When delivered, SIGBUS provides additional details via the siginfo_t structure, including the faulting in the si_addr field and specific error codes such as BUS_ADRALN for invalid address , BUS_ADRERR for a nonexistent , or BUS_OBJERR for hardware errors tied to a particular object. Bus errors are distinct from segmentation faults (SIGSEGV), which arise from invalid references like accessing unmapped pages; SIGBUS instead signals lower-level hardware bus issues, such as those triggered during memory-mapped I/O operations or when exceeding the bounds of a mapped file beyond its current length. This distinction is architecture-dependent—for instance, on some CPUs, misaligned accesses might trigger SIGSEGV instead—but SIGBUS remains the standard mechanism for bus-related faults. In practice, bus errors commonly manifest in scenarios involving pointer dereferences to invalid or uninitialized memory, unaligned data structures on strict-alignment architectures, or errors in memory-mapped files, and they can be caught and handled by applications using signal handlers like sigaction().

Overview

Definition

A bus error is a hardware-generated exception or fault raised by the (CPU) when it detects a violation of bus protocols during a memory access operation. This notifies the operating system that an attempt to read from or write to has encountered an anomalous condition on the , preventing successful data transfer. The core characteristics of a bus error involve its occurrence specifically during active transactions over the , where mechanisms identify irregularities in the addressing or of the request. Unlike purely software-detected issues, bus errors originate from low-level validation, ensuring immediate intervention to avoid system instability. Historically, the bus error was first formalized in Unix systems via the SIGBUS signal, which was introduced in early versions of Unix, such as Version 4 around 1973–1974. This signal provided a standardized mechanism for handling such hardware exceptions in multitasking environments. In general, a bus error results in program termination unless intercepted and managed by the operating system, setting it apart from other memory-related faults like segmentation violations that may involve software-enforced boundaries.

Relation to Other Faults

A bus error fundamentally differs from a in its underlying mechanism and trigger. While a arises from violations of protections, such as attempting to access an invalid outside a process's or dereferencing a , a bus error originates from hardware-level issues on the memory bus, including attempts to access physically non-addressable memory or violations of bus protocols like unaligned data access. For instance, on architectures enforcing strict , loading an from an not aligned to a word (e.g., an odd ) triggers a bus error due to the hardware's inability to complete the bus transaction properly. In contrast to page faults, which occur when a process accesses a valid virtual address mapped to a page not currently resident in physical memory, bus errors represent typically unrecoverable hardware-detected anomalies that cannot be resolved by the operating system through simple page loading or swapping. Page faults are managed by the OS kernel, which can transparently bring the required page into memory and resume execution, maintaining the illusion of contiguous virtual space; bus errors, however, often lead to process termination via signals like SIGBUS, as they indicate irrecoverable physical access failures. Certain overlap exists between these faults on specific architectures. For example, on x86 processors, accessing an undefined portion of a memory object—such as beyond the end of a memory-mapped file—generates a bus error (SIGBUS), whereas invalid virtual addresses trigger segmentation faults (SIGSEGV).
Fault TypeTriggerRecoverabilityExample Architectures
Bus ErrorHardware bus issues, e.g., unaligned access or non-physical addressTypically unrecoverable (process termination)SPARC, ARM
Segmentation FaultVirtual memory protection violation, e.g., invalid virtual addressUnrecoverable (unless handled by application)x86, most Unix-like systems
Page FaultAccess to valid virtual address with non-resident pageRecoverable (OS loads page)x86, ARM, RISC-V

Causes

Non-Existent or Invalid Addresses

A bus error arises when the (CPU) attempts to perform a read or write operation on a that lies outside the physically addressable range or corresponds to an unmapped region in hardware. In such cases, the memory bus controller detects the invalid access and generates an error signal, interrupting the processor to prevent further execution. This mechanism ensures that attempts to interact with non-existent physical memory are halted at the hardware level, distinguishing it from software-detected errors. Typical scenarios include direct access to non-existent physical addresses, such as through interfaces like /dev/mem in systems, or hardware faults where a valid virtual address translates to an invalid physical one. These examples illustrate how low-level interactions can target inaccessible regions, resulting in the fault. In certain architectures lacking memory-mapped (I/O), treating device s as standard (RAM) provokes a bus error, as these addresses do not map to actual physical memory cells. For instance, in embedded systems without proper I/O mapping, direct attempts to read or write to peripheral addresses as RAM will fail due to the absence of responsive at those locations. The immediate consequence of such an access is a hardware-generated to the operating system's handler, potentially escalating to a system-wide like a kernel panic if the fault occurs in privileged code and remains unhandled. Unlike unaligned access issues, which pertain to data positioning within valid addresses, non-existent address faults fundamentally question the address's existence.

Unaligned Memory Access

Unaligned memory access occurs when a program attempts to read or write multi-byte data from or to a memory address that does not meet the processor's alignment requirements, often triggering a bus error on strict architectures. In processors like ARM and MIPS, alignment rules mandate that data types larger than a byte, such as 16-bit halfwords or 32-bit words, must start at addresses divisible by their size—for instance, a 32-bit integer requires an address that is a multiple of 4. These rules optimize bus transactions by ensuring data fetches align with the processor's word boundaries, preventing partial or split accesses across memory cycles. The bus error is triggered when hardware detects an unaligned request, as the memory bus cannot atomically transfer the full data unit without spanning boundaries, halting the operation and raising an exception. For example, attempting to load a 32-bit value from an odd-byte address on MIPS generates an Address Error exception, which manifests as a bus error in operating systems like Unix-like environments. Similarly, on ARM, unaligned accesses in certain memory regions (e.g., Device memory) or when trapping is enabled via the SCTLR_ELx.A bit result in an alignment fault, equivalent to a bus error signal. Architectural responses to unaligned access differ significantly: x86 processors from generally support it without exceptions, imposing only a performance penalty due to multiple bus cycles, though an optional Alignment Check Exception (#AC) can be enabled via the CR0.AM flag and EFLAGS.AC bit for stricter enforcement. In contrast, architectures, such as UltraSPARC, do not handle misalignment in hardware by default and raise a precise bus error trap, configurable via compiler flags like -xmemalign to either crash or emulate the access in software. similarly enforces strict alignment to maintain high performance, faulting unaligned operations immediately rather than emulating them. In C and C++ programming, unaligned bus errors often stem from subtle issues like pointer arithmetic errors, where an off-by-one calculation shifts a multi-byte access to an unaligned address, or from struct packing directives that ignore natural alignment, placing fields at offsets not divisible by their sizes. For instance, casting a misaligned char pointer to an int pointer without ensuring boundary compliance can invoke undefined behavior on strict platforms, leading to runtime faults. These pitfalls highlight the need for portable code to verify alignment explicitly, as behaviors vary across architectures.

Paging and Virtual Memory Errors

In virtual memory systems, the (MMU) translates virtual addresses to es using page tables, where each page table entry (PTE) specifies whether a virtual page is present in physical memory and maps it to a physical frame if so. A bus error can occur during this process when a valid translation leads to a hardware bus fault, such as accessing a physical address that triggers a machine check (e.g., due to memory corruption detected by ) or an invalid bus protocol violation. This hardware-level violation interrupts the processor before data transfer, distinguishing it from recoverable software-handled faults. Such errors are triggered when the hardware page table walker, invoked on a (TLB) miss, derives a that results in a bus error—for instance, if the access encounters faulty hardware or points to a outside physical bounds. In operating systems like , this manifests as a SIGBUS signal to the process, as the kernel's handler detects the underlying hardware issue and cannot resolve it. Common examples include accessing a "poisoned" page due to hardware errors, where the kernel delivers SIGBUS (BUS_MCEERR_AR or BUS_MCEERR_AO), or reading/writing beyond the current length of a , triggering BUS_OBJERR. Bus errors differ from soft page faults, which occur when a PTE's present bit is unset, allowing the operating system to transparently load the from secondary without user-visible interruption. In contrast, bus errors indicate unrecoverable conditions, such as hardware errors during access to a valid , where the terminates the access attempt rather than servicing it. These are not triggered by mere absence of a page in but by translation failures that expose invalid physical accesses. This phenomenon is prevalent in MMU-equipped architectures, including modern x86 and processors, where the page walker hardware enforces strict validation during translation. It is often exacerbated in dynamic environments like memory hotplug, where offline memory modules leave dangling PTEs pointing to removed frames, or in (NUMA) configurations, where remote node failures during inter-socket transfers can invalidate translations.

Segmentation-Specific Issues

In the segmentation memory model employed by certain architectures, physical memory is divided into variable-sized segments, each defined by a descriptor stored in tables such as the (GDT) or Local Descriptor Table (LDT). These descriptors include attributes like base address, limit, and a Present (P) flag indicating whether the segment is loaded into memory. Accessing a segment with the P flag cleared (P=0) raises the Segment Not Present exception (#NP, interrupt vector 11). In x86 architectures, such non-present descriptors in the GDT or LDT trigger the #NP exception during operations like loading segment registers via instructions such as or during control transfers (e.g., CALL, JMP). This exception is raised before any actual on the bus, preventing invalid operations. However, in operating systems like , the #NP handler delivers a SIGSEGV signal to the offending user process, as it is treated as a rather than a bus error. The error code pushed onto the includes the segment selector index, an external event flag (EXT), and an IDT gate indicator if applicable. Historically, segmentation-specific issues were more prevalent in 32-bit x86 systems (e.g., on 80386 and later processors), where explicit segment management was common for and multitasking. In contrast, 64-bit () largely employs a flat segmentation model with minimal use of segments beyond , , and descriptors, reducing the incidence of #NP exceptions; however, they remain possible in legacy , , or misconfigured virtual environments that rely on non-flat segmentation. When segmentation interacts with paging in x86, a non-present can compound errors if the segment's linear address range violates page boundaries or limits during ; while #NP halts access at the level (leading to SIGSEGV), subsequent attempts to resolve or access within a valid segment may trigger a (#PF) if the underlying pages are absent.

Detection and Handling

Signal Mechanisms in Unix-like Systems

In Unix-like operating systems, bus errors are handled through the SIGBUS signal, a POSIX-defined mechanism for notifying processes of invalid memory access attempts. SIGBUS indicates access to an undefined portion of a memory object, such as misaligned addresses. The signal number for SIGBUS is implementation-defined but commonly 7 on architectures like x86 and . Upon detecting a bus error, the CPU generates a hardware exception, or , due to the faulty operation. The operating system intercepts this exception via its dedicated , evaluates the fault context, and queues a SIGBUS signal for delivery to the user-space process that initiated the access. Signal delivery occurs asynchronously when the process next enters user mode, allowing the to resume execution after handling the interrupt. The default disposition of SIGBUS is to terminate the process abnormally and generate a for purposes. Processes can override this by installing a custom handler using the signal() function for basic setup or sigaction() for advanced control, including access to supplementary signal information. To provide granularity on the error cause, SIGBUS delivery includes variants encoded in the si_code field of the siginfo_t structure passed to handlers. These variants encompass BUS_ADRALN for invalid address alignment errors, BUS_ADRERR for attempts to access nonexistent physical addresses, and BUS_OBJERR for object-specific issues, such as hardware errors in segments.

OS and Hardware Response

At the hardware level, bus controllers or units (MMUs) detect invalid bus cycles, such as attempts to access non-existent addresses or perform unaligned memory operations, and generate corresponding traps or exceptions. In architectures, the processor's bus interface triggers a BusFault exception when an error response is received during instruction or data memory transactions. Similarly, in Intel-based systems, such faults for process memory access are handled through page faults or general exceptions, which may lead to SIGBUS delivery by the in cases like exceeding bounds of memory-mapped files. Machine check exceptions are reserved for detected hardware errors. These hardware mechanisms ensure immediate notification of access violations to prevent further system instability. The operating system's intercepts these hardware-generated exceptions via its exception vector table, which maps interrupt vectors to specific handler functions. Upon invocation, the kernel handler typically logs diagnostic information about the fault, including the faulting address and instruction, before deciding on a course of action—most commonly terminating the offending to isolate the issue. In some environments, handlers may attempt limited recovery, such as isolating the affected component or restarting a task, though this is uncommon due to the risk of cascading failures. For reference, in systems, such interception can lead to delivery of a SIGBUS signal to the process as one form of response. In non-Unix operating systems, similar principles apply but with platform-specific implementations. Windows employs structured (SEH) to manage hardware faults akin to bus errors; for instance, unaligned data access triggers the EXCEPTION_DATATYPE_MISALIGNMENT exception code (0x8000002D), which applications can catch and handle if an exception filter is registered. In embedded real-time operating systems (RTOS) like those for Cortex-M processors, bus faults often escalate to a HardFault if unhandled, prompting responses such as task reset or system isolation to preserve overall functionality. Recovery from bus errors is rare, as these faults signal irrecoverable hardware-level issues like physical inaccessibility, leading predominantly to termination in general-purpose OSes or system halts/resets in critical scenarios to avoid or risks.

Examples and Prevention

Illustrative Code Examples

For unaligned access, which causes a bus error on strict architectures like or that do not support unaligned loads/stores, the following example defines a and accesses a multi-byte field from an unaligned buffer offset. This triggers SIGBUS with code BUS_ADRALN (invalid alignment).
c
#include <stdio.h>
#include <stdint.h>

struct example {
    uint32_t value;  // 4-byte field requiring alignment
};

int main() {
    char buf[5];     // Buffer starts at aligned [address](/page/Address)
    struct example *s = (struct example *)(buf + 1);  // Unaligned [offset](/page/Offset) (e.g., [address](/page/Address) % 4 != 0)
    s->value = 42;   // Access triggers unaligned write
    return 0;
}
On a strict-alignment , running this after compilation yields "Bus error ( dumped)", as the hardware detects the misalignment during the 32-bit write. In the context of , a bus error can occur when accessing an offset beyond the mapped segment size, leading to SIGBUS with code BUS_OBJERR (object-specific error, such as invalid shared memory access). The example below uses shmget to create a small segment and shmat to attach it, then attempts to write beyond its bounds.
c
#include <stdio.h>
#include <sys/shm.h>
#include <sys/types.h>

int main() {
    int shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT | 0666);  // Create 1024-byte segment
    if (shmid == -1) {
        perror("shmget");
        return 1;
    }
    char *shm = shmat(shmid, NULL, 0);  // Attach segment
    if (shm == (char *)-1) {
        perror("shmat");
        return 1;
    }
    shm[2048] = 'x';  // Access unmapped offset (beyond 1024 bytes)
    shmdt(shm);
    shmctl(shmid, IPC_RMID, NULL);
    return 0;
}
Executing this program results in "Bus error (core dumped)" on systems where the overrun is treated as a hardware object error in shared memory.

Strategies to Avoid Bus Errors

Programmers can prevent bus errors, which often arise from unaligned memory access or invalid addresses, by employing compiler directives to enforce proper data alignment in structures and variables. In GCC, the __attribute__((aligned(n))) attribute specifies a minimum alignment of n bytes for a variable or type, where n must be a power of two, ensuring that data structures are placed at addresses compatible with hardware requirements. Similarly, the __attribute__((packed)) attribute minimizes padding between structure members to achieve tight packing, though it should be used cautiously as it may lead to unaligned access on strict architectures if not combined with explicit alignment. These attributes help avoid bus errors by aligning data to natural boundaries, such as 4 or 8 bytes, particularly on architectures like ARM where unaligned access triggers faults. Implementing runtime bounds and pointer validation provides an additional layer of defense against accessing invalid or out-of-bounds , which can precipitate bus errors. Developers should incorporate checks such as verifying pointer non-nullness and ensuring addresses fall within allocated limits before dereferencing, for example, if (ptr != [NULL](/page/Null) && (uintptr_t)addr < (uintptr_t)limit). Tools like Valgrind's Memcheck detect potential issues including invalid reads, writes, and uninitialized values during development, allowing preemptive fixes without runtime faults. Adhering to memory management best practices minimizes risks from improper allocation and pointer manipulation. The malloc() function in POSIX-compliant systems returns pointers aligned suitably for any fundamental type, typically to at least the size of the largest scalar type, reducing alignment-related bus errors when used correctly. To further safeguard against errors, avoid raw pointer arithmetic that could misalign addresses; instead, rely on functions like memcpy() for safe data movement and prefer higher-level abstractions where possible. For cross-platform compatibility, architecture-specific considerations via conditional compilation ensure code handles varying alignment tolerances. On strict architectures like , where unaligned access often causes bus errors, explicit checks or alignments can be enforced using directives such as #ifdef __arm__ to include platform-tailored code, contrasting with more tolerant x86 systems that may silently handle minor misalignments at a performance cost. This approach allows developers to maintain portability while preventing hardware-specific faults.

References

  1. [1]
    <signal.h>
    The `<signal.h>` header defines macros for signals, some extending ISO C, and defines types like `sig_atomic_t` and `sigset_t` related to signals.
  2. [2]
    signal(7) - Linux manual page - man7.org
    Real-time signals are distinguished by the following: • Multiple instances of real-time signals can be queued. By contrast, if multiple instances of a standard ...
  3. [3]
    Interrupt and Exception Handling on x86 - PDOS-MIT
    The CPU generally uses interrupts to handle events ... Hardware exceptions. New addition: Machine Check Exception; Ex: bus errors, data parity errors, etc.
  4. [4]
  5. [5]
    [PDF] Lecture 8: Exceptions, Interrupts, Signals
    Jun 20, 2018 · •When hardware detects an exception a user-defined exception ... • Hardware exceptions include bus error, address error, divide by zero, floating.<|control11|><|separator|>
  6. [6]
    Chris's Wiki :: blog/unix/SignalsHowOld
    Oct 7, 2022 · We have relatively good information as far back as V4 (Fourth Edition), the first version of Unix that was written in C. That version has a ...
  7. [7]
    HTML
    You're used to seeing segmentation faults and you're used to seeing bus error, okay. You've probably seen seg faults more recently in assignments three and ...Missing: page explanation
  8. [8]
    CS 010 - Lecture Notes 1 - Computer Science
    Segmentation fault. This indicates that the value in ptr is not a valid address. · Bus error. This indicates that the pointer is within the appropriate range but ...Structs · I/o · Sample Program
  9. [9]
    [PDF] CS4414 Systems Programming - Cornell: Computer Science
    SIGBUS Bus error (bad memory access). SIGCHLD Child stopped or terminated ... With a segmentation fault, there is no way to “repair” the issue. CORNELL ...
  10. [10]
    [PDF] The Kernel and User Mode - Department of Computer Science and ...
    Segmentation fault (core dumped). Faults are program errors that may be recoverable. ... e.g., page faults to bring in new pages. Other faults may be recoverable ...
  11. [11]
    [PDF] FaultSight: A Fault Analysis Tool for HPC Researchers - Luke Olson
    This table is useful in distinguishing how a program terminates unexpectedly such as through segmentation fault vio- lations or failed assertions. Also knowing ...Missing: explanation | Show results with:explanation
  12. [12]
    Bus faults - Armv8-M Exception Model User Guide
    Bus faults can be triggered by error responses received from the processor bus interface during memory accesses. Bus faults can occur in the following ...Missing: definition | Show results with:definition
  13. [13]
    Segmentation Fault (SIGSEGV) vs Bus Error (SIGBUS)
    Dec 16, 2021 · 2) Bus Error (also known as SIGBUS and is usually signal 10) occur when a process is trying to access memory that the CPU cannot physically ...
  14. [14]
    What is a bus error? Is it different from a segmentation fault?
    Oct 17, 2008 · A bus error is trying to access memory that can't possibly be there. You've used an address that's meaningless to the system, or the wrong kind of address for ...Bus error vs Segmentation fault - Stack OverflowBus error in C Program on Unix machine - Stack OverflowMore results from stackoverflow.com
  15. [15]
    bus error & Segmentation fault - 测试窝
    There are two main causes of bus errors: non-existent address The CPU is instructed by software to read or write a specific physical memory address.Missing: mechanism | Show results with:mechanism
  16. [16]
    Troubleshooting Bus Error Crashes - Cisco
    This document explains how to identify bus error crashes and how to troubleshoot those crashes depending on the type of processor you have in your Cisco router.<|separator|>
  17. [17]
    Alignment - Arm Developer
    An access is described as aligned if the address is a multiple of the element size. For LDR and STR instructions, the element size is the size of the access.
  18. [18]
    [PDF] MIPS IV Instruction Set
    and access type; if the required translation is not present in the TLB or the desired access is not permitted the function fails and an exception is taken.
  19. [19]
    Unaligned Memory Accesses — The Linux Kernel documentation
    Unaligned memory accesses occur when you try to read N bytes of data starting from an address that is not evenly divisible by N (i.e. addr % N != 0). For ...
  20. [20]
  21. [21]
    On misaligned memory accesses - Oracle Blogs
    May 31, 2006 · An application can be compiled to either crash on a misaligned memory accesses, or trap to software to correct the alignment.Missing: bus | Show results with:bus
  22. [22]
    Data Alignment Across Architectures: The Good, The Bad And The ...
    May 10, 2022 · The memory controller will generate a bus error when it is asked to access an invalid address, stumbles across a paging error, or is asked to ...Missing: SPARC | Show results with:SPARC
  23. [23]
    Unaligned accesses in C/C++: what, why and solutions to do it ...
    Oct 16, 2018 · The LDMIA instruction is loading data from memory into multiple registers. In our case, it loads our 64-bit integer into two 32-bit registers.
  24. [24]
    [PDF] Virtual Memory - Higher Education | Pearson
    Table 4.1 summarizes key virtual-memory and page-table parameters as a function of the ... kernel should send a bus error signal (SIGBUS) to the process.<|control11|><|separator|>
  25. [25]
    [PDF] Virtual Memory We hav e stated that a UNIX process ... - Cooper Union
    Page Table Entries (PTEs). The starting physical address of this array is ... Bus Error: The kernel was unable to page-in the page because of an error ...
  26. [26]
    hwpoison — The Linux Kernel documentation
    ### Summary: When SIGBUS is Sent in Virtual Memory Contexts
  27. [27]
    MMU faults - Arm Developer
    Translation fault​​ This is generated if the first-level descriptor is marked as invalid. This happens if bits [1:0] of the descriptor are: 0b00, the fault ...Missing: bus | Show results with:bus<|separator|>
  28. [28]
    [PDF] Intel® 64 and IA-32 Architectures Software Developer's Manual
    Intel technologies features and benefits depend on system configuration and may require enabled hardware, software, or service activation. Learn more at intel.
  29. [29]
    sigaction(2) - Linux manual page - man7.org
    The following values can be placed in si_code for a SIGBUS signal: BUS_ADRALN Invalid address alignment. BUS_ADRERR Nonexistent physical address. BUS_OBJERR ...Missing: variants | Show results with:variants
  30. [30]
    Unaligned Memory Accesses — The Linux Kernel documentation
    ### Summary of Unaligned Access Causing Bus Errors in Linux
  31. [31]
    Does unaligned memory access always cause bus errors?
    Sep 30, 2009 · According to the Wikipedia page Segmentation fault, a bus error can be caused by unaligned memory access.What is a bus error? Is it different from a segmentation fault?Why does x86 allows for unaligned accesses, and ... - Stack OverflowMore results from stackoverflow.comMissing: MIPS | Show results with:MIPS
  32. [32]
    Intermittent SIGBUS on shared memory segment - Stack Overflow
    Apr 13, 2022 · I have a server process that allocates a big chunk of memory using the System V XSI shared memory calls (shmget/shmat), from address to ...shmget size limit issue - c++ - Stack OverflowWhat is a bus error? Is it different from a segmentation fault?More results from stackoverflow.comMissing: bus beyond
  33. [33]
    Common Type Attributes (Using the GNU Compiler Collection (GCC))
    The aligned attribute specifies a minimum alignment (in bytes) for variables of the specified type. When specified, alignment must be a power of 2. Specifying ...
  34. [34]
    Unaligned data access in C and C++ code - Arm Developer
    The ARM compiler generates assembly language code that reads the word using an LDR instruction. This works as expected when the address is a multiple of four.
  35. [35]
    4. Memcheck: a memory error detector - Valgrind
    Memcheck is a memory error detector. It can detect the following problems that are common in C and C++ programs. Incorrect freeing of heap memory.
  36. [36]
    malloc
    The following new requirements on POSIX implementations derive from alignment with the Single UNIX Specification: In the RETURN VALUE section, the ...
  37. [37]