Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

*ttl drivers: TTL branch dereferences delete() result without a nil check, killing the fiber

オープン
#264 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
76/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
lua
領域
backend

調査の方向性

Start with the TTL branches in queue/abstract/driver/fifottl.lua and utubettl.lua at the referenced lines, then read the delete implementation around fifottl.lua#L334-L342 and compare the handling in subqueuettl from #259. Verify the chosen fix for a task deleted between selection and deletion, including vinyl and MVCC cases, and ensure TTL processing continues instead of the fiber dying.

索引モデルが issue の本文から書いたものです。

説明

Environment: queue master (07fd732), also 1.5.0. Found by code review while porting the subqueuettl driver (#259), which copies the same loop.

Summary

In the TTL branch of the fiber iteration the result of delete() is dereferenced unconditionally:

-- fifottl.lua#L113-L117, same in utubettl.lua#L243 and #L521
task = self.space.index.watch:min{ task_state }
if task ~= nil and task[i_status] == task_state then
    if now >= task[i_next_event] then
        task = self:delete(task[i_id]):transform(2, 1, state.DONE)
        self:on_task_change(task, 'ttl')

but method.delete() returns nil when the task is already gone (fifottl.lua#L334-L342), so a task that disappears between min() and delete() produces attempt to index a nil value, the fiber dies, and TTL processing stops for good (see #263). The delayed and TTR branches tolerate a nil from update() because abstract.lua ignores on_task_change(nil, ...); only the TTL branch does not.

When it is reachable

  • memtx without MVCC: not reachable, there is no yield between min() and get(); I could not reproduce it there.
  • vinyl (fifottl supports engine = 'vinyl'): reads may yield on disk I/O, so a concurrent ack()/delete() of the same expired task between min() and delete() hits it.
  • memtx with MVCC: delete() may also raise Transaction has been aborted by conflict with a concurrent write on the same task, which kills the fiber the same way.

Suggested fix

Either guard the result:

task = self:delete(task[i_id])
if task ~= nil then
    self:on_task_change(task, 'ttl')
end

or do min() + delete() inside one box.atomic() so the selection and the delete see the same state. The subqueuettl driver in #259 does the former for the fork we run.

主要言語
Lua
スター
244
フォーク
56
平均マージ
6日 8時間
マージ済み PR(30日)
1

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

tarantool/queue のほかの issue

tarantool/queue の issue をすべて見る

似ている issue

Lua の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。