Scope: Tranche A (000–011) patterns observed during 2026-05-07 hardening audit.
Purpose: Document the conventions that are followed, and explicitly call out exceptions with file/line references.
Audience: Contributors writing new modules or refactoring existing ones during the hardening campaign.
Use snake_case for all identifiers.
Pattern:
fio_url_parse(...)
fio_string_write(...)
fio_thread_mutex_lock(...)Exceptions:
- Macro-template APIs require consumer-defined prefixes (
FIO_SORT_NAME,FIO_IMAP_*). These are UPPER_SNAKE_CASE by necessity. - The memory allocator uses
FIO_NAME(FIO_MEMORY_NAME, malloc)macro namespacing in010 mem.h. This is intentional (supports multiple allocator instances) but is the only macro-namespaced public API in Tranche A.
Pattern: fio_xxx_s for structs, fio_xxx_e for enums.
| Type | File |
|---|---|
fio_str_info_s |
011 string core.h |
fio_buf_info_s |
000 core.h |
fio_url_s |
002 url.h |
fio_json_parser_s |
004 json.h |
fio_cli_arg_e |
005 cli.h |
Exception: fio_socket_i in 004 sock.h is a typedef (SOCKET on Windows, int on POSIX). Ends in _i rather than _s to indicate scalar identity.
Pattern: fio___xxx_s (triple underscore).
| Type | File | Line |
|---|---|---|
fio___bstr_meta_s |
011 string core.h |
~481 |
fio___cli_aliases_s |
005 cli.h |
~339 |
fio___url_encoded_cb_s |
004 urlencoded.h |
~156 |
Exception: None observed in Tranche A. All internal types follow this rule.
Pattern: fio_xxx_fn.
| Type | File |
|---|---|
fio_string_realloc_fn |
011 string core.h |
Pattern: fio_xxx (module prefix + verb/noun).
| Function | Module |
|---|---|
fio_url_parse |
URL |
fio_string_write |
String |
fio_thread_create |
Threads |
Exceptions:
fio_atonin002 atol.hlacks module prefix. Should ideally befio_atol_parseor similar. Historical.fio_ltocstr,fio_cstr2u64,fio_u2digin002 atol.hare abbreviated. Acceptable for tight utility functions.
Pattern: fio___xxx (triple underscore).
| Function | File | Line |
|---|---|---|
fio___url_encoded_callbacks_validate |
004 urlencoded.h |
~161 |
fio___cli_data_set |
005 cli.h |
~412 |
fio___mem_block_new |
010 mem.h |
~1651 |
Exception: Some internal helpers in 010 mem.h use FIO_NAME(FIO_MEMORY_NAME, __mem_xxx) macro naming. These are internal and not directly callable.
| Qualifier | Linkage | Body Location | Use Case |
|---|---|---|---|
SFUNC |
External (respects FIO_EXTERN) |
Inside #if defined(FIO_EXTERN_COMPLETE) || !defined(FIO_EXTERN) |
Public API functions |
IFUNC |
External (respects FIO_EXTERN) |
Inside FIO_EXTERN_COMPLETE block |
Public API functions (older style) |
FIO_IFUNC |
Always static inline |
Anywhere | Small helpers, accessors, fast paths |
FIO_SFUNC |
Always static |
Anywhere | Internal helpers |
SFUNC / IFUNC bodies MUST be inside the extern block:
#if defined(FIO_EXTERN_COMPLETE) || !defined(FIO_EXTERN)
SFUNC void fio_example(void) { /* body */ }
#endifFIO_IFUNC bodies MAY be anywhere:
FIO_IFUNC size_t fio_helper(size_t x) { return x + 1; }fio_string_capa4len()in011 string core.h(~656) isFIO_IFUNCbut its body appears in the "declaration" section before theFIO_EXTERN_COMPLETEblock. This is allowed by the qualifier rules but breaks visual separation.fio_bstr_info(),fio_bstr_buf(),fio_bstr_len()in011 string core.hareFIO_IFUNCwith bodies intermixed with declarations. Acceptable for accessors.fio___cli_print_help()in005 cli.h(~959) isFIO_SFUNCbut called before its definition (forward declaration at ~410). This is fine becauseFIO_SFUNCisstatic.
Return -1 on failure, 0 on success. (Kernel style.)
Functions following this convention:
fio_json_parse()→int(0 success, -1 failure)fio_sock_open()→int(0 success, -1 failure)fio_string_write()→int(0 success, -1 truncation/ENOMEM)fio_string_replace()→int(0 success, -1 failure)fio_string_printf()→int(0 success, -1 failure)fio_rand_secure()→int(0 success, -1 failure)fio_filename_open()→int(0 success, -1 failure)fio_string_utf8_select()→int(0 success, -1 error)
A. Struct return with .err field
When a function must return multiple values, use a result struct with an .err field.
| Function | Return Type | Error Field | File |
|---|---|---|---|
fio_aton() |
fio_aton_s |
.err |
002 atol.h |
fio_url_encoded_parse() |
fio_url_encoded_result_s |
.err |
004 urlencoded.h |
B. Pointer return (NULL on failure)
When returning an object, NULL signals failure.
| Function | Return Type | File |
|---|---|---|
fio_malloc() |
void * |
010 mem.h |
fio_cli_get() |
char const * |
005 cli.h |
fio_bstr_write() |
char * |
011 string core.h |
C. Boolean return (1 true, 0 false)
For pure predicates.
| Function | Return Type | File |
|---|---|---|
fio_glob_match() |
uint8_t |
002 glob matching.h |
fio_string_utf8_valid() |
bool |
011 string core.h |
fio_state_callback_is_pending() |
int (1/0) |
004 state callbacks.h |
D. Size return (bytes written/consumed)
For encode/decode functions where 0 is a valid result.
| Function | Return Type | File |
|---|---|---|
fio_url_decode() |
size_t |
002 url.h |
fio_url_encode() |
size_t |
002 url.h |
fio_json_unescape() |
size_t |
004 json.h |
fio_json_escape() |
size_t |
004 json.h |
E. Multi-state integer (0/1/-1)
For streaming parsers with intermediate states.
| Function | Return Values | File |
|---|---|---|
fio_multipart_parser_feed() |
0=need-more, 1=done, -1=error | 004 multipart.h |
fio_resp3_parser_feed() |
0=need-more, 1=done, -1=error | 004 resp3.h |
F. No error path
For pure functions or void returns.
| Function | Return Type | File |
|---|---|---|
fio_crc32() |
uint32_t |
002 crc32.h |
fio_rand64() |
uint64_t |
002 random.h |
fio_time_real() |
void |
004 time.h |
fio_cli_end() |
void |
005 cli.h |
MEDIUM priority:
fio_bstr_write()in011 string core.h(~810) returnschar *. OOM behavior is not explicitly documented (does it return NULL? truncate?).
Two non-owning view types are used throughout:
typedef struct {
char *buf;
size_t len;
} fio_str_info_s; /* NUL-terminated assumption: buf[len] == 0 */
typedef struct {
char *buf;
size_t len;
} fio_buf_info_s; /* Binary safe, no NUL guarantee */Rule: Use fio_str_info_s when the data is expected to be NUL-terminated (e.g., C strings, JSON text). Use fio_buf_info_s when the data may contain NUL bytes (e.g., binary payloads, raw socket data).
Exception: Many functions accept fio_buf_info_s but internally assume NUL termination (e.g., fio_string_write uses dest->buf[dest->len] = 0). This is documented but requires caller discipline.
| Type | Ownership | Cleanup | File |
|---|---|---|---|
fio_bstr ( char * ) |
Reference-counted | fio_bstr_free() |
011 string core.h |
fio_keystr_s |
Heap or embedded SSO | fio_keystr_destroy() with free callback |
011 string core.h |
Rule: Owning types require explicit cleanup. Non-owning views (fio_str_info_s, fio_buf_info_s) do not.
All streaming parsers in Tranche A use the same pattern:
/* 1. Define callbacks */
typedef struct {
void *(*on_event)(void *udata, ...);
void (*on_error)(void *udata);
} fio_xxx_parser_callbacks_s;
/* 2. Initialize parser state */
void fio_xxx_parser_init(fio_xxx_parser_s *parser, ...);
/* 3. Feed data */
int fio_xxx_parser_feed(fio_xxx_parser_s *parser, const char *data, size_t len);Modules using this pattern:
004 json.h004 multipart.h004 resp3.h004 urlencoded.h
Exception: None. This is a highly coherent family.
Use the FIO_MEM_* macros, never raw libc functions:
| Operation | Macro | File |
|---|---|---|
| Allocate | FIO_MEM_REALLOC(NULL, 0, size, 0) |
001 header.h |
| Reallocate | FIO_MEM_REALLOC(ptr, old_size, new_size, copy_len) |
001 header.h |
| Free | FIO_MEM_FREE(ptr, size) |
001 header.h |
| Copy | FIO_MEMCPY(dst, src, len) |
000 core.h |
| Move | FIO_MEMMOVE(dst, src, len) |
000 core.h |
| Set | FIO_MEMSET(ptr, val, len) |
000 core.h |
| Compare | FIO_MEMCMP(a, b, len) |
000 core.h |
Exception: 011 string core.h provides fio_string_sys_reallocate() which uses raw realloc() as a fallback. This is explicitly labeled as "system realloc" and is acceptable for the fallback path.
The custom allocator in 010 mem.h uses macro namespacing:
void *fio_malloc(size_t size);
void *fio_calloc(size_t size_per_unit, size_t unit_count);
void fio_free(void *ptr);
void *fio_realloc(void *ptr, size_t new_size);
void *fio_realloc2(void *ptr, size_t new_size, size_t copy_len);
void *fio_mmap(size_t size);Rule: fio_realloc2() is preferred over fio_realloc() when the amount of data to copy is known to be smaller than new_size.
Macro-template modules (sort, imap) require the consumer to define prefixes before inclusion:
#define FIO_SORT_NAME my_sort
#define FIO_SORT_TYPE int
#define FIO_SORT_CMP(a, b) ((a) < (b))
#include "002 sort.h"
#undef FIO_SORT_NAME
#undef FIO_SORT_TYPE
#undef FIO_SORT_CMPAll #defines introduced by a macro-template module MUST be #undefd at the end of the header.
Exception: 010 mem.h intentionally leaves FIO_MEMORY_NAME defined (line 2668: "don't undefine FIO_MEMORY_NAME due to possible use in allocation macros"). This is acceptable because the allocator is typically the last module configured.
Files are numbered NNN description.h. Descriptions use spaces, not dashes.
Examples:
000 core.h002 glob matching.h004 state callbacks.h011 string core.h
Exception: 004 urlencoded.h has no space. Minor inconsistency.
Use Doxygen-style /** */ blocks for public APIs:
/**
* Brief description.
*
* Detailed description.
*
* * `arg` description.
* * `arg2` description.
*/
SFUNC int fio_example(int arg, int arg2);Some internal helpers have minimal or no comments. Acceptable for FIO_SFUNC static helpers.
| Pattern | Coverage | Key Exceptions |
|---|---|---|
snake_case |
~99% | Macro-template prefixes (UPPER_SNAKE_CASE) |
Public types fio_xxx_s |
~100% | fio_socket_i (scalar typedef) |
Internal types fio___xxx_s |
~100% | None |
Public funcs fio_xxx |
~95% | fio_aton (missing module prefix) |
Internal funcs fio___xxx |
~100% | Macro-namespaced allocator internals |
Error: -1 fail, 0 success |
~60% | Struct returns, pointer returns, boolean returns, size returns |
SFUNC bodies in extern block |
~100% | FIO_IFUNC bodies anywhere |
| Callback-driven parsers | 4/4 modules | None |
FIO_MEM_* macros |
~100% | fio_string_sys_reallocate fallback |
Pattern: Function pointer types use _fn suffix consistently across all modules.
| Type | Signature | File |
|---|---|---|
fio_crypto_enc_fn |
void (*)(void *restrict mac, ...) |
150 crypto core.h |
fio_crypto_dec_fn |
int (*)(void *restrict mac, ...) |
150 crypto core.h |
Note: The _fn suffix is used for all function pointer types, including both crypto operation vtables and user-provided callbacks (e.g., fio_string_realloc_fn in 011 string core.h). There is no _f suffix in the public API.
Pattern: Forward-declare structs to hide implementation details.
typedef struct fio_stream_packet_s fio_stream_packet_s;
typedef struct fio_deflate_s fio_deflate_s;The actual struct definition appears only in the implementation section (#if defined(FIO_EXTERN_COMPLETE) ...).
Modules using this pattern:
102 stream.h(fio_stream_packet_s)162 deflate.h(fio_deflate_s)
Pattern: Use compound literals to provide named arguments for complex structs.
#define fio_argon2(...) \
fio_argon2((fio_argon2_args_s){__VA_ARGS__})
/* Usage: */
fio_argon2(.password = pwd, .salt = salt, .t_cost = 3);Modules using this pattern:
159 argon2.h159 lyra2.h160 otp.h
Rule: The macro must exactly match the function name. The struct type must be {function_name}_args_s.
Pattern: One-shot hash functions return the digest struct by value. No error path.
fio_u256 fio_sha256(const void *data, uint64_t len);
fio_u512 fio_sha512(const void *data, uint64_t len);
fio_u512 fio_sha1(const void *data, uint64_t len);Incremental variant:
fio_sha256_s fio_sha256_init(void); /* returns state */
void fio_sha256_consume(fio_sha256_s *h, ...); /* feeds data */
fio_u256 fio_sha256_finalize(fio_sha256_s *h); /* returns digest */Rule: One-shots are infallible (assuming valid pointers). Incremental APIs use void for consume operations.
Pattern: AEAD encryption returns void; decryption returns int.
/* Encryption: void return — cannot fail with valid key/IV */
void fio_aes128_gcm_enc(void *restrict mac, size_t mac_len,
void *restrict ciphertext,
const void *restrict plaintext, size_t pt_len,
const void *restrict aad, size_t aad_len,
const uint8_t key[16], const uint8_t iv[12]);
/* Decryption: int return — authentication can fail */
int fio_aes128_gcm_dec(void *restrict mac, size_t mac_len,
void *restrict plaintext,
const void *restrict ciphertext, size_t ct_len,
const void *restrict aad, size_t aad_len,
const uint8_t key[16], const uint8_t iv[12]);Justification: Encryption is a deterministic transform with no failure mode other than invalid inputs (programmer error). Decryption must authenticate the tag, which can fail.
Exception: This asymmetry is intentional but must be explicitly documented in header comments.
Pattern: Pure key-derivation functions return void.
void fio_tls13_hkdf_expand_label(void *restrict out, size_t out_len, ...);
void fio_tls13_derive_secret(void *restrict out, ...);
void fio_tls13_derive_early_secret(void *restrict early_secret, ...);Justification: These are deterministic transforms with no allocation and no cryptographic failure mode. Invalid inputs (NULL, out-of-range lengths) are clamped or silently ignored.
Exception: Callers cannot distinguish success from silently-ignored invalid input. Use FIO_ASSERT in debug builds to catch programmer errors.
Pattern: Decompression functions return size_t with three states:
| Return Value | Meaning |
|---|---|
> 0 && <= out_len |
Success — bytes written |
> out_len |
Buffer too small — required size |
== 0 |
Corrupt input or error |
size_t fio_brotli_decompress(void *out, size_t out_len,
const void *in, size_t in_len);Query mode: When out == NULL || out_len == 0, returns required decompressed size (or 0 if corrupt).
Exception: 0 is ambiguous between "corrupt input" and "error". Document this explicitly. Consider using SIZE_MAX for error if the distinction matters to callers.
Pattern: fio_queue_pop() returns fio_queue_task_s by value. Error is signaled by a NULL function pointer inside the struct.
fio_queue_task_s task = fio_queue_pop(q);
if (!task.fn) {
/* queue empty or error */
}Exception: The header comment says "Returns a NULL task on error", but structs cannot be NULL. The convention is implicit and should be documented explicitly.
| Pattern | Coverage | Key Exceptions |
|---|---|---|
snake_case |
~99% | Macro-template prefixes (UPPER_SNAKE_CASE) |
Public types fio_xxx_s |
~100% | fio_socket_i (scalar typedef) |
Internal types fio___xxx_s |
~100% | None |
Public funcs fio_xxx |
~95% | fio_aton (missing module prefix) |
Internal funcs fio___xxx |
~100% | Macro-namespaced allocator internals |
Error: -1 fail, 0 success |
~55% | Void returns (crypto, TLS), struct returns, pointer returns |
SFUNC bodies in extern block |
~100% | FIO_IFUNC bodies anywhere |
| Callback-driven parsers | 5/5 modules | None |
FIO_MEM_* macros |
~100% | fio_string_sys_reallocate fallback |
| AEAD encrypt void-return | 3/3 ciphers | Intentional asymmetry with decrypt |
| TLS key schedule void-return | 14/14 functions | No error signaling |
| Compression triple-state | 4/4 functions | 0 is ambiguous |
Document version: 2026-05-07 Tranche A+B audit.