Skip to content

std::vector element lifetime issue #385

@souk4711

Description

@souk4711

Case

  1. a c++ api returns an instance of std::vector
  2. a ruby function returns a reference to an element of the std::vector
  3. use the ruby function, the return value contains invalid data (and may cause a crash when the C++ side uses pointers)

Reproduce

c++ code

struct Point{
    int x() const { return m_x; }
    int y() const { return m_y; }

    int m_x, m_y;
};

extern "C" void Init_qtcore()
{
    return detail::cpp_protect([] {
        Class rb_cPoint = define_class<Point>("Point")
            .define_method("x", &Point::x)
            .define_method("y", &Point::y);

        define_global_function("get_point_list", []() -> std::vector<Point> {
            std::vector<Point> vec;
            vec.push_back(Point { 1, 2 });
            return vec;
        });
    });
}

ruby code

irb(main):001> GC.disable
=> false
irb(main):002* def find_element
irb(main):003*   get_point_list[0]
irb(main):004> end
=> :find_element
irb(main):005> e = find_element
=> #<Point:0x00007f351c366ed0>
irb(main):006> "(#{e.x}, #{e.y})"
=> "(1, 2)"

irb(main):007> GC.enable; GC.start # the point_list destroyed ?
=> nil
irb(main):008> "(#{e.x}, #{e.y})"  # invalid data
=> "(348141680, 21847)"

Fix

  • the point list should lives longer than the elements.
  • or return a copy of element ?
  • or add a note to the document std support, recommanding users use Point#dup when necessary ?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions