fix: close leaked resource handles (#2040)
This commit is contained in:
@@ -5,8 +5,10 @@
|
||||
#include <HalStorage.h>
|
||||
#include <JPEGDEC.h>
|
||||
#include <Logging.h>
|
||||
#include <Memory.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
|
||||
#include "DirectPixelWriter.h"
|
||||
@@ -347,16 +349,16 @@ bool JpegToFramebufferConverter::getDimensionsStatic(const std::string& imagePat
|
||||
return false;
|
||||
}
|
||||
|
||||
JPEGDEC* jpeg = new (std::nothrow) JPEGDEC();
|
||||
std::unique_ptr<JPEGDEC> jpeg(new (std::nothrow) JPEGDEC());
|
||||
if (!jpeg) {
|
||||
LOG_ERR("JPG", "Failed to allocate JPEG decoder for dimensions");
|
||||
return false;
|
||||
}
|
||||
|
||||
int rc = jpeg->open(imagePath.c_str(), jpegOpen, jpegClose, jpegRead, jpegSeek, nullptr);
|
||||
const ScopedCleanup cleanup{[&jpeg]() { jpeg->close(); }};
|
||||
if (rc != 1) {
|
||||
LOG_ERR("JPG", "Failed to open JPEG for dimensions (err=%d): %s", jpeg->getLastError(), imagePath.c_str());
|
||||
delete jpeg;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -364,8 +366,6 @@ bool JpegToFramebufferConverter::getDimensionsStatic(const std::string& imagePat
|
||||
out.height = jpeg->getHeight();
|
||||
LOG_DBG("JPG", "Image dimensions: %dx%d", out.width, out.height);
|
||||
|
||||
jpeg->close();
|
||||
delete jpeg;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ bool JpegToFramebufferConverter::decodeToFramebuffer(const std::string& imagePat
|
||||
return false;
|
||||
}
|
||||
|
||||
JPEGDEC* jpeg = new (std::nothrow) JPEGDEC();
|
||||
std::unique_ptr<JPEGDEC> jpeg(new (std::nothrow) JPEGDEC());
|
||||
if (!jpeg) {
|
||||
LOG_ERR("JPG", "Failed to allocate JPEG decoder");
|
||||
return false;
|
||||
@@ -392,9 +392,9 @@ bool JpegToFramebufferConverter::decodeToFramebuffer(const std::string& imagePat
|
||||
ctx.screenHeight = renderer.getScreenHeight();
|
||||
|
||||
int rc = jpeg->open(imagePath.c_str(), jpegOpen, jpegClose, jpegRead, jpegSeek, jpegDrawCallback);
|
||||
const ScopedCleanup cleanup{[&jpeg]() { jpeg->close(); }};
|
||||
if (rc != 1) {
|
||||
LOG_ERR("JPG", "Failed to open JPEG (err=%d): %s", jpeg->getLastError(), imagePath.c_str());
|
||||
delete jpeg;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -403,14 +403,10 @@ bool JpegToFramebufferConverter::decodeToFramebuffer(const std::string& imagePat
|
||||
|
||||
if (srcWidth <= 0 || srcHeight <= 0) {
|
||||
LOG_ERR("JPG", "Invalid JPEG dimensions: %dx%d", srcWidth, srcHeight);
|
||||
jpeg->close();
|
||||
delete jpeg;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!validateImageDimensions(srcWidth, srcHeight, "JPEG")) {
|
||||
jpeg->close();
|
||||
delete jpeg;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -453,8 +449,6 @@ bool JpegToFramebufferConverter::decodeToFramebuffer(const std::string& imagePat
|
||||
if (destWidth <= 0 || destHeight <= 0) {
|
||||
LOG_ERR("JPG", "Degenerate output dimensions %dx%d for %s, skipping render", destWidth, destHeight,
|
||||
imagePath.c_str());
|
||||
jpeg->close();
|
||||
delete jpeg;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -490,13 +484,9 @@ bool JpegToFramebufferConverter::decodeToFramebuffer(const std::string& imagePat
|
||||
|
||||
if (rc != 1) {
|
||||
LOG_ERR("JPG", "Decode failed (rc=%d, lastError=%d)", rc, jpeg->getLastError());
|
||||
jpeg->close();
|
||||
delete jpeg;
|
||||
return false;
|
||||
}
|
||||
|
||||
jpeg->close();
|
||||
delete jpeg;
|
||||
LOG_DBG("JPG", "JPEG decoding complete - render time: %lu ms", decodeTime);
|
||||
|
||||
// Write cache file if caching was enabled
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
#include <GfxRenderer.h>
|
||||
#include <HalStorage.h>
|
||||
#include <Logging.h>
|
||||
#include <Memory.h>
|
||||
#include <PNGdec.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
|
||||
#include "DirectPixelWriter.h"
|
||||
@@ -244,7 +246,7 @@ bool PngToFramebufferConverter::getDimensionsStatic(const std::string& imagePath
|
||||
return false;
|
||||
}
|
||||
|
||||
PNG* png = new (std::nothrow) PNG();
|
||||
std::unique_ptr<PNG> png(new (std::nothrow) PNG());
|
||||
if (!png) {
|
||||
LOG_ERR("PNG", "Failed to allocate PNG decoder for dimensions");
|
||||
return false;
|
||||
@@ -252,18 +254,16 @@ bool PngToFramebufferConverter::getDimensionsStatic(const std::string& imagePath
|
||||
|
||||
int rc = png->open(imagePath.c_str(), pngOpenWithHandle, pngCloseWithHandle, pngReadWithHandle, pngSeekWithHandle,
|
||||
nullptr);
|
||||
const ScopedCleanup cleanup{[&png]() { png->close(); }};
|
||||
|
||||
if (rc != 0) {
|
||||
LOG_ERR("PNG", "Failed to open PNG for dimensions: %d", rc);
|
||||
delete png;
|
||||
return false;
|
||||
}
|
||||
|
||||
out.width = png->getWidth();
|
||||
out.height = png->getHeight();
|
||||
|
||||
png->close();
|
||||
delete png;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -278,7 +278,7 @@ bool PngToFramebufferConverter::decodeToFramebuffer(const std::string& imagePath
|
||||
}
|
||||
|
||||
// Heap-allocate PNG decoder (~42 KB) - freed at end of function
|
||||
PNG* png = new (std::nothrow) PNG();
|
||||
std::unique_ptr<PNG> png(new (std::nothrow) PNG());
|
||||
if (!png) {
|
||||
LOG_ERR("PNG", "Failed to allocate PNG decoder");
|
||||
return false;
|
||||
@@ -292,15 +292,13 @@ bool PngToFramebufferConverter::decodeToFramebuffer(const std::string& imagePath
|
||||
|
||||
int rc = png->open(imagePath.c_str(), pngOpenWithHandle, pngCloseWithHandle, pngReadWithHandle, pngSeekWithHandle,
|
||||
pngDrawCallback);
|
||||
const ScopedCleanup cleanup{[&png]() { png->close(); }};
|
||||
if (rc != PNG_SUCCESS) {
|
||||
LOG_ERR("PNG", "Failed to open PNG: %d", rc);
|
||||
delete png;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!validateImageDimensions(png->getWidth(), png->getHeight(), "PNG")) {
|
||||
png->close();
|
||||
delete png;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -335,8 +333,6 @@ bool PngToFramebufferConverter::decodeToFramebuffer(const std::string& imagePath
|
||||
"PNG row buffer too small: need %d bytes for width=%d type=%d, configured PNG_MAX_BUFFERED_PIXELS=%d",
|
||||
requiredInternal, ctx.srcWidth, pixelType, PNG_MAX_BUFFERED_PIXELS);
|
||||
LOG_ERR("PNG", "Aborting decode to avoid PNGdec internal buffer overflow");
|
||||
png->close();
|
||||
delete png;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -349,8 +345,6 @@ bool PngToFramebufferConverter::decodeToFramebuffer(const std::string& imagePath
|
||||
ctx.grayLineBuffer = static_cast<uint8_t*>(malloc(grayBufSize));
|
||||
if (!ctx.grayLineBuffer) {
|
||||
LOG_ERR("PNG", "Failed to allocate gray line buffer");
|
||||
png->close();
|
||||
delete png;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -380,13 +374,9 @@ bool PngToFramebufferConverter::decodeToFramebuffer(const std::string& imagePath
|
||||
|
||||
if (rc != PNG_SUCCESS) {
|
||||
LOG_ERR("PNG", "Decode failed: %d", rc);
|
||||
png->close();
|
||||
delete png;
|
||||
return false;
|
||||
}
|
||||
|
||||
png->close();
|
||||
delete png;
|
||||
LOG_DBG("PNG", "PNG decoding complete - render time: %lu ms", decodeTime);
|
||||
|
||||
// Write cache file if caching was enabled and buffer was allocated
|
||||
|
||||
@@ -52,6 +52,8 @@ void CalibreConnectActivity::onEnter() {
|
||||
void CalibreConnectActivity::onExit() {
|
||||
Activity::onExit();
|
||||
|
||||
MDNS.end();
|
||||
|
||||
if (WiFi.getMode() != WIFI_MODE_NULL) {
|
||||
WiFi.disconnect(false);
|
||||
delay(30);
|
||||
@@ -72,6 +74,7 @@ void CalibreConnectActivity::startWebServer() {
|
||||
state = CalibreConnectState::SERVER_STARTING;
|
||||
requestUpdate();
|
||||
|
||||
MDNS.end();
|
||||
if (MDNS.begin(HOSTNAME)) {
|
||||
// mDNS is optional for the Calibre plugin but still helpful for users.
|
||||
LOG_DBG("CAL", "mDNS started: http://%s.local/", HOSTNAME);
|
||||
|
||||
@@ -32,6 +32,23 @@ constexpr int QR_CODE_HEIGHT = 198;
|
||||
DNSServer* dnsServer = nullptr;
|
||||
constexpr uint16_t DNS_PORT = 53;
|
||||
|
||||
void stopDnsServer() {
|
||||
if (!dnsServer) return;
|
||||
|
||||
dnsServer->stop();
|
||||
delete dnsServer;
|
||||
dnsServer = nullptr;
|
||||
}
|
||||
|
||||
void restartMdns(const char* hostname, const char* tag) {
|
||||
MDNS.end();
|
||||
if (MDNS.begin(hostname)) {
|
||||
LOG_DBG(tag, "mDNS started: http://%s.local/", hostname);
|
||||
} else {
|
||||
LOG_DBG(tag, "WARNING: mDNS failed to start");
|
||||
}
|
||||
}
|
||||
|
||||
// 0..4 bars from RSSI (dBm), with 3 dBm hysteresis on currentBars to suppress flicker.
|
||||
int barsForRssi(int rssi, int currentBars) {
|
||||
static constexpr int RISE_DBM[] = {-85, -75, -65, -55};
|
||||
@@ -75,6 +92,8 @@ void CrossPointWebServerActivity::onExit() {
|
||||
LOG_DBG("WEBACT", "Free heap at onExit start: %d bytes", ESP.getFreeHeap());
|
||||
|
||||
state = WebServerActivityState::SHUTTING_DOWN;
|
||||
stopDnsServer();
|
||||
MDNS.end();
|
||||
|
||||
// Skip reboot if WiFi was never activated (e.g. user backed out of mode selection).
|
||||
if (WiFi.getMode() != WIFI_MODE_NULL) {
|
||||
@@ -151,9 +170,7 @@ void CrossPointWebServerActivity::onWifiSelectionComplete(const bool connected)
|
||||
isApMode = false;
|
||||
|
||||
// Start mDNS for hostname resolution
|
||||
if (MDNS.begin(AP_HOSTNAME)) {
|
||||
LOG_DBG("WEBACT", "mDNS started: http://%s.local/", AP_HOSTNAME);
|
||||
}
|
||||
restartMdns(AP_HOSTNAME, "WEBACT");
|
||||
|
||||
// Start the web server
|
||||
startWebServer();
|
||||
@@ -209,14 +226,11 @@ void CrossPointWebServerActivity::startAccessPoint() {
|
||||
LOG_DBG("WEBACT", "IP: %s", connectedIP.c_str());
|
||||
|
||||
// Start mDNS for hostname resolution
|
||||
if (MDNS.begin(AP_HOSTNAME)) {
|
||||
LOG_DBG("WEBACT", "mDNS started: http://%s.local/", AP_HOSTNAME);
|
||||
} else {
|
||||
LOG_DBG("WEBACT", "WARNING: mDNS failed to start");
|
||||
}
|
||||
restartMdns(AP_HOSTNAME, "WEBACT");
|
||||
|
||||
// Start DNS server for captive portal behavior
|
||||
// This redirects all DNS queries to our IP, making any domain typed resolve to us
|
||||
stopDnsServer();
|
||||
dnsServer = new DNSServer();
|
||||
dnsServer->setErrorReplyCode(DNSReplyCode::NoError);
|
||||
dnsServer->start(DNS_PORT, "*", apIP);
|
||||
|
||||
Reference in New Issue
Block a user