Fix cocoa double-free issue with strings

Reviewed By: mcslee

Other Notes: Submitted by Andrew McGeachie


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665360 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_cocoa_generator.cc b/compiler/cpp/src/generate/t_cocoa_generator.cc
index 6cb86a2..9ade7fd 100644
--- a/compiler/cpp/src/generate/t_cocoa_generator.cc
+++ b/compiler/cpp/src/generate/t_cocoa_generator.cc
@@ -24,7 +24,7 @@
   string f_header_fullname = get_out_dir()+f_header_name;
   f_header_.open(f_header_fullname.c_str());
 
-  f_header_ << 
+  f_header_ <<
     autogen_comment() <<
     endl;
 
@@ -36,7 +36,7 @@
   string f_impl_name = get_out_dir()+program_name_+".m";
   f_impl_.open(f_impl_name.c_str());
 
-  f_impl_ << 
+  f_impl_ <<
     autogen_comment() <<
     endl;
 
@@ -45,7 +45,7 @@
     cocoa_thrift_imports() <<
     "#import \"" << f_header_name << "\"" << endl <<
     endl;
-  
+
 }
 
 /**
@@ -86,7 +86,7 @@
 /**
  * Finish up generation.
  */
-void t_cocoa_generator::close_generator() 
+void t_cocoa_generator::close_generator()
 {
   // stick our constants declarations at the end of the header file
   // since they refer to things we are defining.
@@ -246,13 +246,13 @@
                                                       t_struct* tstruct,
                                                       bool is_exception) {
   out << "@interface " << cocoa_prefix_ << tstruct->get_name() << " : ";
-  
+
   if (is_exception) {
     out << "NSException ";
   } else {
     out << "NSObject ";
-  }    
-  
+  }
+
   scope_up(out);
 
   // members are protected.  this is redundant, but explicit.
@@ -261,7 +261,7 @@
   const vector<t_field*>& members = tstruct->get_members();
 
   // member varialbes
-  vector<t_field*>::const_iterator m_iter; 
+  vector<t_field*>::const_iterator m_iter;
   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
     out << indent() << declare_field(*m_iter) << endl;
   }
@@ -304,7 +304,7 @@
 void t_cocoa_generator::generate_cocoa_struct_initializer_signature(ofstream &out,
                                                                   t_struct* tstruct) {
   const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter; 
+  vector<t_field*>::const_iterator m_iter;
   indent(out) << "- (id) initWith";
   for (m_iter = members.begin(); m_iter != members.end(); ) {
     if (m_iter == members.begin()) {
@@ -330,10 +330,10 @@
                                                                           t_struct* tstruct,
                                                                           bool is_exception) {
   const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter; 
+  vector<t_field*>::const_iterator m_iter;
   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
     out << indent() << "- (" << type_name((*m_iter)->get_type()) << ") " << decapitalize((*m_iter)->get_name()) << ";" << endl;
-    out << indent() << "- (void) set" << capitalize((*m_iter)->get_name()) << 
+    out << indent() << "- (void) set" << capitalize((*m_iter)->get_name()) <<
       ": (" << type_name((*m_iter)->get_type()) << ") " << (*m_iter)->get_name() << ";" << endl;
     out << indent() << "- (BOOL) " << (*m_iter)->get_name() << "IsSet;" << endl << endl;
   }
@@ -375,7 +375,7 @@
       out << indent() << "self = [super init];" << endl;
     }
 
-    vector<t_field*>::const_iterator m_iter; 
+    vector<t_field*>::const_iterator m_iter;
     for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
       t_type* t = get_true_type((*m_iter)->get_type());
       out << indent() << "__" << (*m_iter)->get_name() << " = ";
@@ -397,7 +397,7 @@
     out << "- (void) dealloc" << endl;
     scope_up(out);
 
-    vector<t_field*>::const_iterator m_iter; 
+    vector<t_field*>::const_iterator m_iter;
     for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
       t_type* t = get_true_type((*m_iter)->get_type());
       if (type_can_be_null(t)) {
@@ -445,16 +445,16 @@
   out << endl;
 
   indent(out) << "[inProtocol readStructBeginReturningName: NULL];" << endl;
-  
+
   // Loop over reading in fields
   indent(out) <<
     "while (true)" << endl;
     scope_up(out);
-    
+
     // Read beginning field marker
     indent(out) <<
       "[inProtocol readFieldBeginReturningName: &fieldName type: &fieldType fieldID: &fieldID];" << endl;
-    
+
     // Check for field STOP marker and break
     indent(out) <<
       "if (fieldType == TType_STOP) { " << endl;
@@ -464,13 +464,13 @@
     indent_down();
     indent(out) <<
       "}" << endl;
-    
+
     // Switch statement on the field we are reading
     indent(out) <<
       "switch (fieldID)" << endl;
 
       scope_up(out);
-    
+
       // Generate deserialization code for known cases
       for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
         indent(out) <<
@@ -485,7 +485,10 @@
         // if this is an allocated field, release it since the struct
         // is now retaining it
         if (type_can_be_null((*f_iter)->get_type())) {
-          indent(out) << "[fieldValue release];" << endl;
+          // deserialized strings are autorelease, so don't release them
+          if (!((*f_iter)->get_type()->is_string())) {
+            indent(out) << "[fieldValue release];" << endl;
+          }
         }
 
         indent_down();
@@ -496,21 +499,21 @@
           indent() << "break;" << endl;
         indent_down();
       }
-      
+
       // In the default case we skip the field
       out <<
         indent() << "default:" << endl <<
         indent() << "  [TProtocolUtil skipType: fieldType onProtocol: inProtocol];" << endl <<
         indent() << "  break;" << endl;
-      
+
       scope_down(out);
 
     // Read field end marker
     indent(out) <<
       "[inProtocol readFieldEnd];" << endl;
-    
+
     scope_down(out);
-      
+
     out <<
       indent() << "[inProtocol readStructEnd];" << endl;
 
@@ -549,8 +552,8 @@
       indent_up();
     }
 
-    indent(out) << "[outProtocol writeFieldBeginWithName: @\"" << 
-      (*f_iter)->get_name() << "\" type: " << type_to_enum((*f_iter)->get_type()) << 
+    indent(out) << "[outProtocol writeFieldBeginWithName: @\"" <<
+      (*f_iter)->get_name() << "\" type: " << type_to_enum((*f_iter)->get_type()) <<
       " fieldID: " << (*f_iter)->get_key() << "];" << endl;
 
     // Write field contents
@@ -559,7 +562,7 @@
     // Write field closer
     indent(out) <<
       "[outProtocol writeFieldEnd];" << endl;
-    
+
     if (null_allowed) {
       scope_down(out);
     }
@@ -620,7 +623,7 @@
     }
 
     indent(out) << "[outProtocol writeFieldBeginWithName: @\"" <<
-      (*f_iter)->get_name() << "\" type: " << type_to_enum((*f_iter)->get_type()) << 
+      (*f_iter)->get_name() << "\" type: " << type_to_enum((*f_iter)->get_type()) <<
       " fieldID: " << (*f_iter)->get_key() << "];" << endl;
 
     // Write field contents
@@ -701,7 +704,7 @@
     indent(out) << "return __" << field_name << "_isset;" << endl;
     indent_down();
     indent(out) << "}" << endl << endl;
-    
+
     // Unsetter - do we need this?
     indent(out) << "- (void) unset" << cap_name << " {" << endl;
     indent_up();
@@ -727,7 +730,7 @@
   indent_up();
 
   out <<
-    indent() << "NSMutableString * ms = [NSMutableString stringWithString: @\"" << 
+    indent() << "NSMutableString * ms = [NSMutableString stringWithString: @\"" <<
     tstruct->get_name() << "(\"];" << endl;
 
   const vector<t_field*>& fields = tstruct->get_members();
@@ -775,7 +778,7 @@
  */
 void t_cocoa_generator::generate_cocoa_service_helpers(t_service* tservice) {
   vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter; 
+  vector<t_function*>::iterator f_iter;
   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
     generate_function_helpers(*f_iter);
   }
@@ -826,9 +829,9 @@
   out << "@protocol " << cocoa_prefix_ << tservice->get_name() << " <NSObject>" << endl;
 
   vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::iterator f_iter; 
+  vector<t_function*>::iterator f_iter;
   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    out << "- " << function_signature(*f_iter) << ";" << 
+    out << "- " << function_signature(*f_iter) << ";" <<
       "  // throws ";
     t_struct* xs = (*f_iter)->get_xceptions();
     const std::vector<t_field*>& xceptions = xs->get_members();
@@ -849,7 +852,7 @@
  */
 void t_cocoa_generator::generate_cocoa_service_client_interface(ofstream& out,
                                                                 t_service* tservice) {
-  out << "@interface " << cocoa_prefix_ << tservice->get_name() << "Client : NSObject <" << 
+  out << "@interface " << cocoa_prefix_ << tservice->get_name() << "Client : NSObject <" <<
     cocoa_prefix_ << tservice->get_name() << "> ";
 
   scope_up(out);
@@ -899,7 +902,7 @@
 
   // generate client method implementations
   vector<t_function*> functions = tservice->get_functions();
-  vector<t_function*>::const_iterator f_iter; 
+  vector<t_function*>::const_iterator f_iter;
   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
     string funname = (*f_iter)->get_name();
 
@@ -919,7 +922,7 @@
       indent() << "[outProtocol writeMessageBeginWithName: @\"" << funname << "\"" <<
       " type: TMessageType_CALL" <<
       " sequenceID: 0];" << endl;
-    
+
     out <<
       indent() << "[outProtocol writeStructBeginWithName: @\"" << argsname << "\"];" << endl;
 
@@ -970,7 +973,7 @@
       indent(out) <<
         "- " << function_signature(&recv_function) << endl;
       scope_up(out);
-           
+
       // TODO(mcslee): Message validation here, was the seqid etc ok?
 
       // check for an exception
@@ -986,7 +989,7 @@
       // FIXME - could optimize here to reduce creation of temporary objects.
       string resultname = function_result_helper_struct_type(*f_iter);
       out <<
-        indent() << cocoa_prefix_ << resultname << " * result = [[[" << cocoa_prefix_ << 
+        indent() << cocoa_prefix_ << resultname << " * result = [[[" << cocoa_prefix_ <<
         resultname << " alloc] init] autorelease];" << endl;
       indent(out) << "[result read: inProtocol];" << endl;
       indent(out) << "[inProtocol readMessageEnd];" << endl;
@@ -1018,7 +1021,7 @@
           indent() << "@throw [TApplicationException exceptionWithType: TApplicationException_MISSING_RESULT" << endl <<
           indent() << "                                         reason: @\"" << (*f_iter)->get_name() << " failed: unknown result\"];" << endl;
       }
-      
+
       // Close function
       scope_down(out);
       out << endl;
@@ -1086,7 +1089,7 @@
   } else if (type->is_base_type() || type->is_enum()) {
     indent(out) <<
       type_name(type) << " " << fieldName << " = [inProtocol ";
-    
+
     if (type->is_base_type()) {
       t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
       switch (tbase) {
@@ -1094,7 +1097,7 @@
         throw "compiler error: cannot serialize void field in a struct: " +
           tfield->get_name();
         break;
-      case t_base_type::TYPE_STRING:        
+      case t_base_type::TYPE_STRING:
         if (((t_base_type*)type)->is_binary()) {
           out << "readBinary];";
         } else {
@@ -1139,7 +1142,7 @@
 void t_cocoa_generator::generate_deserialize_struct(ofstream& out,
                                                     t_struct* tstruct,
                                                     string fieldName) {
-  indent(out) << type_name(tstruct) << fieldName << " = [[" << 
+  indent(out) << type_name(tstruct) << fieldName << " = [[" <<
     type_name(tstruct, true) << " alloc] init];" << endl;
   indent(out) << "[" << fieldName << " read: inProtocol];" << endl;
 }
@@ -1155,20 +1158,20 @@
 
   // Declare variables, read header
   if (ttype->is_map()) {
-    indent(out) 
+    indent(out)
       << "[inProtocol readMapBeginReturningKeyType: NULL valueType: NULL size: &" <<
       size << "];" << endl;
-    indent(out) << "NSMutableDictionary * " << fieldName << 
+    indent(out) << "NSMutableDictionary * " << fieldName <<
       " = [[NSMutableDictionary alloc] initWithCapacity: " << size << "];" << endl;
   } else if (ttype->is_set()) {
-    indent(out) 
+    indent(out)
       << "[inProtocol readSetBeginReturningElementType: NULL size: &" << size << "];" << endl;
-    indent(out) << "NSMutableSet * " << fieldName << 
+    indent(out) << "NSMutableSet * " << fieldName <<
       " = [[NSMutableSet alloc] initWithCapacity: " << size << "];" << endl;
   } else if (ttype->is_list()) {
-    indent(out) 
+    indent(out)
       << "[inProtocol readListBeginReturningElementType: NULL size: &" << size << "];" << endl;
-    indent(out) << "NSMutableArray * " << fieldName << 
+    indent(out) << "NSMutableArray * " << fieldName <<
       " = [[NSMutableArray alloc] initWithCapacity: " << size << "];" << endl;
   }
   // FIXME - the code above does not verify that the element types of
@@ -1181,9 +1184,9 @@
     indent() << "for (" << i << " = 0; " <<
     i << " < " << size << "; " <<
     "++" << i << ")" << endl;
-  
+
     scope_up(out);
-    
+
     if (ttype->is_map()) {
       generate_deserialize_map_element(out, (t_map*)ttype, fieldName);
     } else if (ttype->is_set()) {
@@ -1191,7 +1194,7 @@
     } else if (ttype->is_list()) {
       generate_deserialize_list_element(out, (t_list*)ttype, fieldName);
     }
-    
+
     scope_down(out);
 
   // Read container end
@@ -1311,7 +1314,7 @@
     throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
       tfield->get_name();
   }
-  
+
   if (type->is_struct() || type->is_xception()) {
     generate_serialize_struct(out,
                               (t_struct*)type,
@@ -1323,7 +1326,7 @@
   } else if (type->is_base_type() || type->is_enum()) {
     indent(out) <<
       "[outProtocol ";
-    
+
     if (type->is_base_type()) {
       t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
       switch (tbase) {
@@ -1393,7 +1396,7 @@
                                                      t_type* ttype,
                                                      string fieldName) {
   scope_up(out);
-  
+
   if (ttype->is_map()) {
     indent(out) <<
       "[outProtocol writeMapBeginWithKeyType: " <<
@@ -1440,9 +1443,9 @@
     } else if (ttype->is_list()) {
       generate_serialize_list_element(out, (t_list*)ttype, key, fieldName);
     }
-    
+
     scope_down(out);
-    
+
     if (ttype->is_map()) {
       indent(out) <<
         "[outProtocol writeMapEnd];" << endl;
@@ -1453,8 +1456,8 @@
       indent(out) <<
         "[outProtocol writeListEnd];" << endl;
     }
-    
-  scope_down(out);  
+
+  scope_down(out);
 }
 
 /**
@@ -1496,7 +1499,7 @@
 
 /**
  * Serializes the members of a map.
- */ 
+ */
 void t_cocoa_generator::generate_serialize_map_element(ofstream& out,
                                                        t_map* tmap,
                                                        string key,
@@ -1606,8 +1609,8 @@
 /**
  * Spit out code that evaluates to the specified constant value.
  */
-string t_cocoa_generator::render_const_value(string name, 
-                                             t_type* type, 
+string t_cocoa_generator::render_const_value(string name,
+                                             t_type* type,
                                              t_const_value* value,
                                              bool containerize_it) {
   std::ostringstream render;
@@ -1775,7 +1778,7 @@
  */
 string t_cocoa_generator::type_to_enum(t_type* type) {
   type = get_true_type(type);
-  
+
   if (type->is_base_type()) {
     t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
     switch (tbase) {
@@ -1817,7 +1820,7 @@
  */
 string t_cocoa_generator::format_string_for_type(t_type* type) {
   type = get_true_type(type);
-  
+
   if (type->is_base_type()) {
     t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
     switch (tbase) {