Merge "imgdiff: Fix an edge case that leads to infinite loop."

This commit is contained in:
Tao Bao 2017-01-04 21:59:26 +00:00 committed by Gerrit Code Review
commit 3b828d879b
3 changed files with 91 additions and 15 deletions

View file

@ -124,6 +124,7 @@ libimgdiff_cflags := \
libimgdiff_static_libraries := \
libbsdiff \
libbase \
libz
# libimgdiff (static library)

View file

@ -124,6 +124,7 @@
#include "applypatch/imgdiff.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -131,6 +132,9 @@
#include <sys/types.h>
#include <unistd.h>
#include <android-base/file.h>
#include <android-base/unique_fd.h>
#include <bsdiff.h>
#include <zlib.h>
@ -382,19 +386,12 @@ unsigned char* ReadImage(const char* filename, int* num_chunks, ImageChunk** chu
}
size_t sz = static_cast<size_t>(st.st_size);
unsigned char* img = static_cast<unsigned char*>(malloc(sz + 4));
FILE* f = fopen(filename, "rb");
if (fread(img, 1, sz, f) != sz) {
unsigned char* img = static_cast<unsigned char*>(malloc(sz));
android::base::unique_fd fd(open(filename, O_RDONLY));
if (!android::base::ReadFully(fd, img, sz)) {
printf("failed to read \"%s\" %s\n", filename, strerror(errno));
fclose(f);
return NULL;
return nullptr;
}
fclose(f);
// append 4 zero bytes to the data so we can always search for the
// four-byte string 1f8b0800 starting at any point in the actual
// file data, without special-casing the end of the data.
memset(img+sz, 0, 4);
size_t pos = 0;
@ -518,10 +515,8 @@ unsigned char* ReadImage(const char* filename, int* num_chunks, ImageChunk** chu
curr->data = p;
for (curr->len = 0; curr->len < (sz - pos); ++curr->len) {
if (p[curr->len] == 0x1f &&
p[curr->len+1] == 0x8b &&
p[curr->len+2] == 0x08 &&
p[curr->len+3] == 0x00) {
if (sz - pos >= 4 && p[curr->len] == 0x1f && p[curr->len + 1] == 0x8b &&
p[curr->len + 2] == 0x08 && p[curr->len + 3] == 0x00) {
break;
}
}

View file

@ -404,6 +404,86 @@ TEST(ImgdiffTest, image_mode_spurious_magic) {
ASSERT_EQ(tgt, patched);
}
TEST(ImgdiffTest, image_mode_short_input1) {
// src: "abcdefgh" + '0x1f8b0b'.
const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', '\x1f', '\x8b', '\x08' };
const std::string src(src_data.cbegin(), src_data.cend());
TemporaryFile src_file;
ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
// tgt: "abcdefgxyz".
const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
TemporaryFile tgt_file;
ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
TemporaryFile patch_file;
std::vector<const char*> args = {
"imgdiff", src_file.path, tgt_file.path, patch_file.path,
};
ASSERT_EQ(0, imgdiff(args.size(), args.data()));
// Verify.
std::string patch;
ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
// Expect one CHUNK_RAW (header) entry.
size_t num_normal;
size_t num_raw;
size_t num_deflate;
verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
ASSERT_EQ(0U, num_normal);
ASSERT_EQ(0U, num_deflate);
ASSERT_EQ(1U, num_raw);
std::string patched;
ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
MemorySink, &patched));
ASSERT_EQ(tgt, patched);
}
TEST(ImgdiffTest, image_mode_short_input2) {
// src: "abcdefgh" + '0x1f8b0b00'.
const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', '\x1f', '\x8b', '\x08', '\x00' };
const std::string src(src_data.cbegin(), src_data.cend());
TemporaryFile src_file;
ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
// tgt: "abcdefgxyz".
const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
TemporaryFile tgt_file;
ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
TemporaryFile patch_file;
std::vector<const char*> args = {
"imgdiff", src_file.path, tgt_file.path, patch_file.path,
};
ASSERT_EQ(0, imgdiff(args.size(), args.data()));
// Verify.
std::string patch;
ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
// Expect one CHUNK_RAW (header) entry.
size_t num_normal;
size_t num_raw;
size_t num_deflate;
verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
ASSERT_EQ(0U, num_normal);
ASSERT_EQ(0U, num_deflate);
ASSERT_EQ(1U, num_raw);
std::string patched;
ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
MemorySink, &patched));
ASSERT_EQ(tgt, patched);
}
TEST(ImgdiffTest, image_mode_single_entry_long) {
// src: "abcdefgh" + '0x1f8b0b00' + some bytes.
const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',