## Overview Comprehensive development methodology and best practices for building applications with the DAP SDK. This guide covers coding standards, design patterns, performance optimization, debugging techniques, and advanced development workflows that will help you create robust, maintainable, and efficient DAP SDK applications. **What This Guide Covers:** - **Coding Standards** - Consistent coding style and conventions - **Design Patterns** - Common patterns and architectural approaches - **Performance Optimization** - Techniques for high-performance applications - **Error Handling** - Robust error handling strategies - **Testing & Debugging** - Development and debugging best practices - **Security Considerations** - Secure development practices - **Module Integration** - Best practices for using DAP SDK modules ## Coding Standards ### Code Style Guidelines #### Naming Conventions ```c // Functions: snake_case with module prefix int dap_module_function_name(void); static int module_internal_function(void); // Variables: snake_case int user_count; char *config_file_path; const char *default_setting; // Constants and macros: UPPER_CASE #define DAP_MAX_CONNECTIONS 1000 #define DAP_DEFAULT_TIMEOUT 30000 // Types: snake_case with _t suffix typedef struct user_info { char *name; int age; } user_info_t; // Enums: snake_case with module prefix typedef enum dap_status { DAP_STATUS_SUCCESS, DAP_STATUS_ERROR, DAP_STATUS_PENDING } dap_status_t; ``` #### File Organization ```c // Header file structure (example_module.h) #ifndef EXAMPLE_MODULE_H #define EXAMPLE_MODULE_H #include <stdint.h> #include <stdbool.h> // Forward declarations typedef struct example_context example_context_t; // Public constants #define EXAMPLE_MAX_SIZE 256 // Public types typedef enum example_status { EXAMPLE_SUCCESS = 0, EXAMPLE_ERROR = -1 } example_status_t; // Public API functions example_context_t* example_create(const char *name); int example_process(example_context_t *ctx, const void *data, size_t size); void example_destroy(example_context_t *ctx); #endif // EXAMPLE_MODULE_H ``` ```c // Implementation file structure (example_module.c) #include "example_module.h" #include <dap/dap_common.h> #include <stdlib.h> #include <string.h> // Internal constants #define INTERNAL_BUFFER_SIZE 512 // Internal types struct example_context { char *name; uint8_t *buffer; size_t buffer_size; bool is_initialized; }; // Internal function prototypes static int example_validate_input(const void *data, size_t size); static int example_internal_process(example_context_t *ctx, const void *data); // Public API implementation example_context_t* example_create(const char *name) { if (!name) { log_it_error("Name parameter is NULL"); return NULL; } example_context_t *ctx = DAP_NEW_Z(example_context_t); if (!ctx) { log_it_error("Failed to allocate context"); return NULL; } ctx->name = dap_strdup(name); ctx->buffer = DAP_NEW_Z_SIZE(uint8_t, INTERNAL_BUFFER_SIZE); ctx->buffer_size = INTERNAL_BUFFER_SIZE; ctx->is_initialized = true; log_it_debug("Created example context for '%s'", name); return ctx; } // ... rest of implementation ``` ### Documentation Standards #### Function Documentation ```c /** * @brief Process data through the example module * * This function validates and processes the input data using the provided * context. The data is copied to an internal buffer and processed according * to the module's algorithm. * * @param ctx Example context created with example_create() * @param data Input data to process (must not be NULL) * @param size Size of input data in bytes (must be > 0 and <= EXAMPLE_MAX_SIZE) * * @return EXAMPLE_SUCCESS on success * @return EXAMPLE_ERROR on failure (check logs for details) * * @note This function is thread-safe when used with different contexts * @warning The context must be properly initialized before calling this function * * @see example_create(), example_destroy() * @since Version 1.0.0 */ int example_process(example_context_t *ctx, const void *data, size_t size); ``` #### Code Comments ```c int example_complex_function(const char *input) { // Validate input parameters if (!input || strlen(input) == 0) { log_it_error("Invalid input parameter"); return EXAMPLE_ERROR; } // TODO: Implement caching for frequently used inputs // FIXME: Handle edge case when input contains null bytes // NOTE: This algorithm has O(n²) complexity, consider optimization /* * Complex algorithm implementation: * 1. Parse input string into tokens * 2. Validate each token against known patterns * 3. Apply transformation rules * 4. Generate output */ return EXAMPLE_SUCCESS; } ``` ## Design Patterns ### Initialization Pattern ```c // Standard initialization pattern for modules typedef struct module_config { char *name; size_t buffer_size; bool enable_debug; } module_config_t; typedef struct module_context { module_config_t config; bool is_initialized; // ... other fields } module_context_t; int module_init(module_context_t *ctx, const module_config_t *config) { // Parameter validation if (!ctx || !config) { return DAP_ERROR_INVALID_PARAMETER; } // Prevent double initialization if (ctx->is_initialized) { log_it_warning("Module already initialized"); return DAP_ERROR_SUCCESS; } // Copy configuration memcpy(&ctx->config, config, sizeof(module_config_t)); if (config->name) { ctx->config.name = dap_strdup(config->name); } // Initialize resources if (module_allocate_resources(ctx) != 0) { log_it_error("Failed to allocate resources"); module_cleanup_partial(ctx); return DAP_ERROR_OUT_OF_MEMORY; } ctx->is_initialized = true; log_it_info("Module '%s' initialized successfully", config->name); return DAP_ERROR_SUCCESS; } void module_deinit(module_context_t *ctx) { if (!ctx || !ctx->is_initialized) { return; } // Cleanup in reverse order of initialization module_free_resources(ctx); DAP_DELETE(ctx->config.name); ctx->is_initialized = false; log_it_debug("Module deinitialized"); } ``` ### Resource Management Pattern (RAII-style) ```c // Resource handle with automatic cleanup typedef struct resource_handle { void *data; void (*cleanup_func)(void *); bool is_valid; } resource_handle_t; resource_handle_t* resource_acquire(const char *name) { resource_handle_t *handle = DAP_NEW_Z(resource_handle_t); if (!handle) { return NULL; } handle->data = allocate_resource(name); if (!handle->data) { DAP_DELETE(handle); return NULL; } handle->cleanup_func = free_resource; handle->is_valid = true; return handle; } void resource_release(resource_handle_t *handle) { if (!handle) { return; } if (handle->is_valid && handle->data && handle->cleanup_func) { handle->cleanup_func(handle->data); } handle->is_valid = false; handle->data = NULL; handle->cleanup_func = NULL; DAP_DELETE(handle); } // Usage with scope-based cleanup int function_using_resource(void) { resource_handle_t *resource = resource_acquire("example"); if (!resource) { return DAP_ERROR_OUT_OF_MEMORY; } int result = DAP_ERROR_SUCCESS; // Use resource... if (process_with_resource(resource->data) != 0) { result = DAP_ERROR_GENERAL; goto cleanup; } // More operations... cleanup: resource_release(resource); return result; } ``` ### Observer Pattern for Events ```c // Event system implementation typedef struct event_listener { void (*callback)(int event_type, void *data, void *user_data); void *user_data; struct event_listener *next; } event_listener_t; typedef struct event_manager { event_listener_t *listeners[EVENT_TYPE_COUNT]; pthread_mutex_t mutex; } event_manager_t; int event_manager_subscribe(event_manager_t *mgr, int event_type, void (*callback)(int, void*, void*), void *user_data) { if (!mgr || !callback || event_type >= EVENT_TYPE_COUNT) { return DAP_ERROR_INVALID_PARAMETER; } event_listener_t *listener = DAP_NEW_Z(event_listener_t); if (!listener) { return DAP_ERROR_OUT_OF_MEMORY; } listener->callback = callback; listener->user_data = user_data; pthread_mutex_lock(&mgr->mutex); listener->next = mgr->listeners[event_type]; mgr->listeners[event_type] = listener; pthread_mutex_unlock(&mgr->mutex); return DAP_ERROR_SUCCESS; } void event_manager_notify(event_manager_t *mgr, int event_type, void *data) { if (!mgr || event_type >= EVENT_TYPE_COUNT) { return; } pthread_mutex_lock(&mgr->mutex); event_listener_t *listener = mgr->listeners[event_type]; while (listener) { if (listener->callback) { listener->callback(event_type, data, listener->user_data); } listener = listener->next; } pthread_mutex_unlock(&mgr->mutex); } ``` ### Builder Pattern for Complex Configuration ```c // Configuration builder for complex setups typedef struct server_config_builder { char *host; int port; size_t max_connections; size_t buffer_size; bool enable_ssl; char *ssl_cert_path; char *ssl_key_path; } server_config_builder_t; server_config_builder_t* server_config_builder_new(void) { server_config_builder_t *builder = DAP_NEW_Z(server_config_builder_t); if (builder) { // Set defaults builder->host = dap_strdup("localhost"); builder->port = 8080; builder->max_connections = 100; builder->buffer_size = 4096; builder->enable_ssl = false; } return builder; } server_config_builder_t* server_config_set_host(server_config_builder_t *builder, const char *host) { if (builder && host) { DAP_DELETE(builder->host); builder->host = dap_strdup(host); } return builder; } server_config_builder_t* server_config_set_port(server_config_builder_t *builder, int port) { if (builder && port > 0 && port <= 65535) { builder->port = port; } return builder; } server_config_builder_t* server_config_enable_ssl(server_config_builder_t *builder, const char *cert_path, const char *key_path) { if (builder && cert_path && key_path) { builder->enable_ssl = true; DAP_DELETE(builder->ssl_cert_path); DAP_DELETE(builder->ssl_key_path); builder->ssl_cert_path = dap_strdup(cert_path); builder->ssl_key_path = dap_strdup(key_path); } return builder; } server_config_t* server_config_build(server_config_builder_t *builder) { if (!builder) { return NULL; } server_config_t *config = DAP_NEW_Z(server_config_t); if (config) { // Copy all settings from builder config->host = dap_strdup(builder->host); config->port = builder->port; config->max_connections = builder->max_connections; // ... copy other fields } return config; } // Usage example int setup_server(void) { server_config_t *config = server_config_builder_new() ->server_config_set_host("0.0.0.0") ->server_config_set_port(443) ->server_config_enable_ssl("/path/to/cert.pem", "/path/to/key.pem") ->server_config_build(); if (!config) { return DAP_ERROR_OUT_OF_MEMORY; } int result = server_start(config); server_config_free(config); return result; } ``` ## Performance Optimization ### Memory Pool Usage ```c // Memory pool for frequent allocations typedef struct message_pool { void **available_messages; size_t pool_size; size_t available_count; size_t message_size; pthread_mutex_t mutex; } message_pool_t; message_pool_t* message_pool_create(size_t pool_size, size_t message_size) { message_pool_t *pool = DAP_NEW_Z(message_pool_t); if (!pool) { return NULL; } pool->available_messages = DAP_NEW_Z_SIZE(void*, pool_size); if (!pool->available_messages) { DAP_DELETE(pool); return NULL; } // Pre-allocate messages for (size_t i = 0; i < pool_size; i++) { pool->available_messages[i] = dap_malloc(message_size); if (!pool->available_messages[i]) { // Cleanup on failure message_pool_destroy(pool); return NULL; } } pool->pool_size = pool_size; pool->available_count = pool_size; pool->message_size = message_size; pthread_mutex_init(&pool->mutex, NULL); return pool; } void* message_pool_acquire(message_pool_t *pool) { if (!pool) { return NULL; } pthread_mutex_lock(&pool->mutex); void *message = NULL; if (pool->available_count > 0) { message = pool->available_messages[--pool->available_count]; memset(message, 0, pool->message_size); // Clear for reuse } pthread_mutex_unlock(&pool->mutex); // Fall back to regular allocation if pool is empty if (!message) { message = dap_calloc(1, pool->message_size); } return message; } void message_pool_release(message_pool_t *pool, void *message) { if (!pool || !message) { return; } pthread_mutex_lock(&pool->mutex); if (pool->available_count < pool->pool_size) { pool->available_messages[pool->available_count++] = message; message = NULL; // Don't free it } pthread_mutex_unlock(&pool->mutex); // Free if pool is full if (message) { dap_free(message); } } ``` ### Lock-Free Programming ```c // Lock-free queue implementation (simplified) typedef struct lock_free_node { void *data; _Atomic(struct lock_free_node*) next; } lock_free_node_t; typedef struct lock_free_queue { _Atomic(lock_free_node_t*) head; _Atomic(lock_free_node_t*) tail; } lock_free_queue_t; int lock_free_queue_enqueue(lock_free_queue_t *queue, void *data) { if (!queue || !data) { return DAP_ERROR_INVALID_PARAMETER; } lock_free_node_t *new_node = DAP_NEW_Z(lock_free_node_t); if (!new_node) { return DAP_ERROR_OUT_OF_MEMORY; } new_node->data = data; atomic_store(&new_node->next, NULL); lock_free_node_t *prev_tail = atomic_exchange(&queue->tail, new_node); atomic_store(&prev_tail->next, new_node); return DAP_ERROR_SUCCESS; } void* lock_free_queue_dequeue(lock_free_queue_t *queue) { if (!queue) { return NULL; } lock_free_node_t *head = atomic_load(&queue->head); lock_free_node_t *next = atomic_load(&head->next); if (!next) { return NULL; // Queue is empty } void *data = next->data; atomic_store(&queue->head, next); DAP_DELETE(head); return data; } ``` ### Asynchronous Processing Patterns ```c // Asynchronous task system typedef struct async_task { void (*function)(void *arg); void *argument; void (*callback)(void *result, void *user_data); void *user_data; struct async_task *next; } async_task_t; typedef struct async_executor { async_task_t *task_queue; pthread_t *worker_threads; size_t thread_count; pthread_mutex_t queue_mutex; pthread_cond_t queue_condition; bool shutdown; } async_executor_t; void* async_worker_thread(void *arg) { async_executor_t *executor = (async_executor_t*)arg; while (!executor->shutdown) { pthread_mutex_lock(&executor->queue_mutex); // Wait for tasks while (!executor->task_queue && !executor->shutdown) { pthread_cond_wait(&executor->queue_condition, &executor->queue_mutex); } if (executor->shutdown) { pthread_mutex_unlock(&executor->queue_mutex); break; } // Get next task async_task_t *task = executor->task_queue; executor->task_queue = task->next; pthread_mutex_unlock(&executor->queue_mutex); // Execute task if (task->function) { task->function(task->argument); } // Call completion callback if (task->callback) { task->callback(NULL, task->user_data); } DAP_DELETE(task); } return NULL; } int async_executor_submit(async_executor_t *executor, void (*function)(void*), void *argument, void (*callback)(void*, void*), void *user_data) { if (!executor || !function) { return DAP_ERROR_INVALID_PARAMETER; } async_task_t *task = DAP_NEW_Z(async_task_t); if (!task) { return DAP_ERROR_OUT_OF_MEMORY; } task->function = function; task->argument = argument; task->callback = callback; task->user_data = user_data; pthread_mutex_lock(&executor->queue_mutex); task->next = executor->task_queue; executor->task_queue = task; pthread_cond_signal(&executor->queue_condition); pthread_mutex_unlock(&executor->queue_mutex); return DAP_ERROR_SUCCESS; } ``` ## Error Handling Best Practices ### Comprehensive Error Handling ```c // Error context for detailed error reporting typedef struct error_context { dap_error_t code; char message[256]; char function[64]; char file[128]; int line; struct error_context *cause; // Chain of errors } error_context_t; #define SET_ERROR(ctx, err_code, msg) \ do { \ if (ctx) { \ (ctx)->code = (err_code); \ snprintf((ctx)->message, sizeof((ctx)->message), "%s", (msg)); \ snprintf((ctx)->function, sizeof((ctx)->function), "%s", __FUNCTION__); \ snprintf((ctx)->file, sizeof((ctx)->file), "%s", __FILE__); \ (ctx)->line = __LINE__; \ } \ log_it_error("Error in %s:%d - %s", __FUNCTION__, __LINE__, (msg)); \ } while(0) #define PROPAGATE_ERROR(dest_ctx, src_ctx, msg) \ do { \ if ((dest_ctx) && (src_ctx)) { \ SET_ERROR((dest_ctx), (src_ctx)->code, (msg)); \ (dest_ctx)->cause = (src_ctx); \ } \ } while(0) // Example function with comprehensive error handling int process_file_with_validation(const char *filename, error_context_t *error_ctx) { if (!filename) { SET_ERROR(error_ctx, DAP_ERROR_INVALID_PARAMETER, "Filename is NULL"); return DAP_ERROR_INVALID_PARAMETER; } FILE *file = fopen(filename, "r"); if (!file) { SET_ERROR(error_ctx, DAP_ERROR_FILE_NOT_FOUND, "Could not open file for reading"); return DAP_ERROR_FILE_NOT_FOUND; } // Get file size fseek(file, 0, SEEK_END); long file_size = ftell(file); fseek(file, 0, SEEK_SET); if (file_size <= 0) { SET_ERROR(error_ctx, DAP_ERROR_FILE_FORMAT_ERROR, "File is empty or invalid"); fclose(file); return DAP_ERROR_FILE_FORMAT_ERROR; } // Allocate buffer char *buffer = dap_malloc(file_size + 1); if (!buffer) { SET_ERROR(error_ctx, DAP_ERROR_OUT_OF_MEMORY, "Could not allocate buffer for file content"); fclose(file); return DAP_ERROR_OUT_OF_MEMORY; } // Read file content size_t bytes_read = fread(buffer, 1, file_size, file); if (bytes_read != (size_t)file_size) { SET_ERROR(error_ctx, DAP_ERROR_FILE_IO_ERROR, "Could not read complete file content"); dap_free(buffer); fclose(file); return DAP_ERROR_FILE_IO_ERROR; } buffer[file_size] = '\0'; // Process the content error_context_t processing_error = {0}; int result = process_content(buffer, &processing_error); if (result != DAP_ERROR_SUCCESS) { PROPAGATE_ERROR(error_ctx, &processing_error, "Failed to process file content"); dap_free(buffer); fclose(file); return result; } // Cleanup dap_free(buffer); fclose(file); log_it_info("Successfully processed file: %s", filename); return DAP_ERROR_SUCCESS; } ``` ### Retry and Recovery Patterns ```c // Retry mechanism with exponential backoff typedef struct retry_config { int max_attempts; int initial_delay_ms; int max_delay_ms; double backoff_multiplier; } retry_config_t; int execute_with_retry(int (*operation)(void *arg), void *arg, const retry_config_t *config, error_context_t *error_ctx) { if (!operation || !config) { SET_ERROR(error_ctx, DAP_ERROR_INVALID_PARAMETER, "Invalid parameters for retry operation"); return DAP_ERROR_INVALID_PARAMETER; } int delay_ms = config->initial_delay_ms; for (int attempt = 1; attempt <= config->max_attempts; attempt++) { log_it_debug("Attempt %d/%d", attempt, config->max_attempts); error_context_t attempt_error = {0}; int result = operation(arg); if (result == DAP_ERROR_SUCCESS) { log_it_info("Operation succeeded on attempt %d", attempt); return DAP_ERROR_SUCCESS; } // Log the failure log_it_warning("Attempt %d failed with error %d", attempt, result); // Don't retry on certain errors if (result == DAP_ERROR_INVALID_PARAMETER || result == DAP_ERROR_NOT_SUPPORTED) { SET_ERROR(error_ctx, result, "Operation failed with non-retryable error"); return result; } // Sleep before next attempt (except on last attempt) if (attempt < config->max_attempts) { usleep(delay_ms * 1000); delay_ms = (int)(delay_ms * config->backoff_multiplier); if (delay_ms > config->max_delay_ms) { delay_ms = config->max_delay_ms; } } } SET_ERROR(error_ctx, DAP_ERROR_GENERAL, "Operation failed after all retry attempts"); return DAP_ERROR_GENERAL; } // Usage example int unreliable_network_operation(void *arg) { // Simulate network operation that might fail if (rand() % 3 == 0) { // 33% success rate return DAP_ERROR_SUCCESS; } return DAP_ERROR_NETWORK_UNREACHABLE; } int example_with_retry(void) { retry_config_t config = { .max_attempts = 5, .initial_delay_ms = 100, .max_delay_ms = 5000, .backoff_multiplier = 2.0 }; error_context_t error_ctx = {0}; int result = execute_with_retry(unreliable_network_operation, NULL, &config, &error_ctx); if (result != DAP_ERROR_SUCCESS) { log_it_error("Operation failed: %s", error_ctx.message); } return result; } ``` ## Testing and Debugging ### Unit Testing Patterns ```c // Unit test framework integration #include <dap/dap_test.h> // Test fixture setup typedef struct test_fixture { char *test_data; size_t data_size; void *mock_context; } test_fixture_t; DAP_TEST_RESULT setup_string_tests(void) { test_fixture_t *fixture = DAP_NEW_Z(test_fixture_t); if (!fixture) { return DAP_TEST_FAIL; } fixture->test_data = dap_strdup("test string data"); fixture->data_size = strlen(fixture->test_data); fixture->mock_context = create_mock_context(); dap_test_set_fixture(fixture); return DAP_TEST_PASS; } void teardown_string_tests(void) { test_fixture_t *fixture = (test_fixture_t*)dap_test_get_fixture(); if (fixture) { DAP_DELETE(fixture->test_data); destroy_mock_context(fixture->mock_context); DAP_DELETE(fixture); } } DAP_TEST_RESULT test_string_processing_with_mocks(void) { test_fixture_t *fixture = (test_fixture_t*)dap_test_get_fixture(); DAP_ASSERT_NOT_NULL(fixture); DAP_ASSERT_NOT_NULL(fixture->test_data); // Mock external dependencies mock_set_return_value(fixture->mock_context, "external_call", 42); // Test the function result_t result = string_process_function(fixture->test_data); // Verify results DAP_ASSERT_EQUAL(result.status, SUCCESS); DAP_ASSERT_STRING_EQUAL(result.output, "expected output"); // Verify mock interactions DAP_ASSERT_EQUAL(mock_get_call_count(fixture->mock_context, "external_call"), 1); return DAP_TEST_PASS; } // Property-based testing DAP_TEST_RESULT test_hash_function_properties(void) { const int test_iterations = 1000; for (int i = 0; i < test_iterations; i++) { // Generate random test data size_t data_size = rand() % 1000 + 1; uint8_t *test_data = generate_random_data(data_size); dap_hash_fast_t hash1, hash2; // Property: Same input produces same output DAP_ASSERT_EQUAL(dap_hash_fast(test_data, data_size, &hash1), 0); DAP_ASSERT_EQUAL(dap_hash_fast(test_data, data_size, &hash2), 0); DAP_ASSERT_MEMORY_EQUAL(&hash1, &hash2, sizeof(hash1)); // Property: Different input should produce different output if (data_size > 1) { test_data[0] ^= 0xFF; // Flip bits dap_hash_fast_t hash3; DAP_ASSERT_EQUAL(dap_hash_fast(test_data, data_size, &hash3), 0); DAP_ASSERT_MEMORY_NOT_EQUAL(&hash1, &hash3, sizeof(hash1)); } free(test_data); } return DAP_TEST_PASS; } ``` ### Debug Utilities ```c // Debug tracing system #ifdef DAP_DEBUG #define TRACE_ENTRY() \ log_it_debug("ENTER %s:%d", __FUNCTION__, __LINE__) #define TRACE_EXIT(retval) \ do { \ log_it_debug("EXIT %s:%d returning %d", __FUNCTION__, __LINE__, (retval)); \ return (retval); \ } while(0) #define TRACE_EXIT_VOID() \ do { \ log_it_debug("EXIT %s:%d", __FUNCTION__, __LINE__); \ return; \ } while(0) #define DUMP_BUFFER(buf, size) \ do { \ if (dap_log_level >= DAP_LOG_DEBUG) { \ log_it_debug("Buffer dump (%zu bytes):", (size)); \ for (size_t i = 0; i < (size); i += 16) { \ char hex[49] = {0}; \ char ascii[17] = {0}; \ for (size_t j = 0; j < 16 && (i + j) < (size); j++) { \ uint8_t byte = ((uint8_t*)(buf))[i + j]; \ sprintf(hex + j * 3, "%02x ", byte); \ ascii[j] = (byte >= 32 && byte <= 126) ? byte : '.'; \ } \ log_it_debug(" %04zx: %-48s %s", i, hex, ascii); \ } \ } \ } while(0) #else #define TRACE_ENTRY() #define TRACE_EXIT(retval) return (retval) #define TRACE_EXIT_VOID() return #define DUMP_BUFFER(buf, size) #endif // DAP_DEBUG // Usage in functions int complex_function(const void *data, size_t size) { TRACE_ENTRY(); if (!data || size == 0) { log_it_error("Invalid parameters"); TRACE_EXIT(DAP_ERROR_INVALID_PARAMETER); } DUMP_BUFFER(data, size); // Function implementation... int result = process_data(data, size); if (result != 0) { log_it_error("Processing failed: %d", result); TRACE_EXIT(result); } log_it_info("Processing completed successfully"); TRACE_EXIT(DAP_ERROR_SUCCESS); } ``` ## Security Best Practices ### Input Validation and Sanitization ```c // Comprehensive input validation typedef struct validation_result { bool is_valid; char error_message[256]; size_t sanitized_length; } validation_result_t; validation_result_t validate_string_input(const char *input, size_t max_length, bool allow_special_chars) { validation_result_t result = {0}; // Check for NULL input if (!input) { result.is_valid = false; snprintf(result.error_message, sizeof(result.error_message), "Input string is NULL"); return result; } size_t length = strlen(input); // Check length constraints if (length == 0) { result.is_valid = false; snprintf(result.error_message, sizeof(result.error_message), "Input string is empty"); return result; } if (length > max_length) { result.is_valid = false; snprintf(result.error_message, sizeof(result.error_message), "Input string too long: %zu > %zu", length, max_length); return result; } // Character validation for (size_t i = 0; i < length; i++) { unsigned char c = input[i]; // Check for control characters if (c < 32 && c != '\t' && c != '\n' && c != '\r') { result.is_valid = false; snprintf(result.error_message, sizeof(result.error_message), "Invalid control character at position %zu", i); return result; } // Check for high-bit characters (potential encoding issues) if (c > 127) { result.is_valid = false; snprintf(result.error_message, sizeof(result.error_message), "Non-ASCII character at position %zu", i); return result; } // Check special characters if not allowed if (!allow_special_chars) { if (!isalnum(c) && c != ' ' && c != '-' && c != '_' && c != '.') { result.is_valid = false; snprintf(result.error_message, sizeof(result.error_message), "Special character '%c' not allowed at position %zu", c, i); return result; } } } result.is_valid = true; result.sanitized_length = length; return result; } char* sanitize_filename(const char *input) { if (!input) { return NULL; } size_t length = strlen(input); char *sanitized = dap_malloc(length + 1); if (!sanitized) { return NULL; } size_t out_pos = 0; for (size_t i = 0; i < length; i++) { char c = input[i]; // Replace dangerous characters if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' || c == '<' || c == '>' || c == '|') { sanitized[out_pos++] = '_'; } else if (c >= 32 && c <= 126) { // Printable ASCII only sanitized[out_pos++] = c; } // Skip other characters } sanitized[out_pos] = '\0'; return sanitized; } ``` ### Secure Memory Operations ```c // Secure memory utilities void* secure_malloc(size_t size) { if (size == 0) { return NULL; } // Allocate extra space for canary values size_t total_size = size + 2 * sizeof(uint64_t); uint8_t *ptr = dap_malloc(total_size); if (!ptr) { return NULL; } // Set canary values uint64_t canary = 0xDEADBEEFCAFEBABE; memcpy(ptr, &canary, sizeof(canary)); memcpy(ptr + sizeof(canary) + size, &canary, sizeof(canary)); // Zero the actual data area memset(ptr + sizeof(canary), 0, size); return ptr + sizeof(canary); } void secure_free(void *ptr, size_t size) { if (!ptr) { return; } uint8_t *real_ptr = (uint8_t*)ptr - sizeof(uint64_t); uint64_t expected_canary = 0xDEADBEEFCAFEBABE; uint64_t start_canary, end_canary; // Check canary values memcpy(&start_canary, real_ptr, sizeof(start_canary)); memcpy(&end_canary, real_ptr + sizeof(uint64_t) + size, sizeof(end_canary)); if (start_canary != expected_canary || end_canary != expected_canary) { log_it_critical("Memory corruption detected! Canary values mismatch"); abort(); // Terminate immediately on corruption } // Securely clear memory before freeing volatile uint8_t *volatile_ptr = (volatile uint8_t*)ptr; for (size_t i = 0; i < size; i++) { volatile_ptr[i] = 0; } dap_free(real_ptr); } // Secure string operations int secure_strncpy(char *dest, size_t dest_size, const char *src, size_t max_copy) { if (!dest || !src || dest_size == 0) { return DAP_ERROR_INVALID_PARAMETER; } size_t copy_len = strnlen(src, max_copy); if (copy_len >= dest_size) { copy_len = dest_size - 1; } memcpy(dest, src, copy_len); dest[copy_len] = '\0'; return (copy_len < max_copy) ? DAP_ERROR_SUCCESS : DAP_ERROR_BUFFER_TOO_SMALL; } int secure_memcmp(const void *a, const void *b, size_t size) { const volatile uint8_t *va = (const volatile uint8_t*)a; const volatile uint8_t *vb = (const volatile uint8_t*)b; volatile int result = 0; // Constant-time comparison to prevent timing attacks for (size_t i = 0; i < size; i++) { result |= va[i] ^ vb[i]; } return result; } ``` ## Next Steps To apply these development practices effectively: 1. **[[First Application|First Application]]** - Practice these patterns in a real application 2. **[[Architecture Overview|Architecture Overview]]** - Understand how patterns fit into the overall design 3. **[[Modules/Module DAP Test|Module DAP Test]]** - Implement comprehensive testing 4. **[[Troubleshooting|Troubleshooting]]** - Debug and resolve common issues For advanced topics: - **[[Modules/Module Overview|Module Overview]]** - Explore specific module development patterns - **[[Glossary|Glossary]]** - Complete API reference for development functions --- *Last updated: December 2024 | Version: 1.0 | Development Guide for DAP SDK*