File: ubidi_fuzzer.cpp

package info (click to toggle)
icu 76.1-4
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 121,296 kB
  • sloc: cpp: 522,712; ansic: 113,387; sh: 4,983; makefile: 4,709; perl: 3,198; python: 2,847; xml: 2,652; sed: 36; lisp: 12
file content (159 lines) | stat: -rw-r--r-- 4,994 bytes parent folder | download | duplicates (7)
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// © 2024 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html

// Fuzzer for ICU bidi.

#include <cstring>

#include "fuzzer_utils.h"

#include "unicode/ubidi.h"

#define MAXLEN 200

static void testGetVisualRun(UBiDi *bidi) {
  UErrorCode status = U_ZERO_ERROR;
  ubidi_getDirection(bidi);
  ubidi_getParaLevel(bidi);
  ubidi_getReorderingMode(bidi);
  ubidi_getReorderingOptions(bidi);
  int32_t runCount = ubidi_countRuns(bidi, &status);
  if (U_FAILURE(status)) {
    return;
  }
  for (int32_t runIndex = 0; runIndex < runCount; runIndex++) {
    int32_t start, len;
    ubidi_getVisualRun(bidi, runIndex, &start, &len);
  }
}


static void testVisual(UBiDi *bidi) {
  UErrorCode status = U_ZERO_ERROR;
  int32_t visualToLogical[MAXLEN];
  int32_t logicalToVisual[MAXLEN];
  int32_t logicalLimit = ubidi_getProcessedLength(bidi);
  int32_t visualLimit = ubidi_getResultLength(bidi);
  if (visualLimit > MAXLEN) {
    return;
  }
  ubidi_getVisualMap(bidi, visualToLogical, &status);
  ubidi_getLogicalMap(bidi, logicalToVisual, &status);
  if (U_FAILURE(status)) {
    return;
  }

  bool mapIsIncorrect = false;
  for (int32_t logicalIndex = 0; logicalIndex < logicalLimit; logicalIndex++) {
    int32_t visualIndex = ubidi_getVisualIndex(bidi, logicalIndex, &status);
    if (visualIndex != logicalToVisual[logicalIndex]) {
      mapIsIncorrect = true;
    }
    if (visualIndex != UBIDI_MAP_NOWHERE && visualIndex < visualLimit) {
        UBiDiLevel level;
        ubidi_getLogicalRun(bidi, logicalIndex, nullptr, &level);
    }
  }

  if (U_FAILURE(status)) {
    return;
  }
  bool checkGetVisualRun = true;
  if (mapIsIncorrect) {
    testGetVisualRun(bidi);
    checkGetVisualRun = false;
    for (int32_t logicalIndex = 0; logicalIndex < logicalLimit; logicalIndex++) {
      ubidi_getVisualIndex(bidi, logicalIndex, &status);
    }
  }

  mapIsIncorrect = false;
  for (int32_t visualIndex = 0; visualIndex < visualLimit; visualIndex++) {
    int32_t logicalIndex = ubidi_getLogicalIndex(bidi, visualIndex, &status);
    if (logicalIndex != visualToLogical[visualIndex]) {
      mapIsIncorrect = true;
    }
    if (logicalIndex != UBIDI_MAP_NOWHERE && logicalIndex < logicalLimit) {
      UBiDiLevel level;
      ubidi_getLogicalRun(bidi, logicalIndex, nullptr, &level);
    }
  }
  if (U_FAILURE(status)) {
    return;
  }
  if (mapIsIncorrect && checkGetVisualRun) {
    testGetVisualRun(bidi);
  }
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  icu::StringPiece fuzzData(reinterpret_cast<const char *>(data), size);

  UErrorCode status = U_ZERO_ERROR;
  UChar inputText[MAXLEN];
  UChar reorderedText[MAXLEN];

  unsigned char inputTextLength;
  UBiDiLevel paraLevel;
  int16_t options, options2;
  unsigned char reorderedTextSize;
  bool checkSetInverse, checkVisual;
  bool isInverse;

  if (static_cast<size_t>(fuzzData.length()) <
      sizeof(inputTextLength) + sizeof(paraLevel) + sizeof(options) +
      sizeof(reorderedTextSize) + sizeof(checkSetInverse) + sizeof(checkVisual) +
      sizeof(isInverse) + sizeof(options2) + sizeof(UChar)) {
    return 0;
  }
  std::memcpy(&inputTextLength, fuzzData.data(), sizeof(inputTextLength));
  fuzzData.remove_prefix(sizeof(inputTextLength));

  std::memcpy(&paraLevel, fuzzData.data(), sizeof(paraLevel));
  fuzzData.remove_prefix(sizeof(paraLevel));

  std::memcpy(&options, fuzzData.data(), sizeof(options));
  fuzzData.remove_prefix(sizeof(options));

  std::memcpy(&reorderedTextSize, fuzzData.data(), sizeof(reorderedTextSize));
  fuzzData.remove_prefix(sizeof(reorderedTextSize));
  if (reorderedTextSize > MAXLEN) reorderedTextSize = MAXLEN;

  checkSetInverse = (*(fuzzData.data()) & 0x01) == 0;
  fuzzData.remove_prefix(sizeof(checkSetInverse));

  checkVisual = (*(fuzzData.data()) & 0x01) == 0;
  fuzzData.remove_prefix(sizeof(checkVisual));

  isInverse = (*(fuzzData.data()) & 0x01) != 0;
  fuzzData.remove_prefix(sizeof(isInverse));

  std::memcpy(&options2, fuzzData.data(), sizeof(options2));
  fuzzData.remove_prefix(sizeof(options2));

  if (inputTextLength > MAXLEN) inputTextLength = MAXLEN;
  if (inputTextLength > fuzzData.length() / sizeof(UChar)) {
      inputTextLength = fuzzData.length() / sizeof(UChar);
  }
  std::memcpy(&inputText, fuzzData.data(), sizeof(UChar)*inputTextLength);
  fuzzData.remove_prefix(sizeof(UChar)*inputTextLength);

  UBiDi* bidi = ubidi_open();
  if (checkSetInverse) {
    ubidi_setInverse(bidi, isInverse);
  }
  ubidi_setPara(bidi, inputText, inputTextLength, paraLevel, nullptr, &status);
  if (U_SUCCESS(status)) {
    int32_t reorderedTextLength = ubidi_writeReordered(bidi, reorderedText, reorderedTextSize, options, &status);
    if (U_SUCCESS(status)) {
      if (checkVisual) {
        testVisual(bidi);
      } else {
        ubidi_writeReordered(bidi, reorderedText, reorderedTextLength+1, options2, &status);
      }
    }
  }
  ubidi_close(bidi);

  return EXIT_SUCCESS;
}