diff --git a/src/core/peg.c b/src/core/peg.c index 79fee92e..33fd52c8 100644 --- a/src/core/peg.c +++ b/src/core/peg.c @@ -161,6 +161,7 @@ static LineCol get_linecol_from_position(PegState *s, int32_t position) { /* Convert a uint64_t to a int64_t by wrapping to a maximum number of bytes */ static int64_t peg_convert_u64_s64(uint64_t from, int width) { + if (width == 0) return 0; /* Avoid undefined shift */ int shift = 8 * (8 - width); return ((int64_t)(from << shift)) >> shift; } @@ -1516,7 +1517,13 @@ static uint32_t peg_compile1(Builder *b, Janet peg) { int32_t n = peg_getinteger(b, peg); Reserve r = reserve(b, 2); if (n < 0) { - emit_1(r, RULE_NOTNCHAR, -n); + if (n == INT32_MIN) { + /* Since buffers can't hold this many characters, will + * always match. Avoid undefined behavior negating INT32_MIN. */ + emit_1(r, RULE_NCHAR, 0); + } else { + emit_1(r, RULE_NOTNCHAR, -n); + } } else { emit_1(r, RULE_NCHAR, n); } diff --git a/test/suite-peg.janet b/test/suite-peg.janet index 0058e490..8dc54cab 100644 --- a/test/suite-peg.janet +++ b/test/suite-peg.janet @@ -679,6 +679,16 @@ "abcdef" @[]) +(test "undefined behavior: (int 0)" + ~(int 0) + "123" + @[0]) + +(test "undefined behavior: int min" + math/int32-min + "abc" + @[]) + (test "sub: second pattern cannot match more than the first pattern" ~(sub "abcd" "abcde") "abcdef"