OpenZFS Bug Ported to C
There was an (almost) catastrophic OpenZFS bug. If they had used zig, the bug would be easily detected. But the question remains, could we detect this bug in C?
more...
There was an (almost) catastrophic OpenZFS bug. If they had used zig, the bug would be easily detected. But the question remains, could we detect this bug in C?
more...
On OpenBSD, there is a rule that you link with libc to interface with the kernel, because that’s where the syscall stubs live. This causes a great deal of consternation for partisans of other languages, because they don’t want to link “all of libc”. But when does anything link all of libc?
more...
What if we want a grep that doesn’t stuck but we don’t want to resort to wild hacks like editing the source? What if there was some way to flush stdout automatically?
The auto flusher is a very simple preload.
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
static void *
flusher(void *arg)
{
while (1) {
sleep(3);
fflush(stdout);
}
}
__attribute__((constructor))
void
herewego(void)
{
pthread_t thread;
pthread_create(&thread, NULL, flusher, NULL);
}
Magic constructor attribute for initializers in C, and then we create a thread which loops around occasionally flushing stdout, so if there’s any data left lingering, it will eventually find it’s way out instead of waiting forever.
$ cc -shared -lpthread -o libflusher.so flusher.c
$ env LD_PRELOAD=./libflusher.so grep ...
Sometimes pipes get stuck. To recap, if we run this command...
~/src/usr.bin/grep> tail -200 util.c | grep unsigned | grep int
grep_revstr(unsigned char *str, int len)
... we get the expected output. If we run it this way, however, there’s no output.
~/src/usr.bin/grep> tail -f -200 util.c | grep unsigned | grep int
The file isn’t being appended, meaning tail won’t exit, so we don’t expect the pipeline to ever finish, but we would like to see the current results.
Fortunately, grep provides an lbflag we can set. In this case, if the input is a pipe, we’ll assume there’s something fancy going on, and switch to line buffering.
struct stat sb;
fstat(0, &sb);
if ((sb.st_mode & S_IFMT) == S_IFIFO)
lbflag = 1;
Easy fix. (Or one can read the manual.)
But this is excessive. What about those times when we want the efficiency of buffering? There are lots of possible pipelines that don’t involve tail. What we can do instead is take a peek at some of our neighbors and see what’s really going on. Not perfectly accurate, but probably good enough.
static void
checklbflag()
{
pid_t pgrp = getpgrp();
struct kinfo_proc ki[24];
size_t len = sizeof(ki);
int mib[6] = { CTL_KERN, KERN_PROC, KERN_PROC_PGRP, pgrp,
sizeof(ki[0]), sizeof(ki)/sizeof(ki[0]) };
sysctl(mib, 6, ki, &len, NULL, 0);
for (size_t i = 0; i < len / sizeof(ki[0]); i++)
if (strcmp(ki[i].p_comm, "tail") == 0)
lbflag = 1;
}
Alas, this requires including <sys/sysctl.h> which will slow down our compiles.
It is also possible, using forbidden magic, to determine whether the pipe we are reading from is being written to by tail, as opposed to a tail at the end of the pipeline, but that’s left as an exercise for the reader.
Memory leaks have plagued C programs for as long as the language has existed. Many solutions have been proposed, even going so far as to suggest we should rewrite C programs in other languages. But there’s a better way.
Presented here is a simple solution that will eliminate the memory leaks from every C program. Link this into your program, and memory leaks are a thing of the past.
leakproof.c
#include <dlfcn.h>
#include <stdio.h>
struct leaksaver {
struct leaksaver *next;
void *pointer;
} *bigbucket;
void *
malloc(size_t len)
{
static void *(*nextmalloc)(size_t);
nextmalloc = dlsym(RTLD_NEXT, "malloc");
void *ptr = nextmalloc(len);
if (ptr) {
struct leaksaver *saver = nextmalloc(sizeof(*saver));
saver->pointer = ptr;
saver->next = bigbucket;
bigbucket = saver;
}
return ptr;
}
Every allocated pointer is saved in the big bucket, where it remains accessible. Even if no other references to the pointer exist in the program, the pointer has not leaked.
It is now entirely optional to call free
. If you don’t call free, memory usage will increase over time, but technically, it’s not a leak. As an optimization, you may choose to call free to reduce memory, but again, strictly optional.
Problem sovled!
Cosmic rays are believed by some to exist, although I’ve never seen one. Have you? Are the cosmic rays in the room with us now? It has been further claimed that these cosmic rays may interact with our computers, possibly causing strange behaviors. This sounds like pseudo scientific babble from people who don’t believe in the ghost in the machine.
more...
C functions commonly, though not universally, provide information about a failure through the global variable like errno. Provide, not indicate. If there’s no error, as indicated by the function’s normal return value, the value and meaning of errno is unreliable.
more...
Sometimes you have a large file when you want a small file. You may not be able to edit the large file, but that’s okay, you can simply read the small part you want out of the large file. libfdview is a proof of concept library that presents a smaller view of a larger file.
more...
Before relying on compiler warnings for enum mismatches, it’s important to know when or if such warnings will be generated.
more...
Sometimes we have a boolean, which is great for storing two values, but we need just a little more space to squeeze in a third value. There’s a few ways to do this.
more...