Browse Source

[5014_phase2] Fixed lexer cleanup on any exit (note parser uses try-catch)

Francis Dupont 8 years ago
parent
commit
58bb8f3445

+ 32 - 11
src/bin/dhcp6/dhcp6_lexer.ll

@@ -882,6 +882,14 @@ null {
     driver.locs_.pop_back();
     driver.file_ = driver.files_.back();
     driver.files_.pop_back();
+    if (driver.sfile_) {
+        fclose(driver.sfile_);
+        driver.sfile_ = 0;
+    }
+    if (!driver.sfiles_.empty()) {
+        driver.sfile_ = driver.sfiles_.back();
+        driver.sfiles_.pop_back();
+    }
     parser6__delete_buffer(YY_CURRENT_BUFFER);
     parser6__switch_to_buffer(driver.states_.back());
     driver.states_.pop_back();
@@ -896,11 +904,11 @@ using namespace isc::dhcp;
 void
 Parser6Context::scanStringBegin(const std::string& str, ParserType parser_type)
 {
-    static_cast<void>(parser6_lex_destroy());
     start_token_flag = true;
     start_token_value = parser_type;
 
     file_ = "<string>";
+    sfile_ = 0;
     loc_.initialize(&file_);
     yy_flex_debug = trace_scanning_;
     YY_BUFFER_STATE buffer;
@@ -912,21 +920,15 @@ Parser6Context::scanStringBegin(const std::string& str, ParserType parser_type)
 }
 
 void
-Parser6Context::scanStringEnd()
-{
-    yy_delete_buffer(YY_CURRENT_BUFFER);
-}
-
-void
 Parser6Context::scanFileBegin(FILE * f,
                               const std::string& filename,
                               ParserType parser_type)
 {
-    static_cast<void>(parser6_lex_destroy());
     start_token_flag = true;
     start_token_value = parser_type;
 
     file_ = filename;
+    sfile_ = f;
     loc_.initialize(&file_);
     yy_flex_debug = trace_scanning_;
     YY_BUFFER_STATE buffer;
@@ -940,9 +942,24 @@ Parser6Context::scanFileBegin(FILE * f,
 }
 
 void
-Parser6Context::scanFileEnd(FILE * f) {
-    fclose(f);
-    yy_delete_buffer(YY_CURRENT_BUFFER);
+Parser6Context::scanEnd() {
+    if (sfile_)
+        fclose(sfile_);
+    sfile_ = 0;
+    static_cast<void>(parser6_lex_destroy());
+    // Close files
+    while (!sfiles_.empty()) {
+        FILE* f = sfiles_.back();
+        if (f) {
+            fclose(f);
+        }
+        sfiles_.pop_back();
+    }
+    // Delete states
+    while (!states_.empty()) {
+        parser6__delete_buffer(states_.back());
+        states_.pop_back();
+    }
 }
 
 void
@@ -955,6 +972,10 @@ Parser6Context::includeFile(const std::string& filename) {
     if (!f) {
         fatal("Can't open include file " + filename);
     }
+    if (sfile_) {
+        sfiles_.push_back(sfile_);
+    }
+    sfile_ = f;
     states_.push_back(YY_CURRENT_BUFFER);
     YY_BUFFER_STATE buffer;
     buffer = parser6__create_buffer(f, 65536 /*buffer size*/);

+ 3 - 3
src/bin/dhcp6/dhcp6_parser.yy

@@ -259,9 +259,9 @@ global_objects: global_object
 // This represents a single top level entry, e.g. Dhcp6 or DhcpDdns.
 global_object: dhcp6_object
              | logging_object
-	     | dhcp4_json_object
-	     | dhcpddns_json_object
-	     | unknown_map_entry
+             | dhcp4_json_object
+             | dhcpddns_json_object
+             | unknown_map_entry
              ;
 
 dhcp6_object: DHCP6 {

+ 15 - 19
src/bin/dhcp6/parser_context.cc

@@ -28,21 +28,7 @@ isc::data::ConstElementPtr
 Parser6Context::parseString(const std::string& str, ParserType parser_type)
 {
     scanStringBegin(str, parser_type);
-    isc::dhcp::Dhcp6Parser parser(*this);
-    // Uncomment this to get detailed parser logs.
-    // trace_parsing_ = true;
-    parser.set_debug_level(trace_parsing_);
-    int res = parser.parse();
-    if (res != 0) {
-        // @todo: handle exception here
-    }
-    scanStringEnd();
-    if (stack_.size() == 1) {
-        return (stack_[0]);
-    } else {
-        isc_throw(Dhcp6ParseError, "Expected exactly one terminal Element expected, found "
-                  << stack_.size());
-    }
+    return (parseCommon());
 }
 
 isc::data::ConstElementPtr
@@ -52,16 +38,26 @@ Parser6Context::parseFile(const std::string& filename, ParserType parser_type) {
         isc_throw(Dhcp6ParseError, "Unable to open file " << filename);
     }
     scanFileBegin(f, filename, parser_type);
+    return (parseCommon());
+}
 
+isc::data::ConstElementPtr
+Parser6Context::parseCommon() {
     isc::dhcp::Dhcp6Parser parser(*this);
     // Uncomment this to get detailed parser logs.
     // trace_parsing_ = true;
     parser.set_debug_level(trace_parsing_);
-    int res = parser.parse();
-    if (res != 0) {
-        // @todo: handle exception here
+    try {
+        int res = parser.parse();
+        if (res != 0) {
+            isc_throw(Dhcp6ParseError, "Parser abort");
+        }
+        scanEnd();
+    }
+    catch (...) {
+        scanEnd();
+        throw;
     }
-    scanFileEnd(f);
     if (stack_.size() == 1) {
         return (stack_[0]);
     } else {

+ 12 - 6
src/bin/dhcp6/parser_context.h

@@ -53,14 +53,11 @@ public:
     /// @brief Method called before scanning starts on a string.
     void scanStringBegin(const std::string& str, ParserType type);
 
-    /// @brief Method called after the last tokens are scanned from a string.
-    void scanStringEnd();
-
     /// @brief Method called before scanning starts on a file.
     void scanFileBegin(FILE * f, const std::string& filename, ParserType type);
 
-    /// @brief Method called after the last tokens are scanned from a file.
-    void scanFileEnd(FILE * f);
+    /// @brief Method called after the last tokens are scanned.
+    void scanEnd();
 
     /// @brief Divert input to an include file.
     void includeFile(const std::string& filename);
@@ -144,9 +141,15 @@ public:
     /// @brief Location stack
     std::vector<isc::dhcp::location> locs_;
 
-    /// @brief State stack
+    /// @brief Lexer state stack
     std::vector<struct yy_buffer_state*> states_;;
 
+    /// @brief sFile (aka FILE)
+    FILE* sfile_;
+
+    /// @brief sFile (aka FILE) stack
+    std::vector<FILE*> sfiles_;
+
     /// @brief Current syntactic context
     ParserContext ctx_;
 
@@ -169,6 +172,9 @@ public:
 
     /// @brief Syntactic context stack
     std::vector<ParserContext> cstack_;
+
+    /// @brief Common part of parseXXX
+    isc::data::ConstElementPtr parseCommon();
 };
 
 }; // end of isc::eval namespace