internal: improve use of detrand in descfmt and errors
Use a non-breaking space instead of two spaces to vary the output.
This keeps the mutated version aesthetically similar to the normal one.
Change-Id: Ib4ade2795004fe5b30e454e7e533e5a0e3a9ffa2
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/194157
Reviewed-by: Herbie Ong <herbie@google.com>
diff --git a/internal/descfmt/stringer.go b/internal/descfmt/stringer.go
index a6d33c0..4cb8d6d 100644
--- a/internal/descfmt/stringer.go
+++ b/internal/descfmt/stringer.go
@@ -43,7 +43,7 @@
case pref.Descriptor:
name = reflect.ValueOf(vs).MethodByName("Get").Type().Out(0).Name() + "s"
}
- start, end = name+randomSpace()+"{", "}"
+ start, end = name+"{", "}"
}
var ss []string
@@ -123,7 +123,7 @@
start, end := "{", "}"
if isRoot {
- start = rt.Name() + randomSpace() + "{"
+ start = rt.Name() + "{"
}
_, isFile := t.(pref.FileDescriptor)
@@ -269,7 +269,7 @@
// In single line mode, simply join all records with commas.
if !rs.allowMulti {
for _, r := range rs.recs {
- ss = append(ss, r[0]+": "+r[1])
+ ss = append(ss, r[0]+formatColon(0)+r[1])
}
return joinStrings(ss, false)
}
@@ -278,15 +278,14 @@
var maxLen int
flush := func(i int) {
for _, r := range rs.recs[len(ss):i] {
- padding := strings.Repeat(" ", maxLen-len(r[0]))
- ss = append(ss, r[0]+": "+padding+r[1])
+ ss = append(ss, r[0]+formatColon(maxLen-len(r[0]))+r[1])
}
maxLen = 0
}
for i, r := range rs.recs {
if isMulti := strings.Contains(r[1], "\n"); isMulti {
flush(i)
- ss = append(ss, r[0]+": "+strings.Join(strings.Split(r[1], "\n"), "\n\t"))
+ ss = append(ss, r[0]+formatColon(0)+strings.Join(strings.Split(r[1], "\n"), "\n\t"))
} else if maxLen < len(r[0]) {
maxLen = len(r[0])
}
@@ -295,6 +294,17 @@
return joinStrings(ss, true)
}
+func formatColon(padding int) string {
+ // Deliberately introduce instability into the debug output to
+ // discourage users from performing string comparisons.
+ // This provides us flexibility to change the output in the future.
+ if detrand.Bool() {
+ return ":" + strings.Repeat(" ", 1+padding) // use non-breaking spaces (U+00a0)
+ } else {
+ return ":" + strings.Repeat(" ", 1+padding) // use regular spaces (U+0020)
+ }
+}
+
func joinStrings(ss []string, isMulti bool) string {
if len(ss) == 0 {
return ""
@@ -304,12 +314,3 @@
}
return strings.Join(ss, ", ")
}
-
-// randomSpace randomly returns a string that is either empty or a single space.
-// This is done deliberately to ensure that the output is slightly non-stable.
-//
-// These makes it harder for people to depend on the debug string as stable
-// and provides us the flexibility to make changes.
-func randomSpace() string {
- return " "[:detrand.Intn(2)]
-}
diff --git a/internal/detrand/rand.go b/internal/detrand/rand.go
index f5d9eeb..a904dd1 100644
--- a/internal/detrand/rand.go
+++ b/internal/detrand/rand.go
@@ -18,24 +18,16 @@
// Disable disables detrand such that all functions returns the zero value.
// This function is not concurrent-safe and must be called during program init.
func Disable() {
- binHash = 0
+ randSeed = 0
}
// Bool returns a deterministically random boolean.
func Bool() bool {
- return binHash%2 == 1
+ return randSeed%2 == 1
}
-// Intn returns a deterministically random integer within [0,n).
-func Intn(n int) int {
- if n <= 0 {
- panic("invalid argument to Intn")
- }
- return int(binHash % uint64(n))
-}
-
-// binHash is a best-effort at an approximate hash of the Go binary.
-var binHash = binaryHash()
+// randSeed is a best-effort at an approximate hash of the Go binary.
+var randSeed = binaryHash()
func binaryHash() uint64 {
// Open the Go binary.
diff --git a/internal/errors/errors.go b/internal/errors/errors.go
index db1005d..bc495b4 100644
--- a/internal/errors/errors.go
+++ b/internal/errors/errors.go
@@ -25,10 +25,13 @@
type prefixError struct{ s string }
var prefix = func() string {
+ // Deliberately introduce instability into the error message string to
+ // discourage users from performing error string comparisons.
if detrand.Bool() {
- return "proto: "
+ return "proto: " // use non-breaking spaces (U+00a0)
+ } else {
+ return "proto: " // use regular spaces (U+0020)
}
- return "proto: "
}()
func (e *prefixError) Error() string {