#!/usr/bin/env python3 import random import subprocess from runner import run_sql_parallel from sqlite_static_helper import * from stats import save_bug def is_crash(rc: int, _stderr: str) -> bool: # https://tldp.org/LDP/abs/html/exitcodes.html if rc > 128 and rc != 130: return True return False def is_unexpected_error(b_rc, _b_err, r_rc, _r_err, _sql): if b_rc != 0 and r_rc == 0: return True return False def is_valid_sql(r_rc: int, _r_err: str): if r_rc != 0: return False return True def check(buggy_bin: str, ref_bin: str, sql: str, with_flag: bool = False, save_bugs: bool = True) -> int: """ Returns: - `-1`: The query was not successfully executed on the reference binary, probably due to syntax issues - `0`: The query caused a logic bug, crash, or some other unexpected error. - `1`: The query was successfully executed on both binaries. """ flag = '' if not with_flag else random.choice(FLAGS) try: b_out, b_err, b_rc, r_out, r_err, r_rc = run_sql_parallel( buggy_bin, ref_bin, sql, flag) except subprocess.TimeoutExpired: return 0 except Exception: return -1 if not is_valid_sql(r_rc, r_err): return -1 # # Crash Detection if is_crash(b_rc, b_err) and not is_crash(r_rc, r_err): if save_bugs: save_bug(sql, 'crash', b_out, b_err, flag=flag) return 0 # # Unexpected Error Detection elif is_unexpected_error(b_rc, b_err, r_rc, r_err, sql): if save_bugs: save_bug(sql, 'unexpected_error', b_out, b_err, flag=flag) return 0 # # Logic Bug Detection elif b_rc == 0 and r_rc == 0 and b_out != r_out: if save_bugs: save_bug(sql, 'logic', b_out, b_err, r_out, flag=flag) return 0 return 1