Bug 268076 - dc(1): crash on window size change
Summary: dc(1): crash on window size change
Status: Open
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: CURRENT
Hardware: amd64 Any
: --- Affects Some People
Assignee: freebsd-bugs (Nobody)
URL: https://git.yzena.com/gavin/bc/releas...
Keywords: crash
Depends on:
Blocks:
 
Reported: 2022-11-30 11:04 UTC by Marcin Cieślak
Modified: 2022-12-27 15:51 UTC (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Marcin Cieślak 2022-11-30 11:04:53 UTC
> dc --version
dc 5.3.3
Copyright (c) 2018-2022 Gavin D. Howard and contributors
Report bugs at: https://git.yzena.com/gavin/bc

This is free software with ABSOLUTELY NO WARRANTY.
> bc --version
bc 5.3.3
Copyright (c) 2018-2022 Gavin D. Howard and contributors
Report bugs at: https://git.yzena.com/gavin/bc

This is free software with ABSOLUTELY NO WARRANTY


I am running -CURRENT as of 75217c2b470 on my laptop and noticed that dc dumps core on SIGWINCH (I am using x11-wm/dwm as a window manager so this happens often):

Window size change occurs after 4 is printed:

radziecki> dc
2 2 +
p
4
Memory fault(coredump)


Core was generated by `dc'.
Program terminated with signal SIGSEGV, Segmentation fault.
Address not mapped to object.
#0  terminal_get_size (el=el@entry=0x0, lins=lins@entry=0x3cd5864c5b1c, cols=cols@entry=0x3cd5864c5b18)
    at /usr/src/contrib/libedit/terminal.c:931
--Type <RET> for more, q to quit, c to continue without paging--
931		*cols = Val(T_co);
(gdb) bt
#0  terminal_get_size (el=el@entry=0x0, lins=lins@entry=0x3cd5864c5b1c, cols=cols@entry=0x3cd5864c5b18)
    at /usr/src/contrib/libedit/terminal.c:931
#1  0x00003cd587453ff8 in el_resize (el=0x0) at /usr/src/contrib/libedit/el.c:614
#2  <signal handler called>
#3  _read () at _read.S:4
#4  0x00003ccd6561e351 in bc_read_chars (vec=0x3ccd65626848 <vm+896>, prompt=0x3ccd655f297c ">>> ")
    at /usr/src/contrib/bc/src/read.c:165
#5  bc_read_line (vec=0x3ccd65626848 <vm+896>, prompt=0x3ccd655f297c ">>> ")
    at /usr/src/contrib/bc/src/read.c:238
#6  0x00003ccd65622c0b in bc_vm_readLine (clear=<optimized out>) at /usr/src/contrib/bc/src/vm.c:1053
#7  bc_vm_stdin () at /usr/src/contrib/bc/src/vm.c:1099
#8  0x00003ccd65621e9d in bc_vm_exec () at /usr/src/contrib/bc/src/vm.c:1420
#9  bc_vm_boot (argc=1, argv=0x3cd5864c62d0) at /usr/src/contrib/bc/src/vm.c:1570
#10 0x00003ccd65606334 in main (argc=1, argv=0x3cd5864c62d0) at /usr/src/contrib/bc/src/bc.c:60
(gdb) frame 4
#4  0x00003ccd6561e351 in bc_read_chars (vec=0x3ccd65626848 <vm+896>, prompt=0x3ccd655f297c ">>> ")
    at /usr/src/contrib/bc/src/read.c:165
165			r = read(STDIN_FILENO, vm.buf + vm.buf_len,
(gdb) p vm.history
$1 = {el = 0x0, hist = 0x0, badTerm = false}

vm.history.el seems to be zero at this point.

bc, however, behaves different, and frankly I must say I don't like its error handling that obscures things:

radziecki> gdb /usr/bin/bc
GNU gdb (GDB) 12.1 [GDB v12.1 for FreeBSD]
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-portbld-freebsd14.0".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /usr/bin/bc...
Reading symbols from /usr/lib/debug//usr/bin/bc.debug...
(gdb) run
Starting program: /usr/bin/bc 
warning: Could not load shared library symbols for [vdso].
Do you need "set solib-search-path" or "set sysroot"?
2+2
4

Fatal error: I/O error
    Function: (main)

[Inferior 1 (process 26153) exited with code 04]

After a bit of digging I figured out I had to do this:

(gdb) b bc_vm_handleError
Breakpoint 1 at 0x1050c87: file /usr/src/contrib/bc/src/vm.c, line 311.
(gdb) run
Starting program: /usr/bin/bc 
warning: Could not load shared library symbols for [vdso].
Do you need "set solib-search-path" or "set sysroot"?
2+2
4

Breakpoint 1, bc_vm_handleError (e=BC_ERR_FATAL_IO_ERR, line=0) at /usr/src/contrib/bc/src/vm.c:311
311		uchar id = bc_err_ids[e];
(gdb) bt
#0  bc_vm_handleError (e=BC_ERR_FATAL_IO_ERR, line=0) at /usr/src/contrib/bc/src/vm.c:311
#1  0x0000000001036482 in bc_history_line (h=<optimized out>, vec=0x1057848 <vm+896>, prompt=0x102397c ">>> ")
    at /usr/src/contrib/bc/src/history.c:268
#2  0x000000000104f194 in bc_read_line (vec=0x1057848 <vm+896>, prompt=<optimized out>)
    at /usr/src/contrib/bc/src/read.c:236
#3  0x0000000001053c0b in bc_vm_readLine (clear=<optimized out>) at /usr/src/contrib/bc/src/vm.c:1053
#4  bc_vm_stdin () at /usr/src/contrib/bc/src/vm.c:1099
#5  0x0000000001052e9d in bc_vm_exec () at /usr/src/contrib/bc/src/vm.c:1420
#6  bc_vm_boot (argc=1, argv=0x7fffffffe6d0) at /usr/src/contrib/bc/src/vm.c:1570
#7  0x0000000001037334 in main (argc=1, argv=0x7fffffffe6d0) at /usr/src/contrib/bc/src/bc.c:60
(gdb) up
#1  0x0000000001036482 in bc_history_line (h=<optimized out>, vec=0x1057848 <vm+896>, prompt=0x102397c ">>> ")
    at /usr/src/contrib/bc/src/history.c:268
268				bc_err(BC_ERR_FATAL_IO_ERR);
(gdb) list -
263		{
264			// If this is true, there was an error. Otherwise, it's just EOF.
265			if (len == -1)
266			{
267				if (errno == ENOMEM) bc_err(BC_ERR_FATAL_ALLOC_ERR);
268				bc_err(BC_ERR_FATAL_IO_ERR);
269			}
270			else
271			{
272				bc_file_printf(&vm.fout, "\n");
(gdb) p errno
$1 = 4

which is EINTR


As noted in https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=264010 editline integration is tough, but attempting to hide all the errors is not making things better :(

Can't reproduce this with 5.2.2 versions from 13.1-RELEASE
Comment 1 Piotr Pawel Stefaniak freebsd_committer freebsd_triage 2022-11-30 11:16:48 UTC
Can you try the newest release from the upstream?
https://git.yzena.com/gavin/bc/tags
Comment 2 Marcin Cieślak 2022-11-30 14:12:34 UTC
I have tried both 6.1.1 and the master as of https://git.yzena.com/gavin/bc/src/commit/f4816582b1264b64566fc162ef6512601077cc63

Used ./configure.sh --enable-editline --debug

The behaviour of both dc and bc built from the git repo is the same as described above.
Comment 3 Gavin D. Howard 2022-11-30 15:03:46 UTC
Author of the bc/dc here.

I have reproduced this behavior. A couple notes first.

I don't think bc's error handling "obscures" things. When it outputs the error it did, that's because there *was* an I/O error, but one on either `stdin`, `stdout`, or `stderr`. Handling terminal stuff requires a lot of I/O, and if any of it fails, especially since it would have happened on one of the standard streams that should nearly always work, bc/dc has to assume that something has gone terribly wrong, so it quits with a complaint.

But the error handling is actually the same between the calculators, so dc should not have acted differently from bc if history were activated.

That was the problem: in dc, history is *not* activated by default. The bug is that el_resize() was called anyway, despite not being initialized.

I have pushed a commit (https://git.yzena.com/gavin/bc/commit/19f8e4f325f538) that fixes the crash. That seems to have fixed the problem.

Can you pull my changes and test that it works for you? You will need to build like so:

```
./configure -e -gO0
make
```

And the built programs will be `bin/bc` and `bin/dc`.

By the way, if you want to activate history in dc, you need to set the `DC_TTY_MODE` environment variable to a non-zero integer value. The reason it is not activated by default is because that's the behavior of the old dc.
Comment 4 Marcin Cieślak 2022-11-30 16:04:49 UTC
Thank you for a very quick response, here is how it looks now:

dc(1) prints "ready for more input" every time I resize the window, but does not crash at all

radziecki> ./bin/dc              
2 2 + p
4
ready for more input
5 # resize
ready for more input
ready for more input
ready for more input

bc(1) exists as before

radziecki> ./bin/bc
>>> 2 + 2 
4
>>> 
Fatal error: I/O error
    Function: (main)



This is your software and I fully respect your right to design its features as you see fit, especially given the maintenance burden is mostly on you.

I think classic "perror()" would be slighly better here (of course without all the i18n goodies).

diff --git a/src/history.c b/src/history.c
index bc15da5b..15e6e25b 100644
--- a/src/history.c
+++ b/src/history.c
@@ -264,8 +264,7 @@ bc_history_line(BcHistory* h, BcVec* vec, const char* prompt)
                // If this is true, there was an error. Otherwise, it's just EOF.
                if (len == -1)
                {
-                       if (errno == ENOMEM) bc_err(BC_ERR_FATAL_ALLOC_ERR);
-                       bc_err(BC_ERR_FATAL_IO_ERR);
+                       perror("reading next input line failed");
                }
                else
                {

Maybe it could be helpful to tell you how I approached the problem.
This is just my personal story and certainly not a case for everyone approaching unknown software:

1. First I did 

git grep "Fatal error"

to find out there is i18n system in place and it looks like "I/O Error" is an error number 5 (counted by hand in "bc_err_msgs")

2. Then I did

git grep bc_err_msgs

to learn that the whole i18n thing is initialized via bc_vm_defaultMsgs()
but still no clue regarding what might have caused it

3. Then tried my luck to

git grep bc_err_ids

that reveals there is bc_vm_handleError() and the name looks promising

4. Having learned that it was easier:

(gdb) b bc_vm_handleError
Breakpoint 1 at 0x2372f8: file ./src/vm.c, line 351.
(gdb) run
Starting program: /usr/home/saper/src/bc/bin/bc 
warning: Could not load shared library symbols for [vdso].
Do you need "set solib-search-path" or "set sysroot"?
>>> 
Breakpoint 1, bc_vm_handleError (e=BC_ERR_FATAL_IO_ERR, line=0) at ./src/vm.c:351
351		uchar id = bc_err_ids[e];
(gdb) bt
#0  bc_vm_handleError (e=BC_ERR_FATAL_IO_ERR, line=0)
    at ./src/vm.c:351
#1  0x0000000000218169 in bc_history_line (
    h=0x23e440 <vm_data+1584>, vec=0x23e228 <vm_data+1048>, 
    prompt=0x201ca5 ">>> ") at ./src/history.c:268
#2  0x0000000000234e10 in bc_read_line (
    vec=0x23e228 <vm_data+1048>, prompt=0x201ca5 ">>> ")
    at ./src/read.c:236
#3  0x000000000023827e in bc_vm_readLine (clear=true)
    at ./src/vm.c:1114
#4  0x000000000023ac20 in bc_vm_stdin () at ./src/vm.c:1165
#5  0x0000000000239b7d in bc_vm_exec () at ./src/vm.c:1501
#6  0x0000000000238eae in bc_vm_boot (argc=1, argv=0x7fffffffe6b0)
    at ./src/vm.c:1691
#7  0x000000000021131c in bc_main (argc=1, argv=0x7fffffffe6b0)
    at ./src/bc.c:62
#8  0x000000000021a199 in main (argc=1, argv=0x7fffffffe6b0)
    at ./src/main.c:108
(gdb) down
Bottom (innermost) frame selected; you cannot go down.
(gdb) up
#1  0x0000000000218169 in bc_history_line (h=0x23e440 <vm_data+1584>, 
    vec=0x23e228 <vm_data+1048>, prompt=0x201ca5 ">>> ")
    at ./src/history.c:268
268				bc_err(BC_ERR_FATAL_IO_ERR);
(gdb) list -
263		{
264			// If this is true, there was an error. Otherwise, it's just EOF.
265			if (len == -1)
266			{
267				if (errno == ENOMEM) bc_err(BC_ERR_FATAL_ALLOC_ERR);
268				bc_err(BC_ERR_FATAL_IO_ERR);
269			}
270			else
271			{
272				bc_file_printf(&vm->fout, "\n");
(gdb) 
253				}
254			}
255			else bc_history_prompt = bc_vm_strdup(prompt);
256		}
257	
258		// Get the line.
259		line = el_gets(h->el, &len);
260	
261		// If there is no line...
262		if (BC_ERR(line == NULL))
(gdb) p line
$1 = 0x0
(gdb) p h->el
$2 = (EditLine *) 0x800a6a000
(gdb) p len
$3 = -1


What certainly would help is some unique identification of the position of the error in the code (be it __FILE__, __LINE__ if need be). BC_ERR_FATAL_IO_ERR is thrown in dozen or so places so I can't quickly tell where did it fail.

Since FreeBSD runs optimized binaries, but with debug symbols available, it was frustrating to see all local variables optimized out, only errno was there:

(gdb) p len
$1 = <optimized out>
(gdb) p line
$2 = <optimized out>
(gdb) p h->el
value has been optimized out
(gdb) p errno
$3 = 4

(feel free to move this conversation somewhere else, sadly could not register at https://git.yzena.com/gavin/bc/)

But again, thank you for building this software for us.
Comment 5 Marcin Cieślak 2022-11-30 16:20:43 UTC
One more datapoint

env BC_TTY_MODE=0 ./bin/bc

behaves like dc on resize:

> env BC_TTY_MODE=0 ./bin/bc
>>> 2 + 2
4
>>> ready for more input
>>> ready for more input
>>>
Comment 6 Gavin D. Howard 2022-11-30 20:45:34 UTC
I have pushed three more commits.

The first (https://git.yzena.com/gavin/bc/commit/ab3c543ffda9096) should fix the spurious "ready for more input" problem.

The second is just a style fix.

The third addresses your problem with obscuring errors.

I now understand what you meant. I'm sorry for not understanding what you meant.

(And I'm not insulted; don't worry.)

Unfortunately, I couldn't do exactly as you suggested because that error will still be seen by users, so i18n goodies need to stay.

What I *did* do was make it so debug builds will include the C source file and line for the error.

This will not solve the problem for you, however. I looked at the Makefile for my bc in FreeBSD (https://github.com/freebsd/freebsd-src/blob/78bc019d220e05abb5b12f678f9b4a847019bbcc/usr.bin/gh-bc/Makefile), and it specifically *unsets* debug mode.

Whether FreeBSD uses a debug build on my bc is outside of my pay grade, but that discussion is certainly something that still belongs here in the FreeBSD bug tracker. Stefan Esser (@se) would be the one to make that decision. (I'm adding him to this bug.)

(And I'm sorry that you couldn't register at git.yzena.com; I had so much spam I had to disable new accounts not made by me.)

But regardless, the latest master of my code will let you make a debug build with C source and line information. I hope that helps.
Comment 7 Gavin D. Howard 2022-11-30 20:47:25 UTC
Oh, and the third commit I pushed was https://git.yzena.com/gavin/bc/commit/bcdf1753e6f8cc54a1e61773c554172faf914447 .
Comment 8 Gavin D. Howard 2022-12-05 22:21:24 UTC
Marcin, could you confirm if the latest master is what you would like? I would like to put out a release with the fix if it is.
Comment 9 Marcin Cieślak 2022-12-06 00:38:04 UTC
Thank you - as of e1205eaccfa03a8dbbfd625af664f6b074b69a65

dc works fine on window resize
bc (default) exits with

> ./bin/bc
>>> 2 2 
Fatal error: I/O error
    Function: (main)
    ./src/history.c:268


> env BC_TTY_MODE=0 ./bin/bc

works fine (the same way as ./bin/dc) - no crash on resize
Comment 10 Gavin D. Howard 2022-12-06 02:02:05 UTC
Okay. That is not happening for me. I'll reproduce it and fix it.
Comment 11 Gavin D. Howard 2022-12-06 15:20:14 UTC
I cannot reproduce the fatal I/O error at all. Maybe it's because I can only use QEMU, but I don't think so because I'm sending SIGWINCH to bc with kill.

Maybe it's because I'm not running -CURRENT or because I'm running a bare terminal without dwm. Or maybe it's because I'm running in QEMU. I have no idea.

I'm going to see if I can set up a VM with -CURRENT and dwm.
Comment 12 Graham Perrin freebsd_committer freebsd_triage 2022-12-06 16:15:47 UTC
pstef@ would you like to take this (in progress)?
Comment 13 Gavin D. Howard 2022-12-06 22:20:56 UTC
I have successfully reproduced this on a VM with -CURRENT, dwm, and st, and it happened immediately.

I'm not sure what is different about this environment that causes the error, but I'll dig into it. It might be something outside of bc, though.
Comment 14 Marcin Cieślak 2022-12-06 23:24:54 UTC
I have set a breakpoint on the signal handler and single-stepped it a bit:

+b bc_vm_sig
Note: breakpoint 1 also set at pc 0x23a66b.
Breakpoint 2 at 0x23a66b: file ./src/vm.c, line 123.
+run
Starting program: /usr/home/saper/src/bc/bin/bc 
warning: Could not load shared library symbols for [vdso].
Do you need "set solib-search-path" or "set sysroot"?

Breakpoint 1, bc_vm_sig (sig=28) at ./src/vm.c:123
123		if (vm->status == (sig_atomic_t) BC_STATUS_QUIT || vm->sig != 0)
+p *vm
$2 = {status = 0, sig_pop = 0, prs = {l = {buf = 0x0, i = 0, line = 1, len = 0, 
      t = BC_LEX_EOF, last = BC_LEX_EOF, str = {v = 0x800a2a0e0 '\245' <repeats 32 times>, 
        len = 0, cap = 32, size = 1, dtor = 0}, mode = BC_MODE_EXPRS}, flags = {
      v = 0x800a43040 "", len = 1, cap = 32, size = 2, dtor = 0}, exits = {
      v = 0x800a5d300 '\245' <repeats 200 times>..., len = 0, cap = 32, size = 24, 
      dtor = 0}, conds = {v = 0x800a50700 '\245' <repeats 200 times>..., len = 0, cap = 32, 
      size = 8, dtor = 0}, ops = {v = 0x800a09000 '\245' <repeats 128 times>, len = 0, 
      cap = 32, size = 4, dtor = 0}, buf = {v = 0x800a2a0c0 '\245' <repeats 64 times>, 
      len = 0, cap = 32, size = 1, dtor = 0}, prog = 0x23ea00 <vm_data+288>, 
    func = 0x800a47000, fidx = 0, auto_part = false}, prog = {globals = {10, 10, 0, 10}, 
    globals_v = {{v = 0x800a50000 "\n", len = 1, cap = 32, size = 8, dtor = 0}, {
        v = 0x800a50100 "\n", len = 1, cap = 32, size = 8, dtor = 0}, {v = 0x800a50200 "", 
        len = 1, cap = 32, size = 8, dtor = 0}, {v = 0x800a50300 "\n", len = 1, cap = 32, 
        size = 8, dtor = 0}}, rng = {v = {v = 0x800a54000 "", len = 1, cap = 32, size = 32, 
        dtor = 0}}, results = {v = 0x800a57000 '\245' <repeats 200 times>..., len = 0, 
      cap = 32, size = 48, dtor = 6}, stack = {v = 0x800a5d000 "", len = 1, cap = 32, 
      size = 24, dtor = 0}, consts = {v = 0x800a60000 '\245' <repeats 200 times>..., 
      len = 0, cap = 32, size = 56, dtor = 5}, const_map = {
      v = 0x800a44c00 '\245' <repeats 200 times>..., len = 0, cap = 32, size = 16, 
      dtor = 0}, strs = {v = 0x800a50600 '\245' <repeats 200 times>..., len = 0, cap = 32, 
      size = 8, dtor = 0}, str_map = {v = 0x800a44e00 '\245' <repeats 200 times>..., 
      len = 0, cap = 32, size = 16, dtor = 0}, fns = {v = 0x800a47000 "\200\240\242", 
      len = 2, cap = 32, size = 120, dtor = 3}, fn_map = {v = 0x800a44200 "", len = 2, 
      cap = 32, size = 16, dtor = 0}, vars = {v = 0x800a54400 '\245' <repeats 200 times>..., 
      len = 0, cap = 32, size = 32, dtor = 1}, var_map = {
      v = 0x800a44800 '\245' <repeats 200 times>..., len = 0, cap = 32, size = 16, 
      dtor = 0}, arrs = {v = 0x800a54800 '\245' <repeats 200 times>..., len = 0, cap = 32, 
      size = 32, dtor = 1}, arr_map = {v = 0x800a44a00 '\245' <repeats 200 times>..., 
      len = 0, cap = 32, size = 16, dtor = 0}, tail_calls = {v = 0x0, len = 0, cap = 0, 
      size = 0, dtor = 0}, strmb = {num = 0x23ecd8 <vm_data+1016>, rdx = 0, scale = 0, 
      len = 1, cap = 8}, asciify = {num = 0x800a2a040, rdx = 0, scale = 0, len = 0, 
      cap = 8}, last = {num = 0x800a2a060, rdx = 0, scale = 0, len = 0, cap = 8}, 
    strmb_num = {256, 0, 0, 0, 0, 0, 0, 0}}, line_buf = {v = 0x800a2a800 "", len = 1, 
    cap = 32, size = 1, dtor = 0}, buffer = {v = 0x800a2a100 "", len = 1, cap = 32, 
    size = 1, dtor = 0}, read_prs = {l = {buf = 0x0, i = 0, line = 0, len = 0, 
      t = BC_LEX_EOF, last = BC_LEX_EOF, str = {v = 0x0, len = 0, cap = 0, size = 0, 
        dtor = 0}, mode = BC_MODE_EXPRS}, flags = {v = 0x0, len = 0, cap = 0, size = 0, 
      dtor = 0}, exits = {v = 0x0, len = 0, cap = 0, size = 0, dtor = 0}, conds = {v = 0x0, 
      len = 0, cap = 0, size = 0, dtor = 0}, ops = {v = 0x0, len = 0, cap = 0, size = 0, 
      dtor = 0}, buf = {v = 0x0, len = 0, cap = 0, size = 0, dtor = 0}, prog = 0x0, 
    func = 0x0, fidx = 0, auto_part = false}, read_buf = {v = 0x0, len = 0, cap = 0, 
    size = 0, dtor = 0}, jmp_bufs = {v = 0x800a32000 "!\250!", len = 2, cap = 32, size = 96, 
    dtor = 0}, temps_len = 0, file = 0x20ab00 <bc_program_stdin_name> "<stdin>", 
  sigmsg = 0x20a120 <bc_sig_msg> "\ninterrupt (type \"quit\" to exit)\n", sig_lock = 1, 
  sig = 0, siglen = 33 '!', read_ret = 77 'M', flags = 15808, nchars = 0, line_len = 69, 
  no_exprs = false, exit_exprs = false, eof = false, mode = 2 '\002', no_redefine = false, 
  files = {v = 0x0, len = 0, cap = 0, size = 0, dtor = 0}, exprs = {v = 0x0, len = 0, cap = 0, size = 0, dtor = 0}, name = 0x7fffffffea8b "bc", help = 0x2059b0 <bc_help> "usage: %s [options] [file...]\n\nbc is a command-line, arbitrary-precision calculator with a Turing-complete\nlanguage. For details, use `man %s` or see the online documentation at\nhttps://git.yzena.com/"..., history = {el = 0x800a6a000, hist = 0x800a67000, badTerm = false}, next = 0x2113a0 <bc_lex_token>, parse = 0x2126c0 <bc_parse_parse>, expr = 0x213430 <bc_parse_expr>, func_header = 0x80027f32c "Function:", err_ids = {0x80027f336 "Math error:", 0x80027f342 "Parse error:", 0x80027f34f "Runtime error:", 0x80027f35e "Fatal error:", 0x80027f36b "Warning:"}, err_msgs = {0x80027f374 "negative number", 0x80027f384 "non-integer number", 0x80027f397 "overflow: number does not fit into a hardware number", 0x80027f3cc "divide by 0", 0x80027fa7c "memory allocation failed", 0x80027fa95 "I/O error", 0x80027fa9f "cannot open file: %s", 0x80027fab4 "file is not text: %s", 0x80027fac9 "path is a directory: %s", 0x80027fae1 "invalid command-line option: \"%s\"", 0x80027fb03 "option requires an argument: '%c' (\"%s\")", 0x80027fb2c "option takes no arguments: '%c' (\"%s\")", 0x80027fb53 "invalid command-line option argument: \"%s\"", 0x80027f901 "invalid ibase: must be [%lu, %lu]", 0x80027f923 "invalid obase: must be [%lu, %lu]", 0x80027f945 "invalid scale: must be [%lu, %lu]", 0x80027f967 "invalid read() expression", 0x80027f981 "recursive read() call", 0x80027f997 "variable or array element is the wrong type", 0x80027f9c3 "stack has too few elements", 0x80027f9de "stack for register \"%s\" has too few elements", 0x80027fa0b "wrong number of parameters; need %zu, have %zu", 0x80027fa3a "undefined function: %s()", 0x80027fa53 "cannot use a void value in an expression", 0x80027f3d8 "end of file", 0x80027f3e4 "invalid character '%c'", 0x80027f3fb "string end cannot be found", 0x80027f416 "comment end cannot be found", 0x80027f432 "invalid token", 0x80027f440 "invalid expression", 0x80027f453 "empty expression", 0x80027f464 "invalid print or stream statement", 0x80027f486 "invalid function definition", 0x80027f4a2 "invalid assignment: left side must be scale, ibase, obase, seed, last, var, or array element", 0x80027f4ff "no auto variable found", 0x80027f516 "function parameter or auto \"%s%s\" already exists", 0x80027f547 "block end cannot be found", 0x80027f561 "cannot return a value from void function: %s()", 0x80027f590 "var cannot be a reference: %s", 0x80027f5ae "POSIX does not allow names longer than 1 character: %s", 0x80027f5e5 "POSIX does not allow '#' script comments", 0x80027f60e "POSIX does not allow the following keyword: %s", 0x80027f63d "POSIX does not allow a period ('.') as a shortcut for the last result", 0x80027f683 "POSIX requires parentheses around return expressions", 0x80027f6b8 "POSIX does not allow the following operator: %s", 0x80027f6e8 "POSIX does not allow comparison operators outside if statements or loops", 0x80027f731 "POSIX requires 0 or 1 comparison operators per condition", 0x80027f76a "POSIX requires all 3 parts of a for loop to be non-empty", 0x80027f7a3 "POSIX requires a newline between a semicolon and a function definition", 0x80027f7ea "POSIX does not allow exponential notation", 0x80027f814 "POSIX does not allow array references as function parameters", 0x80027f851 "POSIX does not allow void functions", 0x80027f875 "POSIX requires the left brace be on the same line as the function header", 0x80027f8be "POSIX does not allow strings to be assigned to variables or arrays"}, locale = 0x8004a9380 "pl_PL.UTF-8/pl_PL.UTF-8/pl_PL.UTF-8/pl_PL.UTF-8/pl_PL.UTF-8/C", maxes = {36, 1000000000, 18446744073709551614, 18446744073709551615, 0}, last_base = 0, last_pow = 0, last_exp = 0, last_rem = 0, env_args_buffer = 0x0, env_args = {v = 0x0, len = 0, cap = 0, size = 0, dtor = 0}, zero = {num = 0x23f27c <vm_data+2460>, rdx = 0, scale = 0, len = 0, cap = 1}, one = {num = 0x23f278 <vm_data+2456>, rdx = 0, scale = 0, len = 1, cap = 1}, max = {num = 0x23f238 <vm_data+2392>, rdx = 0, scale = 0, len = 3, cap = 8}, max2 = {num = 0x23f258 <vm_data+2424>, rdx = 0, scale = 0, len = 5, cap = 8}, max_num = {709551616, 446744073, 18, 0, 0, 0, 0, 0}, max2_num = {768211456, 374607431, 938463463, 282366920, 340, 0, 0, 0}, one_num = {1}, zero_num = {0}, fout = {f = 0x8004a1b08}, ferr = {f = 0x8004a1c40}, catalog = 0x800a42000, buf = 0x2402f0 <output_bufs> "", buf_len = 0, slabs = {v = 0x800a44000 "", len = 1, cap = 32, size = 16, dtor = 4}, redefined_kws = {false <repeats 37 times>}, temps_buf = {0x0 <repeats 512 times>}}
+p errno
$3 = 2
+n
131		if (sig == SIGWINCH)
+n
133			if (BC_TTY)
+n
135				el_resize(vm->history.el);
+n
136			}
+n
144			return;
+n
198	}
+n
_read () at _read.S:4
4	_read.S: No such file or directory.
+n
cerror () at /usr/src/lib/libc/amd64/sys/cerror.S:52
52		pushq	%rax
+n
cerror () at /usr/src/lib/libc/amd64/sys/cerror.S:53
53		call	PIC_PLT(CNAME(__error))
+bt
#0  cerror () at /usr/src/lib/libc/amd64/sys/cerror.S:53
#1  0x0000000000000004 in ?? ()
#2  0x00000008002a4365 in read_char (el=0x800a6a000, 
    cp=0x7fffffffe294 L"\b\xffffe334翿\x86587f0\x9d83834d\xffffe6a0翿\xffffe688翿")
    at /usr/src/contrib/libedit/read.c:287
#3  0x00000008002a47af in el_wgetc (el=el@entry=0x800a6a000, 
    cp=cp@entry=0x7fffffffe294 L"\b\xffffe334翿\x86587f0\x9d83834d\xffffe6a0翿\xffffe688翿") at /usr/src/contrib/libedit/read.c:406
#4  0x00000008002a49ab in read_getcmd (el=<optimized out>, cmdnum=<optimized out>, 
    ch=<optimized out>) at /usr/src/contrib/libedit/read.c:233
#5  el_wgets (el=0x800a6a000, nread=0x7fffffffe334) at /usr/src/contrib/libedit/read.c:519
#6  0x000000080029b199 in el_gets (el=0x0, nread=0x7fffffffe18a)
    at /usr/src/contrib/libedit/eln.c:75
#7  0x00000000002187e2 in bc_history_line (h=0x23ef10 <vm_data+1584>, 
    vec=0x23ecf8 <vm_data+1048>, prompt=0x201cbd ">>> ") at ./src/history.c:259
#8  0x0000000000235870 in bc_read_line (vec=0x23ecf8 <vm_data+1048>, prompt=0x201cbd ">>> ")
    at ./src/read.c:250
#9  0x0000000000238d3e in bc_vm_readLine (clear=true) at ./src/vm.c:1123
#10 0x000000000023b6f0 in bc_vm_stdin () at ./src/vm.c:1174
#11 0x000000000023a64d in bc_vm_exec () at ./src/vm.c:1510
#12 0x000000000023996e in bc_vm_boot (argc=1, argv=0x7fffffffe690) at ./src/vm.c:1700
#13 0x000000000021138c in bc_main (argc=1, argv=0x7fffffffe690) at ./src/bc.c:62
#14 0x000000000021a8c9 in main (argc=1, argv=0x7fffffffe690) at ./src/main.c:108
+q


What happens here is that the signal handler does not do too much, it tells libedit to resize and then exits with an early "return". Since we are in a read() system call, it will be interrupted.
Comment 15 Gavin D. Howard 2022-12-07 02:49:30 UTC
That is my bad. I thought libedit would handle EINTR. Guess I was wrong.

The latest master (https://git.yzena.com/gavin/bc/commit/3cb0a4b2ec65cfed9d147180230e416b4639e834) should fix the problem by looping on EINTR. Can you pull and test that for me?

By the way, libedit has an unfortunate bug: it loses the data it has gathered if an interrupt happens. There's not much I can do about that. I think.
Comment 16 Piotr Pawel Stefaniak freebsd_committer freebsd_triage 2022-12-07 07:35:44 UTC
(In reply to Graham Perrin from comment #12)
I don't want to step on se@'s toes.

(In reply to Gavin D. Howard from comment #15)
Could you describe the libedit problem to Christos Zoulas <christos@netbsd.org>? I'm sure he'll be willing to fix it and it would be a win for everybody.
Comment 17 Gavin D. Howard 2022-12-07 14:36:40 UTC
pstef@, I have emailed Christos.
Comment 18 Gavin D. Howard 2022-12-24 06:08:19 UTC
I have released 6.2.0 with the bug fixes.

It is up to @se when it will be added to FreeBSD proper, but anyone affected by this bug can use the new release.
Comment 19 Graham Perrin freebsd_committer freebsd_triage 2022-12-27 15:44:30 UTC
(In reply to Gavin D. Howard from comment #18)

Thank you. 

(Also noted, <https://git.yzena.com/gavin/bc/releases>: more recent production release 6.2.1 …)
Comment 20 Gavin D. Howard 2022-12-27 15:51:32 UTC
> (Also noted, <https://git.yzena.com/gavin/bc/releases>: more recent production release 6.2.1 …)

Yeah, sorry. I finished the release, put the comment on this bug, and then switched task to research, which had me using bc. And then I accidentally found a crash.

I didn't post about it because I didn't think it was relevant to the bug. Sorry.