segmentation fault sometimes

Discussion in 'C Programming' started by Ken, Sep 10, 2009.

  1. Ken

    Ken Guest

    Hi,

    I have a little program running on Linux to draw a status bar with
    framebuffer, but it has segment fault after it is run several times,
    first time is ok usually, 2nd, 3rd times it produces segmentation
    fault core dump, it is caused by the line below, could anyone help how
    to fix the issue?

    *(fbp + location) = 255; /* has segmentation fault sometimes here */

    ---------------------------------------------------------------
    #include <unistd.h>
    #include <stdio.h>
    #include <fcntl.h>
    #include <linux/fb.h>
    #include <sys/mman.h>
    #include <stdlib.h>

    inline static unsigned short int make16color(unsigned char r, unsigned
    char g, unsigned char b)
    {
    return (
    (((r >> 3) & 31) << 11) |
    (((g >> 2) & 63) << 5) |
    ((b >> 3) & 31) );
    }

    int main(void) {
    int fbfd = 0;
    struct fb_var_screeninfo vinfo =
    { .xres=0, .yres=0, .bits_per_pixel=0,
    .xoffset=0, .yoffset=0 };
    struct fb_fix_screeninfo finfo = { .line_length=0 };
    long int screensize = 0;
    char *fbp = 0;
    unsigned x = 0, y = 0;
    int guage_height = 20, step = 10;
    unsigned int location = 0;

    // Open the file for reading and writing
    fbfd = open("/dev/fb0", O_RDWR);
    if (!fbfd) {
    printf("Error: cannot open framebuffer device.\n");
    exit(1);
    }
    printf("The framebuffer device was opened successfully.\n");

    // Get fixed screen information
    if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
    printf("Error reading fixed information.\n");
    exit(2);
    }

    // Get variable screen information
    if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
    printf("Error reading variable information.\n");
    exit(3);
    }
    // Figure out the size of the screen in bytes
    screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

    // Map the device to memory
    fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE,
    MAP_SHARED,
    fbfd, 0);

    if ((int)fbp == -1) {
    printf("Error: failed to map framebuffer device to memory.
    \n");
    exit(4);
    }
    printf("The framebuffer device was mapped to memory successfully.
    \n");

    //set to black color first
    memset(fbp, 0, screensize);
    //draw rectangle
    y = (vinfo.yres - guage_height) / 2 - 2; // Where we are
    going to put the pixel

    for (x = step - 2; x < vinfo.xres - step + 2; x++) {
    location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
    (y+vinfo.yoffset) * finfo.line_length;
    *(fbp + location) = 255; /* has segmentation fault sometimes
    here */
    }

    y = (vinfo.yres + guage_height) / 2 + 2; // Where we are
    going to put the pixel
    for (x = step - 2; x < vinfo.xres - step + 2; x++) {
    location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
    (y+vinfo.yoffset) * finfo.line_length;
    *(fbp + location) = 255;
    }

    x = step - 2;
    for (y = (vinfo.yres - guage_height) / 2 - 2; y < (vinfo.yres +
    guage_height) / 2 + 2; y++) {
    location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
    (y+vinfo.yoffset) * finfo.line_length;

    *(fbp + location) = 255;
    }

    x = vinfo.xres - step + 2;
    for (y = (vinfo.yres - guage_height) / 2 - 2; y < (vinfo.yres +
    guage_height) / 2 + 2; y++) {
    location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
    (y+vinfo.yoffset) * finfo.line_length;

    *(fbp + location) = 255;
    }

    // Figure out where in memory to put the pixel
    for ( x = step; x < vinfo.xres - step; x++ ) {
    for ( y = (vinfo.yres - guage_height) / 2; y < (vinfo.yres +
    guage_height) / 2; y++ ) {
    location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
    (y+vinfo.yoffset) * finfo.line_length;

    if ( vinfo.bits_per_pixel == 32 ) {
    *(fbp + location) = 100; // Some blue
    *(fbp + location + 1) = 15+(x-100)/2; // A little
    green
    *(fbp + location + 2) = 200-(y-100)/5; // A lot of
    red
    *(fbp + location + 3) = 0; // No transparency
    } else { //assume 16bpp
    unsigned char b = 255 * x / (vinfo.xres - step);
    unsigned char g = 255; // (x - 100)/6 A little
    green
    unsigned char r = 255; // A lot of red
    unsigned short int t = make16color(r, g, b);
    *((unsigned short int*)(fbp + location)) = t;
    }
    }
    usleep(200);
    }
    //clean framebuffer
    munmap(fbp, screensize);
    close(fbfd);

    return 0;
    }
    ---------------------------------------------------------------
     
    Ken, Sep 10, 2009
    #1
    1. Advertising

  2. In article <>,
    Ken <> wrote:
    >Hi,
    >
    >I have a little program running on Linux to draw a status bar with
    >framebuffer, but it has segment fault after it is run several times,
    >first time is ok usually, 2nd, 3rd times it produces segmentation
    >fault core dump, it is caused by the line below, could anyone help how
    >to fix the issue?


    The fact is, nobody here gives a shit about you or your problems.

    You may find some or all of the following links helpful in understanding
    why this is so:

    http://en.wikipedia.org/wiki/Aspergers
    http://en.wikipedia.org/wiki/Clique
    http://en.wikipedia.org/wiki/C_programming_language
     
    Kenny McCormack, Sep 10, 2009
    #2
    1. Advertising

  3. On Sep 9, 11:43 pm, Ken <> wrote:
    > Hi,
    >
    > I have a little program running on Linux to draw a status bar with
    > framebuffer, but it has segment fault after it is run several times,
    > first time is ok usually, 2nd, 3rd times it produces segmentation
    > fault core dump, it is caused by the line below, could anyone help how
    > to fix the issue?
    >


    A few suggestions:
    1) Valgrind is often very helpful for debugging memory corruption
    issues on linux. This can in general just tell you what is wrong.
    I'm not sure however it is as good with mmap'd memory as it is with
    *alloc memory.

    2) You could add either printfs or run under the debugger depending on
    your tastes for such. Displaying by some means the various fbp and
    location values prior to de-referencing will probably help you. Maybe
    location is unexpectedly calculated to a bigger size than screensize?

    -David
     
    David Resnick, Sep 10, 2009
    #3
  4. Ken

    Ken Guest

    On Sep 10, 6:16 pm, Richard Heathfield <> wrote:
    > In <>,
    >
    > Ken wrote:
    > > Hi,

    >
    > > I have a little program running on Linux to draw a status bar with
    > > framebuffer, but it has segment fault after it is run several times,
    > > first time is ok usually, 2nd, 3rd times it produces segmentation
    > > fault core dump, it is caused by the line below, could anyone help
    > > how to fix the issue?

    >
    > > *(fbp + location) = 255; /* has segmentation fault sometimes here */

    >
    > Idiomatically, this can be written as fbp[location] = 255, and this


    I changed it to fbp[location] = 255, thanks.

    > may give you a clue as to what is probably going wrong. The fbp
    > pointer represents an address in memory. It is of type char *, so any
    > addition to it (say, + n) results in another address, n bytes further
    > on in memory. If your program "owns" all the addresses in between,
    > you're fine. You're not fine, and therefore we may conclude that you
    > don't own all those addresses. The obvious candidate is location,
    > which is calculated immediately prior to your segfault.
    >
    >   location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
    >                  (y+vinfo.yoffset) * finfo.line_length;
    >
    > In your position, I would start off my debugging efforts by writing
    > some trace code that dumps values like x, vinfo.xoffset,
    > vinfo.bits_per_pixel/8, etc etc, to a file, all neatly labelled so
    > that you know what they are - and make sure the file is fflushed
    > before you move to the sometimes-segfaulting line. I think you'll
    > discover on examining the file that the result calculated and
    > assigned to location is screwed (either completely way out and
    > obvious, or perhaps more subtle, maybe just an off-by-one error in
    > one or more of the inputs to that calculation).


    These values are fixed to a specific video card.
    screensize=307200, vinfo.bits_per_pixel/8= 2, finfo.line_length=960,
    vinfo.xres = 480,
    when it is normal and there is no segment fault error, the location
    is : min=142096 max=143022,
    when segment fault happens, the following values are,

    (x,y), (vinfo.xoffset,vinfo.yoffset), location
    (8, 148), (0, 320), 449296

    I still don't figure out the root cause till now why it access memory
    out of the program.

    >
    > On a final note: despite all appearances to the contrary, your
    > question was topical here. It was not immediately obvious, however,
    > that this was the case, so don't be surprised if you get a few
    > kneejerk replies along the lines of "you're off-topic, go to a Linux
    > group".
    >
    > --
    > Richard Heathfield <http://www.cpax.org.uk>
    > Email: -http://www. +rjh@
    > "Usenet is a strange place" - dmr 29 July 1999
    > Sig line vacant - apply within
     
    Ken, Sep 11, 2009
    #4
  5. Ken

    Alan Curry Guest

    In article <>,
    Ken <> wrote:
    >
    >These values are fixed to a specific video card.
    >screensize=307200, vinfo.bits_per_pixel/8= 2, finfo.line_length=960,
    >vinfo.xres = 480,
    >when it is normal and there is no segment fault error, the location
    >is : min=142096 max=143022,
    >when segment fault happens, the following values are,
    >
    >(x,y), (vinfo.xoffset,vinfo.yoffset), location
    >(8, 148), (0, 320), 449296
    >
    >I still don't figure out the root cause till now why it access memory
    >out of the program.


    It looks like the yoffset is causing your trouble. Before going into detail,
    a preliminary question about the code.

    Given an (x,y) coordinate pair, you have used this formula to calculate an
    offset into the fb memory:

    location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
    (y+vinfo.yoffset) * finfo.line_length;

    Did you write that code yourself or copy it from somewhere? Can you explain
    what all the terms mean? I suspect you copied it and haven't actually found
    out what the xoffset and yoffset are for.

    I didn't know what they were for either, a few minutes ago. Documentation on
    the fb ioctls is too hard to find. But I think I've got it figured out:
    xoffset and yoffset are the offset from beginning of fb memory to the first
    visible pixel.

    You've got a lot more video RAM than you'd need to store a screenful of
    pixels at this resolution (by the way, 480 pixels horizontal? what a weird
    number). The fb driver is providing you a virtual screen that is bigger than
    the physical screen. By changing xoffset and yoffset, you can make the screen
    scroll smoothly, revealing previously hidden pieces of the virtual screen.

    Your location = ... calculation adds xoffset and yoffset to translate the
    (x,y) coordinates (taken as relative to the physical screen origin) into a
    byte offset (relative to the beginning of fb memory). So the byte offset can
    be anywhere within the virtual screen, but the size of your mmap was based on
    the physical resolution. You didn't mmap the entire virtual screen.

    You should use xres_virtual and yres_virtual when calculating the amount of
    memory to map. That would be

    screensize =
    vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel / 8;

    But there's still a bug there. Video modes can have unused padding bytes at
    the end of each row of pixels, for alignment purposes. The correct way to
    convert "number of rows" to "number of bytes" is to multiply by
    finfo.line_length (which you already did in the "location" formula, adding to
    my suspicion that you copied that code without understanding it.).

    line_length, also called the "stride" of the video mode, will be equal to
    vinfo.xres_virtual * vinfo.bits_per_pixel/8 in the normal no-padding case.

    The correct mmap size for all cases should be:

    screensize = vinfo.yres_virtual * finfo.line_length;

    If I've got all that right, there's still an unanswered question - what's
    causing yoffset to change between (or during) runs of your program? But maybe
    you won't need to answer that.

    --
    Alan Curry
     
    Alan Curry, Sep 11, 2009
    #5
  6. Ken

    Ken Guest

    On Sep 11, 6:07 pm, (Alan Curry) wrote:
    > In article <>,
    >
    > Ken <> wrote:
    >
    > >These values are fixed to a specific video card.
    > >screensize=307200, vinfo.bits_per_pixel/8= 2, finfo.line_length=960,
    > >vinfo.xres = 480,
    > >when it is normal and there is no segment fault error, the location
    > >is : min=142096 max=143022,
    > >when segment fault happens, the following values are,

    >
    > >(x,y), (vinfo.xoffset,vinfo.yoffset), location
    > >(8, 148), (0, 320), 449296

    >
    > >I still don't figure out the root cause till now why it access memory
    > >out of the program.

    >
    > It looks like the yoffset is causing your trouble. Before going into detail,
    > a preliminary question about the code.
    >
    > Given an (x,y) coordinate pair, you have used this formula to calculate an
    > offset into the fb memory:
    >
    > location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
    > (y+vinfo.yoffset) * finfo.line_length;
    >
    > Did you write that code yourself or copy it from somewhere? Can you explain
    > what all the terms mean? I suspect you copied it and haven't actually found
    > out what the xoffset and yoffset are for.
    >
    > I didn't know what they were for either, a few minutes ago. Documentation on
    > the fb ioctls is too hard to find. But I think I've got it figured out:
    > xoffset and yoffset are the offset from beginning of fb memory to the first
    > visible pixel.
    >
    > You've got a lot more video RAM than you'd need to store a screenful of
    > pixels at this resolution (by the way, 480 pixels horizontal? what a weird
    > number). The fb driver is providing you a virtual screen that is bigger than
    > the physical screen. By changing xoffset and yoffset, you can make the screen
    > scroll smoothly, revealing previously hidden pieces of the virtual screen.
    >
    > Your location = ... calculation adds xoffset and yoffset to translate the
    > (x,y) coordinates (taken as relative to the physical screen origin) into a
    > byte offset (relative to the beginning of fb memory). So the byte offset can
    > be anywhere within the virtual screen, but the size of your mmap was based on
    > the physical resolution. You didn't mmap the entire virtual screen.
    >
    > You should use xres_virtual and yres_virtual when calculating the amount of
    > memory to map. That would be
    >
    > screensize =
    > vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel / 8;
    >
    > But there's still a bug there. Video modes can have unused padding bytes at
    > the end of each row of pixels, for alignment purposes. The correct way to
    > convert "number of rows" to "number of bytes" is to multiply by
    > finfo.line_length (which you already did in the "location" formula, adding to
    > my suspicion that you copied that code without understanding it.).


    Yes are right, I copied the code from some elsewhere post on Internet
    and added minor change to correct bugs, I'd just play with this
    program and learn from it, but the segment fault bug needs the expert
    help in this group.

    >
    > line_length, also called the "stride" of the video mode, will be equal to
    > vinfo.xres_virtual * vinfo.bits_per_pixel/8 in the normal no-padding case.
    >
    > The correct mmap size for all cases should be:
    >
    > screensize = vinfo.yres_virtual * finfo.line_length;


    This fixed the segment fault bug here eventually, I learn from the
    struct fb_fix_screeninfo actually the screen size is finfo.smem_len,
    so instead of calculating it, just using smem_len is ok, I also
    verified, your fixed screensize equals to the smem_len.

    Another on-topic question is,
    We can write *(fbp + location) = 255; as fbp[location] = 255; per the
    suggestion in the thread.
    how to rewrite below statement?
    ((unsigned short int*)(fbp+location)) = t;
    If I rewrite it to fbp[location] = t, then I'll get wrong result.

    >
    > If I've got all that right, there's still an unanswered question - what's
    > causing yoffset to change between (or during) runs of your program? But maybe
    > you won't need to answer that.


    This is what I can not answer as you may see it, I also don't know why
    it is changed between several runs, it is set to zero during
    initialization in fact.
    struct fb_var_screeninfo vinfo =
    { .xres=0, .yres=0, .bits_per_pixel=0,
    .xoffset=0, .yoffset=0 };

    >
    > --
    > Alan Curry
     
    Ken, Sep 14, 2009
    #6
  7. Ken

    Alan Curry Guest

    In article <>,
    Ken <> wrote:
    >On Sep 11, 6:07 pm, (Alan Curry) wrote:
    >> In article

    >
    >Another on-topic question is,
    >We can write *(fbp + location) = 255; as fbp[location] = 255; per the
    >suggestion in the thread.
    >how to rewrite below statement?
    >((unsigned short int*)(fbp+location)) = t;
    >If I rewrite it to fbp[location] = t, then I'll get wrong result.


    That won't easily translate to array syntax because of the mixed pointer
    types. You have a pointer that is mismatched to the actual underlying
    hardware data format, but you have a great excuse: the actual underlying
    hardware data format is not known until runtime. There's gotta be a
    conversion somewhere. The cast is justified. You could hide the addition by
    translating fbp+location into &fbp[location] but I wouldn't consider that an
    improvement.

    >
    >>
    >> If I've got all that right, there's still an unanswered question - what's
    >> causing yoffset to change between (or during) runs of your program? But maybe
    >> you won't need to answer that.

    >
    >This is what I can not answer as you may see it, I also don't know why
    >it is changed between several runs, it is set to zero during
    >initialization in fact.
    > struct fb_var_screeninfo vinfo =
    >{ .xres=0, .yres=0, .bits_per_pixel=0,
    > .xoffset=0, .yoffset=0 };


    Those initial values have no effect because you didn't send them to the
    kernel (with a PUT ioctl). Your first GET ioctl overwrote them. All those
    pretty 0's were never used.

    --
    Alan Curry
     
    Alan Curry, Sep 14, 2009
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Saunders
    Replies:
    0
    Views:
    493
    John Saunders
    Aug 28, 2003
  2. Nehmo Sergheyev
    Replies:
    1
    Views:
    526
    Andrew Urquhart
    May 9, 2004
  3. Marcin Vorbrodt

    ::std sometimes needed, sometimes not

    Marcin Vorbrodt, Sep 16, 2003, in forum: C++
    Replies:
    24
    Views:
    803
    Jerry Coffin
    Sep 17, 2003
  4. Replies:
    1
    Views:
    527
    gkelly
    Nov 29, 2006
  5. Randy Smith
    Replies:
    2
    Views:
    479
    Randy Smith
    Apr 24, 2007
Loading...

Share This Page