dereferencing memory location some time after deleting the same one

F

fabio de francesco

Hi

what do you think of the following? Why are we permitted to do that?
And why the C++ Library doesn't stop someone willing to perfom that
assignement (*a = 20)?


#include <iostream>

using std::cout;

int main()
{
int *a = new int(10);
cout << *a << " " << a << '\n';
delete a;
*a = 20;
cout << *a << " " << a << '\n';
}


After compiling (with gcc-3.4.1 on Linux and with VC++ on XP as well):

#./a.out
10 0x9f6d008
20 0x9f6d008


Maybe what is worse is that if you compile and run the above written
code without the line "*a = 20;" you get the following output:

#./a.out
10 0x9f6d008
0 0x9f6d008

I didn't know that yhis is the behaviour until I read a post on
it.comp.lang.c++ from someone who didn't understand why He got the
printed list of all the nodes of a bin-tree with a "0" output at the
position of some previously deleted nodes. So He didn't realize that
He forgot to assign NULL to the parent pointer field addressing the
just deleted nodes (and unfortunatelly all the deleted nodes were leaf
ones).

I think that if He had got a crash, dereferencing a pointer to
deallocated memory, He would had understood what was bad with his
cancelling algorithm.

So wouldn't it be better if a program crashed when someone tried to
dereference a pointer to deleted memory location?

Ciao,

Fabio De Francesco
 
V

Victor Bazarov

fabio said:
what do you think of the following? Why are we permitted to do that?

Why not? The Standard says that any program that attempts to dereference
a pointer after the pointer has been deleted, has undefined behaviour.
An attempt to define what should happen in such case is a waste of time.
And why the C++ Library doesn't stop someone willing to perfom that
assignement (*a = 20)?

How would it "stop" you?
#include <iostream>

using std::cout;

int main()
{
int *a = new int(10);
cout << *a << " " << a << '\n';
delete a;
*a = 20;
cout << *a << " " << a << '\n';
}


After compiling (with gcc-3.4.1 on Linux and with VC++ on XP as well):

#./a.out
10 0x9f6d008
20 0x9f6d008

Undefined behaviour. Anything is allowed to happen.
Maybe what is worse is that if you compile and run the above written
code without the line "*a = 20;" you get the following output:

#./a.out
10 0x9f6d008
0 0x9f6d008

Again, it really shows nothing. The behaviour of that code is
not defined. It is allowed to produce _any_ output or no output
whatsoever.
I didn't know that yhis is the behaviour until I read a post on
it.comp.lang.c++ from someone who didn't understand why He got the
printed list of all the nodes of a bin-tree with a "0" output at the
position of some previously deleted nodes. So He didn't realize that
He forgot to assign NULL to the parent pointer field addressing the
just deleted nodes (and unfortunatelly all the deleted nodes were leaf
ones).
OK


I think that if He had got a crash, dereferencing a pointer to
deallocated memory, He would had understood what was bad with his
cancelling algorithm.

He could get a crash. Or he could get a thank-you note in the mail.
Or he could get his hard drive formatted. Anything is allowed to
happen.
So wouldn't it be better if a program crashed when someone tried to
dereference a pointer to deleted memory location?

No, it wouldn't. Forcing the program to crash would require some
special processing. Besides, requiring the program to crash would
only permit creation of C++ programs for systems where "crash" is
defined. What if the system _cannot_ (or must not) crash? Even
debugging such system would be a problem.

V
 
R

Rolf Magnus

fabio said:
Hi

what do you think of the following? Why are we permitted to do that?

What makes you think you are?
And why the C++ Library doesn't stop someone willing to perfom that
assignement (*a = 20)?

Because the behavior is undefined, which means the program is not required
to crash.
#include <iostream>

using std::cout;

int main()
{
int *a = new int(10);
cout << *a << " " << a << '\n';
delete a;
*a = 20;
cout << *a << " " << a << '\n';
}


After compiling (with gcc-3.4.1 on Linux and with VC++ on XP as well):

#./a.out
10 0x9f6d008
20 0x9f6d008


Maybe what is worse is that if you compile and run the above written
code without the line "*a = 20;" you get the following output:

#./a.out
10 0x9f6d008
0 0x9f6d008

I didn't know that yhis is the behaviour until I read a post on
it.comp.lang.c++ from someone who didn't understand why He got the
printed list of all the nodes of a bin-tree with a "0" output at the
position of some previously deleted nodes. So He didn't realize that
He forgot to assign NULL to the parent pointer field addressing the
just deleted nodes (and unfortunatelly all the deleted nodes were leaf
ones).

I think that if He had got a crash, dereferencing a pointer to
deallocated memory, He would had understood what was bad with his
cancelling algorithm.

So wouldn't it be better if a program crashed when someone tried to
dereference a pointer to deleted memory location?

It's not so easy to determine every illegal memory access without explicit
hardware support.
 
R

Ron Samuel Klatchko

So wouldn't it be better if a program crashed when someone tried to
dereference a pointer to deleted memory location?

Better is a matter of opinion. It would definitely be easier to debug
but what if the trade off was that the program takes 10 times as long
to run.

While you can't get the compiler to enforce it, you can get close to what
you want by adaptint the style of always NULLing a pointer after deleting it:

delete x;
x = 0;

samuel
 
F

fabio de francesco

Victor Bazarov said:
Why not? The Standard says that any program that attempts to dereference
a pointer after the pointer has been deleted, has undefined behaviour.
An attempt to define what should happen in such case is a waste of time.

I am sorry for my English because sometimes I am not able to explain
what the it is the exact point of my question: I already know that the
behaviour is undefined as the Standard says. What I intended to ask is
why the Standard say that. I think that Standard would be better not
to allow dereferencing a pointer to deleted memory for the reasons I
wrote.
How would it "stop" you?

Ok, let me try a way. I don't have enough IT competence to suggest the
best solution but I start from knowing that the Library takes pages of
memory from the kernel VM and manages the allocation of little pieces
of that to programs requiring bits of that memory. Is it true, isn't
it? So the responsibility for finer allocation of memory is in charge
of the Library that eventually could mark deleted locations as
unavailable and recollect them. May be this is not the right way but I
just tried to answer your question.
Undefined behaviour. Anything is allowed to happen.


Again, it really shows nothing. The behaviour of that code is
not defined. It is allowed to produce _any_ output or no output
whatsoever.

That has been said before.
He could get a crash. Or he could get a thank-you note in the mail.
Or he could get his hard drive formatted. Anything is allowed to
happen.

I think it shouldn't be allowed to happen anything not specified, for
the sake of safety.
No, it wouldn't. Forcing the program to crash would require some
special processing. Besides, requiring the program to crash would
only permit creation of C++ programs for systems where "crash" is
defined. What if the system _cannot_ (or must not) crash? Even
debugging such system would be a problem.

I don't know. What does the standard defines when a program tries to
access a memory location allocated to another process?

Thank you,

Fabio De Francesco
 
F

fabio de francesco

Rolf Magnus said:
SNIP


It's not so easy to determine every illegal memory access without explicit
hardware support.

As I wrote to Victor Bazarov, if the deleted memory is still in the
hands of the C++ Library, the Library itself could deny access some
way. Whereas if the memory has been given back to the kernel we don't
have to worry about it because the kernel (Linux at least) will emit a
segmentation fault. I don't think any hardware support is needed, but
I can be wrong.

Thank you,

Fabio De Francesco
 
V

Victor Bazarov

fabio de francesco said:
I am sorry for my English because sometimes I am not able to explain
what the it is the exact point of my question: I already know that the
behaviour is undefined as the Standard says. What I intended to ask is
why the Standard say that.

You have to ask in comp.std.c++ then. This newsgroup (comp.lang.c++)
discusses _how_ the things are, not _why_. comp.std.c++ discusses
_why_ things are the way they are.
I think that Standard would be better not
to allow dereferencing a pointer to deleted memory for the reasons I
wrote.

It can't disallow it. Just like it can't disallow dividing by 0 or
calculating the arcsine of 5. Maybe that's what you want to do, who
is the Standard Committee to prevent you from doing that? Freedom
is something that is very important. You're free to do what you want.
The compiler and the code is free to behave as it sees fit.
Ok, let me try a way. I don't have enough IT competence to suggest the
best solution but I start from knowing that the Library takes pages of
memory from the kernel VM and manages the allocation of little pieces
of that to programs requiring bits of that memory. Is it true, isn't
it? So the responsibility for finer allocation of memory is in charge
of the Library that eventually could mark deleted locations as
unavailable and recollect them. May be this is not the right way but I
just tried to answer your question.

Yes, and you have fallen into something platform-specific, like 'VM' or
'kernel' or 'pages of memory'. All this is beyond the scope of the
language standard. The main reason is that as soon as the language tries
to incorporate anything OS-specific in the prescribed behaviour, it cannot
be implemented on a system where something is different. It becomes
OS-dependent. That is not acceptable for C++.
I think it shouldn't be allowed to happen anything not specified, for
the sake of safety.

Safety is NOT a concern of a language. It's a concern of a programmer
and/or a library implementer. If you think it's not safe, DO NOT DO IT.
I don't know. What does the standard defines when a program tries to
access a memory location allocated to another process?

There is no such thing as "another process" in the Standard. The C++
language program model is a single process running sequential operations
on a single processor.

If you want security, hand-holding, garbage collection, electric fences
or anything of this sort, C++ is not your language. There are other
languages that have them. Slower, bulkier, but safer, less demanding
on the programmer.

Victor
 
?

=?ISO-8859-1?Q?=22Nils_O=2E_Sel=E5sdal=22?=

hardware support.
As I wrote to Victor Bazarov, if the deleted memory is still in the
hands of the C++ Library, the Library itself could deny access some
way. Whereas if the memory has been given back to the kernel we don't
have to worry about it because the kernel (Linux at least) will emit a
segmentation fault. I don't think any hardware support is needed, but
I can be wrong.
You are. IF the memory is in hands of the C++ library, HOW can it
trap any access to it ? The kernel gives segfault based on help from
hardware, but memory deleted are not usually given back to the kernel.
 
K

Karl Heinz Buchegger

fabio said:
As I wrote to Victor Bazarov, if the deleted memory is still in the
hands of the C++ Library, the Library itself could deny access some
way.

So how should it do that?
The only way would be to intercept each and every access to memory and
look in its internal tables if a request to that specific access is granted.
Well. Programs spend roughly 90% of their time in accessing memory. But this
also would mean that most of the programs time would be spent by checking
if a memory access is granted or not. Besides: The checking routine itself
needs to access memory, who is going to monitor that routine?

Whereas if the memory has been given back to the kernel we don't
have to worry about it because the kernel (Linux at least) will emit a
segmentation fault. I don't think any hardware support is needed, but
I can be wrong.

It strictly isn't needed, the compiler could insert a call to the checking
function whenever code is emitted to access a memory location. But as said:
Your program wouldn't do much more then spending an overwhelming amount
of time in that check function.

Consider this analogy:
There is a library. If you lend a book someone is checking if you are
allowed to lend that book. So far so fine. But now we change the rules slightly:
Instead of checking once for the whole book, the libraraian is now required to
check for each page if you are allowed to read that page. Or better: For each line,
each word, each character. This way the librarian can be very sure that you don't see
anything you shouldn't see. But the bacjdraft is: You could no longer actually 'read'
the book, since you would spend most of your time in asking the librarian if
you are allowed to read the next character, word, line.

It is like in everyday life: 100% safety is possible, but it is impractical. Und thus
it is never done. You can stealth a computer against hackers or viruses or spam or whatever.
You just neeed to remove any and all input devices to that computer, then there would
be no way that a virus could infect it. Hmm. But how are you going to actually work with
that computer in this case?
 
C

Catalin Pitis

fabio de francesco said:
Hi

what do you think of the following? Why are we permitted to do that?
And why the C++ Library doesn't stop someone willing to perfom that
assignement (*a = 20)?


#include <iostream>

using std::cout;

int main()
{
int *a = new int(10);
cout << *a << " " << a << '\n';
delete a;
*a = 20;
cout << *a << " " << a << '\n';
}


After compiling (with gcc-3.4.1 on Linux and with VC++ on XP as well):

#./a.out
10 0x9f6d008
20 0x9f6d008


Maybe what is worse is that if you compile and run the above written
code without the line "*a = 20;" you get the following output:

#./a.out
10 0x9f6d008
0 0x9f6d008

I didn't know that yhis is the behaviour until I read a post on
it.comp.lang.c++ from someone who didn't understand why He got the
printed list of all the nodes of a bin-tree with a "0" output at the
position of some previously deleted nodes. So He didn't realize that
He forgot to assign NULL to the parent pointer field addressing the
just deleted nodes (and unfortunatelly all the deleted nodes were leaf
ones).

I think that if He had got a crash, dereferencing a pointer to
deallocated memory, He would had understood what was bad with his
cancelling algorithm.

So wouldn't it be better if a program crashed when someone tried to
dereference a pointer to deleted memory location?

Ciao,

Fabio De Francesco

I know that some standard libraries implement additional checks at run time,
when allocating or freeing the memory. However, they are implemented only
for debug code, using assertions.

As others already said, C++ is not a safe programming language, but it is
efficient in terms of performance. By providing additional, mandatory checks
for safety, a lot of performance may be lost. This can be compensated by a
good discipline in programming.

Catalin
 
R

Rolf Magnus

fabio said:
As I wrote to Victor Bazarov, if the deleted memory is still in the
hands of the C++ Library, the Library itself could deny access some
way.

What exactly do you mean by "some way"? It's right that the library has
probably some way to determine whether a particular memory location is
properly allocated, but how would it detect which memory location a program
tries to access? After all, it accesses the memory directly, not through
library functions.
Whereas if the memory has been given back to the kernel we don't
have to worry about it because the kernel (Linux at least) will emit a
segmentation fault. I don't think any hardware support is needed, but
I can be wrong.

Even the kernel facility you describe does use hardware support. The memory
is ogranized in pages. If a program tries to access an address in its
virtual address space that doesn't map to a part of a page of physical
memory, the CPU generates an interrupt and the kernel gets control over the
CPU.
 

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
474,183
Messages
2,570,965
Members
47,512
Latest member
FinleyNick

Latest Threads

Top