Skip to content

Commit

Permalink
Detect invalid addresses when parsing profile and report as error.
Browse files Browse the repository at this point in the history
  • Loading branch information
aalexand committed Feb 17, 2017
1 parent daa80a9 commit 236aa1b
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 26 deletions.
10 changes: 7 additions & 3 deletions profile/legacy_java_profile.go
Expand Up @@ -178,10 +178,15 @@ func parseJavaSamples(pType string, b []byte, p *Profile) ([]byte, map[uint64]*L

// Java profiles have data/fields inverted compared to other
// profile types.
value1, value2, addrs := sample[2], sample[1], sample[3]
var err error
value1, value2, value3 := sample[2], sample[1], sample[3]
addrs, err := parseHexAddresses(value3)
if err != nil {
return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err)
}

var sloc []*Location
for _, addr := range parseHexAddresses(addrs) {
for _, addr := range addrs {
loc := locs[addr]
if locs[addr] == nil {
loc = &Location{
Expand All @@ -197,7 +202,6 @@ func parseJavaSamples(pType string, b []byte, p *Profile) ([]byte, map[uint64]*L
Location: sloc,
}

var err error
if s.Value[0], err = strconv.ParseInt(value1, 0, 64); err != nil {
return nil, nil, fmt.Errorf("parsing sample %s: %v", line, err)
}
Expand Down
50 changes: 27 additions & 23 deletions profile/legacy_profile.go
Expand Up @@ -622,32 +622,29 @@ func parseHeapSample(line string, rate int64, sampling string, includeAlloc bool
return nil, 0, nil, err
}

addrs = parseHexAddresses(sampleData[5])
addrs, err = parseHexAddresses(sampleData[5])
if err != nil {
return nil, 0, nil, fmt.Errorf("malformed sample: %s: %v", line, err)
}

return value, blocksize, addrs, nil
}

// extractHexAddresses extracts hex numbers from a string and returns
// them, together with their numeric value, in a slice.
func extractHexAddresses(s string) ([]string, []uint64) {
// parseHexAddresses extracts hex numbers from a string, attempts to convert
// each to an unsigned 64-bit number and returns the resulting numbers as a
// slice, or an error if the string contains hex numbers which are too large to
// handle (which means a malformed profile).
func parseHexAddresses(s string) ([]uint64, error) {
hexStrings := hexNumberRE.FindAllString(s, -1)
var ids []uint64
var addrs []uint64
for _, s := range hexStrings {
if id, err := strconv.ParseUint(s, 0, 64); err == nil {
ids = append(ids, id)
if addr, err := strconv.ParseUint(s, 0, 64); err == nil {
addrs = append(addrs, addr)
} else {
// Do not expect any parsing failures due to the regexp matching.
panic("failed to parse hex value:" + s)
return nil, fmt.Errorf("failed to parse as hex 64-bit number: %s", s)
}
}
return hexStrings, ids
}

// parseHexAddresses parses hex numbers from a string and returns them
// in a slice.
func parseHexAddresses(s string) []uint64 {
_, ids := extractHexAddresses(s)
return ids
return addrs, nil
}

// scaleHeapSample adjusts the data from a heapz Sample to
Expand Down Expand Up @@ -803,16 +800,16 @@ func parseContention(b []byte) (*Profile, error) {
func parseContentionSample(line string, period, cpuHz int64) (value []int64, addrs []uint64, err error) {
sampleData := contentionSampleRE.FindStringSubmatch(line)
if sampleData == nil {
return value, addrs, errUnrecognized
return nil, nil, errUnrecognized
}

v1, err := strconv.ParseInt(sampleData[1], 10, 64)
if err != nil {
return value, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err)
}
v2, err := strconv.ParseInt(sampleData[2], 10, 64)
if err != nil {
return value, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err)
}

// Unsample values if period and cpuHz are available.
Expand All @@ -827,7 +824,10 @@ func parseContentionSample(line string, period, cpuHz int64) (value []int64, add
}

value = []int64{v2, v1}
addrs = parseHexAddresses(sampleData[3])
addrs, err = parseHexAddresses(sampleData[3])
if err != nil {
return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err)
}

return value, addrs, nil
}
Expand Down Expand Up @@ -872,7 +872,7 @@ func parseThread(b []byte) (*Profile, error) {
var err error
line, addrs, err = parseThreadSample(s)
if err != nil {
return nil, errUnrecognized
return nil, err
}
if len(addrs) == 0 {
// We got a --same as previous threads--. Bump counters.
Expand Down Expand Up @@ -936,7 +936,11 @@ func parseThreadSample(s *bufio.Scanner) (nextl string, addrs []uint64, err erro
continue
}

addrs = append(addrs, parseHexAddresses(line)...)
curAddrs, err := parseHexAddresses(line)
if err != nil {
return "", nil, fmt.Errorf("malformed sample: %s: %v", line, err)
}
addrs = append(addrs, curAddrs...)
}
if err := s.Err(); err != nil {
return "", nil, err
Expand Down
15 changes: 15 additions & 0 deletions profile/legacy_profile_test.go
Expand Up @@ -265,6 +265,21 @@ func TestParseMappingEntry(t *testing.T) {
}
}

func TestParseThreadProfileWithInvalidAddress(t *testing.T) {
profile := `
--- threadz 1 ---
--- Thread 7eff063d9940 (name: main/25376) stack: ---
PC: 0x40b688 0x4d5f51 0x40be31 0x473add693e639c6f0
--- Memory map: ---
00400000-00fcb000: /home/rsilvera/cppbench/cppbench_server_main.unstripped
`
wantErr := "failed to parse as hex 64-bit number: 0x473add693e639c6f0"
if _, gotErr := parseThread([]byte(profile)); !strings.Contains(gotErr.Error(), wantErr) {
t.Errorf("parseThread(): got error %q, want error containing %q", gotErr, wantErr)
}
}

func TestParseGoCount(t *testing.T) {
for _, test := range []struct {
in string
Expand Down

0 comments on commit 236aa1b

Please sign in to comment.