55#include " parser.h"
66#include " parser_common.h"
77#include " parser_txdef.h"
8+ #include " schema_reader.h"
9+ #include " schema_txn_parser.h"
810#include " zxmacros_x64.h"
911
1012#ifdef NDEBUG
@@ -16,36 +18,101 @@ using std::size_t;
1618namespace {
1719char PARSER_KEY[16384 ];
1820char PARSER_VALUE[16384 ];
19- } // namespace
2021
21- extern " C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size) {
22- parser_tx_t txObj;
23- MEMZERO (&txObj, sizeof (txObj));
24- parser_context_t ctx;
25- parser_error_t rc;
22+ // Helper function to test individual parsing functions with fresh contexts
23+ void test_individual_functions (const parser_context_t &base_ctx, const parser_tx_t &base_txObj) {
24+ // Test merkle proofs reading independently
25+ {
26+ parser_context_t ctx = base_ctx;
27+ parser_tx_t txObj = base_txObj;
28+ schema_merkle_proofs_read (&ctx, &txObj);
29+ }
2630
27- rc = parser_parse (&ctx, data, size, &txObj);
28- if (rc != parser_ok) {
29- return 0 ;
31+ // Test extra data reading independently
32+ {
33+ parser_context_t ctx = base_ctx;
34+ parser_tx_t txObj = base_txObj;
35+ schema_extra_data_read (&ctx, &txObj);
3036 }
3137
32- rc = parser_validate (&txObj);
33- if (rc != parser_ok) {
34- return 0 ;
38+ // Test transaction parsing independently
39+ {
40+ parser_context_t ctx = base_ctx;
41+ parser_tx_t txObj = base_txObj;
42+ schema_parser_transaction (&ctx, &txObj);
43+ }
44+
45+ // Test chain hash reading independently
46+ {
47+ parser_context_t ctx = base_ctx;
48+ parser_tx_t txObj = base_txObj;
49+ schema_chain_hash_read (&ctx, &txObj);
50+ }
51+ }
52+
53+ // Helper function to test partial pipelines and return successful result
54+ bool test_partial_pipelines (const parser_context_t &base_ctx, const parser_tx_t &base_txObj, parser_tx_t &result_txObj) {
55+ // Test pipeline starting from merkle proofs
56+ {
57+ parser_context_t ctx = base_ctx;
58+ parser_tx_t txObj = base_txObj;
59+
60+ if (schema_merkle_proofs_read (&ctx, &txObj) == parser_ok) {
61+ schema_extra_data_read (&ctx, &txObj);
62+ if (schema_parser_transaction (&ctx, &txObj) == parser_ok) {
63+ schema_chain_hash_read (&ctx, &txObj);
64+ result_txObj = txObj;
65+ return true ;
66+ }
67+ }
68+ }
69+
70+ // Test pipeline starting from extra data (skip merkle)
71+ {
72+ parser_context_t ctx = base_ctx;
73+ parser_tx_t txObj = base_txObj;
74+
75+ schema_extra_data_read (&ctx, &txObj);
76+ if (schema_parser_transaction (&ctx, &txObj) == parser_ok) {
77+ schema_chain_hash_read (&ctx, &txObj);
78+ result_txObj = txObj;
79+ return true ;
80+ }
81+ }
82+
83+ // Test pipeline starting from transaction parsing (skip merkle and extra)
84+ {
85+ parser_context_t ctx = base_ctx;
86+ parser_tx_t txObj = base_txObj;
87+
88+ if (schema_parser_transaction (&ctx, &txObj) == parser_ok) {
89+ schema_chain_hash_read (&ctx, &txObj);
90+ result_txObj = txObj;
91+ return true ;
92+ }
93+ }
94+
95+ return false ;
96+ }
97+
98+ // Helper function to test and iterate through parsed items
99+ void test_parser_output (parser_tx_t &txObj) {
100+ if (parser_validate (&txObj) != parser_ok) {
101+ return ;
35102 }
36103
37104 uint8_t num_items;
38- rc = parser_getNumItems (&txObj, &num_items);
39- if (rc != parser_ok) {
105+ if (parser_getNumItems (&txObj, &num_items) != parser_ok) {
40106 assert (false );
41107 }
42108
43109 for (uint8_t i = 0 ; i < num_items; i += 1 ) {
44110 uint8_t page_idx = 0 ;
45111 uint8_t page_count = 1 ;
112+
46113 while (page_idx < page_count) {
47- rc = parser_getItem (&txObj, i, PARSER_KEY, sizeof (PARSER_KEY), PARSER_VALUE, sizeof (PARSER_VALUE), page_idx ,
48- &page_count);
114+ const parser_error_t rc = parser_getItem (&txObj, i, PARSER_KEY, sizeof (PARSER_KEY), PARSER_VALUE, sizeof (PARSER_VALUE),
115+ page_idx, &page_count);
49116
50117 if (rc != parser_ok) {
51118 (void )fprintf (stderr, " error getting item %u at page index %u: %s\n " , (unsigned )i, (unsigned )page_idx,
@@ -56,6 +123,30 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
56123 page_idx += 1 ;
57124 }
58125 }
126+ }
127+
128+ } // namespace
129+
130+ extern " C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size) {
131+ parser_tx_t txObj;
132+ MEMZERO (&txObj, sizeof (txObj));
133+ parser_context_t ctx;
134+
135+ const parser_error_t rc = parser_init_context (&ctx, data, size);
136+ if (rc != parser_ok) {
137+ return 0 ;
138+ }
139+
140+ // Test individual parsing functions independently to maximize coverage
141+ // This prevents early validation failures from blocking coverage of later stages
142+ test_individual_functions (ctx, txObj);
143+
144+ // Test partial pipelines with different entry points
145+ parser_tx_t result_txObj;
146+ if (test_partial_pipelines (ctx, txObj, result_txObj)) {
147+ // Test parser output with the successful result (no redundant parsing)
148+ test_parser_output (result_txObj);
149+ }
59150
60151 return 0 ;
61152}
0 commit comments