Coverage Report

Created: 2025-06-24 06:54

/src/icu/icu4c/source/test/fuzzer/ubidi_fuzzer.cpp
Line
Count
Source (jump to first uncovered line)
1
// © 2024 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
4
// Fuzzer for ICU bidi.
5
6
#include <cstring>
7
8
#include "fuzzer_utils.h"
9
10
#include "unicode/ubidi.h"
11
12
9.19k
#define MAXLEN 200
13
14
0
static void testGetVisualRun(UBiDi *bidi) {
15
0
  UErrorCode status = U_ZERO_ERROR;
16
0
  ubidi_getDirection(bidi);
17
0
  ubidi_getParaLevel(bidi);
18
0
  ubidi_getReorderingMode(bidi);
19
0
  ubidi_getReorderingOptions(bidi);
20
0
  int32_t runCount = ubidi_countRuns(bidi, &status);
21
0
  if (U_FAILURE(status)) {
22
0
    return;
23
0
  }
24
0
  for (int32_t runIndex = 0; runIndex < runCount; runIndex++) {
25
0
    int32_t start, len;
26
0
    ubidi_getVisualRun(bidi, runIndex, &start, &len);
27
0
  }
28
0
}
29
30
31
847
static void testVisual(UBiDi *bidi) {
32
847
  UErrorCode status = U_ZERO_ERROR;
33
847
  int32_t visualToLogical[MAXLEN];
34
847
  int32_t logicalToVisual[MAXLEN];
35
847
  int32_t logicalLimit = ubidi_getProcessedLength(bidi);
36
847
  int32_t visualLimit = ubidi_getResultLength(bidi);
37
847
  if (visualLimit > MAXLEN) {
38
0
    return;
39
0
  }
40
847
  ubidi_getVisualMap(bidi, visualToLogical, &status);
41
847
  ubidi_getLogicalMap(bidi, logicalToVisual, &status);
42
847
  if (U_FAILURE(status)) {
43
0
    return;
44
0
  }
45
46
847
  bool mapIsIncorrect = false;
47
26.5k
  for (int32_t logicalIndex = 0; logicalIndex < logicalLimit; logicalIndex++) {
48
25.6k
    int32_t visualIndex = ubidi_getVisualIndex(bidi, logicalIndex, &status);
49
25.6k
    if (visualIndex != logicalToVisual[logicalIndex]) {
50
0
      mapIsIncorrect = true;
51
0
    }
52
25.6k
    if (visualIndex != UBIDI_MAP_NOWHERE && visualIndex < visualLimit) {
53
25.6k
        UBiDiLevel level;
54
25.6k
        ubidi_getLogicalRun(bidi, logicalIndex, nullptr, &level);
55
25.6k
    }
56
25.6k
  }
57
58
847
  if (U_FAILURE(status)) {
59
0
    return;
60
0
  }
61
847
  bool checkGetVisualRun = true;
62
847
  if (mapIsIncorrect) {
63
0
    testGetVisualRun(bidi);
64
0
    checkGetVisualRun = false;
65
0
    for (int32_t logicalIndex = 0; logicalIndex < logicalLimit; logicalIndex++) {
66
0
      ubidi_getVisualIndex(bidi, logicalIndex, &status);
67
0
    }
68
0
  }
69
70
847
  mapIsIncorrect = false;
71
26.5k
  for (int32_t visualIndex = 0; visualIndex < visualLimit; visualIndex++) {
72
25.6k
    int32_t logicalIndex = ubidi_getLogicalIndex(bidi, visualIndex, &status);
73
25.6k
    if (logicalIndex != visualToLogical[visualIndex]) {
74
0
      mapIsIncorrect = true;
75
0
    }
76
25.6k
    if (logicalIndex != UBIDI_MAP_NOWHERE && logicalIndex < logicalLimit) {
77
25.6k
      UBiDiLevel level;
78
25.6k
      ubidi_getLogicalRun(bidi, logicalIndex, nullptr, &level);
79
25.6k
    }
80
25.6k
  }
81
847
  if (U_FAILURE(status)) {
82
0
    return;
83
0
  }
84
847
  if (mapIsIncorrect && checkGetVisualRun) {
85
0
    testGetVisualRun(bidi);
86
0
  }
87
847
}
88
89
2.89k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
90
2.89k
  icu::StringPiece fuzzData(reinterpret_cast<const char *>(data), size);
91
92
2.89k
  UErrorCode status = U_ZERO_ERROR;
93
2.89k
  UChar inputText[MAXLEN];
94
2.89k
  UChar reorderedText[MAXLEN];
95
96
2.89k
  unsigned char inputTextLength;
97
2.89k
  UBiDiLevel paraLevel;
98
2.89k
  int16_t options, options2;
99
2.89k
  unsigned char reorderedTextSize;
100
2.89k
  bool checkSetInverse, checkVisual;
101
2.89k
  bool isInverse;
102
103
2.89k
  if (static_cast<size_t>(fuzzData.length()) <
104
2.89k
      sizeof(inputTextLength) + sizeof(paraLevel) + sizeof(options) +
105
2.89k
      sizeof(reorderedTextSize) + sizeof(checkSetInverse) + sizeof(checkVisual) +
106
2.89k
      sizeof(isInverse) + sizeof(options2) + sizeof(UChar)) {
107
6
    return 0;
108
6
  }
109
2.88k
  std::memcpy(&inputTextLength, fuzzData.data(), sizeof(inputTextLength));
110
2.88k
  fuzzData.remove_prefix(sizeof(inputTextLength));
111
112
2.88k
  std::memcpy(&paraLevel, fuzzData.data(), sizeof(paraLevel));
113
2.88k
  fuzzData.remove_prefix(sizeof(paraLevel));
114
115
2.88k
  std::memcpy(&options, fuzzData.data(), sizeof(options));
116
2.88k
  fuzzData.remove_prefix(sizeof(options));
117
118
2.88k
  std::memcpy(&reorderedTextSize, fuzzData.data(), sizeof(reorderedTextSize));
119
2.88k
  fuzzData.remove_prefix(sizeof(reorderedTextSize));
120
2.88k
  if (reorderedTextSize > MAXLEN) reorderedTextSize = MAXLEN;
121
122
2.88k
  checkSetInverse = (*(fuzzData.data()) & 0x01) == 0;
123
2.88k
  fuzzData.remove_prefix(sizeof(checkSetInverse));
124
125
2.88k
  checkVisual = (*(fuzzData.data()) & 0x01) == 0;
126
2.88k
  fuzzData.remove_prefix(sizeof(checkVisual));
127
128
2.88k
  isInverse = (*(fuzzData.data()) & 0x01) != 0;
129
2.88k
  fuzzData.remove_prefix(sizeof(isInverse));
130
131
2.88k
  std::memcpy(&options2, fuzzData.data(), sizeof(options2));
132
2.88k
  fuzzData.remove_prefix(sizeof(options2));
133
134
2.88k
  if (inputTextLength > MAXLEN) inputTextLength = MAXLEN;
135
2.88k
  if (inputTextLength > fuzzData.length() / sizeof(UChar)) {
136
2.74k
      inputTextLength = fuzzData.length() / sizeof(UChar);
137
2.74k
  }
138
2.88k
  std::memcpy(&inputText, fuzzData.data(), sizeof(UChar)*inputTextLength);
139
2.88k
  fuzzData.remove_prefix(sizeof(UChar)*inputTextLength);
140
141
2.88k
  UBiDi* bidi = ubidi_open();
142
2.88k
  if (checkSetInverse) {
143
1.64k
    ubidi_setInverse(bidi, isInverse);
144
1.64k
  }
145
2.88k
  ubidi_setPara(bidi, inputText, inputTextLength, paraLevel, nullptr, &status);
146
2.88k
  if (U_SUCCESS(status)) {
147
2.87k
    int32_t reorderedTextLength = ubidi_writeReordered(bidi, reorderedText, reorderedTextSize, options, &status);
148
2.87k
    if (U_SUCCESS(status)) {
149
2.07k
      if (checkVisual) {
150
847
        testVisual(bidi);
151
1.22k
      } else {
152
1.22k
        ubidi_writeReordered(bidi, reorderedText, reorderedTextLength+1, options2, &status);
153
1.22k
      }
154
2.07k
    }
155
2.87k
  }
156
2.88k
  ubidi_close(bidi);
157
158
2.88k
  return EXIT_SUCCESS;
159
2.89k
}