Commit Graph

106 Commits

Author SHA1 Message Date
anth64 fb0d8adb8f chore: bump version to 0.0.4 v0.0.4 2026-02-11 00:22:59 +01:00
anth64 2c4d27f915 fix(linux): prevent segfault from invalid module indices during rapid reloads
When spamming file changes rapidly, inotify can report stale UNLOAD/RELOAD
events for modules that were already unloaded by previous events in the same
poll cycle. This caused is_mod_loaded() to return -1, which was then cast to
size_t (18446744073709551615) and used as an array index, causing segfaults.

Additionally, event counts were calculated before validation, causing loops to
run more iterations than valid indices were populated, reading garbage values.

Changes:
- stk.c: Check if is_mod_loaded() returns valid index (>= 0) before adding
  to unload/reload lists
- stk.c: Reset and recalculate counts after populating arrays with only valid
  indices to prevent loop overrun
- Skip processing events for modules that are no longer loaded

This completes the Linux stability fixes started in v0.0.2.
2026-02-11 00:17:33 +01:00
anth64 96fb957991 chore: bump version to 0.0.3 v0.0.3 2026-02-09 23:03:35 +01:00
anth64 0cbee45ad2 fix(platform): replace strncpy with memmove to silence -Wrestrict warning 2026-02-09 22:53:42 +01:00
anth64 142a61a843 chore: bump version to 0.0.2 v0.0.2 2026-02-09 22:32:55 +01:00
anth64 f83f2051ef fix(linux): prevent segfaults during rapid module reloads
Fixes multiple issues causing segfaults when hot-reloading modules
on Linux, particularly when file changes are detected rapidly:

- Enable is_file_ready() check on Linux to prevent loading partially-written
  shared libraries (previously only used on Windows/BSD)
- Fix event deduplication on Linux to actually remove duplicate inotify events
  instead of just marking them, preventing double-free on same module
- Reorder reload operations to unload old module only after successfully
  copying new version, avoiding invalid state when copy fails

Changes:
- platform.c: Remove __linux__ guards around is_file_ready() function
- platform.c: Add compaction step after deduplication to remove -1 entries
- stk.c: Move module unload to after platform_copy_file() in reload loop

These changes make Linux hot-reload as robust as Windows/BSD implementations.
2026-02-09 22:25:02 +01:00
anth64 043fea6092 fix(install): install headers to stk/ subdirectory for proper namespacing
- Install headers to /include/stk/ instead of /include/
- Update README examples to use #include <stk/stk.h>
- Update Windows install instructions to reflect stk/ directory structure
- Add MPL-2.0 license badge to README
- Clarify DLL can be placed in binary or lib directory on Windows

This prevents header name collisions with other libraries and follows
standard library distribution conventions (similar to SDL).
Users now include stk headers as <stk/stk.h> rather than <stk.h>.
v0.0.1
2026-02-02 22:52:44 +01:00
anth64 96a3d80e60 docs: add comprehensive usage examples and API reference to README 2026-02-01 12:07:51 +01:00
anth64 e0ee9226e7 chore: bump version to 0.0.1 2026-02-01 11:42:39 +01:00
anth64 761f6fdc02 docs: add changelog for 0.0.1 release 2026-02-01 11:22:46 +01:00
anth64 64f7260b3a feat(build): add install and uninstall targets for Unix systems
- Add PREFIX, LIBDIR, and INCDIR variables (default: /usr/local)
- Implement install target that builds release and installs to system paths
- Implement uninstall target to cleanly remove installed files
- Support custom install locations via PREFIX variable
- Add helpful message on Windows directing users to manual installation

Both gmake.mk and bmake.mk now support standard installation workflow
on Unix-like systems (Linux, BSD, macOS). Windows users are instructed
to copy files manually as per platform conventions.

Usage:
  make install              # Install to /usr/local (requires root)
  make PREFIX=$HOME install # Install to custom location
  make uninstall            # Remove installed files
2026-02-01 11:19:02 +01:00
anth64 28dfc89b15 fix(platform): correct filename buffer handling and prevent overflows
- Replace undefined 'len' variable references with 'name_len'
- Add explicit null terminators after memcpy operations
- Move name_len declaration to Windows-specific scope to eliminate unused variable warning on BSD
- Standardize string copy pattern across all platforms: strlen -> clamp -> memcpy -> null terminate
- Fix increment operator placement for clarity (i++ moved outside array indexing)
- Remove duplicate name_len declaration in platform_directory_watch_check

This ensures proper bounds checking and null termination for filenames
on both Windows and BSD systems, preventing potential buffer overflows
when handling long filenames (approaching STK_PATH_MAX).
2026-02-01 02:38:45 +01:00
anth64 1919287c39 fix(test): ensure Windows compatibility in test suite
- Add OS detection for Windows vs Unix platforms
- Handle .exe extension on Windows for test program
- Fix directory creation with Windows-native commands (mkdir/copy vs mkdir -p/cp)
- Update clean target to use appropriate commands per platform
- Set PATH environment for DLL loading on Windows
- Remove broken uname detection that fails on Windows
2026-02-01 01:41:03 +01:00
anth64 dc30ce5366 fix: cast size_t to unsigned long in printf format specifiers
Prevent potential format string mismatches on platforms where
size_t and unsigned long may have different sizes by explicitly
casting size_t variables to unsigned long when using %lu format
specifier in printf calls.
2026-02-01 01:39:01 +01:00
anth64 11d8c5cd46 fix(platform): fix string truncation warnings on Windows
Replace strncpy with memcpy+nullterm to handle Windows MAX_PATH (259) vs
STK_PATH_MAX (256) mismatch.
2026-02-01 01:35:05 +01:00
anth64 c514b09be9 fix(build): correct release library output path on BSD systems 2026-01-31 23:30:56 +01:00
anth64 d7f6adb5b5 fix(build): resolve BSD make compatibility issues
- Use absolute path ${.CURDIR}/test in main bmake.mk
- Replace automatic variable $< with explicit source filenames in test/bmake.mk
- Ensure proper directory navigation and source file compilation
- Fixes "undefined symbol: main" linker error on BSD systems
2026-01-31 23:08:39 +01:00
anth64 d2bf8fb67a feat(test): add comprehensive test infrastructure
- Add test target to both bmake.mk and gmake.mk Makefiles
- Add test-related artifacts to .gitignore (excluding DLLs/shared libs)
- Create test directory with cross-platform Makefiles (bmake.mk, gmake.mk)
- Implement cross-platform test program with signal handling (test.c)
- Add test module source for compilation (test_mod.c)
- Set up automated test environment with mods/ directory
- Support both POSIX and Windows platforms

The test infrastructure allows running integration tests via 'make test'
and demonstrates stk library functionality with dynamic module loading.
Generated DLLs/shared libraries are excluded from version control.
2026-01-31 22:46:07 +01:00
anth64 2f4b91c729 refactor(stk): change stk_init() return type to uint8_t
- Change function signature from int to uint8_t for clarity
- Makes return type intent explicit as status flag
2026-01-31 22:40:21 +01:00
anth64 22c7da4336 build: add -s flag to release builds
- Add symbol stripping (-s) to release builds
2026-01-31 21:55:40 +01:00
anth64 49ae5ed75e fix(compiler): resolve string truncation and use-after-free warnings
- In stk_module_load: Use memcpy with explicit length check instead of strncpy
- In platform_directory_init_scan: Same fix for directory scanning
- In stk_module_realloc_memory: Replace realloc with malloc+memcpy approach
  to avoid potential use-after-free issues and compiler warnings
- All changes maintain same functionality with improved safety
2026-01-31 21:08:38 +01:00
anth64 4bd1f00b5b refactor: transition return types to uint8_t and improve error reporting
- Update module load and memory functions to use fixed-width uint8_t
- Implement STK_MOD_REALLOC_FAILURE for granular memory error tracking
- Clean up logging prefixes in stk_poll for consistency
- Update error string helper to support new module error codes
2026-01-31 19:56:36 +01:00
anth64 69b4907ff2 fix: resolve Windows segfaults by using platform-specific path separators
On Windows, module IDs were failing to load because paths were being
constructed with hardcoded forward slashes. Oops...

- Added platform.h to centralize path separator macros.
- Updated build_path in stk.c to use STK_PATH_SEP_STR instead of "/".
- Cleaned up redundant platform logic in module.c.
2026-01-31 19:03:19 +01:00
anth64 3a06023265 fix: prevent segfault from rapid module writes
Add platform-specific protections against race conditions when
module files are written rapidly (compilation, copying, etc).

Linux (inotify):
- Deduplicate events within a poll cycle to prevent double-unload
- When duplicate RELOAD events occur, earlier events are skipped
  and only the final event is processed

BSD (kqueue):
- Add file readiness check with flock() before processing mtime changes
- Files that aren't ready have their mtime reset, skipping the reload

All Unix platforms:
- Use atomic .tmp + rename for module copying to prevent loading
  partially-written files

Writes that occur during an active reload or when files aren't
ready are skipped. A subsequent write is required to trigger
detection of those changes.

Fixes segfault caused by processing duplicate reload events
(Linux) or copying incomplete files mid-write (BSD).
2026-01-31 15:04:30 +01:00
anth64 8362889d73 refactor: rename index variables for clarity
-Rename 'idx' instances to use 'index'.
2026-01-31 15:04:30 +01:00
anth64 1e97b69fcd feat: add comprehensive error handling with typed error codes
Add strict error handling for stk initialization and platform operations.
stk_init() now fails fast on critical errors and returns typed error codes
that users can handle programmatically.

Changes:
- Add STK_INIT_* error codes for init failures (memory, tmpdir, watch)
- Add STK_PLATFORM_* error codes for platform operation results
- Check platform_mkdir() and fail if temp directory cannot be created
- Check platform_directory_watch_start() and fail if watch cannot initialize
- Add error_cleanup path in platform_directory_watch_start() to properly
  free resources on critical Windows failures.
- Replace all platform error checks with STK_PLATFORM_OPERATION_SUCCESS
- Log FATAL errors with when critical operations fail
- Add warning logs for non-critical failures

Critical failures now return specific error codes:
- STK_INIT_MEMORY_ERROR: Module memory allocation failed
- STK_INIT_TMPDIR_ERROR: Cannot create temp directory
- STK_INIT_WATCH_ERROR: Cannot start directory watching

Individual module load failures remain non-fatal and are handled logged.
2026-01-31 15:04:20 +01:00
anth64 336a096b82 feat: add error handling for module loading
Modules that fail to load no longer crash or leak memory:
- Check return values from stk_module_load_init() and stk_module_load()
- Log errors with specific failure reasons (library load, symbol lookup, init)
- Track successful_loads counter separately from file_count
- Only increment module_count for modules that actually loaded
- Trim allocated arrays when some modules fail to load
- Continue loading other modules when one fails

This prevents crashes from accessing uninitialized module slots and
avoids memory leaks from over-allocation.
2026-01-30 07:41:18 +01:00
anth64 8ea9ac084f fix: swap STK_MOD_RELOAD and STK_MOD_UNLOAD event handlers
Cases were reversed during if-else to switch refactoring, causing segfault
on module shutdown. Oops...
2026-01-30 07:24:34 +01:00
anth64 aba10d7dac fix: sync module types and replace WIP constants
* Types: Corrected stk.c to use stk_init_mod_func and stk_shutdown_mod_func instead of generic types.
* Errors: Replaced -3 placeholder with STK_MOD_INIT_FAILURE.
* Cleanup: Moved typedefs in module.c for consistency.
2026-01-29 23:11:42 +01:00
anth64 6567fceaec chore: formalize module loading error codes
* Define Constants: Added STK_MOD_LIBRARY_LOAD_ERROR and STK_MOD_SYMBOL_NOT_FOUND_ERROR to the public header.
* Update module.c: Swapped out the -1 and -2 placeholders for the new named constants in stk_module_load.
2026-01-29 22:53:11 +01:00
anth64 2fbf4ca24a feat(module): implement module initialization status check
* Add STK_MOD_INIT_SUCCESS and STK_MOD_INIT_FAILURE macros to stk.h.
* Update stk_module_load to validate module initialization before finalizing the load.
* Unload library if the init func fails, return error.
2026-01-29 22:40:25 +01:00
anth64 450f13fa62 refactor(module): separate init and shutdown function pointer types
* Define stk_init_mod_func as int (*)(void) and stk_shutdown_mod_func as void (*)(void).
* Update stk_inits and stk_shutdowns arrays to use the new specific function pointer types.
* Update the symbol lookup union in stk_module_load to support distinct init and shutdown signatures.
* Adjust memory allocation and reallocation logic in stk_module_init_memory and stk_module_realloc_memory to match new type sizes.
2026-01-29 22:29:59 +01:00
anth64 baa75e897f refactor(module): centralize path parsing and add OS-specific separator
- Define STK_PATH_SEP macro to handle Windows and Unix path separators.
- Refactor extract_module_id to use STK_PATH_SEP.
- Simplify stk_module_load by delegating module ID extraction to extract_module_id.
2026-01-29 22:16:48 +01:00
anth64 92e33ff265 refactor(stk): replace if-else chains with switch statements in stk_poll
- Update event processing to use switch statements.
- Clean up redundant goto jumps after memory reallocation.
2026-01-29 21:25:44 +01:00
anth64 64435fd8cd fix(platform): implement atomic hot-reload synchronization
* Resolve STATUS_INVALID_IMAGE_FORMAT on Windows by preventing race conditions during file I/O.
* is_file_ready: Uses GENERIC_WRITE to block if any process (compiler, copy, etc.) is writing to the source. Added GetFileSize check to ensure headers are flushed.
* platform_copy_file: Copies to .tmp and uses MoveFileExA for an atomic swap, hiding the file from the loader until completion.
* Refactor: Unified Win32 and POSIX logic with a single exit point.
2026-01-29 08:00:15 +01:00
anth64 fb80c3a6c5 feat: implement hot-reload polling with dynamic array management
Implement complete hot-reload logic in stk_poll() supporting reload,
load, and unload operations. Module arrays dynamically grow/shrink
with automatic defragmentation to maintain tight memory layout.

- Grow arrays when loads exceed unloads
- Fill holes left by unloads with new modules
- Defragment and trim arrays when unloads exceed loads
- Unload before realloc to minimize peak memory usage
- Replace sprintf with safe C89 build_path() helper
2026-01-28 00:48:01 +01:00
anth64 c65b2eff6d fix: handle realloc to zero capacity
* Call stk_module_free_memory() when new_capacity is 0.
2026-01-28 00:45:39 +01:00
anth64 91ec40d5b1 fix: nullify module slots after unload
* Set all module slot fields (handle, init, shutdown, id) to NULL/empty
after unloading to prevent use-after-free and enable proper hole
detection during array defragmentation.
2026-01-28 00:18:29 +01:00
anth64 2823c8ab59 feat: add dynamic module array reallocation
* Implement stk_module_realloc_memory() to grow or shrink module arrays during hot-reload operations.
* All-or-nothing strategy with fallback to original pointers on partial realloc failure.
2026-01-28 00:04:34 +01:00
anth64 9491b070d2 refactor(WIP): replace event stubs with module identification logic
Replace the placeholder TODO logs in the polling loop with logic to
resolve filesystem events into specific module indices.

- Centralizing State: Refactored is_module_loaded to is_mod_loaded to
  check against the global stk_module_ids array, removing the need to
  pass local buffers and preparing for unified lifetime management.
- Standardizing Identity: Updated extract_module_id to use a
  consistent output buffer.
- Categorized Event Processing: Implemented a two-pass approach in
  stk_poll to count event types (LOAD, UNLOAD, RELOAD) and allocate
  tracking arrays, replacing the previous stubbed switch statement.
- Mapping Events to Indices: The poll loop now resolves filenames
  back to their specific loaded indices via is_mod_loaded to
  identify exactly which mod_id and index require action.
- Improved Flow Control: Introduced a finish_stk_poll label to
  ensure consistent cleanup and return values when no events are
  detected or processing is complete.
2026-01-27 07:54:51 +01:00
anth64 c558032ea0 feat: prevent configuration changes after initialization
* Introduced stk_initialized flag.
* Updated all configuration setters (stk_set_mod_dir, stk_set_tmp_dir_name, stk_set_module_init_fn, and stk_set_module_shutdown_fn) to silently return if the library is already initialized.
* Ensures internal state consistency by locking paths and function entry points once stk_init has been called.
2026-01-25 17:02:44 +01:00
anth64 472cb3b163 feat: make module paths and entry points configurable
* Added functions to set mod dir, temp dir name, and module init/shutdown function names.
* Replaced hardcoded string literals with configurable static buffers in module.c.
* Improved string safety by replacing sprintf with strncpy/strncat.
* Updated stk_init local path buffers to handle maximum combined path lengths.
2026-01-25 16:52:52 +01:00
anth64 ac0125274d set default values for mod and tmp dir, removed arguments from stk init 2026-01-25 16:01:51 +01:00
anth64 f66a3bc00d fix: legacy printf compatibility and add polling logs
- Change %zu to %lu in stk_init to support older msvcrt.dll (Windows 7/XP)
- Update pluralization logic to correctly handle "0 mods" vs "1 mod"
- Add temporary stk_log calls to stk_poll for monitoring module events
2026-01-25 13:36:53 +01:00
anth64 d1e71faa6d fix(platform): harden linux watch check and clean up whitespace 2026-01-24 09:58:52 +01:00
anth64 f331970ae2 refactor: optimize file watching and fix cross-platform reliability issues
Refactor memory allocation patterns:
- Replace realloc-in-loop with count-then-allocate pattern across all platforms
- Eliminate arbitrary buffer sizes (e.g., malloc(8 * ...)) in favor of exact counts
- Reduce allocation overhead by pre-counting items before malloc

Fix Windows file watching:
- Replace unreliable FindFirstChangeNotification with directory handle approach
- Add is_file_ready() to prevent events while compiler is still writing files
- Preserve timestamps when file is locked to retry on next poll
- Fix do-while loop in platform_directory_init_scan (was skipping first file)

Fix Linux inotify event handling:
- Consolidate DELETE+CREATE pairs into single RELOAD event
- Prevents duplicate events when compiler uses temp-file-and-rename pattern

Fix BSD/macOS kqueue implementation:
- Remove realloc loops from update_watches() and watch initialization
- Pre-count files before allocating file descriptor arrays

All platforms now correctly handle:
- Compiler overwrites (temp file operations)
- Manual copy/move operations
- Explicit file deletions

Tested on Linux, Windows 10, and FreeBSD.
2026-01-23 23:39:24 +01:00
anth64 93657d71e3 gmake file should now use native os commands for file management now 2026-01-23 07:37:52 +01:00
anth64 d1972f7893 refactor(platform): Unify watch logic and fix manual snapshot leaks
Unlike inotify, Windows and BSD require manual state snapshots to detect
specific file changes. This refactor standardizes that manual handling
to ensure it is resource-safe and easy to follow.

- Fix memory leaks in platform_directory_watch_check where temporary
  buffers (new_snaps, file_list) were not reliably freed on 'phantom'
  triggers or error paths.
- Unify control flow using a 'goto' cleanup pattern to ensure
  deterministic resource deallocation.
- Synchronizes the manual snapshot comparison logic between Windows
  and BSD to ensure identical LOAD/RELOAD/UNLOAD event behavior.
- Simplifies the platform_directory_init_scan logic by removing
  redundant directory rewinds and nested checks.
- Add WIN32_LEAN_AND_MEAN to optimize Windows header inclusion.
- Align internal API signatures (is_module_loaded) for consistency.
2026-01-22 00:24:04 +01:00
anth64 b4fbfebc85 build: remove -ldl from Windows target 2026-01-20 22:05:53 +01:00
anth64 c863da08dd fix(platform): address C89 warnings and Windows pointer casting
- Include <stdint.h> so Windows does not complain about int types.
- Cast GetProcAddress return through intptr_t to satisfy -Wpedantic.
- Moved work_path for *nix only macros.
2026-01-20 21:53:33 +01:00