I'm using with a smaller piece of code to test functionality for a larger (beginner) program, but I have a problem displaying the token I've pulled out of a string.
I found and used:
#include <stdio.h>
#include <string.h>
int main()
{
char *string, *found;
string = strdup ("1/2/3");
printf("Original string: '%s'\n",string);
while ((found = strsep(&string,"/")) != NULL )
printf ("%s\n",found);
return (0);
}
and this works fine, prints the tokens one at a time as strings.
Then when I try and move to a user entered string:
#include <stdio.h>
#include <string.h>
int main()
{
char string[13];
char *found, *cp = string;
fprintf(stderr, "\nEnter string: ");
scanf("%12s",string);
printf("Original string: '%s'\n",string);
while((found = strsep(&cp,"/,-")) != NULL )
printf("Test 1"); /*To pinpoint where the seg fault arises*/
printf("%s\n",found);
return(0);
}
I get a seg fault on the printf("%s\n",found); line. I'm getting the hang of basics of pointers, arrays and strings, but clearly I'm missing something, and would love for someone to tell me what it is!
Also - if I change the argument of printf("%s\n",found); e.g. to printf("%i\n",found); I get some randomness returned, but always the correct amount, e.g. If I enter 1/2/3 I get three lines of junk, entering 1111/2222 gives two lines. I tried %c, %i, %d, %p and they all do the same, but %s seg faults.
I'm completely stumped.
The segfault is because you're missing braces around your while. You'll keep printing "Test 1" until strsep returns NULL, then you try to print that result (and segfault).
With several warning flags (probably -Wall), gcc helps out here:
sep.c:13:3: warning: this ‘while’ clause does not guard... [-Wmisleading-indentation]
while((found = strsep(&cp,"/,-")) != NULL )
^~~~~
sep.c:15:5: note: ...this statement, but the latter is misleadingly indented as if it is guarded by the ‘while’
printf("%s\n",found);
^~~~~~
With braces added around the while, the program works as expected:
./sep
Enter string: abc/def
Original string: 'abc/def'
Test 1abc
Test 1def
This is the problem:
while((found = strsep(&cp,"/,-")) != NULL )
printf("Test 1"); /*To pinpoint where the seg fault arises*/
printf("%s\n",found);
and you think you are doing both printfs inside the loop, but in reality this
code is equivalent to
while((found = strsep(&cp,"/,-")) != NULL )
{
printf("Test 1"); /*To pinpoint where the seg fault arises*/
}
printf("%s\n",found);
that means, printf("%s\n",found); is basically doing printf("%s\n",NULL);
which is undefined behaviour and may cause a segfault.
Note that in C indentation does not matter to the compiler. So you would need to
use { and } around the code:
while((found = strsep(&cp,"/,-")) != NULL )
{
printf("Test 1"); /*To pinpoint where the seg fault arises*/
printf("%s\n",found);
}
Doing that I get
$ ./a
Enter string: aa/bb/cc/dd
Original string: 'aa/bb/cc/dd'
Test 1aa
Test 1bb
Test 1cc
Test 1dd
Also note that your first code is leaking memory, you are not freeing the
allocated memory returned by strdup. You would have to save a pointer to that:
#include <stdio.h>
#include <stdlib.h> // for the free function
#include <string.h>
int main()
{
char *orig = *string, *found;
orig = string = strdup ("1/2/3");
printf("Original string: '%s'\n",string);
while ((found = strsep(&string,"/")) != NULL )
printf ("%s\n",found);
free(orig);
return 0;
}
edit
Neither Stephen Newell nor me seems to have the same problem with the
corrected version of the code. The OP provided a link to onlinegdb.com
showing that the corrected version ends with a segfault.
I tried the same code on ideone.com and I also got the segfault. That seemed
strange to me, so I opened my man page of strsep and found this:
man strsep
SYNOPSIS
#include <string.h>
char *strsep(char **stringp, const char *delim);
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
strsep():
Since glibc 2.19:
_DEFAULT_SOURCE
Glibc 2.19 and earlier:
_BSD_SOURCE
The important part is this here: Since glibc 2.19: _DEFAULT_SOURCE
So if you add
#define _DEFAULT_SOURCE
before including any standard C header file, then it works on onlinegdb.com
and ideone.com.
So the code should be:
#define _DEFAULT_SOURCE // <-- important
#include <stdio.h>
#include <string.h>
int main()
{
char string[13];
char *found, *cp = string;
fprintf(stderr, "\nEnter string: ");
scanf("%12s",string);
printf("Original string: '%s'\n",string);
while((found = strsep(&cp,"/,-")) != NULL )
{
printf("Test 1"); /*To pinpoint where the seg fault arises*/
printf("%s\n",found);
}
return(0);
}
See:
corrected onlinegdb.com version
corrected ideone.com version
Related
I am reading the book "Effective C" by Robert C. Seacord.
In this book, it has an exercise where you intentionally double-free a pointer so you can test using dmalloc to debug the cause. However, it doesn't fail as expected.
#include <string.h>
#include <stdlib.h>
#ifdef DMALLOC
#include "dmalloc.h"
#endif
void usage(char *msg) {
fprintf(stderr, "%s", msg);
free(msg);
return;
}
int main(int argc, char *argv[]) {
if (argc != 3 && argc !=4) {
/* The error message won't be more than 80 chars */
char *errmsg = (char *)malloc(80);
sprintf(
errmsg,
"Sorry %s,\nUsage: caesar secret_file keys_file [output_file]\n",
getenv("USER")
);
usage(errmsg);
free(errmsg);
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
Its clear here that *errmsg should get freed twice:
First by the usage function when its passed to it, and then right after in main.
Why doesn't this fail when ran with no arguments? I am using linux (POP!_OS 20.04) with GCC 9.3.0.
EDIT: For more context the book suggests I should see an output like this:
% ./caesar
Sorry student,
Usage: caesar secret_file keys_file [output_file]
debug-malloc library: dumping program, fatal error
Error: tried to free previously freed pointer (err 61)
Aborted (core dumped)
Adding more calls to free doesn't do anything either.
I get the usage portion but not a core dump.
I am sorry for taking up people's time with this. I figured it out.
That crash behavior is supposed to be provided by dmalloc, however its usage has changed a little since the writing of the book I am reading.
I needed to add -DDMALLOC_FUNC_CHECK to the compiler options in order for it to produce the expected result.
I learned its dmalloc, not the OS that causes the program to crash when you double-free the pointer.
I have been trying to intercept calls to malloc and free, following our textbook (CSAPP book).
I have followed their exact code, and nearly the same code that I found online and I keep getting a segmentation fault. I heard our professor saying something about printf that mallocs and frees memory so I think that this happens because I am intercepting a malloc and since I am using a printf function inside the intercepting function, it will call itself recursively.
However I can't seem to find a solution to solving this problem? Our professor demonstrated that intercepting worked ( he didn't show us the code) and prints our information every time a malloc occurs, so I do know that it's possible.
Can anyone suggest a working method??
Here is the code that I used and get nothing:
mymalloc.c
#ifdef RUNTIME
// Run-time interposition of malloc and free based on // dynamic linker's (ld-linux.so) LD_PRELOAD mechanism #define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h> #include <dlfcn.h>
void *malloc(size_t size) {
static void *(*mallocp)(size_t size) = NULL; char *error;
void *ptr;
// get address of libc malloc
if (!mallocp) {
mallocp = dlsym(RTLD_NEXT, "malloc"); if ((error = dlerror()) != NULL) {
fputs(error, stderr);
exit(EXIT_FAILURE);
}
}
ptr = mallocp(size);
printf("malloc(%d) = %p\n", (int)size, ptr); return ptr;
}
#endif
test.c
#include <stdio.h>
#include <stdlib.h>
int main(){
printf("main\n");
int* a = malloc(sizeof(int)*5);
a[0] = 1;
printf("end\n");
}
The result i'm getting:
$ gcc -o test test.c
$ gcc -DRUNTIME -shared -fPIC mymalloc.c -o mymalloc.so
$ LD_PRELOAD=./mymalloc.so ./test
Segmentation Fault
This is the code that I tried and got segmentation fault (from https://gist.github.com/iamben/4124829):
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
void* malloc(size_t size)
{
static void* (*rmalloc)(size_t) = NULL;
void* p = NULL;
// resolve next malloc
if(!rmalloc) rmalloc = dlsym(RTLD_NEXT, "malloc");
// do actual malloc
p = rmalloc(size);
// show statistic
fprintf(stderr, "[MEM | malloc] Allocated: %lu bytes\n", size);
return p;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STR_LEN 128
int main(int argc, const char *argv[])
{
char *c;
char *str1 = "Hello ";
char *str2 = "World";
//allocate an empty string
c = malloc(STR_LEN * sizeof(char));
c[0] = 0x0;
//and concatenate str{1,2}
strcat(c, str1);
strcat(c, str2);
printf("New str: %s\n", c);
return 0;
}
The makefile from the git repo didn't work so I manually compiled the files and got:
$ gcc -shared -fPIC libint.c -o libint.so
$ gcc -o str str.c
$ LD_PRELOAD=./libint.so ./str
Segmentation fault
I have been doing this for hours and I still get the same incorrect result, despite the fact that I copied textbook code. I would really appreciate any help!!
One way to deal with this is to turn off the printf when your return is called recursively:
static char ACallIsInProgress = 0;
if (!ACallIsInProgress)
{
ACallIsInProgress = 1;
printf("malloc(%d) = %p\n", (int)size, ptr);
ACallIsInProgress = 0;
}
return ptr;
With this, if printf calls malloc, your routine will merely call the actual malloc (via mallocp) and return without causing another printf. You will miss printing information about a call to malloc that the printf does, but that is generally tolerable when interposing is being used to study the general program, not the C library.
If you need to support multithreading, some additional work might be needed.
The printf implementation might allocate a buffer only once, the first time it is used. In that case, you can initialize a flag that turns off the printf similar to the above, call printf once in the main routine (maybe be sure it includes a nice formatting task that causes printf to allocate a buffer, not a plain string), and then set the flag to turn on the printf call and leave it set for the rest of the program.
Another option is for your malloc routine not to use printf at all but to cache data in a buffer to be written later by some other routine or to write raw data to a file using write, with that data interpreted and formatted by a separate program later. Or the raw data could be written by a pipe to a program that formats and prints it and that is not using your interposed malloc.
I was wondering how to solve a Core dumped issue on my C code.
When I compile it with: g++ -g MatSim.cpp -o MatSim -lstdc++ -O3, I get three warnings, this is one (The other two are similar and are only differentiated by the string variable name):
MatSim.cpp: In function ‘int main()’:
MatSim.cpp:200037:27: warning: ignoring return value of ‘int fscanf(FILE*, const char*, ...)’, declared with attribute warn_unused_result [-Wunused-result]
fscanf(TM,"%255s",string2);
The principal aspects of my code and the related part that the compiler reports:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <iostream>
#include <fstream>
#include <string.h>
using namespace std;
int to_int(char string[256])
{
if( strcmp(string,"0") == 0 )
{
return 0;
}
...
else if( strcmp(string,"50000") == 0 )
{
return 50000;
}
return -1;
}
int main()
{
int a,b,div,value,k,i,j,tm,ler;
char string[256];
char string1[256];
char string2[256];
FILE *TM;
TM = fopen("TM","r");
if( (TM = fopen("TM","r")) == NULL)
{
printf("Can't open %s\n","TM");
exit(1);
}
fscanf(TM,"%255s",string2);
tm = to_int(string2);
fclose(TM);
...
}
I have tried the reported suggestion in here and I tried to understand what was posted in here. But, I don't see its application on my code.
Finally, when I run the exe file, it returns:
Segmentation fault (core dumped)`.
In your code, you're fopen()ing the file twice. Just get rid of the
TM = fopen("TM","r");
before the if statement.
That said, you should check the value of fscanf() to ensure success. Otherwise, you'll end up reading an uninitialized array string2, which is not null-terminated which in turn invokes undefined behaviour.
Please be aware, almost all string related functions expect a null-terminated char array. If your array is not null terminated, there will be UB. Also, it is a good practice to initialize your automatic local variables to avoid possible UB in later part of code.
You are opening the file twice.
Alll you need is this:
FILE *TM = fopen("TM","r");
if (TM == NULL) { /* file was not opened */ }
I was playing around with C and the scanf function and came across this weird error that I can't seem to figure out. Given the following code:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int a;
} sample;
void fn(sample *s) {
char command;
scanf("%[abc]", &command);
printf("Read: %c\n", command);
printf("In the sample function:, %i\n", s->a);
}
int main() {
sample *s = malloc(sizeof(sample));
s->a = 4;
printf("Before sample function: %i\n", s->a);
fn(s);
printf("After sample function: %i\n", s->a);
return 0;
}
It seems to seg fault. With the output:
$ ./sample
Before sample function: 4
a
Read: a
In the sample function:, 4
Segmentation fault (core dumped)
I used gdb and attached a watch to the struct, it seems that inside the scanf function, it seems to 'modify' the struct? Which is weird, because even after the scanf inside the sample function 'fn', it is able to print out the struct fields fine. However, once returning from the fn and jumping back into main, it seg faults when it tries to print out the same information?
Interestingly, if you change the scanf to scanf("%c\n", &command); (without the character set) it seems to work fine. For the record, the version of gcc I am using is 4.7.2, and I am compiling the code with: gcc -O0 -o sample sample.c.
My only thought is that perhaps character sets aren't supported by gcc? I'm not sure. Just wondering if anyone else could clear this up?
scanf("%[abc]", &command);
writes a string not a single character. The trailing null character of the string is being written in &command + 1 in your program.
You should pass to scanf something like:
command with command being:
char command[2];
I want to preface this by saying that I've done very little programming in C, so I'd prefer to know why a given solution works rather than just what it is.
I'm trying to write a function which will take a pathname, and return a pathname to a different file in the same directory.
"/example/directory/with/image.png" => "/example/directory/with/thumbnail.png"
What I've tried after reading up on example uses of realpath and dirname (I'm working on Linux; if there's a cross-platform equivalent, let me know) is:
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
char *chop_path(char *orig) {
char buf[PATH_MAX + 1];
char *res, *dname, *thumb;
res = realpath(orig, buf);
if (res) {
dname = dirname(res);
thumb = strcat(dname, "/thumbnail.png");
return thumb;
}
return 0;
}
Compiling it seems to work, but running the program with
int main(void) {
char *res = chop_path("original.png");
if (res) {
printf("Resulting pathname: %s", res);
}
return 0;
}
gives me a segfault. Any hints?
The only problem I see is the signature of your chop_path routine; it should be
char *chop_path(char *orig) {
Your version has a missing *. That makes an enormous difference actually; without the *, you're effectively telling dirname and realpath to interpret the character code of the first character in your argument string as the numerical address (i.e., a pointer to) the path. That's going to point into a location in low memory that you definitely have not allocated; trying to use it results in that "segmentation fault" error, which means, effectively, that you're trying to touch memory you're not allowed to.
The other issue turned out to be that the dirname() function is declared in libgen.h, which you weren't including. If you don't include that header, the compiler assumes dirname() returns int instead of a pointer, and on a 64-bit architecture, the 64-bit return value from the function gets chopped down to 32 bits, a bad pointer is assigned to dname, and that's going to cause your seg fault right there.
If you don't want to use dirname, realpath, unwanted string buffer and string operations, etc - you can do the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#define FILE_MAX 100
void chop_path(char path_name[], char new_file[]) {
int len = strlen(path_name);
int i;
for (i=len-1; i>0 ; i--) {
if (path_name[i] == '/') {
strcpy(path_name+i+1, new_file);
break;
}
}
return;
}
int main(void) {
char path[PATH_MAX + 1] = "/this/is/a/path/filename.c";
char new_file[FILE_MAX] = "newfilename.txt";
printf("old : %s \n", path);
chop_path(path, new_file);
printf("new : %s \n", path);
return 0;
}
Output:
$ gcc path.c
$ ./a.out
old : /this/is/a/path/filename.c
new : /this/is/a/path/newfilename.txt
$