[m-users.] Segmentation violation on FFI wrapper for linenoise-ng
Sean Charles (emacstheviking)
objitsu at gmail.com
Sat Jun 19 23:05:33 AEST 2021
Hi Julien,
Yes, the C++ code uses fgets() which returns NULL on end of file, one is supposed to then use feof() I guess but I didnt write that code.
As I am checking the value of LineNull first and foremost on return, I didn’t (still don’t!) see the harm in what I have done i.e. I only use the value in Line to call execute() with if LineNull is 0 i.e. there is something, even an empty line, in it. If you press RETURN, it allocates a zero length buffer but that is still a non-null address which should be fine, and seems to be the case.
See my other notice that it only happens the first time through the loop, if I enter a line, even a blank one, subsequent use of CTRL-D causes an orderly exit but if that is the first keystroke, kablooey!
I am still investigating…
Sean
> On 19 Jun 2021, at 13:31, Julien Fischer <jfischer at opturion.com> wrote:
>
>
> Hi Sean,
>
> On Sat, 19 Jun 2021, Sean Charles (emacstheviking) wrote:
>
>> It all works beautifully, as expected but when I use CTRL-D it balks with this output:
>> *** Mercury runtime: caught segmentation violation ***
>> cause: address not mapped to object
>> address involved: 0x0
>> This may have been caused by a stack overflow, due to unbounded recursion.
>> exiting from signal handler
>> [1] 68417 segmentation fault ./felt -r
>> I have attached the full FFI code at the end. I’ve tried to work it through. The source code for the input function is here:
>> I studied the source code, it is using fgets() which returns NULL on end-of-file and I thought I was managing that just fine!
>> Does Mercury have something to with this e.g. a SIGINT handler or something that might be clashing with the linenoise-ng code I wonder ?
>> The calling code in my REPL loop is as follows:
>> :- pred run_loop(
>> command_line.felt_options::in,
>> replcon::in, replcon::out,
>> io::di, io::uo) is det.
>> run_loop(Options, !Repl, !IO) :-
>> ln_read(prompt, Line, LineNull, !IO),
>> io.format("LNG: NULL:%d, len:%d, \n", [i(LineNull), i(length(Line))], !IO),
>
> Ok, so we are doing stuff with the variable Line here ...
>
>> (if LineNull = 1 then
>> io.format("\n%sBe excellent to one another.\n",
>> [s(prompt)], !IO)
>> else
>> execute(Line, !Repl, !IO),
>> run_loop(Options, !Repl, !IO)
>> ).
>
> ...
>
>> :- pred ln_setup(string::in, int::in, io::di, io::uo) is det.
>> :- pred ln_shutdown(string::in, io::di, io::uo) is det.
>> :- pred ln_read(string::in, string::out, int::out, io::di, io::uo) is det.
>> :- pred ln_free(string::in, io::di, io::uo) is det.
>> % ln_read: Reads and returns a single line.
>> % Line is unified with whataver the library read from stdin.
>> % LineNull is unified with 1 if NULL(CTRL+D) is detected, else 0.
>> % If the line is not empty then we automatically add it to the history.
>> %
>> :- pragma foreign_proc(
>> "C",
>> ln_read(Prompt::in, Line::out, LineNull::out, IOin::di, IOout::uo),
>> [will_not_throw_exception, promise_pure],
>> "
>> char* line = linenoise((const char*)Prompt);
>> if (line) {
>> linenoiseHistoryAdd(line);
>> LineNull = 0;
>> Line = line;
>
> ... which is set to a value in this branch , but ...
>
>> } else {
>> LineNull = 1;
>
> ... not in this one.
>
>
>> }
>> printf(\"leaving, strlen() is %d\\n\", strlen(line));
>> IOout = IOin;
>> "
>
> I'm not familiar with the linenoise library, but I am assuming that the
> function linenoise() returns NULL on EOF?
>
> Julien.
More information about the users
mailing list