problems with sprintf...

Y

Yodai

Hi all....

I have a little problem that's driving me nuts. I can't seem to make any
sense of it. I have this small webserver that substitutes some data from a
page when finds a substitution string. I all works fine, even the sprintf,
when I write numbers. But if I want to write a character string, it all goes
wrong.
I am trying to print "over" on the pointer Key on a function that looks
like this (this is only an extract of the real one, which is much larger).
While I print floats or integers there's no problem, even if I write a small
string with a couple characters like "/bm" works fine. But when I get to the
case 'c' it displays a 5 digit number, always the same, and then my string.


unsigned char *Key;
unsigned char NewKey[25];
unsigned int i;

if (TCPTxDataCount < 4) return;

Key = TCP_TX_BUF;

for (i = 0; i < (TCPTxDataCount - 2); i++)
{
if (*Key == '¿')
{
if (*(Key + 1) == '?')
{
switch (*(Key + 2))
{
case 'a' :
{
sprintf(NewKey, "%4.2f", Func_returning_a_float());
memcpy(Key, NewKey, 5);
break;
}
case 'b' :
{
if (Get_conditional_function() == 0xAFAF)
{
sprintf(NewKey, "%4.3f", Float_number_1());
memcpy(Key, NewKey, 4);
break;
}
else
{
sprintf(NewKey, "%4.3f%s", float_num_2(), "/bm");
memcpy(Key, NewKey, 7);
break;
}
/* up until here it all works smoothly. */
case 'c' :
{
sprintf(NewKey, "%s", "over");
memcpy(Key, NewKey, 4);
break;
}

/* if I reset the amount of data to be copied to Key from 4 to, lets say,
20, I get a 7 digit number, always the same, and then my string....
something like: "20.7570over"


Any idea of what's going on? I thought I was using sprintf correctly, but it
seems it doesn't want to work with characters....


Cheers!

Yodai
 
Y

Yodai

If someone sees the problem and feels like answering, feel free. But I
arranged the problem changing the switch caracters. I still don't know what
was failing, but I had one of those lucky strikes
I-don't-know-how-I-did-it-but-it-works....

Yodai
 
D

Dan Pop

In said:
I am trying to print "over" on the pointer Key on a function that looks
like this (this is only an extract of the real one, which is much larger).
While I print floats or integers there's no problem, even if I write a small
string with a couple characters like "/bm" works fine. But when I get to the
case 'c' it displays a 5 digit number, always the same, and then my string.


unsigned char *Key;
unsigned char NewKey[25];
unsigned int i;

if (TCPTxDataCount < 4) return;

Key = TCP_TX_BUF;

for (i = 0; i < (TCPTxDataCount - 2); i++)
{
if (*Key == '¿')
{
if (*(Key + 1) == '?')
{
switch (*(Key + 2))
{
case 'a' :
{
sprintf(NewKey, "%4.2f", Func_returning_a_float());
memcpy(Key, NewKey, 5);
break;
}
case 'b' :
{
if (Get_conditional_function() == 0xAFAF)
{
sprintf(NewKey, "%4.3f", Float_number_1());
memcpy(Key, NewKey, 4);
break;
}
else
{
sprintf(NewKey, "%4.3f%s", float_num_2(), "/bm");
memcpy(Key, NewKey, 7);
break;
}
/* up until here it all works smoothly. */
case 'c' :
{
sprintf(NewKey, "%s", "over");
memcpy(Key, NewKey, 4);
break;
}

/* if I reset the amount of data to be copied to Key from 4 to, lets say,
20, I get a 7 digit number, always the same, and then my string....
something like: "20.7570over"


Any idea of what's going on? I thought I was using sprintf correctly, but it
seems it doesn't want to work with characters....

I suspect the problem is memory corruption occuring elsewhere in your
program. Put the above code into the main function, along with the
missing bits necessary to turn it into a complete program and see what
happens.

Dan
 
D

Daniel Haude

On Tue, 13 Jan 2004 10:12:40 GMT,
Yodai said:
Hi all....

I have a little problem that's driving me nuts. I can't seem to make any
sense of it. I have this small webserver that substitutes some data from a
page when finds a substitution string. I all works fine, even the sprintf,
when I write numbers. But if I want to write a character string, it all goes
wrong.

While I can't see right away what causes your code to behave the way it
does, here a few tips:

1) When using sprintf() you run the risk of buffer overflow unless you
can make absolutely sure that no possible argument value can cause an
overflow. It's better to use snprintf() if you have it.

2) The string literal "over" requires 5 bytes, not 4 (but that doesn't
seem to be your problem here). Related note: Replace the calls to memcpy
with strcpy which always takes care of the trailing zero. And make sure
that Key is big enouch to hold the data *in all cases*.
string with a couple characters like "/bm" works fine. But when I get to the
case 'c' it displays a 5 digit number, always the same, and then my string.

What does 'it displays' mean? There is no code in your snippet that
displays anything. The code you posted seems to put the right thing into
NewKey, but NewKey might get corrupted someplace else.

You're experiencing a classic case of Undefined Behaviour. The more
difficult it is to track the mistake, the more embarrasing it usually is
when you finally find it ;-)
case 'c' :
{
sprintf(NewKey, "%s", "over");
memcpy(Key, NewKey, 4);
break;
}
Any idea of what's going on? I thought I was using sprintf correctly, but it
seems it doesn't want to work with characters....

Just for giggles... Have you tried strcpy(Key, "over")? Should accomplish
the exact same thing. But yes, you're using sprintf correctly.

--Daniel
 
D

Daniel Haude

On Tue, 13 Jan 2004 10:33:47 GMT,
Yodai said:
If someone sees the problem and feels like answering, feel free. But I
arranged the problem changing the switch caracters. I still don't know what
was failing, but I had one of those lucky strikes
I-don't-know-how-I-did-it-but-it-works....

I'm tempted to think that you're still having UB, only now it happens to
behave the way you expect... for a while... until you change something
someplace and everything goes haywire again.

Has happened many times to me (and to everybody else on this ng, I
daresay).

--Daniel
 
Y

Yodai

Yup.... but I just found the reason... It belonged to another part of the
program where I was forcing to execute 2 different switch under the same
if,else, giving only once the instruction key++, thus, only allowing one of
my switch to advance forward.....

Cheers...

Yodai
 
D

David Resnick

Yodai said:
Hi all....

I have a little problem that's driving me nuts. I can't seem to make any
sense of it. I have this small webserver that substitutes some data from a
page when finds a substitution string. I all works fine, even the sprintf,
when I write numbers. But if I want to write a character string, it all goes
wrong.
I am trying to print "over" on the pointer Key on a function that looks
like this (this is only an extract of the real one, which is much larger).
While I print floats or integers there's no problem, even if I write a small
string with a couple characters like "/bm" works fine. But when I get to the
case 'c' it displays a 5 digit number, always the same, and then my string.


unsigned char *Key;
unsigned char NewKey[25];
unsigned int i;

if (TCPTxDataCount < 4) return;

Key = TCP_TX_BUF;

for (i = 0; i < (TCPTxDataCount - 2); i++)
{
if (*Key == '¿')
{
if (*(Key + 1) == '?')
{
switch (*(Key + 2))
{
case 'a' :
{
sprintf(NewKey, "%4.2f", Func_returning_a_float());
memcpy(Key, NewKey, 5);
break;
}
case 'b' :
{
if (Get_conditional_function() == 0xAFAF)
{
sprintf(NewKey, "%4.3f", Float_number_1());
memcpy(Key, NewKey, 4);
break;
}
else
{
sprintf(NewKey, "%4.3f%s", float_num_2(), "/bm");
memcpy(Key, NewKey, 7);
break;
}
/* up until here it all works smoothly. */
case 'c' :
{
sprintf(NewKey, "%s", "over");
memcpy(Key, NewKey, 4);
break;
}

/* if I reset the amount of data to be copied to Key from 4 to, lets say,
20, I get a 7 digit number, always the same, and then my string....
something like: "20.7570over"


Any idea of what's going on? I thought I was using sprintf correctly, but it
seems it doesn't want to work with characters....


Cheers!

Yodai

You aren't allowing for copying the terminating NUL character with your
memcpy. To copy "over", you need to copy 5 bytes. Note that your
stringified floats will often not be copied in full, and the string
won't be terminated if they are not... %4.2f says minimum field
width 4, max precision of 2 digits after the decimal point.

e.g. 100.4567 -> sprintf("%4.2f",...) -> 100.45

Which takes 7 bytes as a string... If you aren't worried
about efficiency you could use strcpy, though you then must make
sure you don't exceed the bounds of your target array. Or you
could use snprintf if you have C99/compiler extensions to
restrict the number of bytes in the string. From the code above,
you also could perhaps sprintf straight into your Key as well.

-David
 
A

Alex

David Resnick said:
Note that your stringified floats will often not be copied in full,
and the string won't be terminated if they are not...

sprintf() never creates an unterminated string.
 
D

Default User

Yodai wrote:

Please don't top-post. Your replies belong following properly trimmed
quotes.
If someone sees the problem and feels like answering, feel free. But I
arranged the problem changing the switch caracters. I still don't know what
was failing, but I had one of those lucky strikes
I-don't-know-how-I-did-it-but-it-works....


I don't know that I would call it lucky. You've been successful at
shotgun debugging.

shotgun debugging
n. The software equivalent of Easter egging; the making of relatively
undirected changes to software in the hope that a bug will be perturbed
out of existence. This almost never works, and usually introduces more
bugs.


You did manage to perturb your bug temporarily. However, rearranging
case elements is not likely to fix anything, just cover it up. The sort
of problem you describe, and the "fix" often points toward problems with
automatic storage, "whacking the stack" or some equivalent. Likely some
code is overwriting other elements. By changing the order, you change
with gets clobbered, and now it isn't the thing you could see before.

In some ways, you've gone from bad to worse. Before, you at least had an
indication that things were wrong and approximately where. Now it
probably lurking under the surface, waiting for you to make another
change or add something, so it can bite you in a new place.




Brian Rodenborn
 
A

Alan Balmer

If someone sees the problem and feels like answering, feel free. But I
arranged the problem changing the switch caracters. I still don't know what
was failing, but I had one of those lucky strikes
I-don't-know-how-I-did-it-but-it-works....
No, it doesn't. It just misbehaves in a different way, that you
haven't seen yet. "Fixes" like this often produce programs which work
only until a customer uses them.

What you should do now is put the code back the way it was, and find
the real problem. Then look for the same problem in the rest of the
program, because you've probably done it more than once.
 
D

David Resnick

Alex said:
sprintf() never creates an unterminated string.

Yep, even if does a buffer overrun to do so. I wasn't saying that,
I was talking about the memcpy. If you memcpy part of a string generated
with sprintf, you won't get the termination...

-David
 
D

Darrell Grainger

Hi all....

I have a little problem that's driving me nuts. I can't seem to make any
sense of it. I have this small webserver that substitutes some data from a
page when finds a substitution string. I all works fine, even the sprintf,
when I write numbers. But if I want to write a character string, it all goes
wrong.
I am trying to print "over" on the pointer Key on a function that looks
like this (this is only an extract of the real one, which is much larger).
While I print floats or integers there's no problem, even if I write a small
string with a couple characters like "/bm" works fine. But when I get to the
case 'c' it displays a 5 digit number, always the same, and then my string.


unsigned char *Key;
unsigned char NewKey[25];
unsigned int i;

if (TCPTxDataCount < 4) return;

What is the significance of 4 here? You might want to use a const or
something. If I had to take over your code I'd end up wasting a lot of
time figuring out little things like this.
Key = TCP_TX_BUF;

for (i = 0; i < (TCPTxDataCount - 2); i++)

The variable i is an unsigned int. Do you know what will happen if
TCPTxDataCount is 0, 1 or 2? What does i < -2 means when i is unsigned?
{
if (*Key == '¿')

Failed to see if Key is NULL before dereferencing it. If Key == NULL then
you want to abort this whole thing.

/* inside if statement #1 */
if (*(Key + 1) == '?')
{

/* inside if statement #2 */
switch (*(Key + 2))
{

/* inside switch statement */
case 'a' :
{

/* inside case a block */
sprintf(NewKey, "%4.2f", Func_returning_a_float());
memcpy(Key, NewKey, 5);

Why the magic number 5?

/* outside case a block */
case 'b' :
{

/* inside case b block */
if (Get_conditional_function() == 0xAFAF)
{

/* inside if statement #3 */
sprintf(NewKey, "%4.3f", Float_number_1());
memcpy(Key, NewKey, 4);
break;
}

/* outside if statement #3 */


/* inside else statement associated with if #3 */
sprintf(NewKey, "%4.3f%s", float_num_2(), "/bm");
memcpy(Key, NewKey, 7);

Why the magic number 7?

/* outside else statement, but still in case b */
/* up until here it all works smoothly. */

You are about to define case c but you have not closed off the case b
block.
case 'c' :
{
sprintf(NewKey, "%s", "over");
memcpy(Key, NewKey, 4);

Why the magic number 4?
break;
}

/* if I reset the amount of data to be copied to Key from 4 to, lets say,
20, I get a 7 digit number, always the same, and then my string....
something like: "20.7570over"

Maybe you are using memcpy wrong? If I have the data:

char NewKey[] = "over";

then the size of NewKey is 5. This is more obvious if I write it as:

char NewKey[] = { 'o', 'v', 'e', 'r', '\0' };
Any idea of what's going on? I thought I was using sprintf correctly, but it
seems it doesn't want to work with characters....

I saw your message indicating that the problem went away. If you don't
know why something was failing and why it started working again, then you
know nothing. It APPEARS to be working.

In real life development the odds of this attitude working are against
you. You do some testing and it looks like it works. Maybe one other
developers will test your code. Someone from integration and system
testing will look at it. Maybe even a dozen people will go over it during
the software development life cycle. We round up to the nearest 10 and say
that 20 people have tried it and it appears to work. You then release it
to the market and 10,000 people try it within the first week. I bet you
10,000 people using it will find that bug you are missing.
 
Y

Yodai

hey.! thank's for the post....... it WAS helpful.... I posted above the
solution to my problem which I finally found out....

Yodai
 

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,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top