~ubuntu-branches/ubuntu/vivid/golang/vivid

« back to all changes in this revision

Viewing changes to src/pkg/runtime/panic.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2014-11-18 15:12:26 UTC
  • mfrom: (14.2.12 vivid-proposed)
  • Revision ID: package-import@ubuntu.com-20141118151226-zug7vn93mn3dtiz3
Tags: 2:1.3.2-1ubuntu1
* Merge from Debian unstable.  Remaining changes:
  - 016-armhf-elf-header.patch: Use correct ELF header for armhf binaries.
  - Support co-installability with gccgo-go tool:
    - d/rules,golang-go.install: Rename bin/go -> bin/golang-go
    - d/golang-go.{postinst,prerm}: Install/remove /usr/bin/go using
      alternatives.
  - d/copyright: Amendments for full compiliance with copyright format.
  - d/control: Demote golang-go.tools to Suggests to support Ubuntu MIR.
  - dropped patches (now upstream):
    - d/p/issue27650045_40001_50001.diff
    - d/p/issue28050043_60001_70001.diff
    - d/p/issue54790044_100001_110001.diff

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
uint32 runtime·panicking;
14
14
static Lock paniclk;
15
15
 
16
 
enum
17
 
{
18
 
        DeferChunkSize = 2048
19
 
};
20
 
 
21
 
// Allocate a Defer, usually as part of the larger frame of deferred functions.
22
 
// Each defer must be released with both popdefer and freedefer.
 
16
// Each P holds pool for defers with arg sizes 8, 24, 40, 56 and 72 bytes.
 
17
// Memory block is 40 (24 for 32 bits) bytes larger due to Defer header.
 
18
// This maps exactly to malloc size classes.
 
19
 
 
20
// defer size class for arg size sz
 
21
#define DEFERCLASS(sz) (((sz)+7)>>4)
 
22
// total size of memory block for defer with arg size sz
 
23
#define TOTALSIZE(sz) (sizeof(Defer) - sizeof(((Defer*)nil)->args) + ROUND(sz, sizeof(uintptr)))
 
24
 
 
25
// Allocate a Defer, usually using per-P pool.
 
26
// Each defer must be released with freedefer.
23
27
static Defer*
24
28
newdefer(int32 siz)
25
29
{
26
 
        int32 total;
27
 
        DeferChunk *c;
 
30
        int32 total, sc;
28
31
        Defer *d;
29
 
        
30
 
        c = g->dchunk;
31
 
        total = sizeof(*d) + ROUND(siz, sizeof(uintptr)) - sizeof(d->args);
32
 
        if(c == nil || total > DeferChunkSize - c->off) {
33
 
                if(total > DeferChunkSize / 2) {
34
 
                        // Not worth putting in any chunk.
35
 
                        // Allocate a separate block.
36
 
                        d = runtime·malloc(total);
37
 
                        d->siz = siz;
38
 
                        d->special = 1;
39
 
                        d->free = 1;
40
 
                        d->link = g->defer;
41
 
                        g->defer = d;
42
 
                        return d;
43
 
                }
44
 
 
45
 
                // Cannot fit in current chunk.
46
 
                // Switch to next chunk, allocating if necessary.
47
 
                c = g->dchunknext;
48
 
                if(c == nil)
49
 
                        c = runtime·malloc(DeferChunkSize);
50
 
                c->prev = g->dchunk;
51
 
                c->off = sizeof(*c);
52
 
                g->dchunk = c;
53
 
                g->dchunknext = nil;
54
 
        }
55
 
 
56
 
        d = (Defer*)((byte*)c + c->off);
57
 
        c->off += total;
 
32
        P *p;
 
33
 
 
34
        d = nil;
 
35
        sc = DEFERCLASS(siz);
 
36
        if(sc < nelem(p->deferpool)) {
 
37
                p = m->p;
 
38
                d = p->deferpool[sc];
 
39
                if(d)
 
40
                        p->deferpool[sc] = d->link;
 
41
        }
 
42
        if(d == nil) {
 
43
                // deferpool is empty or just a big defer
 
44
                total = TOTALSIZE(siz);
 
45
                d = runtime·malloc(total);
 
46
        }
58
47
        d->siz = siz;
59
48
        d->special = 0;
60
 
        d->free = 0;
61
49
        d->link = g->defer;
62
50
        g->defer = d;
63
 
        return d;       
64
 
}
65
 
 
66
 
// Pop the current defer from the defer stack.
67
 
// Its contents are still valid until the goroutine begins executing again.
68
 
// In particular it is safe to call reflect.call(d->fn, d->argp, d->siz) after
69
 
// popdefer returns.
70
 
static void
71
 
popdefer(void)
72
 
{
73
 
        Defer *d;
74
 
        DeferChunk *c;
75
 
        int32 total;
76
 
        
77
 
        d = g->defer;
78
 
        if(d == nil)
79
 
                runtime·throw("runtime: popdefer nil");
80
 
        g->defer = d->link;
81
 
        if(d->special) {
82
 
                // Nothing else to do.
83
 
                return;
84
 
        }
85
 
        total = sizeof(*d) + ROUND(d->siz, sizeof(uintptr)) - sizeof(d->args);
86
 
        c = g->dchunk;
87
 
        if(c == nil || (byte*)d+total != (byte*)c+c->off)
88
 
                runtime·throw("runtime: popdefer phase error");
89
 
        c->off -= total;
90
 
        if(c->off == sizeof(*c)) {
91
 
                // Chunk now empty, so pop from stack.
92
 
                // Save in dchunknext both to help with pingponging between frames
93
 
                // and to make sure d is still valid on return.
94
 
                if(g->dchunknext != nil)
95
 
                        runtime·free(g->dchunknext);
96
 
                g->dchunknext = c;
97
 
                g->dchunk = c->prev;
98
 
        }
 
51
        return d;
99
52
}
100
53
 
101
54
// Free the given defer.
102
 
// For defers in the per-goroutine chunk this just clears the saved arguments.
103
 
// For large defers allocated on the heap, this frees them.
104
55
// The defer cannot be used after this call.
105
56
static void
106
57
freedefer(Defer *d)
107
58
{
108
 
        int32 total;
 
59
        int32 sc;
 
60
        P *p;
109
61
 
110
 
        if(d->special) {
111
 
                if(d->free)
112
 
                        runtime·free(d);
113
 
        } else {
114
 
                // Wipe out any possible pointers in argp/pc/fn/args.
115
 
                total = sizeof(*d) + ROUND(d->siz, sizeof(uintptr)) - sizeof(d->args);
116
 
                runtime·memclr((byte*)d, total);
117
 
        }
 
62
        if(d->special)
 
63
                return;
 
64
        sc = DEFERCLASS(d->siz);
 
65
        if(sc < nelem(p->deferpool)) {
 
66
                p = m->p;
 
67
                d->link = p->deferpool[sc];
 
68
                p->deferpool[sc] = d;
 
69
                // No need to wipe out pointers in argp/pc/fn/args,
 
70
                // because we empty the pool before GC.
 
71
        } else
 
72
                runtime·free(d);
118
73
}
119
74
 
120
75
// Create a new deferred function fn with siz bytes of arguments.
157
112
// is called again and again until there are no more deferred functions.
158
113
// Cannot split the stack because we reuse the caller's frame to
159
114
// call the deferred function.
160
 
//
161
 
// The ... in the prototype keeps the compiler from declaring
162
 
// an argument frame size. deferreturn is a very special function,
163
 
// and if the runtime ever asks for its frame size, that means
164
 
// the traceback routines are probably broken.
 
115
 
 
116
// The single argument isn't actually used - it just has its address
 
117
// taken so it can be matched against pending defers.
165
118
#pragma textflag NOSPLIT
166
119
void
167
 
runtime·deferreturn(uintptr arg0, ...)
 
120
runtime·deferreturn(uintptr arg0)
168
121
{
169
122
        Defer *d;
170
123
        byte *argp;
184
137
        m->locks++;
185
138
        runtime·memmove(argp, d->args, d->siz);
186
139
        fn = d->fn;
187
 
        popdefer();
 
140
        g->defer = d->link;
188
141
        freedefer(d);
189
142
        m->locks--;
190
143
        if(m->locks == 0 && g->preempt)
192
145
        runtime·jmpdefer(fn, argp);
193
146
}
194
147
 
 
148
// Ensure that defer arg sizes that map to the same defer size class
 
149
// also map to the same malloc size class.
 
150
void
 
151
runtime·testdefersizes(void)
 
152
{
 
153
        P *p;
 
154
        int32 i, siz, defersc, mallocsc;
 
155
        int32 map[nelem(p->deferpool)];
 
156
 
 
157
        for(i=0; i<nelem(p->deferpool); i++)
 
158
                map[i] = -1;
 
159
        for(i=0;; i++) {
 
160
                defersc = DEFERCLASS(i);
 
161
                if(defersc >= nelem(p->deferpool))
 
162
                        break;
 
163
                siz = TOTALSIZE(i);
 
164
                mallocsc = runtime·SizeToClass(siz);
 
165
                siz = runtime·class_to_size[mallocsc];
 
166
                // runtime·printf("defer class %d: arg size %d, block size %d(%d)\n", defersc, i, siz, mallocsc);
 
167
                if(map[defersc] < 0) {
 
168
                        map[defersc] = mallocsc;
 
169
                        continue;
 
170
                }
 
171
                if(map[defersc] != mallocsc) {
 
172
                        runtime·printf("bad defer size class: i=%d siz=%d mallocsc=%d/%d\n",
 
173
                                i, siz, map[defersc], mallocsc);
 
174
                        runtime·throw("bad defer size class");
 
175
                }
 
176
        }
 
177
}
 
178
 
195
179
// Run all deferred functions for the current goroutine.
196
180
static void
197
181
rundefer(void)
199
183
        Defer *d;
200
184
 
201
185
        while((d = g->defer) != nil) {
202
 
                popdefer();
203
 
                reflect·call(d->fn, (byte*)d->args, d->siz);
 
186
                g->defer = d->link;
 
187
                reflect·call(d->fn, (byte*)d->args, d->siz, d->siz);
204
188
                freedefer(d);
205
189
        }
206
190
}
221
205
}
222
206
 
223
207
static void recovery(G*);
 
208
static void abortpanic(Panic*);
 
209
static FuncVal abortpanicV = { (void(*)(void))abortpanic };
224
210
 
225
211
// The implementation of the predeclared function panic.
226
212
void
227
213
runtime·panic(Eface e)
228
214
{
229
 
        Defer *d;
230
 
        Panic *p;
 
215
        Defer *d, dabort;
 
216
        Panic p;
231
217
        void *pc, *argp;
232
 
        
233
 
        p = runtime·mal(sizeof *p);
234
 
        p->arg = e;
235
 
        p->link = g->panic;
236
 
        p->stackbase = g->stackbase;
237
 
        g->panic = p;
 
218
 
 
219
        runtime·memclr((byte*)&p, sizeof p);
 
220
        p.arg = e;
 
221
        p.link = g->panic;
 
222
        p.stackbase = g->stackbase;
 
223
        g->panic = &p;
 
224
 
 
225
        dabort.fn = &abortpanicV;
 
226
        dabort.siz = sizeof(&p);
 
227
        dabort.args[0] = &p;
 
228
        dabort.argp = NoArgs;
 
229
        dabort.special = true;
238
230
 
239
231
        for(;;) {
240
232
                d = g->defer;
241
233
                if(d == nil)
242
234
                        break;
243
235
                // take defer off list in case of recursive panic
244
 
                popdefer();
245
 
                g->ispanic = true;      // rock for newstack, where reflect.newstackcall ends up
 
236
                g->defer = d->link;
 
237
                g->ispanic = true;      // rock for runtime·newstack, where runtime·newstackcall ends up
246
238
                argp = d->argp;
247
239
                pc = d->pc;
 
240
 
 
241
                // The deferred function may cause another panic,
 
242
                // so newstackcall may not return. Set up a defer
 
243
                // to mark this panic aborted if that happens.
 
244
                dabort.link = g->defer;
 
245
                g->defer = &dabort;
 
246
                p.defer = d;
 
247
 
248
248
                runtime·newstackcall(d->fn, (byte*)d->args, d->siz);
 
249
 
 
250
                // Newstackcall did not panic. Remove dabort.
 
251
                if(g->defer != &dabort)
 
252
                        runtime·throw("bad defer entry in panic");
 
253
                g->defer = dabort.link;
 
254
 
249
255
                freedefer(d);
250
 
                if(p->recovered) {
251
 
                        g->panic = p->link;
 
256
                if(p.recovered) {
 
257
                        g->panic = p.link;
 
258
                        // Aborted panics are marked but remain on the g->panic list.
 
259
                        // Recovery will unwind the stack frames containing their Panic structs.
 
260
                        // Remove them from the list and free the associated defers.
 
261
                        while(g->panic && g->panic->aborted) {
 
262
                                freedefer(g->panic->defer);
 
263
                                g->panic = g->panic->link;
 
264
                        }
252
265
                        if(g->panic == nil)     // must be done with signal
253
266
                                g->sig = 0;
254
 
                        runtime·free(p);
255
267
                        // Pass information about recovering frame to recovery.
256
268
                        g->sigcode0 = (uintptr)argp;
257
269
                        g->sigcode1 = (uintptr)pc;
263
275
        // ran out of deferred calls - old-school panic now
264
276
        runtime·startpanic();
265
277
        printpanics(g->panic);
266
 
        runtime·dopanic(0);
 
278
        runtime·dopanic(0);     // should not return
 
279
        runtime·exit(1);        // not reached
 
280
}
 
281
 
 
282
static void
 
283
abortpanic(Panic *p)
 
284
{
 
285
        p->aborted = true;
267
286
}
268
287
 
269
288
// Unwind the stack after a deferred function calls recover
320
339
                gp->stackbase = top->stackbase;
321
340
                gp->stackguard = top->stackguard;
322
341
                gp->stackguard0 = gp->stackguard;
323
 
                if(top->free != 0) {
324
 
                        gp->stacksize -= top->free;
325
 
                        runtime·stackfree(stk, top->free);
326
 
                }
 
342
                runtime·stackfree(gp, stk, top);
327
343
        }
328
344
 
329
345
        if(sp != nil && (sp < (byte*)gp->stackguard - StackGuard || (byte*)gp->stackbase < sp)) {
337
353
// find the stack segment of its caller.
338
354
#pragma textflag NOSPLIT
339
355
void
340
 
runtime·recover(byte *argp, Eface ret)
 
356
runtime·recover(byte *argp, GoOutput retbase, ...)
341
357
{
342
358
        Panic *p;
343
359
        Stktop *top;
 
360
        Eface *ret;
344
361
 
345
362
        // Must be an unrecovered panic in progress.
346
363
        // Must be on a stack segment created for a deferred call during a panic.
351
368
        // do not count as official calls to adjust what we consider the top frame
352
369
        // while they are active on the stack. The linker emits adjustments of
353
370
        // g->panicwrap in the prologue and epilogue of functions marked as wrappers.
 
371
        ret = (Eface*)&retbase;
354
372
        top = (Stktop*)g->stackbase;
355
373
        p = g->panic;
356
374
        if(p != nil && !p->recovered && top->panic && argp == (byte*)top - top->argsize - g->panicwrap) {
357
375
                p->recovered = 1;
358
 
                ret = p->arg;
 
376
                *ret = p->arg;
359
377
        } else {
360
 
                ret.type = nil;
361
 
                ret.data = nil;
 
378
                ret->type = nil;
 
379
                ret->data = nil;
362
380
        }
363
 
        FLUSH(&ret);
364
381
}
365
382
 
366
383
void
371
388
                m->mallocing = 1; // tell rest of panic not to try to malloc
372
389
        } else if(m->mcache == nil) // can happen if called from signal handler or throw
373
390
                m->mcache = runtime·allocmcache();
374
 
        if(m->dying) {
 
391
        switch(m->dying) {
 
392
        case 0:
 
393
                m->dying = 1;
 
394
                if(g != nil)
 
395
                        g->writebuf = nil;
 
396
                runtime·xadd(&runtime·panicking, 1);
 
397
                runtime·lock(&paniclk);
 
398
                if(runtime·debug.schedtrace > 0 || runtime·debug.scheddetail > 0)
 
399
                        runtime·schedtrace(true);
 
400
                runtime·freezetheworld();
 
401
                return;
 
402
        case 1:
 
403
                // Something failed while panicing, probably the print of the
 
404
                // argument to panic().  Just print a stack trace and exit.
 
405
                m->dying = 2;
375
406
                runtime·printf("panic during panic\n");
 
407
                runtime·dopanic(0);
376
408
                runtime·exit(3);
 
409
        case 2:
 
410
                // This is a genuine bug in the runtime, we couldn't even
 
411
                // print the stack trace successfully.
 
412
                m->dying = 3;
 
413
                runtime·printf("stack trace unavailable\n");
 
414
                runtime·exit(4);
 
415
        default:
 
416
                // Can't even print!  Just exit.
 
417
                runtime·exit(5);
377
418
        }
378
 
        m->dying = 1;
379
 
        if(g != nil)
380
 
                g->writebuf = nil;
381
 
        runtime·xadd(&runtime·panicking, 1);
382
 
        runtime·lock(&paniclk);
383
 
        if(runtime·debug.schedtrace > 0 || runtime·debug.scheddetail > 0)
384
 
                runtime·schedtrace(true);
385
 
        runtime·freezetheworld();
386
419
}
387
420
 
388
421
void
453
486
        runtime·throw("recursive call during initialization - linker skew");
454
487
}
455
488
 
 
489
bool
 
490
runtime·canpanic(G *gp)
 
491
{
 
492
        byte g;
 
493
 
 
494
        USED(&g);  // don't use global g, it points to gsignal
 
495
 
 
496
        // Is it okay for gp to panic instead of crashing the program?
 
497
        // Yes, as long as it is running Go code, not runtime code,
 
498
        // and not stuck in a system call.
 
499
        if(gp == nil || gp != m->curg)
 
500
                return false;
 
501
        if(m->locks-m->softfloat != 0 || m->mallocing != 0 || m->throwing != 0 || m->gcing != 0 || m->dying != 0)
 
502
                return false;
 
503
        if(gp->status != Grunning || gp->syscallsp != 0)
 
504
                return false;
 
505
#ifdef GOOS_windows
 
506
        if(m->libcallsp != 0)
 
507
                return false;
 
508
#endif
 
509
        return true;
 
510
}
 
511
 
456
512
void
457
513
runtime·throw(int8 *s)
458
514
{
470
526
{
471
527
        Eface err;
472
528
 
 
529
        // m->softfloat is set during software floating point,
 
530
        // which might cause a fault during a memory load.
 
531
        // It increments m->locks to avoid preemption.
 
532
        // If we're panicking, the software floating point frames
 
533
        // will be unwound, so decrement m->locks as they would.
 
534
        if(m->softfloat) {
 
535
                m->locks--;
 
536
                m->softfloat = 0;
 
537
        }
 
538
 
473
539
        if(m->mallocing) {
474
540
                runtime·printf("panic: %s\n", s);
475
541
                runtime·throw("panic during malloc");
478
544
                runtime·printf("panic: %s\n", s);
479
545
                runtime·throw("panic during gc");
480
546
        }
 
547
        if(m->locks) {
 
548
                runtime·printf("panic: %s\n", s);
 
549
                runtime·throw("panic holding locks");
 
550
        }
481
551
        runtime·newErrorCString(s, &err);
482
552
        runtime·panic(err);
483
553
}
488
558
        rundefer();
489
559
        runtime·goexit();
490
560
}
 
561
 
 
562
void
 
563
runtime·panicdivide(void)
 
564
{
 
565
        runtime·panicstring("integer divide by zero");
 
566
}