1/*
2 * Copyright (c) 2011, 2023, Oracle and/or its affiliates.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include <X11/Xfuncproto.h>
29#include <X11/Intrinsic.h>
30#include <X11/IntrinsicI.h>
31#include <glib.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <errno.h>
36#include <limits.h>
37#include <setjmp.h>
38#include <sys/resource.h>
39#ifdef HAVE_MALLOC_H
40# include <malloc.h>
41#endif
42
43static const char *program_name;
44
45#ifndef g_assert_no_errno /* defined in glib 2.66 & later*/
46#define g_assert_no_errno(expr) g_assert_cmpint((expr), >=, 0)
47#endif
48
49/*
50 * Check that allocations point to properly aligned memory.
51 * For libXt, we consider that to be aligned to an 8-byte (64-bit) boundary.
52 */
53#define EXPECTED_ALIGNMENT 8
54
55#define CHECK_ALIGNMENT(ptr) \
56    g_assert_cmpint(((uintptr_t)ptr) % EXPECTED_ALIGNMENT, ==, 0)
57
58/* Check that allocations point to expected amounts of memory, as best we can. */
59#ifdef HAVE_MALLOC_USABLE_SIZE
60# define CHECK_SIZE(ptr, size) do {		\
61    size_t ps = malloc_usable_size(ptr);	\
62    g_assert_cmpint(ps, >=, (size));		\
63} while (0)
64#else
65# define CHECK_SIZE(ptr, size) *(((char *)ptr) + ((size) - 1)) = 0
66#endif
67
68/* Limit we set for memory allocation to be able to test failure cases */
69#define ALLOC_LIMIT (INT_MAX / 4)
70
71/* Square root of SIZE_MAX+1 */
72#define SQRT_SIZE_MAX ((size_t)1 << (sizeof (size_t) * 4))
73
74/* Just a long string of characters to pull from */
75const char test_chars[] =
76    "|000 nul|001 soh|002 stx|003 etx|004 eot|005 enq|006 ack|007 bel|"
77    "|010 bs |011 ht |012 nl |013 vt |014 np |015 cr |016 so |017 si |"
78    "|020 dle|021 dc1|022 dc2|023 dc3|024 dc4|025 nak|026 syn|027 etb|"
79    "|030 can|031 em |032 sub|033 esc|034 fs |035 gs |036 rs |037 us |"
80    "|040 sp |041  ! |042  \" |043  # |044  $ |045  % |046  & |047  ' |"
81    "|050  ( |051  ) |052  * |053  + |054  , |055  - |056  . |057  / |"
82    "|060  0 |061  1 |062  2 |063  3 |064  4 |065  5 |066  6 |067  7 |"
83    "|070  8 |071  9 |072  : |073  ; |074  < |075  = |076  > |077  ? |"
84    "|100  @ |101  A |102  B |103  C |104  D |105  E |106  F |107  G |"
85    "|110  H |111  I |112  J |113  K |114  L |115  M |116  N |117  O |"
86    "|120  P |121  Q |122  R |123  S |124  T |125  U |126  V |127  W |"
87    "|130  X |131  Y |132  Z |133  [ |134  \\ |135  ] |136  ^ |137  _ |"
88    "|140  ` |141  a |142  b |143  c |144  d |145  e |146  f |147  g |"
89    "|150  h |151  i |152  j |153  k |154  l |155  m |156  n |157  o |"
90    "|160  p |161  q |162  r |163  s |164  t |165  u |166  v |167  w |"
91    "|170  x |171  y |172  z |173  { |174  | |175  } |176  ~ |177 del|"
92    "| 00 nul| 01 soh| 02 stx| 03 etx| 04 eot| 05 enq| 06 ack| 07 bel|"
93    "| 08 bs | 09 ht | 0a nl | 0b vt | 0c np | 0d cr | 0e so | 0f si |"
94    "| 10 dle| 11 dc1| 12 dc2| 13 dc3| 14 dc4| 15 nak| 16 syn| 17 etb|"
95    "| 18 can| 19 em | 1a sub| 1b esc| 1c fs | 1d gs | 1e rs | 1f us |"
96    "| 20 sp | 21  ! | 22  \" | 23  # | 24  $ | 25  % | 26  & | 27  ' |"
97    "| 28  ( | 29  ) | 2a  * | 2b  + | 2c  , | 2d  - | 2e  . | 2f  / |"
98    "| 30  0 | 31  1 | 32  2 | 33  3 | 34  4 | 35  5 | 36  6 | 37  7 |"
99    "| 38  8 | 39  9 | 3a  : | 3b  ; | 3c  < | 3d  = | 3e  > | 3f  ? |"
100    "| 40  @ | 41  A | 42  B | 43  C | 44  D | 45  E | 46  F | 47  G |"
101    "| 48  H | 49  I | 4a  J | 4b  K | 4c  L | 4d  M | 4e  N | 4f  O |"
102    "| 50  P | 51  Q | 52  R | 53  S | 54  T | 55  U | 56  V | 57  W |"
103    "| 58  X | 59  Y | 5a  Z | 5b  [ | 5c  \\ | 5d  ] | 5e  ^ | 5f  _ |"
104    "| 60  ` | 61  a | 62  b | 63  c | 64  d | 65  e | 66  f | 67  g |"
105    "| 68  h | 69  i | 6a  j | 6b  k | 6c  l | 6d  m | 6e  n | 6f  o |"
106    "| 70  p | 71  q | 72  r | 73  s | 74  t | 75  u | 76  v | 77  w |"
107    "| 78  x | 79  y | 7a  z | 7b  { | 7c  | | 7d  } | 7e  ~ | 7f del|";
108
109
110/* Environment saved by setjmp() */
111static jmp_buf jmp_env;
112
113static void _X_NORETURN
114xt_error_handler(String message)
115{
116    if (message && *message)
117        fprintf(stderr, "Caught Error: %s\n", message);
118    else
119        fputs("Caught Error.\n", stderr);
120
121    /* Avoid exit() in XtErrorMsg() */
122    longjmp(jmp_env, 1);
123}
124
125
126/* Test a simple short string & int */
127static void test_XtAsprintf_short(void)
128{
129    char snbuf[1024];
130    char *asbuf;
131    gint32 r = g_test_rand_int();
132    int snlen, aslen;
133
134    snlen = snprintf(snbuf, sizeof(snbuf), "%s: %d\n", program_name, r);
135    aslen = XtAsprintf(&asbuf, "%s: %d\n", program_name, r);
136
137    g_assert_nonnull(asbuf);
138    g_assert_cmpint(snlen, ==, aslen);
139    g_assert_cmpstr(snbuf, ==, asbuf);
140    g_assert_cmpint(asbuf[aslen], ==, '\0');
141}
142
143/* Test a string long enough to be past the 256 character limit that
144   makes XtAsprintf re-run snprintf after allocating memory */
145static void test_XtAsprintf_long(void)
146{
147    char *asbuf;
148    int aslen;
149    gint r1 = g_test_rand_int_range(0, 256);
150    gint r2 = g_test_rand_int_range(1024, sizeof(test_chars) - r1);
151
152    aslen = XtAsprintf(&asbuf, "%.*s", r2, test_chars + r1);
153
154    g_assert_nonnull(asbuf);
155    g_assert_cmpint(aslen, ==, r2);
156    g_assert_cmpint(strncmp(asbuf, test_chars + r1, r2), ==, 0);
157    g_assert_cmpint(asbuf[aslen], ==, '\0');
158}
159
160/* Make sure XtMalloc() works for a non-zero amount of memory */
161static void test_XtMalloc_normal(void)
162{
163    void *p;
164    /* Pick a size between 1 & 256K */
165    guint32 size = g_test_rand_int_range(1, (256 * 1024));
166
167    errno = 0;
168
169    p = XtMalloc(size);
170    g_assert_nonnull(p);
171    CHECK_ALIGNMENT(p);
172    CHECK_SIZE(p, size);
173
174    /* make sure we can write to all the allocated memory */
175    memset(p, 'A', size);
176
177    XtFree(p);
178    g_assert_cmpint(errno, ==, 0);
179}
180
181/* Make sure XtMalloc(0) returns expected results */
182static void test_XtMalloc_zero(void)
183{
184    void *p;
185
186    errno = 0;
187
188    p = XtMalloc(0);
189#if !defined(MALLOC_0_RETURNS_NULL) || defined(XTMALLOC_BC)
190    g_assert_nonnull(p);
191#else
192    g_assert_null(p);
193#endif
194    XtFree(p);
195    g_assert_cmpint(errno, ==, 0);
196
197    /* __XtMalloc always returns a non-NULL pointer for size == 0 */
198    p = __XtMalloc(0);
199    g_assert_nonnull(p);
200    XtFree(p);
201    g_assert_cmpint(errno, ==, 0);
202}
203
204/* Make sure sizes larger than the limit we set in main() fail */
205static void test_XtMalloc_oversize(void)
206{
207    void *p;
208
209    if (setjmp(jmp_env) == 0) {
210        p = XtMalloc(UINT_MAX - 1);
211        g_assert_null(p);
212    } else {
213        /*
214         * We jumped here from error handler as expected.
215         * We cannot verify errno here, as the Xt error handler makes
216         * calls that override errno, when trying to load error message
217         * files from different locations.
218         */
219    }
220}
221
222/* Make sure XtMalloc catches integer overflow if possible, by requesting
223 * sizes that are so large that they cause overflows when either adding the
224 * malloc data block overhead or aligning.
225 *
226 * Testing integer overflow cases is limited by the fact that XtMalloc
227 * only takes unsigned arguments (typically 32-bit), and relies on
228 * the underlying libc malloc to catch overflow, which can't occur if
229 * 32-bit arguments are passed to a function taking 64-bit args.
230 */
231static void test_XtMalloc_overflow(void)
232{
233#if UINT_MAX < SIZE_MAX
234    g_test_skip("overflow not possible in this config");
235#else
236    void *p;
237
238    if (setjmp(jmp_env) == 0) {
239        p = XtMalloc(SIZE_MAX);
240        g_assert_null(p);
241    } else {
242        /*
243         * We jumped here from error handler as expected.
244         * We cannot verify errno here, as the Xt error handler makes
245         * calls that override errno, when trying to load error message
246         * files from different locations.
247         */
248    }
249
250    if (setjmp(jmp_env) == 0) {
251        p = XtMalloc(SIZE_MAX - 1);
252        g_assert_null(p);
253    } else {
254        /*
255         * We jumped here from error handler as expected.
256         * We cannot verify errno here, as the Xt error handler makes
257         * calls that override errno, when trying to load error message
258         * files from different locations.
259         */
260    }
261
262    if (setjmp(jmp_env) == 0) {
263        p = XtMalloc(SIZE_MAX - 8);
264        g_assert_null(p);
265    } else {
266        /*
267         * We jumped here from error handler as expected.
268         * We cannot verify errno here, as the Xt error handler makes
269         * calls that override errno, when trying to load error message
270         * files from different locations.
271         */
272    }
273#endif
274}
275
276
277
278/* Make sure XtCalloc() works for a non-zero amount of memory */
279static void test_XtCalloc_normal(void)
280{
281    char *p;
282    /* Pick a number of elements between 1 & 16K */
283    guint32 num = g_test_rand_int_range(1, (16 * 1024));
284    /* Pick a size between 1 & 16K */
285    guint32 size = g_test_rand_int_range(1, (16 * 1024));
286
287    errno = 0;
288
289    p = XtCalloc(num, size);
290    g_assert_nonnull(p);
291    CHECK_ALIGNMENT(p);
292    CHECK_SIZE(p, num * size);
293
294    /* make sure all the memory was zeroed */
295    for (guint32 i = 0; i < (num * size); i++) {
296        g_assert_cmpint(p[i], ==, 0);
297    }
298
299    /* make sure we can write to all the allocated memory */
300    memset(p, 'A', num * size);
301
302    XtFree(p);
303    g_assert_cmpint(errno, ==, 0);
304}
305
306/* Make sure XtCalloc() returns the expected results for args of 0 */
307static void test_XtCalloc_zero(void)
308{
309    void *p;
310
311    errno = 0;
312
313    p = XtCalloc(0, 0);
314#if !defined(MALLOC_0_RETURNS_NULL) || defined(XTMALLOC_BC)
315    g_assert_nonnull(p);
316    XtFree(p);
317#else
318    g_assert_null(p);
319#endif
320    g_assert_cmpint(errno, ==, 0);
321
322    p = XtCalloc(1, 0);
323#if !defined(MALLOC_0_RETURNS_NULL) || defined(XTMALLOC_BC)
324    g_assert_nonnull(p);
325    XtFree(p);
326#else
327    g_assert_null(p);
328#endif
329    g_assert_cmpint(errno, ==, 0);
330
331    p = XtCalloc(0, 1);
332#if !defined(MALLOC_0_RETURNS_NULL)
333    g_assert_nonnull(p);
334    XtFree(p);
335#else
336    g_assert_null(p);
337#endif
338    g_assert_cmpint(errno, ==, 0);
339
340    /* __XtCalloc always returns a non-NULL pointer for size == 0 */
341    p = __XtCalloc(1, 0);
342    g_assert_nonnull(p);
343    XtFree(p);
344    g_assert_cmpint(errno, ==, 0);
345}
346
347/* Make sure sizes larger than the limit we set in main() fail. */
348static void test_XtCalloc_oversize(void)
349{
350    void *p;
351
352    if (setjmp(jmp_env) == 0) {
353        p = XtCalloc(2, ALLOC_LIMIT);
354        g_assert_null(p);
355    } else {
356        /*
357         * We jumped here from error handler as expected.
358         * We cannot verify errno here, as the Xt error handler makes
359         * calls that override errno, when trying to load error message
360         * files from different locations.
361         */
362    }
363}
364
365/* Make sure XtCalloc catches integer overflow if possible
366 *
367 * Testing integer overflow cases is limited by the fact that XtCalloc
368 * only takes unsigned arguments (typically 32-bit), and relies on
369 * the underlying libc calloc to catch overflow, which can't occur
370 * if 32-bit arguments are passed to a function taking 64-bit args.
371 */
372static void test_XtCalloc_overflow(void)
373{
374#if UINT_MAX < SIZE_MAX
375    g_test_skip("overflow not possible in this config");
376#else
377    void *p;
378
379    if (setjmp(jmp_env) == 0) {
380        p = XtCalloc(2, SIZE_MAX);
381        g_assert_null(p);
382    } else {
383        /*
384         * We jumped here from error handler as expected.
385         * We cannot verify errno here, as the Xt error handler makes
386         * calls that override errno, when trying to load error message
387         * files from different locations.
388         */
389    }
390
391    if (setjmp(jmp_env) == 0) {
392        /* SQRT_SIZE_MAX * SQRT_SIZE_MAX == 0 due to overflow */
393        p = XtCalloc(SQRT_SIZE_MAX, SQRT_SIZE_MAX);
394        g_assert_null(p);
395    } else {
396        /*
397         * We jumped here from error handler as expected.
398         * We cannot verify errno here, as the Xt error handler makes
399         * calls that override errno, when trying to load error message
400         * files from different locations.
401         */
402    }
403
404    if (setjmp(jmp_env) == 0) {
405        /* Overflows to a small positive number */
406        p = XtCalloc(SQRT_SIZE_MAX + 1, SQRT_SIZE_MAX);
407        g_assert_null(p);
408    } else {
409        /*
410         * We jumped here from error handler as expected.
411         * We cannot verify errno here, as the Xt error handler makes
412         * calls that override errno, when trying to load error message
413         * files from different locations.
414         */
415    }
416#endif
417}
418
419/* Make sure XtRealloc() works for a non-zero amount of memory */
420static void test_XtRealloc_normal(void)
421{
422    void *p, *p2;
423    char *p3;
424
425    errno = 0;
426
427    /* Make sure realloc with a NULL pointer acts as malloc */
428    p = XtRealloc(NULL, 814);
429    g_assert_nonnull(p);
430    CHECK_ALIGNMENT(p);
431    CHECK_SIZE(p, 814);
432
433    /* make sure we can write to all the allocated memory */
434    memset(p, 'A', 814);
435
436    /* create another block after the first */
437    p2 = XtMalloc(73);
438    g_assert_nonnull(p2);
439
440    /* now resize the first */
441    p3 = XtRealloc(p, 7314);
442    g_assert_nonnull(p3);
443    CHECK_ALIGNMENT(p3);
444    CHECK_SIZE(p3, 7314);
445
446    /* verify previous values are still present */
447    for (int i = 0; i < 814; i++) {
448        g_assert_cmpint(p3[i], ==, 'A');
449    }
450
451    XtFree(p3);
452    XtFree(p2);
453    g_assert_cmpint(errno, ==, 0);
454}
455
456/* Make sure XtRealloc(0) returns a valid pointer as expected */
457static void test_XtRealloc_zero(void)
458{
459    void *p, *p2;
460
461    errno = 0;
462
463    p = XtRealloc(NULL, 0);
464    g_assert_nonnull(p);
465
466    p2 = XtRealloc(p, 0);
467#ifdef MALLOC_0_RETURNS_NULL
468    g_assert_null(p);
469#else
470    g_assert_nonnull(p);
471#endif
472
473    XtFree(p2);
474    g_assert_cmpint(errno, ==, 0);
475}
476
477/* Make sure sizes larger than the limit we set in main() fail */
478static void test_XtRealloc_oversize(void)
479{
480    void *p, *p2;
481
482    /* Pick a size between 1 & 256K */
483    guint32 size = g_test_rand_int_range(1, (256 * 1024));
484
485    p = XtRealloc(NULL, size);
486    g_assert_nonnull(p);
487    CHECK_ALIGNMENT(p);
488
489    if (setjmp(jmp_env) == 0) {
490        p2 = XtRealloc(p, ALLOC_LIMIT + 1);
491        g_assert_null(p2);
492    } else {
493        /*
494         * We jumped here from error handler as expected.
495         * We cannot verify errno here, as the Xt error handler makes
496         * calls that override errno, when trying to load error message
497         * files from different locations.
498         */
499    }
500
501    errno = 0;
502    XtFree(p);
503    g_assert_cmpint(errno, ==, 0);
504}
505
506/* Make sure XtRealloc catches integer overflow if possible, by requesting
507 * sizes that are so large that they cause overflows when either adding the
508 * realloc data block overhead or aligning.
509 *
510 * Testing integer overflow cases is limited by the fact that XtRealloc
511 * only takes unsigned arguments (typically 32-bit), and relies on
512 * the underlying libc realloc to catch overflow, which can't occur if
513 * 32-bit arguments are passed to a function taking 64-bit args.
514 */
515static void test_XtRealloc_overflow(void)
516{
517#if UINT_MAX < SIZE_MAX
518    g_test_skip("overflow not possible in this config");
519#else
520    void *p, *p2;
521
522    /* Pick a size between 1 & 256K */
523    guint32 size = g_test_rand_int_range(1, (256 * 1024));
524
525    p = XtRealloc(NULL, size);
526    g_assert_nonnull(p);
527    CHECK_ALIGNMENT(p);
528
529    if (setjmp(jmp_env) == 0) {
530        p2 = XtRealloc(p, SIZE_MAX);
531        g_assert_null(p2);
532    } else {
533        /*
534         * We jumped here from error handler as expected.
535         * We cannot verify errno here, as the Xt error handler makes
536         * calls that override errno, when trying to load error message
537         * files from different locations.
538         */
539    }
540
541    if (setjmp(jmp_env) == 0) {
542        p2 = XtRealloc(p, SIZE_MAX - 1);
543        g_assert_null(p2);
544    } else {
545        /*
546         * We jumped here from error handler as expected.
547         * We cannot verify errno here, as the Xt error handler makes
548         * calls that override errno, when trying to load error message
549         * files from different locations.
550         */
551    }
552
553    if (setjmp(jmp_env) == 0) {
554        p2 = XtRealloc(p, SIZE_MAX - 8);
555        g_assert_null(p2);
556    } else {
557        /*
558         * We jumped here from error handler as expected.
559         * We cannot verify errno here, as the Xt error handler makes
560         * calls that override errno, when trying to load error message
561         * files from different locations.
562         */
563    }
564
565    errno = 0;
566    XtFree(p);
567    g_assert_cmpint(errno, ==, 0);
568#endif
569}
570
571
572/* Make sure XtReallocArray() works for a non-zero amount of memory */
573static void test_XtReallocArray_normal(void)
574{
575    void *p, *p2;
576    char *p3;
577
578    errno = 0;
579
580    /* Make sure reallocarray with a NULL pointer acts as malloc */
581    p = XtReallocArray(NULL, 8, 14);
582    g_assert_nonnull(p);
583    CHECK_ALIGNMENT(p);
584    CHECK_SIZE(p, 8 * 14);
585
586    /* make sure we can write to all the allocated memory */
587    memset(p, 'A', 8 * 14);
588
589    /* create another block after the first */
590    p2 = XtMalloc(73);
591    g_assert_nonnull(p2);
592
593    /* now resize the first */
594    p3 = XtReallocArray(p, 73, 14);
595    g_assert_nonnull(p3);
596    CHECK_ALIGNMENT(p3);
597    CHECK_SIZE(p3, 73 * 14);
598    /* verify previous values are still present */
599    for (int i = 0; i < (8 * 14); i++) {
600        g_assert_cmpint(p3[i], ==, 'A');
601    }
602
603    XtFree(p3);
604    XtFree(p2);
605    g_assert_cmpint(errno, ==, 0);
606}
607
608/* Make sure XtReallocArray(0) returns a valid pointer as expected */
609static void test_XtReallocArray_zero(void)
610{
611    void *p, *p2;
612
613    errno = 0;
614
615    p = XtReallocArray(NULL, 0, 0);
616    g_assert_nonnull(p);
617
618    p2 = XtReallocArray(p, 0, 0);
619#ifdef MALLOC_0_RETURNS_NULL
620    g_assert_null(p);
621#else
622    g_assert_nonnull(p);
623#endif
624
625    XtFree(p2);
626    g_assert_cmpint(errno, ==, 0);
627}
628
629/* Make sure sizes larger than the limit we set in main() fail */
630static void test_XtReallocArray_oversize(void)
631{
632    void *p, *p2;
633
634    /* Pick a number of elements between 1 & 16K */
635    guint32 num = g_test_rand_int_range(1, (16 * 1024));
636    /* Pick a size between 1 & 16K */
637    guint32 size = g_test_rand_int_range(1, (16 * 1024));
638
639    p = XtReallocArray(NULL, num, size);
640    g_assert_nonnull(p);
641    CHECK_ALIGNMENT(p);
642    CHECK_SIZE(p, num * size);
643
644    if (setjmp(jmp_env) == 0) {
645        p2 = XtReallocArray(p, 2, ALLOC_LIMIT);
646        g_assert_null(p2);
647    } else {
648        /*
649         * We jumped here from error handler as expected.
650         * We cannot verify errno here, as the Xt error handler makes
651         * calls that override errno, when trying to load error message
652         * files from different locations.
653         */
654    }
655
656    errno = 0;
657    XtFree(p);
658    g_assert_cmpint(errno, ==, 0);
659}
660
661/* Make sure XtReallocArray catches integer overflow if possible, by requesting
662 * sizes that are so large that they cause overflows when either adding the
663 * reallocarray data block overhead or aligning.
664 *
665 * Testing integer overflow cases is limited by the fact that XtReallocArray
666 * only takes unsigned arguments (typically 32-bit), and relies on
667 * the underlying libc reallocarray to catch overflow, which can't occur if
668 * 32-bit arguments are passed to a function taking 64-bit args.
669 */
670static void test_XtReallocArray_overflow(void)
671{
672#if UINT_MAX < SIZE_MAX
673    g_test_skip("overflow not possible in this config");
674#else
675    void *p, *p2;
676
677    /* Pick a number of elements between 1 & 16K */
678    guint32 num = g_test_rand_int_range(1, (16 * 1024));
679    /* Pick a size between 1 & 16K */
680    guint32 size = g_test_rand_int_range(1, (16 * 1024));
681
682    p = XtReallocArray(NULL, num, size);
683    g_assert_nonnull(p);
684    CHECK_ALIGNMENT(p);
685    CHECK_SIZE(p, num * size);
686
687    if (setjmp(jmp_env) == 0) {
688        p2 = XtReallocArray(p, 1, SIZE_MAX);
689        g_assert_null(p2);
690    } else {
691        /*
692         * We jumped here from error handler as expected.
693         * We cannot verify errno here, as the Xt error handler makes
694         * calls that override errno, when trying to load error message
695         * files from different locations.
696         */
697    }
698
699    if (setjmp(jmp_env) == 0) {
700        /* SQRT_SIZE_MAX * SQRT_SIZE_MAX == 0 due to overflow */
701        p2 = XtReallocArray(p, SQRT_SIZE_MAX, SQRT_SIZE_MAX);
702        g_assert_null(p2);
703    } else {
704        /*
705         * We jumped here from error handler as expected.
706         * We cannot verify errno here, as the Xt error handler makes
707         * calls that override errno, when trying to load error message
708         * files from different locations.
709         */
710    }
711
712    if (setjmp(jmp_env) == 0) {
713        /* Overflows to a small positive number */
714        p2 = XtReallocArray(p, SQRT_SIZE_MAX + 1, SQRT_SIZE_MAX);
715        g_assert_null(p2);
716    } else {
717        /*
718         * We jumped here from error handler as expected.
719         * We cannot verify errno here, as the Xt error handler makes
720         * calls that override errno, when trying to load error message
721         * files from different locations.
722         */
723    }
724
725    errno = 0;
726    XtFree(p);
727    g_assert_cmpint(errno, ==, 0);
728#endif
729}
730
731
732int main(int argc, char** argv)
733{
734    struct rlimit lim;
735
736    program_name = argv[0];
737
738    g_test_init(&argc, &argv, NULL);
739    g_test_bug_base("https://gitlab.freedesktop.org/xorg/lib/libxt/-/issues/");
740
741    /* Set a memory limit so we can test allocations over that size fail */
742    g_assert_no_errno(getrlimit(RLIMIT_AS, &lim));
743    if (lim.rlim_cur > ALLOC_LIMIT) {
744        lim.rlim_cur = ALLOC_LIMIT;
745        g_assert_no_errno(setrlimit(RLIMIT_AS, &lim));
746    }
747
748    /* Install xt_error_handler to avoid exit on allocation failure */
749    XtSetErrorHandler(xt_error_handler);
750
751    g_test_add_func("/Alloc/XtAsprintf/short", test_XtAsprintf_short);
752    g_test_add_func("/Alloc/XtAsprintf/long", test_XtAsprintf_long);
753
754    g_test_add_func("/Alloc/XtMalloc/normal", test_XtMalloc_normal);
755    g_test_add_func("/Alloc/XtMalloc/zero", test_XtMalloc_zero);
756    g_test_add_func("/Alloc/XtMalloc/oversize", test_XtMalloc_oversize);
757    g_test_add_func("/Alloc/XtMalloc/overflow", test_XtMalloc_overflow);
758
759    g_test_add_func("/Alloc/XtCalloc/normal", test_XtCalloc_normal);
760    g_test_add_func("/Alloc/XtCalloc/zero", test_XtCalloc_zero);
761    g_test_add_func("/Alloc/XtCalloc/oversize", test_XtCalloc_oversize);
762    g_test_add_func("/Alloc/XtCalloc/overflow", test_XtCalloc_overflow);
763
764    g_test_add_func("/Alloc/XtRealloc/normal", test_XtRealloc_normal);
765    g_test_add_func("/Alloc/XtRealloc/zero", test_XtRealloc_zero);
766    g_test_add_func("/Alloc/XtRealloc/oversize", test_XtRealloc_oversize);
767    g_test_add_func("/Alloc/XtRealloc/overflow", test_XtRealloc_overflow);
768
769    g_test_add_func("/Alloc/XtReallocArray/normal", test_XtReallocArray_normal);
770    g_test_add_func("/Alloc/XtReallocArray/zero", test_XtReallocArray_zero);
771    g_test_add_func("/Alloc/XtReallocArray/oversize",
772                    test_XtReallocArray_oversize);
773    g_test_add_func("/Alloc/XtReallocArray/overflow",
774                    test_XtReallocArray_overflow);
775
776    return g_test_run();
777}
778