bugGforth - Bugs: bug #62030, 'Malformed xchar' error, if...

 
 

bug #62030: 'Malformed xchar' error, if fork'ed child throws

Submitter:  Stephan Rudlof <hartrock>
Submitted:  Fri 11 Feb 2022 01:57:19 AM UTC
   
 
Category:  None Severity:  3 - Normal
Item Group:  None Status:  Fixed
Privacy:  Public Assigned to:  paysan
Open/Closed:  Open
* Mandatory Fields

Add a New Comment Rich Markup
   

Jump to the original submission

Mon 08 Aug 2022 03:43:41 PM UTC, comment #12: 

Last question moved to
  Gforth - Bugs: bug #62878, fork()'ed and then exit()'ing... [Savannah]
  https://savannah.gnu.org/bugs/index.php?62878
(because it's a new thing).

Stephan Rudlof <hartrock>
Mon 08 Aug 2022 07:31:54 AM UTC, comment #11: 

How to avoid exit'ing child procs manipulating history file?

sr@rs:~/Gforth$ rm ~/.local/share/gforth/history
sr@rs:~/Gforth$ cat ~/.local/share/gforth/history
cat: /home/sr/.local/share/gforth/history: No such file or directory
sr@rs:~/Gforth$ gforth
Gforth 0.7.9_20220807
Authors: Anton Ertl, Bernd Paysan, Jens Wilke et al., for more type `authors'
Copyright © 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
Gforth comes with ABSOLUTELY NO WARRANTY; for details type `license'
Type `help' for basic help
see see
: see
  parse-name name-too-short? find-name dup 0= #-13 and throw name-see ; ok

sr@rs:~/Gforth$ cat ~/.local/share/gforth/history
see see
sr@rs:~/Gforth$ cat t_fork2.fs
require unix/libc.fs
: bazz \ good enough for testing purposes
    5 0 do
        fork()
        if \ child pid -> parent, or ..
            cr ." parent " getpid .
        else \ .. 0 -> child
            i 1000 * ms \ avoid mixing child output
            ." child " getpid .
            0 exit()
        then
    loop
;
sr@rs:~/Gforth$ gforth t_fork2.fs
Gforth 0.7.9_20220807
Authors: Anton Ertl, Bernd Paysan, Jens Wilke et al., for more type `authors'
Copyright © 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
Gforth comes with ABSOLUTELY NO WARRANTY; for details type `license'
Type `help' for basic help
bazz
parent 30205 child 30220
parent 30205
parent 30205
parent 30205
parent 30205  ok
child 30221 child 30222 child 30223 child 30224
sr@rs:~/Gforth$ cat ~/.local/share/gforth/history
see see
bazz
bazz
bazz
bazz
bazz
bazz
sr@rs:~/Gforth$


Stephan Rudlof <hartrock>
Sun 13 Feb 2022 06:37:33 PM UTC, comment #10: 

PPS: Same problem as described in comment #8 with current (git pull) gforth.

Stephan Rudlof <hartrock>
Sun 13 Feb 2022 05:20:59 PM UTC, comment #9: 

PS: Deeper question is, how to cleanly decouple forked child processes from terminal CLI input.

Stephan Rudlof <hartrock>
Sun 13 Feb 2022 05:04:12 PM UTC, comment #8: 

comment #7:

> bye and (bye) are for leaving Gforth gracefully (the difference is that (bye) is a primitive).  This means restoring the terminal.  The thing we don't want.  So we want to leave the forked process right at that point, not graceful, not restoring things, not closing and flushing files like the history buffer.


OK.

Possibly the wrong place to ask here, but nevertheless...

Using gforth v0.7.3 command history - by keyboard arrow-up - resulting after multiple CLI calls of buz mixed with other commands becomes messy:

: buz
    5 0 do
        fork-ec \ (imported) C fork() with err handling
        if \ child pid -> parent, or ..

        else \ .. 0 -> child
            history-cold
            \ needed to get normally working terminal (after finishing child)
            stdin close-file throw \ or 'sh stty -icanon' in parent bye...
            stdout close-file throw
            5 0 do
                1000 ms
                LI_foo \ writes to stderr
            loop
            7 exit() \ (bye)
        then
    loop
;


Any idea?
Looks like forked procs do something with command history in spite of 'history-cold'...

Stephan Rudlof <hartrock>
Sat 12 Feb 2022 02:21:35 AM UTC, comment #7: 

bye and (bye) are for leaving Gforth gracefully (the difference is that (bye) is a primitive).  This means restoring the terminal.  The thing we don't want.  So we want to leave the forked process right at that point, not graceful, not restoring things, not closing and flushing files like the history buffer.

Bernd Paysan <paysan>
Group administrator
Sat 12 Feb 2022 02:16:45 AM UTC, comment #6: 

comment #4:

> I added a bit code for handling a closed stdin more gracefully. 


Sounds good: it's good, if an uncatched throw does not end in an endless loop... (shit happens); especially if it's a new effect in comparison with the official version.

> The recommended way to handle forked instances is still to use exit() to leave them, and never let a throw return to the QUIT loop.


OK (if not '(bye)').

Stephan Rudlof <hartrock>
Sat 12 Feb 2022 02:06:53 AM UTC, comment #5: 

comment #3:

> The way to do this in the current Gforth development version is by:
>


> require unix/libc.fs
> : test fork() if ( ... )
>   else [: ( ... ) ;] catch ?dup-if  DoError 1  else  0  then
>       exit()
>   then ;


Thanks for the info!

What about '(bye)' instead of exit()? At least there is one in v0.7.3. Not sufficient?


>
> fork() and exit() as C functions have deliberately () so they don't conflict with Forth words with the same name.


This looks like a good convention: good to have a clear separation of external func call from other forth words (calling them with error handling).

>
> You are supposed to catch whatever you do in the forked version, as otherwise, it will return to the QUIT loop.  Closing stdin as a workaround used to work, but it doesn't look right.


Closing stdin has been first idea to stop interpreting, if something nasty happens (and 'bye' not reached); and it has worked for v0.7.3.

I've looked into the devel version, due to another error (resize with size 0), which is fixed in current version (before I've seen, that there is a non-zero errno after gforth start, but this was not the problem), and also tried my fork experiments...


Current version seems to have some distance to the official one v0.7.3: are there any plans to make a new release?


Best regards and special thanks for your fast reaction,
Stephan

Stephan Rudlof <hartrock>
Fri 11 Feb 2022 03:03:46 PM UTC, comment #4: 

I added a bit code for handling a closed stdin more gracefully.  The recommended way to handle forked instances is still to use exit() to leave them, and never let a throw return to the QUIT loop.

Bernd Paysan <paysan>
Group administrator
Fri 11 Feb 2022 12:48:40 PM UTC, comment #3: 

The way to do this in the current Gforth development version is by:


require unix/libc.fs
: test fork() if ( ... )
  else [: ( ... ) ;] catch ?dup-if  DoError 1  else  0  then
      exit()
  then ;


fork() and exit() as C functions have deliberately () so they don't conflict with Forth words with the same name.

You are supposed to catch whatever you do in the forked version, as otherwise, it will return to the QUIT loop.  Closing stdin as a workaround used to work, but it doesn't look right.

Bernd Paysan <paysan>
Group administrator
Fri 11 Feb 2022 12:27:28 PM UTC, comment #2: 

comment #1:

> I am not quite sure what's going on, so I assigned it to Bernd.
>
> The root of the problem seems to be that, if I do
>
> stdin close-file throw
>
> gforth 0.7.3 exits,


Not here:
+++
: biz
    fork
    if \ child pid -> parent, or ..
    else \ .. 0 -> child
        \ needed to get normally working terminal (after finishing child)
        stdin close-file throw \ or 'sh stty -icanon' in parent bye...
        cr ." inside child process"
        stdout close-file throw
        history-cold
        1 throw
        bye
    then
;
biz
+++
leads to
+++
biz  ok

inside child process
:9: error 1

>>>biz<<<

Backtrace:
$7F9F02168D70 throw
+++
(so child has reached printing and '1 throw').


> while 0.7.9_20220120 goes into an endless loop of throwing -77.
>
> The bug report may point to another problem in the terminal setup and restoration of Gforth: the reporter apparently is trying to work around the way this stuff interacts with forking, but it would be better if such workarounds would not be necessary.



Brainstorming (new to gforth, not knowing low-level details)
------------------------------------------------------------
What happens with low-level stderr of child, if it's throwing (probably used then)?

May be (very vague) one reason could be lack of synchronizing std io streams: with mixing them invalid xchars may be the result. But I don't understand, how low level (C?) stderr could interfere regarding xchars (low level probably just bytes) between child and parent proc...

However: at higher level I have a solution for (cooperatively) synchronizing stderr using fcntl locks; but this does not apply to low level output triggered by throws.

Solutions could be (with much guessing, may totally missing the point):
- fcntl locks of low-level stdout/stderr streams in case of fork'ing;
- no use of xchars, which could become garbage by mixing streams.

Stephan Rudlof <hartrock>
Fri 11 Feb 2022 09:55:35 AM UTC, comment #1: 

I am not quite sure what's going on, so I assigned it to Bernd.

The root of the problem seems to be that, if I do

stdin close-file throw

gforth 0.7.3 exits, while 0.7.9_20220120 goes into an endless loop of throwing -77.

The bug report may point to another problem in the terminal setup and restoration of Gforth: the reporter apparently is trying to work around the way this stuff interacts with forking, but it would be better if such workarounds would not be necessary.

Anton Ertl <anton>
Group administrator
Fri 11 Feb 2022 01:57:19 AM UTC, original submission:  

System info:
+++
sr@rs:~/Gforth$ ../gforth/gforth --version
gforth 0.7.9_20220210 amd64
sr@rs:/usr/local/share/gforth$ uname -a
Linux rs 4.19.0-18-amd64 #1 SMP Debian 4.19.208-1 (2021-09-29) x86_64 GNU/Linux
+++

This triggers the error:
+++
: baz
    fork
    if \ child pid -> parent, or ..
    else \ .. 0 -> child
        \ needed to get normally working terminal (after finishing child)
        stdin close-file throw \ or 'sh stty -icanon' in parent bye...
        stdout close-file throw
        history-cold
        1 throw
        bye
    then
;
baz
+++
as endless loop:
+++
...
kernel/int.fs:658:5:                     5 $7FADAF4B4EA0 bt-rp0-catch
the terminal:1:1: error: Malformed xchar

>>>÷z<<<

Backtrace:
kernel/input.fs:216:30:                  0 $7FADAF4C0438 throw
kernel/input.fs:216:36:                  1 $7FADAF4B5348 get-input-colored
except.fs:83:2:                          2 $7FADAF4CBDD8 execute  [catch frame]
kernel/int.fs:654:5:                     3 $7FADAF4B4E38 catch
                                         4 $7FADAF0E3FC0
kernel/int.fs:658:5:                     5 $7FADAF4B4EA0 bt-rp0-catch
the terminal:1:1: error: Malformed xchar

>>>÷z<<<

Backtrace:
kernel/input.fs:216:30:                  0 $7FADAF4C0438 throw
kernel/input.fs:216:36:                  1 $7FADAF4B5348 get-input-colored
except.fs:83:2:                          2 $7FADAF4CBDD8 execute  [catch frame]
kernel/int.fs:654:5:                     3 $7FADAF4B4E38 catch
                                         4 $7FADAF0E3FC0
kernel/int.fs:658:5:                     5 $7FADAF4B4EA0 bt-rp0-catch
the terminal:1:1: error: Malformed xchar

>>>÷z<<<

Backtrace:
kernel/input.fs:216:30:                  0 $7FADAF4C0438 throw
kernel/input.fs:216:36:                  1 $7FADAF4B5348 get-input-colored
except.fs:83:2:                          2 $7FADAF4CBDD8 execute  [catch frame]
kernel/int.fs:654:5:                     3 $7FADAF4B4E38 catch
                                         4 $7FADAF0E3FC0
kernel/int.fs:658:5:                     5 $7FADAF4B4EA0 bt-rp0-catch
the terminal:1:1: error: Malformed xchar

>>>÷z<<<

...
+++

Notes:
- fork() gotten by
+++
\c #include <sys/types.h>
\c #include <unistd.h>
c-function fork fork -- n ( -- u )
+++
, and working as expected.

- Distribution gforth 0.7.3 not triggering above bug.

Stephan Rudlof <hartrock>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

No files currently attached

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by paysan (Posted a comment)
  • -email is unavailable- added by anton (Posted a comment)
  • -email is unavailable- added by hartrock (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only logged-in users can vote.

     

    Follow 3 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2022-02-11 paysan StatusConfirmed Fixed
    2022-02-11 anton StatusNone Confirmed
        Assigned toNone paysan

    Back to the top

    Powered by Savane 3.13-3230.
    Corresponding source code