From c8c42b18d051b5c23e40bd72e98355cd49c42fab Mon Sep 17 00:00:00 2001 From: Melissa Linkert Date: Wed, 13 May 2026 13:09:12 -0500 Subject: [PATCH] Check for null when calling TiffParser.checkHeader() Fixes #4232. --- .../src/loci/formats/out/PyramidOMETiffWriter.java | 7 ++++++- .../formats-bsd/src/loci/formats/tiff/TiffParser.java | 5 ++++- .../test/loci/formats/utests/tiff/TiffParserTest.java | 5 +++++ .../test/loci/formats/utests/tiff/TiffSaverTest.java | 4 ++++ .../formats-gpl/src/loci/formats/in/LeicaReader.java | 6 +++++- .../formats-gpl/src/loci/formats/in/MetamorphReader.java | 5 ++++- .../formats-gpl/src/loci/formats/in/ZeissLSMReader.java | 3 +++ 7 files changed, 31 insertions(+), 4 deletions(-) diff --git a/components/formats-bsd/src/loci/formats/out/PyramidOMETiffWriter.java b/components/formats-bsd/src/loci/formats/out/PyramidOMETiffWriter.java index 911d72a3161..3c26de5f9f5 100644 --- a/components/formats-bsd/src/loci/formats/out/PyramidOMETiffWriter.java +++ b/components/formats-bsd/src/loci/formats/out/PyramidOMETiffWriter.java @@ -126,7 +126,12 @@ public void close() throws IOException { long[] allOffsets = null; try (RandomAccessInputStream in = new RandomAccessInputStream(id)) { TiffParser parser = new TiffParser(in); - littleEndian = parser.checkHeader(); + Boolean writtenLittleEndian = parser.checkHeader(); + if (writtenLittleEndian == null) { + // this would be extremely unexpected + throw new IOException("Endian check failed on written data"); + } + littleEndian = writtenLittleEndian; allOffsets = parser.getIFDOffsets(); } diff --git a/components/formats-bsd/src/loci/formats/tiff/TiffParser.java b/components/formats-bsd/src/loci/formats/tiff/TiffParser.java index 57f95611936..2ae7895f5a9 100644 --- a/components/formats-bsd/src/loci/formats/tiff/TiffParser.java +++ b/components/formats-bsd/src/loci/formats/tiff/TiffParser.java @@ -114,7 +114,10 @@ public TiffParser(RandomAccessInputStream in) { doCaching = true; try { long fp = in.getFilePointer(); - checkHeader(); + Boolean littleEndian = checkHeader(); + if (littleEndian == null) { + LOGGER.error("Endian check failed, this may be an invalid file"); + } in.seek(fp); } catch (IOException e) { } diff --git a/components/formats-bsd/test/loci/formats/utests/tiff/TiffParserTest.java b/components/formats-bsd/test/loci/formats/utests/tiff/TiffParserTest.java index f839cc15241..724ee7d9ac6 100644 --- a/components/formats-bsd/test/loci/formats/utests/tiff/TiffParserTest.java +++ b/components/formats-bsd/test/loci/formats/utests/tiff/TiffParserTest.java @@ -73,6 +73,7 @@ public void setUp(String mockClassName) throws Exception { @Test public void testHeader() throws IOException { assertTrue(tiffParser.isValidHeader()); + // isValidHeader above makes sure that checkHeader is non-null assertTrue(tiffParser.checkHeader()); assertFalse(tiffParser.isBigTiff()); } @@ -178,6 +179,8 @@ public void testGetResolutionUnit() throws IOException, FormatException { public void testNonUniformRowsPerStrip() throws IOException, FormatException { mock = new NonUniformRowsPerStripMock(); tiffParser = mock.getTiffParser(); + assertTrue(tiffParser.isValidHeader()); + // isValidHeader above makes sure that checkHeader is non-null assertTrue(tiffParser.checkHeader()); tiffParser.getFirstIFD().getRowsPerStrip(); mock.close(); @@ -187,6 +190,8 @@ public void testNonUniformRowsPerStrip() throws IOException, FormatException { public void testBitsPerSampleMismatch() throws IOException, FormatException { mock = new BitsPerSampleSamplesPerPixelMismatchMock(); tiffParser = mock.getTiffParser(); + assertTrue(tiffParser.isValidHeader()); + // isValidHeader above makes sure that checkHeader is non-null assertTrue(tiffParser.checkHeader()); IFD ifd = tiffParser.getFirstIFD(); int[] bitsPerSample = ifd.getBitsPerSample(); diff --git a/components/formats-bsd/test/loci/formats/utests/tiff/TiffSaverTest.java b/components/formats-bsd/test/loci/formats/utests/tiff/TiffSaverTest.java index 46d3750b562..5659221cc15 100644 --- a/components/formats-bsd/test/loci/formats/utests/tiff/TiffSaverTest.java +++ b/components/formats-bsd/test/loci/formats/utests/tiff/TiffSaverTest.java @@ -117,6 +117,7 @@ public void testNullBytes() throws IOException { public void testWriteHeaderBigEndianRegularTiff() throws IOException { tiffSaver.writeHeader(); assertTrue(tiffParser.isValidHeader()); + // isValidHeader above makes sure that checkHeader is non-null assertFalse(tiffParser.checkHeader()); assertFalse(tiffParser.isBigTiff()); } @@ -126,6 +127,7 @@ public void testWriteHeaderLittleEndianRegularTiff() throws IOException { tiffSaver.setLittleEndian(true); tiffSaver.writeHeader(); assertTrue(tiffParser.isValidHeader()); + // isValidHeader above makes sure that checkHeader is non-null assertTrue(tiffParser.checkHeader()); assertFalse(tiffParser.isBigTiff()); } @@ -136,6 +138,7 @@ public void testWriteHeaderBigEndianBigTiff() throws IOException { tiffSaver.setBigTiff(true); tiffSaver.writeHeader(); assertTrue(tiffParser.isValidHeader()); + // isValidHeader above makes sure that checkHeader is non-null assertFalse(tiffParser.checkHeader()); assertTrue(tiffParser.isBigTiff()); } @@ -146,6 +149,7 @@ public void testWriteHeaderLittleEndianBigTiff() throws IOException { tiffSaver.setBigTiff(true); tiffSaver.writeHeader(); assertTrue(tiffParser.isValidHeader()); + // isValidHeader above makes sure that checkHeader is non-null assertTrue(tiffParser.checkHeader()); assertTrue(tiffParser.isBigTiff()); } diff --git a/components/formats-gpl/src/loci/formats/in/LeicaReader.java b/components/formats-gpl/src/loci/formats/in/LeicaReader.java index 5f890fb32f5..72814cad0e2 100644 --- a/components/formats-gpl/src/loci/formats/in/LeicaReader.java +++ b/components/formats-gpl/src/loci/formats/in/LeicaReader.java @@ -772,7 +772,11 @@ else if (checkSuffix(baseFile, TiffReader.TIFF_SUFFIXES) && isGroupFiles()) in = new RandomAccessInputStream(baseFile, 16); TiffParser tp = new TiffParser(in); - in.order(tp.checkHeader().booleanValue()); + Boolean littleEndian = tp.checkHeader(); + if (littleEndian == null) { + throw new FormatException("Invalid TIFF file"); + } + in.order(littleEndian.booleanValue()); in.seek(0); diff --git a/components/formats-gpl/src/loci/formats/in/MetamorphReader.java b/components/formats-gpl/src/loci/formats/in/MetamorphReader.java index 0fead33bd64..082137feab7 100644 --- a/components/formats-gpl/src/loci/formats/in/MetamorphReader.java +++ b/components/formats-gpl/src/loci/formats/in/MetamorphReader.java @@ -1170,7 +1170,10 @@ else if (exposureTimes.size() == 1 && exposureTimes.size() < getEffectiveSizeC() } stream = new RandomAccessInputStream(file, 16); tp = new TiffParser(stream); - tp.checkHeader(); + Boolean tiffLittleEndian = tp.checkHeader(); + if (tiffLittleEndian == null) { + throw new FormatException("Invalid TIFF file: " + file); + } IFDList f = tp.getMainIFDs(); if (f.size() > 0) { lastFile = fileIndex; diff --git a/components/formats-gpl/src/loci/formats/in/ZeissLSMReader.java b/components/formats-gpl/src/loci/formats/in/ZeissLSMReader.java index b33d2a042b4..9cecac8eed6 100644 --- a/components/formats-gpl/src/loci/formats/in/ZeissLSMReader.java +++ b/components/formats-gpl/src/loci/formats/in/ZeissLSMReader.java @@ -491,6 +491,9 @@ protected void initFile(String id) throws FormatException, IOException { int count = seriesCounts.get(lsmFilenames[i]); TiffParser tp = new TiffParser(stream); Boolean littleEndian = tp.checkHeader(); + if (littleEndian == null) { + throw new FormatException("Invalid TIFF file: " + lsmFilenames[i]); + } long[] ifdOffsets = tp.getIFDOffsets(); int ifdsPerSeries = (ifdOffsets.length / 2) / count;