2

I stumbled on a runtime crash in Visual Studio 2017 in minkernel\crts\ucrt\src\appcrt\string\i386\strlen.asm after I modified a function. Here's the situation as a minimal example in Compiler Explorer:

#include <string>

//void func(int i); // Original function signature
void func(const std::string& str); // New function signature: 'int' parameter changed to 'std::string'

int square(int num) {
    func(0); // This implicit conversion of '0' to 'any pointer'
    //func(1); // This doesn't compile anymore, which is expected
    //func((void*) 0); // This doesn't compile, why?
}

Compiler Explorer version here.. I tried several compilers and several versions to make sure this wasn't a specific issue.

Explanations: Originally, my function had an integer parameter. I refactored it to accept a std::string parameter, and used 'Compile' to have the compiler find all calls and report them as errors for me; So I went over each of them and fixed them. For example, func(1); no longer compiled as was changed to func("1");.

However something unexpected happened with calls to func(0);: They didn't provoke any compile-time errors, but instead crash at runtime! Apparently in C++, there is still an invisible/automatic conversion of the integer constant 0 to a mysterious pointer type. It doesn't appear to be void * since func((void*) 0); doesn't compile.

Question: Is there a way to disable this automatic process? Or can you help me understand what is happening according to the standard and why?

Remz
  • 3,338
  • 3
  • 7
  • 11
  • 4
    `0`, in addition to being an integer value, is a null-pointer constant. It is convertible to a pointer to any type. If you cast it to `const char*` you'll get the same problem: it invokes the `std::string` constructor that takes a `const char*`, and passing a null pointer to that constructor produces undefined behavior. – Pete Becker Dec 19 '19 at 13:22
  • MSVC (code analysis): warning C6387: '_Param_(1)' could be '0': this does not adhere to the specification for the function 'std::basic_string,std::allocator >::{ctor}'. – Adrian Mole Dec 19 '19 at 13:25
  • That is good to know, I had never used the Code Analysis feature in MSVC. While is true that it indeed detects it, it would have been nice that the Standard itself would make this a compile-time error by removing this ancient `0` constant. We now have `nullptr` since c++11. Also 10 years. It is odd that a single line program like: `std::string crash_global(0);` brings the mighty c++ to its knees. Even with `-Wall -Wextra` it doesn't say anything. – Remz Dec 19 '19 at 22:02
  • @PeteBecker: I feel my intention was not to be a duplicate of [Why doesn't std::string take a null pointer?](https://stackoverflow.com/questions/49058133/why-doesnt-stdstring-take-a-null-pointer). Perhaps I should have phrased it more along the line of: "Why c++ standard still allows `constant 0` to be considered a pointer, instead of relying on the type-safe `nullptr` that exists since c++11?" – Remz Dec 20 '19 at 12:46
  • @Remz -- the reason for still allowing it is that it's widely used, and changing it would require rewriting a lot of code. – Pete Becker Dec 20 '19 at 15:02
  • @PeteBecker: Indeed, but should there be a compiler option so that newer programs should enforce and stop relying on this old remnant? – Remz Dec 20 '19 at 22:17

0 Answers0