mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-28 20:42:49 +00:00
When this code is compiled by clang, it optimizes two byte writes into one word write, like this: > fake_grow_down[0] = 'c'; > *(fake_grow_down - 1) = 'b'; > 401b60: 66 41 c7 46 ff 62 63 movw $0x6362,-0x1(%r14) This is incorrect, as the stack is supposed to grow page by page, so we need to touch one page then another, i.e. the order is important. To fix, let's use volatile pointer. After this change, the following (correct) code is generated: > *p-- = 'c'; > 401b60: 41 c6 06 63 movb $0x63,(%r14) > *p = 'b'; > 401b64: 41 c6 46 ff 62 movb $0x62,-0x1(%r14) [v2: same fix for another similar place] Cc: Andrei Vagin <avagin@virtuozzo.com> Signed-off-by: Kir Kolyshkin <kir@openvz.org> Acked-by: Andrei Vagin <avagin@virtuozzo.com> Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
69 lines
1.7 KiB
C
69 lines
1.7 KiB
C
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/mman.h>
|
|
|
|
#include "zdtmtst.h"
|
|
|
|
const char *test_doc = "Check that VMA-s with MAP_GROWSDOWN are restored correctly";
|
|
const char *test_author = "Andrew Vagin <avagin@openvz.org>";
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
char *start_addr, *fake_grow_down, *test_addr, *grow_down;
|
|
volatile char *p;
|
|
test_init(argc, argv);
|
|
|
|
start_addr = mmap(NULL, PAGE_SIZE * 10, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
|
if (start_addr == MAP_FAILED) {
|
|
pr_perror("Can't mal a new region");
|
|
return 1;
|
|
}
|
|
munmap(start_addr, PAGE_SIZE * 10);
|
|
|
|
fake_grow_down = mmap(start_addr + PAGE_SIZE * 5, PAGE_SIZE,
|
|
PROT_READ | PROT_WRITE,
|
|
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED | MAP_GROWSDOWN, -1, 0);
|
|
if (fake_grow_down == MAP_FAILED) {
|
|
pr_perror("Can't mal a new region");
|
|
return 1;
|
|
}
|
|
|
|
p = fake_grow_down;
|
|
*p-- = 'c';
|
|
*p = 'b';
|
|
|
|
/* overlap the guard page of fake_grow_down */
|
|
test_addr = mmap(start_addr + PAGE_SIZE * 3, PAGE_SIZE,
|
|
PROT_READ | PROT_WRITE,
|
|
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
|
|
if (test_addr == MAP_FAILED) {
|
|
pr_perror("Can't mal a new region");
|
|
return 1;
|
|
}
|
|
|
|
grow_down = mmap(start_addr + PAGE_SIZE * 2, PAGE_SIZE,
|
|
PROT_READ | PROT_WRITE,
|
|
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED | MAP_GROWSDOWN, -1, 0);
|
|
if (grow_down == MAP_FAILED) {
|
|
pr_perror("Can't mal a new region");
|
|
return 1;
|
|
}
|
|
|
|
test_daemon();
|
|
test_waitsig();
|
|
|
|
munmap(test_addr, PAGE_SIZE);
|
|
if (fake_grow_down[0] != 'c' || *(fake_grow_down - 1) != 'b') {
|
|
fail("%c %c\n", fake_grow_down[0], *(fake_grow_down - 1));
|
|
return 1;
|
|
}
|
|
|
|
p = grow_down;
|
|
*p-- = 'z';
|
|
*p = 'x';
|
|
|
|
pass();
|
|
|
|
return 0;
|
|
}
|