sherincall
Not printf exactly, but I've found bugs with a combination of mprotect, userfaultfd and backtrace_symbols when I couldn't use HW breakpoints.
Basically, mark a set of pages as non-writable so that any writes trigger a pagefault, then register yourself as a pagefault handler for those and see who is doing the write, apply the write and move on. You can do this with LD_PRELOAD without even recompiling the debugee.
Or, just talk to your hiring manager(s) about the dilemma. For both companies, it'd be better to talk through any concerns before joining. If you accept one offer and then regret it a few months later, everyone loses: you, NVIDIA and [FAANG].
Consider a senior SWE at e.g. NVIDIA making $300k, let's say halfsies split between base and RSU. The $150k RSU grant from a few years ago that still hasn't fully vested is worth $1M now. So even for a 50% increase in nominal total comp, it doesn't make financial sense to switch.
I don't know that anyone can afford to pay their engineers 10x more than the competition, and then also offer a cheaper product with thinner margins.
Any code that invokes UB is not a valid C program, regardless of implemention.
More practically, ignoring the bug that did happen, libc also has multiple implementations of these functions and picks one based on HW it is running on. So even a statically linked glibc could behave differently on different HW. Always read the docs, this is well defined in the standard.
For overlapping memory, use memmove()
https://github.com/nothings/stb/blob/master/stb_truetype.h#L...
There are also cases of custom suballocators or arrays of objects - Looking at an address makes it possibly to figure out which array it belongs to. This code would break.
Granted, it would still be possible to do all this if you just mask off the tag bits, but it requires a software change.
EDIT: My math is bad, see comments below.
I can unsarcastically say that no one will ever need full 64bit addresses on this planet.
It is the game publishers that choose to use steam drm. Often the same publishers publish on GOG without the drm (since gog, admirably, does not offer a drm option to them), but it is not steam that is forcing the drm on you. Your issue is with the game publisher.
- It has a bus/lottery factor of 1. The vast majority of all the changes were done by Araq and I have very little faith that the language would survive without him. This is even more pronounced with Zig (mentioned in comments here).
- It has had some very embarrassing bugs after the 1.0 milestone. Most of them were specific to Windows (e.g. [0]), which casts a lot of doubt on its cross-platform promise. Multiple times in the last year, when debugging a nim program, it turned out that the problem was in the language/standard library.
Now, these might not be reasons enough to not use nim, since it's a lovely language when it works, but a pro/con list should be honest.
int *x;
char *y = x;
or similar. But if x was "void*", it really should work on all C compilers.a) is hardly an issue in a one-off macro definition, and b) is hardly an issue as you probably have #include <stdlib.h> just above the define. Besides, sane CFLAGS and any remotely modern compiler will protect you from b) anyway.
There is a minor benefit to casting in this case, as it will error out if I do:
int *x = new(x, 10); // should be new(int, 10)
because x is not a type.However, I still think this is terrible advice because it turns something very standard that every beginner C programmer understands into something that requires familiarity with the codebase and incurs a constant cognitive load. It also makes for some very hard to debug errors if I use "new" as a variable name somewhere. Not to mention total incompatibility with C++ due to choice of name.
I guess you could have a policy of just letting them die if they get into an accident without a helmet, but that its own host of problems.
I've since heard of a second instance of the generalization phenomena - Some people wipe their butt while still sitting, some stand up. Unscientific polling showed that the split is roughly 50/50 in a population. But no one had any idea of the other groups existence at all.
For example, a simple "Close your eyes and imagine a cat. [pause] What color is it? What's it doing?" question results in:
Most people: Orange. A bit scruffy. It's playing with a ball of yarn beneath a chair. I can clearly see it jumping around.
Fewer, but still common: It's orange. It's just suspended in nothingness in a fixed position.
Me: What do you mean color? You didn't tell me I need to give it a color!
Imagining something just summons the concept of that thing to your mind. You can attach properties to the cat and you can analyze it, but unless a given property has been attached in particular, it's simply null.
On the other hand, the people at the far end of the visual spectrum draw a complete blank when you say "Imagine an un-cat leaping over the chair".
A lot of the older 32bit software didn't ever consider the need to switch to 64bit in the future, so there is plenty of implicit assumptions made. These are sometimes very obvious (e.g. hand coded 32bit assembly), but sometimes very hard to detect, and can have a lot of logic built on top of it. For example, consider these two structures:
struct A { int n; void *p; float f; };
struct B { int a, b, c; };
Both structures are 12 byte large on 32bit, but A is 16 bytes on 64bit, because the pointer will be naturally aligned to 64bit boundary, so it will have 4 bytes of padding after n.There's plenty of ways the code could assume that sizeof(A) == sizeof(B). For example, it could use memcmp() to verify the structures are equal, or it could be allocating them from the same slab allocator to minimize fragmentation. These kinds of bugs will not be caught by the compiler, and they might not be easily noticeable at runtime. It takes significant effort to port a, say, 20 year old codebase written for 32bit over to 64bit.
Yes, it's easy to say "that's bad code, you shouldn't have written it like that in the first place", but programming 20 years ago was drastically different than today, and those "hacks" could make or break a product back then. And, at the time some 32bit software was written, it was not even obvious what 64bit would look like, so it was not obvious how you'd prepare for it even if you wanted to.
Not always true. There's plenty of 32bit code that can't trivially be ported over to 64bit, even if you have the full source for all the dependencies. e.g. maybe the file formats have padding or pointer width assumptions - now you need a compatibility shim whenever loading/saving the files. Maybe the code has implicit padding assumptions, which are not documented anywhere - now you'll get occasional random functionality bugs that are a huge effort to catch and debug.
It is not always a matter of flipping a compile-time switch for the developers, even if they are still around, and have all the source, and all the libraries and whatnot.
Your options here are either to manually invalidate your caches and synchronize with the DMA (e.g. via interrupts), or to request from the OS that the given memory section be entirely uncached; or in some cases, you can get away with a write-through cache policy, if the DMA is only ever reading the memory.