このプログラムは、先日Linuxのデバイスドライバで見かけたコードを簡略化してわかりやすくしたものです。
そのデバイスドライバは、メモリ解放のタイミングでカーネルパニックを起こしていました。

#include <stdio.h>
#include <stdlib.h>

struct inst_t {
    char *p;
};

void free_mem(struct inst_t inst)
{
    if (inst.p) {
        free(inst.p);
    }
}

int main(void)
{
    struct inst_t inst;

    if (0) {
        inst.p = malloc(100);
    }
    free_mem(inst);

    return 0;
}

実装上、メモリの取得と解放がすぐ近くにあるのは稀なケースです。
この例では、if (0) で無条件で不成立のコードですが、実装上は条件文がちゃんとあり適切なタイミングで必要分のメモリ取得を行っています。
この例にあるfree_mem()の実装は、inst.pの中がセットされていればメモリ解放するコードですが、実コードもそのつもりだったようです。

一体何が起きているのでしょうか?