-
Notifications
You must be signed in to change notification settings - Fork 303
Update C chat samples with using ChatHistory class #3045
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
base: master
Are you sure you want to change the base?
Conversation
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
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
Copilot reviewed 8 out of 10 changed files in this pull request and generated 7 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (message_container) { | ||
| ov_genai_json_container_free(message_container); | ||
| message_container = NULL; | ||
| } | ||
| CHECK_JSON_CONTAINER_STATUS(ov_genai_json_container_create_from_json_string( | ||
| message_json, &message_container)); | ||
|
|
||
| // Push message using JsonContainer | ||
| CHECK_CHAT_HISTORY_STATUS(ov_genai_chat_history_push_back(chat_history, message_container)); | ||
|
|
||
| results = NULL; | ||
| CHECK_STATUS(ov_genai_llm_pipeline_generate_with_history(pipeline, | ||
| chat_history, | ||
| config, | ||
| &streamer, | ||
| &results)); | ||
|
|
||
| if (results) { | ||
| output_size = sizeof(output_buffer); | ||
| CHECK_STATUS(ov_genai_decoded_results_get_string(results, output_buffer, &output_size)); | ||
|
|
||
| json_escape_string(output_buffer, escaped_output, sizeof(escaped_output)); | ||
|
|
||
| snprintf(assistant_message_json, sizeof(assistant_message_json), | ||
| "{\"role\": \"assistant\", \"content\": \"%s\"}", escaped_output); | ||
|
|
||
| if (assistant_message_container) { | ||
| ov_genai_json_container_free(assistant_message_container); | ||
| assistant_message_container = NULL; | ||
| } | ||
| CHECK_JSON_CONTAINER_STATUS(ov_genai_json_container_create_from_json_string( | ||
| assistant_message_json, &assistant_message_container)); | ||
|
|
||
| // Push message using JsonContainer | ||
| CHECK_CHAT_HISTORY_STATUS(ov_genai_chat_history_push_back(chat_history, assistant_message_container)); |
Copilot
AI
Dec 3, 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.
Inefficient memory management: the code creates and frees message_container and assistant_message_container in every iteration of the loop (lines 135-138 and 161-164). Since these containers are only used temporarily to wrap JSON strings before pushing to history, consider reusing them across iterations or freeing them immediately after push_back succeeds rather than keeping them alive until the next iteration.
| static void json_escape_string(const char* input, char* output, size_t output_size) { | ||
| size_t i = 0; | ||
| size_t j = 0; | ||
| while (input[i] != '\0' && j < output_size - 1) { | ||
| switch (input[i]) { | ||
| case '"': | ||
| if (j < output_size - 2) { | ||
| output[j++] = '\\'; | ||
| output[j++] = '"'; | ||
| } | ||
| break; | ||
| case '\\': | ||
| if (j < output_size - 2) { | ||
| output[j++] = '\\'; | ||
| output[j++] = '\\'; | ||
| } | ||
| break; | ||
| case '\n': | ||
| if (j < output_size - 2) { | ||
| output[j++] = '\\'; | ||
| output[j++] = 'n'; | ||
| } | ||
| break; | ||
| case '\r': | ||
| if (j < output_size - 2) { | ||
| output[j++] = '\\'; | ||
| output[j++] = 'r'; | ||
| } | ||
| break; | ||
| case '\t': | ||
| if (j < output_size - 2) { | ||
| output[j++] = '\\'; | ||
| output[j++] = 't'; | ||
| } | ||
| break; | ||
| default: | ||
| output[j++] = input[i]; | ||
| break; | ||
| } | ||
| i++; | ||
| } | ||
| output[j] = '\0'; | ||
| } |
Copilot
AI
Dec 3, 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 json_escape_string function has a buffer overflow vulnerability. When escaping characters like ", \, \n, \r, and \t, the code checks j < output_size - 2 before writing two characters. However, if the original input fills most of the buffer with characters that need escaping, the output could exceed output_size. The function should track the required output size and return an error if the buffer is insufficient, or ensure proper bounds checking before writing any escaped sequence.
| if (!output) { | ||
| *output_size = json_str.length() + 1; | ||
| } else { | ||
| if (*output_size < json_str.length() + 1) { |
Copilot
AI
Dec 3, 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.
Using std::strncpy is safer, but the implementation still has a subtle issue. When *output_size < json_str.length() + 1, the function returns OUT_OF_BOUNDS, but it should ideally still set *output_size to the required size so the caller knows how much space is needed. This would be consistent with the behavior when output is NULL (line 89).
| if (*output_size < json_str.length() + 1) { | |
| if (*output_size < json_str.length() + 1) { | |
| *output_size = json_str.length() + 1; |
| } catch (const std::exception& e) { | ||
| return OV_GENAI_CHAT_HISTORY_ERROR; |
Copilot
AI
Dec 3, 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 function catches const std::exception& e but doesn't use the exception object e. Either log the error message from the exception or remove the variable name to indicate it's intentionally unused (use catch (const std::exception&) instead). This pattern appears throughout the file.
| #define CHECK_CHAT_HISTORY_STATUS(return_status) \ | ||
| if (return_status != OV_GENAI_CHAT_HISTORY_OK) { \ | ||
| fprintf(stderr, "[ERROR] chat history status %d, line %d\n", return_status, __LINE__); \ | ||
| goto err; \ | ||
| } | ||
|
|
||
| #define CHECK_JSON_CONTAINER_STATUS(return_status) \ | ||
| if (return_status != OV_GENAI_JSON_CONTAINER_OK) { \ | ||
| fprintf(stderr, "[ERROR] json container status %d, line %d\n", return_status, __LINE__); \ | ||
| goto err; \ | ||
| } |
Copilot
AI
Dec 3, 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.
[nitpick] The macro names could be more concise. CHECK_CHAT_HISTORY_STATUS and CHECK_JSON_CONTAINER_STATUS are quite long. Consider using shorter names like CHECK_HISTORY_STATUS and CHECK_JSON_STATUS to improve code readability, especially given that these macros are used frequently throughout the code.
|
|
||
| if (results) { | ||
| output_size = sizeof(output_buffer); | ||
| CHECK_STATUS(ov_genai_decoded_results_get_string(results, output_buffer, &output_size)); |
Copilot
AI
Dec 3, 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.
Inconsistent error handling: the code uses CHECK_STATUS for pipeline operations but doesn't check the return value of ov_genai_decoded_results_get_string at line 154, which could fail. If it fails, output_buffer would contain uninitialized or stale data, leading to incorrect behavior. The return status should be checked using CHECK_STATUS.
| } catch (const ov::Exception& e) { | ||
| return OV_GENAI_CHAT_HISTORY_INVALID_JSON; |
Copilot
AI
Dec 3, 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.
Catching const ov::Exception& e but not using the exception object e. Either log the error message or remove the variable name to indicate it's intentionally unused (use catch (const ov::Exception&) instead). This pattern appears multiple times in this file (lines 65, 84, 128, 152, 176, 243, 283).
No description provided.