Hinted node IDs are not bounded in $_internalJoinHint

    • Type: Bug
    • Resolution: Unresolved
    • Priority: Major - P3
    • None
    • Affects Version/s: None
    • Component/s: None
    • Query Optimization
    • ALL
    • Hide
      /**
       * Reproduces a join hint parser tassert from a node id that is accepted as a non-negative int32 but
       * is outside the join optimizer NodeSet bitset range.
       *
       * @tags: [
       *   requires_fcv_90,
       *   requires_sbe,
       * ]
       */
      
      TestData.cleanUpCoreDumpsFromExpectedCrash = true;
      const conn = MongoRunner.runMongod({
          useLogFiles: false,
          setParameter: {
              featureFlagPathArrayness: true,
              internalEnableJoinOptimization: true,
              internalJoinReorderMode: "bottomUp",
          },
      });
      assert(conn);
      const db = conn.getDB(jsTestName());
      const base = db.base;
      const foreign = db.foreign;
      assert.commandWorked(base.insert({x: 1}));
      assert.commandWorked(foreign.insert({y: 1}));
      assert.commandWorked(base.createIndex({x: 1}));
      assert.commandWorked(foreign.createIndex({y: 1}));
      
      // WILL FAIL: std::out_of_range
      assert.commandWorked(
          db.runCommand({
              aggregate: base.getName(),
              pipeline: [
                  {
                      $_internalJoinHint: {
                          perSubsetLevelMode: [{level: NumberInt(0), mode: "CHEAPEST", hint: {node: NumberInt(64)}}],
                      },
                  },
                  {$lookup: {from: foreign.getName(), localField: "x", foreignField: "y", as: "joined"}},
                  {$unwind: "$joined"},
              ],
              cursor: {},
          }),
      );
      
      MongoRunner.stopMongod(conn, null, {allowedExitCode: MongoRunner.EXIT_ABORT});
       
      Show
      /**  * Reproduces a join hint parser tassert from a node id that is accepted as a non-negative int32 but  * is outside the join optimizer NodeSet bitset range.  *  * @tags: [  *   requires_fcv_90,  *   requires_sbe,  * ]  */ TestData.cleanUpCoreDumpsFromExpectedCrash = true ; const conn = MongoRunner.runMongod({     useLogFiles: false ,     setParameter: {         featureFlagPathArrayness: true ,         internalEnableJoinOptimization: true ,         internalJoinReorderMode: "bottomUp" ,     }, }); assert (conn); const db = conn.getDB(jsTestName()); const base = db.base; const foreign = db.foreign; assert .commandWorked(base.insert({x: 1})); assert .commandWorked(foreign.insert({y: 1})); assert .commandWorked(base.createIndex({x: 1})); assert .commandWorked(foreign.createIndex({y: 1})); // WILL FAIL: std::out_of_range assert .commandWorked(     db.runCommand({         aggregate: base.getName(),         pipeline: [             {                 $_internalJoinHint: {                     perSubsetLevelMode: [{level: NumberInt(0), mode: "CHEAPEST" , hint: {node: NumberInt(64)}}],                 },             },             {$lookup: {from: foreign.getName(), localField: "x" , foreignField: "y" , as: "joined" }},             {$unwind: "$joined" },         ],         cursor: {},     }), ); MongoRunner.stopMongod(conn, null , {allowedExitCode: MongoRunner.EXIT_ABORT});
    • None
    • None
    • None
    • None
    • None
    • None
    • None

      Parser robustness bug: hinted node ids are not bounded to NodeSet<64>JoinHint::fromBSON() only checks non-negative int32. isEnumerationModeValid() calls seenNodes.set(modes[i].baseNode()). A user hint with node: NumberInt(64) can throw std::out_of_range from std::bitset::set.

            Assignee:
            Unassigned
            Reporter:
            Max Verbinnen
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated: