1
0
Fork 0
mirror of https://github.com/LadybirdBrowser/ladybird.git synced 2025-06-09 09:34:57 +09:00

LibWasm/WASI+wasm: Make WASI exit() "noreturn" instead of making it exit

This makes it so exit() traps with a known error; an embedder (wasm.cpp)
can simply match this format and handle the request accordingly.
This commit is contained in:
Ali Mohammad Pur 2024-07-16 17:49:48 +02:00 committed by Andreas Kling
parent e08a7cb94d
commit 16dd8d4d3b
Notes: sideshowbarker 2024-07-18 23:45:34 +09:00
3 changed files with 41 additions and 10 deletions

View file

@ -428,9 +428,9 @@ ErrorOr<Result<EnvironSizes>> Implementation::impl$environ_sizes_get(Configurati
});
}
ErrorOr<Result<void>> Implementation::impl$proc_exit(Configuration&, ExitCode exit_code)
ErrorOr<void> Implementation::impl$proc_exit(Configuration&, ExitCode exit_code)
{
exit(exit_code);
return Error::from_errno(-static_cast<i32>(exit_code + 1));
}
ErrorOr<Result<void>> Implementation::impl$fd_close(Configuration&, FD fd)
@ -963,18 +963,37 @@ struct HostTypeImpl<T> {
using Type = UnderlyingType<T>;
};
template<typename T>
struct HostTypeImpl<LittleEndian<T>> {
using Type = typename HostTypeImpl<T>::Type;
};
template<typename T, typename t, typename... Fs>
struct HostTypeImpl<DistinctNumeric<T, t, Fs...>> {
using Type = typename HostTypeImpl<T>::Type;
};
template<typename T>
using HostType = typename HostTypeImpl<T>::Type;
template<typename T>
auto CompatibleValueType = IsOneOf<HostType<T>, i8, i16, i32, u8, u16>
auto CompatibleValueType = IsOneOf<HostType<T>, char, i8, i16, i32, u8, u16>
? Wasm::ValueType(Wasm::ValueType::I32)
: Wasm::ValueType(Wasm::ValueType::I64);
template<typename R, typename... Args, ErrorOr<Result<R>> (Implementation::*impl)(Configuration&, Args...)>
template<typename RV, typename... Args, ErrorOr<RV> (Implementation::*impl)(Configuration&, Args...)>
struct InvocationOf<impl> {
HostFunction operator()(Implementation& self, StringView function_name)
{
using R = typename decltype([] {
if constexpr (IsSame<RV, Result<void>>)
return TypeWrapper<void> {};
else if constexpr (IsSpecializationOf<RV, Result>)
return TypeWrapper<RemoveCVReference<decltype(*declval<RV>().result())>> {};
else
return TypeWrapper<RV> {};
}())::Type;
Vector<ValueType> arguments_types { CompatibleValueType<typename ABI::ToCompatibleValue<Args>::Type>... };
if constexpr (!IsVoid<R>) {
if constexpr (requires { declval<typename R::SerializationComponents>(); }) {
@ -986,6 +1005,10 @@ struct InvocationOf<impl> {
}
}
Vector<ValueType> return_ty;
if constexpr (IsSpecializationOf<RV, Result>)
return_ty.append(ValueType(ValueType::I32));
return HostFunction(
[&self, function_name](Configuration& configuration, Vector<Value>& arguments) -> Wasm::Result {
Tuple args = [&]<typename... Ts, auto... Is>(IndexSequence<Is...>) {
@ -994,12 +1017,18 @@ struct InvocationOf<impl> {
auto result = args.apply_as_args([&](auto&&... impl_args) { return (self.*impl)(configuration, impl_args...); });
dbgln_if(WASI_DEBUG, "WASI: {}({}) = {}", function_name, arguments, result);
if (result.is_error())
return Wasm::Trap { ByteString::formatted("Invalid call to {}() = {}", function_name, result.error()) };
if (result.is_error()) {
auto error = result.release_error();
if (error.is_errno())
return Wasm::Trap { ByteString::formatted("exit:{}", error.code() + 1) };
return Wasm::Trap { ByteString::formatted("Invalid call to {}() = {}", function_name, error) };
}
auto value = result.release_value();
if (value.is_error())
return Wasm::Result { Vector { Value { ValueType(ValueType::I32), static_cast<u64>(to_underlying(value.error().value())) } } };
if constexpr (IsSpecializationOf<RV, Result>) {
if (value.is_error())
return Wasm::Result { Vector { Value { ValueType(ValueType::I32), static_cast<u64>(to_underlying(value.error().value())) } } };
}
if constexpr (!IsVoid<R>) {
// Return values are passed as pointers, after the arguments
@ -1015,7 +1044,7 @@ struct InvocationOf<impl> {
},
FunctionType {
move(arguments_types),
{ ValueType(ValueType::I32) },
return_ty,
},
function_name);
}

View file

@ -884,7 +884,7 @@ private:
ErrorOr<Result<void>> impl$path_symlink(Configuration&, Pointer<u8> old_path, Size old_path_len, FD, Pointer<u8> new_path, Size new_path_len);
ErrorOr<Result<void>> impl$path_unlink_file(Configuration&, FD, Pointer<u8> path, Size path_len);
ErrorOr<Result<Size>> impl$poll_oneoff(Configuration&, ConstPointer<Subscription> in, Pointer<Event> out, Size nsubscriptions);
ErrorOr<Result<void>> impl$proc_exit(Configuration&, ExitCode); // Note: noreturn.
ErrorOr<void> impl$proc_exit(Configuration&, ExitCode);
ErrorOr<Result<void>> impl$proc_raise(Configuration&, Signal);
ErrorOr<Result<void>> impl$sched_yield(Configuration&);
ErrorOr<Result<void>> impl$random_get(Configuration&, Pointer<u8> buf, Size buf_len);

View file

@ -804,6 +804,8 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
launch_repl();
if (result.is_trap()) {
if (result.trap().reason.starts_with("exit:"sv))
return -result.trap().reason.substring_view(5).to_number<i32>().value_or(-1);
warnln("Execution trapped: {}", result.trap().reason);
} else {
if (!result.values().is_empty())