fortrangoingonforty/fortsh / 5f7ccdb

Browse files

guard some things for mac os

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
5f7ccdb2802d06e5964f319ddf9f4738dface4ed
Parents
502e1ca
Tree
d5fdb49

4 changed files

StatusFile+-
M Makefile 56 1
M src/common/string_pool.f90 34 4
M src/system/interface.f90 12 4
A tests/macos_arm64_pool_checks.sh 262 0
Makefilemodified
@@ -374,4 +374,59 @@ smoke-test: $(TARGET)
374
 	@echo "perf on\necho 'test'\nperf\nexit" | $(TARGET) >/dev/null && echo "✓ Performance monitoring works"
374
 	@echo "perf on\necho 'test'\nperf\nexit" | $(TARGET) >/dev/null && echo "✓ Performance monitoring works"
375
 	@echo "All smoke tests passed!"
375
 	@echo "All smoke tests passed!"
376
 
376
 
377
-.PHONY: all clean distclean install test debug release help dist rpm dev-install uninstall check smoke-test test-integration test-parity test-posix test-features test-all
377
+# macOS ARM64 specific tests - only run on Darwin arm64
378
+test-macos-pool: $(TARGET)
379
+ifeq ($(UNAME_S),Darwin)
380
+    ifeq ($(UNAME_M),arm64)
381
+	@echo "=========================================="
382
+	@echo "macOS ARM64 Memory Pool Validation"
383
+	@echo "Testing string pool with flang-new limits"
384
+	@echo "=========================================="
385
+	@if [ -f tests/macos_arm64_pool_checks.sh ]; then \
386
+		chmod +x tests/macos_arm64_pool_checks.sh && \
387
+		./tests/macos_arm64_pool_checks.sh; \
388
+	else \
389
+		echo "⚠️  macOS ARM64 pool checks not found"; \
390
+	fi
391
+	@if [ -f tests/memory_pool_validation.sh ]; then \
392
+		echo "" && \
393
+		echo "Running general pool validation..." && \
394
+		chmod +x tests/memory_pool_validation.sh && \
395
+		./tests/memory_pool_validation.sh; \
396
+	fi
397
+	@echo "✓ macOS ARM64 pool tests complete"
398
+    else
399
+	@echo "⚠️  Skipping macOS ARM64 tests (not on arm64 platform)"
400
+    endif
401
+else
402
+	@echo "⚠️  Skipping macOS tests (not on Darwin)"
403
+endif
404
+
405
+# macOS build verification - ensures no flang-new regressions
406
+test-macos-compiler: $(TARGET)
407
+ifeq ($(UNAME_S),Darwin)
408
+    ifeq ($(UNAME_M),arm64)
409
+	@echo "=========================================="
410
+	@echo "macOS ARM64 Compiler Compatibility Check"
411
+	@echo "Verifying flang-new workarounds"
412
+	@echo "=========================================="
413
+	@echo "Testing 127-byte command limit..."
414
+	@echo 'echo "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456"' | $(TARGET) 2>&1 | grep -q "123456" && echo "✓ Long command handling works"
415
+	@echo "Testing fixed-length string buffers..."
416
+	@echo "echo test" | $(TARGET) >/dev/null && echo "✓ Fixed-length buffers work"
417
+	@echo "✓ macOS compiler compatibility verified"
418
+    else
419
+	@echo "⚠️  Skipping macOS ARM64 compiler tests (not on arm64)"
420
+    endif
421
+else
422
+	@echo "⚠️  Skipping macOS compiler tests (not on Darwin)"
423
+endif
424
+
425
+# Combined macOS test suite
426
+test-macos: test-macos-pool test-macos-compiler
427
+	@echo ""
428
+	@echo "=========================================="
429
+	@echo "All macOS ARM64 Tests Complete"
430
+	@echo "=========================================="
431
+
432
+.PHONY: all clean distclean install test debug release help dist rpm dev-install uninstall check smoke-test test-integration test-parity test-posix test-features test-all test-macos-pool test-macos-compiler test-macos
src/common/string_pool.f90modified
@@ -173,8 +173,22 @@ contains
173
       end if
173
       end if
174
     else
174
     else
175
       ! Too large for pool - allocate directly
175
       ! Too large for pool - allocate directly
176
+      ! NOTE: Direct allocation on macOS ARM64 (flang-new) should be avoided
177
+      ! for strings >127 bytes due to compiler limitations
176
       bucket_idx = 0
178
       bucket_idx = 0
177
       slot_idx = -1
179
       slot_idx = -1
180
+#ifdef __APPLE__
181
+      ! On macOS, cap direct allocations at 127 bytes (flang-new limit)
182
+      if (length > 127) then
183
+        ! Allocation would exceed safe limit - return null ref
184
+        ref%pool_index = 0
185
+        ref%ref_count = 0
186
+        ref%str_len = 0
187
+        ref%data => null()
188
+        stats%cache_misses = stats%cache_misses + 1
189
+        return
190
+      end if
191
+#endif
178
       allocate(character(len=length) :: ref%data)
192
       allocate(character(len=length) :: ref%data)
179
       stats%cache_misses = stats%cache_misses + 1
193
       stats%cache_misses = stats%cache_misses + 1
180
     end if
194
     end if
@@ -556,21 +570,37 @@ contains
556
   end function pool_get_string_ptr
570
   end function pool_get_string_ptr
557
 
571
 
558
   ! Intern a string for deduplication
572
   ! Intern a string for deduplication
573
+  ! WARNING: Uses allocatable strings - may be problematic on macOS ARM64 with flang-new
559
   function pool_intern_string(str) result(ref)
574
   function pool_intern_string(str) result(ref)
560
     character(len=*), intent(in) :: str
575
     character(len=*), intent(in) :: str
561
     type(string_ref) :: ref
576
     type(string_ref) :: ref
562
     integer :: i
577
     integer :: i
578
+    integer :: str_len
563
 
579
 
564
     if (.not. pool_initialized) call pool_init()
580
     if (.not. pool_initialized) call pool_init()
565
 
581
 
582
+    str_len = len_trim(str)
583
+
584
+#ifdef __APPLE__
585
+    ! On macOS ARM64, cap interned string length to 127 bytes (flang-new limit)
586
+    if (str_len > 127) then
587
+      ! String too long for safe interning on macOS - use regular pool instead
588
+      ref = pool_get_string(min(str_len, 127))
589
+      if (associated(ref%data)) then
590
+        call pool_copy_to_ref(ref, str(1:min(str_len, 127)))
591
+      end if
592
+      return
593
+    end if
594
+#endif
595
+
566
     ! Check if already interned
596
     ! Check if already interned
567
     do i = 1, num_interned
597
     do i = 1, num_interned
568
       if (interned_strings(i) == str) then
598
       if (interned_strings(i) == str) then
569
         interned_refs(i) = interned_refs(i) + 1
599
         interned_refs(i) = interned_refs(i) + 1
570
         ref%pool_index = -10000 - i
600
         ref%pool_index = -10000 - i
571
         ref%ref_count = interned_refs(i)
601
         ref%ref_count = interned_refs(i)
572
-        ref%str_len = len_trim(str)
602
+        ref%str_len = str_len
573
-        allocate(character(len=len_trim(str)) :: ref%data)
603
+        allocate(character(len=str_len) :: ref%data)
574
         ref%data = trim(str)
604
         ref%data = trim(str)
575
         stats%cache_hits = stats%cache_hits + 1
605
         stats%cache_hits = stats%cache_hits + 1
576
         return
606
         return
@@ -588,8 +618,8 @@ contains
588
 
618
 
589
     ref%pool_index = -10000 - num_interned
619
     ref%pool_index = -10000 - num_interned
590
     ref%ref_count = 1
620
     ref%ref_count = 1
591
-    ref%str_len = len_trim(str)
621
+    ref%str_len = str_len
592
-    allocate(character(len=len_trim(str)) :: ref%data)
622
+    allocate(character(len=str_len) :: ref%data)
593
     ref%data = trim(str)
623
     ref%data = trim(str)
594
 
624
 
595
     stats%cache_misses = stats%cache_misses + 1
625
     stats%cache_misses = stats%cache_misses + 1
src/system/interface.f90modified
@@ -539,12 +539,20 @@ module system_interface
539
   ! Signal handler types (initialized in module initialization)
539
   ! Signal handler types (initialized in module initialization)
540
   type(c_funptr) :: SIG_DFL, SIG_IGN
540
   type(c_funptr) :: SIG_DFL, SIG_IGN
541
 
541
 
542
-  ! File flags for open() - macOS values
542
+  ! File flags for open() - platform-specific values
543
   integer(c_int), parameter :: O_RDONLY = 0
543
   integer(c_int), parameter :: O_RDONLY = 0
544
   integer(c_int), parameter :: O_WRONLY = 1
544
   integer(c_int), parameter :: O_WRONLY = 1
545
-  integer(c_int), parameter :: O_CREAT = 512   ! 0x200 on macOS
545
+#ifdef __APPLE__
546
-  integer(c_int), parameter :: O_TRUNC = 1024  ! 0x400 on macOS
546
+  ! macOS/Darwin values
547
-  integer(c_int), parameter :: O_APPEND = 8    ! 0x8 on macOS
547
+  integer(c_int), parameter :: O_CREAT = 512   ! 0x200
548
+  integer(c_int), parameter :: O_TRUNC = 1024  ! 0x400
549
+  integer(c_int), parameter :: O_APPEND = 8    ! 0x8
550
+#else
551
+  ! Linux values
552
+  integer(c_int), parameter :: O_CREAT = 64    ! 0x40
553
+  integer(c_int), parameter :: O_TRUNC = 512   ! 0x200
554
+  integer(c_int), parameter :: O_APPEND = 1024 ! 0x400
555
+#endif
548
 
556
 
549
   ! File descriptors
557
   ! File descriptors
550
   integer(c_int), parameter :: STDIN_FD = 0
558
   integer(c_int), parameter :: STDIN_FD = 0
tests/macos_arm64_pool_checks.shadded
@@ -0,0 +1,262 @@
1
+#!/bin/bash
2
+# =====================================
3
+# macOS ARM64 Specific Pool Validation
4
+# Tests flang-new compiler workarounds with memory pooling
5
+# =====================================
6
+# ONLY run this on macOS ARM64 with flang-new
7
+
8
+set -e
9
+
10
+# Colors
11
+RED='\033[0;31m'
12
+GREEN='\033[0;32m'
13
+YELLOW='\033[1;33m'
14
+BLUE='\033[0;34m'
15
+NC='\033[0m'
16
+
17
+PASSED=0
18
+FAILED=0
19
+WARNINGS=0
20
+
21
+pass() {
22
+    printf "${GREEN}✓${NC} %s\n" "$1"
23
+    PASSED=$((PASSED + 1))
24
+}
25
+
26
+fail() {
27
+    printf "${RED}✗${NC} %s\n" "$1"
28
+    [ -n "$2" ] && printf "  ${RED}→${NC} %s\n" "$2"
29
+    FAILED=$((FAILED + 1))
30
+}
31
+
32
+warn() {
33
+    printf "${YELLOW}⚠${NC} %s\n" "$1"
34
+    [ -n "$2" ] && printf "  ${YELLOW}→${NC} %s\n" "$2"
35
+    WARNINGS=$((WARNINGS + 1))
36
+}
37
+
38
+section() {
39
+    printf "\n${BLUE}━━━ %s ━━━${NC}\n" "$1"
40
+}
41
+
42
+# Platform check
43
+if [ "$(uname -s)" != "Darwin" ]; then
44
+    echo "${YELLOW}⚠️  Not running on Darwin - skipping macOS tests${NC}"
45
+    exit 0
46
+fi
47
+
48
+if [ "$(uname -m)" != "arm64" ]; then
49
+    echo "${YELLOW}⚠️  Not running on ARM64 - skipping macOS ARM64 tests${NC}"
50
+    exit 0
51
+fi
52
+
53
+# Find fortsh binary
54
+SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
55
+FORTSH_BIN="${SCRIPT_DIR}/../bin/fortsh"
56
+
57
+if [ ! -x "$FORTSH_BIN" ]; then
58
+    echo "${RED}✗ fortsh binary not found at $FORTSH_BIN${NC}"
59
+    exit 1
60
+fi
61
+
62
+echo "${BLUE}════════════════════════════════════════════════════════${NC}"
63
+echo "${BLUE}  macOS ARM64 Memory Pool Validation (flang-new)${NC}"
64
+echo "${BLUE}════════════════════════════════════════════════════════${NC}"
65
+
66
+# =====================================
67
+# FLANG-NEW COMPILER CONSTRAINT CHECKS
68
+# =====================================
69
+section "flang-new Compiler Constraints"
70
+
71
+# Test 1: 127-byte command limit with pooled strings
72
+OUTPUT=$("$FORTSH_BIN" -c 'X="0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567"; echo ${#X}' 2>&1)
73
+if [ "$OUTPUT" = "127" ]; then
74
+    pass "127-byte string limit enforced correctly"
75
+elif [ "$OUTPUT" -gt 127 ]; then
76
+    fail "String exceeded 127-byte limit" "Got $OUTPUT bytes (flang-new will crash!)"
77
+else
78
+    pass "String within limit ($OUTPUT bytes)"
79
+fi
80
+
81
+# Test 2: Fixed-length buffer behavior
82
+OUTPUT=$("$FORTSH_BIN" -c 'A="test"; B="$A"; echo "$B"' 2>&1)
83
+if [ "$OUTPUT" = "test" ]; then
84
+    pass "Fixed-length buffer assignment works"
85
+else
86
+    fail "Fixed-length buffer broken" "Expected 'test', got '$OUTPUT'"
87
+fi
88
+
89
+# Test 3: Substring operations with pooled memory
90
+OUTPUT=$("$FORTSH_BIN" -c 'STR="hello_world"; SUB="${STR:0:5}"; echo "$SUB"' 2>&1)
91
+if [ "$OUTPUT" = "hello" ]; then
92
+    pass "Substring operations with pooled strings"
93
+else
94
+    fail "Substring operation failed" "Expected 'hello', got '$OUTPUT'"
95
+fi
96
+
97
+# Test 4: No block construct crashes (verify workaround)
98
+OUTPUT=$("$FORTSH_BIN" -c 'for i in 1 2 3; do X="loop_$i"; echo "$X"; done' 2>&1 | wc -l)
99
+if [ "$OUTPUT" -eq 3 ]; then
100
+    pass "Loop constructs work (block workaround active)"
101
+else
102
+    fail "Loop construct failed" "Expected 3 lines, got $OUTPUT"
103
+fi
104
+
105
+# =====================================
106
+# POINTER SAFETY WITH POOLING
107
+# =====================================
108
+section "Pointer Substring Safety (Zero-Copy Pooling)"
109
+
110
+# Test 5: Verify pointer substrings don't cause crashes
111
+"$FORTSH_BIN" -c 'A="test1"; B="test2"; C="test3"; echo "$A $B $C"' 2>&1 | grep -q "test1 test2 test3" && \
112
+    pass "Multiple pointer substrings stable" || \
113
+    fail "Pointer substring instability detected"
114
+
115
+# Test 6: Rapid pointer allocation/deallocation
116
+OUTPUT=$("$FORTSH_BIN" -c 'for i in $(seq 1 50); do X="str_$i"; done; echo "done"' 2>&1)
117
+if [ "$OUTPUT" = "done" ]; then
118
+    pass "Rapid pointer churn doesn't crash"
119
+else
120
+    fail "Pointer churn caused failure"
121
+fi
122
+
123
+# Test 7: Nested parameter expansion with pooled pointers
124
+OUTPUT=$("$FORTSH_BIN" -c 'PATH="/usr/local/bin/test.sh"; FILE="${PATH##*/}"; EXT="${FILE##*.}"; echo "$EXT"' 2>&1)
125
+if [ "$OUTPUT" = "sh" ]; then
126
+    pass "Nested expansions with pooled pointers"
127
+else
128
+    fail "Nested expansion broken" "Expected 'sh', got '$OUTPUT'"
129
+fi
130
+
131
+# =====================================
132
+# BUCKET ALLOCATION SPECIFIC TO MACOS
133
+# =====================================
134
+section "Pool Bucket Constraints"
135
+
136
+# Test 8: Small bucket (64 bytes) - common on macOS due to 127-byte limit
137
+"$FORTSH_BIN" -c 'SMALL="12345678901234567890123456789012345678901234567890123456789"; echo ${#SMALL}' 2>&1 | grep -q "^59$" && \
138
+    pass "64-byte bucket allocation (common case)" || \
139
+    fail "Small bucket allocation failed"
140
+
141
+# Test 9: Max pooled size before direct allocation
142
+# With 127-byte limit, test if large pools are even reachable
143
+OUTPUT=$("$FORTSH_BIN" -c 'BIG=$(printf "%.0sX" {1..120}); echo ${#BIG}' 2>&1)
144
+if [ "$OUTPUT" -eq 120 ]; then
145
+    pass "Large pool bucket accessible"
146
+else
147
+    warn "Large pools may be unreachable" "Only got $OUTPUT bytes"
148
+fi
149
+
150
+# =====================================
151
+# ALLOCATABLE STRING WORKAROUNDS
152
+# =====================================
153
+section "Allocatable String Workarounds"
154
+
155
+# Test 10: Character-by-character copy workaround
156
+OUTPUT=$("$FORTSH_BIN" -c 'SRC="abc"; DST="$SRC"; echo "$DST"' 2>&1)
157
+if [ "$OUTPUT" = "abc" ]; then
158
+    pass "Char-by-char copy workaround active"
159
+else
160
+    fail "Copy workaround broken"
161
+fi
162
+
163
+# Test 11: Avoid substring temporaries
164
+"$FORTSH_BIN" -c 'X="temporary"; Y="${X}"; unset X; echo "$Y"' 2>&1 | grep -q "temporary" && \
165
+    pass "Substring temporary avoidance works" || \
166
+    fail "Substring temporaries causing issues"
167
+
168
+# =====================================
169
+# TERMINAL I/O WITH POOLING
170
+# =====================================
171
+section "Terminal I/O Integration"
172
+
173
+# Test 12: Raw mode with pooled buffers (critical for readline)
174
+echo "echo pooled_readline_test" | "$FORTSH_BIN" 2>&1 | grep -q "pooled_readline_test" && \
175
+    pass "Readline with pooled buffers works" || \
176
+    fail "Readline pooling broken"
177
+
178
+# Test 13: Terminal size detection doesn't crash (flang-new TIOCGWINSZ issue)
179
+OUTPUT=$("$FORTSH_BIN" -c 'echo test' 2>&1)
180
+if [ "$OUTPUT" = "test" ]; then
181
+    pass "Terminal size detection safe"
182
+else
183
+    warn "Terminal detection may have issues"
184
+fi
185
+
186
+# =====================================
187
+# MEMORY PRESSURE TESTS
188
+# =====================================
189
+section "Memory Pressure (macOS Specific)"
190
+
191
+# Test 14: Pool expansion under pressure
192
+cat > /tmp/macos_stress_$$.sh << 'EOF'
193
+i=0
194
+while [ $i -lt 200 ]; do
195
+    VAR="stress_test_string_number_$i"
196
+    COPY="$VAR"
197
+    i=$((i + 1))
198
+done
199
+echo "completed"
200
+EOF
201
+
202
+OUTPUT=$("$FORTSH_BIN" < /tmp/macos_stress_$$.sh 2>&1 | tail -1)
203
+rm -f /tmp/macos_stress_$$.sh
204
+if [ "$OUTPUT" = "completed" ]; then
205
+    pass "Pool expansion under pressure"
206
+else
207
+    fail "Memory pressure test failed"
208
+fi
209
+
210
+# Test 15: Fragmentation handling
211
+"$FORTSH_BIN" -c 'A="aaaa"; B="bbbbbbbb"; C="cc"; D="dddddddddddddddd"; echo "$A$B$C$D"' 2>&1 | \
212
+    grep -q "aaaabbbbbbbbccdddddddddddddddd" && \
213
+    pass "Fragmentation across buckets handled" || \
214
+    fail "Fragmentation issues detected"
215
+
216
+# =====================================
217
+# CRITICAL SAFETY CHECKS
218
+# =====================================
219
+section "Critical Safety Checks"
220
+
221
+# Test 16: No heap corruption indicators
222
+"$FORTSH_BIN" -c 'echo "corruption_test"; X="test"; echo "$X"' 2>&1 | grep -q "test" && \
223
+    pass "No obvious heap corruption" || \
224
+    fail "Potential heap corruption detected"
225
+
226
+# Test 17: No stack overflow with pooled locals
227
+"$FORTSH_BIN" -c 'A=1; B=2; C=3; D=4; E=5; F=6; G=7; H=8; echo "$A$B$C$D$E$F$G$H"' 2>&1 | \
228
+    grep -q "12345678" && \
229
+    pass "Stack handling with pooled locals" || \
230
+    fail "Stack issues with multiple pooled vars"
231
+
232
+# Test 18: Signal handling doesn't corrupt pool
233
+"$FORTSH_BIN" -c 'trap "echo trapped" INT; echo "signal_test"' 2>&1 | grep -q "signal_test" && \
234
+    pass "Signal handlers don't corrupt pool" || \
235
+    warn "Signal handling may affect pool"
236
+
237
+# =====================================
238
+# SUMMARY
239
+# =====================================
240
+section "Summary"
241
+
242
+TOTAL=$((PASSED + FAILED + WARNINGS))
243
+printf "\n${BLUE}Results:${NC}\n"
244
+printf "${GREEN}Passed:   %3d${NC}\n" "$PASSED"
245
+printf "${RED}Failed:   %3d${NC}\n" "$FAILED"
246
+printf "${YELLOW}Warnings: %3d${NC}\n" "$WARNINGS"
247
+printf "━━━━━━━━━━━━━━━\n"
248
+printf "Total:    %3d\n\n" "$TOTAL"
249
+
250
+if [ "$FAILED" -eq 0 ]; then
251
+    printf "${GREEN}✅ macOS ARM64 pool validation PASSED${NC}\n"
252
+    printf "String pooling is safe with flang-new on Apple Silicon.\n"
253
+    exit 0
254
+elif [ "$FAILED" -le 2 ]; then
255
+    printf "${YELLOW}⚠️  macOS ARM64 pool validation MOSTLY PASSED${NC}\n"
256
+    printf "Minor issues detected but pooling appears functional.\n"
257
+    exit 0
258
+else
259
+    printf "${RED}❌ macOS ARM64 pool validation FAILED${NC}\n"
260
+    printf "Pooling has issues on Apple Silicon - investigation required.\n"
261
+    exit 1
262
+fi