1/*
2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <gtest/gtest.h>
17#include <fcntl.h>
18#include <cinttypes>
19#include <climits>
20#include <cstdio>
21#include <cstdlib>
22#include <unistd.h>
23#include <iomanip>
24#include <iostream>
25#include <string>
26#include <vector>
27#include <sys/mman.h>
28#include <sys/utsname.h>
29#include <string>
30#include <regex>
31#include "securec.h"
32
33#define PAGE_SIZE 4096
34
35
36using namespace testing::ext;
37using namespace std;
38
39class MadviseApiTest : public testing::Test {
40public:
41    static void SetUpTestCase();
42    static void TearDownTestCase();
43    void SetUp();
44    void TearDown();
45private:
46};
47void MadviseApiTest::SetUp()
48{
49}
50void MadviseApiTest::TearDown()
51{
52}
53void MadviseApiTest::SetUpTestCase()
54{
55}
56void MadviseApiTest::TearDownTestCase()
57{
58}
59
60static void CreateFile()
61{
62    FILE *file;
63    int ret = -1;
64    char *buffer =  static_cast<char *>(malloc(PAGE_SIZE));
65    if (buffer != nullptr) {
66        ret = memset_s(buffer, PAGE_SIZE, 'a', PAGE_SIZE);
67        ASSERT_TRUE(ret == 0);
68        file = fopen("output_file.txt", "wb");
69        if (fwrite(buffer, 1, PAGE_SIZE, file) != PAGE_SIZE) {
70            std::cout << "Error fwrite file.\n" << std::endl;
71            ASSERT_TRUE(ret != 0);
72        }
73        fclose(file);
74    }
75    free(buffer);
76}
77
78/*
79 * @tc.number SUB_KERNEL_MEM_MADVISE_0100
80 * @tc.name   MadviseMadvCold001
81 * @tc.desc   MADV_COLD with MAP_PRIVATE
82*/
83HWTEST_F(MadviseApiTest, MadviseMadvCold001, Function | MediumTest | Level1)
84{
85    void *addr = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
86    ASSERT_TRUE(addr != MAP_FAILED);
87    int err = madvise(addr, PAGE_SIZE, MADV_COLD);
88    ASSERT_TRUE(err == 0);
89    int ret = munmap(addr, PAGE_SIZE);
90    ASSERT_TRUE(ret == 0);
91    addr = nullptr;
92}
93
94/*
95 * @tc.number SUB_KERNEL_MEM_MADVISE_0200
96 * @tc.name   MadviseMadvCold002
97 * @tc.desc   MADV_COLD with MAP_SHARED
98*/
99HWTEST_F(MadviseApiTest, MadviseMadvCold002, Function | MediumTest | Level1)
100{
101    CreateFile();
102    int fd = open("output_file.txt", O_RDWR);
103    ASSERT_TRUE(fd > 0);
104    void *addr = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED | MAP_FILE, fd, 0);
105    ASSERT_TRUE(addr != MAP_FAILED);
106    int ret = madvise(addr, PAGE_SIZE, MADV_COLD);
107    ASSERT_TRUE(ret == 0);
108    ret = munmap(addr, PAGE_SIZE);
109    ASSERT_TRUE(ret == 0);
110    addr = nullptr;
111    close(fd);
112    ret = unlink("output_file.txt");
113    ASSERT_TRUE(ret == 0);
114    addr = nullptr;
115}
116
117/*
118 * @tc.number SUB_KERNEL_MEM_MADVISE_0300
119 * @tc.name   MadviseMadvCold003
120 * @tc.desc   MADV_COLD with mlock MAP_PRIVATE FILE
121*/
122HWTEST_F(MadviseApiTest, MadviseMadvCold003, Function | MediumTest | Level1)
123{
124    CreateFile();
125    int fd = open("output_file.txt", O_RDWR);
126    ASSERT_TRUE(fd > 0);
127    void *addr = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED | MAP_FILE, fd, 0);
128    ASSERT_TRUE(addr != MAP_FAILED);
129    int ret = mlock(addr, PAGE_SIZE);
130    ASSERT_TRUE(ret == 0);
131    ret = madvise(addr, PAGE_SIZE, MADV_COLD);
132    ASSERT_TRUE(ret == -1);
133    ret = munmap(addr, PAGE_SIZE);
134    ASSERT_TRUE(ret == 0);
135    addr = nullptr;
136    close(fd);
137    ret = unlink("output_file.txt");
138    ASSERT_TRUE(ret == 0);
139    addr = nullptr;
140}
141
142/*
143 * @tc.number SUB_KERNEL_MEM_MADVISE_0400
144 * @tc.name   MadviseMadvCold004
145 * @tc.desc   MADV_COLD with mlock MAP_PRIVATE anon
146*/
147HWTEST_F(MadviseApiTest, MadviseMadvCold004, Function | MediumTest | Level1)
148{
149    void *addr = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
150    ASSERT_TRUE(addr != MAP_FAILED);
151    int ret = mlock(addr, PAGE_SIZE);
152    ASSERT_TRUE(ret == 0);
153    ret = madvise(addr, PAGE_SIZE, MADV_COLD);
154    ASSERT_TRUE(ret == -1);
155    ret = munmap(addr, PAGE_SIZE);
156    ASSERT_TRUE(ret == 0);
157    addr = nullptr;
158}
159
160/*
161 * @tc.number SUB_KERNEL_MEM_MADVISE_0500
162 * @tc.name MadviseMadvPageOut001
163 * @tc.desc MADV_PAGEOUT with  MAP_PRIVATE anon
164*/
165HWTEST_F(MadviseApiTest, MadviseMadvPageOut001, Function | MediumTest | Level1)
166{
167    int ret = -1;
168    void *addr = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
169    ASSERT_TRUE(addr != MAP_FAILED);
170    ret = memset_s(addr, PAGE_SIZE, 'a', PAGE_SIZE);
171    ASSERT_TRUE(ret == 0);
172    ret = madvise(addr, PAGE_SIZE, MADV_PAGEOUT);
173    ASSERT_TRUE(ret == 0);
174    ret = munmap(addr, PAGE_SIZE);
175    ASSERT_TRUE(ret == 0);
176    addr = nullptr;
177}
178
179/*
180 * @tc.number SUB_KERNEL_MEM_MADVISE_0600
181 * @tc.name MadviseMadvPageOut002
182 * @tc.desc MADV_PAGEOUT with  MAP_SHARED FILE
183*/
184HWTEST_F(MadviseApiTest, MadviseMadvPageOut002, Function | MediumTest | Level1)
185{
186    CreateFile();
187    int fd = open("output_file.txt", O_RDWR);
188    ASSERT_TRUE(fd > 0);
189    void *addr = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED | MAP_FILE, fd, 0);
190    ASSERT_TRUE(addr != MAP_FAILED);
191    int ret = memset_s(addr, PAGE_SIZE, 'a', PAGE_SIZE);
192    ASSERT_TRUE(ret == 0);
193    ret = madvise(addr, PAGE_SIZE, MADV_PAGEOUT);
194    ASSERT_TRUE(ret == 0);
195    ret = munmap(addr, PAGE_SIZE);
196    ASSERT_TRUE(ret == 0);
197    close(fd);
198    ret = unlink("output_file.txt");
199    ASSERT_TRUE(ret == 0);
200    addr = nullptr;
201}
202
203/*
204 * @tc.number SUB_KERNEL_MEM_MADVISE_0700
205 * @tc.name   MadviseMadvPageOut003
206 * @tc.desc   MADV_PAGEOUT with mlock MAP_SHARED FILE
207*/
208HWTEST_F(MadviseApiTest, MadviseMadvPageOut003, Function | MediumTest | Level1)
209{
210    CreateFile();
211    int fd = open("output_file.txt", O_RDWR);
212    ASSERT_TRUE(fd > 0);
213    void *addr = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED | MAP_FILE, fd, 0);
214    ASSERT_TRUE(addr != MAP_FAILED);
215    int ret = memset_s(addr, PAGE_SIZE, 'a', PAGE_SIZE);
216    ASSERT_TRUE(ret == 0);
217    ret = mlock(addr, PAGE_SIZE);
218    ASSERT_TRUE(ret == 0);
219    ret = madvise(addr, PAGE_SIZE, MADV_PAGEOUT);
220    ASSERT_TRUE(ret == -1);
221    ret = munmap(addr, PAGE_SIZE);
222    ASSERT_TRUE(ret == 0);
223    close(fd);
224    ret = unlink("output_file.txt");
225    ASSERT_TRUE(ret == 0);
226    addr = nullptr;
227}
228
229/*
230 * @tc.number SUB_KERNEL_MEM_MADVISE_0800
231 * @tc.name   MadviseMadvPageOut004
232 * @tc.desc   MADV_PAGEOUT with mlock MAP_PRIVATE anon
233*/
234HWTEST_F(MadviseApiTest, MadviseMadvPageOut004, Function | MediumTest | Level1)
235{
236    int ret = -2;
237    void *addr = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
238    ASSERT_TRUE(addr != MAP_FAILED);
239    ret = memset_s(addr, PAGE_SIZE, 'a', PAGE_SIZE);
240    ASSERT_TRUE(ret == 0);
241    ret = mlock(addr, PAGE_SIZE);
242    ASSERT_TRUE(ret == 0);
243    ret = madvise(addr, PAGE_SIZE, MADV_PAGEOUT);
244    ASSERT_TRUE(ret == -1);
245    ret = munmap(addr, PAGE_SIZE);
246    ASSERT_TRUE(ret == 0);
247    addr = nullptr;
248}
249
250/*
251 * @tc.number SUB_KERNEL_MEM_MADVISE_0900
252 * @tc.name   MadviseMadvWipeOnFork001
253 * @tc.desc   MADV_WIPEONFORK with  MAP_PRIVATE anon
254*/
255HWTEST_F(MadviseApiTest, MadviseMadvWipeOnFork001, Function | MediumTest | Level1)
256{
257    int status = 0;
258    char *addr = static_cast<char*>(mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE,
259         MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
260    ASSERT_TRUE(addr != MAP_FAILED);
261    *addr = 'A';
262    int err = madvise(addr, PAGE_SIZE, MADV_WIPEONFORK);
263    ASSERT_TRUE(err == 0);
264    pid_t pid = fork();
265    ASSERT_TRUE(pid >= 0);
266    if (pid == 0)
267    {
268        ASSERT_TRUE(*addr == 0);
269        exit(0);
270    } else {
271        ASSERT_TRUE(*addr == 'A');
272        waitpid(0, &status, 0);
273    }
274    int ret = munmap(addr, PAGE_SIZE);
275    ASSERT_TRUE(ret == 0);
276    addr = nullptr;
277}
278
279/*
280 * @tc.number  SUB_KERNEL_MEM_MADVISE_1000
281 * @tc.name    MadviseMadvWipeOnFork002
282 * @tc.desc    MADV_WIPEONFORK with  MAP_SHARED
283*/
284HWTEST_F(MadviseApiTest, MadviseMadvWipeOnFork002, Function | MediumTest | Level1)
285{
286    void *addr = mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
287    ASSERT_TRUE(addr != MAP_FAILED);
288    int err = madvise(addr, PAGE_SIZE, MADV_WIPEONFORK);
289    ASSERT_TRUE(err == -1);
290    int ret = munmap(addr, PAGE_SIZE);
291    ASSERT_TRUE(ret == 0);
292    addr = nullptr;
293}
294
295/*
296 * @tc.number SUB_KERNEL_MEM_MADVISE_1100
297 * @tc.name   MadviseMadvWipeOnFork003
298 * @tc.desc   MADV_KEEPONFORK after MADV_WIPEONFORK
299*/
300HWTEST_F(MadviseApiTest, MadviseMadvWipeOnFork003, Function | MediumTest | Level1)
301{
302    int status = 0;
303    char *addr = static_cast<char*>(mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE,
304         MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
305    ASSERT_TRUE(addr != MAP_FAILED);
306    *addr = 'A';
307    int err = madvise(addr, PAGE_SIZE, MADV_WIPEONFORK);
308    ASSERT_TRUE(err == 0);
309    err = madvise(addr, PAGE_SIZE, MADV_KEEPONFORK);
310    ASSERT_TRUE(err == 0);
311    pid_t pid = fork();
312    ASSERT_TRUE(pid >= 0);
313    if (pid == 0)
314    {
315        ASSERT_TRUE(*addr == 'A');
316        exit(0);
317    } else {
318        ASSERT_TRUE(*addr == 'A');
319        waitpid(0, &status, 0);
320    }
321    int ret = munmap(addr, PAGE_SIZE);
322    ASSERT_TRUE(ret == 0);
323    addr = nullptr;
324}
325
326/*
327 * @tc.number SUB_KERNEL_MEM_MADVISE_1200
328 * @tc.name   MadviseMadvWipeOnFork004
329 * @tc.desc   next vregion is no MADV_WIPEONFORK
330*/
331HWTEST_F(MadviseApiTest, MadviseMadvWipeOnFork004, Function | MediumTest | Level1)
332{
333    int status = 0;
334    char *addr = static_cast<char*>(mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE,
335         MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
336    ASSERT_TRUE(addr != MAP_FAILED);
337    char *nextAddr = static_cast<char*>(mmap(addr, PAGE_SIZE, PROT_READ | PROT_WRITE,
338         MAP_ANONYMOUS | MAP_PRIVATE, -1, PAGE_SIZE));
339    ASSERT_TRUE(nextAddr != MAP_FAILED);
340    *addr = 'A';
341    *nextAddr = 'B';
342    int err = madvise(addr, PAGE_SIZE, MADV_WIPEONFORK);
343    ASSERT_TRUE(err == 0);
344    pid_t pid = fork();
345    ASSERT_TRUE(pid >= 0);
346    if (pid == 0)
347    {
348        ASSERT_TRUE(*addr == 0);
349        ASSERT_TRUE(*nextAddr == 'B');
350        exit(0);
351    } else {
352        ASSERT_TRUE(*addr == 'A');
353        ASSERT_TRUE(*nextAddr == 'B');
354        waitpid(0, &status, 0);
355    }
356    int ret = munmap(addr, PAGE_SIZE);
357    ASSERT_TRUE(ret == 0);
358    ret = munmap(nextAddr, PAGE_SIZE);
359    ASSERT_TRUE(ret == 0);
360    addr = nullptr;
361    nextAddr = nullptr;
362}
363
364/*
365 * @tc.number SUB_KERNEL_MEM_MADVISE_1300
366 * @tc.name   MadviseMadvWipeOnFork005
367 * @tc.desc   next vregion is MADV_WIPEONFORK
368*/
369HWTEST_F(MadviseApiTest, MadviseMadvWipeOnFork005, Function | MediumTest | Level1)
370{
371    int status = 0;
372    char *addr = static_cast<char*>(mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE,
373         MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
374    ASSERT_TRUE(addr != MAP_FAILED);
375    char *nextAddr = static_cast<char*>(mmap(addr, PAGE_SIZE, PROT_READ | PROT_WRITE,
376         MAP_ANONYMOUS | MAP_PRIVATE, -1, PAGE_SIZE));
377    ASSERT_TRUE(nextAddr != MAP_FAILED);
378    *addr = 'A';
379    *nextAddr = 'B';
380    int err = madvise(addr, PAGE_SIZE, MADV_WIPEONFORK);
381    ASSERT_TRUE(err == 0);
382    err = madvise(nextAddr, PAGE_SIZE, MADV_WIPEONFORK);
383    ASSERT_TRUE(err == 0);
384    pid_t pid = fork();
385    ASSERT_TRUE(pid >= 0);
386    if (pid == 0)
387    {
388        ASSERT_TRUE(*addr == 0);
389        ASSERT_TRUE(*nextAddr == 0);
390        exit(0);
391    } else {
392        ASSERT_TRUE(*addr == 'A');
393        ASSERT_TRUE(*nextAddr == 'B');
394        waitpid(0, &status, 0);
395    }
396    int ret = munmap(addr, PAGE_SIZE);
397    ASSERT_TRUE(ret == 0);
398    ret = munmap(nextAddr, PAGE_SIZE);
399    ASSERT_TRUE(ret == 0);
400    addr = nullptr;
401    nextAddr = nullptr;
402}
403
404/*
405 * @tc.number SUB_KERNEL_MEM_MADVISE_1400
406 * @tc.name   MadviseMadvWipeOnFork006
407 * @tc.desc   next vregion is MADV_KEEPONFORK
408*/
409HWTEST_F(MadviseApiTest, MadviseMadvWipeOnFork006, Function | MediumTest | Level1)
410{
411    int status = 0;
412    char *addr = static_cast<char*>(mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE,
413         MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
414    ASSERT_TRUE(addr != MAP_FAILED);
415    char *nextAddr = static_cast<char*>(mmap(addr, PAGE_SIZE, PROT_READ | PROT_WRITE,
416         MAP_ANONYMOUS | MAP_PRIVATE, -1, PAGE_SIZE));
417    ASSERT_TRUE(nextAddr != MAP_FAILED);
418    *addr = 'A';
419    *nextAddr = 'B';
420    int err = madvise(addr, PAGE_SIZE, MADV_WIPEONFORK);
421    ASSERT_TRUE(err == 0);
422    err = madvise(nextAddr, PAGE_SIZE, MADV_WIPEONFORK);
423    ASSERT_TRUE(err == 0);
424    err = madvise(addr, PAGE_SIZE, MADV_KEEPONFORK);
425    ASSERT_TRUE(err == 0);
426    err = madvise(nextAddr, PAGE_SIZE, MADV_KEEPONFORK);
427    ASSERT_TRUE(err == 0);
428    pid_t pid = fork();
429    ASSERT_TRUE(pid >= 0);
430    if (pid == 0)
431    {
432        ASSERT_TRUE(*addr == 'A');
433        ASSERT_TRUE(*nextAddr == 'B');
434        exit(0);
435    } else {
436        ASSERT_TRUE(*addr == 'A');
437        ASSERT_TRUE(*nextAddr == 'B');
438        waitpid(0, &status, 0);
439    }
440    int ret = munmap(addr, PAGE_SIZE);
441    ASSERT_TRUE(ret == 0);
442    ret = munmap(nextAddr, PAGE_SIZE);
443    ASSERT_TRUE(ret == 0);
444    addr = nullptr;
445    nextAddr = nullptr;
446}