Introduce CassStr* abstractions#449
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces CassStr* wrapper types to improve/standardize C-string ↔ Rust &str conversions across the Rust wrapper’s FFI surface, addressing the inability of the previous helpers to distinguish null pointers from invalid UTF-8 (Issue #301). It updates exported APIs and tests to use these abstractions and starts mapping conversion failures to more explicit error paths.
Changes:
- Add
CassStrWithNul,CassStrLenDelimited,CassStrLen, andPtrToStrErrorabstractions and migrate many FFI functions from raw*const c_char/size_t. - Replace
ptr_to_cstr(_n)usage with typed conversions, improving error differentiation and propagating failures more intentionally in several call sites. - Update integration/unit tests and test utilities to use the new string wrapper APIs.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
| scylla-rust-wrapper/src/argconv.rs | Introduces CassStr* types and PtrToStrError; updates array-to-string helper. |
| scylla-rust-wrapper/src/binding.rs | Migrates bind-by-name APIs to CassStr* and tightens null/empty/non-UTF8 handling. |
| scylla-rust-wrapper/src/cass_error.rs | Changes cass_error_desc to return CassStrWithNul. |
| scylla-rust-wrapper/src/cluster.rs | Migrates many cluster APIs to CassStr* and updates parsing/validation logic. |
| scylla-rust-wrapper/src/cql_types/mod.rs | Changes string-returning helpers to return CassStrWithNul. |
| scylla-rust-wrapper/src/cql_types/data_type.rs | Migrates type-name/keyspace/class-name setters and related name-based APIs to CassStr*. |
| scylla-rust-wrapper/src/cql_types/inet.rs | Migrates inet-from-string APIs to CassStr*. |
| scylla-rust-wrapper/src/cql_types/user_type.rs | Removes now-unneeded raw c_char import (cleanup during migration). |
| scylla-rust-wrapper/src/cql_types/uuid.rs | Migrates uuid-from-string APIs to CassStr*. |
| scylla-rust-wrapper/src/exec_profile.rs | Migrates exec-profile name parameters to CassStr* with improved error handling. |
| scylla-rust-wrapper/src/logging.rs | Updates log level/file string handling to use CassStrWithNul. |
| scylla-rust-wrapper/src/metadata.rs | Migrates metadata “by name” lookups to CassStr*. |
| scylla-rust-wrapper/src/query_result.rs | Migrates column-by-name lookups to CassStr* and adds null/empty handling tests. |
| scylla-rust-wrapper/src/runtime.rs | Updates runtime tests to use CassStrLenDelimited/CassStrLen. |
| scylla-rust-wrapper/src/session.rs | Migrates connect/prepare APIs to CassStr* and updates unit tests accordingly. |
| scylla-rust-wrapper/src/ssl.rs | Migrates SSL PEM input APIs to CassStr* and adds UTF-8 validation path. |
| scylla-rust-wrapper/src/statements/prepared.rs | Migrates prepared-parameter-by-name APIs to CassStr* with explicit error logging. |
| scylla-rust-wrapper/src/statements/statement.rs | Migrates statement creation/host setting to CassStr* and adds null-pointer binding tests. |
| scylla-rust-wrapper/src/testing/integration.rs | Updates integration stubs to use CassStr* types. |
| scylla-rust-wrapper/src/testing/utils.rs | Updates test helpers/macros to use CassStr* conversions. |
| scylla-rust-wrapper/tests/integration/consistency.rs | Updates integration tests to call APIs with CassStrWithNul/CassStrLen*. |
| scylla-rust-wrapper/tests/integration/session.rs | Updates integration session tests to use CassStrWithNul and new signatures. |
| scylla-rust-wrapper/tests/integration/utils.rs | Removes old pointer helpers and updates error/message formatting to new conversions. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
03c2a77 to
9e8a8cb
Compare
CassStr* abstractions
e2b9deb to
928205e
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 23 out of 23 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
scylla-rust-wrapper/src/ssl.rs:354
cass_ssl_set_private_key_nreturnsCASS_ERROR_SSL_INVALID_CERTwhenBIO_new_mem_buffails, but this is a private-key operation and should returnCASS_ERROR_SSL_INVALID_PRIVATE_KEY(consistent with the other error paths in this function).
if bio.is_null() {
return CassError::CASS_ERROR_SSL_INVALID_CERT;
}
928205e to
5d60286
Compare
Fixes: #446 Ref: #301 #446 revealed issues with our handling of NULL string pointers in user-facing APIs. Together with Claude Opus, I examined vulnerable spots in the code: 1. Fixed UB in `binding.rs` - variations of the originally reported issue. 2. Fixed UB/panics in `cass_row_get_column_by_name[_n]` upon null name provided. 3. Fixed `ptr_to_cstr` to return `None` on NULL pointers instead of UB. This made behaviour consistent with `ptr_to_cstr_n`. 4. Refactored `ptr_to_cstr[_n]` to return `Result<&'static str, PtrToStrError>`, with `PtrToStrError` differentiating between null pointer provided and invalid UTF-8 encoding. Migrated all callers carefully. ### Further plans I'm going to address #301 fully soon, by introducing borrowed `CassStr*` FFI types: #449
Introduce three new FFI string wrapper types to replace raw pointer usage: - CassStrWithNul: wraps a CassBorrowedSharedPtr pointing to a NUL-terminated string - CassStrLenDelimited: wraps a CassBorrowedSharedPtr pointing to a length-delimited string - CassStrLen: wraps a size_t representing a string length, used in conjunction with CassStrLenDelimited First two types carry a lifetime parameter tied to the FFI call scope, preventing use-after-free bugs at compile time. The actual unsafe dereference is deferred to `to_str()` methods, which validate non-nullity and UTF-8. Also introduces PtrToStrError for granular error reporting (null pointer vs invalid UTF-8 vs empty string).
5d60286 to
600e750
Compare
|
Rebased on master. |
600e750 to
0c6947d
Compare
|
Made the new |
Migrate all FFI function parameters from raw *const c_char / size_t to the typed CassStrNulTerminated / CassStrLenDelimited wrappers. Delete the now-unused ptr_to_cstr and ptr_to_cstr_n functions. There are a lot of changes, but they are mostly mechanical and follow the same pattern. I reviewed them all after Claude Opus wrote them.
0c6947d to
6500a24
Compare
|
Deleted the commit that introduced the |
`arr_to_cstr` was a badly written helper function, whose only usage was in the logging callback. It was unsafe, and it was not clear that it was only safe to use on null-terminated strings. This commit replaces the use `CassStrNulTerminated`. `arr_to_cstr` is then deleted.
Fixes: #301
Based on: #448
What's done
This PR introduces FFI abstractions for C string types:
CassStrNulTerminated- represents a nul-terminated C string passed by a pointer;CassStrLenDelimited- represents a string slice passed by a pointer, paired withCassStrLen- represents length ofCassStrLenDelimited. I decided to make a newtype for this to increase type safety.All abstractions are
repr(transparent), and they appear in FFI functions' signatures. They provide convenient constructors and conversion methods.What we gain
Type safety
It's now harder to misuse one of string pointer as another.
Borrow checks
Both
CassStrNulTerminatedandCassStrLenDelimitedcarry a lifetime, which prevents UAFs.Self-documenting code
The code is much more explicit and clear in what it does with strings.
The names are a bit verbose, but this is in line with our FFI approach (see long names of
CassPtrabstractions, such asCassBorrowedSharedPtr).Pre-review checklist
[ ] I have enabled appropriate tests inMakefilein{SCYLLA,CASSANDRA}_(NO_VALGRIND_)TEST_FILTER.Fixes:annotations to PR description.