1/*
2 * stpcpy test.
3 *
4 * Copyright (c) 2019-2022, Arm Limited.
5 * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
6 */
7
8#ifndef _GNU_SOURCE
9#define _GNU_SOURCE
10#endif
11
12#include <stdint.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include "mte.h"
17#include "stringlib.h"
18#include "stringtest.h"
19
20#define F(x, mte) {#x, x, mte},
21
22static const struct fun
23{
24  const char *name;
25  char *(*fun) (char *dest, const char *src);
26  int test_mte;
27} funtab[] = {
28  // clang-format off
29  F(stpcpy, 0)
30#if __aarch64__
31  F(__stpcpy_aarch64, 1)
32# if __ARM_FEATURE_SVE
33  F(__stpcpy_aarch64_sve, 1)
34# endif
35#endif
36  {0, 0, 0}
37  // clang-format on
38};
39#undef F
40
41#define ALIGN 32
42#define LEN 512
43static char *dbuf;
44static char *sbuf;
45static char wbuf[LEN + 3 * ALIGN];
46
47static void *
48alignup (void *p)
49{
50  return (void *) (((uintptr_t) p + ALIGN - 1) & -ALIGN);
51}
52
53static void
54test (const struct fun *fun, int dalign, int salign, int len)
55{
56  char *src = alignup (sbuf);
57  char *dst = alignup (dbuf);
58  char *want = wbuf;
59  char *s = src + salign;
60  char *d = dst + dalign;
61  char *w = want + dalign;
62  void *p;
63  int i;
64
65  if (err_count >= ERR_LIMIT)
66    return;
67  if (len > LEN || dalign >= ALIGN || salign >= ALIGN)
68    abort ();
69  for (i = 0; i < len + ALIGN; i++)
70    {
71      src[i] = '?';
72      want[i] = dst[i] = '*';
73    }
74  for (int i = 0; src + i < s; i++)
75    src[i] = 0;
76  for (int i = 1; i <= ALIGN; i++)
77    s[len + i] = (len + salign) & 1 ? 1 : 0;
78  for (i = 0; i < len; i++)
79    s[i] = w[i] = 'a' + (i & 31);
80  s[len] = w[len] = '\0';
81
82  s = tag_buffer (s, len + 1, fun->test_mte);
83  d = tag_buffer (d, len + 1, fun->test_mte);
84  p = fun->fun (d, s);
85  untag_buffer (s, len + 1, fun->test_mte);
86  untag_buffer (d, len + 1, fun->test_mte);
87
88  if (p != d + len)
89    ERR ("%s (%p,..) returned %p expected %p\n", fun->name, d, p, d + len);
90
91  for (i = 0; i < len + ALIGN; i++)
92    {
93      if (dst[i] != want[i])
94	{
95	  ERR ("%s (align %d, align %d, %d) failed\n",
96	       fun->name, dalign, salign, len);
97	  quoteat ("got", dst, len + ALIGN, i);
98	  quoteat ("want", want, len + ALIGN, i);
99	  break;
100	}
101    }
102}
103
104int
105main (void)
106{
107  sbuf = mte_mmap (LEN + 3 * ALIGN);
108  dbuf = mte_mmap (LEN + 3 * ALIGN);
109  int r = 0;
110  for (int i = 0; funtab[i].name; i++)
111    {
112      err_count = 0;
113      for (int d = 0; d < ALIGN; d++)
114	for (int s = 0; s < ALIGN; s++)
115	  for (int n = 0; n < LEN; n++)
116	    test (funtab + i, d, s, n);
117
118      char *pass = funtab[i].test_mte && mte_enabled () ? "MTE PASS" : "PASS";
119      printf ("%s %s\n", err_count ? "FAIL" : pass, funtab[i].name);
120      if (err_count)
121	r = -1;
122    }
123  return r;
124}
125