Ticket #40315

c++17 std::aligned_alloc

Open Date: 2020-04-10 13:55 Last Update: 2020-05-02 01:37

Reporter:
Owner:
Type:
Status:
Closed
Component:
MileStone:
(None)
Priority:
5 - Medium
Severity:
5 - Medium
Resolution:
Fixed
File:
None
Vote
Score: 0
No votes
0.0% (0/0)
0.0% (0/0)

Details

According to cppreference, the function std::aligned_alloc is apart of C++17. When trying to compile the example code found at that page, the following compilation error occurs:

src code

  1. #include <cstdio>
  2. #include <cstdlib>
  3. int main()
  4. {
  5. int* p1 = static_cast<int*>(std::malloc(10*sizeof *p1));
  6. std::printf("default-aligned address: %p\n", static_cast<void*>(p1));
  7. std::free(p1);
  8. int* p2 = static_cast<int*>(std::aligned_alloc(1024, 1024));
  9. std::printf("1024-byte aligned address: %p\n", static_cast<void*>(p2));
  10. std::free(p2);
  11. }

compilation output

$g++ -std=c++17 alignment.cpp -o main
alignment.cpp: In function 'int main()':
alignment.cpp:10:38: error: 'aligned_alloc' is not a member of 'std'
 10 |     int* p2 = static_cast<int*>(std::aligned_alloc(1024, 1024));

gcc version

Target: x86_64-w64-mingw32
Configured with: ../gcc-9.3.0/configure --prefix=/mingw64 --with-local-prefix=/mingw64/local --build=x86_64-w64-mingw32 --host=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --with-native-system-header-dir=/mingw64/x86_64-w64-mingw32/include --libexecdir=/mingw64/lib --enable-bootstrap --with-arch=x86-64 --with-tune=generic --enable-languages=c,lto,c++,fortran,ada,objc,obj-c++ --enable-shared --enable-static --enable-libatomic --enable-threads=posix --enable-graphite --enable-fully-dynamic-string --enable-libstdcxx-filesystem-ts=yes --enable-libstdcxx-time=yes --disable-libstdcxx-pch --disable-libstdcxx-debug --disable-isl-version-check --enable-lto --enable-libgomp --disable-multilib --enable-checking=release --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --enable-plugin --with-libiconv --with-system-zlib --with-gmp=/mingw64 --with-mpfr=/mingw64 --with-mpc=/mingw64 --with-isl=/mingw64 --with-pkgversion='Rev1, Built by MSYS2 project' --with-bugurl=https://sourceforge.net/projects/msys2 --with-gnu-as --with-gnu-ld
Thread model: posix
gcc version 9.3.0 (Rev1, Built by MSYS2 project)

platform

Windows 10 Build: 18362.720

linker version

GNU ld (GNU Binutils) 2.34

mingw version

not quite sure which number is the relevant one in _mingw.h

??

build environment

I have tested using both windows command prompt and the msys-w64 shell, and both yield the same result

MINGW64_NT-10.0-18362  3.0.7-338.x86_64 2019-07-11 10:58 UTC x86_64 Msys

Ticket History (3/13 Histories)

2020-04-10 13:55 Updated by: drakbar
  • New Ticket "c++17 std::aligned_alloc" created
2020-04-10 13:56 Updated by: drakbar
  • Component Update from (None) to GCC
2020-04-10 19:06 Updated by: keith
  • Status Update from Open to Closed
  • Resolution Update from None to Rejected
Comment

gcc version 9.3.0 (Rev1, Built by MSYS2 project)

This is not a MinGW product; (the MSYS2 project is an independent fork of Cygwin, and is in no way associated with MinGW).

Target: x86_64-w64-mingw32

MinGW is a registered trademark, for which we hold sole legal title; we do not support products from projects which infringe our trademark in this manner.

2020-04-11 15:00 Updated by: drakbar
Comment

I wasn't aware that was the situation. After downloading a legit version of mingw, using mingw-get, I got the same result.

Here is the updated version info.

gcc version

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/9.2.0/lto-wrapper.exe
Target: mingw32
Configured with: ../src/gcc-9.2.0/configure --build=x86_64-pc-linux-gnu --host=mingw32 --target=mingw32 --disable-win32-registry --with-arch=i586 --with-tune=generic --enable-static --enable-shared --enable-threads --enable-languages=c,c++,objc,obj-c++,fortran,ada --with-dwarf2 --disable-sjlj-exceptions --enable-version-specific-runtime-libs --enable-libgomp --disable-libvtv --with-libiconv-prefix=/mingw --with-libintl-prefix=/mingw --enable-libstdcxx-debug --disable-build-format-warnings --prefix=/mingw --with-gmp=/mingw --with-mpfr=/mingw --with-mpc=/mingw --with-isl=/mingw --enable-nls --with-pkgversion='MinGW.org GCC Build-20200227-1'
Thread model: win32
gcc version 9.2.0 (MinGW.org GCC Build-20200227-1)

linker version

GNU ld (GNU Binutils) 2.32

mingw version

5.3.0

build environment

Just using command prompt cmd.exe

2020-04-11 20:18 Updated by: keith
  • Status Update from Closed to Open
  • Resolution Update from Rejected to None
Comment

After downloading a legit version of mingw, using mingw-get, I got the same result.

Okay, in that case we should follow up, although I suspect you may need to refer the issue upstream, on GCC BugZilla.

A possible issue could be that Microsoft's MSVCRT.DLL implementations of aligned allocation functions are utterly incompatible with ISO-C11 (and later), and the G++ infrastructure may depend on conformance. FWIW, cppreference.com is not a reliable documentation source, for MS-Windows programming, due to Microsoft's wilful violation of standards.

(Edited, 2020-04-11 22:25 Updated by: keith)
2020-04-11 22:19 Updated by: keith
Comment

This feature request would seem to be relevant. Do please note that there is, currently, no MinGW implementation of ISO-C11's aligned_alloc() function; without that, the G++ maintainers may be unwilling to support C++17's std::aligned_alloc(), on MinGW targets.

(Edited, 2020-04-11 22:24 Updated by: keith)
2020-04-11 22:40 Updated by: drakbar
Comment

Reply To keith

After downloading a legit version of mingw, using mingw-get, I got the same result.

Okay, in that case we should follow up, although I suspect you may need to refer the issue upstream, on GCC BugZilla. A possible issue could be that Microsoft's MSVCRT.DLL implementations of aligned allocation functions are utterly incompatible with ISO-C99 (and later), and the G++ infrastructure may depend on conformance. FWIW, cppreference.com is not a reliable documentation source, for MS-Windows programming, due to Microsoft's wilful violation of standards.

I am not sure if this helps, but it seems that GCC version 7.4 implemented this. Now I realize that a GCC in a browser is different than a GCC on windows, but I guess I am a bit confused. I was under the impression that upstream GCC wouldn't be concerned if it works on windows.

2020-04-12 01:18 Updated by: keith
Comment

Reply To drakbar

I am not sure if this helps, but it seems that GCC version 7.4 implemented this.

Likely when they implemented ISO-C11, or maybe just ISO-C++17 support; (I erroneously referred to ISO-C99, but aligned_alloc() support was added later). However, that GCC support was likely restricted to POSIX.1 compliant platforms, which windows is not.

Now I realize that a GCC in a browser is different than a GCC on windows, but I guess I am a bit confused.

Huh? GCC doesn't (normally) run in a browser; it runs on a variety of host platforms, but primarily those which are POSIX.1 compliant.

I was under the impression that upstream GCC wouldn't be concerned if it works on windows.

Upstream has supported mingw32 for years, but never as a primary target. For GCC-3.4.5, it was a secondary target; today it may have been demoted to tertiary. However, that's bye-the-bye: a MinGW.org release is no more than our binary build from upstream source — with a few local patches — but aligned_alloc() is difficult to implement, because Microsoft's underlying APIs are incompatible with its standardized requirements; (see the other ticket, to which I referred you). Welcome to the world of programming on windows; you often have to work around Microsoft's violation of standards. In the case of aligned_alloc(), you may need to consider _aligned_malloc(), (which you then need to pair with _aligned_free()).

2020-04-13 07:24 Updated by: keith
Comment

Reply To drakbar

I am not sure if this helps, but it seems that GCC version 7.4 implemented this.

Indeed, it did. For -std=c++17, in <cstdlib> it looks like this:

  1. #if __cplusplus >= 201703L && defined(_GLIBCXX_HAVE_ALIGNED_ALLOC)
  2. using ::aligned_alloc;
  3. #endif

The problem, when GCC is built for mingw32, is that there is no implementation for ISO-C11's aligned_alloc(), so that _GLIBCXX_HAVE_ALIGNED_ALLOC macro is not defined, and thus std::aligned_alloc() is not implemented in GCC for mingw32. Of course, if ISO-C11's aligned_alloc() could be implemented, then C++17's std::aligned_alloc() could also be supported; the problem, for aligned_alloc() is that ISO-C11 requires it to allocate over-aligned memory which can subsequently be freed by the standard free() function, or resized by the realloc() function, and Microsoft's free() and realloc() are not compatible with this requirement.

That said, I attached a proposed aligned_alloc() implementation to ticket #38607, for which I invited peer review. To date, no one has bothered to respond to that invitation, and without such review, I'm reluctant to push this into a core MinGW library, (because it would require that Microsoft's realloc() and free() implementations be overridden).

2020-04-13 20:03 Updated by: keith
Comment

FWIW, as a trivial example, the following foo.cc works:

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #if __cplusplus >= 201703L && defined __MINGW32__
  4. #include <malloc.h>
  5. #undef free
  6. #define free aligned_free
  7. extern "C"
  8. { static inline __attribute__((__always_inline__))
  9. void *aligned_alloc( size_t align, size_t wanted )
  10. { return __mingw_aligned_offset_malloc( wanted, align, (size_t)(0) ); }
  11. static inline __attribute__((__always_inline__))
  12. void aligned_free( void *ptr ){ return __mingw_free( ptr ); }
  13. }
  14. namespace std
  15. { using ::aligned_alloc;
  16. using ::aligned_free;
  17. }
  18. #endif // C++17 && __MINGW32__
  19. int main()
  20. { int* p1 = static_cast<int*>(std::malloc(10*sizeof *p1));
  21. std::printf("default-aligned address: %p\n", static_cast<void*>(p1));
  22. std::free(p1);
  23. int* p2 = static_cast<int*>(std::aligned_alloc(1024, 1024));
  24. std::printf("1024-byte aligned address: %p\n", static_cast<void*>(p2));
  25. std::free(p2);
  26. }
When cross-compiled, on my GNU/Linux host, and subsequently run under wine, this produces output similar to:
$ mingw32-g++ -std=gnu++17 foo.cc 
$ ./a.exe
default-aligned address:   00230F70
1024-byte aligned address: 00231400
Unfortunately, for more general application, the above is intrinsically unsafe. The problem is that, while __mingw_aligned_offset_malloc(), (in terms of which aligned_alloc() is implemented), returns a pointer to heap memory, that pointer is incompatible with Microsoft's realloc() and free() functions; thus, if that pointer were to be passed to any (third party) function, which might then pass it to realloc(), or to free(), the behaviour would be undefined. (Of course, the same criticism could be levelled at Microsoft's own over-aligned heap allocation functions, each of which also returns a pointer to heap memory, and which in turn, is equally incompatible with their realloc() and free() functions).

2020-04-20 06:22 Updated by: keith
Comment

Quoting Microsoft's C++ language conformance document:

C11: The Universal CRT implemented the parts of the C11 Standard Library that are required by C++17, with the exception of C99 strftime() E/O alternative conversion specifiers, C11 fopen() exclusive mode, and C11 aligned_alloc(). The latter is unlikely to be implemented, because C11 specified aligned_alloc() in a way that's incompatible with the Microsoft implementation of free(): namely, that free() must be able to handle highly aligned allocations.

Based on the above, I would be justified in dismissing this as a "won't fix", (because MinGW is under no obligation to support features which Microsoft have ruled out, and if they don't support it in the Universal CRT, they definitely do not support it in MSVCRT.DLL). However, I am reluctant to do so, because, when this patch, as attached to ticket #38607, is applied to mingwrt's <stdlib.h>, then your original example code works flawlessly, (thus demonstrating the fallacy of Microsoft's assertion, when free() itself can be so easily overridden by a variant — __mingw_free() — which can transparently handle both normally aligned allocations, and those over-aligned allocations which originate from a suitably designed allocator — aligned_alloc(), which has been implemented in terms of __mingw_aligned_offset_malloc()).

2020-04-21 00:06 Updated by: drakbar
Comment

I appreciate the work put into this. I am glad to have a work around. As far as the patch is concerned, I don't think I have a enough expertise weigh in and I imagine the number of engineers that could/care is very few. I venture to guess that working on project like this has many instances where MS causes a bit of friction.

2020-05-02 01:37 Updated by: keith
  • Component Update from GCC to WSL
  • Resolution Update from None to Fixed
  • Status Update from Open to Closed
  • Owner Update from (None) to keith
Comment

As of mingwrt-5.3.1, published on 30-Apr-2020 as a component of wsl-5.3.1, both C11's aligned_alloc(), and C++17's corresponding std::aligned_alloc() are supported OOTB, as is POSIX.1-2001's posix_memalign().

Attachment File List

No attachments

Edit

Please login to add comment to this ticket » Login