-
Notifications
You must be signed in to change notification settings - Fork 325
unwrap cleanup in types.rs #1122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
unwrap cleanup in types.rs #1122
Conversation
Signed-off-by: Yue Gao <[email protected]>
Signed-off-by: Yue Gao <[email protected]>
- take_cstr - take_string_array - take_field_value_array - take_key_op_field_values_array Signed-off-by: Yue Gao <[email protected]>
- from make_field_value_array - from make_key_op_field_values_array Signed-off-by: Yue Gao <[email protected]>
Signed-off-by: Yue Gao <[email protected]>
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
hi @qiluo-msft and @saiarcot895, please review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR systematically removes unwrap() and expect() calls from types.rs and propagates error handling changes throughout the codebase. The changes convert C string operations to return Result types, enabling graceful error handling instead of runtime panics when encountering null bytes or invalid UTF-8 sequences.
Key Changes:
- Modified
cstr()andtake_cstr()to returnResulttypes with descriptive error messages - Updated
take_field_value_array(),take_key_op_field_values_array(), andtake_string_array()to handle conversion errors while ensuring all C memory is freed - Propagated
?operator changes to ~80 call sites across 14 files
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| crates/swss-common/src/types.rs | Core changes: converted string conversion functions to return Result, updated array processing functions with error handling and memory cleanup |
| crates/swss-common/src/types/zmqserver.rs | Propagated error handling for endpoint parameter |
| crates/swss-common/src/types/zmqproducerstatetable.rs | Updated table_name, key parameters and field value array creation to use ? operator |
| crates/swss-common/src/types/zmqconsumerstatetable.rs | Updated table_name parameter and pops() return to propagate errors |
| crates/swss-common/src/types/zmqclient.rs | Updated endpoint, db_name, table_name parameters and array creation to use ? operator |
| crates/swss-common/src/types/table.rs | Updated key, field parameters and array functions to propagate errors |
| crates/swss-common/src/types/subscriberstatetable.rs | Updated table_name parameter and pops() return to propagate errors |
| crates/swss-common/src/types/sonicv2connector.rs | Updated multiple string parameters with good use of .transpose() for Optional parameters |
| crates/swss-common/src/types/producerstatetable.rs | Updated table_name, key parameters and field value array creation to use ? operator |
| crates/swss-common/src/types/logger.rs | Updated db_name and hardcoded string literals to use ? operator |
| crates/swss-common/src/types/events.rs | Updated event_source and event_tag parameters; good use of .collect::<Result<Vec<_>>>() pattern |
| crates/swss-common/src/types/dbconnector.rs | Updated connection parameters (hostname, sock_path, db_name, etc.) and data access methods to propagate errors |
| crates/swss-common/src/types/consumerstatetable.rs | Updated table_name parameter and pops() return to propagate errors |
| crates/swss-common/src/types/configdbconnector.rs | Updated netns, table, key parameters and array functions to propagate errors |
| crates/swss-common/src/lib.rs | Updated path parameters in config initialization functions to use ? operator |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
crates/swss-common/src/types.rs
Outdated
| err = Some(e); | ||
| break; |
Copilot
AI
Dec 1, 2025
•
edited by qiluo-msft
Loading
edited by qiluo-msft
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Memory leak: When take_cstr fails during iteration, it frees the current string s but doesn't free the remaining strings in the array. The break statement exits the loop early, leaving unprocessed strings that are never freed before SWSSStringArray_free(arr) is called.
To fix this, continue iterating through all strings to free them even after an error occurs, similar to the pattern used in take_field_value_array.
| err = Some(e); | |
| break; | |
| // Record the first error, if any | |
| if err.is_none() { | |
| err = Some(e); | |
| } | |
| // Continue to next entry to ensure all C resources are freed | |
| ``` #Closed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a valid Memory leak bug.
crates/swss-common/src/types.rs
Outdated
| let arr = SWSSFieldValueArray { | ||
| data: data.as_mut_ptr(), | ||
| len: data.len().try_into().unwrap(), | ||
| len: data.len().try_into().map_err(|_| Exception::new("field value array length doesn't fit target type".to_string()))?, |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message "field value array length doesn't fit target type" is vague. Consider making it more specific by indicating what the actual length was and what the target type's maximum is, e.g., format!("field value array length {} exceeds maximum for target type", data.len())
crates/swss-common/src/types.rs
Outdated
| let arr = SWSSKeyOpFieldValuesArray { | ||
| data: data.as_mut_ptr(), | ||
| len: data.len().try_into().unwrap(), | ||
| len: data.len().try_into().map_err(|_| Exception::new("key-op field values array length doesn't fit target type".to_string()))?, |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message "key-op field values array length doesn't fit target type" is vague. Consider making it more specific by indicating what the actual length was and what the target type's maximum is, e.g., format!("key-op field values array length {} exceeds maximum for target type", data.len())
| len: data.len().try_into().map_err(|_| Exception::new("key-op field values array length doesn't fit target type".to_string()))?, | |
| len: data.len().try_into().map_err(|_| Exception::new(format!( | |
| "key-op field values array length {} exceeds maximum for target type (max {})", | |
| data.len(), | |
| usize::MAX | |
| )))?, |
| pub(crate) fn cstr(s: impl AsRef<[u8]>) -> Result<CString> { | ||
| CString::new(s.as_ref()) | ||
| .map_err(|e| Exception::new(format!("String contains null byte at position {}", e.nul_position()))) | ||
| } | ||
|
|
||
| /// Take a malloc'd c string and convert it to a native String | ||
| pub(crate) unsafe fn take_cstr(p: *const libc::c_char) -> String { | ||
| let s = CStr::from_ptr(p) | ||
| .to_str() | ||
| .expect("C string being converted to Rust String contains invalid UTF-8") | ||
| .to_string(); | ||
| /// If any string fails to convert, returns an error and frees all allocated memory. | ||
| pub(crate) unsafe fn take_cstr(p: *const libc::c_char) -> Result<String> { | ||
| let cstr = CStr::from_ptr(p); | ||
| // Convert to Rust String, capturing UTF-8 conversion errors. | ||
| let result: Result<String> = match cstr.to_str() { | ||
| Ok(s) => Ok(s.to_string()), | ||
| Err(_) => Err(Exception::new("C string being converted to Rust String contains invalid UTF-8".to_string())), | ||
| }; | ||
|
|
||
| // Free the original C string in all cases to avoid leaks. | ||
| libc::free(p as *mut libc::c_void); | ||
| s | ||
|
|
||
| result | ||
| } |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new error handling in cstr() for null bytes and in take_cstr() for invalid UTF-8 lacks test coverage. Consider adding tests that verify:
cstr()correctly returns an error when given a string containing a null bytetake_cstr()correctly handles and returns an error for invalid UTF-8 sequences while still freeing the C string- The take_* array functions correctly handle errors while freeing all allocated memory
These error paths are now part of the API contract and should be tested to prevent regressions.
Signed-off-by: Yue Gao <[email protected]>
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
/azpw run |
|
/AzurePipelines run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
why I did it
unwrap() and expect function may crash at runtime. For the issues that may happen, we should catch the error and handle it gracefully instead of crashing.
This PR focuses unwrap calls in types.rs
How I did it
Return error if it fails to convert c-type string to rust str. For the case of take-style functions, such as take_cstr, it will continue the operation and free the memory then return the error. This is to avoid memory leak. Ideally, the functions should act atomically. If it fails, it leaves input intact. However, it requires copy memory or scan twice, which is not efficient for some very rare error and the caller needs to free the memory anyway.