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,
char **pzErr
){
try {
if(argc != 4 || strlen(argv[3]) < 2) {
*pzErr = sqlite3_mprintf("must provide exactly one argument, the path to a parquet file");
return SQLITE_ERROR;
@ -100,6 +101,11 @@ static int parquetConnect(
*pzErr = sqlite3_mprintf(e.what());
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.
*/
static int parquetOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
try {
std::unique_ptr<sqlite3_vtab_cursor_parquet, void(*)(void*)> cursor(
(sqlite3_vtab_cursor_parquet*)sqlite3_malloc(sizeof(sqlite3_vtab_cursor_parquet)),
sqlite3_free);
@ -141,6 +148,11 @@ static int parquetOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
*ppCursor = (sqlite3_vtab_cursor*)cursor.release();
return SQLITE_OK;
} catch(std::bad_alloc& ba) {
return SQLITE_NOMEM;
} catch(std::exception& e) {
return SQLITE_ERROR;
}
}
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.
*/
static int parquetNext(sqlite3_vtab_cursor *cur){
try {
ParquetCursor* cursor = ((sqlite3_vtab_cursor_parquet*)cur)->cursor;
cursor->next();
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_...() */
int col /* Which column to return */
){
try {
ParquetCursor *cursor = ((sqlite3_vtab_cursor_parquet*)cur)->cursor;
cursor->ensureColumn(col);
@ -255,6 +274,11 @@ static int parquetColumn(
}
}
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,
sqlite3_value **argv
){
try {
ParquetCursor* cursor = ((sqlite3_vtab_cursor_parquet*)cur)->cursor;
sqlite3_index_info* indexInfo = (sqlite3_index_info*)idxStr;
@ -438,6 +463,11 @@ static int parquetFilter(
}
cursor->reset(constraints);
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_index_info *pIdxInfo
){
try {
#ifdef DEBUG
ParquetTable* table = ((sqlite3_vtab_parquet*)tab)->table;
@ -510,6 +541,11 @@ static int parquetBestIndex(
}
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
# 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() {
if [ ! -d libfailmalloc ]; then
@ -19,11 +22,16 @@ ensure_failmalloc() {
run_under_low_memory() {
start=$(date +%s%3N)
set +e
env LD_PRELOAD="$here"/libfailmalloc/.libs/libfailmalloc.so FAILMALLOC_PROBABILITY=0.00001 ./test-random &> results.bad_alloc
set -e
env LD_PRELOAD="$here"/libfailmalloc/.libs/libfailmalloc.so FAILMALLOC_PROBABILITY=0.00001 ./test-random >results.bad_alloc 2>&1
rv=$?
now=$(date +%s%3N)
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() {
@ -33,7 +41,7 @@ main() {
ensure_failmalloc
# 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
done
}