From 7c69854e2ad09fa16153e9d21c5512f3c21ecece Mon Sep 17 00:00:00 2001
From: Akim Demaille <akim@lrde.epita.fr>
Date: Thu, 20 Sep 2012 16:59:29 +0200
Subject: [PATCH 3/3] lalr1.cc: fix exception safety

lalr1.cc does not reclaim its memory when ended by an exception.

Reported by Oleksii Taran:
http://lists.gnu.org/archive/html/help-bison/2012-09/msg00000.html

* data/lalr1.cc (yyparse): Protect calls to yylex by a try-catch
block that cleans the stack, but not the lookahead, as we can't
even know its type (since yylex did not return, its token type
is unknown).
Protect user actions by a similar block that does reclaim the
lookahead.
---
 THANKS        |  1 +
 data/lalr1.cc | 62 +++++++++++++++++++++++++++++++++++++++++++++++++----------
 2 files changed, 53 insertions(+), 10 deletions(-)

diff --git a/THANKS b/THANKS
index 95acb1e..ee9ff66 100644
--- a/THANKS
+++ b/THANKS
@@ -80,6 +80,7 @@ Nicolas Tisserand         nicolas.tisserand@epita.fr
 Noah Friedman             friedman@gnu.org
 Odd Arild Olsen           oao@fibula.no
 Oleg Smolsky              oleg.smolsky@pacific-simulators.co.nz
+Oleksii Taran             oleksii.taran@gmail.com
 Paolo Bonzini             bonzini@gnu.org
 Pascal Bart               pascal.bart@epita.fr
 Paul Eggert               eggert@cs.ucla.edu
diff --git a/data/lalr1.cc b/data/lalr1.cc
index 7456f6b..874666d 100644
--- a/data/lalr1.cc
+++ b/data/lalr1.cc
@@ -572,14 +572,27 @@ b4_dollar_popdef])[]dnl
 
     /* Read a lookahead token.  */
     if (yychar == yyempty_)
-      {
-	YYCDEBUG << "Reading a token: ";
-	yychar = ]b4_c_function_call([yylex], [int],
-				     [b4_api_PREFIX[STYPE*], [&yylval]][]dnl
+      try
+        {
+          YYCDEBUG << "Reading a token: ";
+          yychar = ]b4_c_function_call([yylex], [int],
+                                       [b4_api_PREFIX[STYPE*], [&yylval]][]dnl
 b4_locations_if([, [[location*], [&yylloc]]])dnl
 m4_ifdef([b4_lex_param], [, ]b4_lex_param))[;
-      }
-
+        }
+      catch (...)
+        {
+          YYCDEBUG << "Exception caught" << std::endl;
+          while (yystate_stack_.height () != 1)
+            {
+              yydestruct_ ("Cleanup: popping",
+                           yystos_[yystate_stack_[0]],
+                           &yysemantic_stack_[0],
+                           &yylocation_stack_[0]);
+              yypop_ ();
+            }
+          throw;
+        }
 
     /* Convert token to internal form.  */
     if (yychar <= yyeof_)
@@ -651,16 +664,45 @@ m4_ifdef([b4_lex_param], [, ]b4_lex_param))[;
     else
       yyval = yysemantic_stack_[0];
 
+    // Compute the default @@$.
     {
       slice<location_type, location_stack_type> slice (yylocation_stack_, yylen);
       YYLLOC_DEFAULT (yyloc, slice, yylen);
     }
+
+    // Perform the reduction.
     YY_REDUCE_PRINT (yyn);
-    switch (yyn)
+    try
       {
-	]b4_user_actions[
-	default:
-          break;
+        switch (yyn)
+          {
+            ]b4_user_actions[
+          default:
+            break;
+          }
+      }
+    catch (...)
+      {
+        YYCDEBUG << "Exception caught" << std::endl;
+        if (yychar != yyempty_)
+          {
+            /* Make sure we have latest lookahead translation.  See
+               comments at user semantic actions for why this is
+               necessary.  */
+            yytoken = yytranslate_ (yychar);
+            yydestruct_ ("Cleanup: discarding lookahead", yytoken, &yylval,
+                         &yylloc);
+          }
+
+        while (yystate_stack_.height () != 1)
+          {
+            yydestruct_ ("Cleanup: popping",
+                         yystos_[yystate_stack_[0]],
+                         &yysemantic_stack_[0],
+                         &yylocation_stack_[0]);
+            yypop_ ();
+          }
+        throw;
       }
     /* User semantic actions sometimes alter yychar, and that requires
        that yytoken be updated with the new translation.  We take the
-- 
1.7.12.1

