ESPHome 2026.3.0
Loading...
Searching...
No Matches
printf_stubs.cpp
Go to the documentation of this file.
1/*
2 * Linker wrap stubs for FILE*-based printf functions.
3 *
4 * The RP2040 Arduino framework and libraries may reference printf(),
5 * vprintf(), and fprintf() which pull in newlib's _vfprintf_r (~8.9 KB).
6 * ESPHome never uses these — all logging goes through the logger component
7 * which uses snprintf/vsnprintf, so the libc FILE*-based printf path is
8 * dead code.
9 *
10 * These stubs redirect through vsnprintf() (which is already in the binary)
11 * and fwrite(), allowing the linker to dead-code eliminate _vfprintf_r.
12 *
13 * Saves ~8.9 KB of flash.
14 */
15
16#if defined(USE_RP2040) && !defined(USE_FULL_PRINTF)
17#include <cstdarg>
18#include <cstdio>
19#include <cstdlib>
20
21namespace esphome::rp2040 {}
22
23static constexpr size_t PRINTF_BUFFER_SIZE = 512;
24
25// These stubs are essentially dead code at runtime — ESPHome uses its own
26// logging through snprintf/vsnprintf, not libc printf.
27// The buffer overflow check is purely defensive and should never trigger.
28static int write_printf_buffer(FILE *stream, char *buf, int len) {
29 if (len < 0) {
30 return len;
31 }
32 size_t write_len = len;
33 if (write_len >= PRINTF_BUFFER_SIZE) {
34 fwrite(buf, 1, PRINTF_BUFFER_SIZE - 1, stream);
35 // Use fwrite for the message to avoid recursive __wrap_printf call
36 static const char msg[] = "\nprintf buffer overflow\n";
37 fwrite(msg, 1, sizeof(msg) - 1, stream);
38 abort();
39 }
40 if (fwrite(buf, 1, write_len, stream) < write_len || ferror(stream)) {
41 return -1;
42 }
43 return len;
44}
45
46// NOLINTBEGIN(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp,readability-identifier-naming)
47extern "C" {
48
49int __wrap_vprintf(const char *fmt, va_list ap) {
50 char buf[PRINTF_BUFFER_SIZE];
51 return write_printf_buffer(stdout, buf, vsnprintf(buf, sizeof(buf), fmt, ap));
52}
53
54int __wrap_printf(const char *fmt, ...) {
55 va_list ap;
56 va_start(ap, fmt);
57 int len = __wrap_vprintf(fmt, ap);
58 va_end(ap);
59 return len;
60}
61
62int __wrap_fprintf(FILE *stream, const char *fmt, ...) {
63 va_list ap;
64 va_start(ap, fmt);
65 char buf[PRINTF_BUFFER_SIZE];
66 int len = write_printf_buffer(stream, buf, vsnprintf(buf, sizeof(buf), fmt, ap));
67 va_end(ap);
68 return len;
69}
70
71} // extern "C"
72// NOLINTEND(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp,readability-identifier-naming)
73
74#endif // USE_RP2040 && !USE_FULL_PRINTF
int __wrap_fprintf(FILE *stream, const char *fmt,...)
int __wrap_printf(const char *fmt,...)
int __wrap_vprintf(const char *fmt, va_list ap)
uint32_t len