Skip to content

Commit 104b249

Browse files
committed
[lldb] Change the implementation of Status to store an llvm::Error (NFC) (#106774)
(based on a conversation I had with @labath yesterday in #106442) Most APIs that currently vend a Status would be better served by returning llvm::Expected<> instead. If possibles APIs should be refactored to avoid Status. The only legitimate long-term uses of Status are objects that need to store an error for a long time (which should be questioned as a design decision, too). This patch makes the transition to llvm::Error easier by making the places that cannot switch to llvm::Error explicit: They are marked with a call to Status::clone(). Every other API can and should be refactored to use llvm::Expected. In the end Status should only be used in very few places. Whenever an unchecked Error is dropped by Status it logs this to the verbose API channel. Implementation notes: This patch introduces two new kinds of error_category as well as new llvm::Error types. Here is the mapping of lldb::ErrorType to llvm::Errors: ``` (eErrorTypeInvalid) eErrorTypeGeneric llvm::StringError eErrorTypePOSIX llvm::ECError eErrorTypeMachKernel MachKernelError eErrorTypeExpression llvm::ErrorList<ExpressionError> eErrorTypeWin32 Win32Error ``` Relanding with built-in cloning support for llvm::ECError.
1 parent 1f8a328 commit 104b249

File tree

4 files changed

+269
-103
lines changed

4 files changed

+269
-103
lines changed

lldb/include/lldb/Utility/Status.h

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,67 @@ namespace lldb_private {
2828

2929
const char *ExpressionResultAsCString(lldb::ExpressionResults result);
3030

31+
/// Going a bit against the spirit of llvm::Error,
32+
/// lldb_private::Status need to store errors long-term and sometimes
33+
/// copy them. This base class defines an interface for this
34+
/// operation.
35+
class CloneableError
36+
: public llvm::ErrorInfo<CloneableError, llvm::ErrorInfoBase> {
37+
public:
38+
using llvm::ErrorInfo<CloneableError, llvm::ErrorInfoBase>::ErrorInfo;
39+
CloneableError() : ErrorInfo() {}
40+
virtual std::unique_ptr<CloneableError> Clone() const = 0;
41+
static char ID;
42+
};
43+
44+
/// Common base class for all error-code errors.
45+
class CloneableECError
46+
: public llvm::ErrorInfo<CloneableECError, CloneableError> {
47+
public:
48+
using llvm::ErrorInfo<CloneableECError, CloneableError>::ErrorInfo;
49+
std::error_code convertToErrorCode() const override { return EC; }
50+
void log(llvm::raw_ostream &OS) const override { OS << EC.message(); }
51+
static char ID;
52+
53+
protected:
54+
CloneableECError() = delete;
55+
CloneableECError(std::error_code ec) : ErrorInfo(), EC(ec) {}
56+
std::error_code EC;
57+
};
58+
/// FIXME: Move these declarations closer to where they're used.
59+
class MachKernelError
60+
: public llvm::ErrorInfo<MachKernelError, CloneableECError> {
61+
public:
62+
using llvm::ErrorInfo<MachKernelError, CloneableECError>::ErrorInfo;
63+
MachKernelError(std::error_code ec) : ErrorInfo(ec) {}
64+
std::string message() const override;
65+
std::unique_ptr<CloneableError> Clone() const override;
66+
static char ID;
67+
};
68+
69+
class Win32Error : public llvm::ErrorInfo<Win32Error, CloneableECError> {
70+
public:
71+
using llvm::ErrorInfo<Win32Error, CloneableECError>::ErrorInfo;
72+
Win32Error(std::error_code ec, const llvm::Twine &msg = {}) : ErrorInfo(ec) {}
73+
std::string message() const override;
74+
std::unique_ptr<CloneableError> Clone() const override;
75+
static char ID;
76+
};
77+
78+
class ExpressionError
79+
: public llvm::ErrorInfo<ExpressionError, CloneableECError> {
80+
public:
81+
using llvm::ErrorInfo<ExpressionError, CloneableECError>::ErrorInfo;
82+
ExpressionError(std::error_code ec, std::string msg = {})
83+
: ErrorInfo(ec), m_string(msg) {}
84+
std::unique_ptr<CloneableError> Clone() const override;
85+
std::string message() const override { return m_string; }
86+
static char ID;
87+
88+
protected:
89+
std::string m_string;
90+
};
91+
3192
/// \class Status Status.h "lldb/Utility/Status.h" An error handling class.
3293
///
3394
/// This class is designed to be able to hold any error code that can be
@@ -100,9 +161,7 @@ class Status {
100161
}
101162

102163
static Status FromExpressionError(lldb::ExpressionResults result,
103-
std::string msg) {
104-
return Status(result, lldb::eErrorTypeExpression, msg);
105-
}
164+
std::string msg);
106165

107166
/// Set the current error to errno.
108167
///
@@ -115,6 +174,7 @@ class Status {
115174
const Status &operator=(Status &&);
116175
/// Avoid using this in new code. Migrate APIs to llvm::Expected instead.
117176
static Status FromError(llvm::Error error);
177+
118178
/// FIXME: Replace this with a takeError() method.
119179
llvm::Error ToError() const;
120180
/// Don't call this function in new code. Instead, redesign the API
@@ -149,12 +209,20 @@ class Status {
149209

150210
/// Access the error value.
151211
///
212+
/// If the internally stored \ref llvm::Error is an \ref
213+
/// llvm::ErrorList then this returns the error value of the first
214+
/// error.
215+
///
152216
/// \return
153217
/// The error value.
154218
ValueType GetError() const;
155219

156220
/// Access the error type.
157221
///
222+
/// If the internally stored \ref llvm::Error is an \ref
223+
/// llvm::ErrorList then this returns the error value of the first
224+
/// error.
225+
///
158226
/// \return
159227
/// The error type enumeration value.
160228
lldb::ErrorType GetType() const;
@@ -170,12 +238,9 @@ class Status {
170238
bool Success() const;
171239

172240
protected:
173-
Status(llvm::Error error);
174-
/// Status code as an integer value.
175-
ValueType m_code = 0;
176-
/// The type of the above error code.
177-
lldb::ErrorType m_type = lldb::eErrorTypeInvalid;
178-
/// A string representation of the error code.
241+
Status(llvm::Error error) : m_error(std::move(error)) {}
242+
llvm::Error m_error;
243+
/// TODO: Replace this with just calling toString(m_error).
179244
mutable std::string m_string;
180245
};
181246

lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,9 +1108,10 @@ template <typename Base> class OwnedPythonFile : public Base {
11081108
py_error = Status::FromError(r.takeError());
11091109
}
11101110
base_error = Base::Close();
1111+
// Cloning since the wrapped exception may still reference the PyThread.
11111112
if (py_error.Fail())
1112-
return py_error;
1113-
return base_error;
1113+
return py_error.Clone();
1114+
return base_error.Clone();
11141115
};
11151116

11161117
PyObject *GetPythonObject() const {
@@ -1196,15 +1197,17 @@ class PythonIOFile : public OwnedPythonFile<File> {
11961197
return Flush();
11971198
auto r = m_py_obj.CallMethod("close");
11981199
if (!r)
1199-
return Status::FromError(r.takeError());
1200+
// Cloning since the wrapped exception may still reference the PyThread.
1201+
return Status::FromError(r.takeError()).Clone();
12001202
return Status();
12011203
}
12021204

12031205
Status Flush() override {
12041206
GIL takeGIL;
12051207
auto r = m_py_obj.CallMethod("flush");
12061208
if (!r)
1207-
return Status::FromError(r.takeError());
1209+
// Cloning since the wrapped exception may still reference the PyThread.
1210+
return Status::FromError(r.takeError()).Clone();
12081211
return Status();
12091212
}
12101213

@@ -1240,7 +1243,8 @@ class BinaryPythonFile : public PythonIOFile {
12401243
PyObject *pybuffer_p = PyMemoryView_FromMemory(
12411244
const_cast<char *>((const char *)buf), num_bytes, PyBUF_READ);
12421245
if (!pybuffer_p)
1243-
return Status::FromError(llvm::make_error<PythonException>());
1246+
// Cloning since the wrapped exception may still reference the PyThread.
1247+
return Status::FromError(llvm::make_error<PythonException>()).Clone();
12441248
auto pybuffer = Take<PythonObject>(pybuffer_p);
12451249
num_bytes = 0;
12461250
auto bytes_written = As<long long>(m_py_obj.CallMethod("write", pybuffer));
@@ -1260,7 +1264,8 @@ class BinaryPythonFile : public PythonIOFile {
12601264
auto pybuffer_obj =
12611265
m_py_obj.CallMethod("read", (unsigned long long)num_bytes);
12621266
if (!pybuffer_obj)
1263-
return Status::FromError(pybuffer_obj.takeError());
1267+
// Cloning since the wrapped exception may still reference the PyThread.
1268+
return Status::FromError(pybuffer_obj.takeError()).Clone();
12641269
num_bytes = 0;
12651270
if (pybuffer_obj.get().IsNone()) {
12661271
// EOF
@@ -1269,7 +1274,8 @@ class BinaryPythonFile : public PythonIOFile {
12691274
}
12701275
auto pybuffer = PythonBuffer::Create(pybuffer_obj.get());
12711276
if (!pybuffer)
1272-
return Status::FromError(pybuffer.takeError());
1277+
// Cloning since the wrapped exception may still reference the PyThread.
1278+
return Status::FromError(pybuffer.takeError()).Clone();
12731279
memcpy(buf, pybuffer.get().get().buf, pybuffer.get().get().len);
12741280
num_bytes = pybuffer.get().get().len;
12751281
return Status();
@@ -1300,7 +1306,8 @@ class TextPythonFile : public PythonIOFile {
13001306
auto bytes_written =
13011307
As<long long>(m_py_obj.CallMethod("write", pystring.get()));
13021308
if (!bytes_written)
1303-
return Status::FromError(bytes_written.takeError());
1309+
// Cloning since the wrapped exception may still reference the PyThread.
1310+
return Status::FromError(bytes_written.takeError()).Clone();
13041311
if (bytes_written.get() < 0)
13051312
return Status::FromErrorString(
13061313
".write() method returned a negative number!");
@@ -1321,14 +1328,16 @@ class TextPythonFile : public PythonIOFile {
13211328
auto pystring = As<PythonString>(
13221329
m_py_obj.CallMethod("read", (unsigned long long)num_chars));
13231330
if (!pystring)
1324-
return Status::FromError(pystring.takeError());
1331+
// Cloning since the wrapped exception may still reference the PyThread.
1332+
return Status::FromError(pystring.takeError()).Clone();
13251333
if (pystring.get().IsNone()) {
13261334
// EOF
13271335
return Status();
13281336
}
13291337
auto stringref = pystring.get().AsUTF8();
13301338
if (!stringref)
1331-
return Status::FromError(stringref.takeError());
1339+
// Cloning since the wrapped exception may still reference the PyThread.
1340+
return Status::FromError(stringref.takeError()).Clone();
13321341
num_bytes = stringref.get().size();
13331342
memcpy(buf, stringref.get().begin(), num_bytes);
13341343
return Status();

0 commit comments

Comments
 (0)