post Image
runtime.Caller(1)をなめて扱ったら危険かもしれない

議題

Golangでよくやる GetCurrentFile() とか GetCurrentDir() みたいなのはもしかしたら、ちょっと使い方間違えるとヤバイかもしれないというお話です。

よくやるやつ… つまりこう!!

import (
  "runtime"
  "path"
)

// __FILE__
func GetCurrentFile() string {
  _, filename, _, _ := runtime.Caller(1)
  return filename
}

// __DIR__
func GetCurrentDir() string {
  _, filename, _, _ := runtime.Caller(1)
  return path.Dir(filename)
}

runtime.Caller(1)っていうのが問題で、挙動を見る限り、これは現在位置と言うよりビルドしたソースの位置らしいのです。なので、ビルドしてビルドしたディレクトリ構成の外で使うと挙動がおかしくなります。

__DIR__的な考え

ディレクトリ パス 結果
元のディレクトリ /Volumes/go/foo/bar/ /Volumes/go/foo/bar/
お引越し先 /Home/fazbizz/ /Home/fazbizz/

GetCurrentDir()

ディレクトリ パス 結果
元のディレクトリ /Volumes/go/foo/bar/ /Volumes/go/foo/bar/
お引越し先 /Home/fazbizz/ /Volumes/go/foo/bar/

調査

とりあえず、日本語訳のドキュメントを読んでみる。
http://golang.jp/pkg/runtime

Callerは、呼び出したゴルーチンスタック上で実行している関数のファイルと行番号情報をレポートします。引数skipは、引き上げるスタックフレーム数であり、これに0を指定したときはCallerを呼び出したスタックレームになります。戻り値は、プログラムカウンタ、ファイル名、ファイル内で呼び出した箇所の行番号をレポートします。情報を返せなかったときは論理値okにfalseが返ります。

Caller(1)の場合についてのことが書かれてない。

原文も呼んでみる
http://golang.org/pkg/runtime/#Caller

Caller reports file and line number information about function invocations on the calling goroutine’s stack. The argument skip is the number of stack frames to ascend, with 0 identifying the caller of Caller. (For historical reasons the meaning of skip differs between Caller and Callers.) The return values report the program counter, file name, and line number within the file of the corresponding call. The boolean ok is false if it was not possible to recover the information.

う〜ん、おんなじか(´~`;)

海外の記事
http://blog.el-chavez.me/2013/05/17/golang-current-file-path/

Next you can use the Caller method and capture the filename. We need to give this function a 1 to tell it to skip up a caller.

訳す

Callerメソッドを使ってファイル名をキャプチャできる。このファンクションに1を渡すとcallerをスキップできる

振り返る

これに0を指定したときはCallerを呼び出したスタックレームになります。

もしかして0指定してないと実際に呼び出したところの情報は取れないのか!!
∑(゚Д゚)ガーン

(実際にやってみたは後でやってみる)

代替策を考える

考えたくないので、stackoverflowとかから引っ張る
http://stackoverflow.com/questions/18537257/golang-how-to-get-the-directory-of-the-currently-running-file

import (
    "fmt"
    "log"
    "os"
    "path/filepath"
)

func main() {
    dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
    if err != nil {
            log.Fatal(err)
    }
    fmt.Println(dir)
}
import (
    "github.com/kardianos/osext"
    "fmt"
    "log"
)

func main() {
    folderPath, err := osext.ExecutableFolder()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(folderPath)
}
import (
    "fmt"
    "os"
)

func main() {
    pwd, err := os.Getwd()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    fmt.Println(pwd)
}

追記

Googleグループで似た話してました。
https://groups.google.com/forum/#!topic/golang-nuts/XiKfqDO3rKQ


『 Go 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。