STR-762: ast2text segfaults on large inputs
Certain large pretty-print tables and inputs can cause ast2text to segfault.
#0 0x00007f08c9db7799 in tableGet (tableindex=0x2186540, n=416) at hash.c:158Submitted on 20 December 2008 at 23:30
#1 0x00007f08c9db85e2 in ATtableGet (table=0x2186230, key=0x23ccf90) at hash.c:621
#2 0x00007f08ca278a74 in SSL_hashtable_get (table_term=0x23b2950, key=0x23ccf90)
#3 0x00007f08ca51255c in hashtable_get_0_1 (sl=0x0, z_251=0x23ccf90, t=0x21a02c0)
#4 0x00007f08caf6b5f9 in arg2abox_0_3 (sl=0x0, m_25=0x21a02c0, n_25=0x1e28600, o_25=0x23ccfb0,
t=0x21a02c0) at libstratego-gpp.c:3686
This problem was reported by Daniel Waddingon:
I have a .pp table and an ast which reproduces the problem on our latest and greatest SVN revisions.
The issue seems indeed to be a double free.
It also crops up in the same way when doing
ast2abox -p Cxx.pp -i breaks.dast -o fooz.abox:
#0 0x00007fa27f3f3151 in ATindexedSetGetIndex (hashset=0x27c1b70, elem=0x2a16ce0) at hash.c:472
#1 0x00007fa27f3f35bc in ATtableGet (table=0x27c1b70, key=0x2a16ce0) at hash.c:617
#2 0x00007fa27f8b3a74 in SSL_hashtable_get (table_term=0x29fc6a0, key=0x2a16ce0) at collection-hash-table-common.c:51
#3 0x00007fa27fb4d55c in hashtable_get_0_1 (sl=0x0, z_251=0x2a16ce0, t=0x27e9c58) at libstratego-lib-posix-xsi.c:37889
#4 0x00007fa2805a65f9 in arg2abox_0_3 (sl=0x0, m_25=0x27e9c58, n_25=0x2472628, o_25=0x2a16d00, t=0x27e9c58) at libstratego-gpp.c:3686
However, and this is where it gets a bit funky, this works:
ast2abox -p Cxx.pp -i breaks.dast > fooz.abox
I’m guessing the -o might cause some extra garbage collection to occur which is avoided in the stdout case.
I’ve tracked down the reason for the double free.
STRSGLR_open_parse_table() calls parse_table_to_term() which calls ATmakeBlob(). ATmakeBlob() is used to store the pointer to the parse table.
Later, STRSGLR_close_parse_table() calls SG_DiscardParseTable which calls SG_Free on the table pointer. However, in ast2text, the blob remains (in a hashtable) after the parse table has been closed, and it represents a dangling reference to a memory area which is now deallocated.
When the ATerm gc goes to work, a bit later and tries to free the blob, it will also try to free the pointer stored in the blob, resulting in a double free.
Some cryptic trace info:
calloc - parse-table.c:990 0x7f82a5e0cf88 (1, 120)
SG: SG_NewParseTable() - 0x7f82a5e0cf88
STR: STRSGLR_open_parse_table() - 0x7f82a5e0cf88
AT: ATmakeBlob(120, 0x7f82a5e0cf88)
free - parse-table.c:1128 0x7f82a5e0cf88
AT: free BlobData(0x7f82a5e0cf88) - 0x7f82a5f0e538
free - memory.c:983 0x7f82a5e0cf88
Committed a fix for this. The parse table is no longer freed unconditonally when the close-parse-table strategy is called. Instead, it’s added to a “to be destructed” list which is handled by the ATerm gc. This ensures that the memory is only freed once, and only when both the parse table has been closed and all refs to it have gone out of scope.
Log in to post comments