Skip to content
Ernest Baffour, home

Ernest Nana BaffourAccra, Ghana

Ernest Nana Baffour, Systems Software Engineer

I write C that talks straight to the operating system. So far that means a memory allocator, a text editor and a Unix shell.

Third-year CS student at the University of Ghana. Open to interesting engineering roles.

Ernest Nana Baffour, smiling, in front of tall green grass

Projects

Three tools I use every day, rebuilt from scratch to see how they work.

Memory Allocator

Feb to Jun 2026

A drop-in replacement for malloc, free, calloc and realloc.

The problem

I had been calling malloc for two years without knowing what it did with the 24 bytes I asked for, or why a program that frees everything can still keep growing.

What I did

  • Version one was a single free list with first fit, growing the heap with sbrk. Every free walked the whole list, so it was slow.
  • I split free blocks into 12 size classes and added boundary tags, so a freed block merges with its neighbours in constant time.
  • Anything over 128 KiB now goes straight to mmap.
  • Each thread got its own arena and lock.

What went wrong

The threaded version deadlocked the first time a program called fork. The child inherited an arena locked by a thread that no longer existed. pthread_atfork handlers that take every arena lock before the fork, and release them after, fixed it.

heap

483224644832
  • header
  • in use
  • free

malloc splits a free block. free merges it back with its neighbours.

Step through a malloc(24) and a free. The 48-byte free block splits in two, then a freed block merges with the free one beside it.

Results

slower than glibc on a million random allocations
9%
bigger peak heap than glibc
18%
tests over about 1,400 lines of C
86

It runs ls, git status and python3 through LD_PRELOAD with Valgrind reporting nothing.

C on sbrk, mmap and pthreads, built with Make and debugged with GDB and Valgrind.

Source on GitHub: Memory Allocator

Text Editor

May to Aug 2025

A terminal text editor with no dependencies past libc.

The problem

I wanted to know how Vim draws a screen. A terminal is a stream of bytes in both directions, and nothing on it moves unless you tell it to.

What I did

  • I started from antirez's kilo tutorial, then rewrote its storage and rendering.
  • Raw mode comes from termios, and every frame is drawn with VT100 escape codes.
  • Each line lives in a gap buffer, so typing in the middle of a long line doesn't move the rest of it.
  • Search, C syntax highlighting and saving came last.

What went wrong

Over SSH it flickered badly. I was calling write once per character. Building each frame in memory and writing it in one call fixed it.

gap buffer

click, then type

return 0;gap

Typing fills the gap. Moving the cursor moves the gap.

Click and type. Typing fills the gap; moving the cursor moves the gap.

Results

to open a 20 MB log file
0.3 s
lines of C
2,000
dependencies past libc
0

Unix Shell

Jan to Mar 2025

A small Unix shell with pipes, redirection and a few built-ins.

The problem

My operating systems course covered fork and exec in one slide. I wanted to see what happens between cat and grep when I type a pipe.

What I did

  • A tokenizer that understands quotes comes first. Each command then runs with fork, execvp and waitpid.
  • Redirection is open plus dup2, and a pipeline is one pipe per |.
  • The shell ignores SIGINT and each child restores it, so Ctrl+C stops the program and not the shell.

What went wrong

My first pipelines hung forever. The parent still held the write end of each pipe, so grep never saw end of file. Closing every unused end, in the parent and in each child, fixed it, and taught me to reach for strace before guessing.

Each | is a pipe and > is a dup2 onto a file. Hover or tap to run it.

Results

test scripts that diff its output against bash
40
lines of C
1,100
built-ins: cd, pwd, exit, echo
4

It was the first of the three, and most of what I know about debugging comes from it.

C on POSIX system calls, built with Make and tested on Linux.

Source on GitHub: Unix Shell

About

When I want to know how something works, I build a small, worse copy of it.

That habit started with CS50 in 2023. One problem set had me write a spell checker in C, and I lost a weekend to why my hash table was slow. Since then I've mostly picked projects that sit right on top of the kernel: first the shell, then the editor, then the allocator.

I'm in my third year of Computer Science at the University of Ghana. I also tutor the first-year C lab, which mostly means explaining segmentation faults at four on a Thursday afternoon.

Away from the keyboard I play basketball. I also do a LeetCode problem most mornings and lose more Call of Duty Mobile matches than I'd like.

Skills

Writing C
Everything on this page is C11, compiled with -Wall -Wextra -Werror. I use C++ and Rust when a project calls for them.
Debugging
I step through free lists in GDB and find leaks and bad reads with Valgrind. When a pipe hangs, I reach for strace.
Unix
I use Linux every day (Arch on my laptop) and macOS too. I'm at home with processes, signals, file descriptors and memory mapping through the POSIX API.
Building and testing
I build with Make and test with small scripts that diff my output against bash or glibc. Everything goes in Git, and I edit in Neovim.
Scripting
I write Python for test harnesses and benchmark plots, and Bash for glue.
Algorithms
I practise data structures and algorithms on LeetCode. I'm at around 300 problems.

Education and teaching

  1. 2024 to 2028

    BSc Computer Science

    University of Ghana · In progress, third year

  2. 2025 to 2026

    Lab tutor, first-year C programming

    University of Ghana

  3. 2023

    CS50: Introduction to Computer Science

    Harvard, through edX · Certificate

Contact

Email is the best way to reach me.

I'm looking for internships and systems work, and I'm happy to talk about anything on this page.