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.
}
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;
}
#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));
}
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;
}