16 ms·
*(char*)0 = 0; – What does the C++ programmer intend with this code? [video]
- sargstuff 3y agoReference to flush out the OS memory page(s) at some point. Ideally after the appropriate cast of characters has had a no-fault OS page(s) performance.
- sargstuff 3y agoLF macro / character variable set to form feed character (ctrl-L) for setting up an in-band line feed lot clearer/easier way to switch out the various stack pages.[0] [0] : https://www.youtube.com/watch?v=S_qTVhKyY68 https://www.youtube.com/watch?v=S_qTVhKyY68
- rramadass 3y agoA good "under the hood" presentation of going down the rabbit-hole of layers in a Computer System from Language -> Compiler -> OS -> Hardware.
- sargstuff 3y agohttp://www.gnu.org/fun/jokes/paging.game.html http://www.gnu.org/fun/jokes/paging.game.html
- thombat 3y agoThat's not just a beautiful high-level description, it's even therapeutic: the next time my HDD is thrashing I'll sit patiently and think that the Page King is too busy ruling his kingdom to grant my humble request right now.
- sargstuff 3y agoOr being held hostage
- thombat 3y agoFor example, by my forgetting that the "-j" option of "make" had the number of concurrent tasks as an optional parameter, and without that it simply launches every possible compile simultaneously. Paralysis of course: given its uncanny tendency to pick the wrong target I could just about believe that the OOM killer then sniped the King
- PennRobotics 3y agoBefore I watch the full talk for the answer (what I've seen so far, he states there's not a right answer)... I know on some microcontrollers (e.g. Arm) addresses 0x0 and 0x4 are usually used to define the initial stack pointer and entry point and then are never needed again. Later, you probably want to detect the presence of null pointers by checking if &maybeAStruct is either 0 or valid. If you accidentally test the value at that address, you'll get a non-zero and then run code you didn't intend to run. By defining address 0x0 as value 0, you'll avoid this issue. That has two problems. Alternatively, you define address 0x0 to erase the initial stack pointer so that a nefarious actor can't somehow memory dump and then find out where the program starts its execution. I don't see the benefit for several reasons. ----- Scenario 1. The first problem is that you shouldn't write code poorly. If you meant to check a variable's address and instead check its value, that's on you, your test suite, your compiler, and your debugger (and by extension, your colleagues and educators). Second, writing to address 0x0 on a Cortex usually involves writing to flash... which is not a temporary/nonpersistent change, more involved than simply writing to an address (you usually need to enable the flash controller and set some peripheral registers), and would usually not be allowed on a production device because that's where the bootloader is or that section of memory has been write protected following good practices. Scenario 2. The more I think about this one, the less it makes sense. Anyone with debug port access or a memory dump is already inside the castle, well past any defenses e.g. zeroing the main stack pointer. Plus, the same caveats from Scenario 1 apply: if you COULD write to 0x0, it is almost always a terrible idea. ----- Grand takeaway? This is probably a talk relevant to PC and not embedded. A Cortex-M would definitely complain about this code. Even on an AVR (atmega) changing 0x0 would be changing R0. I don't even know if that register is directly writeable during execution---probably because it's how you set some bootloader bits---but it's definitely dangerous. With that in mind, I searched for "virtual address space windows" to figure out what goes in an executable at address 0x0. After reading Microsoft's first two articles, it's still unclear what goes in 0x0. Wikipedia? No answer. Next result? Nothing. Finally, a page about Windows ME/98/95 states address 0x0 is "available to the process" but is "not writable". After ten more minutes of fruitless searching, I'm willing to just test what happens, because I expect that's not even writable without side effects during execution. #include <iostream> int main() { *(char*)0 = 0; std::cout << "test" << std::endl; } and then, "g++ test.cpp -o test", and ... [1] 869 segmentation fault ./test Linux? Fail. ----- "cl test.cpp /link /out:test.exe"... This compiles and runs but does not display the test string. (If you remove the 0x0 assignment, the string displays; no surprise) Interestingly, I can't delete test.exe right away. It has stayed open: ERROR: The process with PID 12776 (child process of PID 19728) could not be terminated. Not only does PID 19728 not exist, I have to use an administrator console to "taskkill test.exe", so this would probably never belong inside user space code on Windows. ----- Thus, this short code snippet seems like trouble, and the answer I would hope for as an interviewer is, "yeah, I don't write code like that, sorry." (Coincidentally, I would say the same in response to the professors giving microcontroller exam questions that try to stump students with multiple casts and dereferences in a single line *ahem Moreno*. Stop teaching students methods they will never, ever use in a shop that cares about its code!!) Now I watch and learn.
- mhkool 3y agoTo test if the system has a functional MMU
- eklitzke 3y agoExcept it's legal to map the zero page, so this isn't actually a good way to test if the system has a functional MMU.
- sargstuff 3y agoOld school C programmer would make it into a calculus problem for clarity/proof of concept. Until accessed, a memory location & variable location can be expressed as an indefinate integral. Memory location access request implies definate integral. 1) evaluation value indefinate of integrand variables: "A" less than/equal to "B" less than/equal to "C" less than/equal to "D". Variable a is start of sequence. Variable D is end of sequence. 2) integrand variables D & A define the continuous range of PC group of bits 3) integrand variables C & B define the cohntinous range of 8 bit char 4) Accessing bits outside the integrand limits implies math equivalent of computer segfault. In order to not generate a segfault, only positive delta, and epsilon is 0 or 1. aka The "alignment request" implies that A MUST be equal to B; C less than or equal to D. K&R C short hand for above is anonymous union.[0] Physics / Mechanical Engineering center of gravity approach rotated 90 & implimented via punch card reader that doesn't skip cards much more interesting physical list processing visual than calculus number line (IMHO). Physical form bit to bulky to carry to/from class room. Fortunately, electrial engineering split the difference via 1/2 way point (45 degree angle). Computer scientests get the autonoma / semantic analysis difference. Software Engineers, by completing the circle with & with out a sigh of "e e e e e e ..." [0] : http://www.catb.org/esr/structure-packing/ http://www.catb.org/esr/structure-packing/
- gigel82 3y agoAfaik, that's a "portable" way to trigger a termination with dump collection :) (particularly on Windows if you just std::terminate you won't get a heap dump unless you do special WER registration and register handlers).
- sacnoradhq 3y agoThis statement would be technically legal on its own in x86 real mode if the compiler didn't do null pointer checks. However it would set the divide-by-zero IRQ handler to itself 0000:0000, and when the next division by zero happened, the machine run into UB (likely a reset or halt) because it would jump there, do 4x ADD byte ptr [BX + SI], AL (or ADD byte ptr [EAX], AL) followed by running the remaining interrupt vectors as instructions.
- cjensen 3y agoNot quite. (char *) 0 is the null pointer. The null pointer is not necessarily a binary all-zero. On some compilers in x86, the null pointer intentionally points to something which will cause a crash when written to.
- sacnoradhq 3y agoFind me one contemporary example (ANSI C) with a disassembled screenshot. This is writing sizeof(char) (== 1 almost everywhere) zero to address zero. It is not using a NULL macro or other predefined symbol. In the real world, this would generally write a byte to address 0000:0000, leading to UB because it would fuck up the divide-by-zero IV. PS: I used Borland C++ 3.1, Microsoft C++ 3.x and 4.5x, Watcom, and early GNU.
- pxx 3y ago(void *) 0 is a null pointer constant and is not necessarily an all zeros representation. This has been defined virtually forever. https://c-faq.com/null/null2.html https://c-faq.com/null/null2.html https://c-faq.com/null/machexamp.html https://c-faq.com/null/machexamp.html Actual ways to do what you want to do are described in https://c-faq.com/null/accessloc0.html https://c-faq.com/null/accessloc0.html but technically speaking the pointer with a constant zero assigned to it _is_ a null pointer (which can be implemented as whatever bit pattern), independent of the preprocessor macro.
- gpderetta 3y ago> sizeof(char) (== 1 almost everywhere) sizeof char is 1 by definition everywhere. /pedantic
- johnea 3y agoSeg fault!
- pizzalife 3y agoNot if you map it first.
- deathanatos 3y agoI believe Linux (only in later versions; and a few other OSes) make this page unmappable[1]. That, of course, would be part of the talk: that this is perhaps an OS-specific feature that the original coder was maybe trying to trigger, and that it is still OS-dependent. [1]: https://en.wikipedia.org/wiki/Zero_page https://en.wikipedia.org/wiki/Zero_page states this to be the case, but mmap(2) seems to disagree / suggests 0 is mappable.
- pizzalife 3y agoBy default you can only map addresses over 65536 (root can map anything though). But you can disable the protections with: echo 0 > /proc/sys/vm/mmap_min_addr
- jenadine 3y agoThat's what I intended when I used it (with an extra 'volatile'). My objective was to test the crash reporter tool.
- olliej 3y ago
- gpderetta 3y agoI once used a (never executed) *(char*)0=0; to force GCC to generate async unwind tables for an otherwise leaf function that could throw from an inline asm statement. It was just an experiment never meant for production, but it was quite effective at doing exactly what I needed.
- rramadass 3y agoThat sounds very interesting but i don't quite understand :-( What were you trying to do and how did this work? I am interested in understanding the interplay between -funwind-tables, -fasyncronous-unwind-tables and -fexceptions.
- gpderetta 3y agoTo correctly handle exceptions GCC generates DWARF unwind tables that the runtime uses during unwinding to call the correct destructors but also restore registers and fixup the stack (i.e. the compensation code). Normally unwind tables have entries for each non-noexcept function call in a function as these are the only exception throwing edges. Asynchronous unwind also generates table entries for any instruction that can trap (typically memory accesses, but also things like division, etc). These can be used for example to correctly handle exceptions thrown by signal handlers, which is needed for ADA and Java support. I had an inline asm statement that could throw exceptions (by indirectly calling exception throwing functions). GCC assumes that asm cannot throw, and the function the statement was in did not have any throw statement nor call any other potentially throwing functions nor any non-optimized out memory access, so the compiler omitted generating unwind tables for the function even with -fasync-unwind-tables. The result was that throwing from the asm would at best not call destructors, at worse, crash with a corrupted stack. By adding a non-optimizable dummy memory access right after the asm (and jumping over it from the asm, so it actually doesn't get executed), I forced GCC to generate the unwind info . I also had to make sure that no compensation code was needed for the asm statements themselves, but after that things worked out fine. I wouldn't really use this in a finished product, it is very fragile and just happened to work on the version of GCC I was using. The right solution would be for GCC to add an attribute to mark asm statements as potentially throwing.
- andix 3y agoIs it still a programming language, or is it already a riddle (like sudoku)?
- sargstuff 3y agopointer(s) are still dangling over that.
- MarkusWandel 3y agoOld school comment... back in the day, there were computers on which dereferencing the null pointer would in fact return zero. And given that a typical linked list is terminated by a null, mistakes could creep in where "points to a 0" was checked when "pointer is 0" should have been. Needless to say, code like this would crash in mysterious ways when compiled on a machine where location 0, while readable, had nonzero contents. The alternative, getting a segfault because 0 wasn't mapped, is preferable because then you see the problem right away. Anyhow it's just barely possible that this assignment was a hack to make this sort of code work on a machine where address 0 is (uninitialized) nonzero and can be harmlessly made zero.
- AlotOfReading 3y agoI've actually seen code equivalent to this used for control flow. It was a very old bit of safety-critical code(!) that initialized a bunch of hardware from predefined tables containing pointers to overrides. For table values that weren't overridden (very few by the time I came along), it would access the null pointer to intentionally trap so an interrupt could insert the correct default and restart the instruction. Certain higher ups determined that behavior was a business requirement when I refused to reimplement it on a new platform.
- pavlov 3y agoIBM AIX is a Unix-like system on which dereferencing a null pointer for a read is guaranteed to return zero. But writes will crash. It’s pretty weird.
- twoodfin 3y agoHP-UX binaries also had an attribute that would control this behavior. https://docstore.mik.ua/manuals/hp-ux/en/B2355-60130/chatr_pa.1.html https://docstore.mik.ua/manuals/hp-ux/en/B2355-60130/chatr_p... Wonderful fun when they shipped a Kerberos library that unconditionally dereferenced a potentially null optional pointer-to-struct, relying on the executable to be set in the “null tolerant” mode!
- rsaxvc 3y ago
- fallingfrog 3y agoIt writes “Thanks for playing Wing Commander!” Reference if you don’t get the joke: https://www.reddit.com/r/shittyprogramming/comments/3bmszo/thank_you_for_playing_wing_commander/ https://www.reddit.com/r/shittyprogramming/comments/3bmszo/t...
- dekhn 3y agoWhen I see that code my head immediately translates to "store a byte with value 0 at memory address zero". 0 the integer needs to be cast to a char * to treat it as a byte address (rather than a word) and the * means "assign to the memory location given by the pointer. I would probably use something like this when hacking on an Apple II with a zero page. I have also written programs that ran on VMS which dumped memory starting at '0' without getting any segfaults.
- stefan_ 3y agoOn ATmega processors, the register file is mapped to 0, so this would be writing 0 to r0.. which GCC reserves as a dedicated 0 register anyway.
- tzs 3y agoThe PDP-10 did that. There was actually core memory at addresses 0-15 but if you had registers they overlaid that. Yes, I said if you had registers--if you were cheap you could buy your PDP-10 without registers and all the instructions that referenced registers would use core instead. Since the registers were in effect just 16 words of fast semiconductor memory overlaying the first 16 words of slow core memory you could do anything in them that you could do in regular memory, including running code out of them. If you had a small loop that did a lot of iterations you could sometimes get a significant speed boost by copying the loop into the registers and running it there.
- D-Coder 3y agoI seem to recall stories that if you put a small loop there, it could end up uninterruptible, with the CPU hung.
- zh3 3y agoExactly so [0]. However, these days something or someone somewhere might object "to keep us safe from ourselves" Turbo-C used to check the zero location to see if it had changed and would issue a warning if so (in the real mode days). [0] My other computer is a PDP-11,
- epx 3y agoTest if system is VAX?
- not2b 3y agoIt wouldn't work, because in the early days of 4.xbsd, whether page 0 was mapped or not depended on linker options. Originally page 0 was mapped, this led to problems with people being sloppy with null pointers, so the default was changed (so that dereferencing a null pointer, whether reading or writing, would trap). But there was an option o map page 0 to get crappy/broken programs to work.
- deleted 3y ago[deleted]
- lainproliant 3y agoThis was a lot of fun. Reminded me of one of the earliest C programs I wrote when I was learning to code on Win98, before I really knew how computers worked. I was curious: "What does the rest of RAM look like?" #include <stdio.h> int main() { for (int x = 0;;x++) { putc(*(char*)x); } return 0; } I was mezmerized by the strings from the uncompressed BIOS ROM being dumped back at me, "American Megatrends".. etc. Eventually this process crashes of course, when it runs past the end of mapped memory locations.
- seydor 3y agoThat's c++
- fluoridation 3y agoWhat's even more fun is the opposite! memset(0, 0, 1 << 20);
- shkurski_ 3y agoYou took me to "Now we are done with RAM, let's play with HDD" moment on 80286 when I was a kid.
- astrodust 3y agoIt was great when virtually everything was mapped 1:1 into "real" memory, even video memory. In those days, everything was a memory address, just like "everything is a file". Then came the realization you could alter any memory location, and further, you could write a tiny TSR to do things...
- yodsanklai 3y agoNot a big fan of the format of the talk. The guy is a good orator, but it takes ages to go to the point. A bit annoying if you're actually interested in the technical part rather than the jokes.
- jinushaun 3y agoSame here. This talk reminds me why I stopped going to tech meetups with tech talks.
- renewiltord 3y agoIf you use GPT-4 with Browsing turned on and supply it with the title, it will find the page and use the transcript and you can ask it questions. Then you can look at the transcripts to find the spots and verify. Alternatively, if you have an AI-enabled browser you can ask it about the transcript once you open it.
- jfbastien 3y agoI will do prompt injection in the next talk, just for you
- renewiltord 3y agoI think that would be fun.
- aldebran 3y agoWait, you’re the presenter!
- derefnull 3y agodereferencing null is a great debug technique
- sargstuff 3y agobillable something from nothing demo.
- smitop 3y agofun trivia: in WebAssembly it's valid to read/write to memory address 0.
- jfbastien 3y agoI’m glad you appreciated me saying exactly this in the talk
- sargstuff 3y agoOhly because the VM WebAssembly physical hardware address to running program memory address 0 isn't actually mapped to physical hardware memory address 0. Note: think there's a way to convert this to some shorter, massively recursive C pointer, to pointer .... to pointer declaration explaination.
- interroboink 3y agoSome comments about this being valid on old-school computers, but even in more modern contexts, there are such cases. When programming SPUs on the Cell processor (okay, still a bit old), address 0 was valid memory you could use, in the 256K per-SPU local store.
- junon 3y agoNothing states NULL is 0x0 (as in bits, not representation). Nothing states the first page (at 0x0) must be empty. It's convention, not rule. (obligatory in C and OS theory, other languages might differ)
- deleted 3y ago[deleted]
- sargstuff 3y agoUse lisp, cast hex on (). Or use modern version of printf with %p and/or cast hex on NULL macro.
- malkia 3y agoCrash? For example test code that makes your app crash, in order to test... say if your crashdumps work as expected?
- AnimalMuppet 3y agoI've done it, on purpose, to cause a crash, so that it would drop a core file and I could find out exactly how it got to that point in the code. (g++ on an ARM, on an embedded system running embedded Linux, with lots of functions that could be called by more than one thread. "ulimit -c unlimited".)
- ribit 3y agoTo me this talk was rather confusing. This statement cannot occur in a well formed standard C or C++ program, and I don’t think that the speaker did a good job conveying this. They also took way too much time to get to the actual point. If the intention was to discuss the particularities of memory mapping on some popular systems, they should have used bitcast from the start.
- jeffbee 3y ago> they should have used bitcast from the start. There are hundreds of instances of (char)0=0; in github, and there are none of the bit_cast variant, so if your goal is to inform people how to read code, starting with the one humans might actually encounter in the wild makes sense.
- sargstuff 3y agoMost assembler instructions are bit manipulations. just use gcc -S to cast the source code to bits.
- nayuki 3y ago> This statement cannot occur in a well formed standard C or C++ program Not true. It's illegal to execute that statement because of undefined behavior. But it's legal to have: if (false) { *(char*)0 = 0; } (And of course it's legal to #ifdef it out or comment it out, but that's too much cheating.)
- sargstuff 3y agoUmm... lot of undefined behavior things in official C spec.
- extraduder_ire 3y agoKind of a tangent, but I've never seen that signature for main with char *apple at the end after char *envp. What's passed in there? Some googling let me know it's used on macOS, but every result was too generic to be helpful.
- rramadass 3y agohttps://stackoverflow.com/questions/16765545/how-to-list-all-environment-variables-in-a-c-c-app/16765572#16765572 https://stackoverflow.com/questions/16765545/how-to-list-all... https://stackoverflow.com/questions/29909115/are-there-any-other-arguments-that-main-can-accept https://stackoverflow.com/questions/29909115/are-there-any-o...
- sargstuff 3y agoOriginally a hidden HDD .sony thing
- silon42 3y agoI've used it several times to crash the program, with cleaner stack trace than the abort() library function.
- Dwedit 3y agoOn Windows, it has a very specific meaning, write to address 0. Which is by default a no-access page, causing an access violation exception, jumping to a user-provided exception handler if present, or 'crashing the program' if not.
- m00dy 3y agoThe intention could be to force the program to execute its exception handler
- sargstuff 3y agoAh, why punch card readers died out -- not paying attention to endianness[0] and aligning the punch card feeder/reader perpendicular to normal handler plane instead of parallel. Pointers and type safety still causing issues decades later. [0] : https://en.wikipedia.org/wiki/Endianness https://en.wikipedia.org/wiki/Endianness
- deleted 3y ago[deleted]
- sargstuff 3y agoFor the typical non-coder hacker news reader: Wait for C++ coder to get disney sponsorship for a stack frame version of/translation to George Lucas expressions / Steven Speilburg expressions. aka * wars vs. * trek crossover comparisons, perhaps with less () than lisp/scheme take. Ideally, in UTF format so no "7 samuri/8 bit kleen", AND/OR, lower API, protocol droids distractions. In interm, learn python, show a python version of beetles 'let it be' and 'eigen a feeling'[1] parody. Although, perhaps 'irq feeling' more on topic with an appropriate reference to irq hooks & NULL dumps. Perhaps get DMCA'd by Wierd Al for using wrong character color scheme. ".plan 0[]", long[sigh] different discussion? http://www.asciimation.co.nz/ http://www.asciimation.co.nz/ [0] : sigh[long] : http://news.ycombinator.com/item?id=3367392 http://news.ycombinator.com/item?id=3367392 [1] : http://news.ycombinator.com/item?id=34261699 http://news.ycombinator.com/item?id=34261699
- sargstuff 3y ago&*strato[cast] to over the top reference for current history?
- sargstuff 3y agoGrasshopper observational note: "Eigen Maze by this pointer" may be theme song for this post; but no letting things be in order to let this stack down to get this pointer back to complete 'init & kill -9' autonoma sequence.
- sargstuff 3y agoIf used on a vaccum tube based hardware, would that be short hand for redirect all tty vaccum relays to point to /dev/null, turn off all vaccum tube relays, or reset rotary relays to start position.