Code Monkey home page Code Monkey logo

Comments (10)

Gumnos avatar Gumnos commented on August 24, 2024

(I reported the initial Debian bug against rlwrap)

It appears to be a readline issue, as I get the same behavior with Python (2.x or 3.x) which uses readline under the hood:

$ python
…
>>> import cmd
>>> cmd.Cmd().cmdloop()  
(Cmd) # do C-x ( <NL> <NL> C-x ) C-x e and it segfaults

Mike Miller (at Debian) reduced the test case to simply having more than one <NL> in it.

Note that readline appears to handle the multi-line macro in bash just fine:

bash$ # just typed C-x ( before this line
bash$ # and here's a second line
bash$ # typed C-x ) before this line, and about to type C-x e on the next line
bash$ # just typed C-x ( before this line
bash$ # and here's a second line

Note that it plays back the two recorded lines just fine.

from rlwrap.

hanslub42 avatar hanslub42 commented on August 24, 2024

Thanks a million! Closing (for now, but it might turn out that python and rlwrap are both unwittingly violating some constraint on the use of the rl*() functions)

from rlwrap.

Gumnos avatar Gumnos commented on August 24, 2024

I'm unfamiliar with the readline libraries, so is there an upstream against which this should be reported?

from rlwrap.

hanslub42 avatar hanslub42 commented on August 24, 2024

Before reporting this to the Bug-readline list, I'll have a closer look. I always give an MWE when reporting a bug, and until now, I haven't been able to find it, as the simplest test program that uses the "callback interface" (as rlwrap does) works just fine on the same input that crashes rlwrap (and , apparently, also pythons cmdloop)

So, the following program works correctly:

#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>

void line_handler(char *line) { /* This function (callback) gets called by readline                                                                 
                                                  whenever rl_callback_read_char sees an ENTER */
     printf("You typed: '%s'\n", line);
}

int main() {
    rl_callback_handler_install("Type anything: ", &line_handler);
    while (1)
        rl_callback_read_char();
}

For now, I'm reopening (until I have an MWE)

from rlwrap.

mtmiller avatar mtmiller commented on August 24, 2024

Confirmed here, your simple example program works for me, but both rlwrap and python segfault, and both are using the callback interface.

I have not figured out the sequence of events yet, but the segfault occurs when the callback handler function has been reset to NULL during the call to rl_callback_read_char(). This seems related to the way that the callback function is installed and removed during execution.

Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) bt
#0  0x0000000000000000 in ?? ()
#1  0x00007ffff79be2ab in rl_callback_read_char () at ../callback.c:238
#2  0x000000000040553a in main_loop () at main.c:552
#3  0x00000000004035de in main (argc=2, argv=0x7fffffffde28) at main.c:181
(gdb) up
#1  0x00007ffff79be2ab in rl_callback_read_char () at ../callback.c:238
238       (*rl_linefunc) (line);
(gdb) list
233         (*rl_deprep_term_function) ();
234 #if defined (HANDLE_SIGNALS)
235       rl_clear_signals ();
236 #endif
237       in_handler = 0;
238       (*rl_linefunc) (line);
239 
240       /* If the user did not clear out the line, do it for him. */
241       if (rl_line_buffer[0])
242         _rl_init_line_state ();
(gdb) p rl_linefunc
$1 = (rl_vcpfunc_t *) 0x0

from rlwrap.

hanslub42 avatar hanslub42 commented on August 24, 2024

rlwrap assumes (incorrectly, as it turns out only now) that the line_handler() will never be called twice in succession without an intervening keypress. Hence the line_handler (or rather, its author...) thinks it can get away with calling rl_callback_handler_remove() because the callback handler will be re-installed in the main loop as soon as a keypress is seen.

This explains why we need a macro with two newlines to cause a crash: the first line is handled just fine by line_handler(), which removes itself, so that the second line is called with a NULL handler, which is clearly visible in Mike's stack trace:

 (gdb) bt
 #0  0x0000000000000000 in ?? ()

rlwrap needs all this trickery with saving and restoring readlines state to maintain transparency.

I cannot think of a good reason why Python's cmd.Cmd().cmdloop() should have the same problems, but it is possible that the same wrong assumption is creating havoc there as well (edit: yes it is, cf issue 25259)

I'll have to think of a way to move the rl_callback_handler_remove() call out of the line_handler, to somewhere in the main loop, or else find some other way to reset the terminal to its pristine state. To be continued....

from rlwrap.

hanslub42 avatar hanslub42 commented on August 24, 2024

I created a branch persistent_linehandler in which I moved the cleanup code at the end of line_handler() to inside the main loop itself. Quick and dirty, but it seems to do the job. This will need some testing!

from rlwrap.

hanslub42 avatar hanslub42 commented on August 24, 2024

Not removing the line_handler() will make readline reprint the prompt, and it will do so without checking for wrapped-around (very long) prompts, as rlwrap does. Not good.

New attempt: now, the linehandler checks rl_readline_state to see whether a macro is being played back. In that case the rl_callback_handler_remove() call is skipped:

if(!RL_ISSTATE(RL_STATE_MACROINPUT))
   rl_callback_handler_remove();

This is much less intrusive, and works pretty well until now. This is probably also a good and easy fix for the Python folks!

from rlwrap.

hanslub42 avatar hanslub42 commented on August 24, 2024

OK, this works, and is minimally intrusive. Merging and closing.

from rlwrap.

hanslub42 avatar hanslub42 commented on August 24, 2024

My comments above are muddle-headed, as it is not the line handler, but the callback handler that is being removed. That should be harmless, but apparently isn't (calling rl_callback_handler_remove() twice in succession doesn't seem to be harmful)

from rlwrap.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.