Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace non-thread-safe functions #4870

Open
Tracked by #4861
kodebach opened this issue Mar 12, 2023 · 2 comments
Open
Tracked by #4861

Replace non-thread-safe functions #4870

kodebach opened this issue Mar 12, 2023 · 2 comments
Assignees

Comments

@kodebach
Copy link
Member

kodebach commented Mar 12, 2023

Using the list of functions for which POSIX does not guarantee thread-safety from here, I have now found that we use (with usage counts):

  • basename: 1
  • dirname: 3
  • dlerror: 1
  • getenv: 9
  • getopt: 1
  • getpwnam: 1
  • getservbyname: 1
  • localeconv: 1
  • nl_langinfo: 1
  • rand: 1
  • setenv: 2
  • setlocale: 3
  • strerror: 18
  • strsignal: 1
  • strtok: 3
  • system: 1
  • unsetenv: 1
  • wctomb: 1

Full results here

I found these replacement functions

  • getpwnam -> getpwnam_r
  • getservbyname -> getaddrinfo
  • localeconv -> nl_langinfo_l
  • nl_langinfo -> nl_langinfo_l
  • strerror -> strerror_r
  • strsignal -> strdescr_np (GNU)
  • strtok -> strtok_r

The other functions listed above have no options at all AFAICT. However, that's not so bad. If we ignore test and example code, as well as the functions which alternatives, we're left with:

  • basename:
    • [../libelektra/src/plugins/curlget/curlget.c:349:28]
  • dirname:
    • [../libelektra/src/bindings/intercept/fs/intercept.c:47:23] Deprecated
    • [../libelektra/src/plugins/gitresolver/gitresolver.c:236:24]
    • [../libelektra/src/plugins/resolver/filename.c:97:15]
  • getservbyname:
    • [../libelektra/src/plugins/network/network.c:78:13]
  • getopt:
    • [../libelektra/src/tools/pythongen/template/genopt.c:113:14] Deprecated
  • getenv:
    • [../libelektra/src/plugins/cache/cache.c:67:20]
    • [../libelektra/src/plugins/wresolver/wresolver.c:122:18]
    • [../libelektra/src/plugins/crypto/gpg.c:140:25]
    • [../libelektra/src/plugins/journald/journald.c:43:17]
    • [../libelektra/src/plugins/fcrypt/fcrypt.c:79:12]
    • [../libelektra/src/plugins/desktop/desktop.c:43:6]

I will write a tree-surgeon script for getpwnam -> getpwnam_r, getservbyname -> getaddrinfo, localeconv -> nl_langinfo_l, nl_langinfo -> nl_langinfo_l, strerror -> strerror_r and strtok -> strtok_r.

basename and dirname are marked thread-safe on Linux and I don't know why they wouldn't be on any platform, AFAIK getenv can only race with setenv, which we only use in tests, and getopt is only used in the deprecated pythongen code. So I think we can ignore all of these.

@kodebach
Copy link
Member Author

Small update:

  1. I will still write a migration script for strerror, but it will be specific to Elektra and rely on a elektraStrError function I'll add to libelektra-core or as static inline to a suitable header. The reason is that glibc and POSIX have conflicting implementations for strerror_r and you cannot write a generic migration script without knowing which implementation will be used.
  2. Automatic migration for getpwnam would probably be possible, but it's very non-trivial because it involves additional calls to sysconf and possible repeated attempts in a loop for the generic case. We only use it once, developing a script is simply not worth it. I'll refactor manually.
  3. It's a similar story for getservbyname.
  4. Generic scripts for nl_langinfo, localconv and strtok should be doable.

@kodebach
Copy link
Member Author

Correction to point 4 in the comment above:

  • strtok cannot be migrated with a generic script. A restricted script that makes some assumptions about how strtok is used (*1) would be possible. But by now we use the function exactly 5 times in the entire repo. Writing and testing a script would not be worth it.
  • Similarly for the two uses of localeconv the time for developing a script is too much. However, in this case a more generic script would be possible (*2).

So only nl_langinfo can actually be updated in generic fashion, by replacing nl_langinfo(X) with

locale_t loc = newlocale (LC_ALL, setlocale (LC_ALL, NULL), NULL);
// nl_langinfo line with nl_langinfo(X) replaced by nl_langinfo_l(X, loc)
freelocale (loc);

(*1) not across different scopes, not switching delimiters, etc.
(*2) it would still be necessary to assume the result of localeconv is only used within a single function call, so that stack allocation can be used as a replacement for the global result of localeconv

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

No branches or pull requests

1 participant