Skip to content

Commit 34b29f3

Browse files
authored
fix: broken pgm having memory access error (#4559)
Fixes #4552 Caught during fuzzing with address sanitizer. The source of the problem was a corrupted/truncated pgm file. Several minor modifications in this PR shore up various cascading errors that followed. Not all were directly causal to the sanitizer trigger, in some cases I fixed what appeared to be related areas. * In imagebuf.cpp, any time we free the local pixel memory m_pixels, also explicitly clear the m_bufspan that has a span representation of the usable memory and its bounds. * An extra check related to oiiotool --printstats to make sure that the image is valid before passing along to stats collection. * In pnminput.cpp, a better error message when we hit a premature end of file. With these fixes in place, we seem to get a graceful error message and exit when running the POC that was provided with the bug report. Signed-off-by: Larry Gritz <[email protected]>
1 parent 78927ac commit 34b29f3

File tree

6 files changed

+26
-3
lines changed

6 files changed

+26
-3
lines changed

src/libOpenImageIO/imagebuf.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,7 @@ ImageBufImpl::new_pixels(size_t size, const void* data)
687687
// consider this an uninitialized ImageBuf, issue an error, and hope
688688
// it's handled well downstream.
689689
m_pixels.reset();
690+
m_bufspan = make_span<std::byte>(nullptr, 0);
690691
OIIO::debugfmt("ImageBuf unable to allocate {} bytes ({})\n", size,
691692
e.what());
692693
error("ImageBuf unable to allocate {} bytes ({})\n", size, e.what());
@@ -720,6 +721,8 @@ ImageBufImpl::free_pixels()
720721
m_allocated_size = 0;
721722
}
722723
m_pixels.reset();
724+
// print("IB Freed pixels of length {}\n", m_bufspan.size());
725+
m_bufspan = make_span<std::byte>(nullptr, 0);
723726
m_deepdata.free();
724727
m_storage = ImageBuf::UNINITIALIZED;
725728
m_blackpixel.clear();
@@ -806,6 +809,7 @@ ImageBufImpl::clear()
806809
m_spec = ImageSpec();
807810
m_nativespec = ImageSpec();
808811
m_pixels.reset();
812+
m_bufspan = make_span<std::byte>(nullptr, 0);
809813
m_localpixels = nullptr;
810814
m_spec_valid = false;
811815
m_pixels_valid = false;

src/oiiotool/oiiotool.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5801,7 +5801,8 @@ action_printstats(Oiiotool& ot, cspan<const char*> argv)
58015801
auto options = ot.extract_options(command);
58025802
bool allsubimages = options.get_int("allsubimages", ot.allsubimages);
58035803

5804-
ot.read();
5804+
if (!ot.read())
5805+
return;
58055806
ImageRecRef top = ot.top();
58065807

58075808
print_info_options opt = ot.info_opts();
@@ -5818,6 +5819,7 @@ action_printstats(Oiiotool& ot, cspan<const char*> argv)
58185819
opt.roi.chend);
58195820
}
58205821
std::string errstring;
5822+
OIIO_ASSERT(top.get());
58215823
print_info(std::cout, ot, top.get(), opt, errstring);
58225824

58235825
ot.printed_info = true;

src/pnm.imageio/pnminput.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,10 @@ PNMInput::read_file_scanline(void* data, int y)
223223
numbytes = m_spec.nchannels * 4 * m_spec.width;
224224
else
225225
numbytes = m_spec.scanline_bytes();
226-
if (size_t(numbytes) > m_remaining.size())
226+
if (size_t(numbytes) > m_remaining.size()) {
227+
errorfmt("Premature end of file");
227228
return false;
229+
}
228230
buf.assign(m_remaining.begin(), m_remaining.begin() + numbytes);
229231

230232
m_remaining.remove_prefix(numbytes);

testsuite/pnm/ref/out.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,17 @@ Reading ../oiio-images/pnm/test-3.pfm
6969
oiio:ColorSpace: "Rec709"
7070
pnm:bigendian: 1
7171
pnm:binary: 1
72+
Reading src/bad-4552.pgm
73+
oiiotool ERROR: -info : SHA-1: Premature end of file
74+
Full command line was:
75+
> oiiotool --info -v -a --hash --oiioattrib try_all_readers 0 --printstats src/bad-4552.pgm
76+
src/bad-4552.pgm : 9 x 1, 1 channel, uint8 pnm
77+
channel list: Y
78+
oiio:ColorSpace: "Rec709"
79+
pnm:binary: 1
80+
oiiotool ERROR: read : "src/bad-4552.pgm": Premature end of file
81+
Full command line was:
82+
> oiiotool --info -v -a --hash --oiioattrib try_all_readers 0 --printstats src/bad-4552.pgm
7283
oiiotool ERROR: read : "src/bad-4553.pgm": pnm image resolution may not exceed 65535x65535, but the file appears to be 2147483647x255. Possible corrupt input?
7384
Full command line was:
7485
> oiiotool --info -v -a --hash --oiioattrib try_all_readers 0 --printstats src/bad-4553.pgm

testsuite/pnm/run.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@
2020
safematch=True, hash=True)
2121

2222
# Damaged files
23-
files = [ "src/bad-4553.pgm" ]
23+
files = [ "src/bad-4552.pgm", "src/bad-4553.pgm" ]
2424
for f in files:
2525
command += info_command (f, extraargs="--oiioattrib try_all_readers 0 --printstats", failureok=True)

testsuite/pnm/src/bad-4552.pgm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
P5
2+
9 1
3+
255
4+

0 commit comments

Comments
 (0)