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