Commit bbbf79e33 for imagemagick.org

commit bbbf79e33935be36890707a49103b0e66698b82e
Author: Cristy <urban-warrior@imagemagick.org>
Date:   Wed Jul 8 20:22:02 2026 -0400

    ensure file resource identify is valid

diff --git a/MagickCore/policy-private.h b/MagickCore/policy-private.h
index 839e6acdc..ba551d558 100644
--- a/MagickCore/policy-private.h
+++ b/MagickCore/policy-private.h
@@ -22,6 +22,7 @@
 extern "C" {
 #endif

+#include "MagickCore/resource-private.h"
 #include "MagickCore/utility-private.h"

 #if MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
@@ -126,20 +127,22 @@ static inline MagickBooleanType IsPathContainsSymlink(const char *path)
 }

 static inline MagickBooleanType IsPathAuthorized(const PolicyRights rights,
-  const char *filename)
+  const char *path)
 {
   MagickBooleanType symlink_follow_allowed = IsRightsAuthorizedByName(
     SystemPolicyDomain,"symlink",rights,"follow");
   MagickBooleanType status =
-   ((IsRightsAuthorized(PathPolicyDomain,rights,filename) != MagickFalse) &&
+   ((IsRightsAuthorized(PathPolicyDomain,rights,path) != MagickFalse) &&
    ((symlink_follow_allowed != MagickFalse) ||
-    (is_symlink_utf8(filename) == MagickFalse))) ? MagickTrue : MagickFalse;
+    (is_symlink_utf8(path) == MagickFalse))) ? MagickTrue : MagickFalse;
   if ((status != MagickFalse) && (symlink_follow_allowed == MagickFalse))
     {
-      if ((is_symlink_utf8(filename) != MagickFalse) ||
-          (IsPathContainsSymlink(filename) != MagickFalse))
+      if ((is_symlink_utf8(path) != MagickFalse) ||
+          (IsPathContainsSymlink(path) != MagickFalse))
         status=MagickFalse;
     }
+  if (status != MagickFalse)
+    status=IsFileResourceIdentityValid(path);
   return(status);
 }

diff --git a/MagickCore/resource-private.h b/MagickCore/resource-private.h
index abcd143a6..0965d6396 100644
--- a/MagickCore/resource-private.h
+++ b/MagickCore/resource-private.h
@@ -26,6 +26,9 @@ extern "C" {
 # define MagickFormatExtent  64
 #endif

+extern MagickExport MagickBooleanType
+  IsFileResourceIdentityValid(const char *);
+
 extern MagickPrivate MagickBooleanType
   ResourceComponentGenesis(void);

diff --git a/MagickCore/resource.c b/MagickCore/resource.c
index 5bdc3704d..05c77d8ec 100644
--- a/MagickCore/resource.c
+++ b/MagickCore/resource.c
@@ -70,7 +70,6 @@
 /*
   Define declarations.
 */
-#define MagickPathTemplate "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"  /* min 6 X's */
 #define NumberOfResourceTypes  \
   (sizeof(resource_semaphore)/sizeof(*resource_semaphore))

@@ -462,89 +461,6 @@ static void *DestroyTemporaryResources(void *temporary_resource)
   return((void *) NULL);
 }

-MagickExport MagickBooleanType GetPathTemplate(char *path)
-{
-  char
-    *directory,
-    *value;
-
-  ExceptionInfo
-    *exception;
-
-  MagickBooleanType
-    status;
-
-  struct stat
-    attributes;
-
-  (void) FormatLocaleString(path,MagickPathExtent,"magick-" MagickPathTemplate);
-  exception=AcquireExceptionInfo();
-  directory=(char *) GetImageRegistry(StringRegistryType,"temporary-path",
-    exception);
-  exception=DestroyExceptionInfo(exception);
-  if (directory == (char *) NULL)
-    directory=GetEnvironmentValue("MAGICK_TEMPORARY_PATH");
-  if (directory == (char *) NULL)
-    directory=GetEnvironmentValue("MAGICK_TMPDIR");
-  if (directory == (char *) NULL)
-    directory=GetEnvironmentValue("TMPDIR");
-#if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__) || defined(__CYGWIN__)
-  if (directory == (char *) NULL)
-    directory=GetEnvironmentValue("TMP");
-  if (directory == (char *) NULL)
-    directory=GetEnvironmentValue("TEMP");
-#endif
-#if defined(__VMS)
-  if (directory == (char *) NULL)
-    directory=GetEnvironmentValue("MTMPDIR");
-#endif
-#if defined(P_tmpdir)
-  if (directory == (char *) NULL)
-    directory=ConstantString(P_tmpdir);
-#endif
-  if (directory == (char *) NULL)
-    return(MagickFalse);
-  value=GetPolicyValue("resource:temporary-path");
-  if (value != (char *) NULL)
-    {
-      (void) CloneString(&directory,value);
-      value=DestroyString(value);
-    }
-  if (strlen(directory) > (MagickPathExtent-25))
-    {
-      directory=DestroyString(directory);
-      return(MagickFalse);
-    }
-  status=GetPathAttributes(directory,&attributes);
-  if ((status == MagickFalse) || !S_ISDIR(attributes.st_mode))
-    {
-      directory=DestroyString(directory);
-      return(MagickFalse);
-    }
-  if (directory[strlen(directory)-1] == *DirectorySeparator)
-    (void) FormatLocaleString(path,MagickPathExtent,"%smagick-"
-      MagickPathTemplate,directory);
-  else
-    (void) FormatLocaleString(path,MagickPathExtent,
-      "%s%smagick-" MagickPathTemplate,directory,DirectorySeparator);
-  directory=DestroyString(directory);
-#if defined(MAGICKCORE_WINDOWS_SUPPORT)
-  {
-    char
-      *p;
-
-    /*
-      Ghostscript does not like backslashes so we need to replace them. The
-      forward slash also works under Windows.
-    */
-    for (p=(path[1] == *DirectorySeparator ? path+2 : path); *p != '\0'; p++)
-      if (*p == *DirectorySeparator)
-        *p='/';
-  }
-#endif
-  return(MagickTrue);
-}
-
 MagickExport int AcquireUniqueFileResource(char *path)
 {
 #if !defined(O_NOFOLLOW)
@@ -785,6 +701,57 @@ MagickExport MagickSizeType GetMagickResource(const ResourceType type)
 %                                                                             %
 %                                                                             %
 %                                                                             %
+%   I s F i l e R e s o u r c e I d e n t i t y V a l i d                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsFileResourceIdentityValid() returns MagickTrue if the file resource
+%  identity is valid.
+%
+%  The format of the IsFileResourceIdentityValid() method is:
+%
+%      MagickBooleanType IsFileResourceIdentityValid(const char *path)
+%
+%  A description of each parameter follows:
+%
+%    o path: the file resource path.
+%
+*/
+MagickExport MagickBooleanType IsFileResourceIdentityValid(const char *path)
+{
+  const struct stat
+    *temporary_attributes;
+
+  MagickBooleanType
+    status = MagickTrue;
+
+  struct stat
+    attributes;
+
+  if (temporary_resources == (SplayTreeInfo *) NULL)
+    return(MagickTrue);
+  LockSemaphoreInfo(resource_semaphore[FileResource]);
+  temporary_attributes=(const struct stat *) GetValueFromSplayTree(
+    temporary_resources,(const void *) path);
+  if (temporary_attributes != (const struct stat *) NULL)
+    {
+      status=GetPathAttributes(path,&attributes);
+      if (status != MagickFalse)
+        if ((attributes.st_dev != temporary_attributes->st_dev) ||
+            (attributes.st_ino != temporary_attributes->st_ino))
+          status=MagickFalse;
+    }
+  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 %   G e t M a g i c k R e s o u r c e L i m i t                               %
 %                                                                             %
 %                                                                             %
@@ -1181,26 +1148,7 @@ MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path)
     ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
   LockSemaphoreInfo(resource_semaphore[FileResource]);
   if (temporary_resources != (SplayTreeInfo *) NULL)
-    {
-      const struct stat
-        *temporary_attributes;
-
-      struct stat
-        attributes;
-
-      temporary_attributes=(const struct stat *) GetValueFromSplayTree(
-        temporary_resources,(const void *) path);
-      status=GetPathAttributes(path,&attributes);
-      if ((temporary_attributes != (const struct stat *) NULL) &&
-          (status != MagickFalse))
-        {
-          if ((attributes.st_dev != temporary_attributes->st_dev) ||
-              (attributes.st_ino != temporary_attributes->st_ino))
-            ThrowFatalException(PolicyFatalError,
-              "time-of-check to time-of-use violation");
-        }
-      status=DeleteNodeFromSplayTree(temporary_resources,(const void *) path);
-    }
+    status=DeleteNodeFromSplayTree(temporary_resources,(const void *) path);
   UnlockSemaphoreInfo(resource_semaphore[FileResource]);
   (void) CopyMagickString(cache_path,path,MagickPathExtent);
   AppendImageFormat("cache",cache_path);
diff --git a/MagickCore/resource_.h b/MagickCore/resource_.h
index 500b64998..a65a1251c 100644
--- a/MagickCore/resource_.h
+++ b/MagickCore/resource_.h
@@ -45,7 +45,6 @@ extern MagickExport int

 extern MagickExport MagickBooleanType
   AcquireMagickResource(const ResourceType,const MagickSizeType),
-  GetPathTemplate(char *),
   ListMagickResourceInfo(FILE *,ExceptionInfo *),
   RelinquishUniqueFileResource(const char *),
   SetMagickResourceLimit(const ResourceType,const MagickSizeType);
diff --git a/MagickCore/utility-private.h b/MagickCore/utility-private.h
index d644c2c14..8242e5f1e 100644
--- a/MagickCore/utility-private.h
+++ b/MagickCore/utility-private.h
@@ -32,6 +32,8 @@
 extern "C" {
 #endif

+#define MagickPathTemplate "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"  /* min 6 X's */
+
 extern MagickPrivate char
   **GetPathComponents(const char *,size_t *),
   **ListFiles(const char *,const char *,size_t *);
diff --git a/MagickCore/utility.c b/MagickCore/utility.c
index 58a46beee..f06cfeaad 100644
--- a/MagickCore/utility.c
+++ b/MagickCore/utility.c
@@ -1522,6 +1522,114 @@ MagickPrivate char **GetPathComponents(const char *path,
 %                                                                             %
 %                                                                             %
 %                                                                             %
+%   G e t P a t h T e m p l a t e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPathTemplate() constructs a template for a temporary filename.
+%
+%  The format of the GetPathComponent function is:
+%
+%      MagickBooleanType GetPathComponent(const char *path)
+%
+%  A description of each parameter follows:
+%
+%    o path: Specifies a pointer to a character array populated with the
+%      file path template.
+%
+%
+*/
+MagickExport MagickBooleanType GetPathTemplate(char *path)
+{
+  char
+    *directory,
+    *value;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  struct stat
+    attributes;
+
+  (void) FormatLocaleString(path,MagickPathExtent,"magick-"
+    MagickPathTemplate);
+  exception=AcquireExceptionInfo();
+  directory=(char *) GetImageRegistry(StringRegistryType,"temporary-path",
+    exception);
+  exception=DestroyExceptionInfo(exception);
+  if (directory == (char *) NULL)
+    directory=GetEnvironmentValue("MAGICK_TEMPORARY_PATH");
+  if (directory == (char *) NULL)
+    directory=GetEnvironmentValue("MAGICK_TMPDIR");
+  if (directory == (char *) NULL)
+    directory=GetEnvironmentValue("TMPDIR");
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__) || defined(__CYGWIN__)
+  if (directory == (char *) NULL)
+    directory=GetEnvironmentValue("TMP");
+  if (directory == (char *) NULL)
+    directory=GetEnvironmentValue("TEMP");
+#endif
+#if defined(__VMS)
+  if (directory == (char *) NULL)
+    directory=GetEnvironmentValue("MTMPDIR");
+#endif
+#if defined(P_tmpdir)
+  if (directory == (char *) NULL)
+    directory=ConstantString(P_tmpdir);
+#endif
+  if (directory == (char *) NULL)
+    return(MagickFalse);
+  value=GetPolicyValue("resource:temporary-path");
+  if (value != (char *) NULL)
+    {
+      (void) CloneString(&directory,value);
+      value=DestroyString(value);
+    }
+  if (strlen(directory) > (MagickPathExtent-25))
+    {
+      directory=DestroyString(directory);
+      return(MagickFalse);
+    }
+  status=GetPathAttributes(directory,&attributes);
+  if ((status == MagickFalse) || !S_ISDIR(attributes.st_mode))
+    {
+      directory=DestroyString(directory);
+      return(MagickFalse);
+    }
+  if (directory[strlen(directory)-1] == *DirectorySeparator)
+    (void) FormatLocaleString(path,MagickPathExtent,"%smagick-"
+      MagickPathTemplate,directory);
+  else
+    (void) FormatLocaleString(path,MagickPathExtent,
+      "%s%smagick-" MagickPathTemplate,directory,DirectorySeparator);
+  directory=DestroyString(directory);
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+  {
+    char
+      *p;
+
+    /*
+      Ghostscript does not like backslashes so we need to replace them. The
+      forward slash also works under Windows.
+    */
+    for (p=(path[1] == *DirectorySeparator ? path+2 : path); *p != '\0'; p++)
+      if (*p == *DirectorySeparator)
+        *p='/';
+  }
+#endif
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 %  I s P a t h A c c e s s i b l e                                            %
 %                                                                             %
 %                                                                             %
diff --git a/MagickCore/utility.h b/MagickCore/utility.h
index ebdc44bb0..5190f967d 100644
--- a/MagickCore/utility.h
+++ b/MagickCore/utility.h
@@ -45,6 +45,7 @@ extern MagickExport MagickBooleanType
   AcquireUniqueSymbolicLink(const char *,char *),
   ExpandFilenames(int *,char ***),
   GetPathAttributes(const char *,void *),
+  GetPathTemplate(char *),
   IsPathAccessible(const char *);

 extern MagickExport size_t
diff --git a/configure b/configure
index d0cb6bfc3..3e4277837 100755
--- a/configure
+++ b/configure
@@ -4104,8 +4104,8 @@ ac_cxx_conftest_cxx11_main='
 }
 {
   // Unicode literals
-  char const *utf8 = u8"UTF-8 string \u2500";
-  char16_t const *utf16 = u"UTF-8 string \u2500";
+  auto const *utf8 = u8"UTF-8 string \u2500";
+  char16_t const *utf16 = u"UTF-16 string \u2500";
   char32_t const *utf32 = U"UTF-32 string \u2500";
 }
 '
@@ -5389,7 +5389,7 @@ MAGICK_PATCHLEVEL_VERSION=28

 MAGICK_VERSION=7.1.2-28

-MAGICK_GIT_REVISION=b661ac969:20260705
+MAGICK_GIT_REVISION=9f1810998:20260707


 # Substitute library versioning
@@ -5423,7 +5423,7 @@ PACKAGE_LIB_VERSION=0x712

 PACKAGE_LIB_VERSION_NUMBER=7,1,2,28

-PACKAGE_RELEASE_DATE=2026-07-05
+PACKAGE_RELEASE_DATE=2026-07-07


 # Ensure that make can run correctly
@@ -12128,18 +12128,18 @@ then :
 fi
 if test "$enable_largefile,$enable_year2038" != no,no
 then :
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CPPFLAGS option for large files" >&5
-printf %s "checking for $CPPFLAGS option for large files... " >&6; }
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable large file support" >&5
+printf %s "checking for $CC option to enable large file support... " >&6; }
 if test ${ac_cv_sys_largefile_opts+y}
 then :
   printf %s "(cached) " >&6
 else case e in #(
-  e) ac_save_CPPFLAGS=$CPPFLAGS
+  e) ac_save_CC="$CC"
   ac_opt_found=no
-  for ac_opt in "none needed" "-D_FILE_OFFSET_BITS=64" "-D_LARGE_FILES=1"; do
+  for ac_opt in "none needed" "-D_FILE_OFFSET_BITS=64" "-D_LARGE_FILES=1" "-n32"; do
     if test x"$ac_opt" != x"none needed"
 then :
-  CPPFLAGS="$ac_save_CPPFLAGS $ac_opt"
+  CC="$ac_save_CC $ac_opt"
 fi
     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
@@ -12168,12 +12168,12 @@ then :
   if test x"$ac_opt" = x"none needed"
 then :
   # GNU/Linux s390x and alpha need _FILE_OFFSET_BITS=64 for wide ino_t.
-	 CPPFLAGS="$CPPFLAGS -DFTYPE=ino_t"
+	 CC="$CC -DFTYPE=ino_t"
 	 if ac_fn_c_try_compile "$LINENO"
 then :

 else case e in #(
-  e) CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=64"
+  e) CC="$CC -D_FILE_OFFSET_BITS=64"
 	    if ac_fn_c_try_compile "$LINENO"
 then :
   ac_opt='-D_FILE_OFFSET_BITS=64'
@@ -12189,7 +12189,7 @@ fi
 rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
     test $ac_opt_found = no || break
   done
-  CPPFLAGS=$ac_save_CPPFLAGS
+  CC="$ac_save_CC"

   test $ac_opt_found = yes || ac_cv_sys_largefile_opts="support not detected" ;;
 esac
@@ -12213,14 +12213,16 @@ printf "%s\n" "#define _FILE_OFFSET_BITS 64" >>confdefs.h

 printf "%s\n" "#define _LARGE_FILES 1" >>confdefs.h
  ;; #(
+  "-n32") :
+    CC="$CC -n32" ;; #(
   *) :
     as_fn_error $? "internal error: bad value for \$ac_cv_sys_largefile_opts" "$LINENO" 5 ;;
 esac

 if test "$enable_year2038" != no
 then :
-  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CPPFLAGS option for timestamps after 2038" >&5
-printf %s "checking for $CPPFLAGS option for timestamps after 2038... " >&6; }
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option for timestamps after 2038" >&5
+printf %s "checking for $CC option for timestamps after 2038... " >&6; }
 if test ${ac_cv_sys_year2038_opts+y}
 then :
   printf %s "(cached) " >&6