Show HN: Progressbar - A C library for displaying command-line progress bars
github.com
github.com
The standard [0] states that the size of `char` will be 1 byte. So there is no point in doing the sizeof operator on char. (e.g: https://github.com/doches/progressbar/blob/master/lib/progre...)
6.5.3.4 - Paragraph 3
> The sizeof operator... (page 80)
[0] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf
[1] http://bytes.com/topic/c/answers/223565-implementations-char...
I always use sizeof with char just to stay consistent - if you don’t you will get caught out one day when you change something and forget to add in the needed new sizeof.
Have you experienced malloc failing a lot? How do you test to ensure error handling code paths work as expected?
Have you read 'notes' section of Linux malloc manpage? It says:
By default, Linux follows an optimistic memory allocation strategy. This means that when malloc() returns non-NULL there is no guarantee that the memory really is available. In case it turns out that the system is out of memory, one or more processes will be killed by the OOM killer.
#include <stdlib.h>
#include <stdio.h>
#include <sys/resource.h>
const int SIZE = 64*1024*1024;
int main() {
char *buffer = NULL;
struct rlimit r;
/* Limit all memory to 1024 bytes */
r.rlim_cur = 1024;
r.rlim_max = 1024;
if (setrlimit(RLIMIT_AS, &r) == -1 ) {
perror("setrlimit(RLIMIT_AS) error\n");
exit(EXIT_FAILURE);
}
if ( (buffer = malloc( sizeof(long) * SIZE) ) == NULL) {
perror("malloc() failed\n");
exit(EXIT_FAILURE);
}
free(buffer);
printf("Malloc worked\n");
return 0;
}
Here's the output: %cc fail.c
%./a.out
malloc() failed
: Cannot allocate memory
If malloc failure testing is important to you, then you'll need some way to replace your use of the system malloc/free with special versions of your own. (Eg, through function pointers, or LD_PRELOAD.) Your own versions can be crafted to insert faults in just the right spots.It's tedious work.
Edit. It is impossible for malloc to fail (at least on linux) [1]. Seems rather pointless checking for something that can’t happen.
Actually the real issue here is that you should be aware that on some systems malloc might fail and not segfault.
I was under the impression that compiler optimisation often removed any NULL checks anyway [1].
1. http://blog.llvm.org/2011/05/what-every-c-programmer-should-...
Goodness.
No, you are misunderstanding the example. The optimizer did not introduce a bug by removing a NULL check. The code had a bug because it dereferenced the pointer before checking for NULL.
Are there any modern platforms where dereferncing a NULL pointer will not cause a crash?
Edit. Answering my own question it looks like ARM is one [1].
1. https://www.securecoding.cert.org/confluence/display/c/EXP34...
Incorrect. The example code did not check for a null pointer. It dereferenced a pointer, which implies that the pointer will never be null, and then it pointlessly checked for null on something that could not have been null. The optimizer in fact made the code more clear and easier to read, while maintaining correctness.
"While this is intentionally a simple and contrived example, this sort of thing happens all the time with inlining: inlining a function often exposes a number of secondary optimization opportunities. This means that if the optimizer decides to inline a function, a variety of local optimizations can kick in, which change the behavior of the code. This is both perfectly valid according to the standard, and important for performance in practice.”
In practice derefencing a NULL pointer on any x86 platform will always cause a crash (defined undefined behaviour I guess), but you can’t assume this on other platforms (ARM seems to be the big one).
I have to say before today I had assumed dereferncing a NULL pointer would always cause a segfault. It is always good to learn something new.
Please be. Seemingly random bits of (honestly - actually very useful) information like yours are why I'm reading HN in the first place instead of, say, random Youtube comments.
Someone may argue about this being overly pedantic, or about such comment being more suitable for sites like Stack Overflow, or about the whole thing being completely clear from the standards documentation itself... etc. But that's really not the point of it when this isn't the kind of thing you would be even intentionally looking at, or for, in the first place.
Every time I open a HN thread, I can be sure that I will find at least a good few nice and memorable comments that seemingly don't add anything revolutionary to the topic at hand, but instead will make you pause, slap your forehead and exclaim "holy moly, that's in essence actually perfectly obvious, yet somehow I never even thought about it from this point of view before!" Which in turn suddenly makes you realize something completely unrelated in your own world, yet affected or plagued by a similar type of issue, that would otherwise end up completely unnoticed if not for your comment.
In short, one man's pedantic can still be other man's sudden epiphany.
That is a fantastic example of something everyone should have in their OSS projects. A simple section at the top of the main doc that states what the thing is. Seems obvious, but I only mention it because it's so rarely done.
$ ./demo
Smooth |=====================================================| ETA: 0h00m06s
Three Second Task with a long label |========================| ETA: 0h00m03s
Fast |=======================================================| ETA: 0h00m02s
Custom <.....................................................> ETA: 0h00m06s
Indeterminate: 0:00:03
Status bar with a really long label: 0:00:01
Custom: 0:00:03The correct solution would be a) check the length of format, and if it less than or equal to 4 but greater than 0, then copy the bytes, else, don't... I guess? Why is 4 such an arbitrary chosen number?
// new->format is allocated to 4 bytes
size_t len = strlen(format);
if(len > 0 && len <= 4) {
memcpy(new->format, format, len); //i to < 4
new->format[3] = '\0';
}
Or it just be better to allocate the new->length to the return value of strlen(format) + 1. new->format[4] = '\0';
is out of bounds, no?It's common to allocate your size needed plus 1 for the NULL byte. But this programmer only allocates 4 bytes.. with no thought of the NULL byte at the end.
Dates back to 2002.
progressbar * p;
p = progressbar_new_with_format(..., ..., "whoops");
... yields a buffer overflow. And why do you malloc format to begin with if it's always 3 chars in size?