Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/build-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,44 @@ jobs:
grep -qF '("note" "lone * and / here")' "$TREE" || { echo "FAIL(data block comments): dict string lost its * or /"; exit 1; }
echo "[block comments] /* */ and .seq // are skipped in .seq, .kb, .dict and .kbb"

- name: Long kbb/dict lines and NLP++ errors (Non-20.04)
if: matrix.id != 'docker-ubuntu-20.04'
shell: bash
run: |
set -eo pipefail
# Three failures that exited 0 with nothing on the console.
# kbb-long-line: readKBB read lines into a 2,048-byte buffer and
# silently stopped loading at the first longer line. Its long line
# is a quoted array, which also loaded a stray 0 after each value.
# kbb-long-value: parseKBBLine and parseDictLine copied values
# unbounded into 512-byte buffers, overflowing the stack at startup.
# code-region-error: an NLP++ error still abandons the rest of its
# region, but is now echoed to stderr, not only written to err.log.
check() {
FIX=.github/workflows/tests/$1
rm -rf "$FIX/logs" "$FIX/input/text.txt_log" "$FIX/output"
./bin/nlp -ANA "$FIX" -WORK ./ "$FIX/input/text.txt" 2> "/tmp/$1.err"
if [ ! -f "$FIX/input/text.txt_log/out.txt" ]; then
echo "FAIL($1): no out.txt"; cat "/tmp/$1.err"; exit 1
fi
got=$(tr -d '\r' < "$FIX/input/text.txt_log/out.txt")
if [ "$got" != "$2" ]; then
echo "FAIL($1): out.txt was '$got'"; cat "/tmp/$1.err"; exit 1
fi
}
check kbb-long-line '30|item30|140'
check kbb-long-value '30|item30|600|3000|600|3000|noun'
check code-region-error "$(printf 'item 1\nitem 2\nitem 3\nnext pass ran')"
ERR=/tmp/code-region-error.err
grep -qF '[Error in NLP++ @CODE: pass 2 (loop) line 13, rest of the region skipped.' "$ERR" \
|| { echo "FAIL(code-region-error): @CODE error not on stderr"; cat "$ERR"; exit 1; }
# The @POST rule matches all four words: one line, not four.
n=$(grep -cF '[Error in NLP++ @POST: pass 4 (post) line 6,' "$ERR" || true)
if [ "$n" != 1 ]; then
echo "FAIL(code-region-error): @POST error echoed $n times, want 1"; cat "$ERR"; exit 1
fi
echo "[long lines] kbb/dict lines and values of any length load; NLP++ errors reach stderr"

- name: Run-mode globals ($dev / $silent, Non-20.04)
if: matrix.id != 'docker-ubuntu-20.04'
shell: bash
Expand Down
37 changes: 37 additions & 0 deletions .github/workflows/build-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,43 @@ jobs:
fi
echo "[rule debugger] pause points fire and leave the analysis unchanged"

- name: Long kbb/dict lines and NLP++ errors
shell: bash
run: |
set -eo pipefail
# Three failures that exited 0 with nothing on the console.
# kbb-long-line: readKBB read lines into a 2,048-byte buffer and
# silently stopped loading at the first longer line. Its long line
# is a quoted array, which also loaded a stray 0 after each value.
# kbb-long-value: parseKBBLine and parseDictLine copied values
# unbounded into 512-byte buffers, overflowing the stack at startup.
# code-region-error: an NLP++ error still abandons the rest of its
# region, but is now echoed to stderr, not only written to err.log.
check() {
FIX=.github/workflows/tests/$1
rm -rf "$FIX/logs" "$FIX/input/text.txt_log" "$FIX/output"
./bin/nlp -ANA "$FIX" -WORK ./ "$FIX/input/text.txt" 2> "/tmp/$1.err"
if [ ! -f "$FIX/input/text.txt_log/out.txt" ]; then
echo "FAIL($1): no out.txt"; cat "/tmp/$1.err"; exit 1
fi
got=$(tr -d '\r' < "$FIX/input/text.txt_log/out.txt")
if [ "$got" != "$2" ]; then
echo "FAIL($1): out.txt was '$got'"; cat "/tmp/$1.err"; exit 1
fi
}
check kbb-long-line '30|item30|140'
check kbb-long-value '30|item30|600|3000|600|3000|noun'
check code-region-error "$(printf 'item 1\nitem 2\nitem 3\nnext pass ran')"
ERR=/tmp/code-region-error.err
grep -qF '[Error in NLP++ @CODE: pass 2 (loop) line 13, rest of the region skipped.' "$ERR" \
|| { echo "FAIL(code-region-error): @CODE error not on stderr"; cat "$ERR"; exit 1; }
# The @POST rule matches all four words: one line, not four.
n=$(grep -cF '[Error in NLP++ @POST: pass 4 (post) line 6,' "$ERR" || true)
if [ "$n" != 1 ]; then
echo "FAIL(code-region-error): @POST error echoed $n times, want 1"; cat "$ERR"; exit 1
fi
echo "[long lines] kbb/dict lines and values of any length load; NLP++ errors reach stderr"

# INTEL MACS (#231). The steps above built and tested arm64 (Apple
# Silicon). Build the same tree for x86_64 too and merge the two with
# lipo, so nlpm.exe and the compile libraries are universal binaries:
Expand Down
37 changes: 37 additions & 0 deletions .github/workflows/build-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,43 @@ jobs:
grep -qF '("note" "lone * and / here")' "$TREE" || { echo "FAIL(data block comments): dict string lost its * or /"; exit 1; }
echo "[block comments] /* */ and .seq // are skipped in .seq, .kb, .dict and .kbb"

- name: Long kbb/dict lines and NLP++ errors
shell: bash
run: |
set -eo pipefail
# Three failures that exited 0 with nothing on the console.
# kbb-long-line: readKBB read lines into a 2,048-byte buffer and
# silently stopped loading at the first longer line. Its long line
# is a quoted array, which also loaded a stray 0 after each value.
# kbb-long-value: parseKBBLine and parseDictLine copied values
# unbounded into 512-byte buffers, overflowing the stack at startup.
# code-region-error: an NLP++ error still abandons the rest of its
# region, but is now echoed to stderr, not only written to err.log.
check() {
FIX=.github/workflows/tests/$1
rm -rf "$FIX/logs" "$FIX/input/text.txt_log" "$FIX/output"
./bin/Release/nlp.exe -ANA "$FIX" -WORK ./ "$FIX/input/text.txt" 2> "/tmp/$1.err"
if [ ! -f "$FIX/input/text.txt_log/out.txt" ]; then
echo "FAIL($1): no out.txt"; cat "/tmp/$1.err"; exit 1
fi
got=$(tr -d '\r' < "$FIX/input/text.txt_log/out.txt")
if [ "$got" != "$2" ]; then
echo "FAIL($1): out.txt was '$got'"; cat "/tmp/$1.err"; exit 1
fi
}
check kbb-long-line '30|item30|140'
check kbb-long-value '30|item30|600|3000|600|3000|noun'
check code-region-error "$(printf 'item 1\nitem 2\nitem 3\nnext pass ran')"
ERR=/tmp/code-region-error.err
grep -qF '[Error in NLP++ @CODE: pass 2 (loop) line 13, rest of the region skipped.' "$ERR" \
|| { echo "FAIL(code-region-error): @CODE error not on stderr"; cat "$ERR"; exit 1; }
# The @POST rule matches all four words: one line, not four.
n=$(grep -cF '[Error in NLP++ @POST: pass 4 (post) line 6,' "$ERR" || true)
if [ "$n" != 1 ]; then
echo "FAIL(code-region-error): @POST error echoed $n times, want 1"; cat "$ERR"; exit 1
fi
echo "[long lines] kbb/dict lines and values of any length load; NLP++ errors reach stderr"

- name: Run-mode globals ($dev / $silent)
shell: bash
run: |
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/tests/code-region-error/input/text.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
one two three four
3 changes: 3 additions & 0 deletions .github/workflows/tests/code-region-error/spec/after.nlp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@CODE
"out.txt" << "next pass ran\n";
@@CODE
4 changes: 4 additions & 0 deletions .github/workflows/tests/code-region-error/spec/analyzer.seq
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
tokenize nil # tokenize
nlp loop # @CODE error mid-loop
nlp after # the next pass still runs
nlp post # @POST error on every match
17 changes: 17 additions & 0 deletions .github/workflows/tests/code-region-error/spec/loop.nlp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# findconcept() on a null concept at item 3 is an NLP++ error. It abandons
# the rest of the @CODE region (items 3-5 and "loop finished" never write),
# and nlp exits 0. That is unchanged. What the CI step asserts is that the
# error is now on stderr, naming the pass, file and line, not only in the
# input's err.log.
@CODE
L("i") = 1;
while (L("i") <= 5) {
"out.txt" << "item " << str(L("i")) << "\n";
L("parent") = makeconcept(findroot(),"reprotest");
if (L("i") == 3)
L("parent") = 0;
L("c") = findconcept(L("parent"),"anything"); # line 13
L("i")++;
}
"out.txt" << "loop finished\n";
@@CODE
8 changes: 8 additions & 0 deletions .github/workflows/tests/code-region-error/spec/post.nlp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# The same error in @POST, on a rule that matches every word. It is echoed
# to stderr once, not once per match.
@NODES _ROOT

@POST
findconcept(0,"anything");
@RULES
_xNIL <- _xALPHA @@
1 change: 1 addition & 0 deletions .github/workflows/tests/kbb-long-line/input/text.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
34 changes: 34 additions & 0 deletions .github/workflows/tests/kbb-long-line/kb/user/longline.kbb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# 30 concepts. item10's line is ~2,700 chars of short values. readKBB
# read lines into a 2,048-byte buffer: the load silently stopped at
# item10 (loaded 10 of 30), with nothing in any log.
longline
item1: n=1
item2: n=2
item3: n=3
item4: n=4
item5: n=5
item6: n=6
item7: n=7
item8: n=8
item9: n=9
item10: term=["term number 000","term number 001","term number 002","term number 003","term number 004","term number 005","term number 006","term number 007","term number 008","term number 009","term number 010","term number 011","term number 012","term number 013","term number 014","term number 015","term number 016","term number 017","term number 018","term number 019","term number 020","term number 021","term number 022","term number 023","term number 024","term number 025","term number 026","term number 027","term number 028","term number 029","term number 030","term number 031","term number 032","term number 033","term number 034","term number 035","term number 036","term number 037","term number 038","term number 039","term number 040","term number 041","term number 042","term number 043","term number 044","term number 045","term number 046","term number 047","term number 048","term number 049","term number 050","term number 051","term number 052","term number 053","term number 054","term number 055","term number 056","term number 057","term number 058","term number 059","term number 060","term number 061","term number 062","term number 063","term number 064","term number 065","term number 066","term number 067","term number 068","term number 069","term number 070","term number 071","term number 072","term number 073","term number 074","term number 075","term number 076","term number 077","term number 078","term number 079","term number 080","term number 081","term number 082","term number 083","term number 084","term number 085","term number 086","term number 087","term number 088","term number 089","term number 090","term number 091","term number 092","term number 093","term number 094","term number 095","term number 096","term number 097","term number 098","term number 099","term number 100","term number 101","term number 102","term number 103","term number 104","term number 105","term number 106","term number 107","term number 108","term number 109","term number 110","term number 111","term number 112","term number 113","term number 114","term number 115","term number 116","term number 117","term number 118","term number 119","term number 120","term number 121","term number 122","term number 123","term number 124","term number 125","term number 126","term number 127","term number 128","term number 129","term number 130","term number 131","term number 132","term number 133","term number 134","term number 135","term number 136","term number 137","term number 138","term number 139"]
item11: n=11
item12: n=12
item13: n=13
item14: n=14
item15: n=15
item16: n=16
item17: n=17
item18: n=18
item19: n=19
item20: n=20
item21: n=21
item22: n=22
item23: n=23
item24: n=24
item25: n=25
item26: n=26
item27: n=27
item28: n=28
item29: n=29
item30: n=30
2 changes: 2 additions & 0 deletions .github/workflows/tests/kbb-long-line/spec/analyzer.seq
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
tokenize nil # tokenize
nlp probe # count what loaded
23 changes: 23 additions & 0 deletions .github/workflows/tests/kbb-long-line/spec/probe.nlp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
###############################################
# FILE: probe.nlp
# SUBJ: Count what longline.kbb loaded, and the values on its long line.
# NOTE: Expected out.txt: 30|item30|140
###############################################

@CODE
L("root") = findconcept(findroot(),"longline");
L("n") = 0;
L("c") = down(L("root"));
while (L("c")) {
L("n")++;
L("last") = conceptname(L("c"));
L("c") = next(L("c"));
}
L("vals") = 0;
L("v") = attrvals(findattr(findconcept(L("root"),"item10"),"term"));
while (L("v")) {
L("vals")++;
L("v") = nextval(L("v"));
}
"out.txt" << str(L("n")) << "|" << L("last") << "|" << str(L("vals")) << "\n";
@@CODE
1 change: 1 addition & 0 deletions .github/workflows/tests/kbb-long-value/input/text.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
34 changes: 34 additions & 0 deletions .github/workflows/tests/kbb-long-value/kb/user/longline.kbb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# 30 concepts. item10 has a 600-char value, item20 a 3,000-char one.
# parseKBBLine copied values unbounded into 512-char buffers: a
# stack buffer overflow that aborted the engine at startup.
longline
item1: n=1
item2: n=2
item3: n=3
item4: n=4
item5: n=5
item6: n=6
item7: n=7
item8: n=8
item9: n=9
item10: note="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
item11: n=11
item12: n=12
item13: n=13
item14: n=14
item15: n=15
item16: n=16
item17: n=17
item18: n=18
item19: n=19
item20: note="yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
item21: n=21
item22: n=22
item23: n=23
item24: n=24
item25: n=25
item26: n=26
item27: n=27
item28: n=28
item29: n=29
item30: n=30
Loading
Loading