Skip to content

Commit 896b1a6

Browse files
committed
add Cstring/Cwstring types for safe passing of NUL-terminated strings to ccall (see JuliaLang#10958, JuliaLang#10991)
1 parent 4ff969f commit 896b1a6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+275
-200
lines changed

NEWS.md

+10-5
Original file line numberDiff line numberDiff line change
@@ -148,16 +148,20 @@ Library improvements
148148

149149
* `Givens` type doesn't have a size anymore and is no longer a subtype of `AbstractMatrix` ([#8660]).
150150

151-
* Large speedup in sparse ``\`` and splitting of Cholesky and LDLᵀ factorizations into ``cholfact`` and ``ldltfact`` ([#10117]).
151+
* Large speedup in sparse `\` and splitting of Cholesky and LDLᵀ factorizations into `cholfact` and `ldltfact` ([#10117]).
152152

153-
* Add sparse least squares to ``\`` by adding ``qrfact`` for sparse matrices based on the SPQR library. ([#10180])
153+
* Add sparse least squares to `\` by adding `qrfact` for sparse matrices based on the SPQR library. ([#10180])
154154

155155
* Split `Triangular` type into `UpperTriangular`, `LowerTriangular`, `UnitUpperTriagular` and `UnitLowerTriangular` ([#9779])
156156

157157
* OpenBLAS 64-bit (ILP64) interface is now compiled with a `64_` suffix ([#8734]) to avoid conflicts with external libraries using a 32-bit BLAS ([#4923]).
158158

159159
* Strings
160160

161+
* NUL-terminated strings should now be passed to C via the new `Cstring` type, not `Ptr{UInt8}` or `Ptr{Cchar}`,
162+
in order to check whether the string is free of NUL characters (which would cause silent truncation in C).
163+
The analogous type `Cwstring` should be used for NUL-terminated `wchar_t*` strings ([#10994]).
164+
161165
* `graphemes(s)` returns an iterator over grapheme substrings of `s` ([#9261]).
162166

163167
* Character predicates such as `islower()`, `isspace()`, etc. use
@@ -1380,11 +1384,12 @@ Too numerous to mention.
13801384
[#10659]: https://github.com/JuliaLang/julia/issues/10659
13811385
[#10679]: https://github.com/JuliaLang/julia/issues/10679
13821386
[#10709]: https://github.com/JuliaLang/julia/issues/10709
1383-
[#10714]: https://github.com/JuliaLang/julia/pull/10714
1387+
[#10714]: https://github.com/JuliaLang/julia/issues/10714
13841388
[#10747]: https://github.com/JuliaLang/julia/issues/10747
13851389
[#10844]: https://github.com/JuliaLang/julia/issues/10844
13861390
[#10870]: https://github.com/JuliaLang/julia/issues/10870
13871391
[#10885]: https://github.com/JuliaLang/julia/issues/10885
1388-
[#10888]: https://github.com/JuliaLang/julia/pull/10888
1389-
[#10893]: https://github.com/JuliaLang/julia/pull/10893
1392+
[#10888]: https://github.com/JuliaLang/julia/issues/10888
1393+
[#10893]: https://github.com/JuliaLang/julia/issues/10893
13901394
[#10914]: https://github.com/JuliaLang/julia/issues/10914
1395+
[#10994]: https://github.com/JuliaLang/julia/issues/10994

base/c.jl

+31-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# definitions related to C interface
22

3-
import Core.Intrinsics.cglobal
3+
import Core.Intrinsics: cglobal, box, unbox
44

55
cfunction(f::Function, r, a) = ccall(:jl_function_ptr, Ptr{Void}, (Any, Any, Any), f, r, a)
66

@@ -43,6 +43,34 @@ end
4343

4444
typealias Coff_t FileOffset
4545

46+
# C NUL-terminated string pointers; these can be used in ccall
47+
# instead of Ptr{Cchar} and Ptr{Cwchar_t}, respectively, to enforce
48+
# a check for embedded NUL chars in the string (to avoid silent truncation).
49+
if Int === Int64
50+
bitstype 64 Cstring
51+
bitstype 64 Cwstring
52+
else
53+
bitstype 32 Cstring
54+
bitstype 32 Cwstring
55+
end
56+
57+
convert{T<:Union(Int8,UInt8)}(::Type{Cstring}, p::Ptr{T}) = box(Cstring, unbox(Ptr{T}, p))
58+
convert(::Type{Cwstring}, p::Ptr{Cwchar_t}) = box(Cwstring, unbox(Ptr{Cwchar_t}, p))
59+
60+
containsnul(p::Ptr, len) = C_NULL != ccall(:memchr, Ptr{Cchar}, (Ptr{Cchar}, Cint, Csize_t), p, 0, len)
61+
function unsafe_convert(::Type{Cstring}, s::ByteString)
62+
p = unsafe_convert(Ptr{Cchar}, s)
63+
if containsnul(p, sizeof(s))
64+
throw(ArgumentError("embedded NUL chars are not allowed in C strings"))
65+
end
66+
return Cstring(p)
67+
end
68+
69+
# symbols are guaranteed not to contain embedded NUL
70+
convert(::Type{Cstring}, s::Symbol) = Cstring(unsafe_convert(Ptr{Cchar}, s))
71+
72+
# in string.jl: unsafe_convert(::Type{Cwstring}, s::WString)
73+
4674
# deferring (or un-deferring) ctrl-c handler for external C code that
4775
# is not interrupt safe (see also issue #2622). The sigatomic_begin/end
4876
# functions should always be called in matched pairs, ideally via:
@@ -56,11 +84,11 @@ disable_sigint(f::Function) = try sigatomic_begin(); f(); finally sigatomic_end(
5684
reenable_sigint(f::Function) = try sigatomic_end(); f(); finally sigatomic_begin(); end
5785

5886
function ccallable(f::Function, rt::Type, argt::Type, name::Union(AbstractString,Symbol)=string(f))
59-
ccall(:jl_extern_c, Void, (Any, Any, Any, Ptr{UInt8}), f, rt, argt, name)
87+
ccall(:jl_extern_c, Void, (Any, Any, Any, Cstring), f, rt, argt, name)
6088
end
6189

6290
function ccallable(f::Function, argt::Type, name::Union(AbstractString,Symbol)=string(f))
63-
ccall(:jl_extern_c, Void, (Any, Ptr{Void}, Any, Ptr{UInt8}), f, C_NULL, argt, name)
91+
ccall(:jl_extern_c, Void, (Any, Ptr{Void}, Any, Cstring), f, C_NULL, argt, name)
6492
end
6593

6694
macro ccallable(def)

base/client.jl

+5-5
Original file line numberDiff line numberDiff line change
@@ -150,18 +150,18 @@ function syntax_deprecation_warnings(f::Function, warn::Bool)
150150
end
151151
end
152152

153-
function parse_input_line(s::AbstractString)
154-
# s = bytestring(s)
153+
function parse_input_line(s::ByteString)
155154
# (expr, pos) = parse(s, 1)
156155
# (ex, pos) = ccall(:jl_parse_string, Any,
157-
# (Ptr{UInt8},Int32,Int32),
158-
# s, pos-1, 1)
156+
# (Ptr{UInt8},Csize_t,Int32,Int32),
157+
# s, sizeof(s), pos-1, 1)
159158
# if !is(ex,())
160159
# throw(ParseError("extra input after end of expression"))
161160
# end
162161
# expr
163-
ccall(:jl_parse_input_line, Any, (Ptr{UInt8},), s)
162+
ccall(:jl_parse_input_line, Any, (Ptr{UInt8}, Csize_t), s, sizeof(s))
164163
end
164+
parse_input_line(s::AbstractString) = parse_input_line(bytestring(s))
165165

166166
function parse_input_line(io::IO)
167167
s = ""

base/datafmt.jl

+5-5
Original file line numberDiff line numberDiff line change
@@ -334,13 +334,13 @@ function colval{T<:Integer, S<:ByteString}(sbuff::S, startpos::Int, endpos::Int,
334334
isnull(n) || (cells[row,col] = get(n))
335335
isnull(n)
336336
end
337-
function colval{S<:ByteString}(sbuff::S, startpos::Int, endpos::Int, cells::Array{Float64,2}, row::Int, col::Int)
338-
n = ccall(:jl_try_substrtod, Nullable{Float64}, (Ptr{UInt8},Csize_t,Cint), sbuff, startpos-1, endpos-startpos+1)
337+
function colval(sbuff::ByteString, startpos::Int, endpos::Int, cells::Array{Float64,2}, row::Int, col::Int)
338+
n = ccall(:jl_try_substrtod, Nullable{Float64}, (Ptr{UInt8},Csize_t,Csize_t), sbuff, startpos-1, endpos-startpos+1)
339339
isnull(n) || (cells[row,col] = get(n))
340340
isnull(n)
341341
end
342-
function colval{S<:ByteString}(sbuff::S, startpos::Int, endpos::Int, cells::Array{Float32,2}, row::Int, col::Int)
343-
n = ccall(:jl_try_substrtof, Nullable{Float32}, (Ptr{UInt8},Csize_t,Cint), sbuff, startpos-1, endpos-startpos+1)
342+
function colval(sbuff::ByteString, startpos::Int, endpos::Int, cells::Array{Float32,2}, row::Int, col::Int)
343+
n = ccall(:jl_try_substrtof, Nullable{Float32}, (Ptr{UInt8},Csize_t,Csize_t), sbuff, startpos-1, endpos-startpos+1)
344344
isnull(n) || (cells[row,col] = get(n))
345345
isnull(n)
346346
end
@@ -358,7 +358,7 @@ function colval{S<:ByteString}(sbuff::S, startpos::Int, endpos::Int, cells::Arra
358358
isnull(nb) || (cells[row,col] = get(nb); return false)
359359

360360
# check float64
361-
nf64 = ccall(:jl_try_substrtod, Nullable{Float64}, (Ptr{UInt8},Csize_t,Cint), sbuff, startpos-1, endpos-startpos+1)
361+
nf64 = ccall(:jl_try_substrtod, Nullable{Float64}, (Ptr{UInt8},Csize_t,Csize_t), sbuff, startpos-1, endpos-startpos+1)
362362
isnull(nf64) || (cells[row,col] = get(nf64); return false)
363363
end
364364
cells[row,col] = SubString(sbuff, startpos, endpos)

base/env.jl

+8-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
@unix_only begin
2-
_getenv(var::AbstractString) = ccall(:getenv, Ptr{UInt8}, (Ptr{UInt8},), var)
2+
_getenv(var::AbstractString) = ccall(:getenv, Ptr{UInt8}, (Cstring,), var)
33
_hasenv(s::AbstractString) = _getenv(s) != C_NULL
44
end
55
@windows_only begin
@@ -24,12 +24,11 @@ function FormatMessage(e=GetLastError())
2424
return utf8(UTF16String(buf))
2525
end
2626

27-
_getenvlen(var::UTF16String) = ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Ptr{UInt16},Ptr{UInt8},UInt32),utf16(var),C_NULL,0)
28-
_hasenv(s::UTF16String) = _getenvlen(s)!=0 || GetLastError()!=ERROR_ENVVAR_NOT_FOUND
29-
_hasenv(s::AbstractString) = _hasenv(utf16(s))
27+
_getenvlen(var::AbstractString) = ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Cwstring,Ptr{UInt8},UInt32),var,C_NULL,0)
28+
_hasenv(s::AbstractString) = _getenvlen(s)!=0 || GetLastError()!=ERROR_ENVVAR_NOT_FOUND
3029
function _jl_win_getenv(s::UTF16String,len::UInt32)
3130
val=zeros(UInt16,len)
32-
ret=ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Ptr{UInt16},Ptr{UInt16},UInt32),s,val,len)
31+
ret=ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Cwstring,Ptr{UInt16},UInt32),s,val,len)
3332
if ret==0 || ret != len-1 || val[end] != 0
3433
error(string("getenv: ", s, ' ', len, "-1 != ", ret, ": ", FormatMessage()))
3534
end
@@ -62,13 +61,13 @@ end
6261

6362
function _setenv(var::AbstractString, val::AbstractString, overwrite::Bool)
6463
@unix_only begin
65-
ret = ccall(:setenv, Int32, (Ptr{UInt8},Ptr{UInt8},Int32), var, val, overwrite)
64+
ret = ccall(:setenv, Int32, (Cstring,Cstring,Int32), var, val, overwrite)
6665
systemerror(:setenv, ret != 0)
6766
end
6867
@windows_only begin
6968
var = utf16(var)
7069
if overwrite || !_hasenv(var)
71-
ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Ptr{UInt16},Ptr{UInt16}),utf16(var),utf16(val))
70+
ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Cwstring,Cwstring),var,val)
7271
systemerror(:setenv, ret == 0)
7372
end
7473
end
@@ -78,11 +77,11 @@ _setenv(var::AbstractString, val::AbstractString) = _setenv(var, val, true)
7877

7978
function _unsetenv(var::AbstractString)
8079
@unix_only begin
81-
ret = ccall(:unsetenv, Int32, (Ptr{UInt8},), var)
80+
ret = ccall(:unsetenv, Int32, (Cstring,), var)
8281
systemerror(:unsetenv, ret != 0)
8382
end
8483
@windows_only begin
85-
ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Ptr{UInt16},Ptr{UInt16}),utf16(var),C_NULL)
84+
ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Cwstring,Ptr{UInt16}),var,C_NULL)
8685
systemerror(:setenv, ret == 0)
8786
end
8887
end

base/exports.jl

+2
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ export
144144
Culonglong,
145145
Cushort,
146146
Cwchar_t,
147+
Cstring,
148+
Cwstring,
147149

148150
# Exceptions
149151
ArgumentError,

base/fftw.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ typealias fftwTypeSingle Union(Type{Float32},Type{Complex64})
7171
# FFTW's api/import-wisdom-from-file.c file].
7272

7373
function export_wisdom(fname::AbstractString)
74-
f = ccall(:fopen, Ptr{Void}, (Ptr{UInt8},Ptr{UInt8}), fname, "w")
74+
f = ccall(:fopen, Ptr{Void}, (Cstring,Ptr{UInt8}), fname, "w")
7575
systemerror("could not open wisdom file $fname for writing", f == C_NULL)
7676
ccall((:fftw_export_wisdom_to_file,libfftw), Void, (Ptr{Void},), f)
7777
ccall(:fputs, Int32, (Ptr{UInt8},Ptr{Void}), " "^256, f)
@@ -80,7 +80,7 @@ function export_wisdom(fname::AbstractString)
8080
end
8181

8282
function import_wisdom(fname::AbstractString)
83-
f = ccall(:fopen, Ptr{Void}, (Ptr{UInt8},Ptr{UInt8}), fname, "r")
83+
f = ccall(:fopen, Ptr{Void}, (Cstring,Ptr{UInt8}), fname, "r")
8484
systemerror("could not open wisdom file $fname for reading", f == C_NULL)
8585
if ccall((:fftw_import_wisdom_from_file,libfftw),Int32,(Ptr{Void},),f)==0||
8686
ccall((:fftwf_import_wisdom_from_file,libfftwf),Int32,(Ptr{Void},),f)==0

base/file.jl

+7-8
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ function pwd()
88
end
99

1010
function cd(dir::AbstractString)
11-
uv_error("chdir $dir", ccall(:uv_chdir, Cint, (Ptr{UInt8},), dir))
11+
uv_error("chdir $dir", ccall(:uv_chdir, Cint, (Cstring,), dir))
1212
end
1313
cd() = cd(homedir())
1414

@@ -35,8 +35,8 @@ end
3535
cd(f::Function) = cd(f, homedir())
3636

3737
function mkdir(path::AbstractString, mode::Unsigned=0o777)
38-
@unix_only ret = ccall(:mkdir, Int32, (Ptr{UInt8},UInt32), path, mode)
39-
@windows_only ret = ccall(:_wmkdir, Int32, (Ptr{UInt16},), utf16(path))
38+
@unix_only ret = ccall(:mkdir, Int32, (Cstring,UInt32), path, mode)
39+
@windows_only ret = ccall(:_wmkdir, Int32, (Cwstring,), path)
4040
systemerror(:mkdir, ret != 0)
4141
end
4242

@@ -61,8 +61,8 @@ function rm(path::AbstractString; recursive::Bool=false)
6161
rm(joinpath(path, p), recursive=true)
6262
end
6363
end
64-
@unix_only ret = ccall(:rmdir, Int32, (Ptr{UInt8},), path)
65-
@windows_only ret = ccall(:_wrmdir, Int32, (Ptr{UInt16},), utf16(path))
64+
@unix_only ret = ccall(:rmdir, Int32, (Cstring,), path)
65+
@windows_only ret = ccall(:_wrmdir, Int32, (Cwstring,), path)
6666
systemerror(:rmdir, ret != 0)
6767
end
6868
end
@@ -168,8 +168,7 @@ end
168168
tempname(uunique::UInt32=UInt32(0)) = tempname(tempdir(), uunique)
169169
function tempname(temppath::AbstractString,uunique::UInt32)
170170
tname = Array(UInt16,32767)
171-
uunique = ccall(:GetTempFileNameW,stdcall,UInt32,(Ptr{UInt16},Ptr{UInt16},UInt32,Ptr{UInt16}),
172-
utf16(temppath),utf16("jul"),uunique,tname)
171+
uunique = ccall(:GetTempFileNameW,stdcall,UInt32,(Cwstring,Ptr{UInt16},UInt32,Ptr{UInt16}), temppath,utf16("jul"),uunique,tname)
173172
lentname = findfirst(tname,0)-1
174173
if uunique == 0 || lentname <= 0
175174
error("GetTempFileName failed: $(FormatMessage())")
@@ -223,7 +222,7 @@ function readdir(path::AbstractString)
223222
uv_readdir_req = zeros(UInt8, ccall(:jl_sizeof_uv_fs_t, Int32, ()))
224223

225224
# defined in sys.c, to call uv_fs_readdir, which sets errno on error.
226-
file_count = ccall(:jl_readdir, Int32, (Ptr{UInt8}, Ptr{UInt8}),
225+
file_count = ccall(:jl_readdir, Int32, (Cstring, Ptr{UInt8}),
227226
path, uv_readdir_req)
228227
systemerror("unable to read directory $path", file_count < 0)
229228

base/fs.jl

+6-6
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ _uv_fs_result(req) = ccall(:jl_uv_fs_result,Int32,(Ptr{Void},),req)
7272

7373
function open(f::File,flags::Integer,mode::Integer=0)
7474
req = Libc.malloc(_sizeof_uv_fs)
75-
ret = ccall(:uv_fs_open,Int32,(Ptr{Void},Ptr{Void},Ptr{UInt8},Int32,Int32,Ptr{Void}),
75+
ret = ccall(:uv_fs_open,Int32,(Ptr{Void},Ptr{Void},Cstring,Int32,Int32,Ptr{Void}),
7676
eventloop(), req, f.path, flags,mode, C_NULL)
7777
f.handle = _uv_fs_result(req)
7878
ccall(:uv_fs_req_cleanup,Void,(Ptr{Void},),req)
@@ -96,7 +96,7 @@ function close(f::File)
9696
end
9797

9898
function unlink(p::AbstractString)
99-
err = ccall(:jl_fs_unlink, Int32, (Ptr{UInt8},), p)
99+
err = ccall(:jl_fs_unlink, Int32, (Cstring,), p)
100100
uv_error("unlink",err)
101101
end
102102
function unlink(f::File)
@@ -112,7 +112,7 @@ end
112112

113113
# For move command
114114
function rename(src::AbstractString, dst::AbstractString)
115-
err = ccall(:jl_fs_rename, Int32, (Ptr{UInt8}, Ptr{UInt8}), src, dst)
115+
err = ccall(:jl_fs_rename, Int32, (Cstring, Cstring), src, dst)
116116

117117
# on error, default to cp && rm
118118
if err < 0
@@ -159,7 +159,7 @@ end
159159
@non_windowsxp_only function symlink(p::AbstractString, np::AbstractString)
160160
flags = 0
161161
@windows_only if isdir(p); flags |= UV_FS_SYMLINK_JUNCTION; p = abspath(p); end
162-
err = ccall(:jl_fs_symlink, Int32, (Ptr{UInt8}, Ptr{UInt8}, Cint), p, np, flags)
162+
err = ccall(:jl_fs_symlink, Int32, (Cstring, Cstring, Cint), p, np, flags)
163163
@windows_only if err < 0
164164
Base.warn_once("Note: on Windows, creating file symlinks requires Administrator privileges.")
165165
end
@@ -171,7 +171,7 @@ end
171171
function readlink(path::AbstractString)
172172
req = Libc.malloc(_sizeof_uv_fs)
173173
ret = ccall(:uv_fs_readlink, Int32,
174-
(Ptr{Void}, Ptr{Void}, Ptr{UInt8}, Ptr{Void}),
174+
(Ptr{Void}, Ptr{Void}, Cstring, Ptr{Void}),
175175
eventloop(), req, path, C_NULL)
176176
uv_error("readlink", ret)
177177
tgt = bytestring(ccall(:jl_uv_fs_t_ptr, Ptr{Cchar}, (Ptr{Void}, ), req))
@@ -181,7 +181,7 @@ function readlink(path::AbstractString)
181181
end
182182

183183
function chmod(p::AbstractString, mode::Integer)
184-
err = ccall(:jl_fs_chmod, Int32, (Ptr{UInt8}, Cint), p, mode)
184+
err = ccall(:jl_fs_chmod, Int32, (Cstring, Cint), p, mode)
185185
uv_error("chmod",err)
186186
end
187187

base/gmp.jl

+14-6
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,25 @@ BigInt(x::BigInt) = x
7777

7878
function tryparse_internal(::Type{BigInt}, s::AbstractString, startpos::Int, endpos::Int, base::Int, raise::Bool)
7979
_n = Nullable{BigInt}()
80-
sgn, base, i = Base.parseint_preamble(true,base,s,startpos,endpos)
80+
81+
# don't make a copy in the common case where we are parsing a whole bytestring
82+
bstr = startpos == start(s) && endpos == endof(s) ? bytestring(s) : bytestring(SubString(s,i,endpos))
83+
84+
sgn, base, i = Base.parseint_preamble(true,base,bstr,start(bstr),endof(bstr))
8185
if i == 0
82-
raise && throw(ArgumentError("premature end of integer: $(repr(s))"))
86+
raise && throw(ArgumentError("premature end of integer: $(repr(bstr))"))
8387
return _n
8488
end
8589
z = BigInt()
86-
err = ccall((:__gmpz_set_str, :libgmp),
87-
Int32, (Ptr{BigInt}, Ptr{UInt8}, Int32),
88-
&z, SubString(s,i,endpos), base)
90+
if Base.containsnul(bstr)
91+
err = -1 # embedded NUL char (not handled correctly by GMP)
92+
else
93+
err = ccall((:__gmpz_set_str, :libgmp),
94+
Int32, (Ptr{BigInt}, Ptr{UInt8}, Int32),
95+
&z, pointer(bstr)+(i-start(bstr)), base)
96+
end
8997
if err != 0
90-
raise && throw(ArgumentError("invalid BigInt: $(repr(s))"))
98+
raise && throw(ArgumentError("invalid BigInt: $(repr(bstr))"))
9199
return _n
92100
end
93101
Nullable(sgn < 0 ? -z : z)

base/interactiveutil.jl

+4-1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ end
107107

108108
@windows_only begin # TODO: these functions leak memory and memory locks if they throw an error
109109
function clipboard(x::AbstractString)
110+
if containsnul(x)
111+
throw(ArgumentError("Windows clipboard strings cannot contain NUL character"))
112+
end
110113
systemerror(:OpenClipboard, 0==ccall((:OpenClipboard, "user32"), stdcall, Cint, (Ptr{Void},), C_NULL))
111114
systemerror(:EmptyClipboard, 0==ccall((:EmptyClipboard, "user32"), stdcall, Cint, ()))
112115
x_u16 = utf16(x)
@@ -355,7 +358,7 @@ end
355358

356359
@windows_only function download(url::AbstractString, filename::AbstractString)
357360
res = ccall((:URLDownloadToFileW,:urlmon),stdcall,Cuint,
358-
(Ptr{Void},Ptr{UInt16},Ptr{UInt16},Cint,Ptr{Void}),0,utf16(url),utf16(filename),0,0)
361+
(Ptr{Void},Cwstring,Cwstring,Cint,Ptr{Void}),C_NULL,url,filename,0,0)
359362
if res != 0
360363
error("automatic download failed (error: $res): $url")
361364
end

base/iostream.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ function open(fname::AbstractString, rd::Bool, wr::Bool, cr::Bool, tr::Bool, ff:
8686
s = IOStream(string("<file ",fname,">"))
8787
systemerror("opening file $fname",
8888
ccall(:ios_file, Ptr{Void},
89-
(Ptr{UInt8}, Ptr{UInt8}, Int32, Int32, Int32, Int32),
89+
(Ptr{UInt8}, Cstring, Int32, Int32, Int32, Int32),
9090
s.ios, fname, rd, wr, cr, tr) == C_NULL)
9191
if ff
9292
systemerror("seeking to end of file $fname", ccall(:ios_seek_end, FileOffset, (Ptr{Void},), s.ios) != 0)

0 commit comments

Comments
 (0)