From f9b455cfd241593f4fbe96c51f9b511fab6c8fc3 Mon Sep 17 00:00:00 2001
From: "Dmitry V. Levin" <ldv@altlinux.org>
Date: Tue, 18 Aug 2015 13:25:36 +0000
Subject: [PATCH] Fix time syscall decoding for some personalities

* time.c (current_time_t_is_int32): Define.
(sys_time): Use it, printnum_int, and printnum_int64 instead
of printnum_long.
* tests/time.c: New file.
* tests/time.test: New test.
* tests/Makefile.am (check_PROGRAMS): Add time.
(TESTS): Add time.test.
* tests/.gitignore: Add time.
---
 tests/.gitignore  |  1 +
 tests/Makefile.am |  2 ++
 tests/time.c      | 43 +++++++++++++++++++++++++++++++++++++++++++
 tests/time.test   | 13 +++++++++++++
 time.c            |  7 ++++++-
 5 files changed, 65 insertions(+), 1 deletion(-)
 create mode 100644 tests/time.c
 create mode 100755 tests/time.test

diff --git a/tests/.gitignore b/tests/.gitignore
index d58e7355..f709d7f2 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -39,6 +39,7 @@ stack-fcall
 stat
 stat32
 statfs
+time
 uid
 uid16
 uid32
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6b299d11..6fa46d3a 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -50,6 +50,7 @@ check_PROGRAMS = \
 	stat \
 	stat32 \
 	statfs \
+	time \
 	uid \
 	uid16 \
 	uid32 \
@@ -115,6 +116,7 @@ TESTS = \
 	pc.test \
 	ppoll.test \
 	sun_path.test \
+	time.test \
 	umovestr.test \
 	umovestr2.test \
 	unix-yy.test \
diff --git a/tests/time.c b/tests/time.c
new file mode 100644
index 00000000..2726b2d0
--- /dev/null
+++ b/tests/time.c
@@ -0,0 +1,43 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <time.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+
+#ifdef __NR_time
+
+int
+main(void)
+{
+	const size_t page_len = sysconf(_SC_PAGESIZE);
+
+	void *p = mmap(NULL, page_len * 2, PROT_READ | PROT_WRITE,
+		       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	if (p == MAP_FAILED || mprotect(p + page_len, page_len, PROT_NONE))
+		return 77;
+
+	time_t *p_t = p + page_len - sizeof(time_t);
+	time_t t = syscall(__NR_time, p_t);
+
+	if ((time_t) -1 == t || t != *p_t)
+		return 77;
+
+	printf("time\\(\\[%jd\\]\\) += %jd\n", (intmax_t) t, (intmax_t) t);
+
+	return 0;
+}
+
+#else
+
+int
+main(void)
+{
+	return 77;
+}
+
+#endif
diff --git a/tests/time.test b/tests/time.test
new file mode 100755
index 00000000..90b1bfb6
--- /dev/null
+++ b/tests/time.test
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+# Check time syscall decoding.
+
+. "${srcdir=.}/init.sh"
+
+run_prog > /dev/null
+OUT="$LOG.out"
+run_strace -etime $args > "$OUT"
+match_grep "$LOG" "$OUT"
+rm -f "$OUT"
+
+exit 0
diff --git a/time.c b/time.c
index dfddc456..920abdf3 100644
--- a/time.c
+++ b/time.c
@@ -46,8 +46,10 @@
 # else
 #  define current_time_t_is_compat (current_wordsize == 4)
 # endif
+# define current_time_t_is_int32 current_time_t_is_compat
 #else
 # define current_time_t_is_compat 0
+# define current_time_t_is_int32 (sizeof(time_t) == 4)
 #endif
 
 struct timeval32
@@ -160,7 +162,10 @@ sprint_timespec(char *buf, struct tcb *tcp, long addr)
 SYS_FUNC(time)
 {
 	if (exiting(tcp)) {
-		printnum_long(tcp, tcp->u_arg[0], "%ld");
+		if (current_time_t_is_int32)
+			printnum_int(tcp, tcp->u_arg[0], "%d");
+		else
+			printnum_int64(tcp, tcp->u_arg[0], "%" PRId64);
 	}
 	return 0;
 }
-- 
2.40.0