Skip to content

Commit

Permalink
Upload system symbols: ensure dumped breakpad filenames are unique
Browse files Browse the repository at this point in the history
At some point, we started hitting limits on symbol file names, so we
began collapsing each path components except the filename down to the
first letter.

This breaks down with the following setup:
Some.framework/Versions/30/libSomething.dylib
Some.framework/Versions/31/libSomething.dylib

Which collapse to the same file name. Since upload_system_symbols
dumps in parallel, this can lead to one of the files overwriting
part of the other, creating a corrupted end product.

This change creates files with O_EXCL. If creating fails due to the
file already existing, we tack on a counter (so f.sym becomes f_1.sym,
for example).

Bug: chromium:40250422
Change-Id: I66ea50b84d68d3c5103eb7e31568b8444ec3be27
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/6064141
Reviewed-by: Mark Mentovai <[email protected]>
  • Loading branch information
speednoisemovement committed Dec 2, 2024
1 parent 1db382f commit 02dd5c3
Showing 1 changed file with 30 additions and 3 deletions.
33 changes: 30 additions & 3 deletions src/tools/mac/upload_system_symbols/upload_system_symbols.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ var (
regexp.MustCompile(`\.a$`),
regexp.MustCompile(`\.dat$`),
}
maxFileCreateTries = 10
)

func main() {
Expand Down Expand Up @@ -226,6 +227,34 @@ func manglePath(path string) string {
return builder.String()
}

// createSymbolFile creates a writable file in `base` with a name derived from
// `original_path`. It ensures that multiple threads can't simultaneously create
// the same file for two `original_paths` that map to the same mangled name.
// Returns the filename, the file, and an error if creating the file failed.
func createSymbolFile(base string, original_path string, arch string) (filename string, f *os.File, err error) {
mangled := manglePath(original_path)
counter := 0
filebase := path.Join(base, mangled)
for {
var symfile string
if counter == 0 {
symfile = fmt.Sprintf("%s_%s.sym", filebase, arch)
} else {
symfile = fmt.Sprintf("%s_%s_%d.sym", filebase, arch, counter)
}
f, err := os.OpenFile(symfile, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
if err == nil {
return symfile, f, nil
}
if os.IsExist(err) && counter < maxFileCreateTries {
counter++
continue
}
return "", nil, err
}

}

type WorkerPool struct {
wg sync.WaitGroup
}
Expand Down Expand Up @@ -359,9 +388,7 @@ func (dq *DumpQueue) worker() {
dumpSyms := path.Join(*breakpadTools, "dump_syms")

for req := range dq.queue {
filebase := path.Join(dq.dumpPath, manglePath(req.path))
symfile := fmt.Sprintf("%s_%s.sym", filebase, req.arch)
f, err := os.Create(symfile)
symfile, f, err := createSymbolFile(dq.dumpPath, req.path, req.arch)
if err != nil {
log.Fatalf("Error creating symbol file: %v", err)
}
Expand Down

0 comments on commit 02dd5c3

Please sign in to comment.