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

Unified Diff: chrome/browser/android/thumbnail/thumbnail_store.cc

Issue 486093002: Fix thumbnail store crashing on loading old files (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 4 months 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | third_party/android_opengl/etc1/etc1.h » ('j') | third_party/android_opengl/etc1/etc1.cpp » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/android/thumbnail/thumbnail_store.cc
diff --git a/chrome/browser/android/thumbnail/thumbnail_store.cc b/chrome/browser/android/thumbnail/thumbnail_store.cc
index 1df7faf7eaf416de2be596aff1482bc22bacb2c1..6e61458c12b06000bc4d398a7c643b5a110f206b 100644
--- a/chrome/browser/android/thumbnail/thumbnail_store.cc
+++ b/chrome/browser/android/thumbnail/thumbnail_store.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <cmath>
+#include "base/big_endian.h"
#include "base/file_util.h"
#include "base/files/file.h"
#include "base/files/file_enumerator.h"
@@ -31,6 +32,8 @@ const base::TimeDelta kCaptureMinRequestTimeMs(
base::TimeDelta::FromMilliseconds(1000));
const int kCompressedKey = 0xABABABAB;
+const int kCurrentExtraVersion = 1;
+const int kMaxDimensionSize = 2048;
// Indicates whether we prefer to have more free CPU memory over GPU memory.
const bool kPreferCPUMemory = true;
@@ -53,6 +56,25 @@ gfx::Size GetEncodedSize(const gfx::Size& bitmap_size) {
NextPowerOfTwo(bitmap_size.height()));
}
+template<typename T>
+bool ReadBigEndianFromFile(base::File& file, T* out) {
+ char buffer[sizeof(T)];
+ if (file.ReadAtCurrentPos(buffer, sizeof(T)) != sizeof(T))
+ return false;
+
+ base::ReadBigEndian(buffer, out);
+ return true;
+}
+
+template<typename T>
+bool WriteBigEndianToFile(base::File& file, T val) {
+ char buffer[sizeof(T)];
+ base::WriteBigEndian(buffer, val);
+ if (file.WriteAtCurrentPos(buffer, sizeof(T)) != sizeof(T))
Ted C 2014/08/19 16:51:09 Could you also just do: return file.WriteAtCurren
David Trainor- moved to gerrit 2014/08/19 18:31:07 Good point. Done
+ return false;
+ return true;
+}
+
} // anonymous namespace
ThumbnailStore::ThumbnailStore(const std::string& disk_cache_path_str,
@@ -417,34 +439,70 @@ void ThumbnailStore::WriteTask(const base::FilePath& file_path,
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
DCHECK(file.IsValid());
- compressed_data->lockPixels();
bool success = true;
- int content_width = content_size.width();
- int content_height = content_size.height();
- int data_width = compressed_data->info().width();
- int data_height = compressed_data->info().height();
-
- if (file.WriteAtCurrentPos(reinterpret_cast<const char*>(&kCompressedKey),
- sizeof(int)) < 0 ||
- file.WriteAtCurrentPos(reinterpret_cast<const char*>(&content_width),
- sizeof(int)) < 0 ||
- file.WriteAtCurrentPos(reinterpret_cast<const char*>(&content_height),
- sizeof(int)) < 0 ||
- file.WriteAtCurrentPos(reinterpret_cast<const char*>(&data_width),
- sizeof(int)) < 0 ||
- file.WriteAtCurrentPos(reinterpret_cast<const char*>(&data_height),
- sizeof(int)) < 0 ||
- file.WriteAtCurrentPos(reinterpret_cast<const char*>(&scale),
- sizeof(float)) < 0) {
- success = false;
- }
- size_t compressed_bytes = etc1_get_encoded_data_size(data_width, data_height);
- if (file.WriteAtCurrentPos(reinterpret_cast<char*>(compressed_data->pixels()),
- compressed_bytes) < 0)
- success = false;
+ if (file.IsValid()) {
Ted C 2014/08/19 16:51:09 Would it be possible to pull out a helper function
David Trainor- moved to gerrit 2014/08/19 18:31:06 Done.
+ if (!WriteBigEndianToFile(file, kCompressedKey))
+ success = false;
+
+ if (success && !WriteBigEndianToFile(file, content_size.width()))
+ success = false;
+
+ if (success && !WriteBigEndianToFile(file, content_size.height()))
+ success = false;
+
+ // Write ETC1 header.
+ compressed_data->lockPixels();
+
+ int bytes_written = 0;
+ unsigned char etc1_buffer[ETC_PKM_HEADER_SIZE];
Ted C 2014/08/19 16:51:09 any reason these lines don't go into the condition
David Trainor- moved to gerrit 2014/08/19 18:31:06 Done.
+ etc1_pkm_format_header(etc1_buffer,
+ compressed_data->info().width(),
+ compressed_data->info().height());
+
+ if (success) {
+ bytes_written = file.WriteAtCurrentPos(
+ reinterpret_cast<char*>(etc1_buffer), ETC_PKM_HEADER_SIZE);
+ if (bytes_written != ETC_PKM_HEADER_SIZE)
+ success = false;
+ }
+
+ if (success) {
+ int data_size = etc1_get_encoded_data_size(
+ compressed_data->info().width(),
+ compressed_data->info().height());
+ bytes_written = file.WriteAtCurrentPos(
+ reinterpret_cast<char*>(compressed_data->pixels()),
+ data_size);
+ if (bytes_written != data_size)
+ success = false;
+ }
+
+ compressed_data->unlockPixels();
+
+ if (success && !WriteBigEndianToFile(file, kCurrentExtraVersion))
+ success = false;
- compressed_data->unlockPixels();
+ if (success) {
+ scale = 1.f / scale;
+
+ char buffer[4];
+ memcpy(buffer, &scale, sizeof(buffer));
+
+ char tmp = buffer[0];
+ buffer[0] = buffer[3];
+ buffer[3] = tmp;
+
+ tmp = buffer[1];
+ buffer[1] = buffer[2];
+ buffer[2] = tmp;
+
+ if (file.WriteAtCurrentPos(buffer, sizeof(buffer)) != sizeof(buffer))
+ success = false;
+ }
+ } else {
+ success = false;
+ }
file.Close();
@@ -544,50 +602,112 @@ void ThumbnailStore::ReadTask(
base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
DCHECK(file.IsValid());
- int key;
bool success = true;
- if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&key), sizeof(int)) < 0 ||
- key != kCompressedKey)
+ int key = 0;
Ted C 2014/08/19 16:51:09 same general comment about success early bail out
David Trainor- moved to gerrit 2014/08/19 18:31:06 Done.
+ if (!ReadBigEndianFromFile(file, &key))
success = false;
- int width = 0;
- int height = 0;
- if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&width), sizeof(int)) <
- 0 ||
- file.ReadAtCurrentPos(reinterpret_cast<char*>(&height), sizeof(int)) <
- 0)
+ if (key != kCompressedKey)
success = false;
- content_size = gfx::Size(width, height);
- if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&width), sizeof(int)) <
- 0 ||
- file.ReadAtCurrentPos(reinterpret_cast<char*>(&height), sizeof(int)) <
- 0)
+
+ int content_width = 0;
+ if (!ReadBigEndianFromFile(file, &content_width))
success = false;
- gfx::Size data_size(width, height);
- if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&scale), sizeof(float)) <
- 0)
+ int content_height = 0;
+ if (!ReadBigEndianFromFile(file, &content_height))
success = false;
- size_t compressed_bytes =
- etc1_get_encoded_data_size(data_size.width(), data_size.height());
- SkImageInfo info = {data_size.width(),
- data_size.height(),
- kUnknown_SkColorType,
- kUnpremul_SkAlphaType};
+ content_size.SetSize(content_width, content_height);
- scoped_ptr<uint8_t[]> data(new uint8_t[compressed_bytes]);
- if (file.ReadAtCurrentPos(reinterpret_cast<char*>(data.get()),
- compressed_bytes) < 0)
+ // Read ETC1 header.
+ int bytes_read = 0;
+ unsigned char etc1_buffer[ETC_PKM_HEADER_SIZE];
+ bytes_read = file.ReadAtCurrentPos(reinterpret_cast<char*>(etc1_buffer),
+ ETC_PKM_HEADER_SIZE);
+ if (bytes_read != ETC_PKM_HEADER_SIZE) {
Ted C 2014/08/19 16:51:09 no need for parens here since it's inconsistent
David Trainor- moved to gerrit 2014/08/19 18:31:07 Done.
success = false;
+ }
- file.Close();
+ if (!etc1_pkm_is_valid(etc1_buffer))
+ success = false;
- skia::RefPtr<SkData> etc1_pixel_data =
- skia::AdoptRef(SkData::NewFromMalloc(data.release(), compressed_bytes));
- compressed_data = skia::AdoptRef(
- SkMallocPixelRef::NewWithData(info, 0, NULL, etc1_pixel_data.get()));
+ int raw_width = 0;
+ if (success)
+ raw_width = etc1_pkm_get_width(etc1_buffer);
+
+ int raw_height = 0;
+ if (success)
+ raw_height = etc1_pkm_get_height(etc1_buffer);
+
+ // Do some simple sanity check validation. This is for Android only, for
Ted C 2014/08/19 16:51:09 this directory is under android, so I don't think
David Trainor- moved to gerrit 2014/08/19 18:31:07 Ah good point I forgot we could access those. Tha
+ // other platforms we'll have to be a bit smarter. Anything over 2048x2048
+ // won't load.
+ if (content_width > kMaxDimensionSize
+ || content_height > kMaxDimensionSize
+ || raw_width > kMaxDimensionSize
+ || raw_height > kMaxDimensionSize) {
+ success = false;
+ }
+
+ skia::RefPtr<SkData> etc1_pixel_data;
+ if (success) {
+ int data_size = etc1_get_encoded_data_size(raw_width, raw_height);
+ scoped_ptr<uint8_t[]> raw_data =
+ scoped_ptr<uint8_t[]>(new uint8_t[data_size]);
+
+ bytes_read = file.ReadAtCurrentPos(
+ reinterpret_cast<char*>(raw_data.get()),
+ data_size);
+
+ if (bytes_read == data_size) {
+ SkImageInfo info = {raw_width,
+ raw_height,
+ kUnknown_SkColorType,
+ kUnpremul_SkAlphaType};
+
+ etc1_pixel_data = skia::AdoptRef(
+ SkData::NewFromMalloc(raw_data.release(), data_size));
+ compressed_data = skia::AdoptRef(
+ SkMallocPixelRef::NewWithData(info,
+ 0,
+ NULL,
+ etc1_pixel_data.get()));
+ } else {
+ success = false;
+ }
+ }
+
+ int extra_data_version = 0;
+ if (!ReadBigEndianFromFile(file, &extra_data_version))
+ success = false;
+
+ scale = 1.f;
+ if (success && extra_data_version == 1) {
+ char buffer[4];
+ if (file.ReadAtCurrentPos(buffer, sizeof(buffer)) == sizeof(buffer)) {
+ char tmp = buffer[0];
+ buffer[0] = buffer[3];
+ buffer[3] = tmp;
+
+ tmp = buffer[1];
+ buffer[1] = buffer[2];
+ buffer[2] = tmp;
+
+ memcpy(&scale, buffer, sizeof(buffer));
+
+ if (scale == 0.f) {
+ success = false;
+ } else {
+ scale = 1.f / scale;
+ }
+ } else {
+ success = false;
+ }
+ }
+
+ file.Close();
if (!success) {
compressed_data.clear();
« no previous file with comments | « no previous file | third_party/android_opengl/etc1/etc1.h » ('j') | third_party/android_opengl/etc1/etc1.cpp » ('J')

Powered by Google App Engine
This is Rietveld 408576698