Утечка памяти в минимально возможном количестве байтов


79

Ваша задача - написать код, который будет пропускать как минимум один байт памяти за как можно меньшее количество байт. Память должна быть просочилась, а не просто распределена .

Утечка памяти - это память, которую программа выделяет, но теряет возможность доступа до того, как она сможет правильно освободить память. Для большинства языков высокого уровня эта память должна быть выделена в куче.

Примером на C ++ будет следующая программа:

int main(){new int;}

Это делает new intв куче без указателя на него. Эта память мгновенно просочилась, потому что у нас нет возможности получить к ней доступ.

Вот как может выглядеть сводка утечек из Valgrind :

LEAK SUMMARY:
   definitely lost: 4 bytes in 1 blocks
   indirectly lost: 0 bytes in 0 blocks
     possibly lost: 0 bytes in 0 blocks
   still reachable: 0 bytes in 0 blocks
        suppressed: 0 bytes in 0 blocks

Во многих языках есть отладчик памяти (например, Valgrind ), если вы можете, вы должны включить вывод такого отладчика, чтобы убедиться, что у вас есть утечка памяти.

Цель состоит в том, чтобы минимизировать количество байтов в вашем источнике.


2
Возможно, у вас могут быть разные диапазоны утечки, и в зависимости от того, сколько вы пропустили, вы потеряете х% от вашего количества байтов
Кристофер

11
@ChristopherPeart Во-первых, я не фанат бонусов за испытания, а для двоих, как вы уже показали, очень легко утекать неограниченную память.
Пшеничный волшебник

1
Относящиеся . Однако, это не дубликат, потому что большинство ответов на этот вопрос образуют бесконечно достижимую структуру в памяти, а не в действительности утечку памяти.

2
в чем идея? Что мем не может быть освобожден? Я предполагаю, что это потребовало бы нативного выполнения для языков сборки мусора или использования ошибок.
Акостадинов

7
Я вижу, как языки, предназначенные для игры в гольф, терпят неудачу на этом ...
Kh40tiK

Ответы:


89

Perl (5.22.2), 0 байт

Попробуйте онлайн!

Я знал, что там будет какой-то язык, который пропустит память в пустой программе. Я ожидал, что это будет esolang, но оказывается, что perlутечка памяти в любой программе. (Я предполагаю, что это преднамеренно, потому что освобождение памяти, если вы знаете, что в любом случае собираетесь выйти, просто тратит время; поэтому общая рекомендация в настоящее время состоит в том, чтобы просто утечка оставшейся памяти, когда вы находитесь в процедурах выхода вашей программы .)

верификация

$ echo -n | valgrind perl
snip
==18517== 
==18517== LEAK SUMMARY:
==18517==    definitely lost: 8,134 bytes in 15 blocks
==18517==    indirectly lost: 154,523 bytes in 713 blocks
==18517==      possibly lost: 0 bytes in 0 blocks
==18517==    still reachable: 0 bytes in 0 blocks
==18517==         suppressed: 0 bytes in 0 blocks
==18517== 
==18517== For counts of detected and suppressed errors, rerun with: -v
==18517== ERROR SUMMARY: 15 errors from 15 contexts (suppressed: 0 from 0)

16
Мне понравился ответ Unlambda, но этот (ИМХО) слишком большой, так как, очевидно, сам интерпретатор теряет память, то есть я «определенно теряюсь: 7 742 байта в 14 блоках», когда я работаю perl --versionна своей машине Несмотря на то, что он никогда не запускает какую-либо программу.
Цеппелин

11
@zeppelin: Согласен, но, согласно нашим правилам, именно реализация определяет язык, таким образом, если реализация утечки памяти, все программы в языке утечки памяти. Я не обязательно уверен, что согласен с этим правилом, но на данный момент оно слишком укоренилось, чтобы реально измениться.

8
Это также работает в Node JS.
Деннис

6
Это похоже на новую стандартную лазейку в процессе создания ...
Майкл Хэмптон

46
Наконец-то скрипт на Perl, который я могу понять.
user11153

66

C 48 31 22 байта

Предупреждение: не запускайте это слишком много раз.

Спасибо Деннису за помощь и идеи!

f(k){shmget(k,1,512);}

Это идет на шаг дальше. shmgetвыделяет разделяемую память, которая не освобождается при завершении программы Он использует ключ для идентификации памяти, поэтому мы используем неинициализированный int. Это технически неопределенное поведение, но практически это означает, что мы используем значение, которое находится чуть выше вершины стека, когда это вызывается. Это будет записано в следующий раз, когда что-либо будет добавлено в стек, поэтому мы потеряем ключ.


Единственный случай, когда это не работает, это если вы можете выяснить, что было в стеке раньше. Для дополнительных 19 байтов вы можете избежать этой проблемы:

f(){srand(time(0));shmget(rand(),1,512);}

Или для 26 байтов:

main(k){shmget(&k,1,512);}

Но с этим, утечка памяти после выхода из программы. Во время работы программа имеет доступ к памяти, что противоречит правилам, но после завершения программы мы теряем доступ к ключу, и память все еще выделяется. Это требует рандомизации макета адресного пространства (ASLR), иначе &kвсегда будет одинаковым. В настоящее время ASLR обычно включен по умолчанию.


Проверка:

Вы можете использовать, ipcs -mчтобы увидеть, какая разделяемая память существует в вашей системе. Я удалил ранее существующие записи для ясности:

$ cat leakMem.c 
f(k){shmget(k,1,512);}
int main(){f();}     
$ gcc leakMem.c -o leakMem
leakMem.c:1:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
 f(k){shmget(k,1,512);}
 ^
leakMem.c: In function ‘f’:
leakMem.c:1:1: warning: type of ‘k’ defaults to ‘int’ [-Wimplicit-int]
leakMem.c:1:6: warning: implicit declaration of function ‘shmget’ [-Wimplicit-function-declaration]
 f(k){shmget(k,1,512);}
ppcg:ipcs -m

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      


$ ./leakMem 

$ ipcs -m

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      

0x0000007b 3375157    Riley      0          1          0  

1
@AndrewSavinykh Теоретически, shmid мог быть сохранен в файле, и программа могла присоединиться к нему в будущем. Вот как работает общая память Unix ...
tbodt

1
@AndrewSavinykh Совместно используемая память в основном становится ресурсом, который ОС может отдавать другим процессам. Он похож на файл, который находится в оперативной памяти, и любой процесс, который знает имя (ключ), имеет доступ к нему, пока он не будет удален. Представьте себе процесс, который вычисляет число, сохраняет его в памяти и завершает работу, прежде чем процесс, который считывает данные, подключается к общей памяти. В этом случае, если ОС освобождает память, второй процесс не может ее получить.
Райли

35
Спасибо за публикацию. Я просто защитил TIO от общих утечек памяти.
Деннис

4
@Dennis Вот почему я не опубликовал ссылку TIO. Я не знал, было ли это защищено или нет.
Райли

12
Мне нравится, как вы используете слово « проблема» для описания сценария, в котором программа теряет меньше памяти, чем предполагалось.
Касперд

40

Unlambda ( c-refcnt/unlambda), 1 байт

i

Попробуйте онлайн!

Это действительно сложная задача - найти уже существующий интерпретатор, который теряет память на очень простых программах. В этом случае я использовал Unlambda. Существует более одного официального интерпретатора Unlambda, но он c-refcntявляется одним из самых простых в сборке, и у него есть полезное свойство, заключающееся в утечке памяти при успешной работе программы. Таким образом, все, что мне нужно было дать, - это простейшая из возможных легальных программ Unlambda, неактивная. (Обратите внимание, что пустая программа здесь не работает; память все еще доступна в момент сбоя интерпретатора.)

верификация

$ wget ftp://ftp.madore.org/pub/madore/unlambda/unlambda-2.0.0.tar.gz
... чик ...
2017-02-18 18:11:08 (975 КБ / с) - «unlambda-2.0.0.tar.gz» сохранено [492894]
$ tar xf unlambda-2.0.0.tar.gz 
$ cd unlambda-2.0.0 / c-refcnt /
$ gcc unlambda.c
$ echo -ni | valgrind ./a.out / dev / stdin
... чик ...
== 3417 == РЕЗЮМЕ:
== 3417 == определенно потеряно: 40 байтов в 1 блоках
== 3417 == косвенно потеряно: 0 байтов в 0 блоках
== 3417 == возможно потеряно: 0 байтов в 0 блоках
== 3417 == все еще достижимо: 0 байтов в 0 блоках
== 3417 == подавлено: 0 байтов в 0 блоках
== 3417 == 
== 3417 == Для подсчета обнаруженных и подавленных ошибок, перезапустите с: -v
== 3417 == РЕЗЮМЕ ОШИБКИ: 1 ошибка из 1 контекста (исключено: 0 из 0)

39

TI-Basic, 12 байт

While 1
Goto A
End
Lbl A
Pause 

«... утечка памяти - это то, где вы используете Goto / Lbl в цикле или если условно (все, что имеет команду End), чтобы выпрыгнуть из этой структуры управления до того, как будет достигнута команда End ...» (подробнее)


7
Вау, я думаю, что помню это. Я продолжал выпрыгивать из своих циклов в моих старых базовых программах и заметил, как мой TI-84 + становился все медленнее и медленнее ...
Рэй

2
Да, большинство из нас знает это чувство;) @RayKoopa
Timtech

13
+1 для Ti Basic. Я потратил большую часть своего девятого класса, программируя эти вещи.
markasoftware

Вам нужно Pause в конце? Вы можете сэкономить 2 байта.
kamoroso94

@ kamoroso94 Я так думаю, потому что «если программа заканчивается, утечка очищается и больше не вызывает проблем», поэтому она останавливает завершение программы.
Timtech

32

Python <3.6.5, 23 байта

property([]).__init__()

property.__init__Утечки ссылки на имущество СТАРЫЙ fget, fset, fdelи __doc__если вы называете его на уже инициализирован propertyинстанции. Это ошибка, которая в конечном итоге сообщается как часть проблемы CPython 31787 и исправлена ​​в Python 3.6.5 и Python 3.7.0 . (Кроме того, да, property([])это то, что вы можете сделать.)


Был ли отправлен отчет об ошибке?
mbomb007


27

C #, 34 байта

class L{~L(){for(;;)new L();}}

Это решение не требует кучи. Ему просто нужен действительно трудолюбивый GC ( сборщик мусора ).

По сути это превращает GC в своего собственного врага.

объяснение

Всякий раз, когда вызывается деструктор , он создает новые экземпляры этого злого класса, пока истекает время ожидания, и говорит GC просто отбросить этот объект, не дожидаясь завершения деструктора. К тому времени были созданы тысячи новых экземпляров.

«Зло» в том, что чем сильнее работает GC, тем больше это взорвется вам в лицо.

Отказ от ответственности : ваш сборщик мусора может быть умнее моего. Другие обстоятельства в программе могут привести к тому, что GC проигнорирует первый объект или его деструктор. В этих случаях это не взорвется. Но во многих вариациях так и будет . Добавление нескольких байтов здесь и там может обеспечить утечку при любых возможных обстоятельствах. Ну, кроме выключателя питания, может быть.

Контрольная работа

Вот тест люкс :

using System;
using System.Threading;
using System.Diagnostics;
class LeakTest {
    public static void Main() {
        SpawnLeakage();
        Console.WriteLine("{0}-: Objects may be freed now", DateTime.Now);
        // any managed object created in SpawbLeakage 
        //  is no longer accessible
        // The GC should take care of them

        // Now let's see
        MonitorGC();
    }
    public static void SpawnLeakage() {
        Console.WriteLine("{0}-: Creating 'leakage' object", DateTime.Now);
        L l = new L();
    }
    public static void MonitorGC() {
        while(true) {
            int top = Console.CursorTop;
            int left = Console.CursorLeft;
            Console.WriteLine(
                "{0}-: Total managed memory: {1} bytes",
                DateTime.Now,
                GC.GetTotalMemory(false)
            );
            Console.SetCursorPosition(left, top);
        }
    }
}

Выход через 10 минут:

2/19/2017 2:12:18 PM-: Creating 'leakage' object
2/19/2017 2:12:18 PM-: Objects may be freed now
2/19/2017 2:22:36 PM-: Total managed memory: 2684476624 bytes

Это 2 684 476 624 байта. Общий WorkingSetобъем процесса составил около 4,8 ГБ

Этот ответ был вдохновлен замечательной статьей Эрика Липперта: « Когда все, что ты знаешь, неправильно» .


Это увлекательно. Сборщик мусора "забывает", что некоторые вещи существуют, и теряет их из-за этого? Я не знаю много о C #. Также сейчас мне интересно, в чем разница между бомбой и утечкой? Я полагаю, что подобное фиаско можно было бы создать, вызвав конструктор изнутри конструктора, или имея бесконечную рекурсивную функцию, которая никогда не останавливается, хотя технически система никогда не теряет эти ссылки, она просто исчерпывает пространство ...
Дон Яркий

1
Конструктор внутри конструктора вызовет переполнение стека. Но деструктор экземпляра вызывается в плоской иерархии. GC фактически никогда не теряет отслеживание объектов. Просто всякий раз, когда он пытается уничтожить их, он невольно создает новые объекты. Код пользователя, с другой стороны, не имеет доступа к указанным объектам. Также могут возникнуть упомянутые несоответствия, поскольку GC может решить уничтожить объект, не вызывая его деструктор.
MrPaulch

Разве проблема не была бы закончена, просто используя class L{~L(){new L();}}? AFAIK for(;;)только делает утечку памяти быстрее, верно?
BgrWorker

1
К сожалению нет. Поскольку для каждого уничтоженного объекта будет создан только один новый экземпляр, который затем снова будет недоступен и помечен для уничтожения. Повторение. Только один объект будет в ожидании уничтожения. Нет увеличения населения.
MrPaulch

2
На самом деле, нет. В конце концов один завершенный будет проигнорирован. Соответствующий объект будет съеден независимо.
MrPaulch

26

C (gcc) , 15 байтов

f(){malloc(1);}

верификация

$ cat leak.c
f(){malloc(1);}
main(){f();}
$ gcc -g -o leak leak.c
leak.c: In function ‘f’:
leak.c:1:5: warning: incompatible implicit declaration of built-in function ‘malloc’ [enabled by default]
 f(){malloc(1);}
     ^
$ valgrind --leak-check=full ./leak
==32091== Memcheck, a memory error detector
==32091== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==32091== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==32091== Command: ./leak
==32091==
==32091==
==32091== HEAP SUMMARY:
==32091==     in use at exit: 1 bytes in 1 blocks
==32091==   total heap usage: 1 allocs, 0 frees, 1 bytes allocated
==32091==
==32091== 1 bytes in 1 blocks are definitely lost in loss record 1 of 1
==32091==    at 0x4C29110: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==32091==    by 0x40056A: f (leak.c:1)
==32091==    by 0x40057A: main (leak.c:2)
==32091==
==32091== LEAK SUMMARY:
==32091==    definitely lost: 1 bytes in 1 blocks
==32091==    indirectly lost: 0 bytes in 0 blocks
==32091==      possibly lost: 0 bytes in 0 blocks
==32091==    still reachable: 0 bytes in 0 blocks
==32091==         suppressed: 0 bytes in 0 blocks
==32091==
==32091== For counts of detected and suppressed errors, rerun with: -v
==32091== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

26

Javascript, 14 байт

Golfed

setInterval(0)

Регистрирует пустой обработчик интервала с задержкой по умолчанию, отбрасывая итоговый идентификатор таймера (делая невозможным отмену).

введите описание изображения здесь

Я использовал интервал не по умолчанию, чтобы создать несколько миллионов таймеров, чтобы проиллюстрировать утечку, так как при использовании интервала по умолчанию процессор расходуется как сумашедший.


5
Ха-ха, мне нравится, что ты напечатал «Golfed», мне интересно, какая версия без гольфа
Martijn

9
это может выглядеть такif(window && window.setInterval && typeof window.setInterval === 'function') { window.setInterval(0); }
Чаллака

3
На самом деле, это не невозможно отменить: идентификаторы интервала (и тайм-аута) нумеруются последовательно, поэтому отменить вещь довольно просто, просто вызывая clearIntervalс возрастающим идентификатором, пока ваш интервал не истечет. Например:for(let i=0;i<1e5;i++){try{clearInterval(i);}catch(ex){}}
user2428118

5
@ user2428118 Как говорит zeppelin, это не более «законно», чем сказать, что утечки в C / C ++ не «реальны», потому что вы можете использовать грубые принудительные вызовыfree()
TripeHound

1
Ничего себе, не так много проблем, где JavaScript является реальным соперником ...
Джаред Смит

19

Java, 10 байт

Наконец, конкурентный ответ на Java!

Golfed

". "::trim

Это ссылка на метод (против строковой константы), которую можно использовать так:

Supplier<String> r = ". "::trim

Литеральная строка ". "будет автоматически добавлена ​​в глобальный пул интернированных строк, поддерживаемый java.lang.Stringклассом, и, как только мы немедленно обрежем ее, ссылка на нее не может быть повторно использована в коде (если вы снова не объявите точно такую ​​же строку).

...

Пул строк, изначально пустой, поддерживается частным образом классом String.

Все литеральные строки и строковые константные выражения интернированы. Строковые литералы определены в разделе 3.10.5 Спецификации языка Java ™.

...

https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#intern--

Вы можете превратить это в утечку памяти «производственного уровня», добавив строку к себе, а затем явно вызвав метод intern () в цикле.


2
Я рассматривал это для C # ... но я не думаю, что это считается, потому что, как вы говорите, вы можете получить доступ к этой памяти, включив другой строковый литерал. Мне также было бы интересно узнать, что ("." + " ").intern()будет делать (если бы они были введены пользователем или без, поэтому мы не учитываем оптимизацию компилятора).
VisualMelon

1
Действительно, единственный консенсус в лучшем случае невелик, я просто твердо на стороне «код должен компилироваться». Я все еще не уверен, что куплю это решение, учитывая формулировку вопроса (эти строки не могут быть освобождены, и их можно найти в обычном рабочем коде, даже если это маловероятно), но я приглашаю других высказать свое мнение
VisualMelon

3
Эта строка даже недоступна , не говоря уже об утечке. Мы можем получить его в любое время, используя одинаковую строку. Если бы это считалось, любая неиспользуемая глобальная переменная (частная статическая в Java) была бы утечкой. Это не то, как утечки памяти определены.
user2357112

3
@ user2357112 "... Эта строка даже недоступна ..." Это кажется очевидным только потому, что вы видите код. Теперь предположим, что вы получили ссылку на этот метод X () в качестве аргумента вашего кода, вы знаете, что он выделяет (и интернирует) строковый литерал внутри, но вы не знаете, какой именно, это может быть "." Или "123" или любая другая строка (обычно) неизвестной длины. Не могли бы вы продемонстрировать, как вы все еще можете получить к нему доступ или освободить запись в пуле "intern", который он занимает?
Цеппелин

2
@ user2357112 На машине с ограниченным объемом памяти вы можете получить доступ к значению, хранящемуся в любом фрагменте памяти simply by guessing it correctly, но это не означает, что такой вещи, как утечки памяти, не существует. there's probably some way to use reflection to determine the string's contents tooне могли бы вы продемонстрировать это? (подсказка, String.intern () реализован в собственном коде).
Цеппелин

17

Ржавчина, 52 байта

extern{fn malloc(_:u8);}fn main(){unsafe{malloc(9)}}

Выделяет несколько байтов системе malloc. Это предполагает, что неправильный ABI приемлем.


Ржавчина (теоретически), 38 байт

fn main(){Box::into_raw(Box::new(1));}

Мы выделяем память в куче, извлекаем необработанный указатель, а затем просто игнорируем его, эффективно вытекая из него. ( Box::into_rawтогда короче std::mem::forget).

Тем не менее, Rust по умолчанию использует jemalloc, который valgrind не может обнаружить утечки . Мы могли бы переключиться на системный распределитель, но это добавляет 50 байтов и требует каждую ночь. Большое спасибо за безопасность памяти.


Выход первой программы:

==10228== Memcheck, a memory error detector
==10228== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==10228== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==10228== Command: ./1
==10228== 
==10228== 
==10228== HEAP SUMMARY:
==10228==     in use at exit: 9 bytes in 1 blocks
==10228==   total heap usage: 7 allocs, 6 frees, 2,009 bytes allocated
==10228== 
==10228== LEAK SUMMARY:
==10228==    definitely lost: 9 bytes in 1 blocks
==10228==    indirectly lost: 0 bytes in 0 blocks
==10228==      possibly lost: 0 bytes in 0 blocks
==10228==    still reachable: 0 bytes in 0 blocks
==10228==         suppressed: 0 bytes in 0 blocks
==10228== Rerun with --leak-check=full to see details of leaked memory
==10228== 
==10228== For counts of detected and suppressed errors, rerun with: -v
==10228== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

классно. Подобные посты привели меня к изучению Rust за последний год, определенно одного из самых забавных языков, которые я пытался выучить.
Дон Яркий

16

8086 ASM, 3 байта

В этом примере предполагается, что среда выполнения C связана с.

jmp _malloc

это собирает туда, e9 XX XXгде XX XXэто относительный адрес_malloc

Это вызывает mallocвыделение непредсказуемого объема памяти, а затем немедленно возвращается, завершая процессы. В некоторых операционных системах, таких как DOS, память может вообще не восстанавливаться, пока система не будет перезагружена!


Нормальная реализация malloc приведет к освобождению памяти при выходе из процесса.
Джошуа

@ Джошуа Да, но это поведение, определяемое реализацией.
FUZxxl

12

Далее 6 байт

Golfed

s" " *

Выделяет пустую строку с s" ", оставляя ее адрес и длину (0) в стеке, затем умножает их (что приводит к потере адреса памяти).

Valgrind

%valgrind --leak-check=full gforth -e 's" " * bye'
...
==12788== HEAP SUMMARY:
==12788==     in use at exit: 223,855 bytes in 3,129 blocks
==12788==   total heap usage: 7,289 allocs, 4,160 frees, 552,500 bytes allocated
==12788== 
==12788== 1 bytes in 1 blocks are definitely lost in loss record 1 of 22
==12788==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==12788==    by 0x406E39: gforth_engine (in /usr/bin/gforth-0.7.0)
==12788==    by 0x41156A: gforth_go (in /usr/bin/gforth-0.7.0)
==12788==    by 0x403F9A: main (in /usr/bin/gforth-0.7.0)
==12788== 
...
==12818== LEAK SUMMARY:
==12818==    definitely lost: 1 bytes in 1 blocks
==12818==    indirectly lost: 0 bytes in 0 blocks

10

идти 45 байтов

package main
func main(){go func(){for{}}()}

это создает анонимную программу с бесконечным циклом внутри нее. программа может продолжать работать в обычном режиме, так как запуск программы походит на порождение одновременно запущенного небольшого потока, но программа не имеет возможности вернуть память, выделенную для программы. сборщик мусора никогда не соберет его, так как он все еще работает. некоторые люди называют это «утечка горутин»


проверка гольфа: это на 2 байта короче, чем вызов C.malloc(8), так как вам нужноimport"C"
Riking

9

Java 1.3, 23 байта

void l(){new Thread();}

Создание потока, но не запуск его. Поток зарегистрирован во внутреннем пуле потоков, но никогда не будет запущен, поэтому никогда не заканчивается и поэтому никогда не будет кандидатом в GC. Это невосстановимый объект, застрявший в лимбе Java.

Это ошибка в Java до версии 1.3, так как она была исправлена ​​позже.

тестирование

Следующая программа гарантирует загрязнение памяти новыми объектами потока и показывает уменьшение свободного места в памяти. Ради тестирования утечек я интенсивно заставляю GC работать.

public class Pcg110485 {

    static
    void l(){new Thread();}

    public static void main(String[] args) {

        while(true){
            l();
            System.gc();
            System.out.println(Runtime.getRuntime().freeMemory());
        }
    }
}

Так как это работает только в определенных версиях Java, вы должны вместо этого сказать «Java 3» в заголовке.

5
Нет такого понятия, как Java 3. Это Java 1.3. Была Java 1.0, 1.1, 2, 1.3, 1.4, 5, 6, 7, 8, 9. Странная нумерация, но это так.
Оливье Грегуар

Это была моя идея тоже. Черт.
Волшебная Урна Осьминога

8

Befunge ( грибки ), 1 байт

$

Это может зависеть от платформы и версии (я тестировал только с версией 1.0.4 для Windows), но грибы исторически были очень утечкой. Команда $(drop) не должна ничего делать в пустом стеке, но зацикливание на этом коде каким-то образом приводит к очень быстрой утечке большой памяти. В течение нескольких секунд он израсходует пару концертов и вылетит с ошибкой «недостаточно памяти».

Обратите внимание, что это не обязательно должна быть $команда - почти все, что подойдет. Это не будет работать с пустым исходным файлом, хотя. Там должна быть хотя бы одна операция.


8

Swift 3, 38 байт

Новая версия:

class X{var x: X!};do{let x=X();x.x=x}

x имеет сильную ссылку на себя, поэтому он не будет освобожден, что приведет к утечке памяти.

Старая версия:

class X{var y:Y!}
class Y{var x:X!}
do{let x=X();let y=Y();x.y=y;y.x=x}

xсодержит сильную ссылку на y, и наоборот. Таким образом, ни один из них не будет освобожден, что приведет к утечке памяти.


Хм, вы все еще можете ссылаться на эту память через, xи y, таким образом, это не выглядит для меня утечкой (если вы не уничтожите их как-нибудь).
Цеппелин

@zeppelin Последняя строка может быть обернута в функцию, чтобы это исправить
NobodyNada

@NobodyNada, если бы я поместил последнюю строку в doблоке, который бы исправил проблему, вызванную цеппелином, верно?
Даниил

@Dopapp Да; А doбудет работать так же. Хорошая идея!
NobodyNada

Он может быть сокращен, вам не нужно два класса - X может содержать ссылку на себя:class X{var x: X!};do{let x=X();x.x=x}
Себастьян

7

Delphi (Object Pascal) - 33 байта

Создание объекта без переменной, полная консольная программа:

program;begin TObject.Create;end.

Включение FastMM4 в проекте покажет утечку памяти:

введите описание изображения здесь


6

C # - 84 байта

class P{static void Main(){System.Runtime.InteropServices.Marshal.AllocHGlobal(1);}}

Это выделяет ровно 1 байт неуправляемой памяти, а затем теряет то IntPtr, что, я считаю, является единственным способом получить или освободить его. Вы можете проверить это, поместив его в цикл и ожидая сбоя приложения (может потребоваться добавить несколько нулей, чтобы ускорить процесс).

Я считал System.IO.File.Create("a");и такое, но я не уверен, что это обязательно утечки памяти, так как само приложение будет собирать память, под ней может просочиться ОС (потому что Closeили Disposeне были вызваны). Для доступа к файлу также требуются разрешения файловой системы, и никто не хочет на них полагаться. И оказывается, что в любом случае это не произойдет, потому что ничто не мешает вызову финализатора (который делает возможным освобождение базовых ресурсов), что включает в себя структура, чтобы смягчить подобные ошибки (в некоторой степени), и путать программистов с, казалось бы, недетерминированной блокировкой файлов (если вы циник). Спасибо Джону Ханне за то, что объяснил мне это.

Я немного разочарован тем, что не могу найти более короткий путь. .NET GC работает, я не могу вспомнить ни одного IDisposablesв mscorlib, который точно утечет (и, действительно, все они, похоже, имеют финализаторы, как это раздражает) , я не знаю ни одного другого способа выделения неуправляемой памяти (если не считать PInvoke ), а отражение гарантирует, что может быть найдено что-либо со ссылкой на него (независимо от семантики языка (например, частные члены или классы без методов доступа)) .


1
System.IO.File.Create("a")не будет ничего пропускать, но GC.SuppressFinalize(System.IO.File.Create("a"))будет, как явно просят, не запускать финализатор FileStreamпроизведенного.
Джон Ханна

@JonHanna совершенно верно. Моя однозначная паранойя, кажется, одолела меня.
VisualMelon

Возможно, у вас есть шанс вызвать утечку GDI + с помощью System.Drawing.Bitmap. Не знаю, считается ли это, потому что это библиотека Windows, вызывающая утечку, а не сама программа.
BgrWorker

@BgrWorker, у них, без сомнения, также есть финализатор, и я склонен избегать внешних библиотек в code-golf, потому что я не согласен с консенсусом по поводу их стоимости: если вы можете найти способ, в котором вы уверены, не стесняйтесь писать это в вашем собственном ответе!
VisualMelon

<!-- language: lang-c# -->Спасибо за это и хороший ответ! (Это C #, так что я люблю его)
Metoniem

5

Фактор , 13 байт

Factor имеет автоматическое управление памятью, но также предоставляет доступ к некоторым функциям libc:

1 malloc drop

Вручную выделяет 1 байт памяти, возвращает его адрес и удаляет его.

malloc на самом деле регистрирует копию для отслеживания утечек памяти и двойного освобождения, но выявление того, что вы обнаружили, не простая задача.

Если вы предпочитаете убедиться, что действительно потеряли эту ссылку:

1 (malloc) drop

Тестирование утечек [ 1 malloc drop ] leaks.говорит:

| Disposable class | Instances |                    |
| malloc-ptr       | 1         | [ List instances ] |

Тестирование утечек [ 1 (malloc) drop ] leaks.говорит:

| Disposable class | Instances | |

о нет! Плохой фактор, теперь у него болезнь Альцгеймера! D:


4

AutoIt , 39 байт

#include<Memory.au3>
_MemGlobalAlloc(1)

Выделяет один байт из кучи. Так как дескриптор, возвращаемый _MemGlobalAllocфункцией, отбрасывается, нет никакого способа явно освободить это распределение.


4

Common Lisp (только SBCL), 28 26 байт

sb-alien::(make-alien int)

Вы запустите его так: sbcl --eval 'sb-alien::(make-alien int)'; ничего не печатается и не возвращается, но происходит выделение памяти. Если я оберну форму внутри (print ...), указатель отобразится в REPL.

  1. package::(form)это специальная запись в SBCL для временного связывания текущего пакета при чтении формы. Это используется здесь, чтобы избежать префиксов как make-alienи intс sb-alien. Я думаю, что было бы обманом предполагать, что текущий пакет установлен на этот, потому что это не так при запуске.

  2. make-alien выделяет память для заданного типа и необязательного размера (используя malloc).

  3. При выполнении этого в REPL добавьте 0после распределения, чтобы REPL не возвращал указатель, а вместо этого значение. В противном случае не, что бы не быть реальной утечкой , потому что РЕПЛИ запоминает последние три возвращаемых значений (см *, **,*** ) , и мы могли бы все еще есть шанс , чтобы освободить выделенную память.

2 байта удалены благодаря PrzemysławP, спасибо!


1
Разве вы не можете использовать 1(или 2, 3и т. Д.) Вместо того, ()чтобы вернуть значение 1? Это спасло бы 1 байт. И этот ответ только REPL? Может быть, если вы загрузите код, который loadвы не можете включить ()или что-то в конце, потому что он не будет доступен в любом случае?

1
@ PrzemysławP Вы правы в обоих моментах, я попробовал с, evalи это работает, как вы сказали. Большое спасибо!
coredump

3

C ++, 16 байт

main(){new int;}

У меня нет valgrind, чтобы проверить, нет ли утечек, но я уверен, что так и должно быть. В противном случае я бы попробовал:

main(){[]{new int;}();}

Результат Valgrind

(Это действительно утечка)

==708== LEAK SUMMARY:
==708==    definitely lost: 4 bytes in 1 blocks

@WheatWizard, который я использую g++ 4.3.2(не самый последний), и он прекрасно компилируется. intДумаю, по умолчанию нет возвращаемого типа . При этом у -Wallменя есть предупреждение, хотя:plop.cpp:1: warning: ISO C++ forbids declaration of 'main' with no type
Матович

2
@WheatWizard Извините, я только что видел, как вы привели пример c ++ для начала конкурса. Исходя из Reddit я только посмотрел на ответы и (как ни странно) не видел C ++. Я чувствую себя немного глупым : /
Матович

Консенсус заключается в том, что вы можете считать только []{new int;}функцией C ++ (в задаче не указана целая программа).
Тоби Спейт

3

Java (OpenJDK 9) , 322 220 байт

import sun.misc.*;class Main{static void main(String[]a)throws Exception{java.lang.reflect.Field f=Unsafe.class.getDeclaredField("theUnsafe");f.setAccessible‌​(1<2);((Unsafe)f.get‌​(1)).allocateMemory(‌​1);}}

Попробуйте онлайн!

Это другая утечка памяти, которая не использует String Cache. Он выделяет половину вашей оперативной памяти, и вы не можете ничего с этим поделать.

Спасибо zeppelin за сохранение всех байтов


Вы можете сэкономить кучу байтов, получив Unsafeэкземпляр из статической переменной внутри него, как то:import sun.misc.*;class M{static void main(String[]a)throws Exception{java.lang.reflect.Field f=Unsafe.class.getDeclaredField("theUnsafe");f.setAccessible(1<2);((Unsafe)f.get(1)).allocateMemory(1);}}
дирижабль

И вы можете сохранить еще немного, заменив public static void mainстатический инициализатор static{try{}catch(Exception e){}}(который может быть немного сложнее в запуске, но, тем не менее, допустим и компилируем).
Цеппелин

да, использование конструктора использовалось в версии кода Android, которую я использовал. Я поменяю некоторые вещи, когда я @home, но я пойду по пути, по которому вы пошли, с одним утверждением;)
Serverfrog

Удалите пробелы, используйте aвместо них argsи удалите публичные. tio.run/nexus/…
Павел

true можно заменить на 1> 0
masterX244,

3

с, 9 байтов

main(){}

Доказательство:

localhost/home/elronnd-10061: cat t.c
main(){}
localhost/home/elronnd-10062: valgrind gcc t.c
==10092== Memcheck, a memory error detector
==10092== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==10092== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==10092== Command: gcc t.c
==10092==
t.c:1:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
 main(){}
 ^~~~
==10092==
==10092== HEAP SUMMARY:
==10092==     in use at exit: 178,518 bytes in 73 blocks
==10092==   total heap usage: 362 allocs, 289 frees, 230,415 bytes allocated
==10092==
==10092== LEAK SUMMARY:
==10092==    definitely lost: 4,659 bytes in 8 blocks
==10092==    indirectly lost: 82 bytes in 5 blocks
==10092==      possibly lost: 0 bytes in 0 blocks
==10092==    still reachable: 173,777 bytes in 60 blocks
==10092==         suppressed: 0 bytes in 0 blocks
==10092== Rerun with --leak-check=full to see details of leaked memory
==10092==
==10092== For counts of detected and suppressed errors, rerun with: -v
==10092== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

1
Вы на самом деле не утечка памяти; gccявляется. Это также должно работать с пустой программой. Попробуйте gcc src.c && valgrind ./a.out, что должно привести к чистому результату.

3

C #, 109 байт

public class P{static void Main({for(;;)System.Xml.Serialization.XmlSerializer.FromTypes(new[]{typeof(P)});}}

Мы нашли идею, лежащую в основе этой утечки, в рабочем коде, и ее исследование ведет к этой статье Основная проблема в этой длинной цитате из статьи (читайте ее для получения дополнительной информации):

Ища мой код для PurchaseOrder, я нахожу эту строку кода на page_loadодной из моих страницXmlSerializer serializer = new XmlSerializer(typeof(PurchaseOrder), new XmlRootAttribute(“”));

Это может показаться довольно невинным фрагментом кода. Мы создаем XMLSerializerдля PurchaseOrder. Но что происходит под одеялом?

Если мы посмотрим на XmlSerializerконструктор с помощью Reflector, то обнаружим, что он вызывает, this.tempAssembly = XmlSerializer.GenerateTempAssembly(this.mapping, type, defaultNamespace, location, evidence);который генерирует временную (динамическую) сборку. Таким образом, каждый раз, когда выполняется этот код (т. Е. Каждый раз, когда открывается страница), он генерирует новую сборку.

Причина, по которой он генерирует сборку, заключается в том, что ему необходимо создавать функции для сериализации и десериализации, и они должны находиться где-то.

Хорошо, хорошо ... это создает сборку, и что? Когда мы закончим с этим, оно должно просто исчезнуть, верно?

Ну ... сборка не является объектом в куче GC, GC действительно не знает о сборках, поэтому она не будет собирать мусор. Единственный способ избавиться от сборок в 1.0 и 1.1 - выгрузить домен приложения, в котором он находится.

И в этом заключается проблема доктора Ватсона.

Запуск из компилятора в Visual Studio 2015 и использование окна инструментов диагностики показывает следующие результаты примерно через 38 секунд. Обратите внимание, что объем памяти процесса постоянно растет, а сборщик мусора (GC) продолжает работать, но ничего не может собрать.

Окно диагностических инструментов


2

C 30 байтов

f(){int *i=malloc(sizeof(4));}

Valgrind Результаты:

         ==26311== HEAP SUMMARY:
         ==26311==     in use at exit: 4 bytes in 1 blocks
         ==26311==   total heap usage: 1 allocs, 0 frees, 4 bytes allocated
         ==26311== 
         ==26311== LEAK SUMMARY:
         ==26311==    definitely lost: 4 bytes in 1 blocks
         ==26311==    indirectly lost: 0 bytes in 0 blocks
         ==26311==      possibly lost: 0 bytes in 0 blocks
         ==26311==    still reachable: 0 bytes in 0 blocks
         ==26311==         suppressed: 0 bytes in 0 blocks
         ==26311== Rerun with --leak-check=full to see details of leaked memory

2
Можно ли вместо этого просто сделать main(){malloc(1);}?
kirbyfan64sos

@ Да, это так! Но это уже было опубликовано!
Абель Том

2

Дротик, 76 байт

import'dart:async';main()=>new Stream.periodic(Duration.ZERO).listen((_){});

Немного похоже на ответ JavaScript. Когда вы вызываете .listenобъект потока Dart, вам возвращается подписка StreamSubscription, которая позволяет вам отключиться от потока. Однако, если вы выбросите это, вы никогда не сможете отписаться от потока, что приведет к утечке. Единственный способ устранить утечку - это если сам поток получен, но на него все еще ссылается внутренняя комбинация StreamController + Timer.

К сожалению, Дарт слишком умен для других вещей, которые я пробовал. ()async=>await new Completer().futureне работает, потому что использование await - это то же самое new Completer().future.then(<continuation>), что и использование, которое позволяет уничтожить само замыкание, если второй Completer не указан (Completer содержит ссылку на Future из .future, а Future содержит ссылку на продолжение как замыкание).

Кроме того, изоляты (то есть потоки) очищаются с помощью GC, поэтому создание нового потока и немедленная его приостановка ( import'dart:isolate';main(_)=>Isolate.spawn(main,0,paused:true);) не работает. Даже создание Isolate с бесконечным циклом ( import'dart:isolate';f(_){while(true){print('x');}}main()=>Isolate.spawn(f,0);) убивает Isolate и выходит из программы.

Ну что ж.


если бы ваша основная программа продолжала работать и делать что-то еще, сможет ли сборщик мусора остановить изолят? Я спрашиваю, потому что мой пример работы с рутиной звучит похоже ... Я предположил, что тот факт, что программа завершает работу и возвращает всю память обратно в ОС, не обязательно означает, что она не просочилась.
Дон Яркий

2

Swift, 12 байт

[3,5][0...0]

Объяснение:

Это фактическая утечка памяти, которая может произойти на любом языке, независимо от того, использует ли язык ручное управление памятью, автоматический подсчет ссылок (например, Swift) или даже уборку мусора.

[3,5]это просто массив букв. Этот массив выделяет достаточно памяти как минимум для этих двух элементов. 3И 5просто произвольно.

Подписание (индексация) Array<T>производит ArraySlice<T>. An ArraySlice<T>- просмотр памяти массива, из которого он был создан.

[3,5][0...0]производит ArraySlice<Int>, чье значение [3]. Обратите внимание, что 3в этом фрагменте тот же 3элемент, что и 3в оригинале, Arrayпоказанном выше, а не копия.

Полученный фрагмент можно затем сохранить в переменной и использовать. На исходный массив больше нет ссылок, поэтому вы могли бы подумать, что он может быть освобожден. Однако не может.

Поскольку срез предоставляет вид на память массива, из которого он получен, исходный массив должен сохраняться в течение всего срока жизни среза. Таким образом, из первоначального 2объема памяти, который был выделен для размеров элементов, используется только первый размер памяти для элементов, а другой должен существовать, чтобы не выделять первый. Второй размер элемента памяти де-факто просочился.

Решение этой проблемы состоит в том, чтобы долго не поддерживать маленькие кусочки больших массивов. Если вам нужно сохранить содержимое среза, поместите его в массив, который запустит копирование памяти, удалив зависимость от памяти исходного массива:

Array([3,5][0...0])

2

Решение 1: C (Mac OS X x86_64), 109 байт

Источник для golf_sol1.c

main[]={142510920,2336753547,3505849471,284148040,2370322315,2314740852,1351437506,1208291319,914962059,195};

Вышеупомянутая программа должна быть скомпилирована с доступом к исполнению в сегменте __DATA.

clang golf_sol1.c -o golf_sol1 -Xlinker -segprot -Xlinker __DATA -Xlinker rwx -Xlinker rwx

Затем для запуска программы выполните следующее:

./golf_sol1 $(ruby -e 'puts "\xf5\xff\xff\xfe\xff\xff\x44\x82\x57\x7d\xff\x7f"')

Результаты:

К сожалению, Valgrind не отслеживает память, выделяемую из системных вызовов, поэтому я не могу показать хорошую обнаруженную утечку.

Однако мы можем посмотреть на vmmap, чтобы увидеть большой кусок выделенной памяти (метаданные MALLOC).

                                VIRTUAL   REGION 
REGION TYPE                        SIZE    COUNT (non-coalesced) 
===========                     =======  ======= 
Kernel Alloc Once                    4K        2 
MALLOC guard page                   16K        4 
MALLOC metadata                   16.2M        7 
MALLOC_SMALL                      8192K        2         see MALLOC ZONE table below
MALLOC_TINY                       1024K        2         see MALLOC ZONE table below
STACK GUARD                       56.0M        2 
Stack                             8192K        3 
VM_ALLOCATE (reserved)             520K        3         reserved VM address space (unallocated)
__DATA                             684K       42 
__LINKEDIT                        70.8M        4 
__TEXT                            5960K       44 
shared memory                        8K        3 
===========                     =======  ======= 
TOTAL                            167.0M      106 
TOTAL, minus reserved VM space   166.5M      106 

объяснение

Поэтому я думаю, что мне нужно описать, что на самом деле здесь происходит, прежде чем переходить к улучшенному решению.

Эта основная функция злоупотребляет отсутствующим объявлением типа C (поэтому по умолчанию используется int, и нам не нужно тратить на это символы), а также то, как работают символы. Компоновщик заботится только о том, может ли он найти символ, вызываемый mainдля вызова. Итак, здесь мы делаем main массив int, который мы инициализируем нашим шелл-кодом, который будет выполнен. Из-за этого main будет добавляться не к сегменту __TEXT, а к сегменту __DATA, поэтому нам нужно скомпилировать программу с исполняемым сегментом __DATA.

Обнаружен шелл-код в main:

movq 8(%rsi), %rdi
movl (%rdi), %eax
movq 4(%rdi), %rdi
notl %eax
shrq $16, %rdi
movl (%rdi), %edi
leaq -0x8(%rsp), %rsi
movl %eax, %edx
leaq -9(%rax), %r10
syscall
movq (%rsi), %rsi
movl %esi, (%rsi)
ret

То, что это делает, вызывает функцию syscall для выделения страницы памяти (syscall mach_vm_allocate использует внутренне). RAX должен быть равен 0x100000a (сообщает системному вызову, какую функцию мы хотим), в то время как RDI содержит цель для выделения (в нашем случае мы хотим, чтобы это было mach_task_self ()), RSI должен содержать адрес для записи указателя во вновь созданную память (поэтому мы просто указываем на раздел в стеке), RDX содержит размер выделения (мы просто передаем RAX или 0x100000a, чтобы сэкономить на байтах), R10 содержит флаги (мы указываем, что он может выделяться где угодно).

Теперь не совсем очевидно, откуда RAX и RDI получают свои значения. Мы знаем, что RAX должен быть 0x100000a, а RDI должен быть значением, возвращаемым mach_task_self (). К счастью, mach_task_self () на самом деле является макросом для переменной (mach_task_self_), которая каждый раз находится по одному и тому же адресу памяти (однако при перезагрузке должна меняться). В моем конкретном случае mach_task_self_ находится по адресу 0x00007fff7d578244. Таким образом, чтобы сократить инструкции, мы вместо этого будем передавать эти данные из argv. Вот почему мы запускаем программу с этим выражением$(ruby -e 'puts "\xf5\xff\xff\xfe\xff\xff\x44\x82\x57\x7d\xff\x7f"')за первый аргумент. Строка представляет собой объединенные два значения, где значение RAX (0x100000a) составляет всего 32 бита и к нему применено одно дополнение (поэтому нулевых байтов нет; мы просто НЕ получаем значение, чтобы получить оригинал), следующее значение RDI (0x00007fff7d578244), который был смещен влево с 2 дополнительными ненужными байтами, добавленными в конец (снова, чтобы исключить нулевые байты, мы просто сдвигаем его обратно вправо, чтобы вернуть его к оригиналу).

После системного вызова мы пишем в нашу недавно выделенную память. Причина этого в том, что память, выделенная с помощью mach_vm_allocate (или этого системного вызова), на самом деле является страницами виртуальной машины и не выгружается в память автоматически. Скорее они зарезервированы до тех пор, пока им не будут записаны данные, а затем эти страницы будут отображены в памяти. Не был уверен, что он будет соответствовать требованиям, если он будет только зарезервирован.

Для следующего решения мы воспользуемся преимуществом того факта, что наш шелл-код не имеет нулевых байтов и поэтому может переместить его за пределы кода нашей программы, чтобы уменьшить размер.

Решение 2: C (Mac OS X x86_64), 44 байта

Источник для golf_sol2.c

main[]={141986632,10937,1032669184,2,42227};

Вышеупомянутая программа должна быть скомпилирована с доступом к исполнению в сегменте __DATA.

clang golf_sol2.c -o golf_sol2 -Xlinker -segprot -Xlinker __DATA -Xlinker rwx -Xlinker rwx

Затем для запуска программы выполните следующее:

./golf_sol2 $(ruby -e 'puts "\xb8\xf5\xff\xff\xfe\xf7\xd0\x48\xbf\xff\xff\x44\x82\x57\x7d\xff\x7f\x48\xc1\xef\x10\x8b\x3f\x48\x8d\x74\x24\xf8\x89\xc2\x4c\x8d\x50\xf7\x0f\x05\x48\x8b\x36\x89\x36\xc3"')

Результат должен быть таким же, как и раньше, поскольку мы делаем выделение того же размера.

объяснение

Следует той же концепции, что и решение 1, за исключением того, что мы переместили часть нашего утекшего кода за пределы программы.

Найденный в main шелл-код теперь выглядит следующим образом:

movq 8(%rsi), %rsi
movl $42, %ecx
leaq 2(%rip), %rdi
rep movsb (%rsi), (%rdi)

Это в основном копирует шелл-код, который мы передаем в argv, чтобы следовать за этим кодом (поэтому после того, как он скопировал его, он запустит вставленный шелл-код). Что работает в нашу пользу, так это то, что сегмент __DATA будет иметь размер как минимум страницы, поэтому даже если наш код не такой большой, мы все равно можем «безопасно» писать больше. Недостатком является идеальное решение здесь, даже не нужно копировать, вместо этого он просто вызовет и выполнит шелл-код напрямую в argv. Но, к сожалению, эта память не имеет прав на исполнение. Мы могли бы изменить права на эту память, однако для этого потребовалось бы больше кода, чем просто его копирование. Альтернативной стратегией будет изменение прав из внешней программы (но об этом позже).

Код шелла, который мы передаем в argv, выглядит следующим образом:

movl $0xfefffff5, %eax
notl %eax
movq $0x7fff7d578244ffff, %rdi
shrq $16, %rdi
movl (%rdi), %edi
leaq -0x8(%rsp), %rsi
movl %eax, %edx
leaq -9(%rax), %r10
syscall
movq (%rsi), %rsi
movl %esi, (%rsi)
ret

Это почти то же самое, что и наш предыдущий код, с той лишь разницей, что мы включаем значения для EAX и RDI напрямую.

Возможное решение 1: C (Mac OS X x86_64), 11 байт

Идея внешней модификации программы дает нам возможное решение о переносе лейкера во внешнюю программу. Где наша фактическая программа (представление) является просто фиктивной программой, и программа-лидер будет выделять часть памяти в нашей целевой программе. Теперь я не был уверен, подпадает ли это под правила для этого вызова, но все же поделился им.

Таким образом, если бы мы использовали mach_vm_allocate во внешней программе с целью, установленной для нашей программы испытаний, это могло бы означать, что наша программа испытаний должна была бы выглядеть примерно так:

main=65259;

Где этот шеллкод - просто короткий переход к самому себе (бесконечный переход / цикл), так что программа остается открытой, и мы можем ссылаться на нее из внешней программы.

Возможное решение 2: C (Mac OS X x86_64), 8 байт

Как ни странно, когда я смотрел на вывод valgrind, я видел, что, по крайней мере, в соответствии с valgrind, утечка памяти теряет память. Таким образом, каждая программа теряет память. В этом случае мы могли бы просто сделать программу, которая ничего не делает (просто завершает работу), и это фактически приводит к утечке памяти.

Источник:

main(){}


==55263== LEAK SUMMARY:
==55263==    definitely lost: 696 bytes in 17 blocks
==55263==    indirectly lost: 17,722 bytes in 128 blocks
==55263==      possibly lost: 0 bytes in 0 blocks
==55263==    still reachable: 0 bytes in 0 blocks
==55263==         suppressed: 16,316 bytes in 272 blocks

2

Простой английский , 71 70 58 35 байт

Удалил 1 байт, удалив пустую строку. Удалил 12 байтов, исключив определение типа «богона» и использовав родительский тип «вещь» вместо подтипа «богона». Удалил 23 байта, переключившись с полной программы на обычную процедуру, которая приводит к утечке памяти.

Гольф версия:

To x:
Allocate memory for a thing.

Версия без поддержки, которая является законченной программой, использует определение подтипа и не пропускает память:

A bogon is a thing.

To do something:
  Allocate memory for a bogon.
  Destroy the bogon.

To run:
  Start up.
  Do something.
  Shut down.

Если вызывается версия «x» для игры в гольф, она будет пропускать память пропорционально количеству вызовов «x». В версии для гольфа "Распределить вещь". бы исправить утечку памяти.

Простой английский проверяет утечки памяти по умолчанию. Когда запускается версия с утечкой памяти, перед закрытием программы появляется диалоговое окно. Диалоговое окно имеет заголовок «отладка», сообщение «1 капель» и кнопку «ОК». Чем больше раз вызывается функция утечки, тем больше количество «капель» в сообщении. При запуске версии, не пропускающей память, диалоговое окно не отображается.

В простом английском языке «вещь» - это указатель на элемент в двусвязном списке. «Вещи», «запускать» и «выключать» определяются в модуле, называемом «лапшой», который необходимо скопировать (обычно в виде отдельного файла) в каждый проект. «A», «the», «to», «выделить память» и «уничтожить» определены в компиляторе.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.