tags:

views:

694

answers:

8

I made a function like this:

bool IsSameString(char* p1, char* p2) 
{
     return 0 == strcmp(p1, p2);
}

The problem is that sometimes, by mistake, arguments are passed which are not strings (meaning that p1 or p2 is not terminated with a null character). Then, strcmp continues comparing until it reaches non-accessible memory and crashes. Is there a safe version of strcmp? Or can I tell whether p1 (and p2) is a string or not in a safe manner?

Thanks in advance.

+6  A: 

There's no cure for this that is portable. The convention states that there's an extra character holding a null character that belongs to the same correctly allocated block of memory as the string itself. Either this convention is followed and everything's fine or undefined behaviour occurs.

If you know the length of the string you compare against you can use strncmp() but his will not help if the string passed to your code is actually shorter than the string you compare against.

sharptooth
+5  A: 

In some cases strncmp can solve your problem:

int strncmp ( const char * str1, const char * str2, size_t num );

It compares up to num characters of the C string str1 to those of the C string str2.


Also, take a look, what the US DHS National Cyber Security Division recommends on this matter:

Ensure that strings are null terminated before passing into strcmp. This can be enforced by always placing a \0 in the last allocated byte of the buffer.

char str1[] ="something";
char str2[] = "another thing";
/* In this case we know strings are null terminated. Pretend we don't. */
str1[sizeof(str1)-1] = '\0';
str2[sizeof(str2)-1] = '\0';
/* Now the following is safe. */
if (strcmp(str1, str2)) { /* do something */ } else { /* do something else */ }
Igor Oks
Pavel Shved
A: 

You can put an upper limit on the number of characters to be compared using the strncmp function.

Paolo Tedesco
But it doesn't make sense. A sane `strcmp(s1, s2)` will not look further in `s1` than there are characters in `s2`, and at the same time, you have to compare the full length of the shortest of them.. so there is no way that `strncmp` can help.
kaizer.se
+10  A: 

No, there's no (standard) way to tell whether a char * actually points to valid memory.

In your situation, it is better to use std::string and the overloaded == operator. If you do this, the compiler would enforce type safety.

iWerner
..and if you use std::string, you don't need to write a function like the one you've written, saving you time and energy.
JBRWilkinson
+3  A: 

you can use strncmp, But if possible use std::string to avoid many problems :)

sat
A: 

You dont write, what platform you are using. Windows has the following functions:

IsBadStringPtr might be what you are looking for, if you are using windows.

RED SOFT ADAIR
The IsBadXXXPtr functions are generally not a good thing to use -- depending on where the pointer points, they can induce random crashes in other parts of the program, and it's much, much easier to debug a crash near its cause, instead of half an hour and sixteen source files away. See http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx for details.
Stephen Veiss
Not only that, it masks other problems. The pointer might be valid from the operating system's point of view, but the memory could be something else (like an address on the stack ...)
janm
Oh, thanks for these comments. I had some similar experience, but counted that to homebrewn problems.
RED SOFT ADAIR
A: 

There is no best answer to this as you can't verify the char* is a string. The only solution is to create a type and use it for string for example str::string or create your own if you want something lighter. ie

struct MyString
  {
  MyString() : str(0), len(0) {}
  MyString( char* x ) { len = strlen(x); str = strdup(x); }
  ⁓MyString() { if(str) free(str); }
  char* str;
  size_t len;
  };

bool IsSameString(MyString& p1, MyString& p2) 
  {
  return 0 == strcmp(p1.str, p2.str);
  }


MyString str1("test");
MyString str2("test");

if( IsSameString( str1, str2 ) {}
David Allan Finch
This just changes the point of failure; if the memory passed in the constructor is not null terminated there will still be a failure.
janm
"Want something lighter" seems to be the downfall. `std::string` will do everything your class does, at no extra cost. Light != less functionality.
GMan
janm - I think that is a problem that you will not be able to solve without only using allowing static strings ie "" to be used and making all other uses of char* compile time errors.
David Allan Finch
GMan - I am not sure but I would expect that std::string will increase the size of your exec by quite a bit. It all depends on what you mean by lighter etc.
David Allan Finch
You'll be linking to the standard library anyway, if that's what you mean. I can't see saving a little space worth trying to correctly re-write an existing class. As it stands, your string class is buggy.
GMan
There are problems with your class unrelated to the actual problem being solved (eg. copyable, possible multiple frees on the same pointer, ...), but the issue related to the actual question is that the program will still crash. What happens when a MyString is constructed like "MyString s(broken_pointer)" or "MyString x = 0"? Answer: The process fails as described by the original poster. So: The actual problem is not the question as asked, it is that the code is broken somewhere else. Calling strcmp() on terminated strings is not bad, and an application can ensure strings are terminated.
janm
David Allan Finch
+5  A: 

If you are passing strings to strcmp() that are not null terminated you have already lost. The fact that you have a string that is not null terminated (but should be) indicates that you have deeper issues in your code. You cannot change strcmp() to safely deal with this problem.

You should be writing your code so that can never happen. Start by using the string class. At the boundaries where you take data into your code you need to make sure you deal with the exceptional cases; if you get too much data you need to Do The Right Thing. That does not involve running off the end of your buffer. If you must perform I/O into a C style buffer, use functions where you specify the length of the buffer and detect and deal with cases where the buffer is not large enough at that point.

janm
Yes, what janm said. When you find a bug, fix the bug. Don't just try to hide it by complicating other code in a futile attempt to make the bug's symptoms less severe. In this case, there is a bug in the code that calls IsSameString().
Jeremy Friesner