Skip to content

Commit 3d38cd3

Browse files
bootjpCopilot
andauthored
Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent f1b0350 commit 3d38cd3

1 file changed

Lines changed: 91 additions & 3 deletions

File tree

proxy/sentry.go

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package proxy
33
import (
44
"fmt"
55
"log/slog"
6+
"reflect"
7+
"strings"
68
"sync"
79
"time"
810

@@ -143,20 +145,106 @@ func cmdNameFromArgs(args [][]byte) string {
143145
// truncateValue formats a value for logging/Sentry, truncating to avoid data leakage and oversized events.
144146
// Handles common types by slicing before formatting to avoid allocating the full string representation.
145147
func truncateValue(v any) string {
146-
var s string
147148
switch tv := v.(type) {
148149
case string:
149-
s = tv
150+
return truncateString(tv)
150151
case []byte:
152+
// Avoid converting an arbitrarily large byte slice into a full string.
151153
if len(tv) > maxSentryValueLen {
152154
return string(tv[:maxSentryValueLen]) + "...(truncated)"
153155
}
154156
return string(tv)
157+
case fmt.Stringer:
158+
// Respect custom String implementations but still apply length limits.
159+
return truncateString(tv.String())
155160
default:
156-
s = fmt.Sprintf("%v", v)
161+
rv := reflect.ValueOf(v)
162+
switch rv.Kind() {
163+
case reflect.Slice, reflect.Array:
164+
return formatSliceValue(rv, maxSentryValueLen)
165+
case reflect.Map:
166+
return formatMapValue(rv, maxSentryValueLen)
167+
default:
168+
// For non-container types, fall back to fmt and then truncate.
169+
return truncateString(fmt.Sprintf("%v", v))
170+
}
157171
}
172+
}
173+
174+
// truncateString enforces maxSentryValueLen on an already-built string.
175+
func truncateString(s string) string {
158176
if len(s) > maxSentryValueLen {
159177
return s[:maxSentryValueLen] + "...(truncated)"
160178
}
161179
return s
162180
}
181+
182+
// formatSliceValue formats a slice/array value without allocating an unbounded string.
183+
// It stops once approximately maxLen bytes have been written and appends a truncation marker.
184+
func formatSliceValue(rv reflect.Value, maxLen int) string {
185+
var b strings.Builder
186+
b.WriteByte('[')
187+
for i := 0; i < rv.Len(); i++ {
188+
if b.Len() >= maxLen {
189+
b.WriteString("...(truncated)]")
190+
return b.String()
191+
}
192+
if i > 0 {
193+
b.WriteString(", ")
194+
}
195+
elemStr := truncateValue(rv.Index(i).Interface())
196+
if b.Len()+len(elemStr) > maxLen {
197+
// Write as much as fits, then mark as truncated.
198+
remaining := maxLen - b.Len()
199+
if remaining > 0 {
200+
if remaining < len(elemStr) {
201+
b.WriteString(elemStr[:remaining])
202+
} else {
203+
b.WriteString(elemStr)
204+
}
205+
}
206+
b.WriteString("...(truncated)]")
207+
return b.String()
208+
}
209+
b.WriteString(elemStr)
210+
}
211+
b.WriteByte(']')
212+
return truncateString(b.String())
213+
}
214+
215+
// formatMapValue formats a map value without allocating an unbounded string.
216+
// It stops once approximately maxLen bytes have been written and appends a truncation marker.
217+
func formatMapValue(rv reflect.Value, maxLen int) string {
218+
var b strings.Builder
219+
b.WriteByte('{')
220+
iter := rv.MapRange()
221+
first := true
222+
for iter.Next() {
223+
if b.Len() >= maxLen {
224+
b.WriteString("...(truncated)}")
225+
return b.String()
226+
}
227+
if !first {
228+
b.WriteString(", ")
229+
}
230+
first = false
231+
keyStr := truncateValue(iter.Key().Interface())
232+
valStr := truncateValue(iter.Value().Interface())
233+
entry := fmt.Sprintf("%s: %s", keyStr, valStr)
234+
if b.Len()+len(entry) > maxLen {
235+
remaining := maxLen - b.Len()
236+
if remaining > 0 {
237+
if remaining < len(entry) {
238+
b.WriteString(entry[:remaining])
239+
} else {
240+
b.WriteString(entry)
241+
}
242+
}
243+
b.WriteString("...(truncated)}")
244+
return b.String()
245+
}
246+
b.WriteString(entry)
247+
}
248+
b.WriteByte('}')
249+
return truncateString(b.String())
250+
}

0 commit comments

Comments
 (0)