I have this code that needs to take in 3 command line arguments that are numbers in order to convert from Fahrenheit to Celsius. I have everything working in the program but I am having issues with changing the 'step' variable to int 1 if it is not specified as an argument when running the program. I added the if statement to check if the argument exists and then have that change the value to one if it does not but it returns a segmentation fault. Here is the if statement:
int step = atoi(argv[3]);
if(argc == 2){
step = 1;
return step;
}
Here are the results of running the program:
root#computer:/home/sus/cyb126/homework$./temperature_chart 32 212
Segmentation fault (core dumped)
root#computer:/home/sus/cyb126/homework$./temperature_chart 32 212 20
32 0.000000
52 11.111111
72 22.222221
92 33.333332
112 44.444443
132 55.555557
152 66.666664
172 77.777779
192 88.888885
212 100.000000
I don't understand why it returns a segmentation fault by compiles fine with no warnings. I can only think that it does not listen to the if statement for some reason.
Appreciate any help.
Changed code to the following after I was answered with good advice below:
int step;
if (argc == 2) {
step = atoi(argv[3]);
}
else {
step = 1;
}
When you pass 2 arguments the argv array is only 3 elements long ( the number of elements is always argc+1). This means that by accessing argv[3] you are accessing the fourth element of a three element vector. This is an out of bound access and you get a seg fault.
Related
The code inside main.c
#include <stdio.h>
#include <unistd.h>
int main() {
int c_variable = 0; // the target
for(int x = 0; x < 100; x++) {
c_variable += 5; // increase by 5 to change the value of the int
printf("%i\n", c_variable); // print current value
sleep(8); // sleep so I have time to scan memory
}
return 0;
}
What I am trying to achieve is to read the integer c_variable and then to modify it inside another .c program. I am on linux so I did ps -A | grep main and got the PID of the running program. I then did sudo scanmem PID and entered the current value of c_variable a few times. I was left with three memory addresses and executing the command set 500 changed the value the program printed, effectively changing the memory address' value to 500 instead of 35 or whatever the program was currently at. I then executed the following code
#include <stdio.h>
int main() {
const long unsigned addr = 0x772d85fa1008; // one of the three addresses from scanmem
printf("%lu\n", addr);
return 0;
}
but I got some random long string of numbers, not the current number. The tutorials and answers I have read on how to read and write memory on linux does not have to use long unsigned but can use char* or just int* instead. My memory address seems to be a bit long, I have not see memory addresses that long before. Anyhow, how do I read and write the memory address of the integer c_variable?
Edit: the output of scanmem looks something like this
info: we currently have 3 matches.
3> list
[ 0] 7771ff64b090, 6 + 1e090, stack, 20, [I64 I32 I16 I8 ]
[ 1] 7771ff64b5d8, 6 + 1e5d8, stack, 20, [I64 I32 I16 I8 ]
[ 2] 7771ff64b698, 6 + 1e698, stack, 20, [I32 I16 I8 ]
3> set 50
info: setting *0x7771ff64b090 to 0x32...
info: setting *0x7771ff64b5d8 to 0x32...
info: setting *0x7771ff64b698 to 0x32...
output
...
150
155
160
165
170
175
55
60
65
...
You're printing the actual address number, but in in decimal notation, not what is at the address.
const int *addr = (int *) 0x772d85fa1008;
printf("%d\n", *addr);
You have to declare addr as a pointer type. More specifically a pointer to an integer. Its value (0x772d85fa1008) holds the address of the integer.
Then, in the printf call you dereference it to obtain the actual integer stored at the address.
Although in practice I can't vouch for whether this is going to work, since memory in modern operating systems isn't as simple as you make it out to be. But I don't have enough knowledge to assess that.
Processes running under Linux generally have their own virtualized memory space. If you want to access memory space of another process, arrangements have been made in the Linux API, see shmctl, shmget, shmat, shmdt.
I have those functions and I would like to know if anyone can help me. I have to investigate why they cause a "segfault", and why it happens faster or slower depending on its conditions.
I supposed that in Rec1, it's caused by an infinite loop that collapses the memory of the memory stack. In rec2 I suppose it's caused faster because of the same condition that in Rec1 but adding that it is allocating memory everytime for the pointer too.
In Rec3 () that crashes instantly because it's allocating the same memory spot in the second iteration and causes a problem because the program is trying to access the same allocated memory.
In Rec4 () I think it's caused because it creates an array with infinite positions, ask is the limiting of the array max space.
Can you give me some advices on those suppositions?
#include <stdio.h>
#include <stdlib.h>
#define MOD 10000
int k = 0;
char global[100];
void
panic (char *m)
{
fprintf (stderr, "%s\n", m);
exit (0);
}
void
rec1 ()
{
k++;
if (k % MOD == 0)
fprintf (stderr, "%d ", k / MOD);
rec1 ();
}
void
rec2 ()
{
int *tmp;
tmp = malloc (100 * sizeof (int));
if (tmp == NULL)
exit (0);
k++;
if (k % MOD == 0)
fprintf (stderr, "%d ", k / MOD);
rec2 ();
}
void
rec3 ()
{
int tmp[100];
k++;
if (k % MOD == 0)
fprintf (stderr, "%d ", k / MOD);
rec3 ();
}
void
rec4 ()
{
global[k] = k;
if (k % 200 == 0)
fprintf (stderr, "%d ", k);
k++;
rec4 ();
}
int
main (int argc, char *argv[])
{
int mode = 1;
if (argc > 1)
mode = atoi (argv[1]);
printf ("Testing rec%d...\n", mode);
switch (mode)
{
case 1:
rec1 ();
break;
case 2:
rec2 ();
break;
case 3:
rec3 ();
break;
case 4:
rec4 ();
break;
default:
panic ("Wrong mode");
}
return 0;
}
This is the output when I run the compiled C program in terminal.
Testing rec1...
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
Program received signal SIGSEGV, Segmentation fault.
0x0000555555554904 in rec1 () at stack.c:24
24 rec1 ();
Testing rec2...
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
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a7b96a in __GI___libc_free (mem=0x555555757670) at malloc.c:3086
3086 malloc.c: No existe el archivo o el directorio.
Testing rec3...
1
Program received signal SIGSEGV, Segmentation fault.
0x0000555555554a43 in rec3 () at stack.c:53
53 rec3 ();
Testing rec4...
0 200 400 600 800 1000 1200 1400 1600 1800 2000 2200 2400 2600 2800 3000 3200 3400 3600 3800 4000 ViolaciĆ³n de segmento (`core' generado)
Program received signal SIGSEGV, Segmentation fault.
0x0000555555554a1f in rec4 ()
The Code that you have is very likely to trigger an error in my experience. Without any compiler or program feedback, it's a little difficult to discern exactly what went wrong, but I believe you may be looking (Generally) for information regarding stacks, heaps, and recursion.
Firstly, please note that
void rec1 () {
k++;
if (k % MOD == 0)
fprintf (stderr, "%d ", k / MOD);
rec1 ();
}
is NOT "Iteration". Iteration refers to the repetition of a sequential portion of code (usually a for or while loop). What you have here is recursion. Recursion creates a new instance of the method to operate from, along with a stack pointer to navigate to the last execution point (As well as store any immediately relevant variables). This occurs every time you call the rec1 () function from your rec1 () function Eventually, you'll run out of space on the stack to store those pointers. The number of pointers you can store on a stack is usually quite large on modern computers, but considering that you have no return statement, you will run into the maximum capacity eventually.
EDIT
This post has been edited to reflect the new material presented by the question.
Okay...From the material you presented, it looks like you're essentially being asked about WHERE each rec stores and processes information...
In the case of Rec1, it does indeed appear to be a simple case of stack overflow. The pointer to the last execution point of the previous Rec1 is stored on the stack, ultimately resulting in the program's crash after about 520,000 instances. Given that each pointer is 4 bytes, that's around 2 MB of just recursive pointer information alone stored on your stack before it collapses and triggers a Seg Fault due to stack overflow.
The second case is a little trickier. Note that your program indicates that it makes it to roughly 260,000 recursions before it triggers a Seg Fault. This is exactly half of Rec1. HOWEVER, this is not necessarily a stack overflow per se. Rec2 allocates 400 bytes of data on the heap per recursion. The pointer to the heap is stored on the stack, meaning that 8 bytes are stored on the stack per recursion (which may be related to why its exactly half, but could also be explained by the ratio of your stack / heap size). Now, the error for Rec2 states that malloc could not find the file or directory, which seems to me as though malloc could not complete correctly. This may actually indicate that the max heap size has been hit.
Rec3 is pretty straightforward. The entire integer array tmp is stored on the stack for each recursion. that's 4 bytes per integer times 100 ints, which is 400 bytes on the stack PER recursion. This is no surprise that it crashes between 10,000 to 20,000 recursions. There just wasn't enough space to store the data on the stack. NOTE: In relation to something you mentioned in your question, this tmp array does not attempt to allocate the same region of memory. Due to the fact that this is recursively built, it creates a new space on the stack for that function instance.
Rec4 is a simple case of buffer overflow. After overwriting the first 100 bytes of memory allocated in global[100], it was only a matter of time before k++ would cause global[k] to point to an address space restricted to the process. This triggered the seg fault after about 4000 recursions (k was not mod 10,000 in rec4).
I hope this clarification helps.
This program takes as an input the following lines:
23 12 33 19 10 8
5
23 19 8 12 60 18
14 60 12 44 54 10
8 3 12 19 33 10
33 15 7 60 12 10
22 12 19 23 33 11
23 12 33 19 10 8 ( The first line ) are the lottery results.
n ( in this specific case, 5 ) informs how many lines will follow below.
Each line has 6 numbers. The number order doesn't matter.
The rules are: numbers range from 1 to 60 ( including 1 and 60 ) and they never repeat themselves in the same line.
The variable "quadra" stores how many lines have got 4 numbers right.
The variable "quina" stores how many lines have got 5 numbers right.
The variable "sena" stores how many lines have got 6 numbers right.
So, a computer program is running some tests over my code below and it's claiming that it goes wrong for most of them, but I can't see what's the problem here. Does anybody have a clue? Is this code wrong, or is there something wrong with the software that's testing this code?
#include <stdio.h>
int main(){
int mega[6];
int v[50500][6];
int n,swap;
int i,j,k; //counters
int quadra,quina,sena;
quadra = 0;
quina = 0;
sena = 0;
for(i=0;i<6;++i) scanf("%i",&mega[i]); //first line, lottery results
scanf("%i",&n);
for(i=0;i<n;++i){
for(j=0;j<6;++j){
scanf("%i",&v[i][j]);
}
}
for(i=0;i<n;++i){
for(j=0;j<6;++j){
for(k=0;k<6;++k){
if(v[i][j] == mega[k]){
v[i][j] = 61;
}
}
}
}
//reverse bubble sort
for(i=0;i<n;++i){
for(j=0;j<6;++j){
for(k=j+1;k<6;++k){
if(v[i][j] < v[i][k]){
swap = v[i][k];
v[i][k] = v[i][j];
v[i][j] = swap;
}
}
}
}
for(i=0;i<n;++i){
for(j=0;v[i][j] == 61 && j<6;++j);
if(j == 4) ++quadra;
else if(j == 5) ++quina;
else if(j == 6) ++sena;
}
return 0;
}
Your code is true, I understood and tried the flow of it. Looks fine but if you dont need to sort everyline (and use j as a counter in this loop for(j=0;v[i][j] == 61 && j<6;++j); ), you can use simpler ifstatements to compare real lottery results with the ones that entered. What I mean is that your algorithm is a little complex. Try a simple one and see how it works.
Yes, there are a couple of noteworthy issues with your code:
Compile time indicates possibility of uninitialized variable:
But, run-time results in fatal run-time at unknown source location. Stack overflow. It is likely due to this line:
int v[50500][6];
Increase your stack size. It needs to be about 2.5Mbytes for v alone.
Also, this line may not be what you intended:
for(i=0;i<6;++i) scanf("%i",&mega[i]); //first line, lottery results
^
If you meant to loop around the remainder of the code, remove the ; after the for() statement, and use curly braces:
for(i=0;i<6;++i) scanf("%i",&mega[i]) //first line, lottery results
{
scanf("%i",&n);
....
This question already has answers here:
What's the need of array with zero elements?
(5 answers)
Closed 6 years ago.
In linux kernel (version 4.8),
"struct pid" is defined as following (from file: http://lxr.free-electrons.com/source/include/linux/pid.h). Here "numbers[1]" (at line 64) is a static array which can have only one element (because of array size is mentioned as 1).
57 struct pid
58 {
59 atomic_t count;
60 unsigned int level;
61 /* lists of tasks that use this pid */
62 struct hlist_head tasks[PIDTYPE_MAX];
63 struct rcu_head rcu;
64 struct upid numbers[1];
65 };
But then, in the following code at line 319 and 320 (from file: http://lxr.free-electrons.com/source/kernel/pid.c), array "numbers" is inside a for loop as 'numbers[i]'. How is it even correct because variable 'i' cannot have any value other than zero without causing segmentation fault? I have checked the value of 'i' during the loops to see if it ever goes more than 1. Yes it goes but still i don't see any segmentation fault. Am i missing something here?
297 struct pid *alloc_pid(struct pid_namespace *ns)
298 {
299 struct pid *pid;
300 enum pid_type type;
301 int i, nr;
302 struct pid_namespace *tmp;
303 struct upid *upid;
304 int retval = -ENOMEM;
305
306 pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL);
307 if (!pid)
308 return ERR_PTR(retval);
309
310 tmp = ns;
311 pid->level = ns->level;
312 for (i = ns->level; i >= 0; i--) {
313 nr = alloc_pidmap(tmp);
314 if (nr < 0) {
315 retval = nr;
316 goto out_free;
317 }
318
319 pid->numbers[i].nr = nr;
320 pid->numbers[i].ns = tmp;
321 tmp = tmp->parent;
322 }
Is it possible to have number of elements in an array more than array's size which is defined at compile time?
Yes. It is call undefined behavior and code should not be written to allow that.
How is it even correct because variable 'i' cannot have any value other than zero without causing segmentation fault?
It is possible; because code broke the contract. Writing outside an array's bounds may work. It may crash the program. It is undefined behavior.
C is not specified to prevent array access outside its bounds nor cause a seg fault. Such an access may be caught or not. Code itself needs to be responsible for insuring access is within bounds.
There are no training wheels and few safety nets specified in C
I'm having a hard time using sscanf to scan hour and minutes from a list. Below is a small snip of the list.
1704 86 2:30p 5:50p Daily
1711 17 10:40a 2:15p 5
1712 86 3:10p 6:30p 1
1731 48 6:25a 9:30a 156
1732 100 10:15a 1:30p Daily
1733 6 2:15p 3:39p Daily
I've tried this, but it keeps getting me segmentation Fault.(I'm putting this information into structures).
for(i=0;i<check_enter;i++){
sscanf(all_flights[i],
"%d %d %d:%d%c %d:%d%c %s",
&all_flights_divid[1].flight_number,
&all_flights_divid[i].route_id,
&all_flights_divid[i].departure_time_hour,
&all_flights_divid[i].departure_time_minute,
&all_flights_divid[i].departure_time_format,
&all_flights_divid[i].arrival_time_minute,
&all_flights_divid[i].arrival_time_minute,
&all_flights_divid[i].arrival_time_format,
&all_flights_divid[i].frequency);
printf("%d ",all_flights_divid[i].flight_number);
printf("%d ",all_flights_divid[i].route_id);
printf("%d ",all_flights_divid[i].departure_time_hour);
printf("%d ",all_flights_divid[i].departure_time_minute);
printf("%c ",all_flights_divid[i].departure_time_format);
printf("%d ",all_flights_divid[i].arrival_time_hour);
printf("%d ",all_flights_divid[i].arrival_time_minute);
printf("%c ",all_flights_divid[i].arrival_time_format);
printf("%s\n",all_flights_divid[i].frequency);
}
This is how I declared it.
struct all_flights{
int flight_number;
int route_id;
int departure_time_hour;
int departure_time_minute;
char departure_time_format;
int arrival_time_hour;
int arrival_time_minute;
char arrival_time_format;
char frequency[10];
};
struct all_flights all_flights_divid[3000];
These are the results I get
0 86 2 30 p 0 50 p Daily
0 17 10 40 a 0 15 p 5
0 86 3 10 p 0 30 p 1
0 48 6 25 a 0 30 a 156
0 100 10 15 a 0 30 p Daily
0 6 2 15 p 0 39 p Daily
Look carefully at your list of output targets in sscanf. Do you see the difference between &all_flights_divid[i].departure_time_minute and all_flights_divid[i].departure_time_format? Similary for .arrival_time_format and .frequency.
What do you think the & ampersand is for? Hint: what is one way of returning multiple values from a single function call, and what does this have to do with the & ampersand?
A segmentation fault arises when your program tries to write data into memory the operating system has never instructed the CPU to make available to the program. Segmentation faults do not always occur when data is misplaced, because sometimes data is misplaced within available memory. By way of analogy, if you inadvertently put a book in the wrong place on the bookshelf, you'll not easily find the book later, but the book is still on a bookshelf and does not seem to anyone to be out of place. On the other hand, if you inadvertently put the same book in the refrigerator, well, when mother goes to get the milk she's going to issue you a segmentation fault! That's the analogy, anyway.
In general, it is hard to guess whether misplacing data will cause a segmentation fault (as misplaced into the refrigerator) or not (as misplaced on the bookshelf) until you run the program. The segmentation fault (refrigerator) is preferable because it makes the mistake obvious, so the operating system tries to give you as many segmentation faults as it can by affording the program as little memory as possible.
I am avoiding giving a 100 percent direct answer because of your "homework" tag. See if you cannot figure out the & ampersand matter, then come back here if it still does not make sense.
Your pointers are all messed up. Perhaps a series of local variables specifically for reading this stuff in would help you organize this all in your head.
int flightNum, routeID, depHour, depMin, arrHour, arrMin;
char depFormat, arrFormat;
char * freq;
for(i=0;i<check_enter;i++){
sscanf(
all_flights[i],"%d %d %d:%d%c %d:%d%c %s"
&flightNum, &routeID,
&depHour, &depMin, &depFormat,
&arrHour, $arrMin, $arrFormat,
freq
);
all_flights_divid[i].flight_number = flightNum;
all_flights_divid[i].route_id = routeID;
all_flights_divid[i].departure_time_hour = depHour;
all_flights_divid[i].departure_time_minute = depMin;
all_flights_divid[i].departure_time_format = depFormat;
all_flights_divid[i].arrival_time_hour = arrHour;
all_flights_divid[i].arrival_time_minute = arrMin;
all_flights_divid[i].arrival_time_format = arrFormat;
strcpy(all_flights_divid[i].frequency, freq);
}