== Why is this an issue?

A function is called reentrant if it can be interrupted in the middle of its execution and then safely called again ("re-entered") before its previous invocations complete execution.


It is especially important that multi-threaded applications do not call the same non-reentrant function from different threads.


This rule will trigger an issue each time a function in the configurable list is invoked.

A call will be matched differently depending on the presence of the scope resolution operator ``::`` in the function name from the configurable list.


For example, `namespace a { namespace b { void f(); } }` can be matched with "f", "b::f", "a::b::f", "::a::b::f" (fully qualified name yielding most precise results).


It is recommended to provide fully qualified names to the configurable list (i.e., start each name with `::`), even for the functions in the global namespace.

=== Noncompliant code example

Given a function that includes ``++localtime++``:

[source,cpp,diff-id=1,diff-type=noncompliant]
----
#include <stdio.h>
#include <time.h>

void print_date_and_time(struct tm *time_ptr)
{
  printf(
    "Current date and time: %d/%02d/%02d %02d:%02d:%02d\n",
    time_ptr->tm_year + 1900,
    time_ptr->tm_mon,
    time_ptr->tm_mday,
    time_ptr->tm_hour,
    time_ptr->tm_min,
    time_ptr->tm_sec);
}

void print_unix_epoch_date_and_time()
{
  time_t unix_epoch_time = (time_t)0;
  struct tm *local_time_ptr = localtime(&unix_epoch_time); // Noncompliant, call to the non-reentrant localtime() function
  print_date_and_time(local_time_ptr);
}

int main(int argc, char* argv[])
{
  time_t current_time;
  struct tm *local_time_ptr;

  time(&current_time);

  local_time_ptr = localtime(&current_time); // Noncompliant, call to the non-reentrant localtime() function

  // As expected, this will print: Current date and time: 1970/00/01 01:00:00
  print_unix_epoch_date_and_time();

  // This will actually also print Current date and time: 1970/00/01 01:00:00
  // Indeed, localtime() is non-reentrant, and always returns the same pointer
  print_date_and_time(local_time_ptr);

  return 0;
}
----


=== Compliant solution

[source,cpp,diff-id=1,diff-type=compliant]
----
#include <stdio.h>
#include <time.h>

void print_date_and_time(struct tm *time_ptr)
{
  printf(
    "Current date and time: %d/%02d/%02d %02d:%02d:%02d\n",
    time_ptr->tm_year + 1900,
    time_ptr->tm_mon,
    time_ptr->tm_mday,
    time_ptr->tm_hour,
    time_ptr->tm_min,
    time_ptr->tm_sec);
}

void print_unix_epoch_date_and_time()
{
  time_t unix_epoch_time = (time_t)0;
  struct tm local_time;
  localtime_r(&unix_epoch_time, &local_time); // Compliant
  print_date_and_time(&local_time);
}

int main(int argc, char* argv[])
{
  time_t current_time;
  struct tm local_time;

  time(&current_time);

  localtime_r(&current_time, &local_time); // Compliant

  // As expected, this will print: Current date and time: 1970/00/01 01:00:00
  print_unix_epoch_date_and_time();

  // As expected, this will print the current date and time
  print_date_and_time(&local_time);

  return 0;
}
----

== Resources

* {cpp} reference - https://en.cppreference.com/w/cpp/language/lookup[Name Lookup]


ifdef::env-github,rspecator-view[]

'''
== Implementation Specification
(visible only on this page)

=== Message

Replace this call to the non-reentrant "{0}" with a call to "{0}_r"


=== Parameters

.nonReentrantFunctionList
****
_STRING_

----
::asctime,::crypt,::ctermid,::ctime,::fgetgrent,::fgetpwent,::fgetspent,::getgrent,::getgrgid,::getgrnam,::gethostbyaddr,::gethostbyname,::gethostbyname2,::gethostent,::getlogin,::getnetbyaddr,::getnetbyname,::getnetent,::getnetgrent,::getprotobyname,::getprotobynumber,::getprotoent,::getpwent,::getpwnam,::getpwuid,::getrpcbyname,::getrpcbynumber,::getrpcent,::getservbyname,::getservbyport,::getservent,::getspent,::getspnam,::gmtime,::localtime,::sgetspent,::strtok,::ttyname
----

List of non-reentrant functions
****


endif::env-github,rspecator-view[]
