Viết mã java để phát hiện phiên bản JVM


17

Mục tiêu là viết mã java phát hiện phiên bản JVM dựa trên các thay đổi tương thích, tác dụng phụ, lỗi và / hoặc hành vi không xác định hoạt động theo cách trong một phiên bản và một cách khác trong phiên bản khác. Hơn nữa, mã phải có ít nhất một chút có thể đọc được, mà không phải hy sinh khoảng trắng và tên biến rõ ràng.

Để đảm bảo mục tiêu đó, các quy tắc chính thức chính xác là:

  1. Mã phải được viết bằng java và sẽ xuất ra phiên bản JRE mà nó đang chạy.

  2. Mã không được sử dụng bất kỳ API JDK hoặc JRE nào được cung cấp riêng để phát hiện phiên bản java hoặc cung cấp phiên bản JDK hoặc JRE miễn phí.

  3. Mã không được sử dụng sự phản chiếu.

  4. Mã chỉ được yêu cầu để hoạt động trong Hotspot Java SE 5, 6 và 7, nhưng có thể hoạt động trong các JVM khác.

  5. Mã không được sử dụng bất kỳ thư viện của bên thứ ba nào trong đường dẫn lớp.

  6. Mã không được bắt đầu bất kỳ quá trình khác, java hay không.

  7. Mã không được sử dụng các biến môi trường.

  8. Mã không được tìm kiếm hệ thống tệp tìm kiếm các tệp hoặc thư mục có sẵn.

  9. Mã phải được chứa trong một tệp duy nhất và được gọi qua public static void main(String[] args)hoặc public static void main(String... args).

  10. Mã không được sử dụng bất kỳ API không công khai nào có trong JRE.

  11. Mã không được tạo ra bất kỳ NoClassDefFoundError, NoSuchMethodError, ClassNotFoundException hoặc NoSuchMethodException trong quá trình thực thi.

  12. Mã phải chạy trong một hệ thống bị ngắt kết nối từ internet hoặc từ bất kỳ mạng cục bộ nào.

  13. Bạn nên cung cấp một lời giải thích tại sao nó hoạt động theo một cách trong một phiên bản và một cách khác trong một phiên bản khác.

Chấm điểm

Phương pháp được sử dụng để đo giải pháp tốt nhất là max (n / s), trong đó n là số phiên bản java khác nhau được phát hiện mà không vi phạm bất kỳ quy tắc nào (ít nhất là phiên bản 5, 6 và 7) và s là số lượng mã thông báo từ vựng trong giải pháp.


Không thể tìm thấy một thẻ tốt hơn và tôi đã phải cung cấp ở hai cuối cùng. Hơn nữa, tôi không có đủ đại diện để tạo thẻ mới. Lý do cho java là vì nó được cho là một ngôn ngữ rất di động, vì vậy viết sẽ rất thú vị. Hơn nữa, các phiên bản java được định nghĩa theo cách chúng ta có thể so sánh các mục phát hiện môi trường với tính đồng nhất, mà không kết thúc để so sánh cam với táo.
Victor Stafusa

Bạn có thể xem xét [ngầm] cho rằng phát hiện phiên bản VM là một bước để tấn công hệ thống. Tôi không thể nói rằng tôi có một đề nghị khác.
dmckee

@dmckee Đánh rơi thẻ [code-golf]. Thêm thẻ [underhanded]. Bạn có thể vui lòng tạo thẻ [java] không?
Victor Stafusa

4
Tôi đang bỏ phiếu để đóng câu hỏi này dưới dạng ngoài chủ đề vì các thử thách ngầm không còn thuộc chủ đề trên trang web này. meta.codegolf.stackexchange.com/a/8326/20469
mèo

@cat, thay vào đó bạn nên xóa thẻ, vì nó không phù hợp với câu hỏi.
Peter Taylor

Câu trả lời:


9

6/102 = 0,0588

Phát hiện 6 phiên bản. Có 102 thẻ từ vựng (giảm từ 103, sau khi tôi đã xóa publictrong public class).

import java.security.Signature;

class GuessVersion {
        public static void main(String[] args) {
                String version = "Java 1.1";
                try {
                        "".getBytes("ISO8859_13");
                        version = "Java 1.3";

                        "".getBytes("ISO8859_15");
                        version = "Java 1.4";

                        Signature.getInstance("SHA256withRSA");
                        version = "Java 5";

                        "".getBytes("KOI8_U");
                        version = "Java 6";

                        Signature.getInstance("SHA256withECDSA");
                        version = "Java 7";
                } catch(Exception e) {}
                System.out.println(version);
        }
}

Java 1.1 đã giới thiệu mã hóa ký tự và thuật toán mã hóa cho Java. Các phiên bản sau này đã thêm nhiều mã hóa và thuật toán. Chương trình này cố gắng sử dụng mã hóa và thuật toán cho đến khi bắt được một ngoại lệ. Tôi hy vọng một mã hóa bị thiếu để ném java.io.UnsupportedEncodingExceptionvà một thuật toán bị thiếu để ném java.security.NoSuchAlgorithmException.

Tôi đã có một Macintosh PowerPC cũ với bốn phiên bản Java cũ. Máy OpenBSD của tôi có thêm hai phiên bản, vì vậy tôi đã thử nghiệm sáu phiên bản sau:

  • Java 1.1.8 trong MRJ 2.2.6 cho Mac OS 9.2.2
  • Java 1.3.1_16 cho Mac OS X Panther
  • Java 1.4.2_21 cho Mac OS X Tiger
  • Java 1.5.0_19 cho Mac OS X Tiger
  • OpenJDK 1.6.0_32 cho OpenBSD 5.5
  • OpenJDK 1.7.0_21 cho OpenBSD 5.5

Chương trình này cũng có thể chạy trong JamVM 1.5.4 và gcj 4.8.2 cho OpenBSD, nhưng không xác định chúng là các triển khai khác nhau. Nó chỉ in "Java 5".

Thời gian chạy Mac OS cho Java

Nhờ "Viết một lần, chạy mọi nơi!", Tôi có thể viết chương trình này một lần, biên dịch nó một lần và chạy một GuessVersion. Class trong tất cả tám máy ảo. Tôi cần một trình biên dịch cho Java 1.1, phiên bản cũ nhất trong bộ sưu tập của tôi.

Trình biên dịch của tôi là javaccông cụ từ MRJ SDK 2.2. Bởi vì Classic Mac OS không có dòng lệnh, javaclà một công cụ đồ họa đẹp, nơi tôi chọn các tệp và tùy chọn và nhấp vào "Do Javac". Sau khi tôi chỉnh sửa mã của mình, tôi chỉ cần nhấp lại vào "Làm Javac".

javac từ MRJ SDK 2.2 cho hệ điều hành Mac cổ điển

Cách dễ nhất để chạy GuessVersion. Class là mở nó trong JBindery, một công cụ khác từ MRJ SDK 2.2. Thời gian chạy là MRJ 2.2.6, triển khai Java 1.1.8.


22

Tôi không chắc điểm của mình là bao nhiêu, vì nó phụ thuộc vào chính xác những gì bạn coi là mã thông báo từ vựng, nhưng tôi đang cố gắng lạm dụng hệ thống đếm đó càng nhiều càng tốt với một chuỗi dài ...

Nó cũng phụ thuộc vào việc bạn tính đây là xác định 7 phiên bản khác nhau hay 16 ... (Nó có thể được mở rộng một cách tầm thường lên tới 190).

class V extends ClassLoader
{
    public static void main(String[]args)
    {
        for(byte b=60;;)
            try {
                byte[]buf="\u00ca\u00fe\u00ba\u00be\u0000\u0000\u00002\u0000\u0005\u0007\u0000\u0003\u0007\u0000\u0004\u0001\u0000\u0001A\u0001\u0000\u0010java/lang/Object\u0006\u0000\u0000\u0001\u0000\u0002\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000".getBytes("ISO-8859-1");
                buf[7]=b--;
                new V().defineClass(buf,0,53);
                System.out.println(b-43);
                break;
            }
            catch(Throwable t){}
    }
}

Nó hoạt động bằng cách cố gắng xác định một giao diện trong trình nạp lớp tùy chỉnh với số phiên bản chính giảm dần của định dạng lớp. Cái đầu tiên không ném java.lang.UnsupportedClassVersionErrortương ứng với phiên bản của VM.


Đếm 84 mã thông báo. Vẫn không kiểm tra nó mặc dù.
Victor Stafusa

Câu trả lời của bạn là thể loại. Có thể giảm đáng kể đến 83 mã thông báo bằng cách sử dụng String... args.
Victor Stafusa

@Victor, điều đó sẽ làm phức tạp câu hỏi liệu nó có hỗ trợ 7 phiên bản khác nhau hơn nữa không. Tôi không biết bất kỳ trình biên dịch nào hỗ trợ cú pháp Java 5 và biên dịch thành các tệp lớp tương thích với Java 1.
Peter Taylor

Điểm tốt. Tôi quên mất điều đó.
Victor Stafusa

1
Java 1.1.8 (trong MRJ 2.2.6) không thể biên dịch cái này, cho đến khi tôi thêm 17 mã thông báo : protected Class loadClass(String name, boolean resolve) { return Object.class; }. Các tài liệu API hiện tại đã bỏ qua việc đề cập đến cách đây là một phương thức trừu tượng trước Java 1.2. Tôi trả về Object. Class vì phương thức này nhận được một cuộc gọi cho "java.lang.Object".
hạt nhân

8
class Evil {
    public static void main(String... args) {
        String s1 = "Good";
        s1 += "morning";
        int a = 7;
        if (s1 != s1.intern())
            try {
                a--;
                javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar().equals(null);
            } catch (Throwable e) {
                a--;
            }
        System.out.println(a);
    }
}

Thuật toán thực tập đã thay đổi giữa Java 6 và 7. Xem /programming//a/7224864/540552

XMLGregorianCalWiki.equals (null) được sử dụng để ném NullPulumException trong java 5, nhưng điều này đã được sửa trong java 6. Xem http://bugs.sun.com/view_orms.do?bug_id=6285370

100 96 92 87 85 mã thông báo ở đây. Cảm ơn Peter Taylor đã giảm 7 mã thông báo.


1
Bạn có thể lưu 3 mã thông báo bằng cách lưu trữ số phiên bản trong s1. Bạn có thể có thể tiết kiệm thêm 2 bằng cách bắt trực tiếp DatatypeConfigurationExceptionNém , với giả định sẽ không bị ném.
Peter Taylor

1
Hoặc tốt hơn, giữ int anhưng khởi tạo nó ngay lập tức, để ifkhối trở nên trống rỗng. Phủ định điều kiện, loại bỏ cái khác và sử dụng --thay vì gán trực tiếp a.
Peter Taylor
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.