Coverage Report

Created: 2026-04-12 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tidy_general_fuzzer.c
Line
Count
Source
1
/*
2
 * Copyright 2021 Google LLC
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
#include <sys/types.h>
17
#include <stdlib.h>
18
#include <stdio.h>
19
#include <stdint.h>
20
#include <string.h>
21
#include <unistd.h>
22
#include "tidybuffio.h"
23
#include "tidy.h"
24
25
// All boolean options. These will be set randomly
26
// based on the fuzzer data.
27
TidyOptionId bool_options[] = {
28
  TidyJoinClasses, 
29
  TidyJoinStyles, 
30
  TidyKeepFileTimes, 
31
  TidyKeepTabs, 
32
  TidyLiteralAttribs, 
33
  TidyLogicalEmphasis, 
34
  TidyLowerLiterals, 
35
  TidyMakeBare, 
36
  TidyFixUri, 
37
  TidyForceOutput, 
38
  TidyGDocClean, 
39
  TidyHideComments,
40
  TidyMark, 
41
  TidyXmlTags, 
42
  TidyMakeClean,
43
  TidyAnchorAsName, 
44
  TidyMergeEmphasis,
45
  TidyMetaCharset,
46
  TidyMuteShow, 
47
  TidyNCR, 
48
  TidyNumEntities, 
49
  TidyOmitOptionalTags, 
50
  TidyPunctWrap, 
51
  TidyQuiet,
52
  TidyQuoteAmpersand,  
53
  TidyQuoteMarks, 
54
  TidyQuoteNbsp, 
55
  TidyReplaceColor, 
56
  TidyShowFilename, 
57
  TidyShowInfo, 
58
  TidyShowMarkup, 
59
  TidyShowMetaChange, 
60
  TidyShowWarnings, 
61
  TidySkipNested, 
62
  TidyUpperCaseTags, 
63
  TidyWarnPropAttrs, 
64
  TidyWord2000, 
65
  TidyWrapAsp, 
66
  TidyWrapAttVals, 
67
  TidyWrapJste, 
68
  TidyWrapPhp, 
69
  TidyWrapScriptlets, 
70
  TidyWrapSection, 
71
  TidyWriteBack,
72
};
73
74
12.4k
void set_option(const uint8_t** data, size_t *size, TidyDoc *tdoc, TidyOptionId tboolID) {
75
12.4k
  uint8_t decider;
76
12.4k
  decider = **data;
77
12.4k
  *data += 1; 
78
12.4k
  *size -= 1;
79
12.4k
  if (decider % 2 == 0) tidyOptSetBool( *tdoc, tboolID, yes );
80
6.08k
  else { tidyOptSetBool( *tdoc, tboolID, no ); }
81
12.4k
}
82
83
283
int TidyXhtml(const uint8_t* data, size_t size, TidyBuffer* output, TidyBuffer* errbuf) {
84
283
  uint8_t decider;
85
86
  // We need enough data for picking all of the options. One byte per option.
87
283
  if (size < 5+(sizeof(bool_options)/sizeof(bool_options[0]))) {
88
0
    return 0;
89
0
  }
90
91
283
  TidyDoc tdoc = tidyCreate();
92
283
  if (!tdoc) {
93
0
    return 0;
94
0
  }
95
96
  // Decide output format
97
283
  decider = *data;
98
283
  data++; size--;
99
283
  if (decider % 3 == 0) tidyOptSetBool( tdoc, TidyXhtmlOut, yes );
100
94
  else { tidyOptSetBool( tdoc, TidyXhtmlOut, no ); }
101
102
283
  if (decider % 3 == 1) tidyOptSetBool( tdoc, TidyHtmlOut, yes );
103
214
  else { tidyOptSetBool( tdoc, TidyHtmlOut, no ); }
104
105
283
  if (decider % 3 == 2) tidyOptSetBool( tdoc, TidyXmlOut, yes );
106
258
  else { tidyOptSetBool( tdoc, TidyXmlOut, no ); }
107
108
  // Set options 
109
12.7k
  for (int i=0; i < sizeof(bool_options)/sizeof(TidyOptionId); i++) {
110
12.4k
    set_option(&data, &size, &tdoc, bool_options[i]);
111
12.4k
  }
112
113
  // Set an error buffer.
114
283
  tidySetErrorBuffer(tdoc, errbuf);
115
116
  // Parse the data
117
283
  decider = *data;
118
283
  data++; size--;
119
283
  switch (decider % 2) {
120
214
    case 0: {
121
214
      char filename[256];
122
214
      sprintf(filename, "/tmp/libfuzzer.%d", getpid());
123
124
214
      FILE *fp = fopen(filename, "wb");
125
214
      if (!fp) {
126
0
          tidyRelease(tdoc);
127
0
          return 0;
128
0
      }
129
214
      fwrite(data, size, 1, fp);
130
214
      fclose(fp);
131
132
214
      tidyParseFile(tdoc, filename);
133
214
      unlink(filename);
134
214
    }
135
0
    break;
136
69
    case 1: {
137
69
      char *inp = malloc(size+1);
138
69
      inp[size] = '\0';
139
69
      memcpy(inp, data, size);
140
69
      tidyParseString(tdoc, inp);
141
69
      free(inp);
142
69
    }
143
283
  }
144
145
  // Process and save output like other tidy fuzzers
146
283
  tidyCleanAndRepair(tdoc);
147
283
  tidyRunDiagnostics(tdoc);
148
283
  tidyOptSetBool(tdoc, TidyForceOutput, yes);
149
283
  tidySaveBuffer(tdoc, output);
150
151
  // Cleanup
152
283
  tidyRelease( tdoc );
153
154
283
  return 0;
155
283
}
156
157
283
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
158
283
  TidyBuffer fuzz_toutput;
159
283
  TidyBuffer fuzz_terror;
160
161
283
  tidyBufInit(&fuzz_toutput);
162
283
  tidyBufInit(&fuzz_terror);
163
164
283
  TidyXhtml(data, size, &fuzz_toutput, &fuzz_terror);
165
166
283
  tidyBufFree(&fuzz_toutput);
167
283
  tidyBufFree(&fuzz_terror);
168
169
283
  return 0;
170
283
}