Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 16240] ファイルの概要

このコミットは、Go言語の標準ライブラリ encoding/json パッケージにおけるJSONエンコーディングの挙動に関するドキュメントの更新と、InvalidUTF8Error の説明追加を目的としています。具体的には、無効なUTF-8シーケンスを含む文字列をJSONにマーシャリング(エンコード)する際の挙動が変更され、エラーを返すようになったことが明記されています。

コミット

commit 5c20a4f2608f80ca6a81b76b2e8b5df15128b3f3
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Tue Apr 30 11:21:48 2013 +0800

    encoding/json: document that marshaling invalid utf-8 sequence will return error
    Also added docs for InvalidUTF8Error.
    Fixes #5360.
    
    R=golang-dev, adg, r
    CC=golang-dev
    https://golang.org/cl/8926046

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/5c20a4f2608f80ca6a81b76b2e8b5df15128b3f3

元コミット内容

このコミットの元の内容は以下の通りです。

  • encoding/json: 無効なUTF-8シーケンスをマーシャリングするとエラーを返すことをドキュメント化。
  • InvalidUTF8Error のドキュメントも追加。
  • Issue #5360 を修正。

変更の背景

この変更の背景には、Go言語の encoding/json パッケージが、無効なUTF-8シーケンスを含む文字列をJSONにエンコードする際の挙動に関する明確な仕様がなかった、あるいはその挙動が期待と異なっていたという問題があります。

以前の挙動では、無効なUTF-8シーケンスはUnicodeの置換文字U+FFFD()に置き換えられていました。これは、データが破損している場合でもJSONの生成を続行できるという利点がある一方で、元のデータが無効なUTF-8を含んでいたことをプログラマが認識できないという問題を引き起こしていました。特に、セキュリティ上の理由やデータ整合性の観点から、無効なデータは明確にエラーとして扱うべきであるという考え方が強まっていました。

Issue #5360 は、この問題提起を具体化したものであり、無効なUTF-8シーケンスが検出された場合にエラーを返すようにすべきだという議論が行われた結果、このコミットによってその挙動がドキュメント化され、実装もそれに合わせて変更されたと考えられます。これにより、開発者はJSONエンコーディング時に無効なUTF-8データが存在することを確実に検知し、適切に処理できるようになります。

前提知識の解説

UTF-8

UTF-8(Unicode Transformation Format - 8-bit)は、Unicode文字を可変長バイトでエンコードする文字エンコーディング方式です。ASCII文字は1バイトで表現され、それ以外の文字は2バイトから4バイトで表現されます。UTF-8は、インターネット上で最も広く使用されている文字エンコーディングであり、多言語対応において非常に重要です。

UTF-8の重要な特性の一つは、その「自己同期性」です。これは、バイトストリームの任意の場所からでも、次の文字の開始位置を特定できることを意味します。また、無効なバイトシーケンスは、UTF-8の仕様に準拠していないバイトの並びを指します。例えば、特定のバイトが期待される範囲外であったり、マルチバイト文字の途中でシーケンスが途切れていたりする場合などです。

JSON (JavaScript Object Notation)

JSONは、軽量なデータ交換フォーマットです。人間にとっても読み書きが容易で、機械にとっても解析と生成が容易です。JavaScriptのオブジェクトリテラルをベースにしていますが、言語に依存しないデータフォーマットとして広く利用されています。

JSONの仕様では、文字列はUnicode文字のシーケンスとして定義されており、通常はUTF-8でエンコードされます。JSON文字列内で特定の文字(例: "\、制御文字)はエスケープシーケンス(例: \"\\\n)を使用して表現されます。また、Unicode文字は \uXXXX の形式でエスケープすることも可能です。

Go言語の encoding/json パッケージ

Go言語の標準ライブラリ encoding/json パッケージは、Goのデータ構造とJSONデータの間でマーシャリング(エンコード)およびアンマーシャリング(デコード)を行う機能を提供します。

  • json.Marshal: Goの値をJSON形式のバイトスライスにエンコードします。
  • json.Unmarshal: JSON形式のバイトスライスをGoの値にデコードします。

このパッケージは、Goの構造体のフィールドタグ(例: json:"field_name")を利用して、Goのフィールド名とJSONのキー名をマッピングする機能も持っています。

Unicode置換文字 (U+FFFD)

Unicode置換文字(REPLACEMENT CHARACTER)は、U+FFFDで表される特殊なUnicode文字です。これは、文字エンコーディングの変換中に、入力されたバイトシーケンスが有効な文字として解釈できない場合に、その無効なシーケンスの代わりに挿入される文字です。これにより、処理を中断することなく、無効なデータが存在することを視覚的に示すことができます。

技術的詳細

このコミットの技術的な変更点は、主に encoding/json パッケージのドキュメント、特に json.Marshal 関数の挙動に関する説明の修正と、InvalidUTF8Error 型のドキュメント追加にあります。

以前のドキュメントでは、文字列値がJSON文字列としてエンコードされる際に、無効なUTF-8シーケンスがUnicode置換文字U+FFFDに置き換えられると記述されていました。しかし、このコミットにより、その挙動が変更され、無効なUTF-8シーケンスが検出された場合には InvalidUTF8Error が返されるようになりました。これは、エラーハンドリングの観点から非常に重要な変更です。

InvalidUTF8Error は、encoding/json パッケージ内で定義されているエラー型で、無効なUTF-8シーケンスを含む文字列全体を保持します。これにより、開発者はどの文字列が無効なUTF-8を含んでいたのかを特定し、適切なエラー処理を行うことができます。

この変更は、JSONエンコーディングの堅牢性を高め、無効なデータが透過的に処理されるのではなく、明示的にエラーとして扱われるようにすることで、アプリケーションの信頼性を向上させることを目的としています。

コアとなるコードの変更箇所

このコミットによるコードの変更は、src/pkg/encoding/json/encode.go ファイルのドキュメントコメントに集中しています。

--- a/src/pkg/encoding/json/encode.go
+++ b/src/pkg/encoding/json/encode.go
@@ -39,8 +39,8 @@ import (
 //
 // Floating point, integer, and Number values encode as JSON numbers.
 //
-// String values encode as JSON strings, with each invalid UTF-8 sequence
-// replaced by the encoding of the Unicode replacement character U+FFFD.
+// String values encode as JSON strings. InvalidUTF8Error will be returned
+// if an invalid UTF-8 sequence is encountered.
 // The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e"
 // to keep some browsers from misinterpreting JSON output as HTML.
 //
@@ -200,8 +200,10 @@ func (e *UnsupportedValueError) Error() string {
 	return "json: unsupported value: " + e.Str
 }
 
+// An InvalidUTF8Error is returned by Marshal when attempting
+// to encode a string value with invalid UTF-8 sequences.
 type InvalidUTF8Error struct {
-\tS string
+\tS string // the whole string value that caused the error
 }
 
 func (e *InvalidUTF8Error) Error() string {

コアとなるコードの解説

変更されたコードは、以下の2つの主要な部分に分けられます。

  1. json.Marshal のドキュメントコメントの更新: encode.go ファイルの冒頭にある Marshal 関数の説明部分が変更されています。

    • 変更前: "String values encode as JSON strings, with each invalid UTF-8 sequence replaced by the encoding of the Unicode replacement character U+FFFD." (文字列値はJSON文字列としてエンコードされ、各無効なUTF-8シーケンスはUnicode置換文字U+FFFDのエンコーディングに置き換えられます。)
    • 変更後: "String values encode as JSON strings. InvalidUTF8Error will be returned if an invalid UTF-8 sequence is encountered." (文字列値はJSON文字列としてエンコードされます。無効なUTF-8シーケンスが検出された場合、InvalidUTF8Errorが返されます。)

    この変更は、json.Marshal の実際の挙動が、無効なUTF-8シーケンスに対して置換文字を挿入するのではなく、エラーを返すように変更されたことを明確に示しています。これは、APIの利用者にとって非常に重要な情報であり、エラーハンドリングのロジックを適切に記述するために不可欠です。

  2. InvalidUTF8Error 型のドキュメントコメントの追加: InvalidUTF8Error 構造体の定義の上に、新しいドキュメントコメントが追加されています。

    • 追加されたコメント: "// An InvalidUTF8Error is returned by Marshal when attempting\n// to encode a string value with invalid UTF-8 sequences." (InvalidUTF8Errorは、無効なUTF-8シーケンスを含む文字列値をエンコードしようとしたときにMarshalによって返されます。)
    • 構造体のフィールド S のコメントも追加: "// the whole string value that caused the error" (エラーの原因となった文字列値全体)

    このコメントは、InvalidUTF8Error がどのような状況で返されるのか、そしてそのエラー型がどのような情報(エラーの原因となった文字列全体)を含んでいるのかを説明しています。これにより、開発者はこのエラーを捕捉し、エラーメッセージやログに含めるべき情報を理解することができます。

これらの変更は、コードの機能そのものを大きく変更するものではなく、むしろその機能のドキュメントを正確に反映させるためのものです。しかし、このドキュメントの変更は、encoding/json パッケージのユーザーが、無効なUTF-8データに対する期待される挙動を正しく理解し、それに基づいて堅牢なアプリケーションを構築するために不可欠です。

関連リンク

参考にした情報源リンク