jakethaw / pivot_vtab

SQLite3 pivot virtual table
MIT License
29 stars 1 forks source link

sqlite3 aborted: free(): double free detected in tcache 2 #7

Open rwaldura opened 1 year ago

rwaldura commented 1 year ago

Terminal failure on simple example pulled from https://antonz.org/sqlite-pivot-table/. Am I doing it wrong?

% curl -o pivot_vtab.c https://raw.githubusercontent.com/jakethaw/pivot_vtab/main/pivot_vtab.c

% gcc -g -fPIC -shared pivot_vtab.c -o pivot_vtab.so

% curl https://antonz.org/sqlite-pivot-table/sales.sql | sqlite3 test.db    

% sqlite3 test.db
SQLite version 3.27.2 2019-02-25 16:06:06
sqlite> select * from sales;
product     year        income    
----------  ----------  ----------
alpha       2020        100       
alpha       2021        120       
alpha       2022        130       
alpha       2023        140       
beta        2020        10        
beta        2021        20        
beta        2022        40        
beta        2023        80        
gamma       2020        80        
gamma       2021        75        
gamma       2022        78        
gamma       2023        80        
sqlite> .load ./pivot_vtab
sqlite> create virtual table v_sales using pivot_vtab (
   ...>   -- rows
   ...>   (select distinct product from sales),
   ...>   -- columns
   ...>   (select distinct year, year from sales),
   ...>   -- cells
   ...>   (select sum(income) from sales where product = ?1 and year = ?2)
   ...> );
sqlite> select * from v_sales;
product     2020        2021        2022        2023      
----------  ----------  ----------  ----------  ----------
alpha       100         120         130         140       
beta        10          20          40          80        
gamma       80          75          78          80        
free(): double free detected in tcache 2
[1]  + 13136 abort      sqlite3 test.db

% uname -a
Linux xxx 4.19.94-ti-r73 #1buster SMP PREEMPT Fri Apr 15 21:38:30 UTC 2022 armv7l GNU/Linux
rwaldura commented 1 year ago

Same issue with the sample provided.

%  sqlite3 test2.db
SQLite version 3.27.2 2019-02-25 16:06:06
sqlite> .load ./pivot_vtab
sqlite> CREATE TABLE r AS
   ...> SELECT 1 id UNION SELECT 2 UNION SELECT 3;
sqlite> CREATE TABLE c(
   ...>   id   INTEGER PRIMARY KEY,
   ...>   name TEXT
   ...> );
sqlite> INSERT INTO c (name) VALUES
   ...> ('a'),('b'),('c'),('d');
sqlite> CREATE TABLE x(
   ...>   r_id INT,
   ...>   c_id INT,
   ...>   val  TEXT
   ...> );
sqlite> INSERT INTO x (r_id, c_id, val)
   ...> SELECT r.id, c.id, c.name || r.id
   ...>   FROM c, r;
sqlite> CREATE VIRTUAL TABLE pivot USING pivot_vtab(
   ...> (SELECT id r_id -- pivot table key
   ...>     FROM r),
   ...>  (SELECT id c_id,   -- pivot column key - can be referenced in pivot query as ?2
   ...>          name       -- pivot column name
   ...>     FROM c),
   ...> (SELECT val
   ...>     FROM x 
   ...>    WHERE r_id = ?1
   ...>      AND c_id = ?2)
   ...> );
sqlite> SELECT *
   ...>   FROM pivot;
r_id  a      b      c      d    
----  -----  -----  -----  -----
1     a1     b1     c1     d1   
2     a2     b2     c2     d2   
3     a3     b3     c3     d3   
free(): double free detected in tcache 2
[1]    16982 abort      sqlite3 test2.db
rwaldura commented 1 year ago

Line 479 appears to trigger the error: freeing the pivot key.

% gdb sqlite3
...
sqlite> .load ./pivot_vtab
sqlite> select * from pivot;
r_id        a           b           c           d         
----------  ----------  ----------  ----------  ----------
1           a1          b1          c1          d1        
2           a2          b2          c2          d2        
3           a3          b3          c3          d3        

Breakpoint 1, pivotClose (pCur=0x51e1a0) at pivot_vtab.c:472
472   pivot_vtab *tab = (pivot_vtab*)pCur->pVtab;
(gdb) n
473   pivot_cursor *cur = (pivot_cursor*)pCur;
(gdb) 
476   if( cur->pivot_key ){
(gdb) 
477     for( i=0; inRow_cols; i++ )
(gdb) 
478       sqlite3_value_free(cur->pivot_key[i]);
(gdb) print i
$1 = 0
(gdb) p cur->pivot_key[i]
$2 = (sqlite3_value *) 0x0
(gdb) p tab->nRow_cols
$3 = 1
(gdb) p cur->pivot_key
$4 = (sqlite3_value **) 0x519c28
(gdb) n
477     for( i=0; inRow_cols; i++ )
(gdb) n
479     sqlite3_free(cur->pivot_key);
(gdb) p cur->pivot_key
$5 = (sqlite3_value **) 0x519c28
(gdb) n
free(): double free detected in tcache 2

Program received signal SIGABRT, Aborted.
rwaldura commented 1 year ago

Commenting out line 479 appears to fix it... but it hardly seems satisfying. Let me know if there's a better fix, thanks!