Coding

POSIX File Handling and Undefined Behaviour

Whilst porting code between Linux and macOS I have come across two issues which make assumptions about how something works but in reality different implementations of libc handle them differently. In this post I’ll talk about recent issues I faced with fopen() and fclose() in codebases.

fopen()

In the code I was porting from Linux to macOS there was a section which opened a file in “a+” mode, read the contents and then as time went on appended more data to the file. Everything was going great, but in macOS the file wasn’t being read at all. The reason is undefined behaviour for the read pointer as outlined in the Linux man page for open:

POSIX is silent on what the
initial read position is when using this mode. For glibc, the
initial file position for reading is at the beginning of the
file, but for Android/BSD/MacOS, the initial file position for
reading is at the end of the file.

http://man7.org/linux/man-pages/man3/fopen.3.html

The Linux code was assuming that when the file was opened in “a+” mode the read pointer was always at the start of the file. But in macOS the read pointer is right at the end of the file when opened. Fixing this was as simple as a basic seek but it was difficult to find this behaviour difference documented outside of the Linux man pages.

fclose()

This issue comes from porting code the other way around, from macOS to Linux. The code in question did this:

fclose(fileptr);

Which is fine, but it was possible that this code could be executed when there is no file open and fileptr is NULL. In macOS this causes fclose() to just return with no operation executed. But in Linux fclose(NULL) will crash with a segmentation fault.

I couldn’t find any explicit documentation on this, but many instances of other people hitting this crash. POSIX doesn’t define what should happen if a NULL pointer is passed to fclose() so this becomes undefined behaviour. Again this was easy to fix with a simple ‘if’ statement.

The moral of the story

The key takeaway here is “undefined behaviour” may not always be explicitly defined in documentation. If there is no explicit documentation for a given input to or usage of a function it is likely that different operating systems will implement it in different ways.

LinuxJedi

Share
Published by
LinuxJedi
Tags: COpen Source

Recent Posts

Diagnosing an Amiga 1200 Data Path Fault

I recently acquired an Amiga 1200 motherboard in a spares/repairs condition for about £100 recently.…

2 days ago

Bare Metal “Hello World” on an STM32MP135F-DK

Whilst I do like working with STM32 development boards, some basic information I need can…

3 days ago

Two special Amiga 4000s: Diagnosing Jops

When I last left this blog series, the first of Stoo Cambridge's A4000s had gone…

6 days ago

Joining wolfSSL

At the beginning of November, I started working for wolfSSL. Now that I'm a week…

1 week ago

Two special Amiga 4000s: Rebuilding Jools

In my previous post, I had the Amiga 4000 known as Jools mostly repaired, there…

4 weeks ago

Two special Amiga 4000s: Repairing Jools

In my last post, I created a list of things I needed to repair on…

4 weeks ago