Type safety

A

aarklon

In the article http://en.wikipedia.org/wiki/Type_safety

it is written as

The archetypal type-unsafe language is C because (for example) it is
possible for an integer to be viewed as a function pointer, which can
then be jumped to and executed, causing errors such as segmentation
faults, or (more insidiously) silent failures.

Even though the semantics of the C language explicitly allow for these
violations of the type system (indeed, it can be critical for the
performance of operating systems to be written in type-unsafe
languages) the language never defines what should happen when,
for example, a floating-point value is treated as a pointer.

now my question is can anybody give examples/explanations for this
 
D

deibit

El Fri, 24 Feb 2006 09:20:28 -0800, aarklon escribió:
Even though the semantics of the C language explicitly allow for these
violations of the type system (indeed, it can be critical for the
performance of operating systems to be written in type-unsafe
languages) the language never defines what should happen when,
for example, a floating-point value is treated as a pointer.

now my question is can anybody give examples/explanations for this



int main()
{
int a = 0xFFFFFF ;

void (*p)() = (void(*)()) a;


p();

return 0;
}
 
A

Andrey Tarasevich

In the article http://en.wikipedia.org/wiki/Type_safety

it is written as

The archetypal type-unsafe language is C because (for example) it is
possible for an integer to be viewed as a function pointer, which can
then be jumped to and executed, causing errors such as segmentation
faults, or (more insidiously) silent failures.

Even though the semantics of the C language explicitly allow for these
violations of the type system (indeed, it can be critical for the
performance of operating systems to be written in type-unsafe
languages) the language never defines what should happen when,
for example, a floating-point value is treated as a pointer.

now my question is can anybody give examples/explanations for this

Well, the article is a bit misleading. For an unprepared reader it might
create an impression of C language allowing implicit use of an integer
value in a function pointer context, which is not the case. In many
cases one can definitely work around the C type-control system without
using explicit cast (for example, but relying on the implicit "to void*"
and "from void*" pointer conversions), but it is normally not a one-step
process.

The truth is C language merely provides certain means for performing
these violations of the type system. Using these means in the program
still requires a conscious effort from the user in most cases,
especially when it comes to mixing values from the realm of "data" and
values from the realm of "code" (as in the above "integer as function
pointer" example).
 
K

Keith Thompson

In the article http://en.wikipedia.org/wiki/Type_safety

it is written as

The archetypal type-unsafe language is C because (for example) it is
possible for an integer to be viewed as a function pointer, which can
then be jumped to and executed, causing errors such as segmentation
faults, or (more insidiously) silent failures.

Even though the semantics of the C language explicitly allow for these
violations of the type system (indeed, it can be critical for the
performance of operating systems to be written in type-unsafe
languages) the language never defines what should happen when,
for example, a floating-point value is treated as a pointer.

This is largely nonsense. It is not possible to treat an integer as a
function pointer unless you *explicitly* convert it (the result of the
conversion is implementation-defined). The language doesn't allow
conversions from floating-point to poitner types, either implicitly or
explicitly.
 
J

Jordan Abel

Well, the article is a bit misleading. For an unprepared reader it might
create an impression of C language allowing implicit use of an integer
value in a function pointer context, which is not the case. In many
cases one can definitely work around the C type-control system without
using explicit cast (for example, but relying on the implicit "to void*"
and "from void*" pointer conversions), but it is normally not a one-step
process.

The truth is C language merely provides certain means for performing
these violations of the type system. Using these means in the program
still requires a conscious effort from the user in most cases,
especially when it comes to mixing values from the realm of "data" and
values from the realm of "code" (as in the above "integer as function
pointer" example).

Yeah - And _especially_ in that case, you can't do it by accident - In
fact, it requires syntax that I had to look up: ((int(*)())42)() - and
none of those parentheses are redundant - leave out any pair and it
wont' compile. [well, if you leave out the rightmost pair, it simply
won't attempt to make a function call, i guess] That amount of required
effort to get it to work certainly requires some level of intent.
 
G

gene.ressler

The language doesn't allow conversions from floating-point to poitner types, either implicitly or explicitly.

What?

float x = 1.0f;
void *p = *((void**)&x);
 
B

Ben Pfaff

What?

float x = 1.0f;
void *p = *((void**)&x);

There's no conversion from a floating-point to pointer type
there. There's a conversion from pointer-to-float type to
pointer-to-pointer-to-void type. Dereferencing that pointer
doesn't cause a conversion. Typically, it causes
reinterpretation of bits, but its effect is formally undefined as
stated by C99 6.5 "Expressions":

7 An object shall have its stored value accessed only by an
lvalue expression that has one of the following types:73)
- a type compatible with the effective type of the object,
- a qualified version of a type compatible with the
effective type of the object,
- a type that is the signed or unsigned type corresponding
to the effective type of the object,
- a type that is the signed or unsigned type corresponding
to a qualified version of the effective type of the
object,
- an aggregate or union type that includes one of the
aforementioned types among its members (including,
recursively, a member of a subaggregate or contained
union), or
- a character type.
 
M

Malcolm

Keith Thompson said:
This is largely nonsense. It is not possible to treat an integer as a
function pointer unless you *explicitly* convert it (the result of the
conversion is implementation-defined). The language doesn't allow
conversions from floating-point to poitner types, either implicitly or
explicitly.
One of the design decisions in C was to allow the programmer to examine the
bit representation of data in memory.
It is an inherent property of a digital computer that the bits of any type
can be reinterpreted as any other type.
C does have a few weak protections against the programmer doing this
inadvertently, but they are fairly easy to circumvent. Often it is a good
idea.

For instance, if I know that on my machine ROM routines are from addresses
0x8000 upwards, then by examining the bits of a function pointer I can tell
if it points to a function in RAM or in ROM. That might be useful to know.
 
N

Nick Keighley

In the article http://en.wikipedia.org/wiki/Type_safety

it is written as

The archetypal type-unsafe language is C because (for example) it is
possible for an integer to be viewed as a function pointer, which can
then be jumped to and executed, causing errors such as segmentation
faults, or (more insidiously) silent failures.

Even though the semantics of the C language explicitly allow for these
violations of the type system (indeed, it can be critical for the
performance of operating systems to be written in type-unsafe
languages) the language never defines what should happen when,
for example, a floating-point value is treated as a pointer.

now my question is can anybody give examples/explanations for this
 
R

Robin Haigh

Jordan Abel said:
Well, the article is a bit misleading. For an unprepared reader it might
create an impression of C language allowing implicit use of an integer
value in a function pointer context, which is not the case. In many
cases one can definitely work around the C type-control system without
using explicit cast (for example, but relying on the implicit "to void*"
and "from void*" pointer conversions), but it is normally not a one-step
process.

The truth is C language merely provides certain means for performing
these violations of the type system. Using these means in the program
still requires a conscious effort from the user in most cases,
especially when it comes to mixing values from the realm of "data" and
values from the realm of "code" (as in the above "integer as function
pointer" example).

Yeah - And _especially_ in that case, you can't do it by accident - In
fact, it requires syntax that I had to look up: ((int(*)())42)() - and
none of those parentheses are redundant - leave out any pair and it
wont' compile. [well, if you leave out the rightmost pair, it simply
won't attempt to make a function call, i guess] That amount of required
effort to get it to work certainly requires some level of intent.


But the easy way to treat an integer as a function pointer is to run off the
end of an array, and thus write an integer where a function pointer is
supposed to be.

It's not really about what the standard authorises, it's about what
compilers are able or unable to prevent, by virtue of the language design
and syntax. Strictly conforming C is necessarily type-safe, but the
compiler can't check that code is strictly conforming. In code that's
merely intended to be C, another very easy way to implicitly treat an
integer as a pointer, for instance, is to forget an & when calling scanf.

Undefined behaviour of course, but the point of type safety would be to get
good undefined behaviour -- compilation error or at worst a run-time trap --
rather than bad undefined behaviour.


To get the kind of type safety defined in the article, which comes from an
abstract computer-science perspective, you would have to prevent buffer
overruns, prevent reaching the end of a non-void function, prevent reading
of uninitialised data, keep track of the type associated with dynamic
storage, eliminate variadic functions, etc etc etc.

There are good reasons why C doesn't do this stuff. This is why we like it.
But a few dodgy casts aren't the beginning of C's lack of type safety
(unless you have a much narrower definition of type safety) -- they're just
extras thrown in on the grounds that it's already hopeless so it hardly
matters.


To go back to the OPs request for an example, here's one:

#include <math.h>
struct st {
double x[1];
double (*func)(double);
};
int main (void) {
struct st s;
s.func = sqrt;
s.x[0] = 1.0;
s.x[1] = 33.7; /* bad */
(void)s.func(s.x[0]);
return 0;
}

By writing off the end of the array, I've probably scribbled over the
function pointer, which I then call through, regardless.
Gcc -ansi -pedantic -Wall compiles this without warnings, and there's no
guarantee that the run-time error will be trapped before anything bad
happens.

Granted a smart-enough compiler could catch this simple example, but a more
elaborate example involving multiple translation units and/or run-time
control flow would be essentially uncatchable.

Not earth-shattering news of course, but it's a very general article, and
isn't aiming to tackle the subtleties.
 
J

Joe Wright

Malcolm wrote:
[ snip ]
One of the design decisions in C was to allow the programmer to examine the
bit representation of data in memory.
It is an inherent property of a digital computer that the bits of any type
can be reinterpreted as any other type.
C does have a few weak protections against the programmer doing this
inadvertently, but they are fairly easy to circumvent. Often it is a good
idea.

For instance, if I know that on my machine ROM routines are from addresses
0x8000 upwards, then by examining the bits of a function pointer I can tell
if it points to a function in RAM or in ROM. That might be useful to know.
How useful? What difference could it make?
 
A

Andrey Tarasevich

What?

float x = 1.0f;
void *p = *((void**)&x);

This piece of code does not perform a _conversion_ of floating-point
value to pointer type. What you have here is a _reinterpretation_ of
floating-point lvalue as pointer lvalue (raw memory reinterpretation).
This is a completely different thing in C language world.

For example, in C language _converting_ a pointer of type 'T*' to
'void*' type and back is defined and has its uses. However, trying to
_reinterpret_ a pointer of type 'T*' as a 'void*' pointer (using the
above technique) leads to undefined results. Feel the difference.

The topic of this discussion is _conversions_. What you are implying has
noting to do with conversions.
 
R

Richard G. Riley

Malcolm wrote:
[ snip ]
One of the design decisions in C was to allow the programmer to examine the
bit representation of data in memory.
It is an inherent property of a digital computer that the bits of any type
can be reinterpreted as any other type.
C does have a few weak protections against the programmer doing this
inadvertently, but they are fairly easy to circumvent. Often it is a good
idea.

For instance, if I know that on my machine ROM routines are from addresses
0x8000 upwards, then by examining the bits of a function pointer I can tell
if it points to a function in RAM or in ROM. That might be useful to know.
How useful? What difference could it make?

Err, so you know if its in ROM or RAM?
 
C

Christian Bau

"Richard G. Riley said:
Malcolm wrote:
[ snip ]
One of the design decisions in C was to allow the programmer to examine
the
bit representation of data in memory.
It is an inherent property of a digital computer that the bits of any type
can be reinterpreted as any other type.
C does have a few weak protections against the programmer doing this
inadvertently, but they are fairly easy to circumvent. Often it is a good
idea.

For instance, if I know that on my machine ROM routines are from addresses
0x8000 upwards, then by examining the bits of a function pointer I can
tell
if it points to a function in RAM or in ROM. That might be useful to know.
How useful? What difference could it make?

Err, so you know if its in ROM or RAM?


There are plenty of implementations where a function pointer does _not_
point to the code of a function.
 
R

Richard G. Riley

Richard G. Riley said:
Malcolm wrote:
[ snip ]
One of the design decisions in C was to allow the programmer to examine
the
bit representation of data in memory.
It is an inherent property of a digital computer that the bits of any type
can be reinterpreted as any other type.
C does have a few weak protections against the programmer doing this
inadvertently, but they are fairly easy to circumvent. Often it is a good
idea.

For instance, if I know that on my machine ROM routines are from addresses
0x8000 upwards, then by examining the bits of a function pointer I can
tell
if it points to a function in RAM or in ROM. That might be useful to know.


How useful? What difference could it make?

Err, so you know if its in ROM or RAM?


There are plenty of implementations where a function pointer does _not_
point to the code of a function.

It was an example to the somewhat strange question : nothing more. The
OP even qualified with "it *might* be useful to know". In addition if you
are writing HW specifics based on known bit patterns then one would
assume you take into the account what the function pointer is pointing
to wouldnt you?
 
J

Joe Wright

Richard said:
Malcolm wrote:
[ snip ]
One of the design decisions in C was to allow the programmer to examine the
bit representation of data in memory.
It is an inherent property of a digital computer that the bits of any type
can be reinterpreted as any other type.
C does have a few weak protections against the programmer doing this
inadvertently, but they are fairly easy to circumvent. Often it is a good
idea.

For instance, if I know that on my machine ROM routines are from addresses
0x8000 upwards, then by examining the bits of a function pointer I can tell
if it points to a function in RAM or in ROM. That might be useful to know.

How useful? What difference could it make?


Err, so you know if its in ROM or RAM?
And knowing that, how might it change what you would do?
 
C

CBFalconer

Joe said:
And knowing that, how might it change what you would do?

It might discourage you from attempting to set a breakpoint there.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
K

Keith Thompson

Joe Wright said:
Richard said:
Malcolm wrote:
[ snip ]

One of the design decisions in C was to allow the programmer to
examine the bit representation of data in memory.
It is an inherent property of a digital computer that the bits of
any type can be reinterpreted as any other type.
C does have a few weak protections against the programmer doing
this inadvertently, but they are fairly easy to circumvent. Often
it is a good idea.

For instance, if I know that on my machine ROM routines are from
addresses 0x8000 upwards, then by examining the bits of a function
pointer I can tell if it points to a function in RAM or in
ROM. That might be useful to know.



How useful? What difference could it make?
Err, so you know if its in ROM or RAM?
And knowing that, how might it change what you would do?

In any of a number of ways, few of which are on-topic here. (For
example, knowing whether a routine is in RAM or ROM might give a clue
about where to look for documentation of the routine, or where to send
bug reports.)
 
R

Richard G. Riley

Richard said:
Malcolm wrote:
[ snip ]

One of the design decisions in C was to allow the programmer to examine the
bit representation of data in memory.
It is an inherent property of a digital computer that the bits of any type
can be reinterpreted as any other type.
C does have a few weak protections against the programmer doing this
inadvertently, but they are fairly easy to circumvent. Often it is a good
idea.

For instance, if I know that on my machine ROM routines are from addresses
0x8000 upwards, then by examining the bits of a function pointer I can tell
if it points to a function in RAM or in ROM. That might be useful to know.



How useful? What difference could it make?


Err, so you know if its in ROM or RAM?
And knowing that, how might it change what you would do?

Well, I can think of one (OT) immediately : a memory test routine. Why
are you so concerned on why a poster would wish to determine ROM or
RAM? I would say that is their business.
 

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,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top