Merge "CloseArchive() to free memory when OpenArchive fails." into nyc-dev
diff --git a/libc/arch-x86/bionic/setjmp.S b/libc/arch-x86/bionic/setjmp.S
index 86e6e3c..efb6459 100644
--- a/libc/arch-x86/bionic/setjmp.S
+++ b/libc/arch-x86/bionic/setjmp.S
@@ -32,6 +32,21 @@
 
 #include <private/bionic_asm.h>
 
+// The internal structure of a jmp_buf is totally private.
+// Current layout (changes from release to release):
+//
+// word   name            description
+// 0      edx             registers
+// 1      ebx
+// 2      esp
+// 3      ebp
+// 4      esi
+// 5      edi
+// 6      sigmask         signal mask (not used with _setjmp / _longjmp)
+// 7      sigflag/cookie  setjmp cookie in top 31 bits, signal mask flag in low bit
+// 8      checksum        checksum of the core registers, to give better error messages.
+// 9      reserved
+
 #define _JB_EDX 0
 #define _JB_EBX 1
 #define _JB_ESP 2
@@ -40,6 +55,7 @@
 #define _JB_EDI 5
 #define _JB_SIGMASK 6
 #define _JB_SIGFLAG 7
+#define _JB_CHECKSUM 8
 
 .macro m_mangle_registers reg
   xorl \reg,%edx
@@ -54,6 +70,13 @@
   m_mangle_registers \reg
 .endm
 
+.macro m_calculate_checksum dst, src
+  movl $0, \dst
+  .irp i,0,1,2,3,4,5
+    xorl (\i*4)(\src), \dst
+  .endr
+.endm
+
 ENTRY(setjmp)
   movl 4(%esp),%ecx
   mov $1,%eax
@@ -111,13 +134,22 @@
   movl %edi,(_JB_EDI * 4)(%ecx)
   m_unmangle_registers %eax
 
+  m_calculate_checksum %eax, %ecx
+  movl %eax, (_JB_CHECKSUM * 4)(%ecx)
+
   xorl %eax,%eax
   ret
 END(sigsetjmp)
 
 ENTRY(siglongjmp)
-  // Do we have a signal mask to restore?
   movl 4(%esp),%edx
+
+  // Check the checksum before doing anything.
+  m_calculate_checksum %eax, %edx
+  xorl (_JB_CHECKSUM * 4)(%edx), %eax
+  jnz 3f
+
+  // Do we have a signal mask to restore?
   movl (_JB_SIGFLAG * 4)(%edx), %eax
   testl $1,%eax
   jz 1f
@@ -165,6 +197,11 @@
 2:
   movl %ecx,0(%esp)
   ret
+
+3:
+  PIC_PROLOGUE
+  pushl (_JB_SIGMASK * 4)(%edx)
+  call PIC_PLT(__bionic_setjmp_checksum_mismatch)
 END(siglongjmp)
 
 ALIAS_SYMBOL(longjmp, siglongjmp)
diff --git a/libc/arch-x86_64/bionic/setjmp.S b/libc/arch-x86_64/bionic/setjmp.S
index 56ebb07..34b4365 100644
--- a/libc/arch-x86_64/bionic/setjmp.S
+++ b/libc/arch-x86_64/bionic/setjmp.S
@@ -35,8 +35,22 @@
 
 #include <private/bionic_asm.h>
 
-// These are only the callee-saved registers. Code calling setjmp
-// will expect the rest to be clobbered anyway.
+
+// The internal structure of a jmp_buf is totally private.
+// Current layout (changes from release to release):
+//
+// word   name            description
+// 0      rbx             registers
+// 1      rbp
+// 2      r12
+// 3      r13
+// 4      r14
+// 5      r15
+// 6      rsp
+// 7      pc
+// 8      sigflag/cookie  setjmp cookie in top 31 bits, signal mask flag in low bit
+// 9      sigmask         signal mask (includes rt signals as well)
+// 10     checksum        checksum of the core registers, to give better error messages.
 
 #define _JB_RBX 0
 #define _JB_RBP 1
@@ -48,9 +62,10 @@
 #define _JB_PC 7
 #define _JB_SIGFLAG 8
 #define _JB_SIGMASK 9
-#define _JB_SIGMASK_RT 10 // sigprocmask will write here too.
+#define _JB_CHECKSUM 10
 
 #define MANGLE_REGISTERS 1
+
 .macro m_mangle_registers reg
 #if MANGLE_REGISTERS
   xorq \reg,%rbx
@@ -68,6 +83,12 @@
   m_mangle_registers \reg
 .endm
 
+.macro m_calculate_checksum dst, src
+  movq $0, \dst
+  .irp i,0,1,2,3,4,5,6,7
+    xorq (\i*8)(\src), \dst
+  .endr
+.endm
 
 ENTRY(setjmp)
   movl $1,%esi
@@ -118,6 +139,9 @@
   movq %r11,(_JB_PC  * 8)(%rdi)
   m_unmangle_registers %rax
 
+  m_calculate_checksum %rax, %rdi
+  movq %rax, (_JB_CHECKSUM * 8)(%rdi)
+
   xorl %eax,%eax
   ret
 END(sigsetjmp)
@@ -127,6 +151,10 @@
   movq %rdi,%r12
   pushq %rsi // Push 'value'.
 
+  m_calculate_checksum %rax, %rdi
+  xorq (_JB_CHECKSUM * 8)(%rdi), %rax
+  jnz 3f
+
   // Do we need to restore the signal mask?
   movq (_JB_SIGFLAG * 8)(%rdi), %rdi
   pushq %rdi // Push cookie
@@ -172,6 +200,9 @@
 1:
   movq %r11,0(%rsp)
   ret
+
+3:
+  call PIC_PLT(__bionic_setjmp_checksum_mismatch)
 END(siglongjmp)
 
 ALIAS_SYMBOL(longjmp, siglongjmp)
diff --git a/libc/dns/resolv/res_cache.c b/libc/dns/resolv/res_cache.c
index 5a78450..ae8debb 100644
--- a/libc/dns/resolv/res_cache.c
+++ b/libc/dns/resolv/res_cache.c
@@ -2093,7 +2093,8 @@
         statp->nscount = nserv;
         // now do search domains.  Note that we cache the offsets as this code runs alot
         // but the setting/offset-computer only runs when set/changed
-        strlcpy(statp->defdname, info->defdname, sizeof(statp->defdname));
+        // WARNING: Don't use str*cpy() here, this string contains zeroes.
+        memcpy(statp->defdname, info->defdname, sizeof(statp->defdname));
         register char **pp = statp->dnsrch;
         register int *p = info->dnsrch_offset;
         while (pp < statp->dnsrch + MAXDNSRCH && *p != -1) {
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index 32308aa..c5128ea 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -411,4 +411,14 @@
                                             << sent.si_code << ", received " << received.si_code
                                             << error_msg;
 }
+
+#if defined(__arm__) || defined(__aarch64__) || defined(__i386__) || defined(__x86_64__)
+TEST(signal, sigset_size) {
+  // The setjmp implementations for ARM, AArch64, x86, and x86_64 assume that sigset_t can fit in a
+  // long. This is true because ARM and x86 have broken rt signal support, and AArch64 and x86_64
+  // both have a SIGRTMAX defined as 64.
+  static_assert(sizeof(sigset_t) <= sizeof(long), "sigset_t doesn't fit in a long");
+}
+
+#endif
 #endif