[lttng-dev] [PATCH lttng-tools] Replace deprecated readdir_r() with readdir()

Jérémie Galarneau jeremie.galarneau at efficios.com
Tue Jun 5 20:21:44 EDT 2018


Merged in master, thanks!

Jérémie

On Tue, Jun 05, 2018 at 12:11:20PM -0400, Michael Jeanson wrote:
> readdir_r() has been deprecated since glibc 2.24 [1].
> 
> We used readdir_r() in load_session_from_path() to be thread-safe
> since this function is part of liblttng-ust-ctl. However, according
> to readdir()'s man page, it's thread-safe as long as the directory
> stream it operates on is not shared across threads :
> 
>   In the current POSIX.1 specification (POSIX.1-2008), readdir(3) is
>   not required to be thread-safe. However, in modern
>   implementations (including the glibc implementation), concurrent
>   calls to readdir(3) that specify different directory streams are
>   thread-safe. Therefore, the use of readdir_r() is generally
>   unnecessary in multithreaded programs. In cases where multiple
>   threads must read from the same directory stream, using readdir(3)
>   with external synchronization is still preferable to the use of
>   readdir_r(), for the reasons given in the points above.
> 
> In our use-case where we open the directory stream in the same function,
> we know it won't be shared across threads and thus it's safe to use
> readdir(). Here is the relevevant bit from the POSIX.1 [2] spec :
> 
>   The returned pointer, and pointers within the structure, might be
>   invalidated or the structure or the storage areas might be overwritten
>   by a subsequent call to readdir() on the same directory stream. They shall
>   not be affected by a call to readdir() on a different directory stream.
> 
>  [1] https://sourceware.org/bugzilla/show_bug.cgi?id=19056
>  [2] http://pubs.opengroup.org/onlinepubs/9699919799/functions/readdir.html
> 
> Signed-off-by: Michael Jeanson <mjeanson at efficios.com>
> ---
>  src/common/config/session-config.c | 54 ++++++++++++++----------------
>  1 file changed, 26 insertions(+), 28 deletions(-)
> 
> diff --git a/src/common/config/session-config.c b/src/common/config/session-config.c
> index 624064a1..56db1195 100644
> --- a/src/common/config/session-config.c
> +++ b/src/common/config/session-config.c
> @@ -2953,23 +2953,6 @@ end:
>  	return ret;
>  }
>  
> -/* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
> -static
> -struct dirent *alloc_dirent(const char *path)
> -{
> -	size_t len;
> -	long name_max;
> -	struct dirent *entry;
> -
> -	name_max = pathconf(path, _PC_NAME_MAX);
> -	if (name_max == -1) {
> -		name_max = PATH_MAX;
> -	}
> -	len = offsetof(struct dirent, d_name) + name_max + 1;
> -	entry = zmalloc(len);
> -	return entry;
> -}
> -
>  static
>  int load_session_from_path(const char *path, const char *session_name,
>  	struct session_config_validation_ctx *validation_ctx, int overwrite,
> @@ -3006,7 +2989,6 @@ int load_session_from_path(const char *path, const char *session_name,
>  		}
>  	}
>  	if (directory) {
> -		struct dirent *entry;
>  		struct dirent *result;
>  		size_t file_path_root_len;
>  
> @@ -3017,16 +2999,9 @@ int load_session_from_path(const char *path, const char *session_name,
>  			goto end;
>  		}
>  
> -		entry = alloc_dirent(path);
> -		if (!entry) {
> -			ret = -LTTNG_ERR_NOMEM;
> -			goto end;
> -		}
> -
>  	        ret = lttng_dynamic_buffer_append(&file_path, path, path_len);
>  		if (ret) {
>  			ret = -LTTNG_ERR_NOMEM;
> -			free(entry);
>  			goto end;
>  		}
>  
> @@ -3040,8 +3015,32 @@ int load_session_from_path(const char *path, const char *session_name,
>  		file_path_root_len = file_path.size;
>  
>  		/* Search for *.lttng files */
> -		while (!readdir_r(directory, entry, &result) && result) {
> -			size_t file_name_len = strlen(result->d_name);
> +		for (;;) {
> +			size_t file_name_len;
> +
> +			/*
> +			 * When the end of the directory stream is reached, NULL is
> +			 * returned and errno is kept unchanged. When an error occurs,
> +			 * NULL is returned and errno is set accordingly. To
> +			 * distinguish between the two, set errno to zero before
> +			 * calling readdir().
> +			 *
> +			 * On success, readdir() returns a pointer to a dirent
> +			 * structure. (This structure may be statically allocated, do
> +			 * not attempt to free(3) it.)
> +			 */
> +			errno = 0;
> +			result = readdir(directory);
> +
> +			/* Reached end of dir stream or error out */
> +			if (!result) {
> +				if (errno) {
> +					PERROR("readdir");
> +				}
> +				break;
> +			}
> +
> +			file_name_len = strlen(result->d_name);
>  
>  			if (file_name_len <=
>  				sizeof(DEFAULT_SESSION_CONFIG_FILE_EXTENSION)) {
> @@ -3089,7 +3088,6 @@ int load_session_from_path(const char *path, const char *session_name,
>  			}
>  		}
>  
> -		free(entry);
>  	} else {
>  		ret = load_session_from_file(path, session_name,
>  			validation_ctx, overwrite, overrides);
> -- 
> 2.17.0
> 


More information about the lttng-dev mailing list