Make execvp work with zero allocations.
This fixes a bug when exec'ing from forked
process in a program that uses threads.
The allocator from another thread can be
holding the lock at fork, so when we fork
it's possible that there's nobody left to
unlock, and we deeadlock.
@@ -4,7 +4,6 @@ use "errno"
use "fmt"
use "option"
use "strfind"
-use "strsplit"
use "syswrap"
pkg std =
@@ -13,46 +12,56 @@ pkg std =
;;
const execvp = {cmd, args
- var paths, binpath
+ var i, j, paths, binpath
var buf : byte[512]
match strfind(cmd, "/")
| `Some _:
-> execv(cmd, args)
| `None:
- paths = getpaths()
- for p : paths
- binpath = bfmt(buf[:], "{}/{}", p, cmd)
+ i = 0
+ j = 0
+ paths = std.getenvv("PATH", "/usr/local/bin:/bin:/usr/bin")
+ while j < paths.len
+ (i, j) = nextpath(paths, j)
+ binpath = bfmt(buf[:], "{}/{}", paths[i:j], cmd)
execv(binpath, args)
;;
- slfree(paths)
;;
-> -1
}
const execvpe = {cmd, args, env
- var paths, binpath
+ var i, j, paths, binpath
var buf : byte[512]
match strfind(cmd, "/")
| `Some _:
-> execve(cmd, args, env)
| `None:
- paths = getpaths()
- for p : paths
- binpath = bfmt(buf[:], "{}/{}", p, cmd)
+ i = 0
+ j = 0
+ paths = std.getenvv("PATH", "/usr/local/bin:/bin:/usr/bin")
+ while j < paths.len
+ (i, j) = nextpath(paths, j)
+ binpath = bfmt(buf[:], "{}/{}", paths[i:j], cmd)
execve(binpath, args, env)
;;
- slfree(paths)
;;
-> -1
}
-const getpaths = {
- var path
- match getenv("PATH")
- | `Some p: path = p
- | `None: path = "/usr/local/bin:/bin:/usr/bin"
+const nextpath = {p, start
+ var i, j
+
+ i = start
+ while i < p.len && p[i] == (':' : byte)
+ i++
+ ;;
+ j = i
+ while j < p.len && p[j] != (':' : byte)
+ j++
;;
- -> strsplit(path, ":")
+ -> (i, j)
}
+
