Skip to content

Alternative approach to using strerror_r for reentrant error string conversion#11010

Merged
xavierleroy merged 3 commits intoocaml:trunkfrom
xavierleroy:strerror_r
Feb 17, 2022
Merged

Alternative approach to using strerror_r for reentrant error string conversion#11010
xavierleroy merged 3 commits intoocaml:trunkfrom
xavierleroy:strerror_r

Conversation

@xavierleroy
Copy link
Copy Markdown
Contributor

This is a variant of #10969 that does not use thread-local storage. Instead, caml_strerror is given the same interface as the GNU nonstandard strerror_r function: it takes a buffer as argument, which it may use or not, and returns a char * pointing to the error message, which can be in the buffer or not.

runtime/sys.c Outdated
#elif defined(_GNU_SOURCE)
return strerror_r(errnum, buf, buflen);
#else
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this special case is necessary: _GNU_SOURCE is not defined in this file, and the fallback case below would result in a type error if the GNU version of strerror_r as , and if it were the C compiler would error on the use of strerror_r with the wrong type.

But I don't mind keeping the special case, and I checked that the function compiles and runs correctly whether _GNU_SOURCE is defined or not.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't you want to define _GNU_SOURCE in order to get the GNU implementation, though? That would avoid a data copy for each caml_strerror call, since GNU strerror_r usually just returns an immutable pointer to its static array of error messages (whereas the XSI version is forced to copy into the destination buffer). That's why I stuck it in a separate file in the other PR, for header hygiene.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, now I understand the motivation for the special case: it's not "do the right thing if _GNU_SOURCE happens to be defined", it's "use the GNU version for performance". Sorry for having missed that. I need to think about it some more, but globally I'm not too concerned about the extra copy done by the POSIX strerror_r.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went out on a limb and removed support for the GNU version of strerror_r. It feels safer to rely exclusively on the POSIX function. Nothing is performance-critical here. Let me know what you think.

@avsm
Copy link
Copy Markdown
Member

avsm commented Feb 14, 2022

This looks good! I used TLS in my PR since I wasn't sure about using so much stack space for some of the invocations in the error path. If that's acceptable, then this is definitely a better approach. I'll try this PR on OpenBSD/FreeBSD later on.

@xavierleroy
Copy link
Copy Markdown
Contributor Author

I think the extra stack space usage is reasonable, esp. on OCaml 5 where the C stacks are not used for OCaml stack frames and therefore have a much lower chance of overflowing.

Maybe check_err in <caml/platform.h> should not be inlined, though. I'll look into this.

@xavierleroy
Copy link
Copy Markdown
Contributor Author

Maybe check_err in <caml/platform.h> should not be inlined, though. I'll look into this.

Done in 127fbe6 .

This uses the POSIX strerror_r function on *nix,
and strerror on Win32 (which is thread-safe).

Co-authored-by: Anil Madhavapeddy <anil@recoil.org>

squashme
It's better to do it in a separate "cold" function, to reduce code
size and stack usage for the platform functions.
Copy link
Copy Markdown
Member

@avsm avsm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope to tempt you with the more efficient version for the common case (Linux/glibc/gnu-strerror) in avsm@d35845c which adds onto this branch, but the existing version is fine by me. Tested on FreeBSD/OpenBSD.

@xavierleroy
Copy link
Copy Markdown
Contributor Author

After much soul-searching, I'd rather stay with a pure POSIX solution. Thanks for your patience!

@xavierleroy xavierleroy merged commit 3202e53 into ocaml:trunk Feb 17, 2022
@xavierleroy xavierleroy deleted the strerror_r branch February 17, 2022 10:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants