Timothy Samson
Timothy Samson

Reputation: 115

Can't run printf() on a null-terminated string

printf() throws a segmentation fault when I pass a null-terminated string for some reason.

Here's a demonstration of my problem in GDB


     λ sudo gdb -q notesearch
    Reading symbols from notesearch...done.
    (gdb) break 53
    Breakpoint 1 at 0x400b32: file notesearch.c, line 53.
    (gdb) run
    Starting program: /home/frosty/hack/chapter_2/code/notesearch 
    [DEBUG] UserID: 0
    [DEBUG] File Descriptor: 3

    Breakpoint 1, print_notes (fd=3, uid=0, searchstring=0x7fff3daf7fc0 "")
        at notesearch.c:53
    53          printf("%s\n", note_buffer);
    (gdb) x/8xb note_buffer
    0x7feb5a997168: 0x68    0x65    0x6c    0x6c    0x6f    0x0a    0x00    0x00
    (gdb) x/s note_buffer
    0x7feb5a997168: "hello\n"
    (gdb) next

    Program received signal SIGSEGV, Segmentation fault.
    _dl_fixup (l=, reloc_arg=)
        at ../elf/dl-runtime.c:148
    148 ../elf/dl-runtime.c: No such file or directory.
    (gdb) 

Here's the source code around the problem


    int print_notes(int fd, int uid, char *searchstring){
        int note_length = find_user_note(fd, uid);

        if (note_length == -1) 
            return 0; // End of file

        char* note_buffer;
        read(fd, note_buffer, note_length);

        note_buffer[note_length] = 0; // null terminator byte

        if(search_note(note_buffer, searchstring)) {
            printf("%s\n", note_buffer);
        }
        return 1;
    }

Upvotes: 1

Views: 358

Answers (2)

user3629249
user3629249

Reputation: 16540

remember that in C, arrays are indexed from 0 through (length of array-1)

This line:

char* note_buffer;

declares an initialized pointer to character. I.E. its value depends on what ever trash is currently in memory at that location. Such an action as accessing where that trash 'points' would be undefined behavior and can lead to a seg fault event.

Strongly suggest, after this line:

char* note_buffer;

inserting the following: (including the checking for a malloc() failure:

note_buffer = malloc( note_length+1 );
if( !note_buffer )
{
    perror( "malloc failed" ); 
    exit( EXIT_FAILURE );
}

// implied else, malloc successful

Note: without the +1 on the call to malloc() the following line:

note_buffer[note_length] = 0;

would be setting a byte that is one past the end of the allocated area. That would be undefined behavior and can lead to a seg fault event

Also, a 0 has the bit pattern 0x000000000000000000000000 and a '\0' has the bit pattern 0x00000000. the implicit conversion feature will save you in this instance, but do not rely on that feature, instead properly code literals. so the line should be:

note_buffer[note_length] = '\0';

Note: perror() outputs the enclosed text string AND the reason the OS thinks the error occurred to stderr, which is where all error messages should be output.

Upvotes: 0

unjankify
unjankify

Reputation: 320

Null terminator is indicated by \0 not 0

note_buffer[note_length] = 0;

should be

note_buffer[note_length] = '\0';

Upvotes: 0

Related Questions