Source
cplewes/microlink commits 38602ab0 (fix) + b25b1eee (extracts derp_free_tls_state() helper reused by both disconnect and the new failure path). Hardware-verified with before/after heap numbers.
Bug
Every failed ml_derp_connect() leaks the TLS I/O buffers (~3-8KB per attempt) because the error paths after mbedtls_ssl_init()/mbedtls_ssl_setup() only do:
ml_close_sock(sock);
ml->derp.sockfd = -1;
without calling mbedtls_ssl_free()/mbedtls_ssl_config_free(). ml_derp_disconnect() only frees when sockfd >= 0, which is already false by the time it runs after a failed connect, so the allocation is never reclaimed. I independently found and verified the same ~10 leaking call sites in our own components/microlink/src/ml_derp.c (between the mbedtls_ssl_init() call and the success path) while investigating upstream PR #22 (see UPSTREAM_PRS.md's "mineable from #22" row) — cplewes already shipped a hardware-verified fix for the identical bug, so use that instead of reinventing it.
This matters for our one downstream consumer (zen-clock): it enables DERP unconditionally and calls microlink_rebind() (which reconnects DERP) on every WiFi reconnect — a long-running battery device will hit this repeatedly.
Target files
components/microlink/src/ml_derp.c (add a derp_tls_abort()/derp_free_tls_state()-style helper, replace the ~10 leaking failure paths in ml_derp_connect()).
Notes
Our fork's derp struct (microlink_internal.h) has no entropy/ctr_drbg fields (already removed for mbedTLS 4.x/PSA compat per ESP_IDF_6X_COMPAT.md) — the helper must free only ssl/ssl_conf, narrower than a generic port of the fix might assume.
Tier 1 — high confidence, hardware-verified, no known conflicts. See FORK_PRS.md row 1.
Source
cplewes/microlinkcommits38602ab0(fix) +b25b1eee(extractsderp_free_tls_state()helper reused by both disconnect and the new failure path). Hardware-verified with before/after heap numbers.Bug
Every failed
ml_derp_connect()leaks the TLS I/O buffers (~3-8KB per attempt) because the error paths aftermbedtls_ssl_init()/mbedtls_ssl_setup()only do:without calling
mbedtls_ssl_free()/mbedtls_ssl_config_free().ml_derp_disconnect()only frees whensockfd >= 0, which is already false by the time it runs after a failed connect, so the allocation is never reclaimed. I independently found and verified the same ~10 leaking call sites in our owncomponents/microlink/src/ml_derp.c(between thembedtls_ssl_init()call and the success path) while investigating upstream PR #22 (seeUPSTREAM_PRS.md's "mineable from #22" row) — cplewes already shipped a hardware-verified fix for the identical bug, so use that instead of reinventing it.This matters for our one downstream consumer (zen-clock): it enables DERP unconditionally and calls
microlink_rebind()(which reconnects DERP) on every WiFi reconnect — a long-running battery device will hit this repeatedly.Target files
components/microlink/src/ml_derp.c(add aderp_tls_abort()/derp_free_tls_state()-style helper, replace the ~10 leaking failure paths inml_derp_connect()).Notes
Our fork's
derpstruct (microlink_internal.h) has noentropy/ctr_drbgfields (already removed for mbedTLS 4.x/PSA compat perESP_IDF_6X_COMPAT.md) — the helper must free onlyssl/ssl_conf, narrower than a generic port of the fix might assume.Tier 1 — high confidence, hardware-verified, no known conflicts. See
FORK_PRS.mdrow 1.