5 ms·
Probably returns a value if the assert works, and aborts otherwise. I would go so far as to say that using asserts in input validation is a good thing, in very
by corndoge 8y ago
Probably returns a value if the assert works, and aborts otherwise.
I would go so far as to say that using asserts in input validation is a good thing, in very limited quantities. I use them in places where the input should have been validated so long ago, so many functions back, that if something isn't as I expect here, I seriously fucked up somewhere else and the whole system has a good likelihood of being compromised by something unrelated to the condition I'm asserting. In that scenario I'd rather log and abort.
- int_19h 8y agoIn this case, though, you're not using asserts to validate. You're using asserts to capture the post-validation guarantees in your code. Basically, you assert that your validation code did the right thing and rejected invalid input through appropriate mechanisms - not that the input was valid.
- LukeShu 8y agoThat's what systemd does. For instance, the article uses a couple of asserts in dhcp6_option_parse_domainname(). By the time that function is getting called, the values should have already been validated, and the asserts (which are at the very top of the function) are asserting that the validation code did the right thing.
- int_19h 8y agoThen why do those "asserts" have return error codes associated with them? A failing assert shouldn't use normal error reporting mechanisms, and it most certainly shouldn't return a specific error code implying that assertion failures can (and should) be handled.
- LukeShu 8y agoFor the same reason read(3) returns EBADF if you pass it a bad file descriptor. Why doesn't the libc wrapper around the syscall just abort() if I give it a bad file descriptor? In systemd-networkd, the "asserts" assert the pre-conditions of a successful call to that function (in dhcp6-option.c). It's up to the caller (in sd-dhcp6-lease.c) to validate the users input, and ensure that it's passing valid arguments to the functions it's calling. Building software in layers, and making use of "internal" libraries is a valid software engineering strategy for managing complexity.
- int_19h 8y ago> For the same reason read(3) returns EBADF if you pass it a bad file descriptor. Why doesn't the libc wrapper around the syscall just abort() if I give it a bad file descriptor? Because, unfortunately, POSIX requires it to do that. But that's a bad decision on the part of POSIX, and we shouldn't perpetuate that when we have the choice. Assertions that can be "handled" are not assertions - they're errors. By returning an error code, you're saying "it's okay to pass bad things here without checking, and check the error code afterwards". If it's not actually okay, because validation is not reliable, then you're just enabling writing bad, unreliable code that shouldn't even be possible to write. The "bad descriptor" check in read() is a good example. You can never rely on EBADF unless you fully control every line of code that ever runs in your process, because a descriptor might be accidentally valid - it might be a descriptor that was closed, but then got reused for something else (and POSIX explicitly requires reuse of file descriptors). So checking for EBADF to e.g. detect closed descriptors and do something about that will mostly work, but it will sporadically break by doing something on the wrong descriptor. Therefore, it would be strictly better if read() just called abort(), and thereby forced the caller to use some other mechanism to keep track of what's valid and what isn't - the one that the caller can implement reliably, if it can.