Skip to content

Glossary

A reference for terms used throughout the SafeHeaders-Go 101 course. Definitions are grouped by theme. If a term appears in a lesson, the lesson link is included.


Go concurrency

goroutine A lightweight thread managed by the Go runtime, not the OS. You start one with go f(). The runtime multiplexes thousands of goroutines onto a small pool of OS threads. Goroutines are cheap to create (a few kilobytes of stack) but can deadlock if they wait on a channel or mutex that never unblocks. See Lesson 11.

channel A typed pipe for passing values between goroutines. A send (ch <- v) blocks until a receiver is ready; a receive (v := <-ch) blocks until a sender arrives. Buffered channels (make(chan T, N)) allow up to N sends before blocking. The size of the buffer matters: sizing it too small is a common cause of deadlocks. See Lesson 11 and Lesson 14.

select A Go statement that waits on multiple channel operations at once and proceeds with whichever is ready first. If several are ready simultaneously, one is chosen at random. A default branch makes it non-blocking. Used extensively in worker pools to multiplex work and cancellation signals.

worker pool A pattern where a fixed number of goroutines (workers) consume jobs from a shared channel. Bounds the total number of goroutines so one big batch cannot exhaust memory. Used in jsmn-go (chunkWorker), stb-image-go (LoadBatchConcurrent), cjson-go (UnmarshalArrayParallel), and others. See Lesson 12.

fan-out Dispatching one piece of work to many goroutines simultaneously, then collecting results. Useful when items are independent (e.g. parsing ten separate image files). Wasteful when items share the same expensive context, because every goroutine re-reads it from scratch.

deadlock A situation where every goroutine in a group is blocked waiting for another member of the same group to proceed — so none ever does. The Go runtime detects total deadlocks (all goroutines blocked) and panics with all goroutines are asleep. Partial deadlocks (one goroutine stuck, rest running) hang silently. See Lesson 14.

data race Two goroutines reading and writing the same memory location concurrently, with no synchronization. The result is undefined: you may get stale data, torn values, or a crash. Detected at runtime by the Go race detector (go test -race). See Lesson 15.

mutex (sync.Mutex) A mutual-exclusion lock. Only one goroutine can hold a mutex at a time; others block on Lock() until it is released with Unlock(). Used in linenoise-go to protect the shared history slice from concurrent AddHistory/LoadHistory calls. See Lesson 15.

context (context.Context) A value that carries a deadline, cancellation signal, and optional key-value bag through a call chain. Passing a context to a long-running function lets the caller cancel it early (e.g. on HTTP request teardown or timeout). Worker pools in this repo check ctx.Done() to abort in-flight jobs. See Lesson 13.


Error handling

sentinel error A package-level var of type error whose identity, not just its message, is meaningful. Callers check it with errors.Is(err, ErrFoo). In jsmn-go the sentinels are ErrInputTooLarge, ErrTooManyTokens, and ErrEmptyInput; callers can branch on each without string-matching. See Lesson 03.

error wrapping (%w) Using fmt.Errorf("context: %w", err) to attach a new message to an existing error while preserving the original for errors.Is/errors.As inspection. The wrapped chain can be unwrapped programmatically, so callers at any layer can still detect a sentinel. See Lesson 03.


Security and robustness

decode bomb A small input that expands into a very large in-memory structure after decoding. Classic example: a tiny image file that claims dimensions of 100,000 × 100,000 pixels, causing the decoder to allocate 40 GB for the pixel buffer. stb-image-go guards against this by calling image.DecodeConfig to read dimensions before allocating, then comparing against MaxImagePixels. See Lesson 18.

decompression bomb The compression-flavored decode bomb: a small zip or deflate stream that expands to gigabytes of output (e.g. a file of repeated zeros compresses to near nothing). miniz-go guards with MaxDecompressedSize — an aggregate budget across all entries in a zip archive, not just per-stream. See Lesson 18.

billion-laughs attack An XML (or similar) structure where each entity references several others exponentially: entity A contains B B B, B contains C C C, … After ten levels the expansion is billions of nodes. tinyxml2-go defends with a hard nesting depth ceiling (maxNestingDepth = 10000) enforced in parseElement. stb-truetype-go faces the same shape in composite glyphs (a glyph that references other glyphs recursively); glyphBudget caps the total number of components and contour points. See Lesson 19.

OOM (out-of-memory) Allocating more memory than the host has available, causing the process to be killed by the OS or the Go runtime to panic. In dr-wav-go an early version allocated a []byte whose size came directly from an untrusted header field; fuzzing found inputs that set that field to 4 GB. The fix: cap the allocation to the number of bytes actually present (r.Len()). See Lesson 17.

fuzzing (go test -fuzz) An automated testing technique that generates mutated inputs and feeds them to a function, hunting for panics, crashes, or unexpected errors. Go's built-in fuzzer (available since Go 1.18) records any crash-inducing input as a seed file under testdata/fuzz/. This repo runs fuzz tests on jsmn-go, tinyxml2-go, dr-wav-go, and miniz-go weekly in CI.

round-trip test A test that encodes data, then decodes the result, and checks that the final value equals the original. It catches subtle codec bugs that do not cause a crash but silently corrupt data. In miniz-go, a round-trip test caught that CreateArchiveConcurrent was double-compressing: it stored already-deflated bytes inside a Deflate entry, making the archive unreadable by standard tools.

configurable limits Security-relevant ceilings (max input bytes, max tokens, max nesting depth, max decompressed bytes) exposed as fields on a Config struct so callers can tighten or loosen them for their use case. All SafeHeaders-Go modules ship a DefaultConfig (production-safe), a StrictConfig (tighter), and an UnlimitedConfig (for trusted offline use). See Lesson 20.


Parsing concepts

tokenizer A function that reads raw bytes and splits them into a flat list of tokens — typed spans with start/end offsets — without building a tree or resolving values. jsmn is a tokenizer: it finds where each JSON string, number, object, or array begins and ends, but leaves the value bytes in place for the caller to interpret. See Lesson 05.

DOM (Document Object Model) A tree representation of a structured document (XML, HTML) held entirely in memory. tinyxml2-go builds a DOM: after Parse returns you can call FindDeep/FindAllDeep to walk the element tree. Contrast with streaming/event parsers that emit nodes one at a time and never hold the whole tree.

streaming parser A parser that reads input incrementally and emits events or values one at a time, keeping only a small window of data in memory at once. cjson-go exposes UnmarshalStream and MarshalStream for this purpose. Contrast with DOM parsers that load everything first.

RIFF (Resource Interchange File Format) A generic container format used by WAV audio files. The file is divided into labeled chunks (RIFF, fmt, data, …), each with a 4-byte tag and a 4-byte little-endian size. dr-wav-go parses RIFF/PCM by hand in dr_wav.go, reading chunk headers and dispatching to handlers like readDataChunk. See Lesson 07.

PCM (Pulse-Code Modulation) The raw, uncompressed representation of audio as a sequence of integer samples. WAV files store PCM data in their data chunk. dr-wav-go exposes the samples as a []byte slice after parsing.

glTF (GL Transmission Format) A JSON-based 3D asset format used in games and web graphics. cgltf-go parses glTF 2.0 via encoding/json and then validates cross-references (scene→node, node→mesh, etc.) in ValidateGLTF.


TrueType / font internals

SFNT The binary container format shared by TrueType and OpenType fonts. A font file begins with an offset table listing named tables; stb-truetype-go reads it in parseSFNT (in sfnt.go). See Lesson 08.

glyf table The TrueType table that stores the actual outline geometry for every glyph as a sequence of contour points. stb-truetype-go reads it in glyphContours (in sfnt.go). See Lesson 09.

cmap table The TrueType "character map" table that translates Unicode code points to glyph IDs. stb-truetype-go supports cmap formats 0, 4, 6, and 12 (the most common encodings), parsed in cmapFormat0, cmapFormat4, cmapFormat6, and cmapFormat12 in sfnt.go. See Lesson 08.

Bézier curve (quadratic) A smooth curve defined by a start point, one off-curve control point, and an end point. TrueType outlines are made of quadratic Bézier segments. stb-truetype-go flattens them into line segments in flattenQuad (in sfnt.go) before rasterizing. See Lesson 09.

scanline fill A rasterization algorithm that fills a polygon by iterating over each horizontal row of pixels (scanline) and finding where the outline edges cross it. The pixels between pairs of crossings are inside the shape. stb-truetype-go implements this in scanlineCrossings and accumulateSpans in sfnt.go. See Lesson 10.

nonzero winding rule A rule for deciding whether a point is inside a filled shape. For each pixel, trace a ray in any direction and count edge crossings: clockwise edges add +1, counter-clockwise edges add -1. If the sum is nonzero, the pixel is inside. TrueType uses this rule; stb-truetype-go's fillCoverage follows it. See Lesson 10.

LRU cache (Least Recently Used) A fixed-capacity cache that evicts the entry that was accessed longest ago when the cache is full. stb-truetype-go uses a GlyphCache LRU in stb_truetype.go so rendered glyphs are not rasterized twice. Without it, a line of text with repeated characters would re-rasterize each glyph on every occurrence.

composite glyph A TrueType glyph built from references to other glyphs (e.g. an accented letter composed of a base letter plus a diacritic). References can be nested. Without a budget cap the fan-out is exponential (a composite of composites of composites …). glyphBudget in sfnt.go limits the total component count and point count to prevent this. See Lesson 19.


Tooling and CI

golangci-lint A meta-linter that runs many Go linters (staticcheck, errcheck, govet, gosec, and 50+ others) in one pass. This repo uses golangci-lint v2 with configuration in .golangci.yml. CI blocks merges if any linter finding is reported.

gosec A Go linter focused on security patterns: hardcoded credentials, unsafe integer conversions, unhandled errors on security-sensitive calls, and more. Runs as part of golangci-lint and as a standalone CI step.

govulncheck An official Go tool that cross-references your module's dependencies against the Go vulnerability database. It reports only vulnerabilities reachable from your code, not every transitive CVE. Runs in CI on every PR.

go.work (workspace) A file at the root of a multi-module repository that lists the local modules so go build and go test can resolve them without publishing. SafeHeaders-Go uses a go.work file to span all nine modules; you can run go test ./... from the root and test all of them. See Lesson 02.

race detector (-race) A flag passed to go test, go build, or go run that instruments memory accesses at compile time. At runtime, if two goroutines touch the same location without synchronization, the detector prints a detailed report and exits nonzero. It has roughly 2–20× overhead, so it is used in CI but not in production binaries. See Lesson 15.

coverage gate A CI check that fails if test coverage drops below a threshold. This repo enforces a 70% minimum per module. Coverage is measured with go test -coverprofile and reported to Codecov. See Lesson 21.

CGO The mechanism that lets Go code call C functions and vice versa. It requires a C compiler, breaks pure cross-compilation, and reintroduces C's memory safety hazards at the boundary. SafeHeaders-Go deliberately avoids CGO: all nine modules are pure Go. See Lesson 01.

io.Reader / io.Writer The two fundamental interfaces in Go's I/O model. Any type with a Read([]byte) (int, error) method satisfies io.Reader; any with Write([]byte) (int, error) satisfies io.Writer. Functions that accept these interfaces work with files, network connections, in-memory buffers, and anything else — including the length-limited readers used to cap decompressed output in miniz-go. See Lesson 04.