Need some help here.
I want to understand what's happening in this code.
I'm trying to generate random numbers as tickets to the TCP_t struct created inside ccreate function.
The problem is, everytime I executed this code WITHOUT the srand(time(NULL)) it returned the same sequence of "random" numbers over and over, for example:
TID: 0 | TICKET : 103
TID: 1 | TICKET : 198
So I seeded it with time, to generate really random numbers.
When I put the seed inside the newTicket function, it brings different numbers in every execution, but the same numbers for every thread. Here is an example of output:
Execution 1:
TID: 0 | TICKET : 148
TID: 1 | TICKET : 148
Execution 2:
TID: 0 | TICKET : 96
TID: 1 | TICKET : 96
So, after some research, I found out I shouldn't seed it everytime I call rand but only once, in the beginning of the program. Now, after putting the seed inside the main function, it gives me segmentation fault, and I have NO IDEA why.
This might be a stupid question, but I really want to understand what's happening.
Is the seed screwing anything, somehow?
Am I missing something?
Should I generate random number in another way?
#include <ucontext.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#define MAX_TICKET 255
#define STACK_SIZE 32000
typedef struct s_TCB {
int threadId;
int ticket;
ucontext_t context;
} TCB_t;
void test();
int newTicket();
int newThreadId();
int ccreate (void* (*start)(void*), void *arg);
int threadId = 0;
int main(){
srand(time(NULL)); //<<<============== HERE = SEGMENTATION FAULT
ccreate((void*)&test, 0);
ccreate((void*)&test, 0);
}
int ccreate (void* (*start)(void*), void *arg){
if(start == NULL) return -1;
ucontext_t threadContext;
getcontext(&threadContext);
makecontext(&threadContext, (void*)start, 0);
threadContext.uc_stack.ss_sp = malloc(STACK_SIZE);
threadContext.uc_stack.ss_size = STACK_SIZE;
TCB_t * newThread = malloc(sizeof(TCB_t));
if (newThread == NULL) return -1;
int threadThreadId = newThreadId();
newThread->threadId = threadThreadId;
newThread->ticket = newTicket();
printf("TID: %d | TICKET : %d\n", newThread->threadId, newThread->ticket);
return threadThreadId;
}
int newThreadId(){
int newThreadId = threadId;
threadId++;
return newThreadId;
}
int newTicket(){
//srand(time(NULL)); //<<<============== HERE = IT PARTIALLY WORKS
return (rand() % (MAX_TICKET+1));
}
void test(){
printf("this is a test function");
}
Thanks to everyone who lends me a hand here.
And sorry if the code is too ugly to read. Tried to simplify it as much as I could.
The problem is not with srand(time(NULL)), but with makecontext.
You can run your code through a sanatizer to confirm:
gcc-6 -fsanitize=undefined -fsanitize=address -fsanitize=leak -fsanitize-recover=all -fuse-ld=gold -o main main.c
./main
ASAN:DEADLYSIGNAL
=================================================================
==8841==ERROR: AddressSanitizer: SEGV on unknown address 0x7fc342ade618 (pc 0x7fc340aad235 bp 0x7ffd1b945950 sp 0x7ffd1b9454f8 T0)
#0 0x7fc340aad234 in makecontext (/lib/x86_64-linux-gnu/libc.so.6+0x47234)
#1 0x400d2f in ccreate (/home/malko/Desktop/main+0x400d2f)
#2 0x400c19 in main (/home/malko/Desktop/main+0x400c19)
#3 0x7fc340a87f44 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21f44)
#4 0x400b28 (/home/malko/Desktop/main+0x400b28)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/lib/x86_64-linux-gnu/libc.so.6+0x47234) in makecontext
==8841==ABORTING
You can solve the problem by setting a stack size before making the context:
char stack[20000];
threadContext.uc_stack.ss_sp = stack;
threadContext.uc_stack.ss_size = sizeof(stack);
makecontext(&threadContext, (void*)start, 0);
Unrelated, but make sure you also free that malloc'd memory in your sample code.
Related
I write a system call function and test it by using kernel modules.
This is my procedure:
build the kernel (get mod.ko)
sudo insmod mod.ko
write test c file
firstly, I found out that number 336 is free for system call, therefore I use 336 as offset, hooked my function into sys_call_table:
static int __init init_addsyscall(void)
{
printk("My syscall is starting...\n");
sys_call_table = (unsigned long *)0xffffffffaae002c0;
printk("sys_call_table: 0x%p\n", sys_call_table);
anything_saved = (int(*)(void))(sys_call_table[__NR_syscall]); /* save original one */
orig_cr0 = clear_and_return_cr0(); /* make cr0 writable */
sys_call_table[__NR_syscall] = (unsigned long)&sys_mycall; /* change function pointer */
setback_cr0(orig_cr0); /* recover cr0 */
return 0;
}
my system call is:
asmlinkage long sys_mycall(unsigned long long num)
{
printk("my call, num = %llu", num);
if (num % 2 == 0)
return num % 1000000;
else
return num % 100000;
}
my test c file:
// t.c
#include <sys/syscall.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("%d\n",syscall(336, 19030123456));
return 0;
}
It is expected that t.c will print 123456, but it print a random number. I have tried many times to run this test function and got different return-value each times. I use sudo dmesg to check the log and can sure that my system call is called, and the argument of system call is not my input as well. It is more likely that the argument is a random number...
[ 9444.176815] My syscall is starting...
[ 9444.176825] sys_call_table: 0x000000002dac30a7
[ 9448.550544] my call, num: 18446667112225996632
[ 9449.256182] my call, num: 18446667112224440152
[ 9449.966801] my call, num: 18446667112225046360
[ 9453.252192] my call, num: 18446667112225177432
[ 9455.373322] my call, num: 18446667112225308504
I am a beginner and I don't sure what's happening here, and can be sure which information is necessary for analysis. If you need more details, just let me know.
#include <stdio.h>
#include <pthread.h>
typedef struct {
int threadNum;
}thread_args;
void thread_func(void*vargp){
thread_args*id=(thread_args*)vargp;
printf("%i\n",id->threadNum);
}
int main() {
for(int i=0;i<20;i++) {
pthread_t id;
thread_args args;
args.threadNum=i;
pthread_create(&id,NULL,thread_func,(void*)&args);
}
pthread_exit(NULL);
return 0;
}
Adapted from https://www.geeksforgeeks.org/multithreading-c-2/.
So this is expected to output:
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
But shuffled in a random order to account for the concurrency of the threads.
The issue here is that it actually prints out this:
4
9
10
5
11
12
13
8
4
4
17
6
18
7
15
19
6
14
19
16
As you can see, there are duplicate numbers and 0-3 are just plain skipped.
I have done concurrency before in other frameworks before, and I have seen similar issues: what is happening here is that the i is being passed as a reference (I think!) and so when the for loop increments i, it is incremented in all thread argument variables.
How can I avoid this?
NOTE: Everything is linking 100% properly and I'm on macOS.
PS: Sorry if this is a duplicate, I'm not very experienced with this.
You are having an UB at your for loop. You are creating an variable called args, where you assign a value to it, pass as reference to your thread, for later execution, and destroy it at the end of your for loop. Then you do it again, possibling overwritting this region.
To solve that problem, I suggest this modification:
int main() {
thread_args args[20] = {0};
pthread_t id[20] = {0};
for(int i=0;i<20;i++) {
args[i].threadNum=i;
pthread_create(&id[i],NULL,thread_func,(void*)&args[i]);
}
for(int i = 0; i < 20; i++)
pthread_join(id[i], NULL);
return 0;
}
This is, in fact, a race condition. You pass a void pointer to the argument struct, but (likely) the same memory address is reused for each argument struct. Therefore, when you later access it, you are likely to read modified memory. Try this:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
typedef struct {
int threadNum;
}thread_args;
void thread_func(void* vargp){
thread_args* id = (thread_args*)vargp;
printf("%i\n", id->threadNum);
free(vargp);
}
int main() {
for(int i=0;i<20;i++) {
pthread_t id;
thread_args* args = malloc(sizeof(thread_args));
args->threadNum = i;
pthread_create(&id, NULL, thread_func, (void*)args);
}
pthread_exit(NULL);
return 0;
}
Thanks to Kamil Cuk for pointing out another race condition.
Note that this snippet might still leak because the code never joins the threads, so the free() might never be called.
I'm using multi-core machine, and tried to run this simple code few times:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int evenCounter = 0;
int nextEven()
{
++evenCounter;
++evenCounter;
return evenCounter;
}
void* pThreadFunction()
{
int i, val;
for (i = 0; i < 8; i++)
{
val = nextEven();
printf("*** increase from pThread - new Value is: %d\n", val);
}
pthread_exit(NULL);
}
void main(){
pthread_t pThread;
int i, val;
if (pthread_create(&pThread, NULL, pThreadFunction, NULL) != 0)
{
puts("failed to create print thread");
return 1;
}
for (i = 0; i < 8; i++)
{
val = nextEven();
printf("increase from main - new Value is: %d\n", val);
}
}
And got results like those all the time:
increase from main - new Value is: 2
*** increase from pThread - new Value is: 4
increase from main - new Value is: 6
*** increase from pThread - new Value is: 8
increase from main - new Value is: 10
*** increase from pThread - new Value is: 12
increase from main - new Value is: 14
*** increase from pThread - new Value is: 16
increase from main - new Value is: 18
*** increase from pThread - new Value is: 20
increase from main - new Value is: 22
*** increase from pThread - new Value is: 24
increase from main - new Value is: 26
*** increase from pThread - new Value is: 28
increase from main - new Value is: 30
*** increase from pThread - new Value is: 32
(The order between the first printings was different sometimes, but the values were the same).
If those two threads run on different cores - I would expect some wrong values (like odd values) in the printings, so for my understanding - those threads run on the same core.
Is it really like that in cygwin?
And if it is, how can I make main thread and the pthread run on different cores?
I saw an option for using sched_setaffinity , but it doesn't work in cygwin.
I encountered a very bizarre bug when I test my interrupt module of my os class project which is based on HOCA system.
When I start my main function (which is from line66 to line101), but when I set the breakpoint at line92, gdb says
No line 92 in the current file. Make breakpoint pending on future shared library load?
Do you guys know what's going on here?
Furthermore, when I set the breakpoint at line 92 and continue GDB, it reports :"
trap: nonexistant memory
address: -1
memory size: 131072
ERROR: address greater than MEMORYSIZE
Program received signal SIGSEGV, Segmentation fault.
0x0000002e in ?? ()
"
Source code is as follow:
/* This module coordinates the initialization of the nucleus and it starts the execution
* of the first process, p1(). It also provides a scheduling function. The module contains
* two functions: main() and init(). init() is static. It also contains a function that it
* exports: schedule().
*/
#include "../../h/const.h"
#include "../../h/types.h"
#include "../../h/util.h"
#include "../../h/vpop.h"
#include "../../h/procq.e"
#include "../../h/asl.e"
#include "../../h/trap.h"
#include "../../h/int.h"
proc_link RQ; /* pointer to the tail of the Ready Queue */
state_t st; /* the starting state_t */
extern int p1();
/* This function determines how much physical memory there is in the system.
* It then calls initProc(), initSemd(), trapinit() and intinit().
*/
void static init(){
STST(&st);
if(st.s_sp%PAGESIZE != 0){
st.s_sp -= st.s_sp%PAGESIZE;
}
initProc();
initSemd();
trapinit();
intinit();
}
/* If the RQ is not empty this function calls intschedule() and loads the state of
* the process at the head of the RQ. If the RQ is empty it calls intdeadlock().
*/
void schedule(){
proc_t *front;
front = headQueue(RQ);
if (checkPointer(front)) {
intschedule();
LDST(&(front->p_s));
}
else {
intdeadlock();
}
}
/* This function calls init(), sets up the processor state for p1(), adds p1() to the
* RQ and calls schedule().
*/
void main(){
proc_t *pp1; // pointer to process table entry
state_t pp1state; //process state
long curr_time; // to store the time
init(); // initialize the process table, semaphore...
/*setup the processor state for p1(), adds p1() to the ReadyQueue */
RQ.next = (proc_t *) ENULL;
RQ.index = 1;
pp1 = allocProc();
if(!checkPointer(pp1)){
return;
}
pp1->parent = (proc_t *) ENULL; // ENULL is set to -1
pp1->child = (proc_t *) ENULL;
pp1->sibling_next = pp1;
pp1->sibling_prev = pp1;
pp1state.s_sp = st.s_sp - (PAGESIZE*2);
pp1state.s_pc = (int)p1;
pp1state.s_sr.ps_s = 1; // here should be line 92
STCK(&curr_time); //store the CPU time to curr_time
pp1->p_s = pp1state;
pp1->start_time = curr_time;
insertProc(&RQ, pp1);
schedule();
return;
}
Compile without optimizations. Use O0 gcc flag for that.
I am getting segmentation fault on line 8 in the code below.
typedef struct _my_struct {
int pArr[21];
int arr1[8191];
int arr2[8191];
int m;
int cLen;
int gArr[53];
int dArr[8191];
int data[4096];
int rArr[53];
int eArr[1024];
};
void *populate_data(void *arg) {
1 register int mask =1, iG;
2 struct _my_struct *var ;
3 var = arg; // arg is passed as initialized struct variable while creating thread
4 var->m = 13;
5 var->arr2[var->m] = 0;
6 for (iG = 0; iG < var->m; iG++) {
7 var->arr2[iG] = mask;
8 var->arr1[var->arr2[iG]] = iG;
9 if (var->pArr[iG] != 0) // pArr[]= 1011000000001
10 var->arr2[var->m] ^= mask;
11 mask <<= 1;
12 }
13 var->arr1[var->arr2[var->m]] = var->m;
14 mask >>= 1;
15 for (iG = var->m+ 1; iG < var->cLen; iG++) {
16 if (var->arr2[iG - 1] >= mask)
17 var->arr2[iG] = var->arr2[var->m] ^ ((var->arr2[iG- 1] ^ mask) << 1);
18 else
19 var->arr2[iG] = var->arr2[iG- 1] << 1;
20 var->arr1[var->arr2[iG]] = iG;
21 }
22 var->arr1[0] = -1;
}
Here is the thread function:
void main() {
unsigned int tid;
struct _my_struct *instance = NULL;
instance = (struct _my_struct *)malloc(sizeof(_my_struct ));
start_thread(&tid , 119312, populate_data, instance );
}
int
start_thread(unsigned int *tid, int stack_size, void * (*my_function)(void *), void *arg)
{
pthread_t ptid = -1;
pthread_attr_t pattrib;
pthread_attr_init(&pattrib);
if(stack_size > 0)
{
pthread_attr_setstacksize(&pattrib, stack_size);
}
else
{
pthread_attr_destroy(&pattrib);
return -1;
}
pthread_create(&ptid, &pattrib, my_function, arg);
pthread_attr_destroy(&pattrib);
return 0;
}
Once I debug it through gdb, got this error,
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffdfec80700 (LWP 22985)]
0x0000000000401034 in populate_data (arg=0x7fffffffe5d8) at Queue.c:19
19 var->arr1[var->arr2[iG]] = iG;
and its backtrace is:
#0 0x0000000000401034 in populate_data (arg=0x7fffffffe5d8) at Queue.c:159
#1 0x00007ffff7bc6971 in start_thread () from /lib/libpthread.so.0
#2 0x00007ffff792292d in clone () from /lib/libc.so.6
#3 0x0000000000000000 in ?? ()
However, I'm unable to correct the error.
Anyhelp is really appreciated.
Please show the calling code in start_thread.
It seems likely to be a stack and/or memory allocation error, the structure is pretty large (8 MB assuming 32-bit ints) and might well overflow some stack limit.
Even more possible is that it's gone out of scope, which is why the calling step must be shown.
I don't know if perhaps you've changed the names of the arrays in your _my_struct in order to hide the purpose of them (company confidential information, perhaps?), but if that's actually what you've named your arrays, I'm just going to suggest that you name them something that makes sense to you that when someone has to read your code 4 years from now, they'll have some hope of following your initialization loops & understanding what's going on. Same goes for your loop variable iG.
My next comment/question is, why are you firing off a thread to initialize this structure that's on the stack of the main thread? Which thread is going to be using this structure once it's initialized? Or are you going to make other threads that will use it? Do you have any mechanism (mutex? semaphore?) to ensure that the other threads won't start using the data until your initialization thread is done initializing it? Which sort of begs the question, why the heck are you bothering to fire off a separate thread to initialize it in the first place; you could just initialize it by calling populate_data() straight from main() and not even have to worry about synchronization because you wouldn't even be starting up any other threads until after it's done being initialized. If you're running on a multicore machine, you might get some small benefit from firing off that separate thread to do the initialization while main() goes on & does other stuff, but from the size of your struct (not tiny, but not huge either) it seems like that benefit would be very miniscule. And if you're running on a single core, you'll get no concurrency benefit at all; you'd just be wasting time firing off another thread to do it due to the context switching overhead; in a unicore environment you'd be better off just calling populate_data() directly from main().
Next comment is, your _my_struct is not huge, so it's not going to blow your stack by itself. But it ain't tiny either. If your app will always need only one copy of this struct, maybe you should make it a global variable or a file-scope variable, so it doesn't eat up stack space.
Finally, to your actual bug............
I didn't bother to try to decipher your cryptic looping code, but valgrind is telling me that you have some conditions that depend on uninitialized locations:
~/test/so$ valgrind a.out
==27663== Memcheck, a memory error detector
==27663== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==27663== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==27663== Command: a.out
==27663==
==27663== Thread 2:
==27663== Conditional jump or move depends on uninitialised value(s)
==27663== at 0x8048577: populate_data (so2.c:34)
==27663== by 0x593851: start_thread (in /lib/libpthread-2.5.so)
==27663== by 0x4BDA8D: clone (in /lib/libc-2.5.so)
==27663==
==27663== Conditional jump or move depends on uninitialised value(s)
==27663== at 0x804868A: populate_data (so2.c:40)
==27663== by 0x593851: start_thread (in /lib/libpthread-2.5.so)
==27663== by 0x4BDA8D: clone (in /lib/libc-2.5.so)
My so2.c line 34 corresponds with line 9 in your code posting above.
My so2.c line 40 corresponds with line 15 in your code posting above.
If I add the following at the top of populate_data(), these valgrind errors disappear:
memset(arg,0,sizeof(_my_struct_t));
(I modified your struct definition as follows:)
typedef struct _my_struct { int pArr[21]; ......... } _my_struct_t;
Now just because adding the memset() call makes the errors disappear doesn't necessarily mean that your loop logic is correct, it just means that now those locations are considered "initialized" by valgrind. If having all-zeros in those locations when your initialization loops begin is what your logic needs, then that should fix it. But you need to verify for yourself that such really is the proper solution.
BTW... someone suggested using calloc() to get a zeroed-out allocation (rather than using dirty stack space)... that would work too, but if you want populate_data() to be foolproof, you'll zero the memory in it and not in the caller, since (assuming you like your initialization logic as it is), populate_data() is the thing that depends on it being zeroed out, main() shouldn't have to care whether it is or not. Not a biggie either way.