rxi / microui

A tiny immediate-mode UI library
MIT License
3.29k stars 239 forks source link

C string gets corrupted when passed to the TextCommand handler #53

Open J-Cake opened 2 years ago

J-Cake commented 2 years ago

I'm playing around with the demo program, and am noticing that the text rendering function receives a corrupt copy of the text to print. I've also noticed that the source it receives each time is different, meaning it's being corrupted along the way. It's received correctly in the text_width function, but I can't find where it could possibly become changed.

In short, my code is this:

void text(mu_TextCommand cmd) {
    std::string str = std::string(cmd.str);

    std::cout << str << std::endl; // Prints mangled copy

    cairo_select_font_face(cr, "raleway", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
    cairo_set_font_size(cr, 12.);
    cairo_set_source_rgba(cr, (double)cmd.color.r / 255, (double)cmd.color.g / 255, (double)cmd.color.b / 255, (double)cmd.color.a / 255);
    cairo_move_to(cr, cmd.pos.x, cmd.pos.y + text_height(cmd.font));
    cairo_text_path(cr, cmd.str);

    cairo_fill(cr);
}

...

int text_width(mu_Font font, const char *str, int len) {
    if (len == -1) len = strlen(str);

    std::cout << str << std::endl; // Prints correctly

    cairo_select_font_face(cr, "raleway", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
    cairo_set_font_size(cr, 12.);

    cairo_text_extents_t extents;
    cairo_text_extents(cr, str, &extents);

    return extents.width;
}

...

while (getElapsedTime(start) < 10) { // has it been 10s since the program started?
    mu_begin(ctx);

    cairo_set_source_rgba(cr, 1., 1., 1., 1.);
    cairo_rectangle(cr, 0, 0, dev->width, dev->height);
    cairo_fill(cr);

    if (mu_begin_window(ctx, window_title, mu_rect(10, 10, 720, 480))) {
        mu_label(ctx, window_title);

        mu_end_window(ctx);
    }

    mu_end(ctx);

    flush(ctx, dev);
}

I can't seem to find the source of the issue. My guess was some sort of memory overwriting, but I removed all memory management calls, and still got the same result.

Some details:

nlapinski commented 2 years ago

Try and null terminate your strings. This worked for me implementing a renderer in GDI

void r_draw_text(const char* text, mu_Vec2 pos, mu_Color color) {
    char buff[1024] = { 0 };

    strcat(buff, text);
    strcat(buff, "\0");

    SelectObject(Memhdc, hFont);
    SetBkMode(Memhdc, TRANSPARENT);
    SetTextColor(Memhdc, RGB(color.r, color.g, color.b));
    ExtTextOutA(Memhdc, pos.x, pos.y, ETO_OPAQUE, NULL, (LPCSTR)buff, sizeof(text), NULL);

}

or since you are using C++ try a std::string and somestring.c_str() to retrieve the char*

I think it is indeed reading into the next byte and not terminating properly, I think this might how GDI (and maybe cairo?) are handling string termination.

nlapinski commented 2 years ago

image

aand the fix image

J-Cake commented 1 year ago

I haven't had a chance to test this yet, but something tells me that'll do it