>LibNSFB: "The overall idea of the library is to provide a
generic abstraction to a linear section of memory which corresponds to a visible array of pixel elements on a display [surface, context, software abstraction layer or] device
Different colour depths are supported and the library provides routines for tasks such as drawing onto the framebuffer and rectangle copy operations.
LibNSFB currently supports the following as framebuffer providers:
Linux framebuffer
X
SDL
VNC
ABLE framebuffer"
Absolutely beautiful -- and necessary!
I was looking for a library like this that was not tightly coupled to other extraneous and unnecessary software (aka "bloatware") but could work across multiple graphics context providers, providing the same abstraction to each (i.e., software that is written for one software stack, i.e., X, automatically works for another software stack, i.e., SDL).
Here we're not trying to be a game engine or a sound engine or anything else.
We (by which I mean the developers!) are only trying to do one thing and do it right, and that's to abstract a graphical drawing surface, a bitmap, a "graphical viewport on the screen" across all of the above lower-level implementations.
So, I was looking for something like this for some time...
Sorry for being a party pooper, but it didn't take me 5 minutes to find an integer overflow in this code (which I've never seen before), as of commit 2443ff581ccd.
The public function nsfb_set_geometry() takes "width" and "height" as "int" values. Assume those are positive. Then we pass them to nsfb->surface_rtns->geometry().
Assume our surface is implemented by "surface/ram.c"; thus the call is made to ram_set_geometry(). There we store the passed-in "int" params into fields of "nsfb" (also ints). Then we do
Unchecked multiplication between signed integers (nsfb->width * nsfb->height); not only can it overflow and yield a bogus result, if that happens, it's even undefined behavior.
It sounds like your concern is that if the caller of the public function nsfb_set_geometry() passes in certain arguments, they can invoke undefined behavior, because the function doesn't correctly handle the case where the desired framebuffer is larger than 256 mebibytes (assuming 32-bit ints), and it may suffer an integer arithmetic overflow.
That doesn't seem very surprising; nearly any function in C can be crashed by passing it invalid arguments. For example, printf((char)37), free((char)main), or memcpy(argv[0], argv[1], 10485760).
Perhaps your concern is that the 256-mebibyte limitation isn't documented? libnsfb in general has very little documentation; this is the only documentation I see for nsfb_set_geometry():
/** Alter the geometry of a surface
*
* @param nsfb The context to alter.
* @param width The new display width.
* @param height The new display height.
* @param format The desired surface format.
*/
int nsfb_set_geometry(nsfb_t *nsfb, int width, int height, enum nsfb_format_e format);
The README says:
API documentation
-----------------
Currently, there is none. However, the code is well commented and the
public API may be found in the "include" directory. The testcase sources
may also be of use in working out how to use it.
So I would say that, if you're concerned about documentation, there are much greater deficiencies in documentation than the documentation of this particular limitation.
Perhaps your concern is that 256 mebibytes is actually a reasonable size for a framebuffer, not an invalid argument? With the 32-bit formats all modern displays seem to use, that would be 8192 × 8192. That seems like a colorable argument; I've worked with some images larger than that since last millennium. But it still seems serviceable for most purposes.
With 16-bit ints, it could fail if the framebuffer was larger than 4096 bytes, which seems like a more serious problem, but I don't know if libnsfb can be built on 16-bit and 8-bit platforms.
Please note that you should ensure that overflow doesn't happen, not detect when it happens. Once you let it happen, it's undefined behavior.
But you don't need to check each operation to ensure that none of them overflow. If you know that b and c are supposed to be bounded between -10 and +10, for example, the above line can't overflow. So just check that your supposition holds. In most cases, that boils down to a check on the inputs at the entry of the function.
> Do you prove that every line of arithmetic in your program will not overflow
My point is the analysis takes time, training, and is easy to regress. In practice programs operate within a reasonable N and if you push the limits they will fail. Or the devs wait for a bug report, and then set a pessimistic limit on user input.
Also undefined != crash. Your compiler has options for what to do when signed overflow is detected.
I don'tknow why we are having this discussion. The question was whether I (but I extrapolate to mean every programmer should) prove that not a single line can overflow, and the answer is yes, usually by proving that some variables are bounded.
Of course we can speculate if there are ways to mitigate the effects of, instead of avoiding, overflows, if they are free or come with performance penalties, and if the final result is a crash, a graceful exit, or a continued run as if nothing happened, and which is worse.
For the record, I think the answers are: there are, they're not free, and the latter is the worst.
AmigaOS, I believe from 2.0 onwards, could do that[0].
Width and Height being 16bit attributes of the struct for the requested screen.
I haven't seen an actual monitor able to display the whole thing at once, but that's fine, because you can make your screen gigantic yet set the video output to a much lower resolution.
Intuition will let you scroll through it by moving the mouse pointer past the edge.
I mean the integer overflow is the least of your problems. If you try to create a 64000*64000 texture most drivers are going to bark at you anyways in the best case.
Under 20 kilobytes, 24-bit TrueColor only, with backends for X-Windows and the Linux framebuffer, and frontends for C, Python, and LuaJIT, and also providing keyboard and mouse events and loading of PNG and JPEG files (via libpng and libjpeg) and some half-baked text rendering stuff.
Fenster looks great too. I hadn't seen LibNSFB or miniFB before.
If they are video frames, you also need to know the chroma subsampling ratio and separate stride values for luma and chroma.
(Some systems also allow for separate base offsets for the chroma planes, but that’s not useful in practice. It’s simpler if you can assume that the chroma planes tightly follow the luma. Stride is enough for alignment.)
>LibNSFB: "The overall idea of the library is to provide a
generic abstraction to a linear section of memory which corresponds to a visible array of pixel elements on a display [surface, context, software abstraction layer or] device
Different colour depths are supported and the library provides routines for tasks such as drawing onto the framebuffer and rectangle copy operations.
LibNSFB currently supports the following as framebuffer providers:
Linux framebuffer
X
SDL
VNC
ABLE framebuffer"
Absolutely beautiful -- and necessary!
I was looking for a library like this that was not tightly coupled to other extraneous and unnecessary software (aka "bloatware") but could work across multiple graphics context providers, providing the same abstraction to each (i.e., software that is written for one software stack, i.e., X, automatically works for another software stack, i.e., SDL).
Here we're not trying to be a game engine or a sound engine or anything else.
We (by which I mean the developers!) are only trying to do one thing and do it right, and that's to abstract a graphical drawing surface, a bitmap, a "graphical viewport on the screen" across all of the above lower-level implementations.
So, I was looking for something like this for some time...
Well done!
Sorry for being a party pooper, but it didn't take me 5 minutes to find an integer overflow in this code (which I've never seen before), as of commit 2443ff581ccd.
The public function nsfb_set_geometry() takes "width" and "height" as "int" values. Assume those are positive. Then we pass them to nsfb->surface_rtns->geometry().
Assume our surface is implemented by "surface/ram.c"; thus the call is made to ram_set_geometry(). There we store the passed-in "int" params into fields of "nsfb" (also ints). Then we do
Unchecked multiplication between signed integers (nsfb->width * nsfb->height); not only can it overflow and yield a bogus result, if that happens, it's even undefined behavior.It's naive code.
It sounds like your concern is that if the caller of the public function nsfb_set_geometry() passes in certain arguments, they can invoke undefined behavior, because the function doesn't correctly handle the case where the desired framebuffer is larger than 256 mebibytes (assuming 32-bit ints), and it may suffer an integer arithmetic overflow.
That doesn't seem very surprising; nearly any function in C can be crashed by passing it invalid arguments. For example, printf((char)37), free((char)main), or memcpy(argv[0], argv[1], 10485760).
Perhaps your concern is that the 256-mebibyte limitation isn't documented? libnsfb in general has very little documentation; this is the only documentation I see for nsfb_set_geometry():
The README says: So I would say that, if you're concerned about documentation, there are much greater deficiencies in documentation than the documentation of this particular limitation.Perhaps your concern is that 256 mebibytes is actually a reasonable size for a framebuffer, not an invalid argument? With the 32-bit formats all modern displays seem to use, that would be 8192 × 8192. That seems like a colorable argument; I've worked with some images larger than that since last millennium. But it still seems serviceable for most purposes.
With 16-bit ints, it could fail if the framebuffer was larger than 4096 bytes, which seems like a more serious problem, but I don't know if libnsfb can be built on 16-bit and 8-bit platforms.
Sorry, that's printf((char*)37) and free((char*)main).
These are being passed by whoever is using the library. They should be checked before being passed to the function.
Do you prove that every line of arithmetic in your program will not overflow for all possible inputs?
Are you aware that no screen is 64k x 64k?
> Do you prove that every line of arithmetic in your program will not overflow for all possible inputs?
If inputs come from outside, a vehement Yes!
In this particular case they wouldn't. But yes, C is a problem.
It’s a register based computer problem, not a C problem.
Not checking for overflow is a developer problem
Do you suggest branching after every operation?
a = b + c
if err { // … }
Please note that you should ensure that overflow doesn't happen, not detect when it happens. Once you let it happen, it's undefined behavior.
But you don't need to check each operation to ensure that none of them overflow. If you know that b and c are supposed to be bounded between -10 and +10, for example, the above line can't overflow. So just check that your supposition holds. In most cases, that boils down to a check on the inputs at the entry of the function.
Yes I mentioned that a few posts above;
> Do you prove that every line of arithmetic in your program will not overflow
My point is the analysis takes time, training, and is easy to regress. In practice programs operate within a reasonable N and if you push the limits they will fail. Or the devs wait for a bug report, and then set a pessimistic limit on user input.
Also undefined != crash. Your compiler has options for what to do when signed overflow is detected.
I don'tknow why we are having this discussion. The question was whether I (but I extrapolate to mean every programmer should) prove that not a single line can overflow, and the answer is yes, usually by proving that some variables are bounded.
Of course we can speculate if there are ways to mitigate the effects of, instead of avoiding, overflows, if they are free or come with performance penalties, and if the final result is a crash, a graceful exit, or a continued run as if nothing happened, and which is worse.
For the record, I think the answers are: there are, they're not free, and the latter is the worst.
>Are you aware that no screen is 64k x 64k?
AmigaOS, I believe from 2.0 onwards, could do that[0].
Width and Height being 16bit attributes of the struct for the requested screen.
I haven't seen an actual monitor able to display the whole thing at once, but that's fine, because you can make your screen gigantic yet set the video output to a much lower resolution.
Intuition will let you scroll through it by moving the mouse pointer past the edge.
0. http://amigadev.elowar.com/read/ADCD_2.1/Includes_and_Autodo...
Does this library serve Amiga developers?
If you mean intuition, it is one of the libraries included in the operating system (usually part of the kickstart ROM).
If you mean amigadev.elowar.com, it is indeed mostly referenced by Amiga developers.
libNSFB, the library being discussed and accused of being low quality because of this range assumption
I mean the integer overflow is the least of your problems. If you try to create a 64000*64000 texture most drivers are going to bark at you anyways in the best case.
>If you try to create a 64000*64000 texture
Huge texture was a quite famous Linux NVIDIA driver vulnerability.
I believe fenster [1] is an alternative.
[1]: https://github.com/zserge/fenster
>keyboard, audio, mouse, timers
Nah, this looks more like an alternative to SDL at that point.
My own solution to this problem is Yeso: https://gitlab.com/kragen/bubbleos/-/tree/master/yeso
Under 20 kilobytes, 24-bit TrueColor only, with backends for X-Windows and the Linux framebuffer, and frontends for C, Python, and LuaJIT, and also providing keyboard and mouse events and loading of PNG and JPEG files (via libpng and libjpeg) and some half-baked text rendering stuff.
Fenster looks great too. I hadn't seen LibNSFB or miniFB before.
MiniFB is another option: https://github.com/emoon/minifb
Also quite interesting, this is part of an original web browser project[0].
0. https://www.netsurf-browser.org/
Dimensions, Pointer to Scanline 0, Stride, and Pixel Format. What else do you need before you start processing images?
If they are video frames, you also need to know the chroma subsampling ratio and separate stride values for luma and chroma.
(Some systems also allow for separate base offsets for the chroma planes, but that’s not useful in practice. It’s simpler if you can assume that the chroma planes tightly follow the luma. Stride is enough for alignment.)