Функция fprintf использует внутреннюю буферизацию. И первым происходит запись в поток stderr, так как туда пишется гораздо больше данных. Так как родительский процесс ожидает данные из stdout, он не вычитывает stderr и как только внутренний буфер pipe переполняется, дочерняя программа зависает — ожидает когда освободится буфер stderr.