12

A there any g++ options which can detect improper initialization of std::string with NULL const char*?

I was in the process of turning some int fields into std::string ones, i.e:

struct Foo
{
   int id;
   Foo() : id(0) {} 
};

...turned into:

struct Foo
{
   std::string id;
   Foo() : id(0) {} //oooops!
};

I completely overlooked bad 'id' initialization with 0 and g++ gave me no warnings at all. This error was detected in the run time(std::string constructor threw an exception) but I'd really like to detect such stuff in the compile time. Is there any way?

5
  • 2
    Unfortunately, 0 is the one value which won't trigger an error for an invalid conversion from int to pointer. Because of course 0 is a null pointer constant, so is convertible to any pointer type. I don't know of anything you can do other than, as visitor says, not write that initializer in the first place. Commented Mar 9, 2010 at 11:23
  • The proper solution would have been to add a private constructor std::string::string(int);. That would be a better match, and thus cause a compile-time error. Commented Mar 9, 2010 at 11:47
  • 1
    Not sure whether you meant it this way, but that might actually work, as a one-time test to catch any errors resulting from this round of changes from int to string. Modify std::basic_string in g++'s standard headers, check that the new code compiles, then change it back fast, before anyone notices. Commented Mar 9, 2010 at 12:01
  • Oh, no changing standard headers is not an option :) But probably I should ask g++ devs to add the private int constructor in the future? Commented Mar 10, 2010 at 9:37
  • Since C++23, there's a deleted std::string::string(std::nullptr_t) constructor that will cause this to be ill-formed, with diagnostic. Commented Jan 5, 2024 at 16:17

3 Answers 3

8

I can't think of a way to detect this at compile-time, so I wrote a string builder function that properly deals with null pointers:

//  FUNCTION :      safe_string(char const* pszS)
//  PARAMATERS :    pszS        source string to build a string from (may be NULL or 0-length)
//  DESCRIPTION :   Safely builds a string object from a char*, even a NULL pointer
//  RETURNS :       string

template<class C>
inline basic_string<C> safe_string(const C* input)
{
    if( !input )
        return basic_string<C>();
    return basic_string<C>(input);
}

I use this whenever I create a string and there's a chance the input might be NULL.

Sign up to request clarification or add additional context in comments.

Comments

5

I think it is actually undefined behavior and not checked by the compiler. You are lucky that this implementation throws an exception.

However, you can avoid such problems by specifying that you want default or zero-initialization in a type-agnostic way:

struct Foo
{
   X id;
   Foo() : id() {} //note empty parenthesis
};

2 Comments

Hm...so you are saying default constructor for int type assigns 0 ?
This syntax means zero-initialization for built-in types.
3

There is infrastructure in GCC to produce exactly this sort of warning:

void foo(const char* cstr) __attribute__((nonnull (1)));

void bar() {
    foo(0);
}

when compiled with -Wnonnull (which is implied by -Wall) produces:

warning: null argument where non-null required (argument 1)

So in principle you ought to be able to modify the relevant system header (or, better for experimenting, modify your own $HOME/bits/basic_string.h copy and then override the system one with -isystem $HOME) similarly:

basic_string(const _CharT* __s, const _Alloc& __a = _Alloc())
    __attribute__((nonnull (1)));

However this doesn't help because (at least in 4.0.1) -Wnonnull is not supported in C++ and the attribute is apparently ignored. It's not obvious why this is so; perhaps it was felt that it interacted badly with overloading or something.

1 Comment

Actually your basic_string ctor __attribute__((nonnull (1))) above checks that the this pointer is not NULL; simply change to __attribute__((nonnull (2))) to check that __s is non-null; see gcc.gnu.org/ml/gcc/2006-04/msg00549.html

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.