Blogs / Personal blogs

Chris Wellons

nullprogram.com

Buffered output typically comes in two flavors: fully buffered and line buffered. If output goes to a terminal then the implementation automatically selects line buffering, flushing its buffer when a line is completed so that it reaches the user immediately. Otherwise it fully buffers, holding output until the buffer…

Popular posts
74
Total points
14,949
HN comments
7,192
Rank
#45 personal

Visit nullprogram.com → RSS feedOn Hacker News Dec 2014 – Oct 2026

Software Engineering 64Systems & Performance 21Programming Languages 17Tools & Productivity 15Math & Algorithms 8Security & Privacy 7

31

Fast CSV Processing with SIMD

I recently learned of csvquote , a tool that encodes troublesome CSV characters such that unix tools can correctly process them. It reverses the encoding at the end of the pipeline, recovering the original input. The original implementation handles CSV quotes using the straightforward, naive method. However, there’s a…

32

Hotpatching a C Function on x86

In this post I’m going to do a silly, but interesting, exercise that should never be done in any program that actually matters. I’m going write a program that changes one of its function definitions while it’s actively running and using that function. Unlike last time , this won’t involve shared libraries, but it will…

33

You Can't Always Hash Pointers in C

Occasionally I’ve needed to key a hash table with C pointers. I don’t care about the contents of the object itself — especially if it might change — just its pointer identity. For example, suppose I’m using null-terminated strings as keys and I know these strings will always be interned in a common table. These…

34

Tips for more effective fuzz testing with AFL++

Fuzz testing is incredibly effective for mechanically discovering software defects, yet remains underused and neglected. Pick any program that must gracefully accept complex input, written in any language , which has not yet been been fuzzed, and fuzz testing usually reveals at least one bug. At least one program…

36

strcpy: A niche function you don't need

The C strcpy function is a common sight in typical C programs. It’s also a source of buffer overflow defects, so linters and code reviewers commonly recommend alternatives such as strncpy (difficult to use correctly; mismatched semantics), strlcpy (non-standard, flawed ), or C11’s optional strcpy_s ( no correct or…

38

SDL2 common mistakes and how to avoid them

SDL has grown on me over the past year. I didn’t understand its value until viewing it in the right lens: as a complete platform and runtime replacing the host’s runtime, possibly including libc. Ideally an SDL application links exclusively against SDL and otherwise not directly against host libraries, though in…

39

OpenBSD's Pledge and Unveil from Python

Years ago, OpenBSD gained two new security system calls, pledge(2) (originally tame(2) ) and unveil . In both, an application surrenders capabilities at run-time. The idea is to perform initialization like usual, then drop capabilities before handling untrusted input, limiting unwanted side effects. This feature is…

40

An easy-to-implement, arena-friendly hash map

My last article had tips for for arena allocation . This next article demonstrates a technique for building bespoke hash maps that compose nicely with arena allocation. In addition, they’re fast, simple, and automatically scale to any problem that could reasonably be solved with an in-memory hash map. To avoid…

41

Fibers: An Elegant Windows API

The Windows API — a.k.a. Win32 — is notorious for being clunky, ugly, and lacking good taste. Microsoft has done a pretty commendable job with backwards compatibility, but the trade-off is that the API is filled to the brim with historical cruft. Every hasty, poor design over the decades is carried forward forever…

42

Unintuitive JSON Parsing

Despite the goal of JSON being a subset of JavaScript — which it failed to achieve (update: this was fixed ) — parsing JSON is quite unlike parsing a programming language. For invalid inputs, the specific cause of error is often counter-intuitive. Normally this doesn’t matter, but I recently ran into a case where it…

43

Interactive Programming in C

I’m a huge fan of interactive programming (see: JavaScript , Java , Lisp , Clojure ). That is, modifying and extending a program while it’s running. For certain kinds of non-batch applications, it takes much of the tedium out of testing and tweaking during development. Until last week I didn’t know how to apply…

44

Render Multimedia in Pure C

In a previous article I demonstrated video filtering with C and a unix pipeline . Thanks to the ubiquitous support for the ridiculously simple Netpbm formats — specifically the “Portable PixMap” ( .ppm , P6 ) binary format — it’s trivial to parse and produce image data in any language without image libraries. Video…

46

Practical Libc-free threading on Linux

Suppose you’re not using a C runtime on Linux, and instead you’re programming against its system call API. It’s long-term and stable after all. Memory management and buffered I/O are easily solved, but a lot of software benefits from concurrency. It would be nice to also have thread spawning capability. This article…

47

Unix "find" expressions compiled to bytecode

In preparation for a future project, I was thinking about at the unix find utility . It operates a file system hierarchies, with basic operations selected and filtered using a specialized expression language. Users compose operations using unary and binary operators, grouping with parentheses for precedence. find may…

49

Emacs Bytecode Internals (2014)

Byte-code compilation is an underdocumented — and in the case of the recent lexical binding updates, undocumented — part of Emacs. Most users know that Elisp is usually compiled into a byte-code saved to .elc files, and that byte-code loads and runs faster than uncompiled Elisp. That’s all users really need to know…

50

Inspecting C's qsort Through Animation

The C standard library includes a qsort() function for sorting arbitrary buffers given a comparator function. The name comes from its original Unix implementation, “quicker sort,” a variation of the well-known quicksort algorithm. The C standard doesn’t specify an algorithm, except to say that it may be unstable (C99…

53

When the Compiler Bites

So far this year I’ve been bitten three times by compiler edge cases in GCC and Clang, each time catching me totally by surprise. Two were caused by historical artifacts, where an ambiguous specification lead to diverging implementations. The third was a compiler optimization being far more clever than I expected…

54

A Basic Just-In-Time Compiler (2015)

Monday’s /r/dailyprogrammer challenge was to write a program to read a recurrence relation definition and, through interpretation, iterate it to some number of terms. It’s given an initial term ( u(0) ) and a sequence of operations, f , to apply to the previous term ( u(n + 1) = f(u(n)) ) to compute the next term…

55

The Value of Undefined Behavior

In several places, the C and C++ language specifications use a curious, and fairly controversial, phrase: undefined behavior . For certain program constructs, the specification prescribes no specific behavior, instead allowing anything to happen . Such constructs are considered erroneous, and so the result depends on…

57

Small, Freestanding Windows Executables

Recently I’ve been experimenting with freestanding C programs on Windows. Freestanding refers to programs that don’t link, either statically or dynamically, against a standard library (i.e. libc). This is typical for operating systems and similar, bare metal situations . Normally a C compiler can make assumptions…

58

Zero-allocation Trie Traversal

As part of a demonstration in an upcoming article , I wrote a simple trie implementation. A trie is a search tree where the keys are a sequence of symbols (i.e. strings). Strings with a common prefix share an initial path down the trie, and the keys themselves are stored implicitly by the structure of the trie. It’s…

59

A custom virtual machine for the Stars 4X game

Stars! is a 1995 4X game (explore, expand, exploit, exterminate) for 16-bit Windows 3.1 that I first played ~28 years ago. While Windows is famously backwards compatible, it’s notoriously difficult to play Stars! today. Windows x64 cannot run 16-bit applications, and playing requires either retro hardware or emulation…

60

Appending to a file from multiple processes

Suppose you have multiple processes appending output to the same file without explicit synchronization. These processes might be working in parallel on different parts of the same problem, or these might be threads blocked individually reading different external inputs. There are two concerns that come into play: