Copilot commented on code in PR #3786:
URL: https://github.com/apache/thrift/pull/3786#discussion_r3970435542


##########
compiler/cpp/tests/cpp/t_cpp_parser_string_constant_tests.cc:
##########
@@ -0,0 +1,109 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "t_cpp_generator_test_utils.h"
+
+#include <cstdio>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+struct yy_buffer_state;
+extern yy_buffer_state* yy_scan_string(const char*);
+extern yy_buffer_state* yy_scan_bytes(const char*, int);
+extern yy_buffer_state* yy_create_buffer(FILE*, int);
+extern void yy_switch_to_buffer(yy_buffer_state*);
+extern int yylex_destroy();
+
+using cpp_generator_test_utils::join_path;
+using cpp_generator_test_utils::parse_thrift_for_test;
+using cpp_generator_test_utils::source_dir;
+
+TEST_CASE("parser preserves supported string escapes", "[parser]")
+{
+    const std::string path = join_path(source_dir(), 
"test_string_escapes.thrift");
+    std::unique_ptr<t_program> program(new t_program(path, 
"test_string_escapes"));
+    parse_thrift_for_test(program.get());
+
+    const std::vector<t_const*>& consts = program->get_consts();
+    REQUIRE(consts.size() == 4);
+    REQUIRE(consts[0]->get_value()->get_string() == "Y-m-d\\TH:i:s.uP");
+    REQUIRE(consts[1]->get_value()->get_string() == "Y-m-d\\TH:i:s.uP");
+    REQUIRE(consts[2]->get_value()->get_string() == "\r\n\t\"'\\");
+    REQUIRE(consts[3]->get_value()->get_string() == "\r\n\t\"'\\");

Review Comment:
   This test assumes `program->get_consts()` preserves declaration order. If 
the parser ever changes to store constants in a different order (or inserts 
synthetic consts), this becomes brittle. A more robust approach is to look up 
constants by name (e.g., `DOUBLE_QUOTED`, `SINGLE_QUOTED`, etc.) and assert 
their values, while still asserting the expected set/count.



##########
compiler/cpp/src/thrift/thriftl.ll:
##########
@@ -290,14 +287,25 @@ literal_begin (['\"])
     int ch = yyinput();
     switch (ch) {
       case EOF:
-        yyerror("End of file while read string at %d\n", yylineno);
+        yyerror("End of file while reading string at %d\n", yylineno);
         exit(1);
       case '\n':
-        yyerror("End of line while read string at %d\n", yylineno - 1);
+        yyerror("End of line while reading string at %d\n", yylineno - 1);
         exit(1);
       case '\\':
+        yyinput_reached_eof = false;
         ch = yyinput();
         switch (ch) {
+          case 0:
+            if (yyinput_reached_eof) {
+              yyerror("End of file while reading string at %d\n", yylineno);
+              exit(1);
+            }
+            yyerror("Invalid escape byte 0x00. Use \\\\ for a literal 
backslash.\n");
+            return -1;

Review Comment:
   EOF handling is inconsistent: the outer switch checks `case EOF` but the 
escape handling now assumes EOF may arrive as `0` (distinguished via `yywrap`). 
If `yyinput()` returns `0` at EOF (as your comment below indicates), the outer 
`case EOF` may never trigger, and unterminated strings without a trailing 
backslash could be mis-parsed or loop incorrectly. Consider handling `case 0` 
in the outer switch (using `yyinput_reached_eof` to distinguish EOF vs literal 
NUL), and also consider handling `case EOF` inside the escape switch for 
robustness if `yyinput()` ever returns `EOF` on some platforms/configurations.



##########
compiler/cpp/tests/thrift_test_parser_support.cc:
##########
@@ -43,14 +43,29 @@ extern std::vector<std::string> g_incl_searchpath;
 
 // Error reporting used by the parser.
 void yyerror(const char* fmt, ...) {
-  std::fprintf(stderr, "[ERROR:%s:%d] ", g_curpath.c_str(), yylineno);
   va_list args;
   va_start(args, fmt);
-  std::vfprintf(stderr, fmt, args);
+  va_list size_args;
+  va_copy(size_args, args);
+  const int size = std::vsnprintf(nullptr, 0, fmt, size_args);
+  va_end(size_args);
+  if (size < 0) {
+    va_end(args);
+    throw std::runtime_error("Unable to format thrift parser error");
+  }
+  std::vector<char> message(size + 1);
+  const int written = std::vsnprintf(message.data(), message.size(), fmt, 
args);

Review Comment:
   The `std::vsnprintf(nullptr, 0, ...)` sizing pattern can be non-portable on 
some toolchains/older MSVC configurations. If this repo targets such 
environments, consider using a platform-conditional sizing method (e.g., 
`_vscprintf` on MSVC) or a small formatting utility already used elsewhere in 
the codebase, to keep the test support portable.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to