diff options
Diffstat (limited to 'examples/redis-unstable/modules/vector-sets/fastjson_test.c')
| -rw-r--r-- | examples/redis-unstable/modules/vector-sets/fastjson_test.c | 406 |
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(); -} |
