Search code examples
cnullrhelhp-uxstrchr

C strchr works with NULL value on HPUX but segfaults on RHEL


I'm moving some code from HPUX 11.11 to RHEL 7.5 and it includes a function that uses strchr. On HPUX it runs fine, and on RHEL there is a segmentation fault. I isolated the code and created the following simple test, with the subsequent results. It looks like HPUX strchr is returning an empty string rather than NULL when the character is not found. This is not what the man page says. I have found it might not be the strchr function but the difference in how HPUX handles NULL values, or a difference in compiler from cc to gcc. Does anyone actually know what's happening here? Why is the code not segfaulting on HPUX?

C Code:

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

int main(int argc, char *argv[]) {
    int i = 0;
    char* phrase = "Here is my phrase.";
    while (i < 5){
        phrase = strchr(phrase, ' ');
        ++phrase;

        ++i;
    }
    return 0;
}

HPUX makefile:

BIN=/path/to/bin/
CFLAGS=-c

#----------Targets----------#
default: $(BIN)strchrtest

#----------Objects----------#
OBJS = strchrtest.o

#----------------BUILD----------------#
$(BIN)strchrtest: $(OBJS) 
    cc -o $@ $(OBJS) 

strchrtest.o: strchrtest.c
    cc $(CFLAGS) strchrtest.c

RHEL makefile:

CC=gcc
BIN=/path/to/bin/
CFLAGS=-c -g -Wall

#----------Targets----------#
default: $(BIN)strchrtest

#----------Objects----------#
OBJS = strchrtest.o

#----------------BUILD----------------#
$(BIN)strchrtest: $(OBJS) 
    $(CC) -o $@ $(OBJS) 

strchrtest.o: strchrtest.c
    $(CC) $(CFLAGS) strchrtest.c

HPUX is just a successful result. No segmentation fault.

RHEL results:

(gdb) run
Starting program: ../strchrtest

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b4c5f4 in __strchr_sse42 () from /lib64/libc.so.6

Copied form my comment below: The point is that the strchr function itself is causing the segfault when asked to find a character in the null pointer (that has been incremented), but on HPUX it doesn't. So it's either returning an empty string that is then passed strchr on the next loop, or strchr is handling the null pointer parameter differently by not segfaulting. Or I misunderstand what's happening.


Solution

  • Make two files, r.c, main.c as such r.c:

    int *r = 0;
    

    main.c:

    extern int *r;
    int main(void) {
         return *r;
    }
    

    then cc main.c r.c; ./a.out if it doesn't sigsegv, your runtime is mapping a page of nulls for you. you could do it yourself - main.c:

    #include <sys/mman.h>
    int main(void) {
        p = mmap(0, 1, PROT_READ, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
        if (p == MAP_FAILED) {
            perror("mmap");
            exit(1);
        }
         ....
    }
    

    but at least on ubuntu, you need to be root :(