-
Notifications
You must be signed in to change notification settings - Fork 38
bcm283x driverGPIO.Init: variable shadowing silently swallows MapGPIO() error on BCM2837 #76
Description
Description
In bcm283x/gpio.go, the driverGPIO.Init() method has a variable shadowing bug that silently swallows errors from pmem.MapGPIO(), causing the driver to initialise with gpioMemory == nil even when /dev/gpiomem is accessible and mmappable.
At line ~1447:
m, err := pmem.MapGPIO()
if err != nil {
var err2 error
m, err2 = pmem.Map(uint64(d.gpioBaseAddr), 4096)
var err error // <-- shadows outer err with a new nil error
if err2 != nil {
if distro.IsRaspbian() {
if os.IsNotExist(err) && os.IsPermission(err2) { // err is always nil here
return true, fmt.Errorf(...)
}
}
if os.IsPermission(err2) {
return true, fmt.Errorf("need more access, try as root: %v", err) // err is nil
}
return true, err // returns nil — Init "succeeds" with gpioMemory unset
}
}Line 1453 declares var err error inside the if err2 != nil block, shadowing the outer err from line 1447. This means:
os.IsNotExist(err)on line 1458 always checks a nil errorreturn true, erron line 1465 returns nil — the driver Init succeeds without settinggpioMemory
Impact
When MapGPIO() fails and Map() also fails (non-root user without /dev/mem access), the Init silently succeeds with gpioMemory == nil. All subsequent Pin.Read() calls fall through to the gpioioctl path, which has a separate issue where it reconfigures output pins (see #75).
We confirmed this on a Raspberry Pi 3 Model A+ (BCM2837). /dev/gpiomem has correct permissions (root:gpio rw-rw----) and we proved via a standalone test program that mmapping it works correctly as a non-root user. Despite this, periph.io's MapGPIO() fails — and the error is swallowed by the shadowing bug, so the driver falls back to gpioioctl without any error indication.
On BCM2711 (Raspberry Pi 4B), MapGPIO() succeeds, so this bug is not triggered. The BCM2837-specific MapGPIO() failure may be a third issue, but the shadowing bug masks it — fixing the shadowing would at least surface the real error.
Suggested fix
Remove the shadowing declaration at line 1453. The outer err from line 1447 should flow through to the error checks:
m, err := pmem.MapGPIO()
if err != nil {
var err2 error
m, err2 = pmem.Map(uint64(d.gpioBaseAddr), 4096)
// removed: var err error
if err2 != nil {
// now err contains the original MapGPIO() error
...
}
}Environment
- periph.io/x/host/v3 v3.8.5
- Raspberry Pi 3 Model A+ (BCM2837), Raspberry Pi OS (kernel 6.12.75+rpt-rpi-v8)
- Running as non-root systemd service user with gpio group membership
Related
- gpioioctl.GPIOLine.Read() silently reconfigures output pins as input with PullUp #75 — gpioioctl.GPIOLine.Read() silently reconfigures output pins as input with PullUp (the downstream consequence of this bug on BCM2837)