diff mbox series

[v2,1/7] eal: add wrappers for POSIX string functions

Message ID 20210221012831.14643-2-dmitry.kozliuk@gmail.com (mailing list archive)
State Superseded, archived
Delegated to: Thomas Monjalon
Headers show
Series eal/windows: do not expose POSIX symbols | expand

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Dmitry Kozlyuk Feb. 21, 2021, 1:28 a.m. UTC
POSIX strncasecmp(), strdup(), and strtok_r() have different names
on Windows, respectively, strnicmp(), _strdup(), and strtok_s().

Add wrappers as inline functions, because they're used from librte_kvargs,
and thus cannot be in librte_eal; besides, implementation is trivial.

Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
---
 lib/librte_eal/common/eal_common_dev.c        |  6 +--
 lib/librte_eal/common/eal_common_devargs.c    |  7 ++--
 lib/librte_eal/common/eal_common_log.c        |  5 ++-
 lib/librte_eal/common/eal_common_options.c    | 12 +++---
 lib/librte_eal/common/eal_common_trace_ctf.c  |  2 +-
 .../common/eal_common_trace_utils.c           |  2 +-
 lib/librte_eal/include/rte_string_fns.h       | 42 +++++++++++++++++++
 7 files changed, 60 insertions(+), 16 deletions(-)

Comments

Bruce Richardson Feb. 22, 2021, 11:47 a.m. UTC | #1
On Sun, Feb 21, 2021 at 04:28:25AM +0300, Dmitry Kozlyuk wrote:
> POSIX strncasecmp(), strdup(), and strtok_r() have different names
> on Windows, respectively, strnicmp(), _strdup(), and strtok_s().
> 
> Add wrappers as inline functions, because they're used from librte_kvargs,
> and thus cannot be in librte_eal; besides, implementation is trivial.
> 
> Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
> ---
>  lib/librte_eal/common/eal_common_dev.c        |  6 +--
>  lib/librte_eal/common/eal_common_devargs.c    |  7 ++--
>  lib/librte_eal/common/eal_common_log.c        |  5 ++-
>  lib/librte_eal/common/eal_common_options.c    | 12 +++---
>  lib/librte_eal/common/eal_common_trace_ctf.c  |  2 +-
>  .../common/eal_common_trace_utils.c           |  2 +-
>  lib/librte_eal/include/rte_string_fns.h       | 42 +++++++++++++++++++
>  7 files changed, 60 insertions(+), 16 deletions(-)
> 
Rather than defining "rte_" versions of these functions, is it possible
just to provide the unprefixed definitions of them for internal use?
While this probably won't work for any functions used in public headers,
for any functions only used in C files, we can use meson to detect the
presence of the standard function and set a macro flag for the compatiblity
version if not present. This is something we already support for the
strlcpy/strlcat functions from libbsd, and it basically allows the
well-known (and loved?) functions to be used directly, and saves DPDK
developers having to worry about what "standard" functions can be used
directly, and which can't.

/Bruce
Nick Connolly Feb. 22, 2021, 12:48 p.m. UTC | #2
> Rather than defining "rte_" versions of these functions, is it possible
> just to provide the unprefixed definitions of them for internal use?
> While this probably won't work for any functions used in public headers,
> for any functions only used in C files, we can use meson to detect the
> presence of the standard function and set a macro flag for the compatiblity
> version if not present. This is something we already support for the
> strlcpy/strlcat functions from libbsd, and it basically allows the
> well-known (and loved?) functions to be used directly, and saves DPDK
> developers having to worry about what "standard" functions can be used
> directly, and which can't.

Hi Bruce,

You're asking a really good question here that highlights a fundamental 
issue:
Does the DPDK code base have an implied POSIX dependency, or should it only
depend upon the standard C library and 'rte_ ' functions.  This hasn't 
been an
issue before, but Windows isn't 'POSIX' based.

Using "well-known" names for missing functions is ok where the definitions
are in private header files, but if the headers are public, or the 
implementation
is better done in a C file, then there can be a clash with the 
application which
is likely dealing with the same issues.

There seem to be two viable approaches to handling this:

 1. Expect the platform to provide POSIX semantic (through an external
    library
    such as Cygwin). That way it becomes "an 'external' problem" and the
    DPDK
    can use the "well-known" names and expected behaviour.

 2. Provide the missing functionality, but wrap it in 'internal' header
    files
    and 'rte_' versions to avoid link errors. This is the approach that
    Dmitry has
    taken based on the guidance we've received.

For background, the approach I've taken with adding Windows support to SPDK
is to create an 'external' library (https://wpdk.github.io) with header 
files that
provide the missing POSIX functionality and functions with a prefix to 
avoid link
errors. As a result, the whole of SPDK can now build and run unchanged.

Regards,
Nick
Bruce Richardson Feb. 22, 2021, 2:26 p.m. UTC | #3
On Mon, Feb 22, 2021 at 12:48:39PM +0000, Nick Connolly wrote:
> Rather than defining "rte_" versions of these functions, is it possible
> just to provide the unprefixed definitions of them for internal use?
> While this probably won't work for any functions used in public headers,
> for any functions only used in C files, we can use meson to detect the
> presence of the standard function and set a macro flag for the compatiblity
> version if not present. This is something we already support for the
> strlcpy/strlcat functions from libbsd, and it basically allows the
> well-known (and loved?) functions to be used directly, and saves DPDK
> developers having to worry about what "standard" functions can be used
> directly, and which can't.
> 
>    Hi Bruce,
>    You're asking a really good question here that highlights a fundamental
>    issue:
>    Does the DPDK code base have an implied POSIX dependency, or should it
>    only
>    depend upon the standard C library and 'rte_ ' functions.  This hasn't
>    been an
>    issue before, but Windows isn't 'POSIX' based.
>    Using "well-known" names for missing functions is ok where the
>    definitions
>    are in private header files, but if the headers are public, or the
>    implementation
>    is better done in a C file, then there can be a clash with the
>    application which
>    is likely dealing with the same issues.
>    There seem to be two viable approaches to handling this:
>     1. Expect the platform to provide POSIX semantic (through an external
>        library
>        such as Cygwin). That way it becomes "an 'external' problem" and
>        the DPDK
>        can use the "well-known" names and expected behaviour.
>     2. Provide the missing functionality, but wrap it in 'internal' header
>        files
>        and 'rte_' versions to avoid link errors. This is the approach that
>        Dmitry has
>        taken based on the guidance we've received.
> 
>    For background, the approach I've taken with adding Windows support to
>    SPDK
>    is to create an 'external' library ([1]https://wpdk.github.io) with
>    header files that
>    provide the missing POSIX functionality and functions with a prefix to
>    avoid link
>    errors. As a result, the whole of SPDK can now build and run unchanged.
>    Regards,
>    Nick
> 

Whatever about the specific implementation, I'd very much like to get to
the point where we don't have to do search-replace for a bunch of functions
like this, not to mention that we'd need to have checkpatch rules in place
to ensure that further instances are not re-introduced.
As you say, though, the main issue will be whether we have instances in
public header files or not. I would hope that no static inline functions in
DPDK use any of the functions in question, but I'm not sure. Perhaps if
there are instances in public headers those could be reworked to not use
the problematic functions.

For any functions, such as strdup, which are not in a public header I would
suggest the following as a possible start point, based off what was done
for strlcpy.

* In DPDK (probably EAL), define an rte_strdup function for use as a
  fallback.
* Inside the meson build scripts, use "cc.has_function()" to check if the
  regular strdup function is available. If not, then add "-DRTE_NO_STRDUP"
  to the c_args for DPDK building
* Inside our DPDK header (rte_string_fns.h in the strdup case), we can add
  a conditional define such as:
   #ifdef RTE_NO_STRDUP
   #define strdup(s) rte_strdup(s)
   #endif

Thoughts on this?
/Bruce
Tyler Retzlaff Feb. 22, 2021, 6:07 p.m. UTC | #4
On Mon, Feb 22, 2021 at 12:48:39PM +0000, Nick Connolly wrote:
> 
> There seem to be two viable approaches to handling this:
> 
> 1. Expect the platform to provide POSIX semantic (through an external
>    library
>    such as Cygwin). That way it becomes "an 'external' problem" and the
>    DPDK
>    can use the "well-known" names and expected behaviour.

I'd prefer not to see this be a requirement of the platform. There have
been multiple attempts over the years to provide a POSIX surfaces
on Windows which arguably haven't been that successful.

It would be helpful if DPDK dependence on POSIX APIs were limited to
be only as necessary to improve portability to non-POSIX platforms.

Ty
Nick Connolly Feb. 22, 2021, 6:21 p.m. UTC | #5
> For any functions, such as strdup, which are not in a public header I would
> suggest the following as a possible start point, based off what was done
> for strlcpy.
>
> * In DPDK (probably EAL), define an rte_strdup function for use as a
>    fallback.
> * Inside the meson build scripts, use "cc.has_function()" to check if the
>    regular strdup function is available. If not, then add "-DRTE_NO_STRDUP"
>    to the c_args for DPDK building
> * Inside our DPDK header (rte_string_fns.h in the strdup case), we can add
>    a conditional define such as:
>     #ifdef RTE_NO_STRDUP
>     #define strdup(s) rte_strdup(s)
>     #endif
>
> Thoughts on this?
Looks like an elegant approach to me.
Nick
Nick Connolly Feb. 22, 2021, 6:36 p.m. UTC | #6
>> There seem to be two viable approaches to handling this:
>>
>> 1. Expect the platform to provide POSIX semantic (through an external
>>     ...
> I'd prefer not to see this be a requirement of the platform. There have
> been multiple attempts over the years to provide a POSIX surfaces
> on Windows which arguably haven't been that successful.
+1
'viable' was the wrong word - I can't see a general-purpose POSIX 
surface giving a good outcome.

> It would be helpful if DPDK dependence on POSIX APIs were limited to
> be only as necessary to improve portability to non-POSIX platforms.
Dmitry Kozlyuk Feb. 22, 2021, 10:57 p.m. UTC | #7
2021-02-22 14:26, Bruce Richardson:
> As you say, though, the main issue will be whether we have instances in
> public header files or not. I would hope that no static inline functions in
> DPDK use any of the functions in question, but I'm not sure. Perhaps if
> there are instances in public headers those could be reworked to not use
> the problematic functions.

No instances of strdup(), strncasecmp(), or strtok_r() in any DPDK headers.

> For any functions, such as strdup, which are not in a public header I would
> suggest the following as a possible start point, based off what was done
> for strlcpy.
> 
> * In DPDK (probably EAL), define an rte_strdup function for use as a
>   fallback.
> * Inside the meson build scripts, use "cc.has_function()" to check if the
>   regular strdup function is available. If not, then add "-DRTE_NO_STRDUP"
>   to the c_args for DPDK building
> * Inside our DPDK header (rte_string_fns.h in the strdup case), we can add
>   a conditional define such as:
>    #ifdef RTE_NO_STRDUP
>    #define strdup(s) rte_strdup(s)
>    #endif
> 
> Thoughts on this?

Looks good to me, I can rework the patchset like so.

Policy considerations:
1. The approach only applies to platform-agnostic functions, like str*().
   Functions like sleep() still belong to librte_eal.
2. Deprecated functions, like index(3p), should be replaced
   with alternatives suggested by the standard.
3. If a standard C11 alternative is available, it should be used.
   This mostly applies to types, like u_int32 -> uint32_t
   (it's even in DPDK coding style already, isn't it?).

A nit: RTE_NO_XXX -> RTE_HAS_XXX (for consistency with existing macros)?
Bruce Richardson Feb. 23, 2021, 9:45 a.m. UTC | #8
On Tue, Feb 23, 2021 at 01:57:50AM +0300, Dmitry Kozlyuk wrote:
> 2021-02-22 14:26, Bruce Richardson:
> > As you say, though, the main issue will be whether we have instances in
> > public header files or not. I would hope that no static inline functions in
> > DPDK use any of the functions in question, but I'm not sure. Perhaps if
> > there are instances in public headers those could be reworked to not use
> > the problematic functions.
> 
> No instances of strdup(), strncasecmp(), or strtok_r() in any DPDK headers.
> 
> > For any functions, such as strdup, which are not in a public header I would
> > suggest the following as a possible start point, based off what was done
> > for strlcpy.
> > 
> > * In DPDK (probably EAL), define an rte_strdup function for use as a
> >   fallback.
> > * Inside the meson build scripts, use "cc.has_function()" to check if the
> >   regular strdup function is available. If not, then add "-DRTE_NO_STRDUP"
> >   to the c_args for DPDK building
> > * Inside our DPDK header (rte_string_fns.h in the strdup case), we can add
> >   a conditional define such as:
> >    #ifdef RTE_NO_STRDUP
> >    #define strdup(s) rte_strdup(s)
> >    #endif
> > 
> > Thoughts on this?
> 
> Looks good to me, I can rework the patchset like so.
> 
> Policy considerations:
> 1. The approach only applies to platform-agnostic functions, like str*().
>    Functions like sleep() still belong to librte_eal.
> 2. Deprecated functions, like index(3p), should be replaced
>    with alternatives suggested by the standard.
> 3. If a standard C11 alternative is available, it should be used.
>    This mostly applies to types, like u_int32 -> uint32_t
>    (it's even in DPDK coding style already, isn't it?).
> 
> A nit: RTE_NO_XXX -> RTE_HAS_XXX (for consistency with existing macros)?

Sure, thanks.
Dmitry Kozlyuk Feb. 27, 2021, 8:23 p.m. UTC | #9
2021-02-23 09:45, Bruce Richardson:
> On Tue, Feb 23, 2021 at 01:57:50AM +0300, Dmitry Kozlyuk wrote:
> > 2021-02-22 14:26, Bruce Richardson:  
> > > As you say, though, the main issue will be whether we have instances in
> > > public header files or not. I would hope that no static inline functions in
> > > DPDK use any of the functions in question, but I'm not sure. Perhaps if
> > > there are instances in public headers those could be reworked to not use
> > > the problematic functions.  
> > 
> > No instances of strdup(), strncasecmp(), or strtok_r() in any DPDK headers.
> >   
> > > For any functions, such as strdup, which are not in a public header I would
> > > suggest the following as a possible start point, based off what was done
> > > for strlcpy.
> > > 
> > > * In DPDK (probably EAL), define an rte_strdup function for use as a
> > >   fallback.
> > > * Inside the meson build scripts, use "cc.has_function()" to check if the
> > >   regular strdup function is available. If not, then add "-DRTE_NO_STRDUP"
> > >   to the c_args for DPDK building
> > > * Inside our DPDK header (rte_string_fns.h in the strdup case), we can add
> > >   a conditional define such as:
> > >    #ifdef RTE_NO_STRDUP
> > >    #define strdup(s) rte_strdup(s)
> > >    #endif
> > > 
> > > Thoughts on this?  
> > 
> > Looks good to me, I can rework the patchset like so.
> > 
> > Policy considerations:
> > 1. The approach only applies to platform-agnostic functions, like str*().
> >    Functions like sleep() still belong to librte_eal.
> > 2. Deprecated functions, like index(3p), should be replaced
> >    with alternatives suggested by the standard.
> > 3. If a standard C11 alternative is available, it should be used.
> >    This mostly applies to types, like u_int32 -> uint32_t
> >    (it's even in DPDK coding style already, isn't it?).
> > 
> > A nit: RTE_NO_XXX -> RTE_HAS_XXX (for consistency with existing macros)?  
> 
> Sure, thanks.

There's a meson issue with `cc.has_function()`:
https://github.com/mesonbuild/meson/issues/5628

What if we just define RTE_INTERNAL for librte_eal/windows/include/rte_os.h
(and other public headers if need be) to distinguish the case when it's used
from within DPDK?
Nick Connolly March 1, 2021, 9:31 p.m. UTC | #10
> There's a meson issue with `cc.has_function()`:
> https://github.com/mesonbuild/meson/issues/5628
>
> What if we just define RTE_INTERNAL for librte_eal/windows/include/rte_os.h
> (and other public headers if need be) to distinguish the case when it's used
> from within DPDK?
It's a pragmatic solution to the problem, but sadly it's not quite as 
clean as letting the build system determine if each 'wrapper' is needed. 
DPDK supports a variety of platforms and toolsets and my experience with 
SPDK suggests that we'll end up with compiler specific ifdef's. It's all 
protected by RTE_INTERNAL so it's not really a problem, but I wonder if 
it makes it easier for someone to accidentally introduce definitions 
outside of the #ifdef RTE_INTERNAL?

How about a new header rte_os_internal.h that contains the 'wrappers'? 
It gets included from rte_os.h only if RTE_INTERNAL is set and doesn't 
get installed so can't impact the user environment. I'm not sure I like 
it, but I guess we could do the same thing for every header that needs 
wrappers. I'm really 'thinking aloud' here and I'm not convinced it's 
the best route forward, so feel free to ignore. What I'm searching for 
is a way of wrapping that's clean and has a reasonably low risk of 
future human error.

Regards,
Nick
Dmitry Kozlyuk March 2, 2021, 12:22 a.m. UTC | #11
2021-03-01 21:31, Nick Connolly:
> > There's a meson issue with `cc.has_function()`:
> > https://github.com/mesonbuild/meson/issues/5628
> >
> > What if we just define RTE_INTERNAL for librte_eal/windows/include/rte_os.h
> > (and other public headers if need be) to distinguish the case when it's used
> > from within DPDK?  
> It's a pragmatic solution to the problem, but sadly it's not quite as 
> clean as letting the build system determine if each 'wrapper' is needed. 
> DPDK supports a variety of platforms and toolsets and my experience with 
> SPDK suggests that we'll end up with compiler specific ifdef's.

I'd argue they are inevitable. Consider POSIX close(): if it's missing, what
would be a correct fallback? It depends on the execution environment (OS).
String function fallbacks, of course, are easily implemented from scratch.

> It's all 
> protected by RTE_INTERNAL so it's not really a problem, but I wonder if 
> it makes it easier for someone to accidentally introduce definitions 
> outside of the #ifdef RTE_INTERNAL?

Public functions without rte_ prefix shall not be introduced at all.

Remember the issue this patchset targets: export of POSIX symbols from EAL.
They are already defined in a way DPDK consumes successfully. RTE_INTERNAL
is a straightforward way to ensure symbols affect to other consumers.
(I'm talking about macros; asprintf should be moved inside EAL in any case.)
Nick Connolly March 2, 2021, 11:27 a.m. UTC | #12
>
>> DPDK supports a variety of platforms and toolsets and my experience with
>> SPDK suggests that we'll end up with compiler specific ifdef's.
> I'd argue they are inevitable. Consider POSIX close(): if it's missing, what
> would be a correct fallback? It depends on the execution environment (OS).
> String function fallbacks, of course, are easily implemented from scratch.
Agreed.

>> Public functions without rte_ prefix shall not be introduced at all.
Agreed. Perhaps as a separate patch we should consider validation rules 
to enforce the requirements.

Regards,
Nick
Thomas Monjalon March 16, 2021, 9:51 a.m. UTC | #13
27/02/2021 21:23, Dmitry Kozlyuk:
> 2021-02-23 09:45, Bruce Richardson:
> > On Tue, Feb 23, 2021 at 01:57:50AM +0300, Dmitry Kozlyuk wrote:
> > > 2021-02-22 14:26, Bruce Richardson:  
> > > > As you say, though, the main issue will be whether we have instances in
> > > > public header files or not. I would hope that no static inline functions in
> > > > DPDK use any of the functions in question, but I'm not sure. Perhaps if
> > > > there are instances in public headers those could be reworked to not use
> > > > the problematic functions.  
> > > 
> > > No instances of strdup(), strncasecmp(), or strtok_r() in any DPDK headers.
> > >   
> > > > For any functions, such as strdup, which are not in a public header I would
> > > > suggest the following as a possible start point, based off what was done
> > > > for strlcpy.
> > > > 
> > > > * In DPDK (probably EAL), define an rte_strdup function for use as a
> > > >   fallback.
> > > > * Inside the meson build scripts, use "cc.has_function()" to check if the
> > > >   regular strdup function is available. If not, then add "-DRTE_NO_STRDUP"
> > > >   to the c_args for DPDK building
> > > > * Inside our DPDK header (rte_string_fns.h in the strdup case), we can add
> > > >   a conditional define such as:
> > > >    #ifdef RTE_NO_STRDUP
> > > >    #define strdup(s) rte_strdup(s)
> > > >    #endif
> > > > 
> > > > Thoughts on this?  
> > > 
> > > Looks good to me, I can rework the patchset like so.
> > > 
> > > Policy considerations:
> > > 1. The approach only applies to platform-agnostic functions, like str*().
> > >    Functions like sleep() still belong to librte_eal.
> > > 2. Deprecated functions, like index(3p), should be replaced
> > >    with alternatives suggested by the standard.
> > > 3. If a standard C11 alternative is available, it should be used.
> > >    This mostly applies to types, like u_int32 -> uint32_t
> > >    (it's even in DPDK coding style already, isn't it?).
> > > 
> > > A nit: RTE_NO_XXX -> RTE_HAS_XXX (for consistency with existing macros)?  
> > 
> > Sure, thanks.
> 
> There's a meson issue with `cc.has_function()`:
> https://github.com/mesonbuild/meson/issues/5628

The meson issue can be fixed or workarounded probably.
Is it the reason for the RTE_INTERNAL proposal below?

> What if we just define RTE_INTERNAL for librte_eal/windows/include/rte_os.h
> (and other public headers if need be) to distinguish the case when it's used
> from within DPDK?

I'm not sure to follow the need for RTE_INTERNAL.

In general, 3 guidelines:
	- avoid inline functions in public headers
	- mark exported internal functions with __rte_internal and in version.map
	- export internal functions in a separate file
diff mbox series

Patch

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 8a3bd3100..0a15fdcf7 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -462,7 +462,7 @@  rte_dev_event_callback_register(const char *device_name,
 			if (!device_name) {
 				event_cb->dev_name = NULL;
 			} else {
-				event_cb->dev_name = strdup(device_name);
+				event_cb->dev_name = rte_strdup(device_name);
 				if (event_cb->dev_name == NULL) {
 					ret = -ENOMEM;
 					goto error;
@@ -630,10 +630,10 @@  dev_str_sane_copy(const char *str)
 
 	end = strcspn(str, ",/");
 	if (str[end] == ',') {
-		copy = strdup(&str[end + 1]);
+		copy = rte_strdup(&str[end + 1]);
 	} else {
 		/* '/' or '\0' */
-		copy = strdup("");
+		copy = rte_strdup("");
 	}
 	if (copy == NULL) {
 		rte_errno = ENOMEM;
diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index fcf3d9a3c..14e082a27 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -18,6 +18,7 @@ 
 #include <rte_errno.h>
 #include <rte_kvargs.h>
 #include <rte_log.h>
+#include <rte_string_fns.h>
 #include <rte_tailq.h>
 #include "eal_private.h"
 
@@ -75,7 +76,7 @@  rte_devargs_layers_parse(struct rte_devargs *devargs,
 	 * anything and keep referring only to it.
 	 */
 	if (devargs->data != devstr) {
-		devargs->data = strdup(devstr);
+		devargs->data = rte_strdup(devstr);
 		if (devargs->data == NULL) {
 			RTE_LOG(ERR, EAL, "OOM\n");
 			ret = -ENOMEM;
@@ -219,9 +220,9 @@  rte_devargs_parse(struct rte_devargs *da, const char *dev)
 	da->bus = bus;
 	/* Parse eventual device arguments */
 	if (devname[i] == ',')
-		da->args = strdup(&devname[i + 1]);
+		da->args = rte_strdup(&devname[i + 1]);
 	else
-		da->args = strdup("");
+		da->args = rte_strdup("");
 	if (da->args == NULL) {
 		RTE_LOG(ERR, EAL, "not enough memory to parse arguments\n");
 		return -ENOMEM;
diff --git a/lib/librte_eal/common/eal_common_log.c b/lib/librte_eal/common/eal_common_log.c
index c5554badb..557a8243f 100644
--- a/lib/librte_eal/common/eal_common_log.c
+++ b/lib/librte_eal/common/eal_common_log.c
@@ -14,6 +14,7 @@ 
 #include <rte_eal.h>
 #include <rte_log.h>
 #include <rte_per_lcore.h>
+#include <rte_string_fns.h>
 
 #include "eal_private.h"
 
@@ -194,7 +195,7 @@  static int rte_log_save_level(int priority,
 		if (regcomp(&opt_ll->re_match, regex, 0) != 0)
 			goto fail;
 	} else if (pattern) {
-		opt_ll->pattern = strdup(pattern);
+		opt_ll->pattern = rte_strdup(pattern);
 		if (opt_ll->pattern == NULL)
 			goto fail;
 	} else
@@ -270,7 +271,7 @@  rte_log_lookup(const char *name)
 static int
 __rte_log_register(const char *name, int id)
 {
-	char *dup_name = strdup(name);
+	char *dup_name = rte_strdup(name);
 
 	if (dup_name == NULL)
 		return -ENOMEM;
diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c
index 622c7bc42..3612ad441 100644
--- a/lib/librte_eal/common/eal_common_options.c
+++ b/lib/librte_eal/common/eal_common_options.c
@@ -228,7 +228,7 @@  eal_save_args(int argc, char **argv)
 		return -1;
 
 	for (i = 0; i < argc; i++) {
-		eal_args[i] = strdup(argv[i]);
+		eal_args[i] = rte_strdup(argv[i]);
 		if (strcmp(argv[i], "--") == 0)
 			break;
 	}
@@ -243,7 +243,7 @@  eal_save_args(int argc, char **argv)
 		return -1;
 
 	for (j = 0; i < argc; j++, i++)
-		eal_app_args[j] = strdup(argv[i]);
+		eal_app_args[j] = rte_strdup(argv[i]);
 	eal_app_args[j] = NULL;
 
 	return 0;
@@ -1273,7 +1273,7 @@  eal_parse_log_level(const char *arg)
 	char *str, *level;
 	int priority;
 
-	str = strdup(arg);
+	str = rte_strdup(arg);
 	if (str == NULL)
 		return -1;
 
@@ -1324,11 +1324,11 @@  eal_parse_log_level(const char *arg)
 static enum rte_proc_type_t
 eal_parse_proc_type(const char *arg)
 {
-	if (strncasecmp(arg, "primary", sizeof("primary")) == 0)
+	if (rte_strncasecmp(arg, "primary", sizeof("primary")) == 0)
 		return RTE_PROC_PRIMARY;
-	if (strncasecmp(arg, "secondary", sizeof("secondary")) == 0)
+	if (rte_strncasecmp(arg, "secondary", sizeof("secondary")) == 0)
 		return RTE_PROC_SECONDARY;
-	if (strncasecmp(arg, "auto", sizeof("auto")) == 0)
+	if (rte_strncasecmp(arg, "auto", sizeof("auto")) == 0)
 		return RTE_PROC_AUTO;
 
 	return RTE_PROC_INVALID;
diff --git a/lib/librte_eal/common/eal_common_trace_ctf.c b/lib/librte_eal/common/eal_common_trace_ctf.c
index 33e419aac..4041d9af6 100644
--- a/lib/librte_eal/common/eal_common_trace_ctf.c
+++ b/lib/librte_eal/common/eal_common_trace_ctf.c
@@ -398,7 +398,7 @@  char *trace_metadata_fixup_field(const char *field)
 	if (strstr(field, ".") == NULL && strstr(field, "->") == NULL)
 		return NULL;
 
-	out = strdup(field);
+	out = rte_strdup(field);
 	if (out == NULL)
 		return NULL;
 	p = out;
diff --git a/lib/librte_eal/common/eal_common_trace_utils.c b/lib/librte_eal/common/eal_common_trace_utils.c
index 64f58fb66..d541a5ea9 100644
--- a/lib/librte_eal/common/eal_common_trace_utils.c
+++ b/lib/librte_eal/common/eal_common_trace_utils.c
@@ -145,7 +145,7 @@  eal_trace_args_save(const char *val)
 		return -ENOMEM;
 	}
 
-	arg->val = strdup(val);
+	arg->val = rte_strdup(val);
 	if (arg->val == NULL) {
 		trace_err("failed to allocate memory for %s", val);
 		free(arg);
diff --git a/lib/librte_eal/include/rte_string_fns.h b/lib/librte_eal/include/rte_string_fns.h
index 8bac8243c..2d9d5afc8 100644
--- a/lib/librte_eal/include/rte_string_fns.h
+++ b/lib/librte_eal/include/rte_string_fns.h
@@ -116,6 +116,48 @@  rte_strlcat(char *dst, const char *src, size_t size)
 ssize_t
 rte_strscpy(char *dst, const char *src, size_t dsize);
 
+/**
+ * @internal
+ * strncasecmp(3) replacement for systems that don't have it.
+ */
+static inline int
+rte_strncasecmp(const char *s1, const char *s2, size_t size)
+{
+#ifdef RTE_EXEC_ENV_WINDOWS
+	return _strnicmp(s1, s2, size);
+#else
+	return strncasecmp(s1, s2, size);
+#endif
+}
+
+/**
+ * @internal
+ * strtor_r(3) replacement for systems that don't have it.
+ */
+static inline char *
+rte_strtok(char *str, const char *delim, char **saveptr)
+{
+#ifdef RTE_EXEC_ENV_WINDOWS
+	return strtok_s(str, delim, saveptr);
+#else
+	return strtok_r(str, delim, saveptr);
+#endif
+}
+
+/**
+ * @internal
+ * strdup(3) replacement for systems that don't have it.
+ */
+static inline char *
+rte_strdup(const char *str)
+{
+#ifdef RTE_EXEC_ENV_WINDOWS
+	return _strdup(str);
+#else
+	return strdup(str);
+#endif
+}
+
 #ifdef __cplusplus
 }
 #endif