find the bugs

A

ak

Recently at an interview i was asked the following question :

Assuming the function lookupName is defined, what's wrong with this
code (hint: 2 bugs)?


const char *getName(const char *c) {
std::string name = lookupName(c);
if (name == NULL)
return "Anonymous";
return name.c_str();



}


int main(int argc, char *argv[]) {
const char *name = NULL, *c = NULL;
if (argc >= 2)
c = argv[1];
name = getName(c);

printf("My name is %s\n", name);
return 0;



}


MY SOLUTION : #bug 1: name==NULL is illegal

#bug 2: name=getName(c) should be included in
the 'if' statement so that NULL will
not be
passed to getName()


The above was my solution...what do you all experts think?
Am i right or have i missed something?


Cheers,
ak
 
S

Sylvester Hesp

ak said:
Recently at an interview i was asked the following question :

Assuming the function lookupName is defined, what's wrong with this
code (hint: 2 bugs)?


const char *getName(const char *c) {
std::string name = lookupName(c);
if (name == NULL)
return "Anonymous";
return name.c_str();



}


int main(int argc, char *argv[]) {
const char *name = NULL, *c = NULL;
if (argc >= 2)
c = argv[1];
name = getName(c);

printf("My name is %s\n", name);
return 0;



}


MY SOLUTION : #bug 1: name==NULL is illegal

#bug 2: name=getName(c) should be included in
the 'if' statement so that NULL will
not be
passed to getName()


The above was my solution...what do you all experts think?
Am i right or have i missed something?

Yes, a very important one. Try to find out what string::c_str() returns and
why it is bad in this particular case.

- Sylvester Hesp
 
Z

Zeppe

ak said:
Recently at an interview i was asked the following question :

Assuming the function lookupName is defined, what's wrong with this
code (hint: 2 bugs)?


const char *getName(const char *c) {
std::string name = lookupName(c);
if (name == NULL)
return "Anonymous";
return name.c_str();



}


int main(int argc, char *argv[]) {
const char *name = NULL, *c = NULL;
if (argc >= 2)
c = argv[1];
name = getName(c);

printf("My name is %s\n", name);
return 0;



}


MY SOLUTION : #bug 1: name==NULL is illegal
ok.

#bug 2: name=getName(c) should be included in
the 'if' statement so that NULL will
not be
passed to getName()

I think it's right outside. The second bug is actually in "return
name.c_str();". name is a local variable, so the pointer returned by
c_str will be invalid outside of the getName function.

Regards,

Zeppe
 
S

Sylvester Hesp

ak said:
#bug 2: name=getName(c) should be included in
the 'if' statement so that NULL will
not be
passed to getName()

Btw, the bug is not calling getName() with a 0 pointer, since we do not know
the pre-conditions of lookupName(). That function may very well accept a
NULL pointer, so the call to getName() doesn't need to be placed inside an
if statement checking for 0 pointers.

- Sylvester Hesp
 
M

Massimo

Recently at an interview i was asked the following question :

Assuming the function lookupName is defined, what's wrong with this
code (hint: 2 bugs)?


const char *getName(const char *c) {
std::string name = lookupName(c);
if (name == NULL)
return "Anonymous";
return name.c_str();



}

Both problems are actually the same: you're returning a pointer to an area
of memory which becomes invalid as soon as you exit the function getName().


Massimo
 
G

Gianni Mariani

ak said:
Recently at an interview i was asked the following question :

Assuming the function lookupName is defined, what's wrong with this
code (hint: 2 bugs)?

first bug - lookupName is not declared.
const char *getName(const char *c) {
std::string name = lookupName(c);
if (name == NULL)

NULL is 0 in C++. I never tried to compare a std::string to an int
before. I assume it's broken.
return "Anonymous";

Ok - the one everyone said. Returning the value of a function temporary.
return name.c_str();



}


int main(int argc, char *argv[]) {
const char *name = NULL, *c = NULL;
if (argc >= 2)
c = argv[1];

It does not parse the arguments correctly. Should you return when argc
<= 1 spouting an error message ? What should happen if you have more
messages ?
name = getName(c);

printf("My name is %s\n", name);
return 0;



}


MY SOLUTION : #bug 1: name==NULL is illegal

#bug 2: name=getName(c) should be included in
the 'if' statement so that NULL will
not be
passed to getName()


The above was my solution...what do you all experts think?
Am i right or have i missed something?

There are at least 4 errors.
 
I

Ian Collins

ak said:
Recently at an interview i was asked the following question :

Assuming the function lookupName is defined, what's wrong with this
code (hint: 2 bugs)?


const char *getName(const char *c) {
std::string name = lookupName(c);
if (name == NULL)

This isn't a bug, its an error.
 
J

Jim Langston

ak said:
Recently at an interview i was asked the following question :

Assuming the function lookupName is defined, what's wrong with this
code (hint: 2 bugs)?


const char *getName(const char *c) {
std::string name = lookupName(c);
if (name == NULL)

a std::string can not be null. If lookupName returns a NULL pointer, then
the line before this one will be in error, you can not assign a std::string
a null pointer. In my compiler when I run it I get memory access reading
location 0x00000000.
return "Anonymous";

You are returning a const char* of a local constant. I believe this is
undefined behavior. It may work as if there is no problem, it may crash.
It may work for a while then crash later when the executable code containing
the constant gets swapped from memory.
return name.c_str();

std::string name is a local variable. As soon as this function ends, it
goes out of scope and it's destructor is called. So you are returning a
pointer to a const string that won't exist pass the function call.
}


int main(int argc, char *argv[]) {
const char *name = NULL, *c = NULL;
if (argc >= 2)
c = argv[1];
name = getName(c);

printf("My name is %s\n", name);
return 0;



}


MY SOLUTION : #bug 1: name==NULL is illegal

#bug 2: name=getName(c) should be included in
the 'if' statement so that NULL will
not be
passed to getName()


The above was my solution...what do you all experts think?
Am i right or have i missed something?


Cheers,
ak
 
A

Alf P. Steinbach

* Jim Langston:
You are returning a const char* of a local constant. I believe this is
undefined behavior. It may work as if there is no problem, it may crash.
It may work for a while then crash later when the executable code containing
the constant gets swapped from memory.

It's technically OK, no UB in that statement.

Whether it's problematic depends on whether the client code is assuming
the result string is dynamically allocated or not.
 
Z

zeppe

Gianni said:
first bug - lookupName is not declared.

it's not an error. If the function is defined, a separate declaration is
not needed.
NULL is 0 in C++. I never tried to compare a std::string to an int
before. I assume it's broken.
right.


Ok - the one everyone said. Returning the value of a function temporary.

this is not the temporary, it is ok. The temporary is the c_str() on the
next line.
return name.c_str();



}


int main(int argc, char *argv[]) {
const char *name = NULL, *c = NULL;
if (argc >= 2)
c = argv[1];

It does not parse the arguments correctly. Should you return when argc
<= 1 spouting an error message ? What should happen if you have more
messages ?

You knows nothing about the semantic of the program. In these
situations, just assume that everything you don't know actually make
sense. The argument parsing in this program is not broken.
There are at least 4 errors.

there are two, as stated in the text of the exercise.

Regards,

Zeppe
 
J

James Kanze

This isn't a bug, its an error.

What's the difference?

In reality, programs don't have bugs, i.e. small "insects" which
somehow crept into the code when we weren't looking. They have
errors: a mistake made by the programmer. In this case, there
are two blatant errors in the code, both equally wrong, and both
showing a misunderstanding about std::string.

Presumably, that's the point of the question.
 
J

James Kanze

[...]
You are returning a const char* of a local constant.

String literals have static storage duration. There's
absolutely nothing wrong with this statement; it's even a common
idiom.
 
I

Ian Collins

James said:
What's the difference?
My understanding of a bug is defective behavior that compiles.
Comparing a std::string with 0 is a compile time error.
 
G

Gianni Mariani

zeppe said:
it's not an error. If the function is defined, a separate declaration is
not needed.

There was no decl in the post. Does it return a char * or a std::string?

If it returns a char * does the return value need to be freed ? If so
that would be bug number 5.
this is not the temporary, it is ok. The temporary is the c_str() on the
next line.

That's the one I was referring to.
return name.c_str();



}


int main(int argc, char *argv[]) {
const char *name = NULL, *c = NULL;
if (argc >= 2)
c = argv[1];

It does not parse the arguments correctly. Should you return when
argc <= 1 spouting an error message ? What should happen if you have
more messages ?

You knows nothing about the semantic of the program. In these
situations, just assume that everything you don't know actually make
sense. The argument parsing in this program is not broken.

It's broken.

More than one argument and those arguments are ignored. That's a bug in
my rulebook and if you were to ever work in my shop it would soon become
a bug in your rule book as well.

Correct parsing should be:

if (argc < 2 )
{
std::cerr<<"Need ???NAME??? parameter to command "<<argv[0]<< "\n";
return 1;
}

if (argc > 2) {
std::cerr<<"too many parameters passed to command "<<argv[0]<<"\n";
return 1;
}

....

as it stands, if there are no parameters to the command, "getName" is
passed a NULL - probably not a good idea.
there are two, as stated in the text of the exercise.

It depends on whose rule book you pick.
 
G

Gianni Mariani

Ian said:
My understanding of a bug is defective behavior that compiles.
Comparing a std::string with 0 is a compile time error.

splitting hairs ...

in my book, (and in the context of an interview where there likely is no
compiler), a bug is any issue with the code. If I was the interviewer
I'd be interested in any comment the candidate had to say about the code.
 
J

James Kanze

My understanding of a bug is defective behavior that compiles.
Comparing a std::string with 0 is a compile time error.

I don't like the word bug, to begin with. Both the problems
here are programmer errors. Bug sounds too much like something
that crept in despite the programmer.

In the generally accepted sense, however, a bug ceases to be a
bug once it has been fixed. "Bugs" that are signaled by the
compiler don't stay in that state very long, and don't make it
into released software (so a user wouldn't consider it a bug,
since he'd never see it). On the other hand, if this code were
checked in, and I had to compile it, I'd certainly consider it a
"bug".
 
I

Ian Collins

James said:
I don't like the word bug, to begin with. Both the problems
here are programmer errors. Bug sounds too much like something
that crept in despite the programmer.

In the generally accepted sense, however, a bug ceases to be a
bug once it has been fixed. "Bugs" that are signaled by the
compiler don't stay in that state very long, and don't make it
into released software (so a user wouldn't consider it a bug,
since he'd never see it). On the other hand, if this code were
checked in, and I had to compile it, I'd certainly consider it a
"bug".
The real bug is in the process that lets you check in untested code!
 
G

Gianni Mariani

Ian Collins wrote:
....
The real bug is in the process that lets you check in untested code!

Well, it can happen for various reasons and I see that it is inevitable
in an optimal development system...

For example, I advocate a 2 platform target in any development using
C++. The reasons is that it pushes devs to use standard C++ (no vendor
lock in is important) and 2 platforms are better than one to discovery
of errors (2 platforms are better than one to discover errors - I can't
count the number of times it a test failed on linux and succeeded on
windows or visa versa that turned out to be a true issue on both platforms).

If have a team of unix dev and windows dev people, I don't necessarily
want to push the expense to educate all devs in both environments all up
front. I'd rather push that over time. The automated build system
picks up errors in one environment not in the other.

Seeing red (failed builds) on the automated build system is in and of
itself never an issue, it's when the issue is not resolved, either by
backing out the change or resolving the problem in a timely manner.

I leave it up to the developer to determine whether the change needs
testing in his sandbox or the automated test system. It also saves my
time (as a developer), make me more productive and makes the build
system more useful (does the hard work of doing the other platform build
and run all the tests for me).

Yes, I hear the chunder from here. I find this approach far more
practical and more developer time efficient than a rigid - check in only
good code - system.

What I want to optimize is for developer productivity. The occasional
cost of problems associated with checking in untested code is minimal
compared to the alternative of having devs wait for what an automated
system can do for them.
 
Z

zeppe

Gianni said:
There was no decl in the post. Does it return a char * or a std::string?

If it returns a char * does the return value need to be freed ? If so
that would be bug number 5.

in my opinion you should simply assume that the code that is not given
is correct. Otherwise, i could say that in the lookupName there could be
also the error 6, 7, 8, and maybe 9. It doesn't make sense....
That's the one I was referring to.

Please answer below the text you're quoting, otherwise you can generate
misinterpretations.
int main(int argc, char *argv[]) {
const char *name = NULL, *c = NULL;
if (argc >= 2)
c = argv[1];

It does not parse the arguments correctly. Should you return when
argc <= 1 spouting an error message ? What should happen if you have
more messages ?

You knows nothing about the semantic of the program. In these
situations, just assume that everything you don't know actually make
sense. The argument parsing in this program is not broken.

It's broken.

More than one argument and those arguments are ignored. That's a bug in
my rulebook and if you were to ever work in my shop it would soon become
a bug in your rule book as well.

What's wrong with ignoring arguments? For me, a bug is something that:
- makes the program crash
- doesn't make the program compile (but I would call it error as Ian
pointed out)
- makes the program act differently from what I want. That is, if
nobody tells me that the program shouldn't ignore input arguments, I
assume that this is legal. It may seem a rather rigid reasoning, but
this is an interview question, it's not a real program, in which case I
would ask what is the program for, before making assumptions.
Correct parsing should be:

if (argc < 2 )
{
std::cerr<<"Need ???NAME??? parameter to command "<<argv[0]<< "\n";
return 1;
}

you decided that there should be at least a parameter? and based on
what? You know nothing about this program, and for me it seems like it
produces a result even without parameters. And, as far as we both know,
it may be the correct (expected) result.
if (argc > 2) {
std::cerr<<"too many parameters passed to command "<<argv[0]<<"\n";
return 1;
}

again. You are imposing restrictions on your own account.
...

as it stands, if there are no parameters to the command, "getName" is
passed a NULL - probably not a good idea.

or probably a precondition on lookUpName, I would say...
It depends on whose rule book you pick.

You made good comments about pieces of code that are questionable, and
that's good. The only thing is that you weren't required to do so, but
just to find the errors.

That's IMHO, of course...

probably, if the interview context would have been appropriate, after
having pointer out the two error I'd have spent some words on the parts
of code that are "weak" in terms of behaviour, that are more or less the
ones that you described (but there would be a lot, for example that it's
so bad mixing char* and std::string, and that there is no reason not to
use only std::string, make the interfaces uniform, etc.).

Regards,

Zeppe
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top