{"record":{"id":"f81a9d485cd81b2b","repo":"dmtrKovalenko/fff","slug":"query-is-null-or-invalid-utf-8","errorCode":null,"errorMessage":"Query is null or invalid UTF-8","messagePattern":"Query is null or invalid UTF-8","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/fff-c/src/lib.rs","lineNumber":353,"sourceCode":"#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn fff_search(\n    fff_handle: *mut c_void,\n    query: *const c_char,\n    current_file: *const c_char,\n    max_threads: u32,\n    page_index: u32,\n    page_size: u32,\n    combo_boost_multiplier: i32,\n    min_combo_count: u32,\n) -> *mut FffResult {\n    let inst = match unsafe { instance_ref(fff_handle) } {\n        Ok(i) => i,\n        Err(e) => return e,\n    };\n\n    let query_str = match unsafe { cstr_to_str(query) } {\n        Some(s) => s,\n        None => return FffResult::err(\"Query is null or invalid UTF-8\"),\n    };\n\n    let current_file_str = unsafe { optional_cstr(current_file) };\n    let page_size = default_u32(page_size, 100) as usize;\n    let min_combo_count = default_u32(min_combo_count, 3);\n    let combo_boost_multiplier = default_i32(combo_boost_multiplier, 100);\n\n    let picker_guard = match inst.picker.read() {\n        Ok(g) => g,\n        Err(e) => return FffResult::err(&format!(\"Failed to acquire file picker lock: {}\", e)),\n    };\n\n    let picker = match picker_guard.as_ref() {\n        Some(p) => p,\n        None => {\n            return FffResult::err(\"File picker not initialized. Call fff_create_instance first.\");\n        }\n    };","sourceCodeStart":335,"sourceCodeEnd":371,"githubUrl":"https://github.com/dmtrKovalenko/fff/blob/7f8537e70f0ea1210f9acbbfc4640141105cdc78/crates/fff-c/src/lib.rs#L335-L371","documentation":"fff_search validates its query argument with cstr_to_str, which returns None when the pointer is NULL or the bytes are not valid UTF-8. The library refuses to search with an unusable query string and returns an error FffResult instead of panicking across the FFI boundary.","triggerScenarios":"Calling fff_search with query = NULL, a pointer to an empty/uninitialized buffer, a non-NUL-terminated C string, or bytes encoded in a non-UTF-8 locale (e.g. Latin-1 file names).","commonSituations":"Lua/C callers passing an uninitialized string buffer; passing strings containing invalid byte sequences from non-UTF-8 filenames; forgetting to NUL-terminate a manually built C string; passing nil/NULL because an earlier call failed and the query variable was never set.","solutions":["Ensure the query is a valid, NUL-terminated, UTF-8 encoded C string before calling.","Check for NULL before invoking; skip the search if the query is absent.","If input may be non-UTF-8, sanitize with String::from_utf8_lossy or equivalent before passing it.","Verify the caller's string lifetime — the buffer must stay valid for the duration of the call."],"exampleFix":"// before: possibly-uninitialized buffer\nconst char *query = NULL;\nfff_search(inst, query, ...); // error\n// after: guarantee a valid UTF-8 C string\nconst char *query = user_query ? user_query : \"\";\nfff_search(inst, query, ...);","handlingStrategy":"validation","validationCode":"if query == nil or not query:match('^[%w%p%s%z]*$') and #query == 0 then return end\nassert(type(query) == 'string')","typeGuard":"local function is_valid_query(q) return type(q) == 'string' and #q > 0 end","tryCatchPattern":"local res = fff.search(inst, query or '')\nif res.is_err then log('search rejected: invalid query') end","preventionTips":["Always pass non-nil, UTF-8 strings from the host language.","NUL-terminate manually built C strings.","Lossily convert or reject non-UTF-8 paths/queries early."],"tags":["ffi","utf-8","null-pointer","validation"],"backgroundTag":"null-argument","analyzedSha":"7f8537e70f0ea1210f9acbbfc4640141105cdc78","analyzedAt":"2026-09-10T07:26:53.407Z","contentChangedAt":"2026-09-10T07:26:53.407Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}