Hacker Newsnew | past | comments | ask | show | jobs | submit | branko_d's commentslogin

But only if they stand.

If they start driving, the situation changes dramatically!


Tragedy of commons.


Is there anything especially hard about decompiling (to) Java?

.NET/C# decompilers are widespread and generally work well (there is one built into Visual Studio nowdays, JetBrains have their own, there were a bunch of stand-alone tools too back in the the day).


< disclaimer - I wrote CFR, which is one of the original set of 'modern' java decompilers >

Generic erasure is a giant pain in the rear. C# doesn't do this. You don't actually keep any information about generics in the bytecode, however some of the metadata is present. BUT IT COULD BE FULL OF LIES.

There's also a huge amount of syntactic sugar in later java versions - take for example switch expressions.

https://www.benf.org/other/cfr/switch_expressions.html

and OH MY GOD FINALLY

https://www.benf.org/other/cfr/finally.html


>Generic erasure is a giant pain in the rear

Personally, I don't get the sentiment. Yeah, decompiling might not produce the original source code, which is fair. It's possible to generate code using invokeDynamic and what not - still being valid code if a compiler opts to do so.

When decomiling bytecode there has to be a reason for, and a good one. There has to be a goal.

If the code is somewhat humanly understandable that's ok. if it's more readable than just bytecode, that's already an improvement.

Reading bytecode alone is not hard when it comes to reverse engineering. Java already comes with methods and fields available by design. Having local variable names and line numbers preserved is very common, due to exception stack traces being an excellent debugging tool. Hence debugging info gets to be preserved.

try/finally shares the same issues, albeit less pronounced.


C# doesn't erase all generics; but there's also some type erasure happening: nullable reference types, tuple element names, and the object/dynamic distinction are all not present in .NET bytecode; these are only stored in attributes for public signatures, but are erased for local variable types.

C# also has huge amounts of syntactic sugar: `yield return` and `await` compile into huge state machines; `fixed` statements come with similar problems as "finally" in java (including the possibility of exponential code growth during decompilation).


You're awesome! I had really good experiences with CFR in the mid 2010s.

I used it for game modding and documentation (and caught/reported a few game bugs + vulnerabilities along the way). I'd pull game files from Steam depots with steamkit, decompile with CFR, and run the resulting java through doxygen.


My personal experience with both is that decompilers work great for easy code. I still have both Java and C# projects that I wish I decompiled even to worst possible, but almost compilable code. Instead getting just decompiler errors or code where all variables got the same letter/name and of course different types...

I think I've tried all available free tools and some paid in Java case. Finally I just deducted logic and reverse engineered the most important path.


China imports substantially all of its uranium from Kazakhstan and Namibia, and a tiny bit from US. Russia is insignificant.

https://wits.worldbank.org/trade/comtrade/en/country/CHN/yea...


Probably because must “emulation” is more like “transpilation” these days - there is a hit up front to translate into native instructions, but they are then cached and repeatedly executed like any other native instructions.


According to Project Farm, Sylvania is the best headlight restoration kit:

https://www.youtube.com/watch?v=kyVCEbfrU-c


Safe things should be easy, dangerous things should be hard.

This .unwrap() sounds too easy for what it does, certainly much easier than having an entire try..catch block with an explicit panic. Full disclosure: I don't actually know Rust.


I don't think 'unwrap' is inherently the problem.

Any project has to reason about what sort of errors can be tolerated gracefully and which cannot. Unwrap is reasonable in scenarios you expect to never be reached, because otherwise your code will be full of all sorts of possible permutations and paths that are harder to reason about and may cascade into extremely nuanced or subtle errors.

Rust also has a version of unwrap called "expect" where you provide a string that logs why the unwrap occurred. It's similar, but for pieces of code that are crucial it could be a good idea to require all 'unwraps' to instead be 'expects' so that people at least are forced to write down a reason why they believe the unwrap can never be reached.


> Exceptions force a panic on all errors

What do you mean?

Exceptions do not force panic at all. In most practical situations, an exception unhandled close to where it was thrown will eventually get logged. It's kind of a "local" panic, if you will, that will terminate the specific function, but the rest of the program will remain unaffected. For example, a web server might throw an exception while processing a specific HTTP request, but other HTTP requests are unaffected.

Throwing an exception does not necessarily mean that your program is suddenly in an unsupported state, and therefore does not require terminating the entire program.


> Throwing an exception does not necessarily mean that your program is suddenly in an unsupported state, and therefore does not require terminating the entire program.

That's not what a panic means. Take a read through Go's panic / resume mechanism; it's similar to exceptions, but the semantics (with multiple return values) make it clear that panic is for exceptional situations. (IE, panic isn't for "file not found," but instead it's for when code isn't written to handle "file not found.")

Even Rust has mechanisms to panic without aborting the process, although I will readily admit that I haven't used them and don't understand them: https://doc.rust-lang.org/std/panic/fn.resume_unwind.html


> Throwing an exception does not necessarily mean that your program is suddenly in an unsupported state

When everyone uses runtime exceptions and doesn’t count for exception handling in every possible code path, that’s exactly what it means.


Sure, but the same is true of any error handling strategy.

When you work with exceptions, the key is to assume that every line can throw unless proven otherwise, which in practice means almost all lines of code can throw. Once you adopt that mental model, things get easier.


Explicit error handling strategies allow you to not worry about all the code paths that explicitly cannot throw -- which is a lot of them. It makes life a lot easier in the non-throwing case, and doesn't complicate life any more in the throwing case as compared to exception-based error handling.

It also makes errors part of the API contract, which is where they belong, because they are.


I would respectfully disagree with most of what you said. I guess individual perspective depends a lot on the kinds of code you work on.

The point about being explicitly part of the API stands, though.


Did you try No Country Redirect?

http://www.google.com/ncr


It doesn't work for some/many things, like account sign-in screens, and I think the last time I tried, Google Files/Drive either


This is not even a regression - it has always been there, unnoticed!


If it has always been there, then your QA process has always sucked and missed it.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: