Skip to content

Commit

Permalink
Handle passing null for unboxed arguments of extern methods (#2950)
Browse files Browse the repository at this point in the history
* Reproduce issue #2866

* Remove redundant build settings

* clenup
  • Loading branch information
WojciechMazur committed Oct 29, 2022
1 parent 4872c8b commit 688c0ff
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 8 deletions.
Expand Up @@ -2443,7 +2443,21 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] =>
argsp.zip(sym.tpe.params).foreach {
case (argp, paramSym) =>
val externType = genExternType(paramSym.tpe)
res += toExtern(externType, genExpr(argp))(argp.pos)
val arg = (genExpr(argp), Type.box.get(externType)) match {
case (value @ Val.Null, Some(unboxedType)) =>
externType match {
case Type.Ptr | _: Type.RefKind => value
case _ =>
reporter.warning(
argp.pos,
s"Passing null as argument of ${paramSym}: ${paramSym.tpe} to the extern method is unsafe. " +
s"The argument would be unboxed to primitive value of type $externType."
)
Val.Zero(unboxedType)
}
case (value, _) => value
}
res += toExtern(externType, arg)(argp.pos)
}

res.result()
Expand Down
Expand Up @@ -1460,7 +1460,21 @@ trait NirGenExpr(using Context) {
case (argp, paramTpe) =>
given nir.Position = argp.span
val externType = genExternType(paramTpe.finalResultType)
res += toExtern(externType, genExpr(argp))
val arg = (genExpr(argp), Type.box.get(externType)) match {
case (value @ Val.Null, Some(unboxedType)) =>
externType match {
case Type.Ptr | _: Type.RefKind => value
case _ =>
report.warning(
s"Passing null as argument of type ${paramTpe.show} to the extern method is unsafe. " +
s"The argument would be unboxed to primitive value of type $externType.",
argp.srcPos
)
Val.Zero(unboxedType)
}
case (value, _) => value
}
res += toExtern(externType, arg)
}
res.result()
}
Expand Down
6 changes: 0 additions & 6 deletions project/Settings.scala
Expand Up @@ -403,12 +403,6 @@ object Settings {
Test / unmanagedSourceDirectories += baseDirectory.value
.getParentFile()
.getParentFile() / "test-interface-common/src/test/scala",
scalacOptions --= scalaVersionsDependendent(scalaVersion.value)(
Seq.empty[String]
) {
// In Scala 2 enum `Status.value` is defined as `values()`, however in Scala 3 it's `values`
case (2, 13) => Seq("-Xfatal-warnings")
}
)

// Projects
Expand Down
Expand Up @@ -555,6 +555,16 @@ class IssuesTest {
assertEquals("class scala.runtime.Null$", classOf[Null].toString())
}

@Test def test_Issue2866() = {
// In the issue the calls to malloc and srand would fail
// becouse null would be passed to extern method taking unboxed type Size/Int
import scala.scalanative.libc.stdlib.{malloc, free, srand}
val ptr = malloc(null) // CSize -> RawSize should equal to malloc(0)
free(ptr) // memory allocated by malloc(0) should always be safe to free
srand(null) // CUnsignedInt -> Int should equal to srand(0UL)
free(null)
}

}

package issue1090 {
Expand Down

0 comments on commit 688c0ff

Please sign in to comment.