Possible reference leak of the argument tuple in `FunctionCall()`
まだ誰も着手していません。
- 主要言語
- Python
- スター
- 186
- フォーク
- 113
- 平均マージ
- 13時間 29分
- マージ済み PR(30日)
- 17
説明
### What happens?
`FunctionCall()` passes a newly created tuple directly to `PyObject_CallObject()`:
File: `src/map.cpp`
Function: `FunctionCall`
```cpp
auto *df_obj = PyObject_CallObject(function, PyTuple_Pack(1, in_df.ptr()));
```
`PyTuple_Pack()` returns a new reference, while `PyObject_CallObject()` does
not steal its `args` reference. Because the tuple is not stored in a local
variable, it is never passed to `Py_DECREF()`.
As a result, every invocation leaks one tuple. The tuple also owns a reference
to `in_df`, so the input pandas DataFrame remains alive after `FunctionCall()`
returns. This occurs on both successful and failed calls.
The function is used during bind-time schema inference and query execution, so
the leak is reachable through ordinary `DuckDBPyRelation.map()` operations.
The handling of `df_obj` is unrelated and correct:
```cpp
auto df = py::reinterpret_steal(df_obj);
```
`PyObject_CallObject()` returns a new reference on success, which
`reinterpret_steal()` adopts.
### To Reproduce
This issue can be confirmed directly from the reference ownership in
`src/map.cpp`.
In `FunctionCall()`, the argument tuple is created inline:
```cpp
auto *df_obj = PyObject_CallObject(function, PyTuple_Pack(1, in_df.ptr()));
```
According to the CPython C API reference ownership rules:
1. `PyTuple_Pack()` returns a new reference.
2. `PyObject_CallObject()` does not steal the reference passed as `args`.
3. The tuple pointer is not stored, so there is no subsequent
`Py_DECREF()` for that new reference.
4. The tuple therefore leaks on every call and retains its reference to
`in_df`.
This issue is specific to the Python API and is not reproducible through plain
SQL in the DuckDB CLI.
### OS:
x86_64
### DuckDB Package Version:
latest version
### Python Version:
3.12
### Full Name:
Ksx
### Affiliation:
SMU
### What is the latest build you tested with? If possible, we recommend testing with the latest nightly build.
I have not tested with any build
### Did you include all relevant data sets for reproducing the issue?
No - Other reason (please specify in the issue body)
### Did you include all code required to reproduce the issue?
- [ ] Yes, I have
### Did you include all relevant configuration to reproduce the issue?
- [ ] Yes, I have
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
src/map.cpp の FunctionCall から始め、PyTuple_Pack と PyObject_CallObject に関する CPython の所有権ルールを確認します。df_obj は既存の所有権処理を維持したまま、引数タプルが呼び出しの成功時と失敗時の両方で解放されることを確認します。繰り返し DuckDBPyRelation.map() を呼び出しても、タプルがリークしたり入力 DataFrame が保持されたりしなくなれば完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- cpp, pandas, python
- 領域
- api
- issue の種類
- バグ
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 活発さ
- 静か
- 明瞭さ
- 明確に書かれている
- 初心者へのやさしさ
- 76/100