JVM sürümünü algılamak için bir java kodu yazın


17

Amaç, JVM sürümünü uyumluluk değişikliklerine, yan etkilere, hatalara ve / veya bir sürümde bir şekilde ve başka bir sürümde başka bir şekilde çalışan tanımlanmamış davranışa bağlı olarak algılayan java kodu yazmaktır. Ayrıca kod, boşluklardan ve okunaklı değişken adlarından ödün vermeden en az biraz okunabilir olmalıdır.

Bu amacı sağlamak için kesin resmi kurallar şunlardır:

  1. Kod java yazılmalı ve içinde çalıştığı JRE sürümünü çıkarmalıdır.

  2. Kod, özellikle java sürümünü algılamak için sağlanan veya JDK veya JRE sürümünü ücretsiz veren herhangi bir JDK veya JRE API'sini kullanmamalıdır.

  3. Kod yansıma kullanmamalıdır.

  4. Kod yalnızca Hotspot Java SE 5, 6 ve 7'de çalışmak için gereklidir, ancak diğer JVM'lerde de çalışabilir.

  5. Kod, sınıf yolunda herhangi bir üçüncü taraf kitaplığı kullanmamalıdır.

  6. Kod başka bir işlem başlatmamalıdır, java veya değil.

  7. Kod, ortam değişkenlerini kullanmamalıdır.

  8. Kod, önceden varolan dosyaları veya klasörleri arayan dosya sisteminde arama yapmamalıdır.

  9. Kod tek bir dosyada bulunmalı ve public static void main(String[] args)veya ile çağrılmalıdır public static void main(String... args).

  10. Kod, JRE'de bulunan herkese açık olmayan herhangi bir API kullanmamalıdır.

  11. Kod, yürütme sırasında NoClassDefFoundError, NoSuchMethodError, ClassNotFoundException veya NoSuchMethodException oluşturmamalıdır.

  12. Kod, internet veya herhangi bir yerel ağ ile bağlantısı kesilmiş bir sistemde çalıştırılmalıdır.

  13. Neden bir versiyonda bir şekilde, başka bir versiyonda başka bir şekilde davrandığını açıklamalısınız.

puanlama

En iyi çözümü ölçmek için kullanılan yöntem max (n / s) 'dir; burada n, bu kurallardan herhangi birini (en az 5, 6 ve 7 sürümlerini) ihlal etmeden algılanan farklı java sürümlerinin sayısıdır ve s, sözcük belirteçlerinin sayısıdır çözelti içinde.


Daha iyi bir etiket bulunamadı ve son iki tanesini vermek zorunda kaldım. Ayrıca, yeni etiketler oluşturmak için yeterli temsilcisi yok. Java'nın nedeni, sözde çok taşınabilir bir dil olmasıdır, bu yüzden yazmak çok ilginç olacaktır. Ayrıca, java versiyonları, portakalları elmalarla karşılaştırmak zorunda kalmadan, ortamı algılayan girişleri tekdüzelikle karşılaştırabileceğimiz şekilde tanımlanmıştır.
Victor Stafusa

VM versiyon tespitinin sisteme saldırmak için bir adım olduğunu savunmaktan kaçınabilirsiniz. Başka bir önerim olduğunu söyleyemem.
dmckee --- eski moderatör yavru kedi

@dmckee [code-golf] etiketini düşürdü. [Underhanded] etiketini ekleyin. Lütfen [java] etiketini oluşturabilir misiniz?
Victor Stafusa

4
Bu soruyu konu dışı olarak kapatmak için oy kullanıyorum çünkü el altında kalan zorluklar artık bu sitede konuyla ilgili değil. meta.codegolf.stackexchange.com/a/8326/20469
kedi

@cat, etiketi kaldırmış olmalısınız, çünkü soruya uymadı.
Peter Taylor

Yanıtlar:


9

6/102 = 0.0588

6 sürümü algılar. (Ben silindi sonra, 103 aşağı 102 sözcük belirteçleri Has publiciçinde 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 , Java'ya karakter kodlamaları ve şifreleme algoritmaları getirdi. Daha sonraki sürümler daha fazla kodlama ve algoritma ekledi. Bu program bir istisna yakalayana kadar kodlamaları ve algoritmaları kullanmaya çalışır. Ben eksik bir kodlama atmak java.io.UnsupportedEncodingExceptionve eksik bir algoritma atmak bekliyoruz java.security.NoSuchAlgorithmException.

Java'nın dört eski sürümüne sahip eski bir PowerPC Macintosh'um vardı. OpenBSD makinemin iki sürümü daha var, bu yüzden bu altı sürümü test ettim:

  • Mac OS 9.2.2 için MRJ 2.2.6'da Java 1.1.8
  • Mac OS X Panther için Java 1.3.1_16
  • Mac OS X Tiger için Java 1.4.2_21
  • Mac OS X Tiger için Java 1.5.0_19
  • OpenBSD 5.5 için OpenJDK 1.6.0_32
  • OpenBSD 5.5 için OpenJDK 1.7.0_21

Bu program, OpenBSD için JamVM 1.5.4 ve gcj 4.8.2'de de çalışabilir, ancak bunları farklı uygulamalar olarak tanımlamaz. Yalnızca "Java 5" yazdırır.

Java için Mac OS Çalışma Zamanı

"Bir kez yazın, her yerde çalıştırın!" Sayesinde, bu programı bir kez yazabilir, bir kez derleyebilir ve sekiz sanal makinede bir GuessVersion.class çalıştırabilirim. Koleksiyonumdaki en eski sürüm olan Java 1.1 için bir derleyiciye ihtiyacım var.

Derleyicim javacMRJ SDK 2.2'nin aracıdır. Klasik Mac OS'de komut satırı olmadığından, javacdosyaları ve seçenekleri seçip "Javac Yap" ı tıkladığım oldukça grafiksel bir araçtır. Kodumu düzenledikten sonra tekrar "Javac Yap" ı tıklıyorum.

Klasik Mac OS için MRJ SDK 2.2'den javac

GuessVersion.class dosyasını çalıştırmanın en kolay yolu, MRJ SDK 2.2'nin başka bir aracı olan JBindery'de açmaktır. Çalışma zamanı, Java 1.1.8'in bir uygulaması olan MRJ 2.2.6'dır.


22

Puanımın ne olduğundan emin değilim, çünkü tam olarak sözlüksel bir jeton olarak düşündüğünüze bağlıdır, ancak bu sayma sistemini uzun bir dizeyle mümkün olduğunca kötüye kullanmaya çalışıyorum ...

Ayrıca, 7 farklı sürümü mi yoksa 16'yı mı tanımladığınıza bağlıdır. (Önemsiz olarak 190'a kadar uzatılabilir).

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){}
    }
}

Sınıf biçiminin büyük sürüm numaralarının azalan özel bir sınıf yükleyicide bir arabirim tanımlamaya çalışarak çalışır. İlkini atmayan ilk kişi java.lang.UnsupportedClassVersionErrorVM'nin sürümüne karşılık gelir.


84 jeton sayıldı. Yine de test etmedi.
Victor Stafusa

Cevabınız güler yüzlü. Kullanarak önemsiz olarak 83 jetonu azaltabilir String... args.
Victor Stafusa

@Victor, bu, 7 farklı sürümü daha da destekleyip desteklemediği sorununu zorlaştıracaktır. Java 5 sözdizimini destekleyen ve Java 1 uyumlu sınıf dosyalarını derleyen herhangi bir derleyicinin farkında değilim.
Peter Taylor

İyi bir nokta. Bunu unutmuştum.
Victor Stafusa

1
Ben 17 daha belirteçleri ekledi kadar Java 1.1.8 (MRJ 2.2.6), bu derlemeye başarısız oldu: protected Class loadClass(String name, boolean resolve) { return Object.class; }. Mevcut API belgeleri, bunun Java 1.2'den önce nasıl soyut bir yöntem olduğunu belirtmeyi ihmal ediyor. Yöntem "java.lang.Object" için bir çağrı alır çünkü Object.class döndürür.
kernigh

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);
    }
}

Staj algoritması Java 6 ile 7 arasında değişti. Bkz. Https://stackoverflow.com/a/7224864/540552

XMLGregorianCalendar.equals (null), java 5'te NullPointerException öğesini atmak için kullanıldı, ancak bu java 6'da düzeltildi. Bkz. Http://bugs.sun.com/view_bug.do?bug_id=6285370

100 96 92 87 85 jetonları burada. Peter Taylor'a 7 jetonu azalttığı için teşekkürler.


1
Sürüm numarasını s1'e kaydederek 3 jeton kaydedebilirsiniz. Atılamayacağınız varsayımına doğrudan Throwable'ı yakalayarak muhtemelen 2 tane daha kurtarabilirsiniz DatatypeConfigurationException.
Peter Taylor

1
Ya da daha iyisi, int ahemen tutun ama hemen başlatın, böylece ifblok boşalır. Koşulu kısaltın, diğerini kaldırın ve --doğrudan atama yerine kullanın a.
Peter Taylor
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.