Merge pull request #3751 from uykusuz/master

fixes issue #3750
diff --git a/cmake/protobuf-config.cmake.in b/cmake/protobuf-config.cmake.in
index 41ab509..fd67edc 100644
--- a/cmake/protobuf-config.cmake.in
+++ b/cmake/protobuf-config.cmake.in
@@ -49,9 +49,23 @@
     endif()
   endif()
 
+  if(protobuf_generate_TARGET)
+    get_target_property(_source_list ${protobuf_generate_TARGET} SOURCES)
+    foreach(_file ${_source_list})
+      if(_file MATCHES "proto$")
+        list(APPEND protobuf_generate_PROTOS ${_file})
+      endif()
+    endforeach()
+  endif()
+
+  if(NOT protobuf_generate_PROTOS)
+    message(SEND_ERROR "Error: protobuf_generate could not find any .proto files")
+    return()
+  endif()
+
   if(protobuf_generate_APPEND_PATH)
     # Create an include path for each file specified
-    foreach(_file ${ARGN})
+    foreach(_file ${protobuf_generate_PROTOS})
       get_filename_component(_abs_file ${_file} ABSOLUTE)
       get_filename_component(_abs_path ${_abs_file} PATH)
       list(FIND _protobuf_include_path ${_abs_path} _contains_already)
@@ -71,20 +85,6 @@
     endif()
   endforeach()
 
-  if(protobuf_generate_TARGET)
-    get_target_property(_source_list ${protobuf_generate_TARGET} SOURCES)
-    foreach(_file ${_source_list})
-      if(_file MATCHES "proto$")
-        list(APPEND protobuf_generate_PROTOS ${_file})
-      endif()
-    endforeach()
-  endif()
-
-  if(NOT protobuf_generate_PROTOS)
-    message(SEND_ERROR "Error: protobuf_generate could not find any .proto files")
-    return()
-  endif()
-
   set(_generated_srcs_all)
   foreach(_proto ${protobuf_generate_PROTOS})
     get_filename_component(_abs_file ${_proto} ABSOLUTE)
diff --git a/docs/third_party.md b/docs/third_party.md
index 5d2695d..b20d4cb 100644
--- a/docs/third_party.md
+++ b/docs/third_party.md
@@ -42,7 +42,9 @@
 * Go: https://github.com/golang/protobuf (Google-official implementation)
 * Go: https://github.com/akunspy/gopbuf
 * Go: https://github.com/gogo/protobuf
+* GopherJS: https://github.com/johanbrandhorst/protobuf
 * Haskell: http://hackage.haskell.org/package/hprotoc
+* Haskell: https://github.com/google/proto-lens (Google-unofficial implementation)
 * Haxe: https://github.com/Atry/protoc-gen-haxe
 * Java: https://github.com/google/protobuf (Google-official implementation)
 * Java/Android: https://github.com/square/wire
@@ -119,6 +121,7 @@
 * https://github.com/madwyn/libpbrpc (C++)
 * https://github.com/SeriousMa/grpc-protobuf-validation (Java)
 * https://github.com/tony612/grpc-elixir (Elixir)
+* https://github.com/johanbrandhorst/protobuf (GopherJS)
 
 ## Other Utilities
 
diff --git a/python/google/protobuf/internal/decoder.py b/python/google/protobuf/internal/decoder.py
index ff3e6d3..52b6491 100755
--- a/python/google/protobuf/internal/decoder.py
+++ b/python/google/protobuf/internal/decoder.py
@@ -181,7 +181,7 @@
   while six.indexbytes(buffer, pos) & 0x80:
     pos += 1
   pos += 1
-  return (buffer[start:pos], pos)
+  return (six.binary_type(buffer[start:pos]), pos)
 
 
 # --------------------------------------------------------------------
diff --git a/python/google/protobuf/internal/encoder.py b/python/google/protobuf/internal/encoder.py
index 8c6a118..40c62d6 100755
--- a/python/google/protobuf/internal/encoder.py
+++ b/python/google/protobuf/internal/encoder.py
@@ -418,7 +418,7 @@
 def TagBytes(field_number, wire_type):
   """Encode the given tag and return the bytes.  Only called at startup."""
 
-  return _VarintBytes(wire_format.PackTag(field_number, wire_type))
+  return six.binary_type( _VarintBytes(wire_format.PackTag(field_number, wire_type)) )
 
 # --------------------------------------------------------------------
 # As with sizers (see above), we have a number of common encoder
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 5882956..3f54b84 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -4309,8 +4309,10 @@
     result->dependencies_once_ = tables_->AllocateOnceDynamic();
     result->dependencies_names_ =
         tables_->AllocateArray<const string*>(proto.dependency_size());
-    memset(result->dependencies_names_, 0,
-           sizeof(*result->dependencies_names_) * proto.dependency_size());
+    if (proto.dependency_size() > 0) {
+      memset(result->dependencies_names_, 0,
+             sizeof(*result->dependencies_names_) * proto.dependency_size());
+    }
   } else {
     result->dependencies_once_ = NULL;
     result->dependencies_names_ = NULL;
diff --git a/src/google/protobuf/stubs/io_win32_unittest.cc b/src/google/protobuf/stubs/io_win32_unittest.cc
index 90bd9c9..3ef6c75 100644
--- a/src/google/protobuf/stubs/io_win32_unittest.cc
+++ b/src/google/protobuf/stubs/io_win32_unittest.cc
@@ -34,7 +34,7 @@
 //
 // This file is only used on Windows, it's empty on other platforms.
 
-#if defined(_WIN32)
+#if defined(_MSC_VER)
 
 #define WIN32_LEAN_AND_MEAN
 #include <errno.h>
@@ -47,6 +47,7 @@
 #include <windows.h>
 
 #include <google/protobuf/stubs/io_win32.h>
+#include <google/protobuf/stubs/scoped_ptr.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 
@@ -61,13 +62,12 @@
 namespace {
 
 using std::string;
-using std::unique_ptr;
 using std::wstring;
 
 class IoWin32Test : public ::testing::Test {
  public:
-  void SetUp() override;
-  void TearDown() override;
+  void SetUp();
+  void TearDown();
 
  protected:
   bool CreateAllUnder(wstring path);
@@ -83,21 +83,31 @@
     EXPECT_FALSE(wtest_tmpdir.empty()); \
   }
 
+namespace {
+void StripTrailingSlashes(string* str) {
+  int i = str->size() - 1;
+  for (; i >= 0 && ((*str)[i] == '/' || (*str)[i] == '\\'); --i) {}
+  str->resize(i+1);
+}
+}  // namespace
+
 void IoWin32Test::SetUp() {
   test_tmpdir = string(TestTempDir());
   wtest_tmpdir.clear();
   if (test_tmpdir.empty()) {
     const char* test_tmpdir_env = getenv("TEST_TMPDIR");
-    if (test_tmpdir_env != nullptr && *test_tmpdir_env) {
+    if (test_tmpdir_env != NULL && *test_tmpdir_env) {
       test_tmpdir = string(test_tmpdir_env);
     }
 
     // Only Bazel defines TEST_TMPDIR, CMake does not, so look for other
     // suitable environment variables.
     if (test_tmpdir.empty()) {
-      for (const char* name : {"TEMP", "TMP"}) {
+      static const char* names[] = {"TEMP", "TMP"};
+      for (int i = 0; i < sizeof(names)/sizeof(names[0]); ++i) {
+        const char* name = names[i];
         test_tmpdir_env = getenv(name);
-        if (test_tmpdir_env != nullptr && *test_tmpdir_env) {
+        if (test_tmpdir_env != NULL && *test_tmpdir_env) {
           test_tmpdir = string(test_tmpdir_env);
           break;
         }
@@ -128,9 +138,7 @@
     }
   }
 
-  while (test_tmpdir.back() == '/' || test_tmpdir.back() == '\\') {
-    test_tmpdir.pop_back();
-  }
+  StripTrailingSlashes(&test_tmpdir);
   test_tmpdir += "\\io_win32_unittest.tmp";
 
   // CreateDirectoryA's limit is 248 chars, see MSDN.
@@ -185,7 +193,7 @@
     path = wstring(L"\\\\?\\") + path;
   }
   // Append "\" if necessary.
-  if (path.back() != '\\') {
+  if (path[path.size() - 1] != '\\') {
     path.push_back('\\');
   }
 
@@ -326,7 +334,7 @@
 
 TEST_F(IoWin32Test, AsWindowsPathTest) {
   DWORD size = GetCurrentDirectoryW(0, NULL);
-  unique_ptr<wchar_t[]> cwd_str(new wchar_t[size]);
+  scoped_array<wchar_t> cwd_str(new wchar_t[size]);
   EXPECT_GT(GetCurrentDirectoryW(size, cwd_str.get()), 0);
   wstring cwd = wstring(L"\\\\?\\") + cwd_str.get();
 
@@ -363,5 +371,5 @@
 }  // namespace protobuf
 }  // namespace google
 
-#endif  // defined(_WIN32)
+#endif  // defined(_MSC_VER)
 
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index 2ea9778..eed2a76 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -1244,10 +1244,12 @@
     while (size > buffer_size_) {
       // Data exceeds space in the buffer.  Copy what we can and request a
       // new buffer.
-      memcpy(buffer_, data, buffer_size_);
-      data += buffer_size_;
-      size -= buffer_size_;
-      void* void_buffer;
+      if (buffer_size_ > 0) {
+        memcpy(buffer_, data, buffer_size_);
+        data += buffer_size_;
+        size -= buffer_size_;
+      }
+      void* void_buffer = NULL;
       failed_ = !output_->Next(&void_buffer, &buffer_size_);
       if (failed_) return;
       buffer_ = reinterpret_cast<char*>(void_buffer);
diff --git a/src/google/protobuf/util/json_util.cc b/src/google/protobuf/util/json_util.cc
index c85f189..ce3569c 100644
--- a/src/google/protobuf/util/json_util.cc
+++ b/src/google/protobuf/util/json_util.cc
@@ -61,9 +61,11 @@
       buffer_size_ -= len;
       return;
     }
-    memcpy(buffer_, bytes, buffer_size_);
-    bytes += buffer_size_;
-    len -= buffer_size_;
+    if (buffer_size_ > 0) {
+      memcpy(buffer_, bytes, buffer_size_);
+      bytes += buffer_size_;
+      len -= buffer_size_;
+    }
     if (!stream_->Next(&buffer_, &buffer_size_)) {
       // There isn't a way for ByteSink to report errors.
       buffer_size_ = 0;
diff --git a/src/google/protobuf/util/json_util.h b/src/google/protobuf/util/json_util.h
index f4f4380..dee3ddb 100644
--- a/src/google/protobuf/util/json_util.h
+++ b/src/google/protobuf/util/json_util.h
@@ -179,7 +179,7 @@
 class LIBPROTOBUF_EXPORT ZeroCopyStreamByteSink : public strings::ByteSink {
  public:
   explicit ZeroCopyStreamByteSink(io::ZeroCopyOutputStream* stream)
-      : stream_(stream), buffer_size_(0) {}
+      : stream_(stream), buffer_(NULL), buffer_size_(0) {}
   ~ZeroCopyStreamByteSink();
 
   virtual void Append(const char* bytes, size_t len);