Web lists-archives.com

_FORTIFY_SOURCE has no effect for C++ due to usage of #define




Cygport now sets _FORTIFY_SOURCE=2 for C and C++ but this has no effect for C++. In <sys/features.h> __SSP_FORTIFY_LEVEL is always set to 0 if __cplusplus is defined. This is needed because <ssp/string.h> ... use #defines to replace the functions.

Testcase:

$ cat copy.c
#include <string.h>

char sbuf[42], *dbuf;

void to_sbuf(const char *p)
{
  strcpy(sbuf, p);
}

void to_dbuf(const char *p)
{
  strcpy(dbuf, p);
}


Examine preprocessed code:

$ gcc -D_FORTIFY_SOURCE=2 -O2 -E copy.c > copy2.c

$ vim copy2.c # Remove unnecessary code && pretty-print

$ cat copy2.c
typedef unsigned int size_t;
char *__strcpy_chk(char *, const char *, size_t);

extern __inline__ __attribute__((__always_inline__, __gnu_inline__)) char *
__strcpy_ichk(char * restrict dst, const char * restrict src)
{
  return __builtin___strcpy_chk(dst, src, __builtin_object_size(dst, 0));
}

char sbuf[42], *dbuf;

void to_sbuf(const char *p)
{
 ((__builtin_object_size(sbuf, 0) != (size_t)-1)
  ? __builtin___strcpy_chk(sbuf, p, __builtin_object_size(sbuf, 0))
  : __strcpy_ichk(sbuf, p));
}

void to_dbuf(const char *p)
{
 ((__builtin_object_size(dbuf, 0) != (size_t)-1)
  ? __builtin___strcpy_chk(dbuf, p, __builtin_object_size(dbuf, 0))
  : __strcpy_ichk(dbuf, p));
}


Why are these (a ? b : c) expanded from the "#define strcpy" needed? Both branches lead to the same __builtin___strcpy_chk() call. Is this possibly needed for (very) old compiler versions with weaker optimization?

According to "gcc -O2 -S" outputs, the generated code is identical for this source:

$ cat copy3.c
typedef unsigned int size_t;
char *strcpy (char *restrict, const char *restrict);
char *__strcpy_chk(char *, const char *, size_t);

char sbuf[42], *dbuf;

void to_sbuf(const char *p)
{
  __strcpy_chk(sbuf, p, 42);
}

void to_dbuf(const char *p)
{
  strcpy(dbuf, p);
}


The same code is generated if strcpy() is replaced itself without a "#define strcpy":

$ cat copy4.c
typedef unsigned int size_t;
char *strcpy (char *restrict, const char *restrict);

// #if __SSP_FORTIFY_LEVEL > 0
extern __inline__ __attribute__((__always_inline__, __gnu_inline__)) char *
strcpy(char * restrict dst, const char * restrict src)
{
  return __builtin___strcpy_chk(dst, src, __builtin_object_size(dst, 0));
}
// #endif

char sbuf[42], *dbuf;

void to_sbuf(const char *p)
{
  strcpy(sbuf, p); // changed to __strcpy_chk(sbuf, p, 42);
}

void to_dbuf(const char *p)
{
  strcpy(dbuf, p); // unchanged
}


This variant would be also compatible with C++. Same results with CLang(++).


Christian

PS: There is an outdated "#define __restrict" section in <sys/cdefs.h> which checks for GCC version 2.95 only.


--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple