Home > Arcadia > Sanitizer

Arcadia Sanitizer

The Arcadia Sanitizer is a native C tool and library for checking and normalizing source-file whitespace on Windows and Linux. It uses Arcadia's own FileSystem, FilePath, DirectoryIterator, FileHandle, and byte-buffer APIs.

Introduction

Use --check before committing to detect whitespace differences without modifying files. Use --fix to apply the supported normalization. Both modes accept a file or a directory; the path defaults to the current working directory.

Build

Configure and build Arcadia with the usual CMake workflow, then build the sanitizer executable and its regression tests:

cmake -S . -B build
cmake --build build --target Arcadia.Sanitizer.Tool
cmake --build build --target Arcadia.Sanitizer.Tests
ctest --test-dir build -R Sanitizer --output-on-failure

The executable location depends on the selected CMake generator and configuration. For Visual Studio or other multi-configuration generators, select the appropriate build/test configuration (for example, with --config Debug and ctest -C Debug).

Examples

Arcadia.Sanitizer.Tool --check .
Arcadia.Sanitizer.Tool --check Runtime/FileSystem
Arcadia.Sanitizer.Tool --fix Runtime/FileSystem
Arcadia.Sanitizer.Tool --check CMakeLists.txt

Run the executable by its actual filesystem path, or place its directory on PATH. The examples assume it is available on PATH. After a fix, inspect the changes using git diff and git diff --check. Do not use --fix on files that cannot be restored if an interruption occurs.

Typical workflow

  1. Run --check for the module being changed.
  2. If differences are expected, run --fix on that module.
  3. Review the changed files and run --check again.
  4. Run the native sanitizer CTest regression suite.

Concepts and Terms

Check mode
Read-only traversal which reports differing whitespace and exits with status 1 when at least one inspected text file is nonconforming.
Fix mode
Traversal which writes normalized bytes back to each affected text file. Files whose content is already conforming are not rewritten.
Root
The explicitly supplied file or directory; if omitted, the working directory. Root directories are traversed recursively.
Eligible source file
A regular file with an allowed extension discovered during directory traversal. An explicitly provided regular file is eligible regardless of its filename extension.
Normalized bytes
The original byte sequence after converting CRLF and lone CR line endings to LF and removing spaces/tabs at the ends of lines.
Binary input
Any inspected file containing a NUL byte. Such files are reported and skipped without modification.

The scanner operates on bytes rather than decoding text. It does not infer a character encoding or interpret language syntax. See the Specification for its exact boundaries.

Specification

Command line and exit statuses

Arcadia.Sanitizer.Tool (--check|--fix) [file-or-directory]

Exactly one mode is required. The optional path is interpreted as a native filesystem path and defaults to .. Invalid arguments, a missing or inaccessible root, and filesystem/runtime errors produce exit status 2. The following exit statuses are part of the CLI contract:

StatusMeaning
0Check found no whitespace differences, or fix completed successfully.
1Check found at least one whitespace difference.
2Argument, filesystem, or runtime error.

Skipped binary and linked files are not counted as formatting violations; a check can therefore return zero even when such files were skipped.

Normalization

The transform is byte-oriented and performs these operations:

  1. Replace each CRLF pair with one LF byte.
  2. Replace each remaining CR byte with one LF byte.
  3. Remove each run of ASCII space or tab bytes immediately before a line ending or at the end of the file.

All other bytes are copied unchanged. In particular, interior spaces, byte order marks, encoded non-ASCII bytes, and the presence or absence of a final line ending are preserved. The transform is idempotent. It does not add a final LF, decode encodings, reorder text, or format C, PDL, or ADL syntax.

File selection

Directory traversal processes regular files with these case-sensitive suffixes:

.txt, .c, .h, .i, .tl, .te, .pdl, .adl, .ddl, .md, .cmake, .c.g, .h.g.

Directory scans exclude child directories named ., .., .git, .vs, .venv, .Dependencies, build, .build, CMakeFiles, node_modules, and __pycache__. These exclusions apply to encountered child directories, not to a root directory explicitly selected by the caller. Hidden files are not otherwise ignored. This is not a Git tracked-file-only scan.

Symbolic links and special files

The sanitizer skips discovered symbolic links and never follows them when descending directories. The filesystem test also treats Windows reparse points, including junctions, as links. Explicitly selecting a symbolic-link or reparse-point root is rejected with status 2. Special file types not recognized as regular files or directories are not processed. See Arcadia FileSystem for the underlying API.

Reporting and writes

A changed file produces one report for its first affected line, for example:

Runtime/FileSystem/Example.c:17: whitespace differs

In fix mode the suffix is fixed whitespace instead. Binary inputs are reported as skipped binary: path; nested links as skipped link: path. File-level reporting is not a report of every offending line, nor a JSON or machine-readable diagnostics format. Directory enumeration order is filesystem-dependent.

Fix mode writes affected files in place using Arcadia_FileSystem_setFileContents. This is not an atomic replacement and does not guarantee preservation of modification times for changed files. Interrupted writes can leave partial output. Use version control or backups, and review the diff before committing.

Non-goals and future checks

This release checks whitespace only. It does not check header guards, C prototypes, C function layouts, PDL/ADL/DDL grammar, documentation structure, or generated-code ownership. Future validators should expose distinct named checks, deterministic diagnostic locations, independent regression tests, and a documented severity/exit-status policy rather than silently changing the meaning of this whitespace pass.

Module Interface

The native public library interface is defined in Tools/Sanitizer/Library/Sources/Arcadia/Sanitizer/Sanitizer.h. It depends on Arcadia FileSystem and Ring2. The executable is implemented separately in Tools/Sanitizer/Tool.

Arcadia_Sanitizer_normalize

Arcadia_BooleanValue
Arcadia_Sanitizer_normalize
  (
    Arcadia_Thread* thread,
    Arcadia_ByteArrayBuilder* input,
    Arcadia_ByteArrayBuilder* output,
    Arcadia_SizeValue* firstAffectedLine
  );

Normalizes the input byte sequence into a distinct output builder. Returns true if any byte would change; otherwise returns false. firstAffectedLine receives the 1-based first affected line number or zero when unchanged. The input and output builders must be different objects. The caller owns the supplied builders and output parameter.

Arcadia_Sanitizer_Statistics

typedef struct Arcadia_Sanitizer_Statistics {
  Arcadia_SizeValue inspected;
  Arcadia_SizeValue changed;
  Arcadia_SizeValue skippedBinary;
  Arcadia_SizeValue skippedLinks;
} Arcadia_Sanitizer_Statistics;

inspected counts regular files read for normalization, including binary files. changed counts files whose normalized bytes differ, including files fixed in fix mode. skippedBinary and skippedLinks count ignored binary inputs and links respectively. Initialize this structure to zero before a scan.

Arcadia_Sanitizer_scan

void
Arcadia_Sanitizer_scan
  (
    Arcadia_Thread* thread,
    Arcadia_FileSystem* fileSystem,
    Arcadia_FilePath* path,
    Arcadia_FileHandle* output,
    Arcadia_BooleanValue fix,
    Arcadia_Sanitizer_Statistics* statistics
  );

Scans a file or directory recursively, writes diagnostics to the supplied open file handle, and updates the provided statistics. When fix is false, no files are rewritten. When true, only files with differing normalized bytes are rewritten. This library function does not return a CLI exit status; the command-line wrapper maps the statistics and failures to statuses 0, 1, and 2.

The library uses Arcadia's normal thread error/status and jump-target conventions. Its caller must establish the required Arcadia process and thread environment, and manage errors according to those conventions.

Build targets and tests

TargetPurpose
Arcadia.SanitizerReusable native C library.
Arcadia.Sanitizer.ToolCommand-line executable.
Arcadia.Sanitizer.TestsNative regression suite, registered with CTest.
Arcadia.Sanitizer.BuildDocsGenerate this documentation with the Arcadia Template Engine.

The documentation source resides in Tools/Sanitizer/Documentation. The generated site is .Website/Arcadia/Sanitizer/index.html. Treat generated files as output, not as the primary editing surface.