Fix crash in layered read path when truncate list is empty

XMLWordPrintableJSON

    • Type: Task
    • Resolution: Fixed
    • Priority: Major - P3
    • WT12.0.0, 9.0.0-rc0
    • Affects Version/s: None
    • Component/s: Truncate
    • Security Level: Public (Available to anyone on the web)
    • Storage Engines - Foundations
    • 1,578.009
    • SE Foundations - 2026-04-24
    • None

      Problem:

      On any follower-mode layered table scan where the in-memory truncate list is empty, __clayered_reposition_truncate_iterate in src/cursor/cur_layered.c dereferences an uninitialized WT_TRUNCATE *t, producing a WT_PANIC:

      WT_CURSOR.set_key: Key size (2615620845447383591) out of range: Invalid argument
      WT_CURSOR.next: the process must exit and restart: WT_PANIC
      

      Reproduces in test_layered38 and test_layered_fast_truncate04 (the cursor-scan tests added in WT-16811). Any scan on a layered cursor whose truncate list happens to be empty can hit it.

      Root cause:

      The caller uses the wrong variant of the NOTFOUND-OK macro:

      WT_RET_NOTFOUND_OK(__wt_truncate_delete_visible_check(...));
      if (ret == WT_NOTFOUND)
          break;
      

      WT_RET_NOTFOUND_OK is defined in terms of a local {}ret; it never writes to the enclosing ret. So when the visibility check returns WT_NOTFOUND (truncate queue empty or no entry covers the key), the outer ret is still 0, the if never triggers, and the loop body uses t which was never assigned by the callee.

      Fix:

      Capture the return value into ret directly and branch on it, propagating non-NOTFOUND errors explicitly:

      ret = __wt_truncate_delete_visible_check(...);
      if (ret == WT_NOTFOUND) {
          ret = 0;
          break;
      }
      WT_RET(ret);
      

            Assignee:
            Jie Chen
            Reporter:
            Jie Chen
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: