jeaye/ncurses-rs

Bug or Feature? Secrets of the percentage sign

Opened this issue · 8 comments

Hi Jeaye

I recently ran into a segmentation fault when displaying text from a file with ncurses.
After playing around a bit I found out that percentage signs in the strings to be displayed caused this behaviour.
Now I'm wondering if this is a feature of which I haven't heard before, or if it is a bug.
If it's a feature, the could you please point me to some doc I can study?

I found the following funny output:

  • When my string contains %p, then something that looks like an address is printed
  • When my string contains %s, the whole string seems to be repeated where the %s is
  • When my string contains twice a %s, I get the segmentation fault (maybe some recursion?)

Here's an example to reproduce (uncommenting the 'killer' line leads to segmenation fault):

extern crate ncurses;

fn main() {
    ncurses::initscr();
    ncurses::keypad(ncurses::stdscr(), true);
    ncurses::clear();

    let texts = vec![
        "Hello, World!",
        "A line with a %p percentage sign.",
        "Another funny %s example.",
        //"The killer %s %s maybe a recursion?",
        "Bye bye"
    ];

    let mut y = 0;
    for t in texts {
        ncurses::mvprintw(y, 0, &t);
        y += 1;
    }

    ncurses::getch();
    ncurses::endwin();
}

This produces the following output:

    Hello, World!
    A line with a 0x60b13d5ae080 percentage sign.
    Another funny Another funny %s example. example.
    Bye bye

(I run all that on Fedora Linux)

Kind regards
Peter

I just noticed another detail that might matter:
What I described above is happening when I build and run in debug mode.
But when I build a release version and run it, then already the line with a single %s leads to a segmentation fault.

Apparently printw, mvprintw and others act like C's printf, where you give a format string and a list of arguments:

int printw(const char *fmt, ...);

Rust doesn't have this concept of variable-argument functions, and just exposes the fixed format string as input. But ncurses still expects percent in the string to refer to parameters, and since no such parameter is given, memory confusion ensues.

Technically, printw should either be unsafe, of perform percent-escaping itself. In the meantime, you just should escape percents yourself: "A line with a %%p percentage sign.".

Thanks, AlexArgoAi, will do that!

And I guess I will have to do some more checks on the strings I want to print (because I just read files, so I don't know what exactly is in there). Seems there is no obvious way to check if a character is printable or not.

In general you may want to use addstr instead, as this doesn't expect formatted input. I'm not sure there's much use for printw since you can't pass in actual arguments anyway.

Yes, that's the hint I needed! Thanks a lot!
(Now the percent signs cause no more problems.)

I found this issue while looking for something else, but wanted to mention, there is a simple way for printw to percent-escape itself, just make it call the C printw("%s", s) instead of printw(s)

Right, but at that point it loses the ability to use formatting, and you're just better off using addstr.

addstr works fine. Thank you.