diamond@jit345.swstokyo.dec.com (Norman Diamond) (01/21/91)
In article <s64421.664471332@zeus> s64421@zeus.usq.EDU.AU (house ron) writes: >Here's a bug which exists in every single DOS C compiler I can find, >and may also exist on others: >In the small memory model, it is possible for a function to have the >address NULL. E.G.: >void x() {} >main() { > void (*y)() = x; > if (y==NULL) printf ("AARRGGHH!!\n"); >} >This sort of program CAN print the message if x() happens to be >loaded by the linker at the start of the code segment (address 0). According to section 3.2.2.3: "An integral constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is assigned to or compared for equality to a pointer, the constant is converted to a pointer of that type. Such a pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object type or function." Every single DOS compiler that you can find is non standard-conforming. >Perhaps on some machines, NULL should _not_ be 0? Of course. On many many architectures, a bit pattern of all 1's would be suitable and very very useful. -- Norman Diamond diamond@tkov50.enet.dec.com If this were the company's opinion, I wouldn't be allowed to post it.
s64421@zeus.usq.EDU.AU (house ron) (01/21/91)
Here's a bug which exists in every single DOS C compiler I can find, and may also exist on others: In the small memory model, it is possible for a function to have the address NULL. E.G.: void x() { ... } main() { void (*y)(); y = x; if (y==NULL) printf ("AARRGGHH!!\n"); } This sort of program CAN print the message if x() happens to be loaded by the linker at the start of the code segment (address 0). The compiler seems unable to prevent the linker from loading functions at that address. Perhaps on some machines, NULL should _not_ be 0? After all, it would be easy to prevent functions being loaded at address 1 (for example) on a DOS machine. -- Regards, Ron House. (s64421@zeus.usq.edu.au) (By post: Info Tech, U.C.S.Q. Toowoomba. Australia. 4350)
hpa@casbah.acns.nwu.edu (Peter Anvin) (01/22/91)
[Program comparing a function pointer to NULL deleted] >>This sort of program CAN print the message if x() happens to be >>loaded by the linker at the start of the code segment (address 0). > >According to section 3.2.2.3: "An integral constant expression with the >value 0, or such an expression cast to type void *, is called a null pointer >constant. If a null pointer constant is assigned to or compared for equality >to a pointer, the constant is converted to a pointer of that type. Such a >pointer, called a null pointer, is guaranteed to compare unequal to a pointer >to any object type or function." >Every single DOS compiler that you can find is non standard-conforming. All DOS compilers I know of use, in small-code models, the beginning of the code segment to store their startup code. Thus, functions cannot be allocated to CS:0000h, and thus no functions correspond to NULL. The startup cod, which is written in assembler, sets up the stack, local heap, floating point emulation and the arguments to main(), as appropriate. main() just acts like a subroutine to the startup code. Should NULL be all ones? Performance issues aside, such a machine would only need to subtract one when converting an int to a pointer, and add one the other way. In constant expressions, such as when using the macro NULL, that can of course be done at compile time. -- H. Peter Anvin +++ A Strange Stranger +++ N9ITP/SM4TKN +++ INTERNET: hpa@casbah.acns.nwu.edu FIDONET: 1:115/989.4 BITNET: HPA@NUACC RBBSNET: 8:970/101.4
dswartz@bigbootay.sw.stratus.com (Dan Swartzendruber) (01/22/91)
In article <2831@casbah.acns.nwu.edu> hpa@casbah.acns.nwu.edu (Peter Anvin) writes:
:
: [Program comparing a function pointer to NULL deleted]
:::This sort of program CAN print the message if x() happens to be
:::loaded by the linker at the start of the code segment (address 0).
::
::According to section 3.2.2.3: "An integral constant expression with the
::value 0, or such an expression cast to type void *, is called a null pointer
::constant. If a null pointer constant is assigned to or compared for equality
::to a pointer, the constant is converted to a pointer of that type. Such a
::pointer, called a null pointer, is guaranteed to compare unequal to a pointer
::to any object type or function."
::Every single DOS compiler that you can find is non standard-conforming.
:
:All DOS compilers I know of use, in small-code models, the beginning of the
:code segment to store their startup code. Thus, functions cannot be
:allocated to CS:0000h, and thus no functions correspond to NULL. The
:startup cod, which is written in assembler, sets up the stack, local heap,
:floating point emulation and the arguments to main(), as appropriate.
:main() just acts like a subroutine to the startup code.
:
:Should NULL be all ones? Performance issues aside, such a machine would
:only need to subtract one when converting an int to a pointer, and add one
:the other way. In constant expressions, such as when using the macro NULL,
:that can of course be done at compile time.
:
Gee, this sounds familiar! I remember when the first PDP 11 with separate
I/D space came out and no one had fixed 'ld', so it blithely put the first
initialized data at data offset 0. Want to guess what happened when some
poor sucker's program took the address of that variable and passed it to
someone who checked for a NULL pointer? You'd be right. Kind of strange
that this problem is STILL cropping up 13 years later.
:
:
:--
:H. Peter Anvin +++ A Strange Stranger +++ N9ITP/SM4TKN +++
:INTERNET: hpa@casbah.acns.nwu.edu FIDONET: 1:115/989.4
:BITNET: HPA@NUACC RBBSNET: 8:970/101.4
--
Dan S.
gwyn@smoke.brl.mil (Doug Gwyn) (01/22/91)
In article <s64421.664471332@zeus> s64421@zeus.usq.EDU.AU (house ron) writes: >In the small memory model, it is possible for a function to have the >address NULL. [Meaning that a pointer to a legitimate function can compare equal to a null pointer constant.] This would be a non-conforming implementation, and one would hope that an example similar to the one you gave is part of any C validation suite. >Perhaps on some machines, NULL should _not_ be 0? No, in the SOURCE CODE, "0" MUST be an allowed way of writing a null pointer constant. This does NOT mean that the compiler has to produce an all 0-bits representation for a null pointer constant, however; it could for example use an all 1-bits representation, or the address of a reserved library object. >After all, it would be easy to prevent functions being >loaded at address 1 (for example) on a DOS machine. That's another solution.
diamond@jit345.swstokyo.dec.com (Norman Diamond) (01/22/91)
In article <2831@casbah.acns.nwu.edu> hpa@casbah.acns.nwu.edu (Peter Anvin) writes: >Should NULL be all ones? Performance issues aside, such a machine would >only need to subtract one when converting an int to a pointer, and add one >the other way. In constant expressions, such as when using the macro NULL, >that can of course be done at compile time. Why would it have to subtract one and add one? At compile time, an integer constant 0 (which has to be evaluated at compile time anyway) in a pointer context (which has to be determined at compile time anyway) would yield a bit-string of all 1's. The library's implementation of free() would either have to be compiled using this compiler, or else be sure that it compares against this compiler's representation of NULL. Casts between pointers and integers (other than compile-time null pointers) are not required to do anything fancy. If I were coding a compiler for a machine where pointers and ints had the same size, I'd just copy the bits. -- Norman Diamond diamond@tkov50.enet.dec.com If this were the company's opinion, I wouldn't be allowed to post it.
zvs@bby.oz.au (Zev Sero) (01/22/91)
Peter = hpa@casbah.acns.nwu.edu (Peter Anvin) Peter> Should NULL be all ones? Performance issues aside, such a Peter> machine would only need to subtract one when converting an int Peter> to a pointer, and add one the other way. In constant Peter> expressions, such as when using the macro NULL, that can of Peter> course be done at compile time. It would have to be done only at compile time. Fragments such as: int x = 0; char *p = (char *)x; *should* point at location zero if that is a valid address on this machine, and dereferencing it should give you whatever is at that address. *Only* constant expressions evaluating to zero (such as the macro NULL) represent the null pointer, and these are determined at compile time. -- Zev Sero - zvs@bby.oz.au This I say unto you, be not sexist pigs. - The prophetess, Morgori Oestrydingh (S.Tepper)
david@csource.oz.au (david nugent) (01/22/91)
In <2831@casbah.acns.nwu.edu> hpa@casbah.acns.nwu.edu (Peter Anvin) writes: > >>This sort of program CAN print the message if x() happens to be > >>loaded by the linker at the start of the code segment (address 0). > All DOS compilers I know of use, in small-code models, the beginning of the > code segment to store their startup code. This is link order dependant; nothing whatever to do with the compiler. > Thus, functions cannot be allocated to CS:0000h, and thus no > functions correspond to NULL. Yes they can, and often are. > The startup cod, which is written in assembler, sets up the stack, > local heap, floating point emulation and the arguments to main(), > as appropriate. main() just acts like a subroutine to the startup code. ... and can be wherever you like in the executable. > Should NULL be all ones? It, or an equivant, could be. # define NULLFUNC (int (*)()-1) david
asylvain@felix.UUCP (Alvin "the Chipmunk" Sylvain) (01/24/91)
In article <s64421.664471332@zeus> s64421@zeus.usq.EDU.AU (house ron) writes: > Here's a bug which exists in every single DOS C compiler I can find, > and may also exist on others: > > In the small memory model, it is possible for a function to have the > address NULL. E.G.: [... example nuked ...] > This sort of program CAN print the message if x() happens to be > loaded by the linker at the start of the code segment (address 0). > The compiler seems unable to prevent the linker from loading > functions at that address. Perhaps on some machines, NULL should > _not_ be 0? After all, it would be easy to prevent functions being > loaded at address 1 (for example) on a DOS machine. I think it would be more correct and portable if the DOS linker avoided loading the function at address 0. Maybe there should be a way the C compiler can inform the linker to avoid this practice. There are too many implementations that joyfully interchange NULL with 0 with no thot to this problem. (Altho, the compiler is supposed to be smart enuff to recognize a 0 in a pointer context and convert it to a "null pointer", whatever it happens to be.) In fact, unless I'm mistaken, I think NULL is *defined* to be 0. NULL and 0 are *defined* to be an invalid address. Therefore, if the func- tion (or anything else) happens to actually have a valid address of 0, then _something_ is _broken_. (Altho, again, this doesn't really impact the internal representation. The compiler should do the conversion. But I don't trust a compiler to recognize {ptr1 = 0; ptr2 = ptr1;} and know somehow that at run-time the 0 must be changed to an internal value for NULL. I've seen compilers that would recognize {y = 5/0;} and flag it: but {x = 0; y = 5/x;} will work every time.) Put another way: "valid address == 0" is a contradiction in terms. -- asylvain@felix.UUCP (Alvin "the Chipmunk" Sylvain) =========== Opinions are Mine, Typos belong to /usr/ucb/vi =========== "We're sorry, but the reality you have dialed is no longer in service. Please check the value of pi, or see your SysOp for assistance." =============== Factual Errors belong to /usr/local/rn =============== UUCP: uunet!{hplabs,fiuggi,dhw68k,pyramid}!felix!asylvain ARPA: {same choices}!felix!asylvain@uunet.uu.net
gwyn@smoke.brl.mil (Doug Gwyn) (01/24/91)
In article <s64421.664559119@zeus> s64421@zeus.usq.EDU.AU (house ron) writes: >I tried Quick C, TopSpeed C and Watcom C (a real loser). It occurs to me that you might be linking the object modules without preceding them by a run-time startup module (that sets up the environment, then invoked main() with appropriate arguments, and after main() returns invokes exit() etc.). If the compiler documentation specifies a certain way of linking, then to assure standard conformance you must follow the vendor's instructions exactly.
s64421@zeus.usq.EDU.AU (house ron) (01/24/91)
david@csource.oz.au (david nugent) writes: >It, or an equivant, could be. ># define NULLFUNC (int (*)()-1) I tried something like this using TopSpeed C, but I had to write a separate one for each type of function pointer, whereas NULL, if only it worked, works for all function types. I tried using variations on void *, but it took that as meaning the function returned a void result, instead of meaning "any type of function". -- Regards, Ron House. (s64421@zeus.usq.edu.au) (By post: Info Tech, U.C.S.Q. Toowoomba. Australia. 4350)
s64421@zeus.usq.EDU.AU (house ron) (01/24/91)
risto@tuura.UUCP (Risto Lankinen) writes: >Hi! >While I don't see it too dramatic a problem (to have NULL pointers to valid >function objects in C), It is a _VERY_ dramatic problem if you write a utility function which takes pointers to other functions as arguments, and needs to test which ones point to genuine functions so that it knows which ones it has to call. EVERY DEVIATION FROM A STANDARD IS DRAMATIC SOMEWHERE! -- Regards, Ron House. (s64421@zeus.usq.edu.au) (By post: Info Tech, U.C.S.Q. Toowoomba. Australia. 4350)
kdq@demott.com (Kevin D. Quitt) (01/25/91)
In article <s64421.664559119@zeus> s64421@zeus.usq.EDU.AU (house ron) writes: >kdq@demott.com (Kevin D. Quitt) writes: > >>In article <s64421.664471332@zeus> s64421@zeus.usq.EDU.AU (house ron) writes: >>>Here's a bug which exists in every single DOS C compiler I can find, >... >> Apparently you haven't tried Microsoft C 6.0? Which ones have you tried? > >I tried Quick C, TopSpeed C and Watcom C (a real loser). Remember >that any particular program might work, without guaranteeing that the >bug is absent. To be sure, look at the value of NULL pointers, and, if >it is zero, look at a program map to verify that a non-function is >necessarily present at the start of the default code segment. Is this >the case with MSC6? I find start-up code at zero, and with a few simple trials was not able to get one of my (or the library's) functions loaded at zero. Maybe if I were more persistent... -- _ Kevin D. Quitt demott!kdq kdq@demott.com DeMott Electronics Co. 14707 Keswick St. Van Nuys, CA 91405-1266 VOICE (818) 988-4975 FAX (818) 997-1190 MODEM (818) 997-4496 PEP last
gwyn@smoke.brl.mil (Doug Gwyn) (01/26/91)
In article <156097@felix.UUCP> asylvain@felix.UUCP (Alvin "the Chipmunk" Sylvain) writes: >I think it would be more correct and portable if the DOS linker avoided >loading the function at address 0. I disagree. This is a combined language+language_implementation constraint, and is no business of the linker. In fact, I think the linker was being misused since a trivial way to satisfy the constraint would be to link a startup object module first, and that is probably what the compiler manuals say to do.
mcdaniel@adi.com (Tim McDaniel) (01/26/91)
Please see the long-form FAQ, Frequently-Asked Questions list, which will be reposted in six days. E-mail me for a copy. Null pointers are thoroughly covered in questions 1 thru 14. asylvain@felix.UUCP (Alvin "the Chipmunk" Sylvain) is somewhat confused. -- Tim McDaniel Applied Dynamics Int'l.; Ann Arbor, Michigan, USA Work phone: +1 313 973 1300 Home phone: +1 313 677 4386 Internet: mcdaniel@adi.com UUCP: {uunet,sharkey}!amara!mcdaniel
raymond@math.berkeley.edu (Raymond Chen) (01/26/91)
In article <14975@smoke.brl.mil>, gwyn@smoke (Doug Gwyn) writes: >a trivial way to satisfy the constraint would be to link a >startup object module first, and that is probably what the compiler manuals >say to do. Pardon me for injecting facts into the discussion, but here's a quote from the Turbo C manual; namely, the section titled, `Using TLINK with Turbo C Modules': The general format for linking Turbo C programs with TLINK is tlink C0x <myobjs>, <exe>, [map], <mylibs> [emu|fp87 mathx] Cx where: C0x = initialization module for memory model t, s, c, n, l or h. The initialization module <<must appear as the first object file in the list>>. [emphasis mine] Consequently, anybody who doesn't list C0x first is not following the instructions and therefore deserves whatever he gets. We now return you to the petty bickering, already in progress.