Printing in thread
| Vulnerability potential | None |
| DDoS potential | Low |
Printing in a thread is not encouraged
Impact
Writing to the standard output/error streams from a worker thread is discouraged
because the streams are a shared, serialized resource. Multiple threads printing
concurrently produce interleaved, hard-to-read output, and every call contends on
the stream’s internal lock — turning logging into an unintended synchronization
point. If the thread is meant to be a fast hot path, the blocking, lock-protected
I/O can dominate its runtime and stall siblings waiting on the same FILE.
This is primarily a quality/design defect: diagnostics belong in a dedicated
logging facility, not scattered printf calls inside threads. The functional
risk is garbled logs and surprising latency rather than a crash.
Vulnerability potential
This has no meaningful security relevance: emitting text to a stream does not
corrupt memory, escalate privilege, or leak data beyond whatever the message
itself contains. The only marginal concern is that heavy per-thread printing
serializes work on the stream lock and adds blocking I/O, which under extreme load
contributes mildly to slowdowns — hence a Low DoS rating and None for
vulnerability. (If the format string were attacker-controlled, that would be a
separate format-string defect, not this one.)
Technical details
Stream-level locking
In C, stdio streams are line-buffered or fully buffered and, per POSIX, each
FILE operation takes an implicit lock (flockfile/funlockfile). So individual
printf calls are atomic, but a sequence of them is not: another thread can
interleave between two calls, splitting a logical message. Mixing printf with
direct write(2) to the same fd bypasses the buffer and scrambles ordering
further.
C++ streams
std::cout is thread-safe per character but not per << chain; a << x << y
from two threads interleaves the tokens. std::cout is also synchronized with C
stdio by default (sync_with_stdio), adding more contention.
Performance and ordering
Because the lock and the actual I/O syscall are on the critical path, a thread that prints frequently effectively serializes with every other printing thread. Output order no longer reflects execution order, which makes the logs misleading for debugging concurrency.
Catching the issue
Static analysis / linters
The analyzer that emits this diagnostic flags direct console I/O (printf,
std::cout, puts) inside functions that run on a non-main thread. Custom
clang-tidy or grep-based review rules can do the same.
Use a logging library
Replace ad-hoc prints with a thread-aware logger (spdlog, glog, a ring-buffer logger) that batches, timestamps, tags the thread id, and serializes output in one place. Prefer a single dedicated I/O thread that other threads feed via a queue.
Atomicity when you must print
If direct printing is unavoidable, build the whole message in a local buffer and
emit it with a single fputs/write, or guard the sequence with
flockfile/funlockfile, so a logical line is never split.
How to reproduce
Run this and observe that the two threads’ messages interleave within a line: the
<< chain is not atomic, so output from different threads is mixed.
#include <iostream>
#include <thread>
void worker(int id)
{
for (int i = 0; i < 1000; ++i)
std::cout << "thread " << id << " line " << i << "\n";
}
int main()
{
std::thread a(worker, 1), b(worker, 2);
a.join();
b.join();
return 0;
}