Skip to main content
This document outlines the code style rules for Firedancer. The code style is ultimately defined by the code in src/tango.
Most contributors do not use a code formatting tool. The Firedancer codebase uses a distinctive style that emphasizes readability through vertical alignment.

General Guidelines

Text Word Wrap

Aspire to word wrap text (comments, not code) at 72 columns for readability. After accounting for the indent, this is right around the level the publishing industry has used for hundreds of years for making print easily readable with minimal eye strain.

Repository Organization

  • See doc/organization.txt for detailed organization guidelines
  • Avoid cluttering the repository root

File Extensions

ExtensionFile Type
.cStandalone C translation unit
.hReusable C include file, no symbol defs (header)
.cInclude-once C file, with symbol defs
.sAssembly files
(none)Shell scripts

Include Guards

Header files must use #ifndef include guards. Never use #pragma once. Given file: src/path/to/file/fd_file_name.h:
#ifndef HEADER_fd_src_path_to_file_fd_file_name_h
#define HEADER_fd_src_path_to_file_fd_file_name_h

...

#endif /* HEADER_fd_path_to_file_fd_file_name_h */

Vertical Alignment

Popular code formatting tools would produce compact but less readable code. Firedancer uses vertical alignment for better readability.
#define FD_FOO_SUCCESS    (0)
#define FD_FOO_ERR_PROTO  (1)
#define FD_FOO_ERR_IO    (20)

void
foo( void ) {
  char const * _init = fd_env_strip_cmdline_cstr( &argc, &argv, "--init", NULL, NULL                 );
  uint         seed  = fd_env_strip_cmdline_uint( &argc, &argv, "--seed", NULL, (uint)fd_tickcount() );
  int          lazy  = fd_env_strip_cmdline_int ( &argc, &argv, "--lazy", NULL, 7                    );
}

Spacing Rules

Function Calls

Zero arguments: No spaces inside brackets
abort();
With arguments: Spaces inside brackets, no space before brackets
printf( "Hello %s\n", "World" );
Exception for sizeof: Usually no spaces
memcpy( dst, src, sizeof(fd_rng_t) );
Exception for double bracket macros: No spaces between brackets
FD_LOG_NOTICE(( "pass" ));

Control Flow

Annotate uncommon error paths with FD_UNLIKELY. Single-line statements: No braces required
if( FD_UNLIKELY( do_crash ) ) abort();
Multi-line statements: Braces are mandatory
if( FD_UNLIKELY( status!=3 ) ) {
  FD_LOG_CRIT(( "Critical error, aborting" ));
}
Spacing: Spaces in brackets, no spaces before brackets
if( c==1 ) c = 2;

Function Prototypes

  • Modifiers and return types on separate lines
  • One function argument per line
  • Vertically align function argument types and names
static inline uint
fd_rng_seq_set( fd_rng_t * rng,
                uint       seq );

Type System

Integers

Use fd_util_base.h types instead of stdint.h integer types.
stdintfd_util_base
int8_tschar
uint8_tuchar
int16_tshort
uint16_tushort
int32_tint
uint32_tuint
int64_tlong
ptrdiff_tlong
uint64_tulong
size_tulong
For more information on why Firedancer uses custom integer types, see src/util/fd_util_base.h and doc/rant/integer-types.md.

Booleans

Do not use bool (stdbool). Instead use int.
  • 1 is “true”
  • 0 is “false”
int is_working = 1;
if( is_working ) { ... }

Function Documentation

  • Documentation goes before the function prototype in a comment block
  • Comments should mention the function name toward the beginning
  • Public API functions must be documented
  • Implementations must not repeat the comment
/* fd_rng_seq_set sets the sequence to be used by rng and returns
   the replaced value. fd_rng_idx_set sets the next slot that will be
   consumed next by rng and returns the replaced value. */

static inline uint
fd_rng_seq_set( fd_rng_t * rng,
                uint       seq );

Macros

Enclose Arguments in Braces

#define wwl_abs(x) _mm512_abs_epi64( (x) )

Use do/while(0) Scopes

#define FD_R43X6_SQR2_INL( za,xa, zb,xb ) \
  do {                                    \
    (za) = fd_r43x6_sqr( (xa) );          \
    (zb) = fd_r43x6_sqr( (xb) );          \
  } while(0)

Evaluate Arguments Only Once

#define TRAP(x)               \
  do {                        \
    int _cnt = (x);           \
    if( _cnt<0 ) return _cnt; \
    cnt += _cnt;              \
  } while(0)

Portability

Build Capabilities

Firedancer aspires to compile under any LP64 environment. Components with additional assumptions should check for capabilities via FD_HAS_{...} switches. Example Makefile:
ifdef FD_HAS_HOSTED
$(call add-objs,fd_numa,fd_util)
endif
Example C code:
#if FD_HAS_HOSTED

...

#endif /* FD_HAS_HOSTED */

Language Features

Stick to ISO C17. GNU C extensions are permitted as long as they are well supported by Clang and CBMC.

seccomp Sandbox

Firedancer uses a strict sandbox architecture on Linux platforms using seccomp.
During initialization, a seccomp profile is installed to each tile containing rules for allowed syscalls. If a syscall is triggered unexpectedly, seccomp will crash Firedancer.Be mindful of what syscalls glibc could use under the hood when using standard library APIs. Note that syscalls used can differ between glibc versions.

File I/O

Prefer fd_io over stdio.h for streaming file I/O. Make sure to handle EINTR correctly.

Security Best Practices

Complex Function Exit

For functions with complex control flow that need cleanup, use a do/while scope:
do {
  if( fail1 ) break;
  ...
  if( fail2 ) break;
  ...
} while(0);

cleanup();
return;
For resource cleanup, you may use the cleanup attribute:
static inline void
release_lock( int * lock ) {
  ...
}

void
my_func( void ) {
  int my_lock __attribute__((cleanup(release_lock))) = acquire_lock();
  
  if( fail1 ) return;  /* calls release_lock when returning */
  
  /* calls release_lock when going out of scope */
}
For better readability, wrap the cleanup attribute in macros. See FD_SCRATCH_SCOPE_BEGIN in src/util/scratch/fd_scratch.h.

Build docs developers (and LLMs) love