Bagaimana Anda menabrak JVM?


144

Saya sedang membaca buku tentang keterampilan pemrograman di mana penulis bertanya kepada orang yang diwawancarai, "Bagaimana Anda menabrak JVM?" Saya pikir Anda bisa melakukannya dengan menulis infinite untuk-loop yang pada akhirnya akan menggunakan semua memori.

Adakah yang punya ide?



stackoverflow.com/questions/30072883/... "Jika saya menggunakan JDK1.8_40 atau yang lebih baru (Oracle atau OpenJDK melakukan hal yang sama), kode berikut bersama-sama dengan ukuran dialog akan merusak aplikasi (mencoba Windows 7, x64, 64bit JDK)" - Kode hanya 40 baris, dan itu menyebabkan crash JVM yang tepat.
Dreamspace President

Jawaban:


6

Hal yang paling dekat dengan satu "jawaban" adalah System.exit()yang mengakhiri JVM segera tanpa pembersihan yang tepat. Namun terlepas dari itu, kode asli dan kehabisan sumber daya adalah jawaban yang paling mungkin. Sebagai alternatif, Anda dapat mencari bug bug Sun di versi JVM Anda, beberapa di antaranya memungkinkan untuk skenario kerusakan berulang. Kami biasa mendapatkan crash semi-reguler ketika mendekati batas memori 4 Gb di bawah versi 32-bit (kami biasanya menggunakan 64-bit sekarang).


71
tanpa pembersihan yang tepat? apakah kamu yakin Dokumentasi mengatakan "Hentikan mesin virtual Java yang sedang berjalan dengan memulai urutan pematiannya ... semua kait pematian yang terdaftar, jika ada, dimulai ... semua pemecah masalah yang tidak dijalankan dijalankan" - bukankah itu pembersihan yang tepat?
user85421

51
Ini bukan crash JVM, itu sengaja dan secara eksplisit memulai penghentian eksekusi yang tertib.
BenM

9
Lebih dekat dengan menabrak jvm adalah Runtime.getRuntime (). Halt (status). Menurut dokumen "metode ini tidak menyebabkan kait shutdown untuk dimulai dan tidak menjalankan finalizer tanpa diundang jika finalisasi saat keluar telah diaktifkan". Masih bukan crash, tapi lebih dekat dari System.exit.
henry

48
Ini benar-benar jawaban yang buruk.
Antonio

174

Saya tidak akan menyebut melempar OutOfMemoryError atau StackOverflowError crash. Ini hanya pengecualian normal. Untuk benar-benar crash VM ada 3 cara:

  1. Gunakan JNI dan crash dalam kode asli.
  2. Jika tidak ada manajer keamanan yang diinstal, Anda dapat menggunakan refleksi untuk crash VM. Ini adalah VM khusus, tetapi biasanya VM menyimpan banyak pointer ke sumber daya asli di bidang pribadi (misalnya pointer ke objek thread asli disimpan dalam bidang yang panjang di java.lang.Thread ). Ubah saja melalui refleksi dan VM akan crash cepat atau lambat.
  3. Semua VM memiliki bug, jadi Anda hanya perlu memicu satu.

Untuk metode terakhir, saya punya contoh singkat, yang akan menabrak Sun Hotspot VM dengan tenang:

public class Crash {
    public static void main(String[] args) {
        Object[] o = null;

        while (true) {
            o = new Object[] {o};
        }
    }
}

Ini mengarah ke tumpukan overflow di GC sehingga Anda tidak akan mendapatkan StackOverflowError tetapi crash nyata termasuk file hs_err *.


9
Wow! Ini crash Sun Java 5, Sun Java 6 dan OpenJDK 6 (di Ubuntu 9.04) tanpa file hs_err * tetapi hanya "Kesalahan segmentasi!" ...
Joachim Sauer

1
System.exit () adalah cara yang jauh lebih mudah untuk menabrak JVM (kecuali manajer keamanan diinstal)
instantsetsuna

4
Tidak tahu kapan diperbaiki, tetapi baru diuji pada 1.7.0_09 dan baik-baik saja. Baru saja mendapatkan yang diharapkan: Pengecualian di utas "utama" java.lang.OutOfMemoryError: Java heap space at CrashJVM.main (CrashJVM.java:7)
Chad NB

2
Saya mencoba kode di atas pada Intel Core i7 2.4 GHz / 8 GB RAM / JDK1.7 64bit tetapi JVM masih menyala setelah 20 menit. (Lucu: Kipas laptop saya lebih keras daripada jet tempur di langit). Apakah masalah ini diperbaiki di JDK 1.7+?
realPK

3
Dalam JDK 1.8_u71 ini menyebabkanjava.lang.OutOfMemoryError: GC overhead limit exceeded
Clashsoft


56

Gunakan ini:

import sun.misc.Unsafe;

public class Crash {
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    public static void crash() {
        unsafe.putAddress(0, 0);
    }
    public static void main(String[] args) {
        crash();
    }
}

Kelas ini harus di boot classpath karena menggunakan kode tepercaya, jadi jalankan seperti ini:

java -Xbootclasspath / p :. Jatuh


14
Alih-alih menggunakan -Xbootclasspath Anda juga bisa melakukan ini: Field f = Unsafe.class.getDeclaredField( "theUnsafe" ); f.setAccessible( true ); unsafe = (Unsafe) f.get( null );Bekerja sangat baik untuk saya.
memaksa

Unsafemenurut definisi, "tidak aman". Ini sedikit curang.
Hot Licks

1
getDeclaredFieldTrik kerja yang dikonfirmasi menggunakan JDK 8u131 di Linux x64, termasuk produksi hs_err_pid*.logdari a SIGSEGV.
Jesse Glick

Menggunakan Unsafebukan cheat. OP tidak mencari solusi 'bersih' untuk masalah pemrograman. Dia membutuhkan jvm untuk crash dalam cara yang paling buruk mungkin. Melakukan hal-hal asli yang jahat adalah apa yang dapat membuat itu terjadi, dan memang itulah yang Unsafeterjadi.
jvdneste

34

Saya datang ke sini karena saya juga mengalami pertanyaan ini di The Passionate Programmer , oleh Chad Fowler. Bagi mereka yang tidak memiliki akses ke salinan, pertanyaan dibingkai sebagai semacam filter / tes untuk kandidat yang mewawancarai posisi yang membutuhkan "programmer Java yang benar-benar baik."

Secara khusus, ia bertanya:

Bagaimana Anda menulis sebuah program, di Java murni, yang akan menyebabkan Java Virtual Machine crash?

Saya telah memprogram di Jawa selama lebih dari 15 tahun, dan saya menemukan pertanyaan ini membingungkan dan tidak adil. Seperti yang ditunjukkan orang lain, Java, sebagai bahasa yang dikelola, dirancang khusus untuk tidak crash . Tentu saja selalu ada bug JVM, tetapi:

  1. Setelah 15+ tahun JRE tingkat produksi, jarang terjadi.
  2. Setiap bug seperti itu kemungkinan akan ditambal pada rilis berikutnya, jadi seberapa besar kemungkinan Anda sebagai seorang programmer untuk bertemu dan mengingat kembali rincian set-stop JRE saat ini?

Seperti yang lain telah disebutkan, beberapa kode asli melalui JNI adalah cara yang pasti untuk menabrak JRE. Tetapi penulis secara khusus disebutkan dalam Java murni , jadi itu keluar.

Pilihan lain adalah memberi makan kode byte palsu JRE; cukup mudah untuk membuang beberapa data biner sampah ke file .class, dan meminta JRE untuk menjalankannya:

$ echo 'crap crap crap' > crap.class
$ java crap
Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 1668440432 in class file crap

Apakah itu penting? Maksudku JRE itu sendiri belum jatuh; itu benar mendeteksi kode palsu, melaporkannya, dan keluar.

Ini memberi kita berbagai solusi yang paling jelas seperti meniup tumpukan melalui rekursi, kehabisan memori tumpukan melalui alokasi objek, atau hanya melempar RuntimeException. Tapi ini hanya menyebabkan JRE keluar dengan StackOverflowErrorpengecualian atau serupa, yang, sekali lagi bukan benar-benar crash .

Jadi, apa yang tersisa? Saya benar-benar ingin mendengar apa yang sebenarnya ada dalam pikiran penulis sebagai solusi yang tepat.

Pembaruan : Chad Fowler merespons di sini .

PS: buku yang bagus. Saya mengambilnya untuk dukungan moral sambil belajar Ruby.


1
Pertanyaan wawancara semacam itu berfungsi sebagai tes lakmus untuk pengembang Java yang telah ada cukup lama untuk 1) telah menyaksikan (banyak) crash JVM dan 2) telah menarik beberapa kesimpulan atau, lebih baik lagi, seperti (memproklamirkan diri sendiri) para ahli Jawa telah mencoba memahami alasan yang mendasari kecelakaan. Chad Fowler juga menyatakan dalam bukunya bahwa pemrogram Java yang memproklamirkan dirinya sendiri "bahkan tidak dapat menemukan jawaban yang salah", yaitu belum mencoba memikirkan kapan seluruh kelas masalah potensial. Intinya: pertanyaan ini adalah segway untuk "Bagaimana mencegah crash JVM?" yang jelas lebih baik untuk diketahui.
Shonzilla

1
Saya akan mencari orang-orang yang hanya menjawab (seperti kebanyakan di sini) "meluap tumpukan", system.exit (), atau shutdown "Normal" lainnya karena mereka tidak benar-benar memahami JVM atau kata "Crash". Untuk mengenali (seperti yang Anda lakukan) bahwa ini sangat tidak normal adalah cara yang cukup baik untuk mengidentifikasi programmer yang lebih maju. Saya setuju dengan pernyataan pertama Anda, saya akan menemukan pertanyaan yang sangat bagus dan sangat adil untuk ditanyakan atau ditanyakan - pertanyaan tanpa jawaban konkret selalu yang terbaik.
Bill K

20

Kode ini akan merusak JVM dengan cara yang tidak menyenangkan

import sun.dc.pr.PathDasher; 

public class Crash
{
     public static void main(String[] args)
     {    
        PathDasher dasher = new PathDasher(null) ;
     }
}

1
Mendapatkan kesalahan kompilasi saat menggunakan JDK 1.7 dengan kode ini: Pembatasan akses: Tipe PathDasher tidak dapat diakses karena pembatasan pada perpustakaan yang diperlukan C: \ Program Files \ Java \ jdk1.7.0_51 \ jre \ lib \ rt.jar
realPK

7
Ini melempar InternalErrordalam JDK 1.8. JVM tidak lagi gagal.
Sotirios Delimanolis

18

Terakhir kali saya mencoba ini akan melakukannya:

public class Recur {
    public static void main(String[] argv) {
        try {
            recur();
        }
        catch (Error e) {
            System.out.println(e.toString());
        }
        System.out.println("Ended normally");
    }
    static void recur() {
        Object[] o = null;
        try {
            while(true) {
                Object[] newO = new Object[1];
                newO[0] = o;
                o = newO;
            }
        }
        finally {
            recur();
        }
    }
}

Bagian pertama dari file log yang dihasilkan:

#
# An unexpected error has been detected by Java Runtime Environment:
#
#  EXCEPTION_STACK_OVERFLOW (0xc00000fd) at pc=0x000000006dad5c3d, pid=6752, tid=1996
#
# Java VM: Java HotSpot(TM) 64-Bit Server VM (11.2-b01 mixed mode windows-amd64)
# Problematic frame:
# V  [jvm.dll+0x2e5c3d]
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
#

---------------  T H R E A D  ---------------

Current thread (0x00000000014c6000):  VMThread [stack: 0x0000000049810000,0x0000000049910000] [id=1996]

siginfo: ExceptionCode=0xc00000fd, ExceptionInformation=0x0000000000000001 0x0000000049813fe8 

Registers:
EAX=0x000000006dc83090, EBX=0x000000003680f400, ECX=0x0000000005d40ce8, EDX=0x000000003680f400
ESP=0x0000000049813ff0, EBP=0x00000000013f2df0, ESI=0x00000000013f0e40, EDI=0x000000003680f400
EIP=0x000000006dad5c3d, EFLAGS=0x0000000000010206

Saya sedikit terhibur dengan downvote, mengingat bahwa ini adalah salah satu dari dua jawaban yang menunjukkan bagaimana melakukannya secara murni dengan kode Java, dan termasuk kode lengkap.
Hot Licks

Saya setuju bahwa downvote tidak beralasan - ini adalah crash yang sebenarnya, tetapi bagaimana Anda akan menjawab pertanyaan wawancara. Kecuali jika Anda sebelumnya telah meneliti dan menghafal ini, Anda tidak dapat memberikannya sebagai jawaban dalam wawancara dan jika Anda bisa, saya akan mempertimbangkan jawaban netral ke buruk - itu tidak menunjukkan bagaimana Anda akan mendekati masalah. Saya berharap apa yang Anda lakukan adalah eksploitasi bug untuk jvm google dan mengimplementasikannya yang merupakan jawaban yang sangat baik.
Bill K

@ BillK - Tidak, di atas adalah sepenuhnya pekerjaan saya sendiri, meskipun saya muncul beberapa tahun yang lalu, bereksperimen dengan berbagai hal. Dalam sebuah wawancara, saya kemungkinan akan mengatakan, "Saya sudah melakukannya, menggunakan coba / tangkap dan rekursi, tapi saya tidak dapat menguraikan kode yang tepat sekarang."
Hot Licks

1
Apa detailnya (versi JDK, argumen VM apa saja)? Tidak yakin apa versi "11.2-b0". Saya menjalankan ini, tetapi hanya mengkonsumsi banyak CPU.
Stefan Reich

@ Hot Licks: Apa konsep dalam contoh crash JVM? Mengapa JVM crash tentang kode. Semua utas memiliki utas tumpukan yang terpisah ...
VJS

15

Implementasi JVM yang sempurna tidak akan pernah crash.

Untuk membuat crash JVM, selain dari JNI, Anda perlu menemukan bug di VM itu sendiri. Infinite loop hanya mengkonsumsi CPU. Mengalokasikan memori yang tidak terbatas seharusnya hanya menyebabkan OutOfMemoryError dalam JVM yang dibangun dengan baik. Ini mungkin akan menyebabkan masalah untuk utas lainnya, tetapi JVM yang baik tetap tidak crash.

Jika Anda dapat menemukan bug dalam kode sumber VM, dan misalnya menyebabkan kesalahan segmentasi dalam penggunaan memori implementasi VM, maka Anda benar-benar dapat crash.


14

Jika Anda ingin membuat crash JVM - gunakan yang berikut ini di Sun JDK 1.6_23 atau di bawah ini:

Double.parseDouble("2.2250738585072012e-308");

Ini disebabkan oleh bug di Sun JDK - juga ditemukan di OpenJDK. Ini diperbaiki dari Oracle JDK 1.6_24 dan seterusnya.


10

Tergantung pada apa yang Anda maksud dengan crash.

Anda dapat melakukan rekursi tak terbatas untuk membuatnya kehabisan ruang stack, tetapi itu akan crash "anggun". Anda akan mendapatkan pengecualian, tetapi JVM itu sendiri akan menangani semuanya.

Anda juga dapat menggunakan JNI untuk memanggil kode asli. Jika Anda tidak melakukannya dengan benar maka Anda dapat membuatnya sulit. Debugging crash itu adalah "menyenangkan" (percayalah, saya harus menulis C ++ DLL besar yang kita sebut dari applet java yang ditandatangani). :)


6

Buku Java Virtual Machine oleh Jon Meyer memiliki contoh serangkaian instruksi bytecode yang menyebabkan JVM ke dump inti. Saya tidak dapat menemukan salinan buku ini. Jika ada orang di luar sana, silakan cari dan kirimkan jawabannya.


5

pada winxpsp2 w / wmp10 jre6.0_7

Desktop.open (uriToAviOrMpgFile)

Hal ini menyebabkan thread yang muncul untuk melemparkan Throwable yang tidak tertangkap dan crash hotspot

YMMV


5

Perangkat keras yang rusak dapat merusak program apa pun. Saya pernah mengalami crash aplikasi yang dapat direproduksi pada mesin tertentu sambil bekerja dengan baik pada mesin lain dengan pengaturan yang sama persis. Ternyata mesin itu memiliki RAM yang rusak.


5

cara terpendek :)

public class Crash
{
    public static void main(String[] args)
    {
        main(args);
    }
}

Tidak crash. Ini memberikan kesalahan waktu kompilasi Exception in thread "main" java.lang.StackOverflowError at Test.main. Saya menggunakan jdk1.8.0_65
Quazi Irfan

5

Bukan crash, tapi lebih dekat ke crash daripada jawaban yang diterima menggunakan System.exit

Anda dapat menghentikan JVM dengan menelepon

Runtime.getRuntime().halt( status )

Menurut dokumen: -

"metode ini tidak menyebabkan kait shutdown untuk dimulai dan tidak menjalankan fininver yang tidak diinvasi jika finalisasi saat keluar telah diaktifkan".



4

Jika Anda ingin berpura-pura kehabisan memori, Anda bisa melakukannya

public static void main(String[] args) {
    throw new OutOfmemoryError();
}

Saya tahu beberapa cara untuk menyebabkan JVM membuang file kesalahan dengan memanggil metode asli (yang dibangun di dalam), tetapi mungkin yang terbaik Anda tidak tahu bagaimana melakukan ini. ;)


4

Jika Anda mendefinisikan crash sebagai proses batal karena situasi tidak tertangani (yaitu tidak ada Pengecualian atau Kesalahan Java), maka ini tidak dapat dilakukan dari dalam Java (kecuali jika Anda memiliki izin untuk menggunakan kelas sun.misc.Unsafe). Ini inti dari kode terkelola.

Kecelakaan umum dalam kode asli terjadi dengan mendeferensier pointer ke area memori yang salah (alamat nol atau tidak selaras). Sumber lain dapat berupa instruksi mesin ilegal (opcodes) atau sinyal tidak tertangani dari pustaka atau panggilan kernel. Keduanya dapat dipicu jika JVM atau pustaka sistem memiliki bug.

Misalnya kode JITed (dihasilkan), metode asli atau panggilan sistem (driver grafis) dapat memiliki masalah yang menyebabkan crash nyata (itu cukup umum untuk mendapatkan crash ketika Anda menggunakan fungsi ZIP dan mereka kehabisan memori). Dalam kasus-kasus tersebut penangan kecelakaan JVM menendang dan membuang negara. Itu juga bisa menghasilkan file inti OS (Dr. Watson pada Windows dan core dump pada * nix).

Di Linux / Unix Anda dapat dengan mudah membuat crash JVM dengan mengirimkannya sinyal ke proses yang sedang berjalan. Catatan: Anda tidak boleh menggunakan SIGSEGVini, karena Hotspot menangkap sinyal ini dan melemparkannya kembali sebagai NullPointerException di sebagian besar tempat. Jadi lebih baik mengirim SIGBUScontoh.


3

JNI adalah sumber besar gangguan. Anda juga dapat crash menggunakan antarmuka JVMTI karena itu perlu ditulis dalam C / C ++ juga.


2

Jika Anda membuat proses utas yang secara tak terhingga memunculkan lebih banyak utas (yang menghasilkan lebih banyak utas, yang ...) pada akhirnya Anda akan menyebabkan kesalahan stack overflow di JVM itu sendiri.

public class Crash {
    public static void main(String[] args) {

        Runnable[] arr = new Runnable[1];
        arr[0] = () -> {

            while (true) {
                new Thread(arr[0]).start();
            }
        };

        arr[0].run();
    }
}

Ini memberi saya output (setelah 5 menit, perhatikan ram Anda)

An unrecoverable stack overflow has occurred.
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_STACK_OVERFLOW (0xc00000fd) at pc=0x0000000070e53ed7, pid=12840, tid=0x0000000000101078
#
# JRE version: Java(TM) SE Runtime Environment (8.0_144-b01) (build 1.8.0_144-b01)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# 

1

Jika dengan "crash" yang Anda maksud adalah pembatalan JVM yang tiba-tiba, seperti yang akan menyebabkan JVM menulis ke hs_err_pid% p.lognya , Anda dapat melakukannya dengan cara ini.

Atur argumen-Xmx ke nilai yang sangat kecil dan beri tahu JVM untuk memaksakan crash pada outemmory:

 -Xmx10m -XX:+CrashOnOutOfMemoryError

Untuk menjadi jelas, tanpa argumen kedua di atas, itu hanya akan mengakibatkan jvm berakhir dengan OutOfMemoryError, tetapi tidak akan "crash" atau tiba-tiba membatalkan jvm.

Teknik ini terbukti membantu ketika saya mencoba untuk menguji JVM -XX: ErrorFile arg, yang mengontrol di mana log hs_err_pid harus ditulis. Saya telah menemukan posting ini di sini, ketika mencoba menemukan cara untuk memaksa crash seperti itu. Ketika saya kemudian menemukan hal di atas berfungsi sebagai yang termudah untuk kebutuhan saya, saya ingin menambahkannya ke daftar di sini.

Akhirnya, FWIW, jika ada yang bisa menguji ini ketika mereka sudah memiliki nilai -Xms yang ditetapkan di args Anda (ke beberapa nilai yang lebih besar dari di atas), Anda akan ingin menghapus atau mengubah itu juga, atau Anda tidak akan mendapatkan crash tetapi hanya kegagalan jvm untuk memulai, melaporkan "Ukuran tumpukan awal diatur ke nilai yang lebih besar dari ukuran tumpukan maksimum". (Itu tidak akan jelas jika menjalankan JVM sebagai layanan, seperti dengan beberapa server aplikasi. Sekali lagi, itu menggigit saya, jadi saya ingin membagikannya.)


0

Jika Anda mengubah infinite for loop ke panggilan rekursif ke fungsi yang sama, maka Anda akan mendapatkan pengecualian stack overflow:

public static void main(String[] args) {
    causeStackOverflow();
}

public void causeStackOverflow() {
    causeStackOverflow();
}

0

Saya melakukannya sekarang, tetapi tidak sepenuhnya yakin bagaimana ... :-) JVM (dan aplikasi saya) terkadang hilang sepenuhnya. Tidak ada kesalahan yang dilemparkan, tidak ada yang dicatat. Berganti dari bekerja menjadi tidak berjalan sama sekali secara instan tanpa peringatan.


Mulailah memeriksa perangkat keras Anda, terutama memori Anda!
Thorbjørn Ravn Andersen

Sayangnya, ini ada di beberapa mesin yang jika tidak berjalan dengan baik. Hanya satu aplikasi khusus ini yang melakukannya (dan bukan memori atau prosesor yang intensif).
Brian Knoblauch

0

Terpendek? Gunakan kelas Robot untuk memicu CTRL + BREAK. Saya melihat ini ketika saya mencoba untuk menutup program saya tanpa menutup konsol (Itu tidak memiliki fungsi 'keluar').


Pertanyaan lama - semoga seseorang mendapat manfaat dari jawaban Anda di masa mendatang.
dbmitch

0

Apakah ini masuk hitungan?

long pid = ProcessHandle.current().pid();
try { Runtime.getRuntime().exec("kill -9 "+pid); } catch (Exception e) {}

Ini hanya berfungsi untuk Linux dan dari Java 9.

Untuk beberapa alasan saya tidak mendapatkan, ProcessHandle.current().destroyForcibly();tidak membunuh JVM dan melempar java.lang.IllegalStateExceptionpesan penghancuran proses saat ini tidak diperbolehkan .


0

Menjalankan ke masalah ini ketika mencoba untuk meniru kecelakaan JVM.

Jni bekerja, tetapi perlu di-tweak untuk platform yang berbeda. Akhirnya, saya menggunakan kombinasi ini untuk membuat crash JVM

  1. Mulai aplikasi dengan opsi JVM ini -XX:+CrashOnOutOfMemoryError
  2. Gunakan a long[] l = new long[Integer.MAX_VALUE];untuk memicu OOM

Kemudian JVM akan crash dan menghasilkan crash log.


-2

Jika 'Crash' adalah sesuatu yang mengganggu jvm / program dari terminasi normal, maka pengecualian yang tidak ditangani dapat melakukan ini.

public static void main(String args[]){
   int i = 1/0;
   System.out.print(i); // This part will not be executed due to above  unhandled exception
  }

Jadi, itu tergantung pada jenis CRASH apa ?!


3
Melempar pengecualian bukanlah kecelakaan.
Quazi Irfan

Pengecualian runtime tertangani adalah crash, meskipun, yang ArithmeticExceptionmerupakan
pertengahan
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.