Changed upb status to suit GCC10's warning about strncpy(). (#268)

Added tests for all cases. Also removed ellipses from truncated
messages, they were more trouble than they are worth.
diff --git a/tests/test_generated_code.c b/tests/test_generated_code.c
index a2a4fc0..25fbf77 100644
--- a/tests/test_generated_code.c
+++ b/tests/test_generated_code.c
@@ -7,6 +7,8 @@
 #include "tests/upb_test.h"
 #include "tests/test.upb.h"
 
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+
 const char test_str[] = "abcdefg";
 const char test_str2[] = "12345678910";
 const char test_str3[] = "rstlnezxcvbnm";
@@ -354,6 +356,36 @@
   ASSERT(msg);
   protobuf_test_messages_proto3_TestAllTypesProto3_serialize(msg, arena, &size);
   ASSERT(size == 0);
+  upb_arena_free(arena);
+}
+
+void test_status_truncation() {
+  int i, j;
+  upb_status status;
+  upb_status status2;
+  for (i = 0; i < UPB_STATUS_MAX_MESSAGE + 20; i++) {
+    char *msg = malloc(i + 1);
+    int end;
+    char ch = (i % 96) + 33;  /* Cycle through printable chars. */
+
+    for (j = 0; j < i; j++) {
+      msg[j] = ch;
+    }
+    msg[i] = '\0';
+
+    upb_status_seterrmsg(&status, msg);
+    upb_status_seterrf(&status2, "%s", msg);
+    end = MIN(i, UPB_STATUS_MAX_MESSAGE - 1);
+    ASSERT(strlen(status.msg) == end);
+    ASSERT(strlen(status2.msg) == end);
+
+    for (j = 0; j < end; j++) {
+      ASSERT(status.msg[j] == ch);
+      ASSERT(status2.msg[j] == ch);
+    }
+
+    free(msg);
+  }
 }
 
 int run_tests(int argc, char *argv[]) {
@@ -363,5 +395,6 @@
   test_int32_map();
   test_repeated();
   test_null_decode_buf();
+  test_status_truncation();
   return 0;
 }
diff --git a/upb/upb.c b/upb/upb.c
index cb2cdfd..258192d 100644
--- a/upb/upb.c
+++ b/upb/upb.c
@@ -11,17 +11,6 @@
 
 #include "upb/port_def.inc"
 
-/* Guarantee null-termination and provide ellipsis truncation.
- * It may be tempting to "optimize" this by initializing these final
- * four bytes up-front and then being careful never to overwrite them,
- * this is safer and simpler. */
-static void nullz(upb_status *status) {
-  const char *ellipsis = "...";
-  size_t len = strlen(ellipsis);
-  UPB_ASSERT(sizeof(status->msg) > len);
-  memcpy(status->msg + sizeof(status->msg) - len, ellipsis, len);
-}
-
 /* upb_status *****************************************************************/
 
 void upb_status_clear(upb_status *status) {
@@ -37,8 +26,8 @@
 void upb_status_seterrmsg(upb_status *status, const char *msg) {
   if (!status) return;
   status->ok = false;
-  strncpy(status->msg, msg, sizeof(status->msg));
-  nullz(status);
+  strncpy(status->msg, msg, UPB_STATUS_MAX_MESSAGE - 1);
+  status->msg[UPB_STATUS_MAX_MESSAGE - 1] = '\0';
 }
 
 void upb_status_seterrf(upb_status *status, const char *fmt, ...) {
@@ -52,7 +41,7 @@
   if (!status) return;
   status->ok = false;
   _upb_vsnprintf(status->msg, sizeof(status->msg), fmt, args);
-  nullz(status);
+  status->msg[UPB_STATUS_MAX_MESSAGE - 1] = '\0';
 }
 
 /* upb_alloc ******************************************************************/