NationalSecurityAgency/ghidra · error · SQLException

Zero byte in SQL string

Error message

Zero byte in SQL string

What it means

`appendEscapedLiteral` walks a string char-by-char to build a safe SQL literal (doubling `\` and `'`). If it hits a NUL byte (`\0`) it throws SQLException immediately rather than escaping. NUL bytes can truncate strings in C-based drivers and corrupt SQL parsing, so they are rejected outright.

Source

Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/client/AbstractSQLFunctionDatabase.java:810

		else {
			newArray = new OptionalTable[1];
			newArray[0] = table;
		}
		optionaltables = newArray;
		return table;
	}

	/**
	 * 
	 * @param buf the string builder object
	 * @param str the string to parse
	 * @throws SQLException if there is a zero byte in the string
	 */
	public static void appendEscapedLiteral(StringBuilder buf, String str) throws SQLException {
		for (int i = 0; i < str.length(); ++i) {
			char ch = str.charAt(i);
			if (ch == '\0') {
				throw new SQLException("Zero byte in SQL string");
			}
			if (ch == '\\' || ch == '\'') {
				buf.append(ch);
			}
			buf.append(ch);
		}
	}

	/**
	 * Convert a low-level list of function rows into full FunctionDescription objects
	 * @param simres (optional -- may be null) generate a SimilarityNote for every function
	 * @param descvec is the list of low-level function rows
	 * @param vecres (optional -- may be null) vector result producing these functions
	 * @param res is the DescriptionManager holding the newly generated FunctionDescriptions
	 * @param srec (optional -- may be null) is a description object of the vector
	 * @throws SQLException is there is an error querying tables
	 * @throws LSHException for internal consistency errors
	 */

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Sanitize the offending string -- strip NUL bytes -- before passing it to BSim insert/query APIs.
  2. Identify which field carries the \0 (exe name vs function name vs metadata) from the call stack.
  3. Fix the upstream importer if it is emitting null bytes into name fields.

Example fix

// before
String name = rawFunctionName;            // may contain \0
// after
String name = rawFunctionName.replace("\0", "");
Defensive patterns

Strategy: validation

Validate before calling

// Reject any string carrying NUL before it reaches appendEscapedLiteral / insert.
static String sanitizeForSql(String s) {
    if (s == null) return s;
    if (s.indexOf('\0') >= 0)
        throw new IllegalArgumentException("NUL byte in value");
    return s;
}

Type guard

// isSafeForSqlLiteral: true iff the string can be escaped without error.
static boolean isSafeForSqlLiteral(String s) {
    return s != null && s.indexOf('\0') < 0;
}

Try / catch

try {
    db.insert(manager);
} catch (SQLException e) {
    if (e.getMessage().equals("Zero byte in SQL string")) {
        // bad input -- sanitize the offending name and retry, or skip the record
        throw new BadInputException("NUL byte in symbol/exe name", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Inserting or querying with a string field (function name, exe name, metadata) that contains an embedded `\0`. In Ghidra's reverse-engineering context, malformed or obfuscated binaries can yield symbol names carrying null bytes that leak through to the BSim ingest path.

Common situations: Importing analysis from corrupted/obfuscated binaries; binary data accidentally placed in a name field; reading non-UTF-8 or non-null-terminated buffers; symbol tables with embedded nulls.

Related errors


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/25e240f6fbdfb123. Report an issue: GitHub.