libtiff: Add reentrant error functions

From aa863b5e8206ab767c150a9941c8aa50ae9bb1d6 Mon Sep 17 00:00:00 2001
From: Laramie Leavitt <[EMAIL REDACTED]>
Date: Fri, 16 Sep 2022 04:11:48 +0000
Subject: [PATCH] Add reentrant error functions

Prior to this change, libtiff relied on global error handlers,
which is problematic when libtiff used by multiple independent
libraries from within the same process, as they may unwittingly
clobber the error handling, introduce race conditions when setting
handlers, or otherwise have unintended side effects.

This change adds error handlers to the TIFF struct, which are
used preferentially when available. The error handlers are invoked
when the re-entrant error functions are called:

void TIFFErrorExtR(TIFF*, const char* module, const char* fmt, ...)
void TIFFWarningExtR(TIFF*, const char* module, const char* fmt, ...)

The handlers have a similar signature to the existing extended
handlers, additionally returning an int:

int TIFFErrorHandlerExtR(thandle_t, const char*, const char*, va_list)

 thandle_t is the userdata passed to TIFFOpen
 When the handler returns 1, the global handlers are not called.

Custom error/warning handlers may be installed on a per-file
basis by calling the Set functions:

  TIFF* tif = TIFFOpen(...);
  TIFFSetErrorHandlerExtR(tif, MyErrorHandler);
  TIFFSetWarningHandlerExtR(tif, MyWarningHandler);

Additionally, the callsites to TIFFErrorExt and TIFFWarningExt
have been updated to call the reentrant versions.
---
 contrib/pds/tif_imageiter.c   |  18 ++--
 contrib/pds/tif_pdsdirread.c  |  24 ++---
 contrib/pds/tif_pdsdirwrite.c |  20 ++--
 contrib/tags/maketif.c        |   2 +-
 contrib/tags/xtif_dir.c       |   4 +-
 contrib/win_dib/Tiffile.cpp   |   2 +-
 libtiff/libtiff.def           |   1 +
 libtiff/libtiff.map           |   1 +
 libtiff/tif_aux.c             |  16 ++--
 libtiff/tif_codec.c           |   2 +-
 libtiff/tif_compress.c        |  10 +-
 libtiff/tif_dir.c             | 101 ++++++++++----------
 libtiff/tif_dirinfo.c         |  16 ++--
 libtiff/tif_dirread.c         | 174 +++++++++++++++++-----------------
 libtiff/tif_dirwrite.c        | 156 +++++++++++++++---------------
 libtiff/tif_dumpmode.c        |   2 +-
 libtiff/tif_error.c           |  25 +++++
 libtiff/tif_fax3.c            |  40 ++++----
 libtiff/tif_fax3.h            |  12 +--
 libtiff/tif_flush.c           |   8 +-
 libtiff/tif_getimage.c        |  62 ++++++------
 libtiff/tif_jbig.c            |  10 +-
 libtiff/tif_jpeg.c            |  94 +++++++++---------
 libtiff/tif_jpeg_12.c         |   2 +-
 libtiff/tif_lerc.c            |  84 ++++++++--------
 libtiff/tif_luv.c             |  44 ++++-----
 libtiff/tif_lzma.c            |  28 +++---
 libtiff/tif_lzw.c             |  30 +++---
 libtiff/tif_next.c            |   8 +-
 libtiff/tif_ojpeg.c           | 136 +++++++++++++-------------
 libtiff/tif_open.c            |  63 +++++++-----
 libtiff/tif_packbits.c        |  10 +-
 libtiff/tif_pixarlog.c        |  46 ++++-----
 libtiff/tif_predict.c         |  36 +++----
 libtiff/tif_read.c            |  86 ++++++++---------
 libtiff/tif_strip.c           |  16 ++--
 libtiff/tif_thunder.c         |   6 +-
 libtiff/tif_tile.c            |  18 ++--
 libtiff/tif_warning.c         |  26 ++++-
 libtiff/tif_webp.c            |  62 ++++++------
 libtiff/tif_write.c           |  54 +++++------
 libtiff/tif_zip.c             |  32 +++----
 libtiff/tif_zstd.c            |  22 ++---
 libtiff/tiffio.h              |  34 +++++--
 libtiff/tiffiop.h             |   6 ++
 45 files changed, 867 insertions(+), 782 deletions(-)

diff --git a/contrib/pds/tif_imageiter.c b/contrib/pds/tif_imageiter.c
index 7ecf61a0..3eb2cdbf 100644
--- a/contrib/pds/tif_imageiter.c
+++ b/contrib/pds/tif_imageiter.c
@@ -111,7 +111,7 @@ TIFFImageIterBegin(TIFFImageIter* img, TIFF* tif, int stop, char emsg[1024])
     case PHOTOMETRIC_PALETTE:
 	if (!TIFFGetField(tif, TIFFTAG_COLORMAP,
 	    &img->redcmap, &img->greencmap, &img->bluecmap)) {
-		TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Missing required \"Colormap\" tag");
+		TIFFErrorExtR(tif, TIFFFileName(tif), "Missing required \"Colormap\" tag");
 	    return (0);
 	}
 	/* fall through... */
@@ -209,11 +209,11 @@ int
 TIFFImageIterGet(TIFFImageIter* img, void *udata, uint32_t w, uint32_t h)
 {
     if (img->get == NULL) {
-	TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No \"get\" routine setup");
+	TIFFErrorExtR(img->tif, TIFFFileName(img->tif), "No \"get\" routine setup");
 	return (0);
     }
     if (img->callback.any == NULL) {
-	TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif),
+	TIFFErrorExtR(img->tif, TIFFFileName(img->tif),
 		"No \"put\" routine setupl; probably can not handle image format");
 	return (0);
     }
@@ -241,7 +241,7 @@ TIFFReadImageIter(TIFF* tif,
 	ok = TIFFImageIterGet(&img, raster, rwidth, img.height);
 	TIFFImageIterEnd(&img);
     } else {
-	TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), emsg);
+	TIFFErrorExtR(tif, TIFFFileName(tif), emsg);
 	ok = 0;
     }
     return (ok);
@@ -268,7 +268,7 @@ gtTileContig(TIFFImageIter* img, void *udata, uint32_t w, uint32_t h)
 
     buf = (u_char*) _TIFFmalloc(TIFFTileSize(tif));
     if (buf == 0) {
-	TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
+	TIFFErrorExtR(tif, TIFFFileName(tif), "No space for tile buffer");
 	return (0);
     }
     TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
@@ -323,7 +323,7 @@ gtTileSeparate(TIFFImageIter* img, void *udata, uint32_t w, uint32_t h)
     tilesize = TIFFTileSize(tif);
     buf = (u_char*) _TIFFmalloc(4*tilesize);
     if (buf == 0) {
-	TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
+	TIFFErrorExtR(tif, TIFFFileName(tif), "No space for tile buffer");
 	return (0);
     }
     r = buf;
@@ -384,7 +384,7 @@ gtStripContig(TIFFImageIter* img, void *udata, uint32_t w, uint32_t h)
 
     buf = (u_char*) _TIFFmalloc(TIFFStripSize(tif));
     if (buf == 0) {
-	TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer");
+	TIFFErrorExtR(tif, TIFFFileName(tif), "No space for strip buffer");
 	return (0);
     }
     orientation = img->orientation;
@@ -427,7 +427,7 @@ gtStripSeparate(TIFFImageIter* img, void *udata, uint32_t w, uint32_t h)
     stripsize = TIFFStripSize(tif);
     r = buf = (u_char *)_TIFFmalloc(4*stripsize);
     if (buf == 0) {
-	TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
+	TIFFErrorExtR(tif, TIFFFileName(tif), "No space for tile buffer");
 	return (0);
     }
     g = r + stripsize;
@@ -508,7 +508,7 @@ main(int argc, char **argv)
 	    ok = TIFFImageIterGet(&img, NULL, img.width, img.height);
 	    TIFFImageIterEnd(&img);
 	} else {
-	    TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), emsg);
+	    TIFFErrorExtR(tif, TIFFFileName(tif), emsg);
 	}
     }
     
diff --git a/contrib/pds/tif_pdsdirread.c b/contrib/pds/tif_pdsdirread.c
index 19fccb38..64542572 100644
--- a/contrib/pds/tif_pdsdirread.c
+++ b/contrib/pds/tif_pdsdirread.c
@@ -87,7 +87,7 @@ CheckMalloc(TIFF* tif, tsize_t n, const char* what)
 {
 	char *cp = (char*)_TIFFmalloc(n);
 	if (cp == NULL)
-		TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "No space %s", what);
+		TIFFErrorExtR(tif, tif->tif_name, "No space %s", what);
 	return (cp);
 }
 
@@ -135,12 +135,12 @@ TIFFReadPrivateDataSubDirectory(TIFF* tif, toff_t pdir_offset,
 
 	if (!isMapped(tif)) {
 		if (!SeekOK(tif, pdir_offset)) {
-			TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			TIFFErrorExtR(tif, tif->tif_name,
 			    "Seek error accessing TIFF private subdirectory");
 			return (0);
 		}
 		if (!ReadOK(tif, &dircount, sizeof (uint16_t))) {
-			TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			TIFFErrorExtR(tif, tif->tif_name,
 			    "Can not read TIFF private subdirectory count");
 			return (0);
 		}
@@ -151,7 +151,7 @@ TIFFReadPrivateDataSubDirectory(TIFF* tif, toff_t pdir_offset,
 		if (dir == NULL)
 			return (0);
 		if (!ReadOK(tif, dir, dircount*sizeof (TIFFDirEntry))) {
-			TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Can not read TIFF private subdirectory");
+			TIFFErrorExtR(tif, tif->tif_name, "Can not read TIFF private subdirectory");
 			goto bad;
 		}
 		/*
@@ -162,7 +162,7 @@ TIFFReadPrivateDataSubDirectory(TIFF* tif, toff_t pdir_offset,
 		toff_t off = pdir_offset;
 
 		if (off + sizeof (short) > tif->tif_size) {
-			TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+			TIFFErrorExtR(tif, tif->tif_name,
 			    "Can not read TIFF private subdirectory count");
 			return (0);
 		} else
@@ -175,7 +175,7 @@ TIFFReadPrivateDataSubDirectory(TIFF* tif, toff_t pdir_offset,
 		if (dir == NULL)
 			return (0);
 		if (off + dircount*sizeof (TIFFDirEntry) > tif->tif_size) {
-			TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Can not read TIFF private subdirectory");
+			TIFFErrorExtR(tif, tif->tif_name, "Can not read TIFF private subdirectory");
 			goto bad;
 		} else
 			_TIFFmemcpy(dir, tif->tif_base + off,
@@ -336,7 +336,7 @@ EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16_t dircount)
 static void
 MissingRequired(TIFF* tif, const char* tagname)
 {
-	TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+	TIFFErrorExtR(tif, tif->tif_name,
 	    "TIFF directory is missing required \"%s\" field", tagname);
 }
 
@@ -400,7 +400,7 @@ TIFFFetchData(TIFF* tif, TIFFDirEntry* dir, char* cp)
 	}
 	return (cc);
 bad:
-	TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error fetching data for field \"%s\"",
+	TIFFErrorExtR(tif, tif->tif_name, "Error fetching data for field \"%s\"",
 	    _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
 	return ((tsize_t) 0);
 }
@@ -428,7 +428,7 @@ static int
 cvtRational(TIFF* tif, TIFFDirEntry* dir, uint32_t num, uint32_t denom, float* rv)
 {
 	if (denom == 0) {
-		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+		TIFFErrorExtR(tif, tif->tif_name,
 		    "%s: Rational with zero denominator (num = %lu)",
 		    _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name, num);
 		return (0);
@@ -717,7 +717,7 @@ TIFFFetchAnyArray(TIFF* tif, TIFFDirEntry* dir, double* v)
 		/* TIFF_NOTYPE */
 		/* TIFF_ASCII */
 		/* TIFF_UNDEFINED */
-		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+		TIFFErrorExtR(tif, tif->tif_name,
 		    "Cannot read TIFF_ANY type %d for field \"%s\"",
 		    _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
 		return (0);
@@ -895,7 +895,7 @@ TIFFFetchPerSampleShorts(TIFF* tif, TIFFDirEntry* dir, int* pl)
 			int i;
 			for (i = 1; i < samples; i++)
 				if (v[i] != v[0]) {
-					TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+					TIFFErrorExtR(tif, tif->tif_name,
 		"Cannot handle different per-sample values for field \"%s\"",
 			   _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
 					goto bad;
@@ -931,7 +931,7 @@ TIFFFetchPerSampleAnys(TIFF* tif, TIFFDirEntry* dir, double* pl)
 			int i;
 			for (i = 1; i < samples; i++)
 				if (v[i] != v[0]) {
-					TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+					TIFFErrorExtR(tif, tif->tif_name,
 		"Cannot handle different per-sample values for field \"%s\"",
 			   _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
 					goto bad;
diff --git a/contrib/pds/tif_pdsdirwrite.c b/contrib/pds/tif_pdsdirwrite.c
index 9e51bfbd..0c402257 100644
--- a/contrib/pds/tif_pdsdirwrite.c
+++ b/contrib/pds/tif_pdsdirwrite.c
@@ -175,7 +175,7 @@ TIFFWritePrivateDataSubDirectory(TIFF* tif,
 	dirsize = nfields * sizeof (TIFFDirEntry);
 	data = (char*) _TIFFmalloc(dirsize);
 	if (data == NULL) {
-		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+		TIFFErrorExtR(tif, tif->tif_name,
 		    "Cannot write private subdirectory, out of space");
 		return (0);
 	}
@@ -268,15 +268,15 @@ TIFFWritePrivateDataSubDirectory(TIFF* tif,
 
 	(void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET);
 	if (!WriteOK(tif, &dircount, sizeof (dircount))) {
-		TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing private subdirectory count");
+		TIFFErrorExtR(tif, tif->tif_name, "Error writing private subdirectory count");
 		goto bad;
 	}
 	if (!WriteOK(tif, data, dirsize)) {
-		TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing private subdirectory contents");
+		TIFFErrorExtR(tif, tif->tif_name, "Error writing private subdirectory contents");
 		goto bad;
 	}
 	if (!WriteOK(tif, &nextdiroff, sizeof (nextdiroff))) {
-		TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing private subdirectory link");
+		TIFFErrorExtR(tif, tif->tif_name, "Error writing private subdirectory link");
 		goto bad;
 	}
 	tif->tif_dataoff += sizeof(dircount) + dirsize + sizeof(nextdiroff);
@@ -876,7 +876,7 @@ TIFFWriteData(TIFF* tif, TIFFDirEntry* dir, char* cp)
 		tif->tif_dataoff += (cc + 1) & ~1;
 		return (1);
 	}
-	TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing data for field \"%s\"",
+	TIFFErrorExtR(tif, tif->tif_name, "Error writing data for field \"%s\"",
 	    _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
 	return (0);
 }
@@ -900,7 +900,7 @@ TIFFLinkDirectory(TIFF* tif)
 	if (tif->tif_flags & TIFF_INSUBIFD) {
 		(void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET);
 		if (!WriteOK(tif, &diroff, sizeof (diroff))) {
-			TIFFErrorExt(tif->tif_clientdata, module,
+			TIFFErrorExtR(tif, module,
 			    "%s: Error writing SubIFD directory link",
 			    tif->tif_name);
 			return (0);
@@ -925,7 +925,7 @@ TIFFLinkDirectory(TIFF* tif)
 #define	HDROFF(f)	((toff_t) &(((TIFFHeader*) 0)->f))
 		(void) TIFFSeekFile(tif, HDROFF(tiff_diroff), SEEK_SET);
 		if (!WriteOK(tif, &diroff, sizeof (diroff))) {
-			TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing TIFF header");
+			TIFFErrorExtR(tif, tif->tif_name, "Error writing TIFF header");
 			return (0);
 		}
 		return (1);
@@ -939,7 +939,7 @@ TIFFLinkDirectory(TIFF* tif)
 
 		if (!SeekOK(tif, nextdir) ||
 		    !ReadOK(tif, &dircount, sizeof (dircount))) {
-			TIFFErrorExt(tif->tif_clientdata, module, "Error fetching directory count");
+			TIFFErrorExtR(tif, module, "Error fetching directory count");
 			return (0);
 		}
 		if (tif->tif_flags & TIFF_SWAB)
@@ -947,7 +947,7 @@ TIFFLinkDirectory(TIFF* tif)
 		(void) TIFFSeekFile(tif,
 		    dircount * sizeof (TIFFDirEntry), SEEK_CUR);
 		if (!ReadOK(tif, &nextdir, sizeof (nextdir))) {
-			TIFFErrorExt(tif->tif_clientdata, module, "Error fetching directory link");
+			TIFFErrorExtR(tif, module, "Error fetching directory link");
 			return (0);
 		}
 		if (tif->tif_flags & TIFF_SWAB)
@@ -955,7 +955,7 @@ TIFFLinkDirectory(TIFF* tif)
 	} while (nextdir != 0);
 	(void) TIFFSeekFile(tif, -(toff_t) sizeof (nextdir), SEEK_CUR);
 	if (!WriteOK(tif, &diroff, sizeof (diroff))) {
-		TIFFErrorExt(tif->tif_clientdata, module, "Error writing directory link");
+		TIFFErrorExtR(tif, module, "Error writing directory link");
 		return (0);
 	}
 	return (1);
diff --git a/contrib/tags/maketif.c b/contrib/tags/maketif.c
index 41ca8859..69e6a4ee 100644
--- a/contrib/tags/maketif.c
+++ b/contrib/tags/maketif.c
@@ -62,7 +62,7 @@ void WriteImage(TIFF *tif)
 	memset(buffer,0,sizeof(buffer));
 	for (i=0;i<HEIGHT;i++)
 		if (!TIFFWriteScanline(tif, buffer, i, 0))
-			TIFFErrorExt(tif->tif_clientdata, "WriteImage","failure in WriteScanline\n");
+			TIFFErrorExtR(tif, "WriteImage","failure in WriteScanline\n");
 }
 
 
diff --git a/contrib/tags/xtif_dir.c b/contrib/tags/xtif_dir.c
index 628bc415..ef949206 100644
--- a/contrib/tags/xtif_dir.c
+++ b/contrib/tags/xtif_dir.c
@@ -138,12 +138,12 @@ _XTIFFVSetField(TIFF* tif, ttag_t tag, va_list ap)
 	va_end(ap);
 	return (status);
 badvalue:
-	TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "%d: Bad value for \"%s\"", v,
+	TIFFErrorExtR(tif, tif->tif_name, "%d: Bad value for \"%s\"", v,
 	    _TIFFFieldWithTag(tif, tag)->field_name);
 	va_end(ap);
 	return (0);
 badvalue32:
-	TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "%ld: Bad value for \"%s\"", v32,
+	TIFFErrorExtR(tif, tif->tif_name, "%ld: Bad value for \"%s\"", v32,
 	    _TIFFFieldWithTag(tif, tag)->field_name);
 	va_end(ap);
 	return (0);
diff --git a/contrib/win_dib/Tiffile.cpp b/contrib/win_dib/Tiffile.cpp
index 27e29b5f..f6805584 100644
--- a/contrib/win_dib/Tiffile.cpp
+++ b/contrib/win_dib/Tiffile.cpp
@@ -410,7 +410,7 @@ getStripContig1Bit(TIFFRGBAImage* img, uint32_t* raster, uint32_t w, uint32_t h)
 
     buf = (u_char*) _TIFFmalloc(TIFFStripSize(tif));
     if (buf == 0) {
-        TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer");
+        TIFFErrorExtR(tif, TIFFFileName(tif), "No space for strip buffer");
         return (0);
     }
     y = setorientation(img, h);
diff --git a/libtiff/libtiff.def b/libtiff/libtiff.def
index 421dfeab..ee5486a6 100644
--- a/libtiff/libtiff.def
+++ b/libtiff/libtiff.def
@@ -5,6 +5,7 @@ EXPORTS	TIFFAccessTagMethods
 	TIFFCheckpointDirectory
 	TIFFCleanup
 	TIFFClientOpen
+	TIFFClientOpenEx
 	TIFFClientdata
 	TIFFClose
 	TIFFComputeStrip
diff --git a/libtiff/libtiff.map b/libtiff/libtiff.map
index 3dcefe3a..4c66ed41 100644
--- a/libtiff/libtiff.map
+++ b/libtiff/libtiff.map
@@ -202,4 +202,5 @@ LIBTIFF_4.4 {
 
 LIBTIFF_4.5 {
     _TIFFClampDoubleToUInt32;
+    TIFFClientOpenEx;
 } LIBTIFF_4.4;
diff --git a/libtiff/tif_aux.c b/libtiff/tif_aux.c
index bfb68a7b..6b800b28 100644
--- a/libtiff/tif_aux.c
+++ b/libtiff/tif_aux.c
@@ -36,7 +36,7 @@ uint32_t
 _TIFFMultiply32(TIFF* tif, uint32_t first, uint32_t second, const char* where)
 {
 	if (second && first > UINT32_MAX / second) {
-		TIFFErrorExt(tif->tif_clientdata, where, "Integer overflow in %s", where);
+		TIFFErrorExtR(tif, where, "Integer overflow in %s", where);
 		return 0;
 	}
 
@@ -47,7 +47,7 @@ uint64_t
 _TIFFMultiply64(TIFF* tif, uint64_t first, uint64_t second, const char* where)
 {
 	if (second && first > UINT64_MAX / second) {
-		TIFFErrorExt(tif->tif_clientdata, where, "Integer overflow in %s", where);
+		TIFFErrorExtR(tif, where, "Integer overflow in %s", where);
 		return 0;
 	}
 
@@ -61,7 +61,7 @@ _TIFFMultiplySSize(TIFF* tif, tmsize_t first, tmsize_t second, const char* where
     {
         if( tif != NULL && where != NULL )
         {
-            TIFFErrorExt(tif->tif_clientdata, where,
+            TIFFErrorExtR(tif, where,
                         "Invalid argument to _TIFFMultiplySSize() in %s", where);
         }
         return 0;
@@ -71,7 +71,7 @@ _TIFFMultiplySSize(TIFF* tif, tmsize_t first, tmsize_t second, const char* where
     {
         if( tif != NULL && where != NULL )
         {
-            TIFFErrorExt(tif->tif_clientdata, where,
+            TIFFErrorExtR(tif, where,
                         "Integer overflow in %s", where);
         }
         return 0;
@@ -85,7 +85,7 @@ tmsize_t _TIFFCastUInt64ToSSize(TIFF* tif, uint64_t val, const char* module)
     {
         if( tif != NULL && module != NULL )
         {
-            TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow");
+            TIFFErrorExtR(tif,module,"Integer overflow");
         }
         return 0;
     }
@@ -107,7 +107,7 @@ _TIFFCheckRealloc(TIFF* tif, void* buffer,
 	}
 
 	if (cp == NULL) {
-		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+		TIFFErrorExtR(tif, tif->tif_name,
 			     "Failed to allocate memory for %s "
 			     "(%"TIFF_SSIZE_FORMAT" elements of %"TIFF_SSIZE_FORMAT" bytes each)",
 			     what, nmemb, elem_size);
@@ -265,7 +265,7 @@ TIFFVGetFieldDefaulted(TIFF* tif, uint32_t tag, va_list ap)
         TIFFPredictorState* sp = (TIFFPredictorState*) tif->tif_data;
         if( sp == NULL )
         {
-            TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+            TIFFErrorExtR(tif, tif->tif_name,
                          "Cannot get \"Predictor\" tag as plugin is not configured");
             *va_arg(ap, uint16_t*) = 0;
             return 0;
@@ -333,7 +333,7 @@ TIFFVGetFieldDefaulted(TIFF* tif, uint32_t tag, va_list ap)
 	case TIFFTAG_TRANSFERFUNCTION:
 		if (!td->td_transferfunction[0] &&
 		    !TIFFDefaultTransferFunction(td)) {
-			TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "No space for \"TransferFunction\" tag");
+			TIFFErrorExtR(tif, tif->tif_name, "No space for \"TransferFunction\" tag");
 			return (0);
 		}
 		*va_arg(ap, const uint16_t **) = td->td_transferfunction[0];
diff --git a/libtiff/tif_codec.c b/libtiff/tif_codec.c
index 931eb093..c1c19411 100644
--- a/libtiff/tif_codec.c
+++ b/libtiff/tif_codec.c
@@ -115,7 +115,7 @@ _notConfigured(TIFF* tif)
         char compression_code[20];
         
         sprintf(compression_code, "%"PRIu16, tif->tif_dir.td_compression );
-	TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+	TIFFErrorExtR(tif, tif->tif_name,
                      "%s compression support is not configured", 
                      c ? c->name : compression_code );
 	return (0);
diff --git a/libtiff/tif_compress.c b/libtiff/tif_compress.c
index 8fcedf45..3a9efb75 100644
--- a/libtiff/tif_compress.c
+++ b/libtiff/tif_compress.c
@@ -35,11 +35,11 @@ TIFFNoEncode(TIFF* tif, const char* method)
 	const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression);
 
 	if (c) {
-		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+		TIFFErrorExtR(tif, tif->tif_name,
 			     "%s %s encoding is not implemented",
 			     c->name, method);
 	} else {
-		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+		TIFFErrorExtR(tif, tif->tif_name,
 			"Compression scheme %"PRIu16" %s encoding is not implemented",
 			     tif->tif_dir.td_compression, method);
 	}
@@ -73,11 +73,11 @@ TIFFNoDecode(TIFF* tif, const char* method)
 	const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression);
 
 	if (c)
-		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+		TIFFErrorExtR(tif, tif->tif_name,
 			     "%s %s decoding is not implemented",
 			     c->name, method);
 	else
-		TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+		TIFFErrorExtR(tif, tif->tif_name,
 			     "Compression scheme %"PRIu16" %s decoding is not implemented",
 			     tif->tif_dir.td_compression, method);
 	return (0);
@@ -115,7 +115,7 @@ int
 _TIFFNoSeek(TIFF* tif, uint32_t off)
 {
 	(void) off;
-	TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+	TIFFErrorExtR(tif, tif->tif_name,
 		     "Compression algorithm does not support random access");
 	return (0);
 }
diff --git a/libtiff/tif_dir.c b/libtiff/tif_dir.c
index d09754fd..73fb5b32 100644
--- a/libtiff/tif_dir.c
+++ b/libtiff/tif_dir.c
@@ -120,7 +120,7 @@ setExtraSamples(TIFF* tif, va_list ap, uint32_t* v)
         if ( td->td_transferfunction[0] != NULL && (td->td_samplesperpixel - *v > 1) &&
                 !(td->td_samplesperpixel - td->td_extrasamples > 1))
         {
-                TIFFWarningExt(tif->tif_clientdata,module,
+                TIFFWarningExtR(tif,module,
                     "ExtraSamples tag value is changing, "
                     "but TransferFunction was read with a different value. Canceling it");
                 TIFFClrFieldBit(tif,FIELD_TRANSFERFUNCTION);
@@ -157,7 +157,7 @@ countInkNamesString(TIFF *tif, uint32_t slen, const char *s)
 		return (i);
 	}
 bad:
-	TIFFErrorExt(tif->tif_clientdata, "TIFFSetField",
+	TIFFErrorExtR(tif, "TIFFSetField",
 		"%s: Invalid InkNames value; no NUL at given buffer end location %"PRIu32", after %"PRIu16" ink",
 		tif->tif_name, slen, i);
 	return (0);
@@ -270,7 +270,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
             /* See http://bugzilla.maptools.org/show_bug.cgi?id=2500 */
             if( td->td_sminsamplevalue != NULL )
             {
-                TIFFWarningExt(tif->tif_clientdata,module,
+                TIFFWarningExtR(tif,module,
                     "SamplesPerPixel tag value is changing, "
                     "but SMinSampleValue tag was read with a different value. Canceling it");
                 TIFFClrFieldBit(tif,FIELD_SMINSAMPLEVALUE);
@@ -279,7 +279,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
             }
             if( td->td_smaxsamplevalue != NULL )
             {
-                TIFFWarningExt(tif->tif_clientdata,module,
+                TIFFWarningExtR(tif,module,
                     "SamplesPerPixel tag value is changing, "
                     "but SMaxSampleValue tag was read with a different value. Canceling it");
                 TIFFClrFieldBit(tif,FIELD_SMAXSAMPLEVALUE);
@@ -291,7 +291,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
             if( td->td_transferfunction[0] != NULL && (v - td->td_extrasamples > 1) &&
                 !(td->td_samplesperpixel - td->td_extrasamples > 1))
             {
-                    TIFFWarningExt(tif->tif_clientdata,module,
+                    TIFFWarningExtR(tif,module,
                         "SamplesPerPixel tag value is changing, "
                         "but TransferFunction was read with a different value. Canceling it");
                     TIFFClrFieldBit(tif,FIELD_TRANSFERFUNCTION);
@@ -389,7 +389,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
 		if (v32 % 16) {
 			if (tif->tif_mode != O_RDONLY)
 				goto badvalue32;
-			TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+			TIFFWarningExtR(tif, tif->tif_name,
 				"Nonstandard tile width %"PRIu32", convert file", v32);
 		}
 		td->td_tilewidth = v32;
@@ -400,7 +400,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
 		if (v32 % 16) {
 			if (tif->tif_mode != O_RDONLY)
 				goto badvalue32;
-			TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+			TIFFWarningExtR(tif, tif->tif_name,
 			    "Nonstandard tile length %"PRIu32", convert file", v32);
 		}
 		td->td_tilelength = v32;
@@ -449,7 +449,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
 			_TIFFsetLong8Array(&td->td_subifd, (uint64_t*) va_arg(ap, uint64_t*),
 			    (uint32_t) td->td_nsubifd);
 		} else {
-			TIFFErrorExt(tif->tif_clientdata, module,
+			TIFFErrorExtR(tif, module,
 				     "%s: Sorry, cannot nest SubIFDs",
 				     tif->tif_name);
 			status = 0;
@@ -489,7 +489,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
 				if (TIFFFieldSet(tif, FIELD_NUMBEROFINKS))
 				{
 					if (td->td_numberofinks != ninksinstring) {
-						TIFFErrorExt(tif->tif_clientdata, module,
+						TIFFErrorExtR(tif, module,
 							"Warning %s; Tag %s:\n  Value %"PRIu16" of NumberOfInks is different from the number of inks %"PRIu16".\n  -> NumberOfInks value adapted to %"PRIu16"",
 							tif->tif_name, fip->field_name, td->td_numberofinks, ninksinstring, ninksinstring);
 						td->td_numberofinks = ninksinstring;
@@ -501,7 +501,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
 				if (TIFFFieldSet(tif, FIELD_SAMPLESPERPIXEL))
 				{
 					if (td->td_numberofinks != td->td_samplesperpixel) {
-						TIFFErrorExt(tif->tif_clientdata, module,
+						TIFFErrorExtR(tif, module,
 							"Warning %s; Tag %s:\n  Value %"PRIu16" of NumberOfInks is different from the SamplesPerPixel value %"PRIu16"",
 							tif->tif_name, fip->field_name, td->td_numberofinks, td->td_samplesperpixel);
 					}
@@ -515,7 +515,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
 		if (TIFFFieldSet(tif, FIELD_INKNAMES))
 		{
 			if (v != td->td_numberofinks) {
-				TIFFErrorExt(tif->tif_clientdata, module,
+				TIFFErrorExtR(tif, module,
 					"Error %s; Tag %s:\n  It is not possible to set the value %"PRIu32" for NumberOfInks\n  which is different from the number of inks in the InkNames tag (%"PRIu16")",
 					tif->tif_name, fip->field_name, v, td->td_numberofinks);
 				/* Do not set / overwrite number of inks already set by InkNames case accordingly. */
@@ -526,7 +526,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
 			if (TIFFFieldSet(tif, FIELD_SAMPLESPERPIXEL))
 			{
 				if (td->td_numberofinks != td->td_samplesperpixel) {
-					TIFFErrorExt(tif->tif_clientdata, module,
+					TIFFErrorExtR(tif, module,
 						"Warning %s; Tag %s:\n  Value %"PRIu32" of NumberOfInks is different from the SamplesPerPixel value %"PRIu16"",
 						tif->tif_name, fip->field_name, v, td->td_samplesperpixel);
 				}
@@ -556,7 +556,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
 		 * This also happens when a FIELD_IGNORE tag is written.
 		 */
 		if (fip->field_bit == FIELD_IGNORE) {
-			TIFFErrorExt(tif->tif_clientdata, module,
+			TIFFErrorExtR(tif, module,
 				"%s: Ignored %stag \"%s\" (not supported by libtiff)",
 				tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "",
 				fip->field_name);
@@ -564,7 +564,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
 			break;
 		}
 		if(fip->field_bit != FIELD_CUSTOM) {
-			TIFFErrorExt(tif->tif_clientdata, module,
+			TIFFErrorExtR(tif, module,
 			    "%s: Invalid %stag \"%s\" (not supported by codec)",
 			    tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "",
 			    fip->field_name);
@@ -598,7 +598,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
 			    _TIFFrealloc(td->td_customValues,
 			    sizeof(TIFFTagValue) * td->td_customValueCount);
 			if (!new_customValues) {
-				TIFFErrorExt(tif->tif_clientdata, module,
+				TIFFErrorExtR(tif, module,
 				    "%s: Failed to allocate space for list of custom values",
 				    tif->tif_name);
 				status = 0;
@@ -620,7 +620,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
 		tv_size = TIFFFieldSetGetSize(fip);
 		if (tv_size == 0) {
 			status = 0;
-			TIFFErrorExt(tif->tif_clientdata, module,
+			TIFFErrorExtR(tif, module,
 			    "%s: Bad field type %d for \"%s\"",
 			    tif->tif_name, fip->field_type,
 			    fip->field_name);
@@ -644,7 +644,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
 				if( len >= 0x80000000U )
 				{
 					status = 0;
-					TIFFErrorExt(tif->tif_clientdata, module,
+					TIFFErrorExtR(tif, module,
 					    "%s: Too long string value for \"%s\". "
 					    "Maximum supported is 2147483647 bytes",
 					    tif->tif_name,
@@ -673,7 +673,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
 
 			if (tv->count == 0) {
 				status = 0;
-				TIFFErrorExt(tif->tif_clientdata, module,
+				TIFFErrorExtR(tif, module,
 					     "%s: Null count for \"%s\" (type "
 					     "%d, writecount %d, passcount %d)",
 					     tif->tif_name,
@@ -717,7 +717,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
 						uint64_t *pui64 = (uint64_t *)tv->value;
 						for (int i = 0; i < tv->count; i++) {
 							if (pui64[i] > 0xffffffffu) {
-								TIFFErrorExt(tif->tif_clientdata, module,
+								TIFFErrorExtR(tif, module,
 									"%s: Bad LONG8 value %"PRIu64" at %d. array position for \"%s\" tag %d in ClassicTIFF. Tag won't be written to file",
 									tif->tif_name, pui64[i], i, fip->field_name, tag);
 								goto badvalueifd8long8;
@@ -727,7 +727,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
 						int64_t *pi64 = (int64_t *)tv->value;
 						for (int i = 0; i < tv->count; i++) {
 							if (pi64[i] > 2147483647 || pi64[i] < (-2147483647 - 1)) {
-								TIFFErrorExt(tif->tif_clientdata, module,
+								TIFFErrorExtR(tif, module,
 									"%s: Bad SLONG8 value %"PRIi64" at %d. array position for \"%s\" tag %d in ClassicTIFF. Tag won't be written to file",
 									tif->tif_name, pi64[i], i, fip->field_name, tag);
 								goto badvalueifd8long8;
@@ -785,7 +785,7 @@ _TIFFVSetField(TIFF* tif, uint32_t tag, va_list ap)
 						_TIFFmemcpy(val, &v2, tv_size);
 						/* Test here for too big values for ClassicTIFF and delete custom field from custom list */
 						if (!(tif->tif_flags & TIFF_BIGTIFF) && (v2 > 0xffffffffu)) {
-							TIFFErrorExt(tif->tif_clientdata, module,
+							TIFFErrorExtR(tif, module,
 								"%s: Bad LONG8 or IFD8 value %"PRIu64" for \"%s\" tag %d in ClassicTIFF. Tag won't be written to file",
 								tif->tif_name, v2, fip->field_name, tag);
 							goto badvalueifd8long8;
@@ -798,7 +798,7 @@ _TIFFVSetField(TIFF* tif, uint

(Patch may be truncated, please check the link at the top of this post.)