0

In the SDL_Surface structure, is there a way to calculate the bounds of the pixels Member?

I need a quicker way of doing this, so my code doesn't catch seg-faults while running.

On my Linux Laptop, my code runs a segfault when I run it there. On my Samsung A04e (Termux+vnc) It runs fine; there is absolutely no problem.

This is the gdb session output messages : https://imgur.com/a/Y30J0Zq

The code that is causing the seg fault. Is In my custom wrapper for freetype2. For performance/RAM reasons, I did not use SDL_ttf/SDL2_ttf.

Read code here :

for( uy = 0; uy < bm.rows; ++uy )  {
    for( ux = 0; ux < bm.width; ++ux )  {
      bitmap_alpha = bm.buffer[ ( bm.pitch * uy ) + ux ];
      if( bitmap_alpha != 0  ) {
        color_ptr->a = bitmap_alpha;
       
        if(( (x+ux) <= canvas->w  ) && ((y+uy) <= canvas->h) ) {
        Transparent_Color = B2D_CalculateNewPixelAlphaColor(canvas,x+ux,y+uy,color_ptr );
        B2D_DrawQuickPixel_WithoutTransparency(canvas, x+ux, y+uy, &Transparent_Color);
        }

        color_ptr->a = original_alpha;
      } 
    } 
  }

The code within B2D_CalculateNewPixelAlphaColor() that caused the bug.

if(xpos < 0)
    xpos = 1;
  if(ypos < 0)
    ypos = 1;
  if(ypos >= canvas->h)
    ypos = canvas->h;
  if(xpos >= canvas->w)
    xpos = canvas->w;
  END_SUB

  /* Step 1 - Get the color of the pixel we intend to overwrite.*/
  
  /* I need the bounds checking here in the pixel array: HERE SPECIFICALLY */
  SDL_Color destination_color;
  SDL_GetRGBA (((Uint32*)canvas->pixels)[(ypos)*(canvas->pitch>>2)+xpos], canvas->format, &destination_color.r,&destination_color.g, &destination_color.b,&destination_color.a);

There is nothing wrong with this code I wrote it in 2023, and it worked for years But just after I updated my distro last week... Nothing is working.

I am running low on time, and I'm quite busy. I want to shut the debugger up so I can finish writing my code and deploy it.

I need a way to perform a bounds check on the sdl_surface->pixels member. I looked online on GitHub, and found some of what I wanted in (src/video/SDL_Surface.c) (line 94 and Line 64)

The function called

bool  SDL_CalculateSurfaceSize()

But ... I want to know if someone here on this platform knows something that I don't before I try something that may or may not work.

I need to know how much was allocated, So I can cache it in my local code, so I put an end to these annoyances.

EDIT After a reboot, recompile the bug is gone... but the question is still valid.

4
  • 1
    "this code I wrote it in 2023, and it worked for years But just after I updated my distro last week... Nothing is working." It does sound as if you have an undefined behavior bug somewhere, not necessarily related to bounds-checking. Commented Oct 3 at 9:13
  • 1
    ( bm.pitch * uy ) + ux maybe it should be ( bm.width * uy ) + ux ? Commented Oct 3 at 9:17
  • You're casting the pixels pointer from void * to Uint32 *. That could be right, or it could be wrong. Presumably, the original type is declared as void * because the pointed-to elements can be of different type depending on the circumstances. Commented Oct 3 at 13:56
  • @Lundin, documentation is surprisingly sparse, but it seems that in SDL2, this "pitch" is the number of bytes from the beginning of one row of a raster to the beginning of the next (a row pitch rather than a pixel pitch), so bm.pitch * uy may well be right. Commented Oct 3 at 14:11

1 Answer 1

1

In the SDL_Surface structure, is there a way to calculate the bounds of the pixels Member?

The pixels member has type void *, so C does not define a meaning for dereferencing it, including indexing into it, or for performing pointer arithmetic with it. In this sense, "bounds" do not apply. However, the object to which this pointer points certainly does have a particular size. SDL2 does not seem to provide a way to determine that size itself, but it does have a way to determine a useful lower bound on that.

In SDL2, the "pitch" of a raster is the offset, in bytes, from the beginning of one row to the beginning of the next. This is not necessarily directly proportional to the number of pixels per row. The raster height gives the number of rows you can rely upon being able to access, so the pixel data are at least pitch * height bytes in size.

If you're willing to use VLA types (without declaring any objects of such a type), then one way you could account for that would be:

((Uint32 *) ((char(*)[canvas->pitch]) canvas->pixels)[ypos])[xpos]

To break that down a bit,

  • (char(*)[canvas->pitch]) canvas->pixels converts canvas->pixels to a pointer to an array of canvas->pitch elements of type char (a.k.a. bytes). This is the pointer type to which a 2D array of type char[][canvas->pitch] would decay.
  • The [ypos] indexing therefore selects row ypos of the raster. The result is an array of type char[canvas->pitch], but this automatically decays to type char *.
  • The resulting char * is converted to type Uint32 *. I'm following you here in assuming that this correctly reflects the appropriate pixel size, which may or may not actually be the case. It is plausible that this is correct for your particular usage context, but it seems likely that there are other contexts where it would be incorrect.
  • The [xpos] indexing selects pixel xpos of the row (assuming pixel values of type Uint32)

Alternatively, something closer to your original code would be:

((Uint32 *) ((char *)canvas->pixels + canvas->pitch * ypos))[xpos]

I do not like your original code itself, however, as it produces the wrong result if the row pitch is not a multiple of 4. SDL does not seem to guarantee that the row pitch will be a multiple of the pixel size, so even assuming 4-byte pixels does not justify canvas->pitch>>2. (Note: online commentary claims that the pitch may be greater than the pixel size times the raster width.)

Additional note

This coordinate clamping looks wrong:

if(xpos < 0)
    xpos = 1;
  if(ypos < 0)
    ypos = 1;
  if(ypos >= canvas->h)
    ypos = canvas->h;
  if(xpos >= canvas->w)
    xpos = canvas->w;

I expect the coordinates to be zero-based, so the valid y coordinates, for example, run from 0 through canvas->h - 1. In that case,

  • ypos = canvas->h and xpos = canvas->w set out-of bounds coordinates, and
  • xpos = 1 and ypos = 1 seem anomalous (probably should be xpos = 0 and ypos = 0)

And in any case, those coordinate assignments seem inconsistent with the conditions expressed. If the minimum xpos you want to allow is 1, then why do you adjust only negative coordinates (not 0) up to 1? If you want to allow y coordinates up to and including canvas->h, then why do you pointlessly update the value canvas->h to itself?

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.