don't segfault on low memory

Fixes #8
This commit is contained in:
Colin Dellow 2018-03-24 12:48:29 -04:00
parent 6fa7bc3d0b
commit 51d0f27a68
2 changed files with 233 additions and 189 deletions

View File

@ -72,6 +72,7 @@ static int parquetConnect(
sqlite3_vtab **ppVtab, sqlite3_vtab **ppVtab,
char **pzErr char **pzErr
){ ){
try {
if(argc != 4 || strlen(argv[3]) < 2) { if(argc != 4 || strlen(argv[3]) < 2) {
*pzErr = sqlite3_mprintf("must provide exactly one argument, the path to a parquet file"); *pzErr = sqlite3_mprintf("must provide exactly one argument, the path to a parquet file");
return SQLITE_ERROR; return SQLITE_ERROR;
@ -100,6 +101,11 @@ static int parquetConnect(
*pzErr = sqlite3_mprintf(e.what()); *pzErr = sqlite3_mprintf(e.what());
return SQLITE_ERROR; return SQLITE_ERROR;
} }
} catch(std::bad_alloc& ba) {
return SQLITE_NOMEM;
} catch(std::exception& e) {
return SQLITE_ERROR;
}
} }
/* /*
@ -131,6 +137,7 @@ static int parquetClose(sqlite3_vtab_cursor *cur){
** Constructor for a new sqlite3_vtab_parquet cursor object. ** Constructor for a new sqlite3_vtab_parquet cursor object.
*/ */
static int parquetOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ static int parquetOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
try {
std::unique_ptr<sqlite3_vtab_cursor_parquet, void(*)(void*)> cursor( std::unique_ptr<sqlite3_vtab_cursor_parquet, void(*)(void*)> cursor(
(sqlite3_vtab_cursor_parquet*)sqlite3_malloc(sizeof(sqlite3_vtab_cursor_parquet)), (sqlite3_vtab_cursor_parquet*)sqlite3_malloc(sizeof(sqlite3_vtab_cursor_parquet)),
sqlite3_free); sqlite3_free);
@ -141,6 +148,11 @@ static int parquetOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
*ppCursor = (sqlite3_vtab_cursor*)cursor.release(); *ppCursor = (sqlite3_vtab_cursor*)cursor.release();
return SQLITE_OK; return SQLITE_OK;
} catch(std::bad_alloc& ba) {
return SQLITE_NOMEM;
} catch(std::exception& e) {
return SQLITE_ERROR;
}
} }
const char* opName(int op) { const char* opName(int op) {
@ -183,9 +195,15 @@ const char* opName(int op) {
** Set the EOF marker if we reach the end of input. ** Set the EOF marker if we reach the end of input.
*/ */
static int parquetNext(sqlite3_vtab_cursor *cur){ static int parquetNext(sqlite3_vtab_cursor *cur){
try {
ParquetCursor* cursor = ((sqlite3_vtab_cursor_parquet*)cur)->cursor; ParquetCursor* cursor = ((sqlite3_vtab_cursor_parquet*)cur)->cursor;
cursor->next(); cursor->next();
return SQLITE_OK; return SQLITE_OK;
} catch(std::bad_alloc& ba) {
return SQLITE_NOMEM;
} catch(std::exception& e) {
return SQLITE_ERROR;
}
} }
/* /*
@ -197,6 +215,7 @@ static int parquetColumn(
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
int col /* Which column to return */ int col /* Which column to return */
){ ){
try {
ParquetCursor *cursor = ((sqlite3_vtab_cursor_parquet*)cur)->cursor; ParquetCursor *cursor = ((sqlite3_vtab_cursor_parquet*)cur)->cursor;
cursor->ensureColumn(col); cursor->ensureColumn(col);
@ -255,6 +274,11 @@ static int parquetColumn(
} }
} }
return SQLITE_OK; return SQLITE_OK;
} catch(std::bad_alloc& ba) {
return SQLITE_NOMEM;
} catch(std::exception& e) {
return SQLITE_ERROR;
}
} }
/* /*
@ -382,6 +406,7 @@ static int parquetFilter(
int argc, int argc,
sqlite3_value **argv sqlite3_value **argv
){ ){
try {
ParquetCursor* cursor = ((sqlite3_vtab_cursor_parquet*)cur)->cursor; ParquetCursor* cursor = ((sqlite3_vtab_cursor_parquet*)cur)->cursor;
sqlite3_index_info* indexInfo = (sqlite3_index_info*)idxStr; sqlite3_index_info* indexInfo = (sqlite3_index_info*)idxStr;
@ -438,6 +463,11 @@ static int parquetFilter(
} }
cursor->reset(constraints); cursor->reset(constraints);
return parquetNext(cur); return parquetNext(cur);
} catch(std::bad_alloc& ba) {
return SQLITE_NOMEM;
} catch(std::exception& e) {
return SQLITE_ERROR;
}
} }
/* /*
@ -450,6 +480,7 @@ static int parquetBestIndex(
sqlite3_vtab *tab, sqlite3_vtab *tab,
sqlite3_index_info *pIdxInfo sqlite3_index_info *pIdxInfo
){ ){
try {
#ifdef DEBUG #ifdef DEBUG
ParquetTable* table = ((sqlite3_vtab_parquet*)tab)->table; ParquetTable* table = ((sqlite3_vtab_parquet*)tab)->table;
@ -510,6 +541,11 @@ static int parquetBestIndex(
} }
return SQLITE_OK; return SQLITE_OK;
} catch(std::bad_alloc& ba) {
return SQLITE_NOMEM;
} catch(std::exception& e) {
return SQLITE_ERROR;
}
} }

View File

@ -3,6 +3,9 @@ set -euo pipefail
# A harness that runs SQLite with the parquet extension in an environment where malloc randomly # A harness that runs SQLite with the parquet extension in an environment where malloc randomly
# fails. "Success" is if the logs don't have any C++ exceptions that talk about std::bad_alloc # fails. "Success" is if the logs don't have any C++ exceptions that talk about std::bad_alloc
#
# The results can need a bit of interpretation; look at the log and see if it sniffs like
# the segfault came from Python or SQLite.
ensure_failmalloc() { ensure_failmalloc() {
if [ ! -d libfailmalloc ]; then if [ ! -d libfailmalloc ]; then
@ -19,11 +22,16 @@ ensure_failmalloc() {
run_under_low_memory() { run_under_low_memory() {
start=$(date +%s%3N) start=$(date +%s%3N)
set +e set +e
env LD_PRELOAD="$here"/libfailmalloc/.libs/libfailmalloc.so FAILMALLOC_PROBABILITY=0.00001 ./test-random &> results.bad_alloc env LD_PRELOAD="$here"/libfailmalloc/.libs/libfailmalloc.so FAILMALLOC_PROBABILITY=0.00001 ./test-random >results.bad_alloc 2>&1
set -e rv=$?
now=$(date +%s%3N) now=$(date +%s%3N)
echo "Bailed after $((now-start)) ms" echo "Bailed after $((now-start)) ms"
! grep std::bad_alloc results.bad_alloc set -e
if [ "$rv" -gt 127 ]; then
cat results.bad_alloc
echo "Segfaulted with exit code: $rv"
exit 1
fi
} }
main() { main() {
@ -33,7 +41,7 @@ main() {
ensure_failmalloc ensure_failmalloc
# Sometimes we'll exit due to a Python memory issue, so try a few times. # Sometimes we'll exit due to a Python memory issue, so try a few times.
for i in {0..10}; do for i in {0..100}; do
run_under_low_memory run_under_low_memory
done done
} }