Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(858)

Side by Side Diff: ui/gfx/codec/png_codec.cc

Issue 2576823002: Fix stack-use-after-scope in png_codec. (Closed)
Patch Set: BuildPNGStruct -> PngReadStructInfo::Build Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/gfx/codec/png_codec.h" 5 #include "ui/gfx/codec/png_codec.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/macros.h" 10 #include "base/macros.h"
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
306 306
307 void DecodeEndCallback(png_struct* png_ptr, png_info* info) { 307 void DecodeEndCallback(png_struct* png_ptr, png_info* info) {
308 PngDecoderState* state = static_cast<PngDecoderState*>( 308 PngDecoderState* state = static_cast<PngDecoderState*>(
309 png_get_progressive_ptr(png_ptr)); 309 png_get_progressive_ptr(png_ptr));
310 310
311 // Mark the image as complete, this will tell the Decode function that we 311 // Mark the image as complete, this will tell the Decode function that we
312 // have successfully found the end of the data. 312 // have successfully found the end of the data.
313 state->done = true; 313 state->done = true;
314 } 314 }
315 315
316 // Automatically destroys the given read structs on destruction to make 316 // Holds png struct and info ensuring the proper destruction.
317 // cleanup and error handling code cleaner. 317 class PngReadStructInfo {
318 class PngReadStructDestroyer {
319 public: 318 public:
320 PngReadStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) { 319 PngReadStructInfo(): png_ptr_(nullptr), info_ptr_(nullptr) {
321 } 320 }
322 ~PngReadStructDestroyer() { 321 ~PngReadStructInfo() {
323 png_destroy_read_struct(ps_, pi_, NULL); 322 png_destroy_read_struct(&png_ptr_, &info_ptr_, NULL);
324 } 323 }
324
325 bool Build(const unsigned char* input, size_t input_size) {
326 if (input_size < 8)
327 return false; // Input data too small to be a png
328
329 // Have libpng check the signature, it likes the first 8 bytes.
330 if (png_sig_cmp(const_cast<unsigned char*>(input), 0, 8) != 0)
331 return false;
332
333 png_ptr_ = png_create_read_struct(
334 PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
335 if (!png_ptr_)
336 return false;
337
338 info_ptr_ = png_create_info_struct(png_ptr_);
339 if (!info_ptr_) {
340 return false;
341 }
342 return true;
343 }
344
345 png_struct* png_ptr_;
346 png_info* info_ptr_;
325 private: 347 private:
326 png_struct** ps_; 348 DISALLOW_COPY_AND_ASSIGN(PngReadStructInfo);
327 png_info** pi_;
328 DISALLOW_COPY_AND_ASSIGN(PngReadStructDestroyer);
329 }; 349 };
330 350
331 // Automatically destroys the given write structs on destruction to make 351 // Holds png struct and info ensuring the proper destruction.
332 // cleanup and error handling code cleaner. 352 class PngWriteStructInfo {
333 class PngWriteStructDestroyer {
334 public: 353 public:
335 explicit PngWriteStructDestroyer(png_struct** ps) : ps_(ps), pi_(0) { 354 PngWriteStructInfo() : png_ptr_(nullptr), info_ptr_(nullptr) {
336 }
337 ~PngWriteStructDestroyer() {
338 png_destroy_write_struct(ps_, pi_);
339 }
340 void SetInfoStruct(png_info** pi) {
341 pi_ = pi;
342 }
343 private:
344 png_struct** ps_;
345 png_info** pi_;
346 DISALLOW_COPY_AND_ASSIGN(PngWriteStructDestroyer);
347 };
348
349 bool BuildPNGStruct(const unsigned char* input, size_t input_size,
350 png_struct** png_ptr, png_info** info_ptr) {
351 if (input_size < 8)
352 return false; // Input data too small to be a png
353
354 // Have libpng check the signature, it likes the first 8 bytes.
355 if (png_sig_cmp(const_cast<unsigned char*>(input), 0, 8) != 0)
356 return false;
357
358 *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
359 if (!*png_ptr)
360 return false;
361
362 *info_ptr = png_create_info_struct(*png_ptr);
363 if (!*info_ptr) {
364 png_destroy_read_struct(png_ptr, NULL, NULL);
365 return false;
366 } 355 }
367 356
368 return true; 357 ~PngWriteStructInfo() {
369 } 358 png_destroy_write_struct(&png_ptr_, &info_ptr_);
359 }
360
361 png_struct* png_ptr_;
362 png_info* info_ptr_;
363 private:
364 DISALLOW_COPY_AND_ASSIGN(PngWriteStructInfo);
365 };
370 366
371 // Libpng user error and warning functions which allows us to print libpng 367 // Libpng user error and warning functions which allows us to print libpng
372 // errors and warnings using Chrome's logging facilities instead of stderr. 368 // errors and warnings using Chrome's logging facilities instead of stderr.
373 369
374 void LogLibPNGDecodeError(png_structp png_ptr, png_const_charp error_msg) { 370 void LogLibPNGDecodeError(png_structp png_ptr, png_const_charp error_msg) {
375 DLOG(ERROR) << "libpng decode error: " << error_msg; 371 DLOG(ERROR) << "libpng decode error: " << error_msg;
376 longjmp(png_jmpbuf(png_ptr), 1); 372 longjmp(png_jmpbuf(png_ptr), 1);
377 } 373 }
378 374
379 void LogLibPNGDecodeWarning(png_structp png_ptr, png_const_charp warning_msg) { 375 void LogLibPNGDecodeWarning(png_structp png_ptr, png_const_charp warning_msg) {
380 DLOG(ERROR) << "libpng decode warning: " << warning_msg; 376 DLOG(ERROR) << "libpng decode warning: " << warning_msg;
381 } 377 }
382 378
383 void LogLibPNGEncodeError(png_structp png_ptr, png_const_charp error_msg) { 379 void LogLibPNGEncodeError(png_structp png_ptr, png_const_charp error_msg) {
384 DLOG(ERROR) << "libpng encode error: " << error_msg; 380 DLOG(ERROR) << "libpng encode error: " << error_msg;
385 longjmp(png_jmpbuf(png_ptr), 1); 381 longjmp(png_jmpbuf(png_ptr), 1);
386 } 382 }
387 383
388 void LogLibPNGEncodeWarning(png_structp png_ptr, png_const_charp warning_msg) { 384 void LogLibPNGEncodeWarning(png_structp png_ptr, png_const_charp warning_msg) {
389 DLOG(ERROR) << "libpng encode warning: " << warning_msg; 385 DLOG(ERROR) << "libpng encode warning: " << warning_msg;
390 } 386 }
391 387
392 } // namespace 388 } // namespace
393 389
394 // static 390 // static
395 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, 391 bool PNGCodec::Decode(const unsigned char* input, size_t input_size,
396 ColorFormat format, std::vector<unsigned char>* output, 392 ColorFormat format, std::vector<unsigned char>* output,
397 int* w, int* h) { 393 int* w, int* h) {
398 png_struct* png_ptr = NULL; 394 PngReadStructInfo si;
399 png_info* info_ptr = NULL; 395 if (!si.Build(input, input_size))
400 if (!BuildPNGStruct(input, input_size, &png_ptr, &info_ptr))
401 return false; 396 return false;
402 397
403 PngReadStructDestroyer destroyer(&png_ptr, &info_ptr); 398 if (setjmp(png_jmpbuf(si.png_ptr_))) {
404 if (setjmp(png_jmpbuf(png_ptr))) {
405 // The destroyer will ensure that the structures are cleaned up in this 399 // The destroyer will ensure that the structures are cleaned up in this
406 // case, even though we may get here as a jump from random parts of the 400 // case, even though we may get here as a jump from random parts of the
407 // PNG library called below. 401 // PNG library called below.
408 return false; 402 return false;
409 } 403 }
410 404
411 PngDecoderState state(format, output); 405 PngDecoderState state(format, output);
412 406
413 png_set_error_fn(png_ptr, NULL, LogLibPNGDecodeError, LogLibPNGDecodeWarning); 407 png_set_error_fn(si.png_ptr_, NULL,
414 png_set_progressive_read_fn(png_ptr, &state, &DecodeInfoCallback, 408 LogLibPNGDecodeError, LogLibPNGDecodeWarning);
409 png_set_progressive_read_fn(si.png_ptr_, &state, &DecodeInfoCallback,
415 &DecodeRowCallback, &DecodeEndCallback); 410 &DecodeRowCallback, &DecodeEndCallback);
416 png_process_data(png_ptr, 411 png_process_data(si.png_ptr_,
417 info_ptr, 412 si.info_ptr_,
418 const_cast<unsigned char*>(input), 413 const_cast<unsigned char*>(input),
419 input_size); 414 input_size);
420 415
421 if (!state.done) { 416 if (!state.done) {
422 // Fed it all the data but the library didn't think we got all the data, so 417 // Fed it all the data but the library didn't think we got all the data, so
423 // this file must be truncated. 418 // this file must be truncated.
424 output->clear(); 419 output->clear();
425 return false; 420 return false;
426 } 421 }
427 422
428 *w = state.width; 423 *w = state.width;
429 *h = state.height; 424 *h = state.height;
430 return true; 425 return true;
431 } 426 }
432 427
433 // static 428 // static
434 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, 429 bool PNGCodec::Decode(const unsigned char* input, size_t input_size,
435 SkBitmap* bitmap) { 430 SkBitmap* bitmap) {
436 DCHECK(bitmap); 431 DCHECK(bitmap);
437 png_struct* png_ptr = NULL; 432 PngReadStructInfo si;
438 png_info* info_ptr = NULL; 433 if (!si.Build(input, input_size))
439 if (!BuildPNGStruct(input, input_size, &png_ptr, &info_ptr))
440 return false; 434 return false;
441 435
442 PngReadStructDestroyer destroyer(&png_ptr, &info_ptr); 436 if (setjmp(png_jmpbuf(si.png_ptr_))) {
443 if (setjmp(png_jmpbuf(png_ptr))) {
444 // The destroyer will ensure that the structures are cleaned up in this 437 // The destroyer will ensure that the structures are cleaned up in this
445 // case, even though we may get here as a jump from random parts of the 438 // case, even though we may get here as a jump from random parts of the
446 // PNG library called below. 439 // PNG library called below.
447 return false; 440 return false;
448 } 441 }
449 442
450 PngDecoderState state(bitmap); 443 PngDecoderState state(bitmap);
451 444
452 png_set_progressive_read_fn(png_ptr, &state, &DecodeInfoCallback, 445 png_set_progressive_read_fn(si.png_ptr_, &state, &DecodeInfoCallback,
453 &DecodeRowCallback, &DecodeEndCallback); 446 &DecodeRowCallback, &DecodeEndCallback);
454 png_process_data(png_ptr, 447 png_process_data(si.png_ptr_,
455 info_ptr, 448 si.info_ptr_,
456 const_cast<unsigned char*>(input), 449 const_cast<unsigned char*>(input),
457 input_size); 450 input_size);
458 451
459 if (!state.done) { 452 if (!state.done) {
460 return false; 453 return false;
461 } 454 }
462 455
463 // Set the bitmap's opaqueness based on what we saw. 456 // Set the bitmap's opaqueness based on what we saw.
464 bitmap->setAlphaType(state.is_opaque ? 457 bitmap->setAlphaType(state.is_opaque ?
465 kOpaque_SkAlphaType : kPremul_SkAlphaType); 458 kOpaque_SkAlphaType : kPremul_SkAlphaType);
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
701 break; 694 break;
702 695
703 default: 696 default:
704 NOTREACHED() << "Unknown pixel format"; 697 NOTREACHED() << "Unknown pixel format";
705 return false; 698 return false;
706 } 699 }
707 700
708 // Row stride should be at least as long as the length of the data. 701 // Row stride should be at least as long as the length of the data.
709 DCHECK(input_color_components * size.width() <= row_byte_width); 702 DCHECK(input_color_components * size.width() <= row_byte_width);
710 703
711 png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 704 PngWriteStructInfo si;
712 NULL, NULL, NULL); 705 si.png_ptr_ = png_create_write_struct(PNG_LIBPNG_VER_STRING,
713 if (!png_ptr) 706 NULL, NULL, NULL);
707 if (!si.png_ptr_)
714 return false; 708 return false;
715 PngWriteStructDestroyer destroyer(&png_ptr); 709
716 png_info* info_ptr = png_create_info_struct(png_ptr); 710 si.info_ptr_ = png_create_info_struct(si.png_ptr_);
717 if (!info_ptr) 711 if (!si.info_ptr_)
718 return false; 712 return false;
719 destroyer.SetInfoStruct(&info_ptr);
720 713
721 output->clear(); 714 output->clear();
722 715
723 PngEncoderState state(output); 716 PngEncoderState state(output);
724 bool success = DoLibpngWrite(png_ptr, info_ptr, &state, 717 bool success = DoLibpngWrite(si.png_ptr_, si.info_ptr_, &state,
725 size.width(), size.height(), row_byte_width, 718 size.width(), size.height(), row_byte_width,
726 input, compression_level, png_output_color_type, 719 input, compression_level, png_output_color_type,
727 output_color_components, converter, comments); 720 output_color_components, converter, comments);
728 721
729 return success; 722 return success;
730 } 723 }
731 724
732 bool InternalEncodeSkBitmap(const SkBitmap& input, 725 bool InternalEncodeSkBitmap(const SkBitmap& input,
733 bool discard_transparency, 726 bool discard_transparency,
734 int compression_level, 727 int compression_level,
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
804 } 797 }
805 798
806 PNGCodec::Comment::Comment(const std::string& k, const std::string& t) 799 PNGCodec::Comment::Comment(const std::string& k, const std::string& t)
807 : key(k), text(t) { 800 : key(k), text(t) {
808 } 801 }
809 802
810 PNGCodec::Comment::~Comment() { 803 PNGCodec::Comment::~Comment() {
811 } 804 }
812 805
813 } // namespace gfx 806 } // namespace gfx
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698