Skip to content

Commit bc5fa9f

Browse files
committed
[mv3] Fix binary search potentially not finding match in edge case
Under certain conditions, binary search could fail finding a match when following conditions were fulfilled: - There was only one item in the haystack - Multiple needles with first one not being a match This would cause subsequent needles from being correctly identified as a match.
1 parent 1982df1 commit bc5fa9f

4 files changed

Lines changed: 70 additions & 71 deletions

File tree

platform/mv3/extension/js/offscreen/css-sandbox.template.js

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -49,35 +49,32 @@ const selectorsFromListIndex = ilist => {
4949
}
5050
};
5151

52-
const selectorsFromHostnames = (haystack, needles) => {
53-
let listref = -1;
54-
for ( const needle of needles ) {
55-
listref = isolatedAPI.binarySearch(haystack, needle, listref);
56-
if ( listref >= 0 ) {
57-
selectorsFromListIndex(cssSpecificData.selectorListRefs[listref]);
58-
} else {
59-
listref = ~listref;
52+
const { hostnames, regexes } = cssSpecificData;
53+
if ( hostnames.length ) {
54+
const selectorsFromHostnames = (haystack, needles) => {
55+
let listref = -1;
56+
for ( const needle of needles ) {
57+
listref = isolatedAPI.binarySearch(haystack, needle, listref);
58+
if ( listref >= 0 ) {
59+
selectorsFromListIndex(cssSpecificData.selectorListRefs[listref]);
60+
} else {
61+
listref = ~listref + 1;
62+
}
6063
}
61-
}
62-
};
63-
64-
const selectorsFromRuleset = ( ) => {
65-
selectorsFromHostnames(cssSpecificData.hostnames, isolatedAPI.contexts.hostnames);
64+
};
65+
selectorsFromHostnames(hostnames, isolatedAPI.contexts.hostnames);
6666
if ( cssSpecificData.hasEntities ) {
67-
selectorsFromHostnames(cssSpecificData.hostnames, isolatedAPI.contexts.entities);
67+
selectorsFromHostnames(hostnames, isolatedAPI.contexts.entities);
6868
}
69-
const { regexes } = cssSpecificData;
70-
for ( let i = 0, n = regexes.length; i < n; i += 3 ) {
71-
if ( thisHostname.includes(regexes[i+0]) === false ) { continue; }
72-
if ( typeof regexes[i+1] === 'string' ) {
73-
regexes[i+1] = new RegExp(regexes[i+1]);
74-
}
75-
if ( regexes[i+1].test(thisHostname) === false ) { continue; }
76-
selectorsFromListIndex(cssSpecificData, regexes[i+2]);
69+
}
70+
for ( let i = 0, n = regexes.length; i < n; i += 3 ) {
71+
if ( thisHostname.includes(regexes[i+0]) === false ) { continue; }
72+
if ( typeof regexes[i+1] === 'string' ) {
73+
regexes[i+1] = new RegExp(regexes[i+1]);
7774
}
78-
};
79-
80-
selectorsFromRuleset();
75+
if ( regexes[i+1].test(thisHostname) === false ) { continue; }
76+
selectorsFromListIndex(cssSpecificData, regexes[i+2]);
77+
}
8178

8279
const s = [];
8380
const p = [];

platform/mv3/extension/js/offscreen/scriptlet.template.js

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -91,51 +91,51 @@ const entries = (( ) => {
9191
})();
9292
if ( entries.length === 0 ) { return; }
9393

94-
const collectArglistRefIndices = (out, hn, r) => {
95-
let l = 0, i = 0, d = 0;
96-
let candidate = '';
97-
while ( l < r ) {
98-
i = l + r >>> 1;
99-
candidate = $scriptletHostnames$[i];
100-
d = hn.length - candidate.length;
101-
if ( d === 0 ) {
102-
if ( hn === candidate ) {
103-
out.add(i); break;
94+
const todoIndices = new Set();
95+
if ( $scriptletHostnames$.length ) {
96+
const collectArglistRefIndices = (out, hn, r) => {
97+
let l = 0, i = 0, d = 0;
98+
let candidate = '';
99+
while ( l < r ) {
100+
i = l + r >>> 1;
101+
candidate = $scriptletHostnames$[i];
102+
d = hn.length - candidate.length;
103+
if ( d === 0 ) {
104+
if ( hn === candidate ) {
105+
out.add(i); break;
106+
}
107+
d = hn < candidate ? -1 : 1;
108+
}
109+
if ( d < 0 ) {
110+
r = i;
111+
} else {
112+
l = i + 1;
104113
}
105-
d = hn < candidate ? -1 : 1;
106-
}
107-
if ( d < 0 ) {
108-
r = i;
109-
} else {
110-
l = i + 1;
111114
}
112-
}
113-
return i;
114-
};
115-
116-
const indicesFromHostname = (out, hnDetails, suffix = '') => {
117-
if ( hnDetails.hns.length === 0 ) { return; }
118-
let r = $scriptletHostnames$.length;
119-
for ( const hn of hnDetails.hns ) {
120-
r = collectArglistRefIndices(out, `${hn}${suffix}`, r);
121-
}
122-
if ( $hasEntities$ ) {
115+
return i + 1;
116+
};
117+
const indicesFromHostname = (out, hnDetails, suffix = '') => {
118+
if ( hnDetails.hns.length === 0 ) { return; }
123119
let r = $scriptletHostnames$.length;
124-
for ( const en of hnDetails.ens ) {
125-
r = collectArglistRefIndices(out, `${en}${suffix}`, r);
120+
for ( const hn of hnDetails.hns ) {
121+
r = collectArglistRefIndices(out, `${hn}${suffix}`, r);
122+
}
123+
if ( $hasEntities$ ) {
124+
let r = $scriptletHostnames$.length;
125+
for ( const en of hnDetails.ens ) {
126+
r = collectArglistRefIndices(out, `${en}${suffix}`, r);
127+
}
128+
}
129+
};
130+
indicesFromHostname(todoIndices, entries[0]);
131+
if ( $hasAncestors$ ) {
132+
for ( const entry of entries ) {
133+
if ( entry.i === 0 ) { continue; }
134+
indicesFromHostname(todoIndices, entry, '>>');
126135
}
127136
}
128-
};
129-
130-
const todoIndices = new Set();
131-
indicesFromHostname(todoIndices, entries[0]);
132-
if ( $hasAncestors$ ) {
133-
for ( const entry of entries ) {
134-
if ( entry.i === 0 ) { continue; }
135-
indicesFromHostname(todoIndices, entry, '>>');
136-
}
137+
$scriptletHostnames$.length = 0;
137138
}
138-
$scriptletHostnames$.length = 0;
139139

140140
// Collect arglist references
141141
const todo = new Set();

platform/mv3/extension/js/scripting/css-generic.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ for ( const entry of genericDetails ) {
253253
if ( i >= 0 ) {
254254
exceptions[i].split('\n').forEach(a => exceptionSet.add(a));
255255
} else {
256-
i = ~i;
256+
i = ~i + 1;
257257
}
258258
}
259259
if ( entry.hasEntities ) {
@@ -263,7 +263,7 @@ for ( const entry of genericDetails ) {
263263
if ( i >= 0 ) {
264264
exceptions[i].split('\n').forEach(a => exceptionSet.add(a));
265265
} else {
266-
i = ~i;
266+
i = ~i + 1;
267267
}
268268
}
269269
}

platform/mv3/extension/js/scripting/css-specific.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ const selectorsFromHostnames = (haystack, needles, data) => {
7474
if ( listref >= 0 ) {
7575
selectorsFromListIndex(data, data.selectorListRefs[listref]);
7676
} else {
77-
listref = ~listref;
77+
listref = ~listref + 1;
7878
}
7979
}
8080
};
@@ -83,11 +83,13 @@ const selectorsFromRuleset = async (rulesetId, result) => {
8383
const data = await localRead(`css.specific.${rulesetId}`);
8484
if ( typeof data !== 'object' || data === null ) { return; }
8585
data.result = result;
86-
selectorsFromHostnames(data.hostnames, isolatedAPI.contexts.hostnames, data);
87-
if ( data.hasEntities ) {
88-
selectorsFromHostnames(data.hostnames, isolatedAPI.contexts.entities, data);
86+
const { hostnames, regexes } = data;
87+
if ( hostnames.length ) {
88+
selectorsFromHostnames(hostnames, isolatedAPI.contexts.hostnames, data);
89+
if ( data.hasEntities ) {
90+
selectorsFromHostnames(hostnames, isolatedAPI.contexts.entities, data);
91+
}
8992
}
90-
const { regexes } = data;
9193
for ( let i = 0, n = regexes.length; i < n; i += 3 ) {
9294
if ( thisHostname.includes(regexes[i+0]) === false ) { continue; }
9395
if ( typeof regexes[i+1] === 'string' ) {

0 commit comments

Comments
 (0)