プロが教えるわが家の防犯対策術!

スタックフレームの消滅についての質問です。
以下のCのプログラムですが、

char *sayHello(void) {

char s[] = "hello";
return s;
}

int main(void) {
char *s;

s = sayHello();
printf("%s\n", s);

return 0;
}

コンパイルすると、
warning: address of stack memory associated with local variable
's' returned [-Wreturn-stack-address]
のワーニングが出て、実行すると、nullが返ってくる様ですが、
書籍にも、「ローカル変数は、スタックフレームの消滅と共に消えて無くなる」とあるのですが、
実際にアセンブルしたコードを見てみると、リターン後は、sayHello関数のスタックフレームは
無くなり、ebpのベースポインタとespのスタックポインタがそれぞれmain関数のBOTTOMとTOPを指す様になるのですが、sayHelloの関数領域は、次の何かの関数が呼び出されて上書きされない限り、残っている様に思うのですが、アセンブラの処理としてどこかの記述で使い終わったスタックフレームの領域を消去する様な記述がされている様な所とかあるのでしょうか?

質問者からの補足コメント

  • 実行ファイルを実行しただけです。

    No.1の回答に寄せられた補足コメントです。 補足日時:2023/05/20 14:26
  • 返される値は使っている環境によると思います。

    No.2の回答に寄せられた補足コメントです。 補足日時:2023/05/20 16:15
  • sayHello()関数内のsとmain()関数内のsを表示させてみたのですが、
    clangのコンパイラを使った場合、

    0x7ffee5b8f9ca
    0x7ffee5b8f9ca
    n?̃?

    gccのコンパイラを使った場合、
    0x7ffee330891a
    0x0
    (null)

    になります。
    gccの場合、main()ではヌルポインタ(0x0)が戻ってきているみたいです。

    No.4の回答に寄せられた補足コメントです。 補足日時:2023/05/21 13:38

A 回答 (6件)

補足確認、および、共有ありがとうございます



コンパイラが意図的に戻り値を変更しているようですね。
gccが変更しているのは、ググったらありました

https://yohhoy.hatenadiary.jp/entry/20160509/p1
    • good
    • 0

コードは典型的な懸垂参照なので、言語仕様上は何が起こるか分かりませんね。


printfでnull表示されるからnullが返っていると判断されているようですが、printf自体が関数なのでprintfが呼び出された時点でスタックフレームは上書きされているわけで、printf関数内で何らかの異常対処をしている可能性もあります。
    • good
    • 0

No3です



>返される値は使っている環境によると思います。
環境によって、nullが戻り値として返ってくる可能性があると思ってるのであれば、それは違います

質問者さんのコードで、nullが返ってくるケースは、何かのバグか、コンパイラが意図的変更をしない限りnullは返ってきません

納得する、しないは、質問者さんが決められることですが、printfで、sayHello()関数内部で、sのアドレス表示と、main()でsの戻り値を表示すれば、何が起きてるのか、もう少し確認できると思います
この回答への補足あり
    • good
    • 0

ローカル変数は、通常その関数が呼ばれたときに、スタック上に確保するので、関数が戻るとそれ以降ローカル変数領域のメモリの保証はないので、コンパイラが、そのコードを解析したときに、nullポインターを返すようなコードを生成してるのでしょう。

スタックフレームを0フィルしてるわけではないと思います

少なくとも、コンパイラはコンパイル時に、そのワーニングが出せるということは、sayHello()関数が破棄予定のローカル変数のアドレスを返していると認識していることを裏付けているので

プログラムが、たまたま、動作してしまうと、いくらテストをしても問題が起きない可能性があるので、nullポインターを返すコードを生成することで、スタックエリアにアクセスしようとしたときに、必ずexceptionが発生するようにコンパイラが意図しているのでしょう


質問者さんが、他の関数を呼び出されない限り、残っているのでは?という推測は、コンパイラの仕様にもよりますが、ほぼ、間違いなくあってます

逆の言い方をすると、そのワーニングを消すようなオプションをつけてコンパイルすれば、多分、スタック上のポインターが戻され、問題なく動作しますが、それは、たまたま動作してるに過ぎないです
    • good
    • 0

「実行ファイルを実行しただけ」というのはどういうこと?



まさか「実行したみたら null と表示された」ので「実行すると、nullが返ってくる」と表現した, わけじゃないよね?
この回答への補足あり
    • good
    • 0

言語仕様ではいかなる保証もない. つまり「残ったまま」かもしれないし「何も言わないまま消滅してしまう」かもしれない. 少なくとも, 「残っている」ことを前提にするプログラムは「行儀が悪い」といえる.



ところで「実行すると、nullが返ってくる様ですが」というのはどうやって確かめた?
この回答への補足あり
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!