Commit 918b0f00 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Change PyMem_Malloc to be gc_malloc instead of malloc

I didn't realize that pymem.h defined it originally to be malloc(),
which was messing things up when we would start allocating GC objects
using malloc().

Now that that's redefined, I *think* that as long as everything uses the
API functions, we shouldn't need to override / hook malloc().
There are a number of uses of raw malloc() in the Modules directory;
I hope that they're mostly string-related.
parent 2a66d281
...@@ -51,6 +51,10 @@ extern "C" { ...@@ -51,6 +51,10 @@ extern "C" {
performed on failure (no exception is set, no warning is printed, etc). performed on failure (no exception is set, no warning is printed, etc).
*/ */
PyAPI_FUNC(void *) gc_compat_malloc(size_t);
PyAPI_FUNC(void *) gc_compat_realloc(void *, size_t);
PyAPI_FUNC(void) gc_compat_free(void *);
PyAPI_FUNC(void *) PyMem_Malloc(size_t); PyAPI_FUNC(void *) PyMem_Malloc(size_t);
PyAPI_FUNC(void *) PyMem_Realloc(void *, size_t); PyAPI_FUNC(void *) PyMem_Realloc(void *, size_t);
PyAPI_FUNC(void) PyMem_Free(void *); PyAPI_FUNC(void) PyMem_Free(void *);
...@@ -74,10 +78,10 @@ PyAPI_FUNC(void) PyMem_Free(void *); ...@@ -74,10 +78,10 @@ PyAPI_FUNC(void) PyMem_Free(void *);
/* Returns NULL to indicate error if a negative size or size larger than /* Returns NULL to indicate error if a negative size or size larger than
Py_ssize_t can represent is supplied. Helps prevents security holes. */ Py_ssize_t can represent is supplied. Helps prevents security holes. */
#define PyMem_MALLOC(n) ((size_t)(n) > (size_t)PY_SSIZE_T_MAX ? NULL \ #define PyMem_MALLOC(n) ((size_t)(n) > (size_t)PY_SSIZE_T_MAX ? NULL \
: malloc((n) ? (n) : 1)) : gc_compat_malloc((n) ? (n) : 1))
#define PyMem_REALLOC(p, n) ((size_t)(n) > (size_t)PY_SSIZE_T_MAX ? NULL \ #define PyMem_REALLOC(p, n) ((size_t)(n) > (size_t)PY_SSIZE_T_MAX ? NULL \
: realloc((p), (n) ? (n) : 1)) : gc_compat_realloc((p), (n) ? (n) : 1))
#define PyMem_FREE free #define PyMem_FREE gc_compat_free
#endif /* PYMALLOC_DEBUG */ #endif /* PYMALLOC_DEBUG */
......
...@@ -310,7 +310,7 @@ enum class GCKind : uint8_t { ...@@ -310,7 +310,7 @@ enum class GCKind : uint8_t {
UNTRACKED = 3, UNTRACKED = 3,
}; };
void* gc_alloc(size_t nbytes, GCKind kind); extern "C" void* gc_alloc(size_t nbytes, GCKind kind);
} }
class PythonGCObject { class PythonGCObject {
......
...@@ -68,6 +68,10 @@ static bool isNonheapRoot(void* p) { ...@@ -68,6 +68,10 @@ static bool isNonheapRoot(void* p) {
return p <= max_nonheap_root && nonheap_roots.count(p) != 0; return p <= max_nonheap_root && nonheap_roots.count(p) != 0;
} }
bool isValidGCObject(void* p) {
return isNonheapRoot(p) || (global_heap.getAllocationFromInteriorPointer(p)->user_data == p);
}
static std::unordered_set<GCRootHandle*>* getRootHandles() { static std::unordered_set<GCRootHandle*>* getRootHandles() {
static std::unordered_set<GCRootHandle*> root_handles; static std::unordered_set<GCRootHandle*> root_handles;
return &root_handles; return &root_handles;
......
...@@ -83,6 +83,8 @@ public: ...@@ -83,6 +83,8 @@ public:
}; };
void runCollection(); void runCollection();
bool isValidGCObject(void* p);
} }
} }
......
// Copyright (c) 2014 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "gc/gc_alloc.h"
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <stdint.h>
#include <sys/mman.h>
#include "core/common.h"
#include "core/util.h"
//#undef VERBOSITY
//#define VERBOSITY(x) 2
namespace pyston {
namespace gc {
extern "C" void* gc_compat_malloc(size_t sz) {
return gc_alloc(sz, GCKind::CONSERVATIVE);
}
extern "C" void* gc_compat_realloc(void* ptr, size_t sz) {
if (ptr == NULL)
return gc_alloc(sz, GCKind::CONSERVATIVE);
return gc_realloc(ptr, sz);
}
extern "C" void gc_compat_free(void* ptr) {
gc_free(ptr);
}
// We may need to hook malloc as well:
/*
extern "C" void* malloc(size_t sz) {
abort();
}
extern "C" void free(void* p) {
abort();
}
*/
} // namespace gc
} // namespace pyston
...@@ -27,8 +27,8 @@ ...@@ -27,8 +27,8 @@
namespace pyston { namespace pyston {
namespace gc { namespace gc {
inline void* gc_alloc(size_t bytes, GCKind kind_id) __attribute__((visibility("default"))); extern "C" inline void* gc_alloc(size_t bytes, GCKind kind_id) __attribute__((visibility("default")));
inline void* gc_alloc(size_t bytes, GCKind kind_id) { extern "C" inline void* gc_alloc(size_t bytes, GCKind kind_id) {
bytes += sizeof(GCAllocation); bytes += sizeof(GCAllocation);
#ifndef NVALGRIND #ifndef NVALGRIND
...@@ -68,8 +68,7 @@ inline void* gc_alloc(size_t bytes, GCKind kind_id) { ...@@ -68,8 +68,7 @@ inline void* gc_alloc(size_t bytes, GCKind kind_id) {
#ifndef NDEBUG #ifndef NDEBUG
// I think I have a suspicion: the gc will see the constant and treat it as a // I think I have a suspicion: the gc will see the constant and treat it as a
// root. So instead, shift to hide the pointer // root. So instead, shift to hide the pointer
// if ((((intptr_t)r) >> 4) == (0x127001424L)) { // if ((((intptr_t)r) >> 4) == (0x127014f9f)) {
// if ((((intptr_t)r) >> 4) == (0x127000718L)) {
// raise(SIGTRAP); // raise(SIGTRAP);
//} //}
...@@ -81,8 +80,11 @@ inline void* gc_alloc(size_t bytes, GCKind kind_id) { ...@@ -81,8 +80,11 @@ inline void* gc_alloc(size_t bytes, GCKind kind_id) {
return r; return r;
} }
inline void* gc_realloc(void* ptr, size_t bytes) __attribute__((visibility("default"))); extern "C" inline void* gc_realloc(void* ptr, size_t bytes) __attribute__((visibility("default")));
inline void* gc_realloc(void* ptr, size_t bytes) { extern "C" inline void* gc_realloc(void* ptr, size_t bytes) {
// Normal realloc() supports receiving a NULL pointer, but we need to know what the GCKind is:
assert(ptr);
bytes += sizeof(GCAllocation); bytes += sizeof(GCAllocation);
#ifndef NVALGRIND #ifndef NVALGRIND
...@@ -103,8 +105,9 @@ inline void* gc_realloc(void* ptr, size_t bytes) { ...@@ -103,8 +105,9 @@ inline void* gc_realloc(void* ptr, size_t bytes) {
#endif #endif
} }
inline void gc_free(void* ptr) __attribute__((visibility("default"))); extern "C" inline void gc_free(void* ptr) __attribute__((visibility("default")));
inline void gc_free(void* ptr) { extern "C" inline void gc_free(void* ptr) {
assert(ptr);
#ifndef NVALGRIND #ifndef NVALGRIND
if (ENABLE_REDZONES) { if (ENABLE_REDZONES) {
void* base = (char*)ptr - REDZONE_SIZE; void* base = (char*)ptr - REDZONE_SIZE;
......
...@@ -553,6 +553,7 @@ static const std::string _call_str("__call__"), _new_str("__new__"), _init_str(" ...@@ -553,6 +553,7 @@ static const std::string _call_str("__call__"), _new_str("__new__"), _init_str("
void Box::setattr(const std::string& attr, Box* val, SetattrRewriteArgs* rewrite_args) { void Box::setattr(const std::string& attr, Box* val, SetattrRewriteArgs* rewrite_args) {
assert(cls->instancesHaveAttrs()); assert(cls->instancesHaveAttrs());
assert(gc::isValidGCObject(val));
// Have to guard on the memory layout of this object. // Have to guard on the memory layout of this object.
// Right now, guard on the specific Python-class, which in turn // Right now, guard on the specific Python-class, which in turn
...@@ -1340,6 +1341,8 @@ extern "C" Box* getattr(Box* obj, const char* attr) { ...@@ -1340,6 +1341,8 @@ extern "C" Box* getattr(Box* obj, const char* attr) {
} }
static void setattr_internal(Box* obj, const std::string& attr, Box* val, SetattrRewriteArgs* rewrite_args) { static void setattr_internal(Box* obj, const std::string& attr, Box* val, SetattrRewriteArgs* rewrite_args) {
assert(gc::isValidGCObject(val));
// Lookup a descriptor // Lookup a descriptor
Box* descr = NULL; Box* descr = NULL;
RewriterVarUsage r_descr(RewriterVarUsage::empty()); RewriterVarUsage r_descr(RewriterVarUsage::empty());
......
# skip-if: True # skip-if: True
# This test works but 1) is very slow [the importing is, not the regex itself], and 2) throws warnings # This test works but 1) is very slow [the importing is, not the regex itself], and 2) throws warnings
# This test also seems to leak a lot of memory.
import sre_compile import sre_compile
r = sre_compile.compile("a(b+)c", 0) r = sre_compile.compile("a(b+)c", 0)
print r.match("") print r.match("")
print r.match("ac") print r.match("ac")
print r.match("abc").groups() print r.match("abc").groups()
print r.match("abbc").groups() for i in xrange(100000):
r.match("abbc").groups()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment