Skip to content

Commit

Permalink
Merge pull request google#10 from bshastry/add_protobuf_giflib
Browse files Browse the repository at this point in the history
Add protobuf giflib
  • Loading branch information
viniul authored May 5, 2019
2 parents 61ded1f + 944bd1a commit 81e61d8
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 9 deletions.
23 changes: 20 additions & 3 deletions projects/giflib/ProtoToGif.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
using namespace gifProtoFuzzer;
using namespace std;

constexpr unsigned char ProtoConverter::m_sig[];
constexpr unsigned char ProtoConverter::m_ver89a[];
constexpr unsigned char ProtoConverter::m_ver87a[];

string ProtoConverter::gifProtoToString(GifProto const& proto)
{
visit(proto);
Expand All @@ -20,10 +24,23 @@ void ProtoConverter::visit(GifProto const& gif)
visit(gif.trailer());
}

void ProtoConverter::visit(Header const&)
void ProtoConverter::visit(Header const& header)
{
const unsigned char header[] = {0x47,0x49,0x46,0x38,0x39,0x61};
m_output.write((const char*)header, sizeof(header));
// Signature GIF
m_output.write((const char*)m_sig, sizeof(m_sig));

switch (header.ver()) {
case Header::ENA:
m_output.write((const char*) m_ver89a, sizeof(m_ver89a));
break;
case Header::ESA:
m_output.write((const char*) m_ver87a, sizeof(m_ver87a));
break;
// We simply don't write anything if it's an invalid version
// Bytes that follow (LSD) will be interpreted as version
case Header::INV:
break;
}
}

void ProtoConverter::visit(LogicalScreenDescriptor const& lsd)
Expand Down
4 changes: 4 additions & 0 deletions projects/giflib/ProtoToGif.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,9 @@ namespace gifProtoFuzzer {
bool m_hasLCT = false;
uint8_t m_globalColorExp = 0;
uint8_t m_localColorExp = 0;

static constexpr unsigned char m_sig[] = {0x47, 0x49, 0x46};
static constexpr unsigned char m_ver89a[] = {0x38, 0x39, 0x61};
static constexpr unsigned char m_ver87a[] = {0x38, 0x37, 0x61};
};
}
4 changes: 2 additions & 2 deletions projects/giflib/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ done
ar rc libgif.a *.o

cd $SRC
$CXX $CFLAGS $LIB_FUZZING_ENGINE -Wall -c -I giflib-code dgif_target.cc -o dgif_target.o
$CXX $CFLAGS -Wall -c -I giflib-code dgif_target.cc -o dgif_target.o
$CXX $CXXFLAGS $LIB_FUZZING_ENGINE -std=c++11 -I giflib-code dgif_fuzz_common.cc dgif_target.o \
-o $OUT/dgif_target giflib-code/libgif.a

rm -rf genfiles && mkdir genfiles && LPM/external.protobuf/bin/protoc gif_fuzz_proto.proto --cpp_out=genfiles

$CXX $CXXFLAGS $LIB_FUZZING_ENGINE -Wall -c -I giflib-code dgif_protobuf_target.cc -I libprotobuf-mutator/ \
$CXX $CXXFLAGS -Wall -c -I giflib-code dgif_protobuf_target.cc -I libprotobuf-mutator/ \
-I genfiles \
-I LPM/external.protobuf/include \
-o dgif_protobuf_target.o
Expand Down
116 changes: 115 additions & 1 deletion projects/giflib/dgif_fuzz_common.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
#include "dgif_fuzz_common.h"
#include <iostream>

using namespace std;

extern "C" void PrintGifError(int ErrorCode);

int stub_input_reader (GifFileType *gifFileType, GifByteType *gifByteType, int len) {
struct gifUserData *gud = (struct gifUserData *)gifFileType->UserData;
Expand Down Expand Up @@ -60,4 +65,113 @@ int fuzz_dgif_extended(const uint8_t *Data, size_t Size)
DGifCloseFile(GifFile, &Error);
free(gifData);
return 0;
}
}

static Color8888 gifColorToColor8888(const GifColorType& color) {
return ARGB_TO_COLOR8888(0xff, color.Red, color.Green, color.Blue);
}

static bool willBeCleared(const GraphicsControlBlock& gcb) {
return gcb.DisposalMode == DISPOSE_BACKGROUND || gcb.DisposalMode == DISPOSE_PREVIOUS;
}

static long getDelayMs(GraphicsControlBlock& gcb) {
return gcb.DelayTime * 10;
}

int fuzz_dgif_ala_android(const uint8_t *Data, size_t Size)
{
GifFileType *GifFile;
int Error;
uint8_t *gifData = (uint8_t *)malloc(Size);
memcpy(gifData, Data, Size);
struct gifUserData gUData = {Size, gifData};

GifFile = DGifOpen((void *)&gUData, stub_input_reader, &Error);
if (GifFile == NULL) {
free(gifData);
return 0;
}

if(DGifSlurp(GifFile) != GIF_OK){
PrintGifError(GifFile->Error);
DGifCloseFile(GifFile, &Error);
free(gifData);
return 0;
}

long durationMs = 0;
int lastUnclearedFrame = -1;
bool *preservedFrames = new bool[GifFile->ImageCount];
int *restoringFrames = new int[GifFile->ImageCount];
int loopCount = 0;
Color8888 bgColor = 0;

GraphicsControlBlock gcb;
for (int i = 0; i < GifFile->ImageCount; i++) {
const SavedImage& image = GifFile->SavedImages[i];
// find the loop extension pair
for (int j = 0; (j + 1) < image.ExtensionBlockCount; j++) {
ExtensionBlock* eb1 = image.ExtensionBlocks + j;
ExtensionBlock* eb2 = image.ExtensionBlocks + j + 1;
if (eb1->Function == APPLICATION_EXT_FUNC_CODE
// look for "NETSCAPE2.0" app extension
&& eb1->ByteCount == 11
&& !memcmp((const char*)(eb1->Bytes), "NETSCAPE2.0", 11)
// verify extension contents and get loop count
&& eb2->Function == CONTINUE_EXT_FUNC_CODE
&& eb2->ByteCount == 3
&& eb2->Bytes[0] == 1) {
loopCount = (int)(eb2->Bytes[2] << 8) + (int)(eb2->Bytes[1]);
}
}
DGifSavedExtensionToGCB(GifFile, i, &gcb);
// timing
durationMs += getDelayMs(gcb);
// preserve logic
preservedFrames[i] = false;
restoringFrames[i] = -1;
if (gcb.DisposalMode == DISPOSE_PREVIOUS && lastUnclearedFrame >= 0) {
preservedFrames[lastUnclearedFrame] = true;
restoringFrames[i] = lastUnclearedFrame;
}
if (!willBeCleared(gcb)) {
lastUnclearedFrame = i;
}
// Draw
// assert(y+8 <= Image->ImageDesc.Height);
// assert(x+8*strlen(legend) <= Image->ImageDesc.Width);
int imgHeight = GifFile->SavedImages[i].ImageDesc.Height;
int imgWidth = GifFile->SavedImages[i].ImageDesc.Width;
// TODO: Source x,y, string, and color from fuzzer input
int x, y = 0;
int strLen = 6;
if (y+8 <= imgHeight && x+8*strLen <= imgWidth)
GifDrawText8x8(&GifFile->SavedImages[i], 0, 0, "legend", 42);
}
#if GIF_DEBUG
ALOGD("FrameSequence_gif created with size %d %d, frames %d dur %ld",
GifFile->SWidth, GifFile->SHeight, GifFile->ImageCount, durationMs);
for (int i = 0; i < GifFile->ImageCount; i++) {
DGifSavedExtensionToGCB(GifFile, i, &gcb);
ALOGD(" Frame %d - must preserve %d, restore point %d, trans color %d",
i, preservedFrames[i], restoringFrames[i], gcb.TransparentColor);
}
#endif
const ColorMapObject* cmap = GifFile->SColorMap;
if (cmap) {
// calculate bg color
GraphicsControlBlock gcb;
DGifSavedExtensionToGCB(GifFile, 0, &gcb);
if (gcb.TransparentColor == NO_TRANSPARENT_COLOR
&& GifFile->SBackGroundColor < cmap->ColorCount) {
bgColor = gifColorToColor8888(cmap->Colors[GifFile->SBackGroundColor]);
}
}

DGifCloseFile(GifFile, &Error);
free(gifData);
delete[] preservedFrames;
delete[] restoringFrames;
return 0;
}
9 changes: 7 additions & 2 deletions projects/giflib/dgif_fuzz_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@
#include <stdlib.h>
#include <string.h>

#define ARGB_TO_COLOR8888(a, r, g, b) \
((a) << 24 | (b) << 16 | (g) << 8 | (r))

typedef uint32_t Color8888;

struct gifUserData {
size_t gifLen;
uint8_t *gifData;
};


int stub_input_reader (GifFileType *gifFileType, GifByteType *gifByteType, int len);
int fuzz_dgif(const uint8_t *Data, size_t Size);
int fuzz_dgif_extended(const uint8_t *Data, size_t Size);
int fuzz_dgif_extended(const uint8_t *Data, size_t Size);
int fuzz_dgif_ala_android(const uint8_t *Data, size_t Size);
12 changes: 11 additions & 1 deletion projects/giflib/gif_fuzz_proto.proto
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,15 @@ message CommentExtension {
repeated SubBlock subs = 1;
}

message Header {}
message Header {
enum Version {
ENA = 1;
ESA = 2;
INV = 3;
}
required Version ver = 1;
}

message Trailer {}

message ImageChunk {
Expand All @@ -82,6 +90,8 @@ message ImageChunk {
message GifProto {
required Header header = 1;
required LogicalScreenDescriptor lsd = 2;
// Instead of making GCT optional here, we condition its visit on LSD's packed byte
// in the converter
required GlobalColorTable gct = 3;
repeated ImageChunk chunks = 4;
required Trailer trailer = 5;
Expand Down

0 comments on commit 81e61d8

Please sign in to comment.