{"record":{"id":"93dfafaaf34bd731","repo":"golang/go","slug":"bytes-join-output-length-overflow","errorCode":null,"errorMessage":"bytes: Join output length overflow","messagePattern":"bytes: Join output length overflow","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/bytes/bytes.go","lineNumber":564,"sourceCode":"\n\treturn a\n}\n\n// Join concatenates the elements of s to create a new byte slice. The separator\n// sep is placed between elements in the resulting slice.\nfunc Join(s [][]byte, sep []byte) []byte {\n\tif len(s) == 0 {\n\t\treturn []byte{}\n\t}\n\tif len(s) == 1 {\n\t\t// Just return a copy.\n\t\treturn append([]byte(nil), s[0]...)\n\t}\n\n\tvar n int\n\tif len(sep) > 0 {\n\t\tif len(sep) >= maxInt/(len(s)-1) {\n\t\t\tpanic(\"bytes: Join output length overflow\")\n\t\t}\n\t\tn += len(sep) * (len(s) - 1)\n\t}\n\tfor _, v := range s {\n\t\tif len(v) > maxInt-n {\n\t\t\tpanic(\"bytes: Join output length overflow\")\n\t\t}\n\t\tn += len(v)\n\t}\n\n\tb := bytealg.MakeNoZero(n)[:n:n]\n\tbp := copy(b, s[0])\n\tfor _, v := range s[1:] {\n\t\tbp += copy(b[bp:], sep)\n\t\tbp += copy(b[bp:], v)\n\t}\n\treturn b\n}","sourceCodeStart":546,"sourceCodeEnd":582,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/bytes/bytes.go#L546-L582","documentation":"bytes.Join concatenates the elements of s with sep between them. Before allocating it computes the total length; it panics with \"bytes: Join output length overflow\" at the separator step when len(sep) >= maxInt/(len(s)-1), i.e. when the total separator contribution alone (len(sep) * (len(s)-1)) would overflow. This guards the multiplication, not the final allocation.","triggerScenarios":"Joining a very large number of slices (huge len(s)) with a non-empty separator such that sep*(len(s)-1) overflows; building CSV/TSV/delimited output where element count is attacker-controlled; joining millions of small fragments with a multi-byte separator.","commonSituations":"Aggregating log lines or tokens into one buffer with a delimiter; serializing a large slice of fields with a separator; producing output where len(s) came from unbounded streaming collection.","solutions":["Reduce the element count: batch and write incrementally to an io.Writer instead of Join into one []byte.","Validate that the expected total (len(s)-1)*len(sep) fits before calling Join.","If a separator is only needed for output formatting, prefer a streaming writer (bufio.Writer) that does not pre-size a single contiguous slice."],"exampleFix":"// before\nout := bytes.Join(chunks, []byte(\"\\n\")) // len(chunks) huge -> overflow\n\n// after\nvar w io.Writer = buf\nfor i, c := range chunks {\n    if i > 0 {\n        w.Write([]byte(\"\\n\"))\n    }\n    w.Write(c)\n}","handlingStrategy":"validation","validationCode":"// Pre-check separator contribution before Join.\nfunc safeJoinSep(s [][]byte, sep []byte) ([]byte, error) {\n    if len(sep) > 0 && len(s) > 1 {\n        if int64(len(sep)) >= int64(maxInt)/int64(len(s)-1) {\n            return nil, fmt.Errorf(\"join separator overflow\")\n        }\n    }\n    return bytes.Join(s, sep), nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not Join unbounded element collections; batch or stream them.","When len(s) is attacker-controlled, cap it before Join.","Prefer a streaming writer for delimited output of large datasets."],"tags":["bytes","join","overflow","panic","go","delimiter"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}