Handle binary path detection errors on non-/proc platforms

On FreeBSD and NetBSD, sysctl() can return -1 when the path is too long,
leaving the buffer unitialised.

On macOS, both _NSGetExecutablePath() and realpath() can fail with
pathological paths or if memory is exhausted.

On Haiku, the kak_assert(status == B_OK) check will be compiled out in
non-debug builds.

Detect all of these cases and error out, reshaping get_kak_binary_path()
to avoid multiple repetitions of the same fatal error message.
This commit is contained in:
Chris Webb 2024-05-12 12:12:58 +01:00 committed by Maxime Coste
parent 97a5d68adf
commit 4e5631daf3

View File

@ -634,10 +634,10 @@ String get_kak_binary_path()
char buffer[2048]; char buffer[2048];
#if defined(__linux__) or defined(__CYGWIN__) or defined(__gnu_hurd__) #if defined(__linux__) or defined(__CYGWIN__) or defined(__gnu_hurd__)
ssize_t res = readlink("/proc/self/exe", buffer, 2048); ssize_t res = readlink("/proc/self/exe", buffer, 2048);
if (res == -1 || res >= 2048) if (res != -1 && res < 2048) {
throw runtime_error("unable to get the executable path"); buffer[res] = '\0';
buffer[res] = '\0'; return buffer;
return buffer; }
#elif defined(__FreeBSD__) or defined(__NetBSD__) #elif defined(__FreeBSD__) or defined(__NetBSD__)
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
@ -645,40 +645,44 @@ String get_kak_binary_path()
int mib[] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME}; int mib[] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME};
#endif #endif
size_t res = sizeof(buffer); size_t res = sizeof(buffer);
sysctl(mib, 4, buffer, &res, NULL, 0); if (sysctl(mib, 4, buffer, &res, NULL, 0) != -1)
return buffer; return buffer;
#elif defined(__APPLE__) #elif defined(__APPLE__)
uint32_t bufsize = 2048; uint32_t bufsize = 2048;
_NSGetExecutablePath(buffer, &bufsize); char* canonical_path = NULL;
char* canonical_path = realpath(buffer, nullptr); if (_NSGetExecutablePath(buffer, &bufsize) != -1)
String path = canonical_path; canonical_path = realpath(buffer, nullptr);
free(canonical_path); if (canonical_path) {
return path; String path = canonical_path;
free(canonical_path);
return path;
}
#elif defined(__HAIKU__) #elif defined(__HAIKU__)
BApplication app("application/x-vnd.kakoune"); BApplication app("application/x-vnd.kakoune");
app_info info; app_info info;
status_t status = app.GetAppInfo(&info); if (app.GetAppInfo(&info) == B_OK) {
kak_assert(status == B_OK); BPath path(&info.ref);
BPath path(&info.ref); return path.Path();
return path.Path(); }
#elif defined(__DragonFly__) #elif defined(__DragonFly__)
ssize_t res = readlink("/proc/curproc/file", buffer, 2048); ssize_t res = readlink("/proc/curproc/file", buffer, 2048);
if (res == -1 || res >= 2048) if (res != -1 && res < 2048) {
throw runtime_error("unable to get the executable path"); buffer[res] = '\0';
buffer[res] = '\0'; return buffer;
return buffer; }
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__)
(void)buffer; (void)buffer;
return KAK_BIN_PATH; return KAK_BIN_PATH;
#elif defined(__sun__) #elif defined(__sun__)
ssize_t res = readlink("/proc/self/path/a.out", buffer, 2048); ssize_t res = readlink("/proc/self/path/a.out", buffer, 2048);
if (res == -1 || res >= 2048) if (res != -1 && res < 2048) {
throw runtime_error("unable to get the executable path"); buffer[res] = '\0';
buffer[res] = '\0'; return buffer;
return buffer; }
#else #else
# error "finding executable path is not implemented on this platform" # error "finding executable path is not implemented on this platform"
#endif #endif
throw runtime_error("unable to get the executable path");
} }
} }