Call to a non-reentrant POSIX function
ID |
objectivec.correctness.mt_unsafe |
Severity |
low |
Remediation Complexity |
medium |
Remediation Risk |
medium |
Remediation Effort |
medium |
Resource |
Concurrency |
Language |
Objective-C |
Description
Reports a call to a POSIX or libc function that is documented as non-reentrant - the random number generators, strtok, strerror, the getpw*/getgr* account lookups, the gethost*/getserv*/getproto* resolvers, readdir, crypt, inet_ntoa and the ecvt/fcvt/gcvt converters. The _r variants and the Objective-C and arc4random alternatives are not reported. The date and time family is reported separately by avoid-time-h, getenv and system by avoid-stdlib-process-functions, and tmpnam by avoid-stdio.
Rationale
Each of these functions keeps its result, or its iteration state, in a single buffer shared by the whole process. A second thread that calls the same function overwrites that buffer while the first thread still holds a pointer into it, so the first thread reads another thread’s answer - the wrong account, the wrong host, another strtok cursor - with no error returned anywhere. The generators are worse than wrong: rand and random mutate one global seed, so concurrent callers can be handed the same value. None of this shows up under light load, which is why it survives testing and appears as an unreproducible defect once a queue starts running the code concurrently.
The following code illustrates the pattern detected by this rule:
@implementation Session
- (NSArray *)splitFields:(char *)line {
// FLAGGED: Call to a non-reentrant POSIX function
char *field = strtok(line, ",");
while (field) {
// FLAGGED: Call to a non-reentrant POSIX function
field = strtok(NULL, ",");
}
return @[];
}
@end
Remediation
Call the _r variant, which takes a caller-supplied buffer - strtok_r, strerror_r, getpwnam_r, getlogin_r, readdir_r - or the Objective-C equivalent, which never shares state: NSString componentsSeparatedByString: for strtok, NSError for strerror, NSHost or getaddrinfo for gethostbyname, NSFileManager for readdir. Replace rand, random and the drand48 family with arc4random_uniform, which needs no seed and is thread-safe.