Stop using real pointers as handles in makemsi.c.
Upgrading to Ubuntu 18.04, which seems to have become more prone to allocating process memory above the 4G boundary, has revealed that the client code of the phony msi.dll functions is not in fact prepared to accept arbitrary machine-word sized pointer values. It's expecting 32-bit handles, so we were segfaulting because MsiDatabaseImportW was only being given the bottom 32 bits of the 64-bit pointer that MsiOpenDatabaseW had returned. So now I just keep a trivial registry of small integer handle values and the pointers they map to. I don't even bother to recycle them - the process isn't expected to run for long enough for me to care.
This commit is contained in:
parent
66f1f5d2bf
commit
1c1c3850e8
1 changed files with 81 additions and 22 deletions
103
makemsi.c
103
makemsi.c
|
@ -41,10 +41,54 @@ typedef struct MsiMainCtx {
|
|||
int nargs, argsize;
|
||||
} MsiMainCtx;
|
||||
|
||||
/*
|
||||
* The Msi functions will expect to identify things by 32-bit handles,
|
||||
* not machine-word sized pointers. So we must keep a list of handles
|
||||
* we've allocated.
|
||||
*/
|
||||
typedef uint32_t MsiHandle;
|
||||
static void **msi_handles = NULL;
|
||||
static size_t n_msi_handles = 0, msi_handles_size = 0;
|
||||
|
||||
static MsiHandle make_handle(void *ptr)
|
||||
{
|
||||
size_t index;
|
||||
|
||||
if (n_msi_handles >= msi_handles_size) {
|
||||
msi_handles_size = n_msi_handles * 5 / 4 + 512;
|
||||
msi_handles = sresize(msi_handles, msi_handles_size, void *);
|
||||
}
|
||||
|
||||
index = n_msi_handles++;
|
||||
msi_handles[index] = ptr;
|
||||
|
||||
/*
|
||||
* A mild error-correcting code, to ensure our handles make sense.
|
||||
*/
|
||||
return index * 59 + 17;
|
||||
}
|
||||
|
||||
static void *lookup_handle(MsiHandle h)
|
||||
{
|
||||
size_t index;
|
||||
|
||||
assert(h % 59 == 17);
|
||||
index = h / 59;
|
||||
|
||||
assert(index < n_msi_handles);
|
||||
return msi_handles[index];
|
||||
}
|
||||
|
||||
static MsiMainCtx *lookup_handle_main(MsiHandle handle)
|
||||
{
|
||||
MsiMainCtx *toret = lookup_handle(handle);
|
||||
assert(toret->t.type == MAIN);
|
||||
return toret;
|
||||
}
|
||||
|
||||
uint32_t MsiOpenDatabaseW(const char16_t *filename,
|
||||
const char16_t *persist,
|
||||
MsiMainCtx **out_ctx)
|
||||
MsiHandle *out_handle)
|
||||
{
|
||||
MsiMainCtx *ctx = snew(MsiMainCtx);
|
||||
ctx->t.type = MAIN;
|
||||
|
@ -64,14 +108,14 @@ uint32_t MsiOpenDatabaseW(const char16_t *filename,
|
|||
ctx->args[ctx->nargs++] = dupstr(ctx->tempdir);
|
||||
ctx->args[ctx->nargs++] = dupstr("msibuild");
|
||||
ctx->args[ctx->nargs++] = dupstr(ctx->outfile);
|
||||
*out_ctx = ctx;
|
||||
*out_handle = make_handle(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t MsiDatabaseImportW(MsiMainCtx *ctx, const char16_t *folder,
|
||||
uint32_t MsiDatabaseImportW(MsiHandle handle, const char16_t *folder,
|
||||
const char16_t *file)
|
||||
{
|
||||
assert(ctx->t.type == MAIN);
|
||||
MsiMainCtx *ctx = lookup_handle_main(handle);
|
||||
system_argv("sh", "-c", "cd \"$0\" && cp \"$1\" \"$2\"",
|
||||
ascii(folder, true), ascii(file, true), ctx->tempdir, cNULL);
|
||||
if (ctx->nargs + 2 >= ctx->argsize) {
|
||||
|
@ -92,10 +136,17 @@ typedef struct MsiView {
|
|||
MsiMainCtx *ctx;
|
||||
} MsiView;
|
||||
|
||||
uint32_t MsiDatabaseOpenViewW(MsiMainCtx *ctx, const char16_t *query,
|
||||
MsiView **outview)
|
||||
static MsiView *lookup_handle_view(MsiHandle handle)
|
||||
{
|
||||
assert(ctx->t.type == MAIN);
|
||||
MsiView *toret = lookup_handle(handle);
|
||||
assert(toret->t.type == VIEW);
|
||||
return toret;
|
||||
}
|
||||
|
||||
uint32_t MsiDatabaseOpenViewW(MsiHandle handle, const char16_t *query,
|
||||
MsiHandle *outhandle)
|
||||
{
|
||||
MsiMainCtx *ctx = lookup_handle_main(handle);
|
||||
MsiView *view = snew(MsiView);
|
||||
view->t.type = VIEW;
|
||||
view->ctx = ctx;
|
||||
|
@ -118,13 +169,13 @@ uint32_t MsiDatabaseOpenViewW(MsiMainCtx *ctx, const char16_t *query,
|
|||
if (mkdir(view->targetdir, 0777) < 0)
|
||||
err(1, "%s: mkdir", view->targetdir);
|
||||
}
|
||||
*outview = view;
|
||||
*outhandle = make_handle(view);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t MsiViewExecute(MsiView *view, void *params)
|
||||
uint32_t MsiViewExecute(MsiHandle handle, void *params)
|
||||
{
|
||||
assert(view->t.type == VIEW);
|
||||
lookup_handle_view(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -134,7 +185,14 @@ typedef struct MsiRecord {
|
|||
char *name, *data;
|
||||
} MsiRecord;
|
||||
|
||||
MsiRecord *MsiCreateRecord(uint32_t nparams)
|
||||
static MsiRecord *lookup_handle_record(MsiHandle handle)
|
||||
{
|
||||
MsiRecord *toret = lookup_handle(handle);
|
||||
assert(toret->t.type == RECORD);
|
||||
return toret;
|
||||
}
|
||||
|
||||
MsiHandle MsiCreateRecord(uint32_t nparams)
|
||||
{
|
||||
MsiRecord *rec = snew(MsiRecord);
|
||||
rec->t.type = RECORD;
|
||||
|
@ -142,31 +200,31 @@ MsiRecord *MsiCreateRecord(uint32_t nparams)
|
|||
if (nparams != 2)
|
||||
errx(1, "bad MsiCreateRecord param count %u", (unsigned)nparams);
|
||||
rec->name = rec->data = NULL;
|
||||
return rec;
|
||||
return make_handle(rec);
|
||||
}
|
||||
|
||||
uint32_t MsiRecordSetStringW(MsiRecord *rec, uint32_t field, char16_t *value)
|
||||
uint32_t MsiRecordSetStringW(MsiHandle handle, uint32_t field, char16_t *value)
|
||||
{
|
||||
assert(rec->t.type == RECORD);
|
||||
MsiRecord *rec = lookup_handle_record(handle);
|
||||
if (field != 1)
|
||||
errx(1, "bad MsiRecordSetString param index %u", (unsigned)field);
|
||||
rec->name = ascii(value, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t MsiRecordSetStreamW(MsiRecord *rec, uint32_t field, char16_t *path)
|
||||
uint32_t MsiRecordSetStreamW(MsiHandle handle, uint32_t field, char16_t *path)
|
||||
{
|
||||
assert(rec->t.type == RECORD);
|
||||
MsiRecord *rec = lookup_handle_record(handle);
|
||||
if (field != 2)
|
||||
errx(1, "bad MsiRecordSetStream param index %u", (unsigned)field);
|
||||
rec->data = ascii(path, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t MsiViewModify(MsiView *view, uint32_t mode, MsiRecord *rec)
|
||||
uint32_t MsiViewModify(MsiHandle viewhandle, uint32_t mode, MsiHandle rechandle)
|
||||
{
|
||||
assert(view->t.type == VIEW);
|
||||
assert(rec->t.type == RECORD);
|
||||
MsiView *view = lookup_handle_view(viewhandle);
|
||||
MsiRecord *rec = lookup_handle_record(rechandle);
|
||||
if (view->fp) {
|
||||
system_argv("sh", "-c", "cp \"$0\" \"$1\"/\"$2\"",
|
||||
rec->data, view->targetdir, rec->name, cNULL);
|
||||
|
@ -184,8 +242,9 @@ uint32_t MsiViewModify(MsiView *view, uint32_t mode, MsiRecord *rec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
uint32_t MsiCloseHandle(MsiTypePrefix *t)
|
||||
uint32_t MsiCloseHandle(MsiHandle handle)
|
||||
{
|
||||
MsiTypePrefix *t = lookup_handle(handle);
|
||||
if (t->type == VIEW) {
|
||||
MsiView *view = (MsiView *)t;
|
||||
if (view->fp)
|
||||
|
@ -194,9 +253,9 @@ uint32_t MsiCloseHandle(MsiTypePrefix *t)
|
|||
return 0;
|
||||
}
|
||||
|
||||
uint32_t MsiDatabaseCommit(MsiMainCtx *ctx)
|
||||
uint32_t MsiDatabaseCommit(MsiHandle handle)
|
||||
{
|
||||
assert(ctx->t.type == MAIN);
|
||||
MsiMainCtx *ctx = lookup_handle_main(handle);
|
||||
printf("commit:");
|
||||
for (int i = 0; i < ctx->nargs; i++) {
|
||||
printf(" '");
|
||||
|
|
Loading…
Add table
Reference in a new issue