Files
bun.sh/src/bun.js/bindings/ProcessBindingUV.cpp
2025-01-21 00:47:47 -08:00

620 lines
17 KiB
C++

#include "ProcessBindingUV.h"
#include "JavaScriptCore/ArrayAllocationProfile.h"
#include "JavaScriptCore/JSCJSValue.h"
#include "JavaScriptCore/ThrowScope.h"
#include "ZigGlobalObject.h"
#include "JavaScriptCore/ObjectConstructor.h"
#include "JavaScriptCore/JSMap.h"
#include "JavaScriptCore/JSMapInlines.h"
// clang-format off
#if EDOM > 0
# define UV__ERR(x) (-(x))
#else
# define UV__ERR(x) (x)
#endif
#define UV__EOF (-4095)
#define UV__UNKNOWN (-4094)
#define UV__EAI_ADDRFAMILY (-3000)
#define UV__EAI_AGAIN (-3001)
#define UV__EAI_BADFLAGS (-3002)
#define UV__EAI_CANCELED (-3003)
#define UV__EAI_FAIL (-3004)
#define UV__EAI_FAMILY (-3005)
#define UV__EAI_MEMORY (-3006)
#define UV__EAI_NODATA (-3007)
#define UV__EAI_NONAME (-3008)
#define UV__EAI_OVERFLOW (-3009)
#define UV__EAI_SERVICE (-3010)
#define UV__EAI_SOCKTYPE (-3011)
#define UV__EAI_BADHINTS (-3013)
#define UV__EAI_PROTOCOL (-3014)
/* Only map to the system errno on non-Windows platforms. It's apparently
* a fairly common practice for Windows programmers to redefine errno codes.
*/
#if defined(E2BIG) && !defined(_WIN32)
# define UV__E2BIG UV__ERR(E2BIG)
#else
# define UV__E2BIG (-4093)
#endif
#if defined(EACCES) && !defined(_WIN32)
# define UV__EACCES UV__ERR(EACCES)
#else
# define UV__EACCES (-4092)
#endif
#if defined(EADDRINUSE) && !defined(_WIN32)
# define UV__EADDRINUSE UV__ERR(EADDRINUSE)
#else
# define UV__EADDRINUSE (-4091)
#endif
#if defined(EADDRNOTAVAIL) && !defined(_WIN32)
# define UV__EADDRNOTAVAIL UV__ERR(EADDRNOTAVAIL)
#else
# define UV__EADDRNOTAVAIL (-4090)
#endif
#if defined(EAFNOSUPPORT) && !defined(_WIN32)
# define UV__EAFNOSUPPORT UV__ERR(EAFNOSUPPORT)
#else
# define UV__EAFNOSUPPORT (-4089)
#endif
#if defined(EAGAIN) && !defined(_WIN32)
# define UV__EAGAIN UV__ERR(EAGAIN)
#else
# define UV__EAGAIN (-4088)
#endif
#if defined(EALREADY) && !defined(_WIN32)
# define UV__EALREADY UV__ERR(EALREADY)
#else
# define UV__EALREADY (-4084)
#endif
#if defined(EBADF) && !defined(_WIN32)
# define UV__EBADF UV__ERR(EBADF)
#else
# define UV__EBADF (-4083)
#endif
#if defined(EBUSY) && !defined(_WIN32)
# define UV__EBUSY UV__ERR(EBUSY)
#else
# define UV__EBUSY (-4082)
#endif
#if defined(ECANCELED) && !defined(_WIN32)
# define UV__ECANCELED UV__ERR(ECANCELED)
#else
# define UV__ECANCELED (-4081)
#endif
#if defined(ECHARSET) && !defined(_WIN32)
# define UV__ECHARSET UV__ERR(ECHARSET)
#else
# define UV__ECHARSET (-4080)
#endif
#if defined(ECONNABORTED) && !defined(_WIN32)
# define UV__ECONNABORTED UV__ERR(ECONNABORTED)
#else
# define UV__ECONNABORTED (-4079)
#endif
#if defined(ECONNREFUSED) && !defined(_WIN32)
# define UV__ECONNREFUSED UV__ERR(ECONNREFUSED)
#else
# define UV__ECONNREFUSED (-4078)
#endif
#if defined(ECONNRESET) && !defined(_WIN32)
# define UV__ECONNRESET UV__ERR(ECONNRESET)
#else
# define UV__ECONNRESET (-4077)
#endif
#if defined(EDESTADDRREQ) && !defined(_WIN32)
# define UV__EDESTADDRREQ UV__ERR(EDESTADDRREQ)
#else
# define UV__EDESTADDRREQ (-4076)
#endif
#if defined(EEXIST) && !defined(_WIN32)
# define UV__EEXIST UV__ERR(EEXIST)
#else
# define UV__EEXIST (-4075)
#endif
#if defined(EFAULT) && !defined(_WIN32)
# define UV__EFAULT UV__ERR(EFAULT)
#else
# define UV__EFAULT (-4074)
#endif
#if defined(EHOSTUNREACH) && !defined(_WIN32)
# define UV__EHOSTUNREACH UV__ERR(EHOSTUNREACH)
#else
# define UV__EHOSTUNREACH (-4073)
#endif
#if defined(EINTR) && !defined(_WIN32)
# define UV__EINTR UV__ERR(EINTR)
#else
# define UV__EINTR (-4072)
#endif
#if defined(EINVAL) && !defined(_WIN32)
# define UV__EINVAL UV__ERR(EINVAL)
#else
# define UV__EINVAL (-4071)
#endif
#if defined(EIO) && !defined(_WIN32)
# define UV__EIO UV__ERR(EIO)
#else
# define UV__EIO (-4070)
#endif
#if defined(EISCONN) && !defined(_WIN32)
# define UV__EISCONN UV__ERR(EISCONN)
#else
# define UV__EISCONN (-4069)
#endif
#if defined(EISDIR) && !defined(_WIN32)
# define UV__EISDIR UV__ERR(EISDIR)
#else
# define UV__EISDIR (-4068)
#endif
#if defined(ELOOP) && !defined(_WIN32)
# define UV__ELOOP UV__ERR(ELOOP)
#else
# define UV__ELOOP (-4067)
#endif
#if defined(EMFILE) && !defined(_WIN32)
# define UV__EMFILE UV__ERR(EMFILE)
#else
# define UV__EMFILE (-4066)
#endif
#if defined(EMSGSIZE) && !defined(_WIN32)
# define UV__EMSGSIZE UV__ERR(EMSGSIZE)
#else
# define UV__EMSGSIZE (-4065)
#endif
#if defined(ENAMETOOLONG) && !defined(_WIN32)
# define UV__ENAMETOOLONG UV__ERR(ENAMETOOLONG)
#else
# define UV__ENAMETOOLONG (-4064)
#endif
#if defined(ENETDOWN) && !defined(_WIN32)
# define UV__ENETDOWN UV__ERR(ENETDOWN)
#else
# define UV__ENETDOWN (-4063)
#endif
#if defined(ENETUNREACH) && !defined(_WIN32)
# define UV__ENETUNREACH UV__ERR(ENETUNREACH)
#else
# define UV__ENETUNREACH (-4062)
#endif
#if defined(ENFILE) && !defined(_WIN32)
# define UV__ENFILE UV__ERR(ENFILE)
#else
# define UV__ENFILE (-4061)
#endif
#if defined(ENOBUFS) && !defined(_WIN32)
# define UV__ENOBUFS UV__ERR(ENOBUFS)
#else
# define UV__ENOBUFS (-4060)
#endif
#if defined(ENODEV) && !defined(_WIN32)
# define UV__ENODEV UV__ERR(ENODEV)
#else
# define UV__ENODEV (-4059)
#endif
#if defined(ENOENT) && !defined(_WIN32)
# define UV__ENOENT UV__ERR(ENOENT)
#else
# define UV__ENOENT (-4058)
#endif
#if defined(ENOMEM) && !defined(_WIN32)
# define UV__ENOMEM UV__ERR(ENOMEM)
#else
# define UV__ENOMEM (-4057)
#endif
#if defined(ENONET) && !defined(_WIN32)
# define UV__ENONET UV__ERR(ENONET)
#else
# define UV__ENONET (-4056)
#endif
#if defined(ENOSPC) && !defined(_WIN32)
# define UV__ENOSPC UV__ERR(ENOSPC)
#else
# define UV__ENOSPC (-4055)
#endif
#if defined(ENOSYS) && !defined(_WIN32)
# define UV__ENOSYS UV__ERR(ENOSYS)
#else
# define UV__ENOSYS (-4054)
#endif
#if defined(ENOTCONN) && !defined(_WIN32)
# define UV__ENOTCONN UV__ERR(ENOTCONN)
#else
# define UV__ENOTCONN (-4053)
#endif
#if defined(ENOTDIR) && !defined(_WIN32)
# define UV__ENOTDIR UV__ERR(ENOTDIR)
#else
# define UV__ENOTDIR (-4052)
#endif
#if defined(ENOTEMPTY) && !defined(_WIN32)
# define UV__ENOTEMPTY UV__ERR(ENOTEMPTY)
#else
# define UV__ENOTEMPTY (-4051)
#endif
#if defined(ENOTSOCK) && !defined(_WIN32)
# define UV__ENOTSOCK UV__ERR(ENOTSOCK)
#else
# define UV__ENOTSOCK (-4050)
#endif
#if defined(ENOTSUP) && !defined(_WIN32)
# define UV__ENOTSUP UV__ERR(ENOTSUP)
#else
# define UV__ENOTSUP (-4049)
#endif
#if defined(EPERM) && !defined(_WIN32)
# define UV__EPERM UV__ERR(EPERM)
#else
# define UV__EPERM (-4048)
#endif
#if defined(EPIPE) && !defined(_WIN32)
# define UV__EPIPE UV__ERR(EPIPE)
#else
# define UV__EPIPE (-4047)
#endif
#if defined(EPROTO) && !defined(_WIN32)
# define UV__EPROTO UV__ERR(EPROTO)
#else
# define UV__EPROTO (-4046)
#endif
#if defined(EPROTONOSUPPORT) && !defined(_WIN32)
# define UV__EPROTONOSUPPORT UV__ERR(EPROTONOSUPPORT)
#else
# define UV__EPROTONOSUPPORT (-4045)
#endif
#if defined(EPROTOTYPE) && !defined(_WIN32)
# define UV__EPROTOTYPE UV__ERR(EPROTOTYPE)
#else
# define UV__EPROTOTYPE (-4044)
#endif
#if defined(EROFS) && !defined(_WIN32)
# define UV__EROFS UV__ERR(EROFS)
#else
# define UV__EROFS (-4043)
#endif
#if defined(ESHUTDOWN) && !defined(_WIN32)
# define UV__ESHUTDOWN UV__ERR(ESHUTDOWN)
#else
# define UV__ESHUTDOWN (-4042)
#endif
#if defined(ESPIPE) && !defined(_WIN32)
# define UV__ESPIPE UV__ERR(ESPIPE)
#else
# define UV__ESPIPE (-4041)
#endif
#if defined(ESRCH) && !defined(_WIN32)
# define UV__ESRCH UV__ERR(ESRCH)
#else
# define UV__ESRCH (-4040)
#endif
#if defined(ETIMEDOUT) && !defined(_WIN32)
# define UV__ETIMEDOUT UV__ERR(ETIMEDOUT)
#else
# define UV__ETIMEDOUT (-4039)
#endif
#if defined(ETXTBSY) && !defined(_WIN32)
# define UV__ETXTBSY UV__ERR(ETXTBSY)
#else
# define UV__ETXTBSY (-4038)
#endif
#if defined(EXDEV) && !defined(_WIN32)
# define UV__EXDEV UV__ERR(EXDEV)
#else
# define UV__EXDEV (-4037)
#endif
#if defined(EFBIG) && !defined(_WIN32)
# define UV__EFBIG UV__ERR(EFBIG)
#else
# define UV__EFBIG (-4036)
#endif
#if defined(ENOPROTOOPT) && !defined(_WIN32)
# define UV__ENOPROTOOPT UV__ERR(ENOPROTOOPT)
#else
# define UV__ENOPROTOOPT (-4035)
#endif
#if defined(ERANGE) && !defined(_WIN32)
# define UV__ERANGE UV__ERR(ERANGE)
#else
# define UV__ERANGE (-4034)
#endif
#if defined(ENXIO) && !defined(_WIN32)
# define UV__ENXIO UV__ERR(ENXIO)
#else
# define UV__ENXIO (-4033)
#endif
#if defined(EMLINK) && !defined(_WIN32)
# define UV__EMLINK UV__ERR(EMLINK)
#else
# define UV__EMLINK (-4032)
#endif
/* EHOSTDOWN is not visible on BSD-like systems when _POSIX_C_SOURCE is
* defined. Fortunately, its value is always 64 so it's possible albeit
* icky to hard-code it.
*/
#if defined(EHOSTDOWN) && !defined(_WIN32)
# define UV__EHOSTDOWN UV__ERR(EHOSTDOWN)
#elif defined(__APPLE__) || \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__NetBSD__) || \
defined(__OpenBSD__)
# define UV__EHOSTDOWN (-64)
#else
# define UV__EHOSTDOWN (-4031)
#endif
#if defined(EREMOTEIO) && !defined(_WIN32)
# define UV__EREMOTEIO UV__ERR(EREMOTEIO)
#else
# define UV__EREMOTEIO (-4030)
#endif
#if defined(ENOTTY) && !defined(_WIN32)
# define UV__ENOTTY UV__ERR(ENOTTY)
#else
# define UV__ENOTTY (-4029)
#endif
#if defined(EFTYPE) && !defined(_WIN32)
# define UV__EFTYPE UV__ERR(EFTYPE)
#else
# define UV__EFTYPE (-4028)
#endif
#if defined(EILSEQ) && !defined(_WIN32)
# define UV__EILSEQ UV__ERR(EILSEQ)
#else
# define UV__EILSEQ (-4027)
#endif
#if defined(EOVERFLOW) && !defined(_WIN32)
# define UV__EOVERFLOW UV__ERR(EOVERFLOW)
#else
# define UV__EOVERFLOW (-4026)
#endif
#if defined(ESOCKTNOSUPPORT) && !defined(_WIN32)
# define UV__ESOCKTNOSUPPORT UV__ERR(ESOCKTNOSUPPORT)
#else
# define UV__ESOCKTNOSUPPORT (-4025)
#endif
/* FreeBSD defines ENODATA in /usr/include/c++/v1/errno.h which is only visible
* if C++ is being used. Define it directly to avoid problems when integrating
* libuv in a C++ project.
*/
#if defined(ENODATA) && !defined(_WIN32)
# define UV__ENODATA UV__ERR(ENODATA)
#elif defined(__FreeBSD__)
# define UV__ENODATA (-9919)
#else
# define UV__ENODATA (-4024)
#endif
#if defined(EUNATCH) && !defined(_WIN32)
# define UV__EUNATCH UV__ERR(EUNATCH)
#else
# define UV__EUNATCH (-4023)
#endif
#define BUN_UV_ERRNO_MAP(macro) \
macro(E2BIG, "argument list too long") \
macro(EACCES, "permission denied") \
macro(EADDRINUSE, "address already in use") \
macro(EADDRNOTAVAIL, "address not available") \
macro(EAFNOSUPPORT, "address family not supported") \
macro(EAGAIN, "resource temporarily unavailable") \
macro(EAI_ADDRFAMILY, "address family not supported") \
macro(EAI_AGAIN, "temporary failure") \
macro(EAI_BADFLAGS, "bad ai_flags value") \
macro(EAI_BADHINTS, "invalid value for hints") \
macro(EAI_CANCELED, "request canceled") \
macro(EAI_FAIL, "permanent failure") \
macro(EAI_FAMILY, "ai_family not supported") \
macro(EAI_MEMORY, "out of memory") \
macro(EAI_NODATA, "no address") \
macro(EAI_NONAME, "unknown node or service") \
macro(EAI_OVERFLOW, "argument buffer overflow") \
macro(EAI_PROTOCOL, "resolved protocol is unknown") \
macro(EAI_SERVICE, "service not available for socket type") \
macro(EAI_SOCKTYPE, "socket type not supported") \
macro(EALREADY, "connection already in progress") \
macro(EBADF, "bad file descriptor") \
macro(EBUSY, "resource busy or locked") \
macro(ECANCELED, "operation canceled") \
macro(ECHARSET, "invalid Unicode character") \
macro(ECONNABORTED, "software caused connection abort") \
macro(ECONNREFUSED, "connection refused") \
macro(ECONNRESET, "connection reset by peer") \
macro(EDESTADDRREQ, "destination address required") \
macro(EEXIST, "file already exists") \
macro(EFAULT, "bad address in system call argument") \
macro(EFBIG, "file too large") \
macro(EHOSTUNREACH, "host is unreachable") \
macro(EINTR, "interrupted system call") \
macro(EINVAL, "invalid argument") \
macro(EIO, "i/o error") \
macro(EISCONN, "socket is already connected") \
macro(EISDIR, "illegal operation on a directory") \
macro(ELOOP, "too many symbolic links encountered") \
macro(EMFILE, "too many open files") \
macro(EMSGSIZE, "message too long") \
macro(ENAMETOOLONG, "name too long") \
macro(ENETDOWN, "network is down") \
macro(ENETUNREACH, "network is unreachable") \
macro(ENFILE, "file table overflow") \
macro(ENOBUFS, "no buffer space available") \
macro(ENODEV, "no such device") \
macro(ENOENT, "no such file or directory") \
macro(ENOMEM, "not enough memory") \
macro(ENONET, "machine is not on the network") \
macro(ENOPROTOOPT, "protocol not available") \
macro(ENOSPC, "no space left on device") \
macro(ENOSYS, "function not implemented") \
macro(ENOTCONN, "socket is not connected") \
macro(ENOTDIR, "not a directory") \
macro(ENOTEMPTY, "directory not empty") \
macro(ENOTSOCK, "socket operation on non-socket") \
macro(ENOTSUP, "operation not supported on socket") \
macro(EOVERFLOW, "value too large for defined data type") \
macro(EPERM, "operation not permitted") \
macro(EPIPE, "broken pipe") \
macro(EPROTO, "protocol error") \
macro(EPROTONOSUPPORT, "protocol not supported") \
macro(EPROTOTYPE, "protocol wrong type for socket") \
macro(ERANGE, "result too large") \
macro(EROFS, "read-only file system") \
macro(ESHUTDOWN, "cannot send after transport endpoint shutdown") \
macro(ESPIPE, "invalid seek") \
macro(ESRCH, "no such process") \
macro(ETIMEDOUT, "connection timed out") \
macro(ETXTBSY, "text file is busy") \
macro(EXDEV, "cross-device link not permitted") \
macro(UNKNOWN, "unknown error") \
macro(EOF, "end of file") \
macro(ENXIO, "no such device or address") \
macro(EMLINK, "too many links") \
macro(EHOSTDOWN, "host is down") \
macro(EREMOTEIO, "remote I/O error") \
macro(ENOTTY, "inappropriate ioctl for device") \
macro(EFTYPE, "inappropriate file type or format") \
macro(EILSEQ, "illegal byte sequence") \
macro(ESOCKTNOSUPPORT, "socket type not supported") \
macro(ENODATA, "no data available") \
macro(EUNATCH, "protocol driver not attached")
// clang-format on
namespace Bun {
namespace ProcessBindingUV {
JSC_DEFINE_HOST_FUNCTION(jsErrname, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
auto& vm = globalObject->vm();
auto arg0 = callFrame->argument(0);
// Node.js crashes here:
// However, we should ensure this function never throws
// That's why we do not call toPrimitive here or throw on invalid input.
if (UNLIKELY(!arg0.isInt32AsAnyInt())) {
return JSValue::encode(jsString(vm, String("Unknown system error"_s)));
}
auto err = arg0.toInt32(globalObject);
#define CASE(name, desc) \
if (err == -UV__##name) return JSValue::encode(JSC::jsString(vm, String(#name##_s)));
BUN_UV_ERRNO_MAP(CASE)
#undef CASE
return JSValue::encode(jsString(vm, makeString("Unknown system error: "_s, err)));
}
JSC_DEFINE_HOST_FUNCTION(jsGetErrorMap, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
auto& vm = globalObject->vm();
auto map = JSC::JSMap::create(vm, globalObject->mapStructure());
// Inlining each of these via macros costs like 300 KB.
const auto putProperty = [](JSC::VM& vm, JSC::JSMap* map, JSC::JSGlobalObject* globalObject, ASCIILiteral name, int value, ASCIILiteral desc) -> void {
auto arr = JSC::constructEmptyArray(globalObject, static_cast<JSC::ArrayAllocationProfile*>(nullptr), 2);
arr->putDirectIndex(globalObject, 0, JSC::jsString(vm, String(name)));
arr->putDirectIndex(globalObject, 1, JSC::jsString(vm, String(desc)));
map->set(globalObject, JSC::jsNumber(value), arr);
};
#define PUT_PROPERTY(name, desc) putProperty(vm, map, globalObject, #name##_s, -UV__##name, desc##_s);
BUN_UV_ERRNO_MAP(PUT_PROPERTY)
#undef PUT_PROPERTY
return JSValue::encode(map);
}
JSObject* create(VM& vm, JSGlobalObject* globalObject)
{
auto bindingObject = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 0);
EnsureStillAliveScope ensureStillAlive(bindingObject);
bindingObject->putDirect(vm, JSC::Identifier::fromString(vm, "errname"_s), JSC::JSFunction::create(vm, globalObject, 1, "errname"_s, jsErrname, ImplementationVisibility::Public));
// Inlining each of these via macros costs like 300 KB.
// Before: 96305608
// After: 95973832
const auto putNamedProperty = [](JSC::VM& vm, JSObject* bindingObject, const ASCIILiteral name, int value) -> void {
bindingObject->putDirect(vm, JSC::Identifier::fromString(vm, name), JSC::jsNumber(value));
};
#define PUT_PROPERTY(name, desc) \
putNamedProperty(vm, bindingObject, "UV_" #name##_s, -UV__##name);
BUN_UV_ERRNO_MAP(PUT_PROPERTY)
#undef PUT_PROPERTY
bindingObject->putDirect(vm, JSC::Identifier::fromString(vm, "getErrorMap"_s), JSC::JSFunction::create(vm, globalObject, 0, "getErrorMap"_s, jsGetErrorMap, ImplementationVisibility::Public));
return bindingObject;
}
} // namespace ProcessBindingUV
} // namespace Bun