infix
A JIT-Powered FFI Library for C
Loading...
Searching...
No Matches
error.c
Go to the documentation of this file.
1
40#include <infix/infix.h>
41#include <stdarg.h>
42#include <stdio.h> // For snprintf
43#include <string.h>
44
45// Use a portable mechanism for thread-local storage (TLS).
46// The order of checks is critical for cross-platform compatibility.
47#if defined(__OpenBSD__)
48// OpenBSD has known issues with TLS cleanup in some linking scenarios (segfault on exit).
49// We disable TLS entirely on this platform to ensure stability, at the cost of thread-safety.
50#define INFIX_TLS
51#elif defined(_MSC_VER)
52// Microsoft Visual C++
53#define INFIX_TLS __declspec(thread)
54#elif defined(_WIN32) && defined(__clang__)
55// Clang on Windows: check if behaving like MSVC or GCC.
56// If using MSVC codegen/headers, use declspec.
57#define INFIX_TLS __declspec(thread)
58#elif defined(__GNUC__)
59// MinGW (GCC on Windows) and standard GCC/Clang on *nix.
60// MinGW prefers __thread or _Thread_local over __declspec(thread).
61#define INFIX_TLS __thread
62#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
63// Fallback to C11 standard
64#define INFIX_TLS _Thread_local
65#else
66// Fallback for compilers that do not support TLS. This is not thread-safe.
67#warning "Compiler does not support thread-local storage; error handling will not be thread-safe."
68#define INFIX_TLS
69#endif
70
71// A portable macro for safe string copying to prevent buffer overflows.
72#if defined(_MSC_VER)
73#define _INFIX_SAFE_STRNCPY(dest, src, count) strncpy_s(dest, sizeof(dest), src, count)
74#else
75#define _INFIX_SAFE_STRNCPY(dest, src, count) \
76 do { \
77 strncpy(dest, src, (count)); \
78 (dest)[(sizeof(dest)) - 1] = '\0'; \
79 } while (0)
80#endif
81
90
100
108 switch (code) {
110 return "Success";
112 return "An unknown error occurred";
114 return "A required pointer argument was NULL";
116 return "A type registry was required but not provided";
118 return "Out of memory";
120 return "Failed to allocate executable memory";
122 return "Failed to change memory protection flags";
124 return "Invalid alignment requested (must be power of two > 0)";
126 return "Unexpected token or character";
128 return "Unterminated aggregate (missing '}', '>', ']', or ')')'";
130 return "Invalid type keyword";
132 return "Function signature missing '->' or return type";
134 return "Integer overflow detected during layout calculation";
136 return "Type definition is too deeply nested";
138 return "Named type was declared with empty angle brackets";
140 return "The provided signature string was empty";
142 return "The current platform ABI is not supported";
144 return "A data type was too large to be handled by the ABI";
146 return "Named type not found in registry or is an undefined forward declaration";
148 return "Aggregate contains an illegal member type (e.g., a struct with a void member)";
150 return "The requested dynamic library could not be found";
152 return "The requested symbol was not found in the library";
154 return "Loading the dynamic library failed";
155 default:
156 return "An unknown or unspecified error occurred";
157 }
158}
159
173void _infix_set_error(infix_error_category_t category, infix_error_code_t code, size_t position) {
174 g_infix_last_error.category = category;
176 g_infix_last_error.position = position;
178 // Check if we can generate a rich parser error message.
179 if (category == INFIX_CATEGORY_PARSER && g_infix_last_signature_context != nullptr) {
180 // Generate a rich, GCC-style error message for parser failures.
181 const char * signature = g_infix_last_signature_context;
182 size_t sig_len = strlen(signature);
183 const size_t radius = 20; // Number of characters to show around the error position.
184 // Calculate the start and end of the snippet to display.
185 size_t start = (position > radius) ? (position - radius) : 0;
186 size_t end = (position + radius < sig_len) ? (position + radius) : sig_len;
187 // Add indicators if the snippet is truncated.
188 const char * start_indicator = (start > 0) ? "... " : "";
189 const char * end_indicator = (end < sig_len) ? " ..." : "";
190 size_t start_indicator_len = (start > 0) ? 4 : 0;
191 // Create the code snippet line.
192 char snippet[128];
193 snprintf(snippet,
194 sizeof(snippet),
195 "%s%.*s%s",
196 start_indicator,
197 (int)(end - start),
198 signature + start,
199 end_indicator);
200 // Create the pointer line with a caret '^' under the error.
201 char pointer[128];
202 size_t caret_pos = position - start + start_indicator_len;
203 snprintf(pointer, sizeof(pointer), "%*s^", (int)caret_pos, "");
204 // Build the final multi-line message piece by piece to avoid buffer overflows.
205 char * p = g_infix_last_error.message;
206 size_t remaining = sizeof(g_infix_last_error.message);
207 int written;
208 // Write the snippet and pointer lines.
209 written = snprintf(p, remaining, "\n\n %s\n %s", snippet, pointer);
210 if (written < 0 || (size_t)written >= remaining) {
211 // Fallback to a simple message on snprintf failure or buffer overflow.
212 const char * msg = _get_error_message_for_code(code);
214 return;
215 }
216 p += written;
217 remaining -= written;
218 // Append the standard error description.
219 snprintf(p, remaining, "\n\nError: %s", _get_error_message_for_code(code));
220 }
221 else {
222 // For non-parser errors, just copy the standard message.
223 const char * msg = _get_error_message_for_code(code);
225 }
226}
227
244 long system_code,
245 const char * msg) {
246 g_infix_last_error.category = category;
250 if (msg)
252 else {
253 const char * default_msg = _get_error_message_for_code(code);
255 }
256}
257
274
clock_t start
Definition 901_call_overhead.c:47
clock_t end
Definition 901_call_overhead.c:47
static const char * _get_error_message_for_code(infix_error_code_t code)
Definition error.c:107
void _infix_set_error(infix_error_category_t category, infix_error_code_t code, size_t position)
Sets the thread-local error state with detailed information.
Definition error.c:173
INFIX_TLS const char * g_infix_last_signature_context
A thread-local pointer to the full signature string being parsed.
Definition error.c:99
void _infix_set_system_error(infix_error_category_t category, infix_error_code_t code, long system_code, const char *msg)
Sets the thread-local error state for a system-level error.
Definition error.c:242
#define _INFIX_SAFE_STRNCPY(dest, src, count)
Definition error.c:75
void _infix_clear_error(void)
Clears the thread-local error state.
Definition error.c:266
static INFIX_TLS infix_error_details_t g_infix_last_error
The thread-local variable that stores the details of the last error.
Definition error.c:89
#define INFIX_TLS
Definition error.c:68
infix_error_code_t
Enumerates specific error codes.
Definition infix.h:1225
infix_error_details_t infix_get_last_error(void)
Retrieves detailed information about the last error that occurred on the current thread.
Definition error.c:279
infix_error_category_t
Enumerates the high-level categories of errors that can occur.
Definition infix.h:1215
@ INFIX_CODE_PROTECTION_FAILURE
Definition infix.h:1235
@ INFIX_CODE_SUCCESS
Definition infix.h:1227
@ INFIX_CODE_LIBRARY_NOT_FOUND
Definition infix.h:1256
@ INFIX_CODE_INVALID_MEMBER_TYPE
Definition infix.h:1252
@ INFIX_CODE_MISSING_REGISTRY
Definition infix.h:1230
@ INFIX_CODE_UNRESOLVED_NAMED_TYPE
Definition infix.h:1251
@ INFIX_CODE_INVALID_ALIGNMENT
Definition infix.h:1236
@ INFIX_CODE_INTEGER_OVERFLOW
Definition infix.h:1243
@ INFIX_CODE_TYPE_TOO_LARGE
Definition infix.h:1250
@ INFIX_CODE_EMPTY_SIGNATURE
Definition infix.h:1246
@ INFIX_CODE_UNEXPECTED_TOKEN
Definition infix.h:1239
@ INFIX_CODE_MISSING_RETURN_TYPE
Definition infix.h:1242
@ INFIX_CODE_EMPTY_MEMBER_NAME
Definition infix.h:1245
@ INFIX_CODE_EXECUTABLE_MEMORY_FAILURE
Definition infix.h:1234
@ INFIX_CODE_UNKNOWN
Definition infix.h:1228
@ INFIX_CODE_SYMBOL_NOT_FOUND
Definition infix.h:1257
@ INFIX_CODE_RECURSION_DEPTH_EXCEEDED
Definition infix.h:1244
@ INFIX_CODE_UNSUPPORTED_ABI
Definition infix.h:1249
@ INFIX_CODE_UNTERMINATED_AGGREGATE
Definition infix.h:1240
@ INFIX_CODE_LIBRARY_LOAD_FAILED
Definition infix.h:1258
@ INFIX_CODE_NULL_POINTER
Definition infix.h:1229
@ INFIX_CODE_INVALID_KEYWORD
Definition infix.h:1241
@ INFIX_CODE_OUT_OF_MEMORY
Definition infix.h:1233
@ INFIX_CATEGORY_PARSER
Definition infix.h:1219
@ INFIX_CATEGORY_NONE
Definition infix.h:1216
size_t position
Definition infix.h:1267
infix_error_category_t category
Definition infix.h:1265
char message[256]
Definition infix.h:1269
long system_error_code
Definition infix.h:1268
infix_error_code_t code
Definition infix.h:1266
The public interface for the infix FFI library.
Internal data structures, function prototypes, and constants.
Provides detailed, thread-local information about the last error that occurred.
Definition infix.h:1264