This article was put together from my findings when I tried to compile libcpy for Windows 11.
Let's say we have some C/C++ code already written for gcc in linux. We want to compile them for Windows 11 as well. To have greater portability. How can we achieve this? Which toolchain to select? What are the obstacles? In this article we'll explore.
🧩 Les problèmes
How everything other than VS2022 fails? In CMake for VS Code, you can have some preset CMake configurations in CMakeSettings.json
file. Also known as toolchain or "kits" for clang, mingw, cl, etc. However:
- mingw doesn't have address sanitizers.
- clang throws syntax errors for multi-line macro, same as cl.
- cl doesn't fully support C99, so
unsigned stack[va_arg_count]
is an error because it "expected a constant expression" ofint
- all projects may not be portable in visual studio; if you clone a project using cmake from github and Open that folder in VS2022, then you're almost on your own with
CMakeSettings.json
or CMake presets - in VS code, you may have quite a hard time in larger projects, e.g. linking external shared libraries (i.e.
vld_x64
) with the compiled executable using CMake
🌟 La lumière de la solution
Enter Microsoft Visual Studio 2022. The pinnacle of excellency from Microsoft. An under-appreciated humble big-friendly-giant. A champ. A software specimen.
If you ask any airline "is this flight safe?", they reply something to the effect of "oh, your trip to the airport was the most risky part".
If you ask me, "how does it feel coding in VS2022?", I'd brighten up my charm and uplift my morale to say "double-clicking this app was the hardest part". T is liketh wat'r.
L'appréciation
So, a major reason behind migrating to Microsoft VS2022 was to have great support, great tooling, and ease in development. VS2022 has a ton of features/tooling/extensions/options/configurations. So much so that, in the beginning it may feel like an overkill or a bloat. However, each feature has a purpose of life, and each of them are helpful. Each of them are built over years of demand from low-level developers from around the global over more than a decade of feedback.
La confusion?
Let's say I have a Project for dll in C/C++ in a Solution. In the same solution, I have another Console App Project to use the library.
You turn on "Enable Address Sanitizer" from Project Properties on the console app - and the whole app crashes for some people. Apparently Visual Studio developers tried fixing this flaw. However this is not fixed yet.
The error output will almost spam your debug console with the following message in enormous quantity:
Exception thrown at 0x00007FFB12B64F69 (KernelBase.dll) in
main.exe: 0xC0000005: Access violation
writing location 0x0000001F3966FCCE.
Please do note that this major problem is for x64 only. However, a dev from the Visual Studio team said that the silent violations are normal, and not a bug. This is incorrect because, these "silent normal access violations" cause:
- all memory leaks to be undetected! (when compiled with Visual Studio's lovely library to detect memory leaks,
<crtdbg.h>
, which we'll discuss later) - causes deadlier, more messy, unfixable Stack overflow 😎 errors. (when compiled with Visual Leak Detector,
<vld.h>
) - crashes the application immediately for some people
La good news :D
Just don't turn on "Enable Address Sanitizer" for the console app. That's it. That's how all of the problems in the previous section can be completely mitigated!
Les armes 🛠️
There are quite a number of libraries and tools to detect memory leaks, but the following two worked great for me. Both of the library masterpieces work without enabling --fsantize=address
, hence no access violation errors. Let's say we have a piece of code, and let's see how they turn out.
#include <crtdbg.h>
This is a system library from the C Runtime library of Microsoft Visual Studio. Therefore this library is available is no other platform except Windows. The library works exceptionally well, and it automatically binds itself to all app exit points, and outputs memory leak info.
Let's say the code we have is:
#define _CRT_SECURE_NO_WARNINGS
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
int main() {
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
char* str = malloc(6);
strcpy(str, "hello");
// free(str);
return 0;
}
The corresponding output:
Detected memory leaks!
Dumping objects ->
main.c(8) : normal block at 0x0000020C7981FB50, 6 bytes long.
Data: <hello> .... some hex values ....
Object dump complete.
#include <vld.h>
This library is developed by KindDragon. Another acme of human intelligence. However the fork from Azure seems to fix an issue.
Let's say the code we have is:
#include <stdlib.h>
int main() {
char* str = malloc(6);
strcpy(str, "hello");
// free(str);
return 0;
}
The corresponding output:
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 1 at 0x00000000C7C0D970: 6 bytes ----------
Leak Hash: 0x9C8CAD7D, Count: 1, Total 6 bytes
Call Stack (TID 13088):
ucrtbased.dll!malloc()
.... more call stack ....
.... more call stack ....
C:\Users\USER\main.c
.... more call stack ....
.... more call stack ....
Data:
.... The readable value of the pointer: "hello" ....
.... outputs the surrounding heap ....
.... outputs the surrounding heap ....
💭 La final thoughts
Msys2 may help while coding in Visual Studio. And as we discussed, you may get VS Code to work correctly on a large project, however Microsoft Visual Studio 2022 would be the best practice! Apparantly you can also write code for linux from VS 2022, however gcc
and gdb
has complete support for address sanitizers.
Top comments (1)
great post buddy! :)