|
5 | 5 | "fmt" |
6 | 6 | "io" |
7 | 7 | "math" |
| 8 | + "math/big" |
8 | 9 | "regexp" |
9 | 10 | "strconv" |
10 | 11 | "strings" |
@@ -191,6 +192,12 @@ type ( |
191 | 192 | posStack []pos |
192 | 193 |
|
193 | 194 | pendingForms []any |
| 195 | + |
| 196 | + // nested syntax quoting grows forms exponentially, so we |
| 197 | + // limit the depth to prevent DoS. |
| 198 | + // |
| 199 | + // Found by the fuzz tester. |
| 200 | + syntaxQuoteNestCounter int |
194 | 201 | } |
195 | 202 | ) |
196 | 203 |
|
@@ -512,7 +519,11 @@ func (r *Reader) readSet() (interface{}, error) { |
512 | 519 | if err != nil { |
513 | 520 | return nil, err |
514 | 521 | } |
515 | | - return lang.NewSet(vals...), nil |
| 522 | + set, err := lang.NewSet2(vals...) |
| 523 | + if err != nil { |
| 524 | + return nil, r.error("invalid set: %w", err) |
| 525 | + } |
| 526 | + return set, nil |
516 | 527 | } |
517 | 528 |
|
518 | 529 | func (r *Reader) readString() (interface{}, error) { |
@@ -724,6 +735,14 @@ func (r *Reader) readQuote() (interface{}, error) { |
724 | 735 | } |
725 | 736 |
|
726 | 737 | func (r *Reader) readSyntaxQuote() (interface{}, error) { |
| 738 | + if r.syntaxQuoteNestCounter > 10 { |
| 739 | + return nil, r.error("syntax-quote nesting too deep") |
| 740 | + } |
| 741 | + r.syntaxQuoteNestCounter++ |
| 742 | + defer func() { |
| 743 | + r.syntaxQuoteNestCounter-- |
| 744 | + }() |
| 745 | + |
727 | 746 | node, err := r.readExpr(false, 0) |
728 | 747 | if err != nil { |
729 | 748 | return nil, err |
@@ -1114,6 +1133,12 @@ func (r *Reader) readNumber(numStr string) (interface{}, error) { |
1114 | 1133 | if err != nil { |
1115 | 1134 | return nil, r.error("invalid ratio: %s", numStr) |
1116 | 1135 | } |
| 1136 | + |
| 1137 | + // if denom is 0, error |
| 1138 | + if denomBig.ToBigInteger().Cmp(big.NewInt(0)) == 0 { |
| 1139 | + return nil, r.error("divide by zero") |
| 1140 | + } |
| 1141 | + |
1117 | 1142 | return lang.NewRatioBigInt(numBig, denomBig), nil |
1118 | 1143 | } |
1119 | 1144 |
|
@@ -1291,6 +1316,14 @@ func (r *Reader) readConditional(eofOK bool, stopRune rune) (any, error) { |
1291 | 1316 | return nil, r.error("splicing read-cond form must be seqable") |
1292 | 1317 | } |
1293 | 1318 | seq := seqable.Seq() |
| 1319 | + if seq == nil { |
| 1320 | + // return the next expression (not nil!) |
| 1321 | + form, err := r.readExpr(eofOK, stopRune) |
| 1322 | + if err != nil { |
| 1323 | + return nil, err |
| 1324 | + } |
| 1325 | + return form, nil |
| 1326 | + } |
1294 | 1327 | first := seq.First() |
1295 | 1328 | for seq = seq.Next(); seq != nil; seq = seq.Next() { |
1296 | 1329 | r.pendingForms = append(r.pendingForms, seq.First()) |
|
0 commit comments