関数内ブロックの局所自動変数のエクステント

思わずこう書きそうに。

...snip
int main(int argc, char *argv[])
{
    Lexer lexer;
    Token *token;
    size_t i;

    if (argc > 1) {
        Reader reader;
        strreader_init(&reader, argv[1]);
        lexer_init_with_reader(&lexer, &reader);
    } else {
...snip

if節を抜けた時点でlexerが持つReaderへのポインタがダングリングポインタになるはず。
ブロック内の局所自動変数のエクステントはスコープに一致すると思っているので。

...snip
    int *p1, *p2, *p3;
    {
        int y = 10;
        p1 = &y;
    }
    {
        int y = 20;
        p2 = &y;
    }
    {
        int y = 30;
        p3 = &y;
    }
...snip

この時それぞれのyのエクステントはそれぞれのブロックを抜けるまでであり、
3つ目のブロックを抜けた時点でp1、p2、p3の値は同じであることも(ないことも)あるはず。
でも手元にある複数のCコンパイラで試すと、
どれもコールスタック上の異なる場所にそれぞれのyを割り付けているので気になってしまった。
単に割り当てを単純にするためにたまたま異なる場所になっているのか、
本当は関数内ブロック内で宣言された局所自動変数のエクステントは関数ブロックを抜けるまでで、
自分の理解が間違っていたのか。
C89の規格上はどうなっているのだろう。