client: free graph and demod buffer save states after restore

save_graphbuffer() and save_buffer8() calloc a copy, and the restore_*()
helpers only copy out of it, so every owner leaked its save state.
check_chiptype() lost 4 * g_GraphTraceLen bytes plus the packed demod
buffer on each online `lf search` (~2 MB after the COTAG probe), and the
Visa2000 demod leaked on every `lf search`, online or offline.

Add free_buffer_savestate() and call it after the last restore in
check_chiptype(), demodTI(), demodVisa2k(), demodzx(),
try_detect_modulation() and t55xx_psk_untrim_head(), including the
early-return and success paths that never restored.

Reported with the check_chiptype() diagnosis and fix by @BeheSQ.

Fixes #3675

Co-Authored-By: Grok Bot <noreply@users.noreply.github.com>
This commit is contained in:
Zhaoqi XuandGrok Bot committed 2026-10-11 06:51:44 +08:00
1 parent a48ce253f7
commit 10fa02ca24
9 files changed
+21

No files matched your search

+1
View File
@@ -2798,6 +2798,7 @@ static int try_detect_modulation(void) {
}
//undo trim samples
restore_graphbuffer(saveState);
free_buffer_savestate(saveState);
}
}
+2
View File
@@ -1733,6 +1733,8 @@ out:
restore_graphbuffer(saveState_gb);
free_buffer_savestate(saveState_db);
free_buffer_savestate(saveState_gb);
return retval;
}
+1
View File
@@ -124,6 +124,7 @@ static buffer_savestate_t t55xx_psk_trim_head(void) {
static void t55xx_psk_untrim_head(buffer_savestate_t st) {
s_sample_bias = 0;
restore_graphbuffer(st);
free_buffer_savestate(st);
}
// the bit offset to read a block at in the demod buffer loaded right now
+2
View File
@@ -100,6 +100,7 @@ int demodTI(bool verbose) {
int retval = PM3_ESOFT;
if (g_GraphTraceLen < convLen) {
free_buffer_savestate(saveState);
return retval;
}
for (i = 0; i < g_GraphTraceLen - convLen; i++) {
@@ -280,6 +281,7 @@ out:
restore_graphbuffer(saveState);
}
free_buffer_savestate(saveState);
return retval;
}
+5
View File
@@ -93,6 +93,7 @@ int demodVisa2k(bool verbose) {
if (ASKDemod_ext(64, 0, 0, 0, false, false, false, 1, &st) != PM3_SUCCESS) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Visa2k: ASK/Manchester Demod failed");
restore_graphbuffer(saveState);
free_buffer_savestate(saveState);
return PM3_ESOFT;
}
size_t size = g_DemodBufferLen;
@@ -108,6 +109,7 @@ int demodVisa2k(bool verbose) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Visa2k: ans: %d", ans);
restore_graphbuffer(saveState);
free_buffer_savestate(saveState);
return PM3_ESOFT;
}
setDemodBuff(g_DemodBuffer, 96, ans);
@@ -126,6 +128,7 @@ int demodVisa2k(bool verbose) {
if (chk != calc) {
PrintAndLogEx(DEBUG, "DEBUG: error: Visa2000 checksum (%s) %x - %x\n", _RED_("fail"), chk, calc);
restore_graphbuffer(saveState);
free_buffer_savestate(saveState);
return PM3_ESOFT;
}
// parity
@@ -134,9 +137,11 @@ int demodVisa2k(bool verbose) {
if (calc_par != chk_par) {
PrintAndLogEx(DEBUG, "DEBUG: error: Visa2000 parity (%s) %x - %x\n", _RED_("fail"), chk_par, calc_par);
restore_graphbuffer(saveState);
free_buffer_savestate(saveState);
return PM3_ESOFT;
}
PrintAndLogEx(SUCCESS, "Visa2000 - Card " _GREEN_("%u") ", Raw: %08X%08X%08X", raw2, raw1, raw2, raw3);
free_buffer_savestate(saveState);
return PM3_SUCCESS;
}
+3
View File
@@ -50,6 +50,7 @@ int demodzx(bool verbose) {
if (ASKDemod_ext(64, 0, 0, 0, false, false, false, 1, &st) != PM3_SUCCESS) {
PrintAndLogEx(DEBUG, "DEBUG: Error - ZX: ASK/Manchester Demod failed");
restore_graphbuffer(saveState);
free_buffer_savestate(saveState);
return PM3_ESOFT;
}
size_t size = g_DemodBufferLen;
@@ -65,6 +66,7 @@ int demodzx(bool verbose) {
PrintAndLogEx(DEBUG, "DEBUG: Error - ZX: ans: %d", ans);
restore_graphbuffer(saveState);
free_buffer_savestate(saveState);
return PM3_ESOFT;
}
setDemodBuff(g_DemodBuffer, 96, ans);
@@ -78,6 +80,7 @@ int demodzx(bool verbose) {
// test checksums
PrintAndLogEx(SUCCESS, "ZX8211 - Card " _GREEN_("%u"), raw1);
free_buffer_savestate(saveState);
return PM3_SUCCESS;
}
+5
View File
@@ -666,3 +666,8 @@ void restore_graphbuffer(buffer_savestate_t saveState) {
g_GraphTraceLen = len;
g_GridOffset = saveState.offset;
}
// restore_*() copy out of the save state, the owner frees it after its last restore
void free_buffer_savestate(buffer_savestate_t saveState) {
free((void *)saveState.buffer);
}
+1
View File
@@ -69,6 +69,7 @@ size_t restore_buffer8(buffer_savestate_t saveState, uint8_t *dest);
buffer_savestate_t save_graphbuffer(void);
void restore_graphbuffer(buffer_savestate_t saveState);
void free_buffer_savestate(buffer_savestate_t saveState);
#define MAX_GRAPH_TRACE_LEN (40000 * 32)
#define GRAPH_SAVE 1