@@ -62,11 +62,10 @@ my_error_exit(j_common_ptr cinfo)
6262{
6363 /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
6464 JpgInput::my_error_ptr myerr = (JpgInput::my_error_ptr)cinfo->err ;
65+ OIIO_ASSERT (myerr);
6566
66- /* Always display the message. */
67- /* We could postpone this until after returning, if we chose. */
68- // (*cinfo->err->output_message) (cinfo);
69- myerr->jpginput ->jpegerror (myerr, true );
67+ if (myerr->jpginput )
68+ myerr->jpginput ->jpegerror (myerr, true );
7069
7170 /* Return control to the setjmp point */
7271 longjmp (myerr->setjmp_buffer , 1 );
@@ -78,11 +77,10 @@ static void
7877my_output_message (j_common_ptr cinfo)
7978{
8079 JpgInput::my_error_ptr myerr = (JpgInput::my_error_ptr)cinfo->err ;
80+ OIIO_ASSERT (myerr);
8181
82- // Create the message
83- char buffer[JMSG_LENGTH_MAX];
84- (*cinfo->err ->format_message )(cinfo, buffer);
85- myerr->jpginput ->jpegerror (myerr, false );
82+ if (myerr->jpginput )
83+ myerr->jpginput ->jpegerror (myerr, false );
8684
8785 // This function is called only for non-fatal problems, so we don't
8886 // need to do the longjmp.
122120JpgInput::jpegerror (my_error_ptr /* myerr*/ , bool fatal)
123121{
124122 // Send the error message to the ImageInput
125- char errbuf[JMSG_LENGTH_MAX];
123+ char errbuf[JMSG_LENGTH_MAX] = " " ;
126124 (*m_cinfo.err ->format_message )((j_common_ptr)&m_cinfo, errbuf);
127125 errorfmt (" JPEG error: {} (\" {}\" )" , errbuf, filename ());
128126
@@ -273,21 +271,25 @@ JpgInput::open(const std::string& name, ImageSpec& newspec)
273271 m_spec.attribute (JPEG_SUBSAMPLING_ATTR, subsampling);
274272
275273 for (jpeg_saved_marker_ptr m = m_cinfo.marker_list ; m; m = m->next ) {
276- if (m->marker == (JPEG_APP0 + 1 )
277- && !strcmp ((const char *)m->data , " Exif" )) {
274+ if (m->marker == (JPEG_APP0 + 1 ) && m-> data_length >= 4
275+ && !strncmp ((const char *)m->data , " Exif" , 4 )) {
278276 // The block starts with "Exif\0\0", so skip 6 bytes to get
279277 // to the start of the actual Exif data TIFF directory
280278 decode_exif (string_view ((char *)m->data + 6 , m->data_length - 6 ),
281279 m_spec);
282- } else if (m->marker == (JPEG_APP0 + 1 )
283- && !strcmp ((const char *)m->data ,
284- " http://ns.adobe.com/xap/1.0/" )) { // NOSONAR
280+ } else if (m->marker == (JPEG_APP0 + 1 ) && m-> data_length >= 28
281+ && !strncmp ((const char *)m->data ,
282+ " http://ns.adobe.com/xap/1.0/" , 28 )) { // NOSONAR
285283 std::string xml ((const char *)m->data , m->data_length );
286284 decode_xmp (xml, m_spec);
287- } else if (m->marker == (JPEG_APP0 + 13 )
288- && !strcmp ((const char *)m->data , " Photoshop 3.0" ))
289- jpeg_decode_iptc ((unsigned char *)m->data );
290- else if (m->marker == JPEG_COM) {
285+ } else if (m->marker == (JPEG_APP0 + 13 ) && m->data_length >= 13
286+ && !strncmp ((const char *)m->data , " Photoshop 3.0" , 13 )) {
287+ if (!jpeg_decode_iptc (
288+ string_view ((const char *)m->data , m->data_length ))) {
289+ errorfmt (" Corrupted IPTC data" );
290+ return false ;
291+ }
292+ } else if (m->marker == JPEG_COM) {
291293 std::string data ((const char *)m->data , m->data_length );
292294 // Additional string metadata can be stored in JPEG files as
293295 // comment markers in the form "key:value" or "ident:key:value".
@@ -646,17 +648,17 @@ JpgInput::read_native_scanlines(int subimage, int miplevel, int ybegin,
646648 return false ;
647649 }
648650
649- int nscanlines = yend - ybegin;
651+ int64_t nscanlines = yend - ybegin;
650652 size_t sl_bytes = m_spec.scanline_bytes (true /* native*/ );
651653 JSAMPLE** readdata = OIIO_ALLOCA (JSAMPLE*, nscanlines);
652- for (int i = 0 ; i < nscanlines; ++i)
654+ for (int64_t i = 0 ; i < nscanlines; ++i)
653655 readdata[i] = reinterpret_cast <JSAMPLE*>(&data[i * sl_bytes]);
654656
655657 if (m_cmyk) {
656658 // If the file's data is CMYK, read into a 4-channel buffer, then
657659 // we'll have to convert.
658660 m_cmyk_buf.resize (m_spec.width * 4 * nscanlines);
659- for (int i = 0 ; i < nscanlines; ++i)
661+ for (int64_t i = 0 ; i < nscanlines; ++i)
660662 readdata[i] = reinterpret_cast <JSAMPLE*>(m_cmyk_buf.data ()
661663 + i * m_spec.width * 4 );
662664 OIIO_DASSERT (m_spec.nchannels == 3 );
@@ -685,7 +687,7 @@ JpgInput::read_native_scanlines(int subimage, int miplevel, int ybegin,
685687 m_next_scanline = yend;
686688
687689 if (m_cmyk) {
688- for (int i = 0 ; i < nscanlines; ++i)
690+ for (int64_t i = 0 ; i < nscanlines; ++i)
689691 cmyk_to_rgb (make_cspan (readdata[i], m_spec.width * 4 ),
690692 span_cast<unsigned char >(data).subspan (
691693 m_spec.width * 3 * i, m_spec.width * 3 ));
@@ -717,34 +719,51 @@ JpgInput::close()
717719
718720
719721
720- void
721- JpgInput::jpeg_decode_iptc (const unsigned char * buf)
722+ bool
723+ JpgInput::jpeg_decode_iptc (string_view buf)
722724{
723725 // APP13 blob doesn't have to be IPTC info. Look for the IPTC marker,
724726 // which is the string "Photoshop 3.0" followed by a null character.
725- if (strcmp ((const char *)buf, " Photoshop 3.0" ))
726- return ;
727- buf += strlen (" Photoshop 3.0" ) + 1 ;
727+ if (!Strutil::starts_with (buf, " Photoshop 3.0" ))
728+ return false ;
729+ buf.remove_prefix (13 );
730+ if (buf.size () < 1 || buf[0 ] != ' \0 ' )
731+ return false ;
732+ buf.remove_prefix (1 );
728733
729734 // Next are the 4 bytes "8BIM"
730- if (strncmp (( const char *) buf, " 8BIM" , 4 ))
731- return ;
732- buf += 4 ;
735+ if (! Strutil::starts_with ( buf, " 8BIM" ))
736+ return false ;
737+ buf. remove_prefix ( 4 ) ;
733738
734739 // Next two bytes are the segment type, in big endian.
735740 // We expect 1028 to indicate IPTC data block.
736- if (((buf[0 ] << 8 ) + buf[1 ]) != 1028 )
737- return ;
738- buf += 2 ;
741+ if (buf.size () < 2
742+ || ((static_cast <unsigned char >(buf[0 ]) << 8 )
743+ + static_cast <unsigned char >(buf[1 ]))
744+ != 1028 )
745+ return false ;
746+ buf.remove_prefix (2 );
739747
740748 // Next are 4 bytes of 0 padding, just skip it.
741- buf += 4 ;
749+ if (buf.size () < 4 )
750+ return false ;
751+ buf.remove_prefix (4 );
742752
743753 // Next is 2 byte (big endian) giving the size of the segment
744- int segmentsize = (buf[0 ] << 8 ) + buf[1 ];
745- buf += 2 ;
754+ if (buf.size () < 2 )
755+ return false ;
756+ size_t segmentsize = (static_cast <unsigned char >(buf[0 ]) << 8 )
757+ + static_cast <unsigned char >(buf[1 ]);
758+ buf.remove_prefix (2 );
759+
760+ // Ensure the declared segment size does not exceed the remaining buffer,
761+ // then restrict buf to exactly segmentsize bytes.
762+ if (segmentsize > buf.size ())
763+ return false ;
764+ buf = buf.substr (0 , segmentsize);
746765
747- decode_iptc_iim (buf, segmentsize , m_spec);
766+ return decode_iptc_iim (buf, m_spec);
748767}
749768
750769OIIO_PLUGIN_NAMESPACE_END
0 commit comments