error()/error_at_line() and threads
enh
enh@google.com
Thu Jun 11 16:52:04 GMT 2026
On Thu, Jun 11, 2026 at 12:44 PM Florian Weimer <fweimer@redhat.com> wrote:
>
> > the man page further has the rather over-optimistic:
> >
> > The internal error_one_per_line variable is accessed (without any
> > form of synchronization, but since it's an int used once, it
> > should be safe enough), and if error_one_per_line is set nonzero,
> > the internal static variables (not exposed to users) used to hold
> > the last printed filename and line number are accessed and
> > modified without synchronization; the update is not atomic and it
> > occurs before disabling cancelation, so it can be interrupted only
> > after one of the two variables is modified. After that,
> > error_at_line() is very much like error().
> >
> > but neither say anything about error_message_count. a quick test
> > program shows that, as you'd expect, some increments get lost in the
> > presence of many threads.
>
> With glibc? That's surprising because we lock stderr before updating
> error_message_count.
yeah, i reproduced this on debian glibc 2.42. the following program
often comes up one short...
#include <error.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <thread>
#include <vector>
int main() {
int old_stderr = dup(STDERR_FILENO);
int dev_null = open("/dev/null", O_WRONLY);
dup2(dev_null, STDERR_FILENO);
close(dev_null);
error_message_count = 0;
const int kNumThreads = 50;
const int kIterations = 10000;
std::vector<std::thread> threads;
for (int i = 0; i < kNumThreads; ++i) {
threads.emplace_back([]() {
for (int j = 0; j < kIterations; ++j) {
error(0, 0, "test %d", j);
}
});
}
for (auto& t : threads) {
t.join();
}
dup2(old_stderr, STDERR_FILENO);
close(old_stderr);
printf("%d\n", kNumThreads * kIterations);
printf("%u\n", error_message_count);
return 0;
}
> Thanks,
> Florian
>
More information about the Libc-alpha
mailing list