Here is another way to avoid use after free: lint out calls to malloc/calloc/realloc/free in all but a small subset of files. Define a header with an interface with something like:
void with_bytes(size_t count, void (*cb)(void *bytes);
You also may need to write similar wrappers around dependencies that require manual freeing of resources.Programming in this style will force you to think about the life cycle of every allocation and there are ways you can still shoot yourself in the foot. But as long as you avoid storing references in static variables, you will generally avoid memory leaks and use after free when programming in this style.
And you can just do this with any c compiler without relying on new dependencies.