Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4b54525b authored by Colin Cross's avatar Colin Cross
Browse files

Fix nondeterminisim in xmlnotice

SafePathPrefixes contains "prebuilts/" which is a prefix of another
entry "prebuilts/module_sdk" which can both match the same path.
SafePathPrefixes is a map, so the iteration order is nondeterminisitic.
Move both SafePathPrefixes and SafePrebuiltPrefixes into lists that
will always have a deterministic iteration order.

Bug: 230357391
Test: build NOTICE.xml.gz multiple times
Change-Id: Ibfcd6715b70f26164e0ef4d59f73b240f47f8db7
parent 7017ac77
Loading
Loading
Loading
Loading
+8 −10
Original line number Diff line number Diff line
@@ -360,19 +360,17 @@ func (ni *NoticeIndex) getLibName(noticeFor *TargetNode, h hash) string {
						continue
					}
				}
				for _, r := range OrderedSafePrebuiltPrefixes {
					prefix := SafePrebuiltPrefixes[r]
					match := r.FindString(licenseText)
				for _, safePrebuiltPrefix := range safePrebuiltPrefixes {
					match := safePrebuiltPrefix.re.FindString(licenseText)
					if len(match) == 0 {
						continue
					}
					strip := SafePathPrefixes[prefix]
					if strip {
					if safePrebuiltPrefix.strip {
						// strip entire prefix
						match = licenseText[len(match):]
					} else {
						// strip from prebuilts/ until safe prefix
						match = licenseText[len(match)-len(prefix):]
						match = licenseText[len(match)-len(safePrebuiltPrefix.prefix):]
					}
					// remove LICENSE or NOTICE or other filename
					li := strings.LastIndex(match, "/")
@@ -392,10 +390,10 @@ func (ni *NoticeIndex) getLibName(noticeFor *TargetNode, h hash) string {
				break
			}
		}
		for prefix, strip := range SafePathPrefixes {
			if strings.HasPrefix(p, prefix) {
				if strip {
					return p[len(prefix):]
		for _, safePathPrefix := range safePathPrefixes {
			if strings.HasPrefix(p, safePathPrefix.prefix) {
				if safePathPrefix.strip {
					return p[len(safePathPrefix.prefix):]
				} else {
					return p
				}
+35 −48
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@ package compliance

import (
	"regexp"
	"sort"
	"strings"
)

@@ -30,35 +29,31 @@ var (
		"toolchain": "toolchain",
	}

	// SafePathPrefixes maps the path prefixes presumed not to contain any
	// safePathPrefixes maps the path prefixes presumed not to contain any
	// proprietary or confidential pathnames to whether to strip the prefix
	// from the path when used as the library name for notices.
	SafePathPrefixes = map[string]bool{
		"external/":             true,
		"art/":                  false,
		"build/":                false,
		"cts/":                  false,
		"dalvik/":               false,
		"developers/":           false,
		"development/":          false,
		"frameworks/":           false,
		"packages/":             true,
		"prebuilts/module_sdk/": true,
		"prebuilts/":            false,
		"sdk/":                  false,
		"system/":               false,
		"test/":                 false,
		"toolchain/":            false,
		"tools/":                false,
	safePathPrefixes = []safePathPrefixesType{
		{"external/", true},
		{"art/", false},
		{"build/", false},
		{"cts/", false},
		{"dalvik/", false},
		{"developers/", false},
		{"development/", false},
		{"frameworks/", false},
		{"packages/", true},
		{"prebuilts/module_sdk/", true},
		{"prebuilts/", false},
		{"sdk/", false},
		{"system/", false},
		{"test/", false},
		{"toolchain/", false},
		{"tools/", false},
	}

	// SafePrebuiltPrefixes maps the regular expression to match a prebuilt
	// safePrebuiltPrefixes maps the regular expression to match a prebuilt
	// containing the path of a safe prefix to the safe prefix.
	SafePrebuiltPrefixes = make(map[*regexp.Regexp]string)

	// OrderedSafePrebuiltPrefixes lists the SafePrebuiltPrefixes ordered by
	// increasing length.
	OrderedSafePrebuiltPrefixes = make([]*regexp.Regexp, 0, 0)
	safePrebuiltPrefixes []safePrebuiltPrefixesType

	// ImpliesUnencumbered lists the condition names representing an author attempt to disclaim copyright.
	ImpliesUnencumbered = LicenseConditionSet(UnencumberedCondition)
@@ -89,6 +84,16 @@ var (
	ImpliesShared = LicenseConditionSet(ReciprocalCondition | RestrictedCondition | WeaklyRestrictedCondition)
)

type safePathPrefixesType struct {
	prefix string
	strip  bool
}

type safePrebuiltPrefixesType struct {
	safePathPrefixesType
	re *regexp.Regexp
}

var (
	anyLgpl      = regexp.MustCompile(`^SPDX-license-identifier-LGPL.*`)
	versionedGpl = regexp.MustCompile(`^SPDX-license-identifier-GPL-\p{N}.*`)
@@ -96,33 +101,15 @@ var (
	ccBySa       = regexp.MustCompile(`^SPDX-license-identifier-CC-BY.*-SA.*`)
)

// byIncreasingLength implements `sort.Interface` to order regular expressions by increasing length.
type byIncreasingLength []*regexp.Regexp

func (l byIncreasingLength) Len() int      { return len(l) }
func (l byIncreasingLength) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
func (l byIncreasingLength) Less(i, j int) bool {
	ri := l[i].String()
	rj := l[j].String()
	if len(ri) == len(rj) {
		return ri < rj
	}
	return len(ri) < len(rj)
}

func init() {
	for prefix := range SafePathPrefixes {
		if strings.HasPrefix(prefix, "prebuilts/") {
	for _, safePathPrefix := range safePathPrefixes {
		if strings.HasPrefix(safePathPrefix.prefix, "prebuilts/") {
			continue
		}
		r := regexp.MustCompile("^prebuilts/(?:runtime/mainline/)?" + prefix)
		SafePrebuiltPrefixes[r] = prefix
	}
	OrderedSafePrebuiltPrefixes = make([]*regexp.Regexp, 0, len(SafePrebuiltPrefixes))
	for r := range SafePrebuiltPrefixes {
		OrderedSafePrebuiltPrefixes = append(OrderedSafePrebuiltPrefixes, r)
		r := regexp.MustCompile("^prebuilts/(?:runtime/mainline/)?" + safePathPrefix.prefix)
		safePrebuiltPrefixes = append(safePrebuiltPrefixes,
			safePrebuiltPrefixesType{safePathPrefix, r})
	}
	sort.Sort(byIncreasingLength(OrderedSafePrebuiltPrefixes))
}

// LicenseConditionSetFromNames returns a set containing the recognized `names` and