diff --git a/libc-test/src/regression/malloc-encode-pointer.c b/libc-test/src/regression/malloc-encode-pointer.c new file mode 100644 index 0000000000000000000000000000000000000000..d72615de8cdba97658de3963bb626b3d3581b57d --- /dev/null +++ b/libc-test/src/regression/malloc-encode-pointer.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include "test.h" + +int main(int argc, char *argv[]) +{ + uintptr_t *c0 = (uintptr_t *)malloc(sizeof(uintptr_t) * 10); + if (!c0) { + t_error("Malloc c0 failed: %s\n", strerror(errno)); + return -1; + } + /* Malloc dividing chunk to avoid combination of neighbouring freed chunk */ + void *d0 = malloc(sizeof(uintptr_t) * 10); + if (!d0) { + t_error("Malloc d0 failed: %s\n", strerror(errno)); + return -1; + } + + uintptr_t *c1 = (uintptr_t *)malloc(sizeof(uintptr_t) * 10); + if (!c1) { + t_error("Malloc c1 failed: %s\n", strerror(errno)); + return -1; + } + /* Malloc dividing chunk to avoid combination of neighbouring freed chunk */ + void *d1 = malloc(sizeof(uintptr_t) * 10); + if (!d1) { + t_error("Malloc d1 failed: %s\n", strerror(errno)); + return -1; + } + + /* Free the chunk, with same size, they're put into the same bin */ + /* -------- -------- -------- + * | c0 | | c1 | | bin | + * -->| next |----->| next |----->| next |----- + * | | prev |<-----| prev |<-----| prev | | + * | ------- ------- ------- | + * -------------------------------------------- + */ + free(c0); + free(c1); + + uintptr_t xoraddr = c0[0]; /* Get the next of c0 */ + uintptr_t realaddr = (uintptr_t)((char *)c1 - sizeof(uintptr_t) * 2); + if (xoraddr == realaddr) { + t_error("encoding pointer is equal to real pointer\n"); + } + + free(d0); + free(d1); + + return t_status; +} diff --git a/libc-test/src/regression/malloc-free-performance.c b/libc-test/src/regression/malloc-free-performance.c new file mode 100644 index 0000000000000000000000000000000000000000..c2a8ba3794535f4a90b8cd2df9d910606c7ec0b2 --- /dev/null +++ b/libc-test/src/regression/malloc-free-performance.c @@ -0,0 +1,194 @@ +#include +#include +#include +#include +#include +#include "test.h" + +#define MALLOC_TIME 131072 +#define CLUSTER_SIZE 16 +#define SIZE_ARR_SIZE 2048 +#define NANOSEC_PER_SEC 1e9 + +/* A random generated size array for performance test + * The sizes array is roughly uniformed distributed in every bin + */ +size_t sizes[SIZE_ARR_SIZE] = { + 70398, 5870, 812, 782, 132092, 44, 10608, 814, 4523, 140, 3989, 2872, 71794, 1503, 3682, +199068, 75, 42231, 682, 622, 154292, 130053, 237, 839, 324, 99182, 140794, 4150, 969, 1080, + 4392, 2978, 202, 174, 4236, 11422, 9935, 449, 164211, 1647, 264, 85939, 125428, 68810, 7330, + 1077, 50947, 224883, 1211, 775, 899, 13313, 13711, 153171, 2629, 29524, 121541, 22415, 462, 547, + 39, 422, 52062, 36162, 517, 1259, 585, 46209, 332, 9488, 555, 940, 395, 108, 70242, + 652, 165, 24921, 10310, 611, 30317, 7061, 43, 170, 553, 127383, 585, 15952, 4790, 82906, + 235, 836, 12391, 267, 28743, 802, 455, 7593, 1992, 865, 1775, 750, 14738, 617, 81735, + 66408, 802, 388, 999, 2000, 18975, 67893, 3, 451, 616, 778, 239766, 6633, 45054, 197, + 303, 12049, 555, 6787, 429, 68, 333, 132413, 937, 12291, 30571, 3302, 44731, 1402, 460, + 772, 3274, 99137, 220195, 3751, 28575, 299, 1893, 229, 487, 21691, 154058, 40029, 4335, 910, +214958, 485, 88161, 900, 14042, 107, 11356, 906, 553, 559, 847, 1593, 815, 271, 8454, + 95479, 814, 486, 556, 325, 13687, 995, 805, 8407, 1179, 332, 244198, 525, 105, 838, +204603, 841, 874, 6653, 647, 9133, 79, 963, 259, 193, 238, 1626, 184019, 968, 360, + 20162, 388, 1368, 31575, 674, 1, 303, 418, 995, 23078, 183823, 56425, 208634, 577, 36907, + 705, 3981, 12763, 328, 621, 4939, 1340, 742, 805, 137, 867, 109, 1466, 205, 1002, + 516, 1007, 742, 258449, 15950, 38, 3818, 295, 552, 39173, 12387, 711, 1376, 29945, 7137, + 1621, 236, 27868, 452, 46, 171, 683, 2843, 6833, 43, 356, 11609, 1305, 805, 53323, + 3832, 198683, 808, 429, 1895, 2713, 558, 654, 813, 9032, 905, 333, 773, 781, 247876, + 47654, 3777, 686, 2506, 5770, 22422, 15557, 292, 79991, 47, 137903, 879, 3736, 20517, 2879, + 460, 749, 423, 61714, 493, 95574, 13594, 69, 10209, 806, 975, 357, 905, 9232, 27054, +235843, 7299, 56998, 106, 7697, 422, 577, 428, 32538, 455, 4304, 1942, 2946, 3531, 424, + 1834, 780, 2013, 228, 159815, 79256, 751, 204, 973, 965, 194, 776, 98967, 5460, 462, + 70645, 111, 6, 1003, 389, 101973, 3200, 463, 43516, 3029, 783, 837, 683, 11671, 33303, + 47768, 10458, 179347, 973, 38940, 75350, 14263, 261886, 333, 4954, 300, 907, 17111, 68577, 19266, + 782, 802, 937, 26320, 28570, 2830, 686, 292, 484, 334, 143, 64594, 54629, 552, 137, + 871, 3248, 1684, 327, 203105, 128726, 3817, 55839, 3382, 163, 151956, 98, 5776, 841, 4906, +138722, 130420, 57664, 3453, 20918, 166702, 260, 226203, 715, 134, 655, 2196, 33196, 515, 233, + 11594, 116927, 3203, 164, 30898, 17118, 1816, 715, 58259, 173, 226, 122801, 17628, 80971, 217244, + 83675, 103, 616, 3842, 47968, 452, 385, 975, 617, 449, 514, 27115, 3, 117059, 2465, + 64951, 2461, 588, 2003, 482, 682, 216424, 488, 101, 20908, 134882, 3347, 388, 547, 975, + 5, 616, 513, 876, 1001, 389, 259, 684, 3288, 106796, 5408, 769, 2984, 45442, 8939, + 9359, 5672, 553, 2258, 9126, 738, 67280, 65, 53874, 3215, 246562, 3820, 996, 156079, 101, + 4231, 651, 12558, 324, 577, 716, 16016, 269, 934, 841, 14866, 609, 21962, 1920, 267, + 674, 676, 70, 488, 707, 99, 322, 129879, 2967, 550, 903, 810, 741, 1739, 76817, + 1514, 875, 75663, 102461, 5887, 5522, 171815, 1220, 206, 559, 134, 744, 900, 5656, 6482, + 5913, 15317, 69, 1500, 14341, 423, 78476, 362, 107, 939, 4963, 47, 240406, 14778, 903, + 330, 2130, 323, 1320, 2378, 64207, 4861, 160245, 231, 171, 609, 161, 11773, 22211, 10458, + 47327, 647, 23595, 41, 333, 1610, 709, 18849, 195435, 558, 866, 18759, 72108, 3244, 102716, + 73862, 353, 302, 6803, 455, 15788, 53140, 109524, 777, 969, 113077, 454, 875, 235, 23856, + 644, 21337, 45424, 873, 161, 652, 807, 99721, 27553, 357, 190179, 330, 14428, 589, 3347, + 65978, 9364, 835, 2002, 47, 995, 930, 1253, 387, 6780, 1998, 905, 29723, 610, 79, + 290, 37169, 1971, 743, 172, 14856, 11888, 943, 1859, 1208, 40, 47201, 23335, 5233, 12980, +171863, 3036, 9107, 45, 490, 869, 6588, 333, 746, 26871, 118844, 127074, 551, 813, 20159, + 3136, 197941, 996, 654, 12931, 3141, 1300, 610, 804, 805, 1345, 197261, 168, 263, 362, + 3293, 3166, 178245, 521, 3116, 43376, 262, 933, 72, 170, 34, 19267, 104, 524, 649, + 139, 387, 1138, 16827, 911, 13562, 1722, 4281, 591, 52262, 193, 238772, 70881, 8430, 453, + 1945, 126322, 164070, 97918, 354, 98, 3662, 22224, 3309, 102266, 877, 645, 59699, 931, 648, + 2134, 214595, 4001, 129563, 5792, 52854, 13, 611, 9275, 45407, 679, 4802, 7668, 53087, 97, + 30461, 73, 203, 14303, 324, 261, 140, 940, 100389, 518, 18613, 253547, 519, 71172, 26630, + 551, 1739, 769, 167627, 6280, 931, 229, 108315, 89014, 12596, 1953, 19134, 57947, 427, 206, + 6173, 3532, 8619, 38561, 138, 22338, 519, 106, 932, 259336, 232, 5748, 207, 61851, 487, + 616, 680, 163, 64600, 7255, 780, 936, 647, 33859, 942, 136598, 708, 866, 196, 17475, + 524, 492, 182291, 3859, 484, 16731, 13992, 513, 10509, 40595, 77200, 15873, 715, 8122, 929, + 31017, 962, 616, 739, 517, 397, 452, 425, 146686, 2005, 173, 1348, 5228, 4, 652, + 14700, 359, 321, 5388, 778, 271, 84182, 966, 34596, 35, 356, 28288, 121659, 1796, 17260, + 808, 243982, 12292, 75, 7399, 548, 217421, 289, 559, 50038, 673, 769, 10769, 1934, 488, + 298, 36678, 389, 581, 89654, 4883, 18525, 676, 65, 55459, 74196, 109744, 623, 2527, 94923, + 328, 900, 328, 1101, 64821, 801, 2197, 201, 68, 1004, 72, 143, 4917, 2409, 449, + 8, 1000, 745, 201, 195, 546, 930, 5793, 15314, 11095, 2756, 3127, 8121, 38, 870, + 11231, 3838, 74228, 63376, 56633, 159022, 942, 174037, 182329, 30664, 150490, 801, 40, 24289, 675, + 547, 4046, 481, 61835, 964, 133, 45929, 35021, 4224, 1000, 910, 30014, 216676, 107110, 59468, +127074, 586, 67, 68, 4344, 3758, 129795, 426, 458, 1466, 556, 295, 26140, 98849, 56438, +161433, 108530, 649, 16593, 54624, 58346, 131, 83535, 1549, 227, 45126, 15, 967, 196, 1031, + 289, 12894, 7347, 11, 808, 29130, 619, 101, 264, 652, 6118, 5445, 270, 938, 1001, + 398, 810, 9316, 194708, 993, 1902, 3191, 293, 98, 527, 1645, 1512, 1988, 586, 76639, +182172, 804, 254145, 866, 30406, 588, 418, 428, 1594, 5151, 4881, 8454, 714, 29323, 515, + 806, 20037, 2379, 77376, 7505, 122331, 67, 46036, 1000, 1046, 333, 621, 582, 207, 555, + 23285, 1917, 937, 519, 267, 35, 77624, 358, 587, 162, 29879, 141182, 194, 20079, 654, + 1717, 10064, 3432, 462, 1001, 23544, 804, 1872, 710, 494, 4163, 8624, 325, 29374, 237775, +161384, 392, 3701, 27911, 4655, 361, 24420, 78, 300, 321, 36528, 876, 739, 620, 1149, + 550, 30840, 164, 484, 525, 292, 520, 2, 485, 6254, 1723, 394, 260413, 1940, 11780, + 2444, 993, 869, 32460, 942, 1384, 1004, 1479, 99, 5976, 335, 389, 299, 90270, 962, + 15520, 2144, 869, 32604, 5137, 549, 63247, 122549, 557, 303, 8963, 206, 6963, 130, 123812, + 332, 3419, 74006, 12617, 484, 163211, 1551, 545, 395, 911, 939, 5195, 42, 26251, 80176, + 4982, 746, 24097, 490, 124671, 70629, 236138, 7829, 79143, 32527, 430, 929, 29291, 335, 2397, + 589, 166, 868, 66068, 709, 298, 8929, 5659, 778, 484, 53316, 872, 591, 27338, 29233, + 1002, 1914, 13784, 878, 4677, 870, 7, 93312, 966, 334, 931, 291, 680, 229, 91335, + 974, 1, 163843, 232509, 719, 295, 815, 66563, 25897, 2112, 137, 206975, 122126, 5636, 840, +178041, 121125, 96929, 12271, 525, 1194, 39935, 1812, 359, 70, 586, 28109, 655, 1823, 15971, + 1165, 50539, 7517, 613, 4334, 869, 143267, 33, 120769, 41743, 181472, 136, 775, 898, 687, + 87489, 81862, 526, 1041, 119803, 203, 556, 2830, 1753, 995, 968, 1000, 362, 105558, 25289, + 30313, 167, 897, 483, 87996, 131, 1286, 73, 4778, 3765, 162611, 2258, 4071, 577, 740, + 19328, 23181, 44833, 356, 300, 481, 101, 1945, 55445, 7862, 586, 1690, 108, 3179, 6265, + 833, 232, 513, 774, 38, 1006, 16313, 2, 5722, 929, 648, 124091, 3128, 12, 653, + 289, 168, 113025, 394, 22275, 36138, 934, 33296, 44428, 648, 23347, 36, 966, 7656, 30616, + 303, 12065, 395, 2175, 110915, 3400, 3985, 547, 1457, 77770, 775, 942, 677, 47, 845, +261480, 20514, 26542, 644, 709, 8629, 160291, 43, 12951, 613, 771, 490, 172, 23687, 2678, +112194, 15152, 583, 6109, 76361, 48932, 138769, 68824, 256665, 1214, 427, 197349, 11553, 35, 292, + 7826, 386, 15287, 143431, 139, 742, 783, 7933, 550, 61036, 153864, 5527, 1220, 179326, 52538, + 297, 331, 116679, 32116, 548, 7180, 24432, 150458, 647, 198, 230679, 492, 183327, 10, 582, + 46, 742, 19932, 139, 333, 838, 190324, 82554, 3673, 263, 810, 20105, 18894, 801, 3902, + 3452, 203, 30556, 521, 805, 399, 491, 261614, 132, 745, 646, 621, 815, 21428, 32822, + 941, 35, 775, 803, 9277, 77, 3531, 73, 877, 353, 582, 1561, 1794, 6272, 14250, + 10258, 87923, 16317, 1574, 107483, 118292, 230, 492, 193, 522, 903, 21672, 259, 101987, 5379, + 547, 42742, 131, 909, 11141, 45670, 650, 327, 203, 417, 1822, 73206, 4047, 5651, 31863, + 364, 6056, 482, 2414, 686, 67, 116497, 233, 89151, 712, 1960, 15023, 457, 911, 87709, + 326, 647, 131, 1544, 493, 103295, 35, 4201, 120600, 679, 4536, 354, 649, 12877, 514, + 11, 7599, 492, 66894, 779, 5012, 803, 270, 27587, 1716, 653, 15, 1745, 81311, 142, + 74662, 2476, 847, 621, 2326, 842, 183990, 48969, 37165, 258, 15920, 1450, 139424, 97, 622, +217730, 389, 14629, 682, 82614, 10637, 170, 205, 16924, 1684, 525, 675, 2, 39617, 237, + 324, 623, 3998, 171709, 130, 44293, 301, 900, 36268, 297, 130, 3905, 364, 8500, 6175, + 267, 74017, 387, 963, 869, 0, 653, 324, 813, 138388, 673, 132383, 835, 2206, 259, + 87218, 99, 7984, 521, 808, 9500, 126004, 1614, 20344, 142, 972, 9619, 684, 1709, 430, + 260, 112449, 73506, 867, 15030, 37867, 417, 874, 43752, 7460, 63448, 582, 1796, 8038, 1495, + 19720, 234481, 43216, 554, 33, 137, 908, 2959, 11, 106, 642, 37055, 973, 495, 969, + 73, 836, 84397, 94851, 1000, 354, 18329, 38597, 970, 16503, 1215, 900, 9823, 9582, 132, + 8123, 801, 236, 642, 929, 120593, 713, 486, 34, 241685, 492, 49871, 30206, 2905, 936, + 6818, 14692, 461, 714, 70500, 718, 868, 996, 65063, 737, 559, 677, 555, 6234, 5245, + 1136, 553, 751, 236, 67, 1167, 28052, 199, 2634, 22830, 38653, 1874, 366, 579, 7451, +194153, 488, 907, 13417, 616, 1593, 293, 14217, 3553, 419, 492, 835, 334, 3730, 875, + 775, 969, 3959, 430, 930, 167, 616, 651, 968, 644, 556, 8349, 710, 551, 647, + 527, 170, 652, 5834, 43, 78, 205, 678, 748, 650, 998, 495, 556, 108, 1917, + 484, 111, 1540, 11, 86819, 547, 267, 527, 21645, 549, 611, 7878, 163845, 269, 1004, + 750, 994, 101, 28372, 386, 173, 3086, 48514, 8148, 961, 9005, 12271, 619, 641, 7038, + 263, 1768, 910, 6053, 6276, 88873, 623, 170360, 685, 16800, 2299, 2431, 35377, 147880, 643, +128403, 5086, 97, 131, 583, 1690, 939, 6601, 221042, 79, 30789, 357, 87455, 522, 239, + 904, 5, 1174, 293, 18785, 587, 3587, 238, 335, 581, 36976, 40494, 933, 198961, 1719, + 554, 267, 132, 674, 421, 5792, 745, 492, 2013, 2290, 3834, 106626, 773, 270, 175, + 901, 6109, 4583, 422, 127089, 73, 88055, 43610, 72305, 1878, 425, 44179, 2765, 1200, 2753, + 749, 150927, 3509, 14040, 1549, 424, 454, 219113, 491, 910, 622, 160490, 21886, 715, 457, + 63071, 178200, 3760, 770, 705, 255855, 1254, 5798, 527, 676, 7920, 716, 17543, 294, 813, + 68, 221793, 100, 1636, 106218, 747, 877, 193, 686, 203251, 100, 587, 554, 1477, 335, + 31222, 324, 398, 711, 5926, 4036, 326, 60222, 233, 3716, 65404, 16007, 142, 419, 874, + 1001, 1829, 253309, 59056, 973, 3390, 1432, 236, 15, 2726, 642, 617, 3782, 135, 186049, + 359, 14274, 193, 972, 105, 934, 47, 810, 746, 744, 41, 813, 16071, 8974, 36929, + 610, 169, 12477, 13763, 259, 259, 845, 2367, 549, 430, 70141, 685, 1962, 580, 68783, + 66713, 196, 387, 292, 1, 9189, 61834, 558, 107624, 750, 367, 678, 1327, 2686, 229, + 91802, 4874, 173587, 31323, 13180, 740, 124601, 1433, 7331, 15637, 1713, 579, 876, 16730, 3138, + 936, 61890, 993, 91003, 102014, 195, 78, 1178, 463, 221454, 451, 59083, 742, 615, 586, +255579, 774, 32922, 6243, 325, 675, 44268, 553, 112234, 1506, 903, 778, 492, 3168, 63549, + 879, 4683, 8721, 7697, 327, 105304, 164, 50339, 171, 55374, 5043, 705, 3741, 16724, 271, + 196, 932, 771, 391, 999, 85846, 51146, 257, 686, 937, 41264, 1003, 197, 20528, 614, + 929, 965, 299, 109, 84938, 7700, 126923, 24435, 460, 551, 591, 18712, 589, 57468, 8396, +172592, 2621, 105, 557, 101, 4858, 187139, 520, 3930, 47360, 296, 259193, 88797, 18147, 642, +122056, 3308, 11404, 452, 20060, 334, 7, 140626, 52316, 13883, 868, 24962, 19392, 7411, 901, +191194, 581, 78399, 386, 200180, 774, 684, 514, 5030, 33323, 21820, 421, 7067, 484, 962, + 683, 75, 209451, 3966, 38, 237, 13130, 23696 +}; + + +int main(int argc, char *argv[]) +{ + cpu_set_t mask; + void *ptr[CLUSTER_SIZE] = {0}; + struct timespec ts[2]; + + CPU_ZERO(&mask); + CPU_SET(0, &mask); + if (sched_setaffinity(0, sizeof(mask), &mask) < 0) { + t_error("Set CPU affinity failure, ERROR:%s\n", strerror(errno)); + return -1; + } + + clock_gettime(CLOCK_REALTIME, ts); + size_t index = 0; + for (int i = 0; i < MALLOC_TIME / CLUSTER_SIZE; ++i) { + for (int j = 0; j < CLUSTER_SIZE; ++j) { + ptr[j] = malloc(sizes[index]); + if (!ptr[j]) { + t_error("Malloc size of %u byte(s) failed: %s\n", sizes[index], strerror(errno)); + return -1; + } + ++index; + index %= SIZE_ARR_SIZE; + } + for (int j = 0; j < CLUSTER_SIZE; ++j) { + free(ptr[j]); + } + } + clock_gettime(CLOCK_REALTIME, ts + 1); + + double cost = (ts[1].tv_sec - ts[0].tv_sec) * NANOSEC_PER_SEC + + (ts[1].tv_nsec - ts[0].tv_nsec); + + t_printf("Malloc and free %d times cost %lf s\n", MALLOC_TIME, cost / NANOSEC_PER_SEC); + + return t_status; +} diff --git a/libc-test/src/regression/malloc-modify-pointer.c b/libc-test/src/regression/malloc-modify-pointer.c new file mode 100644 index 0000000000000000000000000000000000000000..49a454625df7a15022f29563146552456289c3f6 --- /dev/null +++ b/libc-test/src/regression/malloc-modify-pointer.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include "test.h" + +static void handler(int s) +{ +} + +static int child(void) +{ + uintptr_t *p = (uintptr_t *)malloc(10 * sizeof(uintptr_t)); + if (!p) { + t_error("Malloc failed:%s\n", strerror(errno)); + return -1; + } + /* Malloc a dividing chunk to avoid combination of neighbouring freed chunk */ + malloc(10 * sizeof(uintptr_t)); + free(p); + /* Reverse the pointer getting an illegal pointer */ + *p = ~*p; + /* Malloc same chunk to trigger illegal pointer access */ + p = (uintptr_t *)malloc(10 *sizeof(uintptr_t)); + return 0; +} + +static pid_t start_child(void) +{ + pid_t pid; + int ret; + pid = fork(); + if (pid == 0) { + ret = child(); + t_error("child process normally out with %d\n", ret); + return ret; + } + return pid; +} + +int main(int argc, char *argv[]) +{ + sigset_t set; + int status; + pid_t pid; + int flag = 0; + + sigemptyset(&set); + sigaddset(&set, SIGCHLD); + sigprocmask(SIG_BLOCK, &set, 0); + signal(SIGCHLD, handler); + + pid = start_child(); + if (pid == -1) { + t_error("%s fork failed: %s\n", argv[0], strerror(errno)); + return -1; + } + if (sigtimedwait(&set, 0, &(struct timespec){5, 0}) == -1) { /* Wait for 5 seconds */ + if (errno == EAGAIN) + flag = 1; + else + t_error("%s sigtimedwait failed: %s\n", argv[0], strerror(errno)); + if (kill(pid, SIGKILL) == -1) + t_error("%s kill failed: %s\n", argv[0], strerror(errno)); + } + + if (waitpid(pid, &status, 0) != pid) { + t_error("%s waitpid failed: %s\n", argv[0], strerror(errno)); + return -1; + } + + if (flag) { + t_error("Child process time out\n"); + } + + if (WIFSIGNALED(status)) { + if (WTERMSIG(status) != SIGSEGV) { + t_error("%s child process out with %s\n", argv[0], strsignal(WTERMSIG(status))); + return -1; + } + } else { + t_error("%s child process finished normally\n", argv[0]); + } + return t_status; +} diff --git a/libc-test/src/regression/malloc-pressure.c b/libc-test/src/regression/malloc-pressure.c new file mode 100644 index 0000000000000000000000000000000000000000..1cb74ddd96877e1d5ff5ec3d81a85e1cd5b00cd1 --- /dev/null +++ b/libc-test/src/regression/malloc-pressure.c @@ -0,0 +1,26 @@ +#include +#include +#include "test.h" + +#define SIZE_ALIGN (4 * sizeof(size_t)) +#define THRESHOLD (0x1c00 * SIZE_ALIGN) +#define ITER_TIME 20 + +int main(int argc, char *argv[]) +{ + struct timespec ts[2]; + + clock_gettime(CLOCK_REALTIME, &ts[0]); + for (int i = 0; i < ITER_TIME; ++i) { + for (size_t size = 0; size < THRESHOLD; size += SIZE_ALIGN + 1) { + void *ptr = malloc(size); + if (!ptr) { + t_error("Malloc failed for size %u\n", size); + return -1; + } + free(ptr); + } + } + + return t_status; +} diff --git a/libc-test/src/regression/malloc-safe-unlink.c b/libc-test/src/regression/malloc-safe-unlink.c new file mode 100644 index 0000000000000000000000000000000000000000..687a8c1f743de077e1e705d080327876865d7d21 --- /dev/null +++ b/libc-test/src/regression/malloc-safe-unlink.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include "test.h" + +static void handler(int s) +{ +} + +static int child(void) +{ + uintptr_t *c0 = (uintptr_t *)malloc(sizeof(uintptr_t) * 10); + if (!c0) { + t_error("Malloc failed: %s\n", strerror(errno)); + return -1; + } + /* Malloc a dividing chunk to avoiding combination of neighbouring chunk */ + malloc(sizeof(uintptr_t) * 10); + /* Malloc another chunk */ + uintptr_t *c1 = (uintptr_t *)malloc(sizeof(uintptr_t) * 10); + if (!c1) { + t_error("Malloc failed: %s\n", strerror(errno)); + return -1; + } + /* Malloc a dividing chunk to avoiding combination of neighbouring chunk */ + malloc(sizeof(uintptr_t) * 10); + + /* Free the chunk, now they are in same list */ + free(c0); + free(c1); + + /* Exchange the next and prev pointer in chunk */ + /* They are legal but wrongly pointing */ + uintptr_t temp = c0[0]; + c0[0] = c0[1]; + c0[1] = temp; + + /* Malloc again, trigger the safe-unlink check */ + c0 = (uintptr_t *)malloc(sizeof(uintptr_t) * 10); + c1 = (uintptr_t *)malloc(sizeof(uintptr_t) * 10); + return 0; +} + +static pid_t start_child(void) +{ + pid_t pid; + int ret; + pid = fork(); + if (pid == 0) { + ret = child(); + t_error("child process normally out with %d\n", ret); + return ret; + } + return pid; +} + +int main(int argc, char *argv[]) +{ + sigset_t set; + int status; + pid_t pid; + int flag = 0; + + sigemptyset(&set); + sigaddset(&set, SIGCHLD); + sigprocmask(SIG_BLOCK, &set, 0); + signal(SIGCHLD, handler); + + pid = start_child(); + if (pid == -1) { + t_error("%s fork failed: %s\n", argv[0], strerror(errno)); + return -1; + } + if (sigtimedwait(&set, 0, &(struct timespec){5, 0}) == -1) { /* Wait for 5 seconds */ + if (errno == EAGAIN) + flag = 1; + else + t_error("%s sigtimedwait failed: %s\n", argv[0], strerror(errno)); + if (kill(pid, SIGKILL) == -1) + t_error("%s kill failed: %s\n", argv[0], strerror(errno)); + } + + if (waitpid(pid, &status, 0) != pid) { + t_error("%s waitpid failed: %s\n", argv[0], strerror(errno)); + return -1; + } + + if (flag) { + t_error("Child process time out\n"); + } + + if (WIFSIGNALED(status)) { + if (WTERMSIG(status) != SIGSEGV) { + t_error("%s child process out with %s\n", argv[0], strsignal(WTERMSIG(status))); + return -1; + } + } else { + t_error("%s child process finished normally\n", argv[0]); + } + return t_status; +} diff --git a/libc-test/src/regression/test_src_regression.gni b/libc-test/src/regression/test_src_regression.gni index 26ba05c87b2ababf2eceef85cb7e1199b144002e..ffaf1030bbda88ae69a7b872c883ca1a0d99b7b3 100644 --- a/libc-test/src/regression/test_src_regression.gni +++ b/libc-test/src/regression/test_src_regression.gni @@ -20,6 +20,11 @@ regression_list = [ "malloc-0", "malloc-brk-fail", "malloc-oom", + "malloc-modify-pointer", + "malloc-safe-unlink", + "malloc-encode-pointer", + "malloc-free-performance", + "malloc-pressure", "mbsrtowcs-overflow", "memmem-oob-read", "memmem-oob", diff --git a/musl_config.gni b/musl_config.gni index 8ce8b48b063de15be69c827933528326f0dfeaad..42e8bb28c4f21cfe0059687ebc936bf5ae63f44d 100644 --- a/musl_config.gni +++ b/musl_config.gni @@ -52,4 +52,5 @@ declare_args() { declare_args() { enable_musl_log = false + musl_secure_level = 1 } diff --git a/musl_src.gni b/musl_src.gni index 9c9dabc3f4e9806f9efb869c7e846ced2b63c711..5e10c39644c97ed48d1e5170fdd25d066cbff790 100644 --- a/musl_src.gni +++ b/musl_src.gni @@ -461,6 +461,7 @@ musl_src_file = [ "src/malloc/expand_heap.c", "src/malloc/lite_malloc.c", "src/malloc/malloc.c", + "src/malloc/malloc_random.c", "src/malloc/malloc_usable_size.c", "src/malloc/mallocng/mallinfo.c", "src/malloc/memalign.c", @@ -1897,6 +1898,7 @@ musl_src_porting_file = [ "src/linux/reboot.c", "src/linux/tgkill.c", "src/malloc/malloc.c", + "src/malloc/malloc_random.c", "src/multibyte/wcsnrtombs.c", "src/network/inet_legacy.c", "src/passwd/getspnam_r.c", diff --git a/musl_template.gni b/musl_template.gni index 5f1074e41958af1c4a4657241e0e642be407a67a..9914c2d2688f94be08c7449423b86c6e500eccf1 100644 --- a/musl_template.gni +++ b/musl_template.gni @@ -300,8 +300,15 @@ template("musl_libs") { ] } + defines = [] if ("${target_abi}" == "a7_hard_neon-vfpv4") { - defines = [ "__ARM_PCS_VFP" ] + defines += [ "__ARM_PCS_VFP" ] + } + if (musl_secure_level > 0) { + defines += [ "MALLOC_FREELIST_HARDENED" ] + } + if (musl_secure_level >= 3) { + defines += [ "MALLOC_SECURE_ALL" ] } foreach(s, sources_orig) { diff --git a/porting/linux/user/src/internal/malloc_config.h b/porting/linux/user/src/internal/malloc_config.h new file mode 100644 index 0000000000000000000000000000000000000000..4be035ac84c698480fda6b02467d822b6fce68ee --- /dev/null +++ b/porting/linux/user/src/internal/malloc_config.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef MALLOC_SECURE_ALL + +#ifndef MALLOC_FREELIST_HARDENED +#define MALLOC_FREELIST_HARDENED +#endif + +#endif // MALLOC_SECURE_ALL diff --git a/porting/linux/user/src/internal/malloc_impl.h b/porting/linux/user/src/internal/malloc_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..a689202e3437a9e93552ad0693b19d11f2a5c198 --- /dev/null +++ b/porting/linux/user/src/internal/malloc_impl.h @@ -0,0 +1,50 @@ +#ifndef MALLOC_IMPL_H +#define MALLOC_IMPL_H + +#include +#include "malloc_config.h" + +hidden void *__expand_heap(size_t *); + +hidden void __malloc_donate(char *, char *); + +hidden void *__memalign(size_t, size_t); + +struct chunk { + size_t psize, csize; + struct chunk *next, *prev; +}; + +struct bin { + volatile int lock[2]; + struct chunk *head; + struct chunk *tail; +#ifdef MALLOC_FREELIST_HARDENED + void *key; +#endif +}; + +#define SIZE_ALIGN (4*sizeof(size_t)) +#define SIZE_MASK (-SIZE_ALIGN) +#define OVERHEAD (2*sizeof(size_t)) +#define MMAP_THRESHOLD (0x1c00*SIZE_ALIGN) +#define DONTCARE 16 +#define RECLAIM 163840 + +#define CHUNK_SIZE(c) ((c)->csize & -2) +#define CHUNK_PSIZE(c) ((c)->psize & -2) +#define PREV_CHUNK(c) ((struct chunk *)((char *)(c) - CHUNK_PSIZE(c))) +#define NEXT_CHUNK(c) ((struct chunk *)((char *)(c) + CHUNK_SIZE(c))) +#define MEM_TO_CHUNK(p) (struct chunk *)((char *)(p) - OVERHEAD) +#define CHUNK_TO_MEM(c) (void *)((char *)(c) + OVERHEAD) +#define BIN_TO_CHUNK(i) (MEM_TO_CHUNK(&mal.bins[i].head)) + +#define C_INUSE ((size_t)1) + +#define IS_MMAPPED(c) !((c)->csize & (C_INUSE)) + +hidden void __bin_chunk(struct chunk *); + +hidden extern int __malloc_replaced; + +#endif diff --git a/porting/linux/user/src/internal/malloc_random.h b/porting/linux/user/src/internal/malloc_random.h new file mode 100644 index 0000000000000000000000000000000000000000..2edfa072db08c15ec25229b0ea5109ec31404349 --- /dev/null +++ b/porting/linux/user/src/internal/malloc_random.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "malloc_config.h" + +void* encode_ptr(void *ptr, void *key); +void* next_key(void); diff --git a/porting/linux/user/src/malloc/malloc.c b/porting/linux/user/src/malloc/malloc.c index 45a1a936bac5b7f123d434d35b0bc95dadb2e714..bc472cf07c418e4570c74791bf3d0e472d83eb69 100644 --- a/porting/linux/user/src/malloc/malloc.c +++ b/porting/linux/user/src/malloc/malloc.c @@ -9,6 +9,7 @@ #include "atomic.h" #include "pthread_impl.h" #include "malloc_impl.h" +#include "malloc_random.h" #include #if defined(__GNUC__) && defined(__PIC__) @@ -30,6 +31,16 @@ int __malloc_replaced; /* Synchronization tools */ +static inline struct chunk *encode_chunk(struct chunk *ptr, void *key) +{ +#ifndef MALLOC_FREELIST_HARDENED + (void)key; + return ptr; +#else + return (struct chunk *)encode_ptr(ptr, key); +#endif +} + static inline void lock(volatile int *lk) { if (libc.threads_minus_1) @@ -47,8 +58,14 @@ static inline void unlock(volatile int *lk) static inline void lock_bin(int i) { lock(mal.bins[i].lock); - if (!mal.bins[i].head) + if (!mal.bins[i].head) { +#ifdef MALLOC_FREELIST_HARDENED + mal.bins[i].key = next_key(); + mal.bins[i].head = mal.bins[i].tail = encode_chunk(BIN_TO_CHUNK(i), mal.bins[i].key); +#else mal.bins[i].head = mal.bins[i].tail = BIN_TO_CHUNK(i); +#endif + } } static inline void unlock_bin(int i) @@ -193,10 +210,22 @@ static int adjust_size(size_t *n) static void unbin(struct chunk *c, int i) { +#ifdef MALLOC_FREELIST_HARDENED + void *key = mal.bins[i].key; +#else + void *key = NULL; +#endif + struct chunk *next = encode_chunk(c->next, key); + struct chunk *prev = encode_chunk(c->prev, key); + if (prev->next != encode_chunk(c, key) || + next->prev != encode_chunk(c, key)) { + /* crash when the double-link list is corrupt */ + a_crash(); + } if (c->prev == c->next) a_and_64(&mal.binmap, ~(1ULL<prev->next = c->next; - c->next->prev = c->prev; + prev->next = c->next; + next->prev = c->prev; c->csize |= C_INUSE; NEXT_CHUNK(c)->psize |= C_INUSE; } @@ -258,10 +287,17 @@ static int pretrim(struct chunk *self, size_t n, int i, int j) next = NEXT_CHUNK(self); split = (void *)((char *)self + n); +#ifdef MALLOC_FREELIST_HARDENED + void *key = mal.bins[j].key; +#else + void *key = NULL; +#endif + struct chunk *realprev = encode_chunk(self->prev, key); + struct chunk *realnext = encode_chunk(self->next, key); split->prev = self->prev; split->next = self->next; - split->prev->next = split; - split->next->prev = split; + realprev->next = encode_chunk(split, key); + realnext->prev = encode_chunk(split, key); split->psize = n | C_INUSE; split->csize = n1-n; next->psize = n1-n; @@ -328,7 +364,12 @@ void *malloc(size_t n) } j = first_set(mask); lock_bin(j); - c = mal.bins[j].head; +#ifdef MALLOC_FREELIST_HARDENED + void *key = mal.bins[j].key; +#else + void *key = NULL; +#endif + c = encode_chunk(mal.bins[j].head, key); /* Decode the head pointer */ if (c != BIN_TO_CHUNK(j)) { if (!pretrim(c, n, i, j)) unbin(c, j); unlock_bin(j); @@ -503,10 +544,16 @@ void __bin_chunk(struct chunk *self) next->psize = final_size; unlock(mal.free_lock); - self->next = BIN_TO_CHUNK(i); +#ifdef MALLOC_FREELIST_HARDENED + void *key = mal.bins[i].key; +#else + void *key = NULL; +#endif + self->next = encode_chunk(BIN_TO_CHUNK(i), key); self->prev = mal.bins[i].tail; - self->next->prev = self; - self->prev->next = self; + struct chunk *xorptr = encode_ptr(self, key); + encode_chunk(mal.bins[i].tail, key)->next = xorptr; + mal.bins[i].tail = xorptr; /* Replace middle of large chunks with fresh zero pages */ if (reclaim) { diff --git a/porting/linux/user/src/malloc/malloc_random.c b/porting/linux/user/src/malloc/malloc_random.c new file mode 100644 index 0000000000000000000000000000000000000000..b971024ec553fdaaeca915943607ff954e0bcfa8 --- /dev/null +++ b/porting/linux/user/src/malloc/malloc_random.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include "malloc_random.h" + +#ifdef MALLOC_FREELIST_HARDENED +static bool get_random(uint64_t *x) +{ + int fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + return false; + } + int ret = read(fd, x, sizeof(uint64_t)); + if (ret < 0) { + close(fd); + return false; + } + + close(fd); + return true; +} + +void* next_key() +{ + uint64_t x = 0; + struct timespec ts; + /* Try to use urandom to get the random number first */ + if (!get_random(&x)) { + /* Can't get random number from /dev/urandom, generate from addr based on ASLR and time */ + (void)clock_gettime(CLOCK_REALTIME, &ts); + x = (((uint64_t)get_random) << 32) ^ (uint64_t)next_key ^ ts.tv_nsec; + } + /* Return an odd key, make sure that the xor pointer being odd */ + return (void *)(x | 1); +} + +void* encode_ptr(void *ptr, void *key) +{ + return (void *)((uintptr_t)ptr ^ (uintptr_t)key); +} + +#else // MALLOC_FREELIST_HARDENED +void* encode_ptr(void *ptr, void *key) +{ + (void)key; + return ptr; +} +#endif // MALLOC_FREELIST_HARDENED