Do not change the interface to achieve thread safety--getenv security?

Source: Internet
Author: User

In Apue (second edition) This book read the 12th chapter, 12.6 of the thread private data. To enable each thread to access a copy of the data independently, call Pthread_key_create () in the execution function of the thread to create a key for it, using this key to reuse pthread_getspecific () and pthread_setspecific () To associate private data with this thread.

The author then uses thread-private data in code 12-5 to implement a thread-safe getenv ().

Here's a general explanation of my question:

The first is about the implementation mechanism of the getenv () function:

The process should maintain a global variable char **environ, which points to the string of each environment variable, while maintaining a buffer of a global string (named Envbuf) in the original GETENV implementation, and when the thread calls getenv (), The system finds a string of the corresponding environment variable, copies it to the global buffer envbuf, and returns it to the caller via the getenv () function.

If multiple threads call getenv () at the same time, an asynchronous access to envbuf may occur, resulting in the return of an incorrect result. This is the problem under multithreading.

In code 12-4, the author implements the Getenv_r () function, storing the returned environment variable string through a user-supplied buffer, which makes Getenv_r a reentrant function, a thread-safe function.

function declaration of getenv (): char* getenv (const char *name);

function declaration for Getenv_r (): int getenv_r (const char *name, char *buf, int buflen);

It is safe for the user to provide a buffer every time the call is made. However, users are required to change all calls to Getenv to the Getenv_r call.

But then the author suggests that if the interface cannot be changed, thread-private data can be used. So with the second paragraph I said the source code 12-5:


#include <stdio.h>//printf #include <string.h>//strlen, strncmp, strcpy #include <limits.h>//Arg_m

AX #include <pthread.h>//support thread #include <stdlib.h>/free () extern char **environ;
pthread_key_t key;
pthread_once_t init_done = Pthread_once_init;

pthread_mutex_t Env_mutex = Pthread_mutex_initializer;

char *envbuf = NULL;

static void Thread_init (void) {pthread_key_create (&key, free);}
	char* sgetenv (const char *name) {size_t Namelen = 0;
	char *envbuf = NULL;

	int i = 0;
	Pthread_once (&init_done, thread_init);
	Pthread_mutex_lock (&env_mutex);
	Ensure Envbuf has enough memory Envbuf = (char*) pthread_getspecific (key);
		if (NULL = = envbuf) {envbuf = (char*) malloc (Arg_max);
			if (NULL = = Envbuf | | pthread_setspecific (KEY, Envbuf)!= 0) {pthread_mutex_unlock (&env_mutex);
		return NULL;
	}//Find environment Entry Namelen = strlen (name); for (i = 0; environ[i]!= NULL; ++i) {if (strncmp environ[i], name, Namelen = = 0 && ' = ' = ' = Environ[i][namelen]) {strcpy (Envbuf, &environ[i][namelen+1]);
			Pthread_mutex_unlock (&env_mutex);
		return envbuf;
	} pthread_mutex_unlock (&env_mutex);
return NULL;
	int main (int argc, char *argv[]) {printf ("Arg_max =%d\n", Arg_max);
	Char *path = sgetenv ("path");
	printf ("Path =%s\n", path);
return 0; }
(in order to separate the getenv () area of the system, I name the function sgetenv)

The role of the Pthread_once (&init_done, thread_init) function is that when multiple threads call the function at the same time, only one thread executes the thread_init () function.

The problem is that the author uses the Pthread_once (&init_done, thread_init) function to make the system create only one key for private data, that is, no matter how many threads are in the whole process, only one thread_init () is invoked. That is to call only once Pthread_key_create (), each sgeienv () function is returned to the user is that unique "private data", then call the Sgetenv () function of the n threads will not be shared through the unique private data key to access the memory. Is "private data" still a private data? The mechanism of this function is not the same as the original, thread "unsafe" getenv. is to maintain only one buffer, and eventually an asynchronous access problem will occur.


I don't think you should call the Pthread_once () function, otherwise each thread will share the same key, but if you don't call pthread_once, it's not good to call pthread_key_create every time. That means that each call to getenv () creates a thread's private data. It is also necessary to manually free the last private data to ensure that there is no memory leak problem.


In other words, the problem now is that the Pthread_once (&init_done, thread_init) function guarantees that the process only invokes the Thread_init () function once, and there is no way to make each thread call only once Thread_ Init () function.


I do not know whether the above analysis is correct, but also please understand that people can tell whether the Apue author has been wrong. The getenv () above is not thread-safe. If my idea is correct, how can you make each thread call only one thread_init () function at a time?


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.