473,803 Members | 3,195 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

why the usage of gets() is dangerous.

Hi all,

Whenever I use the gets() function, the gnu c compiler gives a
warning that it is dangerous to use gets(). why...?

regards,
jayapal.
Nov 16 '07
104 5281
CBFalconer wrote, On 24/11/07 22:52:
$)CHarald van D)&k wrote:
>CBFalconer wrote:
>>So here is another. Imagine a routine to upshift a string. One
routine receives a char, and answere with 'this is lower case'.
Another receives a char, and answers by replacing it with the
upper case equivalent. Both are passed pointers.

Assuming the original data is a string, the calling routine will
pass something like:

p = &(s[3]); or p = s + 3; (p is parameter)

For the reading routine, there is no harm in allowing reads from
(p - n), where n can be 0 through 3. For the writing routine,
this is not allowable.
Why not? Is it because the behaviour would be undefined, or is
it because the function's actions would be different from its
description? If the former, I'm not seeing it, so could you
please explain? If the latter, as long as it's valid C, there's
no reason why an implementation would or should complain about
it.

Because a char was passed, not an array.
No, a pointer to char was passed, and that is a pointer to a byte within
a larger object.
So a means has to be
found to separate the two.
No, because C does not have a distinction between a pointer to an
element of an array and a pointer to a single object.
Remember that the system is pointless
unless it works all the time.
That is a good argument for getting rid of *all* safety features
everywhere. So go back to DOS because the memory protection in Windows
does not work all the time (otherwise we would not be talking about
whether fat pointers can improve protection), get rid of lifeboats from
cruise ships because sometimes they fail and so on. Not to mention your
ggets routine being pointless because it fails if someone feeds it a
line longer than it can successfully allocate memory for.
--
Flash Gordon
Nov 25 '07 #91
CBFalconer wrote:
Chris Torek wrote:
>Richard Bos <rl*@hoekstra-uitgeverij.nlwr ote:
>>... you do need to link fat-pointer-compiled object files with
fat-pointer-compiled libraries; much as you need to link 64-bit
object files with 64-bit libraries, little-endian object files
with little-endian libraries, and on MS-DOS used to link large
memory model object files with large memory model libraries.
... snip ...
>In general, the simplest method is to have all "fat pointers"
represented as a triple: <currentvalue , base, limit>. A pointer
is "valid" if its current-value is at least as big as its base
and no bigger than its limit:

Just picking on one thing, based on it has to work everywhere, or
it is useless.
We're talking about use of fat pointers as a device to protect against
memory bounds violation. Protection doesn't have to be perfect to be
useful. A bullet-proof vest won't protect against a head shot, washing
your hands before a meal won't protect you against airborne diseases,
the best available contraceptive measures still occasionally fail. That
doesn't make those protective measures useless.

A simple, relatively straightforward fat pointer implementation that is
only moderately inefficient can't protect against every possible
problem. It could protect against use of pointer arithmetic to create a
pointer to a position before the beginning, or more than one position
after the end, of the relevant array. It can also protect against any
attempt to access positions one past the end of the array. Providing
more complete protection requires a more complicated or inefficient
mechanism; but that doesn't make the simpler protection mechanism useless.

....
I have made my share of mistakes in code-generation, and I want
things simple and consistent.
Fat pointers are not as simple to implement as ordinary pointers, and I
would imagine that retrofitting an implementation originally designed to
use ordinary pointers would be a bug-prone process. However, it's
nowhere near to being the most complicated feature that real C compilers
have implemented successfully.
Nov 25 '07 #92

"Chris Torek" <no****@torek.n etwrote in message
>When dealing with pointers to objects embedded within larger objects
(such as elements of "struct"s), the simplest method is again to
widen the base-and-limit to encompass the large object. Consider,
e.g.:

% cat derived.c
#include "base.h"
struct derived {
struct base common;
int additional;
};
void basefunc(struct base *, void (*)(struct base *)); /* in base.c */
static void subfunc(struct base *);
void func(void) {
struct derived var;
...
basefunc(&var.c ommon, subfunc);
...
}
static void subfunc(struct base *p0) {
struct derived *p = (struct derived *)p0; /* line X */
... use p->common and p->additional here ...
}
>There is clearly no problem in the call to basefunc(), even if we
"narrow" the "fat pointer" to point only to the sub-structure
&var.common. However, when basefunc() "calls back" into subfunc(),
as presumably it will, with a "fat pointer" to the "common" part
of a "struct derived", we will have to "re-widen" the pointer. We
can do that at the point of the cast (line X), or simply avoid
"narrowing" the fat pointer at the call to basefunc(), so that when
basefunc() calls subfunc(), it passes a pointer to the entire
structure "var", rather than just var.common.
(It is probably the case, not that I have thought about it that
much, that we can pass only the "fully widened to entire object"
pointer if we are taking the address of the *first* element of
the structure. That is, C code of the form:

You've missed the problem

struct gandma
{
struct mother first[3];
int x;
};

struct mother
{
char child[3];
int x;
};

struct grandma grannies[3];

char *fatkid = &grannies[1].first[1].child;
/* fatkid ought to have bounds between child and child + 3 */

struct grandma *fatoldlady = (struct grandma *) fatkid;
/* fat old lady points tot he middle of an array, it needs bounds
grannies[0] to
grannies[2] */

It's hard to supoort this
You need a "mother pointer" to give the bounds of the containing structure,
purely to support upcasts. That can have its own mother pointer. All in all,
too much trouble purely to support one little-used construct.

struct fatpointer{
void *base;
void *upper;
void *ptr;
struct fatpointer *mother;
};

The real answer is to ban subtractions or additions to upcast pointers.
--
Free games and programming goodies.
http://www.personal.leeds.ac.uk/~bgy1mm

Nov 25 '07 #93
James Kuyper wrote:
CBFalconer wrote:
>Chris Torek wrote:
>>Richard Bos <rl*@hoekstra-uitgeverij.nlwr ote:

... you do need to link fat-pointer-compiled object files with
fat-pointer-compiled libraries; much as you need to link 64-bit
object files with 64-bit libraries, little-endian object files
with little-endian libraries, and on MS-DOS used to link large
memory model object files with large memory model libraries.
... snip ...
>>In general, the simplest method is to have all "fat pointers"
represented as a triple: <currentvalue , base, limit>. A pointer
is "valid" if its current-value is at least as big as its base
and no bigger than its limit:

Just picking on one thing, based on it has to work everywhere, or
it is useless.

We're talking about use of fat pointers as a device to protect against
memory bounds violation. Protection doesn't have to be perfect to be
useful. A bullet-proof vest won't protect against a head shot, washing
your hands before a meal won't protect you against airborne diseases,
the best available contraceptive measures still occasionally fail. That
doesn't make those protective measures useless.

A simple, relatively straightforward fat pointer implementation that is
only moderately inefficient can't protect against every possible
problem. It could protect against use of pointer arithmetic to create a
pointer to a position before the beginning, or more than one position
after the end, of the relevant array. It can also protect against any
attempt to access positions one past the end of the array. Providing
more complete protection requires a more complicated or inefficient
mechanism; but that doesn't make the simpler protection mechanism useless.

...
>I have made my share of mistakes in code-generation, and I want
things simple and consistent.

Fat pointers are not as simple to implement as ordinary pointers, and I
would imagine that retrofitting an implementation originally designed to
use ordinary pointers would be a bug-prone process. However, it's
nowhere near to being the most complicated feature that real C compilers
have implemented successfully.
I think my major point is that, wherever I look, I see continuously
building auxiliary data combined with cpu-eating indirect pointer
accesses.

I also maintain that it has to work all the time. Otherwise the
fact that it passes gives one no confidence whatsoever, and the odd
pass just encourages ignoring the real problem. How many time do
you hear 'It works on my machine' as the excuse/justification for
poor code?

--
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home .att.net>
Try the download section.

--
Posted via a free Usenet account from http://www.teranews.com

Nov 25 '07 #94
Flash Gordon wrote:
CBFalconer wrote, On 24/11/07 22:52:
>$)CHarald van D)&k wrote:
>>CBFalconer wrote:

So here is another. Imagine a routine to upshift a string. One
routine receives a char, and answere with 'this is lower case'.
Another receives a char, and answers by replacing it with the
upper case equivalent. Both are passed pointers.

Assuming the original data is a string, the calling routine will
pass something like:

p = &(s[3]); or p = s + 3; (p is parameter)

For the reading routine, there is no harm in allowing reads from
(p - n), where n can be 0 through 3. For the writing routine,
this is not allowable.

Why not? Is it because the behaviour would be undefined, or is
it because the function's actions would be different from its
description ? If the former, I'm not seeing it, so could you
please explain? If the latter, as long as it's valid C, there's
no reason why an implementation would or should complain about
it.

Because a char was passed, not an array.

No, a pointer to char was passed, and that is a pointer to a byte
within a larger object.
>So a means has to be found to separate the two.

No, because C does not have a distinction between a pointer to an
element of an array and a pointer to a single object.
Exactly. So the only way to pass that distinction is through the
pointer. This involves revising the pointer on every pass. The
data builds and builds, as does the overhead. Don't forget that
the old pointer must be retained, because the called routine will
presumably return.

--
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home .att.net>
Try the download section.

--
Posted via a free Usenet account from http://www.teranews.com

Nov 25 '07 #95

"CBFalconer " <cb********@yah oo.comwrote in message
I think my major point is that, wherever I look, I see continuously
building auxiliary data combined with cpu-eating indirect pointer
accesses.

I also maintain that it has to work all the time. Otherwise the
fact that it passes gives one no confidence whatsoever, and the odd
pass just encourages ignoring the real problem. How many time do
you hear 'It works on my machine' as the excuse/justification for
poor code?
A wild pointer read, write or even calculation renders the program
undefined. Undefined by the C standard, that is, not in some philosphical
state of undefinedness.
If we define it as always printing out to stderr an error message, and
terminating, rather than doing something funny, like corrupting an
instruction in an unrelatred part of the program, or appearing to work as
intended, it is much easiser for a debugger to catch bugs.
The tool is far more useful if it catches every case. However this cannot be
achieved in practise. For instance a recent bug in our code - actually
written in Fortran, went

double energy[12]; /* set up to statistical free energy levels */

for(i=0;i<12;i+ +)
if(theta erange[i] && theta <= erange[i+1])
index = i;

totenergy += energy[index];

of course if theta is not in any of the ranges, UB will result. However the
ranges went from 0 degrees to 160 degrees, and you tend not to get straight
bonds. So it could run for some time until the calculation went wrong.

After a few debug passes, you run code for real with thin pointers. The
runtime overhead is acceptable for some applications, but not the ones C
tends to be used for.
--
Free games and programming goodies.
http://www.personal.leeds.ac.uk/~bgy1mm

Nov 25 '07 #96
CBFalconer wrote:
James Kuyper wrote:
>CBFalconer wrote:
....
>>Just picking on one thing, based on it has to work everywhere, or
it is useless.
We're talking about use of fat pointers as a device to protect against
memory bounds violation. Protection doesn't have to be perfect to be
useful. A bullet-proof vest won't protect against a head shot, ...
....
I think my major point is that, wherever I look, I see continuously
building auxiliary data combined with cpu-eating indirect pointer
accesses.
That depends upon your concept that it has to be a perfect to be useful.
Embrace the fact that it can still be useful if imperfect, and a much
simpler implementation becomes possible that merely seriously impairs
efficiency, rather than completely destroying it.

All that's needed to provide substantial protection is pointers that
carry a base address, an end address, and a current address, and a
compiler that sets those addresses appropriately whenever an expression
has a value of pointer type.
I also maintain that it has to work all the time. Otherwise the
fact that it passes gives one no confidence whatsoever, and the odd
pass just encourages ignoring the real problem.
By the same logic, to apply my previous analogy, a bullet proof vest has
to work against all bullets, or it's useless. If it doesn't it gives you
no confidence whatsoever that you are safe from bullets, and the odd
pass just encourages ignoring the real problem, which is that people are
shooting at you. That's a clearly ridiculous argument; and the reason is
the logic, not the analogy.

The fat pointers we're discussing aren't supposed to give you confidence
that your code has no errors. They're supposed to help you detect
certain kinds of errors, so you can deal with them. The fact that they
can't catch all possible errors is perfectly normal for error detection
techniques.
Nov 26 '07 #97
CBFalconer wrote, On 25/11/07 16:20:
Flash Gordon wrote:
>CBFalconer wrote, On 24/11/07 22:52:
>>$)CHarald van D)&k wrote:
CBFalconer wrote:

So here is another. Imagine a routine to upshift a string. One
routine receives a char, and answere with 'this is lower case'.
Another receives a char, and answers by replacing it with the
upper case equivalent. Both are passed pointers.
>
Assuming the original data is a string, the calling routine will
pass something like:
>
p = &(s[3]); or p = s + 3; (p is parameter)
>
For the reading routine, there is no harm in allowing reads from
(p - n), where n can be 0 through 3. For the writing routine,
this is not allowable.
Why not? Is it because the behaviour would be undefined, or is
it because the function's actions would be different from its
descriptio n? If the former, I'm not seeing it, so could you
please explain? If the latter, as long as it's valid C, there's
no reason why an implementation would or should complain about
it.
Because a char was passed, not an array.
No, a pointer to char was passed, and that is a pointer to a byte
within a larger object.
>>So a means has to be found to separate the two.
No, because C does not have a distinction between a pointer to an
element of an array and a pointer to a single object.

Exactly. So the only way to pass that distinction is through the
pointer.
No, the only way is to accept that there is no distinction.
This involves revising the pointer on every pass.
No, it involves passing exactly the same data all the way down.
The
data builds and builds, as does the overhead. Don't forget that
the old pointer must be retained, because the called routine will
presumably return.
I honestly cannot see what you are getting at. However many functions
the pointer is passed through there is no additional overhead because it
is always valid to access any part of the parent object. Anything else
and you are talking about how useful fat pointers would be for a
language other than C, and no one else is talking about anything other
than what a conforming C implementation could do.
--
Flash Gordon
Nov 26 '07 #98

"James Kuyper" <ja*********@ve rizon.netwrote in message
By the same logic, to apply my previous analogy, a bullet proof vest has
to work against all bullets, or it's useless. If it doesn't it gives you
no confidence whatsoever that you are safe from bullets, and the odd pass
just encourages ignoring the real problem, which is that people are
shooting at you. That's a clearly ridiculous argument; and the reason is
the logic, not the analogy.
If a competing vest offers 100% protection then your vest, offering 99%,
will need to be very much cheaper indeed before it will find a market.
However in the absence of anything better, even 50% protection is much
better than nothing.

--
Free games and programming goodies.
http://www.personal.leeds.ac.uk/~bgy1mm

Nov 26 '07 #99
Flash Gordon wrote:
CBFalconer wrote:
>Flash Gordon wrote:
.... snip ...
>>
>>No, because C does not have a distinction between a pointer to
an element of an array and a pointer to a single object.

Exactly. So the only way to pass that distinction is through
the pointer.

No, the only way is to accept that there is no distinction.
>This involves revising the pointer on every pass.

No, it involves passing exactly the same data all the way down.
>The data builds and builds, as does the overhead. Don't forget
that the old pointer must be retained, because the called
routine will presumably return.

I honestly cannot see what you are getting at. However many
functions the pointer is passed through there is no additional
overhead because it is always valid to access any part of the
parent object. Anything else and you are talking about how useful
fat pointers would be for a language other than C, and no one
else is talking about anything other than what a conforming C
implementation could do.
Just as an example, imagine some idiot designed a function that
operated on two strings known to be stored DIFF bytes apart. That
function is passed a single pointer, as in:

char foo(char *bar) {
char ch;

if (islower(*bar)) *(bar + DIFF) = toupper(*bar);
else *(bar + DIFF) = *bar;
/* now exchange chars */
ch = *bar; *bar = *(bar + DIFF); *(bar + DIFF) = ch;
return ch;
} /* foo */

Now this silly function has a name that makes it seem to upshift
chars in a string. It passes all tests, because of the use of the
magic value of DIFF. Somebody procedes to use it again. All sorts
of things blow up. The function is ignored, because it passes the
tests in the original, and it is in a library, and never got
recompiled. Don't forget that it has been stamped as VALIDATED in
upper case.

I don't want this form of 'checking'.

NOTE: I am pulling up various weird code to show that there are
problems. I have not tried for any consistency.

--
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home .att.net>
Try the download section.

--
Posted via a free Usenet account from http://www.teranews.com

Nov 26 '07 #100

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

48
2743
by: Michael Sig Birkmose | last post by:
Hi everyone! Does anyone know, if it is possible to meassure the maximum stack usage of a C program throughout it's entire execution? -- Michael Birkmose
302
18623
by: Lee | last post by:
Hi Whenever I use the gets() function, the gnu c compiler gives a warning that it is dangerous to use gets(). Is this due to the possibility of array overflow? Is it correct that the program flow can be altered by giving some specific calculated inputs to gets()? How could anyone do so once the executable binary have been generated? I have heard many of the security problems and other bugs are due to array overflows.
89
6087
by: Cuthbert | last post by:
After compiling the source code with gcc v.4.1.1, I got a warning message: "/tmp/ccixzSIL.o: In function 'main';ex.c: (.text+0x9a): warning: the 'gets' function is dangerous and should not be used." Could anybody tell me why gets() function is dangerous?? Thank you very much. Cuthbert
0
10542
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10309
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10289
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
10068
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
9119
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
6840
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5625
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4274
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3795
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.