diff --git a/internal/export/idna/idna9.0.0.go b/internal/export/idna/idna9.0.0.go index 96424a0b..f217b1a4 100644 --- a/internal/export/idna/idna9.0.0.go +++ b/internal/export/idna/idna9.0.0.go @@ -197,7 +197,7 @@ type options struct { bidirule func(s string) bool } -// A Profile defines the configuration of a IDNA mapper. +// A Profile defines the configuration of an IDNA mapper. type Profile struct { options } @@ -426,6 +426,9 @@ func validateRegistration(p *Profile, s string) (string, error) { } for i := 0; i < len(s); { v, sz := trie.lookupString(s[i:]) + if sz == 0 { + return s, runeError(utf8.RuneError) + } // Copy bytes not copied so far. switch p.simplify(info(v).category()) { // TODO: handle the NV8 defined in the Unicode idna data set to allow @@ -448,6 +451,15 @@ func validateAndMap(p *Profile, s string) (string, error) { ) for i := 0; i < len(s); { v, sz := trie.lookupString(s[i:]) + if sz == 0 { + b = append(b, s[k:i]...) + b = append(b, "\ufffd"...) + k = len(s) + if err == nil { + err = runeError(utf8.RuneError) + } + break + } start := i i += sz // Copy bytes not copied so far. @@ -580,6 +592,9 @@ func validateFromPunycode(p *Profile, s string) error { } for i := 0; i < len(s); { v, sz := trie.lookupString(s[i:]) + if sz == 0 { + return runeError(utf8.RuneError) + } if c := p.simplify(info(v).category()); c != valid && c != deviation { return &labelError{s, "V6"} } diff --git a/internal/export/idna/idna9.0.0_test.go b/internal/export/idna/idna9.0.0_test.go index 524727b1..91a1e90d 100644 --- a/internal/export/idna/idna9.0.0_test.go +++ b/internal/export/idna/idna9.0.0_test.go @@ -78,6 +78,7 @@ func TestLabelErrors(t *testing.T) { {resolve, "\u3002b", "b", ""}, {resolve, "..b", "b", ""}, {resolve, "b..", "b..", ""}, + {resolve, "\xed", "", "P1"}, // Raw punycode {punyA, "", "", ""},