Help with segfault - Programming On Unix

Users browsing this thread: 1 Guest(s)
Long time nixers
So I'm barely getting into C and wanted to start with something that goes step by step, fairly recent, and then going to run through K&R2. Chose Zed A. Shaw's Learn C the Hard Way. Exercise 16 ran perfect for me. Until I rebuilt my laptop with Debian on it. I was running Solus. Now when I try to run the following code, it segfaults right after completing the printf statement on line 51. I tried running it through gdb and I get an error saying strlen.S No such file or directory, so I'm not sure what I'm missing to be able to debug this small program. Weird thing is, if I run it through valgrind, it does NOT segfault. It also does not segfault on my work Fedora install. This is verbatim code for exercise 16 from the book.

Is there a perfectly valid reason this code would segfault, or is my machine misconfigured?

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>

struct Person {
    char *name;
    int age;
    int height;
    int weight;

struct Person *Person_create(char *name, int age, int height,
        int weight)
    struct Person *who = malloc(sizeof(struct Person));
    assert(who != NULL);

    who->name = strdup(name);
    who->age = age;
    who->height = height;
    who->weight = weight;

    return who;

void Person_destroy(struct Person *who)
    assert(who != NULL);


void Person_print(struct Person *who)
    printf("Name: %s\n", who->name);
    printf("\tAge: %d\n", who->age);
    printf("\tHeight: %d\n", who->height);
    printf("\tWeight: %d\n", who->weight);

int main(int argc, char*argv[])
    //make two people structures
    struct Person *joe = Person_create("Joe Alex", 32, 64, 140);

    struct Person *frank = Person_create("Frank Blank", 20, 72, 180);

    // print them out and where they are in memory
    printf("Joe is at memory location %p:\n", joe);

    printf("Frank is at memory location %p:\n", frank);

    //make everyone age 20 years and print them again
    joe->age += 20;
    joe->height -= 2;
    joe->weight += 40;

    frank->age += 20;
    frank->weight += 20;

    //destroy them both so we clean up

    return 0;
running the code through my machine, I get this warning
51: warning: format '%p' expects type 'void *', but argument 2 has type 'struct Person *'
if I type cast to a void pointer, everything runs fine.
Maybe that's your issue? The strlen warning is weird, as you have no calls to strlen in your code. Hopefully someone else will be able to help you better.

Here is a good list of c resources that you might appreciate:
Grey Hair Nixers
Your issue is not a direct call to strlen(3), it an internal function of the libc called strlen.S which seems to fail. This is the kind of things that happen when you pass a NULL pointer to a function in string.h (eg. strdup(3).

I ran it on my computer and don't get any warning at compilation, and couldn't get it to segfault though. We'll need the full trace of your runs here.
Long time nixers
i wasn't under the impression a NULL pointer was being passed... how do i provide a full trace?
Grey Hair Nixers
strace ./yourprog
valgrind ./yourprog
gdb ./yourprog

Then send us the WHOLE output. A segfault occurs when some function tries to access a forbidden memory area. This is 90% of the time due to a NULL pointer being passed. In your case, I can't see were this could happen though.
Long time nixers
I can't get it to segfault either. Running it with valgrind is also fine.
Long time nixers
$ strace ./ex16
execve("./ex16", ["./ex16"], [/* 42 vars */]) = 0
brk(NULL)                               = 0x56223f2f4000
access("/etc/", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6c39e7c000
access("/etc/", R_OK)      = 0
open("/etc/", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
close(3)                                = 0
open("/etc/", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=115220, ...}) = 0
mmap(NULL, 115220, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f6c39e5f000
close(3)                                = 0
access("/etc/", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\3\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1689360, ...}) = 0
mmap(NULL, 3795360, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f6c398bd000
mprotect(0x7f6c39a52000, 2097152, PROT_NONE) = 0
mmap(0x7f6c39c52000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x195000) = 0x7f6c39c52000
mmap(0x7f6c39c58000, 14752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f6c39c58000
close(3)                                = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6c39e5d000
arch_prctl(ARCH_SET_FS, 0x7f6c39e5d700) = 0
mprotect(0x7f6c39c52000, 16384, PROT_READ) = 0
mprotect(0x56223db40000, 4096, PROT_READ) = 0
mprotect(0x7f6c39e7f000, 4096, PROT_READ) = 0
munmap(0x7f6c39e5f000, 115220)          = 0
brk(NULL)                               = 0x56223f2f4000
brk(0x56223f315000)                     = 0x56223f315000
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
write(1, "Joe is at memory location 0x5622"..., 42Joe is at memory location 0x56223f2f4010:
) = 42
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x3f2f4030} ---
+++ killed by SIGSEGV +++
Segmentation fault

$ gdb ex16
GNU gdb (Debian 7.12-6)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
Find the GDB manual and other documentation resources online at:
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ex16...done.
(gdb) run
Starting program: /home/chaos/hive/projects/learn-c/lcthw/source/ex16
Joe is at memory location 0x555555756010:

Program received signal SIGSEGV, Segmentation fault.
strlen () at ../sysdeps/x86_64/strlen.S:106
106    ../sysdeps/x86_64/strlen.S: No such file or directory.

$ valgrind ./ex16
==6234== Memcheck, a memory error detector
==6234== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==6234== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==6234== Command: ./ex16
Joe is at memory location 0x51d7040:
Name: Joe Alex
    Age: 32
    Height: 64
    Weight: 140
Frank is at memory location 0x51d70f0:
Name: Frank Blank
    Age: 20
    Height: 72
    Weight: 180
Name: Joe Alex
    Age: 52
    Height: 66
    Weight: 180
Name: Frank Blank
    Age: 40
    Height: 72
    Weight: 200
==6234== HEAP SUMMARY:
==6234==     in use at exit: 0 bytes in 0 blocks
==6234==   total heap usage: 5 allocs, 5 frees, 1,093 bytes allocated
==6234== All heap blocks were freed -- no leaks are possible
==6234== For counts of detected and suppressed errors, rerun with: -v
==6234== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Grey Hair Nixers
That's really odd... Try to add this at the top of your Person_print() function:
assert(who != NULL);
Long time nixers
It compiled and still segfaults. I'm going to assume my machine is missing something somehow. I installed the `build-essential` meta-package as well as some extras. If I can't get it to work on Debian, I'm probably going to switch to another distro... I'm starting to run out of those.