align ALLOCATE'd memory to 8 bytes with a magic number in the extra cell

This commit is contained in:
Jesse D. McDonald 2020-10-25 01:49:42 -05:00
parent 0d107e17d2
commit 24682b970b
3 changed files with 113 additions and 61 deletions

View File

@ -85,6 +85,7 @@ LATEST ' BOOTSTRAP-GET-ORDER DEFER!
-5 CONSTANT EXCP-RETURN-OVERFLOW -5 CONSTANT EXCP-RETURN-OVERFLOW
-6 CONSTANT EXCP-RETURN-UNDERFLOW -6 CONSTANT EXCP-RETURN-UNDERFLOW
-8 CONSTANT EXCP-DICTIONARY-OVERFLOW -8 CONSTANT EXCP-DICTIONARY-OVERFLOW
-9 CONSTANT EXCP-INVALID-ADDRESS
-13 CONSTANT EXCP-UNDEFINED-WORD -13 CONSTANT EXCP-UNDEFINED-WORD
-24 CONSTANT EXCP-BAD-NUMERIC-ARGUMENT -24 CONSTANT EXCP-BAD-NUMERIC-ARGUMENT
-37 CONSTANT EXCP-FILE-IO -37 CONSTANT EXCP-FILE-IO
@ -1008,6 +1009,9 @@ DEFER QUIT ( -- <noreturn> )
EXCP-DICTIONARY-OVERFLOW OF EXCP-DICTIONARY-OVERFLOW OF
"Dictionary overflow\n" TYPE-ERR "Dictionary overflow\n" TYPE-ERR
ENDOF ENDOF
EXCP-INVALID-ADDRESS OF
"Invalid memory address\n" TYPE-ERR
ENDOF
EXCP-UNDEFINED-WORD OF EXCP-UNDEFINED-WORD OF
"Undefined word: " TYPE-ERR THROWN-STRING 2@ TYPE-ERR "\n" TYPE-ERR "Undefined word: " TYPE-ERR THROWN-STRING 2@ TYPE-ERR "\n" TYPE-ERR
ENDOF ENDOF
@ -1191,10 +1195,31 @@ DEFER REFILL
: 2ARRAY ( n "<spaces>name" -- ) : 2ARRAY ( n "<spaces>name" -- )
CREATE 2* CELLS ALLOT DOES> SWAP [ 2 CELLS ] LITERAL * + ; CREATE 2* CELLS ALLOT DOES> SWAP [ 2 CELLS ] LITERAL * + ;
\ Define a threaded word which also displays its name and the data stack when called \ Structures begin with byte alignment and an offset of zero
: (TRACE) >NAME TYPE SPACE .S ; 1 0 2CONSTANT STRUCT
: :TRACE : LATEST POSTPONE LITERAL POSTPONE (TRACE) ;
' (TRACE) (HIDE) \ Basic type descriptors giving alignment and size for each type
1 1 2CONSTANT CHAR%
1 ALIGNED 1 CELLS 2CONSTANT CELL%
1 ALIGNED 2 CELLS 2CONSTANT 2CELL%
\ Within STRUCT … ENDSTRUCT, define a field with the given alignment and size
\ Each field word has runtime effect ( struct-addr -- field-addr)
\ If field offset is zero then the word is marked as immediate and generates no code
: FIELD ( align1 offset1 field-align field-bytes -- align2 offset2 )
-ROT NATURALLY-ALIGNED DUP >R ALIGNED-TO
DUP : ?DUP IF POSTPONE LITERAL POSTPONE + ELSE POSTPONE IMMEDIATE THEN POSTPONE ;
+ SWAP R> UMAX SWAP ;
\ Consume the final alignment and offset and define a type descriptor for the struct
: ENDSTRUCT ( align offset "<spaces?>name" -- )
OVER ALIGNED-TO 2CONSTANT ;
\ Accessors for type descriptors
: %SIZEOF ( align size -- size ) IMMEDIATE
STATE @ IF POSTPONE NIP ELSE NIP THEN ;
: %ALIGNOF ( align size -- align ) IMMEDIATE
STATE @ IF POSTPONE DROP ELSE DROP THEN ;
\ Like : but the definition has no name \ Like : but the definition has no name
\ The zero-length name still included in the word list so LATEST can refer to it \ The zero-length name still included in the word list so LATEST can refer to it
@ -1410,35 +1435,63 @@ VARIABLE TOTAL
R@ OVER R@ - MUNMAP R@ OVER R@ - MUNMAP
DUP R> R@ 2* + SWAP R> + TUCK - MUNMAP ; DUP R> R@ 2* + SWAP R> + TUCK - MUNMAP ;
STRUCT
CELL% FIELD MEMBLOCK>SIZE
CELL% FIELD MEMBLOCK>MAGIC
2CELL% 0 * FIELD MEMBLOCK>DATA
ENDSTRUCT MEMBLOCK%
\ This is used to identify blocks returned by ALLOCATE
( 0xC0DE3319 ) 3235787545 CONSTANT MEMBLOCK-MAGIC
0 MEMBLOCK>DATA CONSTANT MEMBLOCK-DATA-OFFSET
: DATA>MEMBLOCK ( obj-addr -- memblock-addr )
MEMBLOCK-DATA-OFFSET - ;
>>FORTH >>FORTH
: ALLOCATE ( size -- obj-addr ) : ALLOCATE ( size -- obj-addr )
DUP 0= IF EXIT THEN DUP 0= IF EXIT THEN
CELL+ DUP BUDDY-MAX-BYTES U> IF MEMBLOCK-DATA-OFFSET + DUP BUDDY-MAX-BYTES U> IF
PAGESIZE ALIGNED-TO DUP MMAP-ALLOCATE TUCK ! CELL+ EXIT PAGESIZE ALIGNED-TO DUP MMAP-ALLOCATE
THEN ELSE
NATURALLY-ALIGNED DUP BUDDY-MIN-BYTES U< IF DROP BUDDY-MIN-BYTES THEN NATURALLY-ALIGNED DUP BUDDY-MIN-BYTES U< IF DROP BUDDY-MIN-BYTES THEN
BUDDY-ORDER-FROM-BYTES DUP ['] BUDDY-ALLOCATE CATCH ?DUP IF BUDDY-ORDER-FROM-BYTES DUP ['] BUDDY-ALLOCATE CATCH ?DUP IF
DUP EXCP-HEAP-OVERFLOW <> IF RETHROW THEN DROP DUP EXCP-HEAP-OVERFLOW <> IF RETHROW THEN DROP
BUDDY-ORDERS 1- BUDDY-MAX-BYTES MMAP-ALLOCATE-ALIGNED BUDDY-FREE BUDDY-ORDERS 1- BUDDY-MAX-BYTES MMAP-ALLOCATE-ALIGNED BUDDY-FREE
BUDDY-ALLOCATE BUDDY-ALLOCATE
THEN THEN
SWAP OVER ! CELL+ ; THEN
TUCK MEMBLOCK>SIZE !
MEMBLOCK-MAGIC OVER MEMBLOCK>MAGIC !
MEMBLOCK>DATA ;
: FREE ( obj-addr -- ) : FREE ( obj-addr -- )
?DUP IF ?DUP IF
CELL- DUP @ DATA>MEMBLOCK
DUP BUDDY-ORDERS U< IF SWAP BUDDY-FREE EXIT THEN DUP MEMBLOCK>MAGIC @ MEMBLOCK-MAGIC <> IF EXCP-INVALID-ADDRESS THROW THEN
0 OVER MEMBLOCK>MAGIC !
DUP MEMBLOCK>SIZE @
DUP BUDDY-ORDERS U< IF
SWAP BUDDY-FREE
ELSE
BEGIN BEGIN
2DUP SYS_MUNMAP SYSCALL2 ?DUP 0= IF 2DROP EXIT THEN 2DUP SYS_MUNMAP SYSCALL2 ?DUP 0= IF 2DROP EXIT THEN
NEGATE ERRNO_EINTR <> "munmap failed" ?FAIL NEGATE ERRNO_EINTR <> "munmap failed" ?FAIL
AGAIN AGAIN
THEN
THEN ; THEN ;
>>SYSTEM >>SYSTEM
: OBJECT-SIZE ( obj-addr -- size ) : OBJECT-SIZE ( obj-addr -- size )
CELL- @ DUP BUDDY-ORDERS U< IF BUDDY-ORDER-BYTES THEN CELL- ; DUP IF
DATA>MEMBLOCK
DUP MEMBLOCK>MAGIC @ MEMBLOCK-MAGIC <> IF EXCP-INVALID-ADDRESS THROW THEN
MEMBLOCK>SIZE @ DUP BUDDY-ORDERS U< IF BUDDY-ORDER-BYTES THEN
MEMBLOCK-DATA-OFFSET -
THEN ;
>>FORTH >>FORTH
@ -1452,7 +1505,9 @@ VARIABLE TOTAL
: RESIZE ( obj-addr1 size -- obj-addr1 | obj-addr2 | 0 ) : RESIZE ( obj-addr1 size -- obj-addr1 | obj-addr2 | 0 )
DUP 0= IF DROP FREE 0 EXIT THEN DUP 0= IF DROP FREE 0 EXIT THEN
OVER 0= IF NIP ALLOCATE EXIT THEN OVER 0= IF NIP ALLOCATE EXIT THEN
OVER OBJECT-SIZE CELL+ OVER CELL+ BUDDY-MIN-BYTES UMAX 2DUP U>= IF OVER OBJECT-SIZE MEMBLOCK-DATA-OFFSET +
OVER MEMBLOCK-DATA-OFFSET + BUDDY-MIN-BYTES UMAX
2DUP U>= IF
\ Allocated space is larger than requested size, shrink if <= 50% used \ Allocated space is larger than requested size, shrink if <= 50% used
( S: obj-addr1 size obj-size req-size ) ( S: obj-addr1 size obj-size req-size )
SWAP 2/ U> IF DROP EXIT THEN SWAP 2/ U> IF DROP EXIT THEN
@ -1495,30 +1550,6 @@ VARIABLE TOTAL
DODOES OVER ! CELL+ [ ' (CLOSURE) >DFA @ ] LITERAL OVER ! CELL+ DODOES OVER ! CELL+ [ ' (CLOSURE) >DFA @ ] LITERAL OVER ! CELL+
0 OVER ! CELL+ 0 OVER ! CELL+ 2DUP ! CELL+ N! R> ; 0 OVER ! CELL+ 0 OVER ! CELL+ 2DUP ! CELL+ N! R> ;
\ Basic type descriptors giving alignment and size for each type
1 1 2CONSTANT CHAR%
1 ALIGNED 1 CELLS 2CONSTANT CELL%
1 ALIGNED 2 CELLS 2CONSTANT 2CELL%
\ Structures begin with byte alignment and an offset of zero
1 0 2CONSTANT STRUCT
\ Within STRUCT … ENDSTRUCT, define a field with the given alignment and size
\ Each field word has runtime effect ( struct-addr -- field-addr)
\ If field offset is zero then the word is marked as immediate and generates no code
: FIELD ( align1 offset1 field-align field-bytes -- align2 offset2 )
-ROT NATURALLY-ALIGNED DUP >R ALIGNED-TO
DUP : ?DUP IF POSTPONE LITERAL POSTPONE + ELSE POSTPONE IMMEDIATE THEN POSTPONE ;
+ SWAP R> UMAX SWAP ;
\ Consume the final alignment and offset and define a type descriptor for the struct
: ENDSTRUCT ( align offset "<spaces?>name" -- )
OVER ALIGNED-TO 2CONSTANT ;
\ Accessors for type descriptors
: %SIZEOF ( align size -- size ) NIP ;
: %ALIGNOF ( align size -- align ) DROP ;
\ Reserve data or heap space for a data structure given alignment and size \ Reserve data or heap space for a data structure given alignment and size
\ It is assumed that ALLOCATE (but not ALLOT) returns an address suitably \ It is assumed that ALLOCATE (but not ALLOT) returns an address suitably
\ aligned for any primitive data type; %ALLOCATE is not suitable for data \ aligned for any primitive data type; %ALLOCATE is not suitable for data
@ -1709,6 +1740,18 @@ BOOTSTRAP-GET-ORDER SET-ORDER
: :REPLACE ( "<spaces>ccc" -- ) : :REPLACE ( "<spaces>ccc" -- )
: LATEST DUP >NAME FIND-OR-THROW DROP DUP (HIDE) DEFER! ; : LATEST DUP >NAME FIND-OR-THROW DROP DUP (HIDE) DEFER! ;
\ Produce the size or alignment of the subsequent type descriptor as a literal
\ The type-name should be a word like CELL% returning an alignment and a size
: SIZEOF ( "<spaces><type-name>" -- size ) IMMEDIATE
' EXECUTE %SIZEOF STATE @ IF POSTPONE LITERAL THEN ;
: ALIGNOF ( "<spaces><type-name>" -- size ) IMMEDIATE
' EXECUTE %ALIGNOF STATE @ IF POSTPONE LITERAL THEN ;
\ Product the offset of the subsequent field name as a literal
\ The field-name should be a word which adds a field offset to a given address
: OFFSETOF ( "<spaces><field-name>" -- offset ) IMMEDIATE
0 ' EXECUTE STATE @ IF POSTPONE LITERAL THEN ;
>>SYSTEM >>SYSTEM
\ The size of this buffer will determine the maximum line length \ The size of this buffer will determine the maximum line length
@ -1925,6 +1968,11 @@ HIDE BOOTSTRAP-WORDLIST
\ From this point on we only execute threaded FORTH words defined in this file \ From this point on we only execute threaded FORTH words defined in this file
\ ***************************************************************************** \ *****************************************************************************
\ Define a threaded word which also displays its name and the data stack when called
: (TRACE) >NAME TYPE SPACE .S ;
: :TRACE : LATEST POSTPONE LITERAL POSTPONE (TRACE) ;
' (TRACE) (HIDE)
\ Return TRUE if the given address is the execution token of a word in \ Return TRUE if the given address is the execution token of a word in
\ the current search order or compilation word list, or FALSE otherwise \ the current search order or compilation word list, or FALSE otherwise
\ The word's name may be hidden or shadowed by another definition \ The word's name may be hidden or shadowed by another definition

View File

@ -2,14 +2,17 @@
TYPE ":\n Value: " TYPE DUP @ . TYPE ":\n Value: " TYPE DUP @ .
"\n Object size: " TYPE DUP OBJECT-SIZE U. EOL EOL ; "\n Object size: " TYPE DUP OBJECT-SIZE U. EOL EOL ;
SYSTEM-WORDLIST PUSH-ORDER
: TEST : TEST
28 ALLOCATE 1234 OVER ! "Allocated 28 bytes" STATUS 24 ALLOCATE 1234 OVER ! "Allocated 24 bytes" STATUS
33 RESIZE "Resized to 33 bytes" STATUS 33 RESIZE "Resized to 33 bytes" STATUS
28 RESIZE "Resized to 28 bytes" STATUS 24 RESIZE "Resized to 24 bytes" STATUS
256 KB CELL- RESIZE "Resized to 256 KiB - 1 cell" STATUS 256 KB MEMBLOCK-DATA-OFFSET - RESIZE "Resized to 256 KiB - header" STATUS
32 RESIZE "Resized to 32 bytes" STATUS 32 RESIZE "Resized to 32 bytes" STATUS
28 RESIZE "Resized to 28 bytes" STATUS 24 RESIZE "Resized to 24 bytes" STATUS
4 RESIZE "Resized to 4 bytes" STATUS 4 RESIZE "Resized to 4 bytes" STATUS
FREE ; DUP FREE
['] FREE CATCH "CATCH after double-free: " TYPE . EOL ;
TEST TEST

View File

@ -1,29 +1,30 @@
Allocated 28 bytes: Allocated 24 bytes:
Value: 1234 Value: 1234
Object size: 28 Object size: 24
Resized to 33 bytes: Resized to 33 bytes:
Value: 1234 Value: 1234
Object size: 60 Object size: 56
Resized to 28 bytes: Resized to 24 bytes:
Value: 1234 Value: 1234
Object size: 28 Object size: 24
Resized to 256 KiB - 1 cell: Resized to 256 KiB - header:
Value: 1234 Value: 1234
Object size: 262140 Object size: 262136
Resized to 32 bytes: Resized to 32 bytes:
Value: 1234 Value: 1234
Object size: 60 Object size: 56
Resized to 28 bytes: Resized to 24 bytes:
Value: 1234 Value: 1234
Object size: 28 Object size: 24
Resized to 4 bytes: Resized to 4 bytes:
Value: 1234 Value: 1234
Object size: 28 Object size: 24
CATCH after double-free: -9
exit-code: 0 exit-code: 0