Guard AllNumberGroupsRemainGrouped against indexOf/find(-1) for the country-code skip (Java + C++) - #4067
Open
twcclegg wants to merge 2 commits into
Open
Conversation
…(-1) for the country-code skip When the country calling code isn't a literal substring of the candidate text, StringBuilder.indexOf returns -1 and fromIndex became -1 + countryCode.length() instead of a proper "not found" value, silently desyncing the subsequent group-matching loop. Guard it the same way the check one line below already guards its own indexOf call.
Same bug as the Java fix, applied to AllNumberGroupsRemainGrouped in phonenumbermatcher.cc: std::string::find returns string::npos on a miss, and the unguarded "+ country_code.size()" wrapped that around via unsigned overflow into a small, wrong, non-negative from_index instead of leaving it as "not found." AllNumberGroupsRemainGrouped is in an anonymous namespace here, so unlike the Java package-private method it isn't reachable from the test binary for a direct unit test; JS has no PhoneNumberMatcher (find-numbers-in-text) implementation at all, so no fix is needed there.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue
https://issuetracker.google.com/issues/552025944
What's wrong
In
PhoneNumberMatcher.allNumberGroupsRemainGrouped(Java), when the country calling code isn't a literal substring of the candidate text,indexOfreturns-1, and:leaves
fromIndexat a small, wrong, non-negative value instead of "not found." This desyncs the subsequent group-matching loop, which can make a grouping check that should succeed silently returnfalseinstead — i.e. a valid phone number embedded in free text can fail to match, with no exception. The very nextindexOfcall in the same method (one line below, inside the loop) already guards against exactly this withif (fromIndex < 0) { return false; }; this fix applies the same guard to the country-code skip.In practice this is probably rare, since a matched candidate's text usually does contain the country code's digits somewhere. Confirmed with a constructed case (country code 44, candidate text that doesn't contain "44") added as a new unit test.
Fix
Guard the
indexOfresult before using it, leavingfromIndexat its default (0, i.e. "don't skip anything") when the country code isn't found as a literal substring, rather than propagating a bogus offset.Scope across languages
Per the contributing guide's note to check whether a fix applies in C++, Java, and JS:
cpp/src/phonenumbers/phonenumbermatcher.cc) — has the exact same pattern withstd::string::find, and it's arguably worse there:findreturnsnpos(size_tmax) on a miss, and the unguarded+ country_code.size()wraps around via unsigned overflow into a small, wrong, non-negativefrom_indexinstead of crashing loudly. Fixed with the same guard.PhoneNumberMatcher(find-numbers-in-text) implementation at all;allNumberGroupsRemainGrouped/AllNumberGroupsRemainGroupeddoesn't exist there. Verified by greppingjavascript/i18n/phonenumbers/for the function and for any matcher module — onlyasyoutypeformatter.jsandphonenumberutil.js(parse/format/validate) exist, no text-scanning matcher.Testing
No local JDK/C++ toolchain was available to me to run the test suites, so I traced both fixes by hand and I'd appreciate a maintainer/CI double-check.
testAllNumberGroupsRemainGroupedCountryCodeNotInCandidatecalls the package-privateallNumberGroupsRemainGroupeddirectly with aPhoneNumberwhosecountryCodeSourceisFROM_NUMBER_WITH_PLUS_SIGN(country code 44) and a candidate string that never contains the literal digits "44". Before the fix this returnsfalse(bug); after the fix it returnstrue.AllNumberGroupsRemainGroupedis in an anonymous namespace inphonenumbermatcher.cc, so unlike the Java package-private method it isn't reachable from the test binary in a different translation unit for a direct unit test, and I didn't want to change its linkage just to test this. Happy to take a suggestion from a maintainer on how this is normally exercised (e.g. viaPhoneNumberMatcher::Match/Find) if a regression test is wanted here.