Reputation: 16870
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: [email protected]
#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:
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.
Upvotes: 3
Views: 2950
Reputation: 16870
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.
Upvotes: 2
Reputation: 44804
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:
Upvotes: 3