167

I was looking at the source code for nmap that was released in 1997 and I noticed this section of code that looks a little odd to me:

int i=0, j=0,start,end;
char *expr = strdup(origexpr);
ports = safe_malloc(65536 * sizeof(short));
i++;                                         /* <<<<<< */
i--;                                         /* <<<<<< */
for(;j < exlen; j++) 
  if (expr[j] != ' ') expr[i++] = expr[j]; 
expr[i] = '\0';

Why would you have i++; and then i--; right after each other? i is 0, then i++ turns i to 1. After that, i-- turns i to 0.

Link to original source code. Search for:

i++;
i--;

Can anyone explain what this is for?

mattst
  • 13,340
  • 4
  • 31
  • 43
DDiamond
  • 1,628
  • 2
  • 7
  • 17
  • 3
    There is no reason. – Nikos C. Mar 28 '20 at 13:57
  • 25
    Ask [the author](https://en.wikipedia.org/wiki/Gordon_Lyon). – DaBler Mar 28 '20 at 14:40
  • 8
    I'd guess they were part of some experimental or debugging code, which the author forgot to remove afterward. – Nate Eldredge Mar 28 '20 at 14:48
  • In a kernel code that could be a tiny delay, or a compiler optimization bug fix – Déjà vu Mar 28 '20 at 14:48
  • 1
    @RingØ: It probably won't work to produce a delay, because the compiler will optimize it out. – Nate Eldredge Mar 28 '20 at 14:52
  • @NateEldredge I assumed we're talking about an old code (1997, see answer), and compilers at the time..... – Déjà vu Mar 28 '20 at 14:53
  • 6
    The reason is obviously to confuse you, that's the only purpose :-) There's a small chance that this works around some compiler bug in some ancient compiler, in that case there should have been comment telling us this reason. – gnasher729 Mar 28 '20 at 14:58
  • 18
    @RingØ: For fun I tried it with gcc 1.27, circa 1988, on godbolt: https://godbolt.org/z/yYyFrQ. (It doesn't work with modern system headers so I had to declare all the standard library functions myself.) But with `-O` it does indeed optimize out those statements. – Nate Eldredge Mar 28 '20 at 14:59
  • 1
    There might have been some code in-between, which has then been deleted? – Eric Duminil Mar 29 '20 at 10:52
  • 1
    I was thinking, "Might have been that the data type used to be a custom class that overrode an operator..." only to see that it's C, not C++. – Kevin Mar 29 '20 at 21:41
  • 21
    It means the programmer was paid by the line... – TonyK Mar 30 '20 at 11:59
  • If i was a memory mapped i/o port then adding and subtracting would actually do something. So there are cases where you would write code like that. Of course, it isn't true because if that was the use case i should have been defined as volatile so that the reads and writes wouldn't be optimised out. – Jerry Jeremiah Mar 31 '20 at 03:39
  • Quite probably, there was a line of code, a function call between the i++ and the i--; The function call was removed temporarily, and was never restored. – Leslie Satenstein Apr 01 '20 at 01:32

4 Answers4

155

This was a bug. These lines together result in i being unchanged, so they shouldn't have been there.

The linked article that introduced nmap was published on September 1 1997. If you look at the SVN repository for nmap at https://svn.nmap.org/nmap, the initial revision checked in on February 10 1998 does not have those lines:

int i=0, j=0,start,end;
char *expr = strdup(origexpr);
char *mem = expr;

ports = safe_malloc(65536 * sizeof(short));
for(;j < exlen; j++) 
  if (expr[j] != ' ') expr[i++] = expr[j]; 
expr[i] = '\0';

So this is something the author found and fixed between publishing the initial nmap source code and the initial checkin to SVN.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • 1
    Hmm that page is missing `
    ` tags around the article, too; Chrome's inspector reveals how that leads to some document mangling during DOM construction ;)
    – Asteroids With Wings Mar 29 '20 at 01:37
  • Is it really a bug if it does not cause any unintended/unexpected behaviour? – Toivo Säwén Mar 30 '20 at 10:14
  • 4
    It confuses readers, which is completely unintended. I'd say it is clearly a bug. ;-) – sergut Mar 30 '20 at 11:30
  • 2
    @sergut Wikipedia does not agree with you, but [this blog post](https://www.yegor256.com/2015/06/11/wikipedia-bug-definition.html) does, and I'm inclined to as well :-) – Toivo Säwén Mar 30 '20 at 12:44
  • 4
    Now if `i` wasn't an int but some fancy class with operator overloads, it's possible (though unlikely and generally a sign of poor coding practices) that this could have some side effects. (Only applies if this were C++ of course.) – Darrel Hoffman Mar 30 '20 at 18:12
  • 5
    Maybe worth noting that in some contexts (memory-mapped IO), changing a variable can have external effects. – nullromo Mar 30 '20 at 18:17
41

It's useless. It does absolutely nothing.

If I were to speculate it's probably the remains of some debugging code that was used during development.

I'm guessing that either one of i++ or i-- was introduced in one change and the other was introduced in another.

I have no way to find the point of introduction, though, because there was no revision history between the initial source release and the first SVN revision.

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
  • 14
    I think the speculation about debugging code is accurate. I've seen so many different kind of debugging code just to get breakpoints where you expect them. – Nathan Goings Mar 30 '20 at 16:24
9

For a non-optimizing compiler, or one that recognized hardware side effects, the i++; i-- sequence would cause i to be read from memory, then re-written, regardless of the path taken through the for loop and nested if.

In parallel processing, sometimes compiler hacks are taken to ensure a code sequence uses its own local copies of variables rather than global copies.

Since the example is a code snippet, one cannot determine the compiler used, the expected operating system/hardware, nor whether this is in a code sequence/function that is possible to be executed as an independent thread.

In simpler systems, I've temporarily forced changes to variables to exercise the trap feature in a debugging environment. If that were the case, the author may have forgotten to remove the code when development was completed.

  • 1
    then why not just declare it as volatile? – vsz Mar 31 '20 at 04:56
  • 6
    The declaration of `i` as a local variable is shown in the code above, and there is no way it can be accessed by another thread at the point where the `i++; i--` lines are. – interjay Mar 31 '20 at 07:17
  • @vsz I rather think he means `i` is forced to be non-volatile. I haven't dealt with threading in C or C++ though, so I have no clue how it could be treated as volatile and how `i++; i--` would suppress that. – Egor Hans Apr 06 '20 at 14:49
  • volatile has other purposes besides thread-safety. It can also be used while debugging to ensure the compiler won't optimize it away. – vsz Apr 06 '20 at 16:37
2

I will suggest you to check the updated code only. If you use (i = 2+1) right after that (i-1) that make no sense . The value of i remains unchanged. You can try it using any c or c++ compiler. or even in any other language it is same. Run the code in compiler.

TripleM
  • 1,096
  • 7
  • 20