aboutsummaryrefslogtreecommitdiff
path: root/projects/openh264/decoder_fuzzer.cpp
blob: 2c639adf29404895e24bf148a953519420c0a36c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// TODO: This should be moved to the openh264 repo.

#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <memory>

#include "codec_def.h"
#include "codec_app_def.h"
#include "codec_api.h"
#include "read_config.h"
#include "typedefs.h"
#include "measure_time.h"

/*
 * To build locally:
 * CC=clang CXX=clang++ CFLAGS="-fsanitize=address,fuzzer-no-link -g" CXXFLAGS="-fsanitize=address,fuzzer-no-link -g" LDFLAGS="-fsanitize=address,fuzzer-no-link" make -j$(nproc) USE_ASM=No BUILDTYPE=Debug libraries
 * clang++ -o decoder_fuzzer -fsanitize=address -g -O1 -I./codec/api/svc -I./codec/console/common/inc -I./codec/common/inc -L. -lFuzzer -lstdc++ decoder_fuzzer.cpp libopenh264.a
 */

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
  int32_t i;
  int32_t iBufPos = 0;
  int32_t iEndOfStreamFlag;
  int iLevelSetting = (int) WELS_LOG_QUIET; // disable logging while fuzzing
  int32_t iSliceSize;
  ISVCDecoder *pDecoder;
  SDecodingParam sDecParam = {0};
  SBufferInfo sDstBufInfo;
  std::unique_ptr<uint8_t[]> pBuf(new uint8_t[size + 4]);
  uint8_t* pData[3] = {NULL};
  uint8_t uiStartCode[4] = {0, 0, 0, 1};

  memcpy(pBuf.get(), data, size);
  memcpy(pBuf.get() + size, &uiStartCode[0], 4);
  memset(&sDstBufInfo, 0, sizeof(SBufferInfo));

  // TODO: is this the best/fastest ERROR_CON to use?
  sDecParam.eEcActiveIdc = ERROR_CON_SLICE_COPY;
  // TODO: should we also fuzz VIDEO_BITSTREAM_SVC?
  sDecParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_AVC;
  
  WelsCreateDecoder (&pDecoder);
  pDecoder->Initialize (&sDecParam);
  pDecoder->SetOption (DECODER_OPTION_TRACE_LEVEL, &iLevelSetting);

  while (1) {
    if (iBufPos >= size) {
      iEndOfStreamFlag = 1;
      if (iEndOfStreamFlag)
        pDecoder->SetOption (DECODER_OPTION_END_OF_STREAM, (void*)&iEndOfStreamFlag);
      break;
    }

    for (i = 0; i < size; i++) {
      if ((pBuf[iBufPos + i] == 0 && pBuf[iBufPos + i + 1] == 0 && pBuf[iBufPos + i + 2] == 0 && pBuf[iBufPos + i + 3] == 1
          && i > 0) || (pBuf[iBufPos + i] == 0 && pBuf[iBufPos + i + 1] == 0 && pBuf[iBufPos + i + 2] == 1 && i > 0)) {
        break;
      }
    }
    iSliceSize = i;
    if (iSliceSize < 4) {
      if (iSliceSize == 0) {
        // I don't think this should happen but let's just avoid the hang
        goto label_cleanup;
      }
      iBufPos += iSliceSize;
      continue;
    }

    pDecoder->DecodeFrameNoDelay (pBuf.get() + iBufPos, iSliceSize, pData, &sDstBufInfo);
    iBufPos += iSliceSize;
  }

label_cleanup:
  pDecoder->Uninitialize ();
  WelsDestroyDecoder (pDecoder);

  return 0;
}