diff --git mlibc-clean/options/ansi/generic/stdio.cpp mlibc-workdir/options/ansi/generic/stdio.cpp index 070168f..7f20cb2 100644 --- mlibc-clean/options/ansi/generic/stdio.cpp +++ mlibc-workdir/options/ansi/generic/stdio.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -379,6 +380,20 @@ static void store_int(void *dest, unsigned int size, unsigned long long i) { } } +static void store_float(void *dest, unsigned int size, long double f) { + switch(size) { + case SCANF_TYPE_LL: + *(long double *)dest = f; + break; + case SCANF_TYPE_L: + *(double *)dest = f; + break; + default: + *(float *)dest = f; + break; + } +} + template static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) { #define NOMATCH_CHECK(cond) ({ if(cond) return match_count; }) // if cond is true, matching error @@ -521,6 +536,141 @@ static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) { } switch (*fmt) { + case 'a': + case 'A': + case 'E': + case 'e': + case 'G': + case 'g': + case 'F': + case 'f': { + bool is_negative = false; + long double divisor = 10; + long double result = 0; + int count = 0; + bool dot = false; + char c = handler.look_ahead(); + EOF_CHECK(c == '\0'); + + if((c == '-')) { + handler.consume(); + is_negative = true; + c = handler.look_ahead(); + } + + if((c == '+')) { + handler.consume(); + c = handler.look_ahead(); + } + + // nan? + if(tolower(c) == 'n') { + handler.consume(); + c = handler.look_ahead(); + if(tolower(c) != 'a') + return match_count; + + handler.consume(); + c = handler.look_ahead(); + if(tolower(c) != 'n') + return match_count; + + handler.consume(); + if(dest) + store_float(dest, type, NAN); + + continue; + } + + // inf? + if(tolower(c) == 'i') { + handler.consume(); + c = handler.look_ahead(); + size_t i; + for(i = 0; i < strlen("nfinity"); ++i) { + if (tolower(c) != "nfinity"[i]) + break; + handler.consume(); + c = handler.look_ahead(); + } + + NOMATCH_CHECK(i != 2 && i != 8); + + if(dest) + store_float(dest, type, is_negative ? -INFINITY : INFINITY); + + continue; + } + + // check if hexadecimal + if (c == '0') { + handler.consume(); + c = handler.look_ahead(); + if (tolower(c) == 'x') { + mlibc::infoLogger() << "mlibc: no support for hexadecimal floats on scanf" << frg::endlog; + return match_count; + } + + ++count; + } + + while(isdigit(c) || (dot == false && c == '.')) { + handler.consume(); + if(c == '.') { + dot = true; + c = handler.look_ahead(); + continue; + } + + long double character_value = c - '0'; + + if(dot) { + result = result + character_value / divisor; + divisor *= 10; + } else { + result = result * 10 + character_value; + } + + ++count; + c = handler.look_ahead(); + } + + NOMATCH_CHECK(count == 0); + + result = is_negative ? -result : result; + + // check for scientific notation + if (tolower(c) == 'e') { + handler.consume(); + c = handler.look_ahead(); + bool negative_exponent = false; + if(c == '+') { + handler.consume(); + c = handler.look_ahead(); + } + + if(c == '-') { + negative_exponent = true; + handler.consume(); + c = handler.look_ahead(); + } + + int exponent = 0; + + while(isdigit(c)) { + handler.consume(); + int value = c - '0'; + exponent = exponent * 10 + value; + c = handler.look_ahead(); + } + + result = result * powl(10, negative_exponent ? -exponent : exponent); + } + + if (dest) + store_float(dest, type, result); + break; + } case 'd': case 'u': base = 10; @@ -787,21 +937,24 @@ static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) { } for (; *fmt != ']'; fmt++) { + auto fmt_unsigned = reinterpret_cast(fmt); + if (!*fmt) return EOF; if (*fmt == '-' && *fmt != ']') { fmt++; - for (char c = *(fmt - 2); c < *fmt; c++) + fmt_unsigned++; + for (unsigned char c = *(fmt_unsigned - 2); c < *fmt_unsigned; c++) scanset[1 + c] = 1 - invert; } - scanset[1 + *fmt] = 1 - invert; + scanset[1 + *fmt_unsigned] = 1 - invert; } char c = handler.look_ahead(); EOF_CHECK(c == '\0'); while (c && (!width || count < width)) { - handler.consume(); if (!scanset[1 + c]) break; + handler.consume(); if(type == SCANF_TYPE_L) append_to_wbuffer(c); diff --git mlibc-clean/options/glibc/generic/execinfo.cpp mlibc-workdir/options/glibc/generic/execinfo.cpp index 119574e..f9f1cde 100644 --- mlibc-clean/options/glibc/generic/execinfo.cpp +++ mlibc-workdir/options/glibc/generic/execinfo.cpp @@ -7,6 +7,7 @@ #include #include +#include namespace { @@ -52,33 +53,15 @@ _Unwind_Reason_Code trace(_Unwind_Context *context, void *arg) { } // namespace int backtrace(void **buffer, int size) { - if (size <= 0) - return 0; - - if (!libgccHandle) { - libgccHandle = dlopen("libgcc_s.so.1", RTLD_LAZY | RTLD_LOCAL); - if (!libgccHandle || libgccHandle.value() == nullptr) { - mlibc::infoLogger() << "Failed to load libgcc_s.so.1: " << (dlerror() ? dlerror() : "") << frg::endlog; - return 0; - } - - unwindBacktrace = reinterpret_cast(dlsym(libgccHandle.value(), "_Unwind_Backtrace")); - unwindGetIP = reinterpret_cast(dlsym(libgccHandle.value(), "_Unwind_GetIP")); - - if (!unwindBacktrace || !unwindGetIP) { - mlibc::infoLogger() << "Failed to find unwind functions in libgcc_s.so.1: " << dlerror() << frg::endlog; - return 0; - } - } - - UnwindState state{buffer, size}; - unwindBacktrace(trace, &state); - return state.current_frame; + mlibc::infoLogger() << "mlibc: backtrace() is a stub!" << frg::endlog; + errno = ENOSYS; + return -1; } char **backtrace_symbols(void *const *, int) { - __ensure(!"Not implemented"); - __builtin_unreachable(); + mlibc::infoLogger() << "mlibc: backtrace() is a stub!" << frg::endlog; + errno = ENOSYS; + return NULL; } void backtrace_symbols_fd(void *const *buffer, int size, int fd) { diff --git mlibc-clean/options/internal/include/bits/null.h mlibc-workdir/options/internal/include/bits/null.h index 176008f..4fddf21 100644 --- mlibc-clean/options/internal/include/bits/null.h +++ mlibc-workdir/options/internal/include/bits/null.h @@ -9,7 +9,7 @@ #ifndef __cplusplus # define NULL ((void *)0) #else -# define NULL 0 +# define NULL 0L #endif #endif /* MLIBC_NULL_H */ diff --git mlibc-clean/options/posix/generic/lookup.cpp mlibc-workdir/options/posix/generic/lookup.cpp index c2da918..823d85a 100644 --- mlibc-clean/options/posix/generic/lookup.cpp +++ mlibc-workdir/options/posix/generic/lookup.cpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace mlibc { @@ -116,21 +117,41 @@ int lookup_name_dns(struct lookup_result &buf, const char *name, (struct sockaddr*)&sin, sizeof(sin)); if (sent != request.size()) { mlibc::infoLogger() << "lookup_name_dns(): sendto() failed to send everything" << frg::endlog; + close(fd); return -EAI_SYSTEM; } char response[256]; - ssize_t rlen; int num_ans = 0; - while ((rlen = recvfrom(fd, response, 256, 0, nullptr, nullptr)) >= 0) { + int fds_ready; + + struct pollfd pollfd; + pollfd.fd = fd; + pollfd.events = POLLIN; + + // default timeout is 5 seconds + // TODO resolv.conf can specify a timeout and we ignore it currently. + while ((fds_ready = poll(&pollfd, 1, 5000)) > 0) { + ssize_t rlen = recvfrom(fd, response, 256, 0, nullptr, nullptr); + if (rlen < 0) { + mlibc::infoLogger() << "lookup_name_dns(): recvfrom() failed" << frg::endlog; + close(fd); + return -EAI_SYSTEM; + } + if ((size_t)rlen < sizeof(struct dns_header)) continue; + auto response_header = reinterpret_cast(response); - if (response_header->identification != header.identification) + if (response_header->identification != header.identification) { + close(fd); return -EAI_FAIL; + } - if ((ntohs(response_header->flags) & 0xF) == RETURN_NXDOMAIN) + if ((ntohs(response_header->flags) & 0xF) == RETURN_NXDOMAIN) { + close (fd); return -EAI_NONAME; + } auto it = response + sizeof(struct dns_header); for (int i = 0; i < ntohs(response_header->no_q); i++) { @@ -187,6 +208,10 @@ int lookup_name_dns(struct lookup_result &buf, const char *name, } close(fd); + + if (fds_ready == 0) + return -EAI_AGAIN; + return buf.buf.size(); } @@ -265,18 +290,36 @@ int lookup_addr_dns(frg::span name, frg::array &addr, int fam (struct sockaddr*)&sin, sizeof(sin)); if (sent != request.size()) { mlibc::infoLogger() << "lookup_name_dns(): sendto() failed to send everything" << frg::endlog; + close(fd); return -EAI_SYSTEM; } char response[256]; - ssize_t rlen; int num_ans = 0; - while ((rlen = recvfrom(fd, response, 256, 0, nullptr, nullptr)) >= 0) { + int fds_ready; + + struct pollfd pollfd; + pollfd.fd = fd; + pollfd.events = POLLIN; + + // default timeout is 5 seconds + // TODO resolv.conf can specify a timeout and we ignore it currently. + while ((fds_ready = poll(&pollfd, 1, 5000)) > 0) { + ssize_t rlen = recvfrom(fd, response, 256, 0, nullptr, nullptr); + if (rlen < 0) { + mlibc::infoLogger() << "lookup_name_dns(): recvfrom() failed" << frg::endlog; + close(fd); + return -EAI_SYSTEM; + } + if ((size_t)rlen < sizeof(struct dns_header)) continue; + auto response_header = reinterpret_cast(response); - if (response_header->identification != header.identification) + if (response_header->identification != header.identification) { + close(fd); return -EAI_FAIL; + } auto it = response + sizeof(struct dns_header); for (int i = 0; i < ntohs(response_header->no_q); i++) { @@ -300,6 +343,7 @@ int lookup_addr_dns(frg::span name, frg::array &addr, int fam switch (rr_type) { case RECORD_PTR: { + close(fd); auto ptr_name = read_dns_name(response, it); if (ptr_name.size() >= name.size()) return -EAI_OVERFLOW; diff --git mlibc-clean/options/posix/generic/search.cpp mlibc-workdir/options/posix/generic/search.cpp index 5c57cf8..cb2d97f 100644 --- mlibc-clean/options/posix/generic/search.cpp +++ mlibc-workdir/options/posix/generic/search.cpp @@ -53,7 +53,7 @@ namespace { struct node *node = *nodep; int height_a = height(static_cast(node->a[0])); int height_b = height(static_cast(node->a[1])); - if (height_a - height_b < 2) { + if (abs(height_a - height_b) < 2) { int old = node->h; node->h = height_a < height_b ? height_b + 1 : height_a + 1; return node->h - old; @@ -96,7 +96,7 @@ void *tsearch(const void *key, void **rootp, int(*compar)(const void *, const vo // This implementation is taken from musl void *tfind(const void *key, void *const *rootp, int (*compar)(const void *, const void *)) { - if(!rootp) + if(!*rootp) return nullptr; struct node *n = (struct node *)*rootp; @@ -111,16 +111,136 @@ void *tfind(const void *key, void *const *rootp, int (*compar)(const void *, con return n; } -void *tdelete(const void *, void **, int(*compar)(const void *, const void *)) { - (void)compar; - __ensure(!"Not implemented"); - __builtin_unreachable(); +void *tdelete(const void *key, void **rootp, int(*compar)(const void *, const void *)) { + if (!*rootp) + return nullptr; + + struct node *node_parent = nullptr; + struct node *n = static_cast(*rootp); + frg::stack nodes(getAllocator()); + nodes.push(reinterpret_cast(rootp)); + int c = 0; + for (;;) { + if (!n) + break; + c = compar(key, n->key); + if (!c) + break; + + nodes.push(reinterpret_cast(&n->a[c > 0])); + node_parent = n; + n = static_cast(n->a[c > 0]); + } + + if (!n) + return nullptr; + + int child_count = 0; + if (n->a[0]) + ++child_count; + if (n->a[1]) + ++child_count; + + struct node **nodep = nodes.top(); + + // 3 cases: + // - no children, remove node + // - one child, replace node with it + // - two children, the predecessor replaces the node and balance up from the parent of the predecessor + switch (child_count) { + case 0: + nodes.pop(); + *nodep = nullptr; + break; + case 1: + *nodep = static_cast(n->a[0] ? n->a[0] : n->a[1]); + break; + case 2: { + struct node *pred_parent = n; + struct node *predecessor = static_cast(n->a[0]); + + while (predecessor->a[1]) { + pred_parent = predecessor; + predecessor = static_cast(predecessor->a[1]); + nodes.push(reinterpret_cast(&pred_parent->a[1])); + } + + // predecessor can only have a left child + if (pred_parent == n) { + // special case, predecessor is a direct child (left) of node + // set right child to the deleted node's right child + predecessor->a[1] = n->a[1]; + } else { + // the predecessor will always be a right child + // replace the predecessor's place with its left child (if any) + pred_parent->a[1] = predecessor->a[0]; + predecessor->a[0] = static_cast(n->a[0]); + predecessor->a[1] = static_cast(n->a[1]); + nodes.pop(); + } + *nodep = predecessor; + break; + } + } + + free(static_cast(n)); + + // go up balancing the tree + while (!nodes.empty() && balance_tree(nodes.top())) + nodes.pop(); + + // NOTE: this WILL return a dangling pointer. this is expected behaviour (see glibc's manual page) + return node_parent ? node_parent : n; } -void twalk(const void *, void (*action)(const void *, VISIT, int)) { - (void)action; - __ensure(!"Not implemented"); - __builtin_unreachable(); +void twalk(const void *root, void (*action)(const void *, VISIT, int)) { + if (!root) + return; + + struct walk_node { + const struct node *node; + VISIT v; + }; + int depth = 0; + const struct node *node = static_cast(root); + frg::stack nodes(getAllocator()); + + struct walk_node wn = {node, VISIT::preorder}; + nodes.push(wn); + + while(!nodes.empty()) { + wn = nodes.top(); + nodes.pop(); + + if (!wn.node->a[0] && !wn.node->a[1]) + wn.v = VISIT::leaf; + + action(wn.node, wn.v, depth); + + struct node *next_child = nullptr; + switch (wn.v) { + case VISIT::endorder: + case VISIT::leaf: + --depth; + break; + case VISIT::preorder: + next_child = static_cast(wn.node->a[0]); + wn.v = VISIT::postorder; + nodes.push(wn); + break; + case VISIT::postorder: + next_child = static_cast(wn.node->a[1]); + wn.v = VISIT::endorder; + nodes.push(wn); + break; + } + + if (next_child) { + ++depth; + struct walk_node tmp = {next_child, VISIT::preorder}; + nodes.push(tmp); + } + } } void tdestroy(void *root, void (*free_node)(void *)) { diff --git mlibc-clean/options/rtld/generic/main.cpp mlibc-workdir/options/rtld/generic/main.cpp index b2db152..e6438fe 100644 --- mlibc-clean/options/rtld/generic/main.cpp +++ mlibc-workdir/options/rtld/generic/main.cpp @@ -681,6 +681,9 @@ void *__dlapi_open(const char *file, int flags, void *returnAddress) { } } + if (isGlobal) + object->localScope = globalScope.get(); + Loader linker{object->localScope, nullptr, false, rts}; linker.linkObjects(object); linker.initObjects(initialRepository.get()); diff --git mlibc-clean/sysdeps/astral/generic/generic.cpp mlibc-workdir/sysdeps/astral/generic/generic.cpp index be7ad9e..80cc8d9 100644 --- mlibc-clean/sysdeps/astral/generic/generic.cpp +++ mlibc-workdir/sysdeps/astral/generic/generic.cpp @@ -47,6 +47,25 @@ namespace mlibc { return 0; } + int sys_readv(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_read) { + long r; + int error = syscall(SYSCALL_READV, &r, fd, (uint64_t)iovs, iovc); + *bytes_read = r; + return error; + } + + int sys_writev(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_written) { + long r; + int error = syscall(SYSCALL_WRITEV, &r, fd, (uint64_t)iovs, iovc); + *bytes_written = r; + return error; + } + + int sys_sysinfo(struct sysinfo *info) { + long r; + return syscall(SYSCALL_SYSINFO, &r, (uint64_t)info); + } + int sys_getcpu(int *cpu) { long ret; // can never fail diff --git mlibc-clean/sysdeps/astral/include/astral/syscall.h mlibc-workdir/sysdeps/astral/include/astral/syscall.h index 8414286..a6c4067 100644 --- mlibc-clean/sysdeps/astral/include/astral/syscall.h +++ mlibc-workdir/sysdeps/astral/include/astral/syscall.h @@ -100,6 +100,9 @@ #define SYSCALL_NICE 93 #define SYSCALL_FLOCK 94 #define SYSCALL_GETCPU 95 +#define SYSCALL_SYSINFO 96 +#define SYSCALL_WRITEV 97 +#define SYSCALL_READV 98 #ifndef __MLIBC_ABI_ONLY