summaryrefslogtreecommitdiff
path: root/examples/redis-unstable/modules/vector-sets/fastjson_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/redis-unstable/modules/vector-sets/fastjson_test.c')
-rw-r--r--examples/redis-unstable/modules/vector-sets/fastjson_test.c406
1 files changed, 0 insertions, 406 deletions
diff --git a/examples/redis-unstable/modules/vector-sets/fastjson_test.c b/examples/redis-unstable/modules/vector-sets/fastjson_test.c
deleted file mode 100644
index 1ea76a9..0000000
--- a/examples/redis-unstable/modules/vector-sets/fastjson_test.c
+++ /dev/null
@@ -1,406 +0,0 @@
-/* fastjson_test.c - Stress test for fastjson.c
- *
- * This performs boundary and corruption tests to ensure
- * the JSON parser handles edge cases without accessing
- * memory outside the bounds of the input.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <signal.h>
-#include <time.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <setjmp.h>
-
-/* Page size constant - typically 4096 or 16k bytes (Apple Silicon).
- * We use 16k so that it will work on both, but not with Linux huge pages. */
-#define PAGE_SIZE 4096*4
-#define MAX_JSON_SIZE (PAGE_SIZE - 128) /* Keep some margin */
-#define MAX_FIELD_SIZE 64
-#define NUM_TEST_ITERATIONS 100000
-#define NUM_CORRUPTION_TESTS 10000
-#define NUM_BOUNDARY_TESTS 10000
-
-/* Test state tracking */
-static char *safe_page = NULL; /* Start of readable/writable page */
-static char *unsafe_page = NULL; /* Start of inaccessible guard page */
-static int boundary_violation = 0; /* Flag for boundary violations */
-static jmp_buf jmpbuf; /* For signal handling */
-static int tests_passed = 0;
-static int tests_failed = 0;
-static int corruptions_passed = 0;
-static int boundary_tests_passed = 0;
-
-/* Test metadata for tracking */
-typedef struct {
- char *json;
- size_t json_len;
- char field[MAX_FIELD_SIZE];
- size_t field_len;
- int expected_result;
-} test_case_t;
-
-/* Forward declarations for test JSON generation */
-char *generate_random_json(size_t *len, char *field, size_t *field_len, int *has_field);
-void corrupt_json(char *json, size_t len);
-void setup_test_memory(void);
-void cleanup_test_memory(void);
-void run_normal_tests(void);
-void run_corruption_tests(void);
-void run_boundary_tests(void);
-void print_test_summary(void);
-
-/* Signal handler for segmentation violations */
-static void sigsegv_handler(int sig) {
- boundary_violation = 1;
- printf("Boundary violation detected! Caught signal %d\n", sig);
- longjmp(jmpbuf, 1);
-}
-
-/* Wrapper for jsonExtractField to check for boundary violations */
-exprtoken *safe_extract_field(const char *json, size_t json_len,
- const char *field, size_t field_len) {
- boundary_violation = 0;
-
- if (setjmp(jmpbuf) == 0) {
- return jsonExtractField(json, json_len, field, field_len);
- } else {
- return NULL; /* Return NULL if boundary violation occurred */
- }
-}
-
-/* Setup two adjacent memory pages - one readable/writable, one inaccessible */
-void setup_test_memory(void) {
- /* Request a page of memory, with specific alignment. We rely on the
- * fact that hopefully the page after that will cause a segfault if
- * accessed. */
- void *region = mmap(NULL, PAGE_SIZE,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- -1, 0);
-
- if (region == MAP_FAILED) {
- perror("mmap failed");
- exit(EXIT_FAILURE);
- }
-
- safe_page = (char*)region;
- unsafe_page = safe_page + PAGE_SIZE;
- // Uncomment to make sure it crashes :D
- // printf("%d\n", unsafe_page[5]);
-
- /* Set up signal handlers for memory access violations */
- struct sigaction sa;
- sa.sa_handler = sigsegv_handler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
-
- sigaction(SIGSEGV, &sa, NULL);
- sigaction(SIGBUS, &sa, NULL);
-}
-
-void cleanup_test_memory(void) {
- if (safe_page != NULL) {
- munmap(safe_page, PAGE_SIZE);
- safe_page = NULL;
- unsafe_page = NULL;
- }
-}
-
-/* Generate random strings with proper escaping for JSON */
-void generate_random_string(char *buffer, size_t max_len) {
- static const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- size_t len = 1 + rand() % (max_len - 2); /* Ensure at least 1 char */
-
- for (size_t i = 0; i < len; i++) {
- buffer[i] = charset[rand() % (sizeof(charset) - 1)];
- }
- buffer[len] = '\0';
-}
-
-/* Generate random numbers as strings */
-void generate_random_number(char *buffer, size_t max_len) {
- double num = (double)rand() / RAND_MAX * 1000.0;
-
- /* Occasionally make it negative or add decimal places */
- if (rand() % 5 == 0) num = -num;
- if (rand() % 3 != 0) num += (double)(rand() % 100) / 100.0;
-
- snprintf(buffer, max_len, "%.6g", num);
-}
-
-/* Generate a random field name */
-void generate_random_field(char *field, size_t *field_len) {
- generate_random_string(field, MAX_FIELD_SIZE / 2);
- *field_len = strlen(field);
-}
-
-/* Generate a random JSON object with fields */
-char *generate_random_json(size_t *len, char *field, size_t *field_len, int *has_field) {
- char *json = malloc(MAX_JSON_SIZE);
- if (json == NULL) {
- perror("malloc");
- exit(EXIT_FAILURE);
- }
-
- char buffer[MAX_JSON_SIZE / 4]; /* Buffer for generating values */
- int pos = 0;
- int num_fields = 1 + rand() % 10; /* Random number of fields */
- int target_field_index = rand() % num_fields; /* Which field to return */
-
- /* Start the JSON object */
- pos += snprintf(json + pos, MAX_JSON_SIZE - pos, "{");
-
- /* Generate random field/value pairs */
- for (int i = 0; i < num_fields; i++) {
- /* Add a comma if not the first field */
- if (i > 0) {
- pos += snprintf(json + pos, MAX_JSON_SIZE - pos, ", ");
- }
-
- /* Generate a field name */
- if (i == target_field_index) {
- /* This is our target field - save it for the caller */
- generate_random_field(field, field_len);
- pos += snprintf(json + pos, MAX_JSON_SIZE - pos, "\"%s\": ", field);
- *has_field = 1;
- /* Sometimes change the last char so that it will not match. */
- if (rand() % 2) {
- *has_field = 0;
- field[*field_len-1] = '!';
- }
- } else {
- generate_random_string(buffer, MAX_FIELD_SIZE / 4);
- pos += snprintf(json + pos, MAX_JSON_SIZE - pos, "\"%s\": ", buffer);
- }
-
- /* Generate a random value type */
- int value_type = rand() % 5;
- switch (value_type) {
- case 0: /* String */
- generate_random_string(buffer, MAX_JSON_SIZE / 8);
- pos += snprintf(json + pos, MAX_JSON_SIZE - pos, "\"%s\"", buffer);
- break;
-
- case 1: /* Number */
- generate_random_number(buffer, MAX_JSON_SIZE / 8);
- pos += snprintf(json + pos, MAX_JSON_SIZE - pos, "%s", buffer);
- break;
-
- case 2: /* Boolean: true */
- pos += snprintf(json + pos, MAX_JSON_SIZE - pos, "true");
- break;
-
- case 3: /* Boolean: false */
- pos += snprintf(json + pos, MAX_JSON_SIZE - pos, "false");
- break;
-
- case 4: /* Null */
- pos += snprintf(json + pos, MAX_JSON_SIZE - pos, "null");
- break;
-
- case 5: /* Array (simple) */
- pos += snprintf(json + pos, MAX_JSON_SIZE - pos, "[");
- int array_items = 1 + rand() % 5;
- for (int j = 0; j < array_items; j++) {
- if (j > 0) pos += snprintf(json + pos, MAX_JSON_SIZE - pos, ", ");
-
- /* Array items - either number or string */
- if (rand() % 2) {
- generate_random_number(buffer, MAX_JSON_SIZE / 16);
- pos += snprintf(json + pos, MAX_JSON_SIZE - pos, "%s", buffer);
- } else {
- generate_random_string(buffer, MAX_JSON_SIZE / 16);
- pos += snprintf(json + pos, MAX_JSON_SIZE - pos, "\"%s\"", buffer);
- }
- }
- pos += snprintf(json + pos, MAX_JSON_SIZE - pos, "]");
- break;
- }
- }
-
- /* Close the JSON object */
- pos += snprintf(json + pos, MAX_JSON_SIZE - pos, "}");
- *len = pos;
-
- return json;
-}
-
-/* Corrupt JSON by replacing random characters */
-void corrupt_json(char *json, size_t len) {
- if (len < 2) return; /* Too short to corrupt safely */
-
- /* Corrupt 1-3 characters */
- int num_corruptions = 1 + rand() % 3;
- for (int i = 0; i < num_corruptions; i++) {
- size_t pos = rand() % len;
- char corruption = " \t\n{}[]\":,0123456789abcdefXYZ"[rand() % 30];
- json[pos] = corruption;
- }
-}
-
-/* Run standard parser tests with generated valid JSON */
-void run_normal_tests(void) {
- printf("Running normal JSON extraction tests...\n");
-
- for (int i = 0; i < NUM_TEST_ITERATIONS; i++) {
- char field[MAX_FIELD_SIZE] = {0};
- size_t field_len = 0;
- size_t json_len = 0;
- int has_field = 0;
-
- /* Generate random JSON */
- char *json = generate_random_json(&json_len, field, &field_len, &has_field);
-
- /* Use valid field to test parser */
- exprtoken *token = safe_extract_field(json, json_len, field, field_len);
-
- /* Check if we got a token as expected */
- if (has_field && token != NULL) {
- exprTokenRelease(token);
- tests_passed++;
- } else if (!has_field && token == NULL) {
- tests_passed++;
- } else {
- tests_failed++;
- }
-
- /* Test with a non-existent field */
- char nonexistent_field[MAX_FIELD_SIZE] = "nonexistent_field";
- token = safe_extract_field(json, json_len, nonexistent_field, strlen(nonexistent_field));
-
- if (token == NULL) {
- tests_passed++;
- } else {
- exprTokenRelease(token);
- tests_failed++;
- }
-
- free(json);
- }
-}
-
-/* Run tests with corrupted JSON */
-void run_corruption_tests(void) {
- printf("Running JSON corruption tests...\n");
-
- for (int i = 0; i < NUM_CORRUPTION_TESTS; i++) {
- char field[MAX_FIELD_SIZE] = {0};
- size_t field_len = 0;
- size_t json_len = 0;
- int has_field = 0;
-
- /* Generate random JSON */
- char *json = generate_random_json(&json_len, field, &field_len, &has_field);
-
- /* Make a copy and corrupt it */
- char *corrupted = malloc(json_len + 1);
- if (!corrupted) {
- perror("malloc");
- free(json);
- exit(EXIT_FAILURE);
- }
-
- memcpy(corrupted, json, json_len + 1);
- corrupt_json(corrupted, json_len);
-
- /* Test with corrupted JSON */
- exprtoken *token = safe_extract_field(corrupted, json_len, field, field_len);
-
- /* We're just testing that it doesn't crash or access invalid memory */
- if (boundary_violation) {
- printf("Boundary violation with corrupted JSON!\n");
- tests_failed++;
- } else {
- if (token != NULL) {
- exprTokenRelease(token);
- }
- corruptions_passed++;
- }
-
- free(corrupted);
- free(json);
- }
-}
-
-/* Run tests at memory boundaries */
-void run_boundary_tests(void) {
- printf("Running memory boundary tests...\n");
-
- for (int i = 0; i < NUM_BOUNDARY_TESTS; i++) {
- char field[MAX_FIELD_SIZE] = {0};
- size_t field_len = 0;
- size_t json_len = 0;
- int has_field = 0;
-
- /* Generate random JSON */
- char *temp_json = generate_random_json(&json_len, field, &field_len, &has_field);
-
- /* Truncate the JSON to a random length */
- size_t truncated_len = 1 + rand() % json_len;
-
- /* Place at the edge of the safe page */
- size_t offset = PAGE_SIZE - truncated_len;
- memcpy(safe_page + offset, temp_json, truncated_len);
-
- /* Test parsing with non-existent field (forcing it to scan to end) */
- char nonexistent_field[MAX_FIELD_SIZE] = "nonexistent_field";
- exprtoken *token = safe_extract_field(safe_page + offset, truncated_len,
- nonexistent_field, strlen(nonexistent_field));
-
- /* We're just testing that it doesn't access memory beyond the boundary */
- if (boundary_violation) {
- printf("Boundary violation at edge of memory page!\n");
- tests_failed++;
- } else {
- if (token != NULL) {
- exprTokenRelease(token);
- }
- boundary_tests_passed++;
- }
-
- free(temp_json);
- }
-}
-
-/* Print summary of test results */
-void print_test_summary(void) {
- printf("\n===== FASTJSON PARSER TEST SUMMARY =====\n");
- printf("Normal tests passed: %d/%d\n", tests_passed, NUM_TEST_ITERATIONS * 2);
- printf("Corruption tests passed: %d/%d\n", corruptions_passed, NUM_CORRUPTION_TESTS);
- printf("Boundary tests passed: %d/%d\n", boundary_tests_passed, NUM_BOUNDARY_TESTS);
- printf("Failed tests: %d\n", tests_failed);
-
- if (tests_failed == 0) {
- printf("\nALL TESTS PASSED! The JSON parser appears to be robust.\n");
- } else {
- printf("\nSome tests FAILED. The JSON parser may be vulnerable.\n");
- }
-}
-
-/* Entry point for fastjson parser test */
-void run_fastjson_test(void) {
- printf("Starting fastjson parser stress test...\n");
-
- /* Seed the random number generator */
- srand(time(NULL));
-
- /* Setup test memory environment */
- setup_test_memory();
-
- /* Run the various test phases */
- run_normal_tests();
- run_corruption_tests();
- run_boundary_tests();
-
- /* Print summary */
- print_test_summary();
-
- /* Cleanup */
- cleanup_test_memory();
-}