LIEF manages errors using:
Exceptions (deprecated and removed since LIEF 0.13.0)
It turns out that using C++ exceptions (and RTTI) was not the best design choice, as LIEF, as a library, can be used in a -fno-exceptions context. Consequently, we moved to a mechanism based on the ResultOrError idiom. This idiom is similar to those found in LLVM with llvm::ErrorOr and in Rust with std::result. LIEF uses a std::expected-like interface to handle errors. Since this interface is only available in C++23, we rely on TartanLlama/expected, which provides this interface for C++11/C++17.
Functions using this idiom return a LIEF::result, which wraps either the successful result or an error.
The user can process this result as follows:
result<PE_TYPE> pe_type = PE::get_type("/tmp/NotPE.elf")
if (pe_type) {
PE_TYPE effective_type = pe_type.value();
} else {
lief_errors err = as_lief_err(pe_type);
}
In the case of Python, we leverage the dynamic features of the language to return either the expected value or an error if the function fails. For instance, in previous versions of lief.PE.get_type(), the implementation raised an exception to inform the user:
try:
pe_type = lief.PE.get_type("/tmp/NotPE.elf")
# If it does not fail, pe_type handles a lief.PE.PE_TYPE object
except Exception as e:
print(f"Error: {e}")
With the new implementation that relies on the ResultOrError idiom, the function returns the lief.PE.PE_TYPE value if everything is correct, and returns a lief.lief_errors in case of a processing error.
The user can handle this new interface by using the isinstance() function or by comparing the value with a lief.lief_errors attribute:
pe_type = lief.PE.get_type("/tmp/NotPE.elf")
if pe_type == lief.lief_errors.file_error:
print("File error")
elif isinstance(pe_type, lief.lief_errors):
print("Another kind of error")
else:
print("No error, type is: {}".format(pe_type))
Wrapper that contains an Object (T) or an error.
The tl/expected implementation exposes the method value() to access the underlying object (if no error)
Typical usage is:
result<int> intval = my_function();
if (intval) {
int val = intval.value();
} else { // There is an error
std::cout << get_error(intval).message() << "\n";
}
See https://tl.tartanllama.xyz/en/latest/api/expected.html for more details
Subclassed by LIEF::optional< T >
Return the lief_errors when the provided result<T> is an error.
LIEF error codes definition.
Values:
Opaque structure that is used by LIEF to avoid writing result<void> f(...). Instead, it makes the output explicit such as:
ok_error_t process() {
if (fail) {
return make_error_code(...);
}
return ok();
}
Return success for function with return type ok_error_t.
Opaque structure used by ok_error_t.
Bases: Enum
Enum class which represents an error generated by LIEF’s functions
Bases: object
Opaque value returned when a void function is executed successfully.
Bases: object
Return either: ok_t (success) or lief_errors (error)