From f80342b0ce2b392e619cdbe5a77a585087372f9b Mon Sep 17 00:00:00 2001 From: Joe Andaverde Date: Sun, 5 Jul 2026 10:09:08 -0500 Subject: [PATCH] Fix FTDI GetDeviceInfoList stack overflow + duplicate serials in auto-config FT245RBitbangControllerAutoConfigurator passed a single-element stack node to GetDeviceInfoList once per device. GetDeviceInfoList writes one node per detected device, so with 2+ FTDI boards it wrote past the 1-element buffer (a std::string assignment into out-of-bounds stack) -> memory corruption/crash; and the loop index i was never used, so every controller got device[0] serial/description (duplicate serials, only the first board addressable). Fill one correctly-sized buffer in a single call and index by i, matching the C# OpenByIndex(i) loop. Also make GetDeviceInfoList honor the callers buffer capacity (like the real FTD2XX API) so an undersized buffer cannot overflow again. --- ...T245RBitbangControllerAutoConfigurator.cpp | 25 ++++++++++--------- src/cab/out/ftdichip/FTDI.cpp | 5 ++-- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/cab/out/ftdichip/FT245RBitbangControllerAutoConfigurator.cpp b/src/cab/out/ftdichip/FT245RBitbangControllerAutoConfigurator.cpp index 3b4a24c..181e2e5 100644 --- a/src/cab/out/ftdichip/FT245RBitbangControllerAutoConfigurator.cpp +++ b/src/cab/out/ftdichip/FT245RBitbangControllerAutoConfigurator.cpp @@ -30,19 +30,20 @@ void FT245RBitbangControllerAutoConfigurator::AutoConfig(Cabinet* cabinet) return; } - for (uint32_t i = 0; i < amountDevices; i++) + // Fill one properly-sized buffer in a single call and index each device by i, + // like the C# OpenByIndex(i) loop. The previous code passed a 1-element buffer + // per iteration (GetDeviceInfoList writes one node per device -> overflow with + // 2+ boards) and never used i (so every controller got device[0]'s serial). + std::vector devInfos(amountDevices); + uint32_t numDevs = amountDevices; + FTDI* connectFTDI = new FTDI(); + status = connectFTDI->GetDeviceInfoList(devInfos.data(), numDevs); + delete connectFTDI; + + if (status == FTDI::FT_OK) { - FTDI* connectFTDI = new FTDI(); - - FTDI::FT_DEVICE_INFO_NODE devInfo; - uint32_t numDevs = 1; - status = connectFTDI->GetDeviceInfoList(&devInfo, numDevs); - - if (status == FTDI::FT_OK && numDevs > 0) - { - deviceList.emplace_back(devInfo.SerialNumber, devInfo.Description); - } - delete connectFTDI; + for (uint32_t i = 0; i < numDevs && i < devInfos.size(); i++) + deviceList.emplace_back(devInfos[i].SerialNumber, devInfos[i].Description); } for (int deviceIndex = 0; deviceIndex < static_cast(deviceList.size()); deviceIndex++) diff --git a/src/cab/out/ftdichip/FTDI.cpp b/src/cab/out/ftdichip/FTDI.cpp index 37e952d..bd55a04 100644 --- a/src/cab/out/ftdichip/FTDI.cpp +++ b/src/cab/out/ftdichip/FTDI.cpp @@ -78,10 +78,11 @@ FTDI::FT_STATUS FTDI::GetDeviceInfoList(FT_DEVICE_INFO_NODE* devinfo, uint32_t& return ConvertLibftdiError(result); } - numdevs = static_cast(result); + const uint32_t capacity = numdevs; // caller's buffer size (IN) + numdevs = static_cast(result); // total devices found (OUT) struct ftdi_device_list* curdev = devlist; - for (uint32_t i = 0; i < numdevs && curdev; ++i, curdev = curdev->next) + for (uint32_t i = 0; i < numdevs && i < capacity && curdev; ++i, curdev = curdev->next) { char manufacturer[256] = { 0 }; char description[256] = { 0 };