3

I have this piece of code in a function. I want to print the value of y here.

if (x1 < 0 || y1 < 0) {

    // Vertical lign outside of layer
    if (dx == 0 && y1 < 0) {
        return GKIT_NOERR;
    }

    float m = dy / dx;
    float t = y1 - m * x1;
    float x = -t / m;
    float y = m * x + t;

    printf("Hello %s. You are %f years old.\n", "Niklas", y);
}

But I get a segmentation fault. It works with no value at all to be printed as float. I can change that to %d or similar, which works fine.

    int val = (int) y;
    printf("Hello %s. You are %d years old.\n", "Niklas", val);

Any idea where the Segfault comes from?

Edit: Complete function.

// coding: ascii
// author: Niklas Rosenstein
// e-mail: rosensteinniklas@googlemail.com

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gkit/defines.h"
#include "gkit/utils.h"
#include "gkit/graphicslayer.h"

#define SWAP_IF_NECCESSARY(x1, y1, x2, y2)  \
    if (x2 < x1 && y2 < y1) {               \
        int temp = x2;                      \
        x2 = x1;                            \
        x1 = temp;                          \
        temp = y2;                          \
        y2 = y1;                            \
        y1 = temp;                          \
    }

/* Based on Bresenhams line algorithm. */
int gk_GraphicsLayer_drawLine(gk_GraphicsLayer* layer, gk_Color* color,
                              int x1, int y1, int x2, int y2,
                              gk_ColorBlendProc blend, gk_float opacity) {
    SWAP_IF_NECCESSARY(x1, y1, x2, y2);

    float dx = x2 - x1;
    float dy = y2 - y1;
    float cx = x1;
    float cy = y1;

    // Figure out where to start in case x1 or y1 are outside of the layer.
    if (x1 < 0 || y1 < 0) {

        // Vertical lign outside of layer
        if (dx == 0 && y1 < 0) {
            return GKIT_NOERR;
        }

        // The function's slope (m)
        // ------------------------
        float m = dy / dx;


        // Find the y-axis intersection (t)
        // -------------------------------
        // y = mx + t   =>
        // y - mx = t

        float t = y1 - m * x1;

        // Compute the root of the function (N)
        // ------------------------------------
        // 0 = mx + t   =>
        // mx = -t      =>
        // x = -t / m

        float x = -t / m;
        float y = m * x + t;

        printf("Hello %s. You are %f years old.\n", "Niklas", y);
    }


    int incx = GKIT_SIGNUM(dx);
    int incy = GKIT_SIGNUM(dy);
    if (dx < 0) { dx = -dx; }
    if (dy < 0) { dy = -dy; }

    int pdx, pdy;
    int ddx, ddy;
    int es, el;

    ddx = incx;
    ddy = incy;

    if (dx > dy) {
        pdx = incx;
        pdy = 0;
        es = dy;
        el = dx;
    }
    else {
        pdx = 0;
        pdy = incy;
        es = dx;
        el = dy;
    }

    float err = el / 2.0;

    #define SET_PIXEL(x, y) \
        do { \
        gk_Color* c = GKIT_GRAPHICSLAYER_ACCESSPIXEL(layer, (int)x, (int)y); \
        if (blend != Null) {                \
            gk_Color t = *c;                \
            blend(color, &t, c, opacity);   \
        }                                   \
        else {                              \
            *c = *color;                    \
        } } while (0)

    SET_PIXEL(cx, cy);

    int t;
    for (t=0; t < el; t++) {
        err -= es;
        if (err < 0) {
            err += el;
            cx += ddx;
            cy += ddy;
        }
        else {
            cx += pdx;
            cy += pdy;
        }
        SET_PIXEL(cx, cy);
    }

    #undef SET_PIXEL

    return GKIT_NOERR;
}

Edit: Complete stack trace:

#0 0xb7e68cb0   ___printf_fp(fp=0xb7fc3a20, info=0xbffff684, args=0xbffff6f8) (printf_fp.c:844)
#1 0xb7e63ab0   _IO_vfprintf_internal(s=0xb7fc3a20, format=<optimized out>, ap=0xbffff750 "\001") (vfprintf.c:1623)
#2 0xb7e6cc2f   __printf(format=0x8049da0 "Hello %s. You are %f years old.\n") (printf.c:35)
#3 0x8049143    gk_GraphicsLayer_drawLine(layer=0x804d008, color=0xbffff810, x1=-20, y1=-10, x2=49, y2=200, blend=0, opacity=0) (/home/niklas/git/c-gkit/gkit/graphicslayer.c:180)
#4 0x8049ba4    test_drawLine() (/home/niklas/git/c-gkit/main.c:46)
#5 0x8049c80    main() (/home/niklas/git/c-gkit/main.c:68)

Edit: Please note that printf() does work when putting it after or before the if-clause. I.e. Something like

    printf("Foo: %f\n", 1.0);
    // Figure out where to start in case x1 or y1 are outside of the layer.
    if (x1 < 0 || y1 < 0) {

        // Vertical lign outside of layer
        if (dx == 0 && y1 < 0) {
            return GKIT_NOERR;
        }

does work, but moving the printf() inside the if-clause yields a segmentation fault.

Update: According to T.E.D.'s answer, I've tested around a little and this is what came out:

The problem seem the be the outcome of the comparison operations (<). I can do

if (True) { printf("%f", 53.3); }

but I can't do

if (x1 < 0 || y1 < 0) { printf("%f", 53.3); }
// nor
if (x1 < 0) { printf("%f", 53.3); }
// nor
int x_smaller = x1 < 0;
if (x_smaller) { printf("%f", 53.3); }

Interesting is, that this works:

int x_smaller = x1 < 0;
int y_smaller = y1 < 0;
x_smaller = y_smaller = 1;
if (x_smaller || y_smaller) { printf("%f", 53.3); }

Conclusion: The outcome of the operations x1 < 0 and y1 < 0 tested in the if-clause make printf() fail. The questions are:

  1. DAFUQ? Why is this happening?
  2. How can I fix it?

If you are interested in the whole code, I don't mind sharing it. It's on github. It's a Code::Blocks project. The only include-path must be to the parent-directory of the gkit folder.

Niklas R
  • 16,299
  • 28
  • 108
  • 203
  • 2
    Is there a complete piece of code (i.e. including the `main()` and all `#include`s) to test? – kennytm Jun 26 '12 at 15:16
  • It's part of a library I'm writing and is dependent on many of it's contents. I can post the code of course, it's basically part of the Bresenham Algorithm and the code above should figure out where to start the line in case the given points lay outside of the drawing-area. – Niklas R Jun 26 '12 at 15:18
  • 4
    Have you determined where the segfault occurs by examining a stack trace? Chances are good it occurs well past this printf. – William Pursell Jun 26 '12 at 15:19
  • @WilliamPursell Well, when the given points *are* outside of the drawing-area, it gave a segfault. That's why I made a `return GKIT_NOERR` at the end of the first code's if-clause in my code (so it doesn't crash when the if-clause runs fine). Second, see the edit. – Niklas R Jun 26 '12 at 15:22
  • @NiklasR The "complete" function does help. The code doesn't compile without the required headers, and there's no `main()` to invoke `gk_GraphicsLayer_drawLine()`. – Eitan T Jun 26 '12 at 15:22
  • @EitanT `gk_GraphicalLayer_drawLine()` runs when passing valid parameters. But when they lie outside of the drawing area, although the line goes through it, it crashes (because it accesses pixels that are not available) That's what the if-clause was for. – Niklas R Jun 26 '12 at 15:26
  • @NiklasR Also, what is the point of calculating `y`? Substituting `x` into `y` yields `y = -t + t = 0`. – Eitan T Jun 26 '12 at 15:28
  • @EitanT Hm, that's right. I don't need that value. Well, would've noticed that when it's finsihed. :D – Niklas R Jun 26 '12 at 15:30
  • Could it be that your dx is 0!!! your comparison right before usage checks for 2 conditions with an and. If dx is 0 and the other case isn't true, you could have a infinite condition occurring!!! – trumpetlicks Jun 26 '12 at 15:32
  • @trumpetlicks Nope, from the stack trace that `dx = x2 - x1 = 49 - (-20) = 69` – Eitan T Jun 26 '12 at 15:34
  • Try this: add `#include ` at the top, and use `printf("%d %d\n", isnan(y), isinf(y))` in the body. It looks like there is a condition under which your `y` would be a non-number. – Sergey Kalinichenko Jun 26 '12 at 15:34
  • @EitanT No, it isn't. Quote: *It works with no value at all to be printed as float*. See also the recent edit. – Niklas R Jun 26 '12 at 15:37
  • @trumpetlicks what are you talkin about? – Niklas R Jun 26 '12 at 15:39
  • @dasblinkenlight prints `0 0`. – Niklas R Jun 26 '12 at 15:40
  • @NiklasR What platform/compiler are you using? – Eitan T Jun 26 '12 at 15:46
  • does it segfault when first encountering the `printf` or do you run `drawLine` in a loop and it crashes on second iteration or later? – unkulunkulu Jun 26 '12 at 15:46
  • anyway, try commenting `*c = color` and then recompile and run. – unkulunkulu Jun 26 '12 at 15:47
  • ok, there should be something with writing to wrong memory addresses, but it could as well happen in the outer functions, so this context is still not enough, I believe – unkulunkulu Jun 26 '12 at 15:50
  • @unkulunkulu `drawLine` is called once. `*c = color` is *not* where the error is. To your satisfaction, I did comment it out, and it does not have any effect. My latest update contains some additional information. – Niklas R Jun 26 '12 at 15:51
  • @EitanT I'm currently on *Ubuntu LTS 12.04* (32-Bit) running *gcc 4.6.3* which was distributed along the OS. – Niklas R Jun 26 '12 at 15:54
  • @NiklasR, minimization is the way to go, start removing all the unrelevant code, or maybe a dichotomy is on option: just paste this code at the start of `main`, it should work, then advance it through the code to the point where it is now and find the culprit. – unkulunkulu Jun 26 '12 at 15:56
  • @unkulunkulu The whole code?! Or do you mean the `printf()` call? – Niklas R Jun 26 '12 at 15:56
  • @Niklas R - In your "if (dx == 0 && y1 < 0)" You will pass right over this if dx == 0 and y1 is 0 or greater. In your next line, you divide dy by dx to obtain m, if dx is 0, then you end up with an infinite result!!! – trumpetlicks Jun 26 '12 at 15:57
  • @NiklasR, the start of the function, with `if`s and `printfs`, the minimal portion that doesn't work. You can explicitly define `x1`, `x2` etc and initialize them to known values that are passed to your function, i.e. make a code that doesn't depend on the context. – unkulunkulu Jun 26 '12 at 15:58
  • @trumpetlicks Shouldn't matter to `printf`, that ought to print infinities or NaNs fine. – Daniel Fischer Jun 26 '12 at 16:00
  • @trumpetlicks Ahh, I see what you mean. I actually thought, the program will fail then ^.^ However, `printf("%f\n", 1.0 / 0.0);` prints `inf`. *Btw, how is `inf` represented in memory?* – Niklas R Jun 26 '12 at 16:03
  • @NiklasR, you want to know everything at the same time, good :D `inf` has a maximum possible exponent _and_ zero mantissa in float, this is how it's represented internally, but let's return to business :D – unkulunkulu Jun 26 '12 at 16:04
  • @unkulunkulu http://pastebin.com/NfBA76kY, works. This context is `main()->test_printfError()`, and the original context is `main()->test_drawLine()->gk_GraphicalLayer_drawLine()` – Niklas R Jun 26 '12 at 16:08
  • @unkulunkulu Ah thanks. :) PS: Would be good to know why I got downvoted again.. – Niklas R Jun 26 '12 at 16:08
  • @NiklasR, right, move it line after line deeper. First of all, test it at the start of `.._drawLine`, make it fail here. – unkulunkulu Jun 26 '12 at 16:09
  • @unkulunkulu Oh ok. So what's wrong with the question? **THIS IS CONFUSING**: When I put the printing code at the very beginning of `drawLine`, the error still occurs. But returning after the printing-code does work fine! Does that mean, the code *behind* the if-clause influences printf so it doesn't work anymore?! O.o Thanks for your help, btw. :) PS: Maybe you haven't seen, but you can download the complete source-code from github (see bottom of my question) – Niklas R Jun 26 '12 at 16:31
  • @NiklasR, no, code behind the `if` shouldn't be the cause, at least, I haven`t seen such a weird behaviour. What do you mean 'returning after the printing-code' does work fine? I browsed the code on github but haven't downloaded it. – unkulunkulu Jun 26 '12 at 16:38
  • @NiklasR, this is the kind of 'please debug my code for me' question, not a programming question that can be useful to anyone else. I personally just like debugging weird things sometimes and I understand the frustration, so I'm helping, but stackoverflow is not a place for such things really – unkulunkulu Jun 26 '12 at 16:39
  • @unkulunkulu let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/13064/discussion-between-niklas-r-and-unkulunkulu) – Niklas R Jun 26 '12 at 16:40
  • @unkulunkulu Thanks for helping me solving this issue in the chat!! Tell me whether you want to write an answer, otherwise I'm going to write it. – Niklas R Jun 26 '12 at 17:26
  • @NiklasR, you're welcome. Probably writing it yourself would be beneficial, so I'll leave that up to you :D – unkulunkulu Jun 26 '12 at 19:11
  • @unkulunkulu I've added the answer. :) – Niklas R Jun 26 '12 at 21:11

2 Answers2

3

This is exactly why I hate printf(). It is about the most error-prone routine in an otherwise error-prone language.

The first thing to do with a "werid" crash is to simplify the logic to try to narrow it down.

In this case, I'd next try setting your float to a known value (eg: 1.0) right before the printf. It could be that your printf has a bug on some weird value that you happen to have in there.

If that works (prints 1.0) then my next step would be to try to print the bits in that variable. For C, that would probably be changing the format to %x and the parameter to something like *((unsigned int *)(&y))

If it didn't work (I'm guessing not from your comment) keep simplifying. Try removing the %s and its parameter (kind of unnessecary ATM anyway). If that still fails, either try:

  • moving your broken code snippet into a stand-alone "main" and then (assuming it works) add in code until it breaks.
  • commenting out code from your existing code until you find something that makes it work.
T.E.D.
  • 44,016
  • 10
  • 73
  • 134
  • Should `printf("Hello %s. You are %f years old.\n", "Niklas", 1.0);` work with your approach? Because it doesnt... Making `%d` instead works. ._.' Ah, already forgot to tell that `printf` works in another context. I.e. outside the if-clause. Should add that.. – Niklas R Jun 26 '12 at 15:31
  • 3
    my bet is that the `printf` itself is completely innocent here, stack must be broken. – unkulunkulu Jun 26 '12 at 15:57
  • @unkulunkulu - My suspicion too now. Performing either bullet in my answer should help pinpoint the culprit. – T.E.D. Jun 26 '12 at 16:20
  • @T.E.D., right, performing that in the comments to the question itself. – unkulunkulu Jun 26 '12 at 16:22
  • 1
    The language is not error prone if you don't know it sufficiently well. It is otherwise. Don't blame the language. Blame its misuse. – Alexey Frunze Jun 26 '12 at 21:42
  • @Alex - I don't disagree. But as someone who writes stuff actual users have to operate, one thing I've leared over the years is that if certian things keep screwing up your users over and over again, at some point you have to quit blaming the users and admit there's a problem. – T.E.D. Jun 26 '12 at 21:53
  • Then perhaps the problem is not in C, but in choosing C? – Alexey Frunze Jun 26 '12 at 22:18
  • @AlexeyFrunze - Yes. Although I find these days most of the time C isn't a choice, but something you end up with no other real choice but to use for some reason. It has become sort of the Denny's of languages. :-) – T.E.D. Jun 29 '12 at 14:57
2

Thanks to unkulunkulu, who provided his help in the chat, we were able to find the issue.

I couldn't believe that previous calls to gk_GraphicsLayer_drawLine could influence the behaviour of following calls, but exactly this was the case. In my main() function, I called the function three times. The first call recieved accidently values that did also reach out of bounds of the pixel-array of gk_GraphicsLayer. The third call was the one who finally crashed the program.

This also explains why exiting the function after the if-clause (where the error appeared in) fixed the segfault. It was because it prevented the function from accessing memory it shouldn't access.

Summary: Writing to the memory of an invalid address is so much dangerous, it can even trigger a completely other function to fail and lead you to miss-asumptions. Unfortunately, one doesn't recieve Segmentation Fault errors when the invalid address is still in range of the memory that was supplied by the OS for your application.

Community
  • 1
  • 1
Niklas R
  • 16,299
  • 28
  • 108
  • 203