1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16
17 #include "postgres.h"
18
19 #include "access/xlog.h"
20 #include "access/xact.h"
21 #include "common/username.h"
22 #include "executor/spi.h"
23 #include "jit/jit.h"
24 #include "libpq/libpq.h"
25 #include "libpq/pqsignal.h"
26 #include "miscadmin.h"
27 #include "optimizer/optimizer.h"
28 #include "parser/analyze.h"
29 #include "parser/parser.h"
30 #include "storage/proc.h"
31 #include "tcop/tcopprot.h"
32 #include "utils/datetime.h"
33 #include "utils/memutils.h"
34 #include "utils/portal.h"
35 #include "utils/snapmgr.h"
36 #include "utils/timeout.h"
37
38 static void
exec_simple_query(const char * query_string)39 exec_simple_query(const char *query_string)
40 {
41 MemoryContext oldcontext;
42 List *parsetree_list;
43 ListCell *parsetree_item;
44 bool use_implicit_block;
45
46 StartTransactionCommand();
47 oldcontext = MemoryContextSwitchTo(MessageContext);
48
49 parsetree_list = raw_parser(query_string, RAW_PARSE_TYPE_NAME);
50 MemoryContextSwitchTo(oldcontext);
51
52 use_implicit_block = (list_length(parsetree_list) > 1);
53
54 foreach(parsetree_item, parsetree_list)
55 {
56 RawStmt *parsetree = lfirst_node(RawStmt, parsetree_item);
57 bool snapshot_set = false;
58 MemoryContext per_parsetree_context = NULL;
59 List *querytree_list,
60 *plantree_list;
61
62 if (use_implicit_block)
63 BeginImplicitTransactionBlock();
64
65 if (analyze_requires_snapshot(parsetree))
66 {
67 PushActiveSnapshot(GetTransactionSnapshot());
68 snapshot_set = true;
69 }
70
71 if (lnext(parsetree_list, parsetree_item) != NULL)
72 {
73 per_parsetree_context =
74 AllocSetContextCreate(MessageContext,
75 "per-parsetree message context",
76 ALLOCSET_DEFAULT_SIZES);
77 oldcontext = MemoryContextSwitchTo(per_parsetree_context);
78 }
79 else
80 oldcontext = MemoryContextSwitchTo(MessageContext);
81
82 querytree_list = pg_analyze_and_rewrite(parsetree, query_string,
83 NULL, 0, NULL);
84
85 plantree_list = pg_plan_queries(querytree_list, query_string,
86 CURSOR_OPT_PARALLEL_OK, NULL);
87
88 if (per_parsetree_context){
89 MemoryContextDelete(per_parsetree_context);
90 }
91 CommitTransactionCommand();
92 }
93 }
94
95
LLVMFuzzerInitialize(int * argc,char *** argv)96 int LLVMFuzzerInitialize(int *argc, char ***argv) {
97 FuzzerInitialize("query_db", argv);
98 return 0;
99 }
100
101
102 /*
103 ** Main entry point. The fuzzer invokes this function with each
104 ** fuzzed input.
105 */
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)106 int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
107 char* query_string;
108 sigjmp_buf local_sigjmp_buf;
109
110 query_string = (char*) calloc( (size+1), sizeof(char) );
111 memcpy(query_string, data, size);
112
113 if (!sigsetjmp(local_sigjmp_buf, 0))
114 {
115 PG_exception_stack = &local_sigjmp_buf;
116 error_context_stack = NULL;
117 set_stack_base();
118
119 disable_all_timeouts(false);
120 QueryCancelPending = false;
121 pq_comm_reset();
122 EmitErrorReport();
123
124 AbortCurrentTransaction();
125
126 PortalErrorCleanup();
127 SPICleanup();
128
129 jit_reset_after_error();
130
131 MemoryContextSwitchTo(TopMemoryContext);
132 FlushErrorState();
133
134 MemoryContextSwitchTo(MessageContext);
135 MemoryContextResetAndDeleteChildren(MessageContext);
136
137 InvalidateCatalogSnapshotConditionally();
138
139 SetCurrentStatementStartTimestamp();
140
141 exec_simple_query(query_string);
142 }
143
144 free(query_string);
145 return 0;
146 }
147