Environment
- Raspberry Pi 3 Model B Plus, Raspberry Pi OS (Debian 13 "trixie")
libgpiod 2.2.1 (Debian trixie ships the 2.x API, so the #else // new 2.x API branch is the one compiled)
- Built via
usetrmnl/trmnl-display's build.sh, which clones and builds bb_epaper as a dependency
- Commit tested against:
bitbank2/bb_epaper@4896bae (2026-08-22)
Summary
Any call into pinMode() on Linux/RPi with the new libgpiod 2.x API immediately segfaults, because sprintf() is called with a string literal as its destination buffer instead of the local szChip buffer that was declared right above it for that purpose.
Root cause
src/rpi_io.inl, inside pinMode(), #else // new 2.x API branch:
char szChip[16];
sprintf("/dev/%s", szChipName);
sprintf's first argument must be the destination buffer. Here it's passed the format string "/dev/%s" — a string literal living in read-only memory (.rodata). sprintf then tries to write into that literal, which segfaults (SIGSEGV). The freshly-declared szChip[16] buffer is left completely unused.
Backtrace (gdb):
Program received signal SIGSEGV, Segmentation fault.
0x0000007ff7892964 in ?? () from /lib/aarch64-linux-gnu/libc.so.6
#0 0x0000007ff7892964 in ?? () from /lib/aarch64-linux-gnu/libc.so.6
#1 0x0000007ff7872060 in sprintf () from /lib/aarch64-linux-gnu/libc.so.6
#2 0x000000555556f8f8 in pinMode (iPin=<optimized out>, iMode=iMode@entry=0) at ../src/rpi_io.inl:181
#3 0x0000005555557f74 in TRMNL_EPAPER () at main.cpp:1018
#4 0x00000055555559c8 in main (argc=1, argv=0x7ffffffab8) at main.cpp:1382
Fix
char szChip[16];
- sprintf("/dev/%s", szChipName);
+ sprintf(szChip, "/dev/%s", szChipName);
chip = gpiod_chip_open(szChip);
This is a one-character-argument-order fix; verified locally that it resolves the crash and gpiod_chip_open() succeeds against /dev/gpiochip0 afterward.
Impact
This affects every Linux/RPi user on a distro shipping libgpiod 2.x (e.g. any current Raspberry Pi OS / Debian trixie install) — the old-API (GPIOD_API) branch is unaffected, but that's not the one that gets compiled on modern systems. In practice this means bb_epaper-based clients (e.g. usetrmnl/trmnl-display) crash on their very first GPIO pin write on any up-to-date Raspberry Pi OS install.
Environment
libgpiod2.2.1 (Debian trixie ships the 2.x API, so the#else // new 2.x APIbranch is the one compiled)usetrmnl/trmnl-display'sbuild.sh, which clones and buildsbb_epaperas a dependencybitbank2/bb_epaper@4896bae(2026-08-22)Summary
Any call into
pinMode()on Linux/RPi with the new libgpiod 2.x API immediately segfaults, becausesprintf()is called with a string literal as its destination buffer instead of the localszChipbuffer that was declared right above it for that purpose.Root cause
src/rpi_io.inl, insidepinMode(),#else // new 2.x APIbranch:sprintf's first argument must be the destination buffer. Here it's passed the format string"/dev/%s"— a string literal living in read-only memory (.rodata).sprintfthen tries to write into that literal, which segfaults (SIGSEGV). The freshly-declaredszChip[16]buffer is left completely unused.Backtrace (gdb):
Fix
This is a one-character-argument-order fix; verified locally that it resolves the crash and
gpiod_chip_open()succeeds against/dev/gpiochip0afterward.Impact
This affects every Linux/RPi user on a distro shipping libgpiod 2.x (e.g. any current Raspberry Pi OS / Debian trixie install) — the old-API (
GPIOD_API) branch is unaffected, but that's not the one that gets compiled on modern systems. In practice this meansbb_epaper-based clients (e.g.usetrmnl/trmnl-display) crash on their very first GPIO pin write on any up-to-date Raspberry Pi OS install.