summary refs log tree commit diff stats
path: root/results/classifier/zero-shot/105/semantic/1405
blob: f221dd241a9778f1ca3c79c56aa4c061316930f5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
semantic: 0.917
device: 0.914
assembly: 0.910
other: 0.905
graphic: 0.903
instruction: 0.893
socket: 0.878
vnc: 0.868
boot: 0.847
network: 0.821
KVM: 0.792
mistranslation: 0.643

linux-user: calling SYS_get_thread_area and SYS_get_thread_area has incorrent result on multithread environment
Description of problem:

Steps to reproduce:
1. Compile test.out by Command and source code: 
```
gcc -m32 -g test.c -lpthread -o test.out
```
```
#include <sys/syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <asm/ldt.h>

static inline int set_thread_area( struct user_desc *ptr )
{
    return syscall( SYS_set_thread_area, ptr );
}

static inline int get_thread_area( struct user_desc *ptr )
{
    return syscall( SYS_get_thread_area, ptr );
}

static unsigned int entry_number;

static void* start_routine(void* ptr) 
{
    struct user_desc user_desc0 = { entry_number };
    struct user_desc user_desc1 = { entry_number };
    struct user_desc user_desc2 = { entry_number };
    get_thread_area(&user_desc0);
    printf("child thread: %u\n", user_desc0.base_addr);

    user_desc1.base_addr = 2;
    user_desc1.limit     = 0xFFF;
    user_desc1.seg_32bit = 1;
    set_thread_area( &user_desc1 );

    get_thread_area(&user_desc2);
    printf("child thread: %u\n", user_desc2.base_addr);
    return NULL;
}

int main(void) {
    struct user_desc user_desc0 = { -1 }, user_desc1 = { 0 }, user_desc2 = { 0 };
    user_desc0.seg_32bit = 1;
    user_desc0.useable = 1;
    set_thread_area( &user_desc0 );

    entry_number = user_desc0.entry_number;

    user_desc1.entry_number = entry_number;
    user_desc1.base_addr = 1;
    user_desc1.limit     = 0xFFF;
    user_desc1.seg_32bit = 1;
    set_thread_area( &user_desc1 );

    pthread_t thread_id;
    pthread_create(&thread_id, NULL, &start_routine, NULL);
    pthread_join(thread_id, NULL);

    user_desc2.entry_number = entry_number;
    get_thread_area(&user_desc2);
    printf("main  thread: %u\n", user_desc2.base_addr); // main  thread: 1
    return 0;
}
 ```
2. Correct Result:
```
child thread: 1
child thread: 2
main  thread: 1
```
qemu-i386 Print Result:
```
child thread: 1
child thread: 2
main  thread: 2
```
Additional information:
patch for fix the bug: 

https://lists.nongnu.org/archive/html/qemu-devel/2023-02/msg02203.html

CPUX86State::gdt::base on differect threads must have different vaules, but it points to same memory.
value of CPUX86State::gdt::base must be copied when clone thread.

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/tls.c

SYS_set_thread_area call do_set_thread_area in kernel, it set user_desc to different memroy area on differernt threads. tls_array is in thread local memory.

```
static void set_tls_desc(struct task_struct *p, int idx,
			 const struct user_desc *info, int n)
{
	struct thread_struct *t = &p->thread;
	struct desc_struct *desc = &t->tls_array[idx - GDT_ENTRY_TLS_MIN];
	int cpu;

	/*
	 * We must not get preempted while modifying the TLS.
	 */
	cpu = get_cpu();

	while (n-- > 0) {
		if (LDT_empty(info) || LDT_zero(info))
			memset(desc, 0, sizeof(*desc));
		else
			fill_ldt(desc, info);
		++info;
		++desc;
	}

	if (t == &current->thread)
		load_TLS(t, cpu);

	put_cpu();
}
```