Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Activity for alx
| Type | On... | Excerpt | Status | Date |
|---|---|---|---|---|
| Comment | Post #296669 |
@#8176
And there are more issues.
If `restrict` were designed to enable safer code (which should be the goal), it would disallow pointing to an object from two different parameters. However, it is really an optimization-only feature (it's designed so that you can point from two parameters,... (more) |
— | about 22 hours ago |
| Comment | Post #296669 |
> It sounds like they were indeed just talking nonsense then, not aware of the C17 clarification to _Generic.
Either that, or maybe they're pedantic enough that they cared about pointers-to-pointers (which doesn't even work well for `restrict`...).
> Although it would technically be possibl... (more) |
— | 2 days ago |
| Comment | Post #296669 |
Found. The comment seems to be this one:
Member body / National Committee: `GB`
Comment number: `112`
Clause/subclause: `6.7.3`
Paragraph: `9`
Type of comment: `ed` (editorial)
Comments:
> The statement about removing restrict not changing behavior of a conforming program is... (more) |
— | 2 days ago |
| Comment | Post #296669 |
> Yeah sure you can do pointer-to-pointers or function pointers but was that really the meaning of 6.7.4?
The new versions of the standard don't come with a rationale, so we're a bit blind about what they did and why. I've only joined the committee after C23, so I don't know details of discus... (more) |
— | 2 days ago |
| Comment | Post #296669 |
```c
char *restrict *p;
_Static_assert(_Generic(p, char *restrict *: 1, char **: 0));
```
```sh
$ gcc -Wall -Wextra -Wpedantic -S r.c
$
```
> Notably, pointed-at data cannot be restrict qualified, only the pointer object itself.
Is there such a constraint in the language? I've n... (more) |
— | 3 days ago |
| Comment | Post #296595 |
...
And thus, this is not an appropriate example for discussing whether using an indeterminate value results in UB (potentially or definitely), because this example is not using an indeterminate value at all.
Here I'm not arguing whether reading the indeterminate value results in UB or not.... (more) |
— | 8 days ago |
| Comment | Post #296595 |
@#8176
Yes, I was wrong on the first comment and the title. That I admitted above.
The reason why I'm insisting on lvalue conversion is this reasoning in your post:
> Even more obvious:
>
> ```c
> int* p = malloc(n);
> free(p);
> p = NULL;
> ```
>
> If using p while the value ... (more) |
— | 8 days ago |
| Comment | Post #296595 |
That is, "evaluation" isn't a black-or-white thing. It's not "everything happens" or "nothing happens". It's more like in general, evaluation means several things, but in some cases, only one or a few of these things actually happen. Also, the effects of evaluation on the expression might be d... (more) |
— | 8 days ago |
| Comment | Post #296595 |
For example, in `*(p+1) = 0`, the whole `*(p+1)` is an lvalue expression, and is evaluated for designating an object and for initiating the side effect of writing a `0` to it, but its stored value is not read (lvalue conversion is not performed on the whole).
But `p` is a subexpression of it, ... (more) |
— | 8 days ago |
| Comment | Post #296595 |
@#8176
C23 5.1.2.4p2 indeed says that `Evaluation of an expression in general includes both value computations and initiation of side effects.`, but I think that `in general` is meant to be overridden by specific rules.
Indeed, as you say, the left operand of `=` has to be evaluated for its... (more) |
— | 8 days ago |
| Comment | Post #296595 |
You're right: the left operand is evaluated. However, that evaluation is only performed for determining the designated object. The value stored in the designated object is not read; that would require lvalue conversion, which is inhibited for the left operand of the simple assignment operator (... (more) |
— | 8 days ago |
| Comment | Post #296588 |
@#119116 It's not any indeterminate values. Only pointer values cause this unconditional UB, as specified by 6.2.4p2. However, it's true that casting the value doesn't change 6.2.4p2, so yes, it's still UB. (more) |
— | 11 days ago |
| Comment | Post #296595 |
> Even more obvious:
>
> ```c
> int* p = malloc(n);
> free(p);
> p = NULL;
> ```
>
> If using p while the value is indeterminate, you wouldn't even be able to write bog standard code like the above, because the assignment involves a value computation of the left operand p before it is w... (more) |
— | 11 days ago |
| Comment | Post #296587 |
@#8176
Thanks! Yeah, I was wrong in my first message. It's not so clearly UB; it could be, but it isn't necessarily. (more) |
— | 22 days ago |
| Comment | Post #296587 |
... But the call above is reading it through an lvalue that is a pointer, and would produce UB if and only if it is a non-value representation (which we don't know). (more) |
— | 22 days ago |
| Comment | Post #296587 |
@#8176
Hmmm. Thanks!
So, it indeed becomes an indeterminate representation, which means it either represents an unspecified value or is a non-value representation.
If it's an unspecified value, reading it results in unspecified behavior (which means it can have any value, and if you rea... (more) |
— | 22 days ago |
| Comment | Post #296587 |
Yes, it is.
To be specific, the following program triggers UB:
```c
#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
int *p = malloc(42);
free(p);
printf("%p\n", p); // UB; use-after-free
}
```
Even though it doesn't access memory through the pointer. (more) |
— | 26 days ago |
| Comment | Post #282566 |
@#8176
I've been thinking about how an ideal fgets(3)-like API would look like, and I've developed an API that I think I like slightly more than fgets(3).
```c
// fgettextline - FILE get text line
char *
fgettextline(char *buf, size_t n, FILE *stream)
{
if (n > INT_MAX) {
errno = E... (more) |
— | 30 days ago |
| Comment | Post #282566 |
@#8176
And I forgot to mention the obvious: POSIX also requires that all lines are terminated by '\n'. If a line doesn't contain that '\n', it's invalid.
And also forgot to mention: stpsep() does two things: it validates the line, and it removes the '\n'. Both at the same time. (more) |
— | about 1 month ago |
| Comment | Post #282566 |
POSIX defines text files (that includes streams) as being composed of 0 or more lines. And lines are defined to not contain null bytes and be no longer than LINE_MAX characters (including the '\n', but not the '\0' of the string in which it is stored).
If a stream contains null bytes, or does... (more) |
— | about 1 month ago |
| Comment | Post #282566 |
@#8176
If I understand correctly, you mean when reading files that are not text files. Of course, fgets(3) is not good for reading non-text files. But that's not because fgets(3) is a bad API, but because it's not suitable for non-text files. There are APIs for non-text files.
For text f... (more) |
— | about 1 month ago |
| Comment | Post #296362 |
After a lot of research and discussing with other expert programmers, we found that the original use case of memccpy(3) was for implementing fgets(3). Indeed, it's perfect for that.
After all, it's not a bad function per se. Like strncpy(3), it's good for a niche use case.
But it's certai... (more) |
— | about 2 months ago |
| Edit | Post #296362 |
Post edited: V7 had bcopy(), not bcmp(3). Also, SysV had <memory.h>. |
— | about 2 months ago |
| Edit | Post #296362 |
Post edited: truncation is also dangerous, in a different way |
— | about 2 months ago |
| Edit | Post #296384 |
Post edited: tfix |
— | 2 months ago |
| Edit | Post #296384 |
Post edited: tfix |
— | 2 months ago |
| Edit | Post #296384 |
Post edited: pfix |
— | 2 months ago |
| Comment | Post #282566 |
Why would you want to know how much it read? If you really want to know, it should be as simple as `strlen(buf)`, which yeah, might be a bit inefficient, but compared to reading a file, is that observable? Or does it have any obscure/dangerous/tricky behavior?
What do/would you use instead? (more) |
— | 2 months ago |
| Comment | Post #282566 |
I never understood why scanf(3) is taught to new programmers.
fgets(3) is way simpler, and easier to use. And scanf(3) is in general avoided outside of teaching, so it would be better to avoid it entirely.
fgets(3) also helps programmers think of text files, which is usually a good format.
... (more) |
— | 2 months ago |
| Edit | Post #296384 | Initial revision | — | 2 months ago |
| Answer | — |
A: Extern keyword in C and proper way to use extern variables in embedded systems > And with the same logic, shouldn't the function prototypes in gpio.h also be extern for my source files to see them? Function declarations default to being `extern`. If you don't specify any storage-class specifiers, a function prototype is `extern`. This is specified in C23 in 6.2.2p5: ... (more) |
— | 2 months ago |
| Comment | Post #296363 |
Although, if you want to chain, the stpecpy() interface is superior. (more) |
— | 2 months ago |
| Comment | Post #296363 |
> As for comparing memccpy with functions that don't take a buffer size as parameter, that's comparing apples and oranges. If you don't use the buffer size, then you can't use the function for stuff like input sanitation, which would be a possible use-case for memccpy. Unlike all of the str... fu... (more) |
— | 2 months ago |
| Comment | Post #296363 |
> If we want to know if the whole source string was copied or not, we can do this:
And then you show an example:
```c
const char* expected_end = s2 + sizeof(s1);
char* result = memccpy(s2, s1, '\0', sizeof(s2));
...
if(result == expected_end)
{ ... }
```
I believe that code has UB,... (more) |
— | 2 months ago |
| Comment | Post #296363 |
I think it would be okay to define a function that copies a string only if it fits, and which returns a pointer to the NUL if it fits. That function could be indeed implemented with memccpy(3), hiding its ugly and dangerous interface:
```
char *
stpcpy_if_fits(size_t dsize;
char dst[re... (more) |
— | 2 months ago |
| Comment | Post #296363 |
> If you do use it for strings, I find the usage rather straight-forward:
And you show this example:
```c
#include <string.h>
#include <stdio.h>
int main(void)
{
char s1[] = "hello world";
char s2[100];
char* result = memccpy(s2, s1, '\0', sizeof(s2));
if(result == NULL)... (more) |
— | 2 months ago |
| Comment | Post #296363 |
A function that returned a pointer to the NUL character of the string could be used as this:
```c
while (NULL != (nul = fgetsnul(buf, countof(buf), stdin))) {
if (streq(buf, "") || nul[-1] != '\n')
goto invalid_line;
strcpy(--nul, "");
...
}
```
This is slightly... (more) |
— | 2 months ago |
| Comment | Post #296363 |
> functions that come with a broken API, for example fgets
Currently, fgets(3) can be used usually as this:
```c
while (fgets(buf, countof(buf), stdin) != NULL) {
if (stpsep(buf, "\n") == NULL) // Remove '\n' if present
goto invalid_line;
...
}
```
(where stpsep(... (more) |
— | 2 months ago |
| Comment | Post #296363 |
> we do get a pointer to where it stopped copying, so we can calculate the size copied. Which really ought to be "minimum viable product" for any function that writes/copies
memccpy(3) is not such a minimum viable product. The minimum viable product for a function that copies bytes and return... (more) |
— | 2 months ago |
| Edit | Post #296362 |
Post edited: Linux has strscpy(9), but no strscat() |
— | 2 months ago |
| Edit | Post #296362 |
Post edited: strecpy(2) is not buggy; seprint(2) is |
— | 2 months ago |
| Edit | Post #296362 |
Post edited: tfix s/strcpy/strncpy/ |
— | 2 months ago |
| Edit | Post #296362 | Initial revision | — | 2 months ago |
| Answer | — |
A: Are memccpy(3) or strncpy(3) bad for copying and catenating strings with truncation? strncpy(3) strncpy(3) was originally invented in Seventh Edition Unix (a.k.a., V7). It was added with one use case in mind: copying a source string into a destination character sequence in a fixed-size buffer (not a string), and padding the unused bytes with `'\0'`. This was useful back th... (more) |
— | 2 months ago |
| Edit | Post #296361 |
Post edited: |
— | 2 months ago |
| Edit | Post #296361 | Initial revision | — | 2 months ago |
| Question | — |
Are memccpy(3) or strncpy(3) bad for copying and catenating strings with truncation? I heard strncpy(3) is bad, and also heard that C23 added memccpy(3) to replace it. However, I also heard memccpy(3) is even more terrible than strncpy(3). Are these functions really bad? How so? Are there any legitimate uses of any of these functions? What should we use instead? (more) |
— | 2 months ago |
| Comment | Post #296352 |
If one prefers the simplicity of strcpy(3)/strcat(3), one can also have such functions. They are less efficient, but they can be safer, by being even simpler to use in some cases. I have truncating variants of these functions, which I call strtcpy()/strtcat(). They'd be used as:
```c
if (s... (more) |
— | 2 months ago |
| Comment | Post #296352 |
...
At the bottom of the paper n2349 there's a more correct example of how memccpy(3) could be used to copy strings. This shows how terrible this function is.
```c
char *p = memccpy (d, s1, '\0', dsize);
if (p) {
--p;
p = memccpy (p, "/", '\0', dsize - (p - d));
if (p) {
--... (more) |
— | 2 months ago |
| Comment | Post #296352 |
...
But now about the flagship use case: copying with truncation. It shows that one should do this:
```c
char *p = memccpy (d, s1, '\0', dsize);
dsize -= (p - d - 1);
memccpy (p - 1, s2, '\0', dsize);
```
This is more prone to off-by-one bugs than the case above, and more than strnc... (more) |
— | 2 months ago |
