Skip to content

Fix parse_csv() dropping the final CSV field - #181

Merged
brentru merged 1 commit into
adafruit:masterfrom
mikeysklar:fix-parsecsv-last-field
Apr 14, 2026
Merged

brentru merged 1 commit into
adafruit:masterfrom
mikeysklar:fix-parsecsv-last-field

Conversation

@mikeysklar

@mikeysklar mikeysklar commented Apr 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

parse_csv() in src/AdafruitIO_Data.cpp silently drops the final field of every CSV it parses — for an N-field input it only populates slots 0..N-2, leaving NULL at N-1.

Root cause

The '\0' case in the parse loop breaks out without emitting the field accumulated since the last comma, unlike the ',' case which correctly strdups each field.

Fix

Emit the final field from inside the '\0' case before setting fEnd, using the same strdup + cleanup path as the ',' case.

Relationship to #180

#180's index fix in _parseCSV() is correct but depends on this PR — without it, correcting the indices causes atof(NULL) → crash on every incoming location message. Suggest landing this first, then #180.

Verification

Tested on Feather ESP32 V2 with both fixes applied:

=== parse_csv verification ===
lat: 10.111111
lon: 20.222222
ele: 30.333333

Test plan

  • Unit-style sketch on Feather ESP32 V2: all four fields parsed correctly, no crash.
  • - [ ] Maintainer sanity-check on another platform if desired.
    🤖 Generated with Claude Code

parse_csv() advances bptr and strdups into buf on every comma, but on
the terminating '\0' it only sets fEnd and breaks out of the loop. The
content accumulated in tmp since the last comma was never emitted, so
for an N-field CSV the function returned N-1 strings followed by NULL
even though count_fields() correctly reported N.

In practice this meant buf[N-1] was NULL. Callers like _parseCSV() that
read the last field (e.g. atof(fields[3]) for the elevation in a
value,lat,lon,ele location CSV) dereferenced NULL and crashed with
LoadProhibited on ESP32. The bug was masked on main by a second bug in
_parseCSV() that incorrectly read fields[1] three times instead of
fields[1..3], so the last slot was never actually accessed.

Fix: emit the final field from inside the '\0' case before setting
fEnd. Uses the same strdup + allocation-failure cleanup as the ','
case.
@mikeysklar

mikeysklar commented Apr 13, 2026 •

Copy link
Copy Markdown
Contributor Author

End-to-end verified on Feather ESP32 V2 and QT Py ESP32-S3

Ran the stock examples/adafruitio_04_location sketch with both this PR and #180 applied on both an Adafruit Feather ESP32 V2 and an Adafruit QT Py ESP32-S3. Consecutive round-trips through the real AIO broker, every field matching, value incrementing across cycles (no more reboot loop), no crash on either board.

Feather ESP32 V2:

----- sending -----
value: 1
lat: 42.321427
lon: -83.025754
ele: 1.00
----- received -----
value: 1
lat: 42.321427
lon: -83.025754
ele: 1.00
----- sending -----
value: 2
lat: 42.311427
lon: -83.005754
ele: 2.00
----- received -----
value: 2
lat: 42.311427
lon: -83.005754
ele: 2.00
----- sending -----
value: 3
lat: 42.301427
lon: -82.985754
ele: 3.00
----- received -----
value: 3
lat: 42.301427
lon: -82.985754
ele: 3.00
----- sending -----
value: 4
lat: 42.291427
lon: -82.965754
ele: 4.00
----- received -----
value: 4
lat: 42.291427
lon: -82.965754
ele: 4.00

Note: on main the S3 was crashing in what looked like the publish path (right after the ele: 0.00 print), but it was actually the same atof(NULL) deref hit via the inbound echo on a tighter timing window — the save() call returns, the MQTT thread delivers the echoed message a few ms later, and _parseCSV() crashes before loop() gets back to its next print. The combined #180 + #181 patches fix both boards.

The two fixes

They mask each other: #180's index bug kept #180's readers away from fields[N-1], hiding #181's NULL. Fixing #180 alone turns "wrong values" into "null-pointer deref on every receive" (LoadProhibited on ESP32). Both are needed; this one should land first.

brentru added a commit that referenced this pull request Apr 14, 2026
Fix _parseCSV() array index bug: combined PR #180 and PR #181
@brentru
brentru merged commit 590d70e into adafruit:master Apr 14, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants