codec/h264/h264dec/fuzz: added fuzzer test for parseLevelPrefix function

The fuzz package has been created, which will house C based helper code and sub-packages dedicated to each fuzz test. A sub packaged called
fuzzParseLevelPrefix has been created to house the fuzz test for parseLevelPrefix. Emeric's C code has been isolated into some C files, and a file
called fuzz.go has been created, which houses the actual fuzz test function. An initial corpus has been added with 3 inputs.
This commit is contained in:
Saxon 2019-09-23 12:18:14 +09:30
parent f8f78947f9
commit faf5e2df0f
9 changed files with 305 additions and 0 deletions

View File

@ -0,0 +1,32 @@
/*
DESCRIPTION
cavlc_fuzz.go provides exported wrappers for unexported CAVLC functions such
that the fuzz package can access these functions for testing.
AUTHORS
Saxon A. Nelson-Milton <saxon@ausocean.org>
LICENSE
Copyright (C) 2019 the Australian Ocean Lab (AusOcean).
It is free software: you can redistribute it and/or modify them
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
It is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
in gpl.txt. If not, see http://www.gnu.org/licenses.
*/
package h264dec
import "bitbucket.org/ausocean/av/codec/h264/h264dec/bits"
func FuzzParseLevelPrefix(br *bits.BitReader) (int, error) {
return parseLevelPrefix(br)
}

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1 @@
01

View File

@ -0,0 +1 @@
001

View File

@ -0,0 +1,69 @@
/*
DESCRIPTION
fuzz.go provides a function with the required signature such that it may be
accessed by go-fuzz. The function will compare the output of C level_prefix
parser with a go version.
AUTHORS
Saxon A. Nelson-Milton <saxon@ausocean.org>
LICENSE
Copyright (C) 2019 the Australian Ocean Lab (AusOcean).
It is free software: you can redistribute it and/or modify them
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
It is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
in gpl.txt. If not, see http://www.gnu.org/licenses.
*/
// +build gofuzz
package fuzzParseLevelPrefix
/*
#include "../helpers.c"
#include "parse_level_prefix.h"
*/
import "C"
import (
"bytes"
"fmt"
"unsafe"
"bitbucket.org/ausocean/av/codec/h264/h264dec"
"bitbucket.org/ausocean/av/codec/h264/h264dec/bits"
)
func Fuzz(data []byte) int {
// Create C based BitReader based on data.
cbr := C.new_BitReader((*C.char)(unsafe.Pointer(&data[0])), C.int(len(data)))
// Get the level_prefix from the C code. If got is < 0, then the C code
// doesn't like it and we shouldn't have that input in the corpus, so return -1.
got := C.read_levelprefix(cbr)
if got < 0 {
return -1
}
// Get the level_prefix from the go code. If the C code was okay with this
// input, but the go code isn't then that's bad, so panic - want crasher info.
want, err := h264dec.FuzzParseLevelPrefix(bits.NewBitReader(bytes.NewReader(data)))
if err != nil {
panic(fmt.Sprintf("error from go parseLevelPrefix: %v", err))
}
// Compare the result of the C and go code. If they are not the same then
// panic - our go code is not doing what it should.
if int(want) != int(got) {
panic(fmt.Sprintf("did not get expected results for input: %v\nGot: %v\nWant: %v\n", data, got, want))
}
return 1
}

View File

@ -0,0 +1,59 @@
/*
DESCRIPTION
parse_level_prefix.c contains a function that will parse the level_prefix
when performaing CAVLC decoding; extracted from Emeric Grange's h264 decoder
contained in MiniVideo (https://github.com/emericg/MiniVideo). This is used
to generate input and output data for testing purposes.
AUTHORS
Emeric Grange <emeric.grange@gmail.com>
Saxon A. Nelson-Milton <saxon@ausocean.org>
LICENSE
COPYRIGHT (C) 2018 Emeric Grange - All Rights Reserved
This file is part of MiniVideo.
MiniVideo is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
MiniVideo is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with MiniVideo. If not, see <http://www.gnu.org/licenses/>.
*/
#include "parse_level_prefix.h"
#include "../helpers.h"
/*!
* \brief Parsing process for level_prefix.
* \param *dc The current DecodingContext.
* \return leadingZeroBits.
*
* From 'ITU-T H.264' recommendation:
* 9.2.2.1 Parsing process for level_prefix
*
* The parsing process for this syntax element consists in reading the bits
* starting at the current location in the bitstream up to and including the
* first non-zero bit, and counting the number of leading bits that are equal to 0.
*
* level_prefix and level_suffix specify the value of a non-zero transform coefficient level.
* The range of level_prefix and level_suffix is specified in subclause 9.2.2.
*/
int read_levelprefix(struct BitReader *br){
int leadingZeroBits = -1;
int b = 0;
for (b = 0; !b; leadingZeroBits++){
b = read_bits(br,1);
if( br->err != 0 ){
return -1;
}
}
return leadingZeroBits;
}

View File

@ -0,0 +1,11 @@
#ifndef PARSE_LEVEL_PREFIX_H
#define PARSE_LEVEL_PREFIX_H
#include <stdlib.h>
#include <stdint.h>
#include "../helpers.h"
int read_levelprefix(struct BitReader *br);
#endif // PARSE_LEVEL_PREFIX_H

View File

@ -0,0 +1,72 @@
/*
DESCRIPTION
helpers.c provides C helper functions for interfacing with C code used for
testing in this package.
AUTHORS
Saxon A. Nelson-Milton <saxon@ausocean.org>
LICENSE
Copyright (C) 2019 the Australian Ocean Lab (AusOcean).
It is free software: you can redistribute it and/or modify them
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
It is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
in gpl.txt. If not, see http://www.gnu.org/licenses.
*/
#include "helpers.h"
typedef struct BitReader BitReader;
typedef struct Reader Reader;
BitReader* new_BitReader(char* d, int l){
Reader* r = (Reader*)malloc(sizeof(Reader));
r->data = d;
r->curr = 0;
r->len = l;
r->err = 0;
BitReader* br = (BitReader*)malloc(sizeof(BitReader));
br->r = r;
br->n = 0;
br->bits = 0;
br->nRead = 0;
br->err = 0;
return br;
}
char next_byte(Reader *r) {
if(r->curr >= r->len){
r->err = 1;
}
char next = r->data[r->curr];
r->curr++;
return next;
}
uint64_t read_bits(BitReader *br, int n) {
while( n > br->bits ){
char b = next_byte(br->r);
if(br->r->err != 0){
br->err = 1;
return 0;
}
br->nRead++;
br->n <<= 8;
br->n |= (uint64_t)b;
br->bits += 8;
}
uint64_t r = (br->n >> (br->bits-n)) & ((1 << n) - 1);
br->bits -= n;
return r;
}

View File

@ -0,0 +1,59 @@
/*
DESCRIPTION
helpers.h defines some structs and function signatures that will help to
interface with C code used in our fuzz testing.
AUTHORS
Saxon A. Nelson-Milton <saxon@ausocean.org>
LICENSE
Copyright (C) 2019 the Australian Ocean Lab (AusOcean).
It is free software: you can redistribute it and/or modify them
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
It is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
in gpl.txt. If not, see http://www.gnu.org/licenses.
*/
#ifndef HELPERS_H
#define HELPERS_H
#include <stdlib.h>
#include <stdint.h>
struct Reader {
char* data;
int curr;
int len;
int err;
};
struct BitReader {
struct Reader* r;
uint64_t n;
int bits;
int nRead;
int err;
};
// new_BitReader returns a new instance of a BitReader given the backing array
// d and the length of the data l.
struct BitReader* new_BitReader(char*, int);
// next_byte provides the next byte from a Reader r and advances it's byte index.
char next_byte(struct Reader*);
// read_bits intends to emulate the BitReader.ReadBits function defined in the
// bits package. This is used when a bit reader is required to obtain bytes from
// a stream in the C test code.
uint64_t read_bits(struct BitReader*, int);
#endif // HELPERS_H