/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(¶Level, 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 | } |