zephyr/lib/posix/options/env.c
Alberto Escolar Piedras 7c8d538982 posix: env: Fix 2 build warnings
Fix 2 build warnings in posix/options/env:
The maximum length given to strncpy() matches the input
string length, which makes the call equivalent to strcpy().
As the destination buffer size has been ensured sufficient
(in the first case by chechking just before,
in the second case by allocating it big enough),
let's just use strcpy() instead.

lib/posix/options/env.c: In function 'getenv_r':
lib/posix/options/env.c:109:17: error: 'strncpy' specified bound
depends on the length of the source argument
[-Werror=stringop-truncation]
  109 |                 strncpy(buf, val, vsize);
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~
lib/posix/options/env.c:104:25: note: length computed here
  104 |                 vsize = strlen(val) + 1;
      |                         ^~~~~~~~~~~
lib/posix/options/env.c: In function 'setenv':
lib/posix/options/env.c:191:17: error: 'strncpy' output truncated
before terminating nul copying as many bytes from a string as its
length [-Werror=stringop-truncation]
  191 |                 strncpy(environ[ret], name, nsize);
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lib/posix/options/env.c:128:51: note: length computed here
  128 |         const size_t nsize = (name == NULL) ? 0 : strlen(name);
      |                                                   ^~~~~~~~~~~~

Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
2024-05-14 13:25:33 +02:00

267 lines
5.1 KiB
C

/*
* Copyright (c) 2023, Meta
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zephyr/logging/log.h>
#include <zephyr/spinlock.h>
#define TRACK_ALLOC (IS_ENABLED(CONFIG_POSIX_ENV_LOG_LEVEL_DBG) || IS_ENABLED(CONFIG_ZTEST))
LOG_MODULE_REGISTER(posix_env, CONFIG_POSIX_ENV_LOG_LEVEL);
static struct k_spinlock environ_lock;
static size_t allocated;
char **environ;
#ifdef CONFIG_ZTEST
size_t posix_env_get_allocated_space(void)
{
return allocated;
}
#endif
static size_t environ_size(void)
{
size_t ret;
if (environ == NULL) {
return 0;
}
for (ret = 0; environ[ret] != NULL; ++ret) {
}
return ret;
}
static int findenv(const char *name, size_t namelen)
{
const char *env;
if (name == NULL || namelen == 0 || strchr(name, '=') != NULL) {
/* Note: '=' is not a valid name character */
return -EINVAL;
}
if (environ == NULL) {
return -ENOENT;
}
for (char **envp = &environ[0]; *envp != NULL; ++envp) {
env = *envp;
if (strncmp(env, name, namelen) == 0 && env[namelen] == '=') {
return envp - environ;
}
}
return -ENOENT;
}
char *getenv(const char *name)
{
int ret;
size_t nsize;
char *val = NULL;
nsize = (name == NULL) ? 0 : strlen(name);
K_SPINLOCK(&environ_lock)
{
ret = findenv(name, nsize);
if (ret < 0) {
K_SPINLOCK_BREAK;
}
val = environ[ret] + nsize + 1;
}
return val;
}
int getenv_r(const char *name, char *buf, size_t len)
{
int ret = 0;
size_t vsize;
size_t nsize;
char *val = NULL;
nsize = (name == NULL) ? 0 : strlen(name);
K_SPINLOCK(&environ_lock)
{
ret = findenv(name, nsize);
if (ret < 0) {
LOG_DBG("No entry for name '%s'", name);
K_SPINLOCK_BREAK;
}
val = environ[ret] + nsize + 1;
vsize = strlen(val) + 1;
if (vsize > len) {
ret = -ERANGE;
K_SPINLOCK_BREAK;
}
strcpy(buf, val);
LOG_DBG("Found entry %s", environ[ret]);
}
if (ret < 0) {
errno = -ret;
ret = -1;
}
return ret;
}
int setenv(const char *name, const char *val, int overwrite)
{
int ret = 0;
char *env;
char **envp;
size_t esize;
const size_t vsize = (val == NULL) ? 0 : strlen(val);
const size_t nsize = (name == NULL) ? 0 : strlen(name);
/* total size of name + '=' + val + '\0' */
const size_t tsize = nsize + 1 /* '=' */ + vsize + 1 /* '\0' */;
if (name == NULL || val == NULL) {
LOG_DBG("Invalid name '%s' or value '%s'", name, val);
errno = EINVAL;
return -1;
}
K_SPINLOCK(&environ_lock)
{
ret = findenv(name, nsize);
if (ret == -EINVAL) {
LOG_DBG("Invalid name '%s'", name);
K_SPINLOCK_BREAK;
}
if (ret >= 0) {
/* name was found in environ */
esize = strlen(environ[ret]) + 1;
if (overwrite == 0) {
LOG_DBG("Found entry %s", environ[ret]);
ret = 0;
K_SPINLOCK_BREAK;
}
} else {
/* name was not found in environ -> add new entry */
esize = environ_size();
envp = realloc(environ, sizeof(char **) *
(esize + 1 /* new entry */ + 1 /* NULL */));
if (envp == NULL) {
ret = -ENOMEM;
K_SPINLOCK_BREAK;
}
if (TRACK_ALLOC) {
allocated += sizeof(char **) * (esize + 2);
LOG_DBG("realloc %zu bytes (allocated: %zu)",
sizeof(char **) * (esize + 2), allocated);
}
environ = envp;
ret = esize;
environ[ret] = NULL;
environ[ret + 1] = NULL;
esize = 0;
}
if (esize < tsize) {
/* need to malloc or realloc space for new environ entry */
env = realloc(environ[ret], tsize);
if (env == NULL) {
ret = -ENOMEM;
K_SPINLOCK_BREAK;
}
if (TRACK_ALLOC) {
allocated += tsize - esize;
LOG_DBG("realloc %zu bytes (allocated: %zu)", tsize - esize,
allocated);
}
environ[ret] = env;
}
strcpy(environ[ret], name);
environ[ret][nsize] = '=';
strncpy(environ[ret] + nsize + 1, val, vsize + 1);
LOG_DBG("Added entry %s", environ[ret]);
ret = 0;
}
if (ret < 0) {
errno = -ret;
ret = -1;
}
return ret;
}
int unsetenv(const char *name)
{
int ret = 0;
char **envp;
size_t esize;
size_t nsize;
nsize = (name == NULL) ? 0 : strlen(name);
K_SPINLOCK(&environ_lock)
{
ret = findenv(name, nsize);
if (ret < 0) {
ret = (ret == -EINVAL) ? -EINVAL : 0;
K_SPINLOCK_BREAK;
}
esize = environ_size();
if (TRACK_ALLOC) {
allocated -= strlen(environ[ret]) + 1;
LOG_DBG("free %zu bytes (allocated: %zu)", strlen(environ[ret]) + 1,
allocated);
}
free(environ[ret]);
/* shuffle remaining environment variable pointers forward */
for (; ret < esize; ++ret) {
environ[ret] = environ[ret + 1];
}
/* environ must be terminated with a NULL pointer */
environ[ret] = NULL;
/* reduce environ size and update allocation */
--esize;
if (esize == 0) {
free(environ);
environ = NULL;
} else {
envp = realloc(environ, (esize + 1 /* NULL */) * sizeof(char **));
if (envp != NULL) {
environ = envp;
}
}
__ASSERT_NO_MSG((esize >= 1 && environ != NULL) || environ == NULL);
if (TRACK_ALLOC) {
/* recycle nsize here */
nsize = ((esize == 0) ? 2 : 1) * sizeof(char **);
allocated -= nsize;
LOG_DBG("free %zu bytes (allocated: %zu)", nsize, allocated);
}
ret = 0;
}
if (ret < 0) {
errno = -ret;
ret = -1;
}
return ret;
}