Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

auto generation of findConstraintRegex is not consistent #155

Closed
jchunkins opened this issue Sep 26, 2020 · 2 comments · Fixed by #158
Closed

auto generation of findConstraintRegex is not consistent #155

jchunkins opened this issue Sep 26, 2020 · 2 comments · Fixed by #158
Labels

Comments

@jchunkins
Copy link

While I was digging through the implementation to understand the code better, I found that the generation of findConstraintRegex is dependent on ranging over the map constraintOps. The range operation is happening here

semver/constraints.go

Lines 168 to 170 in 60c7ae8

for k := range constraintOps {
ops = append(ops, regexp.QuoteMeta(k))
}

As a result, when the constraint operators are generated for findConstraintRegex the values between the regex "alternates" (i.e. the constraint operators between "|"), end up with random ordering. This is because range will randomly pick items from the map during iteration. This leads odd (or potentially even invalid) regex syntax because one of the constraint operators is an empty string.

For example I captured a few runs to illustrate this (see below). Note that the first 31 characters of these regex examples change from one run to the next. Also the first two lines have the empty string for an "alternate" at the beginning of the line, but the last one has the empty string alternate in the middle, so it is technically invalid. If you take that last line and put it into https://regex101.com it will report:

An alternator at this position effectively truncates the group, rendering any other tokens beyond this point useless

I don't think the Golang regexp.MustCompile reports this as an error. Its not clear to me if Golang regex impl behaves the way that regex101.com suggests in its error message, but it might be worthwhile to fix the way the regex is generated so that you avoid the possibility all together. Since it is random when this will hit, it could make a potential bug difficult to reproduce.

(|=|>|>=|=<|\^|!=|<|=>|<=|~|~>)\s*(v?([0-9|x|X|\*]+)(\.[0-9|x|X|\*]+)?(\.[0-9|x|X|\*]+)?(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?) <--- NOTE: regex101.com does not complain about this
(|=|>=|~>|<=|=<|~|\^|!=|>|<|=>)\s*(v?([0-9|x|X|\*]+)(\.[0-9|x|X|\*]+)?(\.[0-9|x|X|\*]+)?(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?) <--- NOTE: regex101.com does not complain about this
(=|!=|>|<|>=|=<|~||\^|~>|<=|=>)\s*(v?([0-9|x|X|\*]+)(\.[0-9|x|X|\*]+)?(\.[0-9|x|X|\*]+)?(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?) <--- NOTE: This one is technically invalid

To me, it seems like the loop range should be changed to something that will be consistent. Perhaps sort the keys and then access the map with the sorted key during iteration so the empty string ends up at the beginning or end of the iteration. Or better yet, just make a hard coded set of constraint operators so you know exactly what order things will end up in when you do a strings.Join.

@mattfarina mattfarina added the bug label Nov 16, 2020
@mattfarina
Copy link
Member

Thanks for bringing this up. The lack of a deterministic order for range is a good catch.

mattfarina added a commit to mattfarina/semver that referenced this issue Nov 18, 2020
Range was used to iterate over the operations as part of generating
the regex. Range iterations are random. There were cases where the
empty key caused the regex to be generated as invalid.

This change removes the range so that the order is always the same.

Closes Masterminds#155
mattfarina added a commit to mattfarina/semver that referenced this issue Nov 18, 2020
Range was used to iterate over the operations as part of generating
the regex. Range iterations are random. There were cases where the
empty key caused the regex to be generated as invalid.

This change removes the range so that the order is always the same.

Closes Masterminds#155
@jchunkins
Copy link
Author

Thanks for the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants