Com: avoid intentional memory leak in epicsEnvSet

Switch default impl. to setenv/unsetenv
Switch WIN32 to use _putenv_s
On vxWorks putenv() is documented to make a copy.

log error, but never halt, if env (un)set not possible.

RTEMS <4.10 compat where unsetenv() returns void.
This commit is contained in:
Michael Davidsaver
2021-03-11 09:03:36 -08:00
parent 1bd041745b
commit 3eeebb74cd
7 changed files with 48 additions and 323 deletions

View File

@@ -1,72 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Saskatchewan
* SPDX-License-Identifier: EPICS
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* osdEnv.c */
/*
* Author: Eric Norum
* Date: May 7, 2001
*
* Routines to modify/display environment variables and EPICS parameters
*
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
/*
* Starting in Mac OS X 10.5 (Leopard) shared libraries and
* bundles don't have direct access to environ (man environ).
*/
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
#include "epicsStdio.h"
#include "envDefs.h"
#include "iocsh.h"
/*
* Set the value of an environment variable
*/
LIBCOM_API void epicsStdCall epicsEnvSet (const char *name, const char *value)
{
if (!name) return;
iocshEnvClear(name);
setenv(name, value, 1);
}
/*
* Unset an environment variable
*/
LIBCOM_API void epicsStdCall epicsEnvUnset (const char *name)
{
iocshEnvClear(name);
unsetenv(name);
}
/*
* Show the value of the specified, or all, environment variables
*/
LIBCOM_API void epicsStdCall epicsEnvShow (const char *name)
{
if (name == NULL) {
extern char **environ;
char **sp;
for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++)
printf ("%s\n", *sp);
}
else {
const char *cp = getenv (name);
if (cp == NULL)
printf ("%s is not an environment variable.\n", name);
else
printf ("%s=%s\n", name, cp);
}
}

View File

@@ -1,62 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Saskatchewan
* SPDX-License-Identifier: EPICS
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* osdEnv.c */
/*
* Author: Eric Norum
* Date: May 7, 2001
*
* Routines to modify/display environment variables and EPICS parameters
*
*/
#include <stdlib.h>
#include <stdio.h>
#include "epicsStdio.h"
#include "envDefs.h"
#include "osiUnistd.h"
#include "iocsh.h"
/*
* Set the value of an environment variable
*/
LIBCOM_API void epicsStdCall epicsEnvSet (const char *name, const char *value)
{
iocshEnvClear(name);
setenv(name, value, 1);
}
/*
* Unset an environment variable
*/
LIBCOM_API void epicsStdCall epicsEnvUnset (const char *name)
{
iocshEnvClear(name);
unsetenv(name);
}
/*
* Show the value of the specified, or all, environment variables
*/
LIBCOM_API void epicsStdCall epicsEnvShow (const char *name)
{
if (name == NULL) {
extern char **environ;
char **sp;
for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++)
printf ("%s\n", *sp);
}
else {
const char *cp = getenv (name);
if (cp == NULL)
printf ("%s is not an environment variable.\n", name);
else
printf ("%s=%s\n", name, cp);
}
}

View File

@@ -21,12 +21,19 @@
#include "epicsStdio.h"
#include "errlog.h"
#include "cantProceed.h"
#include "envDefs.h"
#include "osiUnistd.h"
#include "epicsFindSymbol.h"
#include "iocsh.h"
static
void setEnv(const char *name, const char *value)
{
errno_t err = _putenv_s(name, value);
if(err)
errlogPrintf("Can't set environment %s=\"%s\" : %d\n", name, value, (int)err);
}
/*
* Set the value of an environment variable
* Leaks memory, but the assumption is that this routine won't be
@@ -34,25 +41,8 @@
*/
LIBCOM_API void epicsStdCall epicsEnvSet (const char *name, const char *value)
{
char *cp;
iocshEnvClear(name);
cp = mallocMustSucceed (strlen (name) + strlen (value) + 2, "epicsEnvSet");
strcpy (cp, name);
strcat (cp, "=");
strcat (cp, value);
if (putenv (cp) < 0) {
errPrintf(
-1L,
__FILE__,
__LINE__,
"Failed to set environment parameter \"%s\" to \"%s\": %s\n",
name,
value,
strerror (errno));
free (cp);
}
setEnv(name, value);
}
/*
@@ -63,8 +53,7 @@ LIBCOM_API void epicsStdCall epicsEnvSet (const char *name, const char *value)
LIBCOM_API void epicsStdCall epicsEnvUnset (const char *name)
{
iocshEnvClear(name);
if (getenv(name) != NULL)
epicsEnvSet((char*)name, "");
setEnv(name, "");
}
/*

View File

@@ -20,13 +20,25 @@
#include <errno.h>
#include "epicsStdio.h"
#include "epicsVersion.h"
#include "errlog.h"
#include "cantProceed.h"
#include "envDefs.h"
#include "osiUnistd.h"
#include "epicsFindSymbol.h"
#include "iocsh.h"
#ifdef __rtems__
# include <rtems.h>
# define RTEMS_VERSION_INT VERSION_INT(__RTEMS_MAJOR__, __RTEMS_MINOR__, 0, 0)
#endif
#if defined(__RTEMS_MAJOR__) && RTEMS_VERSION_INT<VERSION_INT(4,10,0,0)
/* newlib w/ RTEMS <=4.9 returns void */
# define unSetEnv(name) ({unsetenv(name); 0;})
#else
# define unSetEnv(name) unsetenv(name)
#endif
/*
* Set the value of an environment variable
* Leaks memory, but the assumption is that this routine won't be
@@ -34,26 +46,9 @@
*/
LIBCOM_API void epicsStdCall epicsEnvSet (const char *name, const char *value)
{
char *cp;
if (!name) return;
iocshEnvClear(name);
cp = mallocMustSucceed (strlen (name) + strlen (value) + 2, "epicsEnvSet");
strcpy (cp, name);
strcat (cp, "=");
strcat (cp, value);
if (putenv (cp) < 0) {
errPrintf(
-1L,
__FILE__,
__LINE__,
"Failed to set environment parameter \"%s\" to \"%s\": %s\n",
name,
value,
strerror (errno));
free (cp);
}
if(setenv(name, value, 1))
errlogPrintf("setenv(\"%s\", \"%s\") -> %d\n", name, value, errno);
}
/*
@@ -64,8 +59,8 @@ LIBCOM_API void epicsStdCall epicsEnvSet (const char *name, const char *value)
LIBCOM_API void epicsStdCall epicsEnvUnset (const char *name)
{
iocshEnvClear(name);
if (getenv(name) != NULL)
putenv((char*)name);
if(unSetEnv(name))
errlogPrintf("unsetenv(\"%s\") -> %d\n", name, errno);
}
/*

View File

@@ -1,69 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Saskatchewan
* SPDX-License-Identifier: EPICS
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* osdEnv.c */
/*
* Author: Eric Norum
* Date: May 7, 2001
*
* Routines to modify/display environment variables and EPICS parameters
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include "epicsStdio.h"
#include <errlog.h>
#include <cantProceed.h>
#include <envDefs.h>
#include <osiUnistd.h>
#include "epicsFindSymbol.h"
#include <iocsh.h>
/*
* Set the value of an environment variable
*/
LIBCOM_API void epicsStdCall epicsEnvSet (const char *name, const char *value)
{
if (!name) return;
iocshEnvClear(name);
setenv(name, value, 1);
}
/*
* Unset an environment variable
*/
LIBCOM_API void epicsStdCall epicsEnvUnset (const char *name)
{
iocshEnvClear(name);
unsetenv(name);
}
/*
* Show the value of the specified, or all, environment variables
*/
LIBCOM_API void epicsStdCall epicsEnvShow (const char *name)
{
if (name == NULL) {
extern char **environ;
char **sp;
for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++)
printf ("%s\n", *sp);
}
else {
const char *cp = getenv (name);
if (cp == NULL)
printf ("%s is not an environment variable.\n", name);
else
printf ("%s=%s\n", name, cp);
}
}

View File

@@ -1,62 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Saskatchewan
* SPDX-License-Identifier: EPICS
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* osdEnv.c */
/*
* Author: Eric Norum
* Date: May 7, 2001
*
* Routines to modify/display environment variables and EPICS parameters
*
*/
#include <stdlib.h>
#include <stdio.h>
#include "epicsStdio.h"
#include "envDefs.h"
#include "osiUnistd.h"
#include "iocsh.h"
/*
* Set the value of an environment variable
*/
LIBCOM_API void epicsStdCall epicsEnvSet (const char *name, const char *value)
{
iocshEnvClear(name);
setenv(name, value, 1);
}
/*
* Unset an environment variable
*/
LIBCOM_API void epicsStdCall epicsEnvUnset (const char *name)
{
iocshEnvClear(name);
unsetenv(name);
}
/*
* Show the value of the specified, or all, environment variables
*/
LIBCOM_API void epicsStdCall epicsEnvShow (const char *name)
{
if (name == NULL) {
extern char **environ;
char **sp;
for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++)
printf ("%s\n", *sp);
}
else {
const char *cp = getenv (name);
if (cp == NULL)
printf ("%s is not an environment variable.\n", name);
else
printf ("%s=%s\n", name, cp);
}
}

View File

@@ -22,7 +22,6 @@
#include <ctype.h>
#include <envLib.h>
#include "cantProceed.h"
#include "epicsFindSymbol.h"
#include "epicsStdio.h"
#include "errlog.h"
@@ -35,25 +34,32 @@
*/
LIBCOM_API void epicsStdCall epicsEnvSet (const char *name, const char *value)
{
char *cp;
size_t alen = (!name || !value) ? 2u : strlen(name) + strlen(value) + 2u; /* <NAME> '=' <VALUE> '\0' */
const int onstack = alen <= 512u; /* use on-stack dynamic array for small strings */
char stackarr[ onstack ? alen : 1u]; /* gcc specific dynamic array */
char *allocd = onstack ? NULL : malloc(alen);
char *cp = onstack ? stackarr : allocd;
if (!name) {
if (!name || !value) {
printf ("Usage: epicsEnvSet \"name\", \"value\"\n");
return;
}
iocshEnvClear(name);
} else if(!cp) {
errlogPrintf("epicsEnvSet(\"%s\", \"%s\" insufficient memory\n", name, value);
cp = mallocMustSucceed (strlen (name) + strlen (value) + 2, "epicsEnvSet");
strcpy (cp, name);
strcat (cp, "=");
strcat (cp, value);
if (putenv (cp) < 0) {
errPrintf(-1L, __FILE__, __LINE__,
"Failed to set environment parameter \"%s\" to \"%s\": %s\n",
name, value, strerror (errno));
free (cp);
} else {
int err;
strcpy (cp, name);
strcat (cp, "=");
strcat (cp, value);
iocshEnvClear(name);
if((err=putenv(cp)) < 0)
errlogPrintf("epicsEnvSet(\"%s\", \"%s\" -> %d\n", name, value, err);
}
/* from at least vxWorks 5.5 putenv() is making a copy, so we can free */
free (allocd);
}
/*