Breakpoint Boogaloo



  • We've all seen breakpoints. (If you haven't, then what are you doing here?)

    Most of us have also heard of, seen, or used "load-bearing" print statements. (You've probably done this in college.)

    I'm working on a project with 3 other people. Two are student interns (and as such, I forgive their mistakes). The other guy is, let's say, "Guy" from, let's say, "France". Guy is also the project leader. The project is complex and was broken into multiple segments. One of the segments was a TCP connection between a VS.NET system and a DSP running C. Due to delays, I've ended up writing the code for most of the project while the other 3 people have worked on the TCP connection. I can't say much about the project.

    The VS.NET side only sends one packet out - it's a one-shot deal. If you want to resend another packet, you have to restart the program and try again. If you want to run the program on another computer, you have to find the undocumented line where the DNS.Resolve line is called and change your address. Never mind timers or loops or hey, even a button to send another packet. If you want more data, you have to restart the program. When I told him he should - at the very least - put a button on there, he said he'd "get one of the interns to do it."

    On the DSP side, the code that Guy wrote only works when you insert a breakpoint then start the code again. I've tried to explain how wrong that is. Since Guy only really speaks French, it's like speaking to a toddler. His response was that the networking code was from another project, so it's up to that other project to fix it.

    I came up with a fix, and he got upset that I committed it to the repository. (My fix only worked part of the time, and didn't work on his machine., but it was pretty close.) He went back to his old version, saying at least his code worked. I replied, "No. If you have to insert a breakpoint into the code to make it run, it doesn't work. End Of Story."

    So there you have it: a load-bearing breakpoint.



  • W.O.W. - Just - W.O.W.



  • "load-bearing" print statements?

    Are we talking about something like, print $x++;?



  • @merreborn said:

    "load-bearing" print statements?

    Are we talking about something like, print $x++;?

    A load-bearing print statement is one that is required for your code to run correctly. This happens because the printf statements (and all their derivatives) take a loooong time to execute. While they can be used to create a delay, it's sort of like using hammer to drive a screw in because you either can't find nails or can't be bothered to look for a screwdriver. Edit: Actually, it's more like using a rock because you don't know what hammers are.

    What usually happens is someone will write a program that doesn't work correctly. A value will be incremented dozens of times or a statement will be executed prematurely.  Instead of using the debugger, the intrepid programmer will add a debugging line:

      printf( "Value at point A: %x\n\r", SomeValue );

    And re-run the code. The pause will be enough to let the ports settle, or stop a race condition, or do something else. At least, it will work "in the lab".

    I half-remember doing it myself a few times in college.



  • @themagni said:

    At least, it will work "in the lab".

    And later, to make it work in the real world, you'll simply change your printf() to an fprintf() with a FILE* that points off into oblivion. Or at least, into someplace you don't think the user will see it... like COM2, as an anonymous developer once did in a program that got purchased in quantity by a former employer of mine.

    Trouble is, my system had a dot-matrix printer so I could print multi-part forms. So occasionally, I'd be running the program, and it would spew a single line of incomprehensible garbage onto my printer - ruining the loaded form and getting everything out of alignment. It took about an hour to realign the printer forms so the data ended up in the right blanks.

    Eventually, I figured out which part of the program was causing this, and spent many hours over the course of two weeks tracking down the offending code with their tech support. Once they found it, they told me they couldn't take it out because if they did the code would stop working. (There was a comment to that effect in the code.)

    So I suggested they try the deep voodoo magic of... sleep().

    Normally, when I suggest code that impresses another programmer, it makes me feel proud... but in this case, I felt somehow dirty and ashamed.



  • I once had a similar problem where code worked with a printf, but not without it.Oh, and only a complex printf... simply printing "TEST" didn't work.

    This was for an embedded system, and the compiler could output as assembler if you wanted. This allowed me to track down what was going on... The compiler had a bug in its register optimization.

    With optimization turned off you could see it calculate the result of one argument in R2, then write R2 into a memory location on the stack (This was my automatic variable). Later, it would read the value of that automatic from the same place on the stack.

    Turn on optimization (you needed to to fit the whole thing in ROM) and you could see that most automatic variables got register optimized. In this case it allocated R8 to this variable, so when it did the original calculation it did it in R8 rather than in R2. Great... except that when the later code came to use the value, it read it from R2 (the normal working register that holds the result temporarily in the un-optimized code!).

    Put in a printf statement and it can no longer register optimize. Why? Well, this compiler had another optimization in that it tried to pass function parameters in registers rather than on the stack, and of course a nice complex printf uses loads of parameters and so none are left for register optimization.



  • @themagni said:

    We've all seen breakpoints. (If you haven't, then what are you doing here?)

    ...

    So there you have it: a load-bearing breakpoint.



    I thought you were going to talk about a WTF I perpetrated (I plead extenuating circumstances).

    A production system was having issues.  I tracked the problem down to a variable not being updated at a certain point in the code.  Actually taking the system down to install a new version was not an option.  The "solution?"  Attach to the running process in the debugger, add a breakpoint with an executable statement to alter the variable, and detach from the process, leaving it running with the breakpoint active.  Of course, if the process ever restarted, you'd lose the patch, but the fixed executable was ready by then.



  • Wow, nice stories here



    I once had a similar problem too, it was an Asp.Net application written in vb.net (god only knows why):



    A page (and only one page) would not work if the build was set to "Production" or "Release", compiler HAD to be set to "Debug".



    I could, however, trace where the method and the line of the problem: it was a variable asignation, yup:



    var1= var2            'not actual variable names



    And both variables were strings, wtf?
    Almost sure it was a bug on the compiler (.Net version 1.1.4322). I'm not sure what was the solution but it was either

    a) Create a temp var to avoid "direct assignation" hehe
    b) Create a new function with the same code and call this new function.

    Mike Rod



  • @themagni said:

    @merreborn said:

    "load-bearing" print statements?

    Are we talking about something like, print $x++;?

    A load-bearing print statement is one that is required for your code to run correctly. This happens because the printf statements (and all their derivatives) take a loooong time to execute. While they can be used to create a delay, it's sort of like using hammer to drive a screw in because you either can't find nails or can't be bothered to look for a screwdriver. Edit: Actually, it's more like using a rock because you don't know what hammers are.

    Sounds more like wrapping a pillow around your thumb so that it doesn't hurt that much when you hit with the hammer because, for some reason, it keeps landing directly on your hand.

    This is just plain stupid.  Good luck!
        dZ.


  • Ah this reminds me of a perl app I was in charge of. It was this beautiful multi-threaded application. Ran clustered across 7 machines. You really have never seen a perl program written this beautifully. I know even the idea is an oxymoron for some...

    After a while we started noticing that around the same time of night the queuing system would go completely out of control. It would suddenly decide that all the tests we put in to keep it from requesting more jobs then it could handle were ignored and it was just sucking in as much work as it could get.

    We tracked this down to a daemon loop like this:

    while($running) {
        if(isWorkToDo()) {
            doWork();
        }
        sleep(5000);
    }

    Turns out that perl's sleep function call doesn't actually sleep under load and so we had a beautifully hidden race condition. We had logs that had log4perl timestamps and I can't tell you how long we stared at the timestamps in the logs, not believing that the program was actually asking for 10 jobs in the same second. For those who might suspect their own programs the solution is:

    use Time::HiRes qw(sleep);


  • Another reason for "load bearing printfs" is if your stack or heap are messed up (e.g. buffer overrun), but the printf "fixes" it or avoids it with a side effect that seperates the buffer overrun from tthe important stuff you'll use later on...



  • @tthomas48 said:

    ...



    After a while we started noticing that around the same time of night the queuing system would go completely out of control.



    ...




    i am a bit off-topic, but this one reminds me of a bug i encountered
    after updating one of our application to use the system clock instead
    of the encoder signal linked to a conveyor belt: the software, though
    working without any problems all day long, would crash on every
    overnight test.



    it took me some nights to be able to reproduce the problem at
    will: if a (simulated) product entered the system the second before
    midnight, the software would wait for an event to happen just after
    midnight, but the system clock was reset to 0 at midnight, so the event
    would never be fired and products would continue to stack up into the
    system until the event queue overflows.



    i remember i even considered staying all night long starring at the
    computer just to see the software crash...  bad bug ! bad, bad bug !
    sit, bug ( (c)2006 ParkinT )




    (fyi: the same problem existed before the update. when the encoder
    would wraparound, it would make the software crash. the problem was
    known, but the original developper calculated that
    it would take some months before it could happen, and so decided to
    NOT correct it... and NOT document it !)



  • Did "French" "Guy"'s first name begin with a J?

    I have worked with a WTF-worthy French .NET programmer and didn't think there could be that many in the world....



  • @pitofdarkness said:

    Did "French" "Guy"'s first name begin with a J?

    I have worked with a WTF-worthy French .NET programmer and didn't think there could be that many in the world....

    He's not actually French. I just picked a different country at random for anonymity.



  • [quote user="themagni"]

    He's not actually French. I just picked a different country at random for anonymity.

    [/quote]

    Careful... Things like that can turn into expressions. Like in: "I once worked with a "french" programmer."... ;)


Log in to reply