Home > Software engineering >  Segmentation fault when opening file gcc Linux vs gcc clang
Segmentation fault when opening file gcc Linux vs gcc clang

Time:10-31

Initializing the file name via pointer let's crash the gcc on Linux but not on MacOS, can someone explain this?

#include <stdio.h>

int doOpenFile( char *name, FILE **filehdl, char *option );

int doOpenFile( char *name, FILE **filehdl, char *option )
{
  if( *filehdl ) fclose( *filehdl );
  if( (*filehdl = fopen( name, option )) == NULL ) return( -1 );
  return( 0 );
}

int main(int argc, char **argv)
{

  char *file = "test.c";
  FILE *filePtr;
  
  doOpenFile(file, &filePtr, "r");

  if(filePtr != NULL) fclose(filePtr);
  
  printf("%s\n", file);
}

Linux gcc:

oot@1fa88ab5df9e:/build/open62541-server# gcc -o test test.c
root@1fa88ab5df9e:/build/open62541-server# ./test
Segmentation fault (core dumped)
root@1fa88ab5df9e:/build/open62541-server# gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/10/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa:hsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 10.2.1-6' --with-bugurl=file:///usr/share/doc/gcc-10/README.Bugs --enable-languages=c,ada,c  ,go,brig,d,fortran,objc,obj-c  ,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-10 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-10-Km9U7s/gcc-10-10.2.1/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-10-Km9U7s/gcc-10-10.2.1/debian/tmp-gcn/usr,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-mutex
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 10.2.1 20210110 (Debian 10.2.1-6) 
root@1fa88ab5df9e:/build/open62541-server# 

MacOS:

open62541-server % gcc test.c -o test 
open62541-server % ./test
test.c
open62541-server % gcc -v            
Apple clang version 14.0.0 (clang-1400.0.29.102)
Target: arm64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
open62541-server % 

Weird because even if I don't pass the variable, the gcc on Linux crash

doOpenFile("test.c", &filePtr, "r");

CodePudding user response:

if( *filehdl ) invokes undefined behavior since you are accessing a non-initialized FILE pointer. Either document to the caller that the function assumes the parameter to either be a null pointer or a valid file pointer, or drop the if statement.

Unrelated to your problem, you should also use const char* everywhere in this code, for const correctness and because string literals are read-only anyway.

CodePudding user response:

Like the others said. When you declare a variable in C it does contain a (seemingly) random value that happened to be in RAM at runtime. That value can be NULL (or nil if you print it on the console, those two words mean the same). I wrote a small program to show this:

#include <stdio.h>

int main() {
    int* pointer[20];
    for(int i = 0; i < 20;   i) {
        printf("%p\n", &pointer[i]);
    }
}

Output:

(nil)
(nil)
(nil)
(nil)
(nil)
(nil)
(nil)
(nil)
(nil)
0x1007
0x5631f0cff040
0xd
0x7ffe17efbbf0
0x7ffe17efc019
0x7f512adab5e0
0x5631f0d0023d
0x7f512ad862e8
0x5631f0d001f0
(nil)
0x5631f0d00080

So you see that there is a chance that the value is NULL, and that's probably what happened in you MacOS try. But feel free to run my small program here to check if that is always the case on your Mac.

When you pass a pointer that is not NULL to fclose( *filehdl ); you get a segmentation fault because it points to an address that does not belong to your program. The easiest way to fix your problem ist to just initialize:

FILE *filePtr = NULL;
  •  Tags:  
  • c
  • Related