| (code_style)= | |
| # The libc code style | |
| ## Naming style | |
| For the large part, the libc project follows the general [coding standards of | |
| the LLVM project](https://llvm.org/docs/CodingStandards.html). The libc | |
| project differs from that standard with respect to the naming style. The | |
| differences are as follows: | |
| 1. **Non-const variables** - This includes function arguments, struct and | |
| class data members, non-const globals and local variables. They all use the | |
| `snake_case` style. | |
| 2. **const and constexpr variables** - They use the capitalized | |
| `SNAKE_CASE` irrespective of whether they are local or global. | |
| 3. **Function and methods** - They use the `snake_case` style like the | |
| non-const variables. | |
| 4. **Internal type names** - These are types which are internal to the libc | |
| implementation. They use the `CaptilizedCamelCase` style. | |
| 5. **Public names** - These are the names as prescribed by the standards and | |
| will follow the style as prescribed by the standards. | |
| ## Macro style | |
| We define two kinds of macros: | |
| 1. **Build defined** macros are generated by `CMake` or `Bazel` and are passed | |
| down to the compiler with the `-D` command line flag. They start with the | |
| `LIBC_COPT_` prefix. They are used to tune the behavior of the libc. | |
| They either denote an action or define a constant. | |
| 2. **Code defined** macros are defined within the `src/__support/macros` | |
| folder. They all start with the `LIBC_` prefix. | |
| - `src/__support/macros/properties/` - Build related properties like | |
| target architecture or enabled CPU features defined by introspecting | |
| compiler defined preprocessor definitions. | |
| - `architectures.h` - Target architecture properties. | |
| e.g., `LIBC_TARGET_ARCH_IS_ARM`. | |
| - `compiler.h` - Host compiler properties. | |
| e.g., `LIBC_COMPILER_IS_CLANG`. | |
| - `cpu_features.h` - Target cpu feature availability. | |
| e.g., `LIBC_TARGET_CPU_HAS_AVX2`. | |
| - `types.h` - Type properties and availability. | |
| e.g., `LIBC_TYPES_HAS_NATIVE_FLOAT128`. | |
| - `os.h` - Target os properties. | |
| e.g., `LIBC_TARGET_OS_IS_LINUX`. | |
| - `src/__support/macros/config.h` - Important compiler and platform | |
| features. Such macros can be used to produce portable code by | |
| parameterizing compilation based on the presence or lack of a given | |
| feature. e.g., `LIBC_HAS_FEATURE` | |
| - `src/__support/macros/attributes.h` - Attributes for functions, types, | |
| and variables. e.g., `LIBC_UNUSED` | |
| - `src/__support/macros/optimization.h` - Portable macros for performance | |
| optimization. e.g., `LIBC_LIKELY`, `LIBC_LOOP_NOUNROLL` | |
| ## Inline functions and variables defined in header files | |
| When defining functions and variables inline in header files, we follow certain | |
| rules: | |
| 1. The functions should not be given file-static linkage. There can be class | |
| static methods defined inline however. | |
| 2. Instead of using the `inline` keyword, functions should be tagged with the | |
| `LIBC_INLINE` macro and variables should be tagged with the | |
| `LIBC_INLINE_VAR` macro defined in `src/__support/macros/attributes.h`. | |
| For example: | |
| ```c++ | |
| LIBC_INLINE_VAR constexpr bool foo = true; | |
| LIBC_INLINE ReturnType function_defined_inline(ArgType arg) { | |
| ... | |
| } | |
| ``` | |
| 3. The `LIBC_INLINE` tag should also be added to functions which have | |
| definitions that are implicitly inline. Examples of such functions are | |
| class methods (static and non-static) defined inline and `constexpr` | |
| functions. | |
| (setting_errno)= | |
| ## Setting `errno` from runtime code | |
| Many libc functions set `errno` to indicate an error condition. If LLVM's libc | |
| is being used as the only libc, then the `errno` from LLVM's libc is affected. | |
| If LLVM's libc is being used in {ref}`overlay_mode`, then the `errno` from | |
| the system libc is affected. When a libc function that can potentially affect | |
| `errno` is called from a unit test, we do not want the global `errno` | |
| (as in, the `errno` of the process thread running the unit test) to be | |
| affected. If the global `errno` is affected, then the operation of the unit | |
| test infrastructure itself can be affected. | |
| To handle `errno` correctly across all build modes and avoid silent thread-local | |
| storage mismatches, the following rules must be followed: | |
| 1. **Header Inclusion:** | |
| Runtime code and unit tests must **ONLY** `#include "src/__support/libc_errno.h"` | |
| and refer to `libc_errno`. | |
| - Never `#include <errno.h>`. | |
| - Never `#include "src/errno/libc_errno.h"` (this is a legacy path; the header | |
| lives in `src/__support/`). | |
| - For standard error constants (such as `EINVAL`, `ENOMEM`), include | |
| `"hdr/errno_macros.h"`. | |
| Setting `errno` should be done directly via `libc_errno`: | |
| ```c++ | |
| libc_errno = EINVAL; | |
| ``` | |
| 2. **Where to set `errno`:** | |
| `errno` should only be set just before returning from the implementation of | |
| the public function. It should not be set from within helper functions. Helper | |
| functions should use idiomatic C++ constructs like | |
| [cpp::optional](https://github.com/llvm/llvm-project/blob/main/libc/src/__support/CPP/optional.h) | |
| and | |
| [ErrorOr](https://github.com/llvm/llvm-project/blob/main/libc/src/__support/error_or.h) | |
| to return error values. | |
| 3. **CMake Dependencies for Public Entrypoints:** | |
| Any entrypoint that reads or sets `errno` should ideally declare **BOTH** of the | |
| following in the `DEPENDS` list of its `add_entrypoint_object`: | |
| - **`libc.src.__support.libc_errno`**: Satisfies the header dependency for | |
| `src/__support/libc_errno.h`. | |
| - **`libc.src.errno.errno`**: Satisfies the link-time requirement for the compiled | |
| runtime storage (`libc_errno.cpp`) defining `thread_errno`, `__llvm_libc_errno()`, | |
| and the C++ `Errno` class. | |
| While LLVM-libc generally disallows dependencies between public entrypoints, | |
| `libc.src.errno.errno` is an **explicitly allowed exception** in the build system | |
| (see `ALLOWED_DEPS` in `libc/cmake/modules/LLVMLibCObjectRules.cmake`). Downstream | |
| consumers and test suites that link the entrypoint require this dependency so that | |
| the storage for `libc_errno` is linked. | |
| 4. **CMake Dependencies for Internal Support Libraries:** | |
| Header-only utility libraries under `libc/src/__support/` (such as `OSUtil` syscall | |
| wrappers or `FPUtil`) that reference `libc_errno.h` should depend on | |
| **`libc.src.__support.libc_errno`** so they remain pure header libraries without | |
| introducing compiled entrypoint object dependencies. | |
| 5. **Unit and Hermetic Testing:** | |
| Unit tests verifying functions that set `errno` must use the `ErrnoCheckingTest` | |
| fixture (`test/UnitTest/ErrnoCheckingTest.h`) and `ErrnoSetterMatcher` | |
| (`test/UnitTest/ErrnoSetterMatcher.h`). | |
| - Both `ErrnoCheckingTest` and `ErrnoSetterMatcher` already declare `DEPENDS libc.src.errno.errno`, | |
| so tests using them inherit the compiled `errno` object transitively. | |
| - Tests that check `libc_errno` directly without those matchers must declare | |
| `libc.src.errno.errno` in their test `DEPENDS`. | |
| - Tests must never `#include <errno.h>`. | |
| 6. **The "Dual-TLS" Pitfall in Overlay Mode:** | |
| Why is strictly adhering to `libc_errno` and `"src/__support/libc_errno.h"` critical? | |
| In overlay mode, the host system libc (e.g., glibc) maintains its own thread-local | |
| `errno` location (accessed via `*__errno_location()`). In unit tests, LLVM-libc | |
| runs in internal thread-local mode (`LIBC_ERRNO_MODE_THREAD_LOCAL`), writing to | |
| LLVM-libc's own `thread_errno`. | |
| If implementation code or tests mistakenly `#include <errno.h>` and use raw `errno`, | |
| the code will compile cleanly without warnings, but reads and writes will target | |
| different thread-local storage locations in the same thread. This results in silent | |
| test failures or error values that appear to vanish or go to the wrong thread. | |
| (expected_and_optional)= | |
| ## Accessing values from `cpp::expected`, `ErrorOr`, and `cpp::optional` | |
| Because LLVM-libc builds with `-fno-exceptions`, | |
| [`cpp::expected`](https://github.com/llvm/llvm-project/blob/main/libc/src/__support/CPP/expected.h) | |
| (along with `ErrorOr<T>`, which aliases `cpp::expected<T, int>`) and | |
| [`cpp::optional`](https://github.com/llvm/llvm-project/blob/main/libc/src/__support/CPP/optional.h) | |
| cannot throw on invalid access. Instead, their observers provide two distinct | |
| safety contracts: | |
| - **`.value()` and `.error()` are checked in all build modes:** Calling | |
| `.value()` when `!has_value()` (or `.error()` on `cpp::expected` when | |
| `has_value()`) unconditionally executes `__builtin_trap()`, including in | |
| release (`NDEBUG`) builds. | |
| - **`operator*` and `operator->` are unchecked in release builds:** They trap | |
| under `#ifndef NDEBUG` when `!has_value()` to catch bugs during testing, and | |
| compile to direct member access with no check in release builds. | |
| Choose between them as follows: | |
| 1. **Prefer `*` and `->` after an explicit check:** Once `has_value()` or | |
| `operator bool` has been checked, prefer `*res` and `res->member`, especially | |
| in performance-sensitive paths (such as math or formatting fast paths) and | |
| whenever accessing members of the contained object (`res->field` rather than | |
| `res.value().field`). When the unwrapped value is needed more than once in a | |
| scope, bind it to a local variable instead of unwrapping repeatedly: | |
| ```c++ | |
| auto res = linux_syscalls::open(path, flags, mode); | |
| if (!res) { | |
| libc_errno = res.error(); | |
| return -1; | |
| } | |
| int fd = *res; | |
| ``` | |
| 2. **Use `.value()` when relying on an invariant without a branch:** If an | |
| algorithm or API invariant guarantees that a value is present and you | |
| intentionally omit an `if (!res)` check, you **must** use `.value()` rather | |
| than `*res`. That ensures any unexpected violation traps deterministically | |
| in release builds instead of reading an inactive union member. | |
| 3. **`.value()` is also acceptable for readability on `bool` or pointer types:** | |
| After a dominating `if (!res)` check, writing `if (!res.value())` on | |
| `ErrorOr<bool>` or `FILE *stream = res.value();` on `ErrorOr<FILE *>` avoids | |
| visually ambiguous `!*res` expressions or confusion between unwrapping the | |
| container and dereferencing the pointer. Under optimization, jump-threading | |
| eliminates the redundant check in `res.value()` when no opaque calls | |
| intervene. | |
| ## Assertions in libc runtime code | |
| The libc developers should, and are encouraged to, use assertions freely in | |
| the libc runtime code. However, the assertion should be listed via the macro | |
| `LIBC_ASSERT` defined in `src/__support/libc_assert.h`. This macro can be | |
| used from anywhere in the libc runtime code. Internally, all it does is to | |
| print the assertion expression and exit. It does not implement the semantics | |
| of the standard `assert` macro. Hence, it can be used from any where in the | |
| libc runtime code without causing any recursive calls or chicken-and-egg | |
| situations. | |
| ## Allocations in the libc runtime code | |
| Some libc functions allocate memory. For example, the `strdup` function | |
| allocates new memory into which the input string is duplicated. Allocations | |
| are typically done by calling a function from the `malloc` family of | |
| functions. Such functions can fail and return an error value to indicate | |
| allocation failure. To conform to standards, the libc should handle | |
| allocation failures gracefully and surface the error conditions to the user | |
| code as appropriate. Since LLVM's libc is implemented in C++, we want | |
| allocations and deallocations to employ C++ operators `new` and `delete` | |
| as they implicitly invoke constructors and destructors respectively. However, | |
| if we use the default `new` and `delete` operators, the libc will end up | |
| depending on the C++ runtime. To avoid such a dependence, and to handle | |
| allocation failures gracefully, we use special `new` and `delete` operators | |
| defined in | |
| [`src/__support/CPP/new.h`](https://github.com/llvm/llvm-project/blob/main/libc/src/__support/CPP/new.h). | |
| Allocations and deallocations using these operators employ a pattern like | |
| this: | |
| ```c++ | |
| #include "src/__support/CPP/new.h" | |
| #include "src/__support/alloc-checker.h" | |
| ... | |
| LIBC_NAMESPACE::AllocChecker ac; | |
| auto *obj = new (ac) Type(...); | |
| if (!ac) { | |
| // handle allocator failure. | |
| } | |
| ... | |
| delete obj; | |
| ``` | |
| The only exception to using the above pattern is if allocating using the | |
| `realloc` function is of value. In such cases, prefer to use only the | |
| `malloc` family of functions for allocations and deallocations. Allocation | |
| failures will still need to be handled gracefully. Further, keep in mind that | |
| these functions do not call the constructors and destructors of the | |
| allocated/deallocated objects. So, use these functions carefully and only | |
| when it is absolutely clear that constructor and destructor invocation is | |
| not required. | |
| ## Warnings in sources | |
| We expect contributions to be free of warnings from the [minimum supported | |
| compiler versions](../compiler_support.md#minimum-supported-versions) (and newer). | |
| ## Header Inclusion Policy | |
| Because llvm-libc supports | |
| [Overlay Mode](../overlay_mode.md), | |
| [Full Host Build Mode](../full_host_build.md) and | |
| [Full Cross Build Mode](../full_cross_build.md) care | |
| must be taken when `#include`'ing certain headers. | |
| The `include/` directory contains public facing headers that users must | |
| consume for fullbuild mode. As such, types defined here will have ABI | |
| implications as these definitions may differ from the underlying system for | |
| overlay mode and are NEVER appropriate to include in `libc/src/` without | |
| preprocessor guards for `LLVM_LIBC_FULL_BUILD`. | |
| Consider the case where an implementation in `libc/src/` may wish to refer to | |
| a `sigset_t`, what header should be included? `<signal.h>`, `<spawn.h>`, | |
| `<sys/select.h>`? | |
| None of the above. Instead, code under `src/` should `#include | |
| "hdr/types/sigset_t.h"` which contains preprocessor guards on | |
| `LLVM_LIBC_FULL_BUILD` to either include the public type (fullbuild mode) or | |
| the underlying system header (overlay mode). | |
| Implementations in `libc/src/` should NOT be `#include`'ing using `<>` or | |
| `"include/*`, except for these "proxy" headers that first check for | |
| `LLVM_LIBC_FULL_BUILD`. | |
| These "proxy" headers are similarly used when referring to preprocessor | |
| defines. Code under `libc/src/` should `#include` a proxy header from | |
| `hdr/`, which contains a guard on `LLVM_LIBC_FULL_BUILD` to either include | |
| our header from `libc/include/` (fullbuild) or the corresponding underlying | |
| system header (overlay). | |
| ## Policy on Assembly sources | |
| Coding in high level languages such as C++ provides benefits relative to low | |
| level languages like Assembly, such as: | |
| - Improved safety | |
| - Compile time diagnostics | |
| - Instrumentation | |
| - Code coverage | |
| - Profile collection | |
| - Sanitization | |
| - Automatic generation of debug info | |
| While it's not impossible to have Assembly code that correctly provides all of | |
| the above, we do not wish to maintain such Assembly sources in llvm-libc. | |
| That said, there are a few functions provided by llvm-libc that are impossible | |
| to reliably implement in C++ for all compilers supported for building | |
| llvm-libc. | |
| We do use inline or out-of-line Assembly in an intentionally minimal set of | |
| places; typically places where the stack or individual register state must be | |
| manipulated very carefully for correctness, or instances where a specific | |
| instruction sequence does not have a corresponding compiler builtin function | |
| today. | |
| Contributions adding functions implemented purely in Assembly for performance | |
| are not welcome. | |
| Contributors should strive to stick with C++ for as long as it remains | |
| reasonable to do so. Ideally, bugs should be filed against compiler vendors, | |
| and links to those bug reports should appear in commit messages or comments | |
| that seek to add Assembly to llvm-libc. | |
| Patches containing any amount of Assembly ideally should be approved by 2 | |
| maintainers. llvm-libc maintainers reserve the right to reject Assembly | |
| contributions that they feel could be better maintained if rewritten in C++, | |
| and to revisit this policy in the future. | |
| ## LIBC_NAMESPACE_DECL | |
| llvm-libc provides a macro `LIBC_NAMESPACE` which contains internal implementations of | |
| libc functions and globals. This macro should only be used as an | |
| identifier for accessing such symbols within the namespace (like `LIBC_NAMESPACE::cpp::max`). | |
| Any usage of this namespace for declaring or defining internal symbols should | |
| instead use `LIBC_NAMESPACE_DECL` which declares `LIBC_NAMESPACE` with hidden visibility. | |
| Example usage: | |
| ```c++ | |
| #include "src/__support/macros/config.h" // The macro is defined here. | |
| namespace LIBC_NAMESPACE_DECL { | |
| void new_function() { | |
| ... | |
| } | |
| } // LIBC_NAMESPACE_DECL | |
| ``` | |
| Having hidden visibility on the namespace ensures extern declarations in a given TU | |
| have known visibility and never generate GOT indirections. The attribute guarantees | |
| this independently of global compile options and build systems. | |
| (clang_tidy_checks)= | |
| ## Static Analysis & Clang-Tidy | |
| ### Configuration | |
| LLVM libc uses layered `.clang-tidy` configuration files: | |
| - `libc/.clang-tidy`: baseline checks for the `libc` subtree (currently | |
| focuses on identifier naming conventions). | |
| - `libc/src/.clang-tidy`: adds LLVM-libc-specific checks (`llvmlibc-*`) for | |
| implementation code under `libc/src` and also enables | |
| `readability-identifier-naming` and `llvm-header-guard`. Diagnostics from | |
| `llvmlibc-*` checks are treated as errors. | |
| ### Running the checks | |
| Configure with `-DLLVM_LIBC_ENABLE_LINTING=ON` and build the `libc-lint` | |
| target. CMake looks for `clang-tidy` in the LLVM tools directory first (the | |
| build tree in a bootstrapping build, so the freshly built `clang-tidy` wins) | |
| and then on `PATH`. The `clang-tidy` it finds must have the same major | |
| version as the compiler, because `clang-tidy` carries its own clang front end | |
| and a mismatch shows up as spurious diagnostics. To use a specific binary, | |
| pass `-DLLVM_LIBC_CLANG_TIDY=<path>`; this also turns linting on, and a | |
| version mismatch is then reported as a warning rather than an error. | |
| The `.clang-tidy` files and the `llvmlibc-*` checks live in the same | |
| repository and change together, so the configuration is written for the | |
| `clang-tidy` built from the same revision as the libc sources, not for the | |
| latest release. An older `clang-tidy` does not fail loudly on a newer | |
| configuration: it ignores checks and check options it does not know, and | |
| releases up to at least 21 react to an unknown top-level key by discarding | |
| the file and running their default checks, exiting 0 either way. Results | |
| from an older `clang-tidy` are therefore not comparable with a build at the | |
| same revision. To match, add `clang-tools-extra` to a bootstrapping build | |
| and point `LLVM_LIBC_CLANG_TIDY` at the `clang-tidy` it produces; | |
| `clang-tidy --verify-config --config-file=libc/src/.clang-tidy` reports | |
| anything your `clang-tidy` would silently skip. | |
| A configuration that asks for linting but cannot run it (no `clang-tidy`, a | |
| non-clang compiler, or a discovered `clang-tidy` of the wrong major version) | |
| fails to configure. There is no mode in which `libc-lint` exists but does | |
| nothing, so a green `libc-lint` build always means the checks ran. | |
| ### LLVM-libc checks | |
| ### restrict-system-libc-headers | |
| Check name: `llvmlibc-restrict-system-libc-headers`. | |
| One of libc-project's design goals is to use kernel headers and compiler | |
| provided headers to prevent code duplication on a per platform basis. This | |
| presents a problem when writing implementations since system libc headers are | |
| easy to include accidentally and we can't just use the `-nostdinc` flag. | |
| Improperly included system headers can introduce runtime errors because the C | |
| standard outlines function prototypes and behaviors but doesn't define | |
| underlying implementation details such as the layout of a struct. | |
| This check prevents accidental inclusion of system libc headers when writing a | |
| libc implementation. | |
| ```c++ | |
| #include <stdio.h> // Not allowed because it is part of system libc. | |
| #include <stddef.h> // Allowed because it is provided by the compiler. | |
| #include "internal/stdio.h" // Allowed because it is NOT part of system libc. | |
| ``` | |
| ### implementation-in-namespace | |
| Check name: `llvmlibc-implementation-in-namespace`. | |
| All LLVM-libc implementation constructs must be enclosed in the | |
| `LIBC_NAMESPACE_DECL` namespace. See {ref}`code_style` for the full technical | |
| rationale and macro definitions. | |
| This check ensures that top-level declarations in a translation unit are | |
| enclosed within the `LIBC_NAMESPACE_DECL` namespace. | |
| ```c++ | |
| // Correct: implementation inside the correct namespace. | |
| namespace LIBC_NAMESPACE_DECL { | |
| LLVM_LIBC_FUNCTION(char *, strcpy, (char *dest, const char *src)) {} | |
| // Namespaces within LIBC_NAMESPACE namespace are allowed. | |
| namespace inner{ | |
| int localVar = 0; | |
| } | |
| // Functions with C linkage are allowed. | |
| extern "C" void str_fuzz(){} | |
| } | |
| // Incorrect: implementation not in a namespace. | |
| LLVM_LIBC_FUNCTION(char *, strcpy, (char *dest, const char *src)) {} | |
| // Incorrect: outer most namespace is not correct. | |
| namespace something_else { | |
| LLVM_LIBC_FUNCTION(char *, strcpy, (char *dest, const char *src)) {} | |
| } | |
| ``` | |
| ### callee-namespace | |
| Check name: `llvmlibc-callee-namespace`. | |
| LLVM-libc is distinct because it is designed to maintain interoperability with | |
| other libc libraries, including the one that lives on the system. This feature | |
| creates some uncertainty about which library a call resolves to especially when | |
| a public header with non-namespaced functions like `string.h` is included. | |
| This check ensures any function call resolves to a function within the | |
| LIBC_NAMESPACE namespace. | |
| There are exceptions for the following functions: | |
| `__errno_location` so that `errno` can be set; | |
| `malloc`, `calloc`, `realloc`, `aligned_alloc`, and `free` since they | |
| are always external and can be intercepted. | |
| ```c++ | |
| namespace LIBC_NAMESPACE_DECL { | |
| // Disallow calls to the public versions with the LIBC_NAMESPACE. | |
| LIBC_NAMESPACE::strlen("hello"); | |
| // Allow calls to compiler provided functions. | |
| (void)__builtin_abs(-1); | |
| // Disallow bare calls. | |
| strlen("world"); | |
| // Disallow calling into functions in the global namespace. | |
| ::strlen("!"); | |
| // Allow calling into specific global functions (explained above). | |
| ::malloc(10); | |
| } // namespace LIBC_NAMESPACE_DECL | |
| ``` | |
| ### inline-function-decl | |
| Check name: `llvmlibc-inline-function-decl`. | |
| LLVM libc uses the `LIBC_INLINE` macro to tag inline function declarations in | |
| headers. This check enforces that any inline function declaration in a header | |
| begins with `LIBC_INLINE` and provides a fix-it to insert the macro. |