Help with very strange bug with shmctl?

Hello all, I just did a quick programming exercise from a textbook, and I'm finding some strange things with shmctl. Basically, I have some shared memory obtained with shmget and shmat. I then create struct shmid_ds* buf. This line returns NULL, unless it is declared at the beginning of main, and I have the following block of code below it:

1
2
3
if(buf == NULL){
  printf("wat\n");
}


If that isn't there, buf is set to NULL and shmctl returns complains of a bad address (errno is set to EFAULT). I'll paste the rest of my code below, the lines of interest are 23-29 and 56-81. If lines 23-29 are placed lower down in the program (for example right before line 56) it doesn't work (buf is NULL). And, if I don't test for buf being NULL on lines 27-29, buf will again be NULL. Anyone have any idea what is going on here?

Other comments on my code are also welcome, I am quite new to linux programming, and haven't done a lot of work in C either.

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
135
136
137
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <errno.h>

#define MAX_SEQ 20

typedef struct{
  unsigned int fib_sequence[MAX_SEQ];
  int sequence_size;
}shared_data;

extern int errno;

void fib(shared_data* data);

int main(int argc, char *argv[])
{
  unsigned int arg;
  int segment_id;
  struct shmid_ds* buf;

  if (buf == NULL){
    printf("wat\n");
  }

  if (argc == 1){
    printf("You must input an argument\n");
    exit(EXIT_FAILURE);
  }
  
  else if (argc > 2){
    printf("You must input only 1 argument\n");
    exit(EXIT_FAILURE);
  }
  
  else if (arg < 0){
    printf("You must input number greater than or equal to 0\n");
    exit(EXIT_FAILURE);
  }

  else if ((arg = atoi(argv[1])) == 0 && *argv[1] != '0'){
    printf("You must input a number\n");
    exit(EXIT_FAILURE);
  }
  
  if (arg > MAX_SEQ){
    printf("Sorry, you must enter an argument less than %d\n", MAX_SEQ);
    exit(EXIT_SUCCESS);
  }

  segment_id = shmget(IPC_PRIVATE, sizeof(shared_data), S_IRUSR | S_IWUSR);
  if (segment_id < 0){
    perror("shmget");
    exit(EXIT_FAILURE);
  }

  shared_data* shared_memPtr = (shared_data*)shmat(segment_id, NULL, 0);
  
  if(shared_memPtr < 0){
    perror("shmat");
    exit(EXIT_FAILURE);
  }
  
  shared_memPtr->sequence_size = arg;

  if(shmctl(segment_id, IPC_STAT, buf) == -1){
    perror("shmctl");
    exit(EXIT_FAILURE);
  }
  
  printf("segment ID: %d \n", segment_id);
  printf("Key: %d \n", buf->shm_perm.__key);  
  printf("Mode: %d \n", buf->shm_perm.mode);
  printf("OwnerUID: %d \n", buf->shm_perm.uid);
  printf("Size: %zu \n", buf->shm_segsz);
  printf("No. of attaches: %d \n", (int)buf->shm_nattch);

  pid_t pid = fork();
      
  if (pid < 0){ /* error */
    perror("fork");
    exit(EXIT_FAILURE);
  }
      
  else if (pid == 0){ /* child */
    fib(shared_memPtr);
    exit(EXIT_SUCCESS);
  }
      
  else if (pid > 0){ /* parent */
    int status;
    if (wait(&status) < 0){ /* error */
      perror("wait");
      exit(EXIT_FAILURE);
    }

    if (WIFEXITED (status))
      printf("Normal exit from child\n");
    else
      printf("Strange exit from child\n");

    int n = shared_memPtr->sequence_size;
    int i = 0;
    for (i; i<n; i++){
      printf("%d ", shared_memPtr->fib_sequence[i]);
    }
    printf("\n");

    if(shmdt(shared_memPtr) < 0){
      perror("shmdt");
      exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
  }
}

void fib(shared_data* data)
{
  int n = data->sequence_size;
  unsigned int fib1 = 1;
  unsigned int fib2 = 1;
  unsigned int temp = 0;

  int i = 0;
  for (i; i < n; i++){
    data->fib_sequence[i] = fib1;
    temp = fib2;
    fib2 = fib1 + fib2;
    fib1 = temp;
  }
}
Last edited on
> Anyone have any idea what is going on here?
undefined behaviour because you are toying with uninitialized variables, perhaps.

you may want to read the compiler warnings
It compiles without warnings. What should I be initializing? I may be confused about something, is this understanding correct: Calling struct shmid_ds* buf should store in buf a pointer to an unitialized struct of type shmid_ds. The pointer to this buf is then passed to shmctl via shmtcl(id, IPC_STAT, buf) where shmtcl puts stuff in the space pointed to by buf, then returns. So the initial call to create buf, should return a non-null pointer since it points to an allocated space in memory. Is that right?
Last edited on
> It compiles without warnings
No, you are compiling without enabling warnings
$ gcc -W{all,extra,pedantic} -std=c11 -D_XOPEN_SOURCE
bar.c: In function ‘main’:
bar.c:41:2: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
bar.c:64:19: warning: ordered comparison of pointer with integer zero [-Wpedantic]
bar.c:97:3: warning: implicit declaration of function ‘wait’ [-Wimplicit-function-declaration]
bar.c:109:3: warning: statement with no effect [-Wunused-value]
bar.c: In function ‘fib’:
bar.c:131:2: warning: statement with no effect [-Wunused-value]
bar.c: In function ‘main’:
bar.c:27:5: warning: ‘buf’ is used uninitialized in this function [-Wuninitialized]


> Calling struct shmid_ds* buf should store in buf a pointer to an unitialized struct of type shmid_ds.
nope, you are creating a pointer that points to garbage.

If you want to create an object, simply use struct shmid_ds object;
¿want a pointer to it? &object


Note: some APIs may force you to work only with pointers, and would use a function (constructor) to create the object and return a pointer to it
By instanceFILE *input = fopen("foo.txt", "r");
Topic archived. No new replies allowed.