• Ruts (unregistered)

    Frist thought on this is that the hex values will be those used for uninitialised data, populated in Debug mode at least. So initial declaration probably doesn't set to NULL and this avoided a crash on closing a non-null uninitialised file pointer

  • LCrawford (unregistered)

    Some C runtime debug library implementations fill all memory with 0xcd - a value that will trigger an invalid pointer if never initialized and improbable array indexers. Production code could still have possible code paths resulting in an invalid pointer.

  • Stella (unregistered)

    Apart from testing if a variable is uninitialized by testing if it is initialized with a magic value for uninitialized memory that only works if compiled in debug mode, this also assumes 32-bit architecture, and it's using fopen in C++. Remember, it's not C++ only because it compiles with a C++ compiler.

  • bvs23bkv33 (unregistered)

    #define 0xcdcdcdcd NULL

  • Foo AKA Fooo (unregistered) in reply to Stella

    It also works on 64-bit, it'll just be a rather small pointer value, and I think also on 16-bit where it'll just throw away the higher bytes.

    At least it will most likely not conflict with an actual FILE pointer since the address is odd and the FILE structure most likely will have alignment > 1. Same as for the other commonly used one, 0xdeadbeef. Anyway, they should have used a #define (or if it's actually meant to be C++ rather than C, a constexpr) for this magic constant.

  • (nodebb) in reply to LCrawford

    I could well believe a free() implementation filling the freed block with 0xcd in order to ensure that use-after-free bugs get found easily. While yes, it's strictly allowed to use a memory block immediately after the free for a short while (until the next time the memory management subsystem is used) it's really bad practice.

    Guarding against double free() like this is still awful.

  • (nodebb)

    Maybe 0xcdcdcdcd was an RGBA value copied from a CSS file? Very light, barely transparent gray.

  • Free Bird (unregistered) in reply to dkf

    Can you point me towards a source (preferably a snippet from the ISO standard) to back up your claim "it's strictly allowed to use a memory block immediately after the free for a short while (until the next time the memory management subsystem is used)"?

  • Chris Jefferson (unregistered)

    Bit surprising they didn't just try googling for it. It's what visual studio sets uninitialised memory to in debug mode.

    I'd guess (from similar experience) this is an old program which used to rely on uninitialised memory being 0 (which you shouldn't rely on, but some people do), and this was just a hack to get around the problem of it now being 0xcdcdcdcd.

  • Bob Flanders (unregistered)

    This answer the question... https://stackoverflow.com/questions/8275418/with-c-i-get-pointer-with-0xcdcdcdcd-when-creating-a-class-what-is-happenin

  • Foo AKA Fooo (unregistered) in reply to dkf

    Nope, the code doesn't check the block pointed to, but the pointer itself.

    Setting the pointer to a sentinel after free (or to NULL, as they do here) doesn't prevent use-after-free bugs either since copies of the pointer may exist.

    Of course, if it were actually C++, a unique_ptr or shared_ptr (depending on whether or not copies should be allowed to exist) would solve all those problems without any special code.

  • (nodebb) in reply to Mr. TA

    A grey colour field gets assigned to a file pointer?! I know that what a number means in a computer depends entirely on context, but those contexts have absolutely nothing to do with each other.

  • Your Name (unregistered)

    0xcdcdcdcd is perhaps a "magic number". pFile can contain either a file pointer or 0xcdcdcdcd. The cast to (FILE *) is only there to make the comparison pass the typecheck.

    Not that this would be stellar coding, but that would explain the coding.

  • Anonymous') OR 1=1; DROP TABLE wtf; -- (unregistered)

    Wikipedia has a good list of magic debug values here:

    https://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_debug_values

    As others have said, 0xcdcdcdcd is used by Microsoft's debug malloc() routine to mark uninitialized memory.

    While yes, it's strictly allowed to use a memory block immediately after the free for a short while (until the next time the memory management subsystem is used) it's really bad practice.

    No, it's not. A lot of code gets away with that, but it's still Undefined Behavior.

  • (nodebb) in reply to LCrawford

    Some C runtime debug library implementations fill all memory with 0xcd

    Specifically Visual Studio's.

  • SG (unregistered)

    https://stackoverflow.com/a/127404

    • 0xCDCDCDCD : Used by Microsoft's C++ debugging runtime library to mark uninitialised heap memory
  • (nodebb) in reply to Free Bird

    Can you point me towards a source (preferably a snippet from the ISO standard) to back up your claim "it's strictly allowed to use a memory block immediately after the free for a short while (until the next time the memory management subsystem is used)"?

    Of course he can't, because there is no such snippet. Once a pointer has been (correctly) passed to free or realloc(p,0) or delete, it is UB to dereference (or even look at the value of) the pointer. It's entirely possible that the memory in question will be not only freed, but given back to the OS (if there is one) and unmapped, and if that's the case, you'll explode with some equivalent of a SIGSEGV.

    And of course if you do it on the infamous DeathStation 9000, millions of people will be killed by nuclear explosions.

  • Angela Anuszewski (google) in reply to Nutster

    Humor is the intersection of two incongruous concepts.

    TL:DR - WOOSH

  • dcon (unregistered) in reply to dkf

    Guarding against double free() like this is still awful.

    It's not doing that. free passes its arguments by value. So it can't modify the value of pFile. Also, deleted heap memory is marked with 0xDDDDDDDD.

    MSVC Memory patterns
    0xCCCCCCCC // uninitialized stack memory
    0xCDCDCDCD // uninitialized heap memory
    0xFDFDFDFD // "no man's land" guard bytes before and after allocated heap memory
    0xDDDDDDDD // deleted heap memory
    0xFEEEFEEE // deleted heap memory
    0xBAADF00D // before "no man's land" guard bytes
    0xDEADC0DE // after "no man's land" guard bytes
    0xFEEDFACE // uninitialized memory
    0xDEADBEEF // deleted memory
    
  • Stranger Things (unregistered)

    Reminds me of my job in the late 1990's. 0xdeadbeef was a value that stood out in hex dumps of memory. Was easy for us humans to spot. I don't think it was a magical value for any other reason. It was in code for a switch that ran on i960 architecture. No Microsoft compiler need apply.

  • Bill T (unregistered) in reply to Stranger Things

    I always liked 0xdeadbeef. One other marker value I'd used was 0xbaadf00d.

  • Best Practices (unregistered)

    This pointer value is very unlikely to be valid file pointer, because valid user space pointers tend to be multiples of 4 or 8. (In many 32-bit systems the pointer is even outside user space.) However, as debugging initializes memory to 0xCDCDCDCD, it is obviously a feature to treat 0xCDCDCDCD as equivalent to zero.

    This way, software is less likely to crash upon coming across pointer that happens to be 0xCDCDCDCD. For portable libraries (e.g. to Solaris), I recommend also handling 0xDEADBEEF and 0xBAADF00D.

  • (nodebb)

    Add me to the crowd that thinks this is to avoid closing a file handle that was not initialized. It's a coverup for some other bug.

    And I've got a hard drive around here with an 0xDEADBEEF ID. :) (Had to manually change a duplicate ID.)

  • (nodebb)

    constexpr was added in C++11, I'll wager the code predates that by years.

  • Argle (unregistered)

    I've been reading the comments on this one. I was once an old-school c/c++ programmer and this code seems vaguely familiar. This doesn't seem so much a "wtf" as a "sorry, forgot to delete that test bit." No harm; no foul.

  • (nodebb) in reply to Foo AKA Fooo

    Nope, the code doesn't check the block pointed to, but the pointer itself.

    Which would make the pointer itself have been something extracted from freed (or uninitialised) memory. Either way is an indication of major problems.

    Yes, reading from freed memory is UB now. It used to be a pretty common practice though, relying on how the memory allocator code wouldn't actually write into the memory that had previously handed to user code until (usually) it next allocated the block (which made freeing everything in a linked list able to skip using a temporary variable to hold the location of the next entry). Memory manager libraries (in debug mode) setting the contents of memory blocks to something that can't be a sensible pointer is one of the main tools for chasing down problems like that (with anything that is repeated instances of the same byte being favoured since then you can use memset() to do the job efficiently). Yes, memory managers still work the same way, but it's now fantastically unsafe because code is now normally multithreaded. This is real Nasal Demons territory.

  • (nodebb) in reply to dkf

    Yes, reading from freed memory is UB now.

    It has been UB for thirty years.

  • New Graduate (unregistered) in reply to Stella

    The magic constant implies a MS target: 64 bit MS windows uses 32 bit file handles. That is, 64 bit file handles with the top 32 bits set tp zero.

  • Officer Johnny Holzkopf (unregistered) in reply to New Graduate

    That's why the code will be used only in an 0x0FF1CE.

  • SilverSlash (unregistered) in reply to Loren Pechtel

    How life must be for you non Rust systems programmers.

  • (nodebb) in reply to New Graduate

    The magic constant implies a MS target: 64 bit MS windows uses 32 bit file handles. That is, 64 bit file handles with the top 32 bits set tp zero.

    FILE * is not a file handle. It's a pointer to a C runtime structure. The magic value implies a 32-bit Vsial Studio / MSVC starget.

    What do they teach new graduates these days, anyway?

    Addendum 2019-08-02 02:23: Oops. Too early in the morning. My coffee awaits me in the kitchen. "Visual". Sigh.

  • Ruts (unregistered) in reply to Bill T

    For hex marker values/strings, I quite liked to use something like EFF0FF ;-)

  • seebs (unregistered) in reply to dkf

    It's not just undefined behavior "now". It has always been undefined behavior. It has never been acceptable. Not even once. Not even in the line of code right after the free. Yes, I've seen people do it. But back in the 1980s, we were making fun of them for being idiots. It isn't "strictly" allowed, and it was never allowed. At all. Please stop being dangerously wrong, someone might believe you and get into trouble.

  • (nodebb)

    Basically the conclusion that has been reached here is that 0xcdcdcdcd == 0x00000000. Nice. Take that, Euclid.

  • I Saw a Robot (unregistered)

    My favorite magic number initializer is BADC0FFEE0DDF00D

  • Free Bird (unregistered) in reply to dkf

    Your definition of "strictly allowed" must be completely different from mine.

  • FristName LastName (unregistered) in reply to dkf

    While yes, it's strictly allowed to use a memory block immediately after the free for a short while

    If that was ever true, it certainly wasn't true by the late 90's, when I was learning C. If I correctly recall the phrase from K&R's 2nd (ANSI) edition, using memory after it was freed was "a ghastly error."

    Please forgive my ignorance, but under what possible circumstance does it ever make sense to make use of deallocated memory? And for what reason would you ever free memory before you finished needing it?

    If I'd ever turned in code that did either of those things, my boss would have beaten me about my person and fired me on the spot.

  • New Graduate (unregistered) in reply to Steve_The_Cynic

    A file handle /is/ a pointer to a runtime structure. Defined in what is typically a file like fileapi.h or equivalent. It's a 'c' runtime structure if you are using c. It's Delphi/VB/c++/FORTRAN runtime structure if you aren't using c. It's a Windows runtime structure if you are using Windows. The pointer to the runtime structure, -- traditionally called a 'handle' -- is 64 bits long in 64 bit Windows. The top 32 bits are all zeros.

  • Dave (unregistered)

    So presumably someone was debugging an attempt to close a file via a file handle which wasn't valid. But rather than fixing the root cause they ran the debugger and noticed the 0xCDCDCDCD so added the guard? But presumably this means not only did they mask the issue, but only in a debug build?

Leave a comment on “Close to the Point”

Log In or post as a guest

Replying to comment #:

« Return to Article