THRIFT-5855: Add c_glib fuzzers
Add fuzzers for c_glib support, to improve the reliability/robustness of the implementation
diff --git a/FUZZING.md b/FUZZING.md
index f0f0324..b3e0c15 100644
--- a/FUZZING.md
+++ b/FUZZING.md
@@ -16,10 +16,10 @@
We currently maintain fuzzers for the following languages:
- Go (needs improvement)
+- c_glib (partially supported, needs round-trip support)
We are working on adding fuzzers for the following languages:
-- c_glib
- C++
- Rust
- Swift
diff --git a/configure.ac b/configure.ac
index c8c740c..8147a0b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -780,6 +780,7 @@
lib/c_glib/Makefile
lib/c_glib/thrift_c_glib.pc
lib/c_glib/test/Makefile
+ lib/c_glib/test/fuzz/Makefile
lib/d/Makefile
lib/d/test/Makefile
lib/erl/Makefile
diff --git a/lib/c_glib/test/Makefile.am b/lib/c_glib/test/Makefile.am
index 6eeece9..e61f875 100644
--- a/lib/c_glib/test/Makefile.am
+++ b/lib/c_glib/test/Makefile.am
@@ -18,7 +18,7 @@
#
AUTOMAKE_OPTIONS = subdir-objects serial-tests nostdinc
-SUBDIRS =
+SUBDIRS = fuzz
BUILT_SOURCES = \
gen-c_glib/t_test_container_test_types.c \
diff --git a/lib/c_glib/test/fuzz/Makefile.am b/lib/c_glib/test/fuzz/Makefile.am
new file mode 100644
index 0000000..e7d0e35
--- /dev/null
+++ b/lib/c_glib/test/fuzz/Makefile.am
@@ -0,0 +1,66 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+AUTOMAKE_OPTIONS = subdir-objects serial-tests nostdinc
+
+BUILT_SOURCES = \
+ gen-c_glib/fuzz_test_no_uuid_types.h \
+ gen-c_glib/fuzz_test_no_uuid_types.c
+
+noinst_LTLIBRARIES = libtestgencfuzz.la
+nodist_libtestgencfuzz_la_SOURCES = \
+ gen-c_glib/fuzz_test_no_uuid_types.c \
+ gen-c_glib/fuzz_test_no_uuid_types.h
+
+libtestgencfuzz_la_LIBADD = $(top_builddir)/lib/c_glib/libthrift_c_glib.la
+
+AM_CPPFLAGS = -I$(top_srcdir)/lib/c_glib/src -I../gen-c_glib -I./gen-c_glib -I$(top_builddir)
+AM_CFLAGS = -g $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) -I$(top_srcdir)/lib/c_glib/src -I../gen-c_glib -I./gen-c_glib -I$(top_builddir)
+AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS)
+
+if USING_CLANG
+AM_LDFLAGS += -fsanitize=fuzzer
+endif
+
+check_PROGRAMS = fuzz_parse_compact fuzz_parse_binary
+
+fuzz_parse_compact_SOURCES = fuzz_parse_compact.c
+fuzz_parse_compact_LDADD = \
+ libtestgencfuzz.la \
+ $(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_protocol.o \
+ $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o \
+ $(top_builddir)/lib/c_glib/src/thrift/c_glib/libthrift_c_glib_la-thrift_configuration.o
+
+fuzz_parse_binary_SOURCES = fuzz_parse_binary.c
+fuzz_parse_binary_LDADD = \
+ libtestgencfuzz.la \
+ $(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_protocol.o \
+ $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o \
+ $(top_builddir)/lib/c_glib/src/thrift/c_glib/libthrift_c_glib_la-thrift_configuration.o
+
+#
+# Common thrift code generation rules
+#
+gen-c_glib/fuzz_test_no_uuid_types.c gen-c_glib/fuzz_test_no_uuid_types.h: $(top_srcdir)/test/v0.16/FuzzTestNoUuid.thrift
+ $(THRIFT) --gen c_glib -r $<
+
+clean-local:
+ $(RM) -r gen-c_glib/
+ $(RM) *.o
+ $(RM) libtestgencfuzz.la
\ No newline at end of file
diff --git a/lib/c_glib/test/fuzz/README.md b/lib/c_glib/test/fuzz/README.md
new file mode 100644
index 0000000..d1a100e
--- /dev/null
+++ b/lib/c_glib/test/fuzz/README.md
@@ -0,0 +1,20 @@
+# C GLib Fuzzing README
+
+To build the fuzz targets, run `make check` in this directory. The build system uses LLVM's libFuzzer for fuzzing the C GLib Thrift implementation.
+
+These are standard libFuzzer targets, so you can run them using the standard libFuzzer interface. After building, you can run a fuzzer using:
+```bash
+./<fuzzer_name>
+```
+
+We currently have two fuzz targets:
+
+* fuzz_parse_binary -- fuzzes the deserialization of the Binary protocol
+* fuzz_parse_compact -- fuzzes the deserialization of the Compact protocol
+* TODO: Add round trip fuzzers, similar to other languages.
+
+The fuzzers use libFuzzer's built-in mutation engine to generate test cases. Each fuzzer implements the standard `LLVMFuzzerTestOneInput` interface.
+
+For more information about libFuzzer and its options, see the [libFuzzer documentation](https://llvm.org/docs/LibFuzzer.html).
+
+You can also use the corpus generator from the Rust implementation to generate initial corpus files that can be used with these C GLib fuzzers, since the wire formats are identical between implementations.
diff --git a/lib/c_glib/test/fuzz/fuzz_parse_binary.c b/lib/c_glib/test/fuzz/fuzz_parse_binary.c
new file mode 100644
index 0000000..25b9fe0
--- /dev/null
+++ b/lib/c_glib/test/fuzz/fuzz_parse_binary.c
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <thrift/c_glib/protocol/thrift_binary_protocol.h>
+#include <thrift/c_glib/protocol/thrift_protocol.h>
+#include <thrift/c_glib/transport/thrift_memory_buffer.h>
+#include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/thrift_configuration.h>
+#include <stdint.h>
+#include "gen-c_glib/fuzz_test_no_uuid_types.h"
+#include <stdio.h>
+
+// 10MB message size limit to prevent over-allocation during fuzzing
+#define FUZZ_MAX_MESSAGE_SIZE (10 * 1024 * 1024)
+
+int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ GError* error = NULL;
+
+ // Create a GByteArray with the fuzz data
+ GByteArray* byte_array = g_byte_array_new();
+ g_byte_array_append(byte_array, data, size);
+
+ // Create a ThriftConfiguration with message size limits
+ ThriftConfiguration* tconfiguration = g_object_new(THRIFT_TYPE_CONFIGURATION,
+ "max_message_size", FUZZ_MAX_MESSAGE_SIZE,
+ "max_frame_size", FUZZ_MAX_MESSAGE_SIZE,
+ NULL);
+
+ // Create a memory buffer transport with the byte array and configuration
+ ThriftTransport* transport = THRIFT_TRANSPORT(
+ g_object_new(THRIFT_TYPE_MEMORY_BUFFER,
+ "buf", byte_array,
+ "buf_size", size,
+ "configuration", tconfiguration,
+ NULL));
+
+ // Create a binary protocol
+ ThriftProtocol* protocol = THRIFT_PROTOCOL(
+ g_object_new(THRIFT_TYPE_BINARY_PROTOCOL,
+ "transport", transport,
+ NULL));
+
+ // Create a FuzzTest struct to read into
+ FuzzTest* test_struct = g_object_new(TYPE_FUZZ_TEST, NULL);
+ FuzzTestClass* cls = FUZZ_TEST_GET_CLASS(test_struct);
+
+ // Try to read the struct from the fuzz data
+ THRIFT_STRUCT_CLASS(cls)->read(THRIFT_STRUCT(test_struct), protocol, &error);
+
+ // Clean up
+ g_object_unref(test_struct);
+ g_object_unref(protocol);
+ g_object_unref(transport);
+ g_object_unref(tconfiguration);
+ if (error) {
+ g_error_free(error);
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/lib/c_glib/test/fuzz/fuzz_parse_compact.c b/lib/c_glib/test/fuzz/fuzz_parse_compact.c
new file mode 100644
index 0000000..5e0e2c1
--- /dev/null
+++ b/lib/c_glib/test/fuzz/fuzz_parse_compact.c
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <thrift/c_glib/protocol/thrift_compact_protocol.h>
+#include <thrift/c_glib/protocol/thrift_protocol.h>
+#include <thrift/c_glib/transport/thrift_memory_buffer.h>
+#include <thrift/c_glib/transport/thrift_transport.h>
+#include <thrift/c_glib/thrift_configuration.h>
+#include <stdint.h>
+#include "gen-c_glib/fuzz_test_no_uuid_types.h"
+#include <stdio.h>
+
+// 10MB message size limit to prevent over-allocation during fuzzing
+#define FUZZ_MAX_MESSAGE_SIZE (10 * 1024 * 1024)
+
+int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ GError* error = NULL;
+
+ // Create a GByteArray with the fuzz data
+ GByteArray* byte_array = g_byte_array_new();
+ g_byte_array_append(byte_array, data, size);
+
+ // Create a ThriftConfiguration with message size limits
+ ThriftConfiguration* tconfiguration = g_object_new(THRIFT_TYPE_CONFIGURATION,
+ "max_message_size", FUZZ_MAX_MESSAGE_SIZE,
+ "max_frame_size", FUZZ_MAX_MESSAGE_SIZE,
+ NULL);
+
+ // Create a memory buffer transport with the byte array and configuration
+ ThriftTransport* transport = THRIFT_TRANSPORT(
+ g_object_new(THRIFT_TYPE_MEMORY_BUFFER,
+ "buf", byte_array,
+ "buf_size", size,
+ "configuration", tconfiguration,
+ NULL));
+
+ // Create a compact protocol
+ ThriftProtocol* protocol = THRIFT_PROTOCOL(
+ g_object_new(THRIFT_TYPE_COMPACT_PROTOCOL,
+ "transport", transport,
+ NULL));
+
+ // // Create a FuzzTest struct to read into
+ FuzzTest* test_struct = g_object_new(TYPE_FUZZ_TEST, NULL);
+ FuzzTestClass* cls = FUZZ_TEST_GET_CLASS(test_struct);
+
+ // Try to read the struct from the fuzz data
+ THRIFT_STRUCT_CLASS(cls)->read(THRIFT_STRUCT(test_struct), protocol, &error);
+
+ // Clean up
+ g_object_unref(test_struct);
+ g_object_unref(protocol);
+ g_object_unref(transport);
+ g_object_unref(tconfiguration);
+ if (error) {
+ g_error_free(error);
+ }
+
+ return 0;
+}
\ No newline at end of file