Conversation
|
@greptile |
Greptile SummaryThis PR adds comprehensive C language bindings to the zvec project, including a C API wrapper ( Key additions:
Critical issue:
The implementation is otherwise well-structured with thread-safe error handling, proper API versioning, and comprehensive functionality coverage. Confidence Score: 1/5
Important Files Changed
Class Diagram%%{init: {'theme': 'neutral'}}%%
classDiagram
class ZVec_C_API {
+zvec_initialize()
+zvec_shutdown()
+zvec_get_version()
}
class Collection_API {
+zvec_collection_create()
+zvec_collection_open()
+zvec_collection_insert()
+zvec_collection_query()
+zvec_collection_flush()
}
class Schema_API {
+zvec_collection_schema_create()
+zvec_field_schema_create()
+zvec_field_schema_set_hnsw_index()
+zvec_field_schema_set_invert_index()
}
class Document_API {
+zvec_doc_create()
+zvec_doc_set_pk()
+zvec_doc_add_field()
+zvec_doc_get_pk_copy()
}
class Index_API {
+zvec_index_params_hnsw_create()
+zvec_index_params_invert_create()
}
class Config_API {
+zvec_config_data_create()
+zvec_config_log_create()
}
class Memory_Management {
+zvec_free()
+zvec_free_string()
+zvec_free_str()
+zvec_docs_free()
}
ZVec_C_API --> Collection_API
ZVec_C_API --> Config_API
Collection_API --> Schema_API
Collection_API --> Document_API
Schema_API --> Index_API
Document_API --> Memory_Management
Collection_API --> Memory_Management
Last reviewed commit: 67ff247 |
| static char *copy_string(const std::string &str) { | ||
| if (str.empty()) return nullptr; | ||
|
|
||
| char *copy = new char[str.length() + 1]; | ||
| strcpy(copy, str.c_str()); | ||
| return copy; | ||
| } |
There was a problem hiding this comment.
Memory allocated with new[] must be freed with delete[], not free(). This function is used in multiple places (e.g., zvec_get_last_error, zvec_doc_get_pk_copy) where the returned pointers are documented to be freed with free() or zvec_free (which calls free()), causing undefined behavior.
| static char *copy_string(const std::string &str) { | |
| if (str.empty()) return nullptr; | |
| char *copy = new char[str.length() + 1]; | |
| strcpy(copy, str.c_str()); | |
| return copy; | |
| } | |
| // Helper function: copy strings | |
| static char *copy_string(const std::string &str) { | |
| if (str.empty()) return nullptr; | |
| char *copy = static_cast<char*>(malloc(str.length() + 1)); | |
| strcpy(copy, str.c_str()); | |
| return copy; | |
| } |
| char *result = new char[pk.length() + 1]; | ||
| strcpy(result, pk.c_str()); | ||
| return result; |
There was a problem hiding this comment.
Memory allocated with new[] but documented (line 1966 in c_api.h) to be freed with free(). This causes undefined behavior - mixing new[]/delete[] with malloc/free.
| char *result = new char[pk.length() + 1]; | |
| strcpy(result, pk.c_str()); | |
| return result; | |
| char *result = static_cast<char*>(malloc(pk.length() + 1)); | |
| strcpy(result, pk.c_str()); | |
| return result; |
| ZVecString *zvec_string_create(const char *str) { | ||
| if (!str) { | ||
| set_last_error_details(ZVEC_ERROR_INVALID_ARGUMENT, | ||
| "String pointer cannot be null", __FILE__, __LINE__, | ||
| __FUNCTION__); | ||
| return nullptr; | ||
| } | ||
|
|
||
| ZVecString *zstr = nullptr; | ||
| char *data_buffer = nullptr; | ||
|
|
||
| try { | ||
| size_t len = strlen(str); | ||
| zstr = new ZVecString(); | ||
| data_buffer = new char[len + 1]; | ||
| strcpy(const_cast<char *>(data_buffer), str); | ||
|
|
||
| zstr->data = data_buffer; | ||
| zstr->length = len; | ||
| zstr->capacity = len + 1; | ||
|
|
||
| return zstr; | ||
|
|
||
| } catch (const std::exception &e) { | ||
| if (data_buffer) { | ||
| delete[] data_buffer; | ||
| } | ||
| if (zstr) { | ||
| delete zstr; | ||
| } | ||
|
|
||
| set_last_error_details(ZVEC_ERROR_INTERNAL_ERROR, | ||
| std::string("String creation failed: ") + e.what(), | ||
| __FILE__, __LINE__, __FUNCTION__); | ||
| return nullptr; | ||
| } | ||
| } |
There was a problem hiding this comment.
Memory allocated with new[] at line 152 but should be freed with delete[]. Since the API provides zvec_free_string which uses delete[], this is correct. However, zvec_string_create is also used in zvec_config_file_log_create where the memory is later freed with zvec_free_str (which calls free()) instead of delete[].
| ZVecString *zvec_string_create(const char *str) { | |
| if (!str) { | |
| set_last_error_details(ZVEC_ERROR_INVALID_ARGUMENT, | |
| "String pointer cannot be null", __FILE__, __LINE__, | |
| __FUNCTION__); | |
| return nullptr; | |
| } | |
| ZVecString *zstr = nullptr; | |
| char *data_buffer = nullptr; | |
| try { | |
| size_t len = strlen(str); | |
| zstr = new ZVecString(); | |
| data_buffer = new char[len + 1]; | |
| strcpy(const_cast<char *>(data_buffer), str); | |
| zstr->data = data_buffer; | |
| zstr->length = len; | |
| zstr->capacity = len + 1; | |
| return zstr; | |
| } catch (const std::exception &e) { | |
| if (data_buffer) { | |
| delete[] data_buffer; | |
| } | |
| if (zstr) { | |
| delete zstr; | |
| } | |
| set_last_error_details(ZVEC_ERROR_INTERNAL_ERROR, | |
| std::string("String creation failed: ") + e.what(), | |
| __FILE__, __LINE__, __FUNCTION__); | |
| return nullptr; | |
| } | |
| } | |
| ZVecString *zvec_string_create(const char *str) { | |
| if (!str) { | |
| set_last_error_details(ZVEC_ERROR_INVALID_ARGUMENT, | |
| "String pointer cannot be null", __FILE__, __LINE__, | |
| __FUNCTION__); | |
| return nullptr; | |
| } | |
| ZVecString *zstr = nullptr; | |
| char *data_buffer = nullptr; | |
| try { | |
| size_t len = strlen(str); | |
| zstr = new ZVecString(); | |
| data_buffer = static_cast<char*>(malloc(len + 1)); | |
| strcpy(data_buffer, str); | |
| zstr->data = data_buffer; | |
| zstr->length = len; | |
| zstr->capacity = len + 1; | |
| return zstr; | |
| } catch (const std::exception &e) { | |
| if (data_buffer) { | |
| free(data_buffer); | |
| } | |
| if (zstr) { | |
| delete zstr; | |
| } | |
| set_last_error_details(ZVEC_ERROR_INTERNAL_ERROR, | |
| std::string("String creation failed: ") + e.what(), | |
| __FILE__, __LINE__, __FUNCTION__); | |
| return nullptr; | |
| } | |
| } |
| void zvec_config_file_log_destroy(ZVecFileLogConfig *config) { | ||
| if (config) { | ||
| if (config->dir.data) zvec_free_str(config->dir.data); | ||
| if (config->basename.data) zvec_free_str(config->basename.data); | ||
| delete config; | ||
| } | ||
| } |
There was a problem hiding this comment.
Calls zvec_free_str which uses free() to deallocate memory that was allocated with new char[] in zvec_string_create. This causes undefined behavior.
Summary
Add C language bindings.
Changes
src/c_api/c_api.ccsrc/include/zvec/c_api.hexamples/c_api/Testing
tests/c_api/c_api_test.c