home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.forth      Forth programmers eat a lot of Bratwurst      117,927 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 116,253 of 117,927   
   Anton Ertl to Krishna Myneni   
   Re: push for memory safe languages -- im   
   03 Mar 24 07:25:20   
   
   From: anton@mips.complang.tuwien.ac.at   
      
   Krishna Myneni  writes:   
   >On 3/2/24 10:43, Anton Ertl wrote:   
   >> With the gforth engine with the FP stack being empty:   
   >>   
   >> fp@ 32769 - c@   
   >> *the terminal*:3:13: error: Floating-point stack overflow   
   >> fp@ 32769 - >>>c@<<<   
   >> fp@ 1+ c@   
   >> *the terminal*:4:8: error: Floating-point stack underflow   
   >> fp@ 1+ >>>c@<<<   
   >>   
   >   
   >In the version of Gforth which I have (0.7.9_20220120),   
   >   
   >fp@ 32769 - c@   
   >*the terminal*:5:13: error: Floating-point stack overflow   
   >fp@ 32769 - >>>c@<<<   
   >   
   >However,   
   >   
   >fp@ 65536 - c@  ok 1   
   >   
   >and, worse,   
   >   
   >1 fp@ 65536 - c!  ok   
   >   
   >So the guard pages are not a solution to pointer arithmetic bugs with   
   >the stack pointers.   
      
   Yes, that is not their intention and not the intention of these   
   examples.  The intention of these examples is to show that any memory   
   access will be interpreted as a stack underflow or overflow if it is   
   to a certain range of addresses.   
      
   A more serious issue is that, as implemented in Gforth (in particular,   
   gforth-fast), stack underflows can be undetected in some cases: On   
   Gforth on an AMD64 system, with the data stack being empty:   
      
   600 pick  ok 1   
      
   On gforth-fast, with the data stack being empty:   
      
   : foo 600 0 ?do nip loop cr . ; foo   
   0   
   *the terminal*:1:33: error: Stack underflow   
   : foo 600 0 ?do nip loop cr . ; >>>foo<<<   
   Backtrace:   
   kernel/basics.fs:312:27:                 0 $7F30E3BDFE10 throw   
      
   Note that FOO actually performs the "cr .", so the stack underflow is   
   not detected by an access to the the guard page.  Instead, the text   
   interpreter checks the stack pointer and reports a stack underflow.   
   The non-detection of the stack underflow is because NIP is implemented   
   as:   
      
   $7F30E3C72C90 nip    1->1   
   7F30E3917557:   add     r13,$08      #update sp   
      
   With the gforth engine, a similar scenario (involving DROP) is avoided   
   because in this engine DROP loads the value being dropped exactly to   
   trigger stack underflow reports where they happen:   
      
   $7F55EBFA6C98 drop    0->0   
   7F55EBAC51C0:   mov     $50[r13],r15 #save ip (for accurate backtraces)   
   7F55EBAC51C4:   add     r15,$08      #update ip   
   7F55EBAC51C8:   mov     rax,[r14]    #load dropped value   
   7F55EBAC51CB:   add     r14,$08      #update sp   
      
   Neither the deep PICK nor the loop that just NIPs or DROPs occur in   
   practice.   
      
   The motivation for the otherwise unnecessary load in DROP (in gforth)   
   is code sequences like   
      
   drop 1   
      
   in cases where the stack is empty.  The load in DROP results in   
   detecting the stack underflow at the DROP rather than at the "1".   
   Reporting a stack underflow at an operation that just pushes can   
   produce a WTF moment in the programmer; the gforth engine exists to   
   make debugging easier, and that includes avoiding such moments.   
      
   >To make stack access memory safe, there has to be bounds checks on   
   >reading and writing from/to stacks. This suggests that stacks should be   
   >arrays and stack operations always involve array read/write from arrays   
   >with enforced bounds checking e.g. something like   
   >   
   >: DUP STACK[ tos ]@ ;  \ TOS returns an index to the top of the stack   
   >: OVER STACK[ tos 1+ ]@ ;   
   >   
   >etc. and ]@ and ]! performs bounds checks.   
      
   With guard pages, that's not necessary.  The normal bounded-depth   
   stack accesses (of words like 2DROP or 2OVER) are sure to hit the   
   guard pages if the stack is out-of-bounds; you may want to perform an   
   otherwise unnecessary load on words like NIP, DROP, 2DROP etc. that do   
   not otherwise use (and thus load) the stack values that they consume,   
   but that's much cheaper than putting bounds checks on every stack   
   access.  For unbounded stack-access words like PICK, a bounds check is   
   appropriate.   
      
   - anton   
   --   
   M. Anton Ertl  http://www.complang.tuwien.ac.at/anton/home.html   
   comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html   
        New standard: https://forth-standard.org/   
      EuroForth 2023: https://euro.theforth.net/2023   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca