#Stuck at segmentation fault from using unique_ptr in mariadb

58 messages · Page 1 of 1 (latest)

frigid furnace
#

main.cpp

int main(int argc, char **argv) {
    if (argc == 1) {
        std::cout << "Please provide an argument.\n";
    }
    else {
        try {
            sql::Driver* driver = sql::mariadb::get_driver_instance();
            sql::SQLString url("jdbc://localhost:3306/logx_test");
            sql::Properties properties({{"user", "logx_online"}, {"password", "testuser123"}});
            std::unique_ptr<sql::Connection> conn(driver -> connect(url, properties));

            if (!strcmp(argv[1], "addItem")) {
                if (argc != 7) {
                    std::cout << "Invalid arguments.";
                    return 1;
                }
                Item item;
                item.ItemName = argv[2];
                addItem(conn, item);
            }
            conn -> close();
        }
        catch (sql::SQLException &e) {

        }
    }
    return 0;
}

data_storage.cpp

void addItem(std::unique_ptr<sql::Connection> &conn, Item item) {
    try {
        std::unique_ptr<sql::PreparedStatement> stmnt(conn -> prepareStatement("insert into item (name, type, size, unit, qty) values (?, ?, ?, ?, ?)"));

        stmnt -> setString(1, item.ItemName);
        stmnt -> setString(2, item.ItemType);
        stmnt -> setString(3, item.ItemSize);
        stmnt -> setString(4, item.ItemUnit);
        stmnt -> setInt(5, item.ItemQty);

        stmnt -> executeQuery();

    }
    catch (sql::SQLException &e) {
        std::cerr << "Error adding new item: " << e.what() << std::endl;
    }
}

This programs compiles but when run generate segmentation fault

Here's screenshot using gdb and vscode

sick craneBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

midnight pelican
#

!howto format

sick craneBOT
midnight pelican
#

Stupid NSA edition

#

Markup

```cpp
int main() {}
```

Result

int main() {}
frigid furnace
#

Sorry, I've edited it

midnight pelican
#

In theory you look up what sql::Driver::connect returns and then it tells you how to get rid of the connection, which happens to not be delete which is what std::unique_ptr defaults to.

#

In practice I can't find the documentation -.-

#

I'm 90% sure it'll say something like "Use sql::Driver::disconnect to destroy a connection" and then you do that and then it works.

#

Wait, it's about prepared statements, not connections, but same approach.

frigid furnace
#

So i've been following from official mariadb github page https://github.com/mariadb-developers/todo-app-cpp/blob/main/tasks.cpp

I try to compile and run on my computer no segmentation error

The only different from that github page its that i move function into different .cpp file

GitHub

A simple C++ application to demonstrate create-read-update-delete (CRUD) operations on a target MariaDB database using MariaDB's C++ connector. - mariadb-developers/todo-app-cpp

midnight pelican
#

Hmm, seems like I guessed wrong.

#

Check the value of conn in addItem. Maybe it has become invalid somehow.

frigid furnace
#

I check using vscode debug that conn in main.cpp has some value but in data_storage.cpp conn become null

midnight pelican
#

Nice, at least narrowed it down.

#

One small-ish issue I see is that you should generally not make references of smart pointers. Either pass the smart pointer by value or pass a reference or raw pointer to the underlying value.

frigid furnace
#

Sorry, but how to do that, i'm not really understand about pointer

midnight pelican
#

Currently you have void addItem(std::unique_ptr<sql::Connection> &conn, Item item). That is a reference to a unique_ptr. That is generally not good.

#

If you wanted to pass ownership of the connections you'd do void addItem(std::unique_ptr<sql::Connection> conn, Item item).

#

But actually you don't want to pass ownership, you just want to use the connection. So
void addItem(sql::Connection &conn, Item item) would be the correct way to pass it.

#

If you do that everywhere you should find the place where you're accidentally passing ownership away.

frigid furnace
#

Ok, thank, still segmentation fault gives me headache

sweet ocean
#

@frigid furnace To pass ownership to another pointer , you should write std::move(conn) at time of calling additem

frigid furnace
#

I've set two breakpoints in main.cpp when creation of conn it has some value, but when passing to addItem it already null

sweet ocean
#

@frigid furnace As i said, if you don't write std:: move (conn) it will not pass ownership that's why your conn will be null in function

midnight pelican
#

The current code passes std::unique_ptr<sql::Connection> &conn which neither passes ownership, nor means it's a null pointer.

frigid furnace
#

So what should i do now?

#

It is possible for platform specific error?

frigid furnace
#

So it should like addItem(std::move(conn), item) ?

sweet ocean
#

yes

sweet ocean
frigid furnace
#

Still segmentation fault

sweet ocean
#

same place?

frigid furnace
#

Yes, segmentation fault on addItem std::unique_ptr<sql::PreparedStatement> stmnt(conn -> prepareStatement(".."));

sweet ocean
#

Anyway as @midnight pelican said, you need to remove unique_ptr here, because you are using conn for closing connection after calling function, but if you will transfer ownership of conn in function, it will be destroyed and you will not able to use it later

midnight pelican
# frigid furnace So it should like `addItem(std::move(conn), item)` ?

That doesn't help. First, as you figured out, conn is already nullptr at this point, so no matter what you do it's too late. Second, this would give addItem ownership over the connection and then immediately close it through destructing the connection which is most likely not what you want.

frigid furnace
#

Maybe it is because connection to the database failed? Its like conn already destroyed just after its get value

midnight pelican
#

Didn't you see it have a proper value at some point?

#

Maybe add a bunch of assert(conn); everywhere to find the spot where it becomes nullptr.

#

By "everywhere" I mean everywhere where conn is supposed to be valid.

frigid furnace
#

I already test using breakpoint, on first line std::unique_ptr<sql::Connection> conn(driver -> connect(url, properties)); it has some value, on second line just after its creation, conn already null

midnight pelican
#

That probably means the connection has never been successfully created.

#

The current line is the line that has not been executed yet.

#

If that line is the current line, the debugger shows you some garbage memory.

#

Then it gets properly initialized with the actual data, which apparently is nullptr.

#

So you need to find out why driver->connect failed. Maybe it just didn't fine the url or something. See if there is a way to get at error messages on failures.

frigid furnace
#

Ok I'll try that, thanks

midnight pelican
#

They really don't have any documentation, do they?

#

You're just supposed to look at the tasks.cpp and hope you figure it out.

sick craneBOT
#

@frigid furnace Has your question been resolved? If so, type !solved :)

midnight pelican
#

I gave up finding anything on their site.

#

I think I briefly saw demo applications where you can connect via commandline tools.

#

You might be able to use those to test if the url and parameters are valid.

sick craneBOT
#

This question is being automatically marked as stale.
If your question has been answered, type !solved.
If your question is not answered feel free to bump the post or re-ask.
Take a look at !howto ask for tips on improving your question.

frigid furnace
#

Thank you @midnight pelican @sweet ocean this question is now solved.

The problem was indeed the connection to the database, i solved it by reinstall mariadb

#

!solved