If you don't use the standard library, and you don't need JIT, you can simply not use pointers to callbacks. You can still have something like qsort() but you need to have statically defined: typedef void*(*callback)(...);extern const callback callbacks[256]; and qsort() takes an index instead of a raw pointer to a callback. "Validating" a callback is cheap: Just make sure it's <256 (how many do you need anyway?). If…
Neat. But how do you make this modular and still safe? When the code invoking qsort() does not know about how many callbacks there are, can you still deal with it?
struct danger {
sort_fn sorter;
char data[16];
};
danger->sorter(danger); /* what if it's a bad pointer? */
You replace that with this. int add_sort_fn(sort_fn sorter) {
sort_fns[num_sorts++] = sorter;
return num_sorts;
}
struct lessdanger {
int sortidx;
char data[16];
};
danger->sortidx = add_sort_fn(sorter);
/* could clean this up a bit more */
sort_fns[danger->sortidx % num_sorts](danger);
There's still the possibility of calling the wrong function, but only one from a finite set of possibilities. There's no direct control over the pointer value.You can make the sort_fns array resizeable, but in practice there's usually only so many targets.