• (nodebb)

    I do not know what about this is "overlapped".

    It's a memcpy that's safe when the source and destination overlap in some way, that is, it's memmove. Except with an allocation.

  • oldbutgrumpy (unregistered)

    Am I missing something, or are all these also blatant memory leaks?

  • TheCPUWizard (unregistered)

    If the buffers overlap, you have to be careful

    char buffer[100]; memcpy[&buffer[10],%buffer[0], 50); memcpy[&buffer[0],%buffer[20], 50);

  • Naomi (unregistered)

    It's a memcpy that's safe when the source and destination overlap in some way, that is, it's memmove.

    I'm going to take the opportunity to mention one of the weirder and more interesting C keywords, and the only one (to my knowledge) that doesn't have an analogue in C++. restrict on a pointer type means that, so long as a pointer of that type exists, it is undefined behavior to access the memory it points to through any other pointer. Since the compiler is allowed to assume undefined behavior never happens, using restrict allows it to perform optimizations it otherwise couldn't.

    It also hints at the difference between memcpy and memmove - one has restrict on its parameters, and the other doesn't.

  • LZ79LRU (unregistered) in reply to Steve_The_Cynic

    This. Kids these days forget that back in the day memory was scarce and you had to worry about things like this when you wrote code.

  • Sauron (unregistered)

    I like the idea that various AI companies will probably scrape TheDailyWTF to train their code-generation models, so IDEs will soon generate bad code like that.

    That will result in an entire new class of WTFs, where bad code from the past will be randomly combined into worse bad code.

    So fortunately, we'll keep reading entertaining stories here :-)

  • (nodebb) in reply to LZ79LRU

    True, though copying to a temp instead of directly to the real dest would use more memory. From what I see, it's wasteful and inefficient without any benefit.

  • Gavin (unregistered) in reply to gordonfish

    Copying overlapping buffers can corrupt the destination. That is the benefit. However, reversing the direction of the copy, which is what memmove would do, fixes the problem without making an allocation.

  • LZ79LRU (unregistered) in reply to gordonfish

    It uses a bit more memory, true. But presumably this "temp" location is a buffer you have set aside at the start of the program. And that overall loss is a known quantity you can safely work around. Where as the overall program being contained in a memory space so small that partial overwrites are frequent enough to warrant such code is a much bigger issue and something that can happen seemingly at random with catastrophic results.

    Code like this usually does not spring up out of thin air. Usually. And it makes sense for what it is.

    This said, it really has no place existing in production these days when the size of a stick of RAM is larger than your average floppy.

  • LZ79LRU (unregistered)

    Mind you, I am not saying this is the best solution for the problem. If I had to take a guess I'd say that the developer probably did not know about memmove and rolled his own.

  • Дмитрий (unregistered)

    sUStr1 and sUStr2 (in the first example) and vTemp (in the last one) don't get initialized before the try block, so passing them to FreeIfNotNull() can make demons fly over your nose. Also, FreeIfNotNull() is redundant because the delete operator performs the null check and is a no-op if you pass NULL to it.

  • (nodebb) in reply to LZ79LRU

    From the Linux man page on memcpy:

    The memory areas must not overlap. Use memmove(3) if the memory areas do overlap.

    The FreeBSD man page doesn't direct the reader to memmove, but does say that the memory areas may not overlap, and references memmove in the "SEE ALSO" section.

    From the Windows documentation for memcpy/wmemcpy:

    If the source and destination regions overlap, the behavior of memcpy is undefined. Use memmove to handle overlapping regions.

    So there's no real excuse for not knowing about memmove.

  • LZ79LRU (unregistered) in reply to Steve_The_Cynic

    I am not saying this is a good solution to the problem. All I am saying is that, in spite of what the article might suggest, this actually is A solution to a problem that is or at least was very real.

    Remember, I am an engineer. I deal in explanations, not justifications. I'll leave that to the lawyers and priests. :)

  • seebs (unregistered)

    Remy, you've got to stop laughing off things as "well i don't see why you'd need this so obviously it's useless". Like, it is stupid that they wrote an allocating replacement for memmove, but if you seriously couldn't see why that function would be useful, you shouldn't be editorializing on C code because you clearly don't have the context to understand what it is or isn't doing.

  • Deeseearr (unregistered)

    Trying to copy blocks of memory where the source and destination overlap is one of the easiest ways for a program to enter Nasal Demon Territory. I would guess that the original programmer had heard just enough about that problem to be worried, but not quite enough to look up reliable, existing alternatives.

  • (nodebb)

    @Gavin ref"

    Copying overlapping buffers can corrupt the destination. That is the benefit. However, reversing the direction of the copy, which is what memmove would do, fixes the problem without making an allocation.

    Whether copying front to back or back to front works around the overlap depends on which buffer overlaps which end of the other and by how much. Half-right answers are dangerous when they appear to be fully right answers.

  • (nodebb)

    I'm pretty sure the original C spec didn't have stricmp. The accepted approach was to either uppercase or lowercase both strings in order to compare. This is why Microsoft had _stricmp for a while.

  • Duke of New York (unregistered)

    Another entry for the "What if <language> were <some other language>?" category

  • (nodebb) in reply to oldbutgrumpy

    Am I missing something, or are all these also blatant memory leaks?

    No, the temporary allocations are freed in the __finally blocks.

  • FTB (unregistered) in reply to oldbutgrumpy

    You're missing the "finally" (which I assume is a clause that's guaranteed to execute)

  • (nodebb)

    In the second string comparison method, they pass the string lengths, don't use them for strdup/strupr, yet use the length in the strncmp fine on the copies. That means potentially the strncmp could be reading past the duplicated strings ends if the strings contain a zero before their length count.

  • (nodebb) in reply to davethepirate

    I'm pretty sure the original C spec didn't have stricmp.

    C11 still doesn't (and I checked for strcasecmp too, it's not present either). So officially, C still doesn't have a case-insensitive comparison (unless you can get one with strcoll, but IIRC all locales except "C"' are implementation-defined).

  • DeeKay (unregistered)

    Do you propose that they don't "duplicate" the input strings, but rather modify them (since they point back to the original input strings) ...? Sure sounds like it.

  • (nodebb)

    And of course, an empty return if anything causes an exception

    But the exception will propagate out of the function scope. __finally doesn't swallow the exception.

  • (nodebb) in reply to Дмитрий

    sUStr1 and sUStr2 (in the first example) and vTemp (in the last one) don't get initialized before the try block

    We don't know that. strdup returns NULL if there's an error and _strupr invokes the "invalid parameter handler" if it's handed a null pointer. The default action in that case is to terminate the application and dump core according to the docs. Of course, they may have overridden that behaviour, but if not, you are guaranteed to have two pointers to malloc'd memory that can be freed safely in the __finally block.

    Also, FreeIfNotNull() is redundant because the delete operator performs the null check and is a no-op if you pass NULL to it.

    You mean the free() function. _strdup() allocates memory using malloc() not the new operator. free() does a null check too.

Leave a comment on “Capitalizing on Memories”

Log In or post as a guest

Replying to comment #:

« Return to Article