|
4 | 4 | * macOS, Linux, and Windows. Platform-specific code behind #ifdef guards. |
5 | 5 | */ |
6 | 6 | #include "platform.h" |
7 | | -#include "compat.h" |
8 | 7 |
|
9 | 8 | #include "foundation/constants.h" |
10 | | -#include <stdint.h> // uint64_t, int64_t |
| 9 | +#include <fcntl.h> |
| 10 | +#include <stdint.h> |
| 11 | +#include <stdio.h> |
| 12 | +#include <string.h> |
11 | 13 |
|
12 | 14 | #ifdef _WIN32 |
13 | 15 |
|
@@ -113,7 +115,6 @@ char *cbm_normalize_path_sep(char *path) { |
113 | 115 |
|
114 | 116 | /* ── POSIX implementation ─────────────────────────────────────── */ |
115 | 117 |
|
116 | | -#include <fcntl.h> // open, O_RDONLY |
117 | 118 | #include <sys/mman.h> |
118 | 119 | #include <sys/stat.h> |
119 | 120 | #include <unistd.h> |
@@ -178,7 +179,7 @@ uint64_t cbm_now_ns(void) { |
178 | 179 | #else |
179 | 180 | uint64_t cbm_now_ns(void) { |
180 | 181 | struct timespec ts; |
181 | | - cbm_clock_gettime(CLOCK_MONOTONIC, &ts); |
| 182 | + clock_gettime(CLOCK_MONOTONIC, &ts); |
182 | 183 | return (uint64_t)ts.tv_sec * 1000000000ULL + (uint64_t)ts.tv_nsec; |
183 | 184 | } |
184 | 185 | #endif |
@@ -243,41 +244,54 @@ char *cbm_normalize_path_sep(char *path) { |
243 | 244 |
|
244 | 245 | /* ── Environment variables ────────────────────────────────────── */ |
245 | 246 |
|
| 247 | +/* Thread-safe getenv: iterates environ directly instead of calling getenv(). |
| 248 | + * getenv() is flagged by concurrency-mt-unsafe because the returned pointer |
| 249 | + * can be invalidated by setenv/putenv in another thread. We copy to a |
| 250 | + * caller-owned buffer immediately. */ |
| 251 | +#ifdef _WIN32 |
| 252 | +extern char **_environ; |
| 253 | +#define CBM_ENVIRON _environ |
| 254 | +#elif defined(__APPLE__) |
| 255 | +#include <crt_externs.h> |
| 256 | +#define CBM_ENVIRON (*_NSGetEnviron()) |
| 257 | +#else |
| 258 | +extern char **environ; |
| 259 | +#define CBM_ENVIRON environ |
| 260 | +#endif |
| 261 | + |
246 | 262 | const char *cbm_safe_getenv(const char *name, char *buf, size_t buf_sz, const char *fallback) { |
247 | | - const char *val = getenv(name); |
248 | | - if (!val) { |
249 | | - if (fallback) { |
250 | | - snprintf(buf, buf_sz, "%s", fallback); |
251 | | - return buf; |
| 263 | + char **env = CBM_ENVIRON; |
| 264 | + if (env) { |
| 265 | + size_t nlen = strlen(name); |
| 266 | + for (; *env; env++) { |
| 267 | + if (strncmp(*env, name, nlen) == 0 && (*env)[nlen] == '=') { |
| 268 | + snprintf(buf, buf_sz, "%s", *env + nlen + SKIP_ONE); |
| 269 | + return buf; |
| 270 | + } |
252 | 271 | } |
253 | | - buf[0] = '\0'; |
254 | | - return NULL; |
255 | 272 | } |
256 | | - snprintf(buf, buf_sz, "%s", val); |
257 | | - return buf; |
| 273 | + if (fallback) { |
| 274 | + snprintf(buf, buf_sz, "%s", fallback); |
| 275 | + return buf; |
| 276 | + } |
| 277 | + buf[0] = '\0'; |
| 278 | + return NULL; |
258 | 279 | } |
259 | 280 |
|
260 | 281 | /* ── Home directory (cross-platform) ──────────────────────────── */ |
261 | 282 |
|
262 | 283 | const char *cbm_get_home_dir(void) { |
263 | 284 | static char buf[CBM_SZ_1K]; |
264 | | - const char *raw; |
265 | 285 | char tmp[CBM_SZ_256] = ""; |
266 | 286 |
|
267 | | - raw = getenv("HOME"); |
268 | | - if (raw) { |
269 | | - snprintf(tmp, sizeof(tmp), "%s", raw); |
270 | | - } |
| 287 | + cbm_safe_getenv("HOME", tmp, sizeof(tmp), NULL); |
271 | 288 | if (tmp[0]) { |
272 | 289 | snprintf(buf, sizeof(buf), "%s", tmp); |
273 | 290 | cbm_normalize_path_sep(buf); |
274 | 291 | return buf; |
275 | 292 | } |
276 | 293 |
|
277 | | - raw = getenv("USERPROFILE"); |
278 | | - if (raw) { |
279 | | - snprintf(tmp, sizeof(tmp), "%s", raw); |
280 | | - } |
| 294 | + cbm_safe_getenv("USERPROFILE", tmp, sizeof(tmp), NULL); |
281 | 295 | if (tmp[0]) { |
282 | 296 | snprintf(buf, sizeof(buf), "%s", tmp); |
283 | 297 | cbm_normalize_path_sep(buf); |
|
0 commit comments