Hi, On Mon, Aug 31, 2026 at 05:43:53PM +0100, João Pedro Malhado wrote:
Dear Dillo Maintainers,
I noticed that the Dillo 3.3.0 Debian package build was failing on GNU/hurd due to the PATH_MAX macro not being defined on that platform. This is a common portability issue on the platform, and the following page indicates why the macro is not defined in GNU/hurd https://www.gnu.org/software/hurd/faq/foo_max
It was pointed out to me that commit b43ab26e81a1e399e3cb148b972a284518aa4d39 has addressed the hurd build failure already, but it does so by simply defining PATH_MAX to an arbitrary value.
Yes, it is set to 4096 if not defined. Debian thread for reference: https://lists.debian.org/debian-hurd/2026/08/msg00023.html
As per the page above, the preferred way to address the issue by allocating the size of the path dynamically.
That path will be concatenated with the PID to form the UNIX socket path that must fit into sun_path, currently holding up to 108 bytes: demo@debian:~$ uname -a GNU debian 0.9 GNU-Mach 1.8+git20260805-up-amd64/Hurd-0.9 x86_64 GNU demo@debian:~$ grep -C 3 'char sun_path' /usr/include/x86_64-gnu/sys/un.h struct __attribute_struct_may_alias__ sockaddr_un { __SOCKADDR_COMMON (sun_); char sun_path[108]; /* Path name. */ }; demo@debian:~$ cat a.c #include <sys/un.h> #include <stdio.h> int main() { struct sockaddr_un a; printf("sun_path takes %zd bytes\n", sizeof(a.sun_path)); } demo@debian:~$ gcc a.c -o a demo@debian:~$ ./a sun_path takes 108 bytes So I don't see a need for it to be longer than 4096 bytes, but let me know otherwise. Notice that asprintf() is not portable, is a GNU extension. The utility of having a compile time limit is to be able to build the ctlpath in the stack and avoid freeing the heap on errors, as you see in your 5 extra calls to free(). It is not only cleaner, but also faster: demo@debian:~$ cat b.c #define _GNU_SOURCE #include <time.h> #include <stdio.h> #include <stdlib.h> static double get_time(void) { struct timespec tv; if (clock_gettime(CLOCK_MONOTONIC, &tv) != 0) { perror("clock_gettime failed"); exit(EXIT_FAILURE); } return (double) (tv.tv_sec) + (double) tv.tv_nsec * 1.0e-9; } int main() { long nruns = 10; for (long run = 0; run < nruns; run++) { long n = 1000000; double t0 = get_time(); for (long i = 0; i < n; i++) { char path[4096]; if (snprintf(path, 4096, "foobar/%ld", i) >= 4096) { fprintf(stderr, "path too long\n"); exit(1); } } double t1 = get_time(); for (long i = 0; i < n; i++) { char *path; if (asprintf(&path, "foobar/%ld", i) < 0) { fprintf(stderr, "asprintf failed\n"); exit(1); } free(path); } double t2 = get_time(); printf("stack took %e s, asprintf took %e s\n", t1 - t0, t2 - t1); } } demo@debian:~$ gcc -O3 b.c -o b demo@debian:~$ ./b stack took 4.706729e-02 s, asprintf took 5.388443e-02 s stack took 4.644344e-02 s, asprintf took 5.432338e-02 s stack took 5.084137e-02 s, asprintf took 5.387238e-02 s stack took 4.659570e-02 s, asprintf took 5.408105e-02 s stack took 4.678890e-02 s, asprintf took 5.416419e-02 s stack took 4.688072e-02 s, asprintf took 5.322799e-02 s stack took 4.711744e-02 s, asprintf took 5.319471e-02 s stack took 4.713604e-02 s, asprintf took 5.314928e-02 s stack took 4.717523e-02 s, asprintf took 5.360440e-02 s stack took 4.717370e-02 s, asprintf took 5.796235e-02 s demo@debian:~$
Allocating dynamically would use much less memory.
Notice that having a compile-time limit for paths doesn't need to cause paths to always require that size for storage. You can still store only the strlen(path) + 1, but allow building them on the stack having a known limit. Having an unbounded path means that any untrusted input path from the user is potentially a DoS as the path can happily take 1 TiB. It might be worth reconsidering this decision on GNU/hurd. Best, Rodrigo.
I submit the following patch to your consideration. The patch applies to version 3.3.0 of the file present in Debian, before the above mentioned commit.
Best regards, João
--- dillo-3.3.0.orig/src/dilloc.c +++ dillo-3.3.0/src/dilloc.c @@ -16,6 +16,7 @@ #include <dirent.h> #include <errno.h> #include <limits.h> +#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <sys/ioctl.h> @@ -104,9 +105,9 @@ connect_given_pid(int *sock, const char static int find_working_socket(int *sock) { - char ctlpath[PATH_MAX]; - if (snprintf(ctlpath, PATH_MAX, "%s/.dillo/ctl", dGethomedir()) >= PATH_MAX) { - fprintf(stderr, "path too long\n"); + char *ctlpath = NULL; + if (asprintf(ctlpath, "%s/.dillo/ctl", dGethomedir()) == -1) { + fprintf(stderr, "path copy error: %s\n", strerror(errno)); return -1; }
@@ -116,10 +117,11 @@ find_working_socket(int *sock) fprintf(stderr, "error: cannot open %s directory: %s\n", ctlpath, strerror(errno)); fprintf(stderr, "hint: is dillo running?\n"); + free(ctlpath); return -1; }
- int found_pid = 0; + int found_pid = 0; struct sockaddr_un addr; addr.sun_family = AF_UNIX;
@@ -136,6 +138,7 @@ find_working_socket(int *sock) #define LEN ((int) sizeof(addr.sun_path)) if (snprintf(addr.sun_path, LEN, "%s/%s", ctlpath, num) >= LEN) { fprintf(stderr, "pid path too long\n"); + free(ctlpath); return -1; } #undef LEN @@ -143,6 +146,7 @@ find_working_socket(int *sock) int fd; if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { fprintf(stderr, "socket() failed: %s\n", strerror(errno)); + free(ctlpath); return -1; }
@@ -170,11 +174,13 @@ find_working_socket(int *sock)
if (fd != -1 && dClose(fd) != 0) { fprintf(stderr, "cannot close fd: %s", strerror(errno)); + free(ctlpath); return -1; } }
closedir(dp); + free(ctlpath);
if (found_pid == 1) return 0;
_______________________________________________ Dillo-dev mailing list -- dillo-dev@mailman3.com To unsubscribe send an email to dillo-dev-leave@mailman3.com