[CXX-1668] Driver reads array elements less than two incorrectly. Created: 14/Oct/18  Updated: 27/Oct/23  Resolved: 25/Oct/18

Status: Closed
Project: C++ Driver
Component/s: API, Implementation
Affects Version/s: 3.3.1
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Torgaeva Kseniya [X] Assignee: A. Jesse Jiryu Davis
Resolution: Works as Designed Votes: 0
Labels: Bug
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Linux Fedora 28 64-bit,
Processor: Intel® Core™ i5-7300HQ CPU @ 2.50GHz × 4.
C driver 1.11.0(debug) also this problem was replicated with version 1.13.0(debug) (manually installed)


Backwards Compatibility: Fully Compatible

 Description   

Hello, Dear developers!

Driver reads array elements less than two incorrectly.

1. I have this code (which selects array of TEST_CASES from collection):

auto collectionName = CollectionCnst::VARIANT;
auto collection = db.collection(collectionName);
auto doc = bsoncxx::v_noabi::builder::basic::document{};
doc = bsoncxx::v_noabi::builder::basic::document{};
doc.append(kvp(ID, bsoncxx::oid(ourVariantId)));
auto cursor = collection.find_one({doc});
if (cursor->view().length() == 0) {
   // not found
   throw std::exception();
}
// select testCase's
auto testCases = cursor->view()[FieldCnst::TEST_CASES].get_array();
return testCases.value;

2. I want to iterate through it (foreach loop):

for (auto &testCase: testCases) {

  // do smth

}

3. If I have 1 element in collection, loop don't invokes no one time. If I have two elements, it invokes 1 time. If I have three or more array elements, it invokes exactly through all elements.



 Comments   
Comment by Torgaeva Kseniya [X] [ 15/Oct/18 ]

Yes, I've returned a bsoncxx::array::view from function (bsoncxx::array::value HandleLoadSolution::getTestCases(mongocxx::database db, string ourVariantId) {...}).

Your code works correctly. Thank you!

Comment by A. Jesse Jiryu Davis [ 14/Oct/18 ]

Hi, can I see the complete function, including the declaration with return type, of the function you describe in part 1? My guess is that "return testCases.value" is returning a temporary value that is not valid after the function returns. You're experiencing undefined behavior in C++, not a mongocxx bug.

Do "for (auto &testCase: testCases) { ... }" in the same scope as the cursor or else copy the the data before the cursor goes out of scope. Once the cursor is out of scope, then any data retrieved from the cursor is invalid.

One way to fix this is to return a value, not a view:

using bsoncxx::builder::basic::kvp;
using bsoncxx::builder::basic::make_array;
using bsoncxx::builder::basic::make_document;
 
bsoncxx::array::value getTestCases(mongocxx::database db) {
    auto collectionName = "collection";
    auto collection = db.collection(collectionName);
    auto doc = bsoncxx::v_noabi::builder::basic::document{};
    doc = bsoncxx::v_noabi::builder::basic::document{};
    doc.append(kvp("_id", 1));
    /* by the way, this is NOT a cursor, it's a document */
    auto result = collection.find_one({doc});
    if (result->view().length() == 0) {
        // not found
        throw std::exception();
    }
    // select testCase's
    auto testCases = result->view()["testCases"];
    return bsoncxx::array::value(testCases.get_array());
}
 
 
int main(int, char**) {
    mongocxx::instance inst{};
    mongocxx::client conn{mongocxx::uri{}};
 
    auto db = conn["test"];
    auto testCases = getTestCases(db);
 
    for (auto &testCase: testCases.view()) {
        std::cout << bsoncxx::to_json(testCase.get_document()) << std::endl;
    }
}

Generated at Wed Feb 07 22:03:31 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.