]> granicus.if.org Git - graphviz/commitdiff
fix: track source line number accurately across newlines in quoted strings
authorMatthew Fernandez <matthew.fernandez@gmail.com>
Sun, 13 Sep 2020 00:54:43 +0000 (17:54 -0700)
committerMatthew Fernandez <matthew.fernandez@gmail.com>
Sat, 19 Sep 2020 02:58:37 +0000 (19:58 -0700)
The regex for matching arbitrary content within a quoted string (qstring) was
too broad, matching also newlines. Due to the way Flex preferences regex matches
this prevented the literal newline rule from matching at all within a quoted
string. As a result error messages would reference incorrect line numbers.
Closes #1411.

CHANGELOG.md
lib/cgraph/scan.l
rtest/1411.dot [new file with mode: 0644]
rtest/test_regression.py

index 3db717d3d1630544e7bf5ee884f1e838ba823024..b43ef868cd77bd93f9d851dbfe5442ff7860ad27 100644 (file)
@@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - a failure to detect OpenGL glGenTextures() errors has been corrected
 - sfio does compile time benchmarknig #1422
 - iffe "lib" check always succeeds when compiler optimises #1521
+- syntax error near text who is not present #1411
 
 ## [2.44.1] - 2020-06-29
 
index c918396c4577801188a54a47a1049667c82c1e8d..b0af41b64315db3b531884b22bdc828068e7ae08 100644 (file)
@@ -222,7 +222,7 @@ ID          ({NAME}|{NUMBER})
 <qstring>[\\]["]               addstr ("\"");
 <qstring>[\\][\\]              addstr ("\\\\");
 <qstring>[\\][\n]              line_num++; /* ignore escaped newlines */
-<qstring>([^"\\]*|[\\])                addstr(aagtext);
+<qstring>([^"\\\n]*|[\\])              addstr(aagtext);
 [<]                                            BEGIN(hstring); html_nest = 1; beginstr();
 <hstring>[>]                   html_nest--; if (html_nest) addstr(aagtext); else {BEGIN(INITIAL); endstr_html(); return (T_qatom);}
 <hstring>[<]                   html_nest++; addstr(aagtext);
diff --git a/rtest/1411.dot b/rtest/1411.dot
new file mode 100644 (file)
index 0000000..47bc8b0
--- /dev/null
@@ -0,0 +1,81 @@
+digraph G {
+  "/*
+  This mess is the project of *manually* .Dot-ify minor .JavaScript projects
+  Current state: creating nodes, none connection done for the moment
+  May contain lots of stupid english-speaking mistakes
+  */"
+
+  "var VERSION=2.0106;"
+  "var BETA=0;"
+
+  "/*=====================================================================================
+  MISC HELPER FUNCTIONS
+  =======================================================================================*/"
+  "function l(what) {return document.getElementById(what);}"
+  "function choose(arr) {return arr[Math.floor(Math.random()*arr.length)];}"
+
+  "function escapeRegExp(str){return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");}"
+  "function replaceAll(find,replace,str){return str.replace(new RegExp(escapeRegExp(find),'g'),replace);}"
+
+  "//disable sounds (sorry)"
+  "var realAudio=Audio;//backup real audio"
+  "Audio=function(src){
+    if (src && src.indexOf('soundjay')&gt-1) {Game.Popup('Sorry, no sounds');this.play=function(){};}
+    else return new realAudio(src);
+  };"
+
+  "if(!Array.prototype.indexOf) {
+    Array.prototype.indexOf = function(needle) {
+      for(var i = 0; i < this.length; i++) {
+        if(this[i] === needle) {return i;}
+      }
+      return -1;
+    };
+  }"
+
+  "function randomFloor(x) {if ((x%1)<Math.random()) return Math.floor(x); else return Math.ceil(x);}"
+
+  "function shuffle(array)
+  {
+    var counter = array.length, temp, index;
+    // While there are elements in the array
+    while (counter--)
+    {
+      // Pick a random index
+      index = (Math.random() * counter) | 0;
+
+      // And swap the last element with it
+      temp = array[counter];
+      array[counter] = array[index];
+      array[index] = temp;
+    }
+    return array;
+  }"
+
+  "var sinArray=[];"
+  "for (var i=0;i<360;i++)
+  {
+    //let's make a lookup table
+    sinArray[i]=Math.sin(i/360*Math.PI*2);
+  }"
+  "function quickSin(x)
+  {
+    //oh man this isn't all that fast actually
+    //why do I do this. why
+    var sign=x<0?-1:1;
+    return sinArray[Math.round(
+      (Math.abs(x)*360/Math.PI/2)%360
+    )]*sign;
+  }"
+
+  "/*function ajax(url,callback){
+    var ajaxRequest;
+    try{ajaxRequest = new XMLHttpRequest();} catch (e){try{ajaxRequest=new ActiveXObject('Msxml2.XMLHTTP');} catch (e) {try{ajaxRequest=new ActiveXObject('Microsoft.XMLHTTP');} catch (e){alert("Something broke!");return false;}}}
+    if (callback){ajaxRequest.onreadystatechange=function(){if(ajaxRequest.readyState==4){callback(ajaxRequest.responseText);}}}
+    ajaxRequest.open('GET',url+'&nocache='+(new Date().getTime()),true);ajaxRequest.send(null);
+  }*/"
+
+# var ajax=function(url,callback)
+//[lots of unfinished things who have been turned into comments using #]
+# /*=======
+}
index 978ca1979b023604401f0d8d303a285f634a7e9a..4d86f1672cb94d2a28301398df97f00ec4fd486d 100644 (file)
@@ -120,6 +120,26 @@ def test_1314():
     # the execution did not fail as expected
     pytest.fail('dot incorrectly exited with success')
 
+def test_1411():
+    '''
+    parsing strings containing newlines should not disrupt line number tracking
+    https://gitlab.com/graphviz/graphviz/-/issues/1411
+    '''
+
+    # locate our associated test case in this directory
+    input = os.path.join(os.path.dirname(__file__), '1411.dot')
+    assert os.path.exists(input), 'unexpectedly missing test case'
+
+    # process it with Graphviz (should fail)
+    p = subprocess.Popen(['dot', '-Tsvg', '-o', os.devnull, input],
+      stderr=subprocess.PIPE, universal_newlines=True)
+    _, output = p.communicate()
+
+    assert p.returncode != 0, 'Graphviz accepted broken input'
+
+    assert 'syntax error in line 17 near \'\\\'' in output, \
+      'error message did not identify correct location'
+
 def test_1436():
     '''
     test a segfault from https://gitlab.com/graphviz/graphviz/-/issues/1436 has