가능한 적은 바이트로 메모리 누수


79

귀하의 작업은 가능한 한 적은 바이트로 최소 1 바이트의 메모리를 누출시키는 코드를 작성하는 것입니다. 메모리는 할당되지 않은 상태에서 누출되어야합니다 .

누수 된 메모리는 프로그램이 할당하지만 메모리를 올바르게 할당 해제하기 전에 액세스 할 수없는 메모리입니다. 대부분의 고급 언어의 경우이 메모리는 힙에 할당되어야합니다.

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
아마도 당신은 다른 범위의 누수를 겪을 수 있고 당신이 누수하는 양에 따라 바이트 수의 x %를 잃을 수도 있습니다.
Christopher

11
@ChristopherPeart 하나는 도전에 대한 보너스의 팬이 아니며 이미 보여 드린 것처럼 두 가지에 대해 무한한 메모리를 유출하는 것은 매우 쉽습니다.
밀 마법사

1
관련 . 그러나 그 질문에 대한 대부분의 대답은 실제로 메모리 누수가 아니라 메모리에서 무한한 도달 가능한 구조를 형성하기 때문에 중복은 아닙니다.

2
아이디어는 무엇입니까? 멤을 풀 수 없다고? 가비지 수집 언어 또는 버그 악용에 대한 기본 실행이 필요하다고 생각합니다.
akostadinov 2019

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 답변을 좋아하지만, 분명히 메모리 누수 인터프리터 자체가, 즉 내가`확실히 길을 잃지 같이이 하나, (IMHO) 스트레칭의 너무 많이 : 내가 실행할 때 7742 바이트 (14) blocks`에서 perl --version내 컴퓨터에서 , 전혀 프로그램을 실행하지 못하더라도.
zeppelin 's

11
@zeppelin : 동의하지만 규칙에 따라 언어를 정의하는 구현이므로 구현시 메모리가 누출되면 언어의 모든 프로그램에서 메모리가 누출됩니다. 나는 반드시 그 규칙에 동의한다고 확신 할 수는 없지만,이 시점에서 실제로 바꿀 수는 없다.

8
이것은 노드 JS에서도 작동합니다.
Dennis

6
이것은 제작에있어 새로운 표준 허점처럼 느껴집니다.
Michael Hampton

46
마침내 내가 이해할 수있는 Perl 스크립트.
user11153

66

C, 48 31 22 바이트

경고 : 너무 많이 실행하지 마십시오.

많은 도움과 아이디어 를 주신 Dennis 에게 감사합니다 !

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 (Address Space Layout Randomization)이 필요합니다. 그렇지 않으면 &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는 파일에 저장 될 수 있으며 프로그램은 나중에 파일에 첨부 할 수 있습니다. 이것은 유닉스 공유 메모리의 작동 방식입니다 ...
tbodt

1
@AndrewSavinykh 공유 메모리는 기본적으로 OS가 다른 프로세스에 제공 할 수있는 리소스가됩니다. RAM에있는 파일과 유사하며 이름 (키)이 삭제 될 때까지 액세스 할 수있는 프로세스를 알고 있습니다. 숫자를 계산하여 메모리에 저장하고 데이터를 읽는 프로세스가 공유 메모리에 연결되기 전에 종료하는 프로세스를 상상해보십시오. 이 경우 OS에서 메모리를 확보하면 두 번째 프로세스에서 메모리를 확보 할 수 없습니다.
Riley

35
이것을 게시 해 주셔서 감사합니다. 방금 공유 메모리 누출로부터 TIO를 보호했습니다.
Dennis

4
@Dennis 그렇기 때문에 TIO 링크를 게시하지 않았습니다. 그것이 보호되는지 아닌지는 몰랐습니다.
라일리

12
프로그램이 의도 한 것보다 적은 메모리를 누출하는 시나리오를 설명하기 위해 문제 라는 단어를 사용하는 방법이 마음에 듭니다.
kasperd

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 KB / s)- '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 == 확실히 잃어버린 : 1 블록에 40 바이트
== 3417 == 간접적으로 손실 : 0 블록에서 0 바이트
== 3417 == 유실 가능성 : 0 블록에 0 바이트
== 3417 == 여전히 도달 가능 : 0 블록에서 0 바이트
== 3417 == 억제 : 0 블록에서 0 바이트
== 3417 == 
== 3417 == 감지 및 억제 된 오류 수에 대해 다음을 사용하여 다시 실행하십시오. -v
== 3417 == 오류 요약 : 1 컨텍스트에서 1 오류 (억제 : 0에서 0)

39

TI 기본, 12 바이트

While 1
Goto A
End
Lbl A
Pause 

"당신이 최종 명령에 도달하기 전에 제어 구조에서 점프 (최종 명령을 아무거나) 루프 내에서 또는 조건부 경우 고토 /하는 Lbl를 사용하는 곳 ... 메모리 누수는 ..." (더)


7
와우, 나는 이것을 기억한다고 생각한다. 나는 기존의 기본 프로그램에서 루프에서 뛰어 내렸고 TI-84 +가 느리고 느리게 진행되는 것을 보았습니다.
Ray

2
그렇습니다. 우리 대부분은 느낌을 알고 있습니다.) @RayKoopa
Timtech

13
Ti 기본 +1 나는 9 학년 대부분을 그런 것들을 프로그래밍하는 데 보냈다.
markasoftware

Pause 마지막에 필요하십니까 ? 2 바이트를 절약 할 수 있습니다.
kamoroso94

@ kamoroso94 "프로그램이 종료되면 누출이 제거되고 더 이상 문제가 발생하지 않기 때문에"프로그램이 종료되는 것을 막기 때문에 그렇게 생각합니다.
Timtech 2014

32

파이썬 <3.6.5, 23 바이트

property([]).__init__()

property.__init__에 누출 참조 재산의 오래된 fget, fset, fdel, 그리고 __doc__당신은 이미 초기화에를 호출하는 경우 property인스턴스입니다. 이 버그는 결국 CPython 문제 31787의 일부로보고 되어 Python 3.6.5Python 3.7.0 에서 수정되었습니다 . (그렇습니다 property([]). 할 수있는 일입니다.)


버그 리포트가 전송 되었습니까?
mbomb007


27

C #, 34 바이트

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

솔루션 에는 힙이 필요하지 않습니다. 그것은 실제로 열심히 일하는 GC ( 가비지 콜렉터 )가 필요합니다.

본질적으로 그것은 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.8GB입니다.

이 답변은 에릭 Lippert의의 멋진 기사에서 영감을하고있다 : 당신이 알고있는 모든 잘못되면 .


이것은 매력적입니다. 가비지 수집기는 어떤 것들이 존재한다는 것을 잊어 버리고 이것 때문에 그것들을 추적하지 못합니까? 나는 C #에 대해 많이 모른다. 또한 폭탄과 누출의 차이점은 무엇입니까? 시스템 내부에서 생성자를 호출하거나 멈추지 않는 무한 재귀 함수를 사용하여 유사한 실패가 발생할 수 있다고 생각합니다. 기술적으로 시스템은 이러한 참조를 잃지 않지만 공간이 부족합니다 ...
don 밝은

1
생성자 내의 생성자는 스택 오버플로를 유발합니다. 그러나 인스턴스의 소멸자는 플랫 계층 구조로 호출됩니다. GC는 실제로 개체를 추적하지 않습니다. 그것을 파괴하려고 할 때마다 무의식적으로 새로운 물체를 만듭니다. 반면에 사용자 코드는 해당 개체에 액세스 할 수 없습니다. 또한 GC가 소멸자를 호출하지 않고 객체를 파괴하기로 결정할 수 있기 때문에 언급 된 불일치가 발생할 수 있습니다.
MrPaulch 2012

?를 사용하여 도전이 완료되지 class L{~L(){new L();}}않습니까? AFAIK for(;;)만이 메모리 누수를 더 빠르게 만듭니다.
BgrWorker 2019

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

자바 스크립트, 14 바이트

골프

setInterval(0)

빈 지연 처리기를 기본 지연으로 등록하여 결과 타이머 ID를 삭제합니다 (취소 할 수 없음).

여기에 이미지 설명을 입력하십시오

기본 간격을 사용하면 CPU와 같은 CPU를 먹는 것처럼 누출을 설명하기 위해 기본이 아닌 간격을 사용하여 수백만 개의 타이머를 만들었습니다.


5
하하 나는 당신이 '골프'를 입력 한 것을 좋아합니다. 언 골프 버전에 대해 궁금해합니다
Martijn

9
그것은 다음과 같이 보일 것입니다if(window && window.setInterval && typeof window.setInterval === 'function') { window.setInterval(0); }
Tschallacka

3
실제로 이것은 취소가 불가능하지 않습니다. interval (및 timeout) ID는 순차적으로 번호가 매겨져 있으므로 clearInterval간격이 없어 질 때까지 증가하는 ID 로 전화 하는 것만으로도 쉽게 취소 할 수 있습니다. 예를 들면 다음과 같습니다.for(let i=0;i<1e5;i++){try{clearInterval(i);}catch(ex){}}
user2428118

5
@ 비행선으로 user2428118이 더 이상 당신이 강제로 호출 하므 수 있기 때문에 C / C ++ 누수가 "진짜"하지 말보다 "legitmate"입니다, 말한다free()
TripeHound

1
와우, 많은하지 도전 자바 스크립트는 실제 경쟁자는 ...이다
자레드 스미스

19

자바, 10 바이트

마지막으로 Java의 경쟁력있는 답변!

골프

". "::trim

이것은 문자열 상수에 대한 메서드 참조이며 다음과 같이 사용할 수 있습니다.

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

리터럴 문자열 ". "은 클래스에 의해 유지 관리 되는대로 글로벌 인터네 인드 문자열 풀에 자동으로 추가되며 java.lang.String즉시 트리밍 할 때 코드에서 더 이상 재사용 할 수 없습니다 (정확히 동일한 문자열을 다시 선언하지 않는 한).

...

초기에 비어있는 문자열 풀은 String 클래스에 의해 개인적으로 유지됩니다.

모든 리터럴 문자열과 문자열 값 상수 표현식이 인터 닝됩니다. 문자열 리터럴은 Java ™ 언어 스펙의 3.10.5 섹션에 정의되어 있습니다.

...

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

문자열을 자체에 추가 한 다음 루프에서 intern () 메서드를 명시 적으로 호출하여 "생산 등급"메모리 누수로이를 설정할 수 있습니다 .


2
나는 이것을 C #에 대해 고려했지만 ... 다른 문자열 리터럴을 포함하여 해당 메모리에 액세스 할 있기 때문에 카운트하지 않는다고 생각합니다 . 또한 ("." + " ").intern()사용자가 입력하거나 w / e 인 경우 컴파일러 최적화를 할인 하는 방법을 알고 싶습니다 .
VisualMelon 2012

1
실제로, 유일한 합의는 기껏해야 슬림하다. 나는 단지 "코드를 컴파일해야한다"라는 측면에 확고하다. 나는 아직도 내가 질문에 문구를 주어진이 솔루션 구입 확실하지 않다 (이러한 문자열은 없습니다 해방을, 그들은 할 수 는 없을 비록 정상 작동 코드에서 찾을 수),하지만 난 자신의 판단을 만들기 위해 다른 사람을 초대
VisualMelon

3
그 문자열은 유출 되지 않고 액세스 할 수조차 없습니다 . 동일한 문자열을 인턴하면 언제든지 검색 할 수 있습니다. 이것이 계산된다면, 사용되지 않은 전역 변수 (자바에서 정적 인 정적)는 누출입니다. 그것은 메모리 누수가 정의되는 방식이 아닙니다.
user2357112

3
@ user2357112 "... 해당 문자열은 접근 할 수 없습니다 ..."코드가 보이기 때문에 분명해 보입니다. 이제이 메소드 참조 X ()를 코드의 인수로 사용한다고 가정하면 내부에 문자열 리터럴을 할당하고 인턴하는 것을 알지만 정확히 어느 것이 "."또는 "123"인지 알 수 없습니다. 또는 (일반적으로) 알 수없는 길이의 다른 문자열. 여전히 액세스 할 수있는 방법을 보여 주거나 "인턴"풀에있는 항목을 할당 해제 하시겠습니까?
zeppelin

2
@ user2357112 유한 메모리가있는 머신에서는 메모리에 저장된 값에 액세스 할 수 simply by guessing it correctly있지만 메모리 누수와 같은 것이 존재하지는 않습니다. there's probably some way to use reflection to determine the string's contents too이것을 보여줄 수 있습니까? 힌트, String.intern ()은 네이티브 코드로 구현됩니다 .
zeppelin

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)

대박. 이와 같은 게시물을 통해 지난 1 년 동안 Rust를 탐색하게되었으며, 제가 배우려고 시도한 가장 재미있는 언어 중 하나입니다.
밝은

16

8086 ASM, 3 바이트

이 예에서는 C 런타임이 링크되어 있다고 가정합니다.

jmp _malloc

이것은 상대 주소가 e9 XX XX어디로 어셈블XX XX_malloc

이를 malloc통해 예기치 않은 메모리 양을 할당 한 다음 즉시 프로세스를 종료하여 반환합니다. DOS와 같은 일부 운영 체제에서는 시스템이 재부팅 될 때까지 메모리를 전혀 회수 할 수 없습니다!


malloc을 정상적으로 구현하면 프로세스 종료시 메모리가 해제됩니다.
Joshua

@Joshua 그래, 그러나 그것은 구현 정의 행동을 정의한다.
FUZxxl

12

넷째, 6 바이트

골프

s" " *

빈 문자열을로 할당 s" "하고 스택에 주소와 길이 (0)를 그대로 둔 다음 곱합니다 (메모리 주소가 손실 됨).

발 그린 드

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

이것은 내부에 무한 루프를 가진 익명의 고 루틴을 만듭니다. goroutine을 시작하는 것은 동시에 실행중인 작은 스레드를 생성하는 것과 비슷하지만 프로그램은 goroutine에 할당 된 메모리를 회수 할 방법이 없기 때문에 프로그램은 정상적으로 정상적으로 실행될 수 있습니다. 가비지 수집기는 여전히 실행 중이므로 수집하지 않습니다. 어떤 사람들은 이것을 '고 루틴 유출'이라고 부릅니다.


golf check : 다음과 같이 C.malloc(8)해야하기 import"C"
때문에이

9

자바 1.3, 23 바이트

void l(){new Thread();}

스레드를 작성하지만 시작하지는 않습니다. 스레드는 내부 스레드 풀에 등록되어 있지만 시작되지 않으므로 종료되지 않으므로 GC의 후보가되지 않습니다. Java 림보에 갇혀 복구 할 수없는 개체입니다.

나중에 수정 된 1.3이 포함될 때까지 Java의 버그입니다 .

테스팅

다음 프로그램은 새로운 스레드 객체로 메모리를 오염시키고 사용 가능한 메모리 공간을 줄입니다. 누수 테스트를 위해 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가있었습니다. 이상한 번호 매기기가 그 방법입니다.
Olivier Grégoire

이것은 나의 생각이기도했다. 제길.
Magic Octopus Urn

8

Befunge ( 곰팡이 ), 1 바이트

$

이것은 플랫폼 및 버전에 따라 다를 수 있지만 (Windows에서는 버전 1.0.4로만 테스트했습니다) 곰팡이 는 역사적으로 매우 누출 된 해석기였습니다. $(드롭) 명령은 빈 스택에 아무것도하지해야하지만,이 코드를 통해 반복 든 매우 빠르게 많은 메모리 누수가 관리합니다. 몇 초 만에 몇 개의 기가 소모되고 "메모리 부족"오류가 발생합니다.

반드시 $명령 일 필요는 없습니다 . 무엇이든 할 수 있습니다. 빈 소스 파일로는 작동하지 않습니다. 적어도 하나의 작업이 있어야합니다.


8

스위프트 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하며 그 반대도 마찬가지입니다. 따라서 어느 것도 할당 해제되지 않아 메모리 누수가 발생합니다.


흠, 당신은 여전히 통해 해당 메모리를 참조 할 수 xy(당신이 어떻게 든 그들을 파괴하지 않는 한) 그래서 이것은 정말 나에게 누설처럼 보이지 않는다.
zeppelin 's

마지막 줄은 함수에 싸여 수 @zeppelin 그 문제를 해결하기 위해
NobodyNada

@NobodyNada, do제플린이 올린 문제를 해결할 블록에 마지막 줄을 넣으면 ?
Daniel

@Dopapp 예; do뿐만 아니라 작동합니다. 좋은 생각!
NobodyNada

당신이 두 개의 클래스를 필요로하지 않는다 단축 할 수 - X 자체에 대한 참조를 저장할 수 있습니다 :class X{var x: X!};do{let x=X();x.x=x}
세바스찬 Osiński

7

델파이 (오브젝트 파스칼)-33 바이트

가변적이고 완전한 콘솔 프로그램없이 객체 만들기 :

program;begin TObject.Create;end.

프로젝트에서 FastMM4를 활성화하면 메모리 누수가 표시됩니다.

여기에 이미지 설명을 입력하십시오


6

C #-84 바이트

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

이것은 정확히 1 바이트의 관리되지 않는 메모리를 할당 한 다음을 잃어 버립니다 IntPtr. 루프에 채우고 응용 프로그램이 충돌하기를 기다리는 것으로 테스트 할 수 있습니다 (속도를 높이기 위해 몇 가지 0을 추가해야 할 수도 있습니다).

나는 생각 System.IO.File.Create("a");과 같은,하지만 난이 응용 프로그램 자체로, 반드시 메모리 누수 것을 확신 아니에요 것이다 메모리를 수집, 그것은 그 아래에있는 OS의 (때문에 누출 Close이나가 Dispose호출되지 않은이). 파일 액세스에도 파일 시스템 권한이 필요하며 아무도 그에 의존하기를 원하지 않습니다. 그리고 파이널 라이저 호출을 멈추는 것이 없기 때문에 (기본 리소스를 사용할 수 있음) 프레임 워크에 이러한 종류의 판단 오류 (어느 정도)를 완화시키기 위해 포함되어 있기 때문에 이것이 유출되지 않습니다. 비 결정적 파일 잠금과 겉보기에 프로그래머와 혼동하기 위해 (당신이 냉소적 인 경우). 이 문제를 바로 잡아 준 Jon Hanna에게 감사합니다.

나는 더 짧은 길을 찾을 수 없다는 것에 약간 실망했다. .NET GC가 작동합니다 .mscorlib에서IDisposables 확실히 누출 될 것이라고 생각할 수는 없습니다 (실제로 최종 자, 성가신 것 같습니다) , 관리되지 않는 메모리를 할당하는 다른 방법을 알지 못합니다 (PInvoke 부족 )을 반영하고 반영하면 언어 의미 (예 : 접근자가없는 개인 구성원 또는 클래스)와 상관없이이를 참조하는 모든 항목을 찾을 있습니다.


1
System.IO.File.Create("a")누출되지 않지만 GC.SuppressFinalize(System.IO.File.Create("a"))명시 적으로 FileStream생성 된 파이널 라이저를 실행하지 않아야합니다 .
존 한나

@JonHanna 아주 그렇습니다. 내 IDisposable 편집증이 나에게 더 나은 것 같습니다.
VisualMelon 2012

System.Drawing.Bitmap을 사용하여 GDI + 누수가 발생할 수 있습니다. 프로그램 자체가 아니라 누출을 일으키는 Windows 라이브러리이기 때문에 계산되는지 알 수 없습니다.
BgrWorker

@BgrWorker 그들은 의심 할 여지없이 finaliser를 가지고 있으며, 비용을 지불하는 것에 대한 합의에 동의하지 않기 때문에 코드 골프에서 외부 라이브러리를 피하는 경향이 있습니다. 자신감있는 방법을 찾을 수 있다면 자유롭게 게시하십시오 당신의 자신의 대답에!
VisualMelon 2012

<!-- 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 | |

아뇨! 불쌍한 요소, 이제 알츠하이머가 있습니다! 디:


5

공통 리스프 (SBCL 만 해당) 28 26 바이트

sb-alien::(make-alien int)

다음과 같이 실행합니다. sbcl --eval 'sb-alien::(make-alien int)'; 아무것도 인쇄되거나 반환되지 않지만 메모리 할당이 발생합니다. 양식을에 감싸면 (print ...)REPL에 포인터가 표시됩니다.

  1. package::(form)양식을 읽는 동안 현재 패키지를 임시로 바인딩하기위한 SBCL의 특수 표기법입니다. 이 모두 접두사를 방지하기 위해 여기에 사용 make-alien하고 intsb-alien. 현재 패키지가 시작으로 설정되어 있지 않기 때문에 현재 패키지 가이 패키지로 설정되어 있다고 가정하는 것이 부정적이라고 생각합니다.

  2. make-alien 주어진 유형과 선택적 크기 (malloc 사용)에 메모리를 할당합니다.

  3. REPL에서 이것을 실행할 때 0REPL이 포인터를 반환하지 않고 대신 해당 값을 반환하도록 할당 후에 추가하십시오 . REPL 지난 3 개 반환 값 (참조 기억 때문에 그렇지 않으면, 그것은 더 진짜 누수가 없을 것 *, **,*** ) 우리는 여전히 할당 된 메모리를 해제 할 수있는 기회를 가질 수있다.

PrzemysławP 덕분에 2 바이트가 제거되었습니다. 감사합니다!


1
값을 반환하도록 대신 1(또는 2, 3등) 을 사용할 수 없습니까 ? 1 바이트를 절약합니다. 또한이 답변은 REPL입니까? 어쨌든 액세스 할 수 없기 때문에 코드를로드 하면 마지막에 포함 할 수없는 것이 있습니까? ()1load()
PrzemysławP

1
@ PrzemysławP 당신은 두 가지 점에서 옳았습니다 eval. 고마워요!
coredump

4

AutoIt , 39 바이트

#include<Memory.au3>
_MemGlobalAlloc(1)

힙에서 1 바이트를 할당합니다. 에 의해 반환 된 핸들 _MemGlobalAlloc이 삭제 되므로 해당 할당을 명시 적으로 해제 할 수있는 방법이 없습니다.


3

C ++, 16 바이트

main(){new int;}

나는 누출을 확인하기 위해 valgrind가 없지만 꽤해야합니다. 그렇지 않으면 시도 할 것입니다 :

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

발 그린 드 결과

(실제로 누출됩니다)

==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
matovitch

2
@WheatWizard 죄송합니다. 컨테스트를 시작하기 위해 C ++ 예제를 제공하는 것을 보았습니다. reddit에서 왔을 때 나는 대답 만 보았고 (이상하게) C ++을 보지 못했습니다. 조금 바보 같아 : /
matovitch

합의는 []{new int;}C ++ 함수로 계산할 수 있다는 것입니다 (도전이 전체 프로그램을 지정하지는 않음).
Toby Speight

3

자바 (오픈 JDK 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);}}

온라인으로 사용해보십시오!

이것은 문자열 캐시를 사용하지 않는 다른 메모리 누수입니다. 그것은 당신의 RAM의 절반을 할당하고 당신은 그것으로 아무것도 할 수 없습니다.

모든 바이트를 저장 한 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);}}
zeppelin

그리고 public static void main정적 초기화 자로 대체하여 더 많은 비용을 절약 할 수 있습니다 static{try{}catch(Exception e){}}(시작하기가 약간 까다로울 수 있지만 그럼에도 불구하고 유효하고 컴파일 가능합니다).
zeppelin

yhea 생성자의 사용은 내가 사용한 Android 버전의 코드에서 사용되었습니다. im @ home 일 때 몇 가지 사항을 변경하지만 한 문장으로 진행 한 경로로 이동합니다.)
Serverfrog

공백을 제거 하고 a대신에 args공용을 제거하십시오. tio.run/nexus/…
Pavel

true는 1> 0으로 대체 될 수 있음
masterX244

3

c, 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. 그러나 표지 아래에서 어떻게됩니까?

XmlSerializerReflector 를 사용하여 생성자를 살펴보면 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));}

발 그린 드 결과 :

         ==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

@ 그렇습니다! 그러나 이미 게시되었습니다!
Abel Tom

2

다트, 76 바이트

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

JavaScript 답변과 약간 비슷합니다. .listenDart 스트림 객체 를 호출 하면 StreamSubscription이 제공되어 스트림 연결을 끊을 수 있습니다. 그러나 버리면 스트림에서 구독을 취소하여 누수를 일으킬 수 없습니다. 누출을 해결할 수있는 유일한 방법은 Stream 자체가 수집되지만 여전히 StreamController + Timer 콤보에 의해 내부적으로 참조되는 경우입니다.

불행히도 다트는 내가 시도한 다른 것들에 비해 너무 똑똑합니다. ()async=>await new Completer().futureawait를 사용하는 것과 같은 동작을하지 않기 때문에 작동하지 않습니다 new Completer().future.then(<continuation>). 두 번째 Completer가 참조되지 않은 클로저 자체가 소멸 될 수 있습니다 .future.

또한 GC에 의해 분리 물 (일명 스레드)이 정리되므로 새 스레드에서 자신을 생성하고 즉시 일시 중지 ( import'dart:isolate';main(_)=>Isolate.spawn(main,0,paused:true);) 할 수 없습니다. 무한 루프 ( import'dart:isolate';f(_){while(true){print('x');}}main()=>Isolate.spawn(f,0);) 로 분리를 생성하더라도 분리가 종료되고 프로그램이 종료됩니다.

오 잘


주 프로그램이 계속 실행되고 다른 작업을 수행하는 경우 가비지 수집기가 격리를 중지 할 수 있습니까? 나는 goroutine 예제가 비슷하게 들리기 때문에 묻습니다 ... 프로그램이 종료되고 모든 메모리를 OS에 다시 제공한다는 사실이 반드시 누출되지 않았 음을 의미하지는 않습니다.
밝게 돈

2

스위프트, 12 바이트

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

설명:

이는 언어에서 메모리 수동 관리, 자동 참조 카운트 (ARC, Swift와 같은) 또는 전체 가비지 수집을 사용하는지 여부에 관계없이 모든 언어에서 발생할 수있는 사실상의 메모리 누수입니다.

[3,5]단지 배열 리터럴입니다. 이 배열은 적어도이 두 요소에 충분한 메모리를 할당합니다. 35단지 임의이다.

첨자 (인덱싱)는을 Array<T>생성합니다 ArraySlice<T>. An ArraySlice<T>은 생성 된 Array의 메모리에 대한 뷰입니다.

[3,5][0...0]ArraySlice<Int>값이 인을 생성합니다 .[3] . 점을 유의 3이 슬라이스가 동일 3는 AS 소자 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 (원하는 함수를 알려주는 syscall을 알려줘야 함) 여야하지만 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 비트이며 여기에 1의 보수가 적용되었습니다 (따라서 null 바이트는 없습니다. 원본을 얻을 수있는 값은 아닙니다). 다음 값은 RDI (0x00007fff7d578244)는 왼쪽에 2 개의 여분의 정크 바이트가 추가되어 왼쪽으로 이동되었습니다 (널 바이트를 제외하기 위해 다시 오른쪽으로 이동하여 원래로 되돌립니다).

syscall 후에 우리는 새로 할당 된 메모리에 쓰고 있습니다. 그 이유는 mach_vm_allocate (또는이 syscall)를 사용하여 할당 된 메모리는 실제로 VM 페이지이며 자동으로 메모리에 페이징되지 않기 때문입니다. 오히려 데이터가 기록 될 때까지 예약 된 다음 해당 페이지가 메모리에 매핑됩니다. 예약 된 경우에만 요구 사항을 충족하는지 확실하지 않았습니다.

다음 솔루션에서는 쉘 코드에 널 바이트가 없다는 점을 이용하므로 프로그램 코드 외부로 이동하여 크기를 줄일 수 있습니다.

해결 방법 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에 따르면 dyld가 메모리를 누출하는 것을 보았습니다. 따라서 모든 프로그램이 실제로 일부 메모리를 누출하고 있습니다. 이 경우 우리는 실제로 아무것도하지 않는 (단순히 종료) 프로그램을 만들 수 있으며 실제로 메모리가 누출됩니다.

출처:

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 바이트를 제거했습니다. "bogon"유형 정의를 제거하고 "bogon"하위 유형 대신 상위 "thing"유형을 사용하여 12 바이트를 제거했습니다. 완전한 프로그램에서 메모리 누수 루틴으로 전환하여 23 바이트를 제거했습니다.

골프 버전 :

To x:
Allocate memory for a thing.

완전한 프로그램 인 ungolfed 버전은 하위 유형 정의를 사용하며 메모리가 누출되지 않습니다.

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"호출 횟수에 비례하여 메모리가 누출됩니다. 골프 버전에서 "사물 할당 해제" 메모리 누수를 해결합니다.

일반 영어는 기본적으로 메모리 누수를 확인합니다. 메모리 누수 버전이 실행되면 프로그램이 종료되기 직전에 대화 상자가 나타납니다. 대화 상자에는 제목 "debug", 메시지 "1 drip"및 "OK"버튼이 있습니다. 누수 함수를 여러 번 호출할수록 메시지의 "드립"수가 많아집니다. 메모리 누수가없는 버전이 실행되면 대화 상자가 나타나지 않습니다.

일반 영어에서 "thing"은 이중 연결 목록의 항목에 대한 포인터입니다. "사물", "시작"및 "종료"는 "국수"라는 모듈에서 정의되며, 각 프로젝트에 (보통 별도 파일로) 복사해야합니다. "A", "the", "to", "to 메모리 할당"및 "파괴"는 컴파일러에서 정의됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.