From f481585de471fbd4b0dd3b2d9dcd188e224f4497 Mon Sep 17 00:00:00 2001 From: Austin Date: Sat, 1 Aug 2026 14:13:20 -0400 Subject: [PATCH] Make GxEPD2_Multi non-copyable to address cppcheck warnings (#11326) cppcheck reports noCopyConstructor and noOperatorEq against GxEPD2_Multi on every e-ink environment (over 80 duplicate pairs on a single heltec-wireless-paper run, one per template instantiation point): src/graphics/GxEPD2Multi.h:123: [medium:warning] Class 'GxEPD2_Multi < GxEPD2_213_FC1 , GxEPD2_213_E0213A367 >' does not have a copy constructor which is recommended since it has dynamic memory/resource allocation(s). [noCopyConstructor] The warning is correct. The constructor news one of two GxEPD2_BW drivers into a raw pointer member and caches &driver->epd2 in epd2.m_epd2, so the compiler-generated copy operations would alias that driver: two objects would drive the same panel, and the second to be destroyed would free a driver the first still points at. Nothing copies it - EInkDisplay2 heap-allocates a single instance and holds a pointer - so declare that intent by deleting the copy operations rather than adding a suppression. Also null the unselected driver pointer. Only one of driver0/driver1 is allocated and the other was left indeterminate; every method branches on `which` before dereferencing, so this is latent rather than a live bug, but an indeterminate owning pointer is one refactor away from a wild dereference. Behaviour is unchanged: no caller could have copied this type, and the two added stores only initialize a pointer that is never read. Verified on heltec-wireless-paper: `./bin/check-all.sh heltec-wireless-paper` now reports "No defects found" (exit 0), and `pio run -e heltec-wireless-paper` builds clean. The build matters separately here because syntaxError is suppressed in suppressions.txt, so cppcheck alone would stay green on a malformed declaration. Co-authored-by: Claude Opus 5 --- src/graphics/GxEPD2Multi.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/graphics/GxEPD2Multi.h b/src/graphics/GxEPD2Multi.h index f3807c9de..78ae06058 100644 --- a/src/graphics/GxEPD2Multi.h +++ b/src/graphics/GxEPD2Multi.h @@ -115,6 +115,10 @@ template class GxEPD2_Multi // Select driver by passing whichDriver as 0 or 1 GxEPD2_Multi(uint8_t whichDriver, int16_t cs, int16_t dc, int16_t rst, int16_t busy, SPIClass &spi) { + // Only the selected driver is allocated; the other stays null + driver0 = nullptr; + driver1 = nullptr; + assert(whichDriver == 0 || whichDriver == 1); which = whichDriver; LOG_DEBUG("GxEPD2_Multi driver: %d", which); @@ -128,6 +132,11 @@ template class GxEPD2_Multi } } + // The driver we allocate above is owned by this object, and a single display can only be driven + // by one of them: copying would alias that pointer. There is exactly one instance per device. + GxEPD2_Multi(const GxEPD2_Multi &) = delete; + GxEPD2_Multi &operator=(const GxEPD2_Multi &) = delete; + private: uint8_t which; GxEPD2_BW *driver0;