diff --git a/src/js/cosmetic-filtering.js b/src/js/cosmetic-filtering.js index 2c255587c..623b1c80c 100644 --- a/src/js/cosmetic-filtering.js +++ b/src/js/cosmetic-filtering.js @@ -237,7 +237,9 @@ var FilterParser = function() { this.unhide = 0; this.hostnames = []; this.invalid = false; + this.cosmetic = true; this.reParser = /^\s*([^#]*)(##|#@#)(.+)\s*$/; + this.div = document.createElement('div'); }; /******************************************************************************/ @@ -248,18 +250,31 @@ FilterParser.prototype.reset = function() { this.unhide = 0; this.hostnames.length = 0; this.invalid = false; + this.cosmetic = true; return this; }; /******************************************************************************/ +FilterParser.prototype.isValidSelector = function(s) { + try { + this.div.matches(s); + } catch (e) { + console.error('µBlock> invalid cosmetic filter:', s); + return false; + } + return true; +}; + +/******************************************************************************/ + FilterParser.prototype.parse = function(s) { // important! this.reset(); var matches = this.reParser.exec(s); if ( matches === null || matches.length !== 4 ) { - this.invalid = true; + this.cosmetic = false; return this; } @@ -272,7 +287,7 @@ FilterParser.prototype.parse = function(s) { // Any sequence of `#` longer than one means the line is not a valid // cosmetic filter. if ( this.suffix.indexOf('##') !== -1 ) { - this.invalid = true; + this.cosmetic = false; return this; } @@ -283,6 +298,13 @@ FilterParser.prototype.parse = function(s) { this.suffix = this.suffix.slice(1); } + // https://github.com/gorhill/uBlock/issues/1004 + // Detect and report invalid CSS selectors. + if ( this.isValidSelector(this.suffix) === false ) { + this.invalid = true; + return this; + } + this.unhide = matches[2].charAt(1) === '@' ? 1 : 0; if ( this.prefix !== '' ) { this.hostnames = this.prefix.split(/\s*,\s*/); @@ -559,9 +581,12 @@ FilterContainer.prototype.reset = function() { FilterContainer.prototype.compile = function(s, out) { var parsed = this.parser.parse(s); - if ( parsed.invalid ) { + if ( parsed.cosmetic === false ) { return false; } + if ( parsed.invalid ) { + return true; + } var hostnames = parsed.hostnames; var i = hostnames.length;