Fix configure dirname. Also streamline dirname usage.
authorNelson Ferreira <nelson.ferreira@ieee.org>
Thu, 11 Jun 2015 19:21:54 +0000 (15:21 -0400)
committerNelson Ferreira <nelson.ferreira@ieee.org>
Thu, 11 Jun 2015 19:21:54 +0000 (15:21 -0400)
POSIX 1003.1 states: "The dirname() function may modify the string
pointed to by path, and may return a pointer to static storage
that may then be overwritten by subsequent calls to dirname()."

Source: http://www.unix.com/man-page/POSIX/3posix/dirname/

Because of this the only sane way of using dirname is to allocate
our own copy of the argument, call dirname and then copy to the
result.

The interesting news is we don't call xdirname anywhere in our
code, yes, not even in Ffile_dirname.  In fact the contract as far
as the '/' termination and behavior on "non directory" is
completely different and actually changing it would break
build-autoloads.el and packages.el (easily fixed), and god knows
what other user code.

* m4/sxe-fs-funs.m4: Remove _SXE_CHECK_DIRNAME_SIDE_EFFECT,
_SXE_CHECK_DIRNAME_RETVAL_OWNER and
_SXE_CHECK_DIRNAME_RETVAL_OWNER tests since the change in xdirname
makes these checks not necessary.

* m4/sxe-fs-funs.m4 (SXE_CHECK_BROKEN_DIRNAME): Remove calls to
_SXE_CHECK_DIRNAME_SIDE_EFFECT, _SXE_CHECK_DIRNAME_RETVAL_OWNER
and _SXE_CHECK_DIRNAME_RETVAL_OWNER.

* src/sysdep.h (x__dirname): Provide only a POSIX-aware usage of
dirname.  This means copying the argument to the result buffer
before calling dirname and the result (if not at start of the
result buffer), using xstrncpy if non-overlapping, memmove if
overlapping.

m4/sxe-fs-funs.m4
src/sysdep.h

index 48c0dca..fdeca1a 100644 (file)
@@ -306,42 +306,6 @@ AC_DEFUN([SXE_CHECK_DIRNAME], [dnl
        fi
 ])dnl SXE_CHECK_DIRNAME
 
-AC_DEFUN([_SXE_CHECK_DIRNAME_SIDE_EFFECT], [dnl
-       ## defines sxe_func_dirname_side_effect
-       ## and DIRNAME_SIDE_EFFECT
-       pushdef([resvar], [sxe_func_dirname_side_effect])
-
-       AC_MSG_CHECKING([whether dirname modifies its argument by side-effect])
-       AC_RUN_IFELSE([AC_LANG_SOURCE([[
-#ifdef HAVE_LIBGEN_H
-#  include <libgen.h>
-#endif
-
-int dirname_modifies_argument()
-{
-       char p[11] = "somefile\000";
-       dirname(p);
-       return ((p[0] == '.' && p[1] == '\0') == 0);
-}
-
-int main()
-{
-       return dirname_modifies_argument();
-}
-               ]])],
-               resvar[=yes],
-               resvar[=no],
-               resvar[=no])
-       AC_MSG_RESULT([$]resvar)
-
-       if test "$[]resvar[]" = "yes"; then
-               AC_DEFINE([DIRNAME_SIDE_EFFECT], [1],
-                       [Whether dirname() operates by side effect])
-       fi
-
-       popdef([resvar])
-])dnl _SXE_CHECK_DIRNAME_SIDE_EFFECT
-
 AC_DEFUN([_SXE_CHECK_DIRNAME_RETVAL], [dnl
        ## arg #1 is the return type, char* by default
        ## arg #2 is the final test,
@@ -388,116 +352,6 @@ int main()
        popdef([rettest])
 ])dnl _SXE_CHECK_DIRNAME_RETVAL
 
-AC_DEFUN([_SXE_CHECK_DIRNAME_RETVAL_OWNER], [dnl
-       ## defines sxe_func_dirname_retval_owner,
-       ## values are either "sys" or "user"
-       pushdef([resvar], [sxe_func_dirname_retval_owner])
-
-       malloc_check=${MALLOC_CHECK_}
-       ## Turn off the stupid glibc 2.5 stack trace check. We *know* we may
-       ## do something bad here :-)
-       MALLOC_CHECK_=0
-       export MALLOC_CHECK_
-       ## this test is especially critical, because some systems do not
-       ## allocate memory for the user when the return value is "."
-       ## instead they point to a static const char somewhere in their
-       ## guts which, of course, must not be furtherly modified, free'd or
-       ## anything ... took me fucking ages to find out what's going on
-       ## so let's drink to the morons responsible for THAT!
-       AC_MSG_CHECKING([to whom belongs the object returned by dirname])
-       if test "$opsys" = "darwin" ; then
-          resvar=sys
-       else
-       AC_RUN_IFELSE([AC_LANG_SOURCE([[
-#ifdef HAVE_LIBGEN_H
-#  include <libgen.h>
-#endif
-
-#define FOLLOW_FREE_STRATEGY           1
-#define FOLLOW_REALLOC_STRATEGY                1
-
-int owner_of_object_returned_by_dirname()
-{
-       void *r;  /* any pointer is just fine */
-       char p[11] = "./somefile\000";
-
-       r = (void*)dirname(p);
-#if FOLLOW_REALLOC_STRATEGY
-       /* reallocation would help already */
-       r = realloc(r, 4096);
-#endif
-#if FOLLOW_FREE_STRATEGY
-       /* if r was ours we should be able to free it */
-       free(r);
-#endif
-#if FOLLOW_FREE_STRATEGY || FOLLOW_REALLOC_STRATEGY
-       return 0;
-#else
-       return 1;
-#endif
-}
-
-int main()
-{
-       return owner_of_object_returned_by_dirname();
-}
-               ]])],
-               resvar[=user],
-               resvar[=sys],
-               resvar[=sys])
-       fi
-       if test "${malloc_check}" = "" ; then
-               unset MALLOC_CHECK_
-       else
-               MALLOC_CHECK_=${malloc_check}
-       fi
-       AC_MSG_RESULT([$]resvar)
-
-       if test "$[]resvar[]" = "user"; then
-               AC_DEFINE([DIRNAME_USER_OWNS_RETVAL], [1],
-                       [Whether the user space owns the retval of dirname()])
-       elif test "$[]resvar[]" = "sys"; then
-               AC_DEFINE([DIRNAME_SYS_OWNS_RETVAL], [1],
-                       [Whether the system owns the retval of dirname()])
-       fi
-
-       popdef([resvar])
-])dnl _SXE_CHECK_DIRNAME_RETVAL_OWNER
-
-AC_DEFUN([_SXE_CHECK_DIRNAME_ON_PROTECTED_MEMORY], [dnl
-       ## defines sxe_func_dirname_accepts_protmem
-       pushdef([resvar], [sxe_func_dirname_accepts_protmem])
-
-       AC_MSG_CHECKING([whether dirname can operate on protected mem blocks])
-       AC_RUN_IFELSE([AC_LANG_SOURCE([[
-#ifdef HAVE_LIBGEN_H
-#  include <libgen.h>
-#endif
-
-int dirname_can_operate_on_protected_mem_blocks()
-{
-       dirname("./somefile");
-       return 0;
-}
-
-int main()
-{
-       return dirname_can_operate_on_protected_mem_blocks();
-}
-               ]])],
-               resvar[=yes],
-               resvar[=no],
-               resvar[=no])
-       AC_MSG_RESULT([$]resvar)
-
-       if test "$[]resvar[]" = "yes"; then
-               AC_DEFINE([DIRNAME_ACCEPTS_PROTMEM], [1],
-                       [Whether dirname() accepts protected memory blocks])
-       fi
-
-       popdef([resvar])
-])dnl _SXE_CHECK_DIRNAME_ON_PROTECTED_MEMORY
-
 AC_DEFUN([_SXE_CHECK_DIRNAME_ON_C99_RESTRICT_MEMORY], [dnl
        ## defines sxe_func_dirname_accepts_restrmem
        pushdef([resvar], [sxe_func_dirname_accepts_restrmem])
@@ -540,11 +394,8 @@ int main()
 
 AC_DEFUN([SXE_CHECK_BROKEN_DIRNAME], [dnl
        ## defines 3 vars, look in the sub macros to see which ones
-       _SXE_CHECK_DIRNAME_SIDE_EFFECT
-       _SXE_CHECK_DIRNAME_ON_PROTECTED_MEMORY
        _SXE_CHECK_DIRNAME_ON_C99_RESTRICT_MEMORY
        _SXE_CHECK_DIRNAME_RETVAL
-       _SXE_CHECK_DIRNAME_RETVAL_OWNER
 ])dnl SXE_CHECK_BROKEN_DIRNAME
 
 
index 62e2b6b..f34b944 100644 (file)
@@ -223,35 +223,24 @@ x__dirlen(const char *file, size_t len)
 extern_inline void
 x__dirname(char *restrict res, const char *file, size_t len)
        __attribute__((always_inline));
-#if defined(HAVE_DIRNAME) && defined(DIRNAME_SIDE_EFFECT)
+#if defined(HAVE_DIRNAME)
 extern_inline void
 x__dirname(char *restrict res, const char *file, size_t len)
 {
-       /* assumes res is malloc'd of size LEN */
-       xstrncpy(res, file, len);
-       dirname(res);
-       return;
-}
-#elif defined(HAVE_DIRNAME) && !defined(DIRNAME_ACCEPTS_PROTMEM)
-extern_inline void
-x__dirname(char *restrict res, const char *file, size_t len)
-{
-       /* assumes res is malloc'd of size LEN */
-       char *result;
-       xstrncpy(res, file, len);
-       /* if we were using side effects we woulda matched the above cond */
-       result = dirname(res);
-       xstrncpy(res, result, len);
-       return;
-}
-#elif defined(HAVE_DIRNAME)
-extern_inline void
-x__dirname(char *restrict res, const char *file, size_t len)
-{
-       /* assumes res is malloc'd of size LEN */
-       char *result = dirname(res);
-       xstrncpy(res, result, len);
-       return;
+        /* assumes res is malloc'd of size LEN */
+        char *result;
+        xstrncpy(res, file, len);
+        result = dirname(res);
+        if (res == result) {
+                return;
+        }
+        if (result < res || result >= (res+len)) {
+                xstrncpy(res, result, len);
+        } else {
+                /* Use memmove if result overlaps res */
+                memmove(res, result, strlen(result)+1);
+        }
+        return;
 }
 #endif