A categorical programming language
Revisão | 6bcb0678c358220b39f79aacadb3d72ce9b62456 (tree) |
---|---|
Hora | 2024-10-27 08:52:08 |
Autor | Corbin <cds@corb...> |
Commiter | Corbin |
Further harden the parser.
This is enough to cause afl-fuzz to find nothing after 10 cycles.
@@ -1,5 +1,7 @@ | ||
1 | 1 | from cammylib.sexp import sexp |
2 | 2 | |
3 | +from rpython.rlib.objectmodel import specialize | |
4 | +from rpython.rlib.rstackovf import StackOverflow, check_stack_overflow | |
3 | 5 | |
4 | 6 | class ParseError(Exception): |
5 | 7 | def __init__(self, message): |
@@ -21,6 +23,7 @@ def makeParser(parserName, buildAtom, buildList): | ||
21 | 23 | while self.hasMore() and self._s[self._i] in (" ", "\n"): |
22 | 24 | self._i += 1 |
23 | 25 | |
26 | + @specialize.arg(1) | |
24 | 27 | def canAndDoesEat(self, c): |
25 | 28 | if self._s[self._i] == c: |
26 | 29 | self._i += 1 |
@@ -33,6 +36,8 @@ def makeParser(parserName, buildAtom, buildList): | ||
33 | 36 | while self.hasMore() and self._s[self._i] not in (")", "(", " ", "\n"): |
34 | 37 | self._i += 1 |
35 | 38 | stop = self._i |
39 | + if start == stop: | |
40 | + raise ParseError("Expected name starting at %d" % start) | |
36 | 41 | return self._s[start:stop] |
37 | 42 | |
38 | 43 | def takeExpression(self): |
@@ -74,11 +79,16 @@ CammyParser = makeParser("CammyParser", buildCammyAtom, buildCammyTemplate) | ||
74 | 79 | def parse(s): |
75 | 80 | "Parse a Cammy expression, preserving any trailing text." |
76 | 81 | parser = CammyParser(s) |
77 | - sexp = parser.takeExpression() | |
78 | - # Parser is now fast-forwarded to the end of the S-expression, so we can | |
79 | - # slice from that point and get the docstring/etc. | |
80 | - trail = s[parser.position():] | |
81 | - return sexp, trail | |
82 | + try: | |
83 | + sexp = parser.takeExpression() | |
84 | + # Parser is now fast-forwarded to the end of the S-expression, so we can | |
85 | + # slice from that point and get the docstring/etc. | |
86 | + trail = s[parser.position():] | |
87 | + return sexp, trail | |
88 | + except MemoryError: raise ParseError("Out of memory") | |
89 | + except StackOverflow: | |
90 | + check_stack_overflow() | |
91 | + raise ParseError("Stack overflow") | |
82 | 92 | |
83 | 93 | |
84 | 94 | def parseTypes(s): |
@@ -39,16 +39,16 @@ def main(argv): | ||
39 | 39 | if len(argv) != l: return help(stderr, exe, "%s takes %d arguments" % (k, l)) |
40 | 40 | try: return action.do(argv) |
41 | 41 | except ParseError as pe: |
42 | - printErr(stderr, "Could not parse input:", pe.message) | |
42 | + printErr(stderr, "Could not parse input", pe.message) | |
43 | 43 | return 1 |
44 | 44 | except BuildProblem as bp: |
45 | - printErr(stderr, "Could not build arrow:", bp.message) | |
45 | + printErr(stderr, "Could not build arrow", bp.message) | |
46 | 46 | return 1 |
47 | 47 | except UnificationFailed as uf: |
48 | - printErr(stderr, "Could not check type:", uf.message) | |
48 | + printErr(stderr, "Could not check type", uf.message) | |
49 | 49 | return 1 |
50 | 50 | except TypeFail as tf: |
51 | - printErr(stderr, "Type failure:", tf.reason) | |
51 | + printErr(stderr, "Type failure", tf.reason) | |
52 | 52 | return 1 |
53 | 53 | else: |
54 | 54 | help(stderr, exe, "unknown command: " + command) |