Pete Lomax wrote:

Gordon Henriksen wrote:

<snip>
It doesn't matter if an int field could read half of a double or v.v.;
it won't crash the program. Only pointers matter.
<snip>
These rules ensure that dereferencing a pointer will not segfault.

In this model, wouldn't catching the segfault and retrying (once or twice) work?

Determining how to "retry" in the general case would be... much more interesting than this proposal. :)


Furthermore, worse than segfaults could potentially result from using half of a double as a pointer. There's no assurance that *((caddr_t *) &double) won't in fact be a valid memory address. In this case, there would be no segfault, but memory would be subtly corrupted. There's no way to detect that, so there's no way to retry.

The point of all the tweaks and care is to prevent ever dropping something else in a particular variable where parrot would, at another point in the program, expect a pointer of a particular type.


I think you probably got the following, but I'd just like to elaborate more specifically. I think the greatest subtlety of the rules was in the interpretation of


accesses which parrot might perform

and the word specific in


any specific pointer variable ptr

Without understanding precisely what I meant there, one might think that even a simple polymorphic system like the following is prohibited:


        struct eg;
        typedef int (func_ptr*)(struct eg*);
        struct {
                func_ptr fp;
                union { int *pointer; int integer; } u;
        } eg;
        
        int pointer_meth(struct eg *thiz) { return ++*(thiz->u.pointer); }
        int integer_meth(struct eg *thiz) { return ++(thiz->u.integer); }
        
        void main() {
                struct eg eg1 = { pointer_meth, NULL };
                struct eg eg2 = { integer_meth, 1 };
                eg1.u.pointer = malloc(sizeof(int));
                *eg1.u.pointer = 0;
                
                print_it("eg1", &eg1);
                print_it("eg2", &eg2);
        }

        void print_it(char *name, struct eg *some_eg) {
                printf("%s says %d\n", some_eg>fp(&eg2));
        }

But the program IS allowed. While print_it might behave in any number of ways depending on some_eg->fp, it will always access a particular eg.u in a consistent fashion, since it always respects the discriminator (eg.fp), which the program never changes. By extension of this, C++ instances do not violate these rules, either.[*] Were the following line added to main(), though, then the program would be in violation:

eg1.fp = integer_meth;

Because now some other thread could have obvserved eg1.fp == pointer_meth and begun invoking pointer_meth. pointer_meth might now access u.pointer and, instead of a pointer, see n + (int) u.pointer. That probably won't segfault for small values of n, but will certainly not do the right thing either.


This is trite tangent, but also note that the type stability rule prohibits this:


eg1.u.pointer = NULL;

But would not if the definition of pointer_meth became:

        int pointer_meth(struct eg *thiz) {
                int* pointer = this->u.pointer;
                return pointer == NULL? -1 : ++*pointer;
        }

Because now the program will now not dereference u.pointer if its value is NULL. How cute. (But if u.pointer were not copied to a local, then bets are off again, because C might perform an extra load and get a value inconsistent with the one it received when testing for NULL.)

... But even that extra local copy isn't required if u.pointer begins NULL, and can become non-NULL, but will not become NULL again. Why?

all accesses which parrot MIGHT perform on any pointer ever storED in ptr ("A")

Note the past tense there. That's why.



If I'm reading you correctly, which is unlikely,

That has little to do with you, but much to do with my burying important parts of my message in pages of dense text. :)


this has little to do with program correctness, but about the interpreter not crashing because of an unfortunate context switch.. which the programmer should have guarded against in the first place...

Yes. Precisely.


no, I think I just lost the plot again ;-)

I think you're pretty close, just missing a few of the subtleties that got buried in that long missive. :)




Gordon Henriksen
[EMAIL PROTECTED]


[*] Even though C++ changes the vtable of an instance during instantiation, it does so in a broadening fashion, making formerly-inaccessible variables accessible. A C++ instance of "class derived_class : public base_class" is not a derived_class until base_class's constructor finishes and derived_class's constructor begins. (Side-effect: A subclass cannot influence the instantiation behavior of a base class.) (Objective C's class methods are wildly useful. Static languages tend to ignore them. It's sad.)

Reply via email to