oasisprotocol / oasisprotocol/oasis-core

nit: runtime.SetFinalizer as defense in depth for missing Close

Open
#2,146 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Go
Stars
369
Forks
151
Avg merge
1d 3h
Merged PRs (30d)
6

Description

Description of the bug

It is possible to create database references and forget to invoke Close before letting them become unreachable and we would not notice. Most of our code should be long running and probably never Close except in tests, etc, so this is probably an minor nit.

The NodeDB interface in go/storage/mkvs/urkel/db/api/api.go specifies that databases backing the Urkel tree use an interface that requires a call to Close before dropping the database reference. It is unclear whether the underlying databases already implement runtime.SetFinalizer based resource cleanup -- i.e., flush database buffers, closing file references if they don't use the standard File (which internally uses runtime.SetFinalizer to call (*file).close) -- so it may be a good idea to ensure that a missing Close can be detected reliably, e.g., have Close set a closed flag to enforce at-most-once semantics, and have the finalizer function check the flag to enforce at-least-once semantics, panicking (or some a severe log message) otherwise.

https://github.com/oasislabs/ekiden/blob/7a53454bae3ea5e2bdce17e23470b211f7a4c760/go/storage/mkvs/urkel/db/badger/badger.go#L719

Using runtime.SetFinalizer can be a little tricky, since runtime.KeepAlive will likely also be needed, which may make this add too much complexity to be worth it. (May require wrapping like File and file.) If we decide so, there should be a comment that this was considered and to stress the usage contract re the use of Close.

Steps to reproduce

  1. Create a leveldb or badger backed NodeDB.
  2. Let it go out of scope without calling Close on the object and then explicitly call runtime.GC()
  3. See that there is no error.

Expected behavior

Make it hard to write code that does not follow the Close contract.

Environment

  • OS:
  • Versions of relevant software and tools:

Additional information

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with go/storage/mkvs/urkel/db/api/api.go and the Close implementation around line 719 of go/storage/mkvs/urkel/db/badger/badger.go. Compare the leveldb and badger NodeDB implementations and investigate the runtime.SetFinalizer and runtime.KeepAlive requirements. Done means deciding whether finalizer-based detection is appropriate and, if so, enforcing the Close contract without unsafe resource handling.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
database
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.