]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
Fix getcwd(NULL, 0): allocate buffer when buf is NULL (glibc extension)
authorTulio A M Mendes <[email protected]>
Sun, 19 Apr 2026 17:55:59 +0000 (14:55 -0300)
committerTulio A M Mendes <[email protected]>
Sun, 19 Apr 2026 17:55:59 +0000 (14:55 -0300)
Bash calls getcwd(NULL, 0) — a glibc extension where NULL means
"allocate a buffer for me". Both ulibc and newlib wrappers passed
NULL straight to the kernel syscall, which returned -EFAULT because
the kernel rejects user_buf == NULL.

This caused:
  shell-init: error retrieving current directory: getcwd:
  cannot access parent directories: Bad address

Now both wrappers handle NULL buf by malloc'ing a buffer (4096 bytes
if size is 0), passing it to the kernel, and returning the allocated
pointer on success (or freeing it on error). This matches glibc
behavior and unblocks bash and other ported software.

newlib/libgloss/adros/posix_stubs.c
user/ulibc/src/unistd.c

index 75459089e26b091f5cf459af65fab5ce4363530d..c796b0b68fd335c351a2f75c650859a35a008172 100644 (file)
@@ -176,8 +176,19 @@ int chdir(const char *path) {
 }
 
 char *getcwd(char *buf, size_t size) {
+    int allocated = 0;
+    if (!buf) {
+        if (size == 0) size = 4096;
+        buf = (char *)malloc(size);
+        if (!buf) { errno = ENOMEM; return 0; }
+        allocated = 1;
+    }
     int r = _sc2(SYS_GETCWD, (int)buf, (int)size);
-    if (r < 0) { errno = -r; return 0; }
+    if (r < 0) {
+        errno = -r;
+        if (allocated) free(buf);
+        return 0;
+    }
     return buf;
 }
 
index 34c6ac94ffee7b9620eca4df29850418496725d4..6dcadb35e478182e42503204f62de6d23241d0cf 100644 (file)
@@ -11,6 +11,7 @@
 #include "syscall.h"
 #include "errno.h"
 #include "termios.h"
+#include "stdlib.h"
 
 int read(int fd, void* buf, size_t count) {
     return __syscall_ret(_syscall3(SYS_READ, fd, (int)buf, (int)count));
@@ -70,8 +71,19 @@ int chdir(const char* path) {
 }
 
 char* getcwd(char* buf, size_t size) {
+    int allocated = 0;
+    if (!buf) {
+        if (size == 0) size = 4096;
+        buf = (char*)malloc(size);
+        if (!buf) { errno = ENOMEM; return NULL; }
+        allocated = 1;
+    }
     int r = _syscall2(SYS_GETCWD, (int)buf, (int)size);
-    if (r < 0) { errno = -r; return NULL; }
+    if (r < 0) {
+        errno = -r;
+        if (allocated) free(buf);
+        return NULL;
+    }
     return buf;
 }