bind/objc: fixes miscalculation of string length.

Also, fixes the memory allocation bug - misuse of mem_ensure that caused
to allocate 72 bytes of memory to carry 16 bytes of data for instance.

Fixes golang/go#11842.

Change-Id: I21798be2ec7adfb68cc2897bb46a924f05f3478c
Reviewed-on: https://go-review.googlesource.com/12577
Reviewed-by: David Crawshaw <crawshaw@golang.org>
diff --git a/bind/objc/SeqTest.m b/bind/objc/SeqTest.m
index 613c2c2..77c5761 100644
--- a/bind/objc/SeqTest.m
+++ b/bind/objc/SeqTest.m
@@ -60,7 +60,8 @@
   double y = [s Y];
   double sum = [s Sum];
   if (x != 10.0 || y != 100.0 || sum != 110.0) {
-    ERROR(@"GoTestpkgS(10.0, 100.0).X=%f Y=%f SUM=%f; want 10, 100, 110", x, y, sum);
+    ERROR(@"GoTestpkgS(10.0, 100.0).X=%f Y=%f SUM=%f; want 10, 100, 110", x, y,
+          sum);
   }
 
   double sum2 = GoTestpkgCallSSum(s);
@@ -76,6 +77,15 @@
   if (x != 7 || y != 70 || sum != 77) {
     ERROR(@"GoTestpkgS(7, 70).X=%f Y=%f SUM=%f; want 7, 70, 77", x, y, sum);
   }
+
+  NSString *first = @"trytwotested";
+  NSString *second = @"test";
+  NSString *got = [s TryTwoStrings:first second:second];
+  NSString *want = [first stringByAppendingString:second];
+  if (![got isEqualToString:want]) {
+    ERROR(@"GoTestpkgS_TryTwoStrings(%@, %@)= %@; want %@", first, second, got,
+          want);
+  }
 }
 
 // Invokes functions and object methods defined in Testpkg.h.
@@ -103,9 +113,12 @@
     testBytesAppend(@"Foo", @"Bar");
 
     testStruct();
-    int numS = GoTestpkgCollectS(1, 10); // within 10 seconds, collect the S used in testStruct.
+    int numS = GoTestpkgCollectS(
+        1, 10); // within 10 seconds, collect the S used in testStruct.
     if (numS != 1) {
-      ERROR(@"%d S objects were collected; S used in testStruct is supposed to be collected.", numS);
+      ERROR(@"%d S objects were collected; S used in testStruct is supposed to "
+            @"be collected.",
+            numS);
     }
   }
 
diff --git a/bind/objc/seq_darwin.m b/bind/objc/seq_darwin.m
index a1912bd..bd9cd31 100644
--- a/bind/objc/seq_darwin.m
+++ b/bind/objc/seq_darwin.m
@@ -25,14 +25,24 @@
 // mem_ensure ensures that m has at least size bytes free.
 // If m is NULL, it is created.
 static void mem_ensure(GoSeq *m, uint32_t size) {
-  if (m->cap > m->off + size) {
+  size_t cap = m->cap;
+
+  if (cap > m->off + size) {
     return;
   }
-  m->buf = (uint8_t *)realloc((void *)m->buf, m->off + size);
+
+  if (cap == 0) {
+	  cap = 64;
+  }
+  while (cap < m->off + size) {
+	  cap *= 2;
+  }
+
+  m->buf = (uint8_t *)realloc((void *)m->buf, cap);
   if (m->buf == NULL) {
     LOG_FATAL(@"mem_ensure realloc failed, off=%zu, size=%u", m->off, size);
   }
-  m->cap = m->off + size;
+  m->cap = cap;
 }
 
 static uint32_t align(uint32_t offset, uint32_t alignment) {
@@ -66,14 +76,7 @@
               m->off, m->len, size);
   }
   uint32_t offset = align(m->off, alignment);
-  uint32_t cap = m->cap;
-  if (cap == 0) {
-    cap = 64;
-  }
-  while (offset + size > cap) {
-    cap *= 2;
-  }
-  mem_ensure(m, cap);
+  mem_ensure(m, offset - m->off + size);
   uint8_t *res = m->buf + offset;
   m->off = offset + size;
   m->len = offset + size;
@@ -160,7 +163,7 @@
     return;
   }
 
-  char *buf = (char *)mem_write(seq, len + 1, 1);
+  char *buf = (char *)mem_write(seq, len, 1);
   NSUInteger used;
   [s getBytes:buf
            maxLength:len
diff --git a/bind/objc/testpkg/go_testpkg/go_testpkg.go b/bind/objc/testpkg/go_testpkg/go_testpkg.go
index af6253e..50aae94 100644
--- a/bind/objc/testpkg/go_testpkg/go_testpkg.go
+++ b/bind/objc/testpkg/go_testpkg/go_testpkg.go
@@ -65,12 +65,13 @@
 }
 
 const (
-	proxyS_Descriptor = "go.testpkg.S"
-	proxyS_X_Get_Code = 0x00f
-	proxyS_X_Set_Code = 0x01f
-	proxyS_Y_Get_Code = 0x10f
-	proxyS_Y_Set_Code = 0x11f
-	proxyS_Sum_Code   = 0x00c
+	proxyS_Descriptor         = "go.testpkg.S"
+	proxyS_X_Get_Code         = 0x00f
+	proxyS_X_Set_Code         = 0x01f
+	proxyS_Y_Get_Code         = 0x10f
+	proxyS_Y_Set_Code         = 0x11f
+	proxyS_Sum_Code           = 0x00c
+	proxyS_TryTwoStrings_Code = 0x10c
 )
 
 type proxyS seq.Ref
@@ -106,12 +107,22 @@
 	out.WriteFloat64(res)
 }
 
+func proxyS_TryTwoStrings(out, in *seq.Buffer) {
+	ref := in.ReadRef()
+	v := ref.Get().(*testpkg.S)
+	param_first := in.ReadString()
+	param_second := in.ReadString()
+	res := v.TryTwoStrings(param_first, param_second)
+	out.WriteString(res)
+}
+
 func init() {
 	seq.Register(proxyS_Descriptor, proxyS_X_Set_Code, proxyS_X_Set)
 	seq.Register(proxyS_Descriptor, proxyS_X_Get_Code, proxyS_X_Get)
 	seq.Register(proxyS_Descriptor, proxyS_Y_Set_Code, proxyS_Y_Set)
 	seq.Register(proxyS_Descriptor, proxyS_Y_Get_Code, proxyS_Y_Get)
 	seq.Register(proxyS_Descriptor, proxyS_Sum_Code, proxyS_Sum)
+	seq.Register(proxyS_Descriptor, proxyS_TryTwoStrings_Code, proxyS_TryTwoStrings)
 }
 
 func proxy_Sum(out, in *seq.Buffer) {
diff --git a/bind/objc/testpkg/objc_testpkg/GoTestpkg.h b/bind/objc/testpkg/objc_testpkg/GoTestpkg.h
index 9307f6d..baf6ab6 100644
--- a/bind/objc/testpkg/objc_testpkg/GoTestpkg.h
+++ b/bind/objc/testpkg/objc_testpkg/GoTestpkg.h
@@ -20,6 +20,7 @@
 - (double)Y;
 - (void)setY:(double)v;
 - (double)Sum;
+- (NSString*)TryTwoStrings:(NSString*)first second:(NSString*)second;
 @end
 
 FOUNDATION_EXPORT NSData* GoTestpkgBytesAppend(NSData* a, NSData* b);
diff --git a/bind/objc/testpkg/objc_testpkg/GoTestpkg.m b/bind/objc/testpkg/objc_testpkg/GoTestpkg.m
index 968dd47..a9a47fa 100644
--- a/bind/objc/testpkg/objc_testpkg/GoTestpkg.m
+++ b/bind/objc/testpkg/objc_testpkg/GoTestpkg.m
@@ -9,6 +9,10 @@
 
 static NSString *errDomain = @"go.golang.org/x/mobile/bind/objc/testpkg";
 
+@protocol goSeqRefInterface
+-(GoSeqRef*) ref;
+@end
+
 #define _DESCRIPTOR_ "testpkg"
 
 #define _CALL_BytesAppend_ 1
@@ -27,6 +31,7 @@
 #define _GO_testpkg_S_FIELD_Y_GET_ (0x10f)
 #define _GO_testpkg_S_FIELD_Y_SET_ (0x11f)
 #define _GO_testpkg_S_Sum_ (0x00c)
+#define _GO_testpkg_S_TryTwoStrings_ (0x10c)
 
 @implementation GoTestpkgS {
 }
@@ -90,6 +95,19 @@
 	return ret0_;
 }
 
+- (NSString*)TryTwoStrings:(NSString*)first second:(NSString*)second {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeRef(&in_, self.ref);
+	go_seq_writeUTF8(&in_, first);
+	go_seq_writeUTF8(&in_, second);
+	go_seq_send(_GO_testpkg_S_DESCRIPTOR_, _GO_testpkg_S_TryTwoStrings_, &in_, &out_);
+	NSString* ret0_ = go_seq_readUTF8(&out_);
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+	return ret0_;
+}
+
 @end
 
 NSData* GoTestpkgBytesAppend(NSData* a, NSData* b) {
@@ -107,7 +125,12 @@
 double GoTestpkgCallSSum(GoTestpkgS* s) {
 	GoSeq in_ = {};
 	GoSeq out_ = {};
-	go_seq_writeRef(&in_, s.ref);
+	if (![s respondsToSelector:@selector(ref)]) {
+		@throw [NSException exceptionWithName:@"InvalidGoSeqRef"
+		                               reason:@"not a subclass of GoTestpkgSStub"
+		                             userInfo:nil];
+	}
+	go_seq_writeRef(&in_, [(id<goSeqRefInterface>)s ref]);
 	go_seq_send(_DESCRIPTOR_, _CALL_CallSSum_, &in_, &out_);
 	double ret0_ = go_seq_readFloat64(&out_);
 	go_seq_free(&in_);
diff --git a/bind/objc/testpkg/objc_testpkg/reference/GoTestpkg.h b/bind/objc/testpkg/objc_testpkg/reference/GoTestpkg.h
new file mode 100644
index 0000000..08227f4
--- /dev/null
+++ b/bind/objc/testpkg/objc_testpkg/reference/GoTestpkg.h
@@ -0,0 +1,57 @@
+// Objective-C API for talking to golang.org/x/mobile/bind/objc/testpkg Go package.
+//   gobind -lang=objc golang.org/x/mobile/bind/objc/testpkg
+//
+// File is generated by gobind. Do not edit.
+
+#ifndef __GoTestpkg_H__
+#define __GoTestpkg_H__
+
+#include <Foundation/Foundation.h>
+
+@protocol GoTestpkgI
+- (void)Fn:(int32_t)v;
+@end
+
+@interface GoTestpkgI : NSObject {
+}
+@property (strong, readonly) id ref;
+@property (weak, readonly, nonatomic) id delegate;
+
+- (void)call:(int)code in:(void *)in out:(void *)out;
+@end
+
+@class GoTestpkgS;
+
+@interface GoTestpkgS : NSObject {
+}
+@property(strong, readonly) id ref;
+
+- (id)initWithRef:(id)ref;
+- (double)X;
+- (void)setX:(double)v;
+- (double)Y;
+- (void)setY:(double)v;
+- (double)Sum;
+@end
+
+FOUNDATION_EXPORT NSData* GoTestpkgBytesAppend(NSData* a, NSData* b);
+
+FOUNDATION_EXPORT void GoTestpkgCallI(GoTestpkgI* i, int32_t v);
+
+FOUNDATION_EXPORT double GoTestpkgCallSSum(GoTestpkgS* s);
+
+FOUNDATION_EXPORT int GoTestpkgCollectS(int want, int timeoutSec);
+
+FOUNDATION_EXPORT NSString* GoTestpkgHello(NSString* s);
+
+FOUNDATION_EXPORT void GoTestpkgHi();
+
+FOUNDATION_EXPORT void GoTestpkgInt(int32_t x);
+
+FOUNDATION_EXPORT GoTestpkgS* GoTestpkgNewS(double x, double y);
+
+FOUNDATION_EXPORT BOOL GoTestpkgReturnsError(BOOL b, NSString** ret0_, NSError** error);
+
+FOUNDATION_EXPORT int64_t GoTestpkgSum(int64_t x, int64_t y);
+
+#endif
diff --git a/bind/objc/testpkg/objc_testpkg/reference/GoTestpkg.m b/bind/objc/testpkg/objc_testpkg/reference/GoTestpkg.m
new file mode 100644
index 0000000..dedf816
--- /dev/null
+++ b/bind/objc/testpkg/objc_testpkg/reference/GoTestpkg.m
@@ -0,0 +1,249 @@
+// Objective-C API for talking to golang.org/x/mobile/bind/objc/testpkg Go package.
+//   gobind -lang=objc golang.org/x/mobile/bind/objc/testpkg
+//
+// File is generated by gobind. Do not edit.
+
+#include "GoTestpkg.h"
+#include <Foundation/Foundation.h>
+#include "seq.h"
+
+static NSString *errDomain = @"go.golang.org/x/mobile/bind/objc/testpkg";
+
+#define _DESCRIPTOR_ "testpkg"
+
+#define _CALL_BytesAppend_ 1
+#define _CALL_CallI_ 2
+#define _CALL_CallSSum_ 3
+#define _CALL_CollectS_ 4
+#define _CALL_Hello_ 5
+#define _CALL_Hi_ 6
+#define _CALL_Int_ 7
+#define _CALL_NewS_ 8
+#define _CALL_ReturnsError_ 9
+#define _CALL_Sum_ 10
+
+#define _GO_testpkg_S_DESCRIPTOR_ "go.testpkg.S"
+#define _GO_testpkg_S_FIELD_X_GET_ (0x00f)
+#define _GO_testpkg_S_FIELD_X_SET_ (0x01f)
+#define _GO_testpkg_S_FIELD_Y_GET_ (0x10f)
+#define _GO_testpkg_S_FIELD_Y_SET_ (0x11f)
+#define _GO_testpkg_S_Sum_ (0x00c)
+
+#define _GO_testpkg_I_DESCRIPTOR_ "go.testpkg.I"
+#define _GO_testpkg_I_Fn_ 0x10a
+
+@implementation GoTestpkgI {
+}
+@synthesize delegate = _delegate;
+@synthesize ref = _ref;
+
+- (id)init {
+	self = [super init];
+	if (self) {
+		_delegate = self;
+		_ref = [GoSeqRef newForObject:self];
+	}
+	return self;
+}
+
+- (void)call:(int)code in:(void *)in out:(void *)out {
+	GoSeq* inseq = (GoSeq*)in;
+	GoSeq* outseq = (GoSeq*)out;
+	switch (code) {
+	case _GO_testpkg_I_Fn_:
+		{
+			int32_t v = go_seq_readInt32(inseq);
+			[_delegate Fn:v];
+			return;
+		}
+	default:
+	        NSLog(@"unknown code %s:%d", _GO_testpkg_I_DESCRIPTOR_, code);
+	}
+}
+
+@end
+
+@implementation GoTestpkgS {
+}
+
+- (id)initWithRef:(id)ref {
+	self = [super init];
+	if (self) { _ref = ref; }
+	return self;
+}
+
+- (double)X {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeRef(&in_, self.ref);
+	go_seq_send(_GO_testpkg_S_DESCRIPTOR_, _GO_testpkg_S_FIELD_X_GET_, &in_, &out_);
+	double ret_ = go_seq_readFloat64(&out_);
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+	return ret_;
+}
+
+- (void)setX:(double)v {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeRef(&in_, self.ref);
+	go_seq_writeFloat64(&in_, v);
+	go_seq_send(_GO_testpkg_S_DESCRIPTOR_, _GO_testpkg_S_FIELD_X_SET_, &in_, &out_);
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+}
+
+- (double)Y {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeRef(&in_, self.ref);
+	go_seq_send(_GO_testpkg_S_DESCRIPTOR_, _GO_testpkg_S_FIELD_Y_GET_, &in_, &out_);
+	double ret_ = go_seq_readFloat64(&out_);
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+	return ret_;
+}
+
+- (void)setY:(double)v {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeRef(&in_, self.ref);
+	go_seq_writeFloat64(&in_, v);
+	go_seq_send(_GO_testpkg_S_DESCRIPTOR_, _GO_testpkg_S_FIELD_Y_SET_, &in_, &out_);
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+}
+
+- (double)Sum {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeRef(&in_, self.ref);
+	go_seq_send(_GO_testpkg_S_DESCRIPTOR_, _GO_testpkg_S_Sum_, &in_, &out_);
+	double ret0_ = go_seq_readFloat64(&out_);
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+	return ret0_;
+}
+
+@end
+
+NSData* GoTestpkgBytesAppend(NSData* a, NSData* b) {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeByteArray(&in_, a);
+	go_seq_writeByteArray(&in_, b);
+	go_seq_send(_DESCRIPTOR_, _CALL_BytesAppend_, &in_, &out_);
+	NSData* ret0_ = go_seq_readByteArray(&out_);
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+	return ret0_;
+}
+
+void GoTestpkgCallI(GoTestpkgI* i, int32_t v) {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeRef(&in_, i.ref);
+	go_seq_writeInt32(&in_, v);
+	go_seq_send(_DESCRIPTOR_, _CALL_CallI_, &in_, &out_);
+	return;
+}
+
+double GoTestpkgCallSSum(GoTestpkgS* s) {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeRef(&in_, s.ref);
+	go_seq_send(_DESCRIPTOR_, _CALL_CallSSum_, &in_, &out_);
+	double ret0_ = go_seq_readFloat64(&out_);
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+	return ret0_;
+}
+
+int GoTestpkgCollectS(int want, int timeoutSec) {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeInt(&in_, want);
+	go_seq_writeInt(&in_, timeoutSec);
+	go_seq_send(_DESCRIPTOR_, _CALL_CollectS_, &in_, &out_);
+	int ret0_ = go_seq_readInt(&out_);
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+	return ret0_;
+}
+
+NSString* GoTestpkgHello(NSString* s) {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeUTF8(&in_, s);
+	go_seq_send(_DESCRIPTOR_, _CALL_Hello_, &in_, &out_);
+	NSString* ret0_ = go_seq_readUTF8(&out_);
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+	return ret0_;
+}
+
+void GoTestpkgHi() {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_send(_DESCRIPTOR_, _CALL_Hi_, &in_, &out_);
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+}
+
+void GoTestpkgInt(int32_t x) {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeInt32(&in_, x);
+	go_seq_send(_DESCRIPTOR_, _CALL_Int_, &in_, &out_);
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+}
+
+GoTestpkgS* GoTestpkgNewS(double x, double y) {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeFloat64(&in_, x);
+	go_seq_writeFloat64(&in_, y);
+	go_seq_send(_DESCRIPTOR_, _CALL_NewS_, &in_, &out_);
+	GoSeqRef* ret0__ref = go_seq_readRef(&out_);
+	GoTestpkgS* ret0_ = ret0__ref.obj;
+	if (ret0_ == NULL) {
+		ret0_ = [[GoTestpkgS alloc] initWithRef:ret0__ref];
+	}
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+	return ret0_;
+}
+
+BOOL GoTestpkgReturnsError(BOOL b, NSString** ret0_, NSError** error) {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeBool(&in_, b);
+	go_seq_send(_DESCRIPTOR_, _CALL_ReturnsError_, &in_, &out_);
+	NSString* ret0__val = go_seq_readUTF8(&out_);
+	if (ret0_ != NULL) {
+		*ret0_ = ret0__val;
+	}
+	NSString* _error = go_seq_readUTF8(&out_);
+	if ([_error length] != 0 && error != nil) {
+		NSMutableDictionary *details = [NSMutableDictionary dictionary];
+		[details setValue:_error forKey:NSLocalizedDescriptionKey];
+		*error = [NSError errorWithDomain:errDomain code:1 userInfo:details];
+	}
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+	return ([_error length] == 0);
+}
+
+int64_t GoTestpkgSum(int64_t x, int64_t y) {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeInt64(&in_, x);
+	go_seq_writeInt64(&in_, y);
+	go_seq_send(_DESCRIPTOR_, _CALL_Sum_, &in_, &out_);
+	int64_t ret0_ = go_seq_readInt64(&out_);
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+	return ret0_;
+}
+
diff --git a/bind/objc/testpkg/testpkg.go b/bind/objc/testpkg/testpkg.go
index e0895dd..955854c 100644
--- a/bind/objc/testpkg/testpkg.go
+++ b/bind/objc/testpkg/testpkg.go
@@ -75,6 +75,10 @@
 	return s
 }
 
+func (s *S) TryTwoStrings(first, second string) string {
+	return first + second
+}
+
 func (s *S) Sum() float64 {
 	return s.X + s.Y
 }