https://github.com/akkartik/mu/blob/main/313index-bounds-check.subx
 1 # Helper to check an array's bounds, and to abort if they're violated.
 2 # Really only intended to be called from code generated by mu.subx.
 3 
 4 == code
 5 
 6 __check-mu-array-bounds:  # index: int, elem-size: int, arr-size: int, function-name: (addr array byte), array-name: (addr array byte)
 7     # . prologue
 8     55/push-ebp
 9     89/<- %ebp 4/r32/esp
10     # . save registers
11     50/push-eax
12     51/push-ecx
13     52/push-edx
14     # . not bothering saving ebx; it's only clobbered if we're going to abort
15     # ecx = arr-size
16     8b/-> *(ebp+0x10) 1/r32/ecx
17     # var overflow/edx: int = 0
18     ba/copy-to-edx 0/imm32
19     # var offset/eax: int = index * elem-size
20     8b/-> *(ebp+8) 0/r32/eax
21     f7 4/subop/multiply-eax-with *(ebp+0xc)
22     # check for overflow
23     81 7/subop/compare %edx 0/imm32
24     0f 85/jump-if-!= __check-mu-array-bounds:overflow/disp32
25     # check bounds
26     39/compare %eax 1/r32/ecx
27     0f 82/jump-if-unsigned< $__check-mu-array-bounds:end/disp32  # negative index should always abort
28     # abort if necessary
29     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "fn " 3 0)  # 3=cyan
30     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+0x14) 3 0)  # 3=cyan
31     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 ": offset " 3 0)  # 3=cyan
32     (draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0 %eax 3 0)  # 3=cyan
33     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 " is too large for array '" 3 0)  # 3=cyan
34     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+0x18) 3 0)  # 3=cyan
35     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "'" 3 0)  # 3=cyan
36     (abort "")
37     # never gets here
38 $__check-mu-array-bounds:end:
39     # . restore registers
40     5a/pop-to-edx
41     59/pop-to-ecx
42     58/pop-to-eax
43     # . epilogue
44     89/<- %esp 5/r32/ebp
45     5d/pop-to-ebp
46     c3/return
47 
48 __check-mu-array-bounds:overflow:
49     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "fn " 3 0)  # 3=cyan
50     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+0x14) 3 0)  # 3=cyan
51     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 ": offset to array '" 3 0)  # 3=cyan
52     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+0x18) 3 0)  # 3=cyan
53     (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "' overflowed 32 bits" 3 0)  # 3=cyan
54     (abort "")
55     # never gets here
56 
57 __mu-abort-null-index-base-address:
58     (abort "null address in 'index'")
59 
60 __mu-abort-null-get-base-address:
61     (abort "null address in 'get'")