How to handle invalid argument with C?

L

Lambda

When I call the standard strncpy function, I provide it a negative
argument,
such as:

strncpy(s, ct, -1)

I compile the code with gcc, when I run, it says "Segmentation fault".
Do you think it's ok? I try this to see how the library handle invalid
parameter.

When I define my own function, should I handle this kind of argument?
And if so, how can I tell the caller the argument is wrong?
Return some error code such as -1?
But how about the function return type is void?

I know in Java, I can define some invalid parameter exception to
indicate this.
What can I do with C?
 
I

Ian Collins

Lambda said:
When I call the standard strncpy function, I provide it a negative
argument,
such as:

strncpy(s, ct, -1)

I compile the code with gcc, when I run, it says "Segmentation fault".
Do you think it's ok? I try this to see how the library handle invalid
parameter.
The third parameter to strncpy is size_t which is unsigned. (size_t)-1
is a very big number.
When I define my own function, should I handle this kind of argument?
And if so, how can I tell the caller the argument is wrong?
Return some error code such as -1?
But how about the function return type is void?
The the function can return an error, don't use void as the return type.
I know in Java, I can define some invalid parameter exception to
indicate this.
What can I do with C?
Return an error, if you can tell the parameter is invalid.
 
S

santosh

When I call the standard strncpy function, I provide it a negative
argument,
such as:

strncpy(s, ct, -1)

Here -1 is converted to the type size_t which is an unsigned integer.
Thus this actually results in strncpy receiving a very large positive
value. The segmentation fault is probably caused by strncpy trying to
read memory far beyond the legal limits.
I compile the code with gcc, when I run, it says "Segmentation fault".
Do you think it's ok? I try this to see how the library handle invalid
parameter.

In C each function is documented clearly as to what type of values it
accepts. In addition to this there are situations where many values do
not make any sense.

In general the programmer has to be careful to pass the correct type and
range of values to the Standard library function.
When I define my own function, should I handle this kind of argument?

It's a matter of trade-off. It's very common nowadays to sacrifice a
minuscule amount of runtime efficiency to check for common exceptions
like invalid arguments.

Nevertheless there are many situations where such checks are either
inappropriate or not possible, not least of which is the situation
where the callee has no idea if an argument is a valid value. Such
information belongs to the caller. Library function generally blindly
accept the arguments that they are given barring a few elementary check
like null pointer values, checking for values outside the accepted
domain etc.
And if so, how can I tell the caller the argument is wrong?

By setting some kind of error indicator. I generally return a status
value where this is convenient. Otherwise I treat one of the arguments
as a pointer to an object which receives the status value. I usually
don't use global objects like errno.
Return some error code such as -1?

Yes. However designing proper error codes is not a trivial task and
changing things retrospectively is often difficult. Also use symbolic
constants instead of literals.
But how about the function return type is void?

Then the function either has to set an external object, or access an
object through one of it's arguments or invoke a callback function, or
raise a signal or...

Clearly there are numerous ways. Which one is appropriate for a given
function is very dependent on the function's details and related
context.
I know in Java, I can define some invalid parameter exception to
indicate this.
What can I do with C?

C doesn't have standardised support for exceptions so unless your
willing to simulate them, the usual method is to rely on explicit
checking of status values each time the function is invoked. Wrappers
can encapsulate and abstract these details to a large extent.
 
L

Lambda

The third parameter to strncpy is size_t which is unsigned. (size_t)-1
is a very big number.


The the function can return an error, don't use void as the return type.


Return an error, if you can tell the parameter is invalid.

Ian, thank you for your reply.
Maybe this is the only solution with C.

The problem is an error code does not indicate what problem it is.
I can not return some text to indicate the problem,
for example 'the n argument must be a valid array index, >= 0 and <
size'
I have to write all these in the function document and wish the user
note them.

Another problem is some error code such as -1 can be a legal return
value.
I must try to find good error code.

Exception in C++ and Java is a elegant solution, i think.
 
I

Ian Collins

Lambda said:
Ian, thank you for your reply.
Maybe this is the only solution with C.

The problem is an error code does not indicate what problem it is.
I can not return some text to indicate the problem,
for example 'the n argument must be a valid array index, >= 0 and <
size'
I have to write all these in the function document and wish the user
note them.
Error codes work fine, or returning -1 and setting errno which is
typical of system calls. Some environments define an enum of error
codes and have all their system calls return a value of that type.
 
R

Richard

Lambda said:
Ian, thank you for your reply.
Maybe this is the only solution with C.

The problem is an error code does not indicate what problem it is.

That is exactly what it does. This error code is documented according to
its values

e.g

-2 : null pointer

or whatever you choose.

It is generally better to return 0 for success IMO.

I can not return some text to indicate the problem,
for example 'the n argument must be a valid array index, >= 0 and <
size'
I have to write all these in the function document and wish the user
note them.

Yes. Or you could also have a log function which converts the code into
descriptive text.
Another problem is some error code such as -1 can be a legal return
value.
I must try to find good error code.

There is only success or one of many errors from what I can see. What do
you mean by -1 can be a legal return? Are you rewriting strncpy or are
you talking more generally?
Exception in C++ and Java is a elegant solution, i think.
 
R

Richard Tobin

[...]

That is exactly what it does. This error code is documented according to
its values

e.g

-2 : null pointer[/QUOTE]

I don't think this is very useful in a case like strncpy. A null
string or bogus length almost certainly indicate a program error
(rather than a data error), and putting in code to check your code for
errors is of limited use. If there's something wrong with your
program, how often can you recover? Why didn't you check the values
when they were calculated, instead of waiting until they were passed
to a library function? Would you really test the return value of
every str* function you called and do something sensible?

-- Richard
 
S

santosh

Ian, thank you for your reply.
Maybe this is the only solution with C.

The problem is an error code does not indicate what problem it is.
I can not return some text to indicate the problem,
for example 'the n argument must be a valid array index, >= 0 and <
size'

Of course this can be, though it may be considerable work. You can write
dedicated "converting" function that takes an error code and produces
the appropriate error message. Then a logging function can display this
howsoever it wishes.

Again the tricky thing is the design. Hitting upon an elegant, efficient
yet flexible design is not trivial. Once you have the detailed
blueprint, writing the code is relatively straightforward.

Once again C gives you the freedom to design this in many ways. The
selection has to be made by the programmer. A good book on general
software engineering like _Code Complete_ might be a good help in this
regard.
I have to write all these in the function document and wish the user
note them.

This is also essential for any serious code.
Another problem is some error code such as -1 can be a legal return
value.

In this case I separate the return value and the error value and return
both by separate channels.
Exception in C++ and Java is a elegant solution, i think.

They have their problems too.
 
M

Marc Boyer

When I call the standard strncpy function, I provide it a negative
argument,
such as:

strncpy(s, ct, -1)

I compile the code with gcc, when I run, it says "Segmentation fault".
Do you think it's ok? I try this to see how the library handle invalid
parameter.

First of all, from the strncpy function, there is no invalid
parameter. The '-1' is implicity converted into (size_t)-1, a
huge positive value.
When I define my own function, should I handle this kind of argument?
And if so, how can I tell the caller the argument is wrong?
Return some error code such as -1?
But how about the function return type is void?

I know in Java, I can define some invalid parameter exception to
indicate this.

But you also have to change the signature
void strncpy( ... ) throw InvalidParamter;
What can I do with C?

Error handling is a common pb in software...
There are several problems and strategies, and there are several kinds
of errors.

I personnaly makes a difference between 'external errors'
(malloc, fopen, strtoul failure) and 'programming error' (passing
a NULL pointer to strncpy).

There also have different strategies:
- return code
- global error code (like errno)
- loging and assert-like mechanisms
- exceptions

The questions are:
- where/how did you detect the error
- where/how did you signal the error
- where/how did you handle the error
and also
- how did you document the conditions


In C, return code and global error code are the most common tools
for external errors. There are more debates about assert. The same,
some consider setjmp / longjmp as a low-level exceptions mechanisms
(see http://ldeniau.web.cern.ch/ldeniau/oopc.html for example).

Personnaly, I consider that external errors should be handled with
return code (with the help of global error code) and assert-like for
programming errors. I have no strong opinion about setjmp/longjmp.

Marc Boyer
 
C

Chris Dollin

Marc said:
But you also have to change the signature
void strncpy( ... ) throw InvalidParamter;

(fx:OT) Not if InvalidParameter is a subclass of RuntimeException.
 
T

Tor Rustad

Lambda said:
When I call the standard strncpy function, I provide it a negative
argument,
such as:

strncpy(s, ct, -1)

I compile the code with gcc, when I run, it says "Segmentation fault".
Do you think it's ok? I try this to see how the library handle invalid
parameter.

It's not ok.
It's not ok.
It's not ok....never do buffer overflow C!

It's a meaningless test, you invoke UB when you read outside the range
of the 'ct' object, you invoke UB when you update outside the range of
the 's' object.

Note, (size_t) -1 wraps around, and is the maximum value an object of
type size_t can have.
When I define my own function, should I handle this kind of argument?

To avoid GIGO, we normally check the function parameters, validating
they are within allowed range.

You decide on your own, if these checks should be done run-time or only
in debug builds.
And if so, how can I tell the caller the argument is wrong?

A number of alternatives exists e.g.

1. assert() for program faults
2. return an error code
3. invoke your home build error function
4. terminate the program via exit() call
5. longjmp() - not recommended for beginners
Return some error code such as -1?

But how about the function return type is void?

void foo(int *error)

or

void foo(struct *param)

comes to mind.
I know in Java, I can define some invalid parameter exception to
indicate this.
What can I do with C?

Welcome to the real world, there is no VM here, just real machines. C
assume you know what you are doing, and you shouldn't use functions like
strncpy(), unless you know how it works.

C don't have exception handling, so you better get started without it,
doing it the C way, means propagating return codes all over the place.
 
C

Charlie Gordon

Lambda said:
When I call the standard strncpy function, I provide it a negative
argument,
such as:

strncpy(s, ct, -1)

I compile the code with gcc, when I run, it says "Segmentation fault".
Do you think it's ok? I try this to see how the library handle invalid
parameter.

strncpy does *not* do what you think it does.

Read the manual page for strncpy.

Until you understand what strncpy does, you should not use it.

When you understand the precise semantics of strncpy, you should realize
that it is very unlikely you will ever need to use this function. You may
think it is useful for limited string copy, but it is very error prone for
doing that, and almost always requires extra code.

If you want to do a limited string copy, consider BSD's strlcpy as defined
in http://www.openbsd.org/cgi-bin/man.cgi?query=strlcpy or
http://en.wikipedia.org/wiki/Strlcpy
 
C

Charlie Gordon

santosh said:
Here -1 is converted to the type size_t which is an unsigned integer.
Thus this actually results in strncpy receiving a very large positive
value. The segmentation fault is probably caused by strncpy trying to
read memory far beyond the legal limits.

Invoking strncpy with a size of -1 is almost guaranteed to cause undefined
behaviour of the worst kind. Segmentation fault is not unexpected.
Contrary to what you suggest, the crash is most likely caused by strncpy
trying to pad the destination with '\0' upto size (SIZE_MAX) thereby
attempting to write a huge chunk of memory (possibly larger than all
adressable memory) to which write access is unlikely to have been granted.

If you are not familiar with the semantics of strncpy, I urge you to read
the manual or the Standard.
 
S

santosh

Invoking strncpy with a size of -1 is almost guaranteed to cause
undefined
behaviour of the worst kind. Segmentation fault is not unexpected.
Contrary to what you suggest, the crash is most likely caused by
strncpy trying to pad the destination with '\0' upto size (SIZE_MAX)
thereby attempting to write a huge chunk of memory (possibly larger
than all adressable memory) to which write access is unlikely to have
been granted.

If you are not familiar with the semantics of strncpy, I urge you to
read the manual or the Standard.

Thanks! I stand corrected. You and Malcolm are in a class by
yourselves! :)
 
B

Ben Pfaff

Lambda said:
When I call the standard strncpy function, I provide it a negative
argument,
such as:

strncpy(s, ct, -1)

strncpy cannot have a negative third argument, because the third
parameter has an unsigned type. C specifies that -1 will be
converted to the maximum value of size_t, so that this call to
strncpy will likely try to overwrite all memory.

There is occasionally a good reason to use strncpy(). However:

* Using strncpy() into a large buffer can be very inefficient.
strncpy() always writes to every byte in the destination
buffer, which can waste a lot of time if the destination
buffer is much longer than the source string.

* If the source string is longer than the size of the
destination buffer, then strncpy() doesn't write a
terminating null. So a call to strncpy() must be followed
by explicitly writing a null terminator at the end of the
destination buffer in most cases.
 

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,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top