Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: sqliteai/sqlite-sync-dev
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 0.9.110
Choose a base ref
...
head repository: sqliteai/sqlite-sync-dev
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 0.9.111
Choose a head ref
  • 1 commit
  • 13 files changed
  • 1 contributor

Commits on Feb 24, 2026

  1. Fix 35 bugs and bump version to 0.9.111 (#9)

    * Fix 35 bugs across CloudSync SQLite/PostgreSQL sync extension
    
    Comprehensive audit identified and fixed 35 bugs (1 CRITICAL, 7 HIGH,
    18 MEDIUM, 9 LOW) across the entire codebase. All 84 SQLite tests and
    26 PostgreSQL tests pass with 0 failures and 0 memory leaks.
    
    ## src/cloudsync.c (13 fixes)
    
    - [HIGH] Guard NULL db_version_stmt in cloudsync_dbversion_rerun —
      set db_version = CLOUDSYNC_MIN_DB_VERSION and return 0 when stmt
      is NULL, preventing NULL dereference after schema rebuild failure
    - [MEDIUM] Add early return for NULL stmt in dbvm_execute to prevent
      crash when called with uninitialized statement pointer
    - [MEDIUM] Change (bool)dbvm_count() to (dbvm_count() > 0) in
      table_pk_exists — prevents negative return values being cast to
      true, giving false positive "pk exists" results
    - [MEDIUM] Add NULL check on database_column_text result in
      cloudsync_refill_metatable before calling strlen — prevents crash
      on corrupted or empty column data
    - [MEDIUM] Route early returns in cloudsync_payload_apply through
      goto cleanup so CLEANUP callback and vm finalize always run —
      prevents resource leaks and callback contract violation
    - [MEDIUM] Change return false to goto abort_add_table when
      ROWIDONLY rejected — ensures table_free runs on the partially
      allocated table, preventing memory leak
    - [MEDIUM] Initialize *persistent = false at top of
      cloudsync_colvalue_stmt — prevents use of uninitialized value
      when table_lookup returns NULL
    - [LOW] Add NULL check on database_column_blob in merge_did_cid_win
      — prevents memcmp with NULL pointer on corrupted cloudsync table
    - [LOW] Handle partial failure in table_add_to_context_cb — clean
      up col_name, col_merge_stmt, col_value_stmt at index on error
      instead of leaving dangling pointers
    - [LOW] Remove unused pragma_checked field from cloudsync_context
    - [LOW] Change pointer comparison to strcmp in cloudsync_set_schema
      — pointer equality missed cases where different string pointers
      had identical content
    - [LOW] Fix cloudsync_payload_get NULL check: blob == NULL (always
      false for char** arg) changed to *blob == NULL
    - [LOW] Pass extra meta_ref args to SQL_CLOUDSYNC_UPSERT_COL_INIT_OR_BUMP_VERSION
      mprintf call to match updated PostgreSQL format string
    
    ## src/sqlite/cloudsync_sqlite.c (5 fixes)
    
    - [HIGH] Split DEFAULT_FLAGS into FLAGS_PURE (SQLITE_UTF8 |
      SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC) and FLAGS_VOLATILE
      (SQLITE_UTF8). Pure functions: cloudsync_version, cloudsync_pk_encode,
      cloudsync_pk_decode. All others volatile — fixes cloudsync_uuid()
      returning identical values within the same query when SQLite cached
      deterministic results
    - [HIGH] Fix realloc inconsistency in dbsync_update_payload_append:
      on second realloc failure, state was inconsistent (new_values
      resized, old_values not, capacity not updated). Both reallocs now
      checked before updating pointers and capacity
    - [MEDIUM] Move payload->count++ after all database_value_dup NULL
      checks in dbsync_update_payload_append — prevents count increment
      when allocation failed, which would cause use-after-free on cleanup
    - [MEDIUM] Add dbsync_update_payload_free(payload) before 3 early
      returns in dbsync_update_final — prevents memory leak of entire
      aggregate payload on error paths
    - [MEDIUM] Clean up partial database_value_dup allocations on OOM in
      dbsync_update_payload_append — free dup'd values at current index
      when count is not incremented to prevent leak
    
    ## src/sqlite/database_sqlite.c (6 fixes)
    
    - [MEDIUM] Replace fixed 4096-byte trigger WHEN clause buffers with
      dynamic cloudsync_memory_mprintf — prevents silent truncation for
      tables with long filter expressions
    - [MEDIUM] Check cloudsync_memory_mprintf return for NULL before
      storing in col_names[] in database_build_trigger_when — prevents
      strlen(NULL) crash in filter_is_column under OOM
    - [LOW] Use consistent PRId64 format with (int64_t) cast for schema
      hash in database_check_schema_hash and database_update_schema_hash
      — prevents format string mismatch on platforms where uint64_t and
      int64_t have different printf specifiers
    - [LOW] Fix DEBUG_DBFUNCTION using undeclared variable 'table'
      instead of 'table_name' in database_create_metatable (line 568)
      and database_create_triggers (line 782) — compile error when
      debug macros enabled
    - [LOW] Remove dead else branch in database_pk_rowid — unreachable
      code after sqlite3_prepare_v2 success check
    
    ## src/sqlite/sql_sqlite.c (1 fix)
    
    - [MEDIUM] Change %s to %q in SQL_INSERT_SETTINGS_STR_FORMAT —
      prevents SQL injection via malformed setting key/value strings
    
    ## src/dbutils.c (1 fix)
    
    - [MEDIUM] Change snprintf to cloudsync_memory_mprintf for settings
      insert using the new %q format — ensures proper SQL escaping
    
    ## src/utils.c (1 fix)
    
    - [MEDIUM] Fix integer overflow in cloudsync_blob_compare:
      (int)(size1 - size2) overflows for large size_t values, changed
      to (size1 > size2) ? 1 : -1
    
    ## src/network.c (1 fix)
    
    - [MEDIUM] Remove trailing semicolon from savepoint name
      "cloudsync_logout_savepoint;" — semicolon in name caused
      savepoint/release mismatch
    
    ## src/postgresql/sql_postgresql.c (1 fix)
    
    - [CRITICAL] Replace EXCLUDED.col_version with %s.col_version
      (table reference) in SQL_CLOUDSYNC_UPSERT_COL_INIT_OR_BUMP_VERSION
      — PostgreSQL EXCLUDED refers to the proposed INSERT row (always
      col_version=1), not the existing row. This caused col_version to
      never increment correctly on conflict, breaking CRDT merge logic
    
    ## src/postgresql/cloudsync_postgresql.c (4 fixes)
    
    - [HIGH] Change PG_RETURN_INT32(rc) to PG_RETURN_BOOL(rc == DBRES_OK)
      in pg_cloudsync_terminate — SQL declaration returns BOOLEAN but code
      returned raw integer, causing protocol mismatch
    - [HIGH] Copy blob data with palloc+memcpy before databasevm_reset in
      cloudsync_col_value, and fix PG_RETURN_CSTRING to PG_RETURN_BYTEA_P
      — reset invalidates SPI tuple memory, causing use-after-free; wrong
      return type caused type mismatch with SQL declaration
    - [MEDIUM] Use palloc0 instead of cloudsync_memory_alloc+memset in
      aggregate context — palloc0 is lifetime-safe in PG aggregate memory
      context; cloudsync_memory_alloc uses wrong allocator
    - [MEDIUM] Free SPI_tuptable in all paths of get_column_oid — prevents
      SPI tuple table leak on early return
    
    ## src/postgresql/database_postgresql.c (3 fixes)
    
    - [MEDIUM] Use sql_escape_identifier for table_name/schema in CREATE
      INDEX — prevents SQL injection via specially crafted table names
    - [MEDIUM] Use sql_escape_literal for table_name in trigger WHEN
      clause — prevents SQL injection in trigger condition
    - [LOW] Use SPI_getvalue instead of DatumGetName for type safety in
      database_pk_names — DatumGetName assumes Name type which may not
      match the actual column type from information_schema
    
    ## test/unit.c (3 new tests)
    
    - do_test_blob_compare_large_sizes: verifies overflow fix for large
      size_t values in cloudsync_blob_compare
    - do_test_deterministic_flags: verifies cloudsync_uuid() returns
      different values in same query (non-deterministic flag working)
    - do_test_schema_hash_consistency: verifies int64 hash format
      roundtrip through cloudsync_schema_versions table
    
    Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
    
    * Bump version to 0.9.111
    
    Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
    
    * Update .gitignore
    marcobambini authored Feb 24, 2026
    Configuration menu
    Copy the full SHA
    1da92bd View commit details
    Browse the repository at this point in the history
Loading