Skip to content

Commit 6712c9e

Browse files
committed
fix(func): no input, no output
An empty array made the Function API call TA-Lib with pointers one element before its buffers: check_begidx answers length - 1, which is -1, so the wrapper passed startIdx = endIdx = 0 and data + begidx. A function whose lookback is zero reads and writes that element. That is 34 functions at their default parameters, ACOS, ADD and OBV among them, plus any function whose parameters give a zero lookback, such as MA(x, timeperiod=1), through the Function, Abstract, pandas and polars paths alike. The heap corruption may abort the interpreter later, on an unrelated free, or go unnoticed. Stream opens are not affected; they raise InsufficientHistory first. When it started: 0.4.27, tagged 2023-07-13. Commit 02de3a3 ("don't throw exceptions on all nan input", CHANGELOG "[FIX]: Don't throw exceptions when inputs are all NaN") replaced check_begidx's `raise Exception("inputs are all NaN")` with `return length - 1`. An empty array takes that same branch, so until then it raised; since then it has reached TA-Lib with begidx -1. Every release since has it, through 0.8.0. Every wrapper now returns its outputs as empty arrays, before check_begidx, the lookback or TA-Lib are reached. Nothing else changes for an empty input: types, dtypes and tuple layout match the non-empty path, and for valid parameters the results are identical to before across func, the pandas and polars wrappers, and abstract with dict, pandas and polars DataFrame inputs, for all 201 functions. An invalid parameter on an empty input now returns empty outputs instead of TA_BAD_PARAM: there is nothing to compute. The test runs in a child process with the empty inputs right after an inaccessible page, so a read before the buffer faults at once. It fails on the previous code with SIGSEGV. It is skipped on Windows, where the guard would need VirtualProtect and no CI runs the tests. Claude-Session: https://claude.ai/code/session_01TuVjx2Q5urdmwi5opzfCp8
1 parent 1d30499 commit 6712c9e

5 files changed

Lines changed: 12323 additions & 7254 deletions

File tree

‎CHANGELOG‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@
2424
``real`` and ``integer``; they are ``supertrend`` and ``trend``, the names
2525
``abstract.Function('SUPERTREND').output_names`` already reported.
2626

27+
- [FIX]: An empty array given to a function whose lookback is zero, such as
28+
``talib.ACOS`` or ``talib.MA(x, timeperiod=1)``, made TA-Lib read and write
29+
one element outside the buffers, which could crash the interpreter later or
30+
corrupt memory silently. An empty input now returns empty outputs without
31+
calling TA-Lib, whatever the function and its parameters. The bug dates from
32+
0.4.27.
33+
2734
0.8.0
2835
=====
2936

0 commit comments

Comments
 (0)