]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/cgo: replace C.malloc with our own wrapper
authorRuss Cox <rsc@golang.org>
Wed, 11 Sep 2013 15:30:08 +0000 (11:30 -0400)
committerRuss Cox <rsc@golang.org>
Wed, 11 Sep 2013 15:30:08 +0000 (11:30 -0400)
This allows us to make two changes:

1. Force the argument type to be size_t, even on broken
   systems that declare malloc to take a ulong.

2. Call runtime.throw if malloc fails.
   (That is, the program crashes; it does not panic.)

Fixes #3403.
Fixes #5926.

R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/13413047

src/cmd/cgo/ast.go
src/cmd/cgo/main.go
src/cmd/cgo/out.go
src/pkg/runtime/cgocall.c

index 37c1c8f65c120f62736671327760c0bcff654c8c..7757efa1bc31b13217311a29db73371c90e6aaf8 100644 (file)
@@ -187,6 +187,13 @@ func (f *File) saveRef(x interface{}, context string) {
                                error_(sel.Pos(), "cannot refer to errno directly; see documentation")
                                return
                        }
+                       if goname == "_CMalloc" {
+                               error_(sel.Pos(), "cannot refer to C._CMalloc; use C.malloc")
+                               return
+                       }
+                       if goname == "malloc" {
+                               goname = "_CMalloc"
+                       }
                        name := f.Name[goname]
                        if name == nil {
                                name = &Name{
index 319398907fc5c170d241aa49577a9e04ba4d7790..17b0cdd167019cb2fa2f8f7df040755a6247074c 100644 (file)
@@ -341,7 +341,7 @@ func (p *Package) Record(f *File) {
                        if p.Name[k] == nil {
                                p.Name[k] = v
                        } else if !reflect.DeepEqual(p.Name[k], v) {
-                               error_(token.NoPos, "inconsistent definitions for C.%s", k)
+                               error_(token.NoPos, "inconsistent definitions for C.%s", fixGo(k))
                        }
                }
        }
index 012e0365bb283945d5ac71d7f449240976207c81..efa55a335b3be855863aca7ad705aafa79baad89 100644 (file)
@@ -331,7 +331,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
        }
 
        // Builtins defined in the C prolog.
-       inProlog := name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes"
+       inProlog := name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" || name == "_CMalloc"
 
        if *gccgo {
                // Gccgo style hooks.
@@ -476,9 +476,27 @@ func (p *Package) writeOutput(f *File, srcfile string) {
        fgcc.Close()
 }
 
+// fixGo convers the internal Name.Go field into the name we should show
+// to users in error messages. There's only one for now: on input we rewrite
+// C.malloc into C._CMalloc, so change it back here.
+func fixGo(name string) string {
+       if name == "_CMalloc" {
+               return "malloc"
+       }
+       return name
+}
+
+var isBuiltin = map[string]bool{
+       "_Cfunc_CString":   true,
+       "_Cfunc_GoString":  true,
+       "_Cfunc_GoStringN": true,
+       "_Cfunc_GoBytes":   true,
+       "_Cfunc__CMalloc":  true,
+}
+
 func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
        name := n.Mangle
-       if name == "_Cfunc_CString" || name == "_Cfunc_GoString" || name == "_Cfunc_GoStringN" || name == "_Cfunc_GoBytes" || p.Written[name] {
+       if isBuiltin[name] || p.Written[name] {
                // The builtins are already defined in the C prolog, and we don't
                // want to duplicate function definitions we've already done.
                return
@@ -1101,6 +1119,8 @@ __cgo_size_assert(double, 8)
 `
 
 const builtinProlog = `
+#include <sys/types.h> /* for size_t below */
+
 /* Define intgo when compiling with GCC.  */
 #ifdef __PTRDIFF_TYPE__
 typedef __PTRDIFF_TYPE__ intgo;
@@ -1116,6 +1136,7 @@ _GoString_ GoString(char *p);
 _GoString_ GoStringN(char *p, int l);
 _GoBytes_ GoBytes(void *p, int n);
 char *CString(_GoString_);
+void *_CMalloc(size_t);
 `
 
 const cProlog = `
@@ -1153,6 +1174,13 @@ void
        p[s.len] = 0;
        FLUSH(&p);
 }
+
+void
+·_Cfunc__CMalloc(uintptr n, int8 *p)
+{
+       p = runtime·cmalloc(n);
+       FLUSH(&p);
+}
 `
 
 const cPrologGccgo = `
@@ -1193,6 +1221,14 @@ Slice GoBytes(char *p, int32_t n) {
        struct __go_string s = { (const unsigned char *)p, n };
        return __go_string_to_byte_array(s);
 }
+
+extern void runtime_throw(const char *):
+void *Cmalloc(size_t n) {
+        void *p = malloc(n);
+        if(p == NULL)
+                runtime_throw("runtime: C malloc failed");
+        return p;
+}
 `
 
 func (p *Package) gccExportHeaderProlog() string {
index 611ddf0e9e35256eb13cd64202bab1c6c3c5bc80..2a04453fdca6d5f02099193dd6e3c0765da5e2b9 100644 (file)
@@ -198,6 +198,8 @@ runtime·cmalloc(uintptr n)
        a.n = n;
        a.ret = nil;
        runtime·cgocall(_cgo_malloc, &a);
+       if(a.ret == nil)
+               runtime·throw("runtime: C malloc failed");
        return a.ret;
 }