option('tap_tests', type: 'feature', value: 'auto',
description: 'Enable TAP tests')
-option('fuzzing', type: 'boolean', value: false,
- description: 'Build fuzz testing targets')
-
option('injection_points', type: 'boolean', value: false,
description: 'Enable injection points')
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * fuzz_b64decode.c
- * Fuzzing harness for pg_b64_decode()
- *
- * Copyright (c) 2026, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- * src/test/fuzzing/fuzz_b64decode.c
- *
- * This harness feeds arbitrary byte sequences to pg_b64_decode(),
- * which decodes base64-encoded data per RFC 4648. The function is
- * a pure computation with no global state.
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres_fe.h"
-
-#include <stdio.h>
-
-#include "common/base64.h"
-
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
-
-int
-LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- int dstlen;
- uint8 *dst;
-
- if (size == 0)
- return 0;
-
- /* Allocate a buffer large enough for any valid decoding */
- dstlen = pg_b64_dec_len((int) size);
- dst = malloc(dstlen);
- if (!dst)
- return 0;
-
- (void) pg_b64_decode((const char *) data, (int) size, dst, dstlen);
-
- free(dst);
- return 0;
-}
-
-#ifdef STANDALONE_FUZZ_TARGET
-int
-main(int argc, char **argv)
-{
- int i;
- int ret = 0;
-
- for (i = 1; i < argc; i++)
- {
- FILE *f = fopen(argv[i], "rb");
- long len;
- uint8_t *buf;
- size_t n_read;
-
- if (!f)
- {
- fprintf(stderr, "%s: could not open %s: %m\n", argv[0], argv[i]);
- ret = 1;
- continue;
- }
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- fseek(f, 0, SEEK_SET);
-
- if (len < 0)
- {
- fprintf(stderr, "%s: could not determine size of %s\n",
- argv[0], argv[i]);
- fclose(f);
- ret = 1;
- continue;
- }
-
- buf = malloc(len);
- if (!buf)
- {
- fprintf(stderr, "%s: out of memory\n", argv[0]);
- fclose(f);
- return 1;
- }
-
- n_read = fread(buf, 1, len, f);
- fclose(f);
-
- LLVMFuzzerTestOneInput(buf, n_read);
- free(buf);
- }
-
- return ret;
-}
-#endif /* STANDALONE_FUZZ_TARGET */
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * fuzz_conninfo.c
- * Fuzzing harness for libpq connection string parsing
- *
- * Copyright (c) 2026, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- * src/test/fuzzing/fuzz_conninfo.c
- *
- * This harness feeds arbitrary byte sequences to PQconninfoParse(),
- * which parses both key=value connection strings and PostgreSQL URIs
- * (postgresql://...). The function is completely standalone and
- * requires no database connection or other initialization.
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres_fe.h"
-
-#include <stdio.h>
-
-#include "libpq-fe.h"
-
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
-
-int
-LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- char *str;
- char *errmsg = NULL;
- PQconninfoOption *opts;
-
- if (size == 0)
- return 0;
-
- /* PQconninfoParse expects a NUL-terminated string */
- str = malloc(size + 1);
- if (!str)
- return 0;
- memcpy(str, data, size);
- str[size] = '\0';
-
- opts = PQconninfoParse(str, &errmsg);
- if (opts)
- PQconninfoFree(opts);
- if (errmsg)
- PQfreemem(errmsg);
-
- free(str);
- return 0;
-}
-
-#ifdef STANDALONE_FUZZ_TARGET
-int
-main(int argc, char **argv)
-{
- int i;
- int ret = 0;
-
- for (i = 1; i < argc; i++)
- {
- FILE *f = fopen(argv[i], "rb");
- long len;
- uint8_t *buf;
- size_t n_read;
-
- if (!f)
- {
- fprintf(stderr, "%s: could not open %s: %m\n", argv[0], argv[i]);
- ret = 1;
- continue;
- }
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- fseek(f, 0, SEEK_SET);
-
- if (len < 0)
- {
- fprintf(stderr, "%s: could not determine size of %s\n",
- argv[0], argv[i]);
- fclose(f);
- ret = 1;
- continue;
- }
-
- buf = malloc(len);
- if (!buf)
- {
- fprintf(stderr, "%s: out of memory\n", argv[0]);
- fclose(f);
- return 1;
- }
-
- n_read = fread(buf, 1, len, f);
- fclose(f);
-
- LLVMFuzzerTestOneInput(buf, n_read);
- free(buf);
- }
-
- return ret;
-}
-#endif /* STANDALONE_FUZZ_TARGET */
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * fuzz_json.c
- * Fuzzing harness for the non-incremental JSON parser
- *
- * Copyright (c) 2026, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- * src/test/fuzzing/fuzz_json.c
- *
- * This harness feeds arbitrary byte sequences to pg_parse_json() via
- * makeJsonLexContextCstringLen(). It uses the null semantic action so
- * that only lexing and structural validation are exercised.
- *
- * Build with a fuzzing engine (e.g. libFuzzer via -fsanitize=fuzzer)
- * or in standalone mode, which reads files named on the command line.
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres_fe.h"
-
-#include <stdio.h>
-
-#include "common/jsonapi.h"
-#include "mb/pg_wchar.h"
-
-/*
- * Entry point for libFuzzer and other engines that call
- * LLVMFuzzerTestOneInput().
- */
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
-
-int
-LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- JsonLexContext lex;
-
- if (size == 0)
- return 0;
-
- makeJsonLexContextCstringLen(&lex, (const char *) data, size,
- PG_UTF8, true);
- setJsonLexContextOwnsTokens(&lex, true);
-
- (void) pg_parse_json(&lex, &nullSemAction);
-
- freeJsonLexContext(&lex);
-
- return 0;
-}
-
-#ifdef STANDALONE_FUZZ_TARGET
-int
-main(int argc, char **argv)
-{
- int i;
- int ret = 0;
-
- for (i = 1; i < argc; i++)
- {
- FILE *f = fopen(argv[i], "rb");
- long len;
- uint8_t *buf;
- size_t n_read;
-
- if (!f)
- {
- fprintf(stderr, "%s: could not open %s: %m\n", argv[0], argv[i]);
- ret = 1;
- continue;
- }
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- fseek(f, 0, SEEK_SET);
-
- if (len < 0)
- {
- fprintf(stderr, "%s: could not determine size of %s\n",
- argv[0], argv[i]);
- fclose(f);
- ret = 1;
- continue;
- }
-
- buf = malloc(len);
- if (!buf)
- {
- fprintf(stderr, "%s: out of memory\n", argv[0]);
- fclose(f);
- return 1;
- }
-
- n_read = fread(buf, 1, len, f);
- fclose(f);
-
- LLVMFuzzerTestOneInput(buf, n_read);
- free(buf);
- }
-
- return ret;
-}
-#endif /* STANDALONE_FUZZ_TARGET */
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * fuzz_json_incremental.c
- * Fuzzing harness for the incremental JSON parser
- *
- * Copyright (c) 2026, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- * src/test/fuzzing/fuzz_json_incremental.c
- *
- * This harness feeds arbitrary byte sequences to
- * pg_parse_json_incremental() in small chunks, exercising the
- * incremental lexer's boundary handling. The first byte of the input
- * is used to vary the chunk size so that the fuzzer can explore
- * different splitting strategies.
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres_fe.h"
-
-#include <stdio.h>
-
-#include "common/jsonapi.h"
-#include "mb/pg_wchar.h"
-
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
-
-int
-LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- JsonLexContext lex;
- size_t chunk_size;
- size_t offset;
-
- if (size < 2)
- return 0;
-
- /*
- * Use the first byte to select a chunk size between 1 and 128. This lets
- * the fuzzer explore different ways of splitting the same input across
- * incremental parse calls.
- */
- chunk_size = (data[0] % 128) + 1;
- data++;
- size--;
-
- makeJsonLexContextIncremental(&lex, PG_UTF8, true);
- setJsonLexContextOwnsTokens(&lex, true);
-
- offset = 0;
- while (offset < size)
- {
- size_t remaining = size - offset;
- size_t to_feed = (remaining < chunk_size) ? remaining : chunk_size;
- bool is_last = (offset + to_feed >= size);
- JsonParseErrorType result;
-
- result = pg_parse_json_incremental(&lex, &nullSemAction,
- (const char *) data + offset,
- to_feed, is_last);
-
- offset += to_feed;
-
- if (result != JSON_SUCCESS && result != JSON_INCOMPLETE)
- break;
- if (result == JSON_SUCCESS)
- break;
- }
-
- freeJsonLexContext(&lex);
-
- return 0;
-}
-
-#ifdef STANDALONE_FUZZ_TARGET
-int
-main(int argc, char **argv)
-{
- int i;
- int ret = 0;
-
- for (i = 1; i < argc; i++)
- {
- FILE *f = fopen(argv[i], "rb");
- long len;
- uint8_t *buf;
- size_t n_read;
-
- if (!f)
- {
- fprintf(stderr, "%s: could not open %s: %m\n", argv[0], argv[i]);
- ret = 1;
- continue;
- }
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- fseek(f, 0, SEEK_SET);
-
- if (len < 0)
- {
- fprintf(stderr, "%s: could not determine size of %s\n",
- argv[0], argv[i]);
- fclose(f);
- ret = 1;
- continue;
- }
-
- buf = malloc(len);
- if (!buf)
- {
- fprintf(stderr, "%s: out of memory\n", argv[0]);
- fclose(f);
- return 1;
- }
-
- n_read = fread(buf, 1, len, f);
- fclose(f);
-
- LLVMFuzzerTestOneInput(buf, n_read);
- free(buf);
- }
-
- return ret;
-}
-#endif /* STANDALONE_FUZZ_TARGET */
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * fuzz_parsepgarray.c
- * Fuzzing harness for parsePGArray()
- *
- * Copyright (c) 2026, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- * src/test/fuzzing/fuzz_parsepgarray.c
- *
- * This harness feeds arbitrary byte sequences to parsePGArray(),
- * which parses PostgreSQL array literal syntax ({elem,"elem",...})
- * including nested arrays, quoted elements, and backslash escaping.
- * The function is standalone and requires no database connection.
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres_fe.h"
-
-#include <stdio.h>
-
-#include "fe_utils/string_utils.h"
-
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
-
-int
-LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- char *str;
- char **items = NULL;
- int nitems = 0;
-
- if (size == 0)
- return 0;
-
- /* parsePGArray expects a NUL-terminated string */
- str = malloc(size + 1);
- if (!str)
- return 0;
- memcpy(str, data, size);
- str[size] = '\0';
-
- (void) parsePGArray(str, &items, &nitems);
- free(items);
-
- free(str);
- return 0;
-}
-
-#ifdef STANDALONE_FUZZ_TARGET
-int
-main(int argc, char **argv)
-{
- int i;
- int ret = 0;
-
- for (i = 1; i < argc; i++)
- {
- FILE *f = fopen(argv[i], "rb");
- long len;
- uint8_t *buf;
- size_t n_read;
-
- if (!f)
- {
- fprintf(stderr, "%s: could not open %s: %m\n", argv[0], argv[i]);
- ret = 1;
- continue;
- }
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- fseek(f, 0, SEEK_SET);
-
- if (len < 0)
- {
- fprintf(stderr, "%s: could not determine size of %s\n",
- argv[0], argv[i]);
- fclose(f);
- ret = 1;
- continue;
- }
-
- buf = malloc(len);
- if (!buf)
- {
- fprintf(stderr, "%s: out of memory\n", argv[0]);
- fclose(f);
- return 1;
- }
-
- n_read = fread(buf, 1, len, f);
- fclose(f);
-
- LLVMFuzzerTestOneInput(buf, n_read);
- free(buf);
- }
-
- return ret;
-}
-#endif /* STANDALONE_FUZZ_TARGET */
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * fuzz_pgbench_expr.c
- * Fuzzing harness for the pgbench expression parser
- *
- * Copyright (c) 2026, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- * src/test/fuzzing/fuzz_pgbench_expr.c
- *
- * This harness feeds arbitrary byte sequences to the pgbench expression
- * parser (expr_yyparse). The parser exercises a Bison grammar and Flex
- * lexer that handle arithmetic expressions, function calls, boolean
- * operators, and CASE expressions.
- *
- * The pgbench expression parser normally calls syntax_error() on any
- * parse error, which calls exit(1). This harness provides replacement
- * definitions of syntax_error(), strtoint64(), and strtodouble() so
- * that the generated parser and lexer objects can link without pulling
- * in pgbench.c. Our syntax_error() uses longjmp to recover rather
- * than exiting.
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres_fe.h"
-
-#include <setjmp.h>
-#include <stdio.h>
-
-#include "pgbench.h"
-#include "fe_utils/psqlscan.h"
-
-static sigjmp_buf fuzz_jmp_buf;
-
-static void free_pgbench_expr(PgBenchExpr *expr);
-
-static const PsqlScanCallbacks fuzz_callbacks = {
- NULL, /* no variable lookup needed */
-};
-
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
-
-/*
- * Replacement for pgbench.c's syntax_error(). Instead of calling exit(),
- * we longjmp back to the fuzzer's recovery point.
- */
-void
-syntax_error(const char *source, int lineno, const char *line,
- const char *command, const char *msg,
- const char *more, int column)
-{
- siglongjmp(fuzz_jmp_buf, 1);
-}
-
-/*
- * Replacement for pgbench.c's strtoint64().
- */
-bool
-strtoint64(const char *str, bool errorOK, int64 *result)
-{
- char *end;
-
- errno = 0;
- *result = strtoi64(str, &end, 10);
-
- if (errno == ERANGE || errno != 0 || end == str || *end != '\0')
- return false;
- return true;
-}
-
-/*
- * Replacement for pgbench.c's strtodouble().
- */
-bool
-strtodouble(const char *str, bool errorOK, double *dv)
-{
- char *end;
-
- errno = 0;
- *dv = strtod(str, &end);
-
- if (errno == ERANGE || errno != 0 || end == str || *end != '\0')
- return false;
- return true;
-}
-
-/*
- * Recursively free a PgBenchExpr tree.
- */
-static void
-free_pgbench_expr(PgBenchExpr *expr)
-{
- PgBenchExprLink *link;
- PgBenchExprLink *next;
-
- if (expr == NULL)
- return;
-
- switch (expr->etype)
- {
- case ENODE_CONSTANT:
- break;
- case ENODE_VARIABLE:
- pg_free(expr->u.variable.varname);
- break;
- case ENODE_FUNCTION:
- for (link = expr->u.function.args; link != NULL; link = next)
- {
- next = link->next;
- free_pgbench_expr(link->expr);
- pg_free(link);
- }
- break;
- }
-
- pg_free(expr);
-}
-
-int
-LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- char *str;
- PsqlScanState sstate;
- yyscan_t yyscanner;
- PgBenchExpr *result = NULL;
-
- if (size == 0)
- return 0;
-
- /* expr_yyparse needs a NUL-terminated string */
- str = malloc(size + 1);
- if (!str)
- return 0;
- memcpy(str, data, size);
- str[size] = '\0';
-
- sstate = psql_scan_create(&fuzz_callbacks);
- psql_scan_setup(sstate, str, (int) size, 0, true);
-
- yyscanner = expr_scanner_init(sstate, "fuzz", 1, 0, "\\set");
-
- if (sigsetjmp(fuzz_jmp_buf, 0) == 0)
- {
- (void) expr_yyparse(&result, yyscanner);
- }
-
- /* Clean up regardless of success or longjmp */
- expr_scanner_finish(yyscanner);
- psql_scan_finish(sstate);
- psql_scan_destroy(sstate);
-
- if (result)
- free_pgbench_expr(result);
-
- free(str);
- return 0;
-}
-
-#ifdef STANDALONE_FUZZ_TARGET
-int
-main(int argc, char **argv)
-{
- int i;
- int ret = 0;
-
- for (i = 1; i < argc; i++)
- {
- FILE *f = fopen(argv[i], "rb");
- long len;
- uint8_t *buf;
- size_t n_read;
-
- if (!f)
- {
- fprintf(stderr, "%s: could not open %s: %m\n", argv[0], argv[i]);
- ret = 1;
- continue;
- }
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- fseek(f, 0, SEEK_SET);
-
- if (len < 0)
- {
- fprintf(stderr, "%s: could not determine size of %s\n",
- argv[0], argv[i]);
- fclose(f);
- ret = 1;
- continue;
- }
-
- buf = malloc(len);
- if (!buf)
- {
- fprintf(stderr, "%s: out of memory\n", argv[0]);
- fclose(f);
- return 1;
- }
-
- n_read = fread(buf, 1, len, f);
- fclose(f);
-
- LLVMFuzzerTestOneInput(buf, n_read);
- free(buf);
- }
-
- return ret;
-}
-#endif /* STANDALONE_FUZZ_TARGET */
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * fuzz_pglz.c
- * Fuzzing harness for the PostgreSQL LZ decompressor
- *
- * Copyright (c) 2026, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- * src/test/fuzzing/fuzz_pglz.c
- *
- * This harness feeds arbitrary byte sequences to pglz_decompress(),
- * which decompresses PostgreSQL's native LZ-compressed data. The
- * decompressor is a pure function with no global state, making it
- * ideal for fuzzing.
- *
- * The first 4 bytes of the fuzzer input are interpreted as the
- * claimed raw (uncompressed) size in little-endian byte order,
- * capped at 1 MB. The remaining bytes are the compressed payload.
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres_fe.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include "common/pg_lzcompress.h"
-
-#define MAX_RAW_SIZE (1024 * 1024)
-
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
-
-int
-LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- int32 rawsize;
- char *dest;
-
- /* Need at least 4 bytes for the raw size, plus some compressed data */
- if (size < 5)
- return 0;
-
- /* Extract claimed raw size from first 4 bytes (little-endian) */
- rawsize = (int32) data[0] |
- ((int32) data[1] << 8) |
- ((int32) data[2] << 16) |
- ((int32) data[3] << 24);
-
- /* Reject nonsensical sizes */
- if (rawsize <= 0 || rawsize > MAX_RAW_SIZE)
- return 0;
-
- dest = malloc(rawsize);
- if (!dest)
- return 0;
-
- /* Try decompression with completeness check */
- (void) pglz_decompress((const char *) data + 4,
- (int32) (size - 4),
- dest,
- rawsize,
- true);
-
- /* Also try without completeness check to exercise that path */
- (void) pglz_decompress((const char *) data + 4,
- (int32) (size - 4),
- dest,
- rawsize,
- false);
-
- free(dest);
- return 0;
-}
-
-#ifdef STANDALONE_FUZZ_TARGET
-int
-main(int argc, char **argv)
-{
- int i;
- int ret = 0;
-
- for (i = 1; i < argc; i++)
- {
- FILE *f = fopen(argv[i], "rb");
- long len;
- uint8_t *buf;
- size_t n_read;
-
- if (!f)
- {
- fprintf(stderr, "%s: could not open %s: %m\n", argv[0], argv[i]);
- ret = 1;
- continue;
- }
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- fseek(f, 0, SEEK_SET);
-
- if (len < 0)
- {
- fprintf(stderr, "%s: could not determine size of %s\n",
- argv[0], argv[i]);
- fclose(f);
- ret = 1;
- continue;
- }
-
- buf = malloc(len);
- if (!buf)
- {
- fprintf(stderr, "%s: out of memory\n", argv[0]);
- fclose(f);
- return 1;
- }
-
- n_read = fread(buf, 1, len, f);
- fclose(f);
-
- LLVMFuzzerTestOneInput(buf, n_read);
- free(buf);
- }
-
- return ret;
-}
-#endif /* STANDALONE_FUZZ_TARGET */
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * fuzz_rawparser.c
- * Fuzzing harness for the PostgreSQL raw SQL parser
- *
- * Copyright (c) 2026, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- * src/test/fuzzing/fuzz_rawparser.c
- *
- * This harness feeds arbitrary byte sequences to raw_parser(), which
- * performs lexical and grammatical analysis of SQL statements. It
- * performs minimal backend initialization (just the memory-context
- * subsystem) and catches all parser errors via PG_TRY/PG_CATCH.
- *
- * The harness links against postgres_lib using archive semantics.
- * It provides stub definitions for symbols normally supplied by
- * main/main.c (progname, parse_dispatch_option) so that the linker
- * does not pull in main.o and conflict with the harness's own main().
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres.h"
-
-#include <stdio.h>
-
-#include "mb/pg_wchar.h"
-#include "miscadmin.h"
-#include "parser/parser.h"
-#include "postmaster/postmaster.h"
-#include "utils/memutils.h"
-#include "utils/palloc.h"
-
-/*
- * Stub definitions for symbols that main/main.c normally provides.
- * By defining them here we prevent the archive linker from pulling in
- * main.o (which defines its own main()).
- */
-const char *progname = "fuzz_rawparser";
-
-DispatchOption
-parse_dispatch_option(const char *name)
-{
- return DISPATCH_POSTMASTER;
-}
-
-static bool initialized = false;
-
-static void fuzz_initialize(void);
-
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
-
-/*
- * One-time initialization: set up memory contexts and encoding.
- */
-static void
-fuzz_initialize(void)
-{
- MemoryContextInit();
- SetDatabaseEncoding(PG_UTF8);
- SetMessageEncoding(PG_UTF8);
-}
-
-int
-LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- char *str;
- MemoryContext fuzz_context;
- MemoryContext oldcontext;
-
- if (!initialized)
- {
- fuzz_initialize();
- initialized = true;
- }
-
- if (size == 0)
- return 0;
-
- /*
- * Create a temporary memory context for each parse attempt so that all
- * allocations made by the parser are freed afterwards.
- */
- fuzz_context = AllocSetContextCreate(TopMemoryContext,
- "Fuzz Context",
- ALLOCSET_DEFAULT_SIZES);
- oldcontext = MemoryContextSwitchTo(fuzz_context);
-
- /* raw_parser() expects a NUL-terminated string */
- str = palloc(size + 1);
- memcpy(str, data, size);
- str[size] = '\0';
-
- PG_TRY();
- {
- (void) raw_parser(str, RAW_PARSE_DEFAULT);
- }
- PG_CATCH();
- {
- FlushErrorState();
- }
- PG_END_TRY();
-
- MemoryContextSwitchTo(oldcontext);
- MemoryContextDelete(fuzz_context);
-
- return 0;
-}
-
-#ifdef STANDALONE_FUZZ_TARGET
-int
-main(int argc, char **argv)
-{
- int i;
- int ret = 0;
-
- for (i = 1; i < argc; i++)
- {
- FILE *f = fopen(argv[i], "rb");
- long len;
- uint8_t *buf;
- size_t n_read;
-
- if (!f)
- {
- fprintf(stderr, "%s: could not open %s: %m\n", argv[0], argv[i]);
- ret = 1;
- continue;
- }
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- fseek(f, 0, SEEK_SET);
-
- if (len < 0)
- {
- fprintf(stderr, "%s: could not determine size of %s\n",
- argv[0], argv[i]);
- fclose(f);
- ret = 1;
- continue;
- }
-
- buf = malloc(len);
- if (!buf)
- {
- fprintf(stderr, "%s: out of memory\n", argv[0]);
- fclose(f);
- return 1;
- }
-
- n_read = fread(buf, 1, len, f);
- fclose(f);
-
- LLVMFuzzerTestOneInput(buf, n_read);
- free(buf);
- }
-
- return ret;
-}
-#endif /* STANDALONE_FUZZ_TARGET */
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * fuzz_regex.c
- * Fuzzing harness for the PostgreSQL regular expression engine
- *
- * Copyright (c) 2026, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- * src/test/fuzzing/fuzz_regex.c
- *
- * This harness feeds arbitrary byte sequences to pg_regcomp() and
- * pg_regexec(), exercising the full POSIX/ARE regex compiler and
- * executor. The first byte selects regex flags; the remaining bytes
- * are split between the regex pattern and a test subject string.
- *
- * The harness links against postgres_lib using archive semantics.
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres.h"
-
-#include <stdio.h>
-
-#include "catalog/pg_collation.h"
-#include "mb/pg_wchar.h"
-#include "miscadmin.h"
-#include "postmaster/postmaster.h"
-#include "regex/regex.h"
-#include "utils/memutils.h"
-#include "utils/palloc.h"
-
-/* Stubs for symbols from main/main.c */
-const char *progname = "fuzz_regex";
-
-DispatchOption
-parse_dispatch_option(const char *name)
-{
- return DISPATCH_POSTMASTER;
-}
-
-static bool initialized = false;
-
-static void fuzz_initialize(void);
-
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
-
-static void
-fuzz_initialize(void)
-{
- MemoryContextInit();
- SetDatabaseEncoding(PG_UTF8);
- SetMessageEncoding(PG_UTF8);
-}
-
-int
-LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- uint8_t flags_byte;
- int re_flags;
- size_t pat_len;
- size_t subj_len;
- const char *pat_start;
- const char *subj_start;
- pg_wchar *pat_wchar;
- pg_wchar *subj_wchar;
- int pat_wlen;
- int subj_wlen;
- regex_t re;
- regmatch_t matches[10];
- MemoryContext fuzz_context;
- MemoryContext oldcontext;
-
- if (!initialized)
- {
- fuzz_initialize();
- initialized = true;
- }
-
- /* Need at least flags byte + 1 byte of pattern */
- if (size < 2)
- return 0;
-
- /*
- * First byte selects regex flags. We map bits to useful flag combinations
- * to get good coverage of different regex modes.
- */
- flags_byte = data[0];
- re_flags = REG_ADVANCED;
- if (flags_byte & 0x01)
- re_flags = REG_EXTENDED; /* ERE instead of ARE */
- if (flags_byte & 0x02)
- re_flags |= REG_ICASE;
- if (flags_byte & 0x04)
- re_flags |= REG_NEWLINE;
- if (flags_byte & 0x08)
- re_flags |= REG_NOSUB;
-
- data++;
- size--;
-
- /* Split remaining input: first half pattern, second half subject */
- pat_len = size / 2;
- if (pat_len == 0)
- pat_len = 1;
- subj_len = size - pat_len;
-
- pat_start = (const char *) data;
- subj_start = (const char *) data + pat_len;
-
- fuzz_context = AllocSetContextCreate(TopMemoryContext,
- "Fuzz Context",
- ALLOCSET_DEFAULT_SIZES);
- oldcontext = MemoryContextSwitchTo(fuzz_context);
-
- /* Convert to pg_wchar for the regex API */
- pat_wchar = palloc((pat_len + 1) * sizeof(pg_wchar));
- pat_wlen = pg_mb2wchar_with_len(pat_start, pat_wchar, (int) pat_len);
-
- if (pg_regcomp(&re, pat_wchar, pat_wlen, re_flags, C_COLLATION_OID) == 0)
- {
- /* Compile succeeded — try executing against the subject */
- if (subj_len > 0)
- {
- subj_wchar = palloc((subj_len + 1) * sizeof(pg_wchar));
- subj_wlen = pg_mb2wchar_with_len(subj_start, subj_wchar,
- (int) subj_len);
-
- (void) pg_regexec(&re, subj_wchar, subj_wlen, 0, NULL,
- lengthof(matches), matches, 0);
- }
-
- pg_regfree(&re);
- }
-
- MemoryContextSwitchTo(oldcontext);
- MemoryContextDelete(fuzz_context);
-
- return 0;
-}
-
-#ifdef STANDALONE_FUZZ_TARGET
-int
-main(int argc, char **argv)
-{
- int i;
- int ret = 0;
-
- for (i = 1; i < argc; i++)
- {
- FILE *f = fopen(argv[i], "rb");
- long len;
- uint8_t *buf;
- size_t n_read;
-
- if (!f)
- {
- fprintf(stderr, "%s: could not open %s: %m\n", argv[0], argv[i]);
- ret = 1;
- continue;
- }
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- fseek(f, 0, SEEK_SET);
-
- if (len < 0)
- {
- fprintf(stderr, "%s: could not determine size of %s\n",
- argv[0], argv[i]);
- fclose(f);
- ret = 1;
- continue;
- }
-
- buf = malloc(len);
- if (!buf)
- {
- fprintf(stderr, "%s: out of memory\n", argv[0]);
- fclose(f);
- return 1;
- }
-
- n_read = fread(buf, 1, len, f);
- fclose(f);
-
- LLVMFuzzerTestOneInput(buf, n_read);
- free(buf);
- }
-
- return ret;
-}
-#endif /* STANDALONE_FUZZ_TARGET */
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * fuzz_saslprep.c
- * Fuzzing harness for pg_saslprep()
- *
- * Copyright (c) 2026, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- * src/test/fuzzing/fuzz_saslprep.c
- *
- * This harness feeds arbitrary byte sequences to pg_saslprep(),
- * which performs SASLprep normalization (RFC 4013) on UTF-8 strings.
- * This involves Unicode NFKC normalization, character mapping, and
- * prohibited character detection. The function is standalone and
- * requires no database connection.
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres_fe.h"
-
-#include <stdio.h>
-
-#include "common/saslprep.h"
-
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
-
-int
-LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- char *str;
- char *output = NULL;
-
- if (size == 0)
- return 0;
-
- /* pg_saslprep expects a NUL-terminated string */
- str = malloc(size + 1);
- if (!str)
- return 0;
- memcpy(str, data, size);
- str[size] = '\0';
-
- (void) pg_saslprep(str, &output);
-
- if (output)
- free(output);
-
- free(str);
- return 0;
-}
-
-#ifdef STANDALONE_FUZZ_TARGET
-int
-main(int argc, char **argv)
-{
- int i;
- int ret = 0;
-
- for (i = 1; i < argc; i++)
- {
- FILE *f = fopen(argv[i], "rb");
- long len;
- uint8_t *buf;
- size_t n_read;
-
- if (!f)
- {
- fprintf(stderr, "%s: could not open %s: %m\n", argv[0], argv[i]);
- ret = 1;
- continue;
- }
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- fseek(f, 0, SEEK_SET);
-
- if (len < 0)
- {
- fprintf(stderr, "%s: could not determine size of %s\n",
- argv[0], argv[i]);
- fclose(f);
- ret = 1;
- continue;
- }
-
- buf = malloc(len);
- if (!buf)
- {
- fprintf(stderr, "%s: out of memory\n", argv[0]);
- fclose(f);
- return 1;
- }
-
- n_read = fread(buf, 1, len, f);
- fclose(f);
-
- LLVMFuzzerTestOneInput(buf, n_read);
- free(buf);
- }
-
- return ret;
-}
-#endif /* STANDALONE_FUZZ_TARGET */
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * fuzz_typeinput.c
- * Fuzzing harness for PostgreSQL type input functions
- *
- * Copyright (c) 2026, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- * src/test/fuzzing/fuzz_typeinput.c
- *
- * This harness feeds arbitrary byte sequences to the backend's type
- * input functions: numeric_in, date_in, timestamp_in, timestamptz_in,
- * and interval_in. These functions parse textual representations of
- * data types and are a key part of PostgreSQL's input validation.
- *
- * The first byte of input selects which type parser to call; the
- * remaining bytes are the type-input string. All functions support
- * soft error handling via ErrorSaveContext, so errors are caught
- * without ereport/PG_TRY. PG_TRY/PG_CATCH is used as a safety net
- * for any unexpected hard errors.
- *
- * The harness links against postgres_lib using archive semantics.
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres.h"
-
-#include <stdio.h>
-
-#include "fmgr.h"
-#include "mb/pg_wchar.h"
-#include "miscadmin.h"
-#include "nodes/miscnodes.h"
-#include "pgtime.h"
-#include "postmaster/postmaster.h"
-#include "utils/builtins.h"
-#include "utils/datetime.h"
-#include "utils/memutils.h"
-#include "utils/numeric.h"
-#include "utils/palloc.h"
-#include "utils/timestamp.h"
-
-/* Stubs for symbols from main/main.c */
-const char *progname = "fuzz_typeinput";
-
-DispatchOption
-parse_dispatch_option(const char *name)
-{
- return DISPATCH_POSTMASTER;
-}
-
-/* Type selector values */
-#define FUZZ_NUMERIC 0
-#define FUZZ_DATE 1
-#define FUZZ_TIMESTAMP 2
-#define FUZZ_TIMESTAMPTZ 3
-#define FUZZ_INTERVAL 4
-#define FUZZ_NTYPES 5
-
-static bool initialized = false;
-
-static void fuzz_initialize(void);
-
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
-
-static void
-fuzz_initialize(void)
-{
- MemoryContextInit();
- SetDatabaseEncoding(PG_UTF8);
- SetMessageEncoding(PG_UTF8);
-
- /*
- * Initialize timezone subsystem. Use "GMT" because it is resolved
- * without filesystem access (the timezone data directory may not exist in
- * a fuzzing build).
- */
- pg_timezone_initialize();
-}
-
-int
-LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- char *str;
- int type_sel;
-
- LOCAL_FCINFO(fcinfo, 3);
- ErrorSaveContext escontext;
- MemoryContext fuzz_context;
- MemoryContext oldcontext;
-
- if (!initialized)
- {
- fuzz_initialize();
- initialized = true;
- }
-
- /* Need at least type selector + 1 byte of input */
- if (size < 2)
- return 0;
-
- type_sel = data[0] % FUZZ_NTYPES;
- data++;
- size--;
-
- fuzz_context = AllocSetContextCreate(TopMemoryContext,
- "Fuzz Context",
- ALLOCSET_DEFAULT_SIZES);
- oldcontext = MemoryContextSwitchTo(fuzz_context);
-
- /* Build a NUL-terminated string from the input */
- str = palloc(size + 1);
- memcpy(str, data, size);
- str[size] = '\0';
-
- /* Set up ErrorSaveContext for soft error handling */
- memset(&escontext, 0, sizeof(escontext));
- escontext.type = T_ErrorSaveContext;
- escontext.error_occurred = false;
- escontext.details_wanted = false;
-
- /* Set up FunctionCallInfo */
- memset(fcinfo, 0, SizeForFunctionCallInfo(3));
- fcinfo->nargs = 3;
- fcinfo->args[0].value = CStringGetDatum(str);
- fcinfo->args[0].isnull = false;
- fcinfo->args[1].value = ObjectIdGetDatum(InvalidOid); /* typelem */
- fcinfo->args[1].isnull = false;
- fcinfo->args[2].value = Int32GetDatum(-1); /* typmod */
- fcinfo->args[2].isnull = false;
- fcinfo->context = (Node *) &escontext;
-
- PG_TRY();
- {
- switch (type_sel)
- {
- case FUZZ_NUMERIC:
- (void) numeric_in(fcinfo);
- break;
- case FUZZ_DATE:
- (void) date_in(fcinfo);
- break;
- case FUZZ_TIMESTAMP:
- (void) timestamp_in(fcinfo);
- break;
- case FUZZ_TIMESTAMPTZ:
- (void) timestamptz_in(fcinfo);
- break;
- case FUZZ_INTERVAL:
- (void) interval_in(fcinfo);
- break;
- }
- }
- PG_CATCH();
- {
- FlushErrorState();
- }
- PG_END_TRY();
-
- MemoryContextSwitchTo(oldcontext);
- MemoryContextDelete(fuzz_context);
-
- return 0;
-}
-
-#ifdef STANDALONE_FUZZ_TARGET
-int
-main(int argc, char **argv)
-{
- int i;
- int ret = 0;
-
- for (i = 1; i < argc; i++)
- {
- FILE *f = fopen(argv[i], "rb");
- long len;
- uint8_t *buf;
- size_t n_read;
-
- if (!f)
- {
- fprintf(stderr, "%s: could not open %s: %m\n", argv[0], argv[i]);
- ret = 1;
- continue;
- }
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- fseek(f, 0, SEEK_SET);
-
- if (len < 0)
- {
- fprintf(stderr, "%s: could not determine size of %s\n",
- argv[0], argv[i]);
- fclose(f);
- ret = 1;
- continue;
- }
-
- buf = malloc(len);
- if (!buf)
- {
- fprintf(stderr, "%s: out of memory\n", argv[0]);
- fclose(f);
- return 1;
- }
-
- n_read = fread(buf, 1, len, f);
- fclose(f);
-
- LLVMFuzzerTestOneInput(buf, n_read);
- free(buf);
- }
-
- return ret;
-}
-#endif /* STANDALONE_FUZZ_TARGET */
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * fuzz_unescapebytea.c
- * Fuzzing harness for PQunescapeBytea()
- *
- * Copyright (c) 2026, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- * src/test/fuzzing/fuzz_unescapebytea.c
- *
- * This harness feeds arbitrary byte sequences to PQunescapeBytea(),
- * which decodes bytea escape formats: hex (\xDEAD...) and legacy
- * backslash-octal (\352\273\276...). The function is completely
- * standalone and requires no database connection.
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres_fe.h"
-
-#include <stdio.h>
-
-#include "libpq-fe.h"
-
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
-
-int
-LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- char *str;
- size_t resultlen;
- unsigned char *result;
-
- if (size == 0)
- return 0;
-
- /* PQunescapeBytea expects a NUL-terminated string */
- str = malloc(size + 1);
- if (!str)
- return 0;
- memcpy(str, data, size);
- str[size] = '\0';
-
- result = PQunescapeBytea((const unsigned char *) str, &resultlen);
- if (result)
- PQfreemem(result);
-
- free(str);
- return 0;
-}
-
-#ifdef STANDALONE_FUZZ_TARGET
-int
-main(int argc, char **argv)
-{
- int i;
- int ret = 0;
-
- for (i = 1; i < argc; i++)
- {
- FILE *f = fopen(argv[i], "rb");
- long len;
- uint8_t *buf;
- size_t n_read;
-
- if (!f)
- {
- fprintf(stderr, "%s: could not open %s: %m\n", argv[0], argv[i]);
- ret = 1;
- continue;
- }
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- fseek(f, 0, SEEK_SET);
-
- if (len < 0)
- {
- fprintf(stderr, "%s: could not determine size of %s\n",
- argv[0], argv[i]);
- fclose(f);
- ret = 1;
- continue;
- }
-
- buf = malloc(len);
- if (!buf)
- {
- fprintf(stderr, "%s: out of memory\n", argv[0]);
- fclose(f);
- return 1;
- }
-
- n_read = fread(buf, 1, len, f);
- fclose(f);
-
- LLVMFuzzerTestOneInput(buf, n_read);
- free(buf);
- }
-
- return ret;
-}
-#endif /* STANDALONE_FUZZ_TARGET */
+++ /dev/null
-# Copyright (c) 2026, PostgreSQL Global Development Group
-
-# Fuzzing harnesses for security testing.
-#
-# Build with:
-# meson setup build -Dfuzzing=true
-#
-# For libFuzzer (recommended), also pass sanitizer flags:
-# meson setup build -Dfuzzing=true \
-# -Dc_args='-fsanitize=fuzzer-no-link' \
-# -Dc_link_args='-fsanitize=fuzzer'
-#
-# Without a fuzzer engine the harnesses are built in standalone mode:
-# each reads input from files named on the command line.
-
-if not get_option('fuzzing')
- subdir_done()
-endif
-
-# Detect whether a fuzzer engine (e.g. libFuzzer) is available.
-# If so, link fuzzer executables with -fsanitize=fuzzer so that the
-# engine provides main(). Otherwise compile with STANDALONE_FUZZ_TARGET
-# so the harnesses supply their own main() that reads from files.
-
-fuzz_c_args = []
-fuzz_link_args = []
-
-if cc.has_argument('-fsanitize=fuzzer-no-link')
- fuzzer_has_engine = cc.links('''
- #include <stdint.h>
- #include <stddef.h>
- int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
- { return 0; }
- ''',
- args: ['-fsanitize=fuzzer'],
- name: 'libFuzzer support')
-else
- fuzzer_has_engine = false
-endif
-
-if fuzzer_has_engine
- fuzz_link_args += ['-fsanitize=fuzzer']
-else
- fuzz_c_args += ['-DSTANDALONE_FUZZ_TARGET']
-endif
-
-# --- Frontend targets (no backend dependencies) ---
-
-fuzz_json = executable('fuzz_json',
- 'fuzz_json.c',
- c_args: fuzz_c_args,
- link_args: fuzz_link_args,
- dependencies: [frontend_code],
- kwargs: default_bin_args + {
- 'install': false,
- },
-)
-
-fuzz_json_incremental = executable('fuzz_json_incremental',
- 'fuzz_json_incremental.c',
- c_args: fuzz_c_args,
- link_args: fuzz_link_args,
- dependencies: [frontend_code],
- kwargs: default_bin_args + {
- 'install': false,
- },
-)
-
-fuzz_conninfo = executable('fuzz_conninfo',
- 'fuzz_conninfo.c',
- c_args: fuzz_c_args,
- link_args: fuzz_link_args,
- dependencies: [frontend_code, libpq],
- kwargs: default_bin_args + {
- 'install': false,
- },
-)
-
-fuzz_pglz = executable('fuzz_pglz',
- 'fuzz_pglz.c',
- c_args: fuzz_c_args,
- link_args: fuzz_link_args,
- dependencies: [frontend_code],
- kwargs: default_bin_args + {
- 'install': false,
- },
-)
-
-fuzz_unescapebytea = executable('fuzz_unescapebytea',
- 'fuzz_unescapebytea.c',
- c_args: fuzz_c_args,
- link_args: fuzz_link_args,
- dependencies: [frontend_code, libpq],
- kwargs: default_bin_args + {
- 'install': false,
- },
-)
-
-fuzz_b64decode = executable('fuzz_b64decode',
- 'fuzz_b64decode.c',
- c_args: fuzz_c_args,
- link_args: fuzz_link_args,
- dependencies: [frontend_code],
- kwargs: default_bin_args + {
- 'install': false,
- },
-)
-
-fuzz_saslprep = executable('fuzz_saslprep',
- 'fuzz_saslprep.c',
- c_args: fuzz_c_args,
- link_args: fuzz_link_args,
- dependencies: [frontend_code],
- kwargs: default_bin_args + {
- 'install': false,
- },
-)
-
-fuzz_parsepgarray = executable('fuzz_parsepgarray',
- 'fuzz_parsepgarray.c',
- c_args: fuzz_c_args,
- link_args: fuzz_link_args,
- dependencies: [frontend_code, libpq],
- kwargs: default_bin_args + {
- 'install': false,
- },
-)
-
-# The pgbench expression parser is built from generated Bison/Flex
-# sources. We reference the same custom_target outputs used by the
-# pgbench build, and provide our own syntax_error() / strtoint64() /
-# strtodouble() so we don't pull in pgbench.c (which has its own
-# main() and calls exit() on parse errors).
-
-exprscan_fuzz = custom_target('exprscan_fuzz',
- input: files('../../bin/pgbench/exprscan.l'),
- output: 'exprscan.c',
- command: flex_cmd,
-)
-
-exprparse_fuzz = custom_target('exprparse_fuzz',
- input: files('../../bin/pgbench/exprparse.y'),
- kwargs: bison_kw,
-)
-
-fuzz_pgbench_expr = executable('fuzz_pgbench_expr',
- 'fuzz_pgbench_expr.c',
- exprscan_fuzz,
- exprparse_fuzz,
- c_args: fuzz_c_args,
- link_args: fuzz_link_args,
- include_directories: include_directories('../../bin/pgbench'),
- dependencies: [frontend_code, libpq],
- kwargs: default_bin_args + {
- 'install': false,
- },
-)
-
-# --- Backend targets ---
-#
-# These link against postgres_lib using standard archive semantics
-# (link_with), so only objects needed to resolve symbols are pulled in.
-# The harness provides stub definitions for symbols exported by
-# main/main.c, preventing the archive linker from pulling in main.o
-# (which would conflict with the harness's own main()).
-#
-# Backend code uses function-pointer casts in hash tables (dynahash.c)
-# that trigger UBSan's -fsanitize=function check. This is a known
-# benign pattern; when using -fsanitize=undefined, also pass
-# -fno-sanitize=function in the top-level c_args to suppress it.
-
-fuzz_rawparser = executable('fuzz_rawparser',
- 'fuzz_rawparser.c',
- c_args: fuzz_c_args,
- link_args: fuzz_link_args,
- link_with: [postgres_lib],
- dependencies: backend_build_deps,
- kwargs: default_bin_args + {
- 'install': false,
- },
-)
-
-fuzz_regex = executable('fuzz_regex',
- 'fuzz_regex.c',
- c_args: fuzz_c_args,
- link_args: fuzz_link_args,
- link_with: [postgres_lib],
- dependencies: backend_build_deps,
- kwargs: default_bin_args + {
- 'install': false,
- },
-)
-
-fuzz_typeinput = executable('fuzz_typeinput',
- 'fuzz_typeinput.c',
- c_args: fuzz_c_args,
- link_args: fuzz_link_args,
- link_with: [postgres_lib],
- dependencies: backend_build_deps,
- kwargs: default_bin_args + {
- 'install': false,
- },
-)
subdir('icu')
endif
-subdir('fuzzing')
-
subdir('perl')