Golang でのポインター障害の原因と解決策について話し合う

PHPz
リリース: 2023-04-27 09:45:18
オリジナル
947 人が閲覧しました

Golang はセキュリティを重視した言語であり、その大きな特徴の 1 つはポインタ操作を制限することでメモリ セキュリティの多くの脆弱性を防ぐことです。ただし、Golang でも、無効なポインタの問題は依然として存在します。この記事では、Golang でのポインター障害の原因と解決策について説明します。

1. ポインタが失敗する理由

Golang では、ポインタが指すメモリ空間がガベージ コレクタによって再利用され、ポインタが無効になる場合があります。この状況は通常、次の状況で発生します。

  1. ポインタが呼び出された関数に渡された後、関数の終了後にポインタが指すメモリ空間が解放されます。

たとえば、次のコード:

func foo() *int {
   x := 10
   return &x
}

func main() {
   p := foo()
   fmt.Println(*p)
}
ログイン後にコピー

関数 foo では、変数 x は関数の終了後に解放されるローカル変数です。関数が戻ると、x のアドレスが返されます。 main 関数では、p は foo 関数によって返されるアドレスを指します。 #p を印刷すると 10 が出力されます。しかし、foo 関数の終了後に p が指すメモリ空間にアクセスし続けようとすると、ポインタが無効であることがわかります。

func main() {
   p := foo()
   fmt.Println(*p)
   fmt.Println(*p) // 这里会触发panic
}
ログイン後にコピー
  1. ポインタが指すオブジェクトが削除または移動される

要素へのポインタをスライスに格納すると、要素を追加または削除するときに、要素へのポインタが無効です。

たとえば、次のコード:

func main() {
   a := []int{1, 2, 3, 4, 5, 6}
   p := &a[2]
   a = append(a, 7)
   fmt.Println(*p) // 这里会发现指针失效了
}
ログイン後にコピー

ここでは、スライス a を定義し、&p を使用して a[2] のアドレスを取得し、要素 7 を追加します。次の #p 式では、ポインター p を使用して a[2] にアクセスしようとしますが、要素が追加されるため、a[2] は前の要素ではなくなり、p が指すのは無効なメモリアドレスです。

2. ポインタ障害の解決策

  1. ローカル変数のアドレスを返さないようにする

前述したように、関数内でローカル変数を定義し、アドレスを返すと、ポインタが無効になります。解決策は、関数内で変数を定義するときに new キーワードを使用することです。これにより、メモリが割り当てられ、そのメモリへのポインタが返されます。

たとえば、次のコード:

func foo() *int {
   p := new(int)
   *p = 10
   return p
}

func main() {
   p := foo()
   fmt.Println(*p)
}
ログイン後にコピー

ここでは、new() 関数を使用してメモリのブロックを割り当て、それが指す値を 10 に設定します。関数が終了すると、このメモリへのポインタが返されます。これにより、関数が終了してもメモリが解放されず、ポインタが無効になることはありません。

  1. sync.Mutex の使用

マルチスレッド環境では、sync.Mutex を使用してポインターを保護できます。 Mutex は、一度に 1 つの goroutine だけが保護されたポインターにアクセスできるようにし、アクセスが完了した後にロックを解放します。

たとえば、次のコード:

type SafeCounter struct {
   mu sync.Mutex
   count int
}

func (c *SafeCounter) Increment() {
   c.mu.Lock()
   defer c.mu.Unlock()
   c.count++
}

func (c *SafeCounter) Value() int {
   c.mu.Lock()
   defer c.mu.Unlock()
   return c.count
}
ログイン後にコピー

ここでは、カウント変数とロック mu を含む SafeCounter 型を定義します。 Increment() 関数は mu をロックし、カウントを 1 ずつ増やします。 Value() 関数も mu をロックし、count の値を返します。これにより、複数のゴルーチンが count 変数にアクセスするときにポインターが期限切れにならないことが保証されます。

結論

Golang はポインター操作に制限を課していますが、ポインターの無効化の問題は依然として存在します。 Golang では、通常、ポインタが指すメモリ空間がリサイクルまたは移動されるため、ポインタの無効化が発生します。解決策には、ローカル変数のアドレスを返さないようにすることや、ロックを使用してマルチスレッド環境でポインタを保護することが含まれます。ポインターを正しく使用し、適切なソリューションを採用できれば、ポインターの無効化の問題を回避できます。

以上がGolang でのポインター障害の原因と解決策について話し合うの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!