Raise `re2.error` instead of crashing.

Fixes #484.

Change-Id: I152b5ed8a6358d2d74f553bde2e66f2e50cfba1d
Reviewed-on: https://code-review.googlesource.com/c/re2/+/62890
Reviewed-by: Alex Chernyakhovsky <achernya@google.com>
Reviewed-by: Paul Wankadia <junyer@google.com>
diff --git a/python/_re2.cc b/python/_re2.cc
index 8564f8a..07e33ce 100644
--- a/python/_re2.cc
+++ b/python/_re2.cc
@@ -219,6 +219,10 @@
   }
 
   std::vector<int> Match(py::buffer buffer, bool potential) const {
+    if (set_ == nullptr) {
+      py::pybind11_fail("Match() called before compiling");
+    }
+
     auto bytes = buffer.request();
     auto text = FromBytes(bytes);
     std::vector<int> atoms;
@@ -243,6 +247,9 @@
 };
 
 PYBIND11_MODULE(_re2, module) {
+  // Translate exceptions thrown by py::pybind11_fail() into Python.
+  py::register_local_exception<std::runtime_error>(module, "Error");
+
   module.def("CharLenToBytes", &CharLenToBytes);
   module.def("BytesToCharLen", &BytesToCharLen);
 
diff --git a/python/re2.py b/python/re2.py
index 8a6d985..d5023e7 100644
--- a/python/re2.py
+++ b/python/re2.py
@@ -33,8 +33,9 @@
 import _re2
 
 
-class error(Exception):
-  pass
+# pybind11 translates C++ exceptions to Python exceptions.
+# We use that same Python exception class for consistency.
+error = _re2.Error
 
 
 class Options(_re2.RE2.Options):
diff --git a/python/re2_test.py b/python/re2_test.py
index 86aa9ae..df1a9eb 100644
--- a/python/re2_test.py
+++ b/python/re2_test.py
@@ -477,6 +477,13 @@
     # Verify whether the underlying RE2 object is usable.
     self.assertEqual(0, f.re(2).groups)
 
+  def test_issue_484(self):
+    # Previously, the shim would dereference a null pointer and crash.
+    f = re2.Filter()
+    with self.assertRaisesRegex(re2.error,
+                                r'Match\(\) called before compiling'):
+      f.Match('')
+
 
 if __name__ == '__main__':
   absltest.main()