Skip to content

Fix vec0 parser token-type guards: && should be || (20 sites) - #1

Merged
stumpylog merged 1 commit into
paperlessfrom
fix/vec0-parser-token-guards
Sep 1, 2026
Merged

Fix vec0 parser token-type guards: && should be || (20 sites)#1
stumpylog merged 1 commit into
paperlessfrom
fix/vec0-parser-token-guards

Conversation

@stumpylog

Copy link
Copy Markdown
Owner

CI validation for the && -> || parser guard fix (mirrors upstream asg017#319) before merging into paperless.

Every "next token must be X" guard in the vec0 column/option-definition
parser (vec0_parse_table_option, vec0_parse_partition_key_definition,
vec0_parse_auxiliary_column_definition, vec0_parse_primary_key_definition,
vec0_parse_vector_column) is written as:

  rc = vec0_scanner_next(&scanner, &token);
  if (rc != VEC0_TOKEN_RESULT_SOME && token.token_type != TOKEN_TYPE_X) {
    return SQLITE_EMPTY; // or SQLITE_ERROR
  }

This is backwards in two ways:

- When a token IS present (the common case), `rc != VEC0_TOKEN_RESULT_SOME`
  is false, and `false && anything` is unconditionally false -- the
  token_type check never runs at all. A present-but-wrong-type token (e.g.
  a digit where an identifier or '=' was expected) is silently accepted
  and its (wrong) start/end pointers get used as if they were correct.

- When no token is present (EOF), `token` is left uninitialised by the
  scanner. `true && token.token_type != TOKEN_TYPE_X` then reads that
  uninitialised value, so whether the guard fires is undefined -- and on
  the branch where it doesn't, the code falls through and dereferences
  uninitialised `token.start`/`token.end`. This is what the nightly
  valgrind memcheck job (not ASan/UBSan, which don't catch uninitialised
  reads) reports as ~20 "use of uninitialised value" errors in
  vec0_parse_* and the sqlite3_strnicmp calls they feed.

Every one of these guards should be `||`: bail if there's no token, OR
the token that is there is the wrong type. Several sibling checks in the
same functions already use `||` correctly, which is how the drift is
visible -- this makes all 20 sites consistent with those.

Fix: mechanical && -> || flip at all 20 sites. No call site needed the
buggy behavior; each one's job is purely "reject if this isn't token X".

Testing: added test_vec0_column_option_malformed_value to
tests/test-loadable.py, asserting that a distance_metric option with a
missing value (EOF right after '=') now deterministically raises rather
than falling through with an uninitialised token.
@stumpylog
stumpylog merged commit bdd6911 into paperless Sep 1, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant