Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: [Solved] Segmentation Fault when drawing a sf::Text object in Lua  (Read 8929 times)

0 Members and 1 Guest are viewing this topic.

Orfby

  • Newbie
  • *
  • Posts: 31
    • View Profile
This is a very odd and specific circumstance but, I recently exposed some of the classes from SFML (I hope that's allowed) to Lua with a C++ header-only library called LuaBridge (https://github.com/vinniefalco/LuaBridge). Most of the classes were exposed just fine (but sf::Event because LuaBridge doesn't like Enums or Unions), but after trying to use sf::Text I get an error. My error is that I get a Segmentation Fault after I create a sf::Text object, then set the font with a sf::Font object (and no, the reference isn't destroyed because this doesn't happen with sf::Texture and sf::Sprite).

Here is my C++ code to expose some SFML classes, and run a lua script called script.lua:

#include <string>

#include <SFML/Graphics.hpp>

#include <lua.hpp>
#include <LuaBridge.h>

//Wrapper for sf::Text:
class TextWrap
{
    private:
        sf::Text member;

    public:
        void setCharacterSize(const int& newSize) {member.setCharacterSize(newSize);}
        int getCharacterSize() {return member.getCharacterSize();}

        void setColor(const sf::Color& newColor) {member.setColor(newColor);}
        sf::Color getColor() {return member.getColor();}

        void setFont(const sf::Font& newFont) {member.setFont(newFont);}
        const sf::Font* getFont() {return member.getFont();}

        void setPosition(const sf::Vector2f& newPosition) {member.setPosition(newPosition);}
        sf::Vector2f getPosition() {return member.getPosition();}

        void setRotation(const float& rotation) {member.setRotation(rotation);}
        float getRotation() {return member.getRotation();}

        void setScale(const sf::Vector2f& newScale) {member.setScale(newScale);}
        sf::Vector2f getScale() {return member.getScale();}

        void setString(const std::string& text) {member.setString(text);}
        std::string getString() {return member.getString();}

        void move(const sf::Vector2f& movePos) {member.move(movePos);}
        void rotate(const float& rotation) {member.rotate(rotation);}
        void scale(const sf::Vector2f& scaleAmount) {member.scale(scaleAmount);}

        sf::Text getMember() {return member;}
};

class WindowWrap
{
    private:
        sf::RenderWindow member;

    public:
        void createWindowed(const unsigned int width, const unsigned int height, const std::string& title)
        void close() {member.close();}

        void clear(const sf::Color& clearColour) {member.clear(clearColour);}
        void display() {member.display();}
        void draw(TextWrap& text) {member.draw(text.getMember());}
};

int main()
{
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);
    luabridge::getGlobalNamespace(L)
    .beginClass<sf::Vector2f>("Vector2f")
        .addConstructor<void(*)(float, float)>()
        .addData("x", &sf::Vector2f::x)
        .addData("y", &sf::Vector2f::y)
    .endClass()
    .beginClass<sf::Vector2i>("Vector2i")
        .addConstructor<void(*)(int, int)>()
        .addData("x", &sf::Vector2i::x)
        .addData("y", &sf::Vector2i::y)
    .endClass()

    .beginClass<sf::Color>("Color")
        .addConstructor<void(*)(unsigned int, unsigned int, unsigned int, unsigned int)>()
        .addData("r", &sf::Color::r)
        .addData("g", &sf::Color::g)
        .addData("b", &sf::Color::b)
        .addData("a", &sf::Color::a)
    .endClass()

    .beginClass<sf::Font>("Font")
        .addConstructor<void(*)(void)>()
        .addFunction("loadFromFile", &sf::Font::loadFromFile)
    .endClass()
    .beginClass<TextWrap>("Text")
        .addConstructor<void(*)(void)>()
        .addFunction("setCharacterSize", &TextWrap::setCharacterSize)
        .addFunction("getCharacterSize", &TextWrap::getCharacterSize)
        .addFunction("setColor", &TextWrap::setColor)
        .addFunction("getColor", &TextWrap::getColor)
        .addFunction("setFont", &TextWrap::setFont)
        .addFunction("getFont", &TextWrap::getFont)
        .addFunction("setPosition", &TextWrap::setPosition)
        .addFunction("getPosition", &TextWrap::getPosition)
        .addFunction("setRotation", &TextWrap::setRotation)
        .addFunction("getRotation", &TextWrap::getRotation)
        .addFunction("setScale", &TextWrap::setScale)
        .addFunction("getScale", &TextWrap::getScale)
        .addFunction("setString", &TextWrap::setString)
        .addFunction("getString", &TextWrap::getString)
        .addFunction("move", &TextWrap::move)
        .addFunction("rotate", &TextWrap::rotate)
        .addFunction("scale", &TextWrap::scale)
    .endClass()

    .beginClass<WindowWrap>("Window")
        .addConstructor<void(*)(void)>()
        .addFunction("createWindowed", &WindowWrap::createWindowed)
        .addFunction("close", &WindowWrap::close)
        .addFunction("clear", &WindowWrap::clear)
        .addFunction("display", &WindowWrap::display)
        .addFunction("draw", &WindowWrap::draw)
    .endClass();

    WindowWrap mainWindow; //This is defined here so C++ knows if the main application is open
    mainWindow.createWindowed(800, 600, "Lua Test");
    luabridge::push(L, &mainWindow);
    lua_setglobal(L, "mainWindow");

    luaL_dofile(L, "./script.lua");
}

Here is script.lua:

text = Text();
text:setCharacterSize(16);
text:setPosition(Vector2f(100, 100));
text:setColor(Color(255,255,255,255));
text:setString("Hello World");
font = Font();
font:loadFromFile("./font.ttf");
text:setFont(font); --If I remove this I don't get a Segmentation Fault
mainWindow:drawText(text); --But the Segmentation Fault happens here

The chances of someone being familiar with C++, SFML, LuaBridge and Lua are very low, so I don't expect someone to know exactly why, but just to have an idea or suggestion.

Details I forgot:
  • OS: Ubuntu 14.04
  • Graphics Card: NVIDIA GTX 750 Ti (Not sure if it matters)
  • SFML Version: 2.1

Debugger Callstack:

Code: [Select]
#0 0x7ffff7bb4dcc sf::Font::getTexture(unsigned int) const() (/usr/lib/x86_64-linux-gnu/libsfml-graphics.so.2:??)
#1 0x7ffff7bcdd3e sf::Text::draw(sf::RenderTarget&, sf::RenderStates) const() (/usr/lib/x86_64-linux-gnu/libsfml-graphics.so.2:??)
#2 0x7ffff7bc6b17 sf::RenderTarget::draw(sf::Drawable const&, sf::RenderStates const&) () (/usr/lib/x86_64-linux-gnu/libsfml-graphics.so.2:??)
#3 0x407439 WindowWrap::drawText(this=0x7fffffffe0f0, text=...) (/home/ben/Documents/Programming/C++/Projects/TEST/main.cpp:56)
#4 0x410686 luabridge::FuncTraits<void (WindowWrap::*)(TextWrap&) (../../Resources/External/Cross-Platform/LuaBridge/detail/FuncTraits.h:209)
#5 0x40e774 luabridge::CFunc::CallMember<void (WindowWrap::*)(TextWrap&) (../../Resources/External/Cross-Platform/LuaBridge/detail/CFunctions.h:313)
#6 0x7ffff756561d ??() (/usr/lib/x86_64-linux-gnu/liblua5.2.so.0:??)
#7 0x7ffff75709b4 ??() (/usr/lib/x86_64-linux-gnu/liblua5.2.so.0:??)
#8 0x7ffff7565989 ??() (/usr/lib/x86_64-linux-gnu/liblua5.2.so.0:??)
#9 0x7ffff7564fac ??() (/usr/lib/x86_64-linux-gnu/liblua5.2.so.0:??)
#10 0x7ffff7565bc1 ??() (/usr/lib/x86_64-linux-gnu/liblua5.2.so.0:??)
#11 0x7ffff7561c9d lua_pcallk() (/usr/lib/x86_64-linux-gnu/liblua5.2.so.0:??)
#12 0x404523 main() (/home/ben/Documents/Programming/C++/Projects/TEST/main.cpp:181)
« Last Edit: August 08, 2015, 11:53:03 am by Orfby »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
AW: Segmentation Fault when drawing a sf::Text object in Lua
« Reply #1 on: July 29, 2015, 08:47:20 pm »
Create a minimal example from scratch or remove all unnecessary code till you end up with a minimal and complete example.

Then use a debugger to step into the crashed state of the application.

Also keep in mind that if you uae a stream for the font, the stream must be kept alive as long as you use the font.
« Last Edit: July 29, 2015, 08:49:10 pm by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Orfby

  • Newbie
  • *
  • Posts: 31
    • View Profile
Re: Segmentation Fault when drawing a sf::Text object in Lua
« Reply #2 on: July 29, 2015, 09:16:17 pm »
Create a minimal example from scratch or remove all unnecessary code till you end up with a minimal and complete example.
I can't really get any more minimal, since the error is most likely a problem with doing this stuff from lua (unless you mean remove the code to expose sf::Vector2u and such). If I gave any more minimal code (where lua isn't needed) then I wouldn't ever be able to create any sf::Text objects because I'd always get an error.

Then use a debugger to step into the crashed state of the application.
I already have debug output, but I'll assume you mean a debug of the new minimal example (which I can't do)

Also keep in mind that if you uae a stream for the font, the stream must be kept alive as long as you use the font.
I don't know what a stream exactly is, but all objects are alive because I can do almost the exact same code but with sf::Sprite and sf::Texture and I don't get an error.

dabbertorres

  • Hero Member
  • *****
  • Posts: 505
    • View Profile
    • website/blog
Re: Segmentation Fault when drawing a sf::Text object in Lua
« Reply #3 on: July 29, 2015, 11:18:55 pm »
Your issue is with C vs C++ compatibility.

You're using C++ code with lots of references, which C has no concept of. Lua is written in C, so it will only pass things by value or by pointer.

I haven't used LuaBridge myself, so I don't know what it does or doesn't do, but that's my bet on what your issue is.

I know I ran into it when I was writing my Lua binding. Hehe.

Orfby

  • Newbie
  • *
  • Posts: 31
    • View Profile
Re: Segmentation Fault when drawing a sf::Text object in Lua
« Reply #4 on: July 29, 2015, 11:41:55 pm »
You're using C++ code with lots of references, which C has no concept of. Lua is written in C, so it will only pass things by value or by pointer.
I thought I read that Lua has a weird system where an argument will be either passed by reference or by value depending on what you do with it in the function (but I can easily be wrong)

The problem with this is that, as I've mentioned before, if the issue is that the object isn't being passed properly, why don't I get a segmentation fault when I do the same with Textures and Sprites? (I'm not going to change the source code to include this though, because I want my code to be as minimal as possible)

I'm not sure if you're right though, so I guess I need to see what the difference is between sf::Text and sf::Sprite when I expose them

Orfby

  • Newbie
  • *
  • Posts: 31
    • View Profile
Re: Segmentation Fault when drawing a sf::Text object in Lua
« Reply #5 on: August 08, 2015, 11:52:52 am »
This topic is a little bit old but I have to apologise to dabbertorres for being too arrogant to test the solution he gave me. So yes, the problem was to do with references and pointers.

I fixed the code by changing:

void setFont(const sf::Font& newFont) {member.setFont(newFont);}

in TextWrapper, to:

void setFont(const sf::Font* newFont) {member.setFont(*newFont);}

Thank you for the help, and sorry for being too big headed (when I have no right to be). Of course that still doesn't explain why the same isn't true for SpriteWrapper, but I assume no one is going to come back to this question and answer it

dabbertorres

  • Hero Member
  • *****
  • Posts: 505
    • View Profile
    • website/blog
Re: [Solved] Segmentation Fault when drawing a sf::Text object in Lua
« Reply #6 on: August 08, 2015, 08:01:44 pm »
I actually meant to come back to this, but I must've forgotten, sorry about that.

I'm happy to hear you got it working though! Yes, it is odd that SpriteWrapper is working fine, but I'd need to see the implementation to tell. Feel free to reply with that and I'll try to give you an explanation.

Orfby

  • Newbie
  • *
  • Posts: 31
    • View Profile
Re: [Solved] Segmentation Fault when drawing a sf::Text object in Lua
« Reply #7 on: August 09, 2015, 09:35:23 am »
While trying to recreate the sf::Texture and sf::Sprite code I realised that it also needs a pointer argument, so I'm not sure why it worked/seemed like it worked. I do have another question though, would it be a good idea to not use references at all, and replace all functions that pass by reference with a function that passes by pointer. I have a feeling that the other functions that pass an argument by reference aren't actually passing by reference, but are passing by value and only the very strict classes (like sf::Sprite and sf::Text) are actually bringing up an error.
« Last Edit: August 09, 2015, 10:02:19 am by Orfby »

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: [Solved] Segmentation Fault when drawing a sf::Text object in Lua
« Reply #8 on: August 09, 2015, 10:13:07 am »
I personally dislike binding makers and just write all the code myself and I try to not do a 1-1 mappings (Lua and C++ are just too different for that IMO) but write stuff that makes sense.
« Last Edit: August 09, 2015, 10:15:53 am by FRex »
Back to C++ gamedev with SFML in May 2023

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: [Solved] Segmentation Fault when drawing a sf::Text object in Lua
« Reply #9 on: August 09, 2015, 10:31:38 am »
You shouldn't be satisfied with your current "solution". The documentation of LuaBridge clearly states that arguments passed by reference are managed correctly (the same way as pointer arguments). Regarding the "Lua is C, your code is C++" thing, this is really not relevant. LuaBridge is a C++ bridge, it is supposed to take care of the details, and according to its doc, it does.

One thing that may cause problems, is object lifetime. If you create an object (the font) in Lua code, it is managed by the Lua stack and will be garbage collected when the GC decides it is not used anymore. The problem is that Lua has no idea that the font is still referenced on C++ side (inside the sf::Text object), and will decide to kill it as soon as it is not used in Lua code. That may be your problem, although in this case, changing reference arguments to pointers should not fix anything :-\
Laurent Gomila - SFML developer

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: [Solved] Segmentation Fault when drawing a sf::Text object in Lua
« Reply #10 on: August 09, 2015, 11:50:50 am »
Quote
If you create an object (the font) in Lua code, it is managed by the Lua stack and will be garbage collected when the GC decides it is not used anymore.
Yes, GC is a problem, but the font is in one of registers or stored in a table field (globals are table fields too, of _G) somewhere, but not on a stack as it was in 4 and below, Lua stack is only where the things are stored for C, Lua itself uses register based VM since 5. Point of Lua Bridge is to not use the C+Lua stack yourself I guess. (Of course values on stack are kept alive too).

I'd answer a Lua question here but I don't know Lua Bridge so I try not to say anything. Maybe someone on gamedev will know if you ask there.
Lua also has lua_gc function that can stop GC or force it to run full cycle, which makes it easy to find errors caused by GC itself (as does call stack of a crash, that often has functions with 'cycle' or 'gc' in names).
« Last Edit: August 09, 2015, 11:52:55 am by FRex »
Back to C++ gamedev with SFML in May 2023